如何在Datamaps地球仪中实现普通缩放功能?
给Datamaps正交投影地球仪添加普通缩放功能
我懂你想要的效果——给这个能拖拽旋转的地球仪加上滚轮缩放,不是那种跳转到特定国家的缩放,而是平滑的全局缩放对吧?刚好你的代码已经搭好了拖拽旋转的基础,咱们只需要扩展几部分就能实现这个功能。
核心思路
Datamaps的正交投影(orthographic)是基于D3的投影实现的,缩放本质上就是修改投影的scale参数值。我们只需要:
- 把缩放值存在全局变量里,方便每次重绘地图时调用
- 监听鼠标滚轮事件,根据滚轮方向调整缩放值
- 限制缩放范围,避免地球仪缩得太小或者太大
- 每次调整后调用
redraw()重绘地图
具体代码修改步骤
1. 添加全局缩放变量
在你的全局变量区,加上初始缩放值(默认正交投影的scale大概是150,你可以根据需求调整):
var globalRotation = [90,-30]; var globalScale = 150; // 新增全局缩放变量
2. 给投影配置加上scale参数
修改init函数里的projectionConfig,把全局缩放值传进去:
projectionConfig: { rotation: globalRotation, scale: globalScale // 新增这行 },
3. 添加滚轮缩放事件监听
在拖拽事件的后面,添加滚轮事件的处理逻辑:
// 新增缩放功能 var zoom = d3.behavior.zoom() .scaleExtent([80, 300]) // 设置缩放的最小/最大值,防止过度缩放 .on("zoom", function() { // 只处理滚轮事件,避免和拖拽操作冲突 if (d3.event.sourceEvent && d3.event.sourceEvent.type === "wheel") { var delta = d3.event.sourceEvent.deltaY; // 根据滚轮方向调整缩放值,10是缩放灵敏度,可自行调整 globalScale += delta > 0 ? -10 : 10; // 把缩放值限制在我们设定的范围内 globalScale = Math.max(80, Math.min(300, globalScale)); // 重绘地图 redraw(); } }); // 把缩放和拖拽事件都绑定到SVG上 d3.select("#world").select("svg").call(zoom).call(drag);
修改后的完整代码
//basic map config with custom fills, mercator projection var series = [ ["USA",36.2],["GBR",7.4],["CAN",6.2],["DEU",5.7],["FRA", 4.1],["ESP",4.1],["ITA",3.3],["MEX",3.0],["AUS",2.5],["NLD",2.4], ["IND",2.1],["BRA",2.0],["GRC",1.4],["AUT",1.2],["ROU",1.2],["SRB",1.0],["COL",0.8],["POL",0.8],["ZAF",0.7],["SWE",0.7], ["DNK",0.6],["VEN",0.6],["JPN",0.6],["KOR",0.6],["BEL",0.5],["RUS",0.5],["PRT",0.5] ]; var dataset = {}; // We need to colorize every country based on "percent" // colors should be uniq for every value. // For this purpose we create palette(using min/max series-value) var onlyValues = series.map(function(obj){ return obj[1]; }); var minValue = Math.min.apply(null, onlyValues), maxValue = Math.max.apply(null, onlyValues); // create color palette function // color can be whatever you wish var paletteScale = d3.scale.linear() .domain([minValue,maxValue]) .range(["rgb(0,0,0)","rgb(219,219,219)"]); // color // fill dataset in appropriate format series.forEach(function(item){ // item example value ["USA", 36.2] var iso = item[0], value = item[1]; dataset[iso] = { percent: value, fillColor: paletteScale(value) }; }); var map; var globalRotation = [90,-30]; var globalScale = 150; // 新增全局缩放变量 function redraw() { d3.select("#world").html(''); init(); }// redraw function init() { map = new Datamap({//need global var scope: 'world', element: document.getElementById('world'), projection: 'orthographic', projectionConfig: { rotation: globalRotation, scale: globalScale // 新增缩放配置 }, fills: {defaultFill: 'rgba(30,30,30,0.1)'}, data: dataset, geographyConfig: { responsive: true, borderColor: 'rgba(222,222,222,0.2)', highlightBorderWidth: 1, // don't change color on mouse hover highlightFillColor: function(geo) { return geo['fillColor'] || 'rgba(30,30,30,0.5)'; }, // only change border highlightBorderColor: 'rgba(222,222,222,0.5)', // show desired information in tooltip popupTemplate: function(geo, data) { // don't show tooltip if country don't present in dataset if (!data) { return ; } // tooltip content return ['', '<div style="opacity:0.7;" class="hoverinfo">% of visitors in ' + geo.properties.name, ': ' + data.percent, ''].join(''); } } }); //draw a legend for this map map.legend(); map.graticule(); var drag = d3.behavior.drag().on('drag', function() { var dx = d3.event.dx; var dy = d3.event.dy; // var rotation = livemapScope.rotation; var rotation = map.projection.rotate(); var radius = map.projection.scale(); var scale = d3.scale.linear() .domain([-1 * radius, radius]) .range([-90, 90]); var degX = scale(dx); var degY = scale(dy); rotation[0] += degX; rotation[1] -= degY; if (rotation[1] > 90) rotation[1] = 90; if (rotation[1] < -90) rotation[1] = -90; if (rotation[0] >= 180) rotation[0] -= 360; globalRotation = rotation; redraw(); }); // 新增缩放功能 var zoom = d3.behavior.zoom() .scaleExtent([80, 300]) // 限制缩放范围 .on("zoom", function() { if (d3.event.sourceEvent && d3.event.sourceEvent.type === "wheel") { var delta = d3.event.sourceEvent.deltaY; globalScale += delta > 0 ? -10 : 10; globalScale = Math.max(80, Math.min(300, globalScale)); redraw(); } }); d3.select("#world").select("svg").call(zoom).call(drag); }// init redraw();
额外说明
- 你可以调整
scaleExtent([80, 300])里的数值,来改变允许的最小/最大缩放级别 - 调整
globalScale += delta > 0 ? -10 : 10;里的10,可以改变滚轮缩放的灵敏度,数值越大缩放越快 - 如果需要支持触摸缩放,你可以去掉
if (d3.event.sourceEvent.type === "wheel")的判断,但可能需要处理拖拽和触摸缩放的冲突问题
内容的提问来源于stack exchange,提问作者lastnoob
相关产品推荐
相关产品推荐

