带徒手画线条的HTML5画布

时间:2017-07-05 19:10:13

标签: javascript html5 canvas html5-canvas

我是HTML5中画布的新学习者,目前正在尝试为孩子们制作一个简单的绘画线项目。我将背景图像插入画布,并试图想出一个徒手画线方法,但最终没有结果。有人可以帮我修复下面的代码吗?谢谢大家以前。

<!DOCTYPE HTML>
<html>
    <script type="text/javascript">
    var canvas, ctx, flag = false,
        prevX = 0,
        currX = 0,
        prevY = 0,
        currY = 0,
        dot_flag = false;

    var x = "black",
        y = 2;

    function init() {
        canvas = document.getElementById('can');
        ctx = canvas.getContext("2d");
        w = canvas.width;
        h = canvas.height;

        canvas.addEventListener("mousemove", function (e) {
            findxy('move', e)
        }, false);
        canvas.addEventListener("mousedown", function (e) {
            findxy('down', e)
        }, false);
        canvas.addEventListener("mouseup", function (e) {
            findxy('up', e)
        }, false);
        canvas.addEventListener("mouseout", function (e) {
            findxy('out', e)
        }, false);
    }

    function color(obj) {
        switch (obj.id) {
            case "green":
                x = "green";
                break;
            case "blue":
                x = "blue";
                break;
            case "red":
                x = "red";
                break;
            case "yellow":
                x = "yellow";
                break;
            case "orange":
                x = "orange";
                break;
            case "black":
                x = "black";
                break;
            case "white":
                x = "white";
                break;
        }
        if (x == "white") y = 14;
        else y = 2;

    }

    function draw() {
        ctx.beginPath();
        ctx.moveTo(prevX, prevY);
        ctx.lineTo(currX, currY);
        ctx.strokeStyle = x;
        ctx.lineWidth = y;
        ctx.stroke();
        ctx.closePath();
    }

    function erase() {
        var m = confirm("Want to clear");
        if (m) {
            ctx.clearRect(0, 0, w, h);
            document.getElementById("canvasimg").style.display = "none";
        }
    }

    function save() {
        document.getElementById("canvasimg").style.border = "2px solid";
        var dataURL = canvas.toDataURL();
        document.getElementById("canvasimg").src = dataURL;
        document.getElementById("canvasimg").style.display = "inline";
    }

    function findxy(res, e) {
        if (res == 'down') {
            prevX = currX;
            prevY = currY;
            currX = e.clientX - canvas.offsetLeft;
            currY = e.clientY - canvas.offsetTop;

            flag = true;
            dot_flag = true;
            if (dot_flag) {
                ctx.beginPath();
                ctx.fillStyle = x;
                ctx.fillRect(currX, currY, 2, 2);
                ctx.closePath();
                dot_flag = false;
            }
        }
        if (res == 'up' || res == "out") {
            flag = false;
        }
        if (res == 'move') {
            if (flag) {
                prevX = currX;
                prevY = currY;
                currX = e.clientX - canvas.offsetLeft;
                currY = e.clientY - canvas.offsetTop;
                draw();
            }
        }
    }
    </script>
    <body onload="init()" style="background-image: src=c:/WebProgram/Pictures/test1.png;">
        <canvas id="can" width="520" height="700" style="position:absolute;top:10%;left:10%;border:2px solid;"></canvas>
        <div style="position:absolute;top:12%;left:43%;">Choose Color</div>
        <div style="position:absolute;top:15%;left:45%;width:10px;height:10px;background:green;" id="green" onclick="color(this)"></div>
        <div style="position:absolute;top:15%;left:46%;width:10px;height:10px;background:blue;" id="blue" onclick="color(this)"></div>
        <div style="position:absolute;top:15%;left:47%;width:10px;height:10px;background:red;" id="red" onclick="color(this)"></div>
        <div style="position:absolute;top:17%;left:45%;width:10px;height:10px;background:yellow;" id="yellow" onclick="color(this)"></div>
        <div style="position:absolute;top:17%;left:46%;width:10px;height:10px;background:orange;" id="orange" onclick="color(this)"></div>
        <div style="position:absolute;top:17%;left:47%;width:10px;height:10px;background:black;" id="black" onclick="color(this)"></div>
        <div style="position:absolute;top:20%;left:43%;">Eraser</div>
        <div style="position:absolute;top:22%;left:45%;width:15px;height:15px;background:white;border:2px solid;" id="white" onclick="color(this)"></div>
        <img id="canvasimg" style="position:absolute;top:10%;left:52%;" style="display:none;">
        <input type="button" value="save" id="btn" size="30" onclick="save()" style="position:absolute;top:5%;left:10%;">
        <input type="button" value="clear" id="clr" size="23" onclick="erase()" style="position:absolute;top:5%;left:15%;">
    </body>
