Skip to content

Commit 241754d

Browse files
chore: updates for pixi v8
1 parent 41fcc2f commit 241754d

12 files changed

Lines changed: 238 additions & 201 deletions

File tree

packages/react/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@
9393
"@edifice.io/tiptap-extensions": "workspace:*",
9494
"@edifice.io/utilities": "workspace:*",
9595
"@floating-ui/react": "0.26.0",
96-
"@pixi/mixin-get-child-by-name": "7.4.2",
9796
"@popperjs/core": "2.11.8",
9897
"@tiptap/core": "2.11.0",
9998
"@tiptap/extension-blockquote": "2.11.0",

packages/react/src/modules/multimedia/ImageEditor/components/ImageEditor.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useCallback, useRef, useState } from 'react';
1+
import { useCallback, useEffect, useRef, useState } from 'react';
22

33
import * as PIXI from 'pixi.js';
44
import { useTranslation } from 'react-i18next';
@@ -61,6 +61,13 @@ const ImageEditor = ({
6161
const [legend, setLegend] = useState(legendParam ?? '');
6262
// Whether the image has been edited or the text has been changed
6363
const [dirty, setDirty] = useState<boolean>(false);
64+
65+
// Sync local state when props change (e.g. modal reopened with a different image)
66+
useEffect(() => {
67+
setAltText(altTextParam ?? '');
68+
setLegend(legendParam ?? '');
69+
setDirty(false);
70+
}, [altTextParam, legendParam]);
6471
// Load Image Editor action
6572
const {
6673
toBlob,
@@ -114,7 +121,9 @@ const ImageEditor = ({
114121
},
115122
[setApplication],
116123
);
117-
// A function to remove all opened controllers and backup changes if needed
124+
// Stop the current operation and save its result if applicable.
125+
// `currentOperation` refers to the *previous* operation still in progress,
126+
// since `setCurrentOperation` is called after `stopAll`.
118127
const stopAll = () => {
119128
stopBlur();
120129
stopCrop(currentOperation === 'CROP');
@@ -141,7 +150,7 @@ const ImageEditor = ({
141150
};
142151
// A handle to trigger actions on toolbar action
143152
const handleOperation = async (operation: ImageEditorAction) => {
144-
// Stop Remove all previous graphical controllers
153+
// Stop and save the previous operation before starting the new one
145154
stopAll();
146155
// Save the current operation
147156
setCurrentOperation(operation);

packages/react/src/modules/multimedia/ImageEditor/effects/blur.ts

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import * as PIXI from 'pixi.js';
22

33
import { aggregate } from '../utilities/aggregate';
4+
import { BLUR_LAYER_NAME } from './constants';
45
import { getApplicationScale } from './misc';
56

67
//
7-
// Global constants used for crop effects
8+
// Global constants used for blur effects
89
//
910

1011
// Define the radius (pixel) of the brush used to apply blur
@@ -19,10 +20,27 @@ const CURSOR_NAME = 'BRUSH_CURSOR';
1920
//
2021

2122
/**
22-
* This function draw brush graphical object for each points
23+
* Get or create the blur layer Container in the stage.
24+
* Using a Container (not a Sprite) avoids the v8 deprecation warning
25+
* "Only Containers will be allowed to add children".
26+
*/
27+
function getOrCreateBlurLayer(application: PIXI.Application): PIXI.Container {
28+
let layer = application.stage.getChildByLabel(
29+
BLUR_LAYER_NAME,
30+
) as PIXI.Container | null;
31+
if (!layer) {
32+
layer = new PIXI.Container();
33+
layer.label = BLUR_LAYER_NAME;
34+
application.stage.addChild(layer);
35+
}
36+
return layer;
37+
}
38+
39+
/**
40+
* This function draws brush graphical objects for each point
2341
*
2442
* @param points a list of PIXI.Point used to draw brush
25-
* @returns a graphical object that draw brush for each of theses points
43+
* @returns a graphical object that draws brush for each of these points
2644
*/
2745
function drawBrush(
2846
points: Array<PIXI.Point | undefined>,
@@ -31,22 +49,20 @@ function drawBrush(
3149
const container = new PIXI.Graphics();
3250
for (const point of points) {
3351
if (point) {
34-
container.beginFill(0xffffff, 1);
35-
container.drawCircle(point.x, point.y, BRUSH_SIZE / scale);
36-
container.lineStyle(0);
37-
container.endFill();
52+
container.circle(point.x, point.y, BRUSH_SIZE / scale);
53+
container.fill({ color: 0xffffff, alpha: 1 });
3854
}
3955
}
4056
return container;
4157
}
4258

4359
/**
44-
* This function create a mouse event listener that merge and aggregate mouse events
45-
* The aggregated events are used to draw brush and apply blur filter to the stage
46-
* If the spriteName has not been found in the context, the listener do nothing
60+
* This function creates a mouse event listener that merges and aggregates mouse events.
61+
* The aggregated events are used to draw brush and apply blur filter to the stage.
62+
* If the spriteName has not been found in the context, the listener does nothing.
4763
*
4864
* @param application The PIXI.Application context
49-
* @param {spriteName} arg The name of the sprite identifying the original image
65+
* @param spriteName The name of the sprite identifying the original image
5066
* @returns A mouse event listener
5167
*/
5268
function drawBlurListener(
@@ -60,32 +76,34 @@ function drawBlurListener(
6076
},
6177
(points: Array<PIXI.Point | undefined>) => {
6278
// Search for sprite
63-
const child = application.stage.getChildByName(spriteName);
79+
const child = application.stage.getChildByLabel(spriteName);
6480
const scale = getApplicationScale(application);
6581
if (!child) return;
82+
const sprite = child as PIXI.Sprite;
6683
// Create a sprite by copying texture and apply blurFilter
67-
const newSprite = new PIXI.Sprite((child as PIXI.Sprite).texture);
68-
// Apply blur filter to the new sprite, quality for big image (fix lag issue)
69-
84+
const newSprite = new PIXI.Sprite(sprite.texture);
7085
newSprite.filters = [
7186
new PIXI.BlurFilter({
7287
strength: 8,
7388
quality: Math.min(Math.round(4 * scale), 4),
7489
resolution: Math.min(scale, 1),
7590
}),
7691
];
77-
newSprite.width = (child as PIXI.Sprite).width;
78-
newSprite.height = (child as PIXI.Sprite).height;
79-
// Resize the new sprite to match the original
92+
newSprite.width = sprite.width;
93+
newSprite.height = sprite.height;
8094
newSprite.scale = new PIXI.Point(1, 1);
81-
newSprite.anchor = (child as PIXI.Sprite).anchor;
82-
newSprite.mask = drawBrush(points, scale);
83-
(child as PIXI.Sprite).addChild(newSprite);
95+
newSprite.anchor = sprite.anchor;
96+
// Add blur sprite and its mask to the blur layer Container
97+
const blurLayer = getOrCreateBlurLayer(application);
98+
const brushMask = drawBrush(points, scale);
99+
blurLayer.addChild(brushMask);
100+
newSprite.mask = brushMask;
101+
blurLayer.addChild(newSprite);
84102
},
85103
);
86104
}
87105
/**
88-
* This function draw the graphical cursor use to apply the blur effect
106+
* This function draws the graphical cursor used to apply the blur effect
89107
*
90108
* @param application The PIXI.Application context
91109
* @returns the PIXI.Graphics object representing the cursor
@@ -95,26 +113,25 @@ function drawCursor(application: PIXI.Application): PIXI.Graphics {
95113
removeCursor(application);
96114
const scale = getApplicationScale(application);
97115
const circle = new PIXI.Graphics();
98-
circle.lineStyle(Math.max(1, 1 / scale), 0xff0000);
99-
circle.drawCircle(0, 0, BRUSH_SIZE / scale);
100-
circle.endFill();
101-
circle.name = CURSOR_NAME;
116+
circle.circle(0, 0, BRUSH_SIZE / scale);
117+
circle.stroke({ width: Math.max(1, 1 / scale), color: 0xff0000 });
118+
circle.label = CURSOR_NAME;
102119
application.stage.addChild(circle);
103120
return circle;
104121
}
105122
/**
106-
* This function remove cursor if exists in context
123+
* This function removes cursor if it exists in context
107124
*
108125
* @param application The PIXI.Application context
109126
*/
110127
function removeCursor(application: PIXI.Application) {
111-
const child = application.stage.getChildByName(CURSOR_NAME);
128+
const child = application.stage.getChildByLabel(CURSOR_NAME);
112129
if (child) {
113130
child.removeFromParent();
114131
}
115132
}
116133
/**
117-
* Move the cursor graphical controler while mouse is moving
134+
* Move the cursor graphical controller while mouse is moving
118135
*
119136
* @param application the PIXI.Application context
120137
* @returns A mouse event listener
@@ -123,21 +140,21 @@ function moveCursorListener(application: PIXI.Application) {
123140
return (event: PIXI.FederatedMouseEvent) => {
124141
if (!application) return;
125142
const point = application.stage.toLocal(event.global);
126-
const child = application.stage.getChildByName(CURSOR_NAME, true);
143+
const child = application.stage.getChildByLabel(CURSOR_NAME, true);
127144
if (child) {
128145
child.position.x = point.x;
129146
child.position.y = point.y;
130147
}
131148
};
132149
}
133150
/**
134-
* This function start the blur controler
151+
* This function starts the blur controller:
135152
* - drawing cursor
136153
* - listening mouse move to move cursor
137-
* - listening
154+
* - listening pointer events to apply blur
138155
*
139-
* @param application
140-
* @param param1
156+
* @param application The PIXI.Application context
157+
* @param spriteName The name of the sprite identifying the original image
141158
*/
142159
export function start(
143160
application: PIXI.Application,
@@ -151,6 +168,8 @@ export function start(
151168
application.stage.on('pointermove', cursorListener);
152169
const blurListener = drawBlurListener(application, { spriteName });
153170
application.stage.on('pointerdown', () => {
171+
// Remove first to avoid accumulating duplicate listeners on repeated clicks
172+
application.stage.off('pointermove', blurListener);
154173
application.stage.on('pointermove', blurListener);
155174
});
156175
// Stop listening move when cursor is up
@@ -164,7 +183,9 @@ export function start(
164183
});
165184
}
166185
/**
167-
* This function remove cursor and all mouse event listeners
186+
* This function removes cursor and all mouse event listeners.
187+
* The blur layer is kept on stage so it gets captured by toBlob/generateTexture
188+
* when the image is saved or another operation is applied.
168189
*
169190
* @param application the PIXI.Application context
170191
*/
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/** Label used for the blur layer Container in the stage */
2+
export const BLUR_LAYER_NAME = 'BLUR_LAYER';

0 commit comments

Comments
 (0)