Performance issue Vue with Leaflet and Leaflet.markercluster thousands Markers - vue.js

Leaflet this is a popular geo library.
For some reason, I have serious performance problems when using this library together with the Vue.
Problem 1:
More than 500 markers and the page is already beginning to stumble, 2,000 markers - strongly breaks, 10,000 markers - does not load.
On an HTML web page, 50,000 are loaded peacefully.
Problem 2:
The Leaflet.markercluster plugin is very weak, it does not collapse the markers.
mounted() {
this.initMap();
setTimeout(() => {
this.initLocation()
}, 100)
},
methods: {
initMap() {
this.map = L.map('map').setView([38.63, -90.23], 12);
this.tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap contributors',
});
this.tileLayer.addTo(this.map);
},
initLocation() {
this.map.locate({
setView: true,
maxZoom: 17
});
//Leaflet.markercluster
let markers = L.markerClusterGroup();
function r(min, max) {
return Math.random() * (max - min) + min;
}
let icon = L.divIcon({
className: 'icon'
});
for (let i = 0; i < 500; i++) {
let marker = L.marker([r(53.82477192, 53.97365592), r(27.3878027, 27.70640622)], {
icon: icon
}).addTo(this.map);
markers.addLayer(marker);
}
this.map.addLayer(markers);
},
}

Do not add your marker both to this.map and to your markers Marker Cluster Group (MCG).
Add them only to the MCG, and let it handle the adding to your map as needed.
new Vue({
el: '#app',
data: {
map: null,
tileLayer: null,
},
mounted() {
this.initMap();
setTimeout(() => {
this.initLocation()
}, 100)
},
methods: {
initMap() {
this.map = L.map(this.$refs.map).setView([53.9, 27.6], 9);
this.tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap contributors',
});
this.tileLayer.addTo(this.map);
},
initLocation() {
//this.map.locate({setView: true, maxZoom: 17});
//Leaflet.markercluster
let markers = L.markerClusterGroup();
function r(min, max) {
return Math.random() * (max - min) + min;
}
let icon = L.divIcon({
className: 'icon'
});
// Quick test with 5k markers:
for (let i = 0; i < 5000; i++) {
let marker = L.marker([
r(53.82477192, 53.97365592),
r(27.3878027, 27.70640622)
], {
icon: icon
}) /*.addTo(this.map)*/ ; // <= do not add individual `marker` to map!
markers.addLayer(marker); // <= but only to MCG
}
this.map.addLayer(markers);
},
},
});
<script src="https://unpkg.com/vue#2"></script>
<!-- Leaflet assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>
<!-- Leaflet.markercluster assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster#1.3.0/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster#1.3.0/dist/MarkerCluster.Default.css">
<script src="https://unpkg.com/leaflet.markercluster#1.3.0/dist/leaflet.markercluster-src.js"></script>
<div id="app">
<div ref="map" style="height: 180px"></div>
</div>

For greater performance
When handling a lot of markers make sure to make use of the scaling capabilities of markercluster. They have batch methods for adding and removing lots of markers: addLayers(), removeLayers(), and clearLayers(). They are much more performant. Also note that you can use the chunkedLoading option on the markerClusterGroup. Allowing you to return the main thread frequently, to make the UI more snappy.
So extending on the answer from #ghybs above. I would adapt the snippet like this:
new Vue({
el: '#app',
data: {
map: null,
tileLayer: null,
},
mounted() {
this.initMap();
setTimeout(() => {
this.initLocation()
}, 100)
},
methods: {
initMap() {
this.map = L.map(this.$refs.map).setView([53.9, 27.6], 9);
this.tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap contributors',
});
this.tileLayer.addTo(this.map);
},
initLocation() {
//Leaflet.markercluster
const markerClusterGroup = L.markerClusterGroup({
chunkedLoading: true
}); // <= Add chunked loading here
function r(min, max) {
return Math.random() * (max - min) + min;
}
let icon = L.divIcon({
className: 'icon'
});
const markers = []
// Quick test with 5k markers:
for (let i = 0; i < 5000; i++) {
let marker = L.marker([
r(53.82477192, 53.97365592),
r(27.3878027, 27.70640622)
], {
icon: icon
})
markers.push(marker)
// markers.addLayer(marker); // <= do not add individual marker to MCG
}
markerClusterGroup.addLayers(markers) // <= use batch method to add markers to MCG
this.map.addLayer(markerClusterGroup);
},
},
});
<script src="https://unpkg.com/vue#2"></script>
<!-- Leaflet assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>
<!-- Leaflet.markercluster assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster#1.3.0/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster#1.3.0/dist/MarkerCluster.Default.css">
<script src="https://unpkg.com/leaflet.markercluster#1.3.0/dist/leaflet.markercluster-src.js"></script>
<div id="app">
<div ref="map" style="height: 300px"></div>
</div>
I hope that helps others.

