wolyshaw 4 năm trước cách đây
mục cha
commit
fbd3348ea5

+ 36 - 2
package-lock.json

@@ -3482,6 +3482,14 @@
         "stream-shift": "^1.0.0"
       }
     },
+    "echarts": {
+      "version": "4.9.0",
+      "resolved": "https://registry.npmjs.org/echarts/-/echarts-4.9.0.tgz",
+      "integrity": "sha512-+ugizgtJ+KmsJyyDPxaw2Br5FqzuBnyOWwcxPKO6y0gc5caYcfnEUIlNStx02necw8jmKmTafmpHhGo4XDtEIA==",
+      "requires": {
+        "zrender": "4.3.2"
+      }
+    },
     "ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz",
@@ -5425,8 +5433,7 @@
     "lodash": {
       "version": "4.17.20",
       "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.20.tgz?cache=0&sync_timestamp=1597336196663&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.20.tgz",
-      "integrity": "sha1-tEqbYpe8tpjxxRo1RaKzs2jVnFI=",
-      "dev": true
+      "integrity": "sha1-tEqbYpe8tpjxxRo1RaKzs2jVnFI="
     },
     "lodash.camelcase": {
       "version": "4.3.0",
@@ -9461,6 +9468,11 @@
       "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
       "dev": true
     },
+    "resize-detector": {
+      "version": "0.1.10",
+      "resolved": "https://registry.npmjs.org/resize-detector/-/resize-detector-0.1.10.tgz",
+      "integrity": "sha512-iLcXC8A6Fb0DfA+TRiywrK/0A22bFqkhntjMJMEzXDA4XkcEkfwpNbv7W8iewUiD0xYIaeiXOfiEehTqGKsUFw=="
+    },
     "resize-observer-polyfill": {
       "version": "1.5.1",
       "resolved": "https://registry.npm.taobao.org/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fresize-observer-polyfill%2Fdownload%2Fresize-observer-polyfill-1.5.1.tgz",
@@ -10927,6 +10939,23 @@
       "resolved": "https://registry.npm.taobao.org/vue-awesome-swiper/download/vue-awesome-swiper-4.1.1.tgz",
       "integrity": "sha1-j3qyIa0AMCHXVrhqphj0KZJJAP4="
     },
+    "vue-echarts": {
+      "version": "5.0.0-beta.0",
+      "resolved": "https://registry.npmjs.org/vue-echarts/-/vue-echarts-5.0.0-beta.0.tgz",
+      "integrity": "sha512-QZFKGXDAYFQo+F20REpzcdLx79nsl4kOorJRpN+08aYq4YiIlmtWss1Lxadm7Fo+NYyWm8nnT+h4xHv3uqWIDQ==",
+      "requires": {
+        "core-js": "^3.4.4",
+        "lodash": "^4.17.15",
+        "resize-detector": "^0.1.10"
+      },
+      "dependencies": {
+        "core-js": {
+          "version": "3.6.5",
+          "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz",
+          "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA=="
+        }
+      }
+    },
     "vue-hot-reload-api": {
       "version": "2.3.4",
       "resolved": "https://registry.npm.taobao.org/vue-hot-reload-api/download/vue-hot-reload-api-2.3.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-hot-reload-api%2Fdownload%2Fvue-hot-reload-api-2.3.4.tgz",
@@ -11999,6 +12028,11 @@
           "dev": true
         }
       }
+    },
+    "zrender": {
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/zrender/-/zrender-4.3.2.tgz",
+      "integrity": "sha512-bIusJLS8c4DkIcdiK+s13HiQ/zjQQVgpNohtd8d94Y2DnJqgM1yjh/jpDb8DoL6hd7r8Awagw8e3qK/oLaWr3g=="
     }
   }
 }

+ 2 - 0
package.json

@@ -12,6 +12,7 @@
   "dependencies": {
     "animate.css": "^4.1.1",
     "axios": "^0.20.0",
+    "echarts": "^4.9.0",
     "element-ui": "^2.13.2",
     "jquery": "^3.5.1",
     "parallax-js": "^3.1.0",
@@ -20,6 +21,7 @@
     "swiper": "^6.2.0",
     "vue": "^2.5.2",
     "vue-awesome-swiper": "^4.1.1",
+    "vue-echarts": "^5.0.0-beta.0",
     "vue-loader-plugin": "^1.3.0",
     "vue-router": "^3.0.1"
   },

