Skip to content

Commit

Permalink
feat: display of drawn feature (#371)
Browse files Browse the repository at this point in the history
* basic structure for list

* structure with css

* basic functionality added to list

* cleaned code

* prettier

* fix discard button

* added animation

* added diselect feature

* comemnt added

* import style from one file

* ol removed from draw

* revert CHANGELOG
  • Loading branch information
srijitcoder authored Nov 15, 2023
1 parent 8fa4067 commit 43753b6
Show file tree
Hide file tree
Showing 7 changed files with 417 additions and 12 deletions.
49 changes: 49 additions & 0 deletions elements/drawtools/drawtools.stories.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { html } from "lit";
import "../map/main";
import "./src/main";
import { getDefaultSelectedOption } from "./src/helpers";

export default {
title: "Elements/eox-drawtools",
Expand Down Expand Up @@ -39,3 +40,51 @@ export const MultiPolygon = {
multiple-features
></eox-drawtools>`,
};

/**
* By setting the `show-list` attribute or `showList` property to `true`,
* List of features will be visible
*/
export const MultiPolygonWithList = {
play: async ({ canvasElement }) => {
const EOxMap = canvasElement.querySelector("eox-map");

EOxMap.addSelect(
"draw",
getDefaultSelectedOption("draw-hover", "pointermove")
);
EOxMap.addSelect(
"draw",
getDefaultSelectedOption("draw-click", "click", true)
);
},
render: () => html`
<div style="display: flex">
<eox-map
id="list"
style="width: 500px; height: 300px;"
layers=${JSON.stringify([
{
type: "Vector",
id: "draw",
source: {
type: "Vector",
},
},
{
type: "Tile",
source: {
type: "OSM",
},
},
])}
></eox-map>
<eox-drawtools
for="eox-map#list"
layer="draw"
multiple-features
show-list
></eox-drawtools>
</div>
`,
};
216 changes: 216 additions & 0 deletions elements/drawtools/src/components/list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import { LitElement, html, nothing } from "lit";
import { keyed } from "lit/directives/keyed.js";
import { styleEOX } from "../style.eox";
import { getDefaultSelectedOption } from "../helpers";

/**
* Display list of features
*
* @element eox-drawtools-list
*/
export class EOxDrawToolsList extends LitElement {
static properties = {
eoxMap: { attribute: false, state: true },
olMap: { attribute: false, state: true },
draw: { attribute: false, state: true },
layer: { type: String },
drawLayer: { attribute: false, state: true },
drawnFeatures: { attribute: false, state: true, type: Array },
modify: { attribute: false, state: true },
unstyled: { type: Boolean },
};

/**
* @type import("../../../map/src/select").EOxSelectInteraction
*/
hoverInteraction;

/**
* @type import("../../../map/src/select").EOxSelectInteraction
*/
clickInteraction;

/**
* @type string | number
*/
hoverId;

/**
* @type string | number
*/
clickId;

constructor() {
super();

/**
* @type import("../../../map/main").EOxMap
*/
this.eoxMap = null;

/**
* @type import("ol").Map
*/
this.olMap = null;

/**
* The current native OpenLayers `draw` interaction
* @type import("ol/interaction").Draw
*/

this.draw = null;

/**
* The layer id of the draw layer
* @default draw
*/
this.layer = "draw";

/**
* The current native OpenLayers draw `layer`
* @type import("ol/layer").Vector<import("ol/source").Vector>
*/

this.drawLayer = null;

/**
* The array of drawn native OpenLayers features. Normally includes only one feature, until multiple feature drawing is enabled.
* @type Array<import("ol").Feature>
*/
this.drawnFeatures = [];

/**
* The current native OpenLayers `modify` interaction
* @type import("ol/interaction").Modify
*/

this.modify = null;

/**
* Render the element without additional styles
*/
this.unstyled = false;
}

/**
* Delete individual feature @param {any} evt
*/
_handleDelete(evt) {
evt.stopPropagation();
const index = evt.target.getAttribute("index");
const feature = this.drawnFeatures[index];
this.drawLayer.getSource().removeFeature(feature);
this.drawnFeatures.splice(index, 1);
this.requestUpdate();
}

/**
* Select and Deselect feature from the list
*
* @param {import("ol").Feature} feature
*/
_handleFeatureSelectAndDeselect(feature) {
const selectedFeatureId = feature.get("id");

// Deselect selected feature
if (this.clickId === selectedFeatureId) {
const newExtent = this.drawLayer.getSource().getExtent();
this.olMap.getView().fit(newExtent, { duration: 750 });
this.clickInteraction.highlightById([]);
}
// Select the clicked feature
else {
this.clickInteraction.highlightById([selectedFeatureId]);
this.olMap
.getView()
.fit(feature.getGeometry().getExtent(), { duration: 750 });
}

this.requestUpdate();
}

firstUpdated() {
const isHoverInteractionExist =
this.eoxMap?.selectInteractions["draw-hover"];
const isClickInteractionExist =
this.eoxMap?.selectInteractions["draw-click"];

/*
* Check if interaction exist or not
* If not initialize a new interaction for hover and click
*/
if (!isHoverInteractionExist)
this.hoverInteraction = this.eoxMap.addSelect(
this.layer,
getDefaultSelectedOption("draw-hover", "pointermove")
);
if (!isClickInteractionExist)
this.clickInteraction = this.eoxMap.addSelect(
this.layer,
getDefaultSelectedOption("draw-click", "click", true)
);

// Event trigger when style change due to interaction
this.hoverInteraction.selectStyleLayer.on("change", () =>
this.requestUpdate()
);
this.clickInteraction.selectStyleLayer.on("change", () =>
this.requestUpdate()
);
}

render() {
this.hoverInteraction = this.eoxMap.selectInteractions["draw-hover"];
this.clickInteraction = this.eoxMap.selectInteractions["draw-click"];

this.hoverId = this.hoverInteraction?.selectedFids[0];
this.clickId = this.clickInteraction?.selectedFids[0];

return html`
<style>
${!this.unstyled && styleEOX}
</style>
<ul>
${this.drawnFeatures.map((feature, i) => {
const featureId = feature.get("id");
const selected =
this.hoverId === featureId || this.clickId === featureId;
return keyed(
i + 1,
html`
<li
class="${selected ? "selected" : nothing}"
@mouseover=${() => {
if (this.clickId === featureId) return;
this.hoverInteraction.highlightById([featureId]);
}}
@mouseout=${() => {
if (this.clickId === featureId) return;
this.hoverInteraction.highlightById([]);
}}
>
<div
class="list"
@click="${() =>
this._handleFeatureSelectAndDeselect(feature)}"
>
<span class="title">Feature #${i + 1}</span>
<button
index=${i}
class="icon small discard"
@click="${this._handleDelete}"
>
${this.unstyled ? "x" : nothing}
</button>
</div>
</li>
`
);
})}
</ul>
`;
}
}

customElements.define("eox-drawtools-list", EOxDrawToolsList);
28 changes: 28 additions & 0 deletions elements/drawtools/src/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Default selected option
* @param {string} id
* @param {"click" | "pointermove"} condition
* @param {Boolean} panIn
* @returns {import("../../map/src/select").SelectOptions}
*/
export const getDefaultSelectedOption = (id, condition, panIn = false) => {
return {
id,
condition,
panIn,
layer: {
type: "Vector",
properties: {
id: "selectLayer",
},
source: {
type: "Vector",
},
style: {
"fill-color": "rgba(51, 153, 204,0.5)",
"stroke-color": "#3399CC",
"stroke-width": 2.5,
},
},
};
};
21 changes: 21 additions & 0 deletions elements/drawtools/src/main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { LitElement, html, nothing } from "lit";
import "./components/list";
import { style } from "./style";
import { styleEOX } from "./style.eox";

Expand All @@ -17,6 +18,7 @@ export class EOxDrawTools extends LitElement {
layer: { type: String },
modify: { attribute: false, state: true },
multipleFeatures: { attribute: "multiple-features", type: Boolean },
showList: { attribute: "show-list", type: Boolean },
unstyled: { type: Boolean },
};
}
Expand Down Expand Up @@ -83,6 +85,11 @@ export class EOxDrawTools extends LitElement {
*/
this.multipleFeatures = false;

/**
* Show list of features
*/
this.showList = false;

/**
* Render the element without additional styles
*/
Expand Down Expand Up @@ -198,6 +205,20 @@ export class EOxDrawTools extends LitElement {
discard
</button>
</div>
${this.showList && this.drawnFeatures?.length
? html`<eox-drawtools-list
.eoxMap=${this.#eoxMap}
.olMap=${this.#olMap}
.draw=${this.draw}
.layer=${this.layer}
.drawLayer=${this.drawLayer}
.drawnFeatures=${this.drawnFeatures}
.modify=${this.modify}
.unstyled=${this.unstyled}
@changed=${() => this.requestUpdate()}
>
</eox-drawtools-list>`
: nothing}
`;
}
}
Expand Down
Loading

0 comments on commit 43753b6

Please sign in to comment.