Related

Multiple OpenLayers maps in Ionic Vue app

We're building an app using Ionic 6 / Vue 3 / Capacitor as our framework. On one of the pages we need to display a form which, among other inputs, contain 2 map components. The user can tap to pinpoint a geographical location in each of the maps. This is our map component:
<template>
<ion-item>
<ion-label position="stacked" color="tertiary" style="margin-bottom: 10px"
>{{ controlLabel }} (Tap to choose position)</ion-label
>
<div class="mapBox">
<div
:id="'map'+randomId"
class="map"
#click="getCoord($event)"
></div>
</div>
<div>
<ion-label color="tertiary" position="stacked">{{
$lang.Lengdegrad
}}</ion-label>
<ion-input
v-model="lon"
#change="setMarker($event)"
:controlIdLat="controlIdLat"
:data-value="valueLat"
/>
</div>
<div>
<ion-label color="tertiary" position="stacked">{{
$lang.Breddegrad
}}</ion-label>
<ion-input
v-model="lat"
#change="setMarker($event)"
:controlIdLon="controlIdLon"
:data-value="valueLon"
/>
</div>
</ion-item>
</template>
<script>
import { defineComponent } from "#vue/runtime-core";
import { IonInput, IonItem, IonLabel } from "#ionic/vue";
import Map from "ol/Map";
import View from "ol/View";
import Feature from "ol/Feature";
import Point from "ol/geom/Point";
import { Style, Icon } from "ol/style";
import { OSM, Vector as VectorSource } from "ol/source";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import { fromLonLat, toLonLat } from "ol/proj";
import XYZ from "ol/source/XYZ";
import "ol/ol.css";
import PinImg from "../../resources/icons8-pin-48.png";
import { Geolocation } from "#capacitor/geolocation";
export default defineComponent({
props: [
"controlLabel",
"controlIdLat",
"controlIdLon",
"lonLatFields",
"valueLat",
"valueLon",
"setStartMarker",
],
components: {
IonInput,
IonItem,
IonLabel,
},
data() {
return {
mainMap: null,
lat: null,
lon: null,
pinLayer: null,
pinFeat: null,
$lang: this.$lang,
isOnline: this.$isOnline,
isVisible: false,
randomId: Math.random().toString(36).substr(2, 5),
};
},
mounted() {
console.log("randomid",this.randomId)
this.source = new VectorSource();
setTimeout(async () => {
if (document.readyState === "loading") {
document.addEventListener(
"DOMContentLoaded",
await this.getLocation()
);
} else {
await this.getLocation();
}
this.myMap();
this.$nextTick(() => {
if (this.setStartMarker) {
this.setMarker();
}
view.setCenter(fromLonLat([this.lon, this.lat]));
});
}, 100);
},
methods: {
async getLocation() {
const position = await Geolocation.getCurrentPosition();
this.lat = position.coords.latitude.toFixed(3);
this.lon = position.coords.longitude.toFixed(3);
},
getCoord(event) {
let lonlat = toLonLat(this.mainMap.getEventCoordinate(event));
this.lat = lonlat[1].toFixed(3);
this.lon = lonlat[0].toFixed(3);
this.$nextTick(() => {
this.setMarker();
});
},
myMap() {
this.mainMap = new Map({
layers: [
new TileLayer({
source: new OSM(),
}),
new TileLayer({
source: new XYZ({
url: "https://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=sjokartraster&zoom={z}&x={x}&y={y}",
attributions:
'Kartverket',
}),
}),
(this.pinLayer = new VectorLayer({
source: new VectorSource({
features: [],
}),
style: new Style({
image: new Icon({
anchor: [0.5, 46],
anchorXUnits: "fraction",
anchorYUnits: "pixels",
src: PinImg,
}),
}),
})),
],
target: "map" + this.randomId,
view: view,
});
console.log("map", this.mainMap);
},
setMarker() {
let p = new Point(fromLonLat([this.lon, this.lat]));
console.log("setmarker", p);
if (!this.pinLayer.getSource().getFeatures().length) {
this.pinFeat = new Feature({
geometry: p,
});
this.pinLayer.getSource().addFeature(this.pinFeat);
} else {
this.pinFeat.setGeometry(p);
}
let vals = {
[this.controlIdLat]: this.lat,
[this.controlIdLon]: this.lon,
};
this.$emit("input", vals);
console.log(p.getCoordinates());
view.setCenter(p.getCoordinates());
},
},
});
const view = new View({
center: fromLonLat([13.486, 68.131]),
zoom: 10,
constrainResolution: true,
});
</script>
<style scoped>
div.map {
border: 5px solid white;
margin: 0 auto;
height: 100%;
width: 100%;
}
div.mapBox {
width: 100%;
height: 40vh;
}
</style>
Testing in the browser, this kind of works. The user can tap each of the two maps and two separate locations will be saved to the variables. However, when panning or zooming one of the maps, the other one follows so that they both show exactly the same map area.
As you can see, I've tried assigning a random id to each map to separate them from each other. That didn't work.
Testing on an Android phone, only the latter of the two maps are displayed. The first mainMap is left undefined.
My guess is that if I can figure out the first nuisance, then the second problem will also be solved. Any tips?
Edit: I tried making a new identical map component and use one for each map. Now the maps work as expected in the browser, being controlled separately. However the first map is still undefined on Android.

