@tileflow/core 0.1.0-alpha.29 → 0.1.0-alpha.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -1
- package/dist/browser.d.ts +66 -5
- package/dist/browser.js +1102 -39
- package/dist/build.d.ts +7 -7
- package/dist/build.js +485 -163
- package/dist/config-reference.json +1399 -1153
- package/dist/{icon-composition-BquPlPPI.d.ts → icon-composition-BiOTwrvD.d.ts} +12 -3
- package/dist/index.d.ts +105 -11
- package/dist/index.js +770 -168
- package/dist/{manifest-types-BZU4zbmI.d.ts → manifest-types-CTT2eLbp.d.ts} +42 -1
- package/dist/manifest.d.ts +2 -2
- package/dist/native.js +1 -0
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +28 -0
- package/docs/authoring-model.md +30 -3
- package/docs/data-is-separate-from-design.md +2 -1
- package/docs/shared-visual-primitives.md +61 -2
- package/docs/theme-transitions-and-blends.md +165 -0
- package/package.json +1 -1
|
@@ -189,9 +189,26 @@ type TileflowTextPaint = {
|
|
|
189
189
|
haloWidth?: TileflowNumberStyleValue;
|
|
190
190
|
opacity?: TileflowNumberStyleValue;
|
|
191
191
|
};
|
|
192
|
+
/**
|
|
193
|
+
* One opaque strip behind each shaped line of a label. Tileflow lowers it to a derived glyph stack
|
|
194
|
+
* whose cells MapLibre's text halo paints, so placement, wrapping and collision stay native.
|
|
195
|
+
*/
|
|
196
|
+
type TileflowTextBackground = {
|
|
197
|
+
/** Strip colour. Cells overlap at their joins, so the colour must be opaque. */
|
|
198
|
+
color: TileflowColorStyleValue;
|
|
199
|
+
/** `lines` fits one strip to each shaped line. */
|
|
200
|
+
fit: 'lines';
|
|
201
|
+
/** Strip extension beyond the first and last glyph of each line, in ems. Defaults to 0.33. */
|
|
202
|
+
padding?: TileflowThemeNumberValue;
|
|
203
|
+
};
|
|
192
204
|
type TileflowTextLayout = {
|
|
193
205
|
allowOverlap?: boolean;
|
|
194
206
|
anchor?: TileflowTextAnchor;
|
|
207
|
+
/**
|
|
208
|
+
* Replaces the text halo with line-fitted strips. Requires a map `glyphs` provider that serves
|
|
209
|
+
* derived stacks, one font without fallbacks, and constant `letterSpacing` and `lineHeight`.
|
|
210
|
+
*/
|
|
211
|
+
background?: TileflowTextBackground;
|
|
195
212
|
field?: TileflowStringStyleValue;
|
|
196
213
|
font?: TileflowThemeFontValue;
|
|
197
214
|
fallbacks?: readonly TileflowThemeFontValue[];
|
|
@@ -653,6 +670,30 @@ declare function shouldLoadTileflowManifest(options: TileflowManifestLoadOptions
|
|
|
653
670
|
declare function validateTileflowRuntimeSource(source: unknown): TileflowRuntimeSourceValidation;
|
|
654
671
|
/** Validate the only runtime selection grammar: one concrete portable name or `system`. */
|
|
655
672
|
declare function validateTileflowThemeSelection(value: unknown): value is TileflowThemeSelection;
|
|
673
|
+
/**
|
|
674
|
+
* A continuous blend of named themes of one Tileflow map. `position` places the map between
|
|
675
|
+
* neighbouring themes: 0 is the first, 1 the second, and 1.25 a quarter of the way from the second
|
|
676
|
+
* to the third.
|
|
677
|
+
*/
|
|
678
|
+
type TileflowThemeBlendSelection = Readonly<{
|
|
679
|
+
/** From 0 to `themes.length - 1`. */
|
|
680
|
+
position: number;
|
|
681
|
+
/** Two to eight concrete theme names of the map, in blend order. */
|
|
682
|
+
themes: readonly string[];
|
|
683
|
+
}>;
|
|
684
|
+
declare const tileflowThemeBlendLimits: Readonly<{
|
|
685
|
+
maximumThemes: 8;
|
|
686
|
+
minimumThemes: 2;
|
|
687
|
+
}>;
|
|
688
|
+
declare function validateTileflowThemeBlendSelection(value: unknown): value is TileflowThemeBlendSelection;
|
|
689
|
+
/** The theme nearest to a blend position, which a blend shows when it cannot blend. */
|
|
690
|
+
declare function nearestTileflowBlendTheme(blend: TileflowThemeBlendSelection): string;
|
|
691
|
+
/** Resolves every theme of a blend to its published runtime style, in blend order. */
|
|
692
|
+
declare function resolveTileflowRuntimeThemeBlend(options: {
|
|
693
|
+
blend: TileflowThemeBlendSelection;
|
|
694
|
+
manifestMap: TileflowRuntimeManifestMap;
|
|
695
|
+
source: TileflowRuntimeSource;
|
|
696
|
+
}): TileflowRuntimeStyle[];
|
|
656
697
|
declare function assertValidTileflowRuntimeSource(source: unknown): asserts source is TileflowRuntimeSource;
|
|
657
698
|
declare function resolveTileflowRuntimeStyle(options: TileflowRuntimeStyleOptions): TileflowRuntimeStyle | null;
|
|
658
699
|
/** Resolve one concrete published theme without consulting ambient browser state. */
|
|
@@ -746,4 +787,4 @@ type TileflowRuntimeManifest = {
|
|
|
746
787
|
version: typeof tileflowRuntimeManifestVersion;
|
|
747
788
|
};
|
|
748
789
|
|
|
749
|
-
export { type TileflowManifestFetchOptions as $, type TileflowAreaStyle as A, type TileflowBackgroundPaint as B, type TileflowCirclePaint as C, type TileflowColor as D, type TileflowColorStyleValue as E, type TileflowExtrusionPaint as F, type TileflowFillPaint as G, type TileflowIconAnchor as H, type TileflowIconLayout as I, type TileflowIconPaint as J, type TileflowIconStyle as K, type TileflowIconTextFit as L, type MapLibreStyle as M, type TileflowImageStyleValue as N, type TileflowLabelDetail as O, type TileflowLabelLanguage as P, type TileflowLabelStyles as Q, type TileflowLayerRange as R, type TileflowLight as S, type TileflowRuntimeManifest as T, type TileflowLineCap as U, type ValidationMessage as V, type TileflowLineHatchStyle as W, type TileflowLineJoin as X, type TileflowLineLayout as Y, type TileflowLinePaint as Z, type TileflowLineStackStyle as _, type TileflowRuntimeColorScheme as a, type
|
|
790
|
+
export { type TileflowManifestFetchOptions as $, type TileflowAreaStyle as A, type TileflowBackgroundPaint as B, type TileflowCirclePaint as C, type TileflowColor as D, type TileflowColorStyleValue as E, type TileflowExtrusionPaint as F, type TileflowFillPaint as G, type TileflowIconAnchor as H, type TileflowIconLayout as I, type TileflowIconPaint as J, type TileflowIconStyle as K, type TileflowIconTextFit as L, type MapLibreStyle as M, type TileflowImageStyleValue as N, type TileflowLabelDetail as O, type TileflowLabelLanguage as P, type TileflowLabelStyles as Q, type TileflowLayerRange as R, type TileflowLight as S, type TileflowRuntimeManifest as T, type TileflowLineCap as U, type ValidationMessage as V, type TileflowLineHatchStyle as W, type TileflowLineJoin as X, type TileflowLineLayout as Y, type TileflowLinePaint as Z, type TileflowLineStackStyle as _, type TileflowRuntimeColorScheme as a, type TileflowTextBackground as a$, type TileflowManifestLoadOptions as a0, type TileflowMapMode as a1, type TileflowMapModeOptions as a2, type TileflowMarkerSymbolStyle as a3, type TileflowMountainBikeScale as a4, type TileflowNumberInsetsStyleValue as a5, type TileflowNumberStyleValue as a6, type TileflowPlaceLabelClass as a7, type TileflowPoiCategory as a8, type TileflowPoiCategoryStyle as a9, type TileflowRoadWeight as aA, type TileflowRuntimeCenterLike as aB, type TileflowRuntimeManifestMap as aC, type TileflowRuntimeSource as aD, type TileflowRuntimeSourceValidation as aE, type TileflowRuntimeStyle as aF, type TileflowRuntimeStyleOptions as aG, type TileflowRuntimeViewOptions as aH, type TileflowSessionController as aI, type TileflowSessionGrantResponse as aJ, type TileflowStringStyleValue as aK, type TileflowStructuralStyleValue as aL, type TileflowStyleFontFace as aM, type TileflowStyleValue as aN, type TileflowSymbolPlacement as aO, type TileflowSymbolPlacementStyle as aP, type TileflowSymbolZOrder as aQ, type TileflowTerrain as aR, type TileflowTerrainConfig as aS, type TileflowTerrainContourLabelStyle as aT, type TileflowTerrainContourLineStyle as aU, type TileflowTerrainContoursConfig as aV, type TileflowTerrainEncoding as aW, type TileflowTerrainHillshadeStyle as aX, type TileflowTerrainLayerRange as aY, type TileflowTerrainMode as aZ, type TileflowTextAnchor as a_, type TileflowPoiColorMode as aa, type TileflowPoiDensity as ab, type TileflowPriorityOrder as ac, type TileflowProjection as ad, type TileflowResolvedRuntimeTheme as ae, type TileflowRoadAreaStyle as af, type TileflowRoadClass as ag, type TileflowRoadClassStyle as ah, type TileflowRoadCrossingStyle as ai, type TileflowRoadDetail as aj, type TileflowRoadExtras as ak, type TileflowRoadHierarchy as al, type TileflowRoadLabelDetail as am, type TileflowRoadLayerStyle as an, type TileflowRoadModifier as ao, type TileflowRoadOutline as ap, type TileflowRoadRestriction as aq, type TileflowRoadRoundaboutStyle as ar, type TileflowRoadServiceType as as, type TileflowRoadShieldDetail as at, type TileflowRoadShieldStyles as au, type TileflowRoadSidewalkStyle as av, type TileflowRoadStructure as aw, type TileflowRoadTreatmentLayerStyle as ax, type TileflowRoadTreatmentLineStyle as ay, type TileflowRoadTreatmentStyle as az, type TileflowRuntimeManifestMapEntry as b, type TileflowTextJustify as b0, type TileflowTextLayout as b1, type TileflowTextPaint as b2, type TileflowTextStyle as b3, type TileflowThemeBlendSelection as b4, type TileflowThemeColorAlpha as b5, type TileflowThemeColorMix as b6, type TileflowThemeColorValue as b7, type TileflowThemeFontValue as b8, type TileflowThemeImageValue as b9, resolveTileflowAnalyticsRequestUrl as bA, resolveTileflowManifestMap as bB, resolveTileflowMapMode as bC, resolveTileflowRuntimeStyle as bD, resolveTileflowRuntimeTheme as bE, resolveTileflowRuntimeThemeBlend as bF, resolveTileflowRuntimeView as bG, resolveTileflowStaticImageUrl as bH, shouldLoadTileflowManifest as bI, startTileflowSession as bJ, tileflowPoiCategories as bK, tileflowStyleFontFaceLimits as bL, tileflowStyleFontFacesMetadataKey as bM, tileflowThemeBlendLimits as bN, tileflowThemeTokenCategories as bO, token as bP, validateTileflowRuntimeSource as bQ, validateTileflowThemeBlendSelection as bR, validateTileflowThemeSelection as bS, zoom as bT, type TileflowTypographyStyle as bU, type ResolvedTileflowTypography as bV, normalizeTileflowSurfaceId as bW, type TileflowThemeNumberValue as ba, type TileflowThemeSelection as bb, type TileflowThemeTokenCategory as bc, type TileflowThemeValue as bd, type TileflowViewConfig as be, type TileflowWaterLabelClass as bf, type TileflowZoomInterpolation as bg, type TileflowZoomValue as bh, type ValidationResult as bi, assertValidTileflowRuntimeSource as bj, clearTileflowManifestCache as bk, color as bl, createTileflowSessionController as bm, createTileflowSessionId as bn, defaultTileflowManifestUrl as bo, defaultTileflowRuntimeView as bp, fixed as bq, getTileflowAnalyticsApiUrl as br, getTileflowStyleFontFaces as bs, inferTileflowAnalyticsFromStyleUrl as bt, loadTileflowManifest as bu, mergeTileflowAnalytics as bv, nearestTileflowBlendTheme as bw, normalizeTileflowRuntimeCenter as bx, normalizeTileflowStaticImageSize as by, normalizeTileflowUrl as bz, type TileflowRuntimeManifestTheme as c, type TileflowRuntimeSystemThemes as d, tileflowRuntimeManifestVersion as e, type TileflowExpression as f, type TileflowFixedValue as g, type TileflowThemeTokenReference as h, type TileflowThemeColorOperation as i, type TileflowBackgroundStyle as j, type TileflowCircleStyle as k, type TileflowExtrusionStyle as l, type TileflowFillStyle as m, type TileflowLineStyle as n, type TileflowSymbolStyle as o, type TileflowRoadsModuleOptions as p, type TileflowRoadsModuleConfig as q, type TileflowLabelsModuleOptions as r, type TileflowLabelsModuleConfig as s, tileflowRuntimeManifestLimits as t, type TileflowPoiModuleOptions as u, type TileflowPoiModuleConfig as v, type MapLibreSprite as w, type TileflowAerodromeCodeDetail as x, type TileflowAlignment as y, type TileflowAnalytics as z };
|
package/dist/manifest.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { T as TileflowRuntimeManifest } from './manifest-types-
|
|
3
|
-
export { a as TileflowRuntimeColorScheme, b as TileflowRuntimeManifestMapEntry, c as TileflowRuntimeManifestTheme, d as TileflowRuntimeSystemThemes, t as tileflowRuntimeManifestLimits, e as tileflowRuntimeManifestVersion } from './manifest-types-
|
|
2
|
+
import { T as TileflowRuntimeManifest } from './manifest-types-CTT2eLbp.js';
|
|
3
|
+
export { a as TileflowRuntimeColorScheme, b as TileflowRuntimeManifestMapEntry, c as TileflowRuntimeManifestTheme, d as TileflowRuntimeSystemThemes, t as tileflowRuntimeManifestLimits, e as tileflowRuntimeManifestVersion } from './manifest-types-CTT2eLbp.js';
|
|
4
4
|
|
|
5
5
|
declare const tileflowRuntimeManifestSchema: z.ZodType<TileflowRuntimeManifest>;
|
|
6
6
|
declare function parseTileflowRuntimeManifest(input: unknown): TileflowRuntimeManifest;
|
package/dist/native.js
CHANGED
|
@@ -4605,6 +4605,7 @@ var manifestCache = new globalThis.Map();
|
|
|
4605
4605
|
function validateTileflowThemeSelection(value) {
|
|
4606
4606
|
return value === "system" || isTileflowThemeName(value);
|
|
4607
4607
|
}
|
|
4608
|
+
var tileflowThemeBlendLimits = Object.freeze({ maximumThemes: 8, minimumThemes: 2 });
|
|
4608
4609
|
function resolveTileflowRuntimeTheme(map2, selection, colorScheme) {
|
|
4609
4610
|
let name;
|
|
4610
4611
|
if (selection === void 0) {
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { z as TileflowAnalytics, $ as TileflowManifestFetchOptions, a0 as TileflowManifestLoadOptions, a1 as TileflowMapMode, a2 as TileflowMapModeOptions, ae as TileflowResolvedRuntimeTheme, aB as TileflowRuntimeCenterLike, a as TileflowRuntimeColorScheme, T as TileflowRuntimeManifest, aC as TileflowRuntimeManifestMap, b as TileflowRuntimeManifestMapEntry, c as TileflowRuntimeManifestTheme, aD as TileflowRuntimeSource, aE as TileflowRuntimeSourceValidation, aF as TileflowRuntimeStyle, aG as TileflowRuntimeStyleOptions, d as TileflowRuntimeSystemThemes, aH as TileflowRuntimeViewOptions, aI as TileflowSessionController, aJ as TileflowSessionGrantResponse, aM as TileflowStyleFontFace,
|
|
1
|
+
export { z as TileflowAnalytics, $ as TileflowManifestFetchOptions, a0 as TileflowManifestLoadOptions, a1 as TileflowMapMode, a2 as TileflowMapModeOptions, ae as TileflowResolvedRuntimeTheme, aB as TileflowRuntimeCenterLike, a as TileflowRuntimeColorScheme, T as TileflowRuntimeManifest, aC as TileflowRuntimeManifestMap, b as TileflowRuntimeManifestMapEntry, c as TileflowRuntimeManifestTheme, aD as TileflowRuntimeSource, aE as TileflowRuntimeSourceValidation, aF as TileflowRuntimeStyle, aG as TileflowRuntimeStyleOptions, d as TileflowRuntimeSystemThemes, aH as TileflowRuntimeViewOptions, aI as TileflowSessionController, aJ as TileflowSessionGrantResponse, aM as TileflowStyleFontFace, b4 as TileflowThemeBlendSelection, bb as TileflowThemeSelection, bj as assertValidTileflowRuntimeSource, bk as clearTileflowManifestCache, bm as createTileflowSessionController, bn as createTileflowSessionId, bo as defaultTileflowManifestUrl, bp as defaultTileflowRuntimeView, br as getTileflowAnalyticsApiUrl, bs as getTileflowStyleFontFaces, bt as inferTileflowAnalyticsFromStyleUrl, bu as loadTileflowManifest, bv as mergeTileflowAnalytics, bw as nearestTileflowBlendTheme, bx as normalizeTileflowRuntimeCenter, by as normalizeTileflowStaticImageSize, bW as normalizeTileflowSurfaceId, bz as normalizeTileflowUrl, bA as resolveTileflowAnalyticsRequestUrl, bB as resolveTileflowManifestMap, bC as resolveTileflowMapMode, bD as resolveTileflowRuntimeStyle, bE as resolveTileflowRuntimeTheme, bF as resolveTileflowRuntimeThemeBlend, bG as resolveTileflowRuntimeView, bH as resolveTileflowStaticImageUrl, bI as shouldLoadTileflowManifest, bJ as startTileflowSession, bL as tileflowStyleFontFaceLimits, bM as tileflowStyleFontFacesMetadataKey, bN as tileflowThemeBlendLimits, bQ as validateTileflowRuntimeSource, bR as validateTileflowThemeBlendSelection, bS as validateTileflowThemeSelection } from './manifest-types-CTT2eLbp.js';
|
package/dist/runtime.js
CHANGED
|
@@ -496,6 +496,30 @@ function validateTileflowRuntimeSource(source) {
|
|
|
496
496
|
function validateTileflowThemeSelection(value) {
|
|
497
497
|
return value === "system" || isTileflowThemeName(value);
|
|
498
498
|
}
|
|
499
|
+
var tileflowThemeBlendLimits = Object.freeze({ maximumThemes: 8, minimumThemes: 2 });
|
|
500
|
+
function validateTileflowThemeBlendSelection(value) {
|
|
501
|
+
if (!value || typeof value !== "object") return false;
|
|
502
|
+
const { position, themes } = value;
|
|
503
|
+
return Array.isArray(themes) && themes.length >= tileflowThemeBlendLimits.minimumThemes && themes.length <= tileflowThemeBlendLimits.maximumThemes && themes.every((theme) => isTileflowThemeName(theme)) && typeof position === "number" && Number.isFinite(position) && position >= 0 && position <= themes.length - 1;
|
|
504
|
+
}
|
|
505
|
+
function nearestTileflowBlendTheme(blend) {
|
|
506
|
+
const index = Math.min(blend.themes.length - 1, Math.max(0, Math.round(blend.position)));
|
|
507
|
+
return blend.themes[index];
|
|
508
|
+
}
|
|
509
|
+
function resolveTileflowRuntimeThemeBlend(options) {
|
|
510
|
+
if (!validateTileflowThemeBlendSelection(options.blend)) {
|
|
511
|
+
throw new TypeError(
|
|
512
|
+
"A Tileflow theme blend requires two to eight concrete themes and a position."
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
return options.blend.themes.map(
|
|
516
|
+
(theme) => resolveTileflowRuntimeStyle({
|
|
517
|
+
manifestMap: options.manifestMap,
|
|
518
|
+
source: options.source,
|
|
519
|
+
theme
|
|
520
|
+
})
|
|
521
|
+
);
|
|
522
|
+
}
|
|
499
523
|
function assertValidTileflowRuntimeSource(source) {
|
|
500
524
|
const validation = validateTileflowRuntimeSource(source);
|
|
501
525
|
if (!validation.ok) {
|
|
@@ -1269,6 +1293,7 @@ export {
|
|
|
1269
1293
|
inferTileflowAnalyticsFromStyleUrl,
|
|
1270
1294
|
loadTileflowManifest,
|
|
1271
1295
|
mergeTileflowAnalytics,
|
|
1296
|
+
nearestTileflowBlendTheme,
|
|
1272
1297
|
normalizeTileflowRuntimeCenter,
|
|
1273
1298
|
normalizeTileflowStaticImageSize,
|
|
1274
1299
|
normalizeTileflowSurfaceId,
|
|
@@ -1278,12 +1303,15 @@ export {
|
|
|
1278
1303
|
resolveTileflowMapMode,
|
|
1279
1304
|
resolveTileflowRuntimeStyle,
|
|
1280
1305
|
resolveTileflowRuntimeTheme,
|
|
1306
|
+
resolveTileflowRuntimeThemeBlend,
|
|
1281
1307
|
resolveTileflowRuntimeView,
|
|
1282
1308
|
resolveTileflowStaticImageUrl,
|
|
1283
1309
|
shouldLoadTileflowManifest,
|
|
1284
1310
|
startTileflowSession,
|
|
1285
1311
|
tileflowStyleFontFaceLimits,
|
|
1286
1312
|
tileflowStyleFontFacesMetadataKey,
|
|
1313
|
+
tileflowThemeBlendLimits,
|
|
1287
1314
|
validateTileflowRuntimeSource,
|
|
1315
|
+
validateTileflowThemeBlendSelection,
|
|
1288
1316
|
validateTileflowThemeSelection
|
|
1289
1317
|
};
|
package/docs/authoring-model.md
CHANGED
|
@@ -158,6 +158,21 @@ Structural controls such as presets, visibility, and zoom gates remain ordinary
|
|
|
158
158
|
controls address stable concepts such as `roads.classes.primary.surface.fill`, not renderer layer
|
|
159
159
|
IDs.
|
|
160
160
|
|
|
161
|
+
`expr.id()` reads the source-owned feature identifier: a string, number, or `null` when absent.
|
|
162
|
+
It performs no I/O and does not derive an identifier from geometry. `expr.modulo(dividend, divisor)`
|
|
163
|
+
uses native numeric remainder, including its sign behavior. Normalize input and provide a deliberate
|
|
164
|
+
fallback before using numeric IDs for decorative variation; missing or non-numeric IDs must not
|
|
165
|
+
silently imply distinct features. Identity stability across data releases belongs to the producer.
|
|
166
|
+
|
|
167
|
+
<!-- docs:check -->
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
import {expr} from '@tileflow/core';
|
|
171
|
+
|
|
172
|
+
const numericIdentity = expr.abs(expr.toNumber(expr.id(), 0));
|
|
173
|
+
const decorativeBucket = expr.modulo(numericIdentity, 7);
|
|
174
|
+
```
|
|
175
|
+
|
|
161
176
|
The `land` module exposes stable land-use targets for `cemetery`, `civic`, `commercial`,
|
|
162
177
|
`education`, `government`, `industrial`, `medical`, `military`, `parking`, `railway`,
|
|
163
178
|
`recreation`, and `residential`. Its land-cover taxonomy distinguishes physical cover from authored
|
|
@@ -194,6 +209,18 @@ broadleaf and conifer palettes, and independent height and crown scales. The leg
|
|
|
194
209
|
shortcut remains available; `flat.minZoom` takes precedence when both are present. The binding
|
|
195
210
|
includes height, crown diameter, genus, leaf type, and species fields so compatible runtimes can
|
|
196
211
|
preserve source measurements and botanical form without hard-coding raw property names. The
|
|
197
|
-
pitched-scene stack follows physical height: pedestrian and transport surfaces, transport markings
|
|
198
|
-
|
|
199
|
-
|
|
212
|
+
pitched-scene stack follows physical height: pedestrian and transport surfaces, transport markings,
|
|
213
|
+
buildings, then vegetation, so street paint never floats over 3D geometry. Text draws last: road
|
|
214
|
+
names, route shields, junction numbers, and place, water, aerodrome, and POI annotations stay above
|
|
215
|
+
every ground layer, so building fills, boundaries, and trees cannot cover them.
|
|
216
|
+
`labels.collisionPriority` only orders labels within that final stack.
|
|
217
|
+
|
|
218
|
+
Render passes, and refinements that move a target their module owns, share one `placement`
|
|
219
|
+
vocabulary. A band edge is `below-` or `above-` one of `land`, `relief`, `water`, `roads`,
|
|
220
|
+
`boundaries`, `buildings`, `vegetation`, and `labels`; it needs no anchor, so a vegetation pass can
|
|
221
|
+
draw `'above-relief'` without depending on another module. `{above: target}` and `{below: target}`
|
|
222
|
+
draw beside one semantic target and inherit its band and, without their own `feature`, its vector
|
|
223
|
+
data; passes placed beside a moved target follow it. Operations sharing a placement paint in
|
|
224
|
+
declaration order, the first lowest. For symbols, a higher layer is also placed first in MapLibre
|
|
225
|
+
collisions, so placement decides both drawing and precedence. An owner whose layers are all
|
|
226
|
+
render passes still satisfies other operations' `requirements`.
|
|
@@ -116,7 +116,8 @@ to right; a later exact name replaces an earlier face and case-only collisions f
|
|
|
116
116
|
faces used by the final style become content-addressed assets and strict `tileflow:fontFaces`
|
|
117
117
|
metadata. `font` names an exact OpenType full name or glyph face; local `fallbacks` name exact faces
|
|
118
118
|
or explicit CSS generic families. Tileflow never appends a weight suffix or derives one face from
|
|
119
|
-
another
|
|
119
|
+
another; the only derived stacks are line-fitted text backgrounds on a `glyphs` provider, which keep
|
|
120
|
+
their source faces' shapes. Browser adapters load local faces before MapLibre. Native releases use a locked PBF
|
|
120
121
|
`glyphs` URL provider instead, which enumerates the exact comma-joined MapLibre request keys in
|
|
121
122
|
`fontStacks`.
|
|
122
123
|
|
|
@@ -10,8 +10,9 @@ having to learn different spellings for the same MapLibre behavior:
|
|
|
10
10
|
- `LineStyle`: color, width, opacity, dash, blur, gap, offset, pattern, caps, joins, and zoom range.
|
|
11
11
|
- `LineHatchStyle`: repeated diagonal detail with color, opacity, spacing, size, angle, and zoom
|
|
12
12
|
range for a road structure.
|
|
13
|
-
- `TextStyle`: field, exact font face, exact fallback faces, size, color, halo,
|
|
14
|
-
collision policy, rotation, fixed/variable anchoring, line
|
|
13
|
+
- `TextStyle`: field, exact font face, exact fallback faces, size, color, halo, line-fitted
|
|
14
|
+
background, spacing metrics, transform, collision policy, rotation, fixed/variable anchoring, line
|
|
15
|
+
constraints, and zoom range.
|
|
15
16
|
- `IconStyle`: image, size, color, halo, rotation/alignment, collision policy, and zoom range.
|
|
16
17
|
- `CircleStyle`: radius, fill/stroke appearance, blur, opacity, pitch behavior, and zoom range.
|
|
17
18
|
- `ExtrusionStyle`: color, height, base, opacity, pattern, vertical gradient, and zoom range.
|
|
@@ -20,3 +21,61 @@ Compounds express common cartographic structures: `AreaStyle` has `fill` and `ou
|
|
|
20
21
|
`LineStackStyle` has `shadow`, `casing`, and `fill`, and `SymbolStyle` combines placement with
|
|
21
22
|
optional `text`, `icon`, and `marker`. Geographic selection remains owned by semantic modules;
|
|
22
23
|
ordinary visual styles intentionally do not accept raw source filters.
|
|
24
|
+
|
|
25
|
+
## Line-fitted text backgrounds
|
|
26
|
+
|
|
27
|
+
`text.background` draws one opaque strip behind each shaped line of a label, fitted to that line's
|
|
28
|
+
own width. Use it for captions whose lines differ in length, where a stretched icon plate
|
|
29
|
+
(`icon.textFit`) would cover the whole block.
|
|
30
|
+
|
|
31
|
+
<!-- docs:check -->
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import {fixed, poi, zoom} from '@tileflow/core';
|
|
35
|
+
|
|
36
|
+
export const captions = poi({
|
|
37
|
+
categories: ['arts-entertainment'],
|
|
38
|
+
styles: {
|
|
39
|
+
'arts-entertainment': {
|
|
40
|
+
text: {
|
|
41
|
+
background: {
|
|
42
|
+
color: fixed('#080E11', {reason: 'Caption strip'}),
|
|
43
|
+
fit: 'lines',
|
|
44
|
+
padding: 0.33,
|
|
45
|
+
},
|
|
46
|
+
color: fixed('#ECEEE9', {reason: 'Caption text'}),
|
|
47
|
+
font: fixed('Noto Sans Bold', {reason: 'Caption face'}),
|
|
48
|
+
letterSpacing: fixed(0.08, {reason: 'Caption tracking'}),
|
|
49
|
+
lineHeight: fixed(1.2, {reason: 'Caption leading'}),
|
|
50
|
+
size: zoom.linear([
|
|
51
|
+
[14, 11],
|
|
52
|
+
[18, 14],
|
|
53
|
+
]),
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Tileflow lowers the background to MapLibre properties only. `text-font` becomes a derived stack,
|
|
61
|
+
such as `Noto Sans Bold lines-v1-t80-l1200-p330`. Its glyphs keep the source advances and shapes and
|
|
62
|
+
add a rectangular cell, which the text halo paints. The halo width tracks `text-size / 6`, including
|
|
63
|
+
zoom curves. Shaping, wrapping, collision, variable anchors, fading and right-to-left text therefore
|
|
64
|
+
stay native, and the compiled style needs no runtime extension.
|
|
65
|
+
|
|
66
|
+
- The colour must be opaque. Neighbouring cells overlap where they join.
|
|
67
|
+
- `font` must name one stack served by the map's `glyphs` provider, without `fallbacks`. Maps that
|
|
68
|
+
use browser-rendered `fonts` reject backgrounds.
|
|
69
|
+
- `letterSpacing` and `lineHeight` must be constants. The derived stack encodes them in thousandths
|
|
70
|
+
of an em, and the layer uses those rounded values. Tracking runs from 0 to 0.5em, leading from 0.8
|
|
71
|
+
to 3 and padding from 0 to 1em.
|
|
72
|
+
- The background replaces the text halo. While a background is active, `haloWidth` and `haloBlur`
|
|
73
|
+
are derived, and `haloColor` is the strip colour. Later refinements of size, tracking, leading or
|
|
74
|
+
font re-derive the stack and halo.
|
|
75
|
+
- Collision still reserves the shaped block. Padding beyond it is drawn outside that box, so keep
|
|
76
|
+
`padding` (text padding) at least as large as the strip padding in pixels.
|
|
77
|
+
|
|
78
|
+
The map's `glyphs` provider must serve derived stacks. `deriveTileflowLineBackgroundGlyphs`
|
|
79
|
+
computes any range from the source stack's range, and `parseTileflowLineBackgroundFontStack`
|
|
80
|
+
recognises derived requests. Local previews and captures derive ranges themselves; hosted and
|
|
81
|
+
self-hosted providers must do the same.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Theme transitions and blends
|
|
2
|
+
|
|
3
|
+
Start with the [@tileflow/core guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/README.md) for installation and a complete first example.
|
|
4
|
+
|
|
5
|
+
A Tileflow map can change theme with a cross-fade, or show any point between two or more of its
|
|
6
|
+
themes. Use a transition when people switch between appearances, such as light and dark. Use a
|
|
7
|
+
blend when the application controls the appearance continuously, such as a slider or a day that
|
|
8
|
+
passes from night to day.
|
|
9
|
+
|
|
10
|
+
Both work on the one MapLibre map the application already has. They create no second map, add no
|
|
11
|
+
map views, and request the same tiles as a map that does not change theme. They need a browser
|
|
12
|
+
document and MapLibre GL JS; the React Native package does not offer them.
|
|
13
|
+
|
|
14
|
+
## Cross-fade a theme change
|
|
15
|
+
|
|
16
|
+
Pass `themeTransition` to the React, Vue, or Svelte map. This React example assumes a map named
|
|
17
|
+
`city` with `light` and `dark` themes in the published manifest:
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import {Map} from '@tileflow/react';
|
|
21
|
+
import {useState} from 'react';
|
|
22
|
+
|
|
23
|
+
export function CityMap() {
|
|
24
|
+
const [theme, setTheme] = useState<'dark' | 'light'>('light');
|
|
25
|
+
return (
|
|
26
|
+
<>
|
|
27
|
+
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>Switch theme</button>
|
|
28
|
+
<Map source={{map: 'city'}} theme={theme} themeTransition={{duration: 450}} />
|
|
29
|
+
</>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
When the theme changes, a snapshot of the current frame covers the map. The snapshot follows the
|
|
35
|
+
camera while people pan, zoom, rotate, or tilt, and fades out once the new theme is drawn. The map
|
|
36
|
+
stays interactive throughout. `onThemeChange` reports `preloading`, `applying`, and finally `ready`
|
|
37
|
+
after the fade. A `theme="system"` change, entering a blend, and leaving one use the same
|
|
38
|
+
transition.
|
|
39
|
+
|
|
40
|
+
`duration` is in milliseconds, from 0 to 5000. It defaults to 0, which changes the theme at once.
|
|
41
|
+
When the browser asks for reduced motion, every change happens at once.
|
|
42
|
+
|
|
43
|
+
## Blend themes
|
|
44
|
+
|
|
45
|
+
Pass `themeBlend` with the themes to blend, in order, and a `position` between them. Position 0
|
|
46
|
+
shows the first theme, 1 the second, and 1.25 a quarter of the way from the second to the third:
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import {Map} from '@tileflow/react';
|
|
50
|
+
import {useState} from 'react';
|
|
51
|
+
|
|
52
|
+
export function DayMap() {
|
|
53
|
+
const [position, setPosition] = useState(0);
|
|
54
|
+
return (
|
|
55
|
+
<>
|
|
56
|
+
<input
|
|
57
|
+
aria-label="Time of day"
|
|
58
|
+
max={2}
|
|
59
|
+
min={0}
|
|
60
|
+
onChange={(event) => setPosition(Number(event.target.value))}
|
|
61
|
+
step={0.01}
|
|
62
|
+
type="range"
|
|
63
|
+
value={position}
|
|
64
|
+
/>
|
|
65
|
+
<Map source={{map: 'city'}} themeBlend={{position, themes: ['night', 'dusk', 'day']}} />
|
|
66
|
+
</>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The first blend of a set of themes loads each theme's style and fonts, prepares one style that
|
|
72
|
+
holds every theme, and replaces the map's style once, with `themeTransition` if set. Until then the
|
|
73
|
+
map shows the theme nearest to the position. After that, changing `position` updates the map at
|
|
74
|
+
once without loading anything, so it can follow a slider, a clock, or an animation frame by frame.
|
|
75
|
+
Changing `themes` prepares a new blend. Removing `themeBlend` returns to `theme`.
|
|
76
|
+
|
|
77
|
+
While a blend is shown, `data-tileflow-theme` names the theme nearest to the position.
|
|
78
|
+
`onThemeChange` reports the preparation of a blend; moving its position reports nothing.
|
|
79
|
+
|
|
80
|
+
### What follows the position
|
|
81
|
+
|
|
82
|
+
- Colours and numbers of the ground, such as land, water, roads, buildings, and their widths and
|
|
83
|
+
opacities, follow the position continuously. Colours mix in the OKLab colour space, so halfway
|
|
84
|
+
between two themes looks halfway to the eye.
|
|
85
|
+
- Patterns, the sky, and light follow the position too. Pattern artwork is mixed in its pixels.
|
|
86
|
+
- Labels, icons, and other symbols change when the nearest theme changes, with a short cross-fade.
|
|
87
|
+
Light lettering on a dark plate and dark lettering on a light plate would meet in the same grey
|
|
88
|
+
halfway, so symbols do not follow the position.
|
|
89
|
+
- A value that depends on feature state, such as a caption that changes colour when highlighted,
|
|
90
|
+
changes with the nearest theme. MapLibre lays its source out again for that change; a cross-fade
|
|
91
|
+
covers it.
|
|
92
|
+
|
|
93
|
+
### Which themes can be blended
|
|
94
|
+
|
|
95
|
+
Blend themes of the same map. Every theme of a map exposes the same token keys, so its compiled
|
|
96
|
+
styles share sources, layers, filters, and expressions, and differ only in colours, numbers, and
|
|
97
|
+
image names. Up to eight themes can be blended. A blend fails, and the map keeps its current
|
|
98
|
+
appearance, when the styles differ in structure, sources, sprite, or glyphs.
|
|
99
|
+
|
|
100
|
+
Icon and pattern artwork is mixed in place of the first theme's image when every theme's version
|
|
101
|
+
has the same size. Otherwise that image changes with the nearest theme instead.
|
|
102
|
+
|
|
103
|
+
### Cost
|
|
104
|
+
|
|
105
|
+
The prepared style holds every theme. A value that depends on feature data, such as a land-use
|
|
106
|
+
colour chosen by class, becomes one layer per class while the blend is shown, so the prepared
|
|
107
|
+
style has more layers than one theme. Physical layer IDs are diagnostic, not stable; semantic
|
|
108
|
+
interactions are not affected.
|
|
109
|
+
|
|
110
|
+
Entering a blend replaces the map's style once. MapLibre then takes about as long as it takes to
|
|
111
|
+
load the map: for a detailed city map, around half a second on a desktop computer and longer on a
|
|
112
|
+
phone, while the transition snapshot, if any, covers the map. Start a blend before people need it
|
|
113
|
+
to move, for example when the map loads.
|
|
114
|
+
|
|
115
|
+
Each position change after that sets the map's themed values directly, without expression parsing.
|
|
116
|
+
For a detailed city map this takes a few milliseconds on a mid-range phone. Positions closer than a
|
|
117
|
+
four-hundredth of a theme are not applied, so a slowly moving position leaves the map at rest
|
|
118
|
+
between changes.
|
|
119
|
+
|
|
120
|
+
## Use the core controller
|
|
121
|
+
|
|
122
|
+
Framework adapters use `createTileflowThemeController` from `@tileflow/core/browser`. A direct
|
|
123
|
+
MapLibre integration can use it too. Resolve runtime styles from the published manifest with
|
|
124
|
+
`resolveTileflowRuntimeStyle` and `resolveTileflowRuntimeThemeBlend` from `@tileflow/core/runtime`:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import {createTileflowThemeController} from '@tileflow/core/browser';
|
|
128
|
+
import {
|
|
129
|
+
resolveTileflowRuntimeStyle,
|
|
130
|
+
resolveTileflowRuntimeThemeBlend,
|
|
131
|
+
} from '@tileflow/core/runtime';
|
|
132
|
+
import type {Map as MapLibreMap} from 'maplibre-gl';
|
|
133
|
+
import type {TileflowRuntimeManifestMap} from '@tileflow/core/runtime';
|
|
134
|
+
|
|
135
|
+
export async function moveThroughTheDay(map: MapLibreMap, manifestMap: TileflowRuntimeManifestMap) {
|
|
136
|
+
const source = {map: 'city'};
|
|
137
|
+
const styleOf = (theme: string) => {
|
|
138
|
+
const style = resolveTileflowRuntimeStyle({manifestMap, source, theme});
|
|
139
|
+
if (!style) throw new Error(`The manifest has no ${theme} theme for ${source.map}.`);
|
|
140
|
+
return style;
|
|
141
|
+
};
|
|
142
|
+
// `initial` is the runtime style the map was created with.
|
|
143
|
+
const controller = createTileflowThemeController({initial: styleOf('day'), map});
|
|
144
|
+
|
|
145
|
+
await controller.setTheme(styleOf('night'), {transition: {duration: 450}});
|
|
146
|
+
|
|
147
|
+
const themes = resolveTileflowRuntimeThemeBlend({
|
|
148
|
+
blend: {position: 0, themes: ['night', 'dusk', 'day']},
|
|
149
|
+
manifestMap,
|
|
150
|
+
source,
|
|
151
|
+
});
|
|
152
|
+
await controller.setBlend({position: 0.5, themes});
|
|
153
|
+
// The same themes: the position applies at once.
|
|
154
|
+
await controller.setBlend({position: 0.6, themes});
|
|
155
|
+
return controller.getBlend(); // {position: 0.6, themes: ['night', 'dusk', 'day']}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
`setTheme` and `setBlend` accept `{transition: {duration}}`;
|
|
160
|
+
`createTileflowThemeController({transition})` sets a default. Requests are serialized and the
|
|
161
|
+
latest wins. A failed change restores the previous appearance and reports `failed` with its error.
|
|
162
|
+
|
|
163
|
+
The controller loads blended themes' style documents with the same request policy it uses for
|
|
164
|
+
style font metadata: same-origin credentials, no redirects, and a bounded size. Pass `loadStyle`
|
|
165
|
+
when styles need another loader.
|