</html>

2 个答案:

答案 0 :(得分:1)

创建基于画布的绘图应用程序。

绘图应用程序没有那么多。当按钮在鼠标位置向下绘制时,听鼠标。

如果你想拥有一个响应式画布并且还包含undos等等,那么你需要从更复杂的层面开始。

绘图和显示。

首先,您应该将图形与显示区分开。这是通过创建保存绘图的屏幕外画布来完成的。它的大小是恒定的,可以由用户平移和缩放(甚至旋转)。

如果要创建线条或方框,使用离屏画布来保存绘图还可以在绘图上绘制。

有助于创建画布的一些功能

function createCanvas(width, height) {
  const c = document.createElement("canvas");
  c.width = width;
  c.height = height;
  c.ctx = c.getContext("2d");
  return c;
}
const drawing = createCanvas(512,512);

您可以使用

将该画布绘制到显示画布
ctx.drawImage(drawing,0,0);

该片段使用阴影和边框在画布中心绘制绘图,看起来不错。

鼠标处理程序

正确执行鼠标界面非常重要。从画布中聆听鼠标事件有一些问题。当用户拖离画布时,您不再获得任何鼠标事件。这意味着当鼠标离开画布时,您需要停止绘图,因为您不知道鼠标在返回时是否仍然处于停机状态。

要解决此问题,请聆听文档的鼠标事件。这将在按钮关闭时捕获鼠标,允许用户在您仍然获得事件时将鼠标移动到屏幕上的任何位置。如果鼠标在离开画布时上升,你仍然会得到那个事件。

  

注意堆栈溢出代码段窗口会阻止鼠标捕获ATM(最近的更改),因此上述鼠标行为仅限于包含该代码段的iFrame。

您也不应该从鼠标事件中进行任何渲染。某些渲染操作可能很慢,比鼠标的更新速度慢得多。如果从鼠标事件渲染,则会丢失鼠标事件。始终在鼠标事件侦听器中执行尽可能少的代码。

在代码段中,鼠标事件仅记录当前鼠标状态,如果鼠标已关闭并且绘制它将记录鼠标创建的路径。通过函数调用requestAnimationFrame同步到显示刷新率的单独循环负责呈现内容。它以大约60fps的速度运行。为了在没有任何事情发生时停止绘图,会使用一个标志来指示显示需要更新updateDisplay当有更改时,您将其设置为true updateDisplay=true;,并在下次显示硬件准备好显示时一个框架,它将绘制所有更新的内容。

画一条线

一条线只是一组连接点。在代码片段中,我创建了一个线对象。它包含构成线条的点以及线宽和颜色。

当鼠标停止时,我创建一个新的线对象并开始向其添加点。我标记显示需要更新,并在显示循环中通过其绘制方法在显示画布上绘制线条。

当鼠标向上移动时,我在绘图画布上绘制线条。这样做可以让你将一些智能应用到线上(片段很简单,对线条没有任何作用),例如使它沿着它的长度淡出。只有在鼠标启动时才会知道它的长度。

在代码片段中,当鼠标按下时我会丢弃该行,但如果您想要撤消,则会保存在数组中绘制的每一行。要撤消您,只需清除图形并重新绘制除撤消线之外的所有线条。

行对象和相关代码。

// a point object creates point from x,y coords or object that has x,y
const point = (x, y = x.y + ((x = x.x) * 0)) => ({ x, y });

// function to add a point to the line
function addPoint(x, y) { this.points.push(point(x, y)); }

// draw a line on context ctx and adds offset.x, offset.y
function drawLine(ctx, offset) { 
  ctx.strokeStyle = this.color;
  ctx.lineWidth = this.width;
  ctx.lineJoin = "round";
  ctx.lineCap = "round";
  ctx.beginPath();
  var i = 0;
  while (i < this.points.length) {
    const p = this.points[i++];
    ctx.lineTo(p.x + offset.x, p.y + offset.y);
  }
  ctx.stroke();
}
// creates a new line object
function createLine(color, width) {
  return {
    points: [], // the points making up the line
    color,      // colour of the line
    width,      // width of the line
    add: addPoint,  // function to add a point
    draw: drawLine,  // function to draw the whole line
  };
}

