Commit b6550e5c authored by ncastejon's avatar ncastejon
Browse files

Integrate WMS layer if WFS not exist. Try external lib feaflet.wms for WMS options

parent c46eb815
......@@ -25,7 +25,8 @@
"../node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css"
],
"scripts": [
"../node_modules/leaflet.markercluster/dist/leaflet.markercluster.js"
"../node_modules/leaflet.markercluster/dist/leaflet.markercluster.js",
"../node_modules/proj4leaflet/lib/proj4-compressed.js"
],
"environmentSource": "environments/environment.ts",
"environments": {
......
......@@ -325,6 +325,21 @@
"integrity": "sha512-EhNufyBoC1Kqaj+XMHGzi6mPUC8wVABOMTPE5XaSJc49LIVvXsyrV1HYMAPTUViT7E4wLUB38OdDmb+HshjGmA==",
"dev": true
},
"@types/proj4": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/@types/proj4/-/proj4-2.3.4.tgz",
"integrity": "sha1-84i2AgnEy3XsIaF6S0rFWnGlhVg="
},
"@types/proj4leaflet": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@types/proj4leaflet/-/proj4leaflet-1.0.5.tgz",
"integrity": "sha512-xqw5V5wk0iSjpDSN2X1tuEo6qL4QhfffaTpnHN6ISz3vnT4Z4m4aKdH1vQHlpJ6aJ0TBvcRmI8X2/Lv7t/0qOw==",
"requires": {
"@types/geojson": "7946.0.3",
"@types/leaflet": "1.2.7",
"@types/proj4": "2.3.4"
}
},
"@types/q": {
"version": "0.0.32",
"resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz",
......@@ -6943,6 +6958,11 @@
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
"dev": true
},
"mgrs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz",
"integrity": "sha1-+5FYjnjJACVnI5XLQLJffNatGCk="
},
"micromatch": {
"version": "2.3.11",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
......@@ -8425,6 +8445,23 @@
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
"dev": true
},
"proj4": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/proj4/-/proj4-2.4.4.tgz",
"integrity": "sha512-yo6qTpBQXnxhcPopKJeVwwOBRzUpEa3vzSFlr38f5mF4Jnfb6NOL/ePIomefWiZmPgkUblHpcwnWVMB8FS3GKw==",
"requires": {
"mgrs": "1.0.0",
"wkt-parser": "1.2.1"
}
},
"proj4leaflet": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/proj4leaflet/-/proj4leaflet-1.0.2.tgz",
"integrity": "sha512-6GdDeUlhX/tHUiMEj80xQhlPjwrXcdfD0D5OBymY8WvxfbmZcdhNqQk7n7nFf53ue6QdP9ls9ZPjsAxnbZDTsw==",
"requires": {
"proj4": "2.4.4"
}
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
......@@ -12461,6 +12498,11 @@
"integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
"dev": true
},
"wkt-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.2.1.tgz",
"integrity": "sha512-c6iNYzlbWNXwtcZ+0DMy1AOSHxVKFPR4a8EBVOgVbDSeSEnz2gpicmXSnuql1tKgS67CY+ughyjprP8pckk5jg=="
},
"wordwrap": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
......
......@@ -32,11 +32,13 @@
"@angular/router": "^5.2.0",
"@types/leaflet": "^1.2.7",
"@types/leaflet.markercluster": "^1.0.3",
"@types/proj4leaflet": "^1.0.5",
"bulma": "^0.7.1",
"core-js": "^2.4.1",
"font-awesome": "^4.7.0",
"leaflet": "^1.3.1",
"leaflet.markercluster": "^1.3.0",
"proj4leaflet": "^1.0.2",
"rxjs": "^5.5.6",
"zone.js": "^0.8.19"
},
......
import { Component, OnInit, Input } from '@angular/core';
import * as L from 'leaflet';
import 'leaflet.markercluster';
import 'proj4leaflet';
import { ActivatedRoute, ParamMap } from '@angular/router';
import { DatasetService } from '../../../services';
import { Metadata, Data } from '../../../models';
import { MapService } from '../../../services/map.service';
import * as wms from '../../../../../assets/leaflet.wms.js';
@Component({
selector: 'app-dataset-map',
......@@ -14,21 +17,20 @@ export class DatasetMapComponent implements OnInit {
metadata: Metadata;
constructor(
private _route: ActivatedRoute,
private _datasetService: DatasetService,
private route: ActivatedRoute,
private datasetService: DatasetService,
private mapService: MapService
) { }
ngOnInit() {
this._route.parent.paramMap
.switchMap((params: ParamMap) => this._datasetService.getMetadataById(params.get('id')))
this.route.parent.paramMap
.switchMap((params: ParamMap) => this.datasetService.getMetadataById(params.get('id')))
.subscribe((metadata: Metadata) => {
this._datasetService.getDataByMetadataById(metadata.dataset_index).subscribe(results => {
this.constructMap(results);
});
this.constructMap(metadata);
});
}
constructMap(results: Data[]) {
constructMap(metadata: Metadata) {
// Déclaration de la carte avec les coordonnées du centre et le niveau de zoom.
const attribution = 'Data Grand Lyon';
const satellite = L.tileLayer('https://openstreetmap.data.grandlyon.com/3857/tms/1.0.0/ortho2015@GoogleMapsCompatible/{z}/{x}/{-y}.png', { id: 'MapID', attribution: attribution });
......@@ -56,33 +58,89 @@ export class DatasetMapComponent implements OnInit {
const cluster = L.markerClusterGroup({
maxClusterRadius: 120
});
results.forEach(element => {
console.log(element);
switch (element.geometry.type) {
case 'Point':
const marker = L.marker([element.geometry.coordinates[1], element.geometry.coordinates[0]], { icon: myIcon })
.bindPopup(element.properties.nom).addTo(dataGrandLyonMap);
// group.push(marker);
cluster.addLayer(marker);
break;
case 'Polygon':
// create a red polygon from an array of LatLng points
element.geometry.coordinates.forEach(coordinates => {
coordinates.forEach(coord => {
coord.reverse();
});
const polygon = L.polygon(coordinates, { color: 'red' }).addTo(dataGrandLyonMap);
group.push(polygon);
});
break;
const hasWFS = metadata.uri.filter(function (e) { return e.protocol === 'OGC:WFS'; }).length > 0;
metadata.uri.forEach(element => {
if (hasWFS && element.protocol === 'OGC:WFS') {
const options = {
'name': element.name
};
this.mapService.getWFS(options).subscribe(results => {
console.log(results);
if (results.features[0].geometry.type === 'Point') {
L.geoJSON(results, {
pointToLayer: function (feature, latlng) {
return L.marker(latlng, { icon: myIcon }); // The basic style
}
}).addTo(dataGrandLyonMap);
} else if (results.features[0].geometry.type === 'Polygon') {
L.geoJSON(results, {
onEachFeature: function (feature, layer) {
let popContent = '';
for (const key in feature.properties) {
if (feature.properties.hasOwnProperty(key)) {
popContent += '<p>' + key + ': ' + feature.properties[key] + '</p>';
}
}
layer.bindPopup(popContent);
}
}).addTo(dataGrandLyonMap);
}
});
} else if (!hasWFS && element.protocol === 'OGC:WMS') {
const crs = new L.Proj.CRS('EPSG:4171',
'+proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs ');
L.tileLayer.wms('https://download.data.grandlyon.com/wms/grandlyon?', {
crs: crs,
transparent: true,
layers: element.name,
format: 'image/png',
zIndex: 1000
}).addTo(dataGrandLyonMap);
// source.addSubLayer(element.name);
// source.addTo(dataGrandLyonMap);
}
});
dataGrandLyonMap.addLayer(cluster);
const featureGroup = L.featureGroup(group);
// zoom the map to the polygon
dataGrandLyonMap.fitBounds(featureGroup.getBounds());
// results.forEach(element => {
// console.log(element);
// switch (element.geometry.type) {
// case 'Point':
// const marker = L.marker([element.geometry.coordinates[1], element.geometry.coordinates[0]], { icon: myIcon })
// .bindPopup(element.properties.nom).addTo(dataGrandLyonMap);
// // group.push(marker);
// cluster.addLayer(marker);
// break;
// case 'Polygon':
// // create a red polygon from an array of LatLng points
// element.geometry.coordinates.forEach(coordinates => {
// coordinates.forEach(coord => {
// coord.reverse();
// });
// const polygon = L.polygon(coordinates, { color: 'red' }).addTo(dataGrandLyonMap);
// group.push(polygon);
// });
// break;
// }
// });
// dataGrandLyonMap.addLayer(cluster);
// const featureGroup = L.featureGroup(group);
// // zoom the map to the polygon
// dataGrandLyonMap.fitBounds(featureGroup.getBounds());
L.control.scale().addTo(dataGrandLyonMap);
}
onEachFeature(feature, layer) {
// does this feature have a property named popupContent?
console.log(feature);
console.log(layer);
if (feature.properties && feature.properties.nom) {
layer.bindPopup(feature.properties.nom);
}
if (feature.properties && feature.properties.odentifiant) {
layer.bindPopup(feature.properties.identifiant);
}
}
}
......@@ -32,7 +32,7 @@ interface IContact {
export interface IMetadataUri {
'description': string;
'url': string;
'protocol': Array<string>;
'protocol': string;
'name': string;
}
......
import { DatasetService } from './dataset.service';
import { ElasticsearchService } from './elasticsearch.service';
import { MapService } from './map.service';
export { DatasetService, ElasticsearchService };
export const GeosourceServices = [
DatasetService,
ElasticsearchService
ElasticsearchService,
MapService
];
import { Injectable } from '@angular/core';
import { IfObservable } from 'rxjs/observable/IfObservable';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '@angular/common/http';
@Injectable()
export class MapService {
constructor(
private http: HttpClient
) {}
getWFS(options): Observable<any> {
const url = 'https://download.data.grandlyon.com/wfs/grandlyon?SERVICE=WFS&VERSION=2.0.0&outputformat=GEOJSON&maxfeatures=30&request=GetFeature&typename=' + options.name + '&SRSNAME=urn:ogc:def:crs:EPSG::4171';
return this.http.get(url);
}
}
/*!
* leaflet.wms.js
* A collection of Leaflet utilities for working with Web Mapping services.
* (c) 2014-2016, Houston Engineering, Inc.
* MIT License
*/
(function (factory) {
// Module systems magic dance, Leaflet edition
if (typeof define === 'function' && define.amd) {
// AMD
define(['leaflet'], factory);
} else if (typeof module !== 'undefined') {
// Node/CommonJS
module.exports = factory(require('leaflet'));
} else {
// Browser globals
if (typeof this.L === 'undefined')
throw 'Leaflet must be loaded first!';
// Namespace
this.L.WMS = this.L.wms = factory(this.L);
}
}(function (L) {
// Module object
var wms = {};
// Quick shim for Object.keys()
if (!('keys' in Object)) {
Object.keys = function(obj) {
var result = [];
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
result.push(i);
}
}
return result;
};
}
/*
* wms.Source
* The Source object manages a single WMS connection. Multiple "layers" can be
* created with the getLayer function, but a single request will be sent for
* each image update. Can be used in non-tiled "overlay" mode (default), or
* tiled mode, via an internal wms.Overlay or wms.TileLayer, respectively.
*/
wms.Source = L.Layer.extend({
'options': {
'untiled': true,
'identify': true
},
'initialize': function(url, options) {
L.setOptions(this, options);
if (this.options.tiled) {
this.options.untiled = false;
}
this._url = url;
this._subLayers = {};
this._overlay = this.createOverlay(this.options.untiled);
},
'createOverlay': function(untiled) {
// Create overlay with all options other than untiled & identify
var overlayOptions = {};
for (var opt in this.options) {
if (opt != 'untiled' && opt != 'identify') {
overlayOptions[opt] = this.options[opt];
}
}
if (untiled) {
return wms.overlay(this._url, overlayOptions);
} else {
return wms.tileLayer(this._url, overlayOptions);
}
},
'onAdd': function() {
this.refreshOverlay();
},
'getEvents': function() {
if (this.options.identify) {
return {'click': this.identify};
} else {
return {};
}
},
'setOpacity': function(opacity) {
this.options.opacity = opacity;
if (this._overlay) {
this._overlay.setOpacity(opacity);
}
},
'bringToBack': function() {
this.options.isBack = true;
if (this._overlay) {
this._overlay.bringToBack();
}
},
'bringToFront': function() {
this.options.isBack = false;
if (this._overlay) {
this._overlay.bringToFront();
}
},
'getLayer': function(name) {
return wms.layer(this, name);
},
'addSubLayer': function(name) {
this._subLayers[name] = true;
this.refreshOverlay();
},
'removeSubLayer': function(name) {
delete this._subLayers[name];
this.refreshOverlay();
},
'refreshOverlay': function() {
var subLayers = Object.keys(this._subLayers).join(",");
if (!this._map) {
return;
}
if (!subLayers) {
this._overlay.remove();
} else {
this._overlay.setParams({'layers': subLayers});
this._overlay.addTo(this._map);
}
},
'identify': function(evt) {
// Identify map features in response to map clicks. To customize this
// behavior, create a class extending wms.Source and override one or
// more of the following hook functions.
var layers = this.getIdentifyLayers();
if (!layers.length) {
return;
}
this.getFeatureInfo(
evt.containerPoint, evt.latlng, layers,
this.showFeatureInfo
);
},
'getFeatureInfo': function(point, latlng, layers, callback) {
// Request WMS GetFeatureInfo and call callback with results
// (split from identify() to faciliate use outside of map events)
var params = this.getFeatureInfoParams(point, layers),
url = this._url + L.Util.getParamString(params, this._url);
this.showWaiting();
this.ajax(url, done);
function done(result) {
this.hideWaiting();
var text = this.parseFeatureInfo(result, url);
callback.call(this, latlng, text);
}
},
'ajax': function(url, callback) {
ajax.call(this, url, callback);
},
'getIdentifyLayers': function() {
// Hook to determine which layers to identify
if (this.options.identifyLayers)
return this.options.identifyLayers;
return Object.keys(this._subLayers);
},
'getFeatureInfoParams': function(point, layers) {
// Hook to generate parameters for WMS service GetFeatureInfo request
var wmsParams, overlay;
if (this.options.untiled) {
// Use existing overlay
wmsParams = this._overlay.wmsParams;
} else {
// Create overlay instance to leverage updateWmsParams
overlay = this.createOverlay(true);
overlay.updateWmsParams(this._map);
wmsParams = overlay.wmsParams;
wmsParams.layers = layers.join(',');
}
var infoParams = {
'request': 'GetFeatureInfo',
'query_layers': layers.join(','),
'X': Math.round(point.x),
'Y': Math.round(point.y)
};
return L.extend({}, wmsParams, infoParams);
},
'parseFeatureInfo': function(result, url) {
// Hook to handle parsing AJAX response
if (result == "error") {
// AJAX failed, possibly due to CORS issues.
// Try loading content in <iframe>.
result = "<iframe src='" + url + "' style='border:none'>";
}
return result;
},
'showFeatureInfo': function(latlng, info) {
// Hook to handle displaying parsed AJAX response to the user
if (!this._map) {
return;
}
this._map.openPopup(info, latlng);
},
'showWaiting': function() {
// Hook to customize AJAX wait animation
if (!this._map)
return;
this._map._container.style.cursor = "progress";
},
'hideWaiting': function() {
// Hook to remove AJAX wait animation
if (!this._map)
return;
this._map._container.style.cursor = "default";
}
});
wms.source = function(url, options) {
return new wms.Source(url, options);
};
/*
* Layer
* Leaflet "layer" with all actual rendering handled via an underlying Source
* object. Can be called directly with a URL to automatically create or reuse
* an existing Source. Note that the auto-source feature doesn't work well in
* multi-map environments; so for best results, create a Source first and use
* getLayer() to retrieve wms.Layer instances.
*/
wms.Layer = L.Layer.extend({
'initialize': function(source, layerName, options) {
L.setOptions(this, options);
if (!source.addSubLayer) {
// Assume source is a URL
source = wms.getSourceForUrl(source, options);
}
this._source = source;
this._name = layerName;
},
'onAdd': function() {
if (!this._source._map)
this._source.addTo(this._map);
this._source.addSubLayer(this._name);
},
'onRemove': function() {
this._source.removeSubLayer(this._name);
},
'setOpacity': function(opacity) {
this._source.setOpacity(opacity);
},
'bringToBack': function() {
this._source.bringToBack();
},
'bringToFront': function() {
this._source.bringToFront();
}
});
wms.layer = function(source, options) {
return new wms.Layer(source, options);
};
// Cache of sources for use with wms.Layer auto-source option
var sources = {};
wms.getSourceForUrl = function(url, options) {
if (!sources[url]) {
sources[url] = wms.source(url, options);
}