-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Structure
๋ด๋ถ์ ์ผ๋ก ํฌ๊ฒ ๋ ๊ฐ์ง ๋ ์ด์ด๋ก ๋ถ๋ฆฌ๊ฐ ๋๋ฉฐ ์๋์ ๊ฐ๋ค.
-
ImageEditor
- API๋ฅผ ๋ด๋นํ๋ ๊ฐ์ฒด๋ก ์๋ ๋ ๊ฐ์ง ๋ ์ด์ด๋ฅผ ๊ฐ์ง๋ฉฐ, UI์ ์ง์ ์ปค๋ฎค๋์ผ์ด์ ํ๋ค.-
Middle Layer
ย - ๊ทธ๋ฆฌ๊ธฐ ๋์๊ณผ ๋ฌด๊ดํ ์ดํ๋ฆฌ์ผ์ด์ ์ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ์งํฉ์ผ๋ก Invoker, Command, CommandFactory๋ก ๊ตฌ์ฑ๋๋ค. -
Graphics Layer
ย - ์ผ๋ฐ์ ์ผ๋ก ๋งํ๋ canvas๋ฅผ ImageEditor์์ ์ ๊ณตํ๋ ๊ธฐ๋ฅ๋ค๋ก๋ง ์ด๋ฃจ์ด์ง ยCanvas
ย ๋ฅผ ๊ตฌ์ฑํ๋ค. ๊ทธ๋ฆฌ๊ธฐ ๋์์ ์ถ์ํํ๊ณ ์ค์ ๊ตฌํ์ย fabric.jsย ๋ฅผ ์ฌ์ฉํ๋ค.-
Component
๋ ํน์ ๊ธฐ๋ฅ์ ๊ทธ๋ฆฌ๊ธฐ ๋์์ ๋ชจ๋ํ ํ ๊ฒ์ผ๋ก Graphics Layer์ ์์๋๋ค. - ๋๋ก์ ๋ชจ๋ ๋ํ Graphics Layer์์ ํ์ํ ๊ธฐ๋ฅ์ผ๋ก ์ฌ๊ธฐ์์ ๋ด๋นํ๋ค.
-
-
API๋ฅผ ๋ด๋นํ๋ ๊ฐ์ฒด๋ก ์๋์ ์ ์ํ Invoker์ Graphics๋ฅผ ํ๋กํผํฐ๋ก ๊ฐ์ง๋ค.
Command
๋ฅผ ๋ฑ๋ก, ์์ฑํ๋ ํด๋์ค์ด๋ค. Command๋ฅผ ๋ฑ๋กํ ์ ์๋ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๊ณ ImageEditor๋ Command๋ก ๋๋ก์ ๋์์ ํด์ผ ํ๋ ๊ณณ์์ ๋ฑ๋ก๋ Command ์ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ค.
- register - Command ๋ฑ๋ก
- create - ๋ฑ๋ก๋ Command ์ ์ธ์คํด์ค ์์ฑ
Command๋ ํน์ ๊ธฐ๋ฅ์ ์ํํ๊ธฐ ์ํธ ์คํ ๋จ์์ด๋ฉฐ ๋ค๋ฅธ ๋ชจ๋๊ณผ ๋
๋ฆฝ์ ์ด๋ค. ์ด๋ฏธ์ง ์๋ํฐ์์๋ Undo/Redo๋ฅผ ํ๊ธฐ ์ํ ์คํ ๋จ์๋ก ์ฌ์ฉ๋๋ฉฐ Command ์ธ์คํด์ค๋ฅผ Invoker์์ ์คํ์ผ๋ก ๊ด๋ฆฌํ๋ค.
Command ๋ฑ๋ก์ name
, execute
, undo
๋ฅผ ์ ์ํ ๊ฐ์ฒด actions์ args๋ฅผ ์ ๋ฌ ๋ฐ๋๋ค.
class Command {
constructor(actions, args) {
this.name = actions.name;
this.args = args;
this.execute = actions.execute;
this.undo = actions.undo;
this.executeCallback = actions.executeCallback || null;
this.undoCallback = actions.undoCallback || null;
this.undoData = {};
}
}
import๊ฐ ๋ ๋ CommandFactory.register๋ฅผ ์ํํ๋ค. Command ์์๋ ์ฌ์ฉํ Component๋ฅผ import ํ๊ณ Graphics ์ธ์คํด์ค๋ฅผ ์ ๋ฌํ์ฌ ๊ธฐ๋ฅ์ํํ๊ฒ ํ๋ค.
// commandName.js
import commandFactory from '../factory/command';
const command = {
name: 'commandName',
execute(graphics, ...args) {
},
undo(graphics, ...args) {
}
};
CommandFactory.register(command);
module.export = command;
const command = commandFactory.create('commandName', param1, param2);
command.execute(...command.args).then(value => {
// push undo stack
return value;
}).catch(message => {
// do something
return Promise.reject(message);
})
Command
๋ฅผ ์คํํ๊ณ Undo/Redo๋ฅผ ๊ด๋ฆฌํ๋ค. ๋ค๋ฅธ ๊ธฐ๋ฅ์ ์ ๊ฑฐํ๋ค.
-
Component
๋ฆฌ์คํธ ๊ด๋ฆฌ๋ ์ฌ๊ธฐ์๋ ์ ๊ฑฐํ๋ค. ์๋์ ๋ช ์ธํ Canvas๋ก ์ด๊ดํ๋ค.
ImageEditor์ ๋๋ก์ ์ฝ์ด ๋ชจ๋๋ก ์ฐ๋ฆฌ๊ฐ ์ ๊ณตํ๋ ๋๋ก์ ๊ธฐ๋ฅ๋ค์ ๋ชจ๋ ๋ค์ด ์๋ค. ํ๋ถ์ ์ค์ ๊ทธ๋ํฝ ๋ชจ๋์ fabric.js ๋ฅผ ์ฌ์ฉํ๋ค. ์๋๋ ์ด๋ฏธ์ง ์๋ํฐ๊ฐ ์ ๊ณตํ๋ ๊ธฐ๋ฅ ๋ชฉ๋ก์ด๋ค.(๋ถ์ ์์ ์ ๊ท API)
Icon | Image | Shape | Text | Flip | FreeDrawing | LineDrawing | Rotate | Crop | ๊ธฐํ |
---|---|---|---|---|---|---|---|---|---|
addIcon | addImageObject | addShape | addText | flipX | setBrush | setBrush | rotate | crop | resizeCanvasDimension |
registerIcons | loadImageFromFile | setDrawingShape | changeText | flipY | setAngle | getCropzoneRect | toDataURL | ||
changeIconColor | loadImageFromURL | changeShape | changeTextStyle | resetFlip | getDrawingMode | ||||
ApplyFilter | setDrawingMode | ||||||||
RemoveFilter | getImageName | ||||||||
hasFilter | clearObjects | ||||||||
removeActiveObject | |||||||||
destroy | |||||||||
setDefaultPathStyle |
<Canvas ๊ด๋ จ ์ด๋ฒคํธ>
Canvas
๋ CustomEvents
๋ฅผ ย mixin ํ๊ณ Canvas ์ ๊ด๋ จํ ์ด๋ฒคํธ๋ฅผ ๋ฐ์ ํ์๊ฐ ์์ ๋ on("eventName", callback);
์ ์ฌ์ฉํ๋ค.
์๋๋ ๋ฆฌํฉํ ๋ง ์ด์ ๊ธฐ์ค์ผ๋ก fabric.js ๋ก๋ถํฐ ๋ฐ์ํ ์ด๋ฒคํธ ์ค์ ๋ณ๊ฒฝ๋ ์ด๋ฒคํธ๋ค์ด๋ค.
์ด๋ฒคํธ ์ด๋ฆ | ํธ๋ค๋ฌ | from | to | ์ธ๋ถ์ด๋ฒคํธ ์ด๋ฆ | ์ฉ๋ |
---|---|---|---|---|---|
path:created | _onCreatePath | fabric | ImageEditor ->Canvas๋ก ์ด๋ ์์ |
N/A | path ์คํ์ผ์ ํ๋๋ก ์ง์ ํ์ฌ ์ฌ์ฉ |
Component
๋ ๊ธฐ์กด๊ณผ ๋์ผํ๊ฒ ํน์ ๋๋ก์ ๋์์ ๊ตฌํํ ๋ชจ๋์ด๋ค.
๋ค๋ฅธ ์ ์ Component
๋ ๋๋ก์ ์งํฉ์ ๋ถ๋ถ ์งํฉ์ด๋ฏ๋ก Canvas
๋ฅผ ํตํ์ฌ์ ์ฌ์ฉํ๊ฒ ํ๋ค. ย ์ด์ ์๋ Command
์์ Component
๋ฅผ ์ง์ ์ฌ์ฉํ์์ง๋ง ๋ฐ๋ ๊ตฌ์กฐ์์๋ Command
๋ Canvas
๋ฅผ ์ฌ์ฉํ๋ค. Canvas๋ ๋ค์ํ Component๋ค์ ๊ด๋ฆฌํ๋ค.
๋ํ Component์์ ์ธ๋ถ๋ก ์ ๋ฌํด์ผ ํ๋ ์ด๋ฒคํธ๋ Canvas๋ฅผ ํตํ์ฌ ์ ๋ฌํ๋๋ก ํ๋ค. Canvas๋ ํด๋น ์ด๋ฒคํธ๋ฅผ Canvas ์ธ๋ถ์์ ๋ฑ๋กํ ๊ฒฝ์ฐ ๋ค์ ์ ๋ฌํ๋ค.
Component ๋ชฉ๋ก์ ์๋์ ๊ฐ๊ณ ๊ธฐ์กด์ start/end์ ๊ฐ์ด ๋ชจ๋ ๋ณ๊ฒฝ์ด ํ์ํ Component๋ ํ์ํ์๋ค.
์ด๋ฆ | ๋ชจ๋ ํ์ | ์ฉ๋ | to-be |
---|---|---|---|
Cropper | O | Crop ๋ชจ๋, Crop์ฉ UI์ ์ด๋ฒคํธ ์ฒ๋ฆฌ ํ์ | ์ ์ง |
filter | X | ์ด๋ฏธ์ง ํํฐ ๋ชจ๋ | ์ ์ง |
flip | X | ์ด๋ฏธ์ง ๋ค์ง๊ธฐ ๋ชจ๋ | ์ ์ง |
freeDrawing | O | ์์ ๊ทธ๋ฆฌ๊ธฐ ๋ชจ๋ | ์ ์ง |
icon | X | ์์ด์ฝ ์ถ๊ฐ ๋ชจ๋ | ์ ์ง |
imageLoader | X | ๋ฉ์ธ ์ด๋ฏธ์ง ๋ก๋ฉ ๋ชจ๋ | ์ ์ง |
line | O | ์ง์ ๊ทธ๋ฆฌ๊ธฐ ๋ชจ๋ | ์ ์ง |
rotation | X | ๋ฉ์ธ ์ด๋ฏธ์ง ๋ฐ ์ค๋ธ์ ํธ๋ค ํ์ ๋ชจ๋ | ์ ์ง |
shape | O | ๋ํ ๊ทธ๋ฆฌ๊ธฐ ๋ชจ๋ | ์ ์ง |
text | O | ํ ์คํธ ์ค๋ธ์ ํธ ์ ๋ ฅ ๋ชจ๋ | ์ ์ง |
main | X | ๊ณตํต ํ๋กํผํฐ ๊ด๋ฆฌ | ์ ๊ฑฐ ๋ฐ ๊ธฐ๋ฅ Canvas๋ก ์ด๊ด |
๋๋ก์ ๋ชจ๋
๋ ํ ์๊ฐ์ ํ๋๋ง ํ์ฑํ ๋์ด์ผ ํ๋๋ฐ, ๊ฐ ๋ชจ๋๋ง๋ค ์ฌ์ฉํ๋ ์ด๋ฒคํธ์ UI๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋ฌ๋ฏ๋ก ๋๋ก์ ๋ชจ๋๋ ์ํธ ๋ฒ ํ์ ์ด๋ค.
๊ทธ์ ๋ฐํด Command
๋ ๋๋ก์ ๋์์ ๋ํด์ ์ ์ํ ๋ช
๋ น์ด๊ธฐ ๋๋ฌธ์ ๋๋ก์ ๋ชจ๋์ ๋ฌด๊ดํ๊ฒ ๋์ ๊ฐ๋ฅํ๋ค๊ณ ๋ณผ ์ ์๋ค. ๋๋ก์ ๋ชจ๋์ ์ข
์์ฑ์ ์์ ๊ณ ๊ทธ ์ด์์ ์ฌ์ฉ์์๊ฒ ์์ํ๋ค. ๋๋ก์ ๋ชจ๋์ Command ์ ์คํ ์ฌ๋ถ๋ฅผ ๊ด๋ฆฌํ์ง ์์์ผ๋ก์จ ๊ตฌํ์ ๊ฐ๊ฒฐ์ฑ๊ณผ ๋ฒ๊ทธ ๋ฐ์ ๊ฐ๋ฅ์ฑ, ์ ์ง๋ณด์์ ๋ํ ์ด์ ์ ์ป์ ์ ์๋ค. ์ด๋ฏธ์ง ์๋ํฐ๋ ์ฌ์ฉ์๊ฐ ์๋์ ๊ฐ์ด ์์์ ์ธ API ํธ์ถ์ ํ๋ค๊ณ ๋ฏฟ๋๋ค.
<์์์ ์ฌ์ฉ ์>
editor.setDrawingMode("cropper");
editor.crop(editor.getCropzoneRect());
editor.setDrawingMode("normal");
<๋ฌ๊ธ์๋ ์ฌ์ฉ์>
editor.setDrawingMode("cropper");
editor.rotate(90);
editor.setDrawingMode("normal");
๋ฌ๊ธ์๋ ์ฌ์ฉ์์ด์ง๋ง, ๋๋ก์ ๋ชจ๋์ Command๊ฐ ๋ฌด๊ดํจ์ ๋ณด์ฌ์ฃผ๋ ํ๋์ ์๊ฐ ๋ ์ ์๋ค.
๋ณ๊ฒฝ๋ API์ ๋๋ก์๋ชจ๋/Command์ ๋ฌด๊ด์ฑ ๊ฐ๋ ์ ๋ฐํ์ผ๋ก ๋ด๋ถ ์ค๊ณ์ ๋ฆฌํฉํ ๋ง์ ์งํํ๋ค.
Canvas Layer์ ๋ชจ๋ํ๋ฅผ ์ํ์ฌ Canvas ๋ด๋ถ์์ ์ผ์ด๋๋ ๋ชจ๋ ์ด๋ฒคํธ๋ Canvas๋ฅผ ํตํ์ฌ ์ธ๋ถ๋ก ์ ๋ฌํ๋ค. Canvas๊ฐ ๊ด๋ฆฌํ๋ Component์์ ์ผ์ด๋๋ ์ด๋ฒคํธ๋ Canvas์๊ฒ ์ ๋ฌํ๊ณ Canvas๊ฐ ์ธ๋ถ๋ก ์ ๋ฌํ๋ค. ImageEditor๋ ์ธ๋ถ์ ์ง์ ์ ์ผ๋ก ์ปค๋ฎค๋์ผ์ด์ ์ ํ๋ฏ๋ก UI๋ก ์ ๋ฌํ๋ ๋ชจ๋ ์ฝ๋ฐฑ์ ImageEditor ํตํ๋ค. ์๋ฅผ ๋ค์ด ย Canvas์ ย Component๋ก๋ถํฐ ์ฌ๋ผ์์ผ ํ๋ ์ด๋ฒคํธ๋ ImageEditor ๋ด์์ ย Canvas์ ์ด๋ฒคํธ๋ฅผ ๋ฑ๋กํ์ฌ ์ ๋ฌ ๋ฐ๊ฒ ํ๋ค Canvas์์ ์ฌ๋ผ์จ ์ด๋ฒคํธ๊ฐ undo ์คํ์ผ๋ก ๊ด๋ฆฌ๋์ด์ผ ํ๋ ๊ฒฝ์ฐ ImageEditor ์์ Canvas๋ก ์ด๋ฒคํธ๋ฅผ ๋ฐ์ ย Invoker ํจ์๋ฅผ ํธ์ถํ๋ค.
UI ๋ก ์ ๋ฌ๋๋ ์ด๋ฒคํธ๋ ๋๋ถ๋ถ Promise ๋ก ๋์ฒดํ์ฌ ์คํ ์๋ฃ๋ฅผ ์ ๋ฌํ ๊ฒ์ด๊ณ , Undo/Redo์ ๊ด๋ จํ ์ด๋ฒคํธ๋ UI ํด๋ฐ ์ํ๊ฐ ๊ด๋ฆฌ๋ฅผ ์ํ์ฌ ๊ธฐ์กด๊ณผ ๊ฐ์ด UI๋ก ์ด๋ฒคํธ๋ฅผ ์ ๋ฌํ๋ค.
๋จ๋ UI ์ด๋ฒคํธ๋ 5๊ฐ์ด๋ค. objectActivated, objectStyleChanged, mousedown, redoStackChanged, undoStackChanged
Name | Purpose |
---|---|
addText | when mousedown event occurs in 'TEXT' drawing mode |
objectActivated | when user selects an object |
objectMoved | when user drags an object |
objectScaled | when object is being scaled |
textEditing | when textbox is being edited |
mousedown | just mousedown |
undoStackChanged | undo change event |
redoStackChanged | redo change event |
/*
{
id: number
type: type
left: number,
top: number,
width: number,
fill: string
stroke: string
strokeWidth: number
opacity: number,
// text object
text: string,
fontFamily: string,
fontSize: number,
fontStyle: string,
fontWeight: string,
textAlign: string,
textDecoration: string
}
*/
imageEditor.on('objectActivated', function(props) {
console.log(props);
console.log(props.type);
console.log(props.id);
});
class ServiceUI {
-ImageEditor _imageEditor
}
class ImageEditor {
-Invoker _invoker
-Graphics _graphics
ย ย -void execute(commandName)
}
package "Middle Layer" #DDDDDD {
class Invoker
class Command
class CommandFactory
}
together {
class Invoker
class Command
class CommandFactory
}
package "Graphics Layer" #DDDDDD {
class Graphics
}
package "Component" {
class Component
class Cropper
class Filter
class Flip
class FreeDrawing
class Icon
class ImageLoader
class Line
class Rotation
class Shape
class Text
}
package "DrawingMode" {
class DrawingMode
class CropperDrawingMode
class FreeDrawingMode
class LineDrawingMode
class ShapeDrawingMode
class TextDrawingMode
}
class Invoker {
-Array _undoStack
-Array _redoStack
+Promise execute("commandName")
+Promise undo()
+Promise redo()
+void pushUndoStack(command, isSilent)
+void pushRedoStack(command, isSilent)
}
class CommandFactory {
-Map _commands
+void register(commandObject)
+Command create("commandName", ...args)
}
class Command {
+string name
ย ย +Array args
+Object _undoData
+Promise execute()
+Promise undo()
+Command setExecuteCallback(callback)
+Command setUndoCallback(callback)
}
class Graphics {
-DrawingMode[] _drawingModeInstances
-Component[] _components
-Fabric.Canvas _canvas
+setDrawingMode("modeName")
+setDefaultPathStyle(style)
+on("eventName", callback)
}
class Component {
}
class DrawingMode {
}
ServiceUI o-- ImageEditor
ImageEditor o-- Graphics
ImageEditor o-- Invoker
ImageEditor <|-- tui.util.CustomEvents
ImageEditor --> CommandFactory
ImageEditor --> Command
Invoker <|-- tui.util.CustomEvents
Invoker --> CommandFactory
Invoker o-- Command
Command o-- Graphics
Command o-- Component
Graphics o-- DrawingMode
Graphics o-- Component
Graphics o-- Fabric.Canvas
Graphics <|-- tui.util.CustomEvents
Component <|-- Cropper
Component <|-- Filter
Component <|-- Flip
Component <|-- FreeDrawing
Component <|-- Icon
Component <|-- ImageLoader
Component <|-- Line
Component <|-- Rotation
Component <|-- Shape
Component <|-- Text
Cropper <-- Fabric.Canvas
Filter <-- Fabric.Canvas
Flip <-- Fabric.Canvas
FreeDrawing <-- Fabric.Canvas
Icon <-- Fabric.Canvas
ImageLoader <-- Fabric.Canvas
Line <-- Fabric.Canvas
Rotation <-- Fabric.Canvas
Shape <-- Fabric.Canvas
Text <-- Fabric.Canvas
DrawingMode --> Component
DrawingMode <|-- CropperDrawingMode
DrawingMode <|-- FreeDrawingMode
DrawingMode <|-- LineDrawingMode
DrawingMode <|-- ShapeDrawingMode
DrawingMode <|-- TextDrawingMode
CropperDrawingMode <-- Cropper
FreeDrawingMode <-- FreeDrawing
LineDrawingMode <-- Line
ShapeDrawingMode <-- Shape
TextDrawingMode <-- Text