@react-x11/components 0.3.0 → 0.5.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/README.md +131 -4
- package/dist/charts/components.d.ts +3 -1
- package/dist/charts/components.d.ts.map +1 -1
- package/dist/charts/components.js +8 -4
- package/dist/charts/components.js.map +1 -1
- package/dist/charts/node.d.ts +13 -6
- package/dist/charts/node.d.ts.map +1 -1
- package/dist/charts/node.js +75 -24
- package/dist/charts/node.js.map +1 -1
- package/dist/charts/render.d.ts +4 -0
- package/dist/charts/render.d.ts.map +1 -1
- package/dist/charts/render.js +11 -6
- package/dist/charts/render.js.map +1 -1
- package/dist/code-editor/node.d.ts +47 -16
- package/dist/code-editor/node.d.ts.map +1 -1
- package/dist/code-editor/node.js +121 -51
- package/dist/code-editor/node.js.map +1 -1
- package/dist/flow/draw.d.ts +19 -1
- package/dist/flow/draw.d.ts.map +1 -1
- package/dist/flow/draw.js +64 -35
- package/dist/flow/draw.js.map +1 -1
- package/dist/flow/index.d.ts.map +1 -1
- package/dist/flow/index.js +24 -8
- package/dist/flow/index.js.map +1 -1
- package/dist/flow/model.d.ts +4 -2
- package/dist/flow/model.d.ts.map +1 -1
- package/dist/flow/model.js +4 -2
- package/dist/flow/model.js.map +1 -1
- package/dist/flow/node.d.ts +40 -9
- package/dist/flow/node.d.ts.map +1 -1
- package/dist/flow/node.js +142 -53
- package/dist/flow/node.js.map +1 -1
- package/dist/flow/types.d.ts +46 -21
- package/dist/flow/types.d.ts.map +1 -1
- package/dist/formula/index.d.ts +4 -2
- package/dist/formula/index.d.ts.map +1 -1
- package/dist/formula/index.js.map +1 -1
- package/dist/formula/node.d.ts +5 -1
- package/dist/formula/node.d.ts.map +1 -1
- package/dist/formula/node.js +19 -3
- package/dist/formula/node.js.map +1 -1
- package/dist/html/controls.d.ts +4 -1
- package/dist/html/controls.d.ts.map +1 -1
- package/dist/html/controls.js.map +1 -1
- package/dist/html/css/cascade.d.ts +11 -5
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +18 -8
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/parse.d.ts +15 -10
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +41 -16
- package/dist/html/css/parse.js.map +1 -1
- package/dist/html/css/style.d.ts +3 -0
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +3 -1
- package/dist/html/css/style.js.map +1 -1
- package/dist/html/css/values.d.ts +14 -1
- package/dist/html/css/values.d.ts.map +1 -1
- package/dist/html/css/values.js +11 -8
- package/dist/html/css/values.js.map +1 -1
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +1 -0
- package/dist/html/index.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +12 -5
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +7 -4
- package/dist/html/layout/boxes.js.map +1 -1
- package/dist/html/layout/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +22 -1
- package/dist/html/layout/inline.js.map +1 -1
- package/dist/html/node.d.ts +22 -8
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +97 -15
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts +3 -0
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +2 -2
- package/dist/html/paint.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -1
- package/dist/maps/clip.d.ts +43 -0
- package/dist/maps/clip.d.ts.map +1 -0
- package/dist/maps/clip.js +171 -0
- package/dist/maps/clip.js.map +1 -0
- package/dist/maps/gzip.d.ts +15 -0
- package/dist/maps/gzip.d.ts.map +1 -0
- package/dist/maps/gzip.js +56 -0
- package/dist/maps/gzip.js.map +1 -0
- package/dist/maps/index.d.ts +55 -0
- package/dist/maps/index.d.ts.map +1 -0
- package/dist/maps/index.js +141 -0
- package/dist/maps/index.js.map +1 -0
- package/dist/maps/labels.d.ts +123 -0
- package/dist/maps/labels.d.ts.map +1 -0
- package/dist/maps/labels.js +323 -0
- package/dist/maps/labels.js.map +1 -0
- package/dist/maps/mvt.d.ts +244 -0
- package/dist/maps/mvt.d.ts.map +1 -0
- package/dist/maps/mvt.js +820 -0
- package/dist/maps/mvt.js.map +1 -0
- package/dist/maps/node.d.ts +278 -0
- package/dist/maps/node.d.ts.map +1 -0
- package/dist/maps/node.js +1459 -0
- package/dist/maps/node.js.map +1 -0
- package/dist/maps/overlay.d.ts +157 -0
- package/dist/maps/overlay.d.ts.map +1 -0
- package/dist/maps/overlay.js +472 -0
- package/dist/maps/overlay.js.map +1 -0
- package/dist/maps/paint.d.ts +226 -0
- package/dist/maps/paint.d.ts.map +1 -0
- package/dist/maps/paint.js +705 -0
- package/dist/maps/paint.js.map +1 -0
- package/dist/maps/proj.d.ts +281 -0
- package/dist/maps/proj.d.ts.map +1 -0
- package/dist/maps/proj.js +451 -0
- package/dist/maps/proj.js.map +1 -0
- package/dist/maps/sources.d.ts +256 -0
- package/dist/maps/sources.d.ts.map +1 -0
- package/dist/maps/sources.js +210 -0
- package/dist/maps/sources.js.map +1 -0
- package/dist/maps/style.d.ts +141 -0
- package/dist/maps/style.d.ts.map +1 -0
- package/dist/maps/style.js +147 -0
- package/dist/maps/style.js.map +1 -0
- package/dist/maps/styles.d.ts +82 -0
- package/dist/maps/styles.d.ts.map +1 -0
- package/dist/maps/styles.js +898 -0
- package/dist/maps/styles.js.map +1 -0
- package/dist/maps/tiles.d.ts +283 -0
- package/dist/maps/tiles.d.ts.map +1 -0
- package/dist/maps/tiles.js +469 -0
- package/dist/maps/tiles.js.map +1 -0
- package/dist/maps/types.d.ts +244 -0
- package/dist/maps/types.d.ts.map +1 -0
- package/dist/maps/types.js +2 -0
- package/dist/maps/types.js.map +1 -0
- package/dist/qml/containers.d.ts +3 -0
- package/dist/qml/containers.d.ts.map +1 -0
- package/dist/qml/containers.js +331 -0
- package/dist/qml/containers.js.map +1 -0
- package/dist/qml/controls.d.ts +12 -0
- package/dist/qml/controls.d.ts.map +1 -0
- package/dist/qml/controls.js +21 -0
- package/dist/qml/controls.js.map +1 -0
- package/dist/qml/globals.d.ts +6 -0
- package/dist/qml/globals.d.ts.map +1 -0
- package/dist/qml/globals.js +25 -0
- package/dist/qml/globals.js.map +1 -0
- package/dist/qml/index.d.ts +15 -0
- package/dist/qml/index.d.ts.map +1 -0
- package/dist/qml/index.js +25 -0
- package/dist/qml/index.js.map +1 -0
- package/dist/qml/interaction.d.ts +12 -0
- package/dist/qml/interaction.d.ts.map +1 -0
- package/dist/qml/interaction.js +246 -0
- package/dist/qml/interaction.js.map +1 -0
- package/dist/qml/ir.d.ts +106 -0
- package/dist/qml/ir.d.ts.map +1 -0
- package/dist/qml/ir.js +7 -0
- package/dist/qml/ir.js.map +1 -0
- package/dist/qml/layouts.d.ts +3 -0
- package/dist/qml/layouts.d.ts.map +1 -0
- package/dist/qml/layouts.js +122 -0
- package/dist/qml/layouts.js.map +1 -0
- package/dist/qml/models.d.ts +14 -0
- package/dist/qml/models.d.ts.map +1 -0
- package/dist/qml/models.js +80 -0
- package/dist/qml/models.js.map +1 -0
- package/dist/qml/objects.d.ts +228 -0
- package/dist/qml/objects.d.ts.map +1 -0
- package/dist/qml/objects.js +1103 -0
- package/dist/qml/objects.js.map +1 -0
- package/dist/qml/parse.d.ts +10 -0
- package/dist/qml/parse.d.ts.map +1 -0
- package/dist/qml/parse.js +607 -0
- package/dist/qml/parse.js.map +1 -0
- package/dist/qml/qtquick.d.ts +7 -0
- package/dist/qml/qtquick.d.ts.map +1 -0
- package/dist/qml/qtquick.js +347 -0
- package/dist/qml/qtquick.js.map +1 -0
- package/dist/qml/react.d.ts +83 -0
- package/dist/qml/react.d.ts.map +1 -0
- package/dist/qml/react.js +323 -0
- package/dist/qml/react.js.map +1 -0
- package/dist/qml/resolver.d.ts +38 -0
- package/dist/qml/resolver.d.ts.map +1 -0
- package/dist/qml/resolver.js +64 -0
- package/dist/qml/resolver.js.map +1 -0
- package/dist/qml/slots.d.ts +65 -0
- package/dist/qml/slots.d.ts.map +1 -0
- package/dist/qml/slots.js +230 -0
- package/dist/qml/slots.js.map +1 -0
- package/dist/qml/states.d.ts +5 -0
- package/dist/qml/states.d.ts.map +1 -0
- package/dist/qml/states.js +276 -0
- package/dist/qml/states.js.map +1 -0
- package/dist/qml/view-utils.d.ts +42 -0
- package/dist/qml/view-utils.d.ts.map +1 -0
- package/dist/qml/view-utils.js +121 -0
- package/dist/qml/view-utils.js.map +1 -0
- package/dist/reorder/hx.d.ts +18 -0
- package/dist/reorder/hx.d.ts.map +1 -0
- package/dist/reorder/hx.js +10 -0
- package/dist/reorder/hx.js.map +1 -0
- package/dist/reorder/index.d.ts +314 -0
- package/dist/reorder/index.d.ts.map +1 -0
- package/dist/reorder/index.js +1539 -0
- package/dist/reorder/index.js.map +1 -0
- package/dist/reorder/model.d.ts +107 -0
- package/dist/reorder/model.d.ts.map +1 -0
- package/dist/reorder/model.js +162 -0
- package/dist/reorder/model.js.map +1 -0
- package/dist/richtext/node.d.ts +15 -5
- package/dist/richtext/node.d.ts.map +1 -1
- package/dist/richtext/node.js +40 -11
- package/dist/richtext/node.js.map +1 -1
- package/dist/richtext/runs.d.ts +35 -13
- package/dist/richtext/runs.d.ts.map +1 -1
- package/dist/richtext/runs.js +83 -27
- package/dist/richtext/runs.js.map +1 -1
- package/dist/tabs/hx.d.ts +18 -0
- package/dist/tabs/hx.d.ts.map +1 -0
- package/dist/tabs/hx.js +10 -0
- package/dist/tabs/hx.js.map +1 -0
- package/dist/tabs/index.d.ts +160 -0
- package/dist/tabs/index.d.ts.map +1 -0
- package/dist/tabs/index.js +1265 -0
- package/dist/tabs/index.js.map +1 -0
- package/dist/terminal/vt/fonts.d.ts +45 -15
- package/dist/terminal/vt/fonts.d.ts.map +1 -1
- package/dist/terminal/vt/fonts.js +89 -19
- package/dist/terminal/vt/fonts.js.map +1 -1
- package/dist/terminal/vt/index.d.ts +1 -1
- package/dist/terminal/vt/index.d.ts.map +1 -1
- package/dist/terminal/vt/index.js +3 -3
- package/dist/terminal/vt/index.js.map +1 -1
- package/dist/terminal/vt/node.d.ts +42 -0
- package/dist/terminal/vt/node.d.ts.map +1 -1
- package/dist/terminal/vt/node.js +95 -11
- package/dist/terminal/vt/node.js.map +1 -1
- package/dist/terminal/vt/pty.d.ts +16 -0
- package/dist/terminal/vt/pty.d.ts.map +1 -1
- package/dist/terminal/vt/pty.js +186 -0
- package/dist/terminal/vt/pty.js.map +1 -1
- package/dist/terminal/vt/renderer.d.ts.map +1 -1
- package/dist/terminal/vt/renderer.js +13 -3
- package/dist/terminal/vt/renderer.js.map +1 -1
- package/package.json +23 -3
- package/src/charts/components.ts +14 -7
- package/src/charts/node.ts +81 -26
- package/src/charts/render.ts +16 -6
- package/src/code-editor/node.ts +147 -53
- package/src/flow/draw.ts +104 -35
- package/src/flow/index.ts +33 -13
- package/src/flow/model.ts +4 -2
- package/src/flow/node.ts +158 -59
- package/src/flow/types.ts +46 -21
- package/src/formula/index.ts +4 -2
- package/src/formula/node.ts +24 -5
- package/src/html/controls.ts +4 -1
- package/src/html/css/cascade.ts +18 -7
- package/src/html/css/parse.ts +46 -21
- package/src/html/css/style.ts +6 -1
- package/src/html/css/values.ts +25 -9
- package/src/html/index.ts +1 -0
- package/src/html/layout/boxes.ts +19 -9
- package/src/html/layout/inline.ts +23 -1
- package/src/html/node.ts +110 -17
- package/src/html/paint.ts +17 -2
- package/src/index.ts +142 -0
- package/src/maps/clip.ts +184 -0
- package/src/maps/gzip.ts +66 -0
- package/src/maps/index.ts +316 -0
- package/src/maps/labels.ts +442 -0
- package/src/maps/mvt.ts +857 -0
- package/src/maps/node.ts +1819 -0
- package/src/maps/overlay.ts +639 -0
- package/src/maps/paint.ts +978 -0
- package/src/maps/proj.ts +641 -0
- package/src/maps/sources.ts +425 -0
- package/src/maps/style.ts +309 -0
- package/src/maps/styles.ts +1040 -0
- package/src/maps/tiles.ts +676 -0
- package/src/maps/types.ts +260 -0
- package/src/qml/containers.tsx +380 -0
- package/src/qml/controls.tsx +47 -0
- package/src/qml/globals.ts +33 -0
- package/src/qml/index.ts +67 -0
- package/src/qml/interaction.tsx +317 -0
- package/src/qml/ir.ts +80 -0
- package/src/qml/layouts.tsx +141 -0
- package/src/qml/models.ts +101 -0
- package/src/qml/objects.ts +1431 -0
- package/src/qml/parse.ts +624 -0
- package/src/qml/qtquick.tsx +413 -0
- package/src/qml/react.tsx +454 -0
- package/src/qml/resolver.ts +99 -0
- package/src/qml/slots.ts +249 -0
- package/src/qml/states.ts +318 -0
- package/src/qml/view-utils.ts +140 -0
- package/src/reorder/hx.ts +31 -0
- package/src/reorder/index.ts +2223 -0
- package/src/reorder/model.ts +232 -0
- package/src/richtext/node.ts +49 -14
- package/src/richtext/runs.ts +115 -30
- package/src/tabs/hx.ts +31 -0
- package/src/tabs/index.ts +1686 -0
- package/src/terminal/vt/fonts.ts +128 -36
- package/src/terminal/vt/index.ts +4 -2
- package/src/terminal/vt/node.ts +105 -12
- package/src/terminal/vt/pty.ts +243 -0
- package/src/terminal/vt/renderer.ts +13 -3
package/src/flow/draw.ts
CHANGED
|
@@ -9,6 +9,17 @@
|
|
|
9
9
|
// returns `null` there, the pane skips its drawing, and a custom node type
|
|
10
10
|
// written against `FlowPainter` never has to know (see `src/sparkline/`,
|
|
11
11
|
// which makes the same check for one stroke).
|
|
12
|
+
//
|
|
13
|
+
// It is also where the display scale is applied. The pane, and every node
|
|
14
|
+
// type drawing through this, think in logical pixels — the unit a style
|
|
15
|
+
// length is in, the unit an event's `x`/`y` arrive in — while ntk's context
|
|
16
|
+
// draws on the device grid, which on a retina panel is two pixels to the
|
|
17
|
+
// logical one (react-x11's docs/scale.md). The multiply happens here, once,
|
|
18
|
+
// on the way into the context: geometry by `scale`, and text by shaping at
|
|
19
|
+
// `size * scale` so a label on a 2x panel is sharper rather than twice as
|
|
20
|
+
// big or half as small. Deliberately not a `ctx.scale()`: ntk positions
|
|
21
|
+
// glyphs through the transform but sizes them from the font, and a
|
|
22
|
+
// non-identity transform forfeits every server-side fast path a fill has.
|
|
12
23
|
import type {
|
|
13
24
|
FlowPainter,
|
|
14
25
|
ShapeOptions,
|
|
@@ -47,7 +58,8 @@ interface LayoutLike {
|
|
|
47
58
|
draw(ctx: unknown, x: number, y: number): void;
|
|
48
59
|
}
|
|
49
60
|
|
|
50
|
-
/** One shaped string, kept between frames.
|
|
61
|
+
/** One shaped string, kept between frames. `width` and `height` are
|
|
62
|
+
* logical; the layout itself was shaped at device size. */
|
|
51
63
|
export interface CachedText {
|
|
52
64
|
width: number;
|
|
53
65
|
height: number;
|
|
@@ -69,6 +81,13 @@ export interface PainterOptions {
|
|
|
69
81
|
family: string;
|
|
70
82
|
/** Ink for text that names no colour. */
|
|
71
83
|
color: string;
|
|
84
|
+
/**
|
|
85
|
+
* Device pixels per logical pixel — the display scale the pane's window
|
|
86
|
+
* resolved to. Everything handed to the painter is logical; this is the
|
|
87
|
+
* one multiply on the way to the context, and the one divide on the way
|
|
88
|
+
* back from a measured layout.
|
|
89
|
+
*/
|
|
90
|
+
scale: number;
|
|
72
91
|
/**
|
|
73
92
|
* Laid-out text, keyed by face, size, weight, colour and the string.
|
|
74
93
|
*
|
|
@@ -92,13 +111,30 @@ function isCanvas(ctx: unknown): ctx is CanvasLike {
|
|
|
92
111
|
/** Bound, so a pathological graph cannot turn the width cache into a leak. */
|
|
93
112
|
const CACHE_LIMIT = 4000;
|
|
94
113
|
|
|
114
|
+
/**
|
|
115
|
+
* A logical value on the device grid.
|
|
116
|
+
*
|
|
117
|
+
* A value the pane already put on whole device pixels has to *arrive* as the
|
|
118
|
+
* integer it is: `x * 1.5` is not always one in floating point, and ntk's
|
|
119
|
+
* fast paths for a rounded box, a stroke and a blit are all gated on
|
|
120
|
+
* integral geometry. Anything else is left alone — the sub-pixel position
|
|
121
|
+
* of a bezier's control point is not something to snap.
|
|
122
|
+
*/
|
|
123
|
+
export function toDevice(value: number, scale: number): number {
|
|
124
|
+
const out = value * scale;
|
|
125
|
+
const whole = Math.round(out);
|
|
126
|
+
return Math.abs(out - whole) < 1e-6 ? whole : out;
|
|
127
|
+
}
|
|
128
|
+
|
|
95
129
|
function fontStyle(
|
|
96
130
|
opts: PainterOptions,
|
|
97
131
|
options: TextOptions | undefined,
|
|
98
132
|
): Record<string, unknown> {
|
|
99
133
|
return {
|
|
100
134
|
family: options?.family ?? opts.family,
|
|
101
|
-
|
|
135
|
+
// `app.fonts` takes device sizes — core hands it `fontSize * scale`
|
|
136
|
+
// for the same reason — so the face is shaped for the panel's grid.
|
|
137
|
+
size: (options?.size ?? 13) * opts.scale,
|
|
102
138
|
weight: options?.weight ?? 400,
|
|
103
139
|
style: 'normal',
|
|
104
140
|
color: options?.color ?? opts.color,
|
|
@@ -121,15 +157,17 @@ function shape(
|
|
|
121
157
|
const size = options?.size ?? 13;
|
|
122
158
|
const family = options?.family ?? opts.family;
|
|
123
159
|
// The colour is part of the key: it is baked into the layout, so two
|
|
124
|
-
// labels that differ only in ink are two shaped runs.
|
|
160
|
+
// labels that differ only in ink are two shaped runs. The scale is not:
|
|
161
|
+
// it is constant for the life of the pane that owns the cache.
|
|
125
162
|
const key = `${family}|${size}|${options?.weight ?? 400}|${options?.color ?? opts.color}|${text}`;
|
|
126
163
|
const hit = cache.get(key);
|
|
127
164
|
if (hit) return hit;
|
|
128
165
|
const layout = fonts.layout(text, fontStyle(opts, options));
|
|
129
166
|
if (cache.size >= CACHE_LIMIT) cache.clear();
|
|
167
|
+
const s = opts.scale;
|
|
130
168
|
const entry = {
|
|
131
|
-
width: layout.width,
|
|
132
|
-
height: layout.height
|
|
169
|
+
width: layout.width / s,
|
|
170
|
+
height: layout.height ? layout.height / s : size * 1.3,
|
|
133
171
|
layout,
|
|
134
172
|
};
|
|
135
173
|
cache.set(key, entry);
|
|
@@ -153,6 +191,7 @@ export function measureText(
|
|
|
153
191
|
|
|
154
192
|
class Painter implements FlowPainter {
|
|
155
193
|
readonly raw: unknown;
|
|
194
|
+
readonly scale: number;
|
|
156
195
|
private readonly ctx: CanvasLike;
|
|
157
196
|
private readonly opts: PainterOptions;
|
|
158
197
|
|
|
@@ -160,6 +199,12 @@ class Painter implements FlowPainter {
|
|
|
160
199
|
this.ctx = ctx;
|
|
161
200
|
this.raw = ctx;
|
|
162
201
|
this.opts = opts;
|
|
202
|
+
this.scale = opts.scale;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** A logical coordinate or length as the context wants it. */
|
|
206
|
+
private d(value: number): number {
|
|
207
|
+
return toDevice(value, this.scale);
|
|
163
208
|
}
|
|
164
209
|
|
|
165
210
|
save(): void {
|
|
@@ -174,9 +219,9 @@ class Painter implements FlowPainter {
|
|
|
174
219
|
const { ctx } = this;
|
|
175
220
|
ctx.beginPath();
|
|
176
221
|
if (radius > 0 && typeof ctx.roundRect === 'function') {
|
|
177
|
-
ctx.roundRect(x, y, w, h, radius);
|
|
222
|
+
ctx.roundRect(this.d(x), this.d(y), this.d(w), this.d(h), this.d(radius));
|
|
178
223
|
} else {
|
|
179
|
-
ctx.rect(x, y, w, h);
|
|
224
|
+
ctx.rect(this.d(x), this.d(y), this.d(w), this.d(h));
|
|
180
225
|
}
|
|
181
226
|
ctx.clip();
|
|
182
227
|
}
|
|
@@ -184,10 +229,12 @@ class Painter implements FlowPainter {
|
|
|
184
229
|
private applyStroke(options: StrokeOptions): void {
|
|
185
230
|
const { ctx } = this;
|
|
186
231
|
ctx.strokeStyle = options.stroke ?? this.opts.color;
|
|
187
|
-
ctx.lineWidth = options.lineWidth ?? 1;
|
|
232
|
+
ctx.lineWidth = this.d(options.lineWidth ?? 1);
|
|
188
233
|
if (typeof ctx.setLineDash === 'function') {
|
|
189
|
-
ctx.setLineDash(options.dash ?
|
|
190
|
-
if ('lineDashOffset' in ctx)
|
|
234
|
+
ctx.setLineDash(options.dash ? options.dash.map((v) => this.d(v)) : []);
|
|
235
|
+
if ('lineDashOffset' in ctx) {
|
|
236
|
+
ctx.lineDashOffset = this.d(options.dashOffset ?? 0);
|
|
237
|
+
}
|
|
191
238
|
}
|
|
192
239
|
}
|
|
193
240
|
|
|
@@ -215,12 +262,21 @@ class Painter implements FlowPainter {
|
|
|
215
262
|
// single server-side rectangle rather than a path to rasterize.
|
|
216
263
|
if (!rounded && !options.stroke && options.fill) {
|
|
217
264
|
ctx.fillStyle = options.fill;
|
|
218
|
-
ctx.fillRect(x, y, w, h);
|
|
265
|
+
ctx.fillRect(this.d(x), this.d(y), this.d(w), this.d(h));
|
|
219
266
|
return;
|
|
220
267
|
}
|
|
221
268
|
ctx.beginPath();
|
|
222
|
-
if (rounded)
|
|
223
|
-
|
|
269
|
+
if (rounded) {
|
|
270
|
+
ctx.roundRect!(
|
|
271
|
+
this.d(x),
|
|
272
|
+
this.d(y),
|
|
273
|
+
this.d(w),
|
|
274
|
+
this.d(h),
|
|
275
|
+
this.d(radius),
|
|
276
|
+
);
|
|
277
|
+
} else {
|
|
278
|
+
ctx.rect(this.d(x), this.d(y), this.d(w), this.d(h));
|
|
279
|
+
}
|
|
224
280
|
if (options.fill) {
|
|
225
281
|
ctx.fillStyle = options.fill;
|
|
226
282
|
ctx.fill();
|
|
@@ -239,14 +295,19 @@ class Painter implements FlowPainter {
|
|
|
239
295
|
ctx.beginPath();
|
|
240
296
|
if (rounded) {
|
|
241
297
|
ctx.roundRect!(
|
|
242
|
-
x + inset,
|
|
243
|
-
y + inset,
|
|
244
|
-
w - pen,
|
|
245
|
-
h - pen,
|
|
246
|
-
Math.max(0, radius - inset),
|
|
298
|
+
this.d(x + inset),
|
|
299
|
+
this.d(y + inset),
|
|
300
|
+
this.d(w - pen),
|
|
301
|
+
this.d(h - pen),
|
|
302
|
+
this.d(Math.max(0, radius - inset)),
|
|
247
303
|
);
|
|
248
304
|
} else {
|
|
249
|
-
ctx.rect(
|
|
305
|
+
ctx.rect(
|
|
306
|
+
this.d(x + inset),
|
|
307
|
+
this.d(y + inset),
|
|
308
|
+
this.d(w - pen),
|
|
309
|
+
this.d(h - pen),
|
|
310
|
+
);
|
|
250
311
|
}
|
|
251
312
|
}
|
|
252
313
|
this.applyStroke(options);
|
|
@@ -259,7 +320,7 @@ class Painter implements FlowPainter {
|
|
|
259
320
|
if (r <= 0) return;
|
|
260
321
|
const { ctx } = this;
|
|
261
322
|
ctx.beginPath();
|
|
262
|
-
ctx.arc(x, y, r, 0, Math.PI * 2);
|
|
323
|
+
ctx.arc(this.d(x), this.d(y), this.d(r), 0, Math.PI * 2);
|
|
263
324
|
if (options.fill) {
|
|
264
325
|
ctx.fillStyle = options.fill;
|
|
265
326
|
ctx.fill();
|
|
@@ -271,13 +332,20 @@ class Painter implements FlowPainter {
|
|
|
271
332
|
}
|
|
272
333
|
}
|
|
273
334
|
|
|
335
|
+
private trace(points: readonly XYPosition[], close: boolean): void {
|
|
336
|
+
const { ctx } = this;
|
|
337
|
+
ctx.moveTo(this.d(points[0].x), this.d(points[0].y));
|
|
338
|
+
for (let i = 1; i < points.length; i++) {
|
|
339
|
+
ctx.lineTo(this.d(points[i].x), this.d(points[i].y));
|
|
340
|
+
}
|
|
341
|
+
if (close) ctx.closePath();
|
|
342
|
+
}
|
|
343
|
+
|
|
274
344
|
polyline(points: readonly XYPosition[], options: StrokeOptions): void {
|
|
275
345
|
if (points.length < 2) return;
|
|
276
346
|
const { ctx } = this;
|
|
277
347
|
ctx.beginPath();
|
|
278
|
-
|
|
279
|
-
for (let i = 1; i < points.length; i++)
|
|
280
|
-
ctx.lineTo(points[i].x, points[i].y);
|
|
348
|
+
this.trace(points, false);
|
|
281
349
|
this.applyStroke(options);
|
|
282
350
|
ctx.lineJoin = 'round';
|
|
283
351
|
ctx.lineCap = 'round';
|
|
@@ -295,8 +363,7 @@ class Painter implements FlowPainter {
|
|
|
295
363
|
for (const run of runs) {
|
|
296
364
|
if (run.length < 2) continue;
|
|
297
365
|
any = true;
|
|
298
|
-
|
|
299
|
-
for (let i = 1; i < run.length; i++) ctx.lineTo(run[i].x, run[i].y);
|
|
366
|
+
this.trace(run, false);
|
|
300
367
|
}
|
|
301
368
|
if (!any) return;
|
|
302
369
|
this.applyStroke(options);
|
|
@@ -308,8 +375,11 @@ class Painter implements FlowPainter {
|
|
|
308
375
|
if (centres.length === 0 || size <= 0) return;
|
|
309
376
|
const { ctx } = this;
|
|
310
377
|
const half = size / 2;
|
|
378
|
+
const side = this.d(size);
|
|
311
379
|
ctx.beginPath();
|
|
312
|
-
for (const c of centres)
|
|
380
|
+
for (const c of centres) {
|
|
381
|
+
ctx.rect(this.d(c.x - half), this.d(c.y - half), side, side);
|
|
382
|
+
}
|
|
313
383
|
ctx.fillStyle = color;
|
|
314
384
|
ctx.fill();
|
|
315
385
|
}
|
|
@@ -324,10 +394,7 @@ class Painter implements FlowPainter {
|
|
|
324
394
|
for (const points of shapes) {
|
|
325
395
|
if (points.length < 3) continue;
|
|
326
396
|
any = true;
|
|
327
|
-
|
|
328
|
-
for (let i = 1; i < points.length; i++)
|
|
329
|
-
ctx.lineTo(points[i].x, points[i].y);
|
|
330
|
-
ctx.closePath();
|
|
397
|
+
this.trace(points, true);
|
|
331
398
|
}
|
|
332
399
|
if (!any) return;
|
|
333
400
|
if (options.fill) {
|
|
@@ -345,10 +412,7 @@ class Painter implements FlowPainter {
|
|
|
345
412
|
if (points.length < 3) return;
|
|
346
413
|
const { ctx } = this;
|
|
347
414
|
ctx.beginPath();
|
|
348
|
-
|
|
349
|
-
for (let i = 1; i < points.length; i++)
|
|
350
|
-
ctx.lineTo(points[i].x, points[i].y);
|
|
351
|
-
ctx.closePath();
|
|
415
|
+
this.trace(points, true);
|
|
352
416
|
if (options.fill) {
|
|
353
417
|
ctx.fillStyle = options.fill;
|
|
354
418
|
ctx.fill();
|
|
@@ -401,7 +465,12 @@ class Painter implements FlowPainter {
|
|
|
401
465
|
? -layout.width
|
|
402
466
|
: 0;
|
|
403
467
|
const dy = options?.baseline === 'middle' ? -layout.height / 2 : 0;
|
|
404
|
-
|
|
468
|
+
// Rounded on the device grid, where the glyphs land.
|
|
469
|
+
entry.layout.draw(
|
|
470
|
+
this.raw,
|
|
471
|
+
Math.round(this.d(x + dx)),
|
|
472
|
+
Math.round(this.d(y + dy)),
|
|
473
|
+
);
|
|
405
474
|
}
|
|
406
475
|
}
|
|
407
476
|
|
package/src/flow/index.ts
CHANGED
|
@@ -309,6 +309,16 @@ export function Flow<N = FlowNodeData, E = unknown>(
|
|
|
309
309
|
const node = byId.get(body.id);
|
|
310
310
|
const type = node && nodeTypes?.[node.type ?? 'default'];
|
|
311
311
|
if (!node || !type?.render) return null;
|
|
312
|
+
// The two boxes are two units. The outer one is the pane's: it is
|
|
313
|
+
// positioned and clipped in the same logical window pixels the pane
|
|
314
|
+
// painted the card in, so the body lands on the card exactly. The
|
|
315
|
+
// inner one is the body's, and `scale` is what makes the difference
|
|
316
|
+
// between them the zoom (react-x11#449, core 2.6): every length
|
|
317
|
+
// under it is multiplied by that factor, so a body sized in graph
|
|
318
|
+
// units comes out at the size the card is drawn at, with its text
|
|
319
|
+
// shaped at that size rather than stretched.
|
|
320
|
+
const width = body.width / body.zoom;
|
|
321
|
+
const height = body.height / body.zoom;
|
|
312
322
|
return React.createElement(
|
|
313
323
|
'box',
|
|
314
324
|
{
|
|
@@ -319,22 +329,32 @@ export function Flow<N = FlowNodeData, E = unknown>(
|
|
|
319
329
|
top: body.y,
|
|
320
330
|
width: body.width,
|
|
321
331
|
height: body.height,
|
|
322
|
-
//
|
|
323
|
-
// this is what stops
|
|
324
|
-
// the graph.
|
|
332
|
+
// A body is free to overflow what it was given — a popup's
|
|
333
|
+
// fallback, a long line — and this is what stops it spilling
|
|
334
|
+
// over the graph.
|
|
325
335
|
overflow: 'hidden',
|
|
326
336
|
},
|
|
327
337
|
},
|
|
328
|
-
React.createElement(
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
+
React.createElement(
|
|
339
|
+
'box',
|
|
340
|
+
{
|
|
341
|
+
scale: body.zoom,
|
|
342
|
+
// Sized in the unit it establishes, which is what makes it
|
|
343
|
+
// fill the outer box at every zoom.
|
|
344
|
+
style: { width, height },
|
|
345
|
+
},
|
|
346
|
+
React.createElement(FlowNodeBody, {
|
|
347
|
+
type: type as FlowNodeType<unknown>,
|
|
348
|
+
node: node as FlowNode<unknown>,
|
|
349
|
+
selected: body.selected,
|
|
350
|
+
zoom: body.zoom,
|
|
351
|
+
// Graph units, like everything else the body sees.
|
|
352
|
+
x: body.x / body.zoom,
|
|
353
|
+
y: body.y / body.zoom,
|
|
354
|
+
width,
|
|
355
|
+
height,
|
|
356
|
+
}),
|
|
357
|
+
),
|
|
338
358
|
);
|
|
339
359
|
})
|
|
340
360
|
: null;
|
package/src/flow/model.ts
CHANGED
|
@@ -53,8 +53,10 @@ export const NODE_HEADER = 26;
|
|
|
53
53
|
/** How far a `render` node's body is inset from its own border, so the
|
|
54
54
|
* resize grips and the border stay the pane's to hit. */
|
|
55
55
|
export const NODE_BODY_INSET = 5;
|
|
56
|
-
/** Below this the mounted body is not worth showing
|
|
57
|
-
*
|
|
56
|
+
/** Below this the mounted body is not worth showing. It scales with the
|
|
57
|
+
* zoom now, so this is no longer about a form clipped to a corner of its
|
|
58
|
+
* card — it is that nobody can read a form a third of its size, and that a
|
|
59
|
+
* real subtree per card is the one cost a zoomed-out overview cannot pay. */
|
|
58
60
|
export const RENDER_ZOOM = 0.6;
|
|
59
61
|
/** How far outside a handle a press still counts as grabbing it. */
|
|
60
62
|
export const HANDLE_SLOP = 5;
|