@gjsify/canvas2d 0.3.13 → 0.3.15
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/lib/esm/cairo-utils.js +164 -156
- package/lib/esm/canvas-gradient.js +2 -3
- package/lib/esm/canvas-path.js +2 -3
- package/lib/esm/canvas-pattern.js +2 -3
- package/lib/esm/canvas-rendering-context-2d.js +2 -3
- package/lib/esm/canvas-state.js +35 -34
- package/lib/esm/canvas2d-bridge.js +135 -120
- package/lib/esm/color.js +218 -200
- package/lib/esm/image-data.js +3 -4
- package/lib/esm/index.js +23 -28
- package/package.json +15 -15
package/lib/esm/cairo-utils.js
CHANGED
|
@@ -1,172 +1,180 @@
|
|
|
1
|
+
//#region src/cairo-utils.ts
|
|
2
|
+
/**
|
|
3
|
+
* Convert quadratic Bezier control point to cubic Bezier control points.
|
|
4
|
+
* Canvas 2D has quadraticCurveTo but Cairo only has cubic curveTo.
|
|
5
|
+
*
|
|
6
|
+
* Given current point (cx, cy), quadratic control point (cpx, cpy), and end (x, y):
|
|
7
|
+
* cp1 = current + 2/3 * (cp - current)
|
|
8
|
+
* cp2 = end + 2/3 * (cp - end)
|
|
9
|
+
*/
|
|
1
10
|
function quadraticToCubic(cx, cy, cpx, cpy, x, y) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
return {
|
|
12
|
+
cp1x: cx + 2 / 3 * (cpx - cx),
|
|
13
|
+
cp1y: cy + 2 / 3 * (cpy - cy),
|
|
14
|
+
cp2x: x + 2 / 3 * (cpx - x),
|
|
15
|
+
cp2y: y + 2 / 3 * (cpy - y)
|
|
16
|
+
};
|
|
8
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Compute arcTo parameters.
|
|
20
|
+
* Canvas arcTo(x1,y1,x2,y2,radius) draws a line from current point to the tangent point,
|
|
21
|
+
* then an arc of the given radius tangent to both lines (current→p1 and p1→p2).
|
|
22
|
+
*
|
|
23
|
+
* Returns the two tangent points and arc center, or null if degenerate (collinear points).
|
|
24
|
+
*/
|
|
9
25
|
function computeArcTo(x0, y0, x1, y1, x2, y2, radius) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
26
|
+
const dx0 = x0 - x1;
|
|
27
|
+
const dy0 = y0 - y1;
|
|
28
|
+
const dx1 = x2 - x1;
|
|
29
|
+
const dy1 = y2 - y1;
|
|
30
|
+
const len0 = Math.sqrt(dx0 * dx0 + dy0 * dy0);
|
|
31
|
+
const len1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
|
|
32
|
+
if (len0 === 0 || len1 === 0) return null;
|
|
33
|
+
const ux0 = dx0 / len0;
|
|
34
|
+
const uy0 = dy0 / len0;
|
|
35
|
+
const ux1 = dx1 / len1;
|
|
36
|
+
const uy1 = dy1 / len1;
|
|
37
|
+
const cross = ux0 * uy1 - uy0 * ux1;
|
|
38
|
+
if (Math.abs(cross) < 1e-10) return null;
|
|
39
|
+
const dot = ux0 * ux1 + uy0 * uy1;
|
|
40
|
+
const halfAngle = Math.acos(Math.max(-1, Math.min(1, dot))) / 2;
|
|
41
|
+
const tanDist = radius / Math.tan(halfAngle);
|
|
42
|
+
const tx0 = x1 + ux0 * tanDist;
|
|
43
|
+
const ty0 = y1 + uy0 * tanDist;
|
|
44
|
+
const tx1 = x1 + ux1 * tanDist;
|
|
45
|
+
const ty1 = y1 + uy1 * tanDist;
|
|
46
|
+
const centerDist = radius / Math.sin(halfAngle);
|
|
47
|
+
const bisectX = (ux0 + ux1) / 2;
|
|
48
|
+
const bisectY = (uy0 + uy1) / 2;
|
|
49
|
+
const bisectLen = Math.sqrt(bisectX * bisectX + bisectY * bisectY);
|
|
50
|
+
const cx = x1 + bisectX / bisectLen * centerDist;
|
|
51
|
+
const cy = y1 + bisectY / bisectLen * centerDist;
|
|
52
|
+
const startAngle = Math.atan2(ty0 - cy, tx0 - cx);
|
|
53
|
+
const endAngle = Math.atan2(ty1 - cy, tx1 - cx);
|
|
54
|
+
const counterclockwise = cross > 0;
|
|
55
|
+
return {
|
|
56
|
+
tx0,
|
|
57
|
+
ty0,
|
|
58
|
+
tx1,
|
|
59
|
+
ty1,
|
|
60
|
+
cx,
|
|
61
|
+
cy,
|
|
62
|
+
startAngle,
|
|
63
|
+
endAngle,
|
|
64
|
+
counterclockwise
|
|
65
|
+
};
|
|
40
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Apply an arcTo operation to a Cairo context.
|
|
69
|
+
*/
|
|
41
70
|
function cairoArcTo(ctx, x0, y0, x1, y1, x2, y2, radius) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
71
|
+
const result = computeArcTo(x0, y0, x1, y1, x2, y2, radius);
|
|
72
|
+
if (!result) {
|
|
73
|
+
ctx.lineTo(x1, y1);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const { tx0, ty0, cx, cy, startAngle, endAngle, counterclockwise } = result;
|
|
77
|
+
ctx.lineTo(tx0, ty0);
|
|
78
|
+
if (counterclockwise) {
|
|
79
|
+
ctx.arcNegative(cx, cy, radius, startAngle, endAngle);
|
|
80
|
+
} else {
|
|
81
|
+
ctx.arc(cx, cy, radius, startAngle, endAngle);
|
|
82
|
+
}
|
|
54
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Draw an ellipse on a Cairo context.
|
|
86
|
+
* Canvas ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise)
|
|
87
|
+
* is implemented via save/translate/rotate/scale/arc/restore.
|
|
88
|
+
*/
|
|
55
89
|
function cairoEllipse(ctx, x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
90
|
+
ctx.save();
|
|
91
|
+
ctx.translate(x, y);
|
|
92
|
+
ctx.rotate(rotation);
|
|
93
|
+
ctx.scale(radiusX, radiusY);
|
|
94
|
+
if (counterclockwise) {
|
|
95
|
+
ctx.arcNegative(0, 0, 1, startAngle, endAngle);
|
|
96
|
+
} else {
|
|
97
|
+
ctx.arc(0, 0, 1, startAngle, endAngle);
|
|
98
|
+
}
|
|
99
|
+
ctx.restore();
|
|
66
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Draw a rounded rectangle path on a Cairo context.
|
|
103
|
+
* Implements the Canvas roundRect(x, y, w, h, radii) method.
|
|
104
|
+
*/
|
|
67
105
|
function cairoRoundRect(ctx, x, y, w, h, radii) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
106
|
+
let tl, tr, br, bl;
|
|
107
|
+
if (typeof radii === "number") {
|
|
108
|
+
tl = tr = br = bl = radii;
|
|
109
|
+
} else if (radii.length === 1) {
|
|
110
|
+
tl = tr = br = bl = radii[0];
|
|
111
|
+
} else if (radii.length === 2) {
|
|
112
|
+
tl = br = radii[0];
|
|
113
|
+
tr = bl = radii[1];
|
|
114
|
+
} else if (radii.length === 3) {
|
|
115
|
+
tl = radii[0];
|
|
116
|
+
tr = bl = radii[1];
|
|
117
|
+
br = radii[2];
|
|
118
|
+
} else {
|
|
119
|
+
tl = radii[0];
|
|
120
|
+
tr = radii[1];
|
|
121
|
+
br = radii[2];
|
|
122
|
+
bl = radii[3];
|
|
123
|
+
}
|
|
124
|
+
const maxR = Math.min(w / 2, h / 2);
|
|
125
|
+
tl = Math.min(tl, maxR);
|
|
126
|
+
tr = Math.min(tr, maxR);
|
|
127
|
+
br = Math.min(br, maxR);
|
|
128
|
+
bl = Math.min(bl, maxR);
|
|
129
|
+
const PI_2 = Math.PI / 2;
|
|
130
|
+
ctx.newSubPath();
|
|
131
|
+
ctx.arc(x + tl, y + tl, tl, Math.PI, Math.PI + PI_2);
|
|
132
|
+
ctx.arc(x + w - tr, y + tr, tr, -PI_2, 0);
|
|
133
|
+
ctx.arc(x + w - br, y + h - br, br, 0, PI_2);
|
|
134
|
+
ctx.arc(x + bl, y + h - bl, bl, PI_2, Math.PI);
|
|
135
|
+
ctx.closePath();
|
|
98
136
|
}
|
|
137
|
+
/** Map Canvas globalCompositeOperation to Cairo.Operator values */
|
|
99
138
|
const COMPOSITE_OP_MAP = {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
"overlay": 16,
|
|
127
|
-
// OVERLAY
|
|
128
|
-
"darken": 17,
|
|
129
|
-
// DARKEN
|
|
130
|
-
"lighten": 18,
|
|
131
|
-
// LIGHTEN
|
|
132
|
-
"color-dodge": 19,
|
|
133
|
-
// COLOR_DODGE
|
|
134
|
-
"color-burn": 20,
|
|
135
|
-
// COLOR_BURN
|
|
136
|
-
"hard-light": 21,
|
|
137
|
-
// HARD_LIGHT
|
|
138
|
-
"soft-light": 22,
|
|
139
|
-
// SOFT_LIGHT
|
|
140
|
-
"difference": 23,
|
|
141
|
-
// DIFFERENCE
|
|
142
|
-
"exclusion": 24,
|
|
143
|
-
// EXCLUSION
|
|
144
|
-
"hue": 25,
|
|
145
|
-
// HSL_HUE
|
|
146
|
-
"saturation": 26,
|
|
147
|
-
// HSL_SATURATION
|
|
148
|
-
"color": 27,
|
|
149
|
-
// HSL_COLOR
|
|
150
|
-
"luminosity": 28
|
|
151
|
-
// HSL_LUMINOSITY
|
|
139
|
+
"source-over": 2,
|
|
140
|
+
"source-in": 5,
|
|
141
|
+
"source-out": 6,
|
|
142
|
+
"source-atop": 7,
|
|
143
|
+
"destination-over": 8,
|
|
144
|
+
"destination-in": 9,
|
|
145
|
+
"destination-out": 10,
|
|
146
|
+
"destination-atop": 11,
|
|
147
|
+
"lighter": 12,
|
|
148
|
+
"copy": 1,
|
|
149
|
+
"xor": 13,
|
|
150
|
+
"multiply": 14,
|
|
151
|
+
"screen": 15,
|
|
152
|
+
"overlay": 16,
|
|
153
|
+
"darken": 17,
|
|
154
|
+
"lighten": 18,
|
|
155
|
+
"color-dodge": 19,
|
|
156
|
+
"color-burn": 20,
|
|
157
|
+
"hard-light": 21,
|
|
158
|
+
"soft-light": 22,
|
|
159
|
+
"difference": 23,
|
|
160
|
+
"exclusion": 24,
|
|
161
|
+
"hue": 25,
|
|
162
|
+
"saturation": 26,
|
|
163
|
+
"color": 27,
|
|
164
|
+
"luminosity": 28
|
|
152
165
|
};
|
|
166
|
+
/** Map Canvas lineCap to Cairo.LineCap values */
|
|
153
167
|
const LINE_CAP_MAP = {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
168
|
+
"butt": 0,
|
|
169
|
+
"round": 1,
|
|
170
|
+
"square": 2
|
|
157
171
|
};
|
|
172
|
+
/** Map Canvas lineJoin to Cairo.LineJoin values */
|
|
158
173
|
const LINE_JOIN_MAP = {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
};
|
|
163
|
-
export {
|
|
164
|
-
COMPOSITE_OP_MAP,
|
|
165
|
-
LINE_CAP_MAP,
|
|
166
|
-
LINE_JOIN_MAP,
|
|
167
|
-
cairoArcTo,
|
|
168
|
-
cairoEllipse,
|
|
169
|
-
cairoRoundRect,
|
|
170
|
-
computeArcTo,
|
|
171
|
-
quadraticToCubic
|
|
174
|
+
"miter": 0,
|
|
175
|
+
"round": 1,
|
|
176
|
+
"bevel": 2
|
|
172
177
|
};
|
|
178
|
+
|
|
179
|
+
//#endregion
|
|
180
|
+
export { COMPOSITE_OP_MAP, LINE_CAP_MAP, LINE_JOIN_MAP, cairoArcTo, cairoEllipse, cairoRoundRect, computeArcTo, quadraticToCubic };
|
package/lib/esm/canvas-path.js
CHANGED
package/lib/esm/canvas-state.js
CHANGED
|
@@ -1,39 +1,40 @@
|
|
|
1
1
|
import { BLACK } from "./color.js";
|
|
2
|
+
|
|
3
|
+
//#region src/canvas-state.ts
|
|
2
4
|
function createDefaultState() {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
5
|
+
return {
|
|
6
|
+
fillStyle: "#000000",
|
|
7
|
+
fillColor: { ...BLACK },
|
|
8
|
+
strokeStyle: "#000000",
|
|
9
|
+
strokeColor: { ...BLACK },
|
|
10
|
+
lineWidth: 1,
|
|
11
|
+
lineCap: "butt",
|
|
12
|
+
lineJoin: "miter",
|
|
13
|
+
miterLimit: 10,
|
|
14
|
+
lineDash: [],
|
|
15
|
+
lineDashOffset: 0,
|
|
16
|
+
globalAlpha: 1,
|
|
17
|
+
globalCompositeOperation: "source-over",
|
|
18
|
+
shadowColor: "rgba(0, 0, 0, 0)",
|
|
19
|
+
shadowBlur: 0,
|
|
20
|
+
shadowOffsetX: 0,
|
|
21
|
+
shadowOffsetY: 0,
|
|
22
|
+
font: "10px sans-serif",
|
|
23
|
+
textAlign: "start",
|
|
24
|
+
textBaseline: "alphabetic",
|
|
25
|
+
direction: "ltr",
|
|
26
|
+
imageSmoothingEnabled: true,
|
|
27
|
+
imageSmoothingQuality: "low"
|
|
28
|
+
};
|
|
27
29
|
}
|
|
28
30
|
function cloneState(state) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
return {
|
|
32
|
+
...state,
|
|
33
|
+
fillColor: { ...state.fillColor },
|
|
34
|
+
strokeColor: { ...state.strokeColor },
|
|
35
|
+
lineDash: [...state.lineDash]
|
|
36
|
+
};
|
|
35
37
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
};
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
export { cloneState, createDefaultState };
|
|
@@ -1,125 +1,140 @@
|
|
|
1
1
|
import GObject from "gi://GObject";
|
|
2
2
|
import GLib from "gi://GLib?version=2.0";
|
|
3
3
|
import Gtk from "gi://Gtk?version=4.0";
|
|
4
|
-
import { HTMLCanvasElement
|
|
4
|
+
import { HTMLCanvasElement } from "@gjsify/dom-elements";
|
|
5
5
|
import { attachEventControllers } from "@gjsify/event-bridge";
|
|
6
6
|
import { Event } from "@gjsify/dom-events";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
7
|
+
|
|
8
|
+
//#region src/canvas2d-bridge.ts
|
|
9
|
+
/**
|
|
10
|
+
* A `Gtk.DrawingArea` subclass that handles Canvas 2D bootstrapping:
|
|
11
|
+
* - Creates an `HTMLCanvasElement` + `CanvasRenderingContext2D` on first draw
|
|
12
|
+
* - Blits the Canvas 2D Cairo.ImageSurface onto the DrawingArea each frame
|
|
13
|
+
* - Fires `onReady()` callbacks with (canvas, ctx) once the context is available
|
|
14
|
+
* - Provides `requestAnimationFrame()` backed by GTK frame clock (vsync)
|
|
15
|
+
* - `installGlobals()` sets `globalThis.requestAnimationFrame` and `globalThis.performance`
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* ```ts
|
|
19
|
+
* const widget = new Canvas2DBridge();
|
|
20
|
+
* widget.installGlobals(); // sets globalThis.requestAnimationFrame
|
|
21
|
+
* widget.onReady((canvas, ctx) => {
|
|
22
|
+
* ctx.fillStyle = 'red';
|
|
23
|
+
* ctx.fillRect(0, 0, 100, 100);
|
|
24
|
+
* });
|
|
25
|
+
* window.set_child(widget);
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
const Canvas2DBridge = GObject.registerClass({ GTypeName: "GjsifyCanvas2DBridge" }, class Canvas2DBridge extends Gtk.DrawingArea {
|
|
29
|
+
constructor(params) {
|
|
30
|
+
super(params);
|
|
31
|
+
this._canvas = null;
|
|
32
|
+
this._ctx = null;
|
|
33
|
+
this._readyCallbacks = [];
|
|
34
|
+
this._resizeCallbacks = [];
|
|
35
|
+
this._tickCallbackId = null;
|
|
36
|
+
this._frameCallback = null;
|
|
37
|
+
this._timeOrigin = GLib.get_monotonic_time();
|
|
38
|
+
this.set_draw_func(this._onDraw.bind(this));
|
|
39
|
+
attachEventControllers(this, () => this._canvas, { captureKeys: true });
|
|
40
|
+
this.connect("unrealize", () => {
|
|
41
|
+
if (this._tickCallbackId !== null) {
|
|
42
|
+
this.remove_tick_callback(this._tickCallbackId);
|
|
43
|
+
this._tickCallbackId = null;
|
|
44
|
+
}
|
|
45
|
+
if (this._ctx) {
|
|
46
|
+
this._ctx._dispose();
|
|
47
|
+
}
|
|
48
|
+
this._canvas = null;
|
|
49
|
+
this._ctx = null;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/** @internal Draw function called by GTK. Blits the Cairo surface to screen. */
|
|
53
|
+
_onDraw(_area, cr, width, height) {
|
|
54
|
+
if (!this._canvas) {
|
|
55
|
+
this._canvas = new HTMLCanvasElement();
|
|
56
|
+
this._canvas.width = width;
|
|
57
|
+
this._canvas.height = height;
|
|
58
|
+
this._ctx = this._canvas.getContext("2d");
|
|
59
|
+
if (this._ctx) {
|
|
60
|
+
for (const cb of this._readyCallbacks) {
|
|
61
|
+
cb(this._canvas, this._ctx);
|
|
62
|
+
}
|
|
63
|
+
this._readyCallbacks = [];
|
|
64
|
+
}
|
|
65
|
+
} else if (this._canvas.width !== width || this._canvas.height !== height) {
|
|
66
|
+
this._canvas.width = width;
|
|
67
|
+
this._canvas.height = height;
|
|
68
|
+
this._canvas.dispatchEvent(new Event("resize"));
|
|
69
|
+
for (const cb of this._resizeCallbacks) {
|
|
70
|
+
cb(width, height);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (this._ctx) {
|
|
74
|
+
const surface = this._ctx._getSurface();
|
|
75
|
+
cr.setSourceSurface(surface, 0, 0);
|
|
76
|
+
cr.paint();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** The HTMLCanvasElement backing this widget. Available after the first draw. */
|
|
80
|
+
get canvas() {
|
|
81
|
+
return this._canvas;
|
|
82
|
+
}
|
|
83
|
+
/** Get the 2D rendering context. Available after the first draw. */
|
|
84
|
+
getContext(_id) {
|
|
85
|
+
return this._ctx;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Register a callback to be invoked once the Canvas 2D context is ready.
|
|
89
|
+
* If the context is already available, the callback fires synchronously.
|
|
90
|
+
*/
|
|
91
|
+
onReady(cb) {
|
|
92
|
+
if (this._canvas && this._ctx) {
|
|
93
|
+
cb(this._canvas, this._ctx);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
this._readyCallbacks.push(cb);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Register a callback invoked whenever the GTK widget is resized.
|
|
100
|
+
* Canvas dimensions are already updated when the callback fires.
|
|
101
|
+
* Call `queue_draw()` after re-rendering to push the new surface to screen.
|
|
102
|
+
*/
|
|
103
|
+
onResize(cb) {
|
|
104
|
+
this._resizeCallbacks.push(cb);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Schedules a single animation frame callback, matching the browser `requestAnimationFrame` API.
|
|
108
|
+
* Backed by GTK frame clock (vsync-synced, typically ~60 FPS).
|
|
109
|
+
* Returns 0 (handle — cancel not yet implemented).
|
|
110
|
+
*/
|
|
111
|
+
requestAnimationFrame(cb) {
|
|
112
|
+
this._frameCallback = cb;
|
|
113
|
+
if (this._tickCallbackId === null) {
|
|
114
|
+
this._tickCallbackId = this.add_tick_callback((_widget, frameClock) => {
|
|
115
|
+
this._tickCallbackId = null;
|
|
116
|
+
const time = (frameClock.get_frame_time() - this._timeOrigin) / 1e3;
|
|
117
|
+
this._frameCallback?.(time);
|
|
118
|
+
this.queue_draw();
|
|
119
|
+
return GLib.SOURCE_REMOVE;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
this.queue_draw();
|
|
123
|
+
return 0;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Sets browser globals (`requestAnimationFrame`, `performance`) so that
|
|
127
|
+
* browser-targeted code works unchanged on GJS.
|
|
128
|
+
*/
|
|
129
|
+
installGlobals() {
|
|
130
|
+
globalThis.requestAnimationFrame = (cb) => this.requestAnimationFrame(cb);
|
|
131
|
+
const timeOrigin = this._timeOrigin;
|
|
132
|
+
globalThis.performance = {
|
|
133
|
+
now: () => (GLib.get_monotonic_time() - timeOrigin) / 1e3,
|
|
134
|
+
timeOrigin: Date.now()
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
//#endregion
|
|
140
|
+
export { Canvas2DBridge };
|
package/lib/esm/color.js
CHANGED
|
@@ -1,209 +1,227 @@
|
|
|
1
|
+
//#region src/color.ts
|
|
1
2
|
const NAMED_COLORS = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
3
|
+
aliceblue: "#f0f8ff",
|
|
4
|
+
antiquewhite: "#faebd7",
|
|
5
|
+
aqua: "#00ffff",
|
|
6
|
+
aquamarine: "#7fffd4",
|
|
7
|
+
azure: "#f0ffff",
|
|
8
|
+
beige: "#f5f5dc",
|
|
9
|
+
bisque: "#ffe4c4",
|
|
10
|
+
black: "#000000",
|
|
11
|
+
blanchedalmond: "#ffebcd",
|
|
12
|
+
blue: "#0000ff",
|
|
13
|
+
blueviolet: "#8a2be2",
|
|
14
|
+
brown: "#a52a2a",
|
|
15
|
+
burlywood: "#deb887",
|
|
16
|
+
cadetblue: "#5f9ea0",
|
|
17
|
+
chartreuse: "#7fff00",
|
|
18
|
+
chocolate: "#d2691e",
|
|
19
|
+
coral: "#ff7f50",
|
|
20
|
+
cornflowerblue: "#6495ed",
|
|
21
|
+
cornsilk: "#fff8dc",
|
|
22
|
+
crimson: "#dc143c",
|
|
23
|
+
cyan: "#00ffff",
|
|
24
|
+
darkblue: "#00008b",
|
|
25
|
+
darkcyan: "#008b8b",
|
|
26
|
+
darkgoldenrod: "#b8860b",
|
|
27
|
+
darkgray: "#a9a9a9",
|
|
28
|
+
darkgreen: "#006400",
|
|
29
|
+
darkgrey: "#a9a9a9",
|
|
30
|
+
darkkhaki: "#bdb76b",
|
|
31
|
+
darkmagenta: "#8b008b",
|
|
32
|
+
darkolivegreen: "#556b2f",
|
|
33
|
+
darkorange: "#ff8c00",
|
|
34
|
+
darkorchid: "#9932cc",
|
|
35
|
+
darkred: "#8b0000",
|
|
36
|
+
darksalmon: "#e9967a",
|
|
37
|
+
darkseagreen: "#8fbc8f",
|
|
38
|
+
darkslateblue: "#483d8b",
|
|
39
|
+
darkslategray: "#2f4f4f",
|
|
40
|
+
darkslategrey: "#2f4f4f",
|
|
41
|
+
darkturquoise: "#00ced1",
|
|
42
|
+
darkviolet: "#9400d3",
|
|
43
|
+
deeppink: "#ff1493",
|
|
44
|
+
deepskyblue: "#00bfff",
|
|
45
|
+
dimgray: "#696969",
|
|
46
|
+
dimgrey: "#696969",
|
|
47
|
+
dodgerblue: "#1e90ff",
|
|
48
|
+
firebrick: "#b22222",
|
|
49
|
+
floralwhite: "#fffaf0",
|
|
50
|
+
forestgreen: "#228b22",
|
|
51
|
+
fuchsia: "#ff00ff",
|
|
52
|
+
gainsboro: "#dcdcdc",
|
|
53
|
+
ghostwhite: "#f8f8ff",
|
|
54
|
+
gold: "#ffd700",
|
|
55
|
+
goldenrod: "#daa520",
|
|
56
|
+
gray: "#808080",
|
|
57
|
+
green: "#008000",
|
|
58
|
+
greenyellow: "#adff2f",
|
|
59
|
+
grey: "#808080",
|
|
60
|
+
honeydew: "#f0fff0",
|
|
61
|
+
hotpink: "#ff69b4",
|
|
62
|
+
indianred: "#cd5c5c",
|
|
63
|
+
indigo: "#4b0082",
|
|
64
|
+
ivory: "#fffff0",
|
|
65
|
+
khaki: "#f0e68c",
|
|
66
|
+
lavender: "#e6e6fa",
|
|
67
|
+
lavenderblush: "#fff0f5",
|
|
68
|
+
lawngreen: "#7cfc00",
|
|
69
|
+
lemonchiffon: "#fffacd",
|
|
70
|
+
lightblue: "#add8e6",
|
|
71
|
+
lightcoral: "#f08080",
|
|
72
|
+
lightcyan: "#e0ffff",
|
|
73
|
+
lightgoldenrodyellow: "#fafad2",
|
|
74
|
+
lightgray: "#d3d3d3",
|
|
75
|
+
lightgreen: "#90ee90",
|
|
76
|
+
lightgrey: "#d3d3d3",
|
|
77
|
+
lightpink: "#ffb6c1",
|
|
78
|
+
lightsalmon: "#ffa07a",
|
|
79
|
+
lightseagreen: "#20b2aa",
|
|
80
|
+
lightskyblue: "#87cefa",
|
|
81
|
+
lightslategray: "#778899",
|
|
82
|
+
lightslategrey: "#778899",
|
|
83
|
+
lightsteelblue: "#b0c4de",
|
|
84
|
+
lightyellow: "#ffffe0",
|
|
85
|
+
lime: "#00ff00",
|
|
86
|
+
limegreen: "#32cd32",
|
|
87
|
+
linen: "#faf0e6",
|
|
88
|
+
magenta: "#ff00ff",
|
|
89
|
+
maroon: "#800000",
|
|
90
|
+
mediumaquamarine: "#66cdaa",
|
|
91
|
+
mediumblue: "#0000cd",
|
|
92
|
+
mediumorchid: "#ba55d3",
|
|
93
|
+
mediumpurple: "#9370db",
|
|
94
|
+
mediumseagreen: "#3cb371",
|
|
95
|
+
mediumslateblue: "#7b68ee",
|
|
96
|
+
mediumspringgreen: "#00fa9a",
|
|
97
|
+
mediumturquoise: "#48d1cc",
|
|
98
|
+
mediumvioletred: "#c71585",
|
|
99
|
+
midnightblue: "#191970",
|
|
100
|
+
mintcream: "#f5fffa",
|
|
101
|
+
mistyrose: "#ffe4e1",
|
|
102
|
+
moccasin: "#ffe4b5",
|
|
103
|
+
navajowhite: "#ffdead",
|
|
104
|
+
navy: "#000080",
|
|
105
|
+
oldlace: "#fdf5e6",
|
|
106
|
+
olive: "#808000",
|
|
107
|
+
olivedrab: "#6b8e23",
|
|
108
|
+
orange: "#ffa500",
|
|
109
|
+
orangered: "#ff4500",
|
|
110
|
+
orchid: "#da70d6",
|
|
111
|
+
palegoldenrod: "#eee8aa",
|
|
112
|
+
palegreen: "#98fb98",
|
|
113
|
+
paleturquoise: "#afeeee",
|
|
114
|
+
palevioletred: "#db7093",
|
|
115
|
+
papayawhip: "#ffefd5",
|
|
116
|
+
peachpuff: "#ffdab9",
|
|
117
|
+
peru: "#cd853f",
|
|
118
|
+
pink: "#ffc0cb",
|
|
119
|
+
plum: "#dda0dd",
|
|
120
|
+
powderblue: "#b0e0e6",
|
|
121
|
+
purple: "#800080",
|
|
122
|
+
rebeccapurple: "#663399",
|
|
123
|
+
red: "#ff0000",
|
|
124
|
+
rosybrown: "#bc8f8f",
|
|
125
|
+
royalblue: "#4169e1",
|
|
126
|
+
saddlebrown: "#8b4513",
|
|
127
|
+
salmon: "#fa8072",
|
|
128
|
+
sandybrown: "#f4a460",
|
|
129
|
+
seagreen: "#2e8b57",
|
|
130
|
+
seashell: "#fff5ee",
|
|
131
|
+
sienna: "#a0522d",
|
|
132
|
+
silver: "#c0c0c0",
|
|
133
|
+
skyblue: "#87ceeb",
|
|
134
|
+
slateblue: "#6a5acd",
|
|
135
|
+
slategray: "#708090",
|
|
136
|
+
slategrey: "#708090",
|
|
137
|
+
snow: "#fffafa",
|
|
138
|
+
springgreen: "#00ff7f",
|
|
139
|
+
steelblue: "#4682b4",
|
|
140
|
+
tan: "#d2b48c",
|
|
141
|
+
teal: "#008080",
|
|
142
|
+
thistle: "#d8bfd8",
|
|
143
|
+
tomato: "#ff6347",
|
|
144
|
+
turquoise: "#40e0d0",
|
|
145
|
+
violet: "#ee82ee",
|
|
146
|
+
wheat: "#f5deb3",
|
|
147
|
+
white: "#ffffff",
|
|
148
|
+
whitesmoke: "#f5f5f5",
|
|
149
|
+
yellow: "#ffff00",
|
|
150
|
+
yellowgreen: "#9acd32",
|
|
151
|
+
transparent: "#00000000"
|
|
151
152
|
};
|
|
153
|
+
/**
|
|
154
|
+
* Parse a CSS color string into RGBA components (0-1 range).
|
|
155
|
+
* Supports: #rgb, #rrggbb, #rgba, #rrggbbaa, rgb(), rgba(), named colors, 'transparent'.
|
|
156
|
+
*/
|
|
152
157
|
function parseColor(color) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
return null;
|
|
158
|
+
if (!color || typeof color !== "string") return null;
|
|
159
|
+
const trimmed = color.trim().toLowerCase();
|
|
160
|
+
const named = NAMED_COLORS[trimmed];
|
|
161
|
+
if (named) return parseHex(named);
|
|
162
|
+
if (trimmed.startsWith("#")) return parseHex(trimmed);
|
|
163
|
+
const rgbMatch = trimmed.match(/^rgba?\(\s*(\d+(?:\.\d+)?%?)\s*[,\s]\s*(\d+(?:\.\d+)?%?)\s*[,\s]\s*(\d+(?:\.\d+)?%?)\s*(?:[,/]\s*(\d+(?:\.\d+)?%?))?\s*\)$/);
|
|
164
|
+
if (rgbMatch) {
|
|
165
|
+
return {
|
|
166
|
+
r: parseComponent(rgbMatch[1], 255) / 255,
|
|
167
|
+
g: parseComponent(rgbMatch[2], 255) / 255,
|
|
168
|
+
b: parseComponent(rgbMatch[3], 255) / 255,
|
|
169
|
+
a: rgbMatch[4] !== undefined ? parseComponent(rgbMatch[4], 1) : 1
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
170
173
|
}
|
|
171
174
|
function parseHex(hex) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
175
|
+
const h = hex.slice(1);
|
|
176
|
+
let r, g, b, a = 1;
|
|
177
|
+
if (h.length === 3) {
|
|
178
|
+
r = parseInt(h[0] + h[0], 16) / 255;
|
|
179
|
+
g = parseInt(h[1] + h[1], 16) / 255;
|
|
180
|
+
b = parseInt(h[2] + h[2], 16) / 255;
|
|
181
|
+
} else if (h.length === 4) {
|
|
182
|
+
r = parseInt(h[0] + h[0], 16) / 255;
|
|
183
|
+
g = parseInt(h[1] + h[1], 16) / 255;
|
|
184
|
+
b = parseInt(h[2] + h[2], 16) / 255;
|
|
185
|
+
a = parseInt(h[3] + h[3], 16) / 255;
|
|
186
|
+
} else if (h.length === 6) {
|
|
187
|
+
r = parseInt(h.slice(0, 2), 16) / 255;
|
|
188
|
+
g = parseInt(h.slice(2, 4), 16) / 255;
|
|
189
|
+
b = parseInt(h.slice(4, 6), 16) / 255;
|
|
190
|
+
} else if (h.length === 8) {
|
|
191
|
+
r = parseInt(h.slice(0, 2), 16) / 255;
|
|
192
|
+
g = parseInt(h.slice(2, 4), 16) / 255;
|
|
193
|
+
b = parseInt(h.slice(4, 6), 16) / 255;
|
|
194
|
+
a = parseInt(h.slice(6, 8), 16) / 255;
|
|
195
|
+
} else {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
r,
|
|
200
|
+
g,
|
|
201
|
+
b,
|
|
202
|
+
a
|
|
203
|
+
};
|
|
196
204
|
}
|
|
197
205
|
function parseComponent(value, max) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
206
|
+
if (value.endsWith("%")) {
|
|
207
|
+
return parseFloat(value) / 100 * max;
|
|
208
|
+
}
|
|
209
|
+
return parseFloat(value);
|
|
202
210
|
}
|
|
203
|
-
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
211
|
+
/** Default color: opaque black */
|
|
212
|
+
const BLACK = {
|
|
213
|
+
r: 0,
|
|
214
|
+
g: 0,
|
|
215
|
+
b: 0,
|
|
216
|
+
a: 1
|
|
209
217
|
};
|
|
218
|
+
/** Transparent black */
|
|
219
|
+
const TRANSPARENT = {
|
|
220
|
+
r: 0,
|
|
221
|
+
g: 0,
|
|
222
|
+
b: 0,
|
|
223
|
+
a: 0
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
//#endregion
|
|
227
|
+
export { BLACK, TRANSPARENT, parseColor };
|
package/lib/esm/image-data.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ImageData } from "@gjsify/canvas2d-core";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
1
|
+
import { ImageData as OurImageData } from "@gjsify/canvas2d-core";
|
|
2
|
+
|
|
3
|
+
export { OurImageData };
|
package/lib/esm/index.js
CHANGED
|
@@ -1,36 +1,31 @@
|
|
|
1
|
-
import { CanvasRenderingContext2D, CanvasGradient, CanvasPattern, Path2D, ImageData, parseColor } from "@gjsify/canvas2d-core";
|
|
2
1
|
import { Canvas2DBridge } from "./canvas2d-bridge.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
import { CanvasGradient, CanvasPattern, CanvasRenderingContext2D, CanvasRenderingContext2D as CanvasRenderingContext2D$1, ImageData, ImageData as ImageData$1, Path2D, Path2D as Path2D$1, parseColor } from "@gjsify/canvas2d-core";
|
|
3
|
+
import { HTMLCanvasElement } from "@gjsify/dom-elements";
|
|
4
|
+
|
|
5
|
+
//#region src/index.ts
|
|
6
|
+
const CONTEXT_KEY = Symbol.for("gjsify_canvas2d_context");
|
|
7
|
+
HTMLCanvasElement.registerContextFactory("2d", (canvas, options) => {
|
|
8
|
+
const existing = canvas[CONTEXT_KEY];
|
|
9
|
+
if (existing) return existing;
|
|
10
|
+
const ctx = new CanvasRenderingContext2D$1(canvas, options);
|
|
11
|
+
canvas[CONTEXT_KEY] = ctx;
|
|
12
|
+
return ctx;
|
|
12
13
|
});
|
|
13
14
|
Object.defineProperty(globalThis, "CanvasRenderingContext2D", {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
value: CanvasRenderingContext2D$1,
|
|
16
|
+
writable: true,
|
|
17
|
+
configurable: true
|
|
17
18
|
});
|
|
18
19
|
Object.defineProperty(globalThis, "ImageData", {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
value: ImageData$1,
|
|
21
|
+
writable: true,
|
|
22
|
+
configurable: true
|
|
22
23
|
});
|
|
23
24
|
Object.defineProperty(globalThis, "Path2D", {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
value: Path2D$1,
|
|
26
|
+
writable: true,
|
|
27
|
+
configurable: true
|
|
27
28
|
});
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
CanvasPattern,
|
|
32
|
-
CanvasRenderingContext2D,
|
|
33
|
-
ImageData,
|
|
34
|
-
Path2D,
|
|
35
|
-
parseColor
|
|
36
|
-
};
|
|
29
|
+
|
|
30
|
+
//#endregion
|
|
31
|
+
export { Canvas2DBridge, CanvasGradient, CanvasPattern, CanvasRenderingContext2D, ImageData, Path2D, parseColor };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/canvas2d",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.15",
|
|
4
4
|
"description": "Canvas 2D rendering context for GJS, backed by Cairo",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -29,22 +29,22 @@
|
|
|
29
29
|
"cairo"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@girs/gdk-4.0": "
|
|
33
|
-
"@girs/gdkpixbuf-2.0": "
|
|
34
|
-
"@girs/gjs": "
|
|
35
|
-
"@girs/glib-2.0": "
|
|
36
|
-
"@girs/gobject-2.0": "
|
|
37
|
-
"@girs/gtk-4.0": "
|
|
38
|
-
"@girs/pango-1.0": "
|
|
39
|
-
"@girs/pangocairo-1.0": "
|
|
40
|
-
"@gjsify/canvas2d-core": "^0.3.
|
|
41
|
-
"@gjsify/dom-elements": "^0.3.
|
|
42
|
-
"@gjsify/event-bridge": "^0.3.
|
|
43
|
-
"@gjsify/utils": "^0.3.
|
|
32
|
+
"@girs/gdk-4.0": "4.0.0-4.0.0-rc.9",
|
|
33
|
+
"@girs/gdkpixbuf-2.0": "2.0.0-4.0.0-rc.9",
|
|
34
|
+
"@girs/gjs": "4.0.0-rc.9",
|
|
35
|
+
"@girs/glib-2.0": "2.88.0-4.0.0-rc.9",
|
|
36
|
+
"@girs/gobject-2.0": "2.88.0-4.0.0-rc.9",
|
|
37
|
+
"@girs/gtk-4.0": "4.23.0-4.0.0-rc.9",
|
|
38
|
+
"@girs/pango-1.0": "1.57.1-4.0.0-rc.9",
|
|
39
|
+
"@girs/pangocairo-1.0": "1.0.0-4.0.0-rc.9",
|
|
40
|
+
"@gjsify/canvas2d-core": "^0.3.15",
|
|
41
|
+
"@gjsify/dom-elements": "^0.3.15",
|
|
42
|
+
"@gjsify/event-bridge": "^0.3.15",
|
|
43
|
+
"@gjsify/utils": "^0.3.15"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@gjsify/cli": "^0.3.
|
|
47
|
-
"@gjsify/unit": "^0.3.
|
|
46
|
+
"@gjsify/cli": "^0.3.15",
|
|
47
|
+
"@gjsify/unit": "^0.3.15",
|
|
48
48
|
"@types/node": "^25.6.0",
|
|
49
49
|
"typescript": "^6.0.3"
|
|
50
50
|
}
|