JS Canvas 中的栅格图层

Posted

技术标签:

【中文标题】JS Canvas 中的栅格图层【英文标题】:Raster Layers in JS Canvas 【发布时间】:2015-07-31 22:08:52 【问题描述】:

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

【问题讨论】:

那么,您的具体编程问题是什么? 【参考方案1】:

您当然可以只使用一个画布来应用非正式的 z-index。

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

序列化(“记住”)所有绘图命令和参数。 清除画布。 以正确的顺序重绘每一层上的所有折线。

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

这是您的 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; 
canvasborder:1px solid red;
<h4>Drag to draw layered lines</h4>
<canvas id="cvs" width=400 height=400></canvas>

【讨论】:

您好,感谢您的回答。我以前做过,这是一个小提琴(刚刚创建它)jsfiddle.net/drago96/4gq011yx这就是为什么我说这很慢,也许是我的错或者我没有很好地表达我的想法......(对不起语言,我我不是英语) 非常感谢,它真的很好用!没想到缓存积分会这么快! (可能只是中风功能只运行了几次)。我还考虑过使用三个画布(一个用于所选图层顶部的图层,一个用于所选图层上的绘画,另一个用于后面的图层)。比我将所有图层保存为使用 drawImage() 方法绘制的图像。当我完成编程后,我也会在这里放一个这个版本的小提琴。非常感谢!再见! 完成了另一个想法。这是小提琴jsfiddle.net/drago96/4gq011yx/3

以上是关于JS Canvas 中的栅格图层的主要内容,如果未能解决你的问题,请参考以下文章

canvas绘制形状

canvas图层

安卓高德地图开发java如何调用js自定义图层

Android UICanvas 画布 ③ ( Canvas 图层栈 | Canvas#saveLayer() 新建图层 | Canvas 状态栈保存信息标志位 )

[Canvas学习]绘制图形

canvas的常见用法