Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save a reference to a html canvas path

I'm working on some code which is drawing to a canvas. One part of the code draws some lines onto the canvas. The position and colour of those lines don't change, but they often need to be redrawn because other code may have affected it (eg: drawn over the top of it).

There can be several hundred lines to draw, and in these cases, profiling shows me that it's taking ~200ms to draw, so I'm looking to optimise this somewhat.

One thing I noticed was that when drawing to the canvas, you basically are adding points to a path and then once ready, you can fill or stroke that path. Though the pixels on the canvas are out of date, if I were able to keep a reference to the path, then updating would be as simple as re-stroking the previously constructed path.

My question is: how on earth do you get a Path object?

The fill and stroke methods appear to accept a path object, and the spec defines the methods for Path, but I can't seem to find the actual Path class anywhere...

So, just to recap:

I have something like this:

function update() {
  context.beginPath();
  // lots of lines added to the default path...
  context.moveTo(x1, y1); context.lineTo(somewhere, else);
  context.moveTo(x2, y2); context.lineTo(somewhere, else);

  context.stroke();
}

What I'd like is something like this:

function update() {
  if (!this.path) {
    this.path = new Path(); // <-- here's the magic
    this.path.moveTo(x1, y2); this.path.lineTo(somewhere, else); // etc
  }
  this.path.stroke();
}
like image 511
nickf Avatar asked Jan 12 '14 16:01

nickf


2 Answers

The canvas spec calls for a Path object that is not implemented in browsers yet.

BTW, when implemented, the Path object will be useful in hit-testing when combined with context.isPointInPath(myPath); Someday...

Here's how you could create your own Path object until the browsers catch up:

  • Create a JS object that contains a canvas where your path strokes are drawn.
  • When you want to do myPath.stroke(), use myVisibleContext.drawImage(myPath.context,0,0) to "blit" the path's canvas onto your drawing canvas.

Demo: http://jsfiddle.net/m1erickson/QLJv8/

Code:

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    #canvas{border:1px solid red;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    function Path(maxWidth,maxHeight,color,linewidth,drawingContext){
        this.width=maxWidth;
        this.height=maxHeight;
        this.drawingCtx=drawingContext;
        this.points=[]
        this.canvas=document.createElement("canvas");
        this.canvas.width=maxWidth;
        this.canvas.height=maxHeight;
        this.ctx=this.canvas.getContext("2d");
        this.ctx.strokeStyle=color;
        this.ctx.lineWidth=linewidth;
        this.lastX;
        this.lastY;
    }
    Path.prototype.moveTo=function(x,y){
        this.lastX=x;
        this.lastY=y;

    }
    Path.prototype.lineTo=function(x,y){
        this.ctx.moveTo(this.lastX,this.lastY);
        this.ctx.lineTo(x,y);
        this.ctx.stroke();
        this.lastX=x;
        this.lastY=y;
    }
    Path.prototype.stroke=function(){
        this.drawingCtx.drawImage(this.canvas,0,0);
    }

    // create a new path object

    var p=new Path(300,300,"blue",2,ctx);

    // set the Path's drawing commands

    p.moveTo(69,91);
    p.lineTo(250,150);
    p.moveTo(69,208);
    p.lineTo(180,54);
    p.lineTo(180,245);
    p.lineTo(69,91);
    p.moveTo(69,208);
    p.lineTo(250,150);

    // draw the Path.canvas to the drawing canvas
    p.stroke();

    // tests...

    $("#stroke").click(function(){
        p.stroke();
    });
    $("#erase").click(function(){
        ctx.clearRect(0,0,canvas.width,canvas.height);
    });

}); // end $(function(){});
</script>

</head>

<body>
    <button id="stroke">Path.stroke</button><br>
    <button id="erase">Erase main canvas</button><br>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
like image 58
markE Avatar answered Sep 27 '22 01:09

markE


Turns out, it's just that no browser supports it yet, according to this blog (dated 24th January 2013) http://www.rgraph.net/blog/2013/january/html5-canvas-path-objects.html

like image 42
nickf Avatar answered Sep 23 '22 01:09

nickf