javascript - 使用 D3 缩放到外部加载的 svg 上路径的边界框

标签 javascript d3.js svg

我正在使用 D3 加载不使用 topojson 的外部 SVG map (因为 map 是手工创建的,不是传统 map )。我试图将元素 #lines path 定位,以便在单击时,每个路径都会缩放并填充其边界框。

我正在尝试使用 this example来自 Mike Bostock,但无法弄清楚如何使用不使用 topojson 的数据复制它。请参阅这一行:

.data(topojson.feature(us, us.objects.states).features)

这可能吗?

这是我用来加载 SVG 的代码。

var mapContainer = $('.map');

d3.xml("../assets/subwaymap.svg", function(error, subwayMap) {
  if (error) throw error;
  $('.map').append(subwayMap.documentElement)

我尝试使用 .getBBOX 获取边界框,但对它的连接方式感到困惑。似乎我见过的所有示例都使用 d3.create("svg") ,然后添加其中的所有功能,但由于我的数据已经附加到 DOM,这是否有必要?对 D3 来说还算陌生。谢谢!

最佳答案

两个初步考虑因素:d3.create("svg")在实际的 D3 代码中很少使用。另外,您没有将数据附加到 DOM,只是加载了 SVG 元素(除非您将其称为“数据”)。

回到你的问题,你不需要path.bounds为了让你的代码正常工作,实际上你甚至不需要 d3.zoom 。您所需要的只是获取元素的框(使用 getBBox )并进行适当的转换。

但真正的问题是,您需要将所有元素包装在 <g> 中。 ,因为您无法将变换应用于 SVG 1.1 中的根 SVG(显然这在 SVG 2 中是可能的)。

这是一个基本演示。在此演示中,我使用由不同元素(圆形、矩形、文本...)制成的外部 SVG,它代表您要附加的 SVG。您可以通过以下方式获得此 SVG:

const svg = d3.select("svg");

然后,考虑到您以某种方式设法修复了 <g>我提到的问题,你得到那个组...

const g = svg.select("g");

...然后选择要放大的元素(此处为所有内容),绑定(bind)事件监听器:

const elements = g.selectAll("*")
    .on("click", clicked);

在这个演示中,我使用 Bostock 的数学来节省(我的)时间,但您可以更改它。单击该元素可放大,再次单击可缩小。

const width = 500,
  height = 400;
const svg = d3.select("svg");
const g = svg.select("g");
const elements = g.selectAll("*")
  .each(function() {
    d3.select(this).datum({})
  })
  .on("click", clicked);

function clicked(d) {
  d.clicked = !d.clicked;
  const bounds = this.getBBox();
  const x0 = bounds.x;
  const x1 = bounds.x + bounds.width;
  const y0 = bounds.y;
  const y1 = bounds.y + bounds.height;
  g.transition().duration(1000).attr("transform", d.clicked ? "translate(" + (width / 2) + "," + (height / 2) + ") scale(" + (1 / Math.max((x1 - x0) / width, (y1 - y0) / height)) + ") translate(" + (-(x0 + x1) / 2) + "," + (-(y0 + y1) / 2) + ")" : "transform(0,0) scale(1)");
}
<svg width="500" height="400">
<g>
<circle cx="50" cy="50" r="30" stroke="black" stroke-width="3" fill="teal"></circle>
<rect x="300" y="20" rx="20" ry="20" width="150" height="150" style="fill:tomato;stroke:black;stroke-width:3"/>
<polygon points="200,100 250,190 160,210" style="fill:lavender;stroke:purple;stroke-width:3" />
<path d="M 140 350 q 150 -200 350 0" stroke="blue" stroke-width="5" fill="none" />
<text x="30" y="300" transform="rotate(-30, 30, 300)">Foo Bar Baz</text>
</g>
</svg>
<script src="https://d3js.org/d3.v5.min.js"></script>

关于javascript - 使用 D3 缩放到外部加载的 svg 上路径的边界框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60367374/

相关文章:

javascript - 单击样式化组件更改 css( map 功能)

d3.js - 为什么域不使用D3中的d3.max(data)?

javascript - 如何在 d3.js 中的 svg 中拖放一组矩形?

java - 如何使用 iText7 将 SVG 添加到 PDF

javascript - 如何以 Angular 显示每小时前的数据

javascript - 使用Angularjs定期刷新html表格数据

r - 结合ggplot2和d3(gridSVG教程导致非交互式图像)

css - 无法将 .svg 显示为背景图片

html - SVG 网格(图案)在 Firefox 中行为不当

javascript - 一起使用 for 循环和异步 waterfall 的最佳方式