fix(map): stabilize tiled style rendering

This commit is contained in:
2026-07-17 15:12:10 +08:00
parent 59447a100c
commit 589cf45aa7
28 changed files with 3884 additions and 2461 deletions
@@ -0,0 +1,87 @@
jest.mock("ol/layer/WebGLVectorTile", () => ({
__esModule: true,
default: class WebGLVectorTileLayer {},
}));
import { LayerStyleController } from "./layerStyleController";
describe("LayerStyleController", () => {
it("rebuilds only when the structural signature changes", () => {
const layer = {
getSource: () => null,
updateStyleVariables: jest.fn(),
setStyle: jest.fn(),
} as any;
const controller = new LayerStyleController({
layer,
defaultStyle: { "stroke-color": "gray" },
});
const base = {
property: "pressure",
classCount: 5,
template: { "stroke-color": ["var", "tj_color_0"] } as any,
variables: { tj_color_0: "red" },
};
controller.applyNative(base);
controller.applyNative({ ...base, variables: { tj_color_0: "blue" } });
expect(layer.setStyle).toHaveBeenCalledTimes(1);
expect(layer.updateStyleVariables).toHaveBeenCalledTimes(2);
controller.applyNative({ ...base, classCount: 6 });
expect(layer.setStyle).toHaveBeenCalledTimes(2);
});
it("isolates primary and comparison values on a shared vector source", () => {
const properties: Record<string, unknown> = { id: "J-1" };
const feature = {
properties,
properties_: properties,
get: (key: string) => properties[key],
};
const listeners = new Set<(event: any) => void>();
const source = {
sourceTiles_: { loaded: { getFeatures: () => [feature] } },
on: (_type: string, listener: (event: any) => void) => listeners.add(listener),
un: (_type: string, listener: (event: any) => void) => listeners.delete(listener),
};
const createLayer = () => ({
getSource: () => source,
on: jest.fn(),
un: jest.fn(),
getOpacity: () => 1,
setOpacity: jest.fn(),
setStyle: jest.fn(),
updateStyleVariables: jest.fn(),
});
const primary = new LayerStyleController({
layer: createLayer() as any,
defaultStyle: { "circle-fill-color": "gray" },
stateNamespace: "primary",
});
const compare = new LayerStyleController({
layer: createLayer() as any,
defaultStyle: { "circle-fill-color": "gray" },
stateNamespace: "compare",
});
const options = {
property: "pressure",
classCount: 5,
template: { "circle-fill-color": ["get", "pressure"] } as any,
variables: {},
};
primary.applyRuntime(options, new Map([["J-1", 0.25]]));
compare.applyRuntime(options, new Map([["J-1", 0.75]]));
expect(properties.primary_pressure).toBe(0.25);
expect(properties.compare_pressure).toBe(0.75);
expect(listeners.size).toBe(2);
primary.dispose();
expect(listeners.size).toBe(1);
expect(properties.compare_pressure).toBe(0.75);
compare.dispose();
expect(listeners.size).toBe(0);
});
});