@geoblocks/elevation-profile 0.0.25-beta.2 → 0.0.25-beta.3

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 +1 @@
1
- {"mappings":";;AAqBA,0BAA0B,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;AAEjE,0BAA0B;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC;IACjC,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACtB,CAAC;CACH,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,GAAI,GAAG,WAAW,EAAE,GAAG,WAAW,EAAE,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAG,IAAI,CAAO;IAC5E,MAAM;;;;;MAA8C;IACpD,QAAQ;;;MAAmB;IAC1B,aAAa,UAAQ;IACvB,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,aAAa,CAAC,EAAE,WAAW,CAAC;IAG5C,OAAO;;;MAAgB;IA+BvB,OAAO,CAAC,iBAAiB,EAAE,cAAc;IAczC,UAAU,CAAC,iBAAiB,EAAE,cAAc;IAyD5C,MAAM;IAoGR,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,GAAG;IAQzC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,GAAG,GAAG;IAO5C,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc;IAI3D,YAAY;IAYZ,oBAAoB;IAuDpB,gBAAgB;CAG1B;AA2DD,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 {ifDefined} from 'lit/directives/if-defined.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 SegmentData = Array<[number, number, string | null]>;\n\nexport type OverDetails = {\n coordinate: number[];\n position: {x: number; y: number};\n segments?: {\n line: string | null;\n xAxis: string | null;\n };\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: 20};\n @property({type: Object}) tickSize = {x: 100, y: 40};\n @property({type: Boolean}) pointerEvents = true;\n @property({type: Array}) lineSegments?: SegmentData;\n @property({type: Array}) xAxisSegments?: SegmentData;\n private yAxisObserver: ResizeObserver | null = null;\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 lineSegmentsData: SegmentData = [];\n private xAxisSegmentsData: SegmentData = [];\n private originalToSimplifiedIndexMap: Map<number, number> = new Map();\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 this.originalToSimplifiedIndexMap.clear();\n let originalIndex = 0;\n let simplifiedIndex = 0;\n\n for (const line of this.lines) {\n const data = line.map((coordinate, i) => {\n this.originalToSimplifiedIndexMap.set(originalIndex + i, -1); // mark all as not included initially\n return {x: coordinate[3], y: coordinate[2], coordinate};\n });\n\n const simplified = simplify(data, this.tolerance);\n\n // Map which original points made it through simplification\n for (const simplifiedPoint of simplified) {\n const origIdx = line.findIndex(coord =>\n coord[3] === simplifiedPoint.x && coord[2] === simplifiedPoint.y\n );\n if (origIdx >= 0) {\n this.originalToSimplifiedIndexMap.set(originalIndex + origIdx, simplifiedIndex);\n simplifiedIndex++;\n }\n }\n\n this.plotData.push(...simplified);\n this.plotData.push({x: line[line.length - 1][3], y: NaN, coordinate: []});\n simplifiedIndex++; // account for the NaN separator\n\n originalIndex += line.length;\n }\n\n this.scaleX.domain(extent(this.plotData, (data: PlotPoint) => data.x));\n this.scaleY.domain(extent(this.plotData, (data: PlotPoint) => data.y));\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 // FIXME: what if this.lines is not set yet?\n if (changedProperties.has('lineSegments')) {\n const totalOriginalPoints = this.lines.reduce((sum, line) => sum + line.length, 0);\n const originalSegments = fillUnspecified(this.lineSegments || [], totalOriginalPoints);\n this.lineSegmentsData = remapSegments(originalSegments, this.originalToSimplifiedIndexMap);\n }\n if (changedProperties.has('xAxisSegments')) {\n const totalOriginalPoints = this.lines.reduce((sum, line) => sum + line.length, 0);\n const originalSegments = fillUnspecified(this.xAxisSegments || [], totalOriginalPoints);\n this.xAxisSegmentsData = remapSegments(originalSegments, this.originalToSimplifiedIndexMap);\n }\n }\n\n override render() {\n const [width, height] = this.resizeController.value ?? [0, 0];\n const ml = (this.querySelector('.axis.y')?.getBoundingClientRect().width || 0) + this.margin.left\n\n this.scaleX.range([ml, 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 + ml + 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}\" viewBox=\"0 0 ${width} ${height}\" xmlns=\"http://www.w3.org/2000/svg\">\n <g class=\"grid y\" transform=\"translate(${ml}, 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(${ml}, 0)\" />\n\n ${guard([this.lines, width, height, ml], () => svg`\n <path class=\"area\" d=\"${this.area(this.plotData)}\" />\n ${this.renderLineSegments('elevation')}`\n )}\n\n <g style=\"visibility: ${this.pointer.x > 0 ? 'visible' : 'hidden'}\">\n <g clip-path=\"polygon(0 0, ${this.pointer.x - ml} 0, ${this.pointer.x - ml} 100%, 0 100%)\">\n ${guard([this.lines, width, height, ml], () => this.renderLineSegments('elevation highlight'))}\n </g>\n <line\n class=\"pointer-line x\"\n x1=\"${this.pointer.x}\"\n y1=\"${this.margin.top}\"\n x2=\"${this.pointer.x}\"\n y2=\"${height - this.margin.bottom}\"\n />\n <line\n class=\"pointer-line y\"\n x1=\"${ml}\"\n y1=\"${this.pointer.y}\"\n x2=\"${width - this.margin.right}\"\n y2=\"${this.pointer.y}\"\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(${ml},${height - this.margin.bottom + offset})\"\n class=\"axis\"\n style=\"visibility: ${this.lines.length ? 'visible' : 'hidden'}\">\n <line x2=\"${width - ml - this.margin.right}\"></line>\n </g>\n <g transform=\"translate(0,${height - this.margin.bottom + offset})\">\n ${this.renderTrailBands()}\n </g>\n </svg>\n `;\n }\n\n private renderLineSegments(className: string) {\n return this.lineSegmentsData.map(([start, end, value]) => {\n const segmentData = this.plotData.slice(start, end);\n return svg`<path class=\"${className}\" data-value=\"${ifDefined(value)}\" d=\"${this.line(segmentData)}\" fill=\"none\" />`;\n });\n }\n\n private renderTrailBands() {\n return this.xAxisSegmentsData.map(([start, end, value]) => {\n const x1 = this.scaleX(this.plotData[start].x);\n const x2 = this.scaleX(this.plotData[end - 1].x);\n const bandWidth = x2 - x1;\n return svg`<rect class=\"trail-band\" data-value=\"${ifDefined(value)}\" x=\"${x1}\" width=\"${bandWidth}\" />`;\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 tickValues(values: number[], axis: 'x' | 'y') {\n if (values.length === 0 || (axis !== 'x' && axis !== 'y')) {\n return;\n }\n axis === 'x' ? this.xAxis.tickValues(values) : this.yAxis.tickValues(values);\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 const axisY = this.querySelector('.axis.y');\n if (axisY) {\n this.yAxisObserver = new ResizeObserver(() => {\n this.requestUpdate()\n })\n this.yAxisObserver.observe(axisY);\n }\n // FIXME: because the ref element are used before render is done, we need to force an update\n this.requestUpdate();\n }\n\n override disconnectedCallback() {\n if (this.yAxisObserver) {\n this.yAxisObserver.disconnect();\n }\n super.disconnectedCallback();\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 const segments: OverDetails['segments'] = {\n line: getSegmentValueAtIndex(this.lineSegmentsData, index),\n xAxis: getSegmentValueAtIndex(this.xAxisSegmentsData, index),\n };\n\n this.dispatchEvent(\n new CustomEvent<OverDetails>('over', {\n detail: {\n coordinate: this.plotData[index].coordinate,\n position: this.pointer,\n ...(Object.keys(segments).length > 0 && { segments })\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\nfunction fillUnspecified(segment: SegmentData, length: number): SegmentData {\n const filledSegments: SegmentData = [];\n let currentIndex = 0;\n\n for (const [start, end, value] of segment) {\n if (start > currentIndex) {\n filledSegments.push([currentIndex, start, null]);\n }\n filledSegments.push([start, end, value]);\n currentIndex = end;\n }\n\n if (currentIndex < length) {\n filledSegments.push([currentIndex, length, null]);\n }\n\n return filledSegments;\n}\n\nfunction getSegmentValueAtIndex(segments: SegmentData, index: number): string | null {\n for (const [start, end, value] of segments) {\n if (index >= start && index < end) {\n return value;\n }\n }\n // we must never be here because of fillUnspecified\n return null;\n}\n\nfunction remapSegments(segments: SegmentData, indexMap: Map<number, number>): SegmentData {\n const remappedSegments: SegmentData = [];\n\n for (const [start, end, value] of segments) {\n // Find the first simplified index that corresponds to an original index >= start\n let newStart = -1;\n let newEnd = -1;\n\n for (let i = start; i <= end; i++) {\n const simplifiedIdx = indexMap.get(i);\n if (simplifiedIdx !== undefined && simplifiedIdx >= 0) {\n if (newStart === -1) {\n newStart = simplifiedIdx;\n }\n newEnd = simplifiedIdx;\n }\n }\n\n // Only add the segment if we found at least one point that survived simplification\n if (newStart >= 0 && newEnd >= 0) {\n remappedSegments.push([newStart, newEnd + 1, value]);\n }\n }\n\n return remappedSegments;\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":";;AAqBA,0BAA0B,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;AAEjE,0BAA0B;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC;IACjC,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACtB,CAAC;CACH,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,GAAI,GAAG,WAAW,EAAE,GAAG,WAAW,EAAE,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAG,IAAI,CAAO;IAC5E,MAAM;;;;;MAA8C;IACpD,QAAQ;;;MAAmB;IAC1B,aAAa,UAAQ;IACvB,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,aAAa,CAAC,EAAE,WAAW,CAAC;IAG5C,OAAO;;;MAAgB;IA+BvB,OAAO,CAAC,iBAAiB,EAAE,cAAc;IAczC,UAAU,CAAC,iBAAiB,EAAE,cAAc;IAyD5C,MAAM;IAoGR,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,GAAG;IAQzC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,GAAG,GAAG;IAO5C,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc;IAI3D,YAAY;IAYZ,oBAAoB;IAuDpB,gBAAgB;CAG1B;AA6DD,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 {ifDefined} from 'lit/directives/if-defined.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 SegmentData = Array<[number, number, string | null]>;\n\nexport type OverDetails = {\n coordinate: number[];\n position: {x: number; y: number};\n segments?: {\n line: string | null;\n xAxis: string | null;\n };\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: 20};\n @property({type: Object}) tickSize = {x: 100, y: 40};\n @property({type: Boolean}) pointerEvents = true;\n @property({type: Array}) lineSegments?: SegmentData;\n @property({type: Array}) xAxisSegments?: SegmentData;\n private yAxisObserver: ResizeObserver | null = null;\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 lineSegmentsData: SegmentData = [];\n private xAxisSegmentsData: SegmentData = [];\n private originalToSimplifiedIndexMap: Map<number, number> = new Map();\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 this.originalToSimplifiedIndexMap.clear();\n let originalIndex = 0;\n let simplifiedIndex = 0;\n\n for (const line of this.lines) {\n const data = line.map((coordinate, i) => {\n this.originalToSimplifiedIndexMap.set(originalIndex + i, -1); // mark all as not included initially\n return {x: coordinate[3], y: coordinate[2], coordinate};\n });\n\n const simplified = simplify(data, this.tolerance);\n\n // Map which original points made it through simplification\n for (const simplifiedPoint of simplified) {\n const origIdx = line.findIndex(coord =>\n coord[3] === simplifiedPoint.x && coord[2] === simplifiedPoint.y\n );\n if (origIdx >= 0) {\n this.originalToSimplifiedIndexMap.set(originalIndex + origIdx, simplifiedIndex);\n simplifiedIndex++;\n }\n }\n\n this.plotData.push(...simplified);\n this.plotData.push({x: line[line.length - 1][3], y: NaN, coordinate: []});\n simplifiedIndex++; // account for the NaN separator\n\n originalIndex += line.length;\n }\n\n this.scaleX.domain(extent(this.plotData, (data: PlotPoint) => data.x));\n this.scaleY.domain(extent(this.plotData, (data: PlotPoint) => data.y));\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 // FIXME: what if this.lines is not set yet?\n if (changedProperties.has('lineSegments')) {\n const totalOriginalPoints = this.lines.reduce((sum, line) => sum + line.length, 0);\n const originalSegments = fillUnspecified(this.lineSegments || [], totalOriginalPoints);\n this.lineSegmentsData = remapSegments(originalSegments, this.originalToSimplifiedIndexMap);\n }\n if (changedProperties.has('xAxisSegments')) {\n const totalOriginalPoints = this.lines.reduce((sum, line) => sum + line.length, 0);\n const originalSegments = fillUnspecified(this.xAxisSegments || [], totalOriginalPoints);\n this.xAxisSegmentsData = remapSegments(originalSegments, this.originalToSimplifiedIndexMap);\n }\n }\n\n override render() {\n const [width, height] = this.resizeController.value ?? [0, 0];\n const ml = (this.querySelector('.axis.y')?.getBoundingClientRect().width || 0) + this.margin.left\n\n this.scaleX.range([ml, 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 + ml + 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}\" viewBox=\"0 0 ${width} ${height}\" xmlns=\"http://www.w3.org/2000/svg\">\n <g class=\"grid y\" transform=\"translate(${ml}, 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(${ml}, 0)\" />\n\n ${guard([this.lines, width, height, ml], () => svg`\n <path class=\"area\" d=\"${this.area(this.plotData)}\" />\n ${this.renderLineSegments('elevation')}`\n )}\n\n <g style=\"visibility: ${this.pointer.x > 0 ? 'visible' : 'hidden'}\">\n <g clip-path=\"polygon(0 0, ${this.pointer.x - ml} 0, ${this.pointer.x - ml} 100%, 0 100%)\">\n ${guard([this.lines, width, height, ml], () => this.renderLineSegments('elevation highlight'))}\n </g>\n <line\n class=\"pointer-line x\"\n x1=\"${this.pointer.x}\"\n y1=\"${this.margin.top}\"\n x2=\"${this.pointer.x}\"\n y2=\"${height - this.margin.bottom}\"\n />\n <line\n class=\"pointer-line y\"\n x1=\"${ml}\"\n y1=\"${this.pointer.y}\"\n x2=\"${width - this.margin.right}\"\n y2=\"${this.pointer.y}\"\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(${ml},${height - this.margin.bottom + offset})\"\n class=\"axis\"\n style=\"visibility: ${this.lines.length ? 'visible' : 'hidden'}\">\n <line x2=\"${width - ml - this.margin.right}\"></line>\n </g>\n <g transform=\"translate(0,${height - this.margin.bottom + offset})\">\n ${this.renderTrailBands()}\n </g>\n </svg>\n `;\n }\n\n private renderLineSegments(className: string) {\n return this.lineSegmentsData.map(([start, end, value]) => {\n const segmentData = this.plotData.slice(start, end);\n return svg`<path class=\"${className}\" data-value=\"${ifDefined(value)}\" d=\"${this.line(segmentData)}\" fill=\"none\" />`;\n });\n }\n\n private renderTrailBands() {\n return this.xAxisSegmentsData.map(([start, end, value]) => {\n const x1 = this.scaleX(this.plotData[start].x);\n const x2 = this.scaleX(this.plotData[end - 1].x);\n const bandWidth = x2 - x1;\n return svg`<rect class=\"trail-band\" data-value=\"${ifDefined(value)}\" x=\"${x1}\" width=\"${bandWidth}\" />`;\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 tickValues(values: number[], axis: 'x' | 'y') {\n if (values.length === 0 || (axis !== 'x' && axis !== 'y')) {\n return;\n }\n axis === 'x' ? this.xAxis.tickValues(values) : this.yAxis.tickValues(values);\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 const axisY = this.querySelector('.axis.y');\n if (axisY) {\n this.yAxisObserver = new ResizeObserver(() => {\n this.requestUpdate()\n })\n this.yAxisObserver.observe(axisY);\n }\n // FIXME: because the ref element are used before render is done, we need to force an update\n this.requestUpdate();\n }\n\n override disconnectedCallback() {\n if (this.yAxisObserver) {\n this.yAxisObserver.disconnect();\n }\n super.disconnectedCallback();\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 const segments: OverDetails['segments'] = {\n line: getSegmentValueAtIndex(this.lineSegmentsData, index),\n xAxis: getSegmentValueAtIndex(this.xAxisSegmentsData, index),\n };\n\n this.dispatchEvent(\n new CustomEvent<OverDetails>('over', {\n detail: {\n coordinate: this.plotData[index].coordinate,\n position: this.pointer,\n ...(Object.keys(segments).length > 0 && { segments })\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\nfunction fillUnspecified(segment: SegmentData, length: number): SegmentData {\n const filledSegments: SegmentData = [];\n let currentIndex = 0;\n\n for (const [start, end, value] of segment) {\n if (start > currentIndex) {\n filledSegments.push([currentIndex, start, null]);\n }\n filledSegments.push([start, end, value]);\n currentIndex = end;\n }\n\n if (currentIndex < length) {\n filledSegments.push([currentIndex, length, null]);\n }\n\n return filledSegments;\n}\n\nfunction getSegmentValueAtIndex(segments: SegmentData, index: number): string | null {\n for (const [start, end, value] of segments) {\n if (index >= start && index < end) {\n return value;\n }\n }\n // we must never be here because of fillUnspecified\n return null;\n}\n\nfunction remapSegments(segments: SegmentData, indexMap: Map<number, number>): SegmentData {\n const remappedSegments: SegmentData = [];\n \n for (const [start, end, value] of segments) {\n // Find the first and last simplified indices that correspond to original indices in [start, end)\n let newStart = -1;\n let newEnd = -1;\n \n // end is exclusive, so iterate from start to end-1\n for (let i = start; i < end; i++) {\n const simplifiedIdx = indexMap.get(i);\n if (simplifiedIdx !== undefined && simplifiedIdx >= 0) {\n if (newStart === -1) {\n newStart = simplifiedIdx;\n }\n newEnd = simplifiedIdx;\n }\n }\n \n // Only add the segment if we found at least one point that survived simplification\n // newEnd + 1 because we want the new end to be exclusive as well\n if (newStart >= 0 && newEnd >= 0) {\n remappedSegments.push([newStart, newEnd + 1, value]);\n }\n }\n \n return remappedSegments;\n}\n\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'elevation-profile': ElevationProfile;\n }\n}\n"],"names":[],"version":3,"file":"elevation-profile.d.ts.map"}
@@ -481,10 +481,11 @@ function $916babf1e6dc2c08$var$getSegmentValueAtIndex(segments, index) {
481
481
  function $916babf1e6dc2c08$var$remapSegments(segments, indexMap) {
482
482
  const remappedSegments = [];
483
483
  for (const [start, end, value] of segments){
484
- // Find the first simplified index that corresponds to an original index >= start
484
+ // Find the first and last simplified indices that correspond to original indices in [start, end)
485
485
  let newStart = -1;
486
486
  let newEnd = -1;
487
- for(let i = start; i <= end; i++){
487
+ // end is exclusive, so iterate from start to end-1
488
+ for(let i = start; i < end; i++){
488
489
  const simplifiedIdx = indexMap.get(i);
489
490
  if (simplifiedIdx !== undefined && simplifiedIdx >= 0) {
490
491
  if (newStart === -1) newStart = simplifiedIdx;
@@ -492,6 +493,7 @@ function $916babf1e6dc2c08$var$remapSegments(segments, indexMap) {
492
493
  }
493
494
  }
494
495
  // Only add the segment if we found at least one point that survived simplification
496
+ // newEnd + 1 because we want the new end to be exclusive as well
495
497
  if (newStart >= 0 && newEnd >= 0) remappedSegments.push([
496
498
  newStart,
497
499
  newEnd + 1,
@@ -1 +1 @@
1
- {"mappings":";;;;;;;;;;;;;;;;;;;;;ACAA;;;;AAIA,GAEA,mEAAmE;AACnE,8FAA8F;AAE9F,mCAAmC;AACnC,SAAS,gCAAU,EAAE,EAAE,EAAE;IACvB,IAAI,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,EAClB,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC;IAElB,OAAO,KAAK,KAAK,KAAK;AACxB;AAEA,4CAA4C;AAC5C,SAAS,mCAAa,CAAC,EAAE,EAAE,EAAE,EAAE;IAC7B,IAAI,IAAI,GAAG,CAAC,EACV,IAAI,GAAG,CAAC,EACR,KAAK,GAAG,CAAC,GAAG,GACZ,KAAK,GAAG,CAAC,GAAG;IAEd,IAAI,OAAO,KAAK,OAAO,GAAG;QACxB,IAAI,IAAI,AAAC,CAAA,AAAC,CAAA,EAAE,CAAC,GAAG,CAAA,IAAK,KAAK,AAAC,CAAA,EAAE,CAAC,GAAG,CAAA,IAAK,EAAC,IAAM,CAAA,KAAK,KAAK,KAAK,EAAC;QAE7D,IAAI,IAAI,GAAG;YACT,IAAI,GAAG,CAAC;YACR,IAAI,GAAG,CAAC;QACV,OAAO,IAAI,IAAI,GAAG;YAChB,KAAK,KAAK;YACV,KAAK,KAAK;QACZ;IACF;IAEA,KAAK,EAAE,CAAC,GAAG;IACX,KAAK,EAAE,CAAC,GAAG;IAEX,OAAO,KAAK,KAAK,KAAK;AACxB;AACA,mDAAmD;AAEnD,sCAAsC;AACtC,SAAS,yCAAmB,MAAM,EAAE,WAAW;IAC7C,IAAI,YAAY,MAAM,CAAC,EAAE,EACvB,YAAY;QAAC;KAAU,EACvB;IAEF,IAAK,IAAI,IAAI,GAAG,MAAM,OAAO,MAAM,EAAE,IAAI,KAAK,IAAK;QACjD,QAAQ,MAAM,CAAC,EAAE;QAEjB,IAAI,gCAAU,OAAO,aAAa,aAAa;YAC7C,UAAU,IAAI,CAAC;YACf,YAAY;QACd;IACF;IAEA,IAAI,cAAc,OAAO,UAAU,IAAI,CAAC;IAExC,OAAO;AACT;AAEA,SAAS,qCAAe,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU;IAClE,IAAI,YAAY,aACd;IAEF,IAAK,IAAI,IAAI,QAAQ,GAAG,IAAI,MAAM,IAAK;QACrC,IAAI,SAAS,mCAAa,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK;QAEhE,IAAI,SAAS,WAAW;YACtB,QAAQ;YACR,YAAY;QACd;IACF;IAEA,IAAI,YAAY,aAAa;QAC3B,IAAI,QAAQ,QAAQ,GAClB,qCAAe,QAAQ,OAAO,OAAO,aAAa;QACpD,WAAW,IAAI,CAAC,MAAM,CAAC,MAAM;QAC7B,IAAI,OAAO,QAAQ,GACjB,qCAAe,QAAQ,OAAO,MAAM,aAAa;IACrD;AACF;AAEA,uDAAuD;AACvD,SAAS,6CAAuB,MAAM,EAAE,WAAW;IACjD,IAAI,OAAO,OAAO,MAAM,GAAG;IAE3B,IAAI,aAAa;QAAC,MAAM,CAAC,EAAE;KAAC;IAC5B,qCAAe,QAAQ,GAAG,MAAM,aAAa;IAC7C,WAAW,IAAI,CAAC,MAAM,CAAC,KAAK;IAE5B,OAAO;AACT;AAGe,kDAAkB,MAAM,EAAE,SAAS,EAAE,cAAc;IAChE,IAAI,OAAO,MAAM,IAAI,GAAG,OAAO;IAE/B,IAAI,cAAc,cAAc,YAAY,YAAY,YAAY;IAEpE,SAAS,iBAAiB,SAAS,yCAAmB,QAAQ;IAC9D,SAAS,6CAAuB,QAAQ;IAExC,OAAO;AACT;;;A,I,mC,a,U,U,I,S,U,E,M,E,G,E,I;I,I,I,U,M,E,I,I,I,S,S,O,O,O,wB,C,Q,O,M;I,I,O,Y,Y,O,Q,Q,K,Y,I,Q,Q,C,Y,Q,K;S,I,I,I,W,M,G,G,K,G,I,I,I,U,C,E,E,I,A,C,I,I,E,K,I,I,E,Q,K,K,E,Q,I,K;I,O,I,K,K,O,c,C,Q,K,I;A;ADzEe,IAAM,yCAAN,MAAM,yBAAyB,CAAA,GAAA,iBAAA;IAA/B,aAAA;Q,K,I;QACa,IAAA,CAAA,SAAS,GAAG;QACZ,IAAA,CAAA,MAAM,GAAG,UAAU,QAAQ;QAC5B,IAAA,CAAA,KAAK,GAAiB,EAAE;QACxB,IAAA,CAAA,MAAM,GAAe,EAAE;QACpC,IAAA,CAAA,WAAW,GAAG,CAAC,GAAgB,GAAgB,OAAe,UAA0B;QAC1E,IAAA,CAAA,MAAM,GAAG;YAAC,KAAK;YAAI,OAAO;YAAI,QAAQ;YAAI,MAAM;QAAE;QAClD,IAAA,CAAA,QAAQ,GAAG;YAAC,GAAG;YAAK,GAAG;QAAE;QACxB,IAAA,CAAA,aAAa,GAAG;QAGnC,IAAA,CAAA,aAAa,GAA0B;QAEtC,IAAA,CAAA,OAAO,GAAG;YAAC,GAAG;YAAG,GAAG;QAAC;QACtB,IAAA,CAAA,gBAAgB,GAAG,IAAI,CAAA,GAAA,uBAAA,EAAiB,IAAI,EAAE;YACpD,UAAU,IAAM;oBAAC,IAAI,CAAC,WAAW;oBAAE,IAAI,CAAC,YAAY;iBAAC;QACtD;QAEO,IAAA,CAAA,QAAQ,GAAgB,EAAE;QAC1B,IAAA,CAAA,UAAU,GAAgB,EAAE;QAC5B,IAAA,CAAA,gBAAgB,GAAgB,EAAE;QAClC,IAAA,CAAA,iBAAiB,GAAgB,EAAE;QACnC,IAAA,CAAA,4BAA4B,GAAwB,IAAI;QACxD,IAAA,CAAA,MAAM,GAAG,CAAA,GAAA,kBAAA;QACT,IAAA,CAAA,MAAM,GAAG,CAAA,GAAA,kBAAA;QAET,IAAA,CAAA,cAAc,GAAG,CAAA,GAAA,eAAA,EAAS,CAAC,QAAqB,MAAM,CAAC;QAEvD,IAAA,CAAA,IAAI,GAAG,CAAA,GAAA,WAAA,IACZ,OAAO,CAAC,CAAC,QAAqB,CAAC,MAAM,MAAM,CAAC,GAC5C,CAAC,CAAC,CAAC,QAAqB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAC3C,CAAC,CAAC,CAAC,QAAqB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QACtC,IAAA,CAAA,IAAI,GAAG,CAAA,GAAA,WAAA,IACZ,OAAO,CAAC,CAAC,QAAqB,CAAC,MAAM,MAAM,CAAC,GAC5C,CAAC,CAAC,CAAC,QAAqB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAC3C,EAAE,CAAC,CAAC,QAAqB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QACvC,IAAA,CAAA,KAAK,GAAG,CAAA,GAAA,iBAAA,EAAW,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,QAAkB,IAAI,CAAC,UAAU,CAAC,OAAO;QACrF,IAAA,CAAA,KAAK,GAAG,CAAA,GAAA,eAAA,EAAS,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,QAAkB,IAAI,CAAC,UAAU,CAAC,OAAO;QACnF,IAAA,CAAA,KAAK,GAAG,CAAA,GAAA,iBAAA,EAAW,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,IAAM;QACjD,IAAA,CAAA,KAAK,GAAG,CAAA,GAAA,eAAA,EAAS,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,IAAM;QAE/C,IAAA,CAAA,WAAW,GAA6B;QACxC,IAAA,CAAA,eAAe,GAA6B;IAsQtD;IApQW,QAAQ,iBAAiC,EAAzC;QACP,IAAI,kBAAkB,GAAG,CAAC,WAAW;YACnC,IAAI,CAAC,WAAW,GAAG,IAAI,KAAK,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE;gBACpD,OAAO;gBACP,MAAM;YACP;YAED,IAAI,CAAC,eAAe,GAAG,IAAI,KAAK,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE;gBACxD,OAAO;gBACP,MAAM;YACP;QACH;IACF;IAES,WAAW,iBAAiC,EAA5C;QACP,IAAI,kBAAkB,GAAG,CAAC,UAAU;YAClC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG;YACvB,IAAI,CAAC,4BAA4B,CAAC,KAAK;YACvC,IAAI,gBAAgB;YACpB,IAAI,kBAAkB;YAEtB,KAAK,MAAM,QAAQ,IAAI,CAAC,KAAK,CAAE;gBAC7B,MAAM,OAAO,KAAK,GAAG,CAAC,CAAC,YAAY;oBACjC,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,gBAAgB,GAAG,KAAK,qCAAqC;oBACnG,OAAO;wBAAC,GAAG,UAAU,CAAC,EAAE;wBAAE,GAAG,UAAU,CAAC,EAAE;oCAAE;oBAAU;gBACxD;gBAEA,MAAM,aAAa,CAAA,GAAA,wCAAA,EAAS,MAAM,IAAI,CAAC,SAAS;gBAEhD,2DAA2D;gBAC3D,KAAK,MAAM,mBAAmB,WAAY;oBACxC,MAAM,UAAU,KAAK,SAAS,CAAC,CAAA,QAC7B,KAAK,CAAC,EAAE,KAAK,gBAAgB,CAAC,IAAI,KAAK,CAAC,EAAE,KAAK,gBAAgB,CAAC;oBAElE,IAAI,WAAW,GAAG;wBAChB,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,gBAAgB,SAAS;wBAC/D;oBACF;gBACF;gBAEA,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI;gBACtB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;oBAAC,GAAG,IAAI,CAAC,KAAK,MAAM,GAAG,EAAE,CAAC,EAAE;oBAAE,GAAG;oBAAK,YAAY,EAAE;gBAAA;gBACvE,mBAAmB,gCAAgC;gBAEnD,iBAAiB,KAAK,MAAM;YAC9B;YAEA,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA,GAAA,aAAA,EAAO,IAAI,CAAC,QAAQ,EAAE,CAAC,OAAoB,KAAK,CAAC;YACpE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA,GAAA,aAAA,EAAO,IAAI,CAAC,QAAQ,EAAE,CAAC,OAAoB,KAAK,CAAC;YAEpE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY;QAChF;QACA,IAAI,kBAAkB,GAAG,CAAC,WAAW;YACnC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG;YACzB,KAAK,MAAM,SAAS,IAAI,CAAC,MAAM,CAC7B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;gBAAC,GAAG,KAAK,CAAC,EAAE;gBAAE,GAAG,KAAK,CAAC,EAAE;gBAAE,YAAY;YAAK;QAErE;QACA,4CAA4C;QAC5C,IAAI,kBAAkB,GAAG,CAAC,iBAAiB;YACzC,MAAM,sBAAsB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,OAAS,MAAM,KAAK,MAAM,EAAE;YAChF,MAAM,mBAAmB,sCAAgB,IAAI,CAAC,YAAY,IAAI,EAAE,EAAE;YAClE,IAAI,CAAC,gBAAgB,GAAG,oCAAc,kBAAkB,IAAI,CAAC,4BAA4B;QAC3F;QACA,IAAI,kBAAkB,GAAG,CAAC,kBAAkB;YAC1C,MAAM,sBAAsB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,OAAS,MAAM,KAAK,MAAM,EAAE;YAChF,MAAM,mBAAmB,sCAAgB,IAAI,CAAC,aAAa,IAAI,EAAE,EAAE;YACnE,IAAI,CAAC,iBAAiB,GAAG,oCAAc,kBAAkB,IAAI,CAAC,4BAA4B;QAC5F;IACF;IAES,SAAA;QACP,MAAM,CAAC,OAAO,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,IAAI;YAAC;YAAG;SAAE;QAC7D,MAAM,KAAK,AAAC,CAAA,IAAI,CAAC,aAAa,CAAC,YAAY,wBAAwB,SAAS,CAAA,IAAK,IAAI,CAAC,MAAM,CAAC,IAAI;QAEjG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YAAC;YAAI,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK;SAAC;QACjD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YAAC,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM;YAAE,IAAI,CAAC,MAAM,CAAC,GAAG;SAAC;QAEhE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM;QAExC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK;QACnD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM;QAEjE,MAAM,SAAS,QAAQ,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtC,MAAM,SAAS,SAAS,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QACjB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QACjB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QACjB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QAEjB,CAAA,GAAA,aAAA,EAAO,IAAI,CAAC,aAAa,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,KAAK;QACrD,CAAA,GAAA,aAAA,EAAO,IAAI,CAAC,aAAa,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,KAAK;QACrD,CAAA,GAAA,aAAA,EAAO,IAAI,CAAC,aAAa,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,KAAK;QACrD,CAAA,GAAA,aAAA,EAAO,IAAI,CAAC,aAAa,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,KAAK;QAErD,MAAM,SAAS,IAAI,CAAC,KAAK,CAAC,MAAM;QAEhC,OAAO,CAAA,GAAA,UAAA,CAAG,CAAV;kBACgB,EAAA,MAAK,UAAA,EAAa,OAAM,eAAA,EAAkB,MAAK,CAAA,EAAI,OAAnD;+CAC6B,EAAA,GAAA;kDACG,EAAA,IAAI,CAAC,MAAM,CAAC,MAAM,CAAlB;kDACA,EAAA,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM,CAA3B;+CACH,EAAA,GAAA;;QAEvC,EAAA,CAAA,GAAA,YAAA,EAAM;YAAC,IAAI,CAAC,KAAK;YAAE;YAAO;YAAQ;SAAG,EAAE,IAAM,CAAA,GAAA,UAAA,CAAG,CAAhD;gCACwB,EAAA,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAvB;UACtB,EAAA,IAAI,CAAC,kBAAkB,CAAC,aAAY,CAAE,EAAtC;;8BAGoB,EAAA,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,YAAY,SAAjC;qCACO,EAAA,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,GAAE,IAAA,EAAO,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,GAA3C;YACzB,EAAA,CAAA,GAAA,YAAA,EAAM;YAAC,IAAI,CAAC,KAAK;YAAE;YAAO;YAAQ;SAAG,EAAE,IAAM,IAAI,CAAC,kBAAkB,CAAC,wBAArE;;;;gBAII,EAAA,IAAI,CAAC,OAAO,CAAC,CAAC,CAAd;gBACA,EAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAf;gBACA,EAAA,IAAI,CAAC,OAAO,CAAC,CAAC,CAAd;gBACA,EAAA,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM,CAA3B;;;;gBAIA,EAAA,GAAA;gBACA,EAAA,IAAI,CAAC,OAAO,CAAC,CAAC,CAAd;gBACA,EAAA,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAzB;gBACA,EAAA,IAAI,CAAC,OAAO,CAAC,CAAC,CAAd;;qDAEqC,EAAA,IAAI,CAAC,OAAO,CAAC,CAAC,CAAA,MAAA,EAAS,IAAI,CAAC,OAAO,CAAC,CAAC,CAArC;6CACR,EAAA,IAAI,CAAC,OAAO,CAAC,CAAC,CAAA,MAAA,EAAS,IAAI,CAAC,OAAO,CAAC,CAAC,CAArC;;;QAGrC,EAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,OAAO,QAAU,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,QAAhG;;;iBAGS,EAAA,MAAA;kBACC,EAAA,OAAA;;0BAEQ,EAAA,IAAI,CAAC,aAAa,GAAG,QAAQ,OAA7B;;wBAEF,EAAA,IAAI,CAAC,WAAW,CAAhB;uBACD,EAAA,IAAI,CAAC,UAAU,CAAf;;;+BAGQ,EAAA,GAAE,CAAA,EAAI,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,OAApC;;6BAEF,EAAA,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,YAAY,SAAhC;oBACT,EAAA,QAAQ,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,CAA9B;;kCAEc,EAAA,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,OAA9B;UACxB,EAAA,IAAI,CAAC,gBAAgB,GAArB;;;IAGP,CAAA;IACH;IAEQ,mBAAmB,SAAiB,EAApC;QACN,OAAO,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM;YACnD,MAAM,cAAc,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO;YAC/C,OAAO,CAAA,GAAA,UAAA,CAAG,CAAA,aAAA,EAAgB,UAAS,cAAA,EAAiB,CAAA,GAAA,gBAAA,EAAU,OAAM,KAAA,EAAQ,IAAI,CAAC,IAAI,CAAC,aAAY,gBAAA,CAAkB;QACtH;IACF;IAEQ,mBAAA;QACN,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM;YACpD,MAAM,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC7C,MAAM,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YAC/C,MAAM,YAAY,KAAK;YACvB,OAAO,CAAA,GAAA,UAAA,CAAG,CAAA,qCAAA,EAAwC,CAAA,GAAA,gBAAA,EAAU,OAAM,KAAA,EAAQ,GAAE,SAAA,EAAY,UAAS,IAAA,CAAM;QACzG;IACF;IAEO,WAAW,KAAa,EAAE,IAAe,EAAzC;QACL,IAAI,SAAS,OAAO,QAAQ,MAC1B,OAAO,IAAI,CAAC,WAAY,CAAC,MAAM,CAAC;aAEhC,OAAO,IAAI,CAAC,eAAgB,CAAC,MAAM,CAAC,QAAQ;IAEhD;IAEO,WAAW,MAAgB,EAAE,IAAe,EAA5C;QACL,IAAI,OAAO,MAAM,KAAK,KAAM,SAAS,OAAO,SAAS,KACnD;QAEF,SAAS,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;IACvE;IAEO,SAAS,CAAS,EAAE,CAAS,EAAE,KAAa,EAA5C;QACL,OAAO,CAAA,GAAA,UAAA,CAAG,CAAA,0BAAA,EAA6B,EAAC,MAAA,EAAS,EAAC,UAAA,CAAY;IAChE;IAES,eAAA;QACP,MAAM,QAAQ,IAAI,CAAC,aAAa,CAAC;QACjC,IAAI,OAAO;YACT,IAAI,CAAC,aAAa,GAAG,IAAI,eAAe;gBACtC,IAAI,CAAC,aAAa;YACpB;YACA,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;QAC7B;QACA,4FAA4F;QAC5F,IAAI,CAAC,aAAa;IACpB;IAES,uBAAA;QACP,IAAI,IAAI,CAAC,aAAa,EACpB,IAAI,CAAC,aAAa,CAAC,UAAU;QAE/B,KAAK,CAAC;IACR;IAEQ,YAAY,KAAmB,EAA/B;QACN,MAAM,kBAAkB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA,GAAA,cAAA,EAAQ,MAAM,CAAC,EAAE;QAC5D,MAAM,QAAQ,KAAK,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,kBAAkB,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG;QAExG,IAAI,QAAQ,GACV;QAEF,SAAS;QACT,oCAAoC;QACpC,iCAAiC;QACjC,uDAAuD;QACvD,2DAA2D;QAE3D,MAAM,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM;QAEjC,IAAI,MAAM,KAAK,CAAC,GACd;QAGF,IAAI,CAAC,OAAO,GAAG;YACb,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YACrB,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;QACtB;QAED,MAAM,WAAoC;YACxC,MAAM,6CAAuB,IAAI,CAAC,gBAAgB,EAAE;YACpD,OAAO,6CAAuB,IAAI,CAAC,iBAAiB,EAAE;QACvD;QAED,IAAI,CAAC,aAAa,CAChB,IAAI,YAAyB,QAAQ;YACnC,QAAQ;gBACN,YAAY,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU;gBAC3C,UAAU,IAAI,CAAC,OAAO;gBACtB,GAAI,OAAO,IAAI,CAAC,UAAU,MAAM,GAAG,KAAK;8BAAE;gBAAQ,CAAE;YACrD;QACF;IAEL;IAEQ,aAAA;QACN,IAAI,CAAC,OAAO,GAAG;YACb,GAAG;YACH,GAAG;QACJ;QACD,IAAI,CAAC,aAAa,CAAC,IAAI,YAAY;IACrC;IAES,mBAAA;QACP,OAAO,IAAI;IACb;AACD;AA/S2B,iCAAA;IAAzB,CAAA,GAAA,eAAA,EAAS;QAAC,MAAM;IAAM;CAAiB,EAAA,uCAAA,SAAA,EAAA,aAAA,KAAA;AACd,iCAAA;IAAzB,CAAA,GAAA,eAAA,EAAS;QAAC,MAAM;IAAM;CAA+B,EAAA,uCAAA,SAAA,EAAA,UAAA,KAAA;AAC7B,iCAAA;IAAxB,CAAA,GAAA,eAAA,EAAS;QAAC,MAAM;IAAK;CAA4B,EAAA,uCAAA,SAAA,EAAA,SAAA,KAAA;AACzB,iCAAA;IAAxB,CAAA,GAAA,eAAA,EAAS;QAAC,MAAM;IAAK;CAA2B,EAAA,uCAAA,SAAA,EAAA,UAAA,KAAA;AACrC,iCAAA;IAAX,CAAA,GAAA,eAAA;CAAqG,EAAA,uCAAA,SAAA,EAAA,eAAA,KAAA;AAC5E,iCAAA;IAAzB,CAAA,GAAA,eAAA,EAAS;QAAC,MAAM;IAAM;CAAuD,EAAA,uCAAA,SAAA,EAAA,UAAA,KAAA;AACpD,iCAAA;IAAzB,CAAA,GAAA,eAAA,EAAS;QAAC,MAAM;IAAM;CAA8B,EAAA,uCAAA,SAAA,EAAA,YAAA,KAAA;AAC1B,iCAAA;IAA1B,CAAA,GAAA,eAAA,EAAS;QAAC,MAAM;IAAO;CAAwB,EAAA,uCAAA,SAAA,EAAA,iBAAA,KAAA;AACvB,iCAAA;IAAxB,CAAA,GAAA,eAAA,EAAS;QAAC,MAAM;IAAK;CAA8B,EAAA,uCAAA,SAAA,EAAA,gBAAA,KAAA;AAC3B,iCAAA;IAAxB,CAAA,GAAA,eAAA,EAAS;QAAC,MAAM;IAAK;CAA+B,EAAA,uCAAA,SAAA,EAAA,iBAAA,KAAA;AAG5C,iCAAA;IAAR,CAAA,GAAA,YAAA;CAA+B,EAAA,uCAAA,SAAA,EAAA,WAAA,KAAA;AAbb,yCAAA,iCAAA;IADpB,CAAA,GAAA,oBAAA,EAAc;CACM,EAAA;IAAA,2CAAA;AAkTrB,SAAS,sCAAgB,OAAoB,EAAE,MAAc;IAC3D,MAAM,iBAA8B,EAAE;IACtC,IAAI,eAAe;IAEnB,KAAK,MAAM,CAAC,OAAO,KAAK,MAAM,IAAI,QAAS;QACzC,IAAI,QAAQ,cACV,eAAe,IAAI,CAAC;YAAC;YAAc;YAAO;SAAK;QAEjD,eAAe,IAAI,CAAC;YAAC;YAAO;YAAK;SAAM;QACvC,eAAe;IACjB;IAEA,IAAI,eAAe,QACjB,eAAe,IAAI,CAAC;QAAC;QAAc;QAAQ;KAAK;IAGlD,OAAO;AACT;AAEA,SAAS,6CAAuB,QAAqB,EAAE,KAAa;IAClE,KAAK,MAAM,CAAC,OAAO,KAAK,MAAM,IAAI,SAAU;QAC1C,IAAI,SAAS,SAAS,QAAQ,KAC5B,OAAO;IAEX;IACA,mDAAmD;IACnD,OAAO;AACT;AAEA,SAAS,oCAAc,QAAqB,EAAE,QAA6B;IACzE,MAAM,mBAAgC,EAAE;IAExC,KAAK,MAAM,CAAC,OAAO,KAAK,MAAM,IAAI,SAAU;QAC1C,iFAAiF;QACjF,IAAI,WAAW;QACf,IAAI,SAAS;QAEb,IAAK,IAAI,IAAI,OAAO,KAAK,KAAK,IAAK;YACjC,MAAM,gBAAgB,SAAS,GAAG,CAAC;YACnC,IAAI,kBAAkB,aAAa,iBAAiB,GAAG;gBACrD,IAAI,aAAa,IACf,WAAW;gBAEb,SAAS;YACX;QACF;QAEA,mFAAmF;QACnF,IAAI,YAAY,KAAK,UAAU,GAC7B,iBAAiB,IAAI,CAAC;YAAC;YAAU,SAAS;YAAG;SAAM;IAEvD;IAEA,OAAO;AACT","sources":["elevation-profile.ts","simplify.js"],"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 {ifDefined} from 'lit/directives/if-defined.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 SegmentData = Array<[number, number, string | null]>;\n\nexport type OverDetails = {\n coordinate: number[];\n position: {x: number; y: number};\n segments?: {\n line: string | null;\n xAxis: string | null;\n };\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: 20};\n @property({type: Object}) tickSize = {x: 100, y: 40};\n @property({type: Boolean}) pointerEvents = true;\n @property({type: Array}) lineSegments?: SegmentData;\n @property({type: Array}) xAxisSegments?: SegmentData;\n private yAxisObserver: ResizeObserver | null = null;\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 lineSegmentsData: SegmentData = [];\n private xAxisSegmentsData: SegmentData = [];\n private originalToSimplifiedIndexMap: Map<number, number> = new Map();\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 this.originalToSimplifiedIndexMap.clear();\n let originalIndex = 0;\n let simplifiedIndex = 0;\n\n for (const line of this.lines) {\n const data = line.map((coordinate, i) => {\n this.originalToSimplifiedIndexMap.set(originalIndex + i, -1); // mark all as not included initially\n return {x: coordinate[3], y: coordinate[2], coordinate};\n });\n\n const simplified = simplify(data, this.tolerance);\n\n // Map which original points made it through simplification\n for (const simplifiedPoint of simplified) {\n const origIdx = line.findIndex(coord =>\n coord[3] === simplifiedPoint.x && coord[2] === simplifiedPoint.y\n );\n if (origIdx >= 0) {\n this.originalToSimplifiedIndexMap.set(originalIndex + origIdx, simplifiedIndex);\n simplifiedIndex++;\n }\n }\n\n this.plotData.push(...simplified);\n this.plotData.push({x: line[line.length - 1][3], y: NaN, coordinate: []});\n simplifiedIndex++; // account for the NaN separator\n\n originalIndex += line.length;\n }\n\n this.scaleX.domain(extent(this.plotData, (data: PlotPoint) => data.x));\n this.scaleY.domain(extent(this.plotData, (data: PlotPoint) => data.y));\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 // FIXME: what if this.lines is not set yet?\n if (changedProperties.has('lineSegments')) {\n const totalOriginalPoints = this.lines.reduce((sum, line) => sum + line.length, 0);\n const originalSegments = fillUnspecified(this.lineSegments || [], totalOriginalPoints);\n this.lineSegmentsData = remapSegments(originalSegments, this.originalToSimplifiedIndexMap);\n }\n if (changedProperties.has('xAxisSegments')) {\n const totalOriginalPoints = this.lines.reduce((sum, line) => sum + line.length, 0);\n const originalSegments = fillUnspecified(this.xAxisSegments || [], totalOriginalPoints);\n this.xAxisSegmentsData = remapSegments(originalSegments, this.originalToSimplifiedIndexMap);\n }\n }\n\n override render() {\n const [width, height] = this.resizeController.value ?? [0, 0];\n const ml = (this.querySelector('.axis.y')?.getBoundingClientRect().width || 0) + this.margin.left\n\n this.scaleX.range([ml, 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 + ml + 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}\" viewBox=\"0 0 ${width} ${height}\" xmlns=\"http://www.w3.org/2000/svg\">\n <g class=\"grid y\" transform=\"translate(${ml}, 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(${ml}, 0)\" />\n\n ${guard([this.lines, width, height, ml], () => svg`\n <path class=\"area\" d=\"${this.area(this.plotData)}\" />\n ${this.renderLineSegments('elevation')}`\n )}\n\n <g style=\"visibility: ${this.pointer.x > 0 ? 'visible' : 'hidden'}\">\n <g clip-path=\"polygon(0 0, ${this.pointer.x - ml} 0, ${this.pointer.x - ml} 100%, 0 100%)\">\n ${guard([this.lines, width, height, ml], () => this.renderLineSegments('elevation highlight'))}\n </g>\n <line\n class=\"pointer-line x\"\n x1=\"${this.pointer.x}\"\n y1=\"${this.margin.top}\"\n x2=\"${this.pointer.x}\"\n y2=\"${height - this.margin.bottom}\"\n />\n <line\n class=\"pointer-line y\"\n x1=\"${ml}\"\n y1=\"${this.pointer.y}\"\n x2=\"${width - this.margin.right}\"\n y2=\"${this.pointer.y}\"\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(${ml},${height - this.margin.bottom + offset})\"\n class=\"axis\"\n style=\"visibility: ${this.lines.length ? 'visible' : 'hidden'}\">\n <line x2=\"${width - ml - this.margin.right}\"></line>\n </g>\n <g transform=\"translate(0,${height - this.margin.bottom + offset})\">\n ${this.renderTrailBands()}\n </g>\n </svg>\n `;\n }\n\n private renderLineSegments(className: string) {\n return this.lineSegmentsData.map(([start, end, value]) => {\n const segmentData = this.plotData.slice(start, end);\n return svg`<path class=\"${className}\" data-value=\"${ifDefined(value)}\" d=\"${this.line(segmentData)}\" fill=\"none\" />`;\n });\n }\n\n private renderTrailBands() {\n return this.xAxisSegmentsData.map(([start, end, value]) => {\n const x1 = this.scaleX(this.plotData[start].x);\n const x2 = this.scaleX(this.plotData[end - 1].x);\n const bandWidth = x2 - x1;\n return svg`<rect class=\"trail-band\" data-value=\"${ifDefined(value)}\" x=\"${x1}\" width=\"${bandWidth}\" />`;\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 tickValues(values: number[], axis: 'x' | 'y') {\n if (values.length === 0 || (axis !== 'x' && axis !== 'y')) {\n return;\n }\n axis === 'x' ? this.xAxis.tickValues(values) : this.yAxis.tickValues(values);\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 const axisY = this.querySelector('.axis.y');\n if (axisY) {\n this.yAxisObserver = new ResizeObserver(() => {\n this.requestUpdate()\n })\n this.yAxisObserver.observe(axisY);\n }\n // FIXME: because the ref element are used before render is done, we need to force an update\n this.requestUpdate();\n }\n\n override disconnectedCallback() {\n if (this.yAxisObserver) {\n this.yAxisObserver.disconnect();\n }\n super.disconnectedCallback();\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 const segments: OverDetails['segments'] = {\n line: getSegmentValueAtIndex(this.lineSegmentsData, index),\n xAxis: getSegmentValueAtIndex(this.xAxisSegmentsData, index),\n };\n\n this.dispatchEvent(\n new CustomEvent<OverDetails>('over', {\n detail: {\n coordinate: this.plotData[index].coordinate,\n position: this.pointer,\n ...(Object.keys(segments).length > 0 && { segments })\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\nfunction fillUnspecified(segment: SegmentData, length: number): SegmentData {\n const filledSegments: SegmentData = [];\n let currentIndex = 0;\n\n for (const [start, end, value] of segment) {\n if (start > currentIndex) {\n filledSegments.push([currentIndex, start, null]);\n }\n filledSegments.push([start, end, value]);\n currentIndex = end;\n }\n\n if (currentIndex < length) {\n filledSegments.push([currentIndex, length, null]);\n }\n\n return filledSegments;\n}\n\nfunction getSegmentValueAtIndex(segments: SegmentData, index: number): string | null {\n for (const [start, end, value] of segments) {\n if (index >= start && index < end) {\n return value;\n }\n }\n // we must never be here because of fillUnspecified\n return null;\n}\n\nfunction remapSegments(segments: SegmentData, indexMap: Map<number, number>): SegmentData {\n const remappedSegments: SegmentData = [];\n\n for (const [start, end, value] of segments) {\n // Find the first simplified index that corresponds to an original index >= start\n let newStart = -1;\n let newEnd = -1;\n\n for (let i = start; i <= end; i++) {\n const simplifiedIdx = indexMap.get(i);\n if (simplifiedIdx !== undefined && simplifiedIdx >= 0) {\n if (newStart === -1) {\n newStart = simplifiedIdx;\n }\n newEnd = simplifiedIdx;\n }\n }\n\n // Only add the segment if we found at least one point that survived simplification\n if (newStart >= 0 && newEnd >= 0) {\n remappedSegments.push([newStart, newEnd + 1, value]);\n }\n }\n\n return remappedSegments;\n}\n\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'elevation-profile': ElevationProfile;\n }\n}\n","/*\n (c) 2017, Vladimir Agafonkin\n Simplify.js, a high-performance JS polyline simplification library\n mourner.github.io/simplify-js\n*/\n\n// to suit your point format, run search/replace for '.x' and '.y';\n// for 3D version, see 3d branch (configurability would draw significant performance overhead)\n\n// square distance between 2 points\nfunction getSqDist(p1, p2) {\n var dx = p1.x - p2.x,\n dy = p1.y - p2.y;\n\n return dx * dx + dy * dy;\n}\n\n// square distance from a point to a segment\nfunction getSqSegDist(p, p1, p2) {\n var x = p1.x,\n y = p1.y,\n dx = p2.x - x,\n dy = p2.y - y;\n\n if (dx !== 0 || dy !== 0) {\n var t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);\n\n if (t > 1) {\n x = p2.x;\n y = p2.y;\n } else if (t > 0) {\n x += dx * t;\n y += dy * t;\n }\n }\n\n dx = p.x - x;\n dy = p.y - y;\n\n return dx * dx + dy * dy;\n}\n// rest of the code doesn't care about point format\n\n// basic distance-based simplification\nfunction simplifyRadialDist(points, sqTolerance) {\n var prevPoint = points[0],\n newPoints = [prevPoint],\n point;\n\n for (var i = 1, len = points.length; i < len; i++) {\n point = points[i];\n\n if (getSqDist(point, prevPoint) > sqTolerance) {\n newPoints.push(point);\n prevPoint = point;\n }\n }\n\n if (prevPoint !== point) newPoints.push(point);\n\n return newPoints;\n}\n\nfunction simplifyDPStep(points, first, last, sqTolerance, simplified) {\n var maxSqDist = sqTolerance,\n index;\n\n for (var i = first + 1; i < last; i++) {\n var sqDist = getSqSegDist(points[i], points[first], points[last]);\n\n if (sqDist > maxSqDist) {\n index = i;\n maxSqDist = sqDist;\n }\n }\n\n if (maxSqDist > sqTolerance) {\n if (index - first > 1)\n simplifyDPStep(points, first, index, sqTolerance, simplified);\n simplified.push(points[index]);\n if (last - index > 1)\n simplifyDPStep(points, index, last, sqTolerance, simplified);\n }\n}\n\n// simplification using Ramer-Douglas-Peucker algorithm\nfunction simplifyDouglasPeucker(points, sqTolerance) {\n var last = points.length - 1;\n\n var simplified = [points[0]];\n simplifyDPStep(points, 0, last, sqTolerance, simplified);\n simplified.push(points[last]);\n\n return simplified;\n}\n\n// both algorithms combined for awesome performance\nexport default function simplify(points, tolerance, highestQuality) {\n if (points.length <= 2) return points;\n\n var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1;\n\n points = highestQuality ? points : simplifyRadialDist(points, sqTolerance);\n points = simplifyDouglasPeucker(points, sqTolerance);\n\n return points;\n}\n"],"names":[],"version":3,"file":"elevation-profile.js.map"}
1
+ {"mappings":"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","sources":["elevation-profile.ts","simplify.js"],"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 {ifDefined} from 'lit/directives/if-defined.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 SegmentData = Array<[number, number, string | null]>;\n\nexport type OverDetails = {\n coordinate: number[];\n position: {x: number; y: number};\n segments?: {\n line: string | null;\n xAxis: string | null;\n };\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: 20};\n @property({type: Object}) tickSize = {x: 100, y: 40};\n @property({type: Boolean}) pointerEvents = true;\n @property({type: Array}) lineSegments?: SegmentData;\n @property({type: Array}) xAxisSegments?: SegmentData;\n private yAxisObserver: ResizeObserver | null = null;\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 lineSegmentsData: SegmentData = [];\n private xAxisSegmentsData: SegmentData = [];\n private originalToSimplifiedIndexMap: Map<number, number> = new Map();\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 this.originalToSimplifiedIndexMap.clear();\n let originalIndex = 0;\n let simplifiedIndex = 0;\n\n for (const line of this.lines) {\n const data = line.map((coordinate, i) => {\n this.originalToSimplifiedIndexMap.set(originalIndex + i, -1); // mark all as not included initially\n return {x: coordinate[3], y: coordinate[2], coordinate};\n });\n\n const simplified = simplify(data, this.tolerance);\n\n // Map which original points made it through simplification\n for (const simplifiedPoint of simplified) {\n const origIdx = line.findIndex(coord =>\n coord[3] === simplifiedPoint.x && coord[2] === simplifiedPoint.y\n );\n if (origIdx >= 0) {\n this.originalToSimplifiedIndexMap.set(originalIndex + origIdx, simplifiedIndex);\n simplifiedIndex++;\n }\n }\n\n this.plotData.push(...simplified);\n this.plotData.push({x: line[line.length - 1][3], y: NaN, coordinate: []});\n simplifiedIndex++; // account for the NaN separator\n\n originalIndex += line.length;\n }\n\n this.scaleX.domain(extent(this.plotData, (data: PlotPoint) => data.x));\n this.scaleY.domain(extent(this.plotData, (data: PlotPoint) => data.y));\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 // FIXME: what if this.lines is not set yet?\n if (changedProperties.has('lineSegments')) {\n const totalOriginalPoints = this.lines.reduce((sum, line) => sum + line.length, 0);\n const originalSegments = fillUnspecified(this.lineSegments || [], totalOriginalPoints);\n this.lineSegmentsData = remapSegments(originalSegments, this.originalToSimplifiedIndexMap);\n }\n if (changedProperties.has('xAxisSegments')) {\n const totalOriginalPoints = this.lines.reduce((sum, line) => sum + line.length, 0);\n const originalSegments = fillUnspecified(this.xAxisSegments || [], totalOriginalPoints);\n this.xAxisSegmentsData = remapSegments(originalSegments, this.originalToSimplifiedIndexMap);\n }\n }\n\n override render() {\n const [width, height] = this.resizeController.value ?? [0, 0];\n const ml = (this.querySelector('.axis.y')?.getBoundingClientRect().width || 0) + this.margin.left\n\n this.scaleX.range([ml, 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 + ml + 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}\" viewBox=\"0 0 ${width} ${height}\" xmlns=\"http://www.w3.org/2000/svg\">\n <g class=\"grid y\" transform=\"translate(${ml}, 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(${ml}, 0)\" />\n\n ${guard([this.lines, width, height, ml], () => svg`\n <path class=\"area\" d=\"${this.area(this.plotData)}\" />\n ${this.renderLineSegments('elevation')}`\n )}\n\n <g style=\"visibility: ${this.pointer.x > 0 ? 'visible' : 'hidden'}\">\n <g clip-path=\"polygon(0 0, ${this.pointer.x - ml} 0, ${this.pointer.x - ml} 100%, 0 100%)\">\n ${guard([this.lines, width, height, ml], () => this.renderLineSegments('elevation highlight'))}\n </g>\n <line\n class=\"pointer-line x\"\n x1=\"${this.pointer.x}\"\n y1=\"${this.margin.top}\"\n x2=\"${this.pointer.x}\"\n y2=\"${height - this.margin.bottom}\"\n />\n <line\n class=\"pointer-line y\"\n x1=\"${ml}\"\n y1=\"${this.pointer.y}\"\n x2=\"${width - this.margin.right}\"\n y2=\"${this.pointer.y}\"\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(${ml},${height - this.margin.bottom + offset})\"\n class=\"axis\"\n style=\"visibility: ${this.lines.length ? 'visible' : 'hidden'}\">\n <line x2=\"${width - ml - this.margin.right}\"></line>\n </g>\n <g transform=\"translate(0,${height - this.margin.bottom + offset})\">\n ${this.renderTrailBands()}\n </g>\n </svg>\n `;\n }\n\n private renderLineSegments(className: string) {\n return this.lineSegmentsData.map(([start, end, value]) => {\n const segmentData = this.plotData.slice(start, end);\n return svg`<path class=\"${className}\" data-value=\"${ifDefined(value)}\" d=\"${this.line(segmentData)}\" fill=\"none\" />`;\n });\n }\n\n private renderTrailBands() {\n return this.xAxisSegmentsData.map(([start, end, value]) => {\n const x1 = this.scaleX(this.plotData[start].x);\n const x2 = this.scaleX(this.plotData[end - 1].x);\n const bandWidth = x2 - x1;\n return svg`<rect class=\"trail-band\" data-value=\"${ifDefined(value)}\" x=\"${x1}\" width=\"${bandWidth}\" />`;\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 tickValues(values: number[], axis: 'x' | 'y') {\n if (values.length === 0 || (axis !== 'x' && axis !== 'y')) {\n return;\n }\n axis === 'x' ? this.xAxis.tickValues(values) : this.yAxis.tickValues(values);\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 const axisY = this.querySelector('.axis.y');\n if (axisY) {\n this.yAxisObserver = new ResizeObserver(() => {\n this.requestUpdate()\n })\n this.yAxisObserver.observe(axisY);\n }\n // FIXME: because the ref element are used before render is done, we need to force an update\n this.requestUpdate();\n }\n\n override disconnectedCallback() {\n if (this.yAxisObserver) {\n this.yAxisObserver.disconnect();\n }\n super.disconnectedCallback();\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 const segments: OverDetails['segments'] = {\n line: getSegmentValueAtIndex(this.lineSegmentsData, index),\n xAxis: getSegmentValueAtIndex(this.xAxisSegmentsData, index),\n };\n\n this.dispatchEvent(\n new CustomEvent<OverDetails>('over', {\n detail: {\n coordinate: this.plotData[index].coordinate,\n position: this.pointer,\n ...(Object.keys(segments).length > 0 && { segments })\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\nfunction fillUnspecified(segment: SegmentData, length: number): SegmentData {\n const filledSegments: SegmentData = [];\n let currentIndex = 0;\n\n for (const [start, end, value] of segment) {\n if (start > currentIndex) {\n filledSegments.push([currentIndex, start, null]);\n }\n filledSegments.push([start, end, value]);\n currentIndex = end;\n }\n\n if (currentIndex < length) {\n filledSegments.push([currentIndex, length, null]);\n }\n\n return filledSegments;\n}\n\nfunction getSegmentValueAtIndex(segments: SegmentData, index: number): string | null {\n for (const [start, end, value] of segments) {\n if (index >= start && index < end) {\n return value;\n }\n }\n // we must never be here because of fillUnspecified\n return null;\n}\n\nfunction remapSegments(segments: SegmentData, indexMap: Map<number, number>): SegmentData {\n const remappedSegments: SegmentData = [];\n \n for (const [start, end, value] of segments) {\n // Find the first and last simplified indices that correspond to original indices in [start, end)\n let newStart = -1;\n let newEnd = -1;\n \n // end is exclusive, so iterate from start to end-1\n for (let i = start; i < end; i++) {\n const simplifiedIdx = indexMap.get(i);\n if (simplifiedIdx !== undefined && simplifiedIdx >= 0) {\n if (newStart === -1) {\n newStart = simplifiedIdx;\n }\n newEnd = simplifiedIdx;\n }\n }\n \n // Only add the segment if we found at least one point that survived simplification\n // newEnd + 1 because we want the new end to be exclusive as well\n if (newStart >= 0 && newEnd >= 0) {\n remappedSegments.push([newStart, newEnd + 1, value]);\n }\n }\n \n return remappedSegments;\n}\n\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'elevation-profile': ElevationProfile;\n }\n}\n","/*\n (c) 2017, Vladimir Agafonkin\n Simplify.js, a high-performance JS polyline simplification library\n mourner.github.io/simplify-js\n*/\n\n// to suit your point format, run search/replace for '.x' and '.y';\n// for 3D version, see 3d branch (configurability would draw significant performance overhead)\n\n// square distance between 2 points\nfunction getSqDist(p1, p2) {\n var dx = p1.x - p2.x,\n dy = p1.y - p2.y;\n\n return dx * dx + dy * dy;\n}\n\n// square distance from a point to a segment\nfunction getSqSegDist(p, p1, p2) {\n var x = p1.x,\n y = p1.y,\n dx = p2.x - x,\n dy = p2.y - y;\n\n if (dx !== 0 || dy !== 0) {\n var t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);\n\n if (t > 1) {\n x = p2.x;\n y = p2.y;\n } else if (t > 0) {\n x += dx * t;\n y += dy * t;\n }\n }\n\n dx = p.x - x;\n dy = p.y - y;\n\n return dx * dx + dy * dy;\n}\n// rest of the code doesn't care about point format\n\n// basic distance-based simplification\nfunction simplifyRadialDist(points, sqTolerance) {\n var prevPoint = points[0],\n newPoints = [prevPoint],\n point;\n\n for (var i = 1, len = points.length; i < len; i++) {\n point = points[i];\n\n if (getSqDist(point, prevPoint) > sqTolerance) {\n newPoints.push(point);\n prevPoint = point;\n }\n }\n\n if (prevPoint !== point) newPoints.push(point);\n\n return newPoints;\n}\n\nfunction simplifyDPStep(points, first, last, sqTolerance, simplified) {\n var maxSqDist = sqTolerance,\n index;\n\n for (var i = first + 1; i < last; i++) {\n var sqDist = getSqSegDist(points[i], points[first], points[last]);\n\n if (sqDist > maxSqDist) {\n index = i;\n maxSqDist = sqDist;\n }\n }\n\n if (maxSqDist > sqTolerance) {\n if (index - first > 1)\n simplifyDPStep(points, first, index, sqTolerance, simplified);\n simplified.push(points[index]);\n if (last - index > 1)\n simplifyDPStep(points, index, last, sqTolerance, simplified);\n }\n}\n\n// simplification using Ramer-Douglas-Peucker algorithm\nfunction simplifyDouglasPeucker(points, sqTolerance) {\n var last = points.length - 1;\n\n var simplified = [points[0]];\n simplifyDPStep(points, 0, last, sqTolerance, simplified);\n simplified.push(points[last]);\n\n return simplified;\n}\n\n// both algorithms combined for awesome performance\nexport default function simplify(points, tolerance, highestQuality) {\n if (points.length <= 2) return points;\n\n var sqTolerance = tolerance !== undefined ? tolerance * tolerance : 1;\n\n points = highestQuality ? points : simplifyRadialDist(points, sqTolerance);\n points = simplifyDouglasPeucker(points, sqTolerance);\n\n return points;\n}\n"],"names":[],"version":3,"file":"elevation-profile.js.map"}
@@ -368,13 +368,14 @@ function getSegmentValueAtIndex(segments: SegmentData, index: number): string |
368
368
 
369
369
  function remapSegments(segments: SegmentData, indexMap: Map<number, number>): SegmentData {
370
370
  const remappedSegments: SegmentData = [];
371
-
371
+
372
372
  for (const [start, end, value] of segments) {
373
- // Find the first simplified index that corresponds to an original index >= start
373
+ // Find the first and last simplified indices that correspond to original indices in [start, end)
374
374
  let newStart = -1;
375
375
  let newEnd = -1;
376
-
377
- for (let i = start; i <= end; i++) {
376
+
377
+ // end is exclusive, so iterate from start to end-1
378
+ for (let i = start; i < end; i++) {
378
379
  const simplifiedIdx = indexMap.get(i);
379
380
  if (simplifiedIdx !== undefined && simplifiedIdx >= 0) {
380
381
  if (newStart === -1) {
@@ -383,13 +384,14 @@ function remapSegments(segments: SegmentData, indexMap: Map<number, number>): Se
383
384
  newEnd = simplifiedIdx;
384
385
  }
385
386
  }
386
-
387
+
387
388
  // Only add the segment if we found at least one point that survived simplification
389
+ // newEnd + 1 because we want the new end to be exclusive as well
388
390
  if (newStart >= 0 && newEnd >= 0) {
389
391
  remappedSegments.push([newStart, newEnd + 1, value]);
390
392
  }
391
393
  }
392
-
394
+
393
395
  return remappedSegments;
394
396
  }
395
397
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geoblocks/elevation-profile",
3
- "version": "0.0.25-beta.2",
3
+ "version": "0.0.25-beta.3",
4
4
  "license": "BSD-3-Clause",
5
5
  "repository": "github:geoblocks/elevation-profile",
6
6
  "type": "module",