+ 266 - 0
src/components/ECharts.vue

@@ -0,0 +1,266 @@
+<template>
+  <div class="echarts" :class="className" />
+</template>
+
+<style>
+.echarts {
+  width: 600px;
+  height: 400px;
+}
+</style>
+
+<script>
+import echarts from 'echarts/lib/echarts'
+import debounce from 'lodash/debounce'
+import { addListener, removeListener } from 'resize-detector'
+const INIT_TRIGGERS = ['theme', 'initOptions', 'autoresize']
+const REWATCH_TRIGGERS = ['manualUpdate', 'watchShallow']
+export default {
+  props: {
+    options: Object,
+    theme: [String, Object],
+    initOptions: Object,
+    group: String,
+    autoresize: Boolean,
+    watchShallow: Boolean,
+    manualUpdate: Boolean,
+    className: String
+  },
+  data () {
+    return {
+      lastArea: 0
+    }
+  },
+  watch: {
+    group (group) {
+      this.chart.group = group
+    }
+  },
+  methods: {
+    // provide an explicit merge option method
+    mergeOptions (options, notMerge, lazyUpdate) {
+      if (this.manualUpdate) {
+        this.manualOptions = options
+      }
+      if (!this.chart) {
+        this.init(options)
+      } else {
+        this.delegateMethod('setOption', options, notMerge, lazyUpdate)
+      }
+    },
+    // just delegates ECharts methods to Vue component
+    // use explicit params to reduce transpiled size for now
+    appendData (params) {
+      this.delegateMethod('appendData', params)
+    },
+    resize (options) {
+      this.delegateMethod('resize', options)
+    },
+    dispatchAction (payload) {
+      this.delegateMethod('dispatchAction', payload)
+    },
+    convertToPixel (finder, value) {
+      return this.delegateMethod('convertToPixel', finder, value)
+    },
+    convertFromPixel (finder, value) {
+      return this.delegateMethod('convertFromPixel', finder, value)
+    },
+    containPixel (finder, value) {
+      return this.delegateMethod('containPixel', finder, value)
+    },
+    showLoading (type, options) {
+      this.delegateMethod('showLoading', type, options)
+    },
+    hideLoading () {
+      this.delegateMethod('hideLoading')
+    },
+    getDataURL (options) {
+      return this.delegateMethod('getDataURL', options)
+    },
+    getConnectedDataURL (options) {
+      return this.delegateMethod('getConnectedDataURL', options)
+    },
+    clear () {
+      this.delegateMethod('clear')
+    },
+    dispose () {
+      this.delegateMethod('dispose')
+    },
+    delegateMethod (name, ...args) {
+      if (!this.chart) {
+        this.init()
+      }
+      return this.chart[name](...args)
+    },
+    delegateGet (methodName) {
+      if (!this.chart) {
+        this.init()
+      }
+      return this.chart[methodName]()
+    },
+    getArea () {
+      return this.$el.offsetWidth * this.$el.offsetHeight
+    },
+    init (options) {
+      if (this.chart) {
+        return
+      }
+      const chart = echarts.init(this.$el, this.theme, this.initOptions)
+      if (this.group) {
+        chart.group = this.group
+      }
+      chart.setOption(options || this.manualOptions || this.options || {}, true)
+      Object.keys(this.$listeners).forEach(event => {
+        const handler = this.$listeners[event]
+        if (event.indexOf('zr:') === 0) {
+          chart.getZr().on(event.slice(3), handler)
+        } else {
+          chart.on(event, handler)
+        }
+      })
+      if (this.autoresize) {
+        this.lastArea = this.getArea()
+        this.__resizeHandler = debounce(
+          () => {
+            if (this.lastArea === 0) {
+              // emulate initial render for initially hidden charts
+              this.mergeOptions({}, true)
+              this.resize()
+              this.mergeOptions(this.options || this.manualOptions || {}, true)
+            } else {
+              this.resize()
+            }
+            this.lastArea = this.getArea()
+          },
+          100,
+          { leading: true }
+        )
+        addListener(this.$el, this.__resizeHandler)
+      }
+      Object.defineProperties(this, {
+        // Only recalculated when accessed from JavaScript.
+        // Won't update DOM on value change because getters
+        // don't depend on reactive values
+        width: {
+          configurable: true,
+          get: () => {
+            return this.delegateGet('getWidth')
+          }
+        },
+        height: {
+          configurable: true,
+          get: () => {
+            return this.delegateGet('getHeight')
+          }
+        },
+        isDisposed: {
+          configurable: true,
+          get: () => {
+            return !!this.delegateGet('isDisposed')
+          }
+        },
+        computedOptions: {
+          configurable: true,
+          get: () => {
+            return this.delegateGet('getOption')
+          }
+        }
+      })
+      this.chart = chart
+    },
+    initOptionsWatcher () {
+      if (this.__unwatchOptions) {
+        this.__unwatchOptions()
+        this.__unwatchOptions = null
+      }
+      if (!this.manualUpdate) {
+        this.__unwatchOptions = this.$watch(
+          'options',
+          (val, oldVal) => {
+            if (!this.chart && val) {
+              this.init()
+            } else {
+              // mutating `options` will lead to merging
+              // replacing it with new reference will lead to not merging
+              // eg.
+              // `this.options = Object.assign({}, this.options, { ... })`
+              // will trigger `this.chart.setOption(val, true)
+              // `this.options.title.text = 'Trends'`
+              // will trigger `this.chart.setOption(val, false)`
+              this.chart.setOption(val, val !== oldVal)
+            }
+          },
+          { deep: !this.watchShallow }
+        )
+      }
+    },
+    destroy () {
+      if (this.autoresize) {
+        removeListener(this.$el, this.__resizeHandler)
+      }
+      this.dispose()
+      this.chart = null
+    },
+    refresh () {
+      if (this.chart) {
+        this.destroy()
+        this.init()
+      }
+    }
+  },
+  created () {
+
+  },
+  mounted () {
+    this.initOptionsWatcher()
+    INIT_TRIGGERS.forEach(prop => {
+      this.$watch(
+        prop,
+        () => {
+          this.refresh()
+        },
+        { deep: true }
+      )
+    })
+    REWATCH_TRIGGERS.forEach(prop => {
+      this.$watch(prop, () => {
+        this.initOptionsWatcher()
+        this.refresh()
+      })
+    })
+    // auto init if `options` is already provided
+    if (this.options) {
+      this.init()
+    }
+  },
+  activated () {
+    if (this.autoresize) {
+      this.chart && this.chart.resize()
+    }
+  },
+  destroyed () {
+    if (this.chart) {
+      this.destroy()
+    }
+  },
+  connect (group) {
+    if (typeof group !== 'string') {
+      group = group.map(chart => chart.chart)
+    }
+    echarts.connect(group)
+  },
+  disconnect (group) {
+    echarts.disConnect(group)
+  },
+  getMap (mapName) {
+    return echarts.getMap(mapName)
+  },
+  registerMap (mapName, geoJSON, specialAreas) {
+    echarts.registerMap(mapName, geoJSON, specialAreas)
+  },
+  registerTheme (name, theme) {
+    echarts.registerTheme(name, theme)
+  },
+  graphic: echarts.graphic
+}
+</script>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
src/components/china.json


