d3js。缩放和平移后坐标。怎么计算呢?

时间:2018-02-19 08:42:38

标签: javascript d3.js svg

我有一个简单的代码,在Ctrl +点击光标下添加一个新的矩形。默认缩放/平移时一切正常,但在缩放/平移后我们得到错误的坐标。

这是我迄今为止所尝试过的:

let width = 960,
  height = 500

let data = {
  nodes: [{
    name: "node1",
    x: 100,
    y: 100,
    height: 50,
    width: 50
  }, {
    name: "node2",
    x: 200,
    y: 200,
    height: 50,
    width: 50
  }]
}

let svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height)

let g = svg.append('g')
  .attr('class', 'everything')

let zoom_handler = d3.zoom()
  .on("zoom", zoomed)

zoom_handler(svg)

function zoomed() {
  g.attr("transform", d3.event.transform)
}

function update(data) {
  d3.selectAll('.nodes').remove()

  let nodes = g.selectAll("node")
    .data(data.nodes)
    .enter()
    .append('g')
    .attr('class', 'nodes')

  nodes
    .append("rect")
    .attr("class", "node")
    .attr("width", d => {
      return d.width
    })
    .attr("height", d => {
      return d.height
    })
    .attr("x", d => {
      return d.x
    })
    .attr("y", d => {
      return d.y
    })
    .attr("fill", 'red')
}

update(data)

d3.select('body')
  .on('click', () => {
    if (d3.event.ctrlKey) {
      addNode(d3.event.x, d3.event.y)
    }
  })

function addNode(x1, y1) {
  data.nodes.push({
    name: "nodeN",
    x: x1,
    y: y1,
    height: 50,
    width: 50,
  })

  update(data)
}
body {
  width: 960px;
  height: 500px;
  position: relative;
}
<script src="https://d3js.org/d3.v4.min.js"></script>

我知道公式'tx - x \ k',但我可以在哪里找到tx?或者也许我在这里做错了什么。 我该如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

您已经将变换矩阵应用于包含矩形的组。我们通过d3.event获得的坐标将已经应用了这些变换,因此变换矩阵将被应用两次以用于组中的新矩形。因此,您必须首先将反向变换矩阵应用于坐标,然后用于矩形。

工作代码段: -

let width = 960,
  height = 500

let data = {
  nodes: [{
    name: "node1",
    x: 100,
    y: 100,
    height: 50,
    width: 50
  }, {
    name: "node2",
    x: 200,
    y: 200,
    height: 50,
    width: 50
  }]
}

let svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height)

let g = svg.append('g')
  .attr('class', 'everything')

let zoom_handler = d3.zoom()
  .on("zoom", zoomed)

zoom_handler(svg)

function zoomed() {
  g.attr("transform", d3.event.transform)
}

function update(data) {
  d3.selectAll('.nodes').remove()

  let nodes = g.selectAll("node")
    .data(data.nodes)
    .enter()
    .append('g')
    .attr('class', 'nodes')

  nodes
    .append("rect")
    .attr("class", "node")
    .attr("width", d => {
      return d.width
    })
    .attr("height", d => {
      return d.height
    })
    .attr("x", d => {
      return d.x
    })
    .attr("y", d => {
      return d.y
    })
    .attr("fill", 'red')
}

update(data)

d3.select('body')
  .on('click', () => {
    if (d3.event.ctrlKey) {
      var svgEl = svg.node();
      var pt = svgEl.createSVGPoint();
      pt.x = d3.event.x;
      pt.y = d3.event.y;
      pt = pt.matrixTransform(g.node().getCTM().inverse());
      addNode(pt.x, pt.y)
    }
  });

function addNode(x1, y1) {
  data.nodes.push({
    name: "nodeN",
    x: x1,
    y: y1,
    height: 50,
    width: 50,
  })

  update(data)
}
body{
margin: 0px;
}
<script src="https://d3js.org/d3.v4.min.js"></script>