I want to show a layer map with many style depending on some attribute in the layer, but don't know how,. If I use SLD in geoserver I just show only one style, I have tried writing something in javascript (based on Openlayer library) like below, but it didn't work, the code didn't have any effect to the layer map. Any suggestion will be greatly appreciated.
//create a style object
var style = new OpenLayers.Style();
//rule used for all polygons
var rule_p1 = new OpenLayers.Rule({
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.EQUAL_TO,
property: "vi_tri",
value: "1",
}),
symbolizer: {
fillColor: "#00FF00",
fillOpacity: 0.6,
strokeColor: "#FF0000",
strokeWidth: 2,
strokeDashstyle: "solid",
}
});
var rule_p2 = new OpenLayers.Rule({
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.EQUAL_TO,
property: "vi_tri",
value: "2",
}),
symbolizer: {
fillColor: "#40FF00",
fillOpacity: 0.6,
strokeColor: "#FF0000",
strokeWidth: 2,
strokeDashstyle: "solid",
}
});
var rule_p3 = new OpenLayers.Rule({
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.EQUAL_TO,
property: "vi_tri",
value: "3",
}),
symbolizer: {
fillColor: "#80FF00",
fillOpacity: 0.6,
strokeColor: "#FF0000",
strokeWidth: 2,
strokeDashstyle: "solid",
}
});
var rule_p4 = new OpenLayers.Rule({
filter: new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.EQUAL_TO,
property: "vi_tri",
value: "4",
}),
symbolizer: {
fillColor: "#FFFF00",
fillOpacity: 0.6,
strokeColor: "#FF0000",
strokeWidth: 2,
strokeDashstyle: "solid",
}
});
style.addRules([rule_p1, rule_p2, rule_p3, rule_p4]);
mybinh = new OpenLayers.Layer.WMS(
"Lớp Mỹ Bình", urlmapfile,
{
LAYERS: 'demo:mybinh',
transparent:"true",
format: format,
styleMap: style
},
{singleTile: true, ratio: 1, isBaseLayer: false}
);
From your code snippet I assume that you want to serve a WMS Layer provided by the GeoServer. In this case you receive an image file rendered by the server and the styling is part of the Geoserver (SLD). On client side (OpenLayers) you are only able to style Vector features.
You can define different Styles (SLD) for your layer and switch between the styles by changing the WMS query parameter (see http://docs.geoserver.org/latest/en/user/services/wms/reference.html ).
Related
Hi I am using google maps api(JavaScript) to build an interactive world map. It went really well until I ran into this problem. I am using polygons to show to outline of a country. These polygons trigger a modal showing information about the country when clicked on. This worked until I started to use "Data Layer: Earthquake data". Instead of using earthquake data I use sales information of the company I work at. So if a large share of our customers are from the Netherlands then the datalayer assigned to the Netherlands will be very large. The problem is that because of the datalayers the countries are no longer clickable. I can not click "through" the datalayer. Is there a possibility that I can trigger the event behind the datalayer?
This code displays the datalayers:
map.data.loadGeoJson('./data/test.json');
map.data.setStyle(function(feature) {
var percentage = parseFloat(feature.getProperty('percentage'));
return ({
icon: {
path: google.maps.SymbolPath.CIRCLE,
scale: percentage,
fillColor: '#00ff00',
fillOpacity: 0.35,
strokeWeight: 0
}
})
});
map.data.addListener('mouseover', function(event) {
map.data.overrideStyle(event.feature, {
title: 'Hello, World!'
});
});
map.data.addListener('mouseout', function(event) {
map.data.revertStyle();
});
function eqfeed_callback(data) {
map.data.addGeoJson(data);
}
This code displays the polygons:
function drawMap(data) {
var rows = data['rows'];
for (var i in rows) {
if (rows[i][0] != 'Antarctica') {
var newCoordinates = [];
var geometries = rows[i][1]['geometries'];
if (geometries) {
for (var j in geometries) {
newCoordinates.push(constructNewCoordinates(geometries[j]));
}
} else {
newCoordinates = constructNewCoordinates(rows[i][1]['geometry']);
}
var country = new google.maps.Polygon({
paths: newCoordinates,
strokeColor: 'transparent',
strokeOpacity: 1,
strokeWeight: 0.3,
fillColor: '#cd0000',
fillOpacity: 0,
name: rows[i][0]
});
google.maps.event.addListener(country, 'mouseover', function() {
this.setOptions({
fillOpacity: 0.3
});
});
google.maps.event.addListener(country, 'mouseout', function() {
this.setOptions({
fillOpacity: 0
});
});
google.maps.event.addListener(country, 'click', function() {
var countryName = this.name;
var code = convert(countryName); // Calls a function that converts the name of the country to its official ISO 3166-1 alpha-2 code.
var modal = document.querySelector('.modal');
var instance = M.Modal.init(modal);
instance.open();
});
country.setMap(map);
}
}
If read in the documentation that changing the zIndex won't work because "Markers are always displayed in front of line-strings and polygons."
Is there a way to click on a polygon behind a datalayer?
EDIT
I tried to give the polygon a higher zIndex and I made the datalayer not clickable
map.data.loadGeoJson('./data/test.json');
map.data.setStyle(function(feature) {
var percentage = parseFloat(feature.getProperty('percentage'));
return ({
icon: {
path: google.maps.SymbolPath.CIRCLE,
scale: percentage,
fillColor: '#00ff00',
fillOpacity: 0.35,
strokeWeight: 0,
clickAble: false,
zIndex: 50
}
})
});
function eqfeed_callback(data) {
map.data.addGeoJson(data);
}
function drawMap(data) {
var rows = data['rows'];
for (var i in rows) {
if (rows[i][0] != 'Antarctica') {
var newCoordinates = [];
var geometries = rows[i][1]['geometries'];
if (geometries) {
for (var j in geometries) {
newCoordinates.push(constructNewCoordinates(geometries[j]));
}
} else {
newCoordinates = constructNewCoordinates(rows[i][1]['geometry']);
}
var country = new google.maps.Polygon({
paths: newCoordinates,
strokeColor: 'transparent',
strokeOpacity: 1,
strokeWeight: 0.3,
fillColor: '#cd0000',
fillOpacity: 0,
name: rows[i][0],
zIndex: 100
});
google.maps.event.addListener(country, 'mouseover', function() {
this.setOptions({
fillOpacity: 0.3
});
});
google.maps.event.addListener(country, 'mouseout', function() {
this.setOptions({
fillOpacity: 0
});
});
google.maps.event.addListener(country, 'click', function() {
var countryName = this.name;
var code = convert(countryName); // Calls a function that converts the name of the country to its official ISO 3166-1 alpha-2 code.
var modal = document.querySelector('.modal');
var instance = M.Modal.init(modal);
instance.open();
});
country.setMap(map);
}
}
//console.log(map);
//test(map)
}
EDIT
Apparently the datalayer wasn't the problem, but the icon was. That is why it didn't work when I did this:
map.data.setStyle(function(feature) {
var percentage = parseFloat(feature.getProperty('percentage'));
return ({
icon: {
path: google.maps.SymbolPath.CIRCLE,
scale: percentage,
fillColor: '#00ff00',
fillOpacity: 0.35,
strokeWeight: 0,
clickable: false
}
})
});
The correct way to do it is this:
map.data.setStyle(function(feature) {
var percentage = parseFloat(feature.getProperty('percentage'));
return ({
icon: {
path: google.maps.SymbolPath.CIRCLE,
scale: percentage,
fillColor: '#00ff00',
fillOpacity: 0.35,
strokeWeight: 0
},
clickable: false
})
});
You basically have 2 options here:
Set the zIndex of your Polygons to a higher number than the data layer. Your Polygons will be clickable but obviously will appear above the data layer, which might not be what you want.
Set the clickable property of the data layer to false so that you can click elements that are below. This will work if you don't need to react to clicks on the data layer...
Option 2 example code:
map.data.setStyle({
clickable: false
});
Edit: Full working example below, using option 2. As you can see the Polygon is below the data layer but you can still click it.
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: {
lat: -28,
lng: 137
}
});
var polygon = new google.maps.Polygon({
strokeOpacity: 0,
strokeWeight: 0,
fillColor: '#00FF00',
fillOpacity: .6,
paths: [
new google.maps.LatLng(-26, 139),
new google.maps.LatLng(-23, 130),
new google.maps.LatLng(-35, 130),
new google.maps.LatLng(-26, 139)
],
map: map
});
polygon.addListener('click', function() {
console.log('clicked on polygon');
});
// Load GeoJSON
map.data.loadGeoJson('https://storage.googleapis.com/mapsdevsite/json/google.json');
// Set style
map.data.setStyle({
fillColor: '#fff',
fillOpacity: 1,
clickable: false
});
}
#map {
height: 200px;
}
<script async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap"></script>
<div id="map"></div>
I have found that after, setting the z-order, the maps api does not reliably send clicks to polygon feature in the top layer when there are many polygons.
I had one data layer of regions where each feature is a precinct boundary. When you click on one feature, it loads another data layer on top. The top layer consists of polygons inside the region with a higher z-order, representing house title boundaries within that region.
After the houses are loaded, clicking on a house should send the click to the house polygon, not the region. But this sometimes failed - especially if there are many houses.
To resolve the issue, after clicking on a region feature, I set that feature to be non clickable. Then the clicks always propagate to the correct house feature. You can still click on other features of the lower layer, just not the selected one. This solution should work if your data and presentation follows a similar pattern.
/* private utility is only called by this.hideOnlyMatchingFeaturesFromLayer() */
_overrideStyleOnFeature(feature, layer, key, value, overrideStyle, defaultStyle) {
if (feature.getProperty(key) === value) {
if (this.map) {
layer.overrideStyle(feature, overrideStyle);
}
} else {
if (this.map) {
layer.overrideStyle(feature, defaultStyle);
}
}
}
/* Apply an overrideStyle style to features in a data layer that match key==value
* All non-matching features will have the default style applied.
* Otherwise all features except the matching feature is hidden!
* Examples:
* overrideStyle = { clickable: false,strokeWeight: 3}
* defaultStyle = { clickable: true,strokeWeight: 1}
*/
overrideStyleOnMatchingFeaturesInLayer(layer, key, value, overrideStyle, defaultStyle) {
layer.forEach((feature) => {
if (Array.isArray(feature)) {
feature.forEach((f) => {
_overrideStyleOnFeature(f, layer, key, value, overrideStyle, defaultStyle);
});
} else {
_overrideStyleOnFeature(feature, layer, key, value, overrideStyle, defaultStyle);
}
});
}
/* example usage */
overrideStyleOnMatchingFeaturesInLayer(
theRegionsDataLayer,
'PROP_NAME',
propValue,
{ clickable: false, strokeWeight: 3},
{ clickable: true, strokeWeight: 1}
);
How can I remove the drawn circle or polygon using drawing manager from the google map.
Component:
import {Ng2MapComponent, DrawingManager, Polygon} from 'ng2-map';
export class CreateAlertComponent implements OnInit {
#ViewChild(Ng2MapComponent) mapObj: Ng2MapComponent;
#ViewChild(DrawingManager) drawingManager: DrawingManager;
polygonCompleteFunction(e) {
console.log(this.mapObj);
};
});
HTML:
<ng2-map [zoom]="mapOptions.zoom" [minZoom]="mapOptions.minZoom" [center]="mapOptions.center" clickable="false" (click)="mapClick($event)">
<drawing-manager *ngIf = "selectedJurisdictions.length > 0"
[drawingMode]="'null'"
[drawingControl]="true"
[drawingControlOptions]="{
position: 2,
drawingModes: ['circle', 'polygon']
}"
[circleOptions]="{
fillColor: 'red',
fillOpacity: 0.3,
strokeColor: 'black',
strokeWeight: 2,
editable: true,
draggable: true,
zIndex: 1
}"
[polygonOptions]="{
fillColor: 'red',
fillOpacity: 0.3,
strokeColor: 'black',
strokeWeight: 2,
editable: true,
draggable: true,
zIndex: 1
}"
(polygoncomplete)="polygonCompleteFunction($event)"
(circlecomplete)="circleCompleteFunction($event)">
</drawing-manager>
</ng2-map>
But on polygon complete function or circle complete I am not getting the drawn polygons from the map object
You can find the drawn Polygon or Circle from the CircleComplete/PolygonCompolete Event's parameter. Or find the target from OverlayComplete event's parameter by event.overlay.
After get the target object, you can keep it somewhere for deleteing them somewhere else.
polygonCompleteFunction(e) {
console.log(e); // this is the drawn Polygon you are looking for, and same for the circleComplete event
};
overlayComplete(e) {
console.log(e.overlay); // here can also find the drawn shape(Polygon/Circle/Polyline/Rectangle)
}
While deleting the target Polygon or Circle, delete them by reference the instance kept before.
target.setMap(null);
Here is the GooleMapApi Documentation about OverlayComplete Events:
google.maps.event.addListener(drawingManager, 'circlecomplete', function(circle)
{
var radius = circle.getRadius();
});
google.maps.event.addListener(drawingManager, 'overlaycomplete', function(event)
{
if (event.type == 'circle') {
var radius = event.overlay.getRadius();
}
});
Here is the link to GoogleMapApi documentation.
Hope it helps. And here is a plunker you can take reference.
I need to pass 2 styles, i currently have:
First style:
function style(feature) {
return {
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7,
fillColor: getColor(feature.properties.density)
};
}
The I do:
var classNameMap = <?php echo JSON_encode($classesForCountries); ?>;
geojson = L.geoJson(statesData, {
style: style,
style: function(feature) {
var classes = classNameMap[feature.properties.name];
return {className: classes};
},
onEachFeature: onEachFeature
}).addTo(map);
But that ignores the first style
I tried by passing it as an array:
geojson = L.geoJson(statesData, {
style: [style, function(){
var classes = classNameMap[feature.properties.name];
return {className: classes};
}],
onEachFeature: onEachFeature
}).addTo(map);
But yet, first style is ignored.
leaflet docs if this can help, here
This is the solution:
var classNameMap = <?php echo JSON_encode($classesForCountries); ?>;
function style(feature) {
var classes = classNameMap[feature.properties.name];
return {
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7,
fillColor: getColor(feature.properties.density),
className: classes
};
}
geojson = L.geoJson(statesData, {
style: style,
onEachFeature: onEachFeature
}).addTo(map);
Not familiar with leaflet, but looking from js perspective using duplicate key will definitely override its value with the last key entry.
If you are trying append the style1 and style2, since both the functions of style returns an object, you can do so by $.extend.
function style_1(feature) {
return {
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7,
fillColor: getColor(feature.properties.density)
};
}
...
style: function(feature) {
// Now the logic is a simple hashmap look-up
var style1 = style_1(feature);
var classes = classNameMap[feature.properties.name];
var finalStyle = $.extend(style1, {className: classes});
return finalStyle;
}
...
You're putting duplicate keys in the object initializer. Don't.
See How to generate a JSON object dynamically with duplicate keys? , Finding duplicate keys in JavaScript object
I want to build a lot of areas in google maps, and have each defined with a polygon.
If I do it one by one it works without a problem (inside the initialize func):
name = new google.maps.Polygon({
paths: coords,
strokeColor: 'darkgreen',
strokeOpacity: 0.3,
strokeWeight: 1,
fillOpacity: 0.05
});
//some event
//highlights polygon when mouseover
google.maps.event.addListener(name, 'mouseover', function () {
name.setOptions({ fillColor: 'yellow', fillOpacity: 0.25 });
});
//then displaying it on the map:
name.setMap(map);
Now I want to have a function to just put in the coords to build the polygons, something like this. But just calling the function stops other polygons from being rendered, so I know there is a problem calling it:
iName = new drawPolygon(polyName, coords);
iName.setMap(map);
The function looks like this:
function drawPolygon(polyName, coords) {
polyName = new google.maps.Polygon({
paths: coords,
strokeColor: 'darkgreen',
strokeOpacity: 0.3,
strokeWeight: 1,
//fillColor: 'green',
fillOpacity: 0.05
});
//highlights polygon when mouseover
google.maps.event.addListener(polyName, 'mouseover', function () {
polyName.setOptions({ fillColor: 'yellow', fillOpacity: 0.25 });
});
}
any help as to why, how am I calling it wrong?
drawPolygon doesn't have a return statement. It returns null. nulldoesn't have a .setMap method.
Expanding on geocodezip's answer, just add a return statement to your function.
function drawPolygon(polyName, coords) {
polyName = new google.maps.Polygon({
paths: coords,
strokeColor: 'darkgreen',
strokeOpacity: 0.3,
strokeWeight: 1,
fillOpacity: 0.05
});
//highlights polygon when mouseover
google.maps.event.addListener(polyName, 'mouseover', function () {
polyName.setOptions({ fillColor: 'yellow', fillOpacity: 0.25 });
});
return polyName;
}
I'd also be inclined to in that case not bother passing polyName into the function as an argument. You don't bother showing us the code where you create the polyName variable prior to calling drawPolygon. But I assume you're not doing anything particularly clever with it that would require you to do so.
So refactored:
iName = new drawPolygon(coords);
iName.setMap(map);
function drawPolygon(coords) {
var polyName = new google.maps.Polygon({
paths: coords,
strokeColor: 'darkgreen',
strokeOpacity: 0.3,
strokeWeight: 1,
fillOpacity: 0.05
});
//highlights polygon when mouseover
google.maps.event.addListener(polyName, 'mouseover', function () {
polyName.setOptions({ fillColor: 'yellow', fillOpacity: 0.25 });
});
return polyName;
}
I have a KML file with more than 10 placemarks, using OpenLayers. What I want to do is, when I click on radiobutton, a specific placemark change its color.
Does anybody know how to do that?
Thanks.
EDITED:
So here is what I have so far:
function init(){
///////////////////////////////////////////////
CONTROLS AND MAP STUFF
//////////////////////////////////////////////
var myvector = new OpenLayers.Layer.Vector("myvector", {
projection: map.displayProjection,
styleMap: new OpenLayers.StyleMap(
{ 'default':
{
strokeColor: "#777777",
strokeOpacity: 1,
strokeWidth: "2",
fillColor: "#FFF900",
fillOpacity: 1,
pointRadius: 8,
pointerEvents: "visiblePainted",
graphicName: "circle",
}
}),
strategies: [new OpenLayers.Strategy.Fixed()],
protocol: new OpenLayers.Protocol.HTTP({
url: url_time,
format: new OpenLayers.Format.KML({
extractStyles: false,
extractAttributes: true
})
})
});
map.addLayers([wms, wms2, myvector]);
select = new OpenLayers.Control.SelectFeature(myvector);
myvector.events.on({
"featureselected": onFeatureSelect,
"featureunselected": onFeatureUnselect
});
map.addControl(select);
select.activate();
map.zoomToExtent(new OpenLayers.Bounds(-53,-21,13,22));
}
function switchLabels() {
/////// PROBABLY HERE IS THE PLACE TO DO THE TRICK ////////
myvector.redraw();
}
///////////////////////////////////////////////
SOME OTHER THINGS
//////////////////////////////////////////////
And the radion button:
<input name="button1" type="radio" value="button1" onClick="switchLabels()">
Here is a post showing this switchLabels, but I have no idea how to change a point created by one placemark.
Thanks.
OK. I gave up using KML to do what I wanted. For those who need to change some attributes of vectors in OpenLayers, here goes a possible solution:
var features = [];
features[0] = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(10,10),
{
name : "Hello",
body : "world",
}, {strokeColor: "#777777",strokeOpacity: 1,strokeWidth: "2",fillColor: "#FFF900",fillOpacity: 1,pointRadius: 8,pointerEvents: "visiblePainted",graphicName: "circle"});
features[1] = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(15,10),
{
name : "Hello",
body : "Mars",
}, {strokeColor: "#777777",strokeOpacity: 1,strokeWidth: "2",fillColor: "#FFF900",fillOpacity: 1,pointRadius: 8,pointerEvents: "visiblePainted",graphicName: "circle"});
///////////// POPUPS //////////////
vector = new OpenLayers.Layer.Vector("LAYER",{
eventListeners:{
'featureselected':function(evt){
var feature = evt.feature;
var popup = new OpenLayers.Popup.FramedCloud("popup",
OpenLayers.LonLat.fromString(feature.geometry.toShortString()),
new OpenLayers.Size(350,350),
feature.attributes.name + feature.attributes.body,
null, false, onPopupClose
);
popup.maxSize = new OpenLayers.Size(350, 350);
popup.minSize = new OpenLayers.Size(350, 350);
feature.popup = popup;
map.addPopup(popup);
},
'featureunselected':function(evt){
var feature = evt.feature;
map.removePopup(feature.popup);
feature.popup.destroy();
feature.popup = null;
}
}
});
function onPopupClose(evt) {
select.unselectAll();
}
vector.addFeatures(features);
// create the select feature control
var selector = new OpenLayers.Control.SelectFeature(vector,{
click:true,
autoActivate:true
});
map.addLayers([vector]);
map.addControl(selector);
map.zoomToExtent(new OpenLayers.Bounds(-53,-21,13,22));
}
///////////////////// FUNCTION TO CHANGE THE VECTOR STYLE ///////////
function switchColors(p_ind,p_id) {
if (eval('document.form.' + p_id).checked == 1){
vector.features[p_ind].style = {
strokeColor: "#777777",
strokeOpacity: 1,
strokeWidth: "2",
fillColor: "#FF0000",
fillOpacity: 1,
pointRadius: 8,
pointerEvents: "visiblePainted",
graphicName: "circle"
};
}
else {
vector.features[p_ind].style = {
strokeColor: "#777777",
strokeOpacity: 1,
strokeWidth: "2",
fillColor: "#FFF900",
fillOpacity: 1,
pointRadius: 8,
pointerEvents: "visiblePainted",
graphicName: "circle"
};
}
vector.redraw();
}
And then the radio:
<form name="form" method="post" action="action.php">
<input name="p1" type="checkbox" value="p1" onClick="switchColors(0,'p1');">
<input name="p2" type="checkbox" value="p2" onClick="switchColors(1,'p2');">
</form>