react-photo-layout-editor
Version:
Photo layout editor for react
328 lines (297 loc) • 6.12 kB
JavaScript
import $ from 'jquery/dist/jquery.slim';
import * as lib from './';
/**
* Get image size
*
* @param {String} type
* @param {int} cw container width
* @param {int} ch container height
* @param {int} iw image width
* @param {int} ih image height
* @return {Object}
*/
function getImageSize(type, cw, ch, iw, ih)
{
let size = { width : 0, height : 0 };
switch(type)
{
case 'cover':
if (cw > ch)
{
size.width = cw;
size.height = ih * (cw / iw);
if (ch > size.height)
{
size.width = iw * (ch / ih);
size.height = ch;
}
}
else
{
size.width = iw * (ch / ih);
size.height = ch;
if (cw > size.width)
{
size.width = cw;
size.height = ih * (cw / iw);
}
}
break;
case 'width':
size.width = cw;
size.height = ih * (cw / iw);
break;
case 'height':
size.width = iw * (ch / ih);
size.height = ch;
break;
default:
size.width = cw;
size.height = ch;
break;
}
return {
width : Math.round(size.width),
height : Math.round(size.height)
};
}
/**
* export grid
*
* @param {HTMLElement} el
* @param {Array} grids
* @return {Array}
*/
function makeQueue(el, grids)
{
if (!(el && grids)) return null;
const $items = $(el).children();
let result = [];
$items.each((key, item) => {
const $item = $(item);
const grid = grids[$item.data('key')];
let image = grid.image;
if (image)
{
image = {
src: image.src,
position: image.position.split(' '),
size: image.size === 'cover' ? null : image.size.split(' ')
};
}
result.push({
//key: $item.data('key'),
x: $item.position().left,
y: $item.position().top,
width: $item.width(),
height: $item.height(),
image: image || null,
color: grid.color || 'rgba(255,255,255,1)',
});
});
return result;
}
/**
* make block
*
* @param {Object} queue
* @param {Object} options
* @return {Promise}
*/
function makeBlock(queue={}, options={})
{
return new Promise((resolve) => {
lib.util.loadImage(queue.image ? queue.image.src : null).then((image) => {
if (image)
{
const realSize = { width: image.naturalWidth, height: image.naturalHeight };
let size = {};
let position = {};
// get size and position image
if (queue.image.size)
{
size = getImageSize('width', parseInt(queue.image.size[0]), 0, realSize.width, realSize.height);
position.x = parseInt(queue.image.position[0]);
position.y = parseInt(queue.image.position[1]);
}
else
{
size = getImageSize('cover', queue.width, queue.height, realSize.width, realSize.height);
position.x = (queue.width * 0.5) - (size.width * 0.5);
position.y = (queue.height * 0.5) - (size.height * 0.5);
}
// resize image
lib.resamplingImage({
image,
reSampleCount: options.sampling,
width: queue.width,
height: queue.height,
cx: 0,
cy: 0,
cw: realSize.width,
ch: realSize.height,
dx: position.x,
dy: position.y,
dw: size.width,
dh: size.height,
bgColor: queue.color
}).then((res) => {
resolve({
width: queue.width,
height: queue.height,
x: queue.x,
y: queue.y,
image: res
});
});
}
else
{
resolve({
width: queue.width,
height: queue.height,
x: queue.x,
y: queue.y,
color: queue.color,
image: new lib.Canvas(queue.width, queue.height, queue.color)
});
}
});
});
}
/**
* draw block
* 캔버스에다가 블럭을 그려준다.
*
* @param {Canvas} canvas
* @param {Object} block
*/
function drawBlock(canvas, block)
{
return new Promise(resolve => {
canvas.ctx.drawImage(
block.image.el,
block.x,
block.y,
block.width,
block.height
);
resolve(block.image.el);
});
}
/**
* Get image size
*
* @param {Object} el
* @param {String} format
* @param {int} quality
* @return {Object}
*/
function canvasToBase64(el=null, format=null, quality=0.75)
{
switch(format)
{
case 'png':
format = 'image/png';
break;
case 'jpg':
default:
format = 'image/jpeg';
break;
}
return el.toDataURL(format, (format === 'image/jpeg') ? quality : undefined);
}
/**
* making image
*
* @param {HTMLElement} el `.ple-grid` element
* @param {Object} data
* @param {Object} options
* @return {Promise}
*/
export default function makingImage(el, data={}, options={})
{
const defer = $.Deferred(); // resolve, notify, reject
let queues = makeQueue(el, data.grid);
let current = 0;
const queueTotal = queues.length;
// make canvas
let canvas = new lib.Canvas(el.offsetWidth, el.offsetHeight, data.setting.bgColor);
// send progress event
defer.notify(queueTotal, current++, null);
/**
* play
* 큐 플레이. 이미지를 만들고 캔버스에 그리고나서 결과는 `confirm`에서 받는다.
*
* @param {Object} queue
* @return {Promise}
*/
function play(queue)
{
return new Promise((resolve, reject) => {
makeBlock(queue, options).then((block) => {
drawBlock(canvas, block).then(resolve, reject);
}, reject);
});
}
/**
* confirm
* 큐를 하나 삭제하고 계속 `play`함수를 실행할지 종료할지 결정한다.
*
* @param {Canvas} image
*/
function confirm(image)
{
// 큐 하나빼기
queues.splice(0, 1);
// send progress event
defer.notify(queueTotal, current++, image);
// check queues
if (queues.length)
{
play(queues[0]).then(confirm, error);
}
else
{
end();
}
}
/**
* error
*
* @param {String} err
*/
function error(err)
{
defer.reject(err);
}
/**
* end
* `play`가 모두 끝났을때 호출. `done`으로 내보낸다.
*/
function end()
{
switch(options.output)
{
case 'base64':
defer.resolve(canvasToBase64(canvas.el, options.format, options.quality));
break;
case 'canvas':
default:
defer.resolve(canvas.el);
break;
}
}
// check queue
if (queues.length)
{
// play queue
play(queues[0]).then(confirm, error);
}
else
{
// not found queues
error('not found queue');
}
return defer.promise();
}