Skip to content

Commit

Permalink
Merge pull request #46 from aarranz/feature/allow-select-by-id
Browse files Browse the repository at this point in the history
Allow passing a list of ids to the poiInputCenter endpoint
  • Loading branch information
aarranz committed Jan 31, 2022
2 parents 8ef4499 + c130d40 commit 550d47a
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 122 deletions.
2 changes: 1 addition & 1 deletion src/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<wiring>
<inputendpoint name="layerInfo" type="text" label="Layer Info" description="Add or remove layers to the map, in addition to changing its base layer." actionlabel="Update Layers" friendcode="ol-layer-command wms-layer-command"/>
<inputendpoint name="poiInput" type="text" label="Insert/Update PoI" description="Insert or update a Point of Interest." actionlabel="Map Viewer Insert/Update PoI" friendcode="poi poi-list"/>
<inputendpoint name="poiInputCenter" type="text" label="Center PoI" description="Insert or update a Point of Interest and center the map on it." actionlabel="Center" friendcode="poi poi-list" />
<inputendpoint name="poiInputCenter" type="text" label="Center PoI" description="Insert or update a Point of Interest and center the map on it." actionlabel="Center" friendcode="poi poi-list poi-id-list" />
<inputendpoint name="deletePoiInput" type="text" label="Delete PoI" description="Removes one or more point of interests from the map." actionlabel="Remove" friendcode="poi poi-list" />
<inputendpoint name="replacePoIs" type="text" label="Replace PoIs" description="Replace all the rendered PoIs by the ones provided in the event." actionlabel="Map Viewer Insert/Update PoI" friendcode="poi poi-list"/>
<outputendpoint name="poiOutput" type="text" label="PoI selected" description="A PoI has been selected on the map" friendcode="poi"/>
Expand Down
1 change: 1 addition & 0 deletions src/doc/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Fix placement of popovers when icon anchor is different to `[0.5, 1]`
- Switch code to use let and const
- Update popover contents when the selected PoI is updated
- Allow to pass a list of feature ids to the `poiInputCenter` endpoint


## v1.2.3 (2021-03-25)
Expand Down
49 changes: 40 additions & 9 deletions src/doc/userguide.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ Map viewer widget using OpenLayers. It can receive Layers or Point of Interest d
- `anchor`: Anchor position. Default value is `[0.5, 0.5]` (icon
center).
- `anchorXUnits`: Units in which the anchor x value is specified. A
value of `'fraction'` indicates the x value is a fraction of the
icon. A value of `'pixels'` indicates the x value in pixels. Default
is `'fraction'`.
value of `"fraction"` indicates the x value is a fraction of the
icon. A value of `"pixels"` indicates the x value in pixels. Default
is `"fraction"`.
- `anchorYUnits`: Units in which the anchor y value is specified. A
value of `'fraction'` indicates the y value is a fraction of the
icon. A value of `'pixels'` indicates the y value in pixels. Default
is `'fraction'`.
value of `"fraction"` indicates the y value is a fraction of the
icon. A value of `"pixels"` indicates the y value in pixels. Default
is `"fraction"`.
- `opacity`: Opacity of the icon (range from 0 to 1). Default is `1`.
- `scale`: Scale. Default is `1`.
- `src`: Image source URI.
Expand Down Expand Up @@ -117,9 +117,40 @@ Map viewer widget using OpenLayers. It can receive Layers or Point of Interest d
- `subtitle`: subtitle associated to the PoI
- `title`: title associated to the PoI
- `tooltip`: text to be displayed as tooltip when the mouse is over the PoI.
- **Insert/Update Centered PoI**: Insert or update a PoI and change the viewport
centering the map on it. Uses the same format used by the **Insert/Update PoI**
endpoint.
- **Center PoI**: Updates the viewport to make visible the provided list of
PoIs. If the viewport is already displaying the provide list of PoIs, the
viewport is not modified. This endpoint can also be used to update or to insert
new PoIs by providing PoI information using the same format used in the
**Insert/Update PoI** endpoint.

Examples:

- `null`: Clears current selection.
- `["vehicle-1", "vehicle-2"]`: Ensures `vehicle-1` and `vehicle-2` are
visible.
- ```json
[{
"id": "vehicle-1",
"location": {
"type": "Point",
"coordinates": [
-8.51,
41.11
]
},
"infoWindow": "test1",
"icon": {
"fontawesome": {
"glyph": "fa-motorcycle"
}
}
}]
```

Updates `vehicle-1` and makes it visible on the map. If `vehicle-1` is
not the current selecte PoI, selection will be udpated to make it the
selected PoI.

