@gjsify/canvas2d 0.1.1 → 0.1.3
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/canvas-drawing-area.js +13 -2
- package/lib/esm/canvas-gradient.js +1 -20
- package/lib/esm/canvas-path.js +1 -101
- package/lib/esm/canvas-pattern.js +1 -55
- package/lib/esm/canvas-rendering-context-2d.js +1 -862
- package/lib/esm/image-data.js +2 -20
- package/lib/esm/index.js +4 -11
- package/lib/types/canvas-drawing-area.d.ts +8 -1
- package/lib/types/canvas-gradient.d.ts +1 -11
- package/lib/types/canvas-path.d.ts +1 -80
- package/lib/types/canvas-pattern.d.ts +1 -12
- package/lib/types/canvas-rendering-context-2d.d.ts +1 -155
- package/lib/types/image-data.d.ts +1 -12
- package/lib/types/index.d.ts +1 -6
- package/package.json +16 -15
- package/src/canvas-drawing-area.ts +20 -6
- package/src/canvas-gradient.ts +2 -36
- package/src/canvas-path.ts +2 -131
- package/src/canvas-pattern.ts +2 -75
- package/src/canvas-rendering-context-2d.ts +2 -981
- package/src/image-data.ts +3 -34
- package/src/index.ts +6 -13
- package/tmp/.tsbuildinfo +1 -1
|
@@ -11,6 +11,7 @@ const Canvas2DWidget = GObject.registerClass(
|
|
|
11
11
|
this._canvas = null;
|
|
12
12
|
this._ctx = null;
|
|
13
13
|
this._readyCallbacks = [];
|
|
14
|
+
this._resizeCallbacks = [];
|
|
14
15
|
this._tickCallbackId = null;
|
|
15
16
|
this._frameCallback = null;
|
|
16
17
|
// Time origin in microseconds (GLib monotonic clock).
|
|
@@ -44,10 +45,12 @@ const Canvas2DWidget = GObject.registerClass(
|
|
|
44
45
|
}
|
|
45
46
|
this._readyCallbacks = [];
|
|
46
47
|
}
|
|
47
|
-
}
|
|
48
|
-
if (this._canvas.width !== width || this._canvas.height !== height) {
|
|
48
|
+
} else if (this._canvas.width !== width || this._canvas.height !== height) {
|
|
49
49
|
this._canvas.width = width;
|
|
50
50
|
this._canvas.height = height;
|
|
51
|
+
for (const cb of this._resizeCallbacks) {
|
|
52
|
+
cb(width, height);
|
|
53
|
+
}
|
|
51
54
|
}
|
|
52
55
|
if (this._ctx) {
|
|
53
56
|
const surface = this._ctx._getSurface();
|
|
@@ -74,6 +77,14 @@ const Canvas2DWidget = GObject.registerClass(
|
|
|
74
77
|
}
|
|
75
78
|
this._readyCallbacks.push(cb);
|
|
76
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Register a callback invoked whenever the GTK widget is resized.
|
|
82
|
+
* Canvas dimensions are already updated when the callback fires.
|
|
83
|
+
* Call `queue_draw()` after re-rendering to push the new surface to screen.
|
|
84
|
+
*/
|
|
85
|
+
onResize(cb) {
|
|
86
|
+
this._resizeCallbacks.push(cb);
|
|
87
|
+
}
|
|
77
88
|
/**
|
|
78
89
|
* Schedules a single animation frame callback, matching the browser `requestAnimationFrame` API.
|
|
79
90
|
* Backed by GTK frame clock (vsync-synced, typically ~60 FPS).
|
|
@@ -1,23 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { parseColor } from "./color.js";
|
|
3
|
-
class CanvasGradient {
|
|
4
|
-
constructor(type, x0, y0, x1, y1, r0, r1) {
|
|
5
|
-
if (type === "radial") {
|
|
6
|
-
this._pattern = new Cairo.RadialGradient(x0, y0, r0, x1, y1, r1);
|
|
7
|
-
} else {
|
|
8
|
-
this._pattern = new Cairo.LinearGradient(x0, y0, x1, y1);
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
addColorStop(offset, color) {
|
|
12
|
-
const parsed = parseColor(color);
|
|
13
|
-
if (!parsed) return;
|
|
14
|
-
this._pattern.addColorStopRGBA(offset, parsed.r, parsed.g, parsed.b, parsed.a);
|
|
15
|
-
}
|
|
16
|
-
/** @internal Get the underlying Cairo pattern for rendering. */
|
|
17
|
-
_getCairoPattern() {
|
|
18
|
-
return this._pattern;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
1
|
+
import { CanvasGradient } from "@gjsify/canvas2d-core";
|
|
21
2
|
export {
|
|
22
3
|
CanvasGradient
|
|
23
4
|
};
|
package/lib/esm/canvas-path.js
CHANGED
|
@@ -1,104 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
class Path2D {
|
|
3
|
-
constructor(pathOrSvg) {
|
|
4
|
-
/** @internal Recorded operations */
|
|
5
|
-
this._ops = [];
|
|
6
|
-
if (pathOrSvg instanceof Path2D) {
|
|
7
|
-
this._ops = [...pathOrSvg._ops];
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
addPath(path) {
|
|
11
|
-
this._ops.push(...path._ops);
|
|
12
|
-
}
|
|
13
|
-
moveTo(x, y) {
|
|
14
|
-
this._ops.push({ type: "moveTo", x, y });
|
|
15
|
-
}
|
|
16
|
-
lineTo(x, y) {
|
|
17
|
-
this._ops.push({ type: "lineTo", x, y });
|
|
18
|
-
}
|
|
19
|
-
closePath() {
|
|
20
|
-
this._ops.push({ type: "closePath" });
|
|
21
|
-
}
|
|
22
|
-
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
|
|
23
|
-
this._ops.push({ type: "bezierCurveTo", cp1x, cp1y, cp2x, cp2y, x, y });
|
|
24
|
-
}
|
|
25
|
-
quadraticCurveTo(cpx, cpy, x, y) {
|
|
26
|
-
this._ops.push({ type: "quadraticCurveTo", cpx, cpy, x, y });
|
|
27
|
-
}
|
|
28
|
-
arc(x, y, radius, startAngle, endAngle, counterclockwise = false) {
|
|
29
|
-
this._ops.push({ type: "arc", x, y, radius, startAngle, endAngle, ccw: counterclockwise });
|
|
30
|
-
}
|
|
31
|
-
ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise = false) {
|
|
32
|
-
if (radiusX < 0 || radiusY < 0) throw new RangeError("The radii provided are negative");
|
|
33
|
-
this._ops.push({ type: "ellipse", x, y, rx: radiusX, ry: radiusY, rotation, startAngle, endAngle, ccw: counterclockwise });
|
|
34
|
-
}
|
|
35
|
-
rect(x, y, w, h) {
|
|
36
|
-
this._ops.push({ type: "rect", x, y, w, h });
|
|
37
|
-
}
|
|
38
|
-
roundRect(x, y, w, h, radii = 0) {
|
|
39
|
-
this._ops.push({ type: "roundRect", x, y, w, h, radii });
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* @internal Replay all recorded path operations onto a Cairo context.
|
|
43
|
-
*/
|
|
44
|
-
_replayOnCairo(ctx) {
|
|
45
|
-
let lastX = 0, lastY = 0;
|
|
46
|
-
for (const op of this._ops) {
|
|
47
|
-
switch (op.type) {
|
|
48
|
-
case "moveTo":
|
|
49
|
-
ctx.moveTo(op.x, op.y);
|
|
50
|
-
lastX = op.x;
|
|
51
|
-
lastY = op.y;
|
|
52
|
-
break;
|
|
53
|
-
case "lineTo":
|
|
54
|
-
ctx.lineTo(op.x, op.y);
|
|
55
|
-
lastX = op.x;
|
|
56
|
-
lastY = op.y;
|
|
57
|
-
break;
|
|
58
|
-
case "closePath":
|
|
59
|
-
ctx.closePath();
|
|
60
|
-
break;
|
|
61
|
-
case "bezierCurveTo":
|
|
62
|
-
ctx.curveTo(op.cp1x, op.cp1y, op.cp2x, op.cp2y, op.x, op.y);
|
|
63
|
-
lastX = op.x;
|
|
64
|
-
lastY = op.y;
|
|
65
|
-
break;
|
|
66
|
-
case "quadraticCurveTo": {
|
|
67
|
-
const { cp1x, cp1y, cp2x, cp2y } = quadraticToCubic(lastX, lastY, op.cpx, op.cpy, op.x, op.y);
|
|
68
|
-
ctx.curveTo(cp1x, cp1y, cp2x, cp2y, op.x, op.y);
|
|
69
|
-
lastX = op.x;
|
|
70
|
-
lastY = op.y;
|
|
71
|
-
break;
|
|
72
|
-
}
|
|
73
|
-
case "arc":
|
|
74
|
-
if (op.ccw) {
|
|
75
|
-
ctx.arcNegative(op.x, op.y, op.radius, op.startAngle, op.endAngle);
|
|
76
|
-
} else {
|
|
77
|
-
ctx.arc(op.x, op.y, op.radius, op.startAngle, op.endAngle);
|
|
78
|
-
}
|
|
79
|
-
break;
|
|
80
|
-
case "ellipse":
|
|
81
|
-
ctx.save();
|
|
82
|
-
ctx.translate(op.x, op.y);
|
|
83
|
-
ctx.rotate(op.rotation);
|
|
84
|
-
ctx.scale(op.rx, op.ry);
|
|
85
|
-
if (op.ccw) {
|
|
86
|
-
ctx.arcNegative(0, 0, 1, op.startAngle, op.endAngle);
|
|
87
|
-
} else {
|
|
88
|
-
ctx.arc(0, 0, 1, op.startAngle, op.endAngle);
|
|
89
|
-
}
|
|
90
|
-
ctx.restore();
|
|
91
|
-
break;
|
|
92
|
-
case "rect":
|
|
93
|
-
ctx.rectangle(op.x, op.y, op.w, op.h);
|
|
94
|
-
break;
|
|
95
|
-
case "roundRect":
|
|
96
|
-
cairoRoundRect(ctx, op.x, op.y, op.w, op.h, op.radii);
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
1
|
+
import { Path2D } from "@gjsify/canvas2d-core";
|
|
102
2
|
export {
|
|
103
3
|
Path2D
|
|
104
4
|
};
|
|
@@ -1,58 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import Gdk from "gi://Gdk?version=4.0";
|
|
3
|
-
class CanvasPattern {
|
|
4
|
-
constructor(surface, repetition) {
|
|
5
|
-
this._pattern = new Cairo.SurfacePattern(surface);
|
|
6
|
-
const pat = this._pattern;
|
|
7
|
-
switch (repetition) {
|
|
8
|
-
case "repeat":
|
|
9
|
-
case "":
|
|
10
|
-
case null:
|
|
11
|
-
pat.setExtend(Cairo.Extend.REPEAT);
|
|
12
|
-
break;
|
|
13
|
-
case "repeat-x":
|
|
14
|
-
case "repeat-y":
|
|
15
|
-
pat.setExtend(Cairo.Extend.REPEAT);
|
|
16
|
-
break;
|
|
17
|
-
case "no-repeat":
|
|
18
|
-
pat.setExtend(Cairo.Extend.NONE);
|
|
19
|
-
break;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
/** Create a CanvasPattern from a supported image source. Returns null if unsupported. */
|
|
23
|
-
static create(image, repetition) {
|
|
24
|
-
if ("isPixbuf" in image && typeof image.isPixbuf === "function" && image.isPixbuf()) {
|
|
25
|
-
const pixbuf = image._pixbuf;
|
|
26
|
-
const w = pixbuf.get_width();
|
|
27
|
-
const h = pixbuf.get_height();
|
|
28
|
-
const surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, w, h);
|
|
29
|
-
const ctx = new Cairo.Context(surface);
|
|
30
|
-
Gdk.cairo_set_source_pixbuf(ctx, pixbuf, 0, 0);
|
|
31
|
-
ctx.paint();
|
|
32
|
-
ctx.$dispose();
|
|
33
|
-
return new CanvasPattern(surface, repetition);
|
|
34
|
-
}
|
|
35
|
-
if (typeof image?.getContext === "function") {
|
|
36
|
-
const ctx2d = image.getContext("2d");
|
|
37
|
-
if (ctx2d && typeof ctx2d._getSurface === "function") {
|
|
38
|
-
const sourceSurface = ctx2d._getSurface();
|
|
39
|
-
const w = sourceSurface.getWidth();
|
|
40
|
-
const h = sourceSurface.getHeight();
|
|
41
|
-
const surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, w, h);
|
|
42
|
-
const ctx = new Cairo.Context(surface);
|
|
43
|
-
ctx.setSourceSurface(sourceSurface, 0, 0);
|
|
44
|
-
ctx.paint();
|
|
45
|
-
ctx.$dispose();
|
|
46
|
-
return new CanvasPattern(surface, repetition);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
/** @internal Get the underlying Cairo pattern for rendering. */
|
|
52
|
-
_getCairoPattern() {
|
|
53
|
-
return this._pattern;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
1
|
+
import { CanvasPattern } from "@gjsify/canvas2d-core";
|
|
56
2
|
export {
|
|
57
3
|
CanvasPattern
|
|
58
4
|
};
|