画布上的水平滚动。 HTML5
Posted
技术标签:
【中文标题】画布上的水平滚动。 HTML5【英文标题】:Horizontal Scrolling on Canvas. HTML5 【发布时间】:2012-12-31 09:07:39 【问题描述】:我正在一个 web 项目中通过 javascript 创建一个画布。
画布在 x-y 平面上有图形表示。
我正在尝试将水平滚动功能添加到画布。
我研究了一些方法:-
1) 在画布上绘制12个月的数据,当鼠标向前滚动时,第一个月的数据消失,最后添加一个新的月份数据,绘制新的画布。
缺点:- 每次鼠标滚动以平移时间线时 - 都必须进行新的 SQL 查询,这使我的 Web 应用程序非常慢。
2) 也许我可以通过 1 个 SQL 查询在画布上绘制 10 年的数据,但只显示 12 个月的数据。掩盖剩下的 9 年。现在当客户端滚动时,我捕获滚动事件并移动到画布的适当部分。这可能吗?如果是那怎么办?
谁能给点建议?
我当前的画布表示 = 只有 12 个月的数据
为了更具体地说明滚动,我想对我的客户端滚动操作有如下感觉:-
http://www.simile-widgets.org/timeline/
【问题讨论】:
SVG 一般被认为是更合适的数据绘图工具,只是说。 但是你要做的是使用context.translate(-x, 0)
来模拟效果。这样,您就不必更改数据点的 x 坐标。
【参考方案1】:
这是一个非常基本的实现:http://jsfiddle.net/CQPeU/
var can = document.getElementById("can"),
ctx = can.getContext('2d'),
dragging = false,
lastX = 0,
translated = 0;
// these two lines will make the y-axis grow upwards.
ctx.scale(1,-1);
ctx.translate(0, -400);
can.onmousedown = function(e)
var evt = e || event;
dragging = true;
lastX = evt.offsetX;
window.onmousemove = function(e)
var evt = e || event;
if (dragging)
var delta = evt.offsetX - lastX;
translated += delta;
ctx.translate(delta, 0); // translate the context.
lastX = evt.offsetX;
draw(); // redraw
window.onmouseup = function()
dragging = false;
function draw()
ctx.clearRect(-translated, 0, 600, 400); // this is why we need to keep track of how much we've translated
for (var i = 0; i < plot.length; i++)
ctx.beginPath();
ctx.arc(plot[i].x, plot[i].y, 5, 0, 2 * Math.PI); // note we don't have to futz with the x/y values, and can use them directly.
ctx.fill();
要创建网格,您可以执行以下操作:
var grid = (function(dX, dY)
var can = document.createElement("canvas"),
ctx = can.getContext('2d');
can.width = dX;
can.height = dY;
// fill canvas color
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, dX, dY);
// x axis
ctx.strokeStyle = 'orange';
ctx.moveTo(.5, 0.5);
ctx.lineTo(dX + .5, 0.5);
ctx.stroke();
// y axis
ctx.moveTo(.5, .5);
ctx.lineTo(.5, dY + .5);
ctx.stroke();
return ctx.createPattern(can, 'repeat');
)(100, 50);
会这样使用:
function draw()
ctx.clearRect(-translated, 0, 600, 400);
ctx.rect(-translated, 0, 600, 400);
ctx.fillStyle = grid;
ctx.fill();
ctx.fillStyle = "#fff";
for (var i = 0; i < plot.length; i++)
ctx.beginPath();
ctx.arc(plot[i].x, plot[i].y, 5, 0, 2 * Math.PI);
ctx.fill();
更新的演示:http://jsfiddle.net/CQPeU/2/
【讨论】:
通过这种方法,一个新问题浮出水面 - y 轴上的静态标签。如:-jsfiddle.net/WNpKE/10 我建议将它们放在单独的层上(不同的画布,或作为普通的 DOM 元素)。 或者,也许更简单的方法是将它们的 x 坐标设置为-translated
,如下所示:jsfiddle.net/WNpKE/11
效果很好!!!但是我的方法的问题是......背景网格没有被复制......它被限制在 x = 65 和 x = 930 之间//你知道我的意思吗?我想将我的方法与你的无限网格方法结合起来。那将是我的解决方案!!!
我的天!丹尼尔已经做出了判断。这将使我朝着正确的方向前进。非常感谢你,伙计!如果你在,我会给你买午餐、晚餐和啤酒。【参考方案2】:
为避免在@Shmiddty 的回答中重绘每个鼠标移动事件,您可以将整个画布绘制成超大尺寸,然后更改 CSS 边距属性。当画布的内容变得更复杂时,这是一个显着的性能提升。
这是一个演示:https://jsfiddle.net/ax7n8944/
html:
<div id="canvasdiv" style="width: 500px; height: 250px; overflow: hidden">
<canvas id="canvas" ></canvas>
</div>
JS:
var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
var dragging = false;
var lastX;
var marginLeft = 0;
for (var i = 0; i < 1000; i++)
context.beginPath();
context.arc(Math.random() * 10000, Math.random() * 250, 20.0, 0, 2 * Math.PI, false);
context.stroke();
canvas.addEventListener('mousedown', function(e)
var evt = e || event;
dragging = true;
lastX = evt.clientX;
e.preventDefault();
, false);
window.addEventListener('mousemove', function(e)
var evt = e || event;
if (dragging)
var delta = evt.clientX - lastX;
lastX = evt.clientX;
marginLeft += delta;
canvas.style.marginLeft = marginLeft + "px";
e.preventDefault();
, false);
window.addEventListener('mouseup', function()
dragging = false;
, false);
【讨论】:
【参考方案3】:最好使用带有以下插件的 Phaser Framework http://jdnichollsc.github.io/Phaser-Kinetic-Scrolling-Plugin/
【讨论】:
以上是关于画布上的水平滚动。 HTML5的主要内容,如果未能解决你的问题,请参考以下文章
Android Chrome 上的 HTML 画布不滚动窗口
即使水平滚动,如何使放置在fabricjs对象顶部的DOM元素保持在那里