如何使用D3库制作响应式画布动画 [英] How to make a responsive canvas animation using the D3 library
问题描述
我正在使用d3.js库开发一个简单的动画,并通过画布显示它,但是我的画布没有反应。
在代码的开头,我将原宽度设置为960,高度设置为500,但是如何使它可以调整大小(响应)?我不使用CSS应用一些样式(宽度和高度)到画布上,我使用JavaScript来做。解决方案可以是CSS或JavaScript。
var width = 960,height = 500,τ= 2 * Math.PI,gravity = .05; var sample = poissonDiscSampler(width,height,30),nodes = [{x:0,y:0} )nodes.push(s); var force = d3.layout.force().size([width,height]).nodes(nodes.slice()).gravity {return i?-30:-3000;}).on(tick,ticked).start(); var voronoi = d3.geom.voronoi().x(function(d){return dx;})。 var(var)= voronoi.links(nodes); var canvas = d3.select(#canvas) .append(canvas).attr(width,width).attr(height,height).on(ontouchstartin document?touchmove:mousemove,moved); var context = canvas。 node()。getContext(2d); function moved(){var p1 = d3.mouse(this); root.px = p1 [0]; root.py = p1 [1]; force.resume();} function ticked(){force.resume(); for(var i = 0,n = nodes.length; i
< script src =https:// d3js.org/d3.v3.min.js\"</script><section> < div id =canvas> < / div>< / section>
画布就像一个图像。它有自己的物理尺寸,但仍然可以用CSS缩放。使用 width
和 height
属性设置物理尺寸,然后使用CSS将其缩放为<$ c $
示例...
div class =snippetdata-lang =jsdata-hide =falsedata-console =truedata-babel =false>
var c = document.getElementById(myCanvas); var ctx = c.getContext(2d); ctx.rect ,150,100); ctx.stroke();
< canvas id =myCanvaswidth =300height =150style =width:100%;>< / canvas>
div>
I'm developing a simple animation using d3.js library and show it through canvas, but my canvas isn't responsive.
In the beginning of the code, I set original width to 960 and height to 500, but how can I make it resizable (responsive)? I'm not using CSS to apply some style (width and height) to the canvas, I'm using JavaScript to do it. The solution can be CSS or JavaScript.
var width = 960,
height = 500,
τ = 2 * Math.PI,
gravity = .05;
var sample = poissonDiscSampler(width, height, 30),
nodes = [{
x: 0,
y: 0
}],
s;
while (s = sample()) nodes.push(s);
var force = d3.layout.force()
.size([width, height])
.nodes(nodes.slice())
.gravity(0)
.charge(function(d, i) {
return i ? -30 : -3000;
})
.on("tick", ticked)
.start();
var voronoi = d3.geom.voronoi()
.x(function(d) {
return d.x;
})
.y(function(d) {
return d.y;
});
var root = nodes.shift();
root.fixed = true;
var links = voronoi.links(nodes);
var canvas = d3.select("#canvas").append("canvas")
.attr("width", width)
.attr("height", height)
.on("ontouchstart" in document ? "touchmove" : "mousemove", moved);
var context = canvas.node().getContext("2d");
function moved() {
var p1 = d3.mouse(this);
root.px = p1[0];
root.py = p1[1];
force.resume();
}
function ticked() {
force.resume();
for (var i = 0, n = nodes.length; i < n; ++i) {
var node = nodes[i];
node.y += (node.cy - node.y) * gravity;
node.x += (node.cx - node.x) * gravity;
}
context.clearRect(0, 0, width, height);
context.beginPath();
for (var i = 0, n = links.length; i < n; ++i) {
var link = links[i];
context.moveTo(link.source.x, link.source.y);
context.lineTo(link.target.x, link.target.y);
}
context.lineWidth = 1;
context.strokeStyle = "#bbb";
context.stroke();
context.beginPath();
for (var i = 0, n = nodes.length; i < n; ++i) {
var node = nodes[i];
context.moveTo(node.x, node.y);
context.arc(node.x, node.y, 2, 0, τ);
}
context.lineWidth = 3;
context.strokeStyle = "#fff";
context.stroke();
context.fillStyle = "#000";
context.fill();
}
// Based on https://www.jasondavies.com/poisson-disc/
function poissonDiscSampler(width, height, radius) {
var k = 30, // maximum number of samples before rejection
radius2 = radius * radius,
R = 3 * radius2,
cellSize = radius * Math.SQRT1_2,
gridWidth = Math.ceil(width / cellSize),
gridHeight = Math.ceil(height / cellSize),
grid = new Array(gridWidth * gridHeight),
queue = [],
queueSize = 0,
sampleSize = 0;
return function() {
if (!sampleSize) return sample(Math.random() * width, Math.random() * height);
// Pick a random existing sample and remove it from the queue.
while (queueSize) {
var i = Math.random() * queueSize | 0,
s = queue[i];
// Make a new candidate between [radius, 2 * radius] from the existing sample.
for (var j = 0; j < k; ++j) {
var a = 2 * Math.PI * Math.random(),
r = Math.sqrt(Math.random() * R + radius2),
x = s.x + r * Math.cos(a),
y = s.y + r * Math.sin(a);
// Reject candidates that are outside the allowed extent,
// or closer than 2 * radius to any existing sample.
if (0 <= x && x < width && 0 <= y && y < height && far(x, y)) return sample(x, y);
}
queue[i] = queue[--queueSize];
queue.length = queueSize;
}
};
function far(x, y) {
var i = x / cellSize | 0,
j = y / cellSize | 0,
i0 = Math.max(i - 2, 0),
j0 = Math.max(j - 2, 0),
i1 = Math.min(i + 3, gridWidth),
j1 = Math.min(j + 3, gridHeight);
for (j = j0; j < j1; ++j) {
var o = j * gridWidth;
for (i = i0; i < i1; ++i) {
if (s = grid[o + i]) {
var s,
dx = s.x - x,
dy = s.y - y;
if (dx * dx + dy * dy < radius2) return false;
}
}
}
return true;
}
function sample(x, y) {
var s = {
x: x,
y: y,
cx: x,
cy: y
};
queue.push(s);
grid[gridWidth * (y / cellSize | 0) + (x / cellSize | 0)] = s;
++sampleSize;
++queueSize;
return s;
}
}
<script src="https://d3js.org/d3.v3.min.js"></script>
<section>
<div id="canvas">
</div>
</section>
Canvas is like an image. It has it's own physical dimensions but can still be scaled with CSS. Use the width
and height
attributes to set the physical dimensions and then use CSS to scale it with a %
to make it responsive.
Example...
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.rect(20, 20, 150, 100);
ctx.stroke();
<canvas id="myCanvas" width="300" height="150" style="width:100%;"></canvas>
这篇关于如何使用D3库制作响应式画布动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!