[英]Canvas drawing is very slow
我想用工作正常的标记显示比例。 最重要的是,我还想用红色指示器在比例尺中显示鼠标位置。
因此,我在运行应用程序时绘制画布,然后在更改鼠标位置时重新绘制整个画布。
我是画布的新手,不明白我的代码有什么问题。 我一直试图解决它,但没有运气。
问题可能出在这个函数中,
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,这意味着画布上下文必须构建的路径是巨大的。
因此,要解决此问题,您必须找到一种方法来改善该问题。
屏幕高度不是 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, middle: 5, 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, level3: 100, 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, 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); } } 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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.