- **Delete PoI**: Removes a point or more point of interests from the map.
- **Replace PoIs**: Replace all the rendered PoIs by the ones provided in the
event. Uses the same format used by the **Insert/Update PoI**
Expand Down
6 changes: 5 additions & 1 deletion src/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,11 @@
poi_info = [poi_info];
}

poi_info.forEach(widget.registerPoI, widget);
poi_info.forEach((poi) => {
if (poi != null && typeof poi === "object") {
widget.registerPoI(poi)
}
});
widget.centerPoI(poi_info);
});

Expand Down
153 changes: 80 additions & 73 deletions src/js/ol3-map-widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,50 @@
CORE_LAYERS.GOOGLE_HYBRID = CORE_LAYERS.MAPQUEST_HYBRID;
CORE_LAYERS.GOOGLE_SATELLITE = CORE_LAYERS.MAPQUEST_SATELLITE;

const create_popover = function create_popover(feature) {
// The feature has content to be used on a popover
this.popover = new StyledElements.Popover({
placement: ['top', 'bottom', 'right', 'left'],
title: feature.get('title'),
content: new StyledElements.Fragment(feature.get('content')),
sticky: true
});
this.popover.on('hide', (popover) => {
// The popover can be hidden by clicking outside the widget. So we have to listen to this event
// On the other side, we have to detect if this popover is applying to current state
if (this.popover === popover) {
this.popover = null;
update_selected_feature.call(this, null);
}
});
this.popover.show(this.refpos);
};

const update_popover = function update_popover(feature) {
if ("update" in this.popover) {
// WireCloud 1.4+
this.popover.update(
feature.get("title"),
new StyledElements.Fragment(feature.get("content"))
);
} else {
// Workaround for WireCloud 1.3 and below
const popover = this.popover;
this.popover = null;
popover.hide().hide();
create_popover.call(this, feature);
// Call show method again to cancel fade animation
this.popover.show(this.refpos);
}
};

const update_selected_feature = function update_selected_feature(feature) {
if (this.selected_feature != feature) {
this.selected_feature = feature;
if (feature == null && this.popover != null) {
this.popover.hide();
const popover = this.popover;
this.popover = null;
popover.hide();
}
MashupPlatform.widget.outputs.poiOutput.pushEvent(feature != null ? feature.get('data') : null);
}
Expand Down Expand Up @@ -394,6 +432,7 @@
this.base_layer = null;
this.popover = null;
this.layers = {};
this.centering = false;
};

Widget.prototype.init = function init() {
Expand Down Expand Up @@ -540,7 +579,7 @@
});

// display popup on click
this.map.on('click', function (event) {
this.map.on("click", (event) => {
const features = [];
this.map.forEachFeatureAtPixel(
event.pixel,
Expand Down Expand Up @@ -596,10 +635,10 @@
} else if (this.selected_feature != null && this.selected_feature.get('content') == null) {
unselect.call(this, this.selected_feature);
update_selected_feature.call(this, null);
} else if (feature !== this.selected_feature) {
} else {
update_selected_feature.call(this, null);
}
}.bind(this));
});

// change mouse cursor when over marker
this.map.on('pointermove', (event) => {
Expand All @@ -624,7 +663,9 @@
});
this.map.on("movestart", () => {
if (this.popover != null && !("disablePointerEvents" in this.popover)) {
this.popover.hide();
if (!this.centering) {
this.popover.hide();
}
} else if (this.popover != null) {
this.popover.disablePointerEvents();
}
Expand All @@ -637,6 +678,7 @@
this.popover.repaint();
}
send_visible_pois.call(this);
this.centering = false;
});

this.geojsonparser = new ol.format.GeoJSON();
Expand Down Expand Up @@ -711,22 +753,7 @@

if (this.selected_feature === iconFeature) {
if (this.popover != null) {
if ("update" in this.popover) {
// WireCloud 1.4+
this.popover.update(
iconFeature.get("title"),
new StyledElements.Fragment(iconFeature.get("content"))
);
} else {
// Workaround for WireCloud 1.3 and below
const popover = this.popover;
this.popover = null;
popover.hide().hide();
this.popover = popover;
popover.options.title = iconFeature.get("title");
popover.options.content = new StyledElements.Fragment(iconFeature.get("content"));
popover.show(this.refpos);
}
update_popover.call(this, iconFeature);
}
MashupPlatform.widget.outputs.poiOutput.pushEvent(iconFeature.get('data'));
}
Expand All @@ -751,22 +778,7 @@