示例代码段

该片段的结果比我想要的要长一点。我已经为相关代码添加了评论,但如果您有任何疑问,请在评论中提问,我会更新答案并提供更多信息。

&#13;
&#13;
// size of drawing and its starting background colour
const drawingInfo = {
  width: 384 ,
  height: 160,
  bgColor: "white",
}
const brushSizes = [1, 2, 3, 4, 5, 6, 7, 8];
const colors = "red,orange,yellow,green,cyan,blue,purple,white,gray,black".split(",");
var currentColor = "blue";
var currentWidth = 2;
var currentSelectBrush;
var currentSelectColor;
const colorSel = document.getElementById("colorSel");
colors.forEach((color, i) => {
  var swatch = document.createElement("span");
  swatch.className = "swatch";
  swatch.style.backgroundColor = color;
  if (currentColor === color) {
    swatch.className = "swatch highlight";
    currentSelectColor = swatch;
  } else {
    swatch.className = "swatch";
  }
  swatch.addEventListener("click", (e) => {
    currentSelectColor.className = "swatch";
    currentColor = e.target.style.backgroundColor;
    currentSelectColor = e.target;
    currentSelectColor.className = "swatch highlight";
  });
  colorSel.appendChild(swatch);
})
brushSizes.forEach((brushSize, i) => {
  var brush = document.createElement("canvas");
  brush.width = 16;
  brush.height = 16;
  brush.ctx = brush.getContext("2d");
  brush.ctx.beginPath();
  brush.ctx.arc(8, 8, brushSize / 2, 0, Math.PI * 2);
  brush.ctx.fill();
  brush.brushSize = brushSize;
  if (currentWidth === brushSize) {
    brush.className = "swatch highlight";
    currentSelectBrush = brush;
  } else {
    brush.className = "swatch";
  }

  brush.addEventListener("click", (e) => {
    currentSelectBrush.className = "swatch";
    currentSelectBrush = e.target;
    currentSelectBrush.className = "swatch highlight";
    currentWidth = e.target.brushSize;

  });
  colorSel.appendChild(brush);
})


const canvas = document.getElementById("can");
const mouse = createMouse().start(canvas, true);
const ctx = canvas.getContext("2d");
var updateDisplay = true; // when true the display needs updating
var ch, cw, w, h; // global canvas size vars


var currentLine;

var displayOffset = {
  x: 0,
  y: 0
};

// a point object creates point from x,y coords or object that has x,y
const point = (x, y = x.y + ((x = x.x) * 0)) => ({
  x,
  y
});
// function to add a point to the line
function addPoint(x, y) {
  this.points.push(point(x, y));
}

function drawLine(ctx, offset) { // draws a line
  ctx.strokeStyle = this.color;
  ctx.lineWidth = this.width;
  ctx.lineJoin = "round";
  ctx.lineCap = "round";
  ctx.beginPath();
  var i = 0;
  while (i < this.points.length) {
    const p = this.points[i++];
    ctx.lineTo(p.x + offset.x, p.y + offset.y);
  }
  ctx.stroke();
}

function createLine(color, width) {
  return {
    points: [],
    color,
    width,
    add: addPoint,
    draw: drawLine,
  };
}


// creates a canvas
function createCanvas(width, height) {
  const c = document.createElement("canvas");
  c.width = width;
  c.height = height;
  c.ctx = c.getContext("2d");
  return c;
}
// resize main display canvas and set global size vars
function resizeCanvas() {
  ch = ((h = canvas.height = innerHeight - 32) / 2) | 0;
  cw = ((w = canvas.width = innerWidth) / 2) | 0;
  updateDisplay = true;
}

