D3.js 绘制地图

使用D3 V3版本绘制

绘制效果图:
D3.js绘制地图
准备工作: 3d立体柱状图的绘制

绘制地图思路:
  1. 绘制地图及地图投影;
  2. 根据地图地理信息将柱状图放置到指定位置;
  3. 根据scale计算出柱状图实际高度。
1. 绘制地图

地图的绘制可参考 十二月咖啡馆:十五课 地图,下面是地图绘制代码。

其中mapJson为GeoJSON文件,可在DATAV.GeoAtlas下载。

  // 基础数据初始化
  const svgObj = {
    width: 800,
    height: 750,
  };
  const mapColor = '#114a93';
  const mapLineColor = '#0d67c7';
  // 绘制
  const svg = d3.select(node).append('svg')
    .attr({ width: svgObj.width, height: svgObj.height });
  // 定义地图的投影
  const projection = d3.geo.mercator()
    .center([119.621184, 28.511708])
    .scale(19000);
  // 定义地理路径生成器
  const path = d3.geo.path()
    .projection(projection);
    
  const mapGroups = svg.append('g')
    .attr('class', 'mapGroups');
  // 地图路径绘制
  mapGroups.selectAll('path')
    .data(mapJson.features)
    .enter()
    .append('path')
    .attr('class', 'map-path')
    .style('fill', () => mapColor)
    .attr('stroke', mapLineColor)
    .attr('d', path);
  // text地理名称
  mapGroups.selectAll('text')
    .data(mapJson.features)
    .enter()
    .append('text')
    .attr('x', (d) => projection(d.properties.centroid)[0])
    .attr('y', (d) => projection(d.properties.centroid)[1])
    .attr('transform', `translate(${0},${0})`)
    .text((d) => d.properties.name)
    .attr({
      'font-size': '16px',
    });

地图底部的阴影部分可依据相同办法绘制出路径,填充不同的线条及背景颜色,即可完成基础地图的绘制。

在这里插入图片描述

2. 添加地区数据

设置模拟数据如下:

   dataset: [
        { id: 1, name: '遂昌县', rise: 3, unit: '%' },
        { id: 2, name: '龙泉市', rise: 2, unit: '%' },
        { id: 3, name: '松阳县', rise: 4, unit: '%' },
        { id: 4, name: '云和县', rise: 2, unit: '%' },
        { id: 5, name: '庆元县', rise: 3, unit: '%' },
        { id: 6, name: '青田县', rise: 4, unit: '%' },
        { id: 7, name: '莲都区', rise: 2, unit: '%' },
        { id: 8, name: '景宁县', rise: 6, unit: '%' },
        { id: 9, name: '缙云县', rise: 2, unit: '%' },
   ],

相关代码:

  const rectWidth = 13;
  const rectHeight = 60;   // 应根据计算得出,先默认柱体高度为60
  const rectColor = '#14a8f394';
  const rectLineColor = '#12ddda';
  
  const rect3dGroups = svg.append('g')
    .attr('class', 'rect3dGroups');
  const rect3d = rect3dGroups.selectAll('rect3d')
    .data(mapJson.features)
    .enter()
    .append('g')
    .attr('class', 'rect3d')
    .style('transform', (d, i) => {
      if (i === 7) {    // 景宁县全称过长,单独设置样式
        return `translate(${-30 - 65}px, ${-4 + 25}px)`;
      }
      return 'translate(-30px, -4px)';
    });
  // 绘制顶面
  rect3d.append('path')
  .attr('d', (d) => `M${projection(d.properties.centroid)[0]} ${projection(d.properties.centroid)[1] - rectHeight}l${rectWidth} ${-rectWidth}l${-rectWidth} ${-rectWidth}l${-rectWidth} ${rectWidth}z`)
  .attr({
    fill: rectColor,
    stroke: rectLineColor,
    'stroke-width': 1,
    'shape-rendering': 'crispedges',
  });
  // 绘制侧面
  rect3d.append('path')
    .attr('d', (d) => `M${projection(d.properties.centroid)[0]} ${projection(d.properties.centroid)[1]}l0 ${-rectHeight}l${rectWidth} ${-rectWidth}l0 ${rectHeight}l${-rectWidth} ${rectWidth}l${-rectWidth} ${-rectWidth}l0 ${-rectHeight}l${rectWidth} ${rectWidth}z`)
    .attr({
      fill: rectColor,
      stroke: rectLineColor,
      'stroke-width': 1,
      'shape-rendering': 'crispedges',
    });

可参考 W3School SVG 线性渐变 将柱体颜色设置为渐变色,此处未做渐变处理。
效果图:
在这里插入图片描述

3. 根据数据计算柱体高度
  // 定义柱体高度比例尺
  const maxData = d3.max(dataset.map((item) => item.rise));  // 最大增长率对应高度为60
  const rectHScale = d3.scale.linear()   // 设置线性比例尺
    .domain([0, maxData])
    .range([0, 60]);

则侧面与顶面 path 路径 d 中的 rectHeight 应根据数据计算高度,代码如下:

	.attr('d', (d)=>{
		let rectHeight = 0;
      	for (let i = 0; i < dataset.length; i += 1) {
	        if (d.properties.name.indexOf(dataset[i].name.slice(0, -1)) !== -1) {
	          rectHeight = rectHScale(dataset[i].rise);
	        }
      }
      return ...
	})
	

结果如图:
在这里插入图片描述
最后可根据设计图在柱状体旁边添加相关数据,也可添加相关动态效果。

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值