Use CSS for Vector Layer styling in OpenLayers - javascript

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 .

Related

OpenStreetMap OSMXML not rendering

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
})
});

Using a file to hold array items for Google Maps

I have create a Google Map using however, it has a lot of markers and it has become unwieldy to have them in the the same html file. To use the markers I first create a array as follows;
var markers = [
['Balham Leisure Centre',51.441234,-0.152297,'leisure_center.png'],
['Putney Leisure Centre',51.463955,-0.228771,'leisure_center.png'],
['Latchmere Leisure Centre',51.470967,-0.163805,'leisure_center.png']
]
then utilise them as follows;
for( i = 0; i < markers.length; i++ ) {
var position = new google.maps.LatLng(markers[i][1], markers[i][2]);
marker = new google.maps.Marker({
position: position,
map: map,
title: markers[i][0],
icon: iconBase + markers[i][3],
});
}
I would like to store the markers array in a separate text file like;
['Balham Leisure Centre',51.441234,-0.152297,'leisure_center.png'],
['Putney Leisure Centre',51.463955,-0.228771,'leisure_center.png'],
['Latchmere Leisure Centre',51.470967,-0.163805,'leisure_center.png']
then have the main page read that file and put it into the markers array so that everything still works the same.
Since you don't use any frameworks, in native JS you want to use XMLHttpRequest object. Save your data in a separate file (you might want to use JSON for example) and then follow the code below.
Basic usage:
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState == XMLHttpRequest.DONE) {
console.log(req.responseText);
}
}
req.open('GET', url);
req.send();
Readmore: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest

How to generate <a> list from published layers in Geoserver?

I am building a webmapping app. I parse the WMS request to have the title of each layer in layers:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8082/geoserver/wms?service=wms&request=GetCapabilities', true);
xhr.onload = function() {
var parser = new ol.format.WMSCapabilities();
var capabilities = parser.read(xhr.responseText);
var layers = capabilities.Capability.Layer.Layer.Title;
};
But then I fail to access to the titles contain in layers:
$.each(layers, function(i)
{
var list = $('</br><a/>')
.text(layers[i])
.appendTo($('div.myDiv'));
});
What did I miss? Thanx for the help.
I think the problem is, that you need the Name of the Layer, not the Title to be able to call it.
So you would parse the capabilities like this:
var layers = capabilities.Capability.Layer.Layer.Name;

Google Maps API - heatmap not defined (map displaying but cannot alter)

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
})
}
};

ESRI JS API - Buffer FeatureLayer

I have a Feature Layer that I would like to buffer using user input and a geometry service.
FeatureLayer:
var texasPipeline = new FeatureLayer(pipeURL, {
mode: FeatureLayer.MODE_ONDEMAND,
outFields: ["*"],
definitionExpression:texasPipeQuery
});
BufferParameters:
var params = new BufferParameters();
params.distances = [distance];
params.unit = units;
params.outSpatialReference = map.spatialReference;
params.geometries = texasPipeline;
map.graphics.clear();
geomSvc.buffer(params, showBuffer);
The server is returning an error saying that geometries must be supplied. My guess here is that i need to pass in the geometry of the FeatureLayer as opposed to the FeatureLayer itself. How do i get at the geometries of the FeatureLayer and appropriately pass that into the BufferParameters??
EDIT:
Additionally I have tried to loop through as you can see in the code bellow. passing the array of geometries into the BufferParameters still does not return successfully.
var texasPipelineGeom = [];
var graphics = texasPipeline.graphics;
for (var G in graphics) {
var g = graphics[G]["geometry"];
console.log(g);
texasPipelineGeom.push(g);
}
What is the error you re receiving with the edits you made, that looks to be a good start. The buffer parameters does take an array of geometries instead of a feature layer.
You could use something like this (untested, just take as pseudo code):
params.geometries = texasPipeline.graphics.map(function (graphic) {
return graphic.geometry;
});
If using polygons, sometimes the geometry service will complain about the polygons not being simplified. You can find a full working example with polygons here: https://developers.arcgis.com/javascript/3/jssamples/util_buffergraphic.html, You will just need to correctly get your geometries out of the feature layer and add them to params.geometries.
var buffer = function buffer (point, radius) {
var promise = new Deferred();
var gsvc = new GeometryService(CONFIG.GEOMETRY_SERVICE_URL);
var params = new BufferParameters();
params.geometries = [point];
params.distances = [radius];
params.unit = GeometryService.UNIT_KILOMETER;
params.outSpatialReference = new SpatialReference(54010);
gsvc.buffer(params, promise.resolve, console.error);
return promise;
};
What vesrion of js api you are using? Starting from version 3.13 there is a module esri/geometry/geometryEngine. With this module you can do geometry operation on the client side without geometry service. Here is a good example of using it.
Also take a look at module esri/graphicsUtils to get geometries from graphics.

Categories

Resources