BIN
src/components/lifecycle/images/a1.png


BIN
src/components/lifecycle/images/a2.png


BIN
src/components/lifecycle/images/a3.png


BIN
src/components/lifecycle/images/a4.png


BIN
src/components/lifecycle/images/a5.png


BIN
src/components/lifecycle/images/a6.png


+ 29 - 6
src/components/lifecycle/index.vue

@@ -1,13 +1,21 @@
 <template>
   <div class="container width1200">
     <div class="content">
-      <img src="../../assets/images/arrow.png"/>
+      <!-- <img src="../../assets/images/arrow.png"/> -->
       <div class="items">
         <img
           class="animate__animated animate__fadeInDown"
           :src="require(`./images/${index + 1}.png`)"
           v-for="(item, index) in items" :key="index"
-          :style="{top: item[0] + 'px', left: item[1] + 'px', 'animation-delay': (!inited ? (index * 0.3) + 's' : '0s')}"
+          :style="{top: item[0] + 'px', left: item[1] + 'px', 'animation-delay': (!inited ? index * 0.3 + 's' : '0s')}"
+        />
+      </div>
+      <div class="lines">
+        <img
+          class="animate__animated animate__fadeInDown"
+          :src="require(`./images/a${index + 1}.png`)"
+          v-for="(item, index) in lines" :key="index"
+          :style="{top: item[0] + 'px', left: item[1] + 'px', 'animation-delay': (index + 1) * 0.3 + 's'}"
         />
       </div>
     </div>
