Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 82 additions & 21 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
.PHONY: lint typecheck build docs verify test test-update dev clean
.PHONY: install lint typecheck build build-all docs verify test test-update test-ui test-codegen dev map db plot compute clean publish

CONCURRENTLY := npx concurrently
RIMRAF := npx rimraf
RIMRAF := rm -rf

APP ?= gallery
TEST ?= tests/gallery/autk-map/colormap-categorical.test.ts
UPDATE ?= cache images

LIB_PACKAGES := autk-map autk-db autk-plot autk-compute autk-provenance
DOC_PACKAGES := $(LIB_PACKAGES)

lint:
npm run lint

typecheck: build

install:
npm install

typecheck:
$(CONCURRENTLY) \
"cd autk-core && npx tsc --noEmit --skipLibCheck" \
"cd autk-map && npx tsc --noEmit --skipLibCheck" \
"cd autk-db && npx tsc --noEmit --skipLibCheck" \
"cd autk-plot && npx tsc --noEmit --skipLibCheck" \
"cd autk-compute && npx tsc --noEmit --skipLibCheck" \
"cd autk && npx tsc --noEmit --skipLibCheck" \
"cd autk-provenance && npx tsc --noEmit --skipLibCheck" \
"cd gallery && npx tsc --noEmit --skipLibCheck" \
"cd usecases && npx tsc --noEmit --skipLibCheck"

Expand All @@ -27,48 +32,104 @@ build:
"cd autk-db && npm run build" \
"cd autk-plot && npm run build" \
"cd autk-compute && npm run build"
cd autk && npm run build
cd autk-provenance && npm run build

build-all:
$(CONCURRENTLY) \
"cd autk-map && npm run build" \
"cd autk-db && npm run build" \
"cd autk-plot && npm run build" \
"cd autk-compute && npm run build"
cd autk-provenance && npm run build

docs:
$(CONCURRENTLY) \
"cd autk-map && npm run doc" \
"cd autk-db && npm run doc" \
"cd autk-plot && npm run doc" \
"cd autk-provenance && npm run doc" \
"cd autk-compute && npm run doc"

verify: lint typecheck
verify: lint typecheck build-all docs

ifdef OPEN
TEST_TARGET = tests/$(APP)/$(shell echo '$(OPEN)' | sed 's|^/||' | sed 's|^src/||' | sed 's|/$$||' | sed 's|\.[^./]*$$||')
else
TEST_TARGET = tests/$(APP)
endif

CODEGEN_TARGET = src/$(shell echo '$(OPEN)' | sed 's|^/||' | sed 's|^src/||' | sed 's|/$$||' | sed 's|\.[^./]*$$||')

test:
APP=$(APP) npx playwright test $(TEST)
APP=$(APP) OPEN=$(OPEN) npx playwright test $(if $(OPEN),$(TEST_TARGET).test.ts,$(TEST_TARGET))

# make test-update → update both cache (HAR) and images (snapshots)
# make test-update cache → update HAR files only
# make test-update images → update snapshots only
# make test-update cache images → update both explicitly
_CACHE := $(filter cache,$(MAKECMDGOALS))
_IMAGES := $(filter images,$(MAKECMDGOALS))
_BOTH := $(if $(or $(_CACHE),$(_IMAGES)),,1)

# Update committed test baselines locally.
# Examples:
# make test-update TEST=tests/gallery/autk-map/colormap-categorical.test.ts UPDATE=images
# make test-update TEST=tests/gallery/autk-map/osm-layers-api.test.ts UPDATE="cache images"
test-update:
APP=$(APP) \
$(if $(findstring cache,$(UPDATE)),HAR_UPDATE=1) \
npx playwright test $(TEST) \
$(if $(findstring images,$(UPDATE)),--update-snapshots)
APP=$(APP) OPEN=$(OPEN) \
$(if $(or $(_CACHE),$(_BOTH)),HAR_UPDATE=1) \
npx playwright test $(if $(OPEN),$(TEST_TARGET).test.ts,$(TEST_TARGET)) \
$(if $(or $(_IMAGES),$(_BOTH)),--update-snapshots)

