我尝试使用D3创建一个具有可悬停点的交互式可缩放Map。用户可以在Map上拖动一个矩形来放大该区域。
到目前为止,我已经实现了它,所以第一次刷和缩放工程,一旦缩放,如果我点击“重置缩放”按钮重置它,然后刷和缩放再次,这也工程。
不起作用的部分是如果我刷和缩放,然后一旦它已经缩放,我刷和缩放再次。似乎在这种情况下,刷检测到svg在其预缩放的范围,而更新的范围,我不知道如何处理它,所以它实际上放大到刷的区域。
下面是codepen的例子:https://codepen.io/jhjanicki-the-scripter/pen/ExeWgML
下面是相关代码(data = json of the points,land = geojson of the land area)
let width = 1200;
let height = 800;
const svg = d3
.select("#chart1")
.append("svg")
.attr("width", width)
.attr("height", height)
const projection = d3.geoMercator()
.scale(width / 2.5 / Math.PI)
.rotate([0, 0])
.center([0, 0])
.translate([width / 2, height / 2]);
const path = d3.geoPath().projection(projection);
const colorScale =
d3.scaleOrdinal().domain(["class1","class2","class3","class4","class5"])
.range(["#a6cee3", "#1f78b4", "#b2df8a", "#33a02c", "#fb9a99"]);
let brush = d3.brush()
.on('brush', brushMove)
.on("end", brushEnd);
let brushExtent;
let brushedSufficient = true; //check if dragged area big enough
const zoom = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([[0, 0], [width, height]])
.extent([[0, 0], [width, height]])
.on("zoom", zoomed);
function initBrush() {
svg.call(brush);
}
//brushMove related functions
function brushMove(e) {
brushExtent = e.selection;
//update points style within the rect
svg.selectAll("circle.point")
.attr("fill", d => isInBrushExtent(d) ? 'white' : colorScale(d.cat))
.raise(); // in order to be able to hover
brushedSufficient = isSufficient();
}
function isInBrushExtent(d) {
return brushExtent &&
projection([d.lon, d.lat])[0] >= brushExtent[0][0] &&
projection([d.lon, d.lat])[0] <= brushExtent[1][0] &&
projection([d.lon, d.lat])[1] >= brushExtent[0][1] &&
projection([d.lon, d.lat])[1] <= brushExtent[1][1];
}
//
function isSufficient() { // make sure user can't zoom by clicking
return brushExtent[1][0] - brushExtent[0][0] > 10 && brushExtent[1][1] - brushExtent[0][1] > 10;
}
//brushEnd function
function brushEnd() {
//get the four corner coordinates
const x0 = brushExtent[0][0];
const x1 = brushExtent[1][0];
const y0 = brushExtent[0][1];
const y1 = brushExtent[1][1];
if (brushedSufficient) {
const x = -(x0 + x1) / 2;
const y = -(y0 + y1) / 2;
const k = Math.min(8, 0.9 / Math.max((x1 - x0) / width, (y1 - y0) / height));
svg.transition().duration(750).call(
zoom.transform,
d3.zoomIdentity
.translate(width / 2, height / 2)
.scale(k)
.translate(x, y),
)
}
}
function zoomed(e) {
const transform = e.transform; //k,x,y
svg.selectAll('path')
.attr('transform', transform)
.attr("stroke-width", 1 / transform.k);
svg.selectAll("circle")
.attr('transform', transform)
.attr('r', 5 / transform.k)
.attr("fill", d => colorScale(d.cat));
}
function resetZoom() {
svg.transition()
.duration(750)
.call(zoom.transform, d3.zoomIdentity)
}
d3.select("#resetZoom").on("click", resetZoom);
svg.selectAll("path.land")
.data(land.features)
.join("path")
.attr("class", "land")
.attr("id", "land")
.attr("fill", "white")
.attr("stroke", "#808080")
.attr("d", path);
//need to come before points
svg.append("g")
.attr("class", "brush")
.call(brush);
// draw points
svg.selectAll("circle.point")
.data(data)
.join("circle")
.attr("class", "point")
.attr("id", d => "id" + d.id)
.attr("cx", d => projection([d.lon, d.lat])[0])
.attr("cy", d => projection([d.lon, d.lat])[1])
.attr("stroke-width", 1)
.attr("r", 5)
.attr("fill", d => colorScale(d.cat))
.attr("cursor", "pointer")
.on("mouseover", (e, d) => console.log(d.name))
字符串
2条答案
按热度按时间quhf5bfb1#
我在画笔上也遇到了同样的问题,所以我建立了自己的画笔。你可以在x轴上缩放图表,在图表区域上画笔。
x4shl7ld2#
实际上,我通过选择画笔并在缩放功能中对画笔应用变换来解决它,下面是工作示例:https://codepen.io/jhjanicki-the-scripter/pen/eYLWMGo
代码:
字符串