function createMouse() {
  function preventDefault(e) { e.preventDefault() }
  const mouse = {
    x: 0,
    y: 0,
    buttonRaw: 0,
    prevButton: 0
  };
  const bm = [1, 2, 4, 6, 5, 3]; // bit masks for mouse buttons
  const mouseEvents = "mousemove,mousedown,mouseup".split(",");
  const m = mouse;
  // one mouse handler
  function mouseMove(e) {
    m.bounds = m.element.getBoundingClientRect();
    m.x = e.pageX - m.bounds.left - scrollX;
    m.y = e.pageY - m.bounds.top - scrollY;
    
    if (e.type === "mousedown") {
      m.buttonRaw |= bm[e.which - 1];
    } else if (e.type === "mouseup") {
      m.buttonRaw &= bm[e.which + 2];
    }
    // check if there should be a display update
    if (m.buttonRaw || m.buttonRaw !== m.prevButton) {
      updateDisplay = true;
    }
    // if the mouse is down and the prev mouse is up then start a new line
    if (m.buttonRaw !== 0 && m.prevButton === 0) { // starting new line
      currentLine = createLine(currentColor, currentWidth);
      currentLine.add(m); // add current mouse position
    } else if (m.buttonRaw !== 0 && m.prevButton !== 0) { // while mouse is down
      currentLine.add(m); // add current mouse position      
    }
    m.prevButton = m.buttonRaw; // remember the previous mouse state
    e.preventDefault();
  }
  // starts the mouse 
  m.start = function(element, blockContextMenu) {
    m.element = element;

    mouseEvents.forEach(n => document.addEventListener(n, mouseMove));
    if (blockContextMenu === true) {
      document.addEventListener("contextmenu", preventDefault)
    }
    return m
  }
  return m;
}
var cursor = "crosshair";
function update(timer) { // Main update loop
  cursor = "crosshair";
  globalTime = timer;
  // if the window size has changed resize the canvas
  if (w !== innerWidth || h !== innerHeight) {
    resizeCanvas()
  }
  if (updateDisplay) {
    updateDisplay = false;
    display(); // call demo code
  }
 
  ctx.canvas.style.cursor = cursor;
  requestAnimationFrame(update);
}
// create a drawing canvas.
const drawing = createCanvas(drawingInfo.width, drawingInfo.height);
// fill with white
drawing.ctx.fillStyle = drawingInfo.bgColor;
drawing.ctx.fillRect(0, 0, drawing.width, drawing.height);

// function to display drawing 
function display() {
  ctx.clearRect(0, 0, w, h);
  ctx.fillStyle = "rgba(0,0,0,0.25)";
  const imgX = cw - (drawing.width / 2) | 0;
  const imgY = ch - (drawing.height / 2) | 0;
  // add a shadow to make it look nice
  ctx.fillRect(imgX + 5, imgY + 5, drawing.width, drawing.height);

  // add outline
  ctx.strokeStyle = "black";
  ctx.lineWidth = "2";
  ctx.strokeRect(imgX, imgY, drawing.width, drawing.height);
  // draw the image
  ctx.drawImage(drawing, imgX, imgY);
  if (mouse.buttonRaw !== 0) {
    if (currentLine !== undefined) {
      currentLine.draw(ctx, displayOffset); // draw line on display canvas
      cursor = "none";
      updateDisplay = true; // keep updating 
    }
  } else if (mouse.buttonRaw === 0) {
    if (currentLine !== undefined) {
      currentLine.draw(drawing.ctx, {x: -imgX, y: -imgY }); // draw line on drawing
      currentLine = undefined;
      updateDisplay = true;
      // next line is a quick fix to stop a slight flicker due to the current frame not showing the line
      ctx.drawImage(drawing, imgX, imgY);

    }
  }
}

requestAnimationFrame(update);
&#13;
#can {
  position: absolute;
  top: 32px;
  left: 0px;
  background-color: #AAA;
}

.colors {
  border: 1px solid black;
  display: inline-flex;
}

.swatch {
  min-width: 16px;
  min-height: 16px;
  max-width: 16px;
  border: 1px solid black;
  display: inline-block;
  margin: 2px;
  cursor: pointer;

}

.highlight {
  border: 1px solid red;
}
&#13;
<canvas id="can"></canvas>
  <div class="colors" id="colorSel"></div>
&#13;
&#13;
&#13;

更新为了回应OP的评论,我添加了一个HTML版本,您应该能够复制和粘贴(包括<!DOCTYPE HTML>在内的所有内容</HTML>)进入html文档(例如drawing.html),然后在支持ES6的浏览器中打开。例如Chrome,Firefox,Edge。

复制下面的代码段内容。

&#13;
&#13;
<!DOCTYPE HTML>
<html>
<head>
    <style>
#can {
  position: absolute;
  top: 32px;
  left: 0px;
  background-color: #AAA;
}

.colors {
  border: 1px solid black;
  display: inline-flex;
}

.swatch {
  min-width: 16px;
  min-height: 16px;
  max-width: 16px;
  border: 1px solid black;
  display: inline-block;
  margin: 2px;
  cursor: pointer;

}

.highlight {
  border: 1px solid red;
}
    </style>
</head>

<body>
    <canvas id="can"></canvas>
    <div class="colors" id="colorSel"></div>

