微信小程序內使用echart實現中國地圖,點擊省跳轉省地圖,再點擊市跳轉到市區詳情

目的:在微信小程序內實現一張中國地圖,上面要寫上一些全國數據,點擊省 => 省地圖,並請求數據,點擊市區 => 跳轉到市區地圖這樣一個功能,具體實現效果如下:

思路:

 1.首先我們要先畫一張中國地圖,直接用最近版的echarts-for-weixin插件,下載完之後吧echart組件放到小程序根目錄,可以看看裏面的使用方法,也可以下載它的案例來看,但是裏面是一個省份地圖,所以還是要自己畫中國地圖;

2. 要知道的是 echarts-for-weixin 這個插件暫不支持 toolTip(就是小手放上去展示的提示框,具體可以去echart官網來查) 自定義dom的在微信小程序裏,所以想在toolTip裏實現自定義按鈕的現在框架還不支持,所以我這裏選擇的方式是用cover-view來代替實現;

3.中國地圖的數據大概60k,每個省的數據大概40-60k,但是小程序單包數據不能超過2M,所以省市數據放到服務器用json數據拉取,這些數據在git上都有,整出來傳到服務器上即可

直接上代碼:

wxml:

<view class="container">
  <view class="chart-container {{showMap?'container-left':''}}">
    <ec-canvas wx:if="{{!isDisposed}}" id="mychart-dom-map" id="mychart-dom-map" canvas-id="mychart-map" ec="{{ ec }}"></ec-canvas>
    <cover-view style="left:{{toolTip.x}}px;top:{{toolTip.y}}px" wx:if="{{showToolTip}}" class="tool-tip">
      <cover-view>{{toolTip.name}}{{toolTip.value}}
        <cover-view class="nofont"></cover-view>
      </cover-view>
      <cover-view class="tool-detail" bindtap="checkoutDetail">
        <cover-view>查看詳情</cover-view>
        <cover-image class="arrow" src="/img/icon/arrow.png"></cover-image>
      </cover-view>
    </cover-view>
    <cover-view class="tool-back" wx:if="{{showBack}}">
      <button bindtap="drawChina">返回</button>
    </cover-view>
  </view>
  <view class="map-view" wx:if="{{showMap}}">
    <map id="map" longitude="{{centerPoint.longitude}}" latitude="{{centerPoint.latitude}}" scale="11" controls="{{controls}}" bindcontroltap="controltap" markers="{{markers}}" bindmarkertap="markertap" polyline="{{polyline}}" bindregionchange="regionchange" show-location style="width: 100%; height: 300px;"></map>
    <button bindtap="backChart">返回</button>
  </view>
</view>

css:

/**index.wxss**/
.container {
  position: relative;
}
.chart-container {
  width: 100%;
  height: 70vh;
}
.container-left{
  position: absolute;
  left: -200%;
  top: 0;
}
page {
  background-color: #eeeeee;
}
.tool-tip {
  position: fixed;
  top: 200rpx;
  left: 200rpx;
  z-index: 9999;
  background-color: rgba(0, 0, 0, .7);
  padding: 10rpx 15px;
  color: #ffffff;
  border-radius: 10rpx;
  overflow: initial;
}
.tool-detail {
  display: flex;
  justify-content: center;
  align-items: center;
  line-height: 1;
}
.nofont {
  display: inline-block;
	width: 6rpx;
	height: 26rpx;
}
.arrow {
  width: 32rpx;
  height: 32rpx;
}
.tool-back {
  position: fixed;
  top: 50rpx;
  left: 50rpx;
}
.tool-back button {
  padding: 8rpx 25rpx;
  line-height: 50rpx;
  font-size: 36rpx;
}

json:

{
  "usingComponents": {
    "ec-canvas": "../../ec-canvas/ec-canvas"
  }
}

js:

// pages/test/test.js\
import * as echarts from '../../ec-canvas/echarts.js'
import geoJson from '../../lib/mapData.js'
import provinceMap from '../../utils/province.js'
const app = getApp()
/**
 * 生成1000以內的隨機數
 */
