@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.
@@ -1,6 +1,6 @@
1
1
  import { LitElement, PropertyValues } from "lit";
2
2
  export class ElevationProfile extends LitElement {
3
- lines: number[][];
3
+ lines: number[][][];
4
4
  margin: {
5
5
  top: number;
6
6
  right: number;
@@ -1 +1 @@
1
- {"mappings":";AAcA,6BAC8B,SAAQ,UAAU;IACrB,KAAK,EAAE,MAAM,EAAE,EAAE,CAAM;IACtB,MAAM;;;;;MAA8C;IACpD,QAAQ;;;MAAmB;IAE5C,OAAO;;;MAAgB;IA2BvB,UAAU,CAAC,iBAAiB,EAAE,cAAc;IAa5C,MAAM;IAyDN,YAAY;IAuCZ,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 {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.d.ts.map"}
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[0]);
49
- this.line = (0, $agntW$line)().x((point)=>this.scaleX(point[0])).y((point)=>this.scaleY(point[1]));
50
- this.area = (0, $agntW$area)().x((point)=>this.scaleX(point[0])).y1((point)=>this.scaleY(point[1]));
51
- this.xAxis = (0, $agntW$axisBottom)(this.scaleX).tickFormat((val)=>`${val} m`);
52
- this.yAxis = (0, $agntW$axisLeft)(this.scaleY).tickFormat((val)=>`${val} m`);
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.xRef = (0, $agntW$createRef)();
56
- this.yRef = (0, $agntW$createRef)();
57
- this.yGridRef = (0, $agntW$createRef)();
58
- this.xGridRef = (0, $agntW$createRef)();
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
- this.plotData = this.lines.map((coordinate)=>[
63
- coordinate[3],
64
- coordinate[2]
65
- ]);
66
- this.scaleX.domain((0, $agntW$extent)(this.plotData, (data)=>data[0]));
67
- this.scaleY.domain((0, $agntW$extent)(this.plotData, (data)=>data[1])).nice();
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.xRef.value).call(this.xAxis);
94
- (0, $agntW$select)(this.yRef.value).call(this.yAxis);
95
- (0, $agntW$select)(this.xGridRef.value).call(this.xGrid);
96
- (0, $agntW$select)(this.yGridRef.value).call(this.yGrid);
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" ${(0, $agntW$ref)(this.yGridRef)} transform="translate(${this.margin.left}, 0)" />
100
- <g class="grid x" ${(0, $agntW$ref)(this.xGridRef)} transform="translate(0, ${this.margin.bottom})" />
101
- <g class="axis x" ${(0, $agntW$ref)(this.xRef)} transform="translate(0, ${height - this.margin.bottom})" />
102
- <g class="axis y" ${(0, $agntW$ref)(this.yRef)} transform="translate(${this.margin.left}, 0)" />
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 = data[i - 1]
138
- // var d1 = data[i];
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[0]),
144
- y: this.scaleY(data[1])
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.lines[index],
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"}
@@ -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 = number[];
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[0]);
31
+ private bisectDistance = bisector((point: PlotPoint) => point.x);
28
32
 
29
33
  private line = line()
30
- .x((point: PlotPoint) => this.scaleX(point[0]))
31
- .y((point: PlotPoint) => this.scaleY(point[1]));
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
- .x((point: PlotPoint) => this.scaleX(point[0]))
34
- .y1((point: PlotPoint) => this.scaleY(point[1]));
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
- this.plotData = this.lines.map((coordinate) => [coordinate[3], coordinate[2]]);
53
-
54
- this.scaleX.domain(extent(this.plotData, (data: PlotPoint) => data[0]));
55
- this.scaleY.domain(extent(this.plotData, (data: PlotPoint) => data[1])).nice();
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 = data[i - 1]
143
- // var d1 = data[i];
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[0]),
151
- y: this.scaleY(data[1]),
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.lines[index],
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.4",
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"