OGC WFS-T client layer for Leaflet.
Clone or download

README.md

Leaflet-WFST

Build Status

OGC WFS-T client layer for leaflet.

Install plugin

Via npm:

  npm i leaflet-wfst --save

Via Bower:

  bower i leaflet-wfst --save

From GitHub:

  npm i -S git://github.com/Flexberry/Leaflet-WFST.git#v1.1.1

where #v1.1.1 is version of specific release.

Initialization options

   options: {
        crs: L.CRS.EPSG3857,
        showExisting: true,
        geometryField: 'Shape',
        url: '',
        typeNS: '',
        typeName: '',
        opacity: 1,
        style: {
            color: 'black',
            weight: 1
        }
    }

Example

const wfstPointOptions = {
  crs: L.CRS.EPSG4326,
  showExisting: true,
  geometryField: 'geom',
  url: `http://localhost:8080/geoserver/wfs`,
  typeNS: 'test',
  typeName: 'test',
  maxFeatures: 90,
  opacity: 1,
  style: function(layer) {
    // you can use if statemt etc
    return {
      color: 'black',
      weight: 1
    }
  },
};
const wfstPoint = new L.WFST(wfstPointOptions, new L.Format.GeoJSON({
  crs: L.CRS.EPSG4326,
  pointToLayer(geoJsonPoint, latlng) {
    const layer = new L.CircleMarker(latlng, {
      radius: 10,
    });
    return layer;
  },
}));
wfstPoint.addTo(map);
option name default comment
crs L.CRS.EPSG3857 spatial reference system for layer, should implement ICRS, for example Proj4Leaflet
showExisting true load existing features on create layer
geometryField 'Shape' field for storing geometries, for non transaction services may be ommited
url - WFS url, for example http://demo.opengeo.org/geoserver/osm/ows
typeNS - type namespace
typeName - type name
typeNSName - type namespace name
namespaceUri - namespace URI
opacity 1 layer's opacity
style - leaflet vector style. function or object
filter - any filter. see filter
maxFeatures - limit the amount of features returned

Basic WFS example - view

var map = L.map('map').setView([0, 0], 2);

var boundaries = new L.WFS({
    url: 'http://demo.opengeo.org/geoserver/ows',
    typeNS: 'topp',
    typeName: 'tasmania_state_boundaries',
    crs: L.CRS.EPSG4326,
    style: {
        color: 'blue',
        weight: 2
    }
}).addTo(map)
  .on('load', function () {
      map.fitBounds(boundaries);
  })

Methods

Extends leaflet classes with toGml(crs) function:

  • L.Marker
  • L.Polygon
  • L.Polyline
  • L.MultiPolygon
  • L.MultiPolyline
  • L.LatLngBounds

Events

Triggers two type of events:

  • load - triggers when both 'DescribeFeatureType' & 'GetFeature' requests succeed, and features have been successfully parsed into leaflet layers
  • error - triggers when any 'DescribeFeatureType' or 'GetFeature' request fails, and features haven't been parsed into leaflet layers

Markers geometry writes as posNode, for all other layers geometry writes as posList

Filter

Realization of OGC Filter Encoding v1.1.0

Filter implementations return only inner content of filter element.

Some considerations for all filter constructors:

  • "expression" - propertyName, literal, operator filter or function
  • "propertyExpression" - if argument on this position is not Element and is not "expression" method it suspect to be a propertyName
  • "literalExpression" - if argument on this position is not Element and is not "expression" it suspect to be a literal
Name Constructor
ID
GmlObjectId L.Filter.GmlObjectId(value id)
Comparisons
PropertyIsEqualTo L.Filter.EQ(propertyExpression firstArgument, literalExpression secondArgument, bool matchCase)
PropertyIsNotEqualTo L.Filter.NotEQ(propertyExpression firstArgument, literalExpression secondArgument, bool matchCase)
PropertyIsLessThan L.Filter.LT(propertyExpression firstArgument, literalExpression secondArgument, bool matchCase)
PropertyIsGreaterThan L.Filter.GT(propertyExpression firstArgument, literalExpression secondArgument, bool matchCase)
PropertyIsLessThanOrEqualTo L.Filter.LEQ(propertyExpression firstArgument, literalExpression secondArgument, bool matchCase)
PropertyIsGreaterThanOrEqualTo L.Filter.GEQ(propertyExpression firstArgument, literalExpression secondArgument, bool matchCase)
PropertyIsLike L.Filter.Like(string propertyName,string likeExpression,object attributes)
PropertyIsNull L.Filter.IsNull(string propertyName)
PropertyIsBetween L.Filter.IsBetween(propertyExpression firstArgument, literalExpression lowerBoundary, literalExpression upperBoundary)
Operators
Add L.Filter.Add(expression, expression)
Sub L.Filter.Sub(expression, expression)
Mul L.Filter.Mul(expression, expression)
Div L.Filter.Div(expression, expression)
Logic
And L.Filter.And(expression[, expression]*)
Or L.Filter.Or(expression[, expression]*)
Not L.Filter.Not(expression)
Spatial
BBox L.Filter.BBox(string propertyName, latLngBounds bounds, ICRS crs)
Equals L.Filter.Equals(string propertyName, Layer geometry, ICRS crs)
Disjoint L.Filter.Disjoint(string propertyName, Layer geometry, ICRS crs)
Touches L.Filter.Touches(string propertyName, Layer geometry, ICRS crs)
Within L.Filter.Within(string propertyName, Layer geometry, ICRS crs)
Overlaps L.Filter.Overlaps(string propertyName, Layer geometry, ICRS crs)
Crosses L.Filter.Crosses(string propertyName, Layer geometry, ICRS crs)
Intersects L.Filter.Intersects(string propertyName, Layer geometry, ICRS crs)
Contains L.Filter.Contains(string propertyName, Layer geometry, ICRS crs)
Spatial distance buffer
DWithin L.Filter.DWithin(string propertyName, Layer geometry, ICRS crs, value distance, string units)
Beyond L.Filter.Beyond(string propertyName, Layer geometry, ICRS crs, value distance, string units)
Other
Function L.Filter.Function(string functionName[, expression]*)
PropertyName L.Filter.propertyName(string name)
Literal L.Filter.literal(value)