function randomData() {
  return Math.round(Math.random() * 1000);
}
let provinceData = []
let drawProvinceName = ''
let cityList = []
let selectCity = {}
Page({
  /**
   * 頁面的初始數據
   */
  data: {
    ec: {
      // 將 lazyLoad 設爲 true 後,需要手動初始化圖表
      lazyLoad: true
    },
    isLoaded: false,
    isDisposed: false,
    showToolTip: true,
    toolTip: {
      x: -200,
      y: -200,
      name: '',
      value: ''
    },
    showBack: false,
    showMap: !1,
    // 地圖數據
    centerPoint: {
      longitude:0,
      latitude: 0,
    },
    markers: [{
      iconPath: "/resources/others.png",
      id: 0,
      latitude: 23.099994,
      longitude: 113.324520,
      width: 50,
      height: 50
    }],
    polyline: [{
      points: [{
        longitude: 113.3245211,
        latitude: 23.10229
      }, {
        longitude: 113.324520,
        latitude: 23.21229
      }],
      color: "#FF0000DD",
      width: 2,
      dottedLine: true
    }],
    controls: [{
      id: 1,
      iconPath: '/resources/location.png',
      position: {
        left: 0,
        top: 300 - 50,
        width: 50,
        height: 50
      },
      clickable: true
    }]
  },

  /**
   * 生命週期函數--監聽頁面加載
   */
  onLoad: function(options) {
  },
  
  /**
   * 生命週期函數--監聽頁面初次渲染完成
   */
  onReady: function() {
    this.chinaTool = this.data.toolTip
    this.provinceTool = this.data.toolTip
    // 獲取組件
    this.ecComponent = this.selectComponent('#mychart-dom-map');
    this.drawChina()
  },
  drawChina() {
    const defaultTip = {
      x: -200,
      y: -200,
      name: '',
      value: ''
    }
    this.setData({
      toolTip: defaultTip,
      showBack: !1
    })
    this.provinceTool = defaultTip
    this.ecComponent.init((canvas, width, height, dpr) => {
      // 獲取組件的 canvas、width、height 後的回調函數
      // 在這裏初始化圖表
      const chart = echarts.init(canvas, null, {
        width: width,
        height: height,
        devicePixelRatio: dpr // new
      });
      canvas.setChart(chart);
      echarts.registerMap('china', geoJson); // 繪製中國地圖

      this.setChinaOption(chart);

      // 將圖表實例綁定到 this 上,可以在其他成員函數(如 dispose)中訪問
      this.chart = chart;

      this.setData({
        isLoaded: true,
        isDisposed: false,
      });

      setTimeout(() => {
        this.setData({
          showToolTip: true
        })
      }, 500)
      // 注意這裏一定要返回 chart 實例,否則會影響事件處理等
      return chart;
    });
  },
  drawProvince(defaultCityList) {
    this.setData({
      toolTip: this.provinceTool,
      showBack: true
    })
    console.log(this.ecComponent)
    this.ecComponent.init((canvas, width, height, dpr) => {
      // 獲取組件的 canvas、width、height 後的回調函數
      // 在這裏初始化圖表
      const chart = echarts.init(canvas, null, {
        width: width,
        height: height,
        devicePixelRatio: dpr // new
      });
      canvas.setChart(chart);
      console.log('drawProvinceName:', drawProvinceName) // todo
      echarts.registerMap(drawProvinceName, provinceData); // 繪製中國地圖
      this.setProvinceOption(chart);
      // 將圖表實例綁定到 this 上,可以在其他成員函數(如 dispose)中訪問
      this.chart = chart;

      this.setData({
        isLoaded: true,
        isDisposed: false
      });

      // 注意這裏一定要返回 chart 實例,否則會影響事件處理等
      return chart;
    });
  },
  setChinaOption(chart) {
    const option = {
      // tooltip: {
      //   trigger: 'item',
      //   padding: [
      //     10,  // 上
      //     15, // 右
      //     8,  // 下
      //     15, // 左
      //   ],
      //   formatter: '{b}: {c}'
      // },
      tooltip: {
        show: false,
        trigger: 'item',
        backgroundColor: "#FFF",
        padding: [
          10, // 上
          15, // 右
          8, // 下
          15, // 左
        ],
        extraCssText: 'box-shadow: 2px 2px 10px rgba(21, 126, 245, 0.35);',
        textStyle: {
          fontFamily: "'Microsoft YaHei', Arial, 'Avenir', Helvetica, sans-serif",
          color: '#005dff',
          fontSize: 12,
        },
        renderMode: 'richText',
        formatter: (a) => {
          console.log(a)
          return `${a.data.name}${a.data.value}確診<button>123</button>`
        }
        // `{b} :  {c}確診`
      },
      geo: [{
        // 地理座標系組件
        map: "china",
        roam: false, // 可以縮放和平移
        aspectScale: 0.8, // 比例
        layoutCenter: ["50%", "50%"], // position位置
        layoutSize: 370, // 地圖大小,保證了不超過 370x370 的區域
        label: {
          // 圖形上的文本標籤
          normal: {
            show: true,
            textStyle: {
              color: "rgba(0, 0, 0, 0.9)",
              fontSize: '10'
            }
          },
          emphasis: { // 高亮時樣式
            color: "#333"
          }
        },
        itemStyle: {
          // 圖形上的地圖區域
          normal: {
            borderColor: "rgba(0,0,0,0.2)",
            areaColor: "#005dff"
          }
        },
        // regions: [{
        //   name: "南海諸島",
        //   value: 0,
        //   itemStyle: {
        //     // areaColor: 'red',
        //     // color: 'red',
        //     // normal: {
        //     //   opacity: 0,
        //     //   label: {
        //     //     show: false
        //     //   }
        //     // }
        //   }
        // }]
      }],
      toolbox: {
        show: true,
        orient: 'vertical',
        left: 'right',
        top: 'center',
        feature: {
          dataView: {
            readOnly: false
          },
          restore: {},
          saveAsImage: {}
        }
      },
      visualMap: {
        min: 0,
        max: 2000,
        left: 'left',
        top: 'bottom',
        text: ['高', '低'], // 文本,默認爲數值文本
        calculable: true
        // min: 800,
        // max: 50000,
        // text: ['High', 'Low'],
        // realtime: false,
        // calculable: true,
        // inRange: {
        //   color: ['lightskyblue', 'yellow', 'orangered']
        // }
      },
      series: [{
        type: 'map',
        mapType: 'china',
        geoIndex: 0,
        roam: true, // 鼠標是否可以縮放
        label: {
          normal: {
            show: true
          },
          emphasis: {
            show: true
          }
        },
        data: [{
            name: '北京',
            value: randomData()
          },
          {
            name: '天津',
            value: randomData()
          },
          {
            name: '上海',
            value: randomData()
          },
          {
            name: '重慶',
            value: randomData()
          },
          {
            name: '河北',
            value: randomData()
          },
          {
            name: '河南',
            value: randomData()
          },
          {
            name: '雲南',
            value: randomData()
          },
          {
            name: '遼寧',
            value: randomData()
          },
          {
            name: '黑龍江',
            value: randomData()
          },
          {
            name: '湖南',
            value: randomData()
          },
          {
            name: '安徽',
            value: randomData()
          },
          {
            name: '山東',
            value: randomData()
          },
          {
            name: '新疆',
            value: randomData()
          },
          {
            name: '江蘇',
            value: randomData()
          },
          {
            name: '浙江',
            value: randomData()
          },
          {
            name: '江西',
            value: randomData()
          },
          {
            name: '湖北',
            value: randomData()
          },
          {
            name: '廣西',
            value: randomData()
          },
          {
            name: '甘肅',
            value: randomData()
          },
          {
            name: '山西',
            value: randomData()
          },
          {
            name: '內蒙古',
            value: randomData()
          },
          {
            name: '陝西',
            value: randomData()
          },
          {
            name: '吉林',
            value: randomData()
          },
          {
            name: '福建',
            value: randomData()
          },
          {
            name: '貴州',
            value: randomData()
          },
          {
            name: '廣東',
            value: randomData()
          },
          {
            name: '青海',
            value: randomData()
          },
          {
            name: '西藏',
            value: randomData()
          },
          {
            name: '四川',
            value: randomData()
          },
          {
            name: '寧夏',
            value: randomData()
          },
          {
            name: '海南',
            value: randomData()
          },
          {
            name: '臺灣',
            value: randomData()
          },
          {
            name: '香港',
            value: randomData()
          },
          {
            name: '澳門',
            value: randomData()
          }
        ]
      }]
    };

    chart.setOption(option);
    chart.on('click', (e) => {
      const toolTip = {
        x: e.event.offsetX,
        y: e.event.offsetY,
        name: e.data.name,
        value: e.data.value
      }
      this.setData({
        toolTip
      })
      console.log(e)
    })
    chart.on('mousemove', (e) => {
      const toolTip = {
        x: e.event.offsetX,
        y: e.event.offsetY,
        name: e.data.name,
        value: e.data.value
      }
      this.setData({
        toolTip
      })
      console.log(e)
    })
  },
  setProvinceOption(chart) {
    const option = {
      tooltip: {
        show: false,
        trigger: 'item',
        formatter: '{b}: {c}'
      },
      visualMap: {
        min: 0,
        max: 2000,
        left: 'left',
        top: 'bottom',
        text: ['高', '低'], // 文本,默認爲數值文本
        calculable: true
      },
      toolbox: {
        show: true,
        orient: 'vertical',
        left: 'right',
        top: 'center',
        feature: {
          dataView: {
            readOnly: false
          },
          restore: {},
          saveAsImage: {}
        }
      },
      geo: [{
        // 地理座標系組件
        map: drawProvinceName,
        roam: false, // 可以縮放和平移
        aspectScale: 0.8, // 比例
        layoutCenter: ["50%", "50%"], // position位置
        layoutSize: 370, // 地圖大小,保證了不超過 370x370 的區域
        label: {
          // 圖形上的文本標籤
          normal: {
            show: true,
            textStyle: {
              color: "rgba(0, 0, 0, 0.9)",
              fontSize: '10'
            }
          },
          emphasis: { // 高亮時樣式
            color: "#333"
          }
        },
        itemStyle: {
          // 圖形上的地圖區域
          normal: {
            borderColor: "rgba(0,0,0,0.2)",
            areaColor: "#005dff"
          }
        },
        // regions: [{
        //   name: "南海諸島",
        //   value: 0,
        //   itemStyle: {
        //     // areaColor: 'red',
        //     // color: 'red',
        //     // normal: {
        //     //   opacity: 0,
        //     //   label: {
        //     //     show: false
        //     //   }
        //     // }
        //   }
        // }]
      }],
      series: [{
        type: 'map',
        mapType: drawProvinceName,
        geoIndex: 0,
        roam: true, // 鼠標是否可以縮放
        label: {
          normal: {
            show: true
          },
          emphasis: {
            textStyle: {
              color: '#fff'
            }
          }
        },
        itemStyle: {
          normal: {
            borderColor: '#389BB7',
            areaColor: '#fff',
          },
          emphasis: {
            areaColor: '#389BB7',
            borderWidth: 0
          }
        },
        animation: false,
        data: cityList
      }],
    };
    chart.on('click', (e) => {
      const toolTip = {
        x: e.event.offsetX,
        y: e.event.offsetY,
        name: e.data.name,
        value: e.data.value
      }
      this.setData({
        toolTip
      })
      // selectCity = e.data
      console.log(e)
    })
    chart.on('mousemove', (e) => {
      const toolTip = {
        x: e.event.offsetX,
        y: e.event.offsetY,
        name: e.data.name,
        value: e.data.value
      }
      this.setData({
        toolTip
      })
      console.log(e)
    })
    chart.on('mouseup', (e) => {
      console.log('mouseup')
      selectCity = e.data
      console.log(e.data)
    })
    chart.setOption(option);
  },
  checkoutDetail() {
    console.log('checkoutProvince')
    if (!this.data.showBack) { // go province
      console.log(provinceMap[this.data.toolTip.name])
      drawProvinceName = provinceMap[this.data.toolTip.name]
      this.getProvinceData(drawProvinceName, (defaultCityList) => {
        this.drawProvince()
      })
    } else { // go city
      this.setData({
        showBack: !1,
        showToolTip: !1,
        showMap: !0
      })
      this.provinceTool = this.data.toolTip
      this.setData({
        centerPoint: {
          longitude: selectCity.cp[0],
          latitude: selectCity.cp[1]
        }
      })
    }
  },
  backChart () {
    this.setData({
      showBack: !0,
      showMap: !1,
      showToolTip: !0,
      toolTip: this.provinceTool
    })
  },
  backChina () {
    this.setData({
      toolTip: this.provinceTool
    })
  },
  getProvinceData (provinceName, callback = function () {}) {
    const url = `http://sp5566.top/map/${provinceName}.json`
    app.request('get', url).then(res => {
      console.log(res)
      cityList = []
      res.features.forEach((item) => {
        cityList[cityList.length] = {
          name: item.properties.name,
          value: randomData(),
          id: item.id,
          cp: item.properties.cp
        }
      })
      provinceData = res
      callback(cityList)
    })
  },
  /**
   * 生命週期函數--監聽頁面顯示
   */
  onShow: function() {

  },

  /**
   * 生命週期函數--監聽頁面隱藏
   */
  onHide: function() {

  },

  /**
   * 生命週期函數--監聽頁面卸載
   */
  onUnload: function() {

  },

  /**
   * 頁面相關事件處理函數--監聽用戶下拉動作
   */
  onPullDownRefresh: function() {

  },

  /**
   * 頁面上拉觸底事件的處理函數
   */
  onReachBottom: function() {

  },

  /**
   * 用戶點擊右上角分享
   */
  onShareAppMessage: function() {

  }
})