@@ -15,18 +23,27 @@
 </template>
 <script>
 const items = [
-  [80, -120, false],
+  [80, -115, false],
   [-50, 130, false],
   [-50, 400, false],
   [80, 620, false],
   [240, 400, false],
   [240, 130, false],
 ]
+const lines = [
+  [20, -5],
+  [-25, 265],
+  [5, 520],
+  [190, 520],
+  [285, 275],
+  [220, 20],
+]
 export default {
   name: 'lifecycle',
   data() {
     return {
       items,
+      lines,
       inited: false,
     }
   },
@@ -69,6 +86,14 @@ export default {
         max-width: 100%;
       }
       .items{
+        >img{
+          &:hover{
+            margin-top: -10px;
+          }
+        }
+      }
+      .items,
+      .lines{
         width: 100%;
         position: absolute;
         top: 0;
@@ -77,9 +102,7 @@ export default {
           width: 120px;
           position: absolute;
           transition: all .3s ease-in-out;
-          &:hover{
-            margin-top: -10px;
-          }
+          display: inline-block;
         }
       }
     }

+ 168 - 0
src/components/map copy.vue

@@ -0,0 +1,168 @@
+<template>
+  <div class="viewmap">
+    <img src="../assets/images/map.png"/>
+    <svg class="lines" width="895" height="632">
+      <line
+        v-for="(item, index) in links"
+        :key="index"
+        :x2="item[0]"
+        :y2="item[1]"
+        x1="630"
+        y1="288"
+        stroke="rgba(45, 199, 170, 0.5)"
+        stroke-width="2"
+      />
+    </svg>
+    <div class="icon">
+      <div class="dot"></div>
+      <div class="pluse"></div>
+      <div class="pluse-big"></div>
+    </div>
+  </div>
+</template>
+<script>
+const links = [
+  [185, 275],
+  [485, 350],
+  [770, 235],
+  [785, 155],
+  [725, 270],
+  [522, 573],
+  [676, 498],
+  [335, 375],
+  [432, 470],
+  [405, 575],
+  [612, 510],
+  [185, 440],
+  [497, 528],
+]
+export default {
+  name: 'viewmap',
+  data() {
+    return {
+      links,
+      start: [190, 440]
+    }
+  }
+}
+</script>
+<style lang="less" scoped>
+  .viewmap{
+    width: 895px;
+    margin: auto;
+    margin-top: 20px;
+    position: relative;
+    img{
+      max-width: 100%;
+    }
+    .lines{
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+    }
+    .line{
+      position: absolute;
+    }
+    .icon{
+      position: absolute;
+      z-index: 999;
+      width: 26px;
+      height: 26px;
+      top: 275px;
+      left: 615px;
+      .dot{
+        position: absolute;
+        width: 8px;
+        height: 8px;
+        left: 9px;
+        top: 9px;
+        border-radius: 50%;
+        background: rgba(45, 199, 170, 0.7);
+        animation: shink 1.4s ease-out infinite;
+      }
+      .pluse{
+        position: absolute;
+        width: 26px;
+        height: 26px;
+        border: 2px solid #09f;
+        border-radius: 50%;
+        z-index: 100;
+        opacity: 0;
+        background: rgba(45, 199, 170, 0.6);
+        animation: warn 1.4s ease-out;
+        animation-iteration-count: infinite;
+        box-shadow: 1px 1px 30px rgba(45, 199, 170, 1);
+      }
+      .pluse-big{
+        position: absolute;
+        width: 20px;
+        height: 20px;
+        border: 2px solid #09f;
+        border-radius: 50%;
+        z-index: 100;
+        opacity: 0;
+        background: rgba(45, 199, 170, 0.6);
+        animation: warn1 1.4s ease-out;
+        animation-iteration-count: infinite;
+        box-shadow: 1px 1px 30px #EF2D02;
+      }
+    }
+    @keyframes warn{
+        0% {
+            -moz-transform: scale(0);
+            -webkit-transform: scale(0);
+            transform: scale(0);
+            opacity: 1;
+        }
+        100% {
+            -moz-transform: scale(1);
+            -webkit-transform: scale(1);
+            transform: scale(1);
+            opacity: 0;
+        }
+    }
+    @-webkit-keyframes warn{
+        0% {
+            -moz-transform: scale(0);
+            -webkit-transform: scale(0);
+            transform: scale(0);
+            opacity: 1;
+        }
+        100% {
+            -moz-transform: scale(1);
+            -webkit-transform: scale(1);
+            transform: scale(1);
+            opacity: 0;
+        }
+    }
+    @keyframes shink{
+        0% {
+            opacity: 0;
+            transform: scale(0.5);
+        }
+        100% {
+            opacity: 1;
+            transform: scale(1);
+        }
+    }
+  }
+  line {
+    stroke-dashoffset: 0;
+    animation: dash 4s;
+  }
+
+  @keyframes dash {
+    0% {
+      stroke-dashoffset: 0;
+    }
+    1% {
+      stroke-dasharray: 800;
+      stroke-dashoffset: 800;
+    }
+    100% {
+      stroke-dashoffset: 0;
+    }
+  }
+</style>