PropertyName and Literal is functions and returns Gml directly.

Examples

FeatureID

In standard there are two filters - GmlObjectID and FeatureID, but latest is marked as deprecated and so is not implemented.

Example:

  var filter = new L.Filter.GmlObjectID(1);  

result xml:

  <ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
    <ogc:GmlObjectId xmlns:gml="http://www.opengis.net/gml" gml:id="1" />
  </ogc:Filter>

PropertyIsEqualTo

  var filter = new L.Filter.EQ('city', 'Perm');
  filter.toGml()

result xml:

  <ogc:PropertyIsEqualTo>
    <ogc:PropertyName>city</ogc:PropertyName>
    <ogc:Literal>Perm</ogc:Literal>
  </ogc:PropertyIsEqualTo>

PropertyIsLike

This filter accept optional attributes object:

 attributes: {
    wildCard: '*',
    singleChar: '#',
    escapeChar: '!',
    matchCase: true
  }
  var filter = new L.Filter.Like('city', '*perm*', { matchCase: false });
  filter.toGml()

result xml:

  <ogc:ogc:PropertyIsLike wildCard="*" singleChar="#" escapeChar="!" matchCase="false">
    <ogc:PropertyName>city</ogc:PropertyName>
    <ogc:Literal>*perm*</ogc:Literal>
  </ogc:ogc:PropertyIsLike>

BBox

Example:

    var filter = new L.Filter.BBox('ogr_geometry', L.latLngBounds(L.latLng(40.712, -74.227), L.latLng(40.774, -74.125)), L.CRS.EPSG4326);
    filter.toGml()

result xml:

  <ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
    <ogc:BBOX>
      <ogc:PropertyName>ogr_geometry</ogc:PropertyName>
      <gml:Envelope xmlns:gml="http://www.opengis.net/gml" srsName="EPSG:4326">
        <gml:lowerCorner>-74.227 40.712</gml:lowerCorner>
        <gml:upperCorner>-74.125 40.774</gml:upperCorner>
      </gml:Envelope>
    </ogc:BBOX>
  </ogc:Filter>

Intersects

Example:

  var filter = new L.Filter.Intersects('ogr_geometry', L.polygon([L.latLng(40.712, -74.227), L.latLng(40.774, -74.125), L.latLng(40.734, -74.175)]), L.CRS.EPSG4326);
  filter.toGml();

result xml:

  <ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
    <ogc:Intersects>
      <ogc:PropertyName>ogr_geometry</ogc:PropertyName>
      <gml:Polygon xmlns:gml="http://www.opengis.net/gml" srsName="EPSG:4326" srsDimension="2">
        <gml:exterior>
          <gml:LinearRing srsDimension="2">
            <gml:posList>-74.227 40.712 -74.125 40.774 -74.175 40.734 -74.227 40.712</gml:posList>
          </gml:LinearRing>
        </gml:exterior>
      </gml:Polygon>
    </ogc:Intersects>
  </ogc:Filter>

WFST Example

Editing plugin - Leaflet.Editable

L.WFST.include(MultiEditableMixin);

var wfst = new L.WFST({
    url: 'http://myserver/geoserver/ows',
    typeNS: 'myns',
    typeName: 'POIPOINT',
    style: {
        color: 'blue',
        weight: 2
    }
}).addTo(map).once('load', function () {
            map.fitBounds(wfst);
            wfst.enableEdit();
        });

map.on('editable:created', function (e) {
    wfst.addLayer(e.layer);
});

map.on('editable:editing', function (e) {
    wfst.editLayer(e.layer);
});

to make "wfs:Transaction" POST request call save() method, example with Leaflet.EasyButton

 L.easyButton('fa-save', function () {
     wfst.save();
 }, 'Save changes');

Layer properties

//simple layer
layer = new L.Marker([0, 0]);
layer.feature = {
  id: 1,
  properties: {
    a: 'a',
    b: 'b'
  }
};

//get value by key 'a'
var a = layer.getProperty('a');

//change values
layer.setProperties({
  a: 'b',
  b:'a'
});

//add new property
layer.setProperties({
  c:'c'
});

//delete properties
layer.deleteProperties(['a','b','c']);

Demo

demos for GML read format

demo for GeoJSON read format

demo filter bbox

License

MIT License