WMSLayer class
WMSLayer
loads map tiles from a Web Map Server.
class WMSLayer extends TileLayer { String _serviceUrl; final List<String> _layers = []; Map<String, String> _defaultParameters; _initParameters(Map userParameters) { if (userParameters == null) { userParameters = {}; } _defaultParameters = new Map(); // normalize case userParameters.keys.forEach((k) { _defaultParameters[k.toUpperCase()] = userParameters[k]; }); if (!_defaultParameters.containsKey("SERVICE")) { _defaultParameters["SERVICE"] = "WMS"; } if (!_defaultParameters.containsKey("VERSION")) { _defaultParameters["VERSION"] = "1.0.0"; } if (!_defaultParameters.containsKey("FORMAT")) { _defaultParameters["FORMAT"] = "image/png"; } if (!_defaultParameters.containsKey("SRS")) { _defaultParameters["SRS"] = "EPSG:4326"; } } /** * [serviceUrl] is base URL of the WMS server. * * [layers] is either a single layer name or a list of layer * names. * * [parameters] is a map of WMS request parameters. * * [renderer] is one of the renderer values supported by * [TileLayer]. * * ##Examples * var layer1 = new WmsLayer( * serviceUrl: "https://wms.geo.admin.ch?", * layers: "ch.are.gemeindetypen" * ); * * var layer2 = new WmsLayer( * serviceUrl: "https://wms.geo.admin.ch?", * layers: ["ch.are.gemeindetypen", "ch.are.alpenkonvention"], * parameters: { * "FORMAT": "image/jpeg" * } * ); */ WMSLayer({String serviceUrl, layers, Map parameters, renderer}) : super(renderer:renderer) { if (?serviceUrl) this.serviceUrl = serviceUrl; if (?layers) this.layers = layers; _initParameters(parameters); } /// the layer(s) to be loaded from the WMS server List<String> get layers => _layers; /** * Sets the layer(s) to be retrieved from the WMS server. * * ## Possible values * * [String] - a single layer * * [List] - a list of layer names */ void set layers(value) { if (value is String) { _layers.clear(); _layers.add(value); } else if (value is List) { _layers.clear(); _layers.addAll(value); } else { throw new ArgumentError("expected String or list thereof, got $value"); } } /// sets the service URL void set serviceUrl(String value) { if (value != null && value.endsWith("?")) { value = value.substring(0, value.length -1); } _serviceUrl = value; } /// the URL of the WMS server or null, if the server URL /// isn't configured yet String get serviceUrl => _serviceUrl; /** * Builds the tile bounding box for tile ([x],[y]) in geographic * coordinates. */ //TODO: Order of components in the bbox string changed in WMS 1.3.0? String _buildGeographicTileBBox(int x, int y, int zoom) { var size = tileSize; var tx = x * tileSize.width; var ty = y * tileSize.height + (tileSize.height - 1); var min = map.mapToEarth(map.zoomPlaneToMap(new Point2D(tx, ty))); tx = tx + tileSize.width - 1; ty = y * tileSize.height; var max = map.mapToEarth(map.zoomPlaneToMap(new Point2D(tx, ty))); return "${min.lon},${min.lat},${max.lon},${max.lat}"; } /** * Indicates whether the bounding box of a WMS `GetMap`request is * expressed in geographic or in projected coordinates. * * * if false, the bounding box is expressed in geographic coordinates, * i.e. in WGS84 aka * [EPSG:4326](http://spatialreference.org/ref/epsg/4326/) * * * if true, the bounding box is expressed in projected coordinates, * that is coordinate reference system configured on the * map viewport, see [MapViewport.crs]. * * Default value is false. */ bool useProjectedCoordinates = false; /** * Builds the tile bounding box for tile ([x],[y]) in projected * coordinates */ //TODO: Order of components in the bbox string changed in WMS 1.3.0? String _buildProjectedTileBBox(int x, int y, int zoom) { var tx = x * tileSize.width; var ty = y * tileSize.height + (tileSize.height - 1); var min = map.zoomPlaneToMap(new Point2D(tx, ty)); tx = tx + tileSize.width - 1; ty = y * tileSize.height; var max = map.zoomPlaneToMap(new Point2D(tx, ty)); return "${min.x},${min.y},${max.x},${max.y}"; } @override String bindTileToUrl(int x, int y, int zoom) { var ts = tileSize; var parameters = new Map.from(_defaultParameters); parameters["REQUEST"] = "GetMap"; parameters["LAYERS"] = _layers.join(","); parameters["WIDTH"] = ts.width.toString(); parameters["HEIGHT"] = ts.height.toString(); if (useProjectedCoordinates) { parameters["BBOX"] = _buildProjectedTileBBox(x,y,zoom); parameters["SRS"] = _map.crs.code; } else { parameters["BBOX"] = _buildGeographicTileBBox(x,y,zoom); parameters["SRS"] = "EPSG:4326"; } var query = parameters.keys.map((k) => "$k=${parameters[k]}").join("&"); var url = "$_serviceUrl?$query"; return url; } @override void render() { if (_serviceUrl == null) { print("WARNING: can't render, serviceUrl not defined"); return; } if (_layers.isEmpty) { print("WARNING: can't render, no layers defined"); return; } super.render(); } }
Extends
Object_PropertyObservable > Layer > TileLayer > WMSLayer
Constructors
new WMSLayer({String serviceUrl, layers, Map parameters, renderer}) #
serviceUrl is base URL of the WMS server.
layers is either a single layer name or a list of layer names.
parameters is a map of WMS request parameters.
renderer is one of the renderer values supported by TileLayer.
Examples
var layer1 = new WmsLayer(
serviceUrl: "https://wms.geo.admin.ch?",
layers: "ch.are.gemeindetypen"
);
var layer2 = new WmsLayer(
serviceUrl: "https://wms.geo.admin.ch?",
layers: ["ch.are.gemeindetypen", "ch.are.alpenkonvention"],
parameters: {
"FORMAT": "image/jpeg"
}
);
WMSLayer({String serviceUrl, layers, Map parameters, renderer}) : super(renderer:renderer) { if (?serviceUrl) this.serviceUrl = serviceUrl; if (?layers) this.layers = layers; _initParameters(parameters); }
Properties
String get domId #
the unique layer id
String get domId => _container.attributes["id"];
void set domId(String value) #
Sets the DOM id on the layer container
.
If value is null or empty, sets a default id.
void set domId(String value) { if (value != null) value = value.trim(); if (value == null || value.isEmpty) { value = _defaultDOMId(); } _container.attributes["id"] = value; }
List<String> get layers #
the layer(s) to be loaded from the WMS server
List<String> get layers => _layers;
void set layers(value) #
Sets the layer(s) to be retrieved from the WMS server.
Possible values
String
- a single layerList
- a list of layer names
void set layers(value) { if (value is String) { _layers.clear(); _layers.add(value); } else if (value is List) { _layers.clear(); _layers.addAll(value); } else { throw new ArgumentError("expected String or list thereof, got $value"); } }
final MapViewport map #
the map this layer is attached to, or null
MapViewport get map => _map;
String get name #
the layer name
String get name { if (_name == null) return _defaultName; return _name; }
void set name(String value) #
sets the layer name. If value is null or consists of white space only, a default name is chosen.
void set name(String value) { if (value != null) value = value.trim(); var old = _name; if (value == null || value.isEmpty) { _name = null; } else { _name = value; } notify("name", old, name); }
final Stream<PropertyChangeEvent> onPropertyChanged #
the stream of property change events
Example
// an observable with a mixed in PropertyObservable
var observable = ...;
// listen for property change events for the property
// 'my_property'
observable.onPropertyChanged
.where((evt) => evt.name == "my_property")
.listen((evt) => print("new value: ${evt.newValue}"));
Stream<PropertyChangeEvent> get onPropertyChanged { //TODO: fix this - if at least one listener is present, // change events are emitted, regardless of whether the // individual listeners are paused or not. Consequence: // lots of change events are possibly queued up in // paused listener streams. => need a custom implementation // of a multiplexing stream which disards events if // they are streamed to a disabled listener // if (_stream == null) { _stream = _controller.stream.asBroadcastStream(); } return _stream; }
void set opacity(num value) #
set the opacity of this layer.
value is a num
in the range
(0.0 - 1.0). The lower the value, the more transparent the layer.
void set opacity(num value) { value = math.max(0, value); value = math.min(value, 1); var oldvalue = _opacity; this._opacity = value.toDouble(); if (oldvalue != this._opacity) { notify("opacity", oldvalue, this._opacity); if (_map != null) { _map.render(); } } }
String get serviceUrl #
the URL of the WMS server or null, if the server URL isn't configured yet
String get serviceUrl => _serviceUrl;
void set serviceUrl(String value) #
sets the service URL
void set serviceUrl(String value) { if (value != null && value.endsWith("?")) { value = value.substring(0, value.length -1); } _serviceUrl = value; }
final Dimension tileSize #
the tile size used by this tile layer
Dimension get tileSize => DEFAULT_TILE_SIZE;
bool useProjectedCoordinates #
Indicates whether the bounding box of a WMS GetMap
request is
expressed in geographic or in projected coordinates.
-
if false, the bounding box is expressed in geographic coordinates, i.e. in WGS84 aka EPSG:4326
-
if true, the bounding box is expressed in projected coordinates, that is coordinate reference system configured on the map viewport, see
MapViewport.crs
.
Default value is false.
bool useProjectedCoordinates = false
void set visible(bool value) #
sets whether this layer is visible or not
void set visible(bool value) { var old = _visible; if (value != old) { if (_container != null) { _container.style.visibility = value ? "visible" : "hidden"; } _visible = value; notify("visible", old, value); } }
Methods
void attach(MapViewport m) #
Attaches the layer to a map viewport m.
Throws StateError
if this layer is already attached.
@override void attach(MapViewport m) { super.attach(m); var viewportSize = map.viewportSize; var tl = map.topLeftInPage; _container.style ..width="100%" ..height="100%" ..position = "absolute" ..left = "0px" ..top = "0px"; }
String bindTileToUrl(int x, int y, int zoom) #
returns a tile URL for the tile at tile coordinates x, y in the tile plane at zoom level zoom
@override String bindTileToUrl(int x, int y, int zoom) { var ts = tileSize; var parameters = new Map.from(_defaultParameters); parameters["REQUEST"] = "GetMap"; parameters["LAYERS"] = _layers.join(","); parameters["WIDTH"] = ts.width.toString(); parameters["HEIGHT"] = ts.height.toString(); if (useProjectedCoordinates) { parameters["BBOX"] = _buildProjectedTileBBox(x,y,zoom); parameters["SRS"] = _map.crs.code; } else { parameters["BBOX"] = _buildGeographicTileBBox(x,y,zoom); parameters["SRS"] = "EPSG:4326"; } var query = parameters.keys.map((k) => "$k=${parameters[k]}").join("&"); var url = "$_serviceUrl?$query"; return url; }
void detach() #
Detaches this layer from the map viewport it is currently attached to.
void detach(){ _map = null; }
void notify(String property, oldValue, newValue) #
Notifies observers about an update of the property with name property in this object. oldValue was replaced by newValue.
Observers are only notified, provided newValue is different from oldValue and if there is at least one listener.
void notify(String property, oldValue, newValue) { if (oldValue == newValue) return; //TODO: fix me - see notes in onPropertyChanged if (!_controller.hasListener || _controller.isPaused) return; _controller.sink.add( new PropertyChangeEvent(this, property,oldValue,newValue) ); }