@geoblocks/elevation-profile 0.0.11 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -0
- package/dist/elevation-profile.d.ts +2 -0
- package/dist/elevation-profile.d.ts.map +1 -1
- package/dist/elevation-profile.js +11 -5
- package/dist/elevation-profile.js.map +1 -1
- package/elevation-profile.ts +6 -5
- package/package.json +8 -8
- package/dist/index.600fa9d1.js +0 -5366
- package/dist/index.600fa9d1.js.map +0 -1
- package/dist/index.html +0 -291
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# `<elevation-profile>`
|
|
2
|
+
|
|
3
|
+
A web component to display an elevation profile of a MultiLineString.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i --save @geoblocks/elevation-profile
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<elevation-profile .lines="${lines}"></elevation-profile>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## API
|
|
18
|
+
|
|
19
|
+
### Properties/Attributes
|
|
20
|
+
|
|
21
|
+
| Name | Type | Default | Description
|
|
22
|
+
| --------------- | ---------------- | -------------------------------------------- | -----------
|
|
23
|
+
| `lines` | `number[][][]` | | MultiLineString coordinates
|
|
24
|
+
| `margin` | `Object` | `{top: 20, right: 20, bottom: 20, left: 40}` | Margin in pixels around the elevation profile
|
|
25
|
+
| `pointerEvents` | `Boolean` | `true` | Whether to emit pointer events
|
|
26
|
+
| `tickSize` | `Object` | `{x: 100, y: 40}` | Size of the ticks in pixels
|
|
27
|
+
| `locale` | `string` | `navigator.language` | Locale for the axis labels
|
|
28
|
+
| `tolerance` | `number` | `1` | Tolerance for the line simplification. Set to `0` to disable simplification
|
|
29
|
+
|
|
30
|
+
The value of the tick in the axis can be changed by overriding the `tickFormat` method.
|
|
31
|
+
```javascript
|
|
32
|
+
profile.tickFormat = (value, axis) => {
|
|
33
|
+
return Math.round(value);
|
|
34
|
+
};
|
|
35
|
+
```
|
|
36
|
+
Where `value` is the value of the tick and `axis` is the axis where the tick is located (`x` or `y`).
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
### Events
|
|
40
|
+
|
|
41
|
+
If `pointerEvents` is `true`, the component will emit the following custom events on pointer interaction:
|
|
42
|
+
|
|
43
|
+
| Name | When | Detail type | Description
|
|
44
|
+
| --------------- | ------------------------------------------- | ---------------------------------------------------------- | -----------
|
|
45
|
+
| `over` | The pointer is over the profile | `{coordinate: number[], position: {x: number, y: number}}` | `coordinate` is the coordinate of the point on the MultiLineString and `position` is the position of the pointer relative to the component
|
|
46
|
+
| `out` | The pointer leaves the profile | |
|
|
47
|
+
|
|
48
|
+
### Styling
|
|
49
|
+
|
|
50
|
+
TODO: describe CSS selectors
|
|
@@ -21,6 +21,7 @@ export default class ElevationProfile extends LitElement {
|
|
|
21
21
|
x: number;
|
|
22
22
|
y: number;
|
|
23
23
|
};
|
|
24
|
+
pointerEvents: boolean;
|
|
24
25
|
pointer: {
|
|
25
26
|
x: number;
|
|
26
27
|
y: number;
|
|
@@ -28,6 +29,7 @@ export default class ElevationProfile extends LitElement {
|
|
|
28
29
|
updated(changedProperties: PropertyValues): void;
|
|
29
30
|
willUpdate(changedProperties: PropertyValues): void;
|
|
30
31
|
render(): import("lit-html").TemplateResult<2>;
|
|
32
|
+
tickFormat(value: number, axis: 'x' | 'y'): string;
|
|
31
33
|
firstUpdated(): void;
|
|
32
34
|
createRenderRoot(): this;
|
|
33
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";AAmBA,0BAA0B;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC;CAClC,CAAC;AAEF,qCACsC,SAAQ,UAAU;IAC5B,SAAS,SAAK;IACd,MAAM,SAAsB;IAC7B,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAM;IACtC,WAAW,0CAA2C,MAAM,UAAU,MAAM,KAAG,IAAI,CAAO;IAC5E,MAAM;;;;;MAA8C;IACpD,QAAQ;;;MAAmB;
|
|
1
|
+
{"mappings":";AAmBA,0BAA0B;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC;CAClC,CAAC;AAEF,qCACsC,SAAQ,UAAU;IAC5B,SAAS,SAAK;IACd,MAAM,SAAsB;IAC7B,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAM;IACtC,WAAW,0CAA2C,MAAM,UAAU,MAAM,KAAG,IAAI,CAAO;IAC5E,MAAM;;;;;MAA8C;IACpD,QAAQ;;;MAAmB;IAC1B,aAAa,UAAQ;IAEvC,OAAO;;;MAAgB;IAyBvB,OAAO,CAAC,iBAAiB,EAAE,cAAc;IAczC,UAAU,CAAC,iBAAiB,EAAE,cAAc;IAgB5C,MAAM;IA2DR,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,GAAG;IAQvC,YAAY;IA+CZ,gBAAgB;CAG1B;AAGD,QAAQ,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,mBAAmB,EAAE,gBAAgB,CAAC;KACvC;CACF","sources":["elevation-profile.ts"],"sourcesContent":["import {LitElement, svg} from 'lit';\nimport {customElement, state, property} from 'lit/decorators.js';\nimport {ResizeController} from '@lit-labs/observers/resize-controller.js';\nimport type {PropertyValues} from 'lit';\n\nimport {extent, bisector} from 'd3-array';\nimport {scaleLinear} from 'd3-scale';\nimport {line, area} from 'd3-shape';\nimport {axisBottom, axisLeft} from 'd3-axis';\nimport {select, pointer} from 'd3-selection';\n\nimport simplify from 'simplify-js';\n\ntype PlotPoint = {\n x: number;\n y: number;\n coordinate: number[];\n};\n\nexport type OverDetails = {\n coordinate: number[];\n position: {x: number; y: number};\n};\n\n@customElement('elevation-profile')\nexport default class ElevationProfile extends LitElement {\n @property({type: Number}) tolerance = 1;\n @property({type: String}) locale = navigator.language;\n @property({type: Array}) lines: number[][][] = [];\n @property() updateScale = (x: scaleLinear, y: scaleLinear, width: number, height: number): void => {};\n @property({type: Object}) margin = {top: 20, right: 20, bottom: 20, left: 40};\n @property({type: Object}) tickSize = {x: 100, y: 40};\n @property({type: Boolean}) pointerEvents = true;\n\n @state() pointer = {x: 0, y: 0};\n private _resizeController = new ResizeController(this, {});\n\n private plotData: PlotPoint[] = [];\n private scaleX = scaleLinear();\n private scaleY = scaleLinear();\n\n private bisectDistance = bisector((point: PlotPoint) => point.x);\n\n private line = line()\n .defined((point: PlotPoint) => !isNaN(point.y))\n .x((point: PlotPoint) => this.scaleX(point.x))\n .y((point: PlotPoint) => this.scaleY(point.y));\n private area = area()\n .defined((point: PlotPoint) => !isNaN(point.y))\n .x((point: PlotPoint) => this.scaleX(point.x))\n .y1((point: PlotPoint) => this.scaleY(point.y));\n private xAxis = axisBottom(this.scaleX).tickFormat((value: number) => this.tickFormat(value, 'x'));\n private yAxis = axisLeft(this.scaleY).tickFormat((value: number) => this.tickFormat(value, 'y'));\n private xGrid = axisBottom(this.scaleX).tickFormat(() => '');\n private yGrid = axisLeft(this.scaleY).tickFormat(() => '');\n\n private meterFormat: Intl.NumberFormat | null = null;\n private kilometerFormat: Intl.NumberFormat | null = null;\n\n override updated(changedProperties: PropertyValues) {\n if (changedProperties.has('locale')) {\n this.meterFormat = new Intl.NumberFormat(this.locale, {\n style: 'unit',\n unit: 'meter',\n });\n\n this.kilometerFormat = new Intl.NumberFormat(this.locale, {\n style: 'unit',\n unit: 'kilometer',\n });\n }\n }\n\n override willUpdate(changedProperties: PropertyValues) {\n if (changedProperties.has('lines')) {\n this.plotData.length = 0;\n for (const line of this.lines) {\n const data = line.map((coordinate) => ({x: coordinate[3], y: coordinate[2], coordinate}));\n this.plotData.push(...simplify(data, this.tolerance));\n this.plotData.push({x: line[line.length - 1][3], y: NaN, coordinate: []});\n }\n\n this.scaleX.domain(extent(this.plotData, (data: PlotPoint) => data.x));\n this.scaleY.domain(extent(this.plotData, (data: PlotPoint) => data.y)).nice();\n\n this.updateScale(this.scaleX, this.scaleY, this.offsetWidth, this.offsetHeight);\n }\n }\n\n override render() {\n const width = this.offsetWidth;\n const height = this.offsetHeight;\n\n this.scaleX.range([this.margin.left, width - this.margin.right]);\n this.scaleY.range([height - this.margin.bottom, this.margin.top]);\n\n this.area.y0(height - this.margin.bottom);\n\n this.yGrid.tickSize(-width + this.margin.left + this.margin.right);\n this.xGrid.tickSize(height - this.margin.top - this.margin.bottom);\n\n const xTicks = width / this.tickSize.x;\n const yTicks = height / this.tickSize.y;\n this.xAxis.ticks(xTicks);\n this.xGrid.ticks(xTicks);\n this.yAxis.ticks(yTicks);\n this.yGrid.ticks(yTicks);\n\n select(this.querySelector('.axis.x')).call(this.xAxis);\n select(this.querySelector('.axis.y')).call(this.yAxis);\n select(this.querySelector('.grid.x')).call(this.xGrid);\n select(this.querySelector('.grid.y')).call(this.yGrid);\n\n return svg`\n <svg width=\"${width}\" height=\"${height}\" xmlns=\"http://www.w3.org/2000/svg\">\n <g class=\"grid y\" transform=\"translate(${this.margin.left}, 0)\" />\n <g class=\"grid x\" transform=\"translate(0, ${this.margin.bottom})\" />\n <g class=\"axis x\" transform=\"translate(0, ${height - this.margin.bottom})\" />\n <g class=\"axis y\" transform=\"translate(${this.margin.left}, 0)\" />\n <path class=\"area\" d=\"${this.area(this.plotData)}\" />\n <path class=\"elevation\" d=\"${this.line(this.plotData)}\" fill=\"none\" />\n <g style=\"visibility: ${this.pointer.x > 0 ? 'visible' : 'hidden'}\">\n <path class=\"elevation highlight\" d=\"${this.line(this.plotData)}\" fill=\"none\"\n clip-path=\"polygon(0 0, ${this.pointer.x - this.margin.left} 0, ${this.pointer.x - this.margin.left} 100%, 0 100%)\"\n />\n <line\n class=\"pointer-line y\"\n x1=\"${this.pointer.x}\"\n y1=\"${this.margin.top}\"\n x2=\"${this.pointer.x}\"\n y2=\"${height - this.margin.bottom}\"\n />\n <circle class=\"pointer-circle-outline\" cx=\"${this.pointer.x}\" cy=\"${this.pointer.y}\" r=\"16\"/>\n <circle class=\"pointer-circle\" cx=\"${this.pointer.x}\" cy=\"${this.pointer.y}\" r=\"6\"/>\n </g>\n <rect\n width=\"${width}\"\n height=\"${height}\"\n fill=\"none\"\n pointer-events=\"${this.pointerEvents ? 'all' : 'none'}\"\n style=\"display: block; touch-action: none;\"\n @pointermove=\"${this.pointerMove}\"\n @pointerout=\"${this.pointerOut}\"\n />\n </svg>\n `;\n }\n\n public tickFormat(value: number, axis: 'x' | 'y') {\n if (axis === 'y' || value < 1000) {\n return this.meterFormat!.format(value);\n } else {\n return this.kilometerFormat!.format(value / 1000);\n }\n }\n\n override firstUpdated() {\n // FIXME: because the ref element are used before render is done, we need to force an update\n this.requestUpdate();\n }\n\n private pointerMove(event: PointerEvent) {\n const pointerDistance = this.scaleX.invert(pointer(event)[0]);\n const index = Math.min(this.bisectDistance.left(this.plotData, pointerDistance), this.plotData.length - 1);\n\n if (index < 0) {\n return;\n }\n // FIXME:\n // var d0 = this.plotData[index - 1]\n // var d1 = this.plotData[index];\n // // work out which date value is closest to the mouse\n // var d = mouseDate - d0[0] > d1[0] - mouseDate ? d1 : d0;\n\n const data = this.plotData[index];\n\n if (isNaN(data.y)) {\n return;\n }\n\n this.pointer = {\n x: this.scaleX(data.x),\n y: this.scaleY(data.y),\n };\n\n this.dispatchEvent(\n new CustomEvent<OverDetails>('over', {\n detail: {\n coordinate: this.plotData[index].coordinate,\n position: this.pointer\n }\n }),\n );\n }\n\n private pointerOut() {\n this.pointer = {\n x: 0,\n y: 0,\n };\n this.dispatchEvent(new CustomEvent('out'));\n }\n\n override createRenderRoot() {\n return this;\n }\n}\n\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'elevation-profile': ElevationProfile;\n }\n}\n"],"names":[],"version":3,"file":"elevation-profile.d.ts.map"}
|
|
@@ -40,6 +40,7 @@ let $916babf1e6dc2c08$var$ElevationProfile = class ElevationProfile extends (0,
|
|
|
40
40
|
x: 100,
|
|
41
41
|
y: 40
|
|
42
42
|
};
|
|
43
|
+
this.pointerEvents = true;
|
|
43
44
|
this.pointer = {
|
|
44
45
|
x: 0,
|
|
45
46
|
y: 0
|
|
@@ -51,8 +52,8 @@ let $916babf1e6dc2c08$var$ElevationProfile = class ElevationProfile extends (0,
|
|
|
51
52
|
this.bisectDistance = (0, $agntW$bisector)((point)=>point.x);
|
|
52
53
|
this.line = (0, $agntW$line)().defined((point)=>!isNaN(point.y)).x((point)=>this.scaleX(point.x)).y((point)=>this.scaleY(point.y));
|
|
53
54
|
this.area = (0, $agntW$area)().defined((point)=>!isNaN(point.y)).x((point)=>this.scaleX(point.x)).y1((point)=>this.scaleY(point.y));
|
|
54
|
-
this.xAxis = (0, $agntW$axisBottom)(this.scaleX).tickFormat((value)=>this.tickFormat(value));
|
|
55
|
-
this.yAxis = (0, $agntW$axisLeft)(this.scaleY).tickFormat((value)=>this.
|
|
55
|
+
this.xAxis = (0, $agntW$axisBottom)(this.scaleX).tickFormat((value)=>this.tickFormat(value, "x"));
|
|
56
|
+
this.yAxis = (0, $agntW$axisLeft)(this.scaleY).tickFormat((value)=>this.tickFormat(value, "y"));
|
|
56
57
|
this.xGrid = (0, $agntW$axisBottom)(this.scaleX).tickFormat(()=>"");
|
|
57
58
|
this.yGrid = (0, $agntW$axisLeft)(this.scaleY).tickFormat(()=>"");
|
|
58
59
|
this.meterFormat = null;
|
|
@@ -141,7 +142,7 @@ let $916babf1e6dc2c08$var$ElevationProfile = class ElevationProfile extends (0,
|
|
|
141
142
|
width="${width}"
|
|
142
143
|
height="${height}"
|
|
143
144
|
fill="none"
|
|
144
|
-
pointer-events="all"
|
|
145
|
+
pointer-events="${this.pointerEvents ? "all" : "none"}"
|
|
145
146
|
style="display: block; touch-action: none;"
|
|
146
147
|
@pointermove="${this.pointerMove}"
|
|
147
148
|
@pointerout="${this.pointerOut}"
|
|
@@ -149,8 +150,8 @@ let $916babf1e6dc2c08$var$ElevationProfile = class ElevationProfile extends (0,
|
|
|
149
150
|
</svg>
|
|
150
151
|
`;
|
|
151
152
|
}
|
|
152
|
-
tickFormat(value) {
|
|
153
|
-
if (value < 1000) return this.meterFormat.format(value);
|
|
153
|
+
tickFormat(value, axis) {
|
|
154
|
+
if (axis === "y" || value < 1000) return this.meterFormat.format(value);
|
|
154
155
|
else return this.kilometerFormat.format(value / 1000);
|
|
155
156
|
}
|
|
156
157
|
firstUpdated() {
|
|
@@ -218,6 +219,11 @@ $916babf1e6dc2c08$var$__decorate([
|
|
|
218
219
|
type: Object
|
|
219
220
|
})
|
|
220
221
|
], $916babf1e6dc2c08$var$ElevationProfile.prototype, "tickSize", void 0);
|
|
222
|
+
$916babf1e6dc2c08$var$__decorate([
|
|
223
|
+
(0, $agntW$property)({
|
|
224
|
+
type: Boolean
|
|
225
|
+
})
|
|
226
|
+
], $916babf1e6dc2c08$var$ElevationProfile.prototype, "pointerEvents", void 0);
|
|
221
227
|
$916babf1e6dc2c08$var$__decorate([
|
|
222
228
|
(0, $agntW$state)()
|
|
223
229
|
], $916babf1e6dc2c08$var$ElevationProfile.prototype, "pointer", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","sources":["elevation-profile.ts"],"sourcesContent":["import {LitElement, svg} from 'lit';\nimport {customElement, state, property} from 'lit/decorators.js';\nimport {ResizeController} from '@lit-labs/observers/resize-controller.js';\nimport type {PropertyValues} from 'lit';\n\nimport {extent, bisector} from 'd3-array';\nimport {scaleLinear} from 'd3-scale';\nimport {line, area} from 'd3-shape';\nimport {axisBottom, axisLeft} from 'd3-axis';\nimport {select, pointer} from 'd3-selection';\n\nimport simplify from 'simplify-js';\n\ntype PlotPoint = {\n x: number;\n y: number;\n coordinate: number[];\n};\n\nexport type OverDetails = {\n coordinate: number[];\n position: {x: number; y: number};\n};\n\n@customElement('elevation-profile')\nexport default class ElevationProfile extends LitElement {\n @property({type: Number}) tolerance = 1;\n @property({type: String}) locale = navigator.language;\n @property({type: Array}) lines: number[][][] = [];\n @property() updateScale = (x: scaleLinear, y: scaleLinear, width: number, height: number): void => {};\n @property({type: Object}) margin = {top: 20, right: 20, bottom: 20, left: 40};\n @property({type: Object}) tickSize = {x: 100, y: 40};\n\n @state() pointer = {x: 0, y: 0};\n private _resizeController = new ResizeController(this, {});\n\n private plotData: PlotPoint[] = [];\n private scaleX = scaleLinear();\n private scaleY = scaleLinear();\n\n private bisectDistance = bisector((point: PlotPoint) => point.x);\n\n private line = line()\n .defined((point: PlotPoint) => !isNaN(point.y))\n .x((point: PlotPoint) => this.scaleX(point.x))\n .y((point: PlotPoint) => this.scaleY(point.y));\n private area = area()\n .defined((point: PlotPoint) => !isNaN(point.y))\n .x((point: PlotPoint) => this.scaleX(point.x))\n .y1((point: PlotPoint) => this.scaleY(point.y));\n private xAxis = axisBottom(this.scaleX).tickFormat((value: number) => this.tickFormat(value));\n private yAxis = axisLeft(this.scaleY).tickFormat((value: number) => this.meterFormat!.format(value));\n private xGrid = axisBottom(this.scaleX).tickFormat(() => '');\n private yGrid = axisLeft(this.scaleY).tickFormat(() => '');\n\n private meterFormat: Intl.NumberFormat | null = null;\n private kilometerFormat: Intl.NumberFormat | null = null;\n\n override updated(changedProperties: PropertyValues) {\n if (changedProperties.has('locale')) {\n this.meterFormat = new Intl.NumberFormat(this.locale, {\n style: 'unit',\n unit: 'meter',\n });\n\n this.kilometerFormat = new Intl.NumberFormat(this.locale, {\n style: 'unit',\n unit: 'kilometer',\n });\n }\n }\n\n override willUpdate(changedProperties: PropertyValues) {\n if (changedProperties.has('lines')) {\n this.plotData.length = 0;\n for (const line of this.lines) {\n const data = line.map((coordinate) => ({x: coordinate[3], y: coordinate[2], coordinate}));\n this.plotData.push(...simplify(data, this.tolerance));\n this.plotData.push({x: line[line.length - 1][3], y: NaN, coordinate: []});\n }\n\n this.scaleX.domain(extent(this.plotData, (data: PlotPoint) => data.x));\n this.scaleY.domain(extent(this.plotData, (data: PlotPoint) => data.y)).nice();\n\n this.updateScale(this.scaleX, this.scaleY, this.offsetWidth, this.offsetHeight);\n }\n }\n\n override render() {\n const width = this.offsetWidth;\n const height = this.offsetHeight;\n\n this.scaleX.range([this.margin.left, width - this.margin.right]);\n this.scaleY.range([height - this.margin.bottom, this.margin.top]);\n\n this.area.y0(height - this.margin.bottom);\n\n this.yGrid.tickSize(-width + this.margin.left + this.margin.right);\n this.xGrid.tickSize(height - this.margin.top - this.margin.bottom);\n\n const xTicks = width / this.tickSize.x;\n const yTicks = height / this.tickSize.y;\n this.xAxis.ticks(xTicks);\n this.xGrid.ticks(xTicks);\n this.yAxis.ticks(yTicks);\n this.yGrid.ticks(yTicks);\n\n select(this.querySelector('.axis.x')).call(this.xAxis);\n select(this.querySelector('.axis.y')).call(this.yAxis);\n select(this.querySelector('.grid.x')).call(this.xGrid);\n select(this.querySelector('.grid.y')).call(this.yGrid);\n\n return svg`\n <svg width=\"${width}\" height=\"${height}\" xmlns=\"http://www.w3.org/2000/svg\">\n <g class=\"grid y\" transform=\"translate(${this.margin.left}, 0)\" />\n <g class=\"grid x\" transform=\"translate(0, ${this.margin.bottom})\" />\n <g class=\"axis x\" transform=\"translate(0, ${height - this.margin.bottom})\" />\n <g class=\"axis y\" transform=\"translate(${this.margin.left}, 0)\" />\n <path class=\"area\" d=\"${this.area(this.plotData)}\" />\n <path class=\"elevation\" d=\"${this.line(this.plotData)}\" fill=\"none\" />\n <g style=\"visibility: ${this.pointer.x > 0 ? 'visible' : 'hidden'}\">\n <path class=\"elevation highlight\" d=\"${this.line(this.plotData)}\" fill=\"none\"\n clip-path=\"polygon(0 0, ${this.pointer.x - this.margin.left} 0, ${this.pointer.x - this.margin.left} 100%, 0 100%)\"\n />\n <line\n class=\"pointer-line y\"\n x1=\"${this.pointer.x}\"\n y1=\"${this.margin.top}\"\n x2=\"${this.pointer.x}\"\n y2=\"${height - this.margin.bottom}\"\n />\n <circle class=\"pointer-circle-outline\" cx=\"${this.pointer.x}\" cy=\"${this.pointer.y}\" r=\"16\"/>\n <circle class=\"pointer-circle\" cx=\"${this.pointer.x}\" cy=\"${this.pointer.y}\" r=\"6\"/>\n </g>\n <rect\n width=\"${width}\"\n height=\"${height}\"\n fill=\"none\"\n pointer-events=\"all\"\n style=\"display: block; touch-action: none;\"\n @pointermove=\"${this.pointerMove}\"\n @pointerout=\"${this.pointerOut}\"\n />\n </svg>\n `;\n }\n\n private tickFormat(value: number) {\n if (value < 1000) {\n return this.meterFormat!.format(value);\n } else {\n return this.kilometerFormat!.format(value / 1000);\n }\n }\n\n override firstUpdated() {\n // FIXME: because the ref element are used before render is done, we need to force an update\n this.requestUpdate();\n }\n\n private pointerMove(event: PointerEvent) {\n const pointerDistance = this.scaleX.invert(pointer(event)[0]);\n const index = Math.min(this.bisectDistance.left(this.plotData, pointerDistance), this.plotData.length - 1);\n\n if (index < 0) {\n return;\n }\n // FIXME:\n // var d0 = this.plotData[index - 1]\n // var d1 = this.plotData[index];\n // // work out which date value is closest to the mouse\n // var d = mouseDate - d0[0] > d1[0] - mouseDate ? d1 : d0;\n\n const data = this.plotData[index];\n\n if (isNaN(data.y)) {\n return;\n }\n\n this.pointer = {\n x: this.scaleX(data.x),\n y: this.scaleY(data.y),\n };\n\n this.dispatchEvent(\n new CustomEvent<OverDetails>('over', {\n detail: {\n coordinate: this.plotData[index].coordinate,\n position: this.pointer\n }\n }),\n );\n }\n\n private pointerOut() {\n this.pointer = {\n x: 0,\n y: 0,\n };\n this.dispatchEvent(new CustomEvent('out'));\n }\n\n override createRenderRoot() {\n return this;\n }\n}\n\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'elevation-profile': ElevationProfile;\n }\n}\n"],"names":[],"version":3,"file":"elevation-profile.js.map"}
|
|
1
|
+
{"mappings":"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","sources":["elevation-profile.ts"],"sourcesContent":["import {LitElement, svg} from 'lit';\nimport {customElement, state, property} from 'lit/decorators.js';\nimport {ResizeController} from '@lit-labs/observers/resize-controller.js';\nimport type {PropertyValues} from 'lit';\n\nimport {extent, bisector} from 'd3-array';\nimport {scaleLinear} from 'd3-scale';\nimport {line, area} from 'd3-shape';\nimport {axisBottom, axisLeft} from 'd3-axis';\nimport {select, pointer} from 'd3-selection';\n\nimport simplify from 'simplify-js';\n\ntype PlotPoint = {\n x: number;\n y: number;\n coordinate: number[];\n};\n\nexport type OverDetails = {\n coordinate: number[];\n position: {x: number; y: number};\n};\n\n@customElement('elevation-profile')\nexport default class ElevationProfile extends LitElement {\n @property({type: Number}) tolerance = 1;\n @property({type: String}) locale = navigator.language;\n @property({type: Array}) lines: number[][][] = [];\n @property() updateScale = (x: scaleLinear, y: scaleLinear, width: number, height: number): void => {};\n @property({type: Object}) margin = {top: 20, right: 20, bottom: 20, left: 40};\n @property({type: Object}) tickSize = {x: 100, y: 40};\n @property({type: Boolean}) pointerEvents = true;\n\n @state() pointer = {x: 0, y: 0};\n private _resizeController = new ResizeController(this, {});\n\n private plotData: PlotPoint[] = [];\n private scaleX = scaleLinear();\n private scaleY = scaleLinear();\n\n private bisectDistance = bisector((point: PlotPoint) => point.x);\n\n private line = line()\n .defined((point: PlotPoint) => !isNaN(point.y))\n .x((point: PlotPoint) => this.scaleX(point.x))\n .y((point: PlotPoint) => this.scaleY(point.y));\n private area = area()\n .defined((point: PlotPoint) => !isNaN(point.y))\n .x((point: PlotPoint) => this.scaleX(point.x))\n .y1((point: PlotPoint) => this.scaleY(point.y));\n private xAxis = axisBottom(this.scaleX).tickFormat((value: number) => this.tickFormat(value, 'x'));\n private yAxis = axisLeft(this.scaleY).tickFormat((value: number) => this.tickFormat(value, 'y'));\n private xGrid = axisBottom(this.scaleX).tickFormat(() => '');\n private yGrid = axisLeft(this.scaleY).tickFormat(() => '');\n\n private meterFormat: Intl.NumberFormat | null = null;\n private kilometerFormat: Intl.NumberFormat | null = null;\n\n override updated(changedProperties: PropertyValues) {\n if (changedProperties.has('locale')) {\n this.meterFormat = new Intl.NumberFormat(this.locale, {\n style: 'unit',\n unit: 'meter',\n });\n\n this.kilometerFormat = new Intl.NumberFormat(this.locale, {\n style: 'unit',\n unit: 'kilometer',\n });\n }\n }\n\n override willUpdate(changedProperties: PropertyValues) {\n if (changedProperties.has('lines')) {\n this.plotData.length = 0;\n for (const line of this.lines) {\n const data = line.map((coordinate) => ({x: coordinate[3], y: coordinate[2], coordinate}));\n this.plotData.push(...simplify(data, this.tolerance));\n this.plotData.push({x: line[line.length - 1][3], y: NaN, coordinate: []});\n }\n\n this.scaleX.domain(extent(this.plotData, (data: PlotPoint) => data.x));\n this.scaleY.domain(extent(this.plotData, (data: PlotPoint) => data.y)).nice();\n\n this.updateScale(this.scaleX, this.scaleY, this.offsetWidth, this.offsetHeight);\n }\n }\n\n override render() {\n const width = this.offsetWidth;\n const height = this.offsetHeight;\n\n this.scaleX.range([this.margin.left, width - this.margin.right]);\n this.scaleY.range([height - this.margin.bottom, this.margin.top]);\n\n this.area.y0(height - this.margin.bottom);\n\n this.yGrid.tickSize(-width + this.margin.left + this.margin.right);\n this.xGrid.tickSize(height - this.margin.top - this.margin.bottom);\n\n const xTicks = width / this.tickSize.x;\n const yTicks = height / this.tickSize.y;\n this.xAxis.ticks(xTicks);\n this.xGrid.ticks(xTicks);\n this.yAxis.ticks(yTicks);\n this.yGrid.ticks(yTicks);\n\n select(this.querySelector('.axis.x')).call(this.xAxis);\n select(this.querySelector('.axis.y')).call(this.yAxis);\n select(this.querySelector('.grid.x')).call(this.xGrid);\n select(this.querySelector('.grid.y')).call(this.yGrid);\n\n return svg`\n <svg width=\"${width}\" height=\"${height}\" xmlns=\"http://www.w3.org/2000/svg\">\n <g class=\"grid y\" transform=\"translate(${this.margin.left}, 0)\" />\n <g class=\"grid x\" transform=\"translate(0, ${this.margin.bottom})\" />\n <g class=\"axis x\" transform=\"translate(0, ${height - this.margin.bottom})\" />\n <g class=\"axis y\" transform=\"translate(${this.margin.left}, 0)\" />\n <path class=\"area\" d=\"${this.area(this.plotData)}\" />\n <path class=\"elevation\" d=\"${this.line(this.plotData)}\" fill=\"none\" />\n <g style=\"visibility: ${this.pointer.x > 0 ? 'visible' : 'hidden'}\">\n <path class=\"elevation highlight\" d=\"${this.line(this.plotData)}\" fill=\"none\"\n clip-path=\"polygon(0 0, ${this.pointer.x - this.margin.left} 0, ${this.pointer.x - this.margin.left} 100%, 0 100%)\"\n />\n <line\n class=\"pointer-line y\"\n x1=\"${this.pointer.x}\"\n y1=\"${this.margin.top}\"\n x2=\"${this.pointer.x}\"\n y2=\"${height - this.margin.bottom}\"\n />\n <circle class=\"pointer-circle-outline\" cx=\"${this.pointer.x}\" cy=\"${this.pointer.y}\" r=\"16\"/>\n <circle class=\"pointer-circle\" cx=\"${this.pointer.x}\" cy=\"${this.pointer.y}\" r=\"6\"/>\n </g>\n <rect\n width=\"${width}\"\n height=\"${height}\"\n fill=\"none\"\n pointer-events=\"${this.pointerEvents ? 'all' : 'none'}\"\n style=\"display: block; touch-action: none;\"\n @pointermove=\"${this.pointerMove}\"\n @pointerout=\"${this.pointerOut}\"\n />\n </svg>\n `;\n }\n\n public tickFormat(value: number, axis: 'x' | 'y') {\n if (axis === 'y' || value < 1000) {\n return this.meterFormat!.format(value);\n } else {\n return this.kilometerFormat!.format(value / 1000);\n }\n }\n\n override firstUpdated() {\n // FIXME: because the ref element are used before render is done, we need to force an update\n this.requestUpdate();\n }\n\n private pointerMove(event: PointerEvent) {\n const pointerDistance = this.scaleX.invert(pointer(event)[0]);\n const index = Math.min(this.bisectDistance.left(this.plotData, pointerDistance), this.plotData.length - 1);\n\n if (index < 0) {\n return;\n }\n // FIXME:\n // var d0 = this.plotData[index - 1]\n // var d1 = this.plotData[index];\n // // work out which date value is closest to the mouse\n // var d = mouseDate - d0[0] > d1[0] - mouseDate ? d1 : d0;\n\n const data = this.plotData[index];\n\n if (isNaN(data.y)) {\n return;\n }\n\n this.pointer = {\n x: this.scaleX(data.x),\n y: this.scaleY(data.y),\n };\n\n this.dispatchEvent(\n new CustomEvent<OverDetails>('over', {\n detail: {\n coordinate: this.plotData[index].coordinate,\n position: this.pointer\n }\n }),\n );\n }\n\n private pointerOut() {\n this.pointer = {\n x: 0,\n y: 0,\n };\n this.dispatchEvent(new CustomEvent('out'));\n }\n\n override createRenderRoot() {\n return this;\n }\n}\n\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'elevation-profile': ElevationProfile;\n }\n}\n"],"names":[],"version":3,"file":"elevation-profile.js.map"}
|
package/elevation-profile.ts
CHANGED
|
@@ -30,6 +30,7 @@ export default class ElevationProfile extends LitElement {
|
|
|
30
30
|
@property() updateScale = (x: scaleLinear, y: scaleLinear, width: number, height: number): void => {};
|
|
31
31
|
@property({type: Object}) margin = {top: 20, right: 20, bottom: 20, left: 40};
|
|
32
32
|
@property({type: Object}) tickSize = {x: 100, y: 40};
|
|
33
|
+
@property({type: Boolean}) pointerEvents = true;
|
|
33
34
|
|
|
34
35
|
@state() pointer = {x: 0, y: 0};
|
|
35
36
|
private _resizeController = new ResizeController(this, {});
|
|
@@ -48,8 +49,8 @@ export default class ElevationProfile extends LitElement {
|
|
|
48
49
|
.defined((point: PlotPoint) => !isNaN(point.y))
|
|
49
50
|
.x((point: PlotPoint) => this.scaleX(point.x))
|
|
50
51
|
.y1((point: PlotPoint) => this.scaleY(point.y));
|
|
51
|
-
private xAxis = axisBottom(this.scaleX).tickFormat((value: number) => this.tickFormat(value));
|
|
52
|
-
private yAxis = axisLeft(this.scaleY).tickFormat((value: number) => this.
|
|
52
|
+
private xAxis = axisBottom(this.scaleX).tickFormat((value: number) => this.tickFormat(value, 'x'));
|
|
53
|
+
private yAxis = axisLeft(this.scaleY).tickFormat((value: number) => this.tickFormat(value, 'y'));
|
|
53
54
|
private xGrid = axisBottom(this.scaleX).tickFormat(() => '');
|
|
54
55
|
private yGrid = axisLeft(this.scaleY).tickFormat(() => '');
|
|
55
56
|
|
|
@@ -136,7 +137,7 @@ export default class ElevationProfile extends LitElement {
|
|
|
136
137
|
width="${width}"
|
|
137
138
|
height="${height}"
|
|
138
139
|
fill="none"
|
|
139
|
-
pointer-events="all"
|
|
140
|
+
pointer-events="${this.pointerEvents ? 'all' : 'none'}"
|
|
140
141
|
style="display: block; touch-action: none;"
|
|
141
142
|
@pointermove="${this.pointerMove}"
|
|
142
143
|
@pointerout="${this.pointerOut}"
|
|
@@ -145,8 +146,8 @@ export default class ElevationProfile extends LitElement {
|
|
|
145
146
|
`;
|
|
146
147
|
}
|
|
147
148
|
|
|
148
|
-
|
|
149
|
-
if (value < 1000) {
|
|
149
|
+
public tickFormat(value: number, axis: 'x' | 'y') {
|
|
150
|
+
if (axis === 'y' || value < 1000) {
|
|
150
151
|
return this.meterFormat!.format(value);
|
|
151
152
|
} else {
|
|
152
153
|
return this.kilometerFormat!.format(value / 1000);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geoblocks/elevation-profile",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"license": "BSD-3-Clause",
|
|
5
5
|
"repository": "github:geoblocks/elevation-profile",
|
|
6
6
|
"type": "module",
|
|
@@ -35,15 +35,15 @@
|
|
|
35
35
|
"d3-scale": "4.0.2",
|
|
36
36
|
"d3-selection": "3.0.0",
|
|
37
37
|
"d3-shape": "3.2.0",
|
|
38
|
-
"lit": "3.1.
|
|
38
|
+
"lit": "3.1.2",
|
|
39
39
|
"simplify-js": "1.2.4"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@parcel/packager-ts": "2.
|
|
43
|
-
"@parcel/transformer-typescript-tsc": "2.
|
|
44
|
-
"@parcel/transformer-typescript-types": "2.
|
|
45
|
-
"gh-pages": "6.1.
|
|
46
|
-
"parcel": "2.
|
|
47
|
-
"typescript": "5.3.
|
|
42
|
+
"@parcel/packager-ts": "2.11.0",
|
|
43
|
+
"@parcel/transformer-typescript-tsc": "2.11.0",
|
|
44
|
+
"@parcel/transformer-typescript-types": "2.11.0",
|
|
45
|
+
"gh-pages": "6.1.1",
|
|
46
|
+
"parcel": "2.11.0",
|
|
47
|
+
"typescript": "5.3.3"
|
|
48
48
|
}
|
|
49
49
|
}
|