vue.js nuxt.js Creating dynamical pages and pagination

I have several scenes that I want to include in my nuxt project.
The project should have pages, and each page has 4 scenes.
I'm currently 'coding' each page and import the scenes manually.
This is my pages tree:
pages tree
This is my first page
<template>
<main class="main">
<Scene1 />
<Scene2 />
<Scene3 />
<!-- <Scene4 /> -->
</main>
</template>
<script>
import Scene1 from './1/Scene1.vue'
import Scene2 from './1/Scene2.vue'
import Scene3 from './1/Scene3.vue'
// import Scene4 from './1/Scene4.vue'
export default {
components: {
Scene1,
Scene2,
Scene3,
// Scene4
}
}
</script>
<style scoped>
.main{
display: grid;
grid-template-columns: 50% 50%;
}
</style>
And this is how a scene looks like:
<template>
<div class="three-item">
<div class="item-title">
Color Rectangle
</div>
<p>Vertex</p>
<pre><code id="vertexShader">
void main() {
gl_Position = vec4( position, 1.0 );
}
</code></pre>
<p>Fragment</p>
<pre><code id="fragmentShader">
#ifdef GL_ES
precision mediump float;
#endif
uniform float u_time;
void main() {
// Magenta (1,0,1)
gl_FragColor = vec4(1.0,0.0,1.0,1.0);
}
</code></pre>
<div id="scene1" class="scene">
</div>
</div>
</template>
<script>
import * as Three from 'three'
import hljs from 'highlight.js'
import glsl from 'highlight.js/lib/languages/glsl';
export default{
name: 'Scene1',
data() {
return {
camera: null,
scene: null,
renderer: null,
mesh: null
}
},
methods: {
init: function() {
this.container = document.getElementById('scene1');
this.camera = new Three.PerspectiveCamera(70, this.container.clientWidth/this.container.clientHeight, 0.01, 10);
this.camera.position.z = 1;
this.scene = new Three.Scene();
this.uniforms = {
u_time: { type: "f", value: 1.0 },
u_resolution: { type: "v2", value: new Three.Vector2() },
u_mouse: { type: "v2", value: new Three.Vector2() }
};
let material = new Three.ShaderMaterial( {
uniforms: this.uniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );
let geometry = new Three.BoxBufferGeometry(0.2, 0.2, 0.2);
// let material = new Three.MeshNormalMaterial();
this.mesh = new Three.Mesh(geometry, material);
this.scene.add(this.mesh);
this.renderer = new Three.WebGLRenderer({alpha:true});
this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
this.container.appendChild(this.renderer.domElement);
window.addEventListener( 'resize', this.onWindowResize, false );
hljs.registerLanguage('glsl', glsl);
document.querySelectorAll('pre code').forEach((block) => {
hljs.highlightBlock(block);
});
},
animate: function() {
requestAnimationFrame(this.animate);
this.mesh.rotation.x += 0.01;
this.mesh.rotation.y += 0.02;
this.uniforms.u_time.value += 0.05;
this.renderer.render(this.scene, this.camera);
},
onWindowResize: function() {
this.camera.aspect = this.container.clientWidth / this.container.clientHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
}
},
mounted() {
this.init();
this.animate();
this.onWindowResize();
}
}
</script>
To be honest, I don't get behind the dynamical created pages with nuxt. Is there a way to have a template that fetches 4 scenes, puts them into a page and does it all over again? It could be that I want to add scenes in the middle of the pages. That would destroy my current setup.
My goal is to have something like this:
dreams tree
the page.vue is crawling through the scenes, picks 4, creates a page called '1', and does it all over again. Can someone lend me a hand with that? 😊In the examples at the nuxt homepage they use .json files. I already set up all three.js scenes, but these have javascript files in it.
Erik

My html code can't reach my vue component

This is my second day with vue. I was already using webpack and vue-cli, but I would like to understand how to make everything working within one file. I developed a code which works well, but I would like to refactor the code to have a component which I could later use to generate screen full of color changing tiles.
I tried Vue.component('name', {}), but with no result, because in the console I'm seeing [Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions. and [Vue warn]: Unknown custom element: <brick> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
This code works well:
<html>
<head>
<title>v pavle</title>
<script type="text/javascript" src="https://vuejs.org/js/vue.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
template:
'<div v-bind:style="styleobj" v-on:mouseover="changebgcolor" v-on:mouseout="changebgcolor"></div>',
data: {
styleobj: {
width: "100px",
height: "100px",
backgroundColor: "white"
}
},
methods: {
changebgcolor: function() {
this.styleobj.backgroundColor = Math.floor(
Math.random() * 16777215
).toString(16);
}
}
});
</script>
</body>
</html>
And that code gives everything, but not what I want to see :(
<html>
<head>
<title>v pavle</title>
<script type="text/javascript" src="https://vuejs.org/js/vue.js"></script>
</head>
<body>
<div id="app">
<brick></brick>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app"
});
var brick = Vue.component("brick", {
template:
'<div v-bind:style="styleobj" v-on:mouseover="changebgcolor" v-on:mouseout="changebgcolor"></div>',
data: {
styleobj: {
width: "100px",
height: "100px",
backgroundColor: "white"
}
},
methods: {
changebgcolor: function() {
this.styleobj.backgroundColor = Math.floor(
Math.random() * 16777215
).toString(16);
}
}
});
</script>
</body>
</html>
It may seem easy for you, but after 7h spent, there is nothing more for me, but just ask you on SO
Okay I will answer your 2 questions. First and about data, it has to be a function. So you have to write it like that:
data() {
return {
styleobj: {
width: "100px",
height: "100px",
backgroundColor: "white"
}
}
}
After that, your forgot to reference your component in your Vue instance. Try that:
var vm = new Vue({
el: "#app",
components: {
brick: brick
}
})
Hope it will work.
Data must be a function like data: function(){ return obj }
Register the component using components: {yourcomponent}
You needed to use # in front of your color.
<html>
<head>
<title>v pavle</title>
<script type="text/javascript" src="https://vuejs.org/js/vue.js"></script>
</head>
<body>
<div id="app">
Hello App!
<brick>Hello Brick</brick>
</div>
<script type="text/javascript">
var brick = Vue.component("brick", {
template:
'<div :style="styl" #click="changebgcolor" #mouseover="changebgcolor" #mouseout="changebgcolor"><slot></slot></div>',
data: function(){
return {
styl: {
width: "100px",
height: "100px",
backgroundColor: "#b6d8a1",
color: "blue"
}
};
},
methods: {
changebgcolor: function() {
console.log('changebgcolor!');
this.styl.backgroundColor = "#"+ Math.floor(
Math.random() * 16777215
).toString(16);
}
}
});
var vm = new Vue({
el: "#app",
components:{brick:brick}
});
</script>
</body>
</html>
When using Vue.component, you need to make sure that you have registered all components once you start rendering your app. At the moment, you first render the main app and then register the component, so swap those around
var brick = Vue.component("brick", {
template:
'<div v-bind:style="styleobj" v-on:mouseover="changebgcolor" v-on:mouseout="changebgcolor"></div>',
data: {
styleobj: {
width: "100px",
height: "100px",
backgroundColor: "white"
}
},
methods: {
changebgcolor: function() {
this.styleobj.backgroundColor = Math.floor(
Math.random() * 16777215
).toString(16);
}
}
});
var vm = new Vue({
el: "#app"
});
The data property on your component should be a function that returns an object. Why? Because otherwise all instances of your component share the same data, meaning all tiles on your app would have the same color.
data() {
return {
styleobj: {
width: "100px",
height: "100px",
backgroundColor: "white"
}
}
},
You should first register the component before you fire up the Vue instance, just reorder your code and it works!

