Repository navigation
Bring feature/bearing-clockwise into develop - #24
Merged
Merged
Conversation
bearing を「値を増やすと地図が時計回りに回る」向きに統一し、ネイティブ SDK との変換をコアの CameraBearing に集約する。
An independent workspace package, not a core change — it wraps the shared Rust renderer as a TileProvider and serves through the existing LocalTileServer, the same way react-heatmap does. Ships ESM only: the renderer's wasm bindings are ESM, so a CJS build could not load them. The vendored renderer is kept external from the bundle, because inlining it would move the wasm URL out of vendor/pkg and break loading at runtime — verified in a browser rather than assumed.
The repo-wide dist/ ignore rule swallowed vendor/dist, so a clean checkout had a package that could not build: nothing in react-vectortile regenerates it, only the sync script in the mapconductor-vectortile repo. Tracking it matches how android-vectortile carries its .so and ios-vectortile its XCFramework. Also carries in the byte-budgeted tile cache.
wasm-pack writes a .gitignore containing '*' into its output directory, and the sync copied it verbatim - so the wasm the package needs at runtime was silently untracked. The sync script now drops it.
Depends on @mapconductor/vectortile as a package rather than a vendored copy, so react-vectortile is now what it always claimed to be: one 120-line component over a renderer that knows nothing about React. The sample's colour pickers blend each layer's own colour toward the picked one instead of replacing it. A basemap tells forest from grass from farmland with a dozen greens, and flattening a category to a single colour throws that away — the map stops looking like a map. Categories come from the Shortbread source layer a layer draws, not from this style's layer ids, so the same code works on any Shortbread style. Restyling now works end to end, which needed two fixes: - attachTo() threads a cache key, bumped per restyle. Without it the map keeps serving raster tiles it already holds and nothing appears to change. - Changing `style` no longer tears down and rebuilds the renderer. It calls setStyle, which keeps the fetched vector tiles — the geometry did not change, only the paint. Measured on the sample: recolouring refetches 0 vector tiles and re-renders 6 raster tiles. `style` is compared by content rather than object identity, because a colour picker necessarily builds a new style object on every render. vite.config sets worker.format to 'es'. The renderer runs in a module worker and Vite's default iife format cannot code-split, which fails the production build only — dev serves module workers natively.
…dian The cells were 0.02 degrees. On 144k markers a tile-sized query costs 2.31 ms at that size and 0.06 ms at 0.005, because a 0.02 cell hands back about five times the markers a tile actually needs. The Android and iOS indexes were measured onto 0.005 this week; this is the same number for the same reason. Both callers pad their query by a few pixels — a tile by its border, a click by the icon's half extent. Near 180 degrees that padding walks off the end of the coordinate range, and the result was one of two silent failures: corners that come in reversed iterated no cells at all and returned nothing, and a west or east past ±180 compared as a plain number, so a click at 179.99 could not reach a marker at -179.99. Columns now fold back onto the globe, at insert and at query, and the containment test measures the angle east of `west` rather than comparing raw degrees. Neither threw. Markers just went missing, which is why the test compares against a brute-force scan on every query instead of asserting that something came back.
Seven test files were on disk and invisible to git. The ignore list carries `*.mjs`, `*.js`, `*.cjs` and `*.mts` unanchored to catch build output, so they matched everything under test/ as well — `!src/tileserver/tile-sw.js` sitting a few lines above is the same problem, patched narrowly the last time someone hit it. Nothing here is new: these are the tests that already run under `npm test`, all 69 of them passing, only now they are in the repository rather than on one machine. Fresh clone, `npm test`, seven files short and nobody the wiser. `!test/**` is the narrow fix, matching the exception already in the file. Anchoring the patterns to `dist/` would be the broad one, but that changes what every other pattern matches and belongs in its own change.
Keeping one marker per cell of a few pixels is what makes 144,183 street trees readable below street level: they are planted metres apart along a road, so most of them sit on top of one another, and thinning them halves the tile bytes while showing the same map. android-sdk grew the option when that sample was built; porting the sample to the other two turned up its absence. Zero, the default, keeps the behaviour these renderers already had — drop only markers that agree exactly, same rectangle and same icon, which cannot change the tile. Above zero the group is a cell and the icon stops being part of it: the caller has said markers that close together are interchangeable, so one of them stands for the rest whatever they draw. The value is tile pixels on all three, not points or dp. It is compared against destination rectangles the renderer has already rounded into the tile's own pixel grid, and passing it through unscaled is what makes 14 mean the same density on a 3x iPhone as on Android.
Tokyo's 144,183 street trees, the sample android-sdk has had since the marker tiling work. A harder shape than the post office set: six times as many, inside one metropolitan area rather than spread over a country, and each species draws its own colour, so the renderer cannot collapse two trees of different species that land on the same pixel. All three read the same 2.8 MB asset — a magic, three string tables, then a fixed 20-byte record per tree, little-endian. The source is a 12 MB Shift-JIS CSV; parsing that on a phone or in a browser would measure CSV parsing rather than the map. The web decode is 10 ms in node for the whole file. Species colours come out of the same golden-angle hue rotation on each platform, with the last index — the bucket holding every species under a hundred trees — grey rather than competing with a named species for a hue. A species is the same colour on all three. The basemap is the stripped-down style the Android sample uses: land, water, the major roads and the place names, with the finer streets from zoom 13. It is MapLibre's own design type, so it applies there and the page runs on whatever basemap the other providers bring. Verified by rendering, not by compiling. iOS has a screenshot test that opens the page and waits for the trees, because the failures here — asset missing from the bundle, style URL unresolved — all look like "the map draws and the trees do not" and none of them throw. It caught the first cut passing declutterPx scaled by the content scale, which thinned a retina screen to a third of the density Android shows.
The renderer gained a split ground/label layer, glyph handover and the style's attributions; this component was written before any of it and kept using the single combined route. So a map drew no labels, and a basemap drawing OpenStreetMap credited nobody — which is a licence problem, not a cosmetic one. Follows android-vectortile's VectorTileLayer: - groundTiles and labelTiles on two routes, ground mounted first. zIndex is not enough on its own: maplibre and mapkit stack raster layers in mount order and ignore it, so the element order carries the stacking there and zIndex carries it on google-maps, leaflet, openlayers and cesium. - onGlyphsLoaded replaces the label half alone. Mounted alongside its predecessor and the old one dropped 900 ms later, because replacing a raster layer's URL is remove-then-add and the layer is gone until the new source fetches its first tiles. Same window as android's HANDOVER_MS. - attributions attached to both halves. The overlay deduplicates, so hiding either half cannot silence the credit. Restyling still recolours in place; both halves re-key on the style version so the map refetches what it already holds. Registers the package in the API gate, which never covered it. The surface is unchanged — the same seven props. Verified on 17 providers with npm run smoke: 14 OK and all 17 renders distinct. The three that are not (mapkit, mappls, google-maps-3d) fail the same way on an unrelated page — an invalid MapKit token, a blocked Mappls CDN — and did so before this.
PACKAGES is hand-maintained, so adding a package and forgetting to list
it means the gate skips it — silently, which is the worst way for a gate
to break: it stays green. CLAUDE.md records this happening once with
reactnative-for-longdo. It had happened four more times since, to
vectortile, react-vectortile and react-icons-{jp,us,weather}.
check now walks the workspace and fails on any published package that is
in neither PACKAGES nor UNGATED. dump only warns — dump is how you accept
a change, so stopping there would block the way out.
UNGATED carries a reason rather than a list of names. The two templates
are there because they exist to be copied and rewritten, and freezing
that fights their purpose. private workspaces — examples/* — are out of
scope: nothing unpublished has an app developer's frozen API.
Registers the four that were missing, with baselines. vectortile is the
one that matters: it is the renderer react-vectortile is built on, and
its 562-line surface was carrying no gate at all.
"*" accepted any version of @mapconductor/vectortile, and the two have to move together: the binding calls groundTiles, labelTiles and onGlyphsLoaded, none of which existed a version ago. A range that cannot be wrong is a range that cannot warn. Caret, matching js-sdk-core and js-sdk-react alongside it.
CI here was api-surface and deploy only. Nothing ran the tests, so a change that kept every signature and broke what was behind it went through green. `npm test` walks the workspaces; each package's `pretest` builds its own dist, so there is nothing to sequence. Lint runs alongside. `npm run smoke` stays out. It drives real Chrome across every provider and needs API keys and minutes; if it belongs in CI it belongs on its own trigger. Also moves js-sdk-core to the Web Mercator all three platforms now agree on.
The tile is a 256 px canvas shown at 256 CSS px, so nothing here multiplies by devicePixelRatio and the icon is density independent already. `sizePx` did not say which pixels it meant, which is how android-sdk ended up building the same icon at raw device pixels and shrinking it on denser screens. Also drops 14 to 10, matching android-sdk and ios-sdk.
…ty one A transparent tile is the right answer for a spot with nothing on it and the wrong one for a render that failed: the library keeps it, and the hole stays with the neighbouring tiles' overhang cut off at its edge. js-sdk-core now distinguishes the two, so this path reports a failure as a failed tile and lets the library ask again.
Bigger tiles are cheaper for the same screen, so 512 stays the default, but ArcGIS's 3D SceneView picks the level as though every tile were 256 pixels and fetches one level deeper with four times the tiles. The layer now asks the map's service registry first; an explicit tileSize still wins.
Style dimensions are screen units, so the rasteriser needs two numbers to turn them into pixels: the pixel count asked for, and the width the tile will be shown at. It only had the first and assumed the second was 512, which held everywhere until ArcGIS's 3D SceneView, where a tile lands in a 256 px slot whatever pixels it carries -- and every label and every road came out at half size, with the style read one zoom too deep. The renderer now takes the display size and derives both rules from it; 512 reproduces the old numbers exactly, so nothing else moves.
The page gets an "As basemap" checkbox covering MapLibre, Google (2D), ArcGIS, Mapbox, MapTiler, TomTom, Longdo, HERE, Leaflet, OpenLayers, deck.gl, Cesium and Azure; MapKit, Mappls and Google 3D have no design that draws nothing. Bumps the provider packages for their None designs and syncs the vector tile wasm (output version 17).
persistSourceTiles / persistRenderedTiles put them in Cache Storage; cacheBytes bounds the in-memory source cache.
…m and azuremaps deck.gl gets a singleton view and design options; the camera sync registry, heatmap, design and post office pages follow; the vector tile page turns the tile caches on. Bumps maplibre (tests), tomtom and azuremaps (zoom clamp).
…ectly On a map that registers VectorStyleSupport no raster layer is mounted; the style becomes the basemap. Other backends keep the raster path. The sample's As-basemap toggle drives it.
Submodule bumps for the in-place mapDesignType path on every web provider, Google 2D None, and Longdo's deck.gl global isolation. examples: hide inactive singleton map layers with opacity as well as visibility, which Longdo's built-in MapLibre attribution was overriding and staying on screen under every other provider. smoke: DPR env (deviceScaleFactor) and gmp-map-3d as a map surface.
A style can now be adjusted on the vector-tile path, not just handed over whole: rules are applied to the document before anything is drawn, so a rule that hides a role leaves those layers out of what the renderer is given and they cost nothing to not draw. The compiler's wasm is loaded only when there are rules; a URL style is fetched first, because the compiler takes text. examples: the knobs are rules now. Each category hides several roles, because a knob is a thing on the map and a role is a thing in the style — 'land' on screen is the background plus the landuse patches plus the sites, and hiding only the middle one leaves the ground as it was. Labels join them, switchable but not tinted: pulling every symbol layer towards one colour would flatten the legend by merely opening the page. The colour knobs go through the same rules (mix blends towards the picked colour rather than replacing it), so recolour.ts — a hand-rolled colour parser matching on Shortbread source layers — is gone. Same map: 0.3% of pixels differ at the default palette.
# Conflicts: # js-sdk-core # react-for-arcgis # react-for-azuremaps # react-for-cesium # react-for-googlemaps # react-for-here # react-for-leaflet # react-for-longdo # react-for-mapbox # react-for-mapkit # react-for-maplibre # react-for-mappls # react-for-maptiler # react-for-openlayers # react-for-tomtom # reactnative-for-arcgis # reactnative-for-googlemaps # reactnative-for-longdo # reactnative-for-mapbox # reactnative-for-maplibre # reactnative-for-maptiler # reactnative-for-tomtom
The packages' `node --test "test/**/*.test.mjs"` relies on node --test expanding the glob, which it does only from Node 21. On 20 every package with tests fails without running any.
Contributor
Author
|
Added 065c404: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings the rest of
feature/bearing-clockwiseinto develop: the 39 commits after #9 (react-vectortile and react-vectorstyle, vector tile rendering across web providers, the deck.gl sample, the test workflow, API gate coverage, and the provider bumps that go with them).Merging develop
develop was merged into the branch first. The only conflicts were submodule pointers, resolved as follows:
js-sdk-coreandreact-for-*: each submodule's develop tip, which now holds the bearing work (react-for-*0.1.1 #5–build(deps-dev): bump undici from 8.10.0 to 8.11.2 #14, js-sdk-core fix(ci): npm-publish の可視性検証を正しく動かす #8).js-sdk-react: develop tip4fa1db2, which adds labelPosition through the RN bridge.reactnative-for-*(7 repos): the tip ofcheckpoint/vector-style-20261010, after develop was merged into it. These are the heads of the openPass vectorStyle to the native mapPRs.react-icons-{jp,us,weather}: already pointed atfix/register-in-api-gate, the head of each repo's open PR 0.1.0 #1.react-for-deckgl: left as the merge produced it (d339617). Moving it to develop's deck.gl 9.4.0 also needs a lockfile update, so that is left to separate work.Merge order: merge the reactnative-for-* and react-icons-* PRs before this one, so every pointer is on develop. #23 also touches
package-lock.json, so whichever of the two lands second may need a re-merge.Checked locally
The merged tree, with every submodule checked out at its pointer:
npm run build:packages: oknpm test: 227 pass, 1 failnpm run lint: oknode scripts/api-surface.mjs check: every package passes except the ones below.Failures on this branch that this merge did not cause
Expect these in CI until they are fixed:
react-vectorstyle/react-vectortiledo not build from a clean checkout.vectorstyle/distandvectortile/distare gitignored and produced byscripts/sync-sdk.shin mapconductor-vectortile.api-surfacecannot buildreact-icons-{jp,us,weather}.PACKAGES, but they are not npm workspaces, sonpm run build --workspacefails.react-for-template's test fails.dist/index.mjs, but the package has nopretestscript and is not inbuild:packages.test.ymlis new on this branch, so CI never ran this test before.js-sdk-corebaseline is out of date on develop.