微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

画布绘制非常慢

如何解决画布绘制非常慢

我想显示带有刻度的刻度尺,这很好用。最重要的是,我还想用红色指示器在刻度中显示鼠标位置。

因此,我在运行应用程序时绘制画布,然后在更改鼠标位置时重新绘制整个画布。

我是新手,不了解我的代码有什么问题。我一直在试图解决它,但是没有运气。

函数中可能存在问题

 function drawBlackMarkers(y,coordinateMeasurment){
    const markHightY = scaleTextPadding.initial;
    ctxLeft.moveto(coordinateMeasurment,y + markHightY);
    ctxLeft.lineto(completeMarkHight,y + markHightY);
  }

我有一个很大的 for循环,这意味着要进行如此多次的迭代,在该循环中,我多次调用 drawBlackMarkers 函数,如下所示。

function setMarkers(initialValY,rangeValY,coordinateMeasurmentr,divisableVal,scaleCountStartValueOfY,scaleCountRangeValueOfY) {
    let count = 0;
    // re-modifying scale staring and ending values based on zoom factor
    const scaleInceremnt = scaleIncementValue;
    for (let y = (initialValY),scaleCountY = scaleCountStartValueOfY;
      y <= (rangeValY) && scaleCountY <= scaleCountRangeValueOfY;
      y += scaleInceremnt,scaleCountY += incrementFactor) {


      switch (count) {
        case displayScale.starting:
          coordinateMeasurment = marktype.bigMark; count++;
          const scaleValY = scaleCountY - divisableVal;

          ctxLeft.strokeStyle = colors.black;

          ctxLeft.font = scaleNumberFont;
          const size = ctxLeft.measureText(scaleValY.toString());
          ctxLeft.save();
          const textx = coordinateMeasurment + ((size.width) / 2);
          const textY = y - scaleTextPadding.alignment;
          ctxLeft.translate(textx,textY);
          ctxLeft.rotate(-Math.PI / 2);
          ctxLeft.translate(-textx,-textY);
          ctxLeft.fillText(scaleValY.toString(),coordinateMeasurment,y - scaleTextPadding.complete);
          ctxLeft.restore();
          break;
        case displayScale.middle:
          coordinateMeasurment = marktype.middleMark; count++;
          break;
        case displayScale.end:
          coordinateMeasurment = marktype.smallMark; count = 0;
          break;
        default:
          coordinateMeasurment = marktype.smallMark; count++;
          break;
      }

      // to draw scale lines on canvas
  // drawBlackMarkers(y,coordinateMeasurment);      
    }
  }

请检查以下内容http://jsfiddle.net/3v5nt7fe/1/

问题是,如果我注释 drawBlackMarkers 函数调用,鼠标坐标更新非常快,但是如果我取消注释,则更新位置会花费很长时间。

我真的需要帮助来解决此问题。

解决方法

这不是drawBlackMarkers本身,是这样:

for (let y = (initialValY),scaleCountY = scaleCountStartValueOfY;
  y <= (rangeValY) && scaleCountY <= scaleCountRangeValueOfY;
  y += scaleInceremnt,scaleCountY += incrementFactor) {

这个数字不断增加,发生了640,000次。您可以这样写:

  // to draw scale lines on canvas
  // drawBlackMarkers(y,coordinateMeasurment);
  console.log(y);

并查看控制台结果。

所以for循环几乎没有作用,因为它大部分在switch语句后面,并且当它执行此简单的drawBlackMarkers之外时,它也显示了该循环的实际成本。 rangeValY为640,000,这意味着canvas上下文必须构造的路径很大。

因此,要解决此问题,您必须找到一种缓解该问题的方法。

,

这正在做很多不必要的工作

屏幕的高度不是64000像素。您只想计算视口,而只绘制视口中的内容。

您的函数drawBlackMarkers不是罪魁祸首。在此之前,该系统非常缓慢,仅增加了另一幅要绘制的内容。正是稻草折断了骆驼的背。

通过减少绘图的长度,可以非常容易地避免浪费CPU周期。

在此版本中,我要做的就是重新启用drawBlackMarkers,并缩小画布。

const CANVAS_WIDTH = 2000;
const CANVAS_HEIGHT = 50;
const completeMarkHight = 15;
const divisibleValue = 0;
const scaleIncementValue = 10;
const scaleTextPadding = { initial: 0,middle: 5,end: 10,complete: 15,alignment: 18 };
const displayScale = { starting: 0,end: 9 };
const colors = { red: '#FF0000',white: '#D5D6D7',black: '#181c21' };
const marktype = { bigMark: 0,middleMark: 5,smallMark: 10 };
const startingInitialOrigin = { x: 0,y: 0 };
const scaleNumberFont = '10px Titillium Web Regular';
const defaultZoomLevel = 100;
const markingGap = {level1: 400,level2: 200,level3: 100,level4: 50,level5: 20,level6: 10 };
const zoomScaleLevel = {level0: 0,level1: 25,level2: 50,level4: 200,level5: 500,level6: 1000};



var $canvas = $('#canvas');
var ctxLeft = $canvas[0].getContext('2d');
var mousePositionCoordinates;
var pagePositions = { x: 100,y:0 };
var  remainderX;
var  remainderY;
var  scaleCountRemainderX;
var  scaleCountRemainderY;
var  zoomFactor;
var  zoomScale;
var  zoomLevel;
var  multiplyFactor;
var  incrementFactor;
var  markingDistance;
var  timetaken=0;
ctxLeft.fillStyle = colors.white;

function render() {
    clear();
    ctxLeft.beginPath();
    zoomScale = 1000;
    zoomLevel = 1000;
    zoomFactor = zoomLevel / defaultZoomLevel;
    markingDistance = markingGap.level6;
    multiplyFactor = markingDistance / defaultZoomLevel;
    incrementFactor = markingDistance / scaleIncementValue; 

    renderVerticalRuler(startingInitialOrigin.y);
   
}

 function renderVerticalRuler(posY) {
     
    
    const initialValY = - posY / multiplyFactor;
    const rangeValY = (CANVAS_WIDTH - posY) / multiplyFactor;

    const initialValOfYwithMultiplyFactor = -posY;
    const rangeValOfYwithMultiplyFactor = (CANVAS_WIDTH - posY);


    // to adjust scale count get remainder value based on marking gap
    scaleCountRemainderY = initialValOfYwithMultiplyFactor % markingDistance;
    const scaleCountStartValueOfY = initialValOfYwithMultiplyFactor - scaleCountRemainderY;
    const scaleCountRangeValueOfY = rangeValOfYwithMultiplyFactor - scaleCountRemainderY;

    // to get orgin(0,0) values
    remainderY = initialValY % 100;
    const translateY = (posY / multiplyFactor) - remainderY;

    ctxLeft.translate(origin.x,translateY); // x,y
    const coordinateMeasurment = 0;

    const t0 = performance.now();
    setMarkers(initialValY,rangeValY,coordinateMeasurment,divisibleValue,scaleCountStartValueOfY,scaleCountRangeValueOfY);

    const t1 = performance.now()
    console.log("it took " + (t1 - t0) + " milliseconds.");

    ctxLeft.stroke();
    ctxLeft.closePath();
  }
  
function setMarkers(initialValY,coordinateMeasurmentr,divisableVal,scaleCountRangeValueOfY) {
    let count = 0;
    // re-modifying scale staring and ending values based on zoom factor
    const scaleInceremnt = scaleIncementValue;
    for (let y = (initialValY),scaleCountY = scaleCountStartValueOfY;
      y <= (rangeValY) && scaleCountY <= scaleCountRangeValueOfY;
      y += scaleInceremnt,scaleCountY += incrementFactor) {


      switch (count) {
        case displayScale.starting:
          coordinateMeasurment = marktype.bigMark; count++;
          const scaleValY = scaleCountY - divisableVal;

          ctxLeft.strokeStyle = colors.black;

          ctxLeft.font = scaleNumberFont;
          const size = ctxLeft.measureText(scaleValY.toString());
          ctxLeft.save();
          const textX = coordinateMeasurment + ((size.width) / 2);
          const textY = y - scaleTextPadding.alignment;
          ctxLeft.translate(textX,textY);
          ctxLeft.rotate(-Math.PI / 2);
          ctxLeft.translate(-textX,-textY);
          ctxLeft.fillText(scaleValY.toString(),y - scaleTextPadding.complete);
          ctxLeft.restore();
          break;
        case displayScale.middle:
          coordinateMeasurment = marktype.middleMark; count++;
          break;
        case displayScale.end:
          coordinateMeasurment = marktype.smallMark; count = 0;
          break;
        default:
          coordinateMeasurment = marktype.smallMark; count++;
          break;
      }

      // to draw scale lines on canvas
   drawBlackMarkers(y,coordinateMeasurment);
    }
  }
  
  
 function drawBlackMarkers(y,coordinateMeasurment){
    const markHightY = scaleTextPadding.initial;
    ctxLeft.moveTo(coordinateMeasurment,y + markHightY);
    ctxLeft.lineTo(completeMarkHight,y + markHightY);
  }
  
  
function clear() {
    ctxLeft.resetTransform();
    ctxLeft.clearRect(origin.x,origin.y,CANVAS_HEIGHT,CANVAS_WIDTH);
}


render();
$('.canvas-container').mousemove(function(e) {
   
    
    mousePositionCoordinates = {x:e.clientX,y:e.clientY};
             
        render();
        
        // SHOW RED INDICATOR 
        ctxLeft.beginPath();
        ctxLeft.strokeStyle = colors.red;  // show mouse indicator
        ctxLeft.lineWidth = 2;

        // to display purple indicator based on zoom level
        const mouseX = mousePositionCoordinates.x * zoomFactor;
        const mouseY = mousePositionCoordinates.y * zoomFactor;
        const markHightY =scaleTextPadding.initial + this.remainderY;
        ctxLeft.moveTo(marktype.bigMark,e.clientY );
        ctxLeft.lineTo(completeMarkHight,e.clientY);
        ctxLeft.stroke();
        $('.mouselocation').text(`${mousePositionCoordinates.x},${mousePositionCoordinates.y}`);
   
});
body,html{
  width: 100000px;
  height:100000px;
}
.canvas-container{
    width:100%;
    height:100%;
}

.canvasLeft {
    position: absolute;
    border:1px solid black;
    background: grey;
    border-top: none;
    z-index: 1;
    top:0
}


.mouselocation{
  position: fixed;
    right: 0px;
    top: 50px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<div class="canvas-container">
  <canvas id="canvas" class="canvasLeft" width="30" height="2000"></canvas>
</div>


<div class="mouselocation">
   
</div>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。