strava-frontend/src/pages/workouts/components/LineWithLineChart.ts

83 lines
2.2 KiB
TypeScript

import { Ref } from "vue";
import { createTypedChart } from "vue-chartjs";
import { LineController } from "chart.js";
const lineAlign = 8;
type GetMapPlugin = {
mapX: Ref<Array<number>>;
};
class LineWithLineController extends LineController {
static override id = "line-with-line";
private getMapX(): Array<number> {
if (!this.chart.config.plugins) {
return [];
}
if (this.chart.isZoomedOrPanned()) {
return [];
}
for (const i in this.chart.config.plugins) {
if (this.chart.config.plugins[i].id != "yandexMapLine") {
continue;
}
// @ts-expect-error — chart.js plugin config is loosely typed; cast via known shape
const pluginProps: GetMapPlugin = this.chart.config.plugins[i];
return pluginProps.mapX.value;
}
return [];
}
public override draw() {
super.draw();
const ctx = this.chart.ctx;
const topY = this.chart.scales.linearAxis.top;
const bottomY = this.chart.scales.linearAxis.bottom;
const xVertical = this.getMapX();
// The X axis is a time scale with irregular intervals (pauses), so the
// pixel position must come from Chart.js itself, not from index * zoom.
const meta = this.chart.getDatasetMeta(0);
for (const i in xVertical) {
const idx = Number(xVertical[i]);
const point = meta.data[idx] as { x?: number } | undefined;
const x = point?.x ?? NaN;
if (!Number.isFinite(x)) {
continue;
}
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = 3;
ctx.strokeStyle = "#666";
ctx.stroke();
ctx.restore();
}
if (this.chart?.tooltip && this.chart.tooltip.opacity > 0) {
let x = this.chart.tooltip.x - lineAlign;
if (this.chart.tooltip.xAlign === "right") {
x = this.chart.tooltip.x + this.chart.tooltip.width + lineAlign;
}
// draw line
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = 1;
ctx.strokeStyle = "#07C";
ctx.stroke();
ctx.restore();
}
}
}
const LineWithLineChart = createTypedChart(
"line-with-line" as "line",
LineWithLineController,
);
export default LineWithLineChart;