GuillaumeLeclerc / vue-google-maps

Google maps component for vue with 2-way data binding
560 stars 653 forks source link

Open infowindow on polyline #150

Open Mar10n opened 3 years ago

Mar10n commented 3 years ago

I'm trying to open an infowindow on the polylines position, i've tried to open it on the mouse position but it opens in the middle of the polyline shape.

Here's my code:

Vue

<template>
  <div class="ilfind__map">
    <!-- <div class="ilfind__map-buttons">
        <button
            v-show="locations.length > 1"
            @click="searchOpen = !searchOpen;categoriesOpen = false;search = ''"
        >Søg</button>
        v-show="searchOpen"
    </div> -->
    <div class="ilfind__map-search">
      <div class="ilfind__map-search-input">
                <!-- Søgefelt som binder sig til funktionen search via v-model  -->
        <input type="search" placeholder="Søg" v-model="search">
      </div>
            <!-- Div som indeholder alle søge resultater, vises kun hvis der er nogle -->
      <div class="ilfind__map-search-results" v-show="searchResults.length > 0">
                <!-- Looper igennem alle søgeresultater -->
        <a
          v-for="result in searchResults"
          :key="result.ID"
          :href="result.permalink"
        >{{result.coordinate_sets[0].texts.danish.title}}</a>
      </div>
    </div>

        <!-- Viser menu hvor man kan vælge sprog -->
    <div
      class="ilfind__map-choose-language"
      v-show="showLanguageChooser"
    >
      <h2>Vælg ønsket sprog</h2>
      <div>
                <!-- Looper over de sprog man kan vælge imellem og viser dem -->
        <div
          class="ilfind__map-choose-language-button"
          v-for="(languageName, languageIndex) in languages"
          :key="languageIndex"
          @click="chooseLangauge(languageIndex)"
        >
                    <!-- Billedet er binded til alle flag som tilhøre de sprog man kan vælge imellem -->
          <img :src="languageImage(languageIndex)" :alt="languageName">
        </div>
      </div>
    </div>

        <!-- Viser nuværende sprog -->
    <div
      v-show="language"
      class="ilfind__map-current-language"
      @click="showLanguageChooser = !showLanguageChooser"
    >
      <img :src="languageImage(language)" :alt="language">
    </div>

    <GmapMap ref="map" :center="center" :zoom="zoom" map-type-id="hybrid">

            <!-- Laver info vindue som vises når man klikker på en lokation, den modtager objekterne infoOptions, infoWindowPos og infoWinOpen. Viser infoContent som html -->
      <GmapInfoWindow
        :options="infoOptions"
        :position="infoWindowPos"
        :opened="infoWinOpen"
        @closeclick="infoWinOpen=false">

        <div v-html="infoContent"></div>
      </GmapInfoWindow>
            <!-- Looper over alle lokationer som brugeren gerne vil se -->
      <span v-for="(location, index) in filteredLocations" :key="index">
        <span
          v-for="(coordinate_set, coordinate_set_index) in location.coordinate_sets"
          :key="coordinate_set_index"
        >
          <div>{{ coordinate_set }}</div>
                    <!-- Looper over alle markøre og placerer dem på kortet, og bliver binded til de tilhørende ikoner -->
          <GmapMarker
            v-for="(marker, marker_index) in coordinate_set.drawings.markers"
            :key="index + '_' + coordinate_set_index + '_marker_' + marker_index"
            :position="marker"
            @click="toggleInfoWindowNy(marker, index, coordinate_set_index, '_marker_'+ marker_index)"
            :icon="{url: changeMarkerIcon(location.categories.map(category => category.name)), scaledSize:{width: 50,height: 50}}"
          ></GmapMarker>

                    <!-- Looper over alle polygoner og placerer dem på kortet -->
          <GmapPolygon
            v-for="(polygon, polygon_index) in coordinate_set.drawings.polygons"
            :key="index + '_' + coordinate_set_index + '_polygon_' + polygon_index"
            :paths="polygon"
            @click="toggleInfoWindow($event, index, coordinate_set_index, '_polygon_'+ marker_index)"
            :options="strokeOptions(coordinate_set.drawings_options.polygons[polygon_index].color)"
          ></GmapPolygon>
                    <!-- Looper over alle cirkler og placerer dem på kortet -->
          <GmapCircle
            v-for="(circle, circle_index) in coordinate_set.drawings.circles"
            :key="index + '_' + coordinate_set_index + '_circle_' + circle_index"
            :radius="circle.radius"
            :center="circle.center"
            @click="toggleInfoWindow($event, index, coordinate_set_index, '_circle_'+ marker_index)"
            :options="strokeOptions(coordinate_set.drawings_options.circles[circle_index].color)"
          ></GmapCircle>
                    <!-- Looper over alle polylines (stier) og placerer dem på kortet -->
          <GmapPolyline
            v-for="(polyline, polyline_index) in coordinate_set.drawings.polylines"
            :key="index + '_' + coordinate_set_index + '_polyline_' + polyline_index"
            :path="polyline"
            @click="toggleInfoWindowPolyline($event, polyline, index, coordinate_set_index, '_polyline_'+ index)"
            :options="strokeOptions(coordinate_set.drawings_options.polylines[polyline_index].color)"
          ></GmapPolyline>

                    <!-- Looper over alle rektangler på placerer dem på kortet -->
          <GmapRectangle
            v-for="(rectangle, rectangle_index) in coordinate_set.drawings.rectangles"
            :key="index + '_' + coordinate_set_index + '_rectangle_' + rectangle_index"
            :bounds="rectangle"
            @click="toggleInfoWindow($event, index, coordinate_set_index, '_rectangle_'+ marker_index)"
            :options="strokeOptions(coordinate_set.drawings_options.rectangles[rectangle_index].color )"
          ></GmapRectangle>
        </span>
      </span>
    </GmapMap>
    <div class="ilfind__map-infowindow">
      <h2 class="catH2">Kategorier</h2>
      <div class="flex">
                <!-- Looper over alle kategorier -->
        <div
        class="catList"
        v-for="category in categories"
        :key="category.term_id"
      >
                <!-- Viser alle kategorier med tilhørende markør og checkbox så man kan vælge / fravælge kategorier -->
        <label :form="`category${category.term_id}`">
          <input class="checkbox"
            type="checkbox"
            :id="`category${category.term_id}`"
            :value="category.term_id"
            v-model="selectedCategories"
          >
          <img class="markerCheck" :src="'../wp-content/plugins/ilfind-master/icon/icons/nyny/' + category.name.toLowerCase().replace('/', '-') + '.svg'" alt="">
          {{ category.name }}
        </label>
      </div>
      </div>
    </div>
  </div>
</template>
Mar10n commented 3 years ago

JS

`import Cookies from 'js-cookie'; export default { props: { rawLocations: String, rawLanguages: String, },

//Definere objekter data() { return { infoOptions: { pixelOffset: { width: 0, height: -35 } }, infoWindowPos: { lat: 57.20411639117025, lng: 10.494128107678389 }, currentMidx: null, selectedCategories: [], searchOpen: false, infoWinOpen: false, infoContent: { title: null, content: null, permalink: null, image: null, }, currentKeyDisplaying: null, map: null, search: "", searchResults: [], language: '', showLanguageChooser: false, isActive: {}, }; },

//Mehtods er statiske funktioner som reagere på event fra DOM methods: { // getMousePosition() { // var x = clientX; // var y = clientY; // console.log(x + y); // },

toggleInfoWindow(event, location_index, coordinate_set_index, index) {
  const key = location_index + "_" + coordinate_set_index + index;

  this.infoContent = {
    title: this.locations[location_index].coordinate_sets[coordinate_set_index].texts[this.language].title,
    content: this.locations[location_index].coordinate_sets[coordinate_set_index].texts[this.language].content,
    permalink: this.locations[location_index].permalink
        };
         infoWindow.setContent(
        JSON.stringify(mapsMouseEvent.latLng.toJSON(), null, 2)
        );

  if (this.currentKeyDisplaying == key) {
    this.infoWinOpen = !this.infoWinOpen;
  } else {
    this.infoWinOpen = true;
    this.currentKeyDisplaying = key;
  }
},

toggleInfoWindowNy(marker, location_index, coordinate_set_index, index){
  const key = location_index + "_" + coordinate_set_index + index;

  //console.dir(marker);                                       // ???
  //alert('marker lat: '+marker.lat);                          // marker: [object Object]
  //alert('marker lng: '+marker.lng);                          // marker: [object Object]
  //alert('location_index: '+location_index);                  // location_index: 21
  //alert('coordinate_set_index: '+coordinate_set_index);      // coordinate_set_index: 0
  //alert('index: '+index);                                    // index: _master_0
  //alert('location: '+location);                              // location: URL

  this.infoWindowPos = {
    lat: marker.lat,
    lng: marker.lng
  }

  this.infoContent = this.getInfoWindowContent(location_index, coordinate_set_index);

  //check if its the same marker that was selected if yes toggle
  if (this.currentMidx == key) {
    this.infoWinOpen = !this.infoWinOpen;
  }
  //if different marker set infowindow to open and reset current marker index
  else {
    this.infoWinOpen = true;
    this.currentMidx = key;
  }
},

toggleInfoWindowPolyline(event, polyline, location_index, coordinate_set_index, index) {
  const key = location_index + "_" + coordinate_set_index + index;
  this.infoWindowPos = {
   lat: parseInt(event.clientX),
   lng: parseInt(event.clientY)
  }

  this.infoContent = this.getInfoWindowContent(location_index, coordinate_set_index);

     if (this.currentKeyDisplaying == key) {
    this.infoWinOpen = !this.infoWinOpen;
  } else {
    this.infoWinOpen = true;
    this.currentKeyDisplaying = key;
  }
},

getInfoWindowContent: function (location_index, coordinate_set_index) {

  this.infoContent = {
    title: this.locations[location_index].coordinate_sets[coordinate_set_index].texts[this.language].title,
    content: this.locations[location_index].coordinate_sets[coordinate_set_index].texts[this.language].content,
    permalink: this.locations[location_index].permalink,
    image: this.locations[location_index].image,
  };
  if (this.infoContent.image != false) {
    return(`
      <div class="card">
      <div class="card-image"><img src="${this.infoContent.image}"></div>
       <div class="card-content">
       <div class="media">
       <div class="media-content">
       <p class="title is-4">${this.infoContent.title}</p>
       </div>
      </div>

  <div class="content">
  ${this.infoContent.content}
  <a href="${this.infoContent.permalink}">Gå til lokation</a>
  </div>
  </div>
  </div>
    `)
  }

return(`
     <div class="card">
       <div class="card-content">
       <div class="media">
       <div class="media-content">
       <p class="title is-4">${this.infoContent.title}</p>
       </div>
      </div>

  <div class="content">
  ${this.infoContent.content}
  <a href="${this.infoContent.permalink}">Gå til lokation</a>
  </div>
  </div>
  </div>
`);

},

strokeOptions(color) {
        if (color) {
            return { strokeColor: color };
        }

        return { strokeColor: '#000000' };
    },

setBounds() {
  const bounds = new google.maps.LatLngBounds();

  this.$children[0].$children.forEach(vueComponent => {
    if (!vueComponent.$vnode.key) {
      return;
    }

    if (vueComponent.$vnode.key.match(/marker/)) {
      bounds.extend(
        new google.maps.LatLng(
          vueComponent.position.lat,
          vueComponent.position.lng
        )
      );
    } else if (vueComponent.$vnode.key.match(/circle/)) {
      bounds.extend(
        new google.maps.LatLng(
          vueComponent.center.lat,
          vueComponent.center.lng
        )
      );
    } else if (vueComponent.$vnode.key.match(/rectangle/)) {
      const NE = vueComponent.$rectangleObject.bounds.getNorthEast();
      const SW = vueComponent.$rectangleObject.bounds.getSouthWest();

      bounds.extend(new google.maps.LatLng(NE.lat, NE.lng));
      bounds.extend(new google.maps.LatLng(SW.lat, SW.lng));
    } else if (vueComponent.$vnode.key.match(/polygon/)) {
      const pathObject = vueComponent.$polygonObject.getPath();
      for (var i = 0; i < pathObject.getLength(); i++) {
        const latLng = pathObject.getAt(i);
        bounds.extend(new google.maps.LatLng(latLng.lat(), latLng.lng()));
      }
    } else if (vueComponent.$vnode.key.match(/polyline/)) {
      const pathObject = vueComponent.$polylineObject.getPath();
      for (var i = 0; i < pathObject.getLength(); i++) {
        const latLng = pathObject.getAt(i);
        bounds.extend(new google.maps.LatLng(latLng.lat(), latLng.lng()));
      }
    }
  });

  this.map.fitBounds(bounds);
},

removeDuplicates(myArr, prop) {
  return myArr.filter((obj, pos, arr) => {
    return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos;
  });
},

languageImage(language) {
  if (language == 'danish') {
    return 'http://statisk.infolandcms.dk/flags-iso/shiny/64/DK.png'
  }

  if (language == 'english') {
    return 'http://statisk.infolandcms.dk/flags-iso/shiny/64/GB.png'
  }

  if (language == 'german') {
    return 'http://statisk.infolandcms.dk/flags-iso/shiny/64/DE.png'
  }
},

chooseLangauge(language) {
  this.language = language;
  Cookies.set('ilfind_language', language);
  this.showLanguageChooser = false;
},

changeMarkerIcon(category) {

  //console.log(category);
  if (category[0] == 'Shopping') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/shopping.svg'
  }
  if (category[0] == 'Erhverv') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/erhverv.svg'
  }
  if (category[0] == 'Sport') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/sport.svg'
  }
  if (category[0] == 'Badning/Svømning') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/badning-svømning.svg'
  }
  if (category[0] == 'Oltidsminder') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/oltidsminder.svg'
  }
  if (category[0] == 'Fiskeri') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/fiskeri.svg'
  }
  if (category[0] == 'Cykling') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/cykling.svg'
  }
  if (category[0] == 'Legepladser') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/legepladser.svg'
  }
  if (category[0] == 'Overnatning') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/overnatning.svg'
  }
  if (category[0] == 'Camping') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/camping.svg'
  }
  if (category[0] == 'Udsigt') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/udsigt.svg'
  }
  if (category[0] == 'Seværdigheder') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/seværdigheder.svg'
  }
  if (category[0] == 'Turistattraktioner') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/turistattraktioner.svg'
  }
  if (category[0] == 'Spisesteder') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/spisesteder.svg'
  }
  if (category[0] == 'Parkering/Rastepladser') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/parkering-rastepladser.svg'
  }
  if (category[0] == 'Stier') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/stier.svg'
  }
  if (category[0] == 'Kirker') {
    return '../wp-content/plugins/ilfind-master/icon/icons/nyny/kirker.svg'
  }
}

},

//Computed er dynamiske funktioner som bla bruges til at ændre eksisterende objekter med dynamiske værdier computed: { locations() { if (this.rawLocations.length) { return JSON.parse(this.rawLocations) .map(function(location) { for (let index = 0; index < location.coordinate_sets.length; index++) { const set = location.coordinate_sets[index]; if (!set.drawings_options) { set.drawings_options = {} const keys = Object.keys(set.drawings); for (let index = 0; index < keys.length; index++) { const key = keys[index]; set.drawings_options[key] = [];

                  for (let index2 = 0; index2 < set.drawings[key].length; index2++) {
                      set.drawings_options[key].push({
                          color: '#000000'
                      });
                  }
              }

            location.coordinate_sets[index] = set;
          }
        }
        return location;
      })
  }

  return [];
},

filteredLocations() {
  return this.locations.filter(location => {
    if (location.categories.length == 0) {
      return true;
    }

    return (
      this.selectedCategories.filter(categoryID => {
        return (
          location.categories
            .map(category => category.term_id)
            .indexOf(categoryID) !== -1
        );
      }).length > 0
    );
  });
},

center() {
  return this.locations[0].coordinate_sets[0].mapOptions.center;
},
zoom() {
  return this.locations[0].coordinate_sets[0].mapOptions.zoom;
},

categories() {
  let categories = new Array();
  this.locations.forEach(location => {
    location.categories.forEach(category => {
      categories.push(category);
    });
  });

  categories = this.removeDuplicates(categories, "term_id");

  return categories;
},

languages() {
  return JSON.parse(this.rawLanguages);
},

},

//Watch funktioner bliver først kørt når data bliver ændret watch: { search(search) { search = search.toLowerCase();

  if (search === "") {
    this.searchResults = [];
    return;
  }

  this.searchResults = this.locations.filter(location => {
    let found = location.more_information.toLowerCase().search(search);

    if (found !== -1) {
      return true;
    }

    let sets = Array.from(location.coordinate_sets);

    sets = sets.filter(coordinate_set => {
      return (
        coordinate_set.texts[this.language].content.toLowerCase().search(search) !==
          -1 ||
        coordinate_set.texts[this.language].title.toLowerCase().search(search) !==
          -1
      );
    });

    if (sets.length > 0) {
      return true;
    }

    return false;
  });
}

},

//Mounted funktioner bliver kaldt efter vue instancen er blevet udskiftet med vm.instancenavn mounted() { this.selectedCategories = this.categories.map(category => category.term_id);

this.$refs.map.$mapPromise.then(map => {
  this.map = map;

  setTimeout(() => {
    this.setBounds();
  }, 500);
});

if (Cookies.get('ilfind_language')) {
  this.language = Cookies.get('ilfind_language')
} else {
  this.showLanguageChooser = true;
}

} };`