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

Posted

技术标签:

【中文标题】HTML5 Canvas 如何填充鼠标绘制的三角形【英文标题】:HTML5 Canvas How To Fill A Mouse Drawn Triangle 【发布时间】:2021-10-31 20:19:33 【问题描述】:

我正在尝试在通过拖动鼠标绘制的 html5 画布上填充三角形。

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

显示工作 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>

【问题讨论】:

【参考方案1】:
    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();

    

【讨论】:

谢谢。所以问题是额外的moveTo 我打破了路径,所以没有封闭的路径可以填充。【参考方案2】:

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>

【讨论】:

谢谢。我已经接受了答案,但我也感谢您的解释和回答。 +1。 没问题 TenG - 我写得太慢了,没有注意到其他人已经回答了。 ;)

以上是关于HTML5 Canvas 如何填充鼠标绘制的三角形的主要内容,如果未能解决你的问题,请参考以下文章

HTML5 Canvas元素绘制地图,如何实现显示鼠标所移动地方名称?

如何使用HTML5中canvas绘制一个立体金字塔图形?(javascript可以)

试图找到两个向量之间的角度(三角形)(HTML5 Canvas)

HTML5 Canvas 填充文本和字体

如何将canvas轨迹保存为动画

怎样用h5canvas鼠标绘制图形