You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:51:52