It took a lot of trouble to get this map done, but… Emm is very ugly and there are many places that need to be optimized. At the beginning, I was looking for this map in the example of ANTV L7, but I didn’t find it. After searching for information and referring to this blog, I had an Epiphany that it was possible to obtain the data of China map and make a chart.

html

<div id='map'></div>
Copy the code

CSS, G2-tooltip and G2-Tooltip-list are the styles copied from the official website, which are the div styles that are displayed when the mouse is over

<style>
    .labelclass {
      width: 50px;
      height: 50px;
      border-radius: 50%;
      color: #9c0a0d;
      text-align: center;
      line-height: 50px;
    }
    .g2-tooltip{
      position: absolute;
        visibility: hidden;
        border: 1px solid #efefef;
        background-color: white;
        color: # 000;Opacity: 0.8; padding: 5px 15px; transition: top 200ms,left 200ms; } .g2-tooltip-list{ margin: 10px; } </style>Copy the code

Import the required JS files

<script src="Jquery - 3.4.1 track. Min. Js"></script>
  <script src="https://gw.alipayobjects.com/os/lib/antv/g2/3.4.10/dist/g2.min.js"></script>
  <script src="https://unpkg.com/@antv/data-set"></script>
Copy the code

To avoid a callback hell of a mess, I’ve wrapped ajax of the Promise type

function $get(url) {
    return new Promise((resolve, rejected) => {
        $.get(url, res => {
            resolve(res)
        })
    })
}
Copy the code

Encapsulate the getColor function to determine the area of the data to get a different color

function getColor(v) {
    const trend = ['#ffefd7'.'#ffd2a0'.'#fe8664'.'#e64b47'.'#c91014'.'#9c0a0d',];
    return v > 9999
        ? trend[5]
        : v > 999
            ? trend[4]
            : v > 499
                ? trend[3]
                : v > 99
                    ? trend[2]
                    : v > 9
                        ? trend[1]
                        : trend[0];
}
Copy the code

Let’s start with the frame of the map

let mapData = await $get('https://geo.datav.aliyun.com/areas/bound/100000_full.json')
   
    var chart = new G2.Chart({
        container: 'map', height: 1000, width: 1000, padding: [55, 20] }); Chart.scale ({//sync: the range of values used to unify the same data attribute when chart has views from different data sources //nice: defaults totrueIs used to optimize the value range so that the scale lines of the plotted axes are evenly distributed. For example, the range of the original data is [3, 97], if nice istrue, the value range is set to [0, 100] x: {sync:true, nice: false },
        y: { sync: true, nice: false }
    })
    //chart.coord().reflect(' ' | 'x' | 'y'): coordinate system transpose, invert the start and end values of x or y. chart.coord().reflect(); chart.axis(false); Var ds = new DataSet(); Var dv = ds.createView('back')
        .source(mapData, {
            type: 'GeoJSON'}).transform({//geo. Projectiontype: 'geo.projection',
            projection: 'geoMercator',
            as: ['x'.'y'.'centroidX'.'centroidY']}); // Draw the map varbgView = chart.view();
    bgView.source(dv);
    bgView.polygon()
        .position('x*y')
        .style({
            fill: '# 000088',// Map color stroke:'#b1b1b1',// lineWidth: 0.5,// fillOpacity: 1})Copy the code

All right, we’ve got a map frame

The next step is to export the epidemic data to the chart, and I got the data from the website, so I have to process it

  let res = await $get('http://lovebridge.migu.cn:18188/api/map?url=http:%2F%2Fgarnetcdn.migu.cn%2Flovebridge.html') res = res.data.country[0]. TypeCopy the code

Only place names can be used to connect epidemic data with maps, but the names in epidemic books do not show cities or provinces, so I used find and slice methods to find corresponding objects and process the data I need

Var userData = ds.createView().source(res) userData.transform({// Transform data,typeEquivalent to an array conversion methodtype: 'map'// The latitude and longitude callback is obtained by searching for the same characters as the first two characters, since cities and provinces are removed from the data obtained from the Internet:function (obj, index) {
            let one = dv.rows.find(item => { return item.name.slice(0, 2) === obj.na.slice(0, 2) })
            obj.x = one.centroidX * 1;
            obj.y = one.centroidY * 1;
            obj.data = parseInt(obj.tn.split(', ')[0])
            one.data = obj.data
            returnobj; }}); Var pointView = chart.view(); pointView.source(userData); pointView.intervalStack() .position('x*y').label('na', {
            offset: -5,
            textStyle: {
                fontSize: 10,
                fill: '# 000',
            },
            formatter: (text, item) => {
                const d = item.point;
                return d.na + '\n'+ d.data; }})Copy the code

Different areas need to display the corresponding color according to the number of confirmed patients. I have stored the data in userData before

bgView.polygon().position('x*y').color('data', getColor)// Pass the callback function to make different data display different background colorCopy the code

The corresponding data is displayed as the mouse moves over it, and only chart has the Tooltip method

chart.tooltip({
        showTitle: false// The default title does not display containerTpl: '<div class="g2-tooltip"><ul class="g2-tooltip-list"></ul>
      </div>`,
        itemTpl: '
  • diagnose {value} case
  • '
    }) Copy the code

    Unanimate and render the chart to canvas

     chart.animate(false)
    chart.render();
    Copy the code

    The finished product

    Here is the total JS code

    function $get(url) {
        return new Promise((resolve, rejected) => {
            $.get(url, res => {
                resolve(res)
            })
        })
    }
    function getColor(v) {
        const trend = ['#ffefd7'.'#ffd2a0'.'#fe8664'.'#e64b47'.'#c91014'.'#9c0a0d',];
        return v > 9999
            ? trend[5]
            : v > 999
                ? trend[4]
                : v > 499
                    ? trend[3]
                    : v > 99
                        ? trend[2]
                        : v > 9
                            ? trend[1]
                            : trend[0];
    }
    async function aa() {
        let mapData = await $get('https://geo.datav.aliyun.com/areas/bound/100000_full.json')
       
        var chart = new G2.Chart({
            container: 'map',
            // forceFit: true, height: 1000, width: 1000, padding: [55, 20] }); // // force sync scales chart.scale({//sync: range of values used to unify the same data attributes when different data source views exist in chart //nice: defaults totrueIs used to optimize the value range so that the scale lines of the plotted axes are evenly distributed. For example, the range of the original data is [3, 97], if nice istrue, the value range is set to [0, 100] x: {sync:true, nice: false },
            y: { sync: true, nice: false }
        })
        //chart.coord().reflect(' ' | 'x' | 'y'): coordinate system transpose, invert the start and end values of x or y. chart.coord().reflect(); chart.axis(false); Var ds = new DataSet(); Var dv = ds.createView('back')
            .source(mapData, {
                type: 'GeoJSON'}).transform({//geo. Projectiontype: 'geo.projection',
                projection: 'geoMercator',
                as: ['x'.'y'.'centroidX'.'centroidY']}); varbgView = chart.view();
        bgView.source(dv);
        bgView.polygon()
            .position('x*y')
            .style({
                fill: '# 000088',// Map color stroke:'#b1b1b1',// lineWidth: 0.5,// fillOpacity: 1}).'data', getColor)// Pass the callback function to make different data display different background colorlet res = await $get('http://lovebridge.migu.cn:18188/api/map?url=http:%2F%2Fgarnetcdn.migu.cn%2Flovebridge.html') res = res.data.country[0]. Var userData = ds.createView().source(res) userData.transform({// Transform data,typeEquivalent to an array conversion methodtype: 'map'// The latitude and longitude callback is obtained by searching for the same characters as the first two characters, since cities and provinces are removed from the data obtained from the Internet:function (obj, index) {
                let one = dv.rows.find(item => { return item.name.slice(0, 2) === obj.na.slice(0, 2) })
                obj.x = one.centroidX * 1;
                obj.y = one.centroidY * 1;
                obj.data = parseInt(obj.tn.split(', ')[0])
                one.data = obj.data
                returnobj; }}); Var pointView = chart.view(); pointView.source(userData); pointView.intervalStack() .position('x*y').label('na', {
                offset: -5,
                textStyle: {
                    fontSize: 10,
                    fill: '# 000',
                },
                formatter: (text, item) => {
                    const d = item.point;
                    return d.na + '\n'+ d.data; }}) // Chart. Legend ('data', {
            position: 'right'Chart.tooltip ({showTitle: < chart >);})false// The default title does not display containerTpl: '<div class="g2-tooltip"><ul class="g2-tooltip-list"></ul>
          </div>`,
            itemTpl: '
  • diagnose {value} case
  • '
    }) chart.animate(false) chart.render(); } aa() Copy the code