【问题标题】:EaselJs, CreateJs Undo canvas drawing is too slow on mobileEaselJs、CreateJs Undo canvas 绘图在移动端太慢
【发布时间】:2015-05-29 08:20:54
【问题描述】:

我正在为画布绘图创建 phonegap/cordova android 应用程序。

我已将 CordovaWebView(android stock browser webview) 替换为 https://github.com/ludei/webview-plus/ webview+ 以提高 android 平台上的绘图性能。更换 webview 后,在 android 上绘图流畅。

现在我正在使用下面的演示作为基础创建撤消功能

http://www.createjs.com/Demos/EaselJS/CurveTo

撤消功能按预期工作,但随着画布上的绘图数据增多,撤消性能逐渐下降。由于我遵循撤消的方法,这种逐渐的性能下降是绝对肯定的。 在桌面浏览器上性能不错,但在 Android 手机和平板电脑上撤消需要很长时间。

我的撤消方法:

  1. 将每个绘制的点连同笔划宽度和颜色一起存储(推送)到一个 points[] 数组中。这个 points[] 数组存储了一条连续线的所有信息。

  2. 然后我在 mouseup 事件中存储(推送)allPoints 数组中的每条连续线信息。

  3. 然后在单击撤消时,我从 allPoints[] 数组中弹出(删除)最后一条连续线,然后通过重绘 allPoints[] 数组中的所有点来更新舞台。

随着画布绘制笔画的增加,allPoints[] 数组大小增加,重绘 allPoints 需要更多时间。

我已经设置了一个小提琴来演示我的撤消方法。

http://jsfiddle.net/JTqvJ/188/

var canvas, stage;
var drawingCanvas;
var oldPt;
var oldMidPt;
var title;
var color;
var stroke;
var colors;
var index;
var allPoints = [];
var points = [];

function init() {
    canvas = document.getElementById("canvas");
    var undoEl = document.getElementById('undo');
    undoEl.addEventListener("click",undoDrawing);
    index = 0;
    colors = ["#828b20"];

    //check to see if we are running in a browser with touch support
    stage = new createjs.Stage(canvas);
    stage.autoClear = false;
    stage.enableDOMEvents(true);

    createjs.Touch.enable(stage);
    createjs.Ticker.setFPS(24);

    drawingCanvas = new createjs.Shape();

    stage.addEventListener("stagemousedown", handleMouseDown);
    stage.addEventListener("stagemouseup", handleMouseUp);

    stage.addChild(drawingCanvas);
    stage.update();
}

function stop() {
}

function handleMouseDown(event) {
    color = colors[(index++) % colors.length];
    stroke = 2;
    oldPt = new createjs.Point(stage.mouseX, stage.mouseY);
    oldMidPt = oldPt.clone();
    stage.addEventListener("stagemousemove", handleMouseMove);
}

function handleMouseMove(event) {
  var midPt = new createjs.Point(oldPt.x + stage.mouseX >> 1, oldPt.y + stage.mouseY >> 1);

  // current point to draw
   var point = {
      midPt_x: midPt.x,
      midPt_y: midPt.y,
      oldPt_x: oldPt.x,
      oldPt_y: oldPt.y,
      oldMidPt_x:oldMidPt.x,
      oldMidPt_y: oldMidPt.y,
      s_stroke: stroke,
      s_color: color, 
   }
  //store this point in points array 
  points.push(point);

  //draw this point
  drawLine(point);


  oldPt.x = stage.mouseX;
  oldPt.y = stage.mouseY;

  oldMidPt.x = midPt.x;
  oldMidPt.y = midPt.y;


  stage.update();
}

function handleMouseUp(event) {
    stage.removeEventListener("stagemousemove", handleMouseMove);

    allPoints.push(points);

    //empty points array for saving new point objects
    points = [];

    console.log(allPoints);
}

function drawLine(point){
    console.log("drawing");
drawingCanvas.graphics.clear().setStrokeStyle(point.s_stroke, 'round', 'round').beginStroke(point.s_color).moveTo(point.midPt_x, point.midPt_y).curveTo(point.oldPt_x, point.oldPt_y, point.oldMidPt_x, point.oldMidPt_y);
};

function reDrawAllLines(){
  //clear whole canvas to refresh

    stage.clear();
    for (var index1 in allPoints) {
        for(var index2 in allPoints[index1]){
            drawLine(allPoints[index1][index2]);
            stage.update();
            //alert(allPoints[index1][index2]);
        }
    }


};

function undoDrawing(){
    console.log('undo');

  if(allPoints.length > 0){
      console.log('pop last one');
    //pop/remove last continuous line from allPoints
    allPoints.pop();
    allPoints.pop();
    console.log(allPoints);

    //redraw allPoints array to refresh canvas
    reDrawAllLines();              
  }    
}

init();