app.js  裏面有些有關緊要的代碼 不要關心 

//app.js
App({
  onLaunch: function () {
    // 展示本地存儲能力
    // mqttClient.initMqtt({ clientId: `C${}${new Date().getTime()}` })
  },
  baseUrl: 'https://www.wanandroid.com',
  globalData: {
    userInfo: null
  },
  httpGet: function (url, data, loading, loadingMsg) {
    return this.httpBase("GET", url, data, loading, loadingMsg);
  },
  httpBase: function (method, url, data, loading = false, loadingMsg) {
    let _this = this;

    let requestUrl = this.baseUrl + url;

    if (loading) {
      wx.showLoading({
        title: loadingMsg || '提交中...',
        mask: true
      });
    } else {
      wx.showNavigationBarLoading()
    }

    function request(resolve, reject) {
      wx.request({
        header: {
          'Content-Type': 'application/json'
        },
        method: method,
        url: requestUrl,
        data: data,
        success: function (result) {
          if (loading) {
            wx.hideLoading();
          } else {
            wx.hideNavigationBarLoading()
          }

          let res = result.data || {};
          let code = res.errorCode;

          if (code !== 0) {
            reject(res);
            if (res.message) {
              wx.showToast({
                title: res.message,
                icon: 'none'
              });
            }
          } else {
            resolve(res);
          }
        },
        fail: function (res) {
          reject(res);
          if (loading) {
            wx.hideLoading();
          } else {
            wx.hideNavigationBarLoading()
          }
          wx.showToast({
            title: '網絡出錯',
            icon: 'none'
          });
        }
      })
    }
    return new Promise(request);
  },
  request(method, url, data = {}, loading = false, loadingMsg = 'loading...') {
    return new Promise((resolve, reject) => {
      if (loading) {
        wx.showLoading({
          title: loadingMsg,
          mask: true
        });
      } else {
        wx.showNavigationBarLoading()
      }
      wx.request({
        header: {
          'Content-Type': 'application/json'
        },
        method: method,
        url,
        data: data,
        success: function (result) {
          if (loading) {
            wx.hideLoading();
          } else {
            wx.hideNavigationBarLoading()
          }
          if(result.statusCode === 200) {
            const res = result.data || {};
            resolve(res);
          } else {
            wx.showToast({
              title: '出錯了',
              icon: 'none'
            });
            reject(res);
          }
          // let code = res.errorCode;
          // if (code !== 0) {
          //   reject(res);
          //   if (res.message) {
          //     wx.showToast({
          //       title: res.message,
          //       icon: 'none'
          //     });
          //   }
          // } else {
          // }
        },
        fail: function (res) {
          reject(res);
          if (loading) {
            wx.hideLoading();
          } else {
            wx.hideNavigationBarLoading()
          }
          wx.showToast({
            title: '網絡出錯',
            icon: 'none'
          });
        }
      })
    })
  }
})

最後附上源碼地址:https://github.com/peng20017/chinaMap-for-wexin  別忘了給個星星

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章