<script>
// size of drawing and its starting background colour
const drawingInfo = {
  width: 384 ,
  height: 160,
  bgColor: "white",
}
const brushSizes = [1, 2, 3, 4, 5, 6, 7, 8];
const colors = "red,orange,yellow,green,cyan,blue,purple,white,gray,black".split(",");
var currentColor = "blue";
var currentWidth = 2;
var currentSelectBrush;
var currentSelectColor;
const colorSel = document.getElementById("colorSel");
colors.forEach((color, i) => {
  var swatch = document.createElement("span");
  swatch.className = "swatch";
  swatch.style.backgroundColor = color;
  if (currentColor === color) {
    swatch.className = "swatch highlight";
    currentSelectColor = swatch;
  } else {
    swatch.className = "swatch";
  }
  swatch.addEventListener("click", (e) => {
    currentSelectColor.className = "swatch";
    currentColor = e.target.style.backgroundColor;
    currentSelectColor = e.target;
    currentSelectColor.className = "swatch highlight";
  });
  colorSel.appendChild(swatch);
})
brushSizes.forEach((brushSize, i) => {
  var brush = document.createElement("canvas");
  brush.width = 16;
  brush.height = 16;
  brush.ctx = brush.getContext("2d");
  brush.ctx.beginPath();
  brush.ctx.arc(8, 8, brushSize / 2, 0, Math.PI * 2);
  brush.ctx.fill();
  brush.brushSize = brushSize;
  if (currentWidth === brushSize) {
    brush.className = "swatch highlight";
    currentSelectBrush = brush;
  } else {
    brush.className = "swatch";
  }

  brush.addEventListener("click", (e) => {
    currentSelectBrush.className = "swatch";
    currentSelectBrush = e.target;
    currentSelectBrush.className = "swatch highlight";
    currentWidth = e.target.brushSize;

  });
  colorSel.appendChild(brush);
})


const canvas = document.getElementById("can");
const mouse = createMouse().start(canvas, true);
const ctx = canvas.getContext("2d");
var updateDisplay = true; // when true the display needs updating
var ch, cw, w, h; // global canvas size vars


var currentLine;

var displayOffset = {
  x: 0,
  y: 0
};

// a point object creates point from x,y coords or object that has x,y
const point = (x, y = x.y + ((x = x.x) * 0)) => ({
  x,
  y
});
// function to add a point to the line
function addPoint(x, y) {
  this.points.push(point(x, y));
}

function drawLine(ctx, offset) { // draws a line
  ctx.strokeStyle = this.color;
  ctx.lineWidth = this.width;
  ctx.lineJoin = "round";
  ctx.lineCap = "round";
  ctx.beginPath();
  var i = 0;
  while (i < this.points.length) {
    const p = this.points[i++];
    ctx.lineTo(p.x + offset.x, p.y + offset.y);
  }
  ctx.stroke();
}

function createLine(color, width) {
  return {
    points: [],
    color,
    width,
    add: addPoint,
    draw: drawLine,
  };
}


// creates a canvas
function createCanvas(width, height) {
  const c = document.createElement("canvas");
  c.width = width;
  c.height = height;
  c.ctx = c.getContext("2d");
  return c;
}
// resize main display canvas and set global size vars
function resizeCanvas() {
  ch = ((h = canvas.height = innerHeight - 32) / 2) | 0;
  cw = ((w = canvas.width = innerWidth) / 2) | 0;
  updateDisplay = true;
}

