react-design-editor
Version:
Design Editor Tools with React.js + ant.design + fabric.js
355 lines (354 loc) • 15.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const fabric_1 = require("fabric");
class WorkareaHandler {
constructor(handler) {
/**
* Set the layout on workarea
* @param {WorkareaLayout} layout
* @returns
*/
this.setLayout = (layout) => {
this.handler.workarea.set('layout', layout);
const { _element, isElement, workareaWidth, workareaHeight } = this.handler.workarea;
const { canvas } = this.handler;
let scaleX = 1;
let scaleY = 1;
const isFixed = layout === 'fixed';
const isResponsive = layout === 'responsive';
const isFullscreen = layout === 'fullscreen';
if (isElement) {
if (isFixed) {
scaleX = workareaWidth / _element.width;
scaleY = workareaHeight / _element.height;
}
else if (isResponsive) {
const scales = this.calculateScale();
scaleX = scales.scaleX;
scaleY = scales.scaleY;
}
else {
scaleX = canvas.getWidth() / _element.width;
scaleY = canvas.getHeight() / _element.height;
}
}
this.handler.getObjects().forEach(obj => {
const { id, player } = obj;
if (id !== 'workarea') {
const objScaleX = !isFullscreen ? 1 : scaleX;
const objScaleY = !isFullscreen ? 1 : scaleY;
const objWidth = obj.width * objScaleX * canvas.getZoom();
const objHeight = obj.height * objScaleY * canvas.getZoom();
const el = this.handler.elementHandler.findById(obj.id);
this.handler.elementHandler.setSize(el, obj);
if (player) {
player.setPlayerSize(objWidth, objHeight);
}
obj.set({
scaleX: !isFullscreen ? 1 : objScaleX,
scaleY: !isFullscreen ? 1 : objScaleY,
});
}
});
if (isResponsive) {
const center = canvas.getCenter();
if (isElement) {
this.handler.workarea.set({
scaleX: 1,
scaleY: 1,
});
this.handler.zoomHandler.zoomToPoint(new fabric_1.fabric.Point(center.left, center.top), scaleX);
}
else {
this.handler.workarea.set({
width: workareaWidth,
height: workareaHeight,
});
scaleX = canvas.getWidth() / workareaWidth;
scaleY = canvas.getHeight() / workareaHeight;
if (workareaHeight >= workareaWidth) {
scaleX = scaleY;
}
else {
scaleY = scaleX;
}
this.handler.zoomHandler.zoomToPoint(new fabric_1.fabric.Point(center.left, center.top), scaleX);
}
canvas.centerObject(this.handler.workarea);
canvas.renderAll();
return;
}
if (isElement) {
this.handler.workarea.set({
width: _element.width,
height: _element.height,
scaleX,
scaleY,
});
}
else {
const width = isFixed ? workareaWidth : this.handler.canvas.getWidth();
const height = isFixed ? workareaHeight : this.handler.canvas.getHeight();
this.handler.workarea.set({
width,
height,
backgroundColor: 'rgba(255, 255, 255, 1)',
});
this.handler.canvas.renderAll();
if (isFixed) {
canvas.centerObject(this.handler.workarea);
}
else {
this.handler.workarea.set({
left: 0,
top: 0,
});
}
}
canvas.centerObject(this.handler.workarea);
const center = canvas.getCenter();
canvas.setViewportTransform([1, 0, 0, 1, 0, 0]);
this.handler.zoomHandler.zoomToPoint(new fabric_1.fabric.Point(center.left, center.top), 1);
canvas.renderAll();
};
/**
* Set the responsive image on Workarea
* @param {string | File} [source]
* @param {boolean} [loaded]
* @returns
*/
this.setResponsiveImage = async (source, loaded) => {
const imageFromUrl = async (src = '') => {
return new Promise(resolve => {
fabric_1.fabric.Image.fromURL(src, (img) => {
const { canvas, workarea, editable } = this.handler;
const { workareaWidth, workareaHeight } = workarea;
const { scaleX, scaleY } = this.calculateScale(img);
if (img._element) {
workarea.set({
...img,
isElement: true,
selectable: false,
});
}
else {
const image = new Image(workareaWidth, workareaHeight);
workarea.setElement(image);
workarea.set({
isElement: false,
selectable: false,
width: workareaWidth,
height: workareaHeight,
});
}
if (editable && !loaded) {
canvas.getObjects().forEach(obj => {
const { id, player } = obj;
if (id !== 'workarea') {
const objWidth = obj.width * scaleX;
const objHeight = obj.height * scaleY;
const el = this.handler.elementHandler.findById(id);
this.handler.elementHandler.setScaleOrAngle(el, obj);
this.handler.elementHandler.setSize(el, obj);
if (player) {
player.setPlayerSize(objWidth, objHeight);
}
obj.set({
scaleX: 1,
scaleY: 1,
});
obj.setCoords();
}
});
}
// 파일이 없을 경우 Canvas의 nextWidth, nextHeight 값이 변경되기 전 상태에서 zoomToFit이 동작함
// 정상 동작 resize event logic => zoomToFit
// 현재 동작 zoomToFit -> resize event logic
this.handler.zoomHandler.zoomToFit();
canvas.centerObject(workarea);
resolve(workarea);
});
});
};
const { workarea } = this.handler;
if (!source) {
workarea.set({
src: null,
file: null,
});
return imageFromUrl(source);
}
if (source instanceof File) {
return new Promise(resolve => {
const reader = new FileReader();
reader.onload = () => {
workarea.set({
file: source,
});
imageFromUrl(reader.result).then(resolve);
};
reader.readAsDataURL(source);
});
}
else {
workarea.set({
src: source,
});
return imageFromUrl(source);
}
};
/**
* Set the image on Workarea
* @param {string | File} source
* @param {boolean} [loaded=false]
* @returns
*/
this.setImage = async (source, loaded = false) => {
const { canvas, workarea, editable } = this.handler;
if (workarea.layout === 'responsive') {
return this.setResponsiveImage(source, loaded);
}
const imageFromUrl = async (src) => {
return new Promise(resolve => {
fabric_1.fabric.Image.fromURL(src, (img) => {
let width = canvas.getWidth();
let height = canvas.getHeight();
if (workarea.layout === 'fixed') {
width = workarea.width * workarea.scaleX;
height = workarea.height * workarea.scaleY;
}
let scaleX = 1;
let scaleY = 1;
if (img._element) {
scaleX = width / img.width;
scaleY = height / img.height;
img.set({
originX: 'left',
originY: 'top',
scaleX,
scaleY,
});
workarea.set({
...img,
isElement: true,
selectable: false,
});
}
else {
workarea.setElement(new Image());
workarea.set({
width,
height,
scaleX,
scaleY,
isElement: false,
selectable: false,
});
}
canvas.centerObject(workarea);
if (editable && !loaded) {
const { layout } = workarea;
canvas.getObjects().forEach(obj => {
const { id, player } = obj;
if (id !== 'workarea') {
scaleX = layout === 'fullscreen' ? scaleX : obj.scaleX;
scaleY = layout === 'fullscreen' ? scaleY : obj.scaleY;
const el = this.handler.elementHandler.findById(id);
this.handler.elementHandler.setSize(el, obj);
if (player) {
const objWidth = obj.width * scaleX;
const objHeight = obj.height * scaleY;
player.setPlayerSize(objWidth, objHeight);
}
obj.set({
scaleX,
scaleY,
});
obj.setCoords();
}
});
}
const center = canvas.getCenter();
const zoom = loaded || workarea.layout === 'fullscreen' ? 1 : this.handler.canvas.getZoom();
canvas.setViewportTransform([1, 0, 0, 1, 0, 0]);
this.handler.zoomHandler.zoomToPoint(new fabric_1.fabric.Point(center.left, center.top), zoom);
canvas.renderAll();
resolve(workarea);
}, { crossOrigin: 'anonymous' });
});
};
if (!source) {
workarea.set({
src: null,
file: null,
});
return imageFromUrl(source);
}
if (source instanceof File) {
return new Promise(resolve => {
const reader = new FileReader();
reader.onload = () => {
workarea.set({
file: source,
});
imageFromUrl(reader.result).then(resolve);
};
reader.readAsDataURL(source);
});
}
else {
workarea.set({
src: source,
});
return imageFromUrl(source);
}
};
/**
* Calculate scale to the image
*
* @param {FabricImage} [image]
* @returns
*/
this.calculateScale = (image) => {
const { canvas, workarea } = this.handler;
const { workareaWidth, workareaHeight } = workarea;
const { _element } = image || workarea;
const width = _element?.width || workareaWidth;
const height = _element?.height || workareaHeight;
let scaleX = canvas.getWidth() / width;
let scaleY = canvas.getHeight() / height;
if (height >= width) {
scaleX = scaleY;
if (canvas.getWidth() < width * scaleX) {
scaleX = scaleX * (canvas.getWidth() / (width * scaleX));
}
}
else {
scaleY = scaleX;
if (canvas.getHeight() < height * scaleX) {
scaleX = scaleX * (canvas.getHeight() / (height * scaleX));
}
}
return { scaleX, scaleY };
};
this.handler = handler;
this.initialize();
}
/**
* Initialize workarea
*
* @author salgum1114
*/
initialize() {
const { workareaOption } = this.handler;
const image = new Image(workareaOption.width, workareaOption.height);
image.width = workareaOption.width;
image.height = workareaOption.height;
this.handler.workarea = new fabric_1.fabric.Image(image, workareaOption);
this.handler.canvas.add(this.handler.workarea);
this.handler.objects = this.handler.getObjects();
this.handler.canvas.centerObject(this.handler.workarea);
this.handler.canvas.renderAll();
}
}
exports.default = WorkareaHandler;