OpenLayers: display remote kml - networking

I'm trying to let OpenLayers display a KML file that was retrieved from a server.
For some reason this does not work.
Similar questions have been asked, but I could not find a working example.
What I did was improve one of the examples in the OpenLayers distribution: kml-track.js
I improved it with what I found. This is what it looks like. I feel like I'm missing something obvious.
Any pointers are welcome
var map ;
function init() {
var mercator = new OpenLayers.Projection("EPSG:900913");
var geographic = new OpenLayers.Projection("EPSG:4326");
//note that I have host equal to location// //Math.Random will stop caching//
var mykmlurl = 'http://myserver/kml-track.kml';
map = new OpenLayers.Map({
div: "map",
projection: mercator,
layers: [
new OpenLayers.Layer.OSM(),
//Defiine your KML layer//
new OpenLayers.Layer.Vector("This Is My KML Layer", {
//Set your projection and strategies//
projection: geographic,
strategies: [new OpenLayers.Strategy.Fixed()],
//set the protocol with a url//
protocol: new OpenLayers.Protocol.HTTP({
//set the url to your variable//
url: mykmlurl,
//format this layer as KML//
format: new OpenLayers.Format.KML({
//maxDepth is how deep it will follow network links//
maxDepth: 1,
//extract styles from the KML Layer//
extractStyles: true,
//extract attributes from the KML Layer//
extractAttributes: true
})
}),
styleMap: new OpenLayers.StyleMap({
"default": new OpenLayers.Style({
graphicName: "circle",
pointRadius: 2,
fillOpacity: 0.5,
fillColor: "#ffcc66",
strokeColor: "#666633",
strokeWidth: 1
})
})
})
],
center: new OpenLayers.LonLat(-93.2735, 44.8349).transform(geographic, mercator),
zoom: 8
});
//function called// //timer// //layer to refresh//
window.setInterval(UpdateKmlLayer, 5000, MyKmlLayer);
}
function UpdateKmlLayer(layer) {
//setting loaded to false unloads the layer//
layer.loaded = false;
//setting visibility to true forces a reload of the layer//
layer.setVisibility(true);
//the refresh will force it to get the new KML data//
layer.refresh({ force: true, params: { 'key': Math.random()} });
}

This is an example of how to display a KML layer in OpenLayers which might help you:
http://openlayers.org/dev/examples/kml-layer.html
Are you getting any errors when opening your page - or does it run ok but nothing appear? If you're not getting any errors then it might indicate an issue with how your projections are set up (i.e. your features might not appear where you expect them to)

Related

Update a Mapbox layer by zoom level when loading geojson

Very similar to this tutorial, I would like to create a MapBox map that at a zoomed out level shows regions (labelled Pcode in my data), but once zoomed it switched to a district level (labelled Name). Ideally both these layers would be part of a single geojson shapefile though that can be loaded from an external source (https://raw.githubusercontent.com/Laurent-Smeets-GSS-Account/geojsons/main/geojsons_files/Districts_261_simplified.json). my questions are
how can I format the geojson in such a way that is possible (in R)? (Maybe it is necessary to combine the district polygons into new region polygons and save a seperate geojson file with these regions that gets loaded at another zoom level?)
how do I load the data into Mapbox to make it switch at a certain zoom level?
I am using this example on how to load the code
mapboxgl.accessToken = 'MY TOKEN';
// Create a new map.
const map = new mapboxgl.Map({
container: 'map',
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: 'mapbox://styles/mapbox/streets-v12',
center: [-100.04, 38.907],
zoom: 3
});
map.on('load', () => {
// Add a source for the state polygons.
map.addSource('states', {
'type': 'geojson',
'data': 'https://raw.githubusercontent.com/Laurent-Smeets-GSS-Account/geojsons/main/geojsons_files/Districts_261_simplified.json'
});
// Add a layer showing the state polygons.
map.addLayer({
'id': 'states-layer',
'type': 'fill',
'source': 'states',
'paint': {
'fill-color': 'rgba(200, 100, 240, 0.4)',
'fill-outline-color': 'rgba(200, 100, 240, 1)'
}
});
// When a click event occurs on a feature in the states layer,
// open a popup at the location of the click, with description
// HTML from the click event's properties.
map.on('click', 'states-layer', (e) => {
new mapboxgl.Popup()
.setLngLat(e.lngLat)
.setHTML(e.features[0].properties.Name)
.addTo(map);
});
// Change the cursor to a pointer when
// the mouse is over the states layer.
map.on('mouseenter', 'states-layer', () => {
map.getCanvas().style.cursor = 'pointer';
});
// Change the cursor back to a pointer
// when it leaves the states layer.
map.on('mouseleave', 'states-layer', () => {
map.getCanvas().style.cursor = '';
});
});
You can combine both sets of features into one GeoJSON FeatureCollection, just be sure to add some property that you can filter on, like:
...
{
type: 'Feature',
geometry: {...},
properties: {
type: 'district'
}
}
...
When you load the data, add one source, and two layers. Each layer should have a filter attribute so that only the features of a certain type show in that layer. Make sure one has its visibility set to none when the map first loads.
map.addLayer({
...,
layout: {
visibility: 'none'
},
filter: ['==', 'type', 'district']
});
map.addLayer({
...,
filter: ['==', 'type', 'pcode']
});
Then you can follow the same example you posted, and toggle the visibility on zoom.

Load ESRI Vector Tiles in mapbox-gl

I am using mapbox-gl v 1.8.0. I am trying to load ESRI Vector Tiles using the ArcGIS Online service. Here is my code snippet
mapboxgl.accessToken = '<your access token here>';
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'https://basemaps.arcgis.com/arcgis/rest/services/OpenStreetMap_GCS_v2/VectorTileServer/resources/styles/root.json', // stylesheet location
center: [-74.5, 40], // starting position [lng, lat]
zoom: 9 // starting zoom
});
Do I need to create an access token to access that style in ArcGIS Online?
Any help is greatly appreciated!
This is a very late replay, but yes, you can load Esri Vector tile basemap layers and other layers with MapBox. And yes, you need to sign up for a free account to get an access token.
const apiKey = "YOUR_API_KEY";
const basemapEnum = "ArcGIS:Streets";
const map = new mapboxgl.Map({
container: "map", // the id of the div element
style: `https://basemaps-api.arcgis.com/arcgis/rest/services/styles/${basemapEnum}?type=style&token=${apiKey}`,
zoom: 12, // starting zoom
center: [-118.805, 34.027] // starting location [longitude, latitude]
});
Go here for the full code

Autocomplete polygons while drawing with drawingManager using the Google Maps API v3

I have a basic Google Map, with a drawingManager, like this:
var mapOptions = {
center: centroid,
zoom: 14,
scrollwheel: false,
mapTypeId: google.maps.MapTypeId.HYBRID,
mapTypeControlOptions: {
mapTypeIds: [google.maps.MapTypeId.HYBRID, google.maps.MapTypeId.ROADMAP]
}
}
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
var drawingManager = new google.maps.drawing.DrawingManager({
drawingMode: google.maps.drawing.OverlayType.POLYGON,
drawingControl: false,
polygonOptions: {
clickable: true,
draggable: true,
editable: true,
fillColor: '#ffff00',
fillOpacity: 0.8,
strokeWeight: 5
}
});
drawingManager.setMap(map);
Drawing polygons on the map works like a charm, except for one little thing. I have to explicitly close my polygon, either by clicking the first point, or by double clicking somewhere (or at least, I can't find another way). But I would like for my polygon to be closed at all times while drawing, a bit like this:
http://www.birdtheme.org/useful/v3tool.html
(select 'polygon' in the first select box next to the title).
Now I know this example doesn't use the drawingManager, but creates the polygon by hand, but I am wondering if something similar is possible using the drawingManager. I'm afraid there isn't, since I can't seem to find any reference to it in the manual, but that also kind of surprised about that, since I would think it is something that more people would like to have.
You could just make it yourself; you can easily register the click events.
google.maps.event.addListener(map, 'click', addLatLng);
poly = new google.maps.POLYGON(polyOptions);
poly.setMap(map);
function addLatLng(event) {
path = poly.getPath();
path.push(event.latLng);
}
Because you know the latlng of every point in you're polygon; you can just draw it.
You'll have to redraw it every time a new point is added.

Geofencing with Google Maps

I'm trying to let people draw a rectangle on Google Maps and store the bottomLeft and topRight coordinates.
I know I can draw a Rectangle codewise (see: http://code.google.com/intl/nl-NL/apis/maps/documentation/javascript/reference.html#Rectangle), but before i can load the bounds from my DB the people need to define it themself first off course :)
So my question is, how can I let people draw a rectangle on Google Maps (API v3) and store the coordinates of the bottomLeft and topRight corner?
Already got it to work by looking into events. Took a lot of my time to make :)
This is how i've done it for people that need it to:
function mapsInitialize()
{
startPoint = new google.maps.LatLng(lat,lon);
options = { zoom: 16, center: startPoint, mapTypeId: google.maps.MapTypeId.HYBRID};
map = new google.maps.Map(document.getElementById("map_canvas"), options);
google.maps.event.addListener(map, 'click', function(event) {
if (drawing == true){
placeMarker(event.latLng);
if (bottomLeft == null) {
bottomLeft = new google.maps.LatLng(event.latLng.Oa, event.latLng.Pa);
}
else if (topRight == null){
topRight = new google.maps.LatLng(event.latLng.Oa, event.latLng.Pa);
drawing = false;
rectangle = new google.maps.Rectangle();
var bounds = new google.maps.LatLngBounds(bottomLeft, topRight);
var rectOptions = {
strokeColor: "#FF0000",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35,
map: map,
bounds: bounds
};
rectangle.setOptions(rectOptions);
}
}
});
}
function placeMarker(location) {
var marker = new google.maps.Marker({
position: location,
map: map
});
}
If I understand you properly - You need a way to get users inputting some polyline/polygon. If so - take a look at this example, where polygon is created by clicking a map. It uses some class PolygonCreator and jquery. You can adopt this method, and save result in form field (there possible a number of options: JSON or your own method of serialization)
If you just need to show that polygons on map and nothing more: you even can take advantage of geometry.encoding library and store encoded polylines into database. Or, if you are going to use spatial queries (for instance - detect if some point falls into your polygons) you better use spatial extnsion of some sort: MySQL spatial extensions, PostGIS, etc. In MySQL you can store polyline into Polyline or Polygon typed columns, which is based on OpenGIS formats.
Frankly, here on stackoverflow is a whole bunch of related information.

How do I get a reference to the polygon clicked? (google maps api v3)

I've set up some polygons, drew them on the map just fine. I also managed to fire console.log when they were clicked. However, how would I go on about figuring out which polygon was actually clicked?
As you can see in my sample code here I store each object within the collection "lots", however - clicking them only gives me the lat-long of the click. I figured I might need to loop through my polygons and check if the point was clicked is intersecting them and thus figure out which polygon it is... is there an easier solution?
var lot = new google.maps.Polygon({
paths: me.area,
strokeColor: 'black',
strokeOpacity: 0.35,
strokeWeight: 1,
fillColor: fillcol,
fillOpacity: 0.35
});
lot.setMap(map);
var obj = {
'id':me.id,
'rented':me.rented,
'area':lot
};
google.maps.event.addListener(lot, 'click', function(event) {
console.log(event);
});
lots.push(lot);
Why don't assign to each polygon some id property when you create them and later just use this.myID? Truly speaking, you can hang all information you need on that polygon object.
var lot = new google.maps.Polygon({
paths: me.area,
strokeColor: 'black',
strokeOpacity: 0.35,
strokeWeight: 1,
fillColor: fillcol,
fillOpacity: 0.35
});
lot.setMap(map);
var obj = {
'id':me.id,
'rented':me.rented,
'area':lot
};
lot.objInfo = obj;
google.maps.event.addListener(lot, 'click', function(event) {
console.log(this.objInfo);
});
lots.push(lot);
It would be more effective than path comparison in a loop, or am i missing something? :)
If I can step in a little late with a different solution, I was having the same problem and discovered that you can define custom properties on a polygon.
My example (which creates a state on a map of the U.S.)
poly = new google.maps.Polygon({
map_state_id: map_state_id,
paths: pts,
fillColor: colour,
fillOpacity: 0.66,
strokeWeight: 1,
clickable:true
});
In this case "map_state_id" is the custom property. I have defined it to be the ID of the state (1 for Alabama, 2 for Alaska, etc.)
Then when the particular state is clicked later, this "map_state_id" can be passed into the event function.
google.maps.event.addListener(poly, 'click', function()
{
var map_state_id = this.map_state_id; //retrieve correct state_id
$.ajax(
{
type: "POST",
url: "http://www...get_state_info.php",
data: {state_id : map_state_id},
dataType: "html",
success: function(data)
{
$("#state_info").html(data); //display some info
}
});
});
I found this particular concept at http://dominoc925.blogspot.com/2011/12/add-your-own-property-field-to-google.html
Turned out getPath() works like a charm. I did not realize I actually got the polygon reference passed on the click event, to match this with my stored "lots" I simply loop through my stored lots and compare this.getPath to other.getPath, if they match I know which lot was clicked and can now show info related to this particular object.
Here's a code sample:
(where parking is an array of my parking area objects which themselves have arrays containing parking lot objects)
google.maps.event.addListener(lot, 'click', function(event) {
var myPath = this.getPath();
for(var i = 0; i < parking.length; i++){
for(var j = 0; j < parking[i].lots.length; j++){
var lot = parking[i].lots[j];
var otherPath = lot.poly.getPath();
if(otherPath == myPath){
console.log(lot);
break;
}
}
}
});

Resources