final pan fix

This commit is contained in:
Chris Amow 2026-08-16 23:25:36 -05:00
parent dfe5224e35
commit fc09da7053
3 changed files with 64 additions and 10 deletions

View file

@ -1106,6 +1106,12 @@ that object replaced the whole option, so `pressedMouseMove` and
`axisPressedMouseMove` never returned. Desktop vertical click-drag died
after any tool use. Restore the full mouse-on, touch-off set.
LWC reads `axisPressedMouseMove.price`, not a boolean. Passing `true`
made `.price` undefined and axis/price drag stayed dead. Use
`{ time: true, price: true }`. Pane vertical drag is also a no-op while
the scale is still auto; a mostly-vertical mouse drag now sets
`manualPriceRange` the same way two-finger pan does.
### 2026-08-16 — the rest of the same session, none of it subtle
Written because they were skipped the first time and then asked for.

View file

@ -234,7 +234,7 @@ createApp({
const dataUpdatedAt = computed(() => {
if (dataReceivedAt.value == null) return '—';
return new Intl.DateTimeFormat(undefined, {
hour: 'numeric', minute: '2-digit', second: '2-digit',
hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit',
}).format(new Date(dataReceivedAt.value));
});
const build = ref({ commit: '', startedAt: '' });
@ -244,7 +244,7 @@ createApp({
const at = new Date(build.value.startedAt);
if (Number.isNaN(at.getTime())) return commit;
return `${commit} ${new Intl.DateTimeFormat(undefined, {
day: 'numeric', month: 'short', hour: 'numeric', minute: '2-digit',
day: 'numeric', month: 'short', hour12: false, hour: '2-digit', minute: '2-digit',
}).format(at)}`;
});
const quoteChange = computed(() => {
@ -302,7 +302,7 @@ createApp({
function addEvent(message, kind = 'info', url = null, number = null) {
events.value = [
{ key: ++eventSequence, at: new Date().toLocaleTimeString(), message, kind, url, number },
{ key: ++eventSequence, at: new Date().toLocaleTimeString(undefined, { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' }), message, kind, url, number },
...events.value,
].slice(0, 20);
}

View file

@ -192,8 +192,8 @@ class ConfluenceChart {
handleScale: {
mouseWheel: true,
pinch: false,
axisPressedMouseMove: true,
axisDoubleClickReset: true,
axisPressedMouseMove: { time: true, price: true },
axisDoubleClickReset: { time: true, price: true },
},
handleScroll: {
mouseWheel: true,
@ -751,6 +751,7 @@ class ConfluenceChart {
const touch = event.touches[0];
if (Math.hypot(touch.clientX - this.touchTap.x, touch.clientY - this.touchTap.y) > 10) {
this.touchTap = null;
this.mousePan = null;
}
}
if (!this.touchTwo || event.touches.length !== 2) return;
@ -1245,8 +1246,8 @@ class ConfluenceChart {
handleScale: tool ? false : {
mouseWheel: true,
pinch: false,
axisPressedMouseMove: true,
axisDoubleClickReset: true,
axisPressedMouseMove: { time: true, price: true },
axisDoubleClickReset: { time: true, price: true },
},
});
this.hideSnapDot();
@ -1372,9 +1373,13 @@ class ConfluenceChart {
}
startToolGesture(event) {
if (!this.armedTool || event.button !== 0) return;
if (event.button !== 0) return;
const point = this.eventPoint(event);
if (!point) return;
if (!this.armedTool) {
if (this.withinPlot(point)) this.mousePan = { start: point };
return;
}
event.preventDefault();
this.gesture = { start: point, end: point };
this.chartEl.setPointerCapture?.(event.pointerId);
@ -1382,7 +1387,10 @@ class ConfluenceChart {
}
moveToolGesture(event) {
if (!this.armedTool) return;
if (!this.armedTool) {
this.moveMousePan(event);
return;
}
const point = this.eventPoint(event);
if (!point) return;
// The listener is on window, so it fires over the sidebar and the price
@ -1497,7 +1505,47 @@ class ConfluenceChart {
if (a.t != null && b.t != null) this.setLinePreview(a, b, '#65b7cf', 2);
}
moveMousePan(event) {
if (!this.mousePan) return;
const point = this.eventPoint(event);
if (!point) return;
const gesture = this.mousePan;
if (gesture.minValue == null) {
const dx = point.x - gesture.start.x;
const dy = point.y - gesture.start.y;
if (Math.hypot(dx, dy) < 8) return;
if (Math.abs(dy) <= Math.abs(dx)) {
this.mousePan = null;
return;
}
const plot = this.plotCanvas()?.getBoundingClientRect();
if (!plot) {
this.mousePan = null;
return;
}
const margins = this.chart.priceScale('right').options().scaleMargins;
const top = this.candles.coordinateToPrice(plot.height * margins.top);
const bottom = this.candles.coordinateToPrice(plot.height * (1 - margins.bottom));
if (top == null || bottom == null) {
this.mousePan = null;
return;
}
gesture.minValue = Math.min(top, bottom);
gesture.maxValue = Math.max(top, bottom);
gesture.pricePerPx = (gesture.maxValue - gesture.minValue)
/ Math.max(plot.height * (1 - margins.top - margins.bottom), 1);
}
const dPrice = (point.y - gesture.start.y) * gesture.pricePerPx;
this.manualPriceRange = {
minValue: gesture.minValue + dPrice,
maxValue: gesture.maxValue + dPrice,
};
this.candles.applyOptions({ autoscaleInfoProvider: this.candleAutoscaleProvider });
this.updateCurrentPrice(this.lastCurrentPrice);
}
finishToolGesture(event) {
this.mousePan = null;
if (!this.armedTool || !this.gesture) return;
const tool = this.armedTool;
const { start, end } = this.gesture;