|
<!DOCTYPE html> |
|
<head> |
|
<meta charset="utf-8"> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.12.0/d3.min.js" integrity="sha256-+9Mf3cAVmxxudDsr1XwXUeRZFtvdWVYdq5/vcgiYyNU=" crossorigin="anonymous"></script> |
|
<style> |
|
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } |
|
canvas, svg { |
|
display: block; |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
} |
|
.box { |
|
position: relative; |
|
width: 1100px; |
|
margin: 2em auto; |
|
} |
|
</style> |
|
</head> |
|
|
|
<body> |
|
<style> |
|
canvas, svg { |
|
display: block; |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
} |
|
.box { |
|
position: relative; |
|
width: 900px; |
|
margin: 2em auto; |
|
} |
|
</style> |
|
|
|
|
|
<div class="box" id="box"></div> |
|
|
|
|
|
<script> |
|
var w = 900, h = 450, |
|
p = {top: 20, right: 20, bottom: 40, left: 50}, |
|
cw = w - p.left - p.right, |
|
ch = h - p.top - p.bottom; |
|
|
|
var data = d3.range(1000) |
|
.map(function (d, i) { |
|
return { |
|
x: Math.random() * cw, |
|
y: Math.random() * ch, |
|
r: Math.random() * 5 + 3 |
|
}; |
|
}); |
|
|
|
var point = {x: 0, y: 0}, |
|
area = [[0, 0], [0, 0]]; |
|
|
|
var box = d3.select("#box"); |
|
|
|
box.on("mousemove", function () { |
|
var t = d3.mouse(this); |
|
point.x = t[0]; point.y = t[1]; |
|
}) |
|
.on("click", function () { area = [[0, 0], [0, 0]]; }); |
|
|
|
|
|
var canvas = box.append("canvas").attr("width", w).attr("height", h); |
|
var ctx = canvas.node().getContext("2d"); |
|
var svg = box.append("svg").attr("width", w).attr("height", h); |
|
|
|
function canvasDraw () { |
|
ctx.save(); |
|
ctx.clearRect(0, 0, w, h); |
|
ctx.translate(p.left, p.top); |
|
ctx.strokeStyle = "#666"; |
|
ctx.fillStyle = "rgba(250,0,0,1)"; |
|
ctx.lineWidth = 1; |
|
|
|
var i = 0, length = data.length, |
|
c, |
|
hc, |
|
isMouseOver = false, |
|
isFenced = false; |
|
while (i < length) { |
|
c = data[i]; |
|
ctx.beginPath(); |
|
ctx.arc(c.x, ch - c.y, c.r, 0, Math.PI * 2, false); |
|
|
|
isFenced = c.x >= area[0][0] && |
|
c.x <= area[1][0] && |
|
(ch - c.y) >= area[0][1] && |
|
(ch - c.y) <= area[1][1]; |
|
isMouseOver = ctx.isPointInPath(point.x, point.y); |
|
|
|
if (isFenced) { ctx.fill(); } |
|
if (isMouseOver) { hc = c; } |
|
ctx.stroke(); |
|
|
|
i++; |
|
} |
|
|
|
if (hc) { |
|
ctx.beginPath(); |
|
ctx.arc(hc.x, ch - hc.y, hc.r, 0, Math.PI * 2, false); |
|
ctx.fill(); |
|
} |
|
|
|
ctx.restore(); |
|
|
|
window.requestAnimationFrame(canvasDraw); |
|
} |
|
|
|
function SVGDraw () { |
|
var yScale, xScale, yAxis, xAxis; |
|
yScale = d3.scaleLinear().domain([0, ch]).range([ch, 0]); |
|
xScale = d3.scaleLinear().domain([0, cw]).range([0, cw]); |
|
yAxis = d3.axisLeft().scale(yScale); |
|
xAxis = d3.axisBottom().scale(xScale); |
|
|
|
var brush = d3.brush() |
|
.extent([[0, 0], [cw, ch]]) |
|
.on("brush", function () { area = d3.event.selection; }); |
|
|
|
svg.append("g") |
|
.attr("transform", "translate(" + [p.left, p.top] + ")") |
|
.call(yAxis); |
|
|
|
svg.append("g") |
|
.attr("transform", "translate(" + [p.left, p.top + ch] + ")") |
|
.call(xAxis); |
|
|
|
svg.append("g") |
|
.attr("transform", "translate(" + [p.left, p.top] + ")") |
|
.call(function (g) { |
|
g.call(brush); |
|
|
|
// active one brush area |
|
brush.move(g, [[300,100], [500, 250]]); |
|
}); |
|
} |
|
|
|
SVGDraw(); |
|
canvasDraw(); |
|
|
|
</script> |
|
|
|
</body> |