+ 249 - 0
src/components/map-data.js

@@ -0,0 +1,249 @@
+const geoCoordMap = {
+  '甘肃': [103.73, 36.03],
+  '青海': [101.74, 36.56],
+  '四川': [104.06, 30.67],
+  '河北': [114.48, 38.03],
+  '云南': [102.73, 25.04],
+  '贵州': [106.71, 26.57],
+  '湖北': [114.31, 30.52],
+  '河南': [113.65, 34.76],
+  '山东': [117, 36.65],
+  '江苏': [118.78, 32.04],
+  '安徽': [117.27, 31.86],
+  '浙江': [120.19, 30.26],
+  '江西': [115.89, 28.68],
+  '福建': [119.3, 26.08],
+  '广东': [113.23, 23.16],
+  '湖南': [113, 28.21],
+  '海南': [110.35, 20.02],
+  '辽宁': [123.38, 41.8],
+  '吉林': [125.35, 43.88],
+  '黑龙江': [126.63, 45.75],
+  '山西': [112.53, 37.87],
+  '陕西': [108.95, 34.27],
+  '台湾': [121.30, 25.03],
+  '北京': [116.46, 39.92],
+  '上海': [121.48, 31.22],
+  '重庆': [106.54, 29.59],
+  '天津': [117.2, 39.13],
+  '内蒙古': [111.65, 40.82],
+  '广西': [108.33, 22.84],
+  '西藏': [91.11, 29.97],
+  '宁夏': [106.27, 38.47],
+  '新疆': [87.68, 43.77],
+  '香港': [114.17, 22.28],
+  '澳门': [113.54, 22.19]
+}
+
+function convertData(data) {
+  const res = []
+  for (let i = 0; i < data.length; i++) {
+    const geoCoord = geoCoordMap[data[i].name]
+    if (geoCoord) {
+      res.push({
+        name: data[i].name,
+        value: geoCoord.concat(data[i].value)
+      })
+    }
+  }
+  return res
+}
+
+let convert = (data) => {
+  let res = [];
+  for (var i = 0; i < data.length; i++) {
+    var dataItem = data[i];
+    var from = geoCoordMap[dataItem[0].name];
+    var to = geoCoordMap[dataItem[1].name];
+    if (from && to) {
+      res.push({
+        fromName: dataItem[0].name,
+        toName: dataItem[1].name,
+        coords: [from, to]
+      });
+    }
+  }
+
+  return res;
+}
+
+const randomData = () => {
+  return Math.round(Math.random() * 1000)
+}
+
+const getItemStyle = (opacity) => {
+  return {
+    normal: {
+      areaColor: '#96CFC6',
+      borderColor: '#fff',
+      borderWidth: 0.5,
+      show: false,
+      opacity,
+    },
+    emphasis: {
+      areaColor: '#96CFC6',
+      opacity: 1,
+    }
+  }
+}
+
+const areas = [
+  { name: '北京', value: randomData(), itemStyle: getItemStyle(.5) },
+  { name: '天津', value: randomData(), itemStyle: getItemStyle(.8) },
+  { name: '上海', value: randomData(), itemStyle: getItemStyle(.4) },
+  { name: '重庆', value: randomData(), itemStyle: getItemStyle(.3) },
+  { name: '河北', value: randomData(), itemStyle: getItemStyle(.3) },
+  { name: '河南', value: randomData(), itemStyle: getItemStyle(.2) },
+  { name: '云南', value: randomData(), itemStyle: getItemStyle(.6) },
+  { name: '辽宁', value: randomData(), itemStyle: getItemStyle(.5) },
+  { name: '黑龙江', value: randomData(), itemStyle: getItemStyle(.8) },
+  { name: '湖南', value: randomData(), itemStyle: getItemStyle(.6) },
+  { name: '安徽', value: randomData(), itemStyle: getItemStyle(.7) },
+  { name: '山东', value: randomData(), itemStyle: getItemStyle(.4) },
+  { name: '新疆', value: randomData(), itemStyle: getItemStyle(4) },
+  { name: '江苏', value: randomData(), itemStyle: getItemStyle(.6) },
+  { name: '浙江', value: randomData(), itemStyle: getItemStyle(.8) },
+  { name: '江西', value: randomData(), itemStyle: getItemStyle(.5) },
+  { name: '湖北', value: randomData(), itemStyle: getItemStyle(.9) },
+  { name: '广西', value: randomData(), itemStyle: getItemStyle(.3) },
+  { name: '甘肃', value: randomData(), itemStyle: getItemStyle(.5) },
+  { name: '山西', value: randomData(), itemStyle: getItemStyle(.3) },
+  { name: '内蒙古', value: randomData(), itemStyle: getItemStyle(.6) },
+  { name: '陕西', value: randomData(), itemStyle: getItemStyle(.4) },
+  { name: '吉林', value: randomData(), itemStyle: getItemStyle(.6) },
+  { name: '福建', value: randomData(), itemStyle: getItemStyle(.7) },
+  { name: '贵州', value: randomData(), itemStyle: getItemStyle(.8) },
+  { name: '广东', value: randomData, itemStyle: getItemStyle(.3) },
+  { name: '青海', value: randomData, itemStyle: getItemStyle(.6) },
+  { name: '西藏', value: randomData, itemStyle: getItemStyle(.4) },
+  { name: '四川', value: randomData, itemStyle: getItemStyle(.7) },
+  { name: '宁夏', value: randomData, itemStyle: getItemStyle(.5) },
+  { name: '海南', value: randomData, itemStyle: getItemStyle(.5) },
+  { name: '台湾', value: randomData, itemStyle: getItemStyle(.4) },
+  { name: '香港', value: randomData, itemStyle: getItemStyle(.2) },
+  { name: '澳门', value: randomData, itemStyle: getItemStyle(.6) },
+  { name: '南海诸岛', value: randomData, itemStyle: getItemStyle(1) },
+]
+
+const formatLines = (name = '北京') => {
+  return areas.map(item => ([{ name }, { name: item.name, value: 100 }]))
+}
+
+export default activeName => ({
+  tooltip: {
+    show: false,
+  },
+  geo: {
+    map: 'china',
+    label: {
+      normal: {
+        show: false
+      },
+      emphasis: {
+        show: false
+      }
+    },
+    itemStyle: {
+      normal: {
+        areaColor: '#96CFC6',
+        borderColor: '#fff',
+        opacity: 0,
+      },
+      emphasis: {
+        areaColor: '#96CFC6',
+        opacity: 0,
+      }
+    },
+    regions: [{
+      value: 0,
+      itemStyle: {
+        normal: {
+          opacity: 0,
+        }
+      },
+      emphasis: {
+        itemStyle: {
+          areaColor: '#96CFC6',
+          opacity: 0,
+        }
+      }
+    }],
+  },
+  series: [
+    {
+      type: 'lines',
+      zlevel: 1,
+      symbol: ['none'],
+      symbolSize: 10,
+      animationDuration: 2500,
+      animationDurationUpdate: 1000,
+      lineStyle: {
+        normal: {
+          color: '#96CFC6',
+          width: 2,
+          opacity: 0.6,
+          curveness: 0.05
+        }
+      },
+      data: convert(formatLines(activeName))
+    },
+    {
+      type: 'map',
+      coordinateSystem: 'geo',
+      geoIndex: 1,
+      mapType: 'china',
+      showLegendSymbol: false,
+      showEffectOn: 'render',
+      rippleEffect: {
+        brushType: 'stroke'
+      },
+      roam: false,
+      label: {
+        normal: {
+          show: false,
+          areaColor: '#96CFC6',
+          color: '#808080',
+        },
+        emphasis: {
+          areaColor: '#96CFC6',
+          opacity: 1,
+          show: false
+        }
+      },
+      regions: [{
+        value: 0,
+        itemStyle: {
+          normal: {
+            opacity: 0,
+          }
+        },
+      }],
+      data: areas,
+    },
+    {
+      type: 'effectScatter',
+      coordinateSystem: 'geo',
+      data: convertData(areas),
+      symbolSize: 5,
+      showEffectOn: 'render',
+      rippleEffect: {
+        brushType: 'stroke'
+      },
+      hoverAnimation: true,
+      label: {
+        normal: {
+          formatter: '{b}',
+          position: 'left',
+          show: true,
+          color: '#808080',
+        }
+      },
+      itemStyle: {
+        normal: {
+          color: '#52C88D',
+        }
+      },
+      zlevel: 9
+    }
+  ]
+})

