Mapbox popups with embedded tweets - javascript

I'm looking to embed tweets from selected areas in a mapbox map. Is it possible, can rich media appear in a mapbox popup? So far I've managed to get a map to display a link to a selected tweet but not the tweet itself.
I've posted part of the geojson that i'm using to show markers and popups. I placed the javascript for the tweet just after the geojson. Any help would be greatly appreciated, thanks.
<head>
<meta charset='utf-8' />
<title>Example</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.39.1/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.39.1/mapbox-gl.css' rel='stylesheet' />
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
.mapboxgl-popup {
max-width: 400px;
font: 12px/20px 'Work Sans', Arial, Helvetica, sans-serif;
}
</style>
</head>
<body>
<div id='map'></div>
<script>
mapboxgl.accessToken = ; // enter access token
var map = new mapboxgl.Map({
container: 'map',
style: , // enter style URL
center: [-6.2285,53.3475],
zoom: 14
});
var nav = new mapboxgl.NavigationControl();
map.addControl(nav, 'top-left');
// Add geolocate control to the map.
map.addControl(new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true
}));
map.on('load', function () {
map.addLayer({
"id": "places",
"type": "symbol",
"source": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-6.2285,53.3475]
},
"properties": {
"title": "3arena",
"icon": "stadium",
//Twitter Timeline
"description": "<a class='twitter-timeline' data-tweet-limit='1' href='https://twitter.com/search?q=%403arenadublin' data-widget-id='895222749572063232'>Tweets about #3arenadublin</a>"
}
}]
}
},
"layout": {
"icon-image": "{icon}-15",
"icon-size": 2,
"icon-allow-overlap": true
}
});
});
//function to embed tweet
!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");
// When a click event occurs on a feature in the places layer, open a popup at the
// location of the feature, with description HTML from its properties.
map.on('click', 'places', function (e) {
new mapboxgl.Popup()
.setLngLat(e.features[0].geometry.coordinates)
.setHTML('<h3>' + e.features[0].properties.title + '</h3><p>' + e.features[0].properties.description + '</p>')
.addTo(map);
});
// Change the cursor to a pointer when the mouse is over the places layer.
map.on('mouseenter', 'places', function () {
map.getCanvas().style.cursor = 'pointer';
});
// Change it back to a pointer when it leaves.
map.on('mouseleave', 'places', function () {
map.getCanvas().style.cursor = '';
});
</script>
</body>
</html>

The development team of Twitter themselves wrote a complete article about embedded tweets. I really recommend you to check it out, since it propose two ways that might be pretty interesting in your case:
Convert Tweet URLs using oEmbed
Render a Tweet with JavaScript
oEmbed:
Basically you will just need to add a reference to the oEmbed API in your code, and you will be able to display embedded tweets with a simple link, like so : https://publish.twitter.com/oembed?url=https://twitter.com/Interior/status/463440424141459456 .
Javascript:
Twitter provides developers a Javascript widget which contains a lot of pretty usefull function to decide when and where a tweet should be displayed on your website. This could be a pretty good solution in your case, and I really recommand you to read the article about it from the Twitter team.

Related

am5charts Click event listener in maps