我认为重绘 allPoints 比将画布绘图的快照保存为图像以进行撤消更好,因为这将是一个消耗大量内存的过程,但现在重绘 allPoints 很慢,我的运气不好:(

我是否在撤消功能中做错了什么,因为画布需要很长时间才能从 allPoints[] 数组重绘绘图。在 10 行或更多行之后,撤消在 Android 手机上非常缓慢。

有人可以帮助我用更好的方法来撤消沉重的画布绘图吗?

注意:我的画布是 A4 页面大小,即高度为 1123 像素,宽度为 794 像素。

【问题讨论】:

  • 用白色重新绘制绘制点并不能解决我撤消的目的。有谁知道如何在绘制之前将画布上的绘制点重置为其原始状态?

标签: android canvas easeljs undo createjs


【解决方案1】:

我设法使用画架快速绘图和快速撤消。

现在我对每条新线都使用了基于对象(形状)的方法,而不是保存每个点。

对于快速撤消:刚刚从舞台上移除最后一个形状并调用 stage.update() 以重绘所有形状。

对于快速绘图:只需在我的 tick() 侦听器或 handleMouseMove() 中用 currentShape.draw(ctx) 替换 stage.update() 调用,它就像一个魅力。 currentShape.draw() 仅绘制调用它的形状,而 stage.update() 在每个 tick() 上也重绘其所有子形状,从而使绘制速度变慢。

快速撤消和快速绘图的工作小提琴http://jsfiddle.net/MkRCg/134/

var stage;
var isMouseDown;
var currentShape;
var oldMidX, oldMidY, oldX, oldY;
var canvas;
var ctx;

function init() {
    stage = new createjs.Stage('canvas');
    stage.autoClear = true;
    stage.addEventListener("stagemousedown", handleMouseDown);
    stage.addEventListener("stagemouseup", handleMouseUp);            
    createjs.Touch.enable(stage);
    stage.update();
    createjs.Ticker.addEventListener("tick", tick);

    //bind element with id 'undo-drawing' with undoDrawing function
    var undoEl = document.getElementById('undo-drawing');
    undoEl.addEventListener("click",undoDrawing);

    ctx = stage.canvas.getContext('2d');    
}

function stop() {
   createjs.Ticker.removeEventListener("tick", tick);          
}

function tick() {
    if (isMouseDown) {
        var pt = new createjs.Point(stage.mouseX, stage.mouseY);
        var midPoint = new createjs.Point(oldX + pt.x>>1, oldY+pt.y>>1);
        currentShape.graphics.moveTo(midPoint.x, midPoint.y);
        currentShape.graphics.curveTo(oldX, oldY, oldMidX, oldMidY);

        oldX = pt.x;
        oldY = pt.y;

        oldMidX = midPoint.x;
        oldMidY = midPoint.y;

        /* Costly redrawing all previous objects too */
        //stage.update();

        /* only draws currentShape, made drawing fast*/
        currentShape.draw(ctx);


    }
}

function handleMouseDown() {
    isMouseDown = true;

    var s = new createjs.Shape();
    oldX = stage.mouseX;
    oldY = stage.mouseY;
    oldMidX = stage.mouseX;
    oldMidY = stage.mouseY;
    var g = s.graphics;

    var stroke = 2;
    g.setStrokeStyle(stroke, 'round', 'round');

    var color = "#000000";

    g.beginStroke(color);
    stage.addChild(s);

    currentShape = s;
}

function handleMouseUp() {
  isMouseDown = false;

    //make drawing smooth on each mouse up
    stage.update();
   // alert();
}


function undoDrawing() {
  console.log('undo clicked');
  stage.removeChildAt(stage.children.length - 1);
  stage.update();
}


init();

【讨论】:

    【解决方案2】:

    我还没有在具有大量形状的移动设备上对此进行测试,但是您可以将绘图画布设为容器,并且每条线都有自己的形状,然后在撤消的情况下,您不必重绘任何东西,只需从画布中删除最后一个形状。

    【讨论】:

    • 我在easeljs的文档和示例中没有找到任何可以将线条绘制为形状的内容。您能帮我将线条绘制为形状对象吗?
    • 我已经创建了撤消方法,正如您所说,通过创建自己形状的每一行并在撤消时删除最后一行或形状。现在撤消速度非常快,但是随着#行的增加,我的画布绘制性能变得越来越慢。这仅在 android 手机和平板电脑上明显,但在桌面浏览器上不明显。以线条为形状的新撤消操作fiddle
    • 我明白你现在在我的 Nexus 5 上绘图速度变慢的意思。我想另一个选择是限制撤消次数,达到该限制后,绘制第一个但有很多形状成一个形状,甚至是位图。 ?
    • 感谢您的支持。我解决了这两个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-09
    • 2015-05-06
    • 2016-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-28
    相关资源
    最近更新 更多