if (this.popover != null) {
if (new_selected_feature != null) {
if ("update" in this.popover) {
// WireCloud 1.4+
this.popover.update(
new_selected_feature.get("title"),
new StyledElements.Fragment(new_selected_feature.get("content"))
);
} else {
// Workaround for WireCloud 1.3 and below
const popover = this.popover;
this.popover = null;
popover.hide().hide();
this.popover = popover;
popover.options.title = new_selected_feature.get("title");
popover.options.content = new StyledElements.Fragment(new_selected_feature.get("content"));
popover.show(this.refpos);
}
update_popover.call(this, new_selected_feature);
} else {
this.popover.hide();
this.popover = null;
Expand All @@ -782,33 +794,37 @@
* @param poi_info
*/
Widget.prototype.centerPoI = function centerPoI(poi_info) {
if (poi_info.length === 0) {
const geometries = poi_info.map((poi) => {
const feature = this.vector_source.getFeatureById(typeof poi === "string" ? poi : poi.id);
return feature != null ? feature.getGeometry() : null;
}).filter((geometry) => geometry != null);

if (geometries.length === 0) {
// Just empty current selection
unselect.call(this, this.selected_feature);
return update_selected_feature.call(this, null);
}

const geometry = new ol.geom.GeometryCollection(poi_info.map((poi) => {
const feature = this.vector_source.getFeatureById(poi.id);
return feature.getGeometry();
}));
const geometryset = new ol.geom.GeometryCollection(geometries);

// Update map view
const zoom = parseInt(MashupPlatform.prefs.get('poiZoom'), 10);
const currentZoom = this.map.getView().getZoom();
if (currentZoom < zoom) {
this.map.getView().fit(geometry.getExtent(), {
this.centering = true;
this.map.getView().fit(geometryset.getExtent(), {
maxZoom: zoom
});
} else {
const view_extent = this.map.getView().calculateExtent(this.map.getSize());
const geometry_extent = geometry.getExtent();
const geometry_extent = geometryset.getExtent();
if (!ol.extent.containsExtent(view_extent, geometry_extent)) {
const view_size = ol.extent.getSize(view_extent);
const geometry_size = ol.extent.getSize(geometry_extent);

this.centering = true;
if (view_size[0] < geometry_size[0] && view_size[1] < geometry_size[1]) {
this.map.getView().fit(geometry.getExtent(), {
this.map.getView().fit(geometryset.getExtent(), {
maxZoom: zoom
});
} else {
Expand All @@ -819,7 +835,7 @@
}

if (poi_info.length == 1) {
this.select_feature(this.vector_source.getFeatureById(poi_info[0].id));
this.select_feature(this.vector_source.getFeatureById(typeof poi_info[0] === "string" ? poi_info[0] : poi_info[0].id));
}
};

Expand Down Expand Up @@ -1253,6 +1269,10 @@
};

Widget.prototype.select_feature = function select_feature(feature) {
if (this.selected_feature === feature) {
// Selection is not changing
return;
}

unselect.call(this, this.selected_feature);

Expand All @@ -1262,36 +1282,23 @@

update_selected_feature.call(this, feature);

if (feature.get('content') != null) {
// The feature has content to be used on a popover
const popover = this.popover = new StyledElements.Popover({
placement: ['top', 'bottom', 'right', 'left'],
title: feature.get('title'),
content: new StyledElements.Fragment(feature.get('content')),
sticky: true
});
popover.on('show', () => {
update_selected_feature.call(this, feature);
});
popover.on('hide', (popover) => {
// The popover can be hidden by clicking outside the widget. So we have to listen to this event
// On the other side, we have to detect if this popover is applying to current state
if (this.popover === popover) {
this.popover = null;
update_selected_feature.call(this, null);
}
});
if (this.popover == null && feature.get('content') != null) {
create_popover.call(this, feature);

// Delay popover show action
// Repaint popover after 200ms, to handle the situation where the
// marker is not yet loaded
// TODO, do this with events instead of using a fixed time
setTimeout(() => {
if (this.popover !== popover) {
// Selection has changed in the middle
return;
if (this.popover != null) {
this.popover.repaint();
}

update_selected_feature.call(this, feature);
this.popover.show(this.refpos);
}, 100);
}, 200);
} else if (this.popover != null && feature.get("content") == null) {
const popover = this.popover;
this.popover = null;
popover.hide().hide();
} else if (this.popover != null /* && feature.get("content") != null */) {
update_popover.call(this, feature);
}
};

Expand Down

0 comments on commit 550d47a

Please sign in to comment.