I have a Vue component BaseMap that contains a marker component Location.
The Location component has a Polygon marker that can be edtited.
// BaseMap
<GmapMap>
<Location :location="location" />
</GmapMap>
// Location
<gmap-marker>
<gmap-polygon
ref="polyMarker"
:editable="true"
:path="location.path"
#mouseup="updatePath('polyMarker')"
/>
</gmap-marker>
<script>
methods: {
updatePath(ref_name){
console.log(this.$refs[ref_name].path) // same array as origin
}
}
</script>
How do I access the new edited points of the polygon? If I use this.$ref.polyMarker.path I keep getting the original array of points not the new ones.
EDIT
After discussion with MrUpsidown I went ahead and coded the minimum app in codesandbox. The same problem exist.
Dependancies:
- vue
- vue2-gmap-cuspom-marker
//////////////////////////////////////////////////////////////
// main.js
import Vue from "vue";
import App from "./App.vue";
import * as VueGoogleMaps from "vue2-google-maps";
Vue.config.productionTip = false;
Vue.use(VueGoogleMaps, {
load: {
// libraries: "places", // This is required if you use the Autocomplete plugin
key: "[USE YOUR OWN KEY]"
}
// autobindAllEvents: false,
// installComponents: true
});
new Vue({
render: h => h(App)
}).$mount("#app");
//////////////////////////////////////////
//App.vue
<template>
<div id="app">
<HelloWorld />
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
name: "App",
components: {
HelloWorld
}
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>
//////////////////////////////////////////////////////
// HelloWorld.vue
<template>
<div>
<baseMap/>
</div>
</template>
<script>
import baseMap from "#/components/baseMap";
export default {
name: "HelloWorld",
components: { baseMap },
props: {
msg: String
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
</style>
////////////////////////////////////////////////////
//baseMap.vue
<template>
<div>
<GmapMap :style="'height:500px'" :center="center" :zoom="zoom">
<Location :location="location"/>
</GmapMap>
</div>
</template>
<script>
import Location from "#/components/Location";
export default {
name: "baseMap",
components: { Location },
data: function() {
return {
center: { lat: -33.9249, lng: 18.4241 },
zoom: 12,
location: {
path: [
{ lat: -33.91170210440241, lng: 18.422548745513268 },
{ lat: -33.90993912517883, lng: 18.422806237578698 },
{ lat: -33.90874597713464, lng: 18.42422244393856 },
{ lat: -33.90482806012767, lng: 18.42952248895199 },
{ lat: -33.90073186345211, lng: 18.42428681695492 },
{ lat: -33.90128397100101, lng: 18.420596097350426 },
{ lat: -33.90256627151344, lng: 18.417656396270104 },
{ lat: -33.90367045927834, lng: 18.416454766631432 },
{ lat: -33.90532671411109, lng: 18.417913888335534 },
{ lat: -33.908389810302396, lng: 18.413579438567467 },
{ lat: -33.91084733115123, lng: 18.41703412377865 },
{ lat: -33.91170210440241, lng: 18.422548745513268 }
]
}
};
},
props: {
msg: String
}
};
</script>
<style>
</style>
/////////////////////////////////////////////////////////
// Location.vue
<template>
<div>
<gmap-marker>
<gmap-polygon
ref="polyMarker"
:editable="true"
:path="location.path"
#mouseup="updatePath('polyMarker')"
/>
</gmap-marker>
</div>
</template>
<script>
import GmapCustomMarker from "vue2-gmap-custom-marker";
export default {
name: "Location",
components: {
GmapCustomMarker
},
props: {
location: {
type: Object,
default() {
return {};
}
}
},
methods: {
updatePath(name) {
console.log(this.$refs[name].path);
}
}
};
</script>
<style>
</style>
First replace :path with :paths:
:paths="location.path"
Then replace the #mouseup event with #paths_changed using $event as parameter:
#paths_changed="updatePath($event)"
Finally log your path; you'll see how it's getting updated now.
updatePath(mvcArray) {
for (let i = 0; i < mvcArray.getLength(); i++) {
for (let j = 0; j < mvcArray.getAt(i).getLength(); j++) {
console.log(mvcArray.getAt(i).getAt(j).lat() + "," + mvcArray.getAt(i).getAt(j).lng());
}
}
console.log("-------")
}
For further guidance I recommend you check out the library's examples such as this one.
Hope this helps you!
Related
I am using GoogleMap from #capacitor/google-maps plugin. I am trying to change the map type from Normal to Satellite. But this is not working.
await this.map.setMapType(MapType.Satellite);
I have recently found solution for this issue. Integrate 2 separate functions for browser and native devices.
For browser:
async createMapForWeb(map: ElementRef) {
this.map = await GoogleMap.create({
id: "capacitor-google-maps",
element: map.nativeElement,
apiKey: environment.browserKey,
config: {
zoom: 18,
mapTypeControl: false,
center: {
lat: this.location.lat,
lng: this.location.lng,
},
mapTypeId: "satellite",
disableDefaultUI: true,
},
forceCreate: true,
});
}
For native devices:
async createMapForDevice(map: ElementRef) {
this.map = await GoogleMap.create({
id: "capacitor-google-maps",
element: map.nativeElement,
apiKey: environment.browserKey,
config: {
zoom: 18,
mapTypeControl: false,
center: {
lat: this.location.lat,
lng: this.location.lng,
},
disableDefaultUI: false,
},
forceCreate: true,
});
await this.map.setMapType(MapType.Satellite);}
Extending Ariyan Ashfaque's answer below:
You can make use of Capacitor.isNativePlatform() to identify browser / native device.
import { Capacitor } from '#capacitor/core';
const createMap = async () => {
if (!mapRef.current) return;
if (Capacitor.isNativePlatform()) {
console.warn('Native Platform Map');
newMap = await GoogleMap.create({
id: 'google-map',
element: mapRef.current,
apiKey: CONFIG.GOOGLE_MAPS_API_KEY,
config: mapConfig,
forceCreate: true,
});
await newMap.setMapType(MapType.Satellite);
await newMap.enableCurrentLocation(true);
} else {
console.warn('Browser Map');
newMap = await GoogleMap.create({
id: 'google-map',
element: mapRef.current,
apiKey: CONFIG.GOOGLE_MAPS_API_KEY,
config: mapConfig,
forceCreate: true,
});
}
await newMap.addMarker({
coordinate: {
lat: props?.geoLocation?.latitude,
lng: props?.geoLocation?.longitude,
},
title: 'Marker Title',
});
await Geolocation.getCurrentPosition();
};
I'm trying to make this work on my vue3 project but came to a very weird issue.
The same code works fine on vue2 but not on vue3 and there is no error shown, has anyone tried to use Google Data Driven Maps styling and figure out a way to use them in vue3?
Vue 3 Map(the map is loaded, but there is no data-driven styling included, no errors provided in console).: https://jsfiddle.net/dgalic/2pebj6ct/4/
const { createApp } = Vue
createApp({
name: 'MapStyling',
data: function() {
return {
no_data: [null, "", undefined, "null"],
mapName: "route-manager-map",
bounds: {},
map: {},
markers: {},
polylines: {},
};
},
mounted() {
this.defineMap()
},
methods: {
defineMap() {
/* eslint-disable */
// this.bounds = new google.maps.LatLngBounds();
const element = document.getElementById(this.mapName);
const options = {
center: { lat: 30.266666, lng: -97.733330 },
zoom: 12,
mapId: "map_id",
};
this.map = new google.maps.Map(element, options);
const featureLayer = this.map.getFeatureLayer(
google.maps.FeatureType.POSTAL_CODE
)
featureLayer.style = function (placeFeature) {
let fillColor = "blue";
if (postal_codes.includes(placeFeature.feature.displayName)) {
return {
fillColor,
fillOpacity: 0.5,
}
} else {
return {
fillColor,
fillOpacity: 0
}
}
}
const postal_codes = [
'78701',
'78702',
'78703',
'78704',
'78705'
]
}
}
}).mount('#app')
.google-map {
width: 100%;
height: 600px;
margin: 0 auto;
background: #e5e3df;
}
<script src="https://unpkg.com/vue#3"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=API-KEY&libraries=places&v=beta"></script>
<div id="app">
<div
class="google-map"
:id="mapName"
></div>
</div>
Vue 2 Map(works fine, same code): https://jsfiddle.net/dgalic/1wutoja2/8/
new Vue({
el: '#app',
name: 'MapStyling',
data: function() {
return {
no_data: [null, "", undefined, "null"],
mapName: "route-manager-map",
bounds: {},
map: {},
markers: {},
polylines: {},
};
},
mounted() {
this.defineMap()
},
methods: {
defineMap() {
/* eslint-disable */
// this.bounds = new google.maps.LatLngBounds();
const element = document.getElementById(this.mapName);
const options = {
center: {
lat: 30.266666,
lng: -97.733330
},
zoom: 12,
mapId: "map_id",
};
this.map = new google.maps.Map(element, options);
const featureLayer = this.map.getFeatureLayer(
google.maps.FeatureType.POSTAL_CODE
)
featureLayer.style = function(placeFeature) {
let fillColor = "blue";
if (postal_codes.includes(placeFeature.feature.displayName)) {
return {
fillColor,
fillOpacity: 0.5,
}
} else {
return {
fillColor,
fillOpacity: 0
}
}
}
// featureLayer = JSON.parse(JSON.stringify(featureLayer))
console.log(featureLayer.h.get('mapId'))
const postal_codes = [
'78701',
'78702',
'78703',
'78704',
'78705'
]
}
}
}).mount('#app')
.google-map {
width: 100%;
height: 600px;
margin: 0 auto;
background: #e5e3df;
}
<script src="https://unpkg.com/vue#2"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=API-KEY&libraries=places&v=beta"></script>
<div id="app">
<div class="google-map" :id="mapName"></div>
</div>
Any help or feedback would be much appreciated.
I read a lot about how to implementing external files into stencil but nothing worked yet like I want it. The speciality is that stencil runs in a Liferay theme. But I think that shouldn't matter.
I installed the MarkerClustererPlus from google via npm and in the stencil config i copy the min file into an "asset" folder like this:
import { Config } from '#stencil/core';
import { sass } from '#stencil/sass';
import nodePolyfills from 'rollup-plugin-node-polyfills';
export const config: Config = {
namespace: 'gwkp-components',
srcDir: 'src/js/components',
plugins: [
sass({
injectGlobalPaths: [
'build/css/clay/_mixins.scss',
'build/css/fonts/font-awesome/scss/_mixins.scss',
'build/css/fonts/font-awesome/scss/_variables.scss',
'build/css/fonts/font-awesome/scss/_core.scss',
'src/js/components/utils/_stencilvars.scss',
'build/css/fonts/font-awesome/scss/regular.scss',
'build/css/fonts/font-awesome/scss/light.scss',
'build/css/fonts/font-awesome/scss/solid.scss',
'build/css/clay/bootstrap/_functions.scss',
'build/css/clay/bootstrap/_mixins.scss',
'build/css/clay/bootstrap/_variables.scss',
'src/css/gw/_colors.scss',
'src/css/gw/_variables.scss',
'src/css/gw/bem/_includes.scss'
]
})
],
outputTargets: [
{
type: 'www',
buildDir: '.',
dir: 'build/js/components',
serviceWorker: null, // disable service workers
copy: [
{ src: '../../../build/css/fonts/font-awesome/webfonts', dest: 'webfonts' },
{ src: '../../../node_modules/#google/markerclustererplus/dist/markerclustererplus.min.js', dest: 'assets/js/markerclustererplus.min.js' }
]
}
],
rollupPlugins: {
after: [
nodePolyfills()
]
}
};
Now the question arises how to get access to the min.js file? Do I need an import statement and declaring a variable or create a script tag? I tried both in some way but nothing worked so far. I need it only in one component.
At the end I wanna use the following code in the component:
var markerCluster = new MarkerClusterer(this.map, this.markerMap,
{imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'});
No need to copy node_modules/#google/markerclustererplus/dist/markerclustererplus.min.js to assets/js/markerclustererplus.min.js.
In your component's tsx file just import MarkerCluster
import MarkerClusterer from "#google/markerclustererplus";
You'll need to have the google maps javascript library already loaded. As far as I'm aware you'll have to load it via a script tag but this can be done dynamically.
I'm using // #ts-ignore in my examples but you can install the Google Maps types if you prefer.
The final component should look something like the following:
import { h, Component, Host, Element, Listen } from "#stencil/core";
import MarkerClusterer from "#google/markerclustererplus";
#Component({
tag: "my-component",
styles: `
:host {
position: absolute;
width: 100%;
height: 100%;
}
.map {
height: 100%;
}
`,
shadow: true,
})
export class MyComponent {
#Element() el: HTMLElement;
private googleMapsApiKey = "YOUR_API_KEY_HERE";
private locations = [
{ lat: -31.56391, lng: 147.154312 },
{ lat: -33.718234, lng: 150.363181 },
{ lat: -33.727111, lng: 150.371124 },
{ lat: -33.848588, lng: 151.209834 },
{ lat: -33.851702, lng: 151.216968 },
{ lat: -34.671264, lng: 150.863657 },
{ lat: -35.304724, lng: 148.662905 },
{ lat: -36.817685, lng: 175.699196 },
{ lat: -36.828611, lng: 175.790222 },
{ lat: -37.75, lng: 145.116667 },
{ lat: -37.759859, lng: 145.128708 },
{ lat: -37.765015, lng: 145.133858 },
{ lat: -37.770104, lng: 145.143299 },
{ lat: -37.7737, lng: 145.145187 },
{ lat: -37.774785, lng: 145.137978 },
{ lat: -37.819616, lng: 144.968119 },
{ lat: -38.330766, lng: 144.695692 },
{ lat: -39.927193, lng: 175.053218 },
{ lat: -41.330162, lng: 174.865694 },
{ lat: -42.734358, lng: 147.439506 },
{ lat: -42.734358, lng: 147.501315 },
{ lat: -42.735258, lng: 147.438 },
{ lat: -43.999792, lng: 170.463352 },
];
private _mapEl: HTMLElement;
componentDidLoad() {
if (document.getElementById("maps-script")) {
this.initMap();
return;
}
// Create the script tag, set the appropriate attributes
var script = document.createElement("script");
script.id = "maps-script";
script.src = `https://maps.googleapis.com/maps/api/js?key=${this.googleMapsApiKey}&callback=initMap`;
script.defer = true;
// Attach your callback function to the `window` object
// #ts-ignore
window.initMap = () => this.initMap();
// Append the 'script' element to 'head'
document.head.appendChild(script);
}
initMap() {
// #ts-ignore
const map = new google.maps.Map(this._mapEl, {
zoom: 3,
center: { lat: -28.024, lng: 140.887 },
});
// Create an array of alphabetical characters used to label the markers.
const labels = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// Add some markers to the map.
// Note: The code uses the JavaScript Array.prototype.map() method to
// create an array of markers based on a given "locations" array.
// The map() method here has nothing to do with the Google Maps API.
const markers = this.locations.map((location, i) => {
// #ts-ignore
return new google.maps.Marker({
position: location,
label: labels[i % labels.length],
});
});
// Add a marker clusterer to manage the markers.
const markerCluster = new MarkerClusterer(map, markers, {
imagePath:
"https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m",
});
}
render() {
return (
<Host>
<div class="map" ref={(el) => (this._mapEl = el)}></div>
</Host>
);
}
}
Here is a Working example on webcomponents.dev
I need help linking buttons to cities. When clicked, opens a new map which then zooms in and I can have places of interest also. This is my file below and I am not the best at coding so help appreciated please.
I haven't included the HTML file as its so basic and was more what I needed to add here.
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
zoom: 3,
center: {
lat: 50.7436337,
lng: 18.4208039
}
});
to loop around
Need help to link buttons to cities that when clicked upon opens up to a map of that city
var labels = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
My places are outlined below of the cities I want in my buttons:
function addMarker(feature) {
var marker = new google.maps.Marker({
position: feature.position,
map: map,
icon: icons[feature.type].icon,
});
}
The map of the world:
var map;
var InforObj = [];
var centerCords = {
lat: 50.7436337,
lng: 18.4208039
};
var markersOnMap = [{
placeName: "Amsterdam (Johan Cryuff Arena)",
LatLng: [{
lat: 52.314371,
lng: 4.941964
}],
},
{ placeName: "Baku (Olympic Stadium)",
LatLng: [{
lat: 40.4300,
lng: 49.9196
}]
},
{ placeName: "Bilbao (San Mames)",
LatLng: [{
lat: 43.2641,
lng: -2.9494
}]
},
{ placeName: "Bucharest (Arena Nationala)",
LatLng: [{
lat: 44.437139,
lng: 26.152579
}]
},
{ placeName: "Budapest (Puskas Arena)",
LatLng: [{
lat: 47.503172,
lng: 19.097022
}]
},
{ placeName: "Copenhagen (Parken Stadium)",
LatLng: [{
lat: 55.702701,
lng: 12.572433
}]
},
{ placeName: "Dublin (Aviva Stadium)",
LatLng: [{
lat: 53.335232,
lng: -6.228457
}]
},
{ placeName: "Glasgow (Hampden Park)",
LatLng: [{
lat: 55.825842,
lng: -4.252048
}]
},
{ placeName: "London (Wembley Stadium)",
LatLng: [{
lat: 51.556021,
lng: -0.279519
}]
},
{ placeName: "Munich (Allianz Arena)",
LatLng: [{
lat: 48.2188,
lng: 11.624707
}]
},
{ placeName: "Rome (Stadio Olimpico)",
LatLng: [{
lat: 41.934077,
lng: 12.454725
}]
},
{ placeName: "Saint Petersburg (Krestovsky Stadium)",
LatLng: [{
lat: 59.972728,
lng: 30.221405
}]
},
];
List of the cities above:
window.onload = function () {
initMap();
};
function addMarkerInfo() {
for (var i = 0; i < markersOnMap.length; i++) {
var contentString = '<div id="content"><h1>' + markersOnMap[i].placeName +
'</h1><p>Lorem ipsum dolor sit amet, vix mutat posse suscipit id, vel ea tantas omittam detraxit.</p></div>';
const marker = new google.maps.Marker({
position: markersOnMap[i].LatLng[0],
map: map,
});
const infowindow = new google.maps.InfoWindow({
content: contentString,
maxWidth: 200
});
marker.addListener('click', function () {
closeOtherInfo();
infowindow.open(marker.get('map'), marker);
InforObj[0] = infowindow;
});
}
}
All part of the same code and I am not sure how its done properly
function closeOtherInfo() {
if (InforObj.length > 0) {
// detach the info-window from the marker ... undocumented in the API docs
InforObj[0].set("marker", null);
// and close it
InforObj[0].close();
// blank the array
InforObj.length = 0;
}
}
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: centerCords
});
addMarkerInfo();
}
function initialize() {
map = new google.maps.Map(document.getElementById('map-canvas'), {
center: new google.maps.LatLng(48.1293954, 12.556663), //Setting Initial Position
zoom: 10
});
}
my file path
var markerCluster = new MarkerClusterer(map, markers, {
imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'
});
}
This is my javascript code
i have a vue2-google-map apps that display map.
before this i using this code
<GmapMarker
ref="myMarker"
:position="google && new google.maps.LatLng(1.38, 103.8)"
/>
<GmapMarker
ref="myMarker"
:position="google && new google.maps.LatLng(3.1488976, 101.6126774)"
/>
to display multiple marker, but if the latlng data is too many, it will be many need to be create.
my idea is to take data from
const latlng = [
{
lat: value,
lng: value,
},
{
lat: value,
lng: value,
},
and apply {{latlng}} into <GmapMarker :position="google && new google.maps.LatLn({{latlng.lng}},{{latlng.lat}})">
but i have problem to apply that {{latlng}} into the marker.
can someone explain how to apply them?
For generating multiple markers your need to push latitude and longitude in the marker collection and then iterate the marker.i have updated code as per the requirement.
<template>
<div>
<GmapMap
ref="gmap"
:center="getCenter()"
:zoom="11"
style="height: 500px;margin: 0px -8px;"
class="no-padding"
:options="getOptions()"
>
<GmapMarker
:key="index"
v-for="(m, index) in getMarkers()"
:position="m.position"
:clickable="true"
:draggable="false"
:title="m.title"
:icon="m.icon"
#click="clicked()"
/>
</GmapMap>
</div>
</template>
<script>
import MarkerClusterer from "marker-clusterer-plus";
export default {
name: "SiteMap",
props: [],
methods: {
getOptions() {
return {
zoomControl: true,
mapTypeControl: false,
scaleControl: false,
streetViewControl: false,
rotateControl: false,
fullscreenControl: false,
disableDefaultUi: false
};
},
clicked() {
// after click
},
getCenter() {
return {
lat: 37.12523,
lng: -122.1252
};
},
getMarkers() {
// generating markers for site map
var markers = [];
// remove this after lat long received from api.
const tempLatLong = [
{ lat: 37.9068361, lng: -122.116971 },
{ lat: 37.9168362, lng: -122.076972 },
{ lat: 37.9268363, lng: -122.136973 },
{ lat: 37.9368364, lng: -122.146974 },
{ lat: 37.9468365, lng: -122.106975 },
{ lat: 37.9568366, lng: -122.166976 },
{ lat: 37.9668367, lng: -122.176977 },
{ lat: 37.9768368, lng: -122.016978 },
{ lat: 37.9868369, lng: -122.196979 }
];
for(let i=0;i<tempLatLong.length;i++){
markers.push({
position: tempLatLong[i],
title: 'test title',
icon: this.getSiteIcon(1) // if you want to show different as per the condition.
});
}
return markers;
},
getSiteIcon(status) {
try {
switch (status) {
case 1:
return require("#/assets/images/icons/map-marker-online.svg");
break;
case 2:
return require("#/assets/images/icons/map-marker-critical.svg");
break;
case 3:
return require("#/assets/images/icons/map-marker-offline.svg");
break;
case 4:
return require("#/assets/images/icons/map-marker-lifesafety.svg");
break;
default:
return require("#/assets/images/icons/map-marker-online.svg");
}
} catch (e) {
return null;
}
},
},
components: {},
created() {},
mounted() {
}
};
</script>
<style scoped></style>