d3实现地图, 鼠标悬浮显示区域名称

d3实现地图, 鼠标悬浮显示区域名称

前期准备

  1. 安装d3.js
    npm i d3 --save
  2. 安装d3-scale-chromatic
    npm i d3-scale-chromatic --save
  3. 安装d3-geo(从球体到平面的投影)
    npm i d3-geo --save
  4. main.js配置
    //d3
    import * as d3 from 'd3';
    import * as geo from 'd3-geo';
    import * as d3Color from 'd3-scale-chromatic'
    Vue.prototype.$d3 = d3;
    Vue.prototype.$geo = geo;
    Vue.prototype.$d3Color = d3Color;
  5. 地图json
    点击查看JSON文件

页面布局及样式

<template>
    <div class="d3">
        <svg id="svg"></svg>
        <div id="tooltip"></div>
    </div>
</template>
<style scoped>
.d3{
    margin: 0 auto;
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
}
#svg {
    background: #666;
    width: 100%;
    height: 100%;
}
#tooltip {
    position: absolute;
    padding: 3px 5px;
    background: #333333;
    border: 1px solid #e8e8e8;
    color: #33cc99;
    font-size: 10px;
    border-radius: 4px;
  }
</style>

JS准备

<script>
import chinaJson from '@/assets/json/china.json';
export default {
  name: "mapOnline",
  data() {
    return {
        svg:undefined,
        projection: undefined,
        path: undefined
    }
  },
  async mounted(){
    this.svg = this.$d3.select('#svg');
    const style = getComputedStyle(this.svg.node());
    const width = parseInt(style.getPropertyValue('width'), 10);
    const height = parseInt(style.getPropertyValue('height'), 10);
    // 定义地图的投影
    this.projection = this.$geo.geoMercator()
        .scale(750)
        .center([105, 33])
        .translate([width / 2, height / 2]);
    //  定义地理路径生成器
    this.path = this.$geo.geoPath(this.projection);

    // this.getAllProviceJson();
    this.drawChinaMap();

  },
  methods:{
    drawChinaMap() {
      // 地图路径绘制
      this.svg.selectAll('path')
            .data(chinaJson.features)
            .enter()
            .append('path')
            .attr('d', this.path)
            .attr('fill', (d, i) => {
                return 'transparent';
            })
            .attr('fill-rule', 'evenodd')
            .attr('stroke', '#fff')
            .attr('stroke-width', 2)
            .on('mouseover', (d, i) => {
                this.mouseMove(chinaJson.features)
            });

        // text地理名称
        this.svg
            .selectAll("text")
            .data(chinaJson.features)
            .enter()
            .append("text")
            .attr("x", (d) => {
                const position = this.projection(d.properties.centroid || [0, 0]);
                return position[0];
            })
            .attr("y", (d) => {
                const position = this.projection(d.properties.centroid || [0, 0]);
                return position[1];
            })
            .text((d) => {
                return d.properties.name
            })
            .attr("text-anchor", "middle")
            .attr("dominant-baseline", "middle")
            .transition()
            .duration(1000)
            .delay((d, i) => i * 50)
    },
    getAllProviceJson(){
        chinaJson.features.forEach((obj) => {
            if(obj.properties && obj.properties.name){
                this.drawProvice(obj.properties.name)
            }
        })
    },
    drawProvice(name){
        const jsonData = require(`@/assets/json/${name}.json`);
        const colors = (i) => this.$d3Color.interpolateGnBu(i);

        if (!jsonData || !jsonData.features) {
            return;
        }

        this.svg.append('g')
            .attr('id', name)
            .selectAll('g')
            .data(jsonData.features)
            .enter()
            .append('g')
            .append('path')
            .attr('d', this.path)
            .attr('fill', (d, i) => {
                if(d.properties.name == '泸州市'){
                    return "transparent"
                }else{
                    return colors(i / 40);
                }
            })
            .attr('fill-rule', 'evenodd')
            .attr('id', (d, i) => (d.properties || {}).name)
            .attr('stroke', '#ccc')
            .attr('stroke-width', 1)
            // .on('mouseover', (d, i) => {
            //     this.mouseMove(jsonData.features, name)
            // });
    },
    mouseMove(jsonData){
        var tooltip = this.$d3.select('#tooltip');
        const location = this.svg.selectAll('.location')
        .data(jsonData)
        .enter()
        .append('g')
        .attr('class', 'location')
        .attr('transform', (d) => {
            const position = this.projection(d.properties.centroid || [0, 0]);
            return 'translate(' + position[0] + ',' + position[1] + ')';
        });

        location.append('circle')
        .attr('r', 4)
        .attr('fill', '#e91e63')
        .attr('class', 'location')
        .on('mouseover', function (d, i) {
          return tooltip.style('visibility', 'visible').text(i.properties.name)
        })
        .on('mousemove', function (d, i) {
          return tooltip.style('top', (event.pageY-10)+'px').style('left',(event.pageX+10)+'px')
        })
        .on('mouseout', function (d, i) {
          return tooltip.style('visibility', 'hidden')
        })
    }
  }
};

地图可以设置两个颜色值, 根据value不同, 颜色不同

const maxData = this.mapDataJson.max;
const minData = this.mapDataJson.min;
var palegreen = this.$d3.rgb(2, 175, 102);
var darkgreen = this.$d3.rgb(81, 37, 255);
var color = this.$d3.interpolate(palegreen, darkgreen);
const cliner = this.$d3.scaleLinear().domain([minData, maxData]).range([0, 1]);
//根据value, 不同颜色
svg
.attr("fill", (d) => {
  let prov = d.properties.name;
  let curProvData = this.mapDataJson.data.find(
    (provData) => provData.cityNameCN === prov
  );
  return color(cliner(curProvData ? curProvData.value : minData));
})

实现效果

传不上去, 就这样吧, 运行起来就看到了

上一篇:D3.js介绍


下一篇:计算吻合率