gpt4 book ai didi

javascript - D3 : Map Zoom scaled by points

转载 作者:行者123 更新时间:2023-12-03 07:06:22 26 4
gpt4 key购买 nike

我是 D3 的新手,所以如果这与其他帖子多余,我很抱歉。我正在尝试制作一张 map ,其中包含用户通过单击条形图选择的点。目前我有一张世界地图,点根据点击的栏进入和退出。我想知道如何还包含缩放效果,该效果会裁剪地球以仅包含所选栏的点区域。例如:第一个栏应显示美利坚合众国 map 。

enter image description here

        var data = [{
"name": "Apples",
"value": 20,
"latlong": [
{"latitude": 32.043478, "longitude": -110.7851017},
{"latitude": 40.49, "longitude": -106.83},
{"latitude": 39.1960652, "longitude": -120.2384172},
{"latitude": 36.137076, "longitude": -81.183722},
{"latitude": 35.1380976, "longitude": -90.0611644},
{"latitude": 33.76875, "longitude": -84.376217},
{"latitude": 32.867153, "longitude": -79.9678813},
{"latitude": 39.61078, "longitude": -78.79830099999},
{"latitude": 40.8925, "longitude": -89.5074},
{"latitude": 44.1862, "longitude": -85.8031},
{"latitude": 35.48759154, "longitude": -86.10236359},
{"latitude": 37.9342807, "longitude": -107.8073787999},
{"latitude": 41.3530864, "longitude": -75.6848074},
{"latitude": 38.423137, "longitude": -80.021118},
{"latitude": 43.5121, "longitude": -72.4021},
{"latitude": 48.4070083, "longitude": -114.2827366}
]
},
{
"name": "Oranges",
"value": 26,
"latlong": [
{"latitude": -36.8506158, "longitude": 174.7678785},
{"latitude": -27.4510454, "longitude": 153.0319808},
{"latitude": -33.867111, "longitude": 151.217941},
{"latitude": -34.8450381, "longitude": 138.4985548},
{"latitude": -37.7928386, "longitude": 144.9051327},
{"latitude": -32.0582947, "longitude": 115.7460244},
{"latitude": 29.934926599999, "longitude": -90.0615085},
{"latitude": -34.4829472, "longitude": -58.518548},
{"latitude": -33.460464, "longitude": -70.656868},
{"latitude": 4.8007362, "longitude": -74.0373992},
{"latitude": 4.9375556, "longitude": -73.9649426},
{"latitude": -23.701185, "longitude": -46.7001431},
{"latitude": 33.678023, "longitude": -116.23754},
{"latitude": 51.8451208, "longitude": 5.6872547},
{"latitude": 40.3688321, "longitude": -3.6866294},
{"latitude": 40.4817271, "longitude": -3.6330802},
{"latitude": 40.4642, "longitude": -3.6131},
{"latitude": 52.327353537, "longitude": 1.67658117421},
]
}
];

//set up svg using margin conventions - we'll need plenty of room on the left for labels
var margin = {
top: 15,
right: 25,
bottom: 15,
left: 60
};

var width = 400 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;

var svg = d3.select("#graphic").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var x = d3.scale.linear()
.range([0, width])
.domain([0, d3.max(data, function (d) {
return d.value;
})]);

var y = d3.scale.ordinal()
.rangeRoundBands([height, 0], .1)
.domain(data.map(function (d) {
return d.name;
}));

//make y axis to show bar names
var yAxis = d3.svg.axis()
.scale(y)
//no tick marks
.tickSize(0)
.orient("left");

var gy = svg.append("g")
.attr("class", "y axis")
.call(yAxis)

var bars = svg.selectAll(".bar")
.data(data)
.enter()
.append("g")

//append rects
bars.append("rect")
.attr("class", "bar")
.attr("y", function (d) {
return y(d.name);
})
.attr("height", y.rangeBand())
.attr("x", 0)
.attr("width", function (d) {
return x(d.value);
})
.on("click", function (d) {
// d3.select("#chart circle")
// .attr("fill", function () { return "rgb(0, 0, " + Math.round(d.key * 10) + ")"; });
d3.selectAll('rect').style('fill', '#5f89ad');
d3.select(this).style("fill", "#012B4E");

var circle = svg_map.select("g").selectAll("circle")
.data(d.latlong);
circle.exit().remove();//remove unneeded circles
circle.enter().append("circle")
.attr("r",0);//create any new circles needed
//update all circles to new positions
circle.transition()
.duration(500)
.attr("cx", function(d){ return projection([d.longitude, d.latitude])[0] })
.attr("cy", function(d){ return projection([d.longitude, d.latitude])[1] })
.attr("r", 7)
.attr("class", "circle")
.style("fill", "#012B4E")
.attr("stroke", "#012B4E")
.style("opacity", 0.7)
.attr("r", 4)
})


