javascript - 如何在散点图中使用 d3.drag 处理比例
问题描述
我试图在 D3 中实现具有拖动行为的散点图,但我不明白如何处理具有拖动效果的缩放。
现在我这样做了:
据我了解,有两个坐标系:一个是我要绘制的对象(每个对象都由 x 和 y 坐标描述,两者都遵循正常规律),另一个是显示的画布。d3.scale 对象允许在两者之间进行映射。
因此,首先,要找到从 d3.event 对象的坐标拖动的对象,我遍历所有数据数组并找到其缩放坐标等于 d3.event 的 x 和 y 的对象。
然后我用 d3.event 坐标修改这个对象坐标,用比例对象进行逆变换以从画布坐标系映射到对象坐标系。
但是,这不起作用:当一个点被拖动时,它会移动,但不会移动光标所在的位置。我不明白这种行为。
解决方案
您将需要知道鼠标位置并将其应用于当前的 x 和 y。做了一些改变,看看mousePosition
,你需要更多的工作来使它完美,但你会得到idee
let width = 960,
height = 500,
radius = 3,
transform = d3.zoomIdentity
let canvas = d3.select("body").append("canvas")
.attr("width", width)
.attr("height", height)
let ctx = canvas.node().getContext("2d");
let data = d3.range(200)
.map(() => { return {"x": d3.randomNormal()(),
"y": d3.randomNormal()()}})
let scaleX = d3.scaleLinear()
.domain(d3.extent(data, function(d){return d.x}))
.range([0, width])
let scaleY = d3.scaleLinear()
.domain(d3.extent(data, function(d){return d.y}))
.range([height, 0])
//canvas.call(d3.zoom()
// .on("zoom", zoomed))
canvas.call(d3.drag()
.subject(dragSubject)
.on("drag", dragged))
function zoomed(){
transform = d3.event.transform
render()
}
function dragSubject(){
x = d3.event.x
y = d3.event.y
for(let i = 0; i < data.length; i++){
point = data[i]
dx = x - scaleX(point.x)
dy = y - scaleY(point.y)
if (dx * dx + dy * dy < radius * radius){
return data[i];
}
}
}
// get the position of the mouse, you need to calculate scale to
function mousePosition(event) {
if (event == undefined || (!event.pageX && !event.offsetX))
return {x:0, y:0}
return { x: event.pageX || event.offsetX, y: event.pageY || event.offsetY };
};
function dragged(){
var mouse = mousePosition(window.event)
d3.event.subject.x = scaleX.invert(d3.event.x + (mouse.x))
d3.event.subject.y = scaleY.invert(d3.event.y + mouse.y)
render()
}
function render(){
ctx.save()
ctx.clearRect(0, 0, width, height)
ctx.beginPath()
//ctx.translate(transform.x, transform.y)
//ctx.scale(transform.k, transform.k)
data.forEach(function(d){
ctx.moveTo(scaleX(d.x) + radius, scaleY(d.y))
ctx.arc(scaleX(d.x), scaleY(d.y), radius, 0, Math.PI * 2)
})
ctx.stroke()
/*
ctx.globalAlpha = 0.2
ctx.fillStyle = "blue"
ctx.fillRect(0,0,width,height) */
ctx.restore()
}
render()
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
</body>
推荐阅读
- javascript - 如何简化 JavaScript/React
- maven - 在参数中使用带有连字符的 maven exec 插件
- android - 相机预览在预览中拉伸/挤压
- java - GetStringExtra 总是返回 null
- angular - RXJS 6.0:./node_modules/rxjs-compat/_esm5/add/operator/publishReplay.js 中的错误
- mql4 - 尝试读取文件时 MQL4 错误 5004 和 5002
- android - Android studio升级到3.2后出现startup failed:initialization script '/tmp/ijinit.gradle'错误
- java - 如何递归删除列表中具有特定值的节点
- django - Django:计算字段 + admin_order_field + action => FieldError:无法解析关键字
- xml - 使用 bash 读取和解析 kodi nfo 文件的 XML