HTML5 Canvas 如何填充鼠标绘制的三角形

HTML5 Canvas How To Fill A Mouse Drawn Triangle

我正在尝试通过拖动鼠标在 HTML5 canvas 上填充三角形。

我对圆形、矩形有类似的效果。

下面显示了有效的 drawCircle 和无效的 drawTriangle 函数的代码。绘制了三角形的轮廓,但未填充。我试过按顺序将 context.stroke 行爱到不同的地方,但没有效果。

<style>
#divContainer {
    width: 100%;
    height: 80%;
    background: #ddd;
}

#divContentArea {
    left: 0px;
    top: 0px;
    right: 0px;
    bottom: 0px;
}


.canvas {
   cursor: crosshair;
   position:relative;
   left:0px;
   top:0px;
}

</style>

   <div>
      Click the button to select the shape type then click and drag mouse on the canvas below.
      <BR>
      
      <button type="button" onClick='shapetype="circle";'>Draw Circle</button>
      <button type="button" onClick='shapetype="triangle";'>Draw Triangle</button>
      <BR>

   </div>
   
<div id="divContainer">
   
   <div id="divContentArea">

            <canvas id="canvas" class='canvas'>
            Sorry, your browser does not support a canvas object.
            </canvas>

   </div>

</div>

<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

var canrect = canvas.getBoundingClientRect();

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

var lastPoint;
var startPoint;

var isDrawing = false;

var shapetype = 'triangle';

canvas.onmousedown = function(e) {

   isDrawing = true;   
   if ( shapetype == 'circle' ) {
      canvas.removeEventListener("mousemove", drawTriangle, false);
      canvas.addEventListener("mousemove", drawCircle, false);
   } else {
      canvas.removeEventListener("mousemove", drawCircle, false);
      canvas.addEventListener("mousemove", drawTriangle, false);
   }
      
   lastPoint = { x: e.offsetX, y: e.offsetY };
   startPoint = lastPoint;      
};

function drawTriangle(e) {

   // This doesn't work - triangle is not filled
   
   e.preventDefault();
   e.stopPropagation();

   if (!isDrawing) return;

   mx = e.offsetX;
   my = e.offsetY;

   // clear the canvas
   context.clearRect(0, 0, canvas.width, canvas.height);

   // calculate the rectangle width/height based
   // on starting vs current mouse position
   var twidth = Math.abs(mx - startPoint.x) ;
   var theight = Math.abs(my - startPoint.y) ;

   // draw a new rect from the start position 
   // to the current mouse position
   context.beginPath();
   context.lineWidth = 3;
   context.lineJoin = context.lineCap = 'round';
   context.setLineDash([0, 0]);
   context.globalAlpha = 1.0;


   if ( mx >= startPoint.x ) {
      context.moveTo(startPoint.x, startPoint.y );
      context.lineTo(mx, my);
      context.moveTo(mx-(2*twidth), my );
      context.lineTo(mx, my);
      context.moveTo(startPoint.x, startPoint.y );
      context.lineTo(mx-(2*twidth), my );
   } else {
      context.moveTo(startPoint.x, startPoint.y );
      context.lineTo(mx, my);
      context.moveTo(mx+(2*twidth), my );
      context.lineTo(mx, my);
      context.moveTo(startPoint.x, startPoint.y );
      context.lineTo(mx+(2*twidth), my );
   }

   context.closePath();
   context.strokeStyle = 'red';
   context.stroke();
   context.fillStyle = 'rgba(25,50,75,0.5)';
   context.fill();

}

function drawCircle(e) {

   // This works

   e.preventDefault();
   e.stopPropagation();

   if (!isDrawing) return;

   mx = e.offsetX;
   my = e.offsetY;

   // clear the canvas
   context.clearRect(0, 0, canvas.width, canvas.height);

   // calculate the rectangle width/height based
   // on starting vs current mouse position
   var cradius = Math.abs(mx - startPoint.x) ;

   // draw a new rect from the start position 
   // to the current mouse position
   context.beginPath();
   context.lineWidth = 3;
   context.lineJoin = context.lineCap = 'round';
   context.setLineDash([0, 0]);
   context.globalAlpha = 1.0;

   context.strokeStyle = 'red';
   context.arc(startPoint.x, startPoint.y, cradius, 0, 2 * Math.PI, false);

   context.fillStyle = 'rgba(25,50,75,0.5)';
   context.fill();
   context.stroke();


}

canvas.onmouseup = function() {
   isDrawing = false;
};

canvas.onmouseleave = function() {
   isDrawing = false;
};

