правки по графикам
Gitea Actions Demo / build_and_push (push) Failing after 23s
Details
Gitea Actions Demo / build_and_push (push) Failing after 23s
Details
This commit is contained in:
parent
43354ecaed
commit
2cfd863dbf
|
|
@ -50,14 +50,31 @@ export class ChartGroup {
|
||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Event position must be the real pixel coordinates of the data
|
||||||
|
// point: with a fake (0, 0) position the tooltip box on receiver
|
||||||
|
// charts is positioned from the corner and flips/clamps near the
|
||||||
|
// chart edges, so the hover line lagged and got stuck at borders.
|
||||||
|
const el = chart.getDatasetMeta(0).data[dataIndex] as
|
||||||
|
{ x?: number; y?: number } | undefined;
|
||||||
|
const px = el?.x;
|
||||||
|
const py = el?.y;
|
||||||
|
const pos =
|
||||||
|
px !== undefined &&
|
||||||
|
py !== undefined &&
|
||||||
|
Number.isFinite(px) &&
|
||||||
|
Number.isFinite(py)
|
||||||
|
? { x: px, y: py }
|
||||||
|
: { x: 0, y: 0 };
|
||||||
chart.tooltip.setActiveElements(
|
chart.tooltip.setActiveElements(
|
||||||
[{ datasetIndex: 0, index: dataIndex }],
|
[{ datasetIndex: 0, index: dataIndex }],
|
||||||
{
|
pos,
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
chart.draw();
|
// update("none") = full recompute + render without animations; the
|
||||||
|
// animator does not start, so tooltip.opacity/position apply
|
||||||
|
// synchronously and the blue line is visible on "cold" charts
|
||||||
|
// immediately (with chart.draw() the opacity stayed 0 until the
|
||||||
|
// first animation tick).
|
||||||
|
chart.update("none");
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this.hovering = false;
|
this.hovering = false;
|
||||||
|
|
@ -81,7 +98,9 @@ export class ChartGroup {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
chart.tooltip.setActiveElements([], { x: 0, y: 0 });
|
chart.tooltip.setActiveElements([], { x: 0, y: 0 });
|
||||||
chart.draw();
|
// Same as in setHover: opacity -> 0 must apply synchronously,
|
||||||
|
// otherwise the lines would linger until the animator starts.
|
||||||
|
chart.update("none");
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this.hovering = false;
|
this.hovering = false;
|
||||||
|
|
|
||||||
|
|
@ -119,8 +119,8 @@ export const GetWorkout = (url: string) => {
|
||||||
yAxisID: "logAxis",
|
yAxisID: "logAxis",
|
||||||
radius: 0,
|
radius: 0,
|
||||||
label: "Мощность",
|
label: "Мощность",
|
||||||
borderColor: "#cccccc",
|
borderColor: "#00bcd4",
|
||||||
backgroundColor: "#cccccc",
|
backgroundColor: "#00bcd4",
|
||||||
data: power,
|
data: power,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ import { Ref } from "vue";
|
||||||
import { createTypedChart } from "vue-chartjs";
|
import { createTypedChart } from "vue-chartjs";
|
||||||
import { LineController } from "chart.js";
|
import { LineController } from "chart.js";
|
||||||
|
|
||||||
const lineAlign = 8;
|
|
||||||
|
|
||||||
type GetMapPlugin = {
|
type GetMapPlugin = {
|
||||||
mapX: Ref<Array<number>>;
|
mapX: Ref<Array<number>>;
|
||||||
};
|
};
|
||||||
|
|
@ -55,13 +53,19 @@ class LineWithLineController extends LineController {
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
// Draw the vertical hover line at the pixel X of the active tooltip
|
||||||
|
// element (the data point itself), not at the tooltip box position:
|
||||||
|
// the box has a fixed size and flips/clamps near the chart edges, so
|
||||||
|
// using tooltip.x would lag and get stuck at the borders.
|
||||||
if (this.chart?.tooltip && this.chart.tooltip.opacity > 0) {
|
if (this.chart?.tooltip && this.chart.tooltip.opacity > 0) {
|
||||||
let x = this.chart.tooltip.x - lineAlign;
|
const active = this.chart.tooltip.getActiveElements();
|
||||||
if (this.chart.tooltip.xAlign === "right") {
|
const point = active[0]
|
||||||
x = this.chart.tooltip.x + this.chart.tooltip.width + lineAlign;
|
? (this.chart.getDatasetMeta(active[0].datasetIndex).data[
|
||||||
}
|
active[0].index
|
||||||
|
] as { x?: number } | undefined)
|
||||||
// draw line
|
: undefined;
|
||||||
|
const x = point?.x ?? NaN;
|
||||||
|
if (Number.isFinite(x)) {
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(x, topY);
|
ctx.moveTo(x, topY);
|
||||||
|
|
@ -73,6 +77,7 @@ class LineWithLineController extends LineController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const LineWithLineChart = createTypedChart(
|
const LineWithLineChart = createTypedChart(
|
||||||
"line-with-line" as "line",
|
"line-with-line" as "line",
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,15 @@
|
||||||
{{ Math.floor(workoutItem.power) }} Вт
|
{{ Math.floor(workoutItem.power) }} Вт
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="workout-item-params"
|
||||||
|
v-if="workoutItem.power && workoutNP !== null"
|
||||||
|
>
|
||||||
|
<div class="workout-item-params-name">Нормализованная мощность:</div>
|
||||||
|
<div class="workout-item-params-value">
|
||||||
|
{{ Math.floor(workoutNP) }} Вт
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="workout-item-params" v-if="workoutItem.max_power">
|
<div class="workout-item-params" v-if="workoutItem.max_power">
|
||||||
<div class="workout-item-params-name">Максимальная мощность:</div>
|
<div class="workout-item-params-name">Максимальная мощность:</div>
|
||||||
<div class="workout-item-params-value">
|
<div class="workout-item-params-value">
|
||||||
|
|
@ -311,6 +320,7 @@ import {
|
||||||
|
|
||||||
import LineWithLineChart from "./LineWithLineChart.js";
|
import LineWithLineChart from "./LineWithLineChart.js";
|
||||||
import ChartGroup from "./ChartGroup.js";
|
import ChartGroup from "./ChartGroup.js";
|
||||||
|
import { normalizedPower } from "./NormalizedPower.js";
|
||||||
import {
|
import {
|
||||||
PowerZonesPlugin,
|
PowerZonesPlugin,
|
||||||
ftpToZones,
|
ftpToZones,
|
||||||
|
|
@ -440,6 +450,13 @@ const computeAreaData = (start: number, end: number) => {
|
||||||
Math.floor(sum / present.length).toString() +
|
Math.floor(sum / present.length).toString() +
|
||||||
getUnit(config.data.datasets[0].label);
|
getUnit(config.data.datasets[0].label);
|
||||||
}
|
}
|
||||||
|
if (data.power?.datasets[0].data && end - start >= 2) {
|
||||||
|
const np = normalizedPower(times, data.power.datasets[0].data, start, end);
|
||||||
|
if (np !== null) {
|
||||||
|
avgData["Нормализованная мощность"] =
|
||||||
|
Math.floor(np).toString() + getUnit("Мощность");
|
||||||
|
}
|
||||||
|
}
|
||||||
areaAvgData.value = avgData;
|
areaAvgData.value = avgData;
|
||||||
};
|
};
|
||||||
/** Splits the points into sections: 10-minute steps in time mode, 5-km steps in distance mode. */
|
/** Splits the points into sections: 10-minute steps in time mode, 5-km steps in distance mode. */
|
||||||
|
|
@ -889,6 +906,11 @@ const times: Array<string | number> =
|
||||||
data.power?.labels ??
|
data.power?.labels ??
|
||||||
data.elevation?.labels ??
|
data.elevation?.labels ??
|
||||||
[];
|
[];
|
||||||
|
// Normalized power for the whole workout (data is static after load, so a
|
||||||
|
// plain computed is memoized automatically).
|
||||||
|
const workoutNP = computed<number | null>(() =>
|
||||||
|
normalizedPower(times, data.power?.datasets[0].data ?? [], 0, times.length),
|
||||||
|
);
|
||||||
// Rebuilt per x-axis mode: labels switch between times and distances and
|
// Rebuilt per x-axis mode: labels switch between times and distances and
|
||||||
// options get a fresh x-scale, so every canvas must remount on mode change.
|
// options get a fresh x-scale, so every canvas must remount on mode change.
|
||||||
const chartConfigs = computed<Array<ChartConfig>>(() => {
|
const chartConfigs = computed<Array<ChartConfig>>(() => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue