I am trying to offline-render a part of OpenStreetMap, previously loaded as map.osm (OSM XML). I'm starting a localhost and loading the xml from disk.
I tried to use similar example (https://openlayers.org/en/latest/examples/vector-osm.html) changing only the source to my file, yet this didn't work out. Data loaded is pretty much similar to data I see in the example.
I tried a bunch of various approaches, and I still can't render the map. I get no errors, and I can't get what I'm missing.
var vectorSource = new VectorSource({
format: new OSMXML()
});
var xml = await fetch('map.osm').then(res => res.text());
var features = (new OSMXML()).readFeatures(xml);
// Features are parsed OK
vectorSource.addFeatures(features);
var vector = new VectorLayer({
source: vectorSource,
// Using styles, I don't post them here (a lot of code)
style: function (feature) {
for (var key in styles) {
var value = feature.get(key);
if (value !== undefined) {
for (var regexp in styles[key]) {
if (new RegExp(regexp).test(value)) {
return styles[key][regexp];
}
}
}
}
return null;
}
});
map = new Map({
layers: [vector],
target: document.getElementById('map'),
view: new View({
center: [0, 0],
maxZoom: 0,
zoom: 0
})
});
Related
On 2nd version of a heatmapping system I am making using google maps api.
Initial version works fine but uses PHP and MySQL to write the points into the map, this displays fine and can then alter map (e.g. radius / opacity) using heatmap.set the only problem is you cant change heatmap displayed without reloading (points are effectively hard coded into script by PHP).
So I have altered original code to instead call a php script (using a serialized version of form) which returns query in JSON format, this works fine in as far as get a blank map to begin with, can choose some settings and it will load heatmap fine, can change these and it will do a new heatmap (which it layers on top of old one) so have gone through how to remove previous heatmap and hit a brick wall...
If I try any function calling heatmap. I get "heatmap not defined" this includes all the previous functions that worked fine in old map.
Full code is quite large so will hopefully cover everything in these snippets...
Initial map load...
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 13,
center: {lat: 51.514898, lng: -0.144432},
mapTypeId: 'roadmap'
});
}
Make a heatmap...
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var heatmapData = [];
myObj = JSON.parse(this.responseText);
for (var i = 0; i < myObj.points.length; i++) {
var latLng = new google.maps.LatLng(myObj.points[i].lat,myObj.points[i].lng);
var pushData = {
location: latLng,
weight: myObj.points[i].weight
}
heatmapData.push(pushData);
}
var heatmap = new google.maps.visualization.HeatmapLayer({
data: heatmapData,
maxIntensity: 10,
radius:30,
opacity: 0.4,
map: map
})
}
};
Which is called by form submit...
$( "form" ).on( "submit", function( event ) {
event.preventDefault();
url = "query.php?" + $( this ).serialize();
xmlhttp.open("GET", url, true);
xmlhttp.send();
});
and an example function which don't work (value set by a slider with an onchange event)...
function changeOp(val) {
heatmap.set('opacity', val);
}
The heatmap is currently local to the xmlhttp.onreadystatechange function, you can't access it outside of there. You need to declare it outside of that function (the global scope works, like the map variable), then you can access it to modify it later (or in the next call to the AJAX request).
var heatmap;
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var heatmapData = [];
myObj = JSON.parse(this.responseText);
for (var i = 0; i < myObj.points.length; i++) {
var latLng = new google.maps.LatLng(myObj.points[i].lat, myObj.points[i].lng);
var pushData = {
location: latLng,
weight: myObj.points[i].weight
}
heatmapData.push(pushData);
}
heatmap = new google.maps.visualization.HeatmapLayer({
data: heatmapData,
maxIntensity: 10,
radius: 30,
opacity: 0.4,
map: map
})
}
};
I'm trying to create a heatmap using Google's API, but running into a few issues. The main issue I have run into so far is converting a large set of about ~25000 addresses into geocoordinates for use in the API. The two approaches I have used are Google's own API, which has heavy limitations, and Python's Geopy module, which also has limitations. Since I am trying to convert ~25000, Geopy's one second delay is a pretty steep issue.
The second issue I can see coming is a size limitation. Once I have a list of ~25000 geocoordinates, putting those into an array in Javascript seems ridiculous. Assuming a user would upload a text file in a format like this:
12.3456,-12.3456
23.4567,-23.4567
...
Would there be a way to process the file in blocks, or some other work around?
In case it helps, this is my current Javascript code for processing a file of addresses. I'm planning on changing the file reading format to find a better system.
var map, heatmap, geocoder;
var MVCarr;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 36.85, lng: -75.97},
zoom: 7
});
MVCarr = new google.maps.MVCArray();
heatmap = new google.maps.visualization.HeatmapLayer({
data: MVCarr,
map: map
})
}
window.onload = function() {
var fileInput = document.getElementById('fileInput');
var fileDisplayArea = document.getElementById('fileDisplayArea');
geocoder = new google.maps.Geocoder();
fileInput.addEventListener('change', function(e) {
var file = fileInput.files[0];
var reader = new FileReader();
reader.onload = function(e) {
var mySplit = (reader.result).split("\n");
for(var i = 0, len = mySplit.length; i < len; i++) {
//console.log(mySplit[i]);
geocodeAddress(geocoder, mySplit[i]);
}
}
reader.readAsText(file);
});
}
function geocodeAddress(geocoder, address) {
geocoder.geocode({'address': address}, function(results, status) {
if (status === google.maps.GeocoderStatus.OK) {
MVCarr.push(results[0].geometry.location);
console.log(MVCarr.length);
} else {
console.log('Failed: ' + status);
}
});
}
I am trying to make a polygon editable after it is drawn with ol.interaction.Draw.When I instantiate ol.interaction.Modify I get a "b.attachEvent is not a function" error. This is the code:
drawPolygon.on("drawend",function(p)
{
setTimeout(function()
{
modifyPoligon = new ol.interaction.Modify({
features: vectorSource.getFeatures()
});
},200);
}
I also use a timeout because in the drawend call the Feature is still not in the layer, is there a better way to get a callback after the feature is drawn and on the layer?
Not sure if suits your case but here's a fiddle with a similar approach: https://jsfiddle.net/ko822xjw/
// Create a draw interaction and add it to the map:
drawInteraction = new ol.interaction.Draw({ source:vectorSource, type:"Polygon" });
map.addInteraction(drawInteraction);
// set listener on "drawend":
drawInteraction.on('drawend', function(e) {
// get drawn feature:
var feature = e.feature;
// remove draw interaction:
map.removeInteraction(drawInteraction);
// Create a select interaction and add it to the map:
selectInteraction = new ol.interaction.Select();
map.addInteraction(selectInteraction);
// select feature:
selectInteraction.getFeatures().push(feature);
// do something after drawing (e.g. saving):
// ...
// Create a modify interaction and add to the map:
modifyInteraction = new ol.interaction.Modify({ features: selectInteraction.getFeatures() });
map.addInteraction(modifyInteraction);
// set listener on "modifyend":
modifyInteraction.on('modifyend', function(evt) {
// get features:
var collection = evt.features;
// There's only one feature, so get the first and only one:
var featureClone = collection.item(0).clone();
// do something after modifying (e.g. saving):
// ...
});
});
It could be as simple as:
var
features = new ol.Collection(),
modify = new ol.interaction.Modify({
features: features
}),
vectorSource = new ol.source.Vector({
features: features
}),
vectorLayer = new ol.layer.Vector({
source: vectorSource
}),
map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.MapQuest({layer: 'osm'})
}),
vectorLayer
],
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
}),
drawPolygon = new ol.interaction.Draw({
features: features,
type: 'Polygon'
})
;
map.addInteraction(modify);
map.addInteraction(drawPolygon);
http://jsfiddle.net/jonataswalker/r2g1atty/
how can add a custom image marker in here map,
i can add markers in map by using this code:
var map, standardMarker;
map = new nokia.maps.map.Display(mapContainer, {
center: [lat, log],
zoomLevel: 12,
components: [new nokia.maps.map.component.Behavior(),
new nokia.maps.map.component.ZoomBar(),
new nokia.maps.map.component.TypeSelector()]
});
standardMarker = new nokia.maps.map.StandardMarker(map.center);
map.objects.add(standardMarker);
but the problem is map contains many markers ,so i need small custom markers.
can anyone help me!?
nokia.maps are old version of the HERE map JavaScript API version 2.5, you can use new version of HERE map JS API 3.0. I recommend for new developments to use the latest 3.0 version.
https://developer.here.com/documentation
and some examples http://developer.here.com/api-explorer
/**
* Step 1: initialize communication with the platform
*/
var platform = new H.service.Platform({
app_id: hereMapAppID,
app_code: hereMapAppCode,
useHTTPS: true,
useCIT: false
});
var defaultLayers = platform.createDefaultLayers();
var mapContainer = document.getElementById('hereMapDivId');
//Step 2: initialize a map - not specificing a location will give a whole world view.
var map = new H.Map(mapContainer,
defaultLayers.normal.map,{
center: {lat: 53.430, lng: -2.961},
zoom: 7
});
//Step 3: make the map interactive
// MapEvents enables the event system
// Behavior implements default interactions for pan/zoom (also on mobile touch environments)
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// Create the default UI components
var ui = H.ui.UI.createDefault(map, defaultLayers);
var yourMarker = baseUrl+'/images/ico/your_marker.png';
var icon = new H.map.Icon(yourMarker);
marker = new H.map.Marker(map.center, { icon: icon });
var group = new H.map.Group();
map.addObject(group);
group.addObject(marker);
Add Custom Marker From Your System
function addMarkerToGroup(group, coordinate, html) {
var marker = new H.map.Marker(coordinate,{ icon: pngIcon });
// add custom data to the marker
marker.setData(html);
group.addObject(marker);
}
var yourMarker = '<PATH_OF_IMG/IMG_NAME>';
var pngIcon = new H.map.Icon(yourMarker, {size: {w: 56, h: 56}});
I am using OpenLayers to show multiple Vector layers based on some API calls. Currently, I style these layers using a StyleMap-Style combination for each layer, like so:
var layer1Style = new OpenLayers.Style({
strokeColor: "blue",
strokeWidth: 2,
strokeOpacity: 0.8
});
var layer1 = new OpenLayers.Layer.Vector("Layer 1", {
strategies: [new OpenLayers.Strategy.Fixed()],
styleMap: new OpenLayers.StyleMap({
"default": layer1Style
})
});
map.addLayer(layer1);
var layer2Style = ...
var layer2 = ...
map.addLayer(layer2);
// and so on
Is there a way to pull out these per-layer styles into a CSS file? I really do not want to declare these inline in JS for every layer - CSS/LESS is much better at abstracting these out.
Note that this is a dummy snippet - the actual code is more complex and uses async API calls to create layers on the fly.
I am currently using OL 2.13.x.
This question is similar, but deals with a different, very specific scenario.
You can use a css parser and generate JSON data for your layer style . JSCSSP is a good library for parsing css . I've written a small wrapper class for your problem using JSCSSP .
In the constructor of the Parser class , make a get request to the css file using XMLHttpRequest and
parse the css data with CSSParser.parse() .
function Parser(url)
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", url, false );
xmlHttp.send();
this.cssData = xmlHttp.responseText;
var cssParser = new CSSParser();
this.sheet = cssParser.parse(this.cssData, false, true);
}
Add a method to the Parser class which searchs for the given rule name in the css file and generates json data from that rule .
Parser.prototype.parse = function(element)
{
var result = {};
var rules = this.sheet.cssRules;
for (var i = 0; i < rules.length; i++)
{
if (rules[i].mSelectorText == element )
{
for (var j = 0; j < rules[i].declarations.length; j++)
{
var value = rules[i].declarations[j].valueText;
if (isNaN(Number(value)))
result[rules[i].declarations[j].property] = value;
else
result[rules[i].declarations[j].property] = Number(value);
}
}
}
return result;
}
Example usage :
test.css
#layer1{
strokeColor: blue;
strokeWidth: 2;
strokeOpacity: 0.8;
}
javascript file
var parser = new Parser("test.css");
var layer1 = new OpenLayers.Layer.Vector("Layer 1", {
strategies: [new OpenLayers.Strategy.Fixed()],
styleMap: new OpenLayers.StyleMap({
"default": new OpenLayers.Style(parser.parse("#layer1"))
})
});
You can change return value of parse method to
return new OpenLayers.Style(result);
to have a cleaner syntax while constructing a OpenLayers layer like this
"default": parser.parse("#layer1")
do not forget to include JSCSSP javascript file .