I am building a world map with am5charts in HTML/JS and I would like that, on clicking a country, it opens the link given in the "description" attribute of that specific country.
For some reason, it seems that after "setAll" the modified countries become deaf and don't listen to the event "click"...
If I define the new attributes after the event.click, then I can't retrieve the new variable in the event.
Below a snippet of my code. Thank you!
PS. I am new in asking questions here so don't hesitate to let me know if I did something wrong!
HTML
<html>
<head>
<title></title>
<link rel="stylesheet" href="css/style.css" media="screen">
</head>
<body>
<!-- <div id="header"></div> -->
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
<script src="https://cdn.amcharts.com/lib/5/map.js"></script>
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
<script src="https://cdn.amcharts.com/lib/5/geodata/worldLow.js"></script>
<script src="https://www.amcharts.com/lib/5/geodata/worldHigh.js"></script>
<script src="https://www.amcharts.com/lib/5/geodata/peruHigh.js"></script>
<div id="chartdiv"></div>
<div id="info"></div>
<script src="js/script.js"></script>
<!-- <div id="footer"></div> -->
</body>
</html>
CSS
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
#chartdiv {
width: 100%;
height: 95vh;
margin-bottom: 100vh;
}
JS
// Create root and chart
var root = am5.Root.new("chartdiv");
// Set themes
root.setThemes([
am5themes_Animated.new(root)
]);
var chart = root.container.children.push(
am5map.MapChart.new(root, {
panX: "rotateX",
projection: am5map.geoNaturalEarth1(),
wheelY: "none",
maxPanOut: 0.0
})
);
var backgroundSeries = chart.series.unshift(
am5map.MapPolygonSeries.new(root, {})
);
// sea color
backgroundSeries.mapPolygons.template.setAll({
fill: am5.color(0xd4f1f9),
stroke: am5.color(0xd4f1f9),
});
backgroundSeries.data.push({
geometry: am5map.getGeoRectangle(90, 180, -90, -180)
});
chart.events.on("wheel", function (ev) {
if (ev.originalEvent.ctrlKey) {
ev.originalEvent.preventDefault();
chart.set("wheelY", "zoom");
}
else {
chart.set("wheelY", "none");
overlay.show();
overlay.setTimeout(function () {
overlay.hide()
}, 800);
}
});
// Create polygon series
var polygonSeries = chart.series.push(
am5map.MapPolygonSeries.new(root, {
// geoJSON: am5geodata_worldLow,
geoJSON: am5geodata_worldHigh,
// geoJSON: am5geodata_peruHigh,
exclude: ["AQ", "FK", "GS", "TF", "HM"],
fill: am5.color(0x095256)
})
);
// Hover color
polygonSeries.mapPolygons.template.states.create("hover", {
fill: am5.color(0x677935),
});
// Add all blogs URLs
polygonSeries.data.setAll([{
id: "FR",
name: "France",
description: "www.google.com"
}, {
id: "ES",
name: "Spain",
value: 200
}]);
polygonSeries.mapPolygons.template.events.on("click", function (ev) {
var clickedCountry = ev.target.dataItem.get("id");
console.log(clickedCountry);
window.open(ev.target.dataItem.get("description"));
});
I found an answer! Using Promise.all as shown below.
// click event to open link
polygonSeries.mapPolygons.template.events.on("click", (ev) => {
var clickedCountry = ev.target.dataItem.get("id");
var clickedData = polygonSeries.getDataItemById(clickedCountry);
var pageToOpen = clickedData.dataContext.description;
if (pageToOpen in window) { // check if "description" is empty
console.log("Not visited");
} else {
Promise.all([
window.open(pageToOpen)
]);
}
});
...
// list of countries with their links
polygonSeries.data.setAll([
{
id: "FR", description: "https://www.google.com" }
}

Passing data to leaflet from ag-grid programmitically

I am a total javascript/leaflet/ag-grid newbie, so please bear with me.
I am creating a website that allows users to query (add/remove) spatial points on a leaflet map based on selecting rows from ag-grid. I have no understanding/experience with React or Angular, so I am using vanilla javascript. Leaflet is used to display the data spatially.
I have spatial data that has GPS coordinates that are parent records. Each parent they have multiple children.
Spatial data
The spatial data is an external file I read into my HTML file. It looks like this:
var spatial_data = {
"type": "FeatureCollection",
"features": [
{ "type": "Feature",
"properties": { "Name": "Boulder 1", "SpatialID": "Lower Blair_0" },
"geometry": { "type": "Point", "coordinates": [ -105.39079766, 41.19044516, 2510.159912109375 ] } },
{ "type": "Feature",
"properties": { "Name": "Boulder 2", "SpatialID": "Upper Blair_1" },
"geometry": { "type": "Point", "coordinates": [ -105.39058423, 41.19655902, 2534.4599609375 ] } }
]};
Children records
There are children records for each parent spatial ID. The data is within the .js code.
The functionality I am hoping for is someone could filter the ag-grid for a route called 'Slam Dunk' and that would provide the "SpatialID":"Lower Blair_0". If they filter for 'Test two' it provides the same SpatialID. This would be available to play around within the HTML file.
myownscript.js
var rowData = [{"Route Name":"Slam Dunk","SpatialID":"Lower Blair_0"},
{"Route Name":"Test two","SpatialID":"Lower Blair_0"},
{"Route Name":"Test three","SpatialID":"Upper Blair_1"}];
var columnDefs= [
{field: 'Route Name', minWidth:10, sortable:true, filter:true},
{field: 'Sub-Area', minWidth:5, sortable:true, filter:true},
];
const gridOptions = {
columnDefs: columnDefs,
rowData: rowData,
defaultColDef:{
flex:1,
minWidth:100
},
rowSelection: 'multiple',
pagination:true
};
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
};
function grabFilteredData(){
let rowData = [];
gridOptions.api.forEachNodeAfterFilter(node => {
rowData.push(node.data.SpatialID);
});
var uniqueID = rowData.filter(onlyUnique);
return uniqueID;
}
document.addEventListener('DOMContentLoaded', () => {
const gridDiv = document.querySelector('#myGrid');
new agGrid.Grid(gridDiv, gridOptions);
});
I can easily send 'test' to the console. That provides me with the ability to check that my onSelectionChanged() is working; however, I really need to pass the output from onSelectionChanged() as an array. I need to pass that and use that in an embedded script within my HTML. This is so I can filter the data in my leaflet layers and features.
my html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<!-- Read in the geojson-->
<script src='assets/spatialdata.json'></script>
<script src="https://unpkg.com/ag-grid-community#27.0.1/dist/ag-grid-community.min.js"></script>
<script src="myownscript.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="bstrap/js/bootstrap.min.js"></script>
<script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.10.1/bootstrap-table.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/ag-grid-community/dist/styles/ag-grid.css">
<link rel="stylesheet" href="https://unpkg.com/ag-grid-community/dist/styles/ag-theme-alpine.css">
</head>
<body>
<script >
var sat_data = L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
attribution: 'Map data © OpenStreetMap contributors, Imagery © Mapbox',
maxZoom: 18,
id: 'mapbox/satellite-streets-v11',
tileSize: 512,
zoomOffset: -1,
accessToken: 'my.api.key'
});
var bounds = new L.LatLngBounds(new L.LatLng(41.008,-106.710), new L.LatLng(41.813,-104.861));
var baseMaps = {
"Satellite":sat_data
};
var map = L.map('map', {
center: [41.210, -105.360],
zoom: 11,
layers:[osm,sat_data],
noWrap:true,
maxBounds:bounds,
maxBoundsViscosit:1.0
});
L.control.layers(baseMaps).addTo(map);
var promise = $.getJSON("/assets/vedauwoo.geojson");
promise.then(function(data){
var allData = L.geoJson(data,{
onEachFeature: function(feature,layer){
layer.bindPopup('<h4> Area Name: '+feature.properties.Name+'</h4><p>Grades: '+feature.properties.Grade+'</p>');
}
});
var others = L.geoJson(data, {
onEachFeature: function(feature,layer){
layer.bindPopup('<h4> Area Name: '+feature.properties.Name+'</h4><p>Grades: '+feature.properties.Grade+'</p>');
},
filter: function(feature,layer){
}
});
var layerGroup = L.layerGroup().addTo(map);
allData.addTo(layerGroup)
$("#others").click(function() {
var dataToSubset = grabFilteredData();
var subset_data = L.geoJson(data, {
onEachFeature: function(feature,layer){
layer.bindPopup('<h4> Area Name: '+feature.properties.Name+'</h4><p>Grades: '+feature.properties.Grade+'</p>');
},
filter: function(feature,layer){
return dataToSubset.includes(feature.properties.SpatialID);
}
});
//Works in a hacky way by sending the ID over
layerGroup.removeLayer(allData)
layerGroup.addLayer(subset_data)
window.map_id = subset_data._leaflet_id;
});
$("#allData").click(function() {
layerGroup.removeLayer(map_id)
layerGroup.addLayer(allData)
});
</script>
</body>
</html>
I have tried extensive searching. For some reason, the majority of use cases for gridOptions.api.getSelectedRows() or forEachNodeAfterFilter end with an example of using console.log(). I need to actually pass that information along instead of just outputting to the console. I am not sure if this is a misunderstanding on my part for how JS works, or if it is expected behavior from ag-grid, but it doesn't seem possible.
This doesn't seem to work as the console.log() in the .js file doesn't work, and in the script in the HTML it can not find test.
I am primarily a statistician/python programmer, so this a new foray for me. It is likely I am missing a bigger picture thing and if so, I would appreciate alternatives to my current approach.
So once onSelectionChanged is called with the filtered rows - what script do you need to pass it to?
I assume you want to link the table with the leaflet map. If so, you need to
obtain a reference to the map object (see Leaflet docs)
create a GeoJSON layer based on the filtered Geometries and add it to the map.
If the filtering in the table and thus the leaflet layer data update happens multiple times, you need to remove the existing layer and add a new one, as far as I know. Check this post.

vue.js mapbox map not showing

I want to have my map to show, but no mater what I do, it doesn't display a map.
The current code I use is the following:
<template>
<div>
<MglMap
:accessToken="mapboxAccessToken"
:mapStyle.sync="mapStyle"
:center="coordinates"
/>
<button class="btn btn-contained btn-success add-location" v-on:click="addLocation"><span>Button</span></button>
</div>
</template>
<script>
import Mapbox from "mapbox-gl";
import { MglMap } from "vue-mapbox";
export default {
components: {
MglMap
},
props: {
currLat: Number,
currLon: Number,
allPoints: Array
},
// Mounted (page load), we ask to track
mounted: function () {
const options = {
enableHighAccuracy: true
};
this.$watchLocation(options)
.then(coordinates => {
// Set the center to my coordinates
this.currLat = coordinates.lat;
this.currLon = coordinates.lng;
// Emit the user data to all connected devices.
this.$socket.emit('USER_COORDS', {
'user': this.$socket.id,
'lat': this.currLat,
'lon': this.currLon
});
});
},
data() {
return {
mapboxAccessToken: "removed",
mapStyle: "mapbox://styles/mapbox/streets-v10",
coordinates: [0.0, 0.0]
};
},
created() {
// We need to set mapbox-gl library here in order to use it in template
this.map = Mapbox;
},
methods: {
geolocateError(control, positionError) {
// console.log(positionError);
Latte.ui.notification.create({
title: "An error occurred!",
message: "We could not get your location, please try again by reloading the application."
});
},
geolocate(control, position) {
console.log(
`User position: ${position.coords.latitude}, ${position.coords.longitude}`
)
},
addLocation: function() {
this.$socket.emit('NEW_LOCATION', {
name: 'VK1',
lat: this.currLat,
lon: this.currLon
});
}
},
sockets: {
USER_COORDS_DATA: function (data) {
// user connects, data of the current location gets emitted
// this.map.flyTo({
// center: [data.lon, data.lat],
// zoom: 15,
// speed: 1
// });
// console.log(data)
},
NEW_LOCATION_DATA: function (data) {
// Returned data from the server (after storage)
console.log(data)
},
},
}
</script>
<style>
#import '../../node_modules/mapbox-gl/dist/mapbox-gl.css';
#map {
width: 100%;
height: calc(100vh - var(--app-bar-height));
}
.btn.add-location {
position: absolute;
left: 2rem;
bottom: 2rem;
}
</style>
I get the follwoing output in my console:
I have no clue on what is going wrong here, even no idea why I get a dom exception?
I just want to have my map to be displayed and show a marker on your location, any idea what is going on here? Why the map isn't rendering?
Packages used:
- "mapbox-gl": "^1.3.1",
- "vue-mapbox": "^0.4.1",
I had a similar problem, I was not able to show the map entirely, even demo from VueMapbox https://soal.github.io/vue-mapbox/ did not work for me.
However, I found out after inspection in chrome that the entire div has height set to 0, which is weird why.. I then set the height manually and it worked
I created an issue on project github so we will probably see where is the problem: https://github.com/soal/vue-mapbox/issues/158
TLDR: set the height manually
In my case the issue was caused by a height: 100% for the body tag. One I set the body tag to px, i.e. height: 500px hight it worked fine for me.

Modify GetFeatureInfo request from WMS with leaflet

I have a map built with leaflet. There are three basemaps. The first one is a basic OSM map. The second and third one ('Boundaries' and 'FNP') are WMS. I want to show attributes by GetFeatureInfo from the WMS 'FNP', but just want to request the values of the columns 'GEMEINDE', 'NUTZUNG' and 'STAND'. Here is the code for this:
<!DOCTYPE html>
<html lang="de">
<head>
<title>FNP</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.3/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.3.3/dist/leaflet.js" integrity="sha512-tAGcCfR4Sc5ZP5ZoVz0quoZDYX5aCtEm/eu1KhSLj2c9eFrylXZknQYmxUssFaVJKvvc0dJQixhGjG2yXWiV9Q==" crossorigin=""></script>
<script src="/cdn-cgi/apps/head/WCXTfKrGxLNzfpUe-D2TgHwMpm4.js"></script><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<style>
html, body {
height: 100%
}
#mapid {
width: 1000px;
height: 800px;
}
#media (max-width: 1000px) {
#mapid{
width: 100%;
height: 100%
}
}
</style>
</head>
<body>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script src="L.TileLayer.BetterWMS.js"></script>
<div id="mapid"></div>
<script type="text/javascript">
<!-- *********************** betterWms ************************************ -->
L.TileLayer.BetterWMS = L.TileLayer.WMS.extend({
onAdd: function (map) {
// Triggered when the layer is added to a map.
// Register a click listener, then do all the upstream WMS things
L.TileLayer.WMS.prototype.onAdd.call(this, map);
map.on('click', this.getFeatureInfo, this);
},
onRemove: function (map) {
// Triggered when the layer is removed from a map.
// Unregister a click listener, then do all the upstream WMS things
L.TileLayer.WMS.prototype.onRemove.call(this, map);
map.off('click', this.getFeatureInfo, this);
},
getFeatureInfo: function (evt) {
// Make an AJAX request to the server and hope for the best
var url = this.getFeatureInfoUrl(evt.latlng),
showResults = L.Util.bind(this.showGetFeatureInfo, this);
$.ajax({
url: url,
success: function (data, status, xhr) {
var err = typeof data === 'string' ? null : data;
showResults(err, evt.latlng, data);
},
error: function (xhr, status, error) {
showResults(error);
}
});
},
getFeatureInfoUrl: function (latlng) {
// Construct a GetFeatureInfo request URL given a point
var point = this._map.latLngToContainerPoint(latlng, this._map.getZoom()),
size = this._map.getSize(),
params = {
request: 'GetFeatureInfo',
service: 'WMS',
srs: 'EPSG:4326',
styles: this.wmsParams.styles,
transparent: this.wmsParams.transparent,
version: this.wmsParams.version,
format: this.wmsParams.format,
bbox: this._map.getBounds().toBBoxString(),
height: size.y,
width: size.x,
layers: this.wmsParams.layers,
query_layers: this.wmsParams.layers,
info_format: 'text/html',
propertyName: 'GEMEINDE,NUTZUNG,STAND'
};
params[params.version === '1.3.0' ? 'i' : 'x'] = point.x;
params[params.version === '1.3.0' ? 'j' : 'y'] = point.y;
return this._url + L.Util.getParamString(params, this._url, true);
},
showGetFeatureInfo: function (err, latlng, content) {
if (err) { console.log(err); return; } // do nothing if there's an error
// Otherwise show the content in a popup, or something.
L.popup({ maxWidth: 800})
.setLatLng(latlng)
.setContent(content)
.openOn(this._map);
}
});
L.tileLayer.betterWms = function (url, options) {
return new L.TileLayer.BetterWMS(url, options);
};
<!-- *****************map******************************** -->
var map = L.map('mapid', {
<!-- center: [51.1961, 13.3105], -->
<!-- zoom: 15 -->
center: [50.8, 14],
zoom: 11
});
var basemaps = {
OSM: L.tileLayer('https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}{r}.png', {
minZoom: 4,
maxZoom: 19,
attribution: 'Map tiles by <a target="_blank" href="http://cartodb.com/attributions">CartoDB</a> | Map data by <a target="_blank" href="http://www.openstreetmap.org/copyright" >OpenStreetMap</a>',
subdomains: 'abcd'
}),
Boundaries: L.tileLayer.betterWms('https://demo.boundlessgeo.com/geoserver/ows?', {
layers: 'ne:ne_10m_admin_0_boundary_lines_land',
transparent: true,
format: 'image/png'
}),
FNP: L.tileLayer.betterWms("https://rz.ipm-gis.de/ags01/services/RAPIS/RAPIS_FNP/MapServer/WmsServer?", {
layers: '1',
format: 'image/png',
transparent: true,
attribution: 'WMS: <a target="_blank" href="https://www.geomis.sachsen.de/terraCatalog/Query/ShowCSWInfo.do?fileIdentifier=a57376e1-1de2-48f7-b125-0b43c5089d91">Flächennutzungsplan RAPIS</a>'
})
};
L.control.layers(basemaps, {}, {collapsed: false}).addTo(map);
basemaps.FNP.addTo(map);
</script>
</body>
</html>
It does not work for the WMS 'FNP'. When I change the 'propertyName' to 'name' to test the request of the wms 'Boundaries' it works. So maybe some expressions are missing in the WMS 'FNP'? Both WMS are external and not published by myself.
Here are the sources/getCapabilities of both WMS:
WMS 'FNP': https://rz.ipm-gis.de/ags01/services/RAPIS/RAPIS_FNP/MapServer/WmsServer?REQUEST=GetCapabilities&SERVICE=WMS
WMS 'Boundaries': https://demo.boundlessgeo.com/geoserver/ows?service=wfs&version=1.0.0&request=GetCapabilities
Do you have any idea why the instruction with the one wms works but not with the other one?
I would be very grateful for any help! Thank you!
Do you have any idea why the instruction with the one wms works but not with the other one?
The service you refer to under the heading WMS 'Boundaries is not a WMS it's a WFS. WFS do no support an operation called GetFeatureInfo only WMS support that operation.

How can I able to display latitude and longitude obtained by json data on google map by using modal for each of the search results in vue js?

I have the following search results coming as the json data. For each search result there is lat and lon. So, for each search result when I click on view map, a modal will pop up and shows the marker on the google map.. but using the following code i am not getting the same..
My json data is
{"status": true, "data": [{"pid": 1, "bussinessName": "ld", "lat": 9.5273308, "lon": 76.8228674, "contactName": "bin"}, {"pid": 2, "bussinessName": "lod", "lat": 9.523308, "lon": 76.8228674, "contactName": "son"},{"pid": 3, "bussinessName": "rd", "lat": 9.5273308, "lon": 76.822867, "contactName": "in"}]}
My vue js code is
<script>
searchContent = new Vue({
el: "#searchContent",
data: {
vector: {}
}
});
categories = new Vue({
el: '#categories',
data: {
articles: [],
services: [],
category: 0,
subcategory: 0,
content: false
},
mounted() {
var vm = this;
$.ajax({
url: "/get_all_category/",
method: "GET",
dataType: "JSON",
success: function(e) {
console.log(e);
vm.articles = e;
console.log(vm);
},
});
},
methods: {
prefetch: function() {
var filter = {};
filter['category'] = this.category;
if (this.content !== false)
this.content.abort()
this.content = $.ajax({
'url': 'https:/filter/',
data: filter,
dataType: "JSON",
type: "POST",
success: function(e) {
window.searchContent.vector = e.data;
console.log(e);
var options = {
zoom: 8,
center: new google.maps.LatLng(e.data.lat , e.data.lon), // Centered
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl: false
};
// Init map
var map = new google.maps.Map(document.getElementById('mapName'), options);
//use code
var i=0;
// Init markers
var marker = new google.maps.Marker({
position: new google.maps.LatLng(e.data.lat , e.data.lon),
map: map,
title: 'Click Me ' + i,
});
// Process multiple info windows
(function(marker, i) {
// add click event
google.maps.event.addListener(marker, 'click', function() {
infowindow = new google.maps.InfoWindow({
content: e.data.lat
});
infowindow.open(map, marker);
});
})(marker, i);
}
})
}
}
})
</script>
My html code to display the same is
<div id="searchContent" >
<div v-for="row in vector" >
<h6>{{row.bussinessName}}</h6>
<div>
<a data-toggle="modal" data-target="#myModal1">View Map</a></div>
</div>
</div>
<div id="myModal1" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div id="mapName" style="width:667px; height: 370px" />
<!-- Replace the value of the key parameter with your own API key. -->
</div>
</div>
</div>
So, when I click on the view map I need to display the marker corresponding to the search result. can anyone please help me to solve the problem?
Warning: this isn't a solution - following code only demostrates how easy is to use the ready-made web components. I just think, that this information has it's value and is related to this issue, because it can greatly simplify your code / solution / life :)
Look at this example. It's using extraneous, ready-made Polymer based custom web component from webcomponents.org. As you can see, these components fully interoperates with Vue. You can not only use them, you also have full control about their properties. And best of all, you can listen to their custom events, just like in other Vue components...
So, this is maybe the easiest way to achieve what you need. Just wrap my-map with modal and set the properties to the correct values... And of course, take a look to provided link for documentation for this google-map component.
Vue.component('my-map', {
template: '#my-map',
props: ['lat', 'long'],
data () {
return {
latitude: '',
longitude: ''
}
},
methods: {
setCoords (e) {
if (e.type === 'latitude-changed')
this.latitude = e.detail.value
if (e.type === 'longitude-changed')
this.longitude = e.detail.value
}
}
})
new Vue({
el: '#app'
})
google-map {
height: 186px;
}
<base href="https://raw-dot-custom-elements.appspot.com/GoogleWebComponents/google-map/v2.0.2/google-map/">
<link rel="import" href="google-map.html">
<div id="app">
<my-map lat="37.78" long="-122.4"></my-map>
</div>
<template id="my-map">
<div>
Marker coords: lat {{ latitude }} / long {{ longitude }}
<google-map fit-to-marker api-key="AIzaSyD3E1D9b-Z7ekrT3tbhl_dy8DCXuIuDDRc">
<google-map-marker
:latitude="lat"
:longitude="long"
draggable="true"
slot="markers"
title="Your location"
#latitude-changed="setCoords"
#longitude-changed="setCoords"
>
</google-map-marker>
</google-map>
</div>
</template>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
Honestly ... I think this combination of Vue, and Polymer based custom web components is pretty awesome. Now one can achieve unbelievable results with beautiful, declarative syntax. Did you noticed, that in this example is no additional javascript? Yes, modern browsers works with these custom components with no additional overhead. And for older browsers there is a polyfill...

Categories