单击时弹出 SVG 美国州要素路径
Pop Out SVG US State Feature Path On Click
我正在使用 d3-geo
和 topojson-client
渲染 geoAlbersUSA
SVG 地图 - 如下所示 - 但当用户点击路径时我想做一些奇特的事情.我想缩放和平移基本路径,在本例中为爱达荷州或弗吉尼亚州,以便该州“漂浮”在美国上方,但仍以质心为中心。每次我尝试简单地 scale
和 <path/>
元素时,它最终都会远离许多像素;有没有一种方法可以计算出 translate()
对应于元素的缩放程度?
const states = topojson.feature(us, us.objects.states as GeometryObject) as ExtendedFeatureCollection;
const path = geoPath()
.projection(geoAlbersUsa()
.fitSize([innerWidth as number, innerHeight as number], states)
);
<svg>
{
states.features.map(feature => {
return <path key={`state-path-${feature.id}`} d={path(feature) as string} onClick={() => updateScaleAndTranslate(feature)} />
}
}
</svg>
你需要先设置transform-origin
style property. It determines the point relative to which the transformations are applied. If you can find the centre of the path (for example, using getBBox()
),再设置
.style("transform-origin", `${myCenter.x}px ${myCenter.y}px`)
这应该会改变应用变换的方式。
我为你做了一个小例子,使用d3 v6。请注意,随着状态被“扩展”,它们现在可能开始重叠,所以在功能上,我建议只允许一个或几个状态像这样扩展。
const svg = d3.select('body')
.append("svg")
.attr("viewBox", [0, 0, 975, 610]);
d3.json("https://cdn.jsdelivr.net/npm/us-atlas@3/states-albers-10m.json").then((us) => {
const path = d3.geoPath()
const color = d3.scaleQuantize([1, 10], d3.schemeBlues[9]);
const statesContainer = svg.append("g");
const states = statesContainer
.selectAll("path")
.data(topojson.feature(us, us.objects.states).features)
.join("path")
.attr("class", "state")
.attr("fill", () => color(Math.random() * 10))
.attr("d", path)
.on("click", function(event, d) {
const {
x,
y,
width,
height
} = this.getBBox();
// First, move the state to the front so it's in front of others
const state = d3.select(this)
.attr("transform-origin", `${x + width / 2}px ${y + height / 2}px`).remove();
statesContainer.append(() => state.node());
d.properties.expanded = !d.properties.expanded;
state
.transition()
.duration(500)
.attr("transform", d.properties.expanded ? "scale(1.25)" : "scale(1)")
});
states
.append("title")
.text(d => d.properties.name)
});
.state {
stroke: #fff;
stroke-linejoin: round;
stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.js"></script>
<script src="https://d3js.org/topojson.v3.js"></script>
我正在使用 d3-geo
和 topojson-client
渲染 geoAlbersUSA
SVG 地图 - 如下所示 - 但当用户点击路径时我想做一些奇特的事情.我想缩放和平移基本路径,在本例中为爱达荷州或弗吉尼亚州,以便该州“漂浮”在美国上方,但仍以质心为中心。每次我尝试简单地 scale
和 <path/>
元素时,它最终都会远离许多像素;有没有一种方法可以计算出 translate()
对应于元素的缩放程度?
const states = topojson.feature(us, us.objects.states as GeometryObject) as ExtendedFeatureCollection;
const path = geoPath()
.projection(geoAlbersUsa()
.fitSize([innerWidth as number, innerHeight as number], states)
);
<svg>
{
states.features.map(feature => {
return <path key={`state-path-${feature.id}`} d={path(feature) as string} onClick={() => updateScaleAndTranslate(feature)} />
}
}
</svg>
你需要先设置transform-origin
style property. It determines the point relative to which the transformations are applied. If you can find the centre of the path (for example, using getBBox()
),再设置
.style("transform-origin", `${myCenter.x}px ${myCenter.y}px`)
这应该会改变应用变换的方式。
我为你做了一个小例子,使用d3 v6。请注意,随着状态被“扩展”,它们现在可能开始重叠,所以在功能上,我建议只允许一个或几个状态像这样扩展。
const svg = d3.select('body')
.append("svg")
.attr("viewBox", [0, 0, 975, 610]);
d3.json("https://cdn.jsdelivr.net/npm/us-atlas@3/states-albers-10m.json").then((us) => {
const path = d3.geoPath()
const color = d3.scaleQuantize([1, 10], d3.schemeBlues[9]);
const statesContainer = svg.append("g");
const states = statesContainer
.selectAll("path")
.data(topojson.feature(us, us.objects.states).features)
.join("path")
.attr("class", "state")
.attr("fill", () => color(Math.random() * 10))
.attr("d", path)
.on("click", function(event, d) {
const {
x,
y,
width,
height
} = this.getBBox();
// First, move the state to the front so it's in front of others
const state = d3.select(this)
.attr("transform-origin", `${x + width / 2}px ${y + height / 2}px`).remove();
statesContainer.append(() => state.node());
d.properties.expanded = !d.properties.expanded;
state
.transition()
.duration(500)
.attr("transform", d.properties.expanded ? "scale(1.25)" : "scale(1)")
});
states
.append("title")
.text(d => d.properties.name)
});
.state {
stroke: #fff;
stroke-linejoin: round;
stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.js"></script>
<script src="https://d3js.org/topojson.v3.js"></script>