/////////////////////// WORLD MAP ////////////////////////////

var width = window.innerWidth,
height = window.innerHeight,
centered,
clicked_point;

var projection = d3.geoMercator()
// .translate([width / 2.2, height / 1.5]);

var plane_path = d3.geoPath()
.projection(projection);

var svg_map = d3.select("#graphic").append("svg")
.attr("width", 900)
.attr("height", 550)
.attr("class", "map");

var g = svg_map.append("g");
var path = d3.geoPath()
.projection(projection);

// load and display the World
d3.json("https://unpkg.com/world-atlas@1/world/110m.json", function(error, topology) {
g.selectAll("path")
.data(topojson.feature(topology, topology.objects.countries)
.features)
.enter()
.append("path")
.attr("d", path)
;
});
      path {
stroke: #2296F3;
stroke-width: 0.25px;
fill: #f8f8ff;
}
body {
font-family: "Arial", sans-serif;
}

.bar {
fill: #5f89ad;
}

.axis {
font-size: 13px;
}

.axis path,
.axis line {
fill: none;
display: none;
}

.label {
font-size: 13px;
}
<!DOCTYPE html>
<html>

<head>
<meta charset='utf-8' />
<title>Simple Bar chart</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.13/d3.js"></script>
<script src="https://unpkg.com/topojson-client@3"></script>
<script src="https://unpkg.com/topojson-client@3"></script>
<script src="https://d3js.org/d3-array.v1.min.js"></script>
<script src="https://d3js.org/d3-geo.v1.min.js"></script>
<script src="https://d3js.org/d3-geo-projection.v2.min.js"></script>


</head>

<body>

<div id="graphic"></div>


</body>

</html>

最佳答案

此功能基本上可以满足您的需求。用例略有不同,因为它是在使用新数据重新绘制 map 后调用的,但结果是相同的。 map 中会出现一组数据, map 会缩放到其上呈现的点的范围。

recenter() {
console.log('recentering')
try {
// get a handle to the transform object, and reset it to the
// zoom identity (resets to zoom out all the way)
let ztrans = this.zoom.transform
let t = this.d3.zoomIdentity
this.svg.transition().duration(DURATION*2).call(ztrans,t)

// get the object and measurements to determine the virtual
// "bounding" rectangle around the directional extremes of sites
// i.e., north (topmost), east (rightmost), etc
let circles = this.g.selectAll('a > circle')
let data = circles.data()
let long = data.map(o => parseFloat(o.Longitude))
let lat = data.map(o => parseFloat(o.Latitude))
let rightmost = this.d3.max(long)
let leftmost = this.d3.min(long)
let topmost = this.d3.max(lat)
let bottommost = this.d3.min(lat)
// convert the lat/long to points in the projection
let lt = this.projection([leftmost,topmost])
let rb = this.projection([rightmost,bottommost])
// calc the gaps (east - west, south - north) in pixels
let g = rb[0]-lt[0]
let gh = rb[1]-lt[1]

// get the dimensions of the panel in which the map sits
let w = this.svg.node().parentElement.getBoundingClientRect().width
let h = this.svg.node().parentElement.getBoundingClientRect().height

// the goal here is to move the halfway point between leftmost and rightmost
// on the projection sites to the halfway point of the panel in which the
// svg element resides, and same for 'y'
// the scale is the value 90% of the scale factor of either east-west to width
// or south-north to height, whichever is greater
let neoScale = 0.9 / Math.max(g/w, gh/h)

// now recalculate what will be the difference between the current
// center and the center of the scaled virtual rectangle
// this finds the difference between the centers
// the new center of the scaled rectangle is the average of the left and right
// or top and bottom points
let neoX = w/2 - (neoScale * ((lt[0]+rb[0])/2))
let neoY = h/2 - (neoScale * ((lt[1]+rb[1])/2))

// TRANSLATE FIRST! then scale.
t = this.d3.zoomIdentity.translate(neoX,neoY).scale(neoScale)
this.svg.transition().duration(DURATION*2).call(ztrans, t)
}
catch(e)
{
console.log(e)
}

更新
我 fork 了 op 的 fiddle ,并创建了一个 working fiddle具有以下变化:

  • 上面描述的 recenter 函数最初是用 d3 v4 编写的。 op 的 fiddle 在 v3 中。新的 fiddle 使用 v4。
  • 上面的recenter 函数是从另一个项目“按原样”复制和粘贴的。它在 fiddle 中进行了修改,以说明局部变量名称和范围。

此外,点不会在第一次点击栏时呈现,但会在后续点击时呈现。

关于javascript - D3 : Map Zoom scaled by points,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60214308/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com