</script>

    function drawTriangle(e) {
        e.preventDefault();
        e.stopPropagation();

        if (!isDrawing) return;
        
        // clear the canvas
        context.clearRect(0, 0, canvas.width, canvas.height);

        // draw a new rect from the start position
        // to the current mouse position
        context.strokeStyle = 'red';
        context.fillStyle = 'rgba(25,50,75,0.5)';
        context.lineWidth = 3;
        context.lineJoin = context.lineCap = 'round';
        context.setLineDash([0, 0]);
        context.globalAlpha = 1.0;
        context.beginPath();


        context.moveTo(startPoint.x, startPoint.y);
        context.lineTo(e.offsetX, e.offsetY);
        context.lineTo(startPoint.x * 2 - e.offsetX, e.offsetY);
        context.closePath();
        context.stroke();
        context.fill();

    }

CanvasRenderingContext2D 的 fill() 方法用给定的颜色填充路径。为了能够填充这样的路径,它必须至少包含三个点 - 这在您的情况下已实现。

问题在于您创建路径的方式:

  context.moveTo(startPoint.x, startPoint.y );
  context.lineTo(mx, my);
  context.moveTo(mx-(2*twidth), my );
  context.lineTo(mx, my);
  context.moveTo(startPoint.x, startPoint.y );
  context.lineTo(mx-(2*twidth), my );

通过再次调用 moveTo(),您实际上是在开始一条新路径 - 因此您只有三行,因此无需填写任何内容。

尝试一次完成路径:

  context.moveTo(startPoint.x, startPoint.y );
  context.lineTo(mx, my);
  context.lineTo(mx-(2*twidth), my );

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

var canrect = canvas.getBoundingClientRect();

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

var lastPoint;
var startPoint;

var isDrawing = false;

var shapetype = 'triangle';

canvas.onmousedown = function(e) {

  isDrawing = true;
  if (shapetype == 'circle') {
    canvas.removeEventListener("mousemove", drawTriangle, false);
    canvas.addEventListener("mousemove", drawCircle, false);
  } else {
    canvas.removeEventListener("mousemove", drawCircle, false);
    canvas.addEventListener("mousemove", drawTriangle, false);
  }

  lastPoint = {
    x: e.offsetX,
    y: e.offsetY
  };
  startPoint = lastPoint;
};

function drawTriangle(e) {

  // This doesn't work - triangle is not filled

  e.preventDefault();
  e.stopPropagation();

  if (!isDrawing) return;

  mx = e.offsetX;
  my = e.offsetY;

  // clear the canvas
  context.clearRect(0, 0, canvas.width, canvas.height);

  // calculate the rectangle width/height based
  // on starting vs current mouse position
  var twidth = Math.abs(mx - startPoint.x);
  var theight = Math.abs(my - startPoint.y);

  // draw a new rect from the start position 
  // to the current mouse position
  context.beginPath();
  context.lineWidth = 3;
  context.lineJoin = context.lineCap = 'round';
  context.setLineDash([0, 0]);
  context.globalAlpha = 1.0;


  if (mx >= startPoint.x) {
    context.moveTo(startPoint.x, startPoint.y);
    context.lineTo(mx, my);
    context.lineTo(mx - (2 * twidth), my);

  } else {
    context.moveTo(startPoint.x, startPoint.y);
    context.lineTo(mx, my);
    context.lineTo(mx + (2 * twidth), my);
  }

  context.closePath();
  context.strokeStyle = 'red';
  context.stroke();
  context.fillStyle = 'rgba(25,50,75,0.5)';
  context.fill();

}

function drawCircle(e) {

  // This works

  e.preventDefault();
  e.stopPropagation();

  if (!isDrawing) return;

  mx = e.offsetX;
  my = e.offsetY;

  // clear the canvas
  context.clearRect(0, 0, canvas.width, canvas.height);

  // calculate the rectangle width/height based
  // on starting vs current mouse position
  var cradius = Math.abs(mx - startPoint.x);

  // draw a new rect from the start position 
  // to the current mouse position
  context.beginPath();
  context.lineWidth = 3;
  context.lineJoin = context.lineCap = 'round';
  context.setLineDash([0, 0]);
  context.globalAlpha = 1.0;

  context.strokeStyle = 'red';
  context.arc(startPoint.x, startPoint.y, cradius, 0, 2 * Math.PI, false);

  context.fillStyle = 'rgba(25,50,75,0.5)';
  context.fill();
  context.stroke();


}

canvas.onmouseup = function() {
  isDrawing = false;
};

canvas.onmouseleave = function() {
  isDrawing = false;
};
#divContainer {
  width: 100%;
  height: 80%;
  background: #ddd;
}

#divContentArea {
  left: 0px;
  top: 0px;
  right: 0px;
  bottom: 0px;
}

.canvas {
  cursor: crosshair;
  position: relative;
  left: 0px;
  top: 0px;
}
<div>
  Click the button to select the shape type then click and drag mouse on the canvas below.
  <BR>

  <button type="button" onClick='shapetype="circle";'>Draw Circle</button>
  <button type="button" onClick='shapetype="triangle";'>Draw Triangle</button>
  <BR>

</div>

<div id="divContainer">

  <div id="divContentArea">

    <canvas id="canvas" class='canvas'>
            Sorry, your browser does not support a canvas object.
            </canvas>

  </div>
</div>