Share via


Canvas enhancements

Internet Explorer 11 further rounds out support for Canvas with new features from the W3C Canvas 2D Context Level 2 specification, including image smoothing, the even-odd fill rule, and dashed lines.

msImageSmoothingEnabled

You can use the msImageSmoothingEnabled property as described in the W3C Canvas 2D Context Level 2 spec to choose either traditional bilinear scaling or nearest-neighbor scaling when enlarging small images.

This property impacts drawing images and patterns on the following APIs.

Before IE11, images were scaled using bilinear scaling. This often results in a fuzzy image, especially on simple, small images such as rescaled game sprites.

When you turn off bilinear scaling by setting msImageSmoothingEnabled to false. It defaults to nearest-neighbor scaling and an enlarged game sprite becomes pixilated, but appears sharper. This is useful in creating a retro-style game effect.

You can see here how to switch between bilinear and nearest-neighbor scaling using msImageSmoothingEnabled to get the best look for your scaled graphics.

<!DOCTYPE html> <html>
<head>
  <title>canvasImageTest </title>
      <meta http-equiv="X-UA-Compatible" content="IE=edge"/> 
</head>
<body>   
  <canvas id="MyCanvas" width="225" height="225"> </canvas>
  <p>
    <button onclick="draw()">Change smoothing </button>    
  </p>
  <script type="text/javascript">        
    var smooth = true;
    draw();

    function draw() {
      var image = document.createElement("img");
      image.src = "geotest.png";
      image.addEventListener("load", function () {
        var canvas = document.getElementById("MyCanvas");
        if (canvas.getContext) {
          var ctx = canvas.getContext("2d");   // Get the context.
          // Set image smoothing mode
          if (smooth == true) {
            smooth = false;  // nearest neighbor
          } else {
            smooth = true;   // bilinear
          }
          ctx.msImageSmoothingEnabled = smooth;
          ctx.clearRect(0, 0, canvas.width, canvas.height);    // Clear the last image, if it exists.
          // var image = document.getElementById("pix");       // Get the address of the picture.
          // Straight draw. 
          ctx.drawImage(image, 1, 1);
          // Stretch the image a bit.
          ctx.drawImage(image, 20, 20, 200, 200);
          }
      }, false);
    }
  </script>
</body>
</html> 

Even-odd Fill rule

A Fill rule impacts how a shape is filled. The fill rule attribute now gives you two options, the default non-zero fill rule, and the even-odd fill rule. You can also set the fill rule individually as described in the W3C Canvas 2D Context, Level 2 spec on the following APIs:

Non-zero winding rule and even-odd rule are two algorithms used to check if a point is inside or outside an enclosed shape built with a path.

The non-zero winding rule specifies that you draw a ray from a point inside the shape to infinity in any direction. Starting with a count of zero, increment by one each time a path crosses the ray from left to right. If the path crosses the ray from the right to the left, decrement by one. If the result is zero after the counting is complete, the point is outside the path; otherwise it's inside. This star is drawn and filled using the non-zero fill rule with the point set to the center.

The even-odd rule specifies that you draw a ray from a point to infinity in any direction. Count the number of path segments that the ray crosses. If the count is an odd number, the point is inside the shape. If it's even, the point is outside the shape. The next picture is drawn the same way as the previous one, except it is filled using the even-odd fill rule.

This example creates the images shown above. It runs in IE11 and shows the effect of the fill rule attribute.

<!DOCTYPE html> 
<html>
<head>
  <title>msFillRule example</title>
  <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
  <script type="text/javascript">
    var fillRule = "nonzero";
    function draw() {
      var canvas = document.getElementById("MyCanvas");
      if (canvas.getContext) {

        var ctx = canvas.getContext("2d");
        ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear area for repeated use
        ctx.beginPath();
        ctx.strokeStyle = "blue";
        ctx.lineWidth = "5"
        ctx.moveTo(200, 110);
        ctx.lineTo(50, 110);
        ctx.lineTo(300, 310);
        ctx.lineTo(200, 10);
        ctx.lineTo(100, 310);
        ctx.lineTo(350, 110);
        ctx.lineTo(100, 110);
        ctx.stroke();
        ctx.fillStyle = "yellow";

        if (fillRule == "nonzero") {
          fillRule = "evenodd";
          document.getElementById("myButton").innerHTML = "Change to non-zero";
        } else {
          fillRule = "nonzero";
          document.getElementById("myButton").innerHTML = "Change to even-odd";
        }
        ctx.fill(fillRule);
      }
    }
  </script>
