Solution 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();

    }

Solution 2 :

The CanvasRenderingContext2D’s fill() method fills a path with a given color. To be able to fill such a path, it must contain at least three points – which is fulfilled in your case.

The problem is the way you’re creating the path:

  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 );

By calling moveTo() again, you’re essentially starting a new path – thus you have just three single lines hence nothing to fill.

Try making the path in one go:

  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>

Problem :

I am trying to fill a triangle shape on a HTML5 canvas drawn by dragging the mouse.

I have similar effect for circles, rectangles working.

The code showing both the working drawCircle and not working drawTriangle functions is below. The outline of the triangle gets drawn but it is not filled. I have tried loving the context.stroke line to various places in the sequence of there is no effect.

<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>

Comments

Comment posted by TenG

Thank you. So the issue was the extra

Comment posted by TenG

Thanks. I already accepted an answer but I appreciate your explanation and answers as well. +1.

Comment posted by obscure

No problem TenG – I was writing a little too slow and didn’t notice someone else answered yet. 😉

By