cache images:
@true

test-ui:
APP=$(APP) OPEN=$(OPEN) npx playwright test --ui $(if $(OPEN),$(TEST_TARGET).test.ts,$(TEST_TARGET))

test-codegen:
node playwright.codegen.mjs http://localhost:5173$(OPEN) $(if $(OPEN),$(TEST_TARGET).test.ts)


dev:
npm install
make install
make build
$(CONCURRENTLY) \
ulimit -n 65536; $(CONCURRENTLY) \
"cd autk-map && npm run dev-build" \
"cd autk-db && npm run dev-build" \
"cd autk-plot && npm run dev-build" \
"cd autk-compute && npm run dev-build" \
"cd autk && npm run dev-build" \
"cd autk-provenance && npm run dev-build" \
"cd $(APP) && VITE_OPEN=\"$(OPEN)\" npm run dev"

map:
cd autk-map && npm run build

db:
cd autk-db && npm run build

plot:
cd autk-plot && npm run build

compute:
cd autk-compute && npm run build


clean:
$(RIMRAF) node_modules
$(CONCURRENTLY) \
"cd autk-map && $(RIMRAF) dist build" \
"cd autk-db && $(RIMRAF) dist build" \
"cd autk-plot && $(RIMRAF) dist build" \
"cd autk-compute && $(RIMRAF) dist build" \
"cd autk && $(RIMRAF) dist build" \
"cd autk-provenance && $(RIMRAF) dist build" \
"cd gallery && $(RIMRAF) dist build" \
"cd usecases && $(RIMRAF) dist build"

publish:
@if [ -z "$(LIB)" ]; then \
echo "Error: Please specify a library to publish using LIB=<library>"; \
echo "Usage: make publish LIB=autk-map|autk-db|autk-plot|autk-compute"; \
exit 1; \
fi
@if [ "$(LIB)" != "autk-map" ] && [ "$(LIB)" != "autk-db" ] && [ "$(LIB)" != "autk-plot" ] && [ "$(LIB)" != "autk-compute" ]; then \
echo "Error: LIB must be one of: autk-map, autk-db, autk-plot, autk-compute"; \
exit 1; \
fi
cd $(LIB) && npm pack && npm publish *.tgz
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ Autark is available as an umbrella package plus individual modules:
* `autk-map`: A map visualization library that allows the exploration of 2D and 3D physical and thematical layers.
* `autk-plot`: A d3.js based plot library designed to consume urban data in standard formats and create linked views.

## Provenance Module

Autark also includes a provenance module (`autk-provenance`) for recording and replaying user analysis history across map, plot, and database interactions.

For detailed provenance startup, verification, and testing instructions, see:

- `autk-provenance/README.md`

For demonstration purposes and to facilitate the adoption of Autark, we created a large collection of simple examples illustrating the core functionalities of each module. We also provide several examples on how to combine several modules to build complex applications. All examples are organized in the `example/` directory.

## Installation
Expand Down
8 changes: 4 additions & 4 deletions autk-compute/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
}
},
"scripts": {
"dev": "vite",
"dev-build": "tsc && vite build --watch",
"build": "tsc && vite build",
"preview": "vite preview",
"dev": "ulimit -n 65536 && vite",
"dev-build": "ulimit -n 65536 && tsc && vite build --watch",
"build": "ulimit -n 65536 && tsc && vite build",
"preview": "ulimit -n 65536 && vite preview",
"format": "prettier --write .",
"doc": "typedoc --options typedoc.json"
},
Expand Down
3 changes: 1 addition & 2 deletions autk-compute/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"types": ["@webgpu/types"]
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
}
14 changes: 14 additions & 0 deletions autk-core/src/camera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,20 @@ export class Camera {
return this.mViewMatrix;
}

/**
* Returns a serialisable snapshot of the current camera state.
*
* @returns Plain arrays for `up`, `lookAt`, and `eye`.
* @throws Never throws.
*/
public getCameraData(): CameraData {
return {
up: [this.wUp[0], this.wUp[1], this.wUp[2]],
eye: [this.wEye[0], this.wEye[1], this.wEye[2]],
lookAt: [this.wLookAt[0], this.wLookAt[1], this.wLookAt[2]],
};
}

/**
* Updates viewport size and recomputes matrices in one call.
*
Expand Down
8 changes: 4 additions & 4 deletions autk-db/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
}
},
"scripts": {
"dev": "vite",
"dev-build": "tsc && vite build --watch",
"build": "tsc && vite build",
"preview": "vite preview",
"dev": "ulimit -n 65536 && vite",
"dev-build": "ulimit -n 65536 && tsc && vite build --watch",
"build": "ulimit -n 65536 && tsc && vite build",
"preview": "ulimit -n 65536 && vite preview",
"format": "prettier --write .",
"doc": "typedoc --options typedoc.json"
},
Expand Down
8 changes: 4 additions & 4 deletions autk-map/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@
},
"scripts": {
"doc": "typedoc --options typedoc.json",
"dev": "vite",
"dev-build": "tsc && vite build --watch",
"build": "tsc && vite build",
"preview": "vite preview",
"dev": "ulimit -n 65536 && vite",
"dev-build": "ulimit -n 65536 && tsc && vite build --watch",
"build": "ulimit -n 65536 && tsc && vite build",
"preview": "ulimit -n 65536 && vite preview",
"format": "prettier --write ."
},
"devDependencies": {
Expand Down
3 changes: 3 additions & 0 deletions autk-map/src/events-mouse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ export class MouseEvents {
this._map.camera.translate(dx / cssWidth, dy / cssHeight);
}

this._map.notifyViewChange();

this._lastPoint = point;
}

Expand Down Expand Up @@ -216,6 +218,7 @@ export class MouseEvents {
const y = 1.0 - (event.clientY - rect.top) / this._map.renderer.cssHeight;

this._map.camera.zoom(event.deltaY * 0.01, x, y);
this._map.notifyViewChange();
}

/**
Expand Down
8 changes: 8 additions & 0 deletions autk-map/src/map-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,17 +543,25 @@ export class AutkMapUi {
const eyeBtn = this.makeIconButton(EYE_SVG, !layer.layerRenderInfo.isSkip, () => {
this.map.updateRenderInfo(layer.layerInfo.id, { renderInfo: { isSkip: !layer.layerRenderInfo.isSkip } });
});
eyeBtn.dataset.autkMapControl = 'visibility';
eyeBtn.dataset.layerId = layer.layerInfo.id;

const paletteBtn = this.makeIconButton(RAMP_SVG, layer.layerRenderInfo.isColorMap ?? false, () => {
this.map.updateRenderInfo(layer.layerInfo.id, { renderInfo: { isColorMap: !layer.layerRenderInfo.isColorMap } });
});
paletteBtn.dataset.autkMapControl = 'thematic';
paletteBtn.dataset.layerId = layer.layerInfo.id;

const isRaster = layer.layerInfo.typeLayer === 'raster';
const cursorBtn = isRaster
? (() => { const s = document.createElement('span'); s.style.width = '28px'; s.style.flexShrink = '0'; return s; })()
: this.makeIconButton(CURSOR_SVG, layer.layerRenderInfo.isPick ?? false, () => {
this.changeActiveLayer(this.map.layerManager.searchByLayerId(layer.layerInfo.id));
});
if (cursorBtn instanceof HTMLButtonElement) {
cursorBtn.dataset.autkMapControl = 'active-layer';
cursorBtn.dataset.layerId = layer.layerInfo.id;
}

const nameEl = document.createElement('span');
nameEl.textContent = layer.layerInfo.id;
Expand Down
53 changes: 53 additions & 0 deletions autk-map/src/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ import { PipelineBuildingSSAO } from './pipeline-triangle-ssao';

import { AutkMapUi } from './map-ui';

type ViewListener = (state: { eye: [number, number, number]; lookAt: [number, number, number]; up: [number, number, number] }) => void;

/**
* Main map controller for rendering, interaction, and layer lifecycle.
*
Expand Down Expand Up @@ -105,6 +107,8 @@ export class AutkMap {
protected _resizeEvents!: ResizeEvents;
/** Public event bus for map events. */
protected _mapEvents!: EventEmitter<MapEventRecord>;
/** Subscribers notified when the camera view changes due to interaction or replay. */
protected _viewListeners: Set<ViewListener> = new Set();

/** Map UI controller. */
protected _ui!: AutkMapUi;
Expand Down Expand Up @@ -166,6 +170,47 @@ export class AutkMap {
return this._mapEvents;
}

/**
* Registers a callback for camera view changes.
*
* @param callback Listener receiving a serialisable camera snapshot.
*/
addViewListener(callback: ViewListener): void {
this._viewListeners.add(callback);
}

/**
* Removes a previously registered camera view listener.
*
* @param callback Listener to remove.
*/
removeViewListener(callback: ViewListener): void {
this._viewListeners.delete(callback);
}

/**
* Returns the current serialisable camera state.
*/
getViewState(): { eye: [number, number, number]; lookAt: [number, number, number]; up: [number, number, number] } {
const state = this._camera.getCameraData();
return {
eye: [state.eye[0], state.eye[1], state.eye[2]],
lookAt: [state.lookAt[0], state.lookAt[1], state.lookAt[2]],
up: [state.up[0], state.up[1], state.up[2]],
};
}

/**
* Restores the camera to a serialised view state and notifies listeners.
*
* @param state View snapshot to restore.
*/
setViewState(state: { eye: [number, number, number]; lookAt: [number, number, number]; up: [number, number, number] }): void {
this._camera.resetCamera(state.up, state.lookAt, state.eye);
this._camera.update();
this.notifyViewChange();
}

/** Currently active pick-enabled layer, if any. */
get activePickingLayer(): Layer | null {
return this._layerManager.layers.find((layer) => layer.layerRenderInfo.isPick) ?? null;
Expand Down Expand Up @@ -197,6 +242,14 @@ export class AutkMap {
this._ui.buildUi();
}

/**
* Notifies registered listeners of the latest camera view.
*/
notifyViewChange(): void {
const snapshot = this.getViewState();
this._viewListeners.forEach((listener) => listener(snapshot));
}

/**
* Loads a GeoJSON feature collection as a map layer.
*
Expand Down
8 changes: 4 additions & 4 deletions autk-plot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
}
},
"scripts": {
"dev": "vite",
"dev-build": "tsc && vite build --watch",
"build": "tsc && vite build",
"preview": "vite preview",
"dev": "ulimit -n 65536 && vite",
"dev-build": "ulimit -n 65536 && tsc && vite build --watch",
"build": "ulimit -n 65536 && tsc && vite build",
"preview": "ulimit -n 65536 && vite preview",
"format": "prettier --write .",
"doc": "typedoc --options typedoc.json",
"doc:watch": "typedoc --options typedoc.json --watch"
Expand Down
5 changes: 5 additions & 0 deletions autk-plot/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,8 @@ export { PlotStyle } from './plot-style';

/** Shared data transformation engine and ready-to-use transform presets. */
export * from './transforms';

// ─── Individual plot classes ─────────────────────────────────────────────────

export { Scatterplot, Barchart, ParallelCoordinates, Linechart, TableVis, Heatmatrix } from './plots';
export { Histogram } from './plot-types/histogram';
Loading