Skip to main content

Updating GeoJSON sources

For manual drawing and vertex editing on independent numeric layers, use the drawing and editing API, including sessions, snapping, tracing and undo/redo.

The shared facade follows addSource/getSource/removeSource/isSourceLoaded and source setData/updateData/getData. Lookup and updates are asynchronous for cross-thread hosts. Registration creates data only. Use GeoJSON circle/line/fill style layers for display; existing GIS source/layer calls stay compatible but are not interchangeable with this registry.

import { map } from 'sqsmap';
map.addSource('trees', {type:'geojson', data:{type:'FeatureCollection',features:[]}});
const trees = await map.getSource('trees');
await trees.setData({type:'Feature', id:'oak', properties:{height:12}, geometry:{type:'Point',coordinates:[116.4,39.9]}});
await trees.updateData({update:[{id:'oak',addOrUpdateProperties:[{key:'height',value:15}]}]});
const data = await trees.getData();
map.removeSource('trees');
await map.sqs.flush();

Handles bind a public id to a non-reused sourceInstanceId. Whole-data replacement advances the data revision without replacing that identity. Deletion and re-registration invalidate old handles with STALE_HANDLE. Updates preserve the camera/order, original GeoJSON and f64 coordinates. promoteId selects display/incremental identity without rewriting original data returned by getData. generateId supplies positional display IDs for whole-data replacement only.

Incremental updates require unique explicit IDs or promoteId. Numeric and string IDs differ. Removal, addition and feature changes apply in that order; adding an existing identity replaces its feature, while unknown removals/updates are ignored. Geometry and property changes are supported. Invalid updates preserve previous data and revision. Empty/null geometries are valid; empty bounds are null. Longitude/latitude are limited to ±180/±90; positions may include altitude.

Core/C/WASM SDK limits: 16 MiB JSON, 50,000 logical features and 500,000 positions per source; 128 sources, 64 MiB retained JSON and 128 MiB resident source data per map. Shared scripts also have a 4,096-node/32-level argument budget and 64 KiB host request/response limit. Native script queues retain their 64 KiB limit; use C/SDK for larger sources. HTTP(S) GeoJSON URLs and shared Point clustering are connected; image/video/canvas and shared raster tiles are connected; remaining vector types/DEM remain in progress. Inline GeoJSON circle/line/fill displays are connected.

Desktop/web hosts and retained native sessions forward source-count and GeoJSON loading events. Matched SDK/WASM is required. Shared Point clustering is verified by the same script on native/application QuickJS and browser main/strict Worker with actual rendering; see the clustering guide. These local software results do not replace Windows/macOS, hardware WebGPU or mobile device acceptance. The mobile application host remains pending and reports CAPABILITY_UNAVAILABLE.

API references: GeoJSONSource, source diff and feature diff. Only interface descriptions are referenced; SqsMap supplies its own implementation.

Attribute/ID duplication in collections is conservatively estimated before decoding; data below raw byte/count limits can still exceed the expansion budget. Resident data limits do not describe peak memory of the entire host process.

Source-change observers

Desktop, web and retained native scripts support sqs.sourceschange. Each successful registration, deletion or data update produces a sourceCount snapshot of registered sources. Data replacement may leave the count unchanged. Queries and failed writes produce no event. The event does not confirm display layers, downloads or rendering. sequence and mapInstanceId identify ordered events on one map. Session disposal removes observers. The mobile host is still pending.

import {map} from 'sqsmap';
export const sessionMode = 'persistent';
const subscription = map.on('sqs.sourceschange', event => console.log(event.sourceCount));
// subscription.unsubscribe();

The standalone browser SDK offers view.onSourcesChange(listener) and view.on('sources', listener), returning an unsubscribe function. Snapshots are immutable; limits are 32 observers and 128 pending discrete changes. A full queue rejects before writing. Observer exceptions are logged without undoing committed writes. SDK callbacks omit script-session target/sequence; the shared host adds them. Older npm SDKs without this observer are not advertised by map.sqs.events(). Native C events retain the full state; native JavaScript also provides the shared top-level sourceCount.

A command barrier does not wait for observer callbacks. To consume a particular notification, create map.once('sqs.sourceschange') before writing and await that promise before unsubscribing.

Live source batches

Shared live point sources use addSource with sqsLive: fields declares string/number/boolean values and allowDelta defaults to false. Initial data must be an empty FeatureCollection, without URL, promoteId or generateId. The source.sqs LiveSourceAPI provides:

source.sqs.applyLiveUpdate(frame: LiveUpdate): Promise<LiveUpdateResult>
source.sqs.getLiveState(): Promise<LiveSourceState>
source.sqs.freezeLiveSnapshot(): Promise<LiveSourceSnapshot>

The protocol uses decimal u128 sequence strings; replaying the last batch returns applied:false. Protocol, source, clusters and display commit atomically; failure keeps the last good data. sourcedata.sqsLive is immutable historical state. Manual setData/updateData conflict on live sources; stale handles report STALE_HANDLE and unconfigured sources report CAPABILITY_UNAVAILABLE. Batches allow 4096 points/8MiB; scripts have a separate 64KiB response limit. Editing an independent frozen copy does not alter the map. See live source batches for complete constraints, SDK liveSourceUpdates and native SQSM_MAP_LIVE_UPDATES. Batch ingestion, HTTP polling and WebSocket are connected; receiver scene ownership is connected by15.1; static scene resources/playback/tracks and mobile hosting remain pending.

HTTP live receivers

Shared sources support source.sqs.connectLive({protocol:'gis-live-v1',transport:{type:'http-poll',url,intervalMs:2000}}). It returns an identity-bound receiver; await getState/pause/resume/stop. getLiveReceiver returns undefined when absent. Intervals500..60000ms,8 active/paused receivers per map. pause/stop cancel in-flight I/O; stop retains data; old identities are STALE_HANDLE. Manual applyLiveUpdate conflicts while active/paused. Historical sqsLiveReceiver events omit URL/credentials. HTTP errors retain data and retry; replay completion emits sourcedata without a data revision change. The map/source owns the receiver after script exit. See bilingual live-http for budgets, C pumping, state/events and full HTML. WebSocket is connected separately; static scene resources/playback/tracks/mobile remain pending.

WebSocket live receivers

Shared source.sqs.connectLive also accepts transport:{type:"websocket",url,reconnectDelayMs:2000}. Snapshot-first reconnection, cancellation and bounded queues are documented in WebSocket live receivers. Eight receivers and8frames/16MiB waiting data per map; binary messages are rejected. Core/C resource channels add no network dependency. Scene/mobile and external-device acceptance continue separately.

Shared scenes and receiver ownership

Create a draft with map.sqs.scenes.create({id,name?}); get(id) returns a current handle or undefined and list() returns immutable small snapshots. A handle has id/sceneInstanceId and awaited getState/start/pause/resume/stop. remove(scene) stops owned receivers and releases the scene identity while preserving source data. connectLive accepts owner:scene; the bridge extracts its identity. Rebuilding an id or passing a foreign map identity yields STALE_HANDLE.

Draft scenes start no network I/O. Scene pause and manual receiver pause remain independent; scene resume does not restart manually paused/stopped receivers. receiver.resume under a non-running owner yields CONFLICT. Stop is terminal. Maps own scenes/connections after script exit. Observe sqs.scenechange with reason and immutable historical scene, and owner/ownerState on source events. Confirmed control does not mean data is ready.

await map.sqs.getCapabilities() exposes implemented capabilities: sceneLifecycle/sceneReceiverOwnership are true; sceneStaticResources is true; scenePlayback/sceneRoutePlayback/sceneLinePlayback/sceneTracks are true. Limits are16 scenes and8 active/paused receivers per map including drafts; output/events/control are bounded and failed group controls change no receivers. Legacy desktop map.scenes keeps its existing compatibility scope. See shared scenes.

Static scenes: await scene.attachSource(await map.getSource(id)) / scene.detachSource(source). Frozen sources list identities; draft/stopped hides, paused preserves display, remove restores user layout. All same-source shared layers, rendered queries and credits use the same effective visibility. See static scenes.

Shared scene clock

await scene.getClock() returns immutable {id,sceneInstanceId,state,elapsedMs}. Draft is zero, running accumulates monotonic milliseconds, pause/stop freeze, and resume keeps time. Pure reads emit no event or write sequence. VM exit does not pause it. Running includes host background monotonic gaps; system sleep follows platform clock behavior. sceneClock:true does not promise playback/tracks; old desktop map.scenes remains a compatibility API. See the complete scene clock guide.

Standalone SDK prefers map.on('sqs.sourceschange', listener); the old sources alias addresses the same subscription. See event names.

Shared vector/raster registration,metadata state and setTiles/setUrl are connected. Shared raster layers support planar/pitched/globe views,ordering,visibility,opacity and tileState. Shared vector circle/line/fill and source-layer queries are also connected; remaining types,DEM and feature state remain pending. See shared raster tile layers.

Shared MVT layers and queries

Vector sources now display standard circle,line,fill layers through addSource/addLayer. Each layer requires source-layer. Layers share downloads and cached content, with common geometry for planar,pitched and globe views. Planar rendering interleaves fills,lines and points in logical layer order: moveLayer can place a fill above a circle while retaining spatial-cell culling and LOD.

import {map} from 'sqsmap';
map.addSource('roads',{type:'vector',tiles:['https://your-server.example/{z}/{x}/{y}.pbf'],attribution:'Your provider'});
map.addLayer({id:'roads-line',type:'line',source:'roads','source-layer':'transportation',paint:{'line-color':'#e87925','line-width':3}});
await map.sqs.flush({render:true});
console.log(await map.querySourceFeatures('roads',{sourceLayer:'transportation'}));

Scheduling/cancellation reuse shared tile handling, including TileJSON,setTiles/setUrl,XYZ/TMS,world copies and attribution. Each MVT response permits8MiB,32 source layers,50,000 features and500,000 vertices. A map permits64 visible tiles,32 pending requests and64MiB decoded tile cache; visible source data additionally obeys16MiB JSON,50,000 features,500,000 coordinates and resident source budgets. Over-budget responses fail explicitly and failed refresh retains old content. Parent/child fallback is not connected; cached invisible tiles are excluded from queries.

querySourceFeatures requires sourceLayer. queryRenderedFeatures filters by display layer and returns sourceLayer,original MVT id and attributes, with WGS84 coordinates including visible world copies. Native/shared script reads use await. A feature may appear multiple times across tiles or world copies. GeoJSON/media sources cannot specify source-layer. metadataLoaded describes metadata; tileState and loaded describe actual current-view readiness.

vectorTileSourceStore=true represents this MVT subset, not complete vector style compatibility. Shared symbol,fill-extrusion and other types,buffer-geometry tile-boundary clipping,MLT,promoteId,volatile,parent/child fallback and the mobile host remain pending. Existing setStyle(URL) basemaps retain their separately documented scope.

The complete HTML includes every button,query,credit and disposal action. The portable acceptance script uses locally generated MVT through real native QuickJS and WASM main-thread/strict Worker. Replace the template and display required provider credits for real services.

MVT feature state is connected in07.9; see feature state.

13.6c supports custom GeoJSON/TileJSON/georeferenced image/video source URLs and updates, retaining decoder/cancellation/identity rules. See source protocols; Style/glyph/loadImage/live entries retain their own scope.