inocan-group / vue3-google-map

A set of composable components for easy use of Google Maps in your Vue 3 projects.
https://vue3-google-map.com
MIT License
272 stars 54 forks source link

Polygon options not reactive #117

Closed JamesArthurHolland closed 1 year ago

JamesArthurHolland commented 1 year ago

I'm trying to change the fillColor of a polygon on mouseover. The polygon changes fillColor but it doesn't seem to react to the change.

I'm new to Vue3, I used Vue 1 or 2 a few years back so it's maybe something noobish.

<template>
  <div class="hello">
    <GoogleMap api-key="MY_KEY" style="width: 100%; height: 500px" :center="center" :zoom="7">
      <Polygon @mouseover="mouseover(polygon)" @mouseout="mouseout(polygon)" v-for="(polygon, index) in polygonData" :key="index" :options="polygon" />
    </GoogleMap>
  </div>
</template>

<script>
import { GoogleMap, Polygon } from "vue3-google-map";
import json from '@/assets/myjson.json';

export default {
  name: 'HelloWorld',
  components: { GoogleMap, Polygon },
  props: {
    msg: String
  },
  setup() {
    const center = {lat: 55.8642, lng: -4.2518};

    let polygonData = [];
    json.forEach(district => {
        // TODO null geometry like district AB44
      if (district.paths != null) {
        district.paths.forEach(pathsItem => {
          polygonData.push({
            paths: pathsItem,
            strokeColor: "#FFFFFF",
            strokeOpacity: 0.8,
            strokeWeight: 0.5,
            fillColor: "#004b84",
            fillOpacity: 0.55,
          })
        })
      }
    })

    const mouseover = function (polygon) {
      console.log("mouseover")
      console.log(polygon)
      polygon.fillColor = "#FF0000"
    }

    const mouseout = function (polygon) {
      console.log("moustout")
      console.log(polygon)
    }

    console.log(polygonData);

    return {center, polygonData, mouseover, mouseout};
  },
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>
JoseGoncalves commented 1 year ago

In the current implementation, component options are not deep watched, so you will need to change the options object to trigger the reactivity. See also https://github.com/inocan-group/vue3-google-map/issues/73#issuecomment-1132339279

JamesArthurHolland commented 1 year ago

Can you explain this to me really simply?

I'm from a backend/devops background. I can't even explain scope in js to another person.

JoseGoncalves commented 1 year ago

You need to change the polygon object that has the attributes for the Polygon, instead of changing a property on that object (like fillColor), which will not work.

The following example should get you kickstarted:

<template>
    <GoogleMap
      id="map"
      :api-key="map.key"
      :center="map.center"
      :zoom="map.zoom"
    >
        <Polygon
          :options="polygon"
          @mouseover="onPolygonMouseover"
          @mouseout="onPolygonMouseout"
        />
    </GoogleMap>
</template>

<script setup>
import { ref } from 'vue';
import { GoogleMap, Polygon } from 'vue3-google-map';

const map = {
    key: '', // Place a Google API Key here
    center: {
        lat: 24.886,
        lng: -70.268
    },
    zoom: 5
};

const triangleCoords = [
    { lat: 25.774, lng: -80.19 },
    { lat: 18.466, lng: -66.118 },
    { lat: 32.321, lng: -64.757 }
];

const bermudaTriangle = {
    paths: triangleCoords,
    strokeColor: '#FFFFFF',
    strokeOpacity: 0.8,
    strokeWeight: 2,
    fillColor: '#FF0000',
    fillOpacity: 0.35
};

const polygon = ref(bermudaTriangle);

function onPolygonMouseover() {
    polygon.value = {
        ...bermudaTriangle,
        fillColor: '#00FF00'
    };
}

function onPolygonMouseout() {
    polygon.value = {
        ...bermudaTriangle,
        fillColor: '#0000FF'
    };
}
</script>

<style>
html,
body,
#app,
#map {
    height: 100%;
}

body {
    margin: 0;
}
</style>
JamesArthurHolland commented 1 year ago

Thanks for the help.

That "ref()" is new to me.

For anyone else doing something similar, this works:

const center = {lat: 55.8642, lng: -4.2518};

    let polygonData = [];

    const polygon = {
      paths: [],
      strokeColor: "#FFFFFF",
      strokeOpacity: 0.8,
      strokeWeight: 0.5,
      fillColor: "#004b84",
      fillOpacity: 0.55,
    }

    json.forEach(district => {
        // TODO null geometry like district AB44
      if (district.paths != null) {
        district.paths.forEach(pathsItem => {

          polygonData.push(ref({
            ...polygon,
            paths: pathsItem
          }))
        })
      }
    })

    const mouseover = function (index) {
      polygonData[index].value = {
        ...polygonData[index],
        fillOpacity: 0.8
      }
    }

    const mouseout = function (index) {
      polygonData[index].value = {
        ...polygonData[index],
        fillOpacity: 0.55
      }
    }

    return {center, polygonData, mouseover, mouseout};