@geoblocks/elevation-profile 0.0.16 → 0.0.18
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.
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { LitElement, PropertyValues, TemplateResult } from "lit";
|
|
2
|
+
export type OverDetails = {
|
|
3
|
+
coordinate: number[];
|
|
4
|
+
position: {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export default class ElevationProfile extends LitElement {
|
|
10
|
+
tolerance: number;
|
|
11
|
+
locale: string;
|
|
12
|
+
lines: number[][][];
|
|
13
|
+
points: number[][];
|
|
14
|
+
updateScale: (x: scaleLinear, y: scaleLinear, width: number, height: number) => void;
|
|
15
|
+
margin: {
|
|
16
|
+
top: number;
|
|
17
|
+
right: number;
|
|
18
|
+
bottom: number;
|
|
19
|
+
left: number;
|
|
20
|
+
};
|
|
21
|
+
tickSize: {
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
};
|
|
25
|
+
pointerEvents: boolean;
|
|
26
|
+
pointer: {
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
};
|
|
30
|
+
updated(changedProperties: PropertyValues): void;
|
|
31
|
+
willUpdate(changedProperties: PropertyValues): void;
|
|
32
|
+
render(): TemplateResult<2>;
|
|
33
|
+
tickFormat(value: number, axis: 'x' | 'y'): string;
|
|
34
|
+
pointSvg(x: number, y: number, index: number): TemplateResult;
|
|
35
|
+
firstUpdated(): void;
|
|
36
|
+
createRenderRoot(): this;
|
|
37
|
+
}
|
|
38
|
+
declare global {
|
|
39
|
+
interface HTMLElementTagNameMap {
|
|
40
|
+
'elevation-profile': ElevationProfile;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=elevation-profile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":";AAoBA,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;IACzB,MAAM,EAAE,MAAM,EAAE,EAAE,CAAM;IACrC,WAAW,0CAA2C,MAAM,UAAU,MAAM,KAAG,IAAI,CAAO;IAC5E,MAAM;;;;;MAA8C;IACpD,QAAQ;;;MAAmB;IAC1B,aAAa,UAAQ;IAEvC,OAAO;;;MAAgB;IA4BvB,OAAO,CAAC,iBAAiB,EAAE,cAAc;IAczC,UAAU,CAAC,iBAAiB,EAAE,cAAc;IAsB5C,MAAM;IAyER,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,GAAG;IAQzC,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc;IAI3D,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 {guard} from 'lit/directives/guard.js';\nimport type {PropertyValues, TemplateResult} 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({type: Array}) points: 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 callback: () => [this.offsetWidth, this.offsetHeight],\n });\n\n private plotData: PlotPoint[] = [];\n private pointsData: 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 if (changedProperties.has('points')) {\n this.pointsData.length = 0;\n for (const point of this.points) {\n this.pointsData.push({x: point[3], y: point[2], coordinate: point});\n }\n }\n }\n\n override render() {\n const [width, height] = this.resizeController.value ?? [0, 0];\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 const offset = this.yGrid.offset();\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\n ${guard([this.lines, width, height], () => svg`\n <path class=\"area\" d=\"${this.area(this.plotData)}\" />\n <path class=\"elevation\" d=\"${this.line(this.plotData)}\" fill=\"none\" />`\n )}\n\n <g style=\"visibility: ${this.pointer.x > 0 ? 'visible' : 'hidden'}\">\n <g clip-path=\"polygon(0 0, ${this.pointer.x - this.margin.left} 0, ${this.pointer.x - this.margin.left} 100%, 0 100%)\">\n ${guard([this.lines, width, height], () => svg`<path class=\"elevation highlight\" d=\"${this.line(this.plotData)}\" fill=\"none\" />`)}\n </g>\n <line\n class=\"pointer-line\"\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\n ${this.pointsData.map((point, index) => this.pointSvg(this.scaleX(point.x), this.scaleY(point.y), index))}\n\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 <g \n transform=\"translate(${this.margin.left},${height - this.margin.bottom + offset})\"\n class=\"axis\"\n style=\"visibility: ${this.lines.length ? 'visible' : 'hidden'}\">\n <line x2=\"${width - this.margin.left - this.margin.right}\"></line>\n </g>\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 public pointSvg(x: number, y: number, index: number): TemplateResult {\n return svg`<circle class=\"point\" cx=\"${x}\" cy=\"${y}\" r=\"10\"/>`;\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"}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import {svg as $agntW$svg, LitElement as $agntW$LitElement} from "lit";
|
|
2
|
+
import {property as $agntW$property, state as $agntW$state, customElement as $agntW$customElement} from "lit/decorators.js";
|
|
3
|
+
import {ResizeController as $agntW$ResizeController} from "@lit-labs/observers/resize-controller.js";
|
|
4
|
+
import {guard as $agntW$guard} from "lit/directives/guard.js";
|
|
5
|
+
import {bisector as $agntW$bisector, extent as $agntW$extent} from "d3-array";
|
|
6
|
+
import {scaleLinear as $agntW$scaleLinear} from "d3-scale";
|
|
7
|
+
import {line as $agntW$line, area as $agntW$area} from "d3-shape";
|
|
8
|
+
import {axisBottom as $agntW$axisBottom, axisLeft as $agntW$axisLeft} from "d3-axis";
|
|
9
|
+
import {select as $agntW$select, pointer as $agntW$pointer} from "d3-selection";
|
|
10
|
+
import $agntW$simplifyjs from "simplify-js";
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
var $916babf1e6dc2c08$var$__decorate = undefined && undefined.__decorate || function(decorators, target, key, desc) {
|
|
23
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
24
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
25
|
+
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
26
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
27
|
+
};
|
|
28
|
+
let $916babf1e6dc2c08$var$ElevationProfile = class ElevationProfile extends (0, $agntW$LitElement) {
|
|
29
|
+
constructor(){
|
|
30
|
+
super(...arguments);
|
|
31
|
+
this.tolerance = 1;
|
|
32
|
+
this.locale = navigator.language;
|
|
33
|
+
this.lines = [];
|
|
34
|
+
this.points = [];
|
|
35
|
+
this.updateScale = (x, y, width, height)=>{};
|
|
36
|
+
this.margin = {
|
|
37
|
+
top: 20,
|
|
38
|
+
right: 20,
|
|
39
|
+
bottom: 20,
|
|
40
|
+
left: 40
|
|
41
|
+
};
|
|
42
|
+
this.tickSize = {
|
|
43
|
+
x: 100,
|
|
44
|
+
y: 40
|
|
45
|
+
};
|
|
46
|
+
this.pointerEvents = true;
|
|
47
|
+
this.pointer = {
|
|
48
|
+
x: 0,
|
|
49
|
+
y: 0
|
|
50
|
+
};
|
|
51
|
+
this.resizeController = new (0, $agntW$ResizeController)(this, {
|
|
52
|
+
callback: ()=>[
|
|
53
|
+
this.offsetWidth,
|
|
54
|
+
this.offsetHeight
|
|
55
|
+
]
|
|
56
|
+
});
|
|
57
|
+
this.plotData = [];
|
|
58
|
+
this.pointsData = [];
|
|
59
|
+
this.scaleX = (0, $agntW$scaleLinear)();
|
|
60
|
+
this.scaleY = (0, $agntW$scaleLinear)();
|
|
61
|
+
this.bisectDistance = (0, $agntW$bisector)((point)=>point.x);
|
|
62
|
+
this.line = (0, $agntW$line)().defined((point)=>!isNaN(point.y)).x((point)=>this.scaleX(point.x)).y((point)=>this.scaleY(point.y));
|
|
63
|
+
this.area = (0, $agntW$area)().defined((point)=>!isNaN(point.y)).x((point)=>this.scaleX(point.x)).y1((point)=>this.scaleY(point.y));
|
|
64
|
+
this.xAxis = (0, $agntW$axisBottom)(this.scaleX).tickFormat((value)=>this.tickFormat(value, "x"));
|
|
65
|
+
this.yAxis = (0, $agntW$axisLeft)(this.scaleY).tickFormat((value)=>this.tickFormat(value, "y"));
|
|
66
|
+
this.xGrid = (0, $agntW$axisBottom)(this.scaleX).tickFormat(()=>"");
|
|
67
|
+
this.yGrid = (0, $agntW$axisLeft)(this.scaleY).tickFormat(()=>"");
|
|
68
|
+
this.meterFormat = null;
|
|
69
|
+
this.kilometerFormat = null;
|
|
70
|
+
}
|
|
71
|
+
updated(changedProperties) {
|
|
72
|
+
if (changedProperties.has("locale")) {
|
|
73
|
+
this.meterFormat = new Intl.NumberFormat(this.locale, {
|
|
74
|
+
style: "unit",
|
|
75
|
+
unit: "meter"
|
|
76
|
+
});
|
|
77
|
+
this.kilometerFormat = new Intl.NumberFormat(this.locale, {
|
|
78
|
+
style: "unit",
|
|
79
|
+
unit: "kilometer"
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
willUpdate(changedProperties) {
|
|
84
|
+
if (changedProperties.has("lines")) {
|
|
85
|
+
this.plotData.length = 0;
|
|
86
|
+
for (const line of this.lines){
|
|
87
|
+
const data = line.map((coordinate)=>({
|
|
88
|
+
x: coordinate[3],
|
|
89
|
+
y: coordinate[2],
|
|
90
|
+
coordinate: coordinate
|
|
91
|
+
}));
|
|
92
|
+
this.plotData.push(...(0, $agntW$simplifyjs)(data, this.tolerance));
|
|
93
|
+
this.plotData.push({
|
|
94
|
+
x: line[line.length - 1][3],
|
|
95
|
+
y: NaN,
|
|
96
|
+
coordinate: []
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
this.scaleX.domain((0, $agntW$extent)(this.plotData, (data)=>data.x));
|
|
100
|
+
this.scaleY.domain((0, $agntW$extent)(this.plotData, (data)=>data.y)).nice();
|
|
101
|
+
this.updateScale(this.scaleX, this.scaleY, this.offsetWidth, this.offsetHeight);
|
|
102
|
+
}
|
|
103
|
+
if (changedProperties.has("points")) {
|
|
104
|
+
this.pointsData.length = 0;
|
|
105
|
+
for (const point of this.points)this.pointsData.push({
|
|
106
|
+
x: point[3],
|
|
107
|
+
y: point[2],
|
|
108
|
+
coordinate: point
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
render() {
|
|
113
|
+
const [width, height] = this.resizeController.value ?? [
|
|
114
|
+
0,
|
|
115
|
+
0
|
|
116
|
+
];
|
|
117
|
+
this.scaleX.range([
|
|
118
|
+
this.margin.left,
|
|
119
|
+
width - this.margin.right
|
|
120
|
+
]);
|
|
121
|
+
this.scaleY.range([
|
|
122
|
+
height - this.margin.bottom,
|
|
123
|
+
this.margin.top
|
|
124
|
+
]);
|
|
125
|
+
this.area.y0(height - this.margin.bottom);
|
|
126
|
+
this.yGrid.tickSize(-width + this.margin.left + this.margin.right);
|
|
127
|
+
this.xGrid.tickSize(height - this.margin.top - this.margin.bottom);
|
|
128
|
+
const xTicks = width / this.tickSize.x;
|
|
129
|
+
const yTicks = height / this.tickSize.y;
|
|
130
|
+
this.xAxis.ticks(xTicks);
|
|
131
|
+
this.xGrid.ticks(xTicks);
|
|
132
|
+
this.yAxis.ticks(yTicks);
|
|
133
|
+
this.yGrid.ticks(yTicks);
|
|
134
|
+
(0, $agntW$select)(this.querySelector(".axis.x")).call(this.xAxis);
|
|
135
|
+
(0, $agntW$select)(this.querySelector(".axis.y")).call(this.yAxis);
|
|
136
|
+
(0, $agntW$select)(this.querySelector(".grid.x")).call(this.xGrid);
|
|
137
|
+
(0, $agntW$select)(this.querySelector(".grid.y")).call(this.yGrid);
|
|
138
|
+
const offset = this.yGrid.offset();
|
|
139
|
+
return (0, $agntW$svg)`
|
|
140
|
+
<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">
|
|
141
|
+
<g class="grid y" transform="translate(${this.margin.left}, 0)" />
|
|
142
|
+
<g class="grid x" transform="translate(0, ${this.margin.bottom})" />
|
|
143
|
+
<g class="axis x" transform="translate(0, ${height - this.margin.bottom})" />
|
|
144
|
+
<g class="axis y" transform="translate(${this.margin.left}, 0)" />
|
|
145
|
+
|
|
146
|
+
${(0, $agntW$guard)([
|
|
147
|
+
this.lines,
|
|
148
|
+
width,
|
|
149
|
+
height
|
|
150
|
+
], ()=>(0, $agntW$svg)`
|
|
151
|
+
<path class="area" d="${this.area(this.plotData)}" />
|
|
152
|
+
<path class="elevation" d="${this.line(this.plotData)}" fill="none" />`)}
|
|
153
|
+
|
|
154
|
+
<g style="visibility: ${this.pointer.x > 0 ? "visible" : "hidden"}">
|
|
155
|
+
<g clip-path="polygon(0 0, ${this.pointer.x - this.margin.left} 0, ${this.pointer.x - this.margin.left} 100%, 0 100%)">
|
|
156
|
+
${(0, $agntW$guard)([
|
|
157
|
+
this.lines,
|
|
158
|
+
width,
|
|
159
|
+
height
|
|
160
|
+
], ()=>(0, $agntW$svg)`<path class="elevation highlight" d="${this.line(this.plotData)}" fill="none" />`)}
|
|
161
|
+
</g>
|
|
162
|
+
<line
|
|
163
|
+
class="pointer-line"
|
|
164
|
+
x1="${this.pointer.x}"
|
|
165
|
+
y1="${this.margin.top}"
|
|
166
|
+
x2="${this.pointer.x}"
|
|
167
|
+
y2="${height - this.margin.bottom}"
|
|
168
|
+
/>
|
|
169
|
+
<circle class="pointer-circle-outline" cx="${this.pointer.x}" cy="${this.pointer.y}" r="16"/>
|
|
170
|
+
<circle class="pointer-circle" cx="${this.pointer.x}" cy="${this.pointer.y}" r="6"/>
|
|
171
|
+
</g>
|
|
172
|
+
|
|
173
|
+
${this.pointsData.map((point, index)=>this.pointSvg(this.scaleX(point.x), this.scaleY(point.y), index))}
|
|
174
|
+
|
|
175
|
+
<rect
|
|
176
|
+
width="${width}"
|
|
177
|
+
height="${height}"
|
|
178
|
+
fill="none"
|
|
179
|
+
pointer-events="${this.pointerEvents ? "all" : "none"}"
|
|
180
|
+
style="display: block; touch-action: none;"
|
|
181
|
+
@pointermove="${this.pointerMove}"
|
|
182
|
+
@pointerout="${this.pointerOut}"
|
|
183
|
+
/>
|
|
184
|
+
<g
|
|
185
|
+
transform="translate(${this.margin.left},${height - this.margin.bottom + offset})"
|
|
186
|
+
class="axis"
|
|
187
|
+
style="visibility: ${this.lines.length ? "visible" : "hidden"}">
|
|
188
|
+
<line x2="${width - this.margin.left - this.margin.right}"></line>
|
|
189
|
+
</g>
|
|
190
|
+
</svg>
|
|
191
|
+
`;
|
|
192
|
+
}
|
|
193
|
+
tickFormat(value, axis) {
|
|
194
|
+
if (axis === "y" || value < 1000) return this.meterFormat.format(value);
|
|
195
|
+
else return this.kilometerFormat.format(value / 1000);
|
|
196
|
+
}
|
|
197
|
+
pointSvg(x, y, index) {
|
|
198
|
+
return (0, $agntW$svg)`<circle class="point" cx="${x}" cy="${y}" r="10"/>`;
|
|
199
|
+
}
|
|
200
|
+
firstUpdated() {
|
|
201
|
+
// FIXME: because the ref element are used before render is done, we need to force an update
|
|
202
|
+
this.requestUpdate();
|
|
203
|
+
}
|
|
204
|
+
pointerMove(event) {
|
|
205
|
+
const pointerDistance = this.scaleX.invert((0, $agntW$pointer)(event)[0]);
|
|
206
|
+
const index = Math.min(this.bisectDistance.left(this.plotData, pointerDistance), this.plotData.length - 1);
|
|
207
|
+
if (index < 0) return;
|
|
208
|
+
// FIXME:
|
|
209
|
+
// var d0 = this.plotData[index - 1]
|
|
210
|
+
// var d1 = this.plotData[index];
|
|
211
|
+
// // work out which date value is closest to the mouse
|
|
212
|
+
// var d = mouseDate - d0[0] > d1[0] - mouseDate ? d1 : d0;
|
|
213
|
+
const data = this.plotData[index];
|
|
214
|
+
if (isNaN(data.y)) return;
|
|
215
|
+
this.pointer = {
|
|
216
|
+
x: this.scaleX(data.x),
|
|
217
|
+
y: this.scaleY(data.y)
|
|
218
|
+
};
|
|
219
|
+
this.dispatchEvent(new CustomEvent("over", {
|
|
220
|
+
detail: {
|
|
221
|
+
coordinate: this.plotData[index].coordinate,
|
|
222
|
+
position: this.pointer
|
|
223
|
+
}
|
|
224
|
+
}));
|
|
225
|
+
}
|
|
226
|
+
pointerOut() {
|
|
227
|
+
this.pointer = {
|
|
228
|
+
x: 0,
|
|
229
|
+
y: 0
|
|
230
|
+
};
|
|
231
|
+
this.dispatchEvent(new CustomEvent("out"));
|
|
232
|
+
}
|
|
233
|
+
createRenderRoot() {
|
|
234
|
+
return this;
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
$916babf1e6dc2c08$var$__decorate([
|
|
238
|
+
(0, $agntW$property)({
|
|
239
|
+
type: Number
|
|
240
|
+
})
|
|
241
|
+
], $916babf1e6dc2c08$var$ElevationProfile.prototype, "tolerance", void 0);
|
|
242
|
+
$916babf1e6dc2c08$var$__decorate([
|
|
243
|
+
(0, $agntW$property)({
|
|
244
|
+
type: String
|
|
245
|
+
})
|
|
246
|
+
], $916babf1e6dc2c08$var$ElevationProfile.prototype, "locale", void 0);
|
|
247
|
+
$916babf1e6dc2c08$var$__decorate([
|
|
248
|
+
(0, $agntW$property)({
|
|
249
|
+
type: Array
|
|
250
|
+
})
|
|
251
|
+
], $916babf1e6dc2c08$var$ElevationProfile.prototype, "lines", void 0);
|
|
252
|
+
$916babf1e6dc2c08$var$__decorate([
|
|
253
|
+
(0, $agntW$property)({
|
|
254
|
+
type: Array
|
|
255
|
+
})
|
|
256
|
+
], $916babf1e6dc2c08$var$ElevationProfile.prototype, "points", void 0);
|
|
257
|
+
$916babf1e6dc2c08$var$__decorate([
|
|
258
|
+
(0, $agntW$property)()
|
|
259
|
+
], $916babf1e6dc2c08$var$ElevationProfile.prototype, "updateScale", void 0);
|
|
260
|
+
$916babf1e6dc2c08$var$__decorate([
|
|
261
|
+
(0, $agntW$property)({
|
|
262
|
+
type: Object
|
|
263
|
+
})
|
|
264
|
+
], $916babf1e6dc2c08$var$ElevationProfile.prototype, "margin", void 0);
|
|
265
|
+
$916babf1e6dc2c08$var$__decorate([
|
|
266
|
+
(0, $agntW$property)({
|
|
267
|
+
type: Object
|
|
268
|
+
})
|
|
269
|
+
], $916babf1e6dc2c08$var$ElevationProfile.prototype, "tickSize", void 0);
|
|
270
|
+
$916babf1e6dc2c08$var$__decorate([
|
|
271
|
+
(0, $agntW$property)({
|
|
272
|
+
type: Boolean
|
|
273
|
+
})
|
|
274
|
+
], $916babf1e6dc2c08$var$ElevationProfile.prototype, "pointerEvents", void 0);
|
|
275
|
+
$916babf1e6dc2c08$var$__decorate([
|
|
276
|
+
(0, $agntW$state)()
|
|
277
|
+
], $916babf1e6dc2c08$var$ElevationProfile.prototype, "pointer", void 0);
|
|
278
|
+
$916babf1e6dc2c08$var$ElevationProfile = $916babf1e6dc2c08$var$__decorate([
|
|
279
|
+
(0, $agntW$customElement)("elevation-profile")
|
|
280
|
+
], $916babf1e6dc2c08$var$ElevationProfile);
|
|
281
|
+
var $916babf1e6dc2c08$export$2e2bcd8739ae039 = $916babf1e6dc2c08$var$ElevationProfile;
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
export {$916babf1e6dc2c08$export$2e2bcd8739ae039 as default};
|
|
285
|
+
//# sourceMappingURL=elevation-profile.js.map
|
|
@@ -0,0 +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 {guard} from 'lit/directives/guard.js';\nimport type {PropertyValues, TemplateResult} 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({type: Array}) points: 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 callback: () => [this.offsetWidth, this.offsetHeight],\n });\n\n private plotData: PlotPoint[] = [];\n private pointsData: 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 if (changedProperties.has('points')) {\n this.pointsData.length = 0;\n for (const point of this.points) {\n this.pointsData.push({x: point[3], y: point[2], coordinate: point});\n }\n }\n }\n\n override render() {\n const [width, height] = this.resizeController.value ?? [0, 0];\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 const offset = this.yGrid.offset();\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\n ${guard([this.lines, width, height], () => svg`\n <path class=\"area\" d=\"${this.area(this.plotData)}\" />\n <path class=\"elevation\" d=\"${this.line(this.plotData)}\" fill=\"none\" />`\n )}\n\n <g style=\"visibility: ${this.pointer.x > 0 ? 'visible' : 'hidden'}\">\n <g clip-path=\"polygon(0 0, ${this.pointer.x - this.margin.left} 0, ${this.pointer.x - this.margin.left} 100%, 0 100%)\">\n ${guard([this.lines, width, height], () => svg`<path class=\"elevation highlight\" d=\"${this.line(this.plotData)}\" fill=\"none\" />`)}\n </g>\n <line\n class=\"pointer-line\"\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\n ${this.pointsData.map((point, index) => this.pointSvg(this.scaleX(point.x), this.scaleY(point.y), index))}\n\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 <g \n transform=\"translate(${this.margin.left},${height - this.margin.bottom + offset})\"\n class=\"axis\"\n style=\"visibility: ${this.lines.length ? 'visible' : 'hidden'}\">\n <line x2=\"${width - this.margin.left - this.margin.right}\"></line>\n </g>\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 public pointSvg(x: number, y: number, index: number): TemplateResult {\n return svg`<circle class=\"point\" cx=\"${x}\" cy=\"${y}\" r=\"10\"/>`;\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
|
@@ -62,8 +62,6 @@ export default class ElevationProfile extends LitElement {
|
|
|
62
62
|
private meterFormat: Intl.NumberFormat | null = null;
|
|
63
63
|
private kilometerFormat: Intl.NumberFormat | null = null;
|
|
64
64
|
|
|
65
|
-
private lowestY: number | undefined;
|
|
66
|
-
|
|
67
65
|
override updated(changedProperties: PropertyValues) {
|
|
68
66
|
if (changedProperties.has('locale')) {
|
|
69
67
|
this.meterFormat = new Intl.NumberFormat(this.locale, {
|
|
@@ -86,8 +84,6 @@ export default class ElevationProfile extends LitElement {
|
|
|
86
84
|
this.plotData.push(...simplify(data, this.tolerance));
|
|
87
85
|
this.plotData.push({x: line[line.length - 1][3], y: NaN, coordinate: []});
|
|
88
86
|
}
|
|
89
|
-
this.lowestY = this.plotData.length && this.plotData
|
|
90
|
-
.reduce((a, b) => !isNaN(b.y) ? Math.min(a, b.y) : a, this.plotData[0].y);
|
|
91
87
|
|
|
92
88
|
this.scaleX.domain(extent(this.plotData, (data: PlotPoint) => data.x));
|
|
93
89
|
this.scaleY.domain(extent(this.plotData, (data: PlotPoint) => data.y)).nice();
|
|
@@ -125,8 +121,7 @@ export default class ElevationProfile extends LitElement {
|
|
|
125
121
|
select(this.querySelector('.grid.x')).call(this.xGrid);
|
|
126
122
|
select(this.querySelector('.grid.y')).call(this.yGrid);
|
|
127
123
|
|
|
128
|
-
|
|
129
|
-
const firstYTick = this.scaleY.ticks(yTicks)[0];
|
|
124
|
+
const offset = this.yGrid.offset();
|
|
130
125
|
|
|
131
126
|
return svg`
|
|
132
127
|
<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">
|
|
@@ -167,9 +162,9 @@ export default class ElevationProfile extends LitElement {
|
|
|
167
162
|
@pointerout="${this.pointerOut}"
|
|
168
163
|
/>
|
|
169
164
|
<g
|
|
170
|
-
transform="translate(${this.margin.left},${height - this.margin.bottom})"
|
|
165
|
+
transform="translate(${this.margin.left},${height - this.margin.bottom + offset})"
|
|
171
166
|
class="axis"
|
|
172
|
-
style="visibility: ${this.
|
|
167
|
+
style="visibility: ${this.lines.length ? 'visible' : 'hidden'}">
|
|
173
168
|
<line x2="${width - this.margin.left - this.margin.right}"></line>
|
|
174
169
|
</g>
|
|
175
170
|
</svg>
|