function createMouse() {
  function preventDefault(e) { e.preventDefault() }
  const mouse = {
    x: 0,
    y: 0,
    buttonRaw: 0,
    prevButton: 0
  };
  const bm = [1, 2, 4, 6, 5, 3]; // bit masks for mouse buttons
  const mouseEvents = "mousemove,mousedown,mouseup".split(",");
  const m = mouse;
  // one mouse handler
  function mouseMove(e) {
    m.bounds = m.element.getBoundingClientRect();
    m.x = e.pageX - m.bounds.left - scrollX;
    m.y = e.pageY - m.bounds.top - scrollY;
    
    if (e.type === "mousedown") {
      m.buttonRaw |= bm[e.which - 1];
    } else if (e.type === "mouseup") {
      m.buttonRaw &= bm[e.which + 2];
    }
    // check if there should be a display update
    if (m.buttonRaw || m.buttonRaw !== m.prevButton) {
      updateDisplay = true;
    }
    // if the mouse is down and the prev mouse is up then start a new line
    if (m.buttonRaw !== 0 && m.prevButton === 0) { // starting new line
      currentLine = createLine(currentColor, currentWidth);
      currentLine.add(m); // add current mouse position
    } else if (m.buttonRaw !== 0 && m.prevButton !== 0) { // while mouse is down
      currentLine.add(m); // add current mouse position      
    }
    m.prevButton = m.buttonRaw; // remember the previous mouse state
    e.preventDefault();
  }
  // starts the mouse 
  m.start = function(element, blockContextMenu) {
    m.element = element;

    mouseEvents.forEach(n => document.addEventListener(n, mouseMove));
    if (blockContextMenu === true) {
      document.addEventListener("contextmenu", preventDefault)
    }
    return m
  }
  return m;
}
var cursor = "crosshair";
function update(timer) { // Main update loop
  cursor = "crosshair";
  globalTime = timer;
  // if the window size has changed resize the canvas
  if (w !== innerWidth || h !== innerHeight) {
    resizeCanvas()
  }
  if (updateDisplay) {
    updateDisplay = false;
    display(); // call demo code
  }
 
  ctx.canvas.style.cursor = cursor;
  requestAnimationFrame(update);
}
// create a drawing canvas.
const drawing = createCanvas(drawingInfo.width, drawingInfo.height);
// fill with white
drawing.ctx.fillStyle = drawingInfo.bgColor;
drawing.ctx.fillRect(0, 0, drawing.width, drawing.height);

// function to display drawing 
function display() {
  ctx.clearRect(0, 0, w, h);
  ctx.fillStyle = "rgba(0,0,0,0.25)";
  const imgX = cw - (drawing.width / 2) | 0;
  const imgY = ch - (drawing.height / 2) | 0;
  // add a shadow to make it look nice
  ctx.fillRect(imgX + 5, imgY + 5, drawing.width, drawing.height);

  // add outline
  ctx.strokeStyle = "black";
  ctx.lineWidth = "2";
  ctx.strokeRect(imgX, imgY, drawing.width, drawing.height);
  // draw the image
  ctx.drawImage(drawing, imgX, imgY);
  if (mouse.buttonRaw !== 0) {
    if (currentLine !== undefined) {
      currentLine.draw(ctx, displayOffset); // draw line on display canvas
      cursor = "none";
      updateDisplay = true; // keep updating 
    }
  } else if (mouse.buttonRaw === 0) {
    if (currentLine !== undefined) {
      currentLine.draw(drawing.ctx, {x: -imgX, y: -imgY }); // draw line on drawing
      currentLine = undefined;
      updateDisplay = true;
      // next line is a quick fix to stop a slight flicker due to the current frame not showing the line
      ctx.drawImage(drawing, imgX, imgY);

    }
  }
}

requestAnimationFrame(update);

/* load and add image to the drawing. It may take time to load. */
function loadImage(url){
    const image = new Image();
    image.src = url;
    image.onload = function(){
        if(drawing && drawing.ctx){
            drawing.width = image.width;
            drawing.height = image.height;
            drawing.ctx.drawImage(image,0,0);
        };
    }

 }
 loadImage("https://i.stack.imgur.com/C7qq2.png?s=328&g=1");
        

</script>

</body>
</html>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

当你想到这个过程时,这个过程非常简单:

  • 首先,单击鼠标时获取鼠标的点(x和y坐标)(确保在单击鼠标时仅取这些点)。列表项
  • 然后在点之间绘制线条。这也应该很容易。 (请记住,只有当鼠标按下时才能绘制线条,并且应该从用户按下鼠标或触摸屏幕的第一个点开始。几乎每当有输入时)
  • 现在保存你的绘图
    • 使用画布将图像转换为数据网址&#39; toDataURL()功能。
    • 然后使用this code将dataURL转换为Blob。
    • 使用URL.createObjectURL(blob)创建指向blob的链接。
    • 创建一个<a>代码并将其href设置为前面提到的链接。同时将其download属性设置为您希望调用文件的任何内容(例如&#39; myImage.png&#39;)。这应该会为您留下<a>标记,其内容类似于此<a href="blob:https://example.com/3d45a4f6-7302-485a-a255-d7f56ecf8074" download="myImage.png">Click to Save</a>

当然,这是我看到你完成这个应用程序的方式。

还有一件事,请阅读以下教程以了解更多信息:

美好的一天!希望这会有所帮助,抱歉这么懒,而且没有给出实际代码来支持这个答案。