将 d3 svg 坐标转换为画布坐标,或尝试为两者匹配相同的位置



我有一些 d3 svg 元素,其中我将坐标列表 x,y 作为属性传递,并将它们绘制在 svg 地图上。如下例所示:

var svg = iniMarker().append("g")
.attr("data-lineData", JSON.stringify(lineData))
//Function to draw line
var lineFunction = d3.svg.line()
.x(function (d) { return d.x; })
.y(function (d) { return d.y; });

生成的路径结构如下所示:

<path d="M1100,850L1180,800" class="pPath" stroke-dasharray="94.33981323242188 94.33981323242188" stroke-dashoffset="0"></path>
<path d="M1180,800L1280,800" class="pPath" stroke-dasharray="100 100" stroke-dashoffset="0"></path>
<path d="M1280,800L1380,800" class="pPath" stroke-dasharray="100 100" stroke-dashoffset="0"></path>

在此行路径的顶部还有一个圆圈,它将行数据坐标值作为输入:

var circle = svg.append("circle")
.attr("r", 10)
.attr("fill", "#fff")
.attr("class", "marker")
.attr("transform", function () {
return "translate(" + lineData[0].x + "," + lineData[0].y + ")";
});

我获取坐标信息的数据以以下格式存储:

var DataSet = [{
"id": "",
"isActive": true,
"personId": "p1",
"name": "test",
"lineData": [
{ "timestamp": "2018/09/15 10:00:05 AM", "x": 1100, "y": 950 }]

现在,我需要在画布地图上表示从此坐标列表中获取的每个点,完全叠加在 svg 地图上在这种情况下,问题在于列表的 svg 坐标与画布坐标的相同位置不匹配。

实际上,如果我尝试使用以下函数生成一些画布坐标点:

document.getElementById("canv").onclick = function (e) {
var localX = e.clientX - e.target.offsetLeft;
var localY = e.clientY - e.target.offsetTop;
}

然后,onclick事件的坐标与我从 DataSet obj 作为位置的 svg 坐标几乎不同。

实际上为了匹配它们,我刚刚尝试在函数上传递 DataSet obj,以便获取 svg 坐标并将它们绘制在画布地图上,如下所示:

DataSet.map(function (m) { if(m.isActive) return m.lineData; else return []; }).forEach(f => data = data.concat(f));
data.forEach(e => {
//here I call another function for plot the svg coordinates as points on the canvas map 
});

但很明显,我需要先转换它们才能正确匹配。

按照@enxaneta的建议,我需要从这些数据对象创建一个画布。但问题是我已经拥有的坐标是用于 svg,而不是用于画布格式。

我需要找到一种方法来转换我拥有的 svg 坐标列表,以便与画布坐标系匹配或更相似。

我愿意接受建议。

您的问题不是很清楚,但假设您有一个 svg 路径,您可以使用 Path2D 对象将其转换为画布路径: 在下一个示例中,SVG 路径为红色,画布路径为黑色。

var svgPathApple = Apple.getAttribute("d");
var svgPathLeaf = Leaf.getAttribute("d");
var c = document.getElementById("c");
var ctx = c.getContext("2d");
var cw = c.width = 500;
var ch = c.height = 500;
var apple = new Path2D(svgPathApple);
var leaf = new Path2D(svgPathLeaf);
ctx.stroke(apple);
ctx.stroke(leaf);
canvas,svg{border:1px solid #d9d9d9; width:45vw;}
path{fill: none; stroke:red;}
<svg viewBox="0 0 500 500">
	<path id="Apple" d="M376.349,171.58
		c0,0-37.276,22.484-36.094,60.946s31.438,61.577,42.012,63.313c4.127,0.678-24.314,57.988-42.039,72.189
		s-36.067,17.159-64.47,5.917c-28.403-11.242-48.521,0.724-65.089,6.871s-36.687-0.361-63.905-39.415
		s-57.396-129.585-15.976-173.964s87.574-26.627,100-20.71s34.32,5.325,59.172-5.917S363.922,153.237,376.349,171.58z"/>
	<path id="Leaf" d="M311.852,68.621c0,0,2.367,14.793-3.55,27.219
		s-28.189,55.061-60.473,47.337c-0.809-0.193-5.529-14.482,1.398-29.002C259.004,93.682,284.49,70.699,311.852,68.621z"/>
</svg>
<canvas id="c"></canvas>

更新:

SVG 代表 可缩放矢量图形。虽然您的 svg 大小与画布大小相同,但在 facr 中,您的 svg 是画布大小的四倍。为了知道实际大小,您必须查看viewBox属性的值:"52 0 2104 1200"。翻译成简单的英语,您的 svg 的宽度为 2104,高度为 1200。这还不是全部。您的 svg 坐标从 x=52 和 y = 0 开始。给定 SVG 上的点 p={x:100,y:100},则画布坐标为:x = (100 - 52)/2y = 100/2;

接下来是一个简单的例子,我在画布和 svg 元素上画了一个圆:

const canvas = document.getElementById("canv");
const ctx = canvas.getContext("2d");
let x = (100 - 52)/2, 
y = 100/2,
r = 10/2;
ctx.beginPath();
ctx.arc(x,y,5,0,2*Math.PI);
ctx.fill();
canvas,svg{border:1px solid;}
<svg version="1.1" id="svgMap" width="1052px" height="600px" viewBox="52 0 2104 1200">
<circle  id="testCircle" cx="100" cy ="100" r="10" />
</svg>
<canvas width="1052" height="600" id="canv"></canvas>

我希望这有所帮助。

最新更新