</head>
<body onload="draw();">
  <canvas id="MyCanvas" width="400" height="400">This browser or document mode doesn't support canvas</canvas>
    <br />
    <button id="myButton" onclick="draw();">Change</button>
</body>
</html>

In addition to the W3C standard fill rule attributes, IE11 offers msFillRule, a global fill rule property. This sets the fill rule across all methods, rather than individually setting the fill rule for each.

Dashed lines

In IE11, you can use dashed lines as described inW3C Canvas 2D Context, Level 2 spec to create dotted lines for maps, charts, or just decoration. Use dashed lines with the stroke or strokeRect methods in IE11, setLineDash, getLineDash, and lineDashOffset to create and animate patterns for your lines.

Every canvas context has a dash list that's initially empty. To make dashed lines, create an array (dash list) for the pattern you want to use in pixels. The array is an even number and each pair of elements contains a line length and a space length. In this example, you create a simple 3x3 pixel dotted line.

var dashList = [3, 3];  // Create 3x3 dots and spaces
var ctx = document.getElementById("myCanvas").getContext("2d");
ctx.setLineDash(dashList);

To get the current value of the dash list, use getLineDash. This code shows you how.

          var dashList = [12, 3, 3, 3];  // Create a dot/dash sequence    
          //  Set the current dash list 
          ctx.setLineDash(dashList);
          ctx.lineJoin = "round";
          ctx.lineWidth = "3";
          ctx.strokeStyle = "blue";
          ctx.strokeRect(5, 5, 300, 250);
          //  Get the current dash list and display it
          var tempDash = ctx.getLineDash();
          document.getElementById("myDiv").innerHTML = tempDash;

Dashed lines can be static, or by using the lineDashOffset property you can animate the lines by changing the phase (place where dashes start) of the dash pattern. The lineDashOffset property is set to the amount of offset in pixels where the pattern starts. By changing the offset incrementally in a timing loop, you can create the effect of moving lines, like the marching ants effect. This example creates three rectangles with moving dashed lines.

To change from counter-clockwise to clockwise rotation, set the initial offset a number and decrement it.

<!DOCTYPE html>
 <html>
<head>
  <title>Dash line example</title>

</head>
<body>
  <canvas id="MyCanvas" width="500" height="400">This browser or document mode doesn't support canvas</canvas> 
    <script type="text/javascript">

      var dashList = [12, 3, 3, 3];  // Create a dot/dash sequence

      function draw() {
        var canvas = document.getElementById("MyCanvas");
        if (canvas.getContext) {
          var ctx = canvas.getContext("2d");
          ctx.clearRect(0, 0, canvas.width, canvas.height);
          //  Assign the dashList for the dash sequence
          ctx.setLineDash(dashList);
          //  Get the current offset 
          ctx.lineDashOffset = antOffset;  // Animate the lines
          ctx.lineJoin = "round";
          ctx.lineWidth = "3";
          ctx.strokeStyle = "blue";
          ctx.strokeRect(5, 5, 300, 250);
          ctx.strokeStyle = "red";
          ctx.strokeRect(150, 200, 300, 150);
          ctx.lineDashOffset = -antOffset;  // Reverse animation
          ctx.lineWidth = "7";
          ctx.strokeStyle = "green";
          ctx.strokeRect(250, 50, 150, 250);
        }
      }

      //  Marching Ant code
      var antOffset = 0;  // Starting offset value
      function doAnts() {
        antOffset++;    
        if (antOffset > 20)  // Reset offset after total of dash List values
        {
          antOffset = 0;
        }
        draw();
        setTimeout(doAnts, 30);  //  Set a leisurely march of 30ms               
      }
      doAnts();  //  Start the demo 
  </script>
</body>
</html>

W3C Canvas 2D Context Level 2 spec

msImageSmoothingEnabled

msFillRule

setLineDash

getLineDash

lineDashOffset