+ 55 - 5
src/components/map.vue

@@ -1,6 +1,13 @@
 <template>
   <div class="viewmap">
-    <img src="../assets/images/map.png"/>
+    <chart
+      :options="map"
+      :init-options="initOptions"
+      ref="map"
+      autoresize
+      className="chart"
+    />
+    <!-- <img src="../assets/images/map.png"/>
     <svg class="lines" width="895" height="632">
       <line
         v-for="(item, index) in links"
@@ -17,10 +24,20 @@
       <div class="dot"></div>
       <div class="pluse"></div>
       <div class="pluse-big"></div>
-    </div>
+    </div> -->
   </div>
 </template>
 <script>
+import ECharts from './ECharts.vue'
+import 'echarts/lib/component/geo'
+import 'echarts/lib/chart/map'
+import 'echarts/map/js/china'
+
+import china from './china.json'
+import mapOption from './map-data'
+
+// ECharts.registerMap('china', china)
+
 const links = [
   [185, 275],
   [485, 350],
@@ -38,20 +55,53 @@ const links = [
 ]
 export default {
   name: 'viewmap',
+  components: {
+    chart: ECharts
+  },
   data() {
     return {
+      activeName: '北京',
       links,
-      start: [190, 440]
+      start: [190, 440],
+      initOptions: {
+        renderer: 'canvas'
+      },
     }
-  }
+  },
+  computed: {
+    map() {
+      const { map } = this.$refs
+      const option = mapOption(this.activeName)
+      if (map && map.chart) {
+        map.chart.clear()
+        map.chart.setOption(option)
+      }
+      return option
+    }
+  },
+  mounted() {
+    const { map } = this.$refs
+    if (map && map.chart) {
+      map.chart.on('click', evt => {
+        console.log(evt)
+        if (evt.name && evt.name !== '南海诸岛') {
+          this.activeName = evt.name
+        }
+      })
+    }
+  },
 }
 </script>
 <style lang="less" scoped>
   .viewmap{
     width: 895px;
     margin: auto;
-    margin-top: 20px;
+    margin-top: -20px;
     position: relative;
+    .chart{
+      width: 100%;
+      height: 750px;
+    }
     img{
       max-width: 100%;
     }

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác