@opendata-ai/openchart-vanilla 7.3.0 → 7.4.0
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/dist/index.js +208 -28
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +3 -3
- package/src/__tests__/font-race.test.ts +199 -0
- package/src/__tests__/svg-renderer.test.ts +6 -4
- package/src/barlist-mount.ts +58 -3
- package/src/barlist-renderer.ts +4 -1
- package/src/measure-text.ts +93 -6
- package/src/mount.ts +65 -2
- package/src/renderers/axes.ts +7 -7
- package/src/renderers/brand.ts +6 -4
- package/src/renderers/chrome.ts +7 -4
- package/src/sankey-mount.ts +62 -2
- package/src/sankey-renderer.ts +4 -1
- package/src/svg-renderer.ts +6 -4
- package/src/tilemap-mount.ts +60 -4
- package/src/tilemap-renderer.ts +23 -5
package/dist/index.js
CHANGED
|
@@ -41,6 +41,7 @@ function setupTableAnimationCleanup(wrapper) {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
// src/barlist-renderer.ts
|
|
44
|
+
import { textAscent } from "@opendata-ai/openchart-core";
|
|
44
45
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
45
46
|
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
|
46
47
|
var BRAND_URL = "https://tryopendata.ai";
|
|
@@ -64,7 +65,7 @@ function renderChrome(parent, layout) {
|
|
|
64
65
|
const text = createSVGElement("text");
|
|
65
66
|
setAttrs(text, {
|
|
66
67
|
x: el.x,
|
|
67
|
-
y: isBottom ? bottomOffset + el.y : el.y
|
|
68
|
+
y: (isBottom ? bottomOffset + el.y : el.y) + textAscent(el.style.fontSize)
|
|
68
69
|
});
|
|
69
70
|
text.setAttribute("class", `oc-${key}`);
|
|
70
71
|
text.setAttribute("font-family", el.style.fontFamily);
|
|
@@ -468,7 +469,8 @@ function csvEscape(value) {
|
|
|
468
469
|
|
|
469
470
|
// src/measure-text.ts
|
|
470
471
|
import { estimateTextWidth } from "@opendata-ai/openchart-core";
|
|
471
|
-
|
|
472
|
+
var DEFAULT_FONT_FAMILY = "Inter, sans-serif";
|
|
473
|
+
function createMeasureText(fontFamily = DEFAULT_FONT_FAMILY) {
|
|
472
474
|
let canvas = null;
|
|
473
475
|
let ctx = null;
|
|
474
476
|
return (text, fontSize, fontWeight) => {
|
|
@@ -483,7 +485,7 @@ function createMeasureText() {
|
|
|
483
485
|
};
|
|
484
486
|
}
|
|
485
487
|
const weight = fontWeight ?? 400;
|
|
486
|
-
ctx.font = `${weight} ${fontSize}px
|
|
488
|
+
ctx.font = `${weight} ${fontSize}px ${fontFamily}`;
|
|
487
489
|
const metrics = ctx.measureText(text);
|
|
488
490
|
return {
|
|
489
491
|
width: metrics.width,
|
|
@@ -491,6 +493,57 @@ function createMeasureText() {
|
|
|
491
493
|
};
|
|
492
494
|
};
|
|
493
495
|
}
|
|
496
|
+
function resolveFontFamily(container) {
|
|
497
|
+
if (typeof window === "undefined" || typeof getComputedStyle !== "function") {
|
|
498
|
+
return DEFAULT_FONT_FAMILY;
|
|
499
|
+
}
|
|
500
|
+
try {
|
|
501
|
+
const style = getComputedStyle(container);
|
|
502
|
+
const custom = style.getPropertyValue("--oc-font-family").trim();
|
|
503
|
+
if (custom) return custom;
|
|
504
|
+
const computed = style.fontFamily?.trim();
|
|
505
|
+
if (computed) return computed;
|
|
506
|
+
} catch {
|
|
507
|
+
}
|
|
508
|
+
return DEFAULT_FONT_FAMILY;
|
|
509
|
+
}
|
|
510
|
+
function primaryFontName(fontFamily) {
|
|
511
|
+
const first = fontFamily.split(",")[0]?.trim() ?? "";
|
|
512
|
+
return first.replace(/^["']|["']$/g, "").trim();
|
|
513
|
+
}
|
|
514
|
+
function fontsPending(fontFamily) {
|
|
515
|
+
if (typeof document === "undefined") return false;
|
|
516
|
+
const fonts = document.fonts;
|
|
517
|
+
if (!fonts || typeof fonts.check !== "function") return false;
|
|
518
|
+
const name = primaryFontName(fontFamily);
|
|
519
|
+
if (!name) return false;
|
|
520
|
+
const generics = /* @__PURE__ */ new Set([
|
|
521
|
+
"sans-serif",
|
|
522
|
+
"serif",
|
|
523
|
+
"monospace",
|
|
524
|
+
"system-ui",
|
|
525
|
+
"cursive",
|
|
526
|
+
"fantasy",
|
|
527
|
+
"ui-sans-serif",
|
|
528
|
+
"ui-serif",
|
|
529
|
+
"ui-monospace"
|
|
530
|
+
]);
|
|
531
|
+
if (generics.has(name.toLowerCase())) return false;
|
|
532
|
+
try {
|
|
533
|
+
return !fonts.check(`12px "${name}"`);
|
|
534
|
+
} catch {
|
|
535
|
+
return false;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
function scheduleFontReload(fontFamily, isAlive, onReady) {
|
|
539
|
+
if (!fontsPending(fontFamily)) return false;
|
|
540
|
+
const fonts = document.fonts;
|
|
541
|
+
if (!fonts?.ready) return false;
|
|
542
|
+
fonts.ready.then(() => {
|
|
543
|
+
if (isAlive()) onReady();
|
|
544
|
+
});
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
494
547
|
|
|
495
548
|
// src/resize-observer.ts
|
|
496
549
|
var DEBOUNCE_MS = 16;
|
|
@@ -627,7 +680,14 @@ function createBarList(container, spec, options) {
|
|
|
627
680
|
let disconnectResize = null;
|
|
628
681
|
let animationCleanup = null;
|
|
629
682
|
let pendingResize = false;
|
|
630
|
-
|
|
683
|
+
let fontsReloadPending = false;
|
|
684
|
+
container.classList.add("oc-barlist-root");
|
|
685
|
+
function resolveEffectiveFont() {
|
|
686
|
+
return options?.theme?.fonts?.family ?? currentSpec.theme?.fonts?.family ?? resolveFontFamily(container);
|
|
687
|
+
}
|
|
688
|
+
let fontFamily = resolveEffectiveFont();
|
|
689
|
+
let measureText = createMeasureText(fontFamily);
|
|
690
|
+
let renderGen = 0;
|
|
631
691
|
function getContainerDimensions() {
|
|
632
692
|
const rect = container.getBoundingClientRect();
|
|
633
693
|
return {
|
|
@@ -747,9 +807,20 @@ function createBarList(container, spec, options) {
|
|
|
747
807
|
}
|
|
748
808
|
});
|
|
749
809
|
}
|
|
810
|
+
renderGen += 1;
|
|
811
|
+
container.dataset.ocRenderGen = String(renderGen);
|
|
812
|
+
if (fontsReloadPending) {
|
|
813
|
+
fontsReloadPending = false;
|
|
814
|
+
container.dataset.ocFontsState = "ready";
|
|
815
|
+
}
|
|
750
816
|
}
|
|
751
817
|
function update(newSpec) {
|
|
752
818
|
currentSpec = newSpec;
|
|
819
|
+
const nextFont = resolveEffectiveFont();
|
|
820
|
+
if (nextFont !== fontFamily) {
|
|
821
|
+
fontFamily = nextFont;
|
|
822
|
+
measureText = createMeasureText(fontFamily);
|
|
823
|
+
}
|
|
753
824
|
currentLayout = compile();
|
|
754
825
|
render();
|
|
755
826
|
}
|
|
@@ -803,12 +874,20 @@ function createBarList(container, spec, options) {
|
|
|
803
874
|
}
|
|
804
875
|
container.classList.remove("oc-barlist-root", "oc-dark");
|
|
805
876
|
}
|
|
806
|
-
container.classList.add("oc-barlist-root");
|
|
807
877
|
if (resolveDarkMode(options?.darkMode)) {
|
|
808
878
|
container.classList.add("oc-dark");
|
|
809
879
|
}
|
|
810
880
|
currentLayout = compile();
|
|
811
881
|
render(true);
|
|
882
|
+
const fontsPending2 = scheduleFontReload(
|
|
883
|
+
fontFamily,
|
|
884
|
+
() => !destroyed,
|
|
885
|
+
() => {
|
|
886
|
+
fontsReloadPending = true;
|
|
887
|
+
resize();
|
|
888
|
+
}
|
|
889
|
+
);
|
|
890
|
+
container.dataset.ocFontsState = fontsPending2 ? "pending" : "ready";
|
|
812
891
|
if (options?.responsive !== false) {
|
|
813
892
|
disconnectResize = observeResize(container, () => resize());
|
|
814
893
|
}
|
|
@@ -5259,7 +5338,8 @@ import {
|
|
|
5259
5338
|
axisTitleOffset,
|
|
5260
5339
|
estimateTextWidth as estimateTextWidth2,
|
|
5261
5340
|
getAxisTitleOffset,
|
|
5262
|
-
TICK_LABEL_OFFSET
|
|
5341
|
+
TICK_LABEL_OFFSET,
|
|
5342
|
+
textAscent as textAscent2
|
|
5263
5343
|
} from "@opendata-ai/openchart-core";
|
|
5264
5344
|
function appendCompoundLabel(parent, primaryText, subtitle, fontWeight) {
|
|
5265
5345
|
const primarySpan = createSVGElement2("tspan");
|
|
@@ -5314,9 +5394,8 @@ function renderAxis(parent, axis, orientation, layout) {
|
|
|
5314
5394
|
const xLabelPad = axis.labelPadding ?? layout.theme.spacing.xAxisLabelPadding;
|
|
5315
5395
|
setAttrs2(label, {
|
|
5316
5396
|
x: tick.position,
|
|
5317
|
-
y: area.y + area.height + xLabelPad,
|
|
5318
|
-
"text-anchor": "middle"
|
|
5319
|
-
"dominant-baseline": "hanging"
|
|
5397
|
+
y: area.y + area.height + xLabelPad + textAscent2(axis.tickLabelStyle.fontSize),
|
|
5398
|
+
"text-anchor": "middle"
|
|
5320
5399
|
});
|
|
5321
5400
|
}
|
|
5322
5401
|
applyTextStyle(label, axis.tickLabelStyle);
|
|
@@ -5522,7 +5601,7 @@ function renderAxes(parent, layout) {
|
|
|
5522
5601
|
}
|
|
5523
5602
|
|
|
5524
5603
|
// src/renderers/brand.ts
|
|
5525
|
-
import { BRAND_FONT_SIZE as BRAND_FONT_SIZE2, BRAND_MIN_WIDTH as BRAND_MIN_WIDTH2 } from "@opendata-ai/openchart-core";
|
|
5604
|
+
import { BRAND_FONT_SIZE as BRAND_FONT_SIZE2, BRAND_MIN_WIDTH as BRAND_MIN_WIDTH2, textAscent as textAscent3 } from "@opendata-ai/openchart-core";
|
|
5526
5605
|
var BRAND_URL2 = "https://tryopendata.ai";
|
|
5527
5606
|
function renderBrand(parent, layout) {
|
|
5528
5607
|
if (layout.dimensions.width < BRAND_MIN_WIDTH2) return;
|
|
@@ -5546,8 +5625,7 @@ function renderBrand(parent, layout) {
|
|
|
5546
5625
|
const text = createSVGElement2("text");
|
|
5547
5626
|
setAttrs2(text, {
|
|
5548
5627
|
x: rightEdge,
|
|
5549
|
-
y: chromeY,
|
|
5550
|
-
"dominant-baseline": "hanging",
|
|
5628
|
+
y: chromeY + textAscent3(BRAND_LARGE),
|
|
5551
5629
|
"font-family": layout.theme.fonts.family,
|
|
5552
5630
|
"font-size": BRAND_FONT_SIZE2,
|
|
5553
5631
|
"text-anchor": "end",
|
|
@@ -5572,10 +5650,10 @@ function renderBrand(parent, layout) {
|
|
|
5572
5650
|
}
|
|
5573
5651
|
|
|
5574
5652
|
// src/renderers/chrome.ts
|
|
5575
|
-
import { estimateTextWidth as estimateTextWidth3, wrapText } from "@opendata-ai/openchart-core";
|
|
5653
|
+
import { estimateTextWidth as estimateTextWidth3, textAscent as textAscent4, wrapText } from "@opendata-ai/openchart-core";
|
|
5576
5654
|
function renderChromeElement(parent, element, className, chromeKey, measureText, uppercase = false) {
|
|
5577
5655
|
const text = createSVGElement2("text");
|
|
5578
|
-
setAttrs2(text, { x: element.x, y: element.y });
|
|
5656
|
+
setAttrs2(text, { x: element.x, y: element.y + textAscent4(element.style.fontSize) });
|
|
5579
5657
|
applyTextStyle(text, element.style);
|
|
5580
5658
|
text.setAttribute("class", className);
|
|
5581
5659
|
text.setAttribute("data-chrome-key", chromeKey);
|
|
@@ -6292,10 +6370,12 @@ function renderChartSVG(layout, container, opts) {
|
|
|
6292
6370
|
setAttrs2(svg, {
|
|
6293
6371
|
viewBox: `0 0 ${width} ${height}`,
|
|
6294
6372
|
xmlns: SVG_NS3,
|
|
6295
|
-
//
|
|
6296
|
-
//
|
|
6297
|
-
//
|
|
6298
|
-
//
|
|
6373
|
+
// The SVG spec default is overflow:"hidden", which clips anything a hair
|
|
6374
|
+
// outside the viewBox. We now position all text on the alphabetic/central
|
|
6375
|
+
// baseline (dominant-baseline:hanging was dropped because WebKit computed
|
|
6376
|
+
// it from different metrics), but WebKit/iOS still reports getBBox extents
|
|
6377
|
+
// with a few pixels of slack around tspans, so text touching an edge can
|
|
6378
|
+
// still get clipped. overflow:visible avoids that. Chart marks are already
|
|
6299
6379
|
// constrained by a clipPath, so nothing bleeds out.
|
|
6300
6380
|
overflow: "visible",
|
|
6301
6381
|
// Hint browsers to enable sub-pixel font hinting and kerning for chart text.
|
|
@@ -6647,13 +6727,20 @@ function createChart(container, spec, options) {
|
|
|
6647
6727
|
let isFirstRender = true;
|
|
6648
6728
|
let cleanupAnimations = null;
|
|
6649
6729
|
let pendingResize = false;
|
|
6730
|
+
let fontsReloadPending = false;
|
|
6650
6731
|
let selectedElement = options?.selectedElement ?? null;
|
|
6651
6732
|
let overlayElement = null;
|
|
6652
6733
|
let isTextEditingActive = false;
|
|
6653
6734
|
const runtimeHiddenSeries = /* @__PURE__ */ new Set();
|
|
6654
6735
|
const runtimeShownSeries = /* @__PURE__ */ new Set();
|
|
6655
6736
|
let textEditCleanup = null;
|
|
6656
|
-
|
|
6737
|
+
container.classList.add("oc-root");
|
|
6738
|
+
function resolveEffectiveFont() {
|
|
6739
|
+
return options?.theme?.fonts?.family ?? currentSpec.theme?.fonts?.family ?? resolveFontFamily(container);
|
|
6740
|
+
}
|
|
6741
|
+
let fontFamily = resolveEffectiveFont();
|
|
6742
|
+
let measureText = createMeasureText(fontFamily);
|
|
6743
|
+
let renderGen = 0;
|
|
6657
6744
|
function compile() {
|
|
6658
6745
|
const { width, height } = getContainerDimensions();
|
|
6659
6746
|
const darkMode = resolveDarkMode3(options?.darkMode);
|
|
@@ -7101,6 +7188,12 @@ function createChart(container, spec, options) {
|
|
|
7101
7188
|
}
|
|
7102
7189
|
});
|
|
7103
7190
|
}
|
|
7191
|
+
renderGen += 1;
|
|
7192
|
+
container.dataset.ocRenderGen = String(renderGen);
|
|
7193
|
+
if (fontsReloadPending) {
|
|
7194
|
+
fontsReloadPending = false;
|
|
7195
|
+
container.dataset.ocFontsState = "ready";
|
|
7196
|
+
}
|
|
7104
7197
|
if (isFirstRender) {
|
|
7105
7198
|
isFirstRender = false;
|
|
7106
7199
|
}
|
|
@@ -7108,6 +7201,11 @@ function createChart(container, spec, options) {
|
|
|
7108
7201
|
function update(newSpec, updateOpts) {
|
|
7109
7202
|
if (destroyed) return;
|
|
7110
7203
|
currentSpec = newSpec;
|
|
7204
|
+
const nextFont = resolveEffectiveFont();
|
|
7205
|
+
if (nextFont !== fontFamily) {
|
|
7206
|
+
fontFamily = nextFont;
|
|
7207
|
+
measureText = createMeasureText(fontFamily);
|
|
7208
|
+
}
|
|
7111
7209
|
runtimeHiddenSeries.clear();
|
|
7112
7210
|
runtimeShownSeries.clear();
|
|
7113
7211
|
if (updateOpts && "selectedElement" in updateOpts) {
|
|
@@ -7198,6 +7296,15 @@ function createChart(container, spec, options) {
|
|
|
7198
7296
|
container.classList.remove("oc-root");
|
|
7199
7297
|
}
|
|
7200
7298
|
render();
|
|
7299
|
+
const pending = scheduleFontReload(
|
|
7300
|
+
fontFamily,
|
|
7301
|
+
() => !destroyed,
|
|
7302
|
+
() => {
|
|
7303
|
+
fontsReloadPending = true;
|
|
7304
|
+
resize();
|
|
7305
|
+
}
|
|
7306
|
+
);
|
|
7307
|
+
container.dataset.ocFontsState = pending ? "pending" : "ready";
|
|
7201
7308
|
if (options?.responsive !== false) {
|
|
7202
7309
|
disconnectResize = observeResize(container, () => {
|
|
7203
7310
|
resize();
|
|
@@ -7556,6 +7663,7 @@ import {
|
|
|
7556
7663
|
BRAND_FONT_SIZE as BRAND_FONT_SIZE3,
|
|
7557
7664
|
BRAND_MIN_WIDTH as BRAND_MIN_WIDTH3,
|
|
7558
7665
|
estimateTextWidth as estimateTextWidth5,
|
|
7666
|
+
textAscent as textAscent5,
|
|
7559
7667
|
wrapText as wrapText2
|
|
7560
7668
|
} from "@opendata-ai/openchart-core";
|
|
7561
7669
|
import { clampStaggerDelay as clampStaggerDelay2 } from "@opendata-ai/openchart-engine";
|
|
@@ -7599,7 +7707,7 @@ function stampAnimationAttrs2(el, mark, fallbackIndex, animation) {
|
|
|
7599
7707
|
}
|
|
7600
7708
|
function renderChromeElement2(parent, element, className, chromeKey, measureText) {
|
|
7601
7709
|
const text = createSVGElement3("text");
|
|
7602
|
-
setAttrs3(text, { x: element.x, y: element.y });
|
|
7710
|
+
setAttrs3(text, { x: element.x, y: element.y + textAscent5(element.style.fontSize) });
|
|
7603
7711
|
applyTextStyle2(text, element.style);
|
|
7604
7712
|
text.setAttribute("class", className);
|
|
7605
7713
|
text.setAttribute("data-chrome-key", chromeKey);
|
|
@@ -7984,7 +8092,14 @@ function createSankey(container, spec, options) {
|
|
|
7984
8092
|
let isFirstRender = true;
|
|
7985
8093
|
let animationCleanup = null;
|
|
7986
8094
|
let pendingResize = false;
|
|
7987
|
-
|
|
8095
|
+
let fontsReloadPending = false;
|
|
8096
|
+
container.classList.add("oc-sankey-root");
|
|
8097
|
+
function resolveEffectiveFont() {
|
|
8098
|
+
return options?.theme?.fonts?.family ?? currentSpec.theme?.fonts?.family ?? resolveFontFamily(container);
|
|
8099
|
+
}
|
|
8100
|
+
let fontFamily = resolveEffectiveFont();
|
|
8101
|
+
let measureText = createMeasureText(fontFamily);
|
|
8102
|
+
let renderGen = 0;
|
|
7988
8103
|
function getContainerDimensions() {
|
|
7989
8104
|
const rect = container.getBoundingClientRect();
|
|
7990
8105
|
return {
|
|
@@ -8190,10 +8305,21 @@ function createSankey(container, spec, options) {
|
|
|
8190
8305
|
}
|
|
8191
8306
|
});
|
|
8192
8307
|
}
|
|
8308
|
+
renderGen += 1;
|
|
8309
|
+
container.dataset.ocRenderGen = String(renderGen);
|
|
8310
|
+
if (fontsReloadPending) {
|
|
8311
|
+
fontsReloadPending = false;
|
|
8312
|
+
container.dataset.ocFontsState = "ready";
|
|
8313
|
+
}
|
|
8193
8314
|
}
|
|
8194
8315
|
function update(newSpec) {
|
|
8195
8316
|
if (destroyed) return;
|
|
8196
8317
|
currentSpec = newSpec;
|
|
8318
|
+
const nextFont = resolveEffectiveFont();
|
|
8319
|
+
if (nextFont !== fontFamily) {
|
|
8320
|
+
fontFamily = nextFont;
|
|
8321
|
+
measureText = createMeasureText(fontFamily);
|
|
8322
|
+
}
|
|
8197
8323
|
isFirstRender = true;
|
|
8198
8324
|
render();
|
|
8199
8325
|
}
|
|
@@ -8250,6 +8376,7 @@ function createSankey(container, spec, options) {
|
|
|
8250
8376
|
}
|
|
8251
8377
|
svgElement = null;
|
|
8252
8378
|
container.classList.remove("oc-dark");
|
|
8379
|
+
container.classList.remove("oc-sankey-root");
|
|
8253
8380
|
}
|
|
8254
8381
|
try {
|
|
8255
8382
|
currentLayout = compile();
|
|
@@ -8277,10 +8404,21 @@ function createSankey(container, spec, options) {
|
|
|
8277
8404
|
}
|
|
8278
8405
|
});
|
|
8279
8406
|
}
|
|
8407
|
+
renderGen += 1;
|
|
8408
|
+
container.dataset.ocRenderGen = String(renderGen);
|
|
8280
8409
|
} catch (err) {
|
|
8281
8410
|
console.error("[viz] Sankey mount failed:", err);
|
|
8282
8411
|
throw err;
|
|
8283
8412
|
}
|
|
8413
|
+
const fontsPending2 = scheduleFontReload(
|
|
8414
|
+
fontFamily,
|
|
8415
|
+
() => !destroyed,
|
|
8416
|
+
() => {
|
|
8417
|
+
fontsReloadPending = true;
|
|
8418
|
+
resize();
|
|
8419
|
+
}
|
|
8420
|
+
);
|
|
8421
|
+
container.dataset.ocFontsState = fontsPending2 ? "pending" : "ready";
|
|
8284
8422
|
if (options?.responsive !== false) {
|
|
8285
8423
|
disconnectResize = observeResize(container, () => {
|
|
8286
8424
|
resize();
|
|
@@ -9135,6 +9273,7 @@ function createTable(container, spec, options) {
|
|
|
9135
9273
|
import { compileTileMap } from "@opendata-ai/openchart-engine";
|
|
9136
9274
|
|
|
9137
9275
|
// src/tilemap-renderer.ts
|
|
9276
|
+
import { textAscent as textAscent6 } from "@opendata-ai/openchart-core";
|
|
9138
9277
|
var SVG_NS5 = "http://www.w3.org/2000/svg";
|
|
9139
9278
|
var XLINK_NS4 = "http://www.w3.org/1999/xlink";
|
|
9140
9279
|
var BRAND_URL5 = "https://tryopendata.ai";
|
|
@@ -9158,7 +9297,10 @@ function renderChrome4(parent, layout) {
|
|
|
9158
9297
|
const bottomOffset = layout.area.y + layout.area.height;
|
|
9159
9298
|
if (chrome.title) {
|
|
9160
9299
|
const text = createSVGElement4("text");
|
|
9161
|
-
setAttrs4(text, {
|
|
9300
|
+
setAttrs4(text, {
|
|
9301
|
+
x: chrome.title.x,
|
|
9302
|
+
y: chrome.title.y + textAscent6(chrome.title.style.fontSize)
|
|
9303
|
+
});
|
|
9162
9304
|
text.setAttribute("class", "oc-title");
|
|
9163
9305
|
text.setAttribute("font-family", chrome.title.style.fontFamily);
|
|
9164
9306
|
text.setAttribute("font-size", String(chrome.title.style.fontSize));
|
|
@@ -9169,7 +9311,10 @@ function renderChrome4(parent, layout) {
|
|
|
9169
9311
|
}
|
|
9170
9312
|
if (chrome.subtitle) {
|
|
9171
9313
|
const text = createSVGElement4("text");
|
|
9172
|
-
setAttrs4(text, {
|
|
9314
|
+
setAttrs4(text, {
|
|
9315
|
+
x: chrome.subtitle.x,
|
|
9316
|
+
y: chrome.subtitle.y + textAscent6(chrome.subtitle.style.fontSize)
|
|
9317
|
+
});
|
|
9173
9318
|
text.setAttribute("class", "oc-subtitle");
|
|
9174
9319
|
text.setAttribute("font-family", chrome.subtitle.style.fontFamily);
|
|
9175
9320
|
text.setAttribute("font-size", String(chrome.subtitle.style.fontSize));
|
|
@@ -9183,7 +9328,10 @@ function renderChrome4(parent, layout) {
|
|
|
9183
9328
|
}
|
|
9184
9329
|
if (chrome.source) {
|
|
9185
9330
|
const text = createSVGElement4("text");
|
|
9186
|
-
setAttrs4(text, {
|
|
9331
|
+
setAttrs4(text, {
|
|
9332
|
+
x: chrome.source.x,
|
|
9333
|
+
y: bottomOffset + chrome.source.y + textAscent6(chrome.source.style.fontSize)
|
|
9334
|
+
});
|
|
9187
9335
|
text.setAttribute("class", "oc-source");
|
|
9188
9336
|
text.setAttribute("font-family", chrome.source.style.fontFamily);
|
|
9189
9337
|
text.setAttribute("font-size", String(chrome.source.style.fontSize));
|
|
@@ -9197,7 +9345,10 @@ function renderChrome4(parent, layout) {
|
|
|
9197
9345
|
}
|
|
9198
9346
|
if (chrome.byline) {
|
|
9199
9347
|
const text = createSVGElement4("text");
|
|
9200
|
-
setAttrs4(text, {
|
|
9348
|
+
setAttrs4(text, {
|
|
9349
|
+
x: chrome.byline.x,
|
|
9350
|
+
y: bottomOffset + chrome.byline.y + textAscent6(chrome.byline.style.fontSize)
|
|
9351
|
+
});
|
|
9201
9352
|
text.setAttribute("class", "oc-byline");
|
|
9202
9353
|
text.setAttribute("font-family", chrome.byline.style.fontFamily);
|
|
9203
9354
|
text.setAttribute("font-size", String(chrome.byline.style.fontSize));
|
|
@@ -9211,7 +9362,10 @@ function renderChrome4(parent, layout) {
|
|
|
9211
9362
|
}
|
|
9212
9363
|
if (chrome.footer) {
|
|
9213
9364
|
const text = createSVGElement4("text");
|
|
9214
|
-
setAttrs4(text, {
|
|
9365
|
+
setAttrs4(text, {
|
|
9366
|
+
x: chrome.footer.x,
|
|
9367
|
+
y: bottomOffset + chrome.footer.y + textAscent6(chrome.footer.style.fontSize)
|
|
9368
|
+
});
|
|
9215
9369
|
text.setAttribute("class", "oc-footer");
|
|
9216
9370
|
text.setAttribute("font-family", chrome.footer.style.fontFamily);
|
|
9217
9371
|
text.setAttribute("font-size", String(chrome.footer.style.fontSize));
|
|
@@ -9474,7 +9628,14 @@ function createTileMap(container, spec, options) {
|
|
|
9474
9628
|
let disconnectResize = null;
|
|
9475
9629
|
let animationCleanup = null;
|
|
9476
9630
|
let pendingResize = false;
|
|
9477
|
-
|
|
9631
|
+
let fontsReloadPending = false;
|
|
9632
|
+
container.classList.add("oc-tilemap-root");
|
|
9633
|
+
function resolveEffectiveFont() {
|
|
9634
|
+
return options?.theme?.fonts?.family ?? currentSpec.theme?.fonts?.family ?? resolveFontFamily(container);
|
|
9635
|
+
}
|
|
9636
|
+
let fontFamily = resolveEffectiveFont();
|
|
9637
|
+
let measureText = createMeasureText(fontFamily);
|
|
9638
|
+
let renderGen = 0;
|
|
9478
9639
|
function getContainerDimensions() {
|
|
9479
9640
|
const rect = container.getBoundingClientRect();
|
|
9480
9641
|
const width = Math.max(rect.width || 600, 100);
|
|
@@ -9587,9 +9748,20 @@ function createTileMap(container, spec, options) {
|
|
|
9587
9748
|
}
|
|
9588
9749
|
});
|
|
9589
9750
|
}
|
|
9751
|
+
renderGen += 1;
|
|
9752
|
+
container.dataset.ocRenderGen = String(renderGen);
|
|
9753
|
+
if (fontsReloadPending) {
|
|
9754
|
+
fontsReloadPending = false;
|
|
9755
|
+
container.dataset.ocFontsState = "ready";
|
|
9756
|
+
}
|
|
9590
9757
|
}
|
|
9591
9758
|
function update(newSpec) {
|
|
9592
9759
|
currentSpec = newSpec;
|
|
9760
|
+
const nextFont = resolveEffectiveFont();
|
|
9761
|
+
if (nextFont !== fontFamily) {
|
|
9762
|
+
fontFamily = nextFont;
|
|
9763
|
+
measureText = createMeasureText(fontFamily);
|
|
9764
|
+
}
|
|
9593
9765
|
currentLayout = compile();
|
|
9594
9766
|
render();
|
|
9595
9767
|
}
|
|
@@ -9643,12 +9815,20 @@ function createTileMap(container, spec, options) {
|
|
|
9643
9815
|
}
|
|
9644
9816
|
container.classList.remove("oc-tilemap-root", "oc-dark");
|
|
9645
9817
|
}
|
|
9646
|
-
container.classList.add("oc-tilemap-root");
|
|
9647
9818
|
if (resolveDarkMode6(options?.darkMode)) {
|
|
9648
9819
|
container.classList.add("oc-dark");
|
|
9649
9820
|
}
|
|
9650
9821
|
currentLayout = compile();
|
|
9651
9822
|
render(true);
|
|
9823
|
+
const fontsPending2 = scheduleFontReload(
|
|
9824
|
+
fontFamily,
|
|
9825
|
+
() => !destroyed,
|
|
9826
|
+
() => {
|
|
9827
|
+
fontsReloadPending = true;
|
|
9828
|
+
resize();
|
|
9829
|
+
}
|
|
9830
|
+
);
|
|
9831
|
+
container.dataset.ocFontsState = fontsPending2 ? "pending" : "ready";
|
|
9652
9832
|
if (options?.responsive !== false) {
|
|
9653
9833
|
disconnectResize = observeResize(container, () => {
|
|
9654
9834
|
resize();
|