How to make components wait for Ajax changes

How can I make my components wait for an ajax call to complete before being rendered? Right now, their data objects are empty because the ajax call has not completed when they are mounted.
Additionally, I want all components to have access to this ajax data, which will be refreshed and updated every 30 seconds. What is the best way to achieve this?
//Snippet of what gets return from ajax call
{
121: {
table_info: {
id: "121",
name: "Test",
table_number: "51",
cap: "6",
seating: "OPEN",
position_x: "0.19297285",
position_y: "0.07207237",
participants_in_tables: "5",
count: 5
}
}
}
//Global
var tableData; //This gets set when the Vue ajax call is complete after being mounted
var width = $(document).width();
var height = $(document).height();
//Vue
Vue.component('tables', {
data: () => {
return {
tables: tableData
}
},
template: `
<div id="tableContain">
<div class='table' v-for="table in tables" :style="computeOffsets(table)">
{{table.table_info.name}}
</div>
</div>
`,
methods: {
computeOffsets(table) {
return {
top: (table.table_info.position_x * width) + 'px',
left: (table.table_info.position_y * height) + 'px'
}
}
});
var app = new Vue({
el: '#main',
mounted() {
$.ajax({
method: 'POST',
dataType: 'json',
url: base_url + 'users/getTableAssignments/' + event_id
}).done(data => {
tableData = data; //Set global tableData
});
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="main">
<table></table>
</div>
It's better to use created in vue and then get the data with props in component like:
Vue.component('tables', {
props: ['tables']
// ...
});
var app = new Vue({
el: '#main',
data: { tables: [] },
created() {
axios.get('url').then( response => { this.tables = response.data } )
}
});
I prefer axios but u can use ajax if u like :D
And if u like to refresh u can just use intervals but I prefer server side solution like sockets. Im using it in my app with laravel broadcasting, redis and sockets to have a realtime dashboard :D

onclick event for marker is not working in openlayer3 on changing the size of the div

i am plotting the markers on the map in openlayer3 as shown below
<!DOCTYPE html>
<html>
<head>
<title>Rotation example</title>
<link rel="stylesheet" href="http://openlayers.org/en/v3.0.0/css/ol.css" type="text/css">
<script src="http://openlayers.org/en/v3.11.2/build/ol.js"></script>
</head>
<body>
<div id="map" style="width:1000px;height:1000px"></div>
<script>
var map;
function initMap() {
map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: 'map',
controls: ol.control.defaults({
attributionOptions: ({
collapsible: false,
})
}),
view: new ol.View({
center: ol.proj.fromLonLat([103.986908, 1.353199]),
rotation: 68*Math.PI/180,
zoom: 18
})
});
}
function invokeAddMarker(){
var markerData = [
{
"title": 'point1',
"lat": 1.350664,
"lng": 103.985190,
"description": 'yyyy'
}, {
"title": 'point2',
"lat":1.353604,
"lng": 103.986395,
"description": 'zzz'
}, {
"title": 'point3',
"lat": 1.357227,
"lng": 103.9879999,
"description": 'uuu'
}
];
for(var i=0;i<markerData.length;i++){
addmarker(markerData[i].lat,markerData[i].lng);
}
}
function addmarker(lat,lng){
console.log("*****lat******"+lat);
console.log("*****lng******"+lng);
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([lng,lat],'EPSG:4326', 'EPSG:3857')),
name: 'camera'
});
var iconStyle = new ol.style.Style({
image: new ol.style.Icon(({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
opacity: 0.75,
src: 'camera.png'
}))
});
iconFeature.setStyle(iconStyle);
vectorSource = new ol.source.Vector({
features: [iconFeature]
});
/*t clear the markers*/
/*vectorSource.clear();*/
vectorLayer = new ol.layer.Vector({
source: vectorSource
});
map.addLayer(vectorLayer);
map.on('click', function(evt) {
var feature = map.forEachFeatureAtPixel(evt.pixel,
function(feature, layer) {
return feature;
});
if (feature) {
alert("video comes here");
}
});
}
initMap();
invokeAddMarker();
</script>
</body>
</html>
I am facing two problem in the above code
1:the click event will fired 3 times ie, the number marker on the map that should only onces by theory
2:when i resize the div say(new width and height of the div is varied to new value in which the map is displayed)the markers will adjust to div but the event is not fired
please say why is this behavior and how to overcome it