2013-01-16 58 views
9

我正在通过web上的javascript创建画布。在画布上水平滚动。 HTML5

画布在x-y平面上有图形表示。

我想将水平滚动功能添加到画布上。

我已经调查了几个方法: -

1),还有12个月的价值在画布上的数据,当鼠标滚动前进,1个月的数据消失,并在最后添加新个月的数据,画新画布。答:每次鼠标滚动到平移时间轴时,都必须创建一个新的SQL查询,这使得我的Web应用程序非常缓慢。

2)也许我可以通过1次SQL查询在画布上画出10年的数据,但只显示12个月的数据。掩盖了9年的其余时间。现在,当客户端滚动时,我捕获滚动事件并移动到画布的相应部分。这可能吗?如果是的话那么如何?

任何人都可以建议吗?

My current representation of the canvas = with only 12 months worth of data

我目前的画布表示=仅12个月有价值的数据

要在滚动更加具体,我想有一种感觉,如下面的小部件我的客户端滚动操作: -

http://www.simile-widgets.org/timeline/

+1

SVG通常被认为是数据绘图,只是说一个更合适的工具。 – Shmiddty

+0

但是你想要做的是使用'context.translate(-x,0)'来模拟效果。这样,您不必更改数据点的x坐标。 – Shmiddty

回答

12

这里的一个非常基本的实现: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/

+0

好不好啊! – Philo

+0

在这种方法下,y轴上的光静电标签会出现新的问题。 如: - http://jsfiddle.net/WNpKE/10/ – Philo

+0

我建议把它们放在一个单独的图层上(不同的画布或正常的DOM元素)。 – Shmiddty

3

为了避免从@Shmiddty的答案中的每个鼠标移动事件重绘,您可以绘制整个画布超大,然后更改CSS边距属性。当画布的内容变得更加复杂时,这是显着的性能提升。

这里是一个演示:https://jsfiddle.net/ax7n8944/

HTML:

<div id="canvasdiv" style="width: 500px; height: 250px; overflow: hidden"> 
    <canvas id="canvas" width="10000px" height="250px"></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);