Hi do somebody know or have some samples of code how to add searchbar for vue2-leaflet map, I have tried the following https://www.npmjs.com/package/vue2-leaflet-geosearch but failed, do you know any alternatives how to resolve it,hope for your help, thanks . This is code that works and I would like to add searchbar in the code .
<template>
<div>
<b-modal size="md" :visible="visible" #hidden="$emit('clear')" #shown="modalShown" title="Event details">
<div class="foobar1">
<l-map :minZoom="3" :zoom="13" ref="mymap" #click="addMarker">
<l-tile-layer :url="url" :attribution="attribution"></l-tile-layer>
<!-- <l-marker :lat-lng="center"></l-marker> -->
</l-map>
</div>
<template slot="modal-footer">
<b-btn variant="danger" #click="">Delete</b-btn>
</template>
</b-modal>
</div>
</template>
<style scoped>
.foobar1 {
width: 450px;
height: 400px;
align: center;
}
</style>
<script>
import {LMap, LMarker, LTileLayer} from "vue2-leaflet";
import L from "leaflet"
export default {
name: "loc",
components: {
LMap,
LMarker,
LTileLayer,
L
},
data() {
return {
marker: L.latLng(77, 154.0),
visible: true,
url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}",
attribution:
'© OpenStreetMap contributors'
};
},
methods: {
plotCurrentLocation(map) {
var vm = this;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
var currLocation = new L.latLng(position.coords.latitude, position.coords.longitude);
if (vm.marker)
map.removeLayer(vm.marker);
vm.marker = L.marker([position.coords.latitude, position.coords.longitude], {}).addTo(map);
map.setView(currLocation, 11, {animation: true});
map.panTo(currLocation);
}, err => {
// alert(JSON.stringify(err))
}, {timeout: 30000, enableHighAccuracy: true, maximumAge: 75000})
} else {
alert("no");
}
},
async modalShown() {
var map = this.$refs.mymap.mapObject;
map.invalidateSize();
this.plotCurrentLocation(map);
},
addMarker(e) {
var map = this.$refs.mymap.mapObject;
// alert(JSON.stringify(this.marker.getLatLng()));
if (this.marker)
map.removeLayer(this.marker);
this.marker = L.marker([e.latlng.lat, e.latlng.lng], {}).addTo(map);
map.panTo(e.latlng);
}
}
}
</script>
Instructions on the npm package works fine. Something like this should work.
Remember to install and import the necessary libraries.
<template>
<div style="height: 300px; width: 100%" class="text-grey-10">
<l-map #click="addMarker" :zoom="zoom" :center="center">
<l-tile-layer :url="url" :attribution="attribution" />
<l-geosearch :options="geosearchOptions"/>
<l-marker v-if="locationMarker" :latlng="locationMarker"/>
</l-map>
</div>
</template>
<script>
import { LMap, LTileLayer, LMarker } from "vue2-leaflet";
import { OpenStreetMapProvider } from "leaflet-geosearch";
import LGeosearch from "vue2-leaflet-geosearch";
export default {
components: {
LMap,
LTileLayer,
LMarker,
LGeosearch
},
data: () => {
geosearchOptions: {
provider: new OpenStreetMapProvider()
}
}
}
</script>
Related
I have a GeoJson file and added it to my project file, but I don't know how to import and use it in my map component. I tried the code below, but it didn't work.
<template>
<div class="locationMap">
<l-map
:zoom="6"
:center="[47.31322, -1.319482]"
style="height: 800px; width: 1000px"
>
<l-tile-layer :url="url" :attribution="attribution" />
<l-geo-json
:geojson="geojson"
:options="options"
:options-style="styleFunction"
/>
</l-map>
</div>
</template>
<script>
import geojson from "../components/provinces.json";
export default {
name: "locationMap",
data() {
return {
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution:
'© <a target="_blank" href="http://osm.org/copyright">OpenStreetMap</a>contributors',
geojson: null,
};
},
mounted() {
this.geojson = geojson;
},
};
</script>
Try to assign this.geojson before mounting and load the file with the fetch method.
async created () {
const jsonFile = await fetch('../components/provinces.json')
this.geojson = await jsonFile.json()
}
This example is available in Vue Leaflet documentation.
https://vue2-leaflet.netlify.app/components/LGeoJson.html#demo
So I still couldn't find a solution to import the GeoJson file using vue2-leaflet package , but I was able to import the file using the code below:
<template>
<div class="container">
<div id="mapContainer">
</div>
</div>
</template>
<script>
import "leaflet/dist/leaflet.css";
import L from "leaflet";
import geojson from "../components/provinces.json"
export default{
name: "locationMap",
data() {
return{
center: [32.87255939010237, 53.781741816799745],
}
},
methods: {
setupLeafletMap: function () {
const mapDiv = L.map("mapContainer").setView(this.center, 5);
L.tileLayer(
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
{
attribution: '© <a target="_blank" href="http://osm.org/copyright">OpenStreetMap</a> contributors',
// maxZoom: 18,
}
).addTo(mapDiv);
var myStyle = {
"fillColor": "#818181",
"color": "black",
"weight": 2,
"opacity": 0.65,
"fillOpacity": 0.6
};
L.geoJSON(geojson,{
style: myStyle,
}
}
}
mounted() {
this.setupLeafletMap()
console.log(mockData.colors[1].id)
},
}
</script>
I'm new to Vue JS and I'm trying to make a map with marker clusters because I'm having a great number of markers in my map. I wrote a code based on the Vue2leaflet documentation, but it doesn't show the clusters and there is no error.
I tried to use l-marker,but I was struggling with it, I was having "Cannot read property 'lat' of undefined" error and even though I was really trying to resolve this problem, at the end I decided to use l-geo-json to show the markers on the map.
<template lang="html">
<section class="charts-highcharts">
<grid-block title="Map">
<div class="-map" id="map" >
<l-map :zoom="8" :center="[47.41322, -1.219482]" :options="{ gestureHandling: true }" ref="map">
<l-tile-layer url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"></l-tile-layer>
<l-marker-cluster :options="clusterOptions">
<l-geo-json v-for="l in locations" :key="l.id" :geojson="l.location" :options="options"></l-geo-json>
</l-marker-cluster>
</l-map>
</div>
</grid-block>
</section>
</template>
<script lang="js">
import L from "leaflet";
import { LMap, LTileLayer, LMarker, LGeoJson, LPopup } from "vue2-leaflet";
import { GestureHandling } from "leaflet-gesture-handling";
import Vue2LeafletMarkercluster from 'vue2-leaflet-markercluster';
import 'vue2-leaflet-markercluster/dist/leaflet.markercluster.js';
import 'vue2-leaflet-markercluster/dist/leaflet.markercluster-src.js';
export default {
name: 'Maps',
components: {
LMap,
LTileLayer,
LMarker,
LGeoJson,
LPopup,
"l-marker-cluster": Vue2LeafletMarkercluster,
},
data () {
return {
geojson: null,
clusterOptions: { disableClusteringAtZoom: 11},
locations: [],
options: {
onEachFeature: function onEachFeature(feature, layer) {
layer.bindPopup(feature.properties.name);
},
},
};
},
created () {
L.Map.addInitHook("addHandler","gestureHandling", GestureHandling);
},
mounted() {
let geojson = response.data.features,
id = 0,
tmpLocations = [];
for (let l of geojson) {
tmpLocations.push({
id: id,
location: l,
});
id++;
}
this.locations = tmpLocations;
});
},
};
</script>
<style scoped lang="scss">
#import "~leaflet.markercluster/dist/MarkerCluster.css";
#import "~leaflet.markercluster/dist/MarkerCluster.Default.css";
.charts-highcharts {
}
.-map {
width: 100%;
height: 800px;
}
</style>
Do you know why the clusters aren't showing?
In this codeSandBox demo, the child cmp contains the image file input,
The file is uploaded to and read using reader.readAsDataURL(file) as the background image of the input's parent wrapper div.
The problem is that the uploaded file gets repeated in all siblings.
I want to uploaded file to affect only the component where the child was upload.
Parent.vue
<template>
<div id="app">
<div v-for="n in 5">
<div class="wrapper" :style="bgImg">
<child #imageSelected="updateBgImg($event)"/>
</div>
</div>
</div>
</template>
<script>
import child from "./components/child";
export default {
name: "App",
data() {
return {
bgImgURL: "Image URL",
bgImg: {}
};
},
methods: {
updateBg(url) {
this.bgImgURL = url;
this.bgImg = {
"background-image": "url(" + this.bgImgURL + ")"
}
}
},
components: {
child
}
}
</script>
child.vue
<template>
<div>
<input type="file" #change="getImage">
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
},
methods: {
getImage(e) {
var file = e.target.files[0];
this.createImage(file);
},
createImage(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
var vm = this;
reader.onload = function() {
vm.$emit("imageSelected", this.result);
};
}
}
};
</script>
Thanks
Update the image in your child. Example on codesandbox
Your parent look like this
<template>
<div id="app">
<div v-for="n in 5" :key='n'>
<child/>
<!-- <child #imageSelected="updateBg($event)"/> -->
</div>
</div>
</template>
<script>
import child from "./components/child";
export default {
name: "App",
data() {
return {
msg: "Parent Message",
// testUrl: "Image URL",
// bgImg: {}
};
},
methods: {
// updateBg(url,index) {
// // this.testUrl = url;
// this.bgImg[index] = {
// "background-image": "url(" + url + ")"
// };
// // console.log(this.bgImg);
// },
},
components: {
child
}
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.wrapper {
width: 300px;
height: 100px;
margin-bottom: 30px;
border: 1px solid red;
background-size: cover;
}
</style>
and your child like this
<template>
<div>
<div class="wrapper" :style="img">
<input type="file" #change="getImage">
</div>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String
},
data(){
return {
img:''
}
},
methods: {
getImage(e) {
var file = e.target.files[0];
this.createImage(file);
},
createImage(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
var vm = this;
reader.onload = function() {
// console.log(this.result)
vm.img = {
"background-image": "url(" + this.result + ")"
}
// don't need
// vm.$emit("imageSelected", this.result);
};
}
}
};
</script>
Updated
Update image in parent from child. Example on codepen
Your parent
<template>
<div id="app">
<div v-for="n in imgCount" :key="n">
<div class="wrapper" :style="imgs[n]">
<sibling/>
<child :image-id="n" #imageSelected="updateBg($event)"/>
</div>
</div>
</div>
</template>
<script>
import child from "./components/child";
import sibling from "./components/simpleCmp";
export default {
name: "App",
data() {
return {
imgCount: 5,
msg: "Parent Message",
testUrl: "Image URL",
bgImg: {},
imgs: []
};
},
methods: {
updateBg(item) {
// console.log(item.index);
this.$set(this.imgs, item.index, item.bg)
}
},
components: {
child,
sibling
}
};
</script>
your child
<template>
<div>
<input type="file" #change="getImage">
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String,
imageId: Number
},
methods: {
getImage(e) {
var file = e.target.files[0];
if (!file) return;
this.createImage(file);
},
createImage(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
var vm = this;
reader.onload = function() {
// console.log(this.result);
vm.$emit("imageSelected", {
index: vm.imageId,
bg: {
"background-image": "url(" + this.result + ")"
}
});
};
}
}
};
</script>
Error loading tiles maps
the page loads but the map is not centered completely and tiles are missing even if I already put the props :center & :zoom
can I initialize the map when loading the page?
Vue-Leaflet
this is my code
<template>
<div class="map">
<l-map class="maps" :zoom="zoom" :center="center">
<l-marker :lat-lng="marker"></l-marker>
<l-tile-layer :url="url" :attribution="attribution"></l-tile-layer>
</l-map>
</div>
</template>
<script>
import { L, LMap, LTileLayer, LMarker } from 'vue2-leaflet';
import { Icon } from 'leaflet';
import 'leaflet/dist/leaflet.css'
delete Icon.Default.prototype._getIconUrl;
Icon.Default.mergeOptions({
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
iconUrl: require('leaflet/dist/images/marker-icon.png'),
shadowUrl: require('leaflet/dist/images/marker-shadow.png')
});
export default {
props:['lat','lng'],
mounted(){
// this.center = L.latLng(this.lat,this.lng)
// this.marker = L.latLng(this.lat,this.lng)
},
data(){
return{
zoom:13,
center: L.latLng(this.lat,this.lng),
url:'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
attribution:'© OpenStreetMap contributors',
marker: L.latLng(this.lat,this.lng),
}
},
components:{
LMap, LTileLayer, LMarker
}
}
</script>
<style>
.map{
width: 100%;
height: 500px;
}
</style>
I would like to know how can I implement a CustomHeader with a custom functionality (other than sort, for example).
Basically what I want to know is how to communicate my HeaderComponent with my component that holds the grid. E.g.:
<template>
<div style="height: 100%" class="table-chart" ref="root">
<div class="title" ref="title">{{ objectData.title }}</div>
<div class="ag-dashboard" style="height: 100%; width: 90%; margin: 0 auto">
<ag-grid-vue
:style="{ height: tableHeight }"
:gridOptions="gridOptions"
:columnDefs="columnDefs"
:rowData="rowData"
/>
</div>
</div>
</template>
<script>
export default {
components: {
'HeaderComponent': {
template: '<span>{{this.params.displayName}} <span #click="custom">CLICK</span></span>',
methods: {
custom() {
// emmit an event here or find a way to comunnicate with the function "customEvent" below
}
}
}
},
methods: {
customEvent() {
console.log('Event from header');
}
},
beforeMount() {
// ... setup Ag-Grid and the HeaderComponent in the columns' headerComponentFramework
}
}
</script>
Apreciate any help,
The cleaner way I found of doing this was through an EventBus:
import Vue from 'vue';
const EventBus = new Vue();
export default {
//...
'HeaderComponent': {
// ...
methods: {
custom() {
EventBus.$emit('customEvent');
}
}
// ...
mounted() {
EventBus.$on('customEvent', () => {
// Do whatever...
});
}
}