@geoblocks/elevation-profile 0.0.4 → 0.0.6
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/dist/elevation-profile.d.ts +1 -1
- package/dist/elevation-profile.d.ts.map +1 -1
- package/dist/elevation-profile.js +49 -33
- package/dist/elevation-profile.js.map +1 -1
- package/elevation-profile.ts +32 -21
- package/package.json +2 -1
- package/dist/index.600fa9d1.js +0 -5245
- package/dist/index.600fa9d1.js.map +0 -1
- package/dist/index.html +0 -574
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":";
|
|
1
|
+
{"mappings":";AAiBA,6BAC8B,SAAQ,UAAU;IACrB,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAM;IACxB,MAAM;;;;;MAA8C;IACpD,QAAQ;;;MAAmB;IAE5C,OAAO;;;MAAgB;IAgCvB,UAAU,CAAC,iBAAiB,EAAE,cAAc;IAc5C,MAAM;IAkEN,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\ntype PlotPoint = {\n x: number;\n y: number;\n coordinate: number[];\n};\n\n@customElement('elevation-profile')\nexport class ElevationProfile extends LitElement {\n @property({type: Array}) lines: number[][][] = [];\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.tickFormat(value));\n private xGrid = axisBottom(this.scaleX).tickFormat(() => '');\n private yGrid = axisLeft(this.scaleY).tickFormat(() => '');\n\n private meterFormat = Intl.NumberFormat('de-CH', {\n style: 'unit',\n unit: 'meter',\n });\n\n private kilometerFormat = Intl.NumberFormat('de-CH', {\n style: 'unit',\n unit: 'kilometer',\n });\n\n override willUpdate(changedProperties: PropertyValues) {\n if (changedProperties.has('lines')) {\n console.log('lines changed', this.lines);\n this.plotData.length = 0;\n for (const line of this.lines) {\n this.plotData.push(...line.map((coordinate) => ({x: coordinate[3], y: coordinate[2], coordinate})));\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 }\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\" cx=\"${this.pointer.x}\" cy=\"${this.pointer.y}\" />\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('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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {svg as $agntW$svg, LitElement as $agntW$LitElement} from "lit";
|
|
2
2
|
import {property as $agntW$property, state as $agntW$state, customElement as $agntW$customElement} from "lit/decorators.js";
|
|
3
3
|
import {ResizeController as $agntW$ResizeController} from "@lit-labs/observers/resize-controller.js";
|
|
4
|
-
import {createRef as $agntW$createRef, ref as $agntW$ref} from "lit/directives/ref.js";
|
|
5
4
|
import {bisector as $agntW$bisector, extent as $agntW$extent} from "d3-array";
|
|
6
5
|
import {scaleLinear as $agntW$scaleLinear} from "d3-scale";
|
|
7
6
|
import {line as $agntW$line, area as $agntW$area} from "d3-shape";
|
|
@@ -16,7 +15,6 @@ import {select as $agntW$select, pointer as $agntW$pointer} from "d3-selection";
|
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
|
|
19
|
-
|
|
20
18
|
var $916babf1e6dc2c08$var$__decorate = undefined && undefined.__decorate || function(decorators, target, key, desc) {
|
|
21
19
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
22
20
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -45,31 +43,42 @@ let $916babf1e6dc2c08$export$14ab3917b98d786a = class ElevationProfile extends (
|
|
|
45
43
|
this.plotData = [];
|
|
46
44
|
this.scaleX = (0, $agntW$scaleLinear)();
|
|
47
45
|
this.scaleY = (0, $agntW$scaleLinear)();
|
|
48
|
-
this.bisectDistance = (0, $agntW$bisector)((point)=>point
|
|
49
|
-
this.line = (0, $agntW$line)().x((point)=>this.scaleX(point
|
|
50
|
-
this.area = (0, $agntW$area)().x((point)=>this.scaleX(point
|
|
51
|
-
this.xAxis = (0, $agntW$axisBottom)(this.scaleX).tickFormat((
|
|
52
|
-
this.yAxis = (0, $agntW$axisLeft)(this.scaleY).tickFormat((
|
|
46
|
+
this.bisectDistance = (0, $agntW$bisector)((point)=>point.x);
|
|
47
|
+
this.line = (0, $agntW$line)().defined((point)=>!isNaN(point.y)).x((point)=>this.scaleX(point.x)).y((point)=>this.scaleY(point.y));
|
|
48
|
+
this.area = (0, $agntW$area)().defined((point)=>!isNaN(point.y)).x((point)=>this.scaleX(point.x)).y1((point)=>this.scaleY(point.y));
|
|
49
|
+
this.xAxis = (0, $agntW$axisBottom)(this.scaleX).tickFormat((value)=>this.tickFormat(value));
|
|
50
|
+
this.yAxis = (0, $agntW$axisLeft)(this.scaleY).tickFormat((value)=>this.tickFormat(value));
|
|
53
51
|
this.xGrid = (0, $agntW$axisBottom)(this.scaleX).tickFormat(()=>"");
|
|
54
52
|
this.yGrid = (0, $agntW$axisLeft)(this.scaleY).tickFormat(()=>"");
|
|
55
|
-
this.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
this.meterFormat = Intl.NumberFormat("de-CH", {
|
|
54
|
+
style: "unit",
|
|
55
|
+
unit: "meter"
|
|
56
|
+
});
|
|
57
|
+
this.kilometerFormat = Intl.NumberFormat("de-CH", {
|
|
58
|
+
style: "unit",
|
|
59
|
+
unit: "kilometer"
|
|
60
|
+
});
|
|
59
61
|
}
|
|
60
62
|
willUpdate(changedProperties) {
|
|
61
63
|
if (changedProperties.has("lines")) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
console.log("lines changed", this.lines);
|
|
65
|
+
this.plotData.length = 0;
|
|
66
|
+
for (const line of this.lines){
|
|
67
|
+
this.plotData.push(...line.map((coordinate)=>({
|
|
68
|
+
x: coordinate[3],
|
|
69
|
+
y: coordinate[2],
|
|
70
|
+
coordinate: coordinate
|
|
71
|
+
})));
|
|
72
|
+
this.plotData.push({
|
|
73
|
+
x: line[line.length - 1][3],
|
|
74
|
+
y: NaN,
|
|
75
|
+
coordinate: []
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
this.scaleX.domain((0, $agntW$extent)(this.plotData, (data)=>data.x));
|
|
79
|
+
this.scaleY.domain((0, $agntW$extent)(this.plotData, (data)=>data.y)).nice();
|
|
68
80
|
}
|
|
69
81
|
}
|
|
70
|
-
// override shouldUpdate(): boolean {
|
|
71
|
-
// return this.lines.length > 0;
|
|
72
|
-
// }
|
|
73
82
|
render() {
|
|
74
83
|
const width = this.offsetWidth;
|
|
75
84
|
const height = this.offsetHeight;
|
|
@@ -90,16 +99,16 @@ let $916babf1e6dc2c08$export$14ab3917b98d786a = class ElevationProfile extends (
|
|
|
90
99
|
this.xGrid.ticks(xTicks);
|
|
91
100
|
this.yAxis.ticks(yTicks);
|
|
92
101
|
this.yGrid.ticks(yTicks);
|
|
93
|
-
(0, $agntW$select)(this.
|
|
94
|
-
(0, $agntW$select)(this.
|
|
95
|
-
(0, $agntW$select)(this.
|
|
96
|
-
(0, $agntW$select)(this.
|
|
102
|
+
(0, $agntW$select)(this.querySelector(".axis.x")).call(this.xAxis);
|
|
103
|
+
(0, $agntW$select)(this.querySelector(".axis.y")).call(this.yAxis);
|
|
104
|
+
(0, $agntW$select)(this.querySelector(".grid.x")).call(this.xGrid);
|
|
105
|
+
(0, $agntW$select)(this.querySelector(".grid.y")).call(this.yGrid);
|
|
97
106
|
return (0, $agntW$svg)`
|
|
98
107
|
<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">
|
|
99
|
-
<g class="grid y"
|
|
100
|
-
<g class="grid x"
|
|
101
|
-
<g class="axis x"
|
|
102
|
-
<g class="axis y"
|
|
108
|
+
<g class="grid y" transform="translate(${this.margin.left}, 0)" />
|
|
109
|
+
<g class="grid x" transform="translate(0, ${this.margin.bottom})" />
|
|
110
|
+
<g class="axis x" transform="translate(0, ${height - this.margin.bottom})" />
|
|
111
|
+
<g class="axis y" transform="translate(${this.margin.left}, 0)" />
|
|
103
112
|
<path class="area" d="${this.area(this.plotData)}" />
|
|
104
113
|
<path class="elevation" d="${this.line(this.plotData)}" fill="none" />
|
|
105
114
|
<g style="visibility: ${this.pointer.x > 0 ? "visible" : "hidden"}">
|
|
@@ -120,12 +129,17 @@ let $916babf1e6dc2c08$export$14ab3917b98d786a = class ElevationProfile extends (
|
|
|
120
129
|
height="${height}"
|
|
121
130
|
fill="none"
|
|
122
131
|
pointer-events="all"
|
|
132
|
+
style="display: block; touch-action: none;"
|
|
123
133
|
@pointermove="${this.pointerMove}"
|
|
124
134
|
@pointerout="${this.pointerOut}"
|
|
125
135
|
/>
|
|
126
136
|
</svg>
|
|
127
137
|
`;
|
|
128
138
|
}
|
|
139
|
+
tickFormat(value) {
|
|
140
|
+
if (value < 1000) return this.meterFormat.format(value);
|
|
141
|
+
else return this.kilometerFormat.format(value / 1000);
|
|
142
|
+
}
|
|
129
143
|
firstUpdated() {
|
|
130
144
|
// FIXME: because the ref element are used before render is done, we need to force an update
|
|
131
145
|
this.requestUpdate();
|
|
@@ -133,19 +147,21 @@ let $916babf1e6dc2c08$export$14ab3917b98d786a = class ElevationProfile extends (
|
|
|
133
147
|
pointerMove(event) {
|
|
134
148
|
const pointerDistance = this.scaleX.invert((0, $agntW$pointer)(event)[0]);
|
|
135
149
|
const index = Math.min(this.bisectDistance.left(this.plotData, pointerDistance), this.plotData.length - 1);
|
|
150
|
+
if (index < 0) return;
|
|
136
151
|
// FIXME:
|
|
137
|
-
// var d0 =
|
|
138
|
-
// var d1 =
|
|
152
|
+
// var d0 = this.plotData[index - 1]
|
|
153
|
+
// var d1 = this.plotData[index];
|
|
139
154
|
// // work out which date value is closest to the mouse
|
|
140
155
|
// var d = mouseDate - d0[0] > d1[0] - mouseDate ? d1 : d0;
|
|
141
156
|
const data = this.plotData[index];
|
|
157
|
+
if (isNaN(data.y)) return;
|
|
142
158
|
this.pointer = {
|
|
143
|
-
x: this.scaleX(data
|
|
144
|
-
y: this.scaleY(data
|
|
159
|
+
x: this.scaleX(data.x),
|
|
160
|
+
y: this.scaleY(data.y)
|
|
145
161
|
};
|
|
146
162
|
this.dispatchEvent(new CustomEvent("over", {
|
|
147
163
|
detail: {
|
|
148
|
-
coordinate: this.
|
|
164
|
+
coordinate: this.plotData[index].coordinate,
|
|
149
165
|
position: this.pointer
|
|
150
166
|
}
|
|
151
167
|
}));
|
|
@@ -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 {createRef, ref} from 'lit/directives/ref.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\ntype PlotPoint = number[];\n\n@customElement('elevation-profile')\nexport class ElevationProfile extends LitElement {\n @property({type: Array}) lines: number[][] = [];\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[0]);\n\n private line = line()\n .x((point: PlotPoint) => this.scaleX(point[0]))\n .y((point: PlotPoint) => this.scaleY(point[1]));\n private area = area()\n .x((point: PlotPoint) => this.scaleX(point[0]))\n .y1((point: PlotPoint) => this.scaleY(point[1]));\n private xAxis = axisBottom(this.scaleX)\n .tickFormat((val: number) => `${val} m`);\n private yAxis = axisLeft(this.scaleY)\n .tickFormat((val: number) => `${val} m`);\n private xGrid = axisBottom(this.scaleX).tickFormat(() => '');\n private yGrid = axisLeft(this.scaleY).tickFormat(() => '');\n\n private xRef = createRef();\n private yRef = createRef();\n private yGridRef = createRef();\n private xGridRef = createRef();\n\n override willUpdate(changedProperties: PropertyValues) {\n if (changedProperties.has('lines')) {\n this.plotData = this.lines.map((coordinate) => [coordinate[3], coordinate[2]]);\n\n this.scaleX.domain(extent(this.plotData, (data: PlotPoint) => data[0]));\n this.scaleY.domain(extent(this.plotData, (data: PlotPoint) => data[1])).nice();\n }\n }\n\n // override shouldUpdate(): boolean {\n // return this.lines.length > 0;\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.xRef.value).call(this.xAxis);\n select(this.yRef.value).call(this.yAxis);\n select(this.xGridRef.value).call(this.xGrid);\n select(this.yGridRef.value).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\" ${ref(this.yGridRef)} transform=\"translate(${this.margin.left}, 0)\" />\n <g class=\"grid x\" ${ref(this.xGridRef)} transform=\"translate(0, ${this.margin.bottom})\" />\n <g class=\"axis x\" ${ref(this.xRef)} transform=\"translate(0, ${height - this.margin.bottom})\" />\n <g class=\"axis y\" ${ref(this.yRef)} 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\" cx=\"${this.pointer.x}\" cy=\"${this.pointer.y}\" />\n </g>\n <rect\n width=\"${width}\"\n height=\"${height}\"\n fill=\"none\"\n pointer-events=\"all\"\n @pointermove=\"${this.pointerMove}\"\n @pointerout=\"${this.pointerOut}\"\n />\n </svg>\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 // FIXME:\n // var d0 = data[i - 1]\n // var d1 = data[i];\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 this.pointer = {\n x: this.scaleX(data[0]),\n y: this.scaleY(data[1]),\n };\n\n this.dispatchEvent(\n new CustomEvent('over', {\n detail: {\n coordinate: this.lines[index],\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\ntype PlotPoint = {\n x: number;\n y: number;\n coordinate: number[];\n};\n\n@customElement('elevation-profile')\nexport class ElevationProfile extends LitElement {\n @property({type: Array}) lines: number[][][] = [];\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.tickFormat(value));\n private xGrid = axisBottom(this.scaleX).tickFormat(() => '');\n private yGrid = axisLeft(this.scaleY).tickFormat(() => '');\n\n private meterFormat = Intl.NumberFormat('de-CH', {\n style: 'unit',\n unit: 'meter',\n });\n\n private kilometerFormat = Intl.NumberFormat('de-CH', {\n style: 'unit',\n unit: 'kilometer',\n });\n\n override willUpdate(changedProperties: PropertyValues) {\n if (changedProperties.has('lines')) {\n console.log('lines changed', this.lines);\n this.plotData.length = 0;\n for (const line of this.lines) {\n this.plotData.push(...line.map((coordinate) => ({x: coordinate[3], y: coordinate[2], coordinate})));\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 }\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\" cx=\"${this.pointer.x}\" cy=\"${this.pointer.y}\" />\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('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
|
@@ -9,11 +9,15 @@ import {line, area} from 'd3-shape';
|
|
|
9
9
|
import {axisBottom, axisLeft} from 'd3-axis';
|
|
10
10
|
import {select, pointer} from 'd3-selection';
|
|
11
11
|
|
|
12
|
-
type PlotPoint =
|
|
12
|
+
type PlotPoint = {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
coordinate: number[];
|
|
16
|
+
};
|
|
13
17
|
|
|
14
18
|
@customElement('elevation-profile')
|
|
15
19
|
export class ElevationProfile extends LitElement {
|
|
16
|
-
@property({type: Array}) lines: number[][] = [];
|
|
20
|
+
@property({type: Array}) lines: number[][][] = [];
|
|
17
21
|
@property({type: Object}) margin = {top: 20, right: 20, bottom: 20, left: 40};
|
|
18
22
|
@property({type: Object}) tickSize = {x: 100, y: 40};
|
|
19
23
|
|
|
@@ -24,14 +28,16 @@ export class ElevationProfile extends LitElement {
|
|
|
24
28
|
private scaleX = scaleLinear();
|
|
25
29
|
private scaleY = scaleLinear();
|
|
26
30
|
|
|
27
|
-
private bisectDistance = bisector((point: PlotPoint) => point
|
|
31
|
+
private bisectDistance = bisector((point: PlotPoint) => point.x);
|
|
28
32
|
|
|
29
33
|
private line = line()
|
|
30
|
-
.
|
|
31
|
-
.
|
|
34
|
+
.defined((point: PlotPoint) => !isNaN(point.y))
|
|
35
|
+
.x((point: PlotPoint) => this.scaleX(point.x))
|
|
36
|
+
.y((point: PlotPoint) => this.scaleY(point.y));
|
|
32
37
|
private area = area()
|
|
33
|
-
.
|
|
34
|
-
.
|
|
38
|
+
.defined((point: PlotPoint) => !isNaN(point.y))
|
|
39
|
+
.x((point: PlotPoint) => this.scaleX(point.x))
|
|
40
|
+
.y1((point: PlotPoint) => this.scaleY(point.y));
|
|
35
41
|
private xAxis = axisBottom(this.scaleX).tickFormat((value: number) => this.tickFormat(value));
|
|
36
42
|
private yAxis = axisLeft(this.scaleY).tickFormat((value: number) => this.tickFormat(value));
|
|
37
43
|
private xGrid = axisBottom(this.scaleX).tickFormat(() => '');
|
|
@@ -49,17 +55,18 @@ export class ElevationProfile extends LitElement {
|
|
|
49
55
|
|
|
50
56
|
override willUpdate(changedProperties: PropertyValues) {
|
|
51
57
|
if (changedProperties.has('lines')) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
console.log('lines changed', this.lines);
|
|
59
|
+
this.plotData.length = 0;
|
|
60
|
+
for (const line of this.lines) {
|
|
61
|
+
this.plotData.push(...line.map((coordinate) => ({x: coordinate[3], y: coordinate[2], coordinate})));
|
|
62
|
+
this.plotData.push({x: line[line.length - 1][3], y: NaN, coordinate: []});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this.scaleX.domain(extent(this.plotData, (data: PlotPoint) => data.x));
|
|
66
|
+
this.scaleY.domain(extent(this.plotData, (data: PlotPoint) => data.y)).nice();
|
|
56
67
|
}
|
|
57
68
|
}
|
|
58
69
|
|
|
59
|
-
// override shouldUpdate(): boolean {
|
|
60
|
-
// return this.lines.length > 0;
|
|
61
|
-
// }
|
|
62
|
-
|
|
63
70
|
override render() {
|
|
64
71
|
const width = this.offsetWidth;
|
|
65
72
|
const height = this.offsetHeight;
|
|
@@ -110,7 +117,7 @@ export class ElevationProfile extends LitElement {
|
|
|
110
117
|
height="${height}"
|
|
111
118
|
fill="none"
|
|
112
119
|
pointer-events="all"
|
|
113
|
-
style="touch-action: none;"
|
|
120
|
+
style="display: block; touch-action: none;"
|
|
114
121
|
@pointermove="${this.pointerMove}"
|
|
115
122
|
@pointerout="${this.pointerOut}"
|
|
116
123
|
/>
|
|
@@ -139,22 +146,26 @@ export class ElevationProfile extends LitElement {
|
|
|
139
146
|
return;
|
|
140
147
|
}
|
|
141
148
|
// FIXME:
|
|
142
|
-
// var d0 =
|
|
143
|
-
// var d1 =
|
|
149
|
+
// var d0 = this.plotData[index - 1]
|
|
150
|
+
// var d1 = this.plotData[index];
|
|
144
151
|
// // work out which date value is closest to the mouse
|
|
145
152
|
// var d = mouseDate - d0[0] > d1[0] - mouseDate ? d1 : d0;
|
|
146
153
|
|
|
147
154
|
const data = this.plotData[index];
|
|
148
155
|
|
|
156
|
+
if (isNaN(data.y)) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
149
160
|
this.pointer = {
|
|
150
|
-
x: this.scaleX(data
|
|
151
|
-
y: this.scaleY(data
|
|
161
|
+
x: this.scaleX(data.x),
|
|
162
|
+
y: this.scaleY(data.y),
|
|
152
163
|
};
|
|
153
164
|
|
|
154
165
|
this.dispatchEvent(
|
|
155
166
|
new CustomEvent('over', {
|
|
156
167
|
detail: {
|
|
157
|
-
coordinate: this.
|
|
168
|
+
coordinate: this.plotData[index].coordinate,
|
|
158
169
|
position: this.pointer
|
|
159
170
|
}
|
|
160
171
|
}),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geoblocks/elevation-profile",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"license": "BSD-3-Clause",
|
|
5
5
|
"repository": "github:geoblocks/elevation-profile",
|
|
6
6
|
"type": "module",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
25
|
"start": "parcel index.html",
|
|
26
|
+
"prepack": "npm run build",
|
|
26
27
|
"build": "rm -rf dist && parcel build",
|
|
27
28
|
"build-demo": "parcel build --target demo index.html",
|
|
28
29
|
"publish-demo": "rm -rf build && npm run build-demo && gh-pages -d build"
|