plainheart / echarts-extension-gmap

🌎 A Google Map (https://www.google.com/maps) extension for Apache ECharts (https://github.com/apache/echarts)
https://github.com/plainheart/echarts-extension-gmap
MIT License
48 stars 8 forks source link

Can this extension implement polygons and polylines on Google Map? #3

Closed JasonLaux closed 3 years ago

JasonLaux commented 3 years ago

Also how to add an api key when using webpack? Thank you!

plainheart commented 3 years ago

Can this extension implement polygons and polylines on Google Map?

Yes, you can refer to the official example about Baidu Map.

Also how to add an api key when using webpack?

You can add a script to your HTML template or use a google-map-loader in your js code. For example, https://github.com/davidkudera/google-maps-loader.

Or wrap simply a script loader like this.

const mapScriptURL = 'https://maps.googleapis.com/maps/api/js?key=your api key from google map platform'

function isGoogleMapAPILoaded() {
    return typeof google !== 'undefined' && typeof google.maps !== 'undefined'
}

function loadGoogleMapScript() {
    return new Promise((resolve, reject) => {
      // if google map API script has loaded, no need to insert it again
      if (isGoogleMapAPILoaded()) {
        resolve(google)
      } else {
        const scriptNode = document.createElement('script')
        scriptNode.setAttribute('type', 'text/javascript')
        scriptNode.setAttribute('charset', 'utf-8')
        scriptNode.setAttribute('src', mapScriptURL)
        scriptNode.setAttribute('id', 'google-map-api-script')
        scriptNode.onload = () => {
          if (isGoogleMapAPILoaded()) {
            resolve(google)
          } else {
            reject('failed to load google map API script')
          }
        }
        scriptNode.onerror = e => {
          reject(e)
        }
        // check again before inserting script
        if (isGoogleMapAPILoaded()) {
          resolve(google)
        } else {
          document.head.appendChild(scriptNode)
        }
      }
    })
}

Then you can use the loader in your code,

loadGoogleMapScript().then(google => {
   console.log('google map script loaded', google)
   // to create echarts instance and get google map instance
   const chart = echarts.init(document.getElementById('chart-container'));
   chart.setOption(option);
   // get google map instance
   const gmap = chart.getModel().getComponent('gmap').getGoogleMap();
   // to add a marker
   const marker = new google.maps.Marker({ position: gmap.getCenter() });
   marker.setMap(gmap);
})
JasonLaux commented 3 years ago

Thanks! I'm really appreciated. Currently I'm using your extension under vue-echarts environment. I loaded the map correctly but it failed to display scatter chart on the map using your demo code. Also when I add another tooltip component, the map is just crashed which I don't know why.

plainheart commented 3 years ago

Could I know if you are assigning the ECharts instance object with Vue ref? If so, I'd like to suggest using a normal variable without any wrapper.

let chart;
chart = echarts.init(document.getElementById('chart-container'));
JasonLaux commented 3 years ago

No I didn't use ref. It's just <v-chart :option="this.option"></v-chart>. All components and series can be set in option.

plainheart commented 3 years ago

I tried the example from vue-echarts, it works.

<template>
  <v-chart class="chart" :option="option" />
</template>

<script>
import { use } from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { ScatterChart } from "echarts/charts";
import {
  TitleComponent,
  TooltipComponent
} from "echarts/components";
// import google map extension
import "echarts-extension-gmap";
import VChart from "vue-echarts";
import { ref, defineComponent, onMounted } from "vue";

use([
  CanvasRenderer,
  ScatterChart,
  TitleComponent,
  TooltipComponent
]);

function isGoogleMapAPILoaded() {
    return typeof google !== 'undefined' && typeof google.maps !== 'undefined'
}

function loadGoogleMapScript() {
    const mapScriptURL = 'https://maps.googleapis.com/maps/api/js?key=you key';
    return new Promise((resolve, reject) => {
      // if google map API script has loaded, no need to insert it again
      if (isGoogleMapAPILoaded()) {
        resolve()
      } else {
        const scriptNode = document.createElement('script')
        scriptNode.setAttribute('type', 'text/javascript')
        scriptNode.setAttribute('charset', 'utf-8')
        scriptNode.setAttribute('src', mapScriptURL)
        scriptNode.setAttribute('id', 'google-map-api-script')
        scriptNode.onload = () => {
          if (isGoogleMapAPILoaded()) {
            resolve()
          } else {
            reject('failed to load google map API script')
          }
        }
        scriptNode.onerror = e => {
          reject(e)
        }
        // check again before inserting script
        if (isGoogleMapAPILoaded()) {
          resolve()
        } else {
          document.head.appendChild(scriptNode)
        }
      }
    })
}

export default defineComponent({
  name: "HelloWorld",
  components: {
    VChart
  },
  setup: () => {
    const option = ref();

    onMounted(async () => {
      // load api
      await loadGoogleMapScript()

      option.value = {
        title: {
          text: "Traffic Sources",
          left: "center"
        },
        tooltip: {
          trigger: "item"
        },
        legend: {
          orient: "vertical",
          left: "left",
          data: ["Direct", "Email", "Ad Networks", "Video Ads", "Search Engines"]
        },
        gmap: {
          center: [108.39, 39.9],
          zoom: 4
        },
        series: [
          {
            name: "Scatter",
            type: "scatter",
            coordinateSystem: "gmap",
            data: [
              [120, 30, 50]
            ],
            encode: {
              value: 2
            }
          }
        ]
      }
    })

    return { option };
  }
});
</script>

<style scoped>
.chart {
  height: 100vh;
}
</style>

<style>
body {
  margin: 0;
}
</style>
JasonLaux commented 3 years ago

Actually I use Vue2 and just tag script in index.html to get permission like this: <script async src="https://maps.googleapis.com/maps/api/js?key=..."> </script> Also I think I didn't define the async vue component like you do. Is that the potential reason?

JasonLaux commented 3 years ago

I think I found where is wrong. Map needs to be specified height, that is: <v-chart class="chart" :option="option" /> <style scoped> .chart { height: 100vh; } </style> Otherwise scatter or other overlays won't be displayed.

plainheart commented 3 years ago

That's great. Glad to see your problem solved.