react-native-livechart 3.5.0 → 3.5.1
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarkerOverlay.d.ts","sourceRoot":"","sources":["../../src/components/MarkerOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,MAAM,EACZ,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"MarkerOverlay.d.ts","sourceRoot":"","sources":["../../src/components/MarkerOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,MAAM,EACZ,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAejD,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,MAAM,EACN,YAAY,EACb,MAAM,UAAU,CAAC;AA8FlB;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,MAAM,EACN,OAAO,EACP,OAAO,EACP,IAAI,EACJ,MAAM,EACN,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,MAAM,CAAC,EAAE,WAAW,CAAC,YAAY,EAAE,CAAC,CAAC;IACrC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,WAAW,CAAC,cAAc,EAAE,CAAC,CAAC;CAC1C,2CAgIA"}
|
|
@@ -22,7 +22,9 @@ export declare function isConnectorMarker(m: Marker): boolean;
|
|
|
22
22
|
export declare function markerAppearanceSig(m: Marker): string;
|
|
23
23
|
/** One packed glyph in the atlas image: its source rect + box size. */
|
|
24
24
|
export interface AtlasCell {
|
|
25
|
+
/** Source rect into the (hi-res) atlas texture, in **device** pixels. */
|
|
25
26
|
rect: SkRect;
|
|
27
|
+
/** Logical (DPR-independent) cell width/height, used to center the blit. */
|
|
26
28
|
w: number;
|
|
27
29
|
h: number;
|
|
28
30
|
}
|
|
@@ -31,6 +33,13 @@ export interface MarkerAtlas {
|
|
|
31
33
|
image: SkImage | null;
|
|
32
34
|
/** appearance-signature → cell. */
|
|
33
35
|
cells: Record<string, AtlasCell>;
|
|
36
|
+
/**
|
|
37
|
+
* Device-pixel scale the texture was rasterized at. Cell `rect`s are in
|
|
38
|
+
* texture (device) pixels, while `w`/`h` stay in logical pixels — so the
|
|
39
|
+
* per-frame blit must apply an `RSXform` scale of `1 / scale` to map the
|
|
40
|
+
* hi-res cell back to its logical on-canvas size. See `buildMarkerAtlas`.
|
|
41
|
+
*/
|
|
42
|
+
scale: number;
|
|
34
43
|
}
|
|
35
44
|
/**
|
|
36
45
|
* Rasterize every distinct marker appearance into a single packed atlas image,
|
|
@@ -39,6 +48,12 @@ export interface MarkerAtlas {
|
|
|
39
48
|
*
|
|
40
49
|
* Connector kinds (see `isConnectorMarker`) are skipped — they render via a
|
|
41
50
|
* self-projecting fallback component.
|
|
51
|
+
*
|
|
52
|
+
* The texture is rasterized at `scale` (the screen's device-pixel ratio) so the
|
|
53
|
+
* cells carry enough resolution to stay crisp when blitted onto a retina canvas
|
|
54
|
+
* — every glyph is recorded in logical coords then magnified by `scale`, and the
|
|
55
|
+
* per-frame `drawAtlas` shrinks it back with an `RSXform` scale of `1 / scale`.
|
|
56
|
+
* Without this the logical-sized texture is upscaled ~3× on iOS and looks blurry.
|
|
42
57
|
*/
|
|
43
|
-
export declare function buildMarkerAtlas(markers: Marker[], palette: LiveChartPalette, font: SkFont): MarkerAtlas;
|
|
58
|
+
export declare function buildMarkerAtlas(markers: Marker[], palette: LiveChartPalette, font: SkFont, scale?: number): MarkerAtlas;
|
|
44
59
|
//# sourceMappingURL=markerAtlas.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markerAtlas.d.ts","sourceRoot":"","sources":["../../src/draw/markerAtlas.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,MAAM,EACX,KAAK,OAAO,EAEZ,KAAK,MAAM,EACZ,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAErE,yDAAyD;AACzD,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAQpC,iEAAiE;AACjE,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,gBAAgB,GACxB,MAAM,CAaR;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAOpD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAOrD;AAED,uEAAuE;AACvE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,WAAW;IAC1B,8EAA8E;IAC9E,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACtB,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"markerAtlas.d.ts","sourceRoot":"","sources":["../../src/draw/markerAtlas.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,MAAM,EACX,KAAK,OAAO,EAEZ,KAAK,MAAM,EACZ,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAErE,yDAAyD;AACzD,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAQpC,iEAAiE;AACjE,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,gBAAgB,GACxB,MAAM,CAaR;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAOpD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAOrD;AAED,uEAAuE;AACvE,MAAM,WAAW,SAAS;IACxB,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,WAAW;IAC1B,8EAA8E;IAC9E,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACtB,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACjC;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAC;CACf;AAuKD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,MAAM,EACZ,KAAK,SAAI,GACR,WAAW,CAgDb"}
|
package/package.json
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
type SkFont,
|
|
7
7
|
} from "@shopify/react-native-skia";
|
|
8
8
|
import { useMemo, useRef, useState } from "react";
|
|
9
|
+
import { PixelRatio } from "react-native";
|
|
9
10
|
import {
|
|
10
11
|
useDerivedValue,
|
|
11
12
|
useAnimatedReaction,
|
|
@@ -189,13 +190,19 @@ export function MarkerOverlay({
|
|
|
189
190
|
}, [snapshot]);
|
|
190
191
|
// Cells bake in resolved colors; include the palette fields they depend on.
|
|
191
192
|
const paletteKey = `${palette.bgRgb.join(",")}|${palette.line}|${palette.refLine}|${palette.dotUp}|${palette.refLabel}`;
|
|
193
|
+
// Rasterize at the screen's device-pixel ratio so sprites stay crisp on
|
|
194
|
+
// retina canvases instead of being upscaled from a logical-sized texture.
|
|
195
|
+
const dpr = PixelRatio.get();
|
|
192
196
|
const atlas = useMemo(
|
|
193
|
-
() => buildMarkerAtlas(snapshot, palette, font),
|
|
197
|
+
() => buildMarkerAtlas(snapshot, palette, font, dpr),
|
|
194
198
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- appearanceKey/paletteKey capture the inputs that change cell pixels
|
|
195
|
-
[appearanceKey, paletteKey, font],
|
|
199
|
+
[appearanceKey, paletteKey, font, dpr],
|
|
196
200
|
);
|
|
197
201
|
const cells: Record<string, AtlasCell> = atlas.cells;
|
|
198
202
|
const atlasImage = atlas.image;
|
|
203
|
+
// Inverse of the texture's device-pixel scale; shrinks each hi-res cell back
|
|
204
|
+
// to its logical on-canvas size in the per-frame blit.
|
|
205
|
+
const invScale = 1 / atlas.scale;
|
|
199
206
|
|
|
200
207
|
// One pooled, ping-ponged projection buffer reused every frame (no per-frame
|
|
201
208
|
// array allocation for the projection itself).
|
|
@@ -240,15 +247,16 @@ export function MarkerOverlay({
|
|
|
240
247
|
if (isConnectorMarker(m)) continue;
|
|
241
248
|
const cell = cells[markerAppearanceSig(m)];
|
|
242
249
|
if (!cell) continue;
|
|
243
|
-
// Center the cell on the projected point
|
|
250
|
+
// Center the cell on the projected point. The cell's source rect is in
|
|
251
|
+
// device pixels, so scale by 1/dpr to land it at its logical size.
|
|
244
252
|
transforms.push(
|
|
245
|
-
Skia.RSXform(
|
|
253
|
+
Skia.RSXform(invScale, 0, pt.x - cell.w / 2, pt.y - cell.h / 2),
|
|
246
254
|
);
|
|
247
255
|
sprites.push(cell.rect);
|
|
248
256
|
}
|
|
249
257
|
return { transforms, sprites };
|
|
250
258
|
},
|
|
251
|
-
[cells, markers, engine, padding, series, lineData],
|
|
259
|
+
[cells, invScale, markers, engine, padding, series, lineData],
|
|
252
260
|
);
|
|
253
261
|
const transforms = useDerivedValue(() => atlasData.get().transforms, [atlasData]);
|
|
254
262
|
const sprites = useDerivedValue(() => atlasData.get().sprites, [atlasData]);
|
package/src/draw/markerAtlas.ts
CHANGED
|
@@ -74,7 +74,9 @@ export function markerAppearanceSig(m: Marker): string {
|
|
|
74
74
|
|
|
75
75
|
/** One packed glyph in the atlas image: its source rect + box size. */
|
|
76
76
|
export interface AtlasCell {
|
|
77
|
+
/** Source rect into the (hi-res) atlas texture, in **device** pixels. */
|
|
77
78
|
rect: SkRect;
|
|
79
|
+
/** Logical (DPR-independent) cell width/height, used to center the blit. */
|
|
78
80
|
w: number;
|
|
79
81
|
h: number;
|
|
80
82
|
}
|
|
@@ -84,9 +86,16 @@ export interface MarkerAtlas {
|
|
|
84
86
|
image: SkImage | null;
|
|
85
87
|
/** appearance-signature → cell. */
|
|
86
88
|
cells: Record<string, AtlasCell>;
|
|
89
|
+
/**
|
|
90
|
+
* Device-pixel scale the texture was rasterized at. Cell `rect`s are in
|
|
91
|
+
* texture (device) pixels, while `w`/`h` stay in logical pixels — so the
|
|
92
|
+
* per-frame blit must apply an `RSXform` scale of `1 / scale` to map the
|
|
93
|
+
* hi-res cell back to its logical on-canvas size. See `buildMarkerAtlas`.
|
|
94
|
+
*/
|
|
95
|
+
scale: number;
|
|
87
96
|
}
|
|
88
97
|
|
|
89
|
-
const EMPTY_ATLAS: MarkerAtlas = { image: null, cells: {} };
|
|
98
|
+
const EMPTY_ATLAS: MarkerAtlas = { image: null, cells: {}, scale: 1 };
|
|
90
99
|
|
|
91
100
|
function fillPaint(color: string): SkPaint {
|
|
92
101
|
const p = Skia.Paint();
|
|
@@ -258,11 +267,18 @@ function cellSpec(m: Marker, palette: LiveChartPalette, font: SkFont): CellSpec
|
|
|
258
267
|
*
|
|
259
268
|
* Connector kinds (see `isConnectorMarker`) are skipped — they render via a
|
|
260
269
|
* self-projecting fallback component.
|
|
270
|
+
*
|
|
271
|
+
* The texture is rasterized at `scale` (the screen's device-pixel ratio) so the
|
|
272
|
+
* cells carry enough resolution to stay crisp when blitted onto a retina canvas
|
|
273
|
+
* — every glyph is recorded in logical coords then magnified by `scale`, and the
|
|
274
|
+
* per-frame `drawAtlas` shrinks it back with an `RSXform` scale of `1 / scale`.
|
|
275
|
+
* Without this the logical-sized texture is upscaled ~3× on iOS and looks blurry.
|
|
261
276
|
*/
|
|
262
277
|
export function buildMarkerAtlas(
|
|
263
278
|
markers: Marker[],
|
|
264
279
|
palette: LiveChartPalette,
|
|
265
280
|
font: SkFont,
|
|
281
|
+
scale = 1,
|
|
266
282
|
): MarkerAtlas {
|
|
267
283
|
const seen = new Set<string>();
|
|
268
284
|
const specs: { sig: string; spec: CellSpec }[] = [];
|
|
@@ -282,11 +298,16 @@ export function buildMarkerAtlas(
|
|
|
282
298
|
totalW += specs[i].spec.w;
|
|
283
299
|
if (specs[i].spec.h > maxH) maxH = specs[i].spec.h;
|
|
284
300
|
}
|
|
301
|
+
// Logical packed size; the texture itself is `scale`× larger in each axis.
|
|
285
302
|
const W = Math.max(1, Math.ceil(totalW));
|
|
286
303
|
const H = Math.max(1, Math.ceil(maxH));
|
|
304
|
+
const texW = Math.max(1, Math.ceil(W * scale));
|
|
305
|
+
const texH = Math.max(1, Math.ceil(H * scale));
|
|
287
306
|
|
|
288
307
|
const recorder = Skia.PictureRecorder();
|
|
289
|
-
const canvas = recorder.beginRecording(Skia.XYWHRect(0, 0,
|
|
308
|
+
const canvas = recorder.beginRecording(Skia.XYWHRect(0, 0, texW, texH));
|
|
309
|
+
// Magnify so glyphs drawn in logical coords fill the hi-res texture.
|
|
310
|
+
canvas.scale(scale, scale);
|
|
290
311
|
const cells: Record<string, AtlasCell> = {};
|
|
291
312
|
let x = 0;
|
|
292
313
|
for (let i = 0; i < specs.length; i++) {
|
|
@@ -295,10 +316,15 @@ export function buildMarkerAtlas(
|
|
|
295
316
|
canvas.translate(x, 0);
|
|
296
317
|
spec.draw(canvas, spec.w / 2, H / 2);
|
|
297
318
|
canvas.restore();
|
|
298
|
-
|
|
319
|
+
// Source rect indexes the device-pixel texture; w/h stay logical.
|
|
320
|
+
cells[sig] = {
|
|
321
|
+
rect: Skia.XYWHRect(x * scale, 0, spec.w * scale, texH),
|
|
322
|
+
w: spec.w,
|
|
323
|
+
h: H,
|
|
324
|
+
};
|
|
299
325
|
x += spec.w;
|
|
300
326
|
}
|
|
301
327
|
const picture = recorder.finishRecordingAsPicture();
|
|
302
|
-
const image = drawAsImageFromPicture(picture, { width:
|
|
303
|
-
return { image, cells };
|
|
328
|
+
const image = drawAsImageFromPicture(picture, { width: texW, height: texH });
|
|
329
|
+
return { image, cells, scale };
|
|
304
330
|
}
|