Files
road-compiler/workbench/client/probe/ol-ext-transform/ol-ext.d.ts
que01 bc4b9a9717 feat: add direct edit handles behind directEdit flag
Steps 1-3 of the main map road interval editor.

EditSession keeps the command stack, undo/redo and previewSeq arbitration as
pure logic with no OpenLayers reference, so all of it is unit-tested in node.
Pointer displacement converts to meters through EPSG:4326 and spherical
distance: treating a 3857 delta as meters desyncs the geometry from the cursor
by 1/cos(latitude). Handle drags project onto the axis the manifest declares
and clamp to its range, so the client never writes a coordinate into a road
polygon.

All of it sits behind a directEdit flag that defaults to off. With the flag off
the workbench requests no manifest, creates no extra source and registers no
interaction, so behaviour matches main.

The ol-ext probe passed its three gates but is not adopted for road handles.
Transform translates by the raw pointer delta, so a handle detaches from its
clamped constraint value: a drag reading -24.1 m produced a draft of -5.4 m.
Production needs the handle position derived from the constraint instead, which
means owning the position update, so native OL PointerInteraction will carry
the drag. ol-ext stays out of package.json; the probe is kept as a manual
harness. Reserve handles are unreachable with the current solver, recorded in
research/ rather than worked around.

Also names the dead backend when an API response is empty, instead of
surfacing "Unexpected end of JSON input" from response.json().

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 14:59:11 +08:00

58 lines
2.1 KiB
TypeScript

// ol-ext 4.0.38 ships no TypeScript declarations and there is no @types/ol-ext.
// This local declaration covers only what the probe touches. It deliberately
// lives inside the probe directory: if the gate fails, deleting the directory
// removes the typing debt with it. Promoting ol-ext to a real dependency would
// also mean owning a real declaration file.
declare module 'ol-ext/interaction/Transform' {
import type Feature from 'ol/Feature';
import type Collection from 'ol/Collection';
import type BaseLayer from 'ol/layer/Base';
import PointerInteraction from 'ol/interaction/Pointer';
interface TransformOptions {
layers?: BaseLayer[] | BaseLayer;
features?: Collection<Feature>;
filter?: (feature: Feature, layer: BaseLayer) => boolean;
hitTolerance?: number;
translate?: boolean;
translateFeature?: boolean;
translateBBox?: boolean;
stretch?: boolean;
scale?: boolean;
rotate?: boolean;
selection?: boolean;
pointRadius?: number | number[] | ((feature: Feature) => number | number[]);
style?: unknown;
}
/** Events: select, translatestart | translating | translateend, scale*, rotate*. */
export interface TransformEvent {
type: string;
feature?: Feature;
features?: Collection<Feature>;
/** `translating` only: [deltaX, deltaY] in map units (EPSG:3857 here). */
delta?: [number, number];
coordinate?: [number, number];
pixel?: [number, number];
/** `*end` only. */
transformed?: boolean;
}
/**
* ol-ext's custom event names are not in OpenLayers' event-type unions, so
* overriding `on` / `un` on the class would clash with `Interaction` and break
* `map.addInteraction()`. Consumers narrow through this interface instead —
* one documented conversion rather than a cast at every listener.
*/
export interface TransformEvents {
on(type: string, listener: (event: TransformEvent) => void): void;
un(type: string, listener: (event: TransformEvent) => void): void;
}
export default class Transform extends PointerInteraction {
constructor(options?: TransformOptions);
select(feature: Feature | null, add?: boolean): void;
}
}