Javascript D3.js拖动realtive到图形svg

Javascript D3.js拖动realtive到图形svg,javascript,d3.js,Javascript,D3.js,我有一些代码,可以使用D3.js v6移动绘制在svg图形上的圆。应该将圆拖动到光标相对于图形的位置,但我认为给定的光标位置相对于整个窗口,而不是图形/svg。我不确定如何将鼠标位置修改为相对于svg。我也尝试使用这个答案中的建议: 编辑: 如果我从(0.5,0.5)这样的位置开始画圆,我将如何使它只沿着以(0,0)为中心半径为0.5的圆的圆周移动?我尝试使用以下方法将鼠标位置缩放为0.5量级: x = x*(0.5/(Math.sqrt(x**2 + y**2))); y = y*(0.5/

我有一些代码,可以使用D3.js v6移动绘制在svg图形上的圆。应该将圆拖动到光标相对于图形的位置,但我认为给定的光标位置相对于整个窗口,而不是图形/svg。我不确定如何将鼠标位置修改为相对于svg。我也尝试使用这个答案中的建议:

编辑:

如果我从(0.5,0.5)这样的位置开始画圆,我将如何使它只沿着以(0,0)为中心半径为0.5的圆的圆周移动?我尝试使用以下方法将鼠标位置缩放为0.5量级:

x = x*(0.5/(Math.sqrt(x**2 + y**2)));
y = y*(0.5/(Math.sqrt(x**2 + y**2)));
因为这是如何将向量缩放为特定长度,同时保持与此处所示相同的方向:

然而,这似乎不起作用,即使它应该缩放鼠标所在的任何点,使其位于以原点为中心半径为0.5的圆上

var margin={top:-20,right:30,bottom:40,left:40};
//刚刚安装
var svg=d3。选择(“mysvg”)
.attr(“宽度”,300)
.attr(“高度”,300)
.附加(“g”)
.attr(“转换”,
“翻译(“+margin.left+”,“+margin.top+”);
var xAxis=d3.scaleLinear()
.domain([-1.5,1.5])
.范围([0,300]);
svg.append(“g”)
.attr(“转换”、“转换(0、+300+)”)
.call(d3.axisBottom(xAxis));
var yAxis=d3.scaleLinear()
.domain([-1.5,1.5])
.范围([300,0]);
svg.append(“g”)
.call(d3.axisLeft(yAxis));
var circle1=svg.append('circle')
.attr('id','circle1')
.attr('cx',xAxis(0))
.attr('cy',yAxis(0))
.attr('r',10)
.style('fill','000000')
.call(d3.drag().on('drag',dragCircle))//添加拖动侦听器
函数dragCircle(事件){
设x=d3.pointer(事件,svg.node())[0];
设y=d3.pointer(事件,svg.node())[1];
控制台日志(“x:+x+”y:+y);
d3.选择(“圆圈1”)
.attr(“cx”,xAxis(x))
.attr(“cy”,yAxis(y));
} 

两件事

D3.pointer返回以像素为单位的单位,这些单位不需要缩放-缩放的目的是获取任意单位并将其转换为像素:

因此,不是:

    d3.select("#circle1")
        .attr("cx", xAxis(x))
        .attr("cy", yAxis(y));
尝试:

此外,我们希望阻力相对于
g
,后者保存绘图并对其应用变换。此部分在您的链接中有详细说明。我们可以指定希望拖动相对于父级
g
,使用:

    let x = d3.pointer(event,svg.node())[0];
    let y = d3.pointer(event,svg.node())[1];
然后,我们可以使用一些三角学将点约束到一个环上,并使阻力基于到任意点的角度:

        let x = d3.pointer(event,svg.node())[0];
        let y = d3.pointer(event,svg.node())[1]; 
        
        let cx = xAxis(0);
        let cy = yAxis(0);
        let r = xAxis(0.5)-xAxis(0);
        
        let dx = x- cx;
        let dy = y-cy;
        
        var angle = Math.atan2(dy,dx);

        d3.select("#circle1")
            .attr("cx", cx + Math.cos(angle)*r)
            .attr("cy", cy + Math.sin(angle)*r);
这给了我们:

var margin={top:-20,right:30,bottom:40,left:40};
//刚刚安装
var svg=d3。选择(“mysvg”)
.attr(“宽度”,300)
.attr(“高度”,300)
.附加(“g”)
.attr(“转换”,
“翻译(“+margin.left+”,“+margin.top+”);
var xAxis=d3.scaleLinear()
.domain([-1.5,1.5])
.范围([0,300]);
svg.append(“g”)
.attr(“转换”、“转换(0、+300+)”)
.call(d3.axisBottom(xAxis));
var yAxis=d3.scaleLinear()
.domain([-1.5,1.5])
.范围([300,0]);
svg.append(“g”)
.call(d3.axisLeft(yAxis));
var circle1=svg.append('circle')
.attr('id','circle1')
.attr('cx',xAxis(0))
.attr('cy',yAxis(0))
.attr('r',10)
.style('fill','000000')
.call(d3.drag().on('drag',dragCircle))//添加拖动侦听器
var dragCircle=svg.append('circle'))
.attr('id','circle1')
.attr('cx',xAxis(0))
.attr('cy',yAxis(0))
.attr('r',xAxis(0.5)-xAxis(0))
.style('填充','无')
.style('笔划','黑色')
.style('stroke-line',1)
.call(d3.drag().on('drag',dragCircle))//添加拖动侦听器
函数dragCircle(事件){
设x=d3.pointer(事件,svg.node())[0];
设y=d3.pointer(事件,svg.node())[1];
设cx=xAxis(0);
设cy=yAxis(0);
设r=xAxis(0.5)-xAxis(0);
设dx=x-cx;
设dy=y-cy;
变量角度=数学常数2(dy,dx);
d3.选择(“圆圈1”)
.attr(“cx”,cx+数学cos(角度)*r)
.attr(“cy”,cy+数学sin(角度)*r);
}


谢谢您的解释。我还想知道别的事情。我已经编辑到原始帖子中,我对您在代码中所做的事情进行了跟踪。我注意到,当我在定义r时没有包含-xAxis(0)时,我得到了错误的位置答案。这让我想到xAxis(0)并不总是0,即使它应该将0映射到多个像素?r在数据单位中定义,而不是像素单位,但拖动以像素单位工作,因此我们需要使用比例将r转换为像素。我们需要缩放0,因为xAxis(0)≠ 在您的情况下为0(当缩放域和范围都从0开始时,它们通常相等)。我不确定我是否完全听从了你的评论。你不是用像素来定义r吗,因为xAxis(0.5)和xAxis(0)都是以像素为单位的吗?在我的回答中,词的选择很差-半径被指定为以数据为单位的[0,0]和[0.5,0]之间的距离,我们需要将
r
定义为以像素为单位的距离。
        let x = d3.pointer(event,svg.node())[0];
        let y = d3.pointer(event,svg.node())[1]; 
        
        let cx = xAxis(0);
        let cy = yAxis(0);
        let r = xAxis(0.5)-xAxis(0);
        
        let dx = x- cx;
        let dy = y-cy;
        
        var angle = Math.atan2(dy,dx);

        d3.select("#circle1")
            .attr("cx", cx + Math.cos(angle)*r)
            .attr("cy", cy + Math.sin(angle)*r);