JS 中的栅格图层 Canvas

Raster Layers in JS Canvas

我需要你的帮助来制作一个带有图层的小绘画应用程序。 我希望我的程序能够处理不同的层,但不使用多个 canvas 或使用外部库,以便更多地了解整个 canvas 的工作原理。 我想记住位于不同层对象的数组中的每个数据,而不是将它们从最低到最高打印在 canvas 上。问题是我想用手绘画,而不仅仅是用圆圈和正方形。如果我会记住我手绘的所有东西,那么它会很慢(已经尝试过)。 谢谢大家的帮助!

您当然可以仅使用一个 canvas 来应用非正式的 z-index。

并且您已经确定了一种正确的方法:

  • 序列化("remember")所有绘图命令和参数。
  • 清除 canvas.
  • 按正确顺序重新绘制每一层上的所有多段线。

然后您可以重播那些保存的命令。显示将很快出现。

这是您的 Layer.draw 方法 的一个版本,它经过重构以获得更好的性能:

// draw() will define & stroke all polylines on this layer
// The 1st point in each polyline contains that line's styling
Layer.prototype.draw = function( ctx ) {

    // just return if there's no points to draw
    if(this.points.length<2){return;}

    // cache an often used array
    var pts=this.points;

    // index for points
    var i=0;

    // process all points in the
    while(i<pts.length){

        // cache the often used first point in a new polyline
        var p=pts[i];

        // set styles for this polyline 
        ctx.lineWidth = p.lineWidth;
        ctx.lineJoin = p.lineJoin;
        ctx.lineCap = p.lineCap;
        ctx.strokeStyle = p.strokeStyle;

        // begin this polyline path
        ctx.beginPath();
        ctx.moveTo(p.x, p.y);
        i++;

        // define all segment points on this polyline
        while( i<pts.length && pts[i].lineWidth==undefined ) {
            ctx.lineTo( pts[i].x , pts[i].y );
            i++;
        }

        // stroke this polyline
        ctx.stroke();

    } // end while(i<pts.length)
}

下面是示例代码和演示:

Point = function( x , y ) {
  this.x = x;
  this.y = y;
}

Point.prototype.invert = function() {
  var t = this.x;
  this.x = this.y;
  this.y = t;
}

Layer = function() {
  this.points = [];
}

Layer.prototype.draw = function( ctx ) {

  // just return if there's no points to draw
  if(this.points.length<2){return;}

  // cache an often used array
  var pts=this.points;

  // index for points
  var i=0;

  // process all points in the
  while(i<pts.length){

    // cache the often used first point in a new polyline
    var p=pts[i];

    // set styles for this polyline 
    ctx.lineWidth = p.lineWidth;
    ctx.lineJoin = p.lineJoin;
    ctx.lineCap = p.lineCap;
    ctx.strokeStyle = p.strokeStyle;

    // begin this polyline path
    ctx.beginPath();
    ctx.moveTo(p.x, p.y);
    i++;

    // define all segment points on this polyline
    while( i<pts.length && pts[i].lineWidth==undefined ) {
      ctx.lineTo( pts[i].x , pts[i].y );
      i++;
    }

    // stroke this polyline
    ctx.stroke();

  } // end while(i<pts.length)
}

ExtendedPoint = function( x , y , style ) {
  this.x = x;
  this.y = y;
  this.lineWidth = style.lineWidth;
  this.lineJoin = style.lineJoin;
  this.lineCap = style.lineCap;
  this.strokeStyle = style.strokeStyle;
}

function startLine( e ) {

  var x = e.clientX - canvas.offsetLeft;
  var y = e.clientY - canvas.offsetTop;

  var p = new ExtendedPoint( x , y , {
    lineWidth: 5,
    lineJoin: "round",
    lineCap: "round",
    // testing only: make each new polyline a different color
    // strokeStyle: "black"
    strokeStyle: randomColor(),
  });
  selectedLayer.points.push(p);

  isDrawing = true;
}

function continueLine( e ) {

  if (isDrawing == true) {
    var x = e.clientX - canvas.offsetLeft;
    var y = e.clientY - canvas.offsetTop;

    var p = new Point( x , y );
    selectedLayer.points.push( p );
  }
}

function endLine() {

  isDrawing = false;
}

function redraw() {
  context.clearRect( 0, 0, 400, 400 );
  for ( var i = 0 ; i < layers.length ; i++ ) {
    layers[i].draw( context );
  }
}

var canvas = document.getElementById("cvs");

canvas.setAttribute("width" , 400);
canvas.setAttribute("height", 400);

var context = canvas.getContext("2d");

var layers = [];
layers.push( new Layer() );
var selectedLayer = layers[0];

var isDrawing = false;

canvas.addEventListener( "mousedown" , startLine );
canvas.addEventListener( "mousemove" , continueLine );
canvas.addEventListener( "mousemove" , redraw );
canvas.addEventListener( "mouseup" , endLine );



// testing only: make each polyline a different color
function randomColor(){ 
  return('#'+Math.floor(Math.random()*16777215).toString(16));
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<h4>Drag to draw layered lines</h4>
<canvas id="cvs" width=400 height=400></canvas>