543 lines
26 KiB
JavaScript
543 lines
26 KiB
JavaScript
// Scripting by Oleg Okhotnikov, contact - svoboda200786@gmail.com
|
||
let poupup = document.querySelector(".poupup-menu");
|
||
|
||
let actionsHist = [];
|
||
let actionsIndex = -1;
|
||
|
||
let myUndo = document.getElementById('undo-btn');
|
||
let myRedo = document.getElementById('redo-btn');
|
||
|
||
let group = {groupName: undefined};
|
||
|
||
myUndo.onclick = function() {
|
||
if(actionsIndex >= 0){
|
||
undo_redo('undo');
|
||
actionsIndex--;
|
||
var ctx = canvas.contextTop;
|
||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||
}
|
||
};
|
||
myRedo.onclick = function () {
|
||
if(actionsIndex < actionsHist.length - 1){
|
||
actionsIndex++;
|
||
undo_redo('redo');
|
||
var ctx = canvas.contextTop;
|
||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||
}
|
||
};
|
||
function onObjectAdded(obj){
|
||
let item = obj.target;
|
||
if(!file_loaded || item.clonned){ // в этом условии объекты создаются при загрузке сохраненного файла или клонировании
|
||
let shape_type = /shape.*/.test(item.groupName); // если groupName содержит "shape", то это примитив
|
||
if(shape_type){ // если примитив
|
||
item.parent = item;
|
||
item.parent.added = true; // для составных объектов параметр added задается в functions.js
|
||
// также added задается в controls.js и editor.js в add_image
|
||
index++;
|
||
item.index = index;
|
||
shape[index] = item;
|
||
item.clonned = false;
|
||
item.groupName = /[a-zA-Z\_]+/.exec(item.groupName) + index; // перезаписываем groupName, добавляя новый индекс
|
||
}
|
||
if(!item.parent){
|
||
item.parent = item;
|
||
}
|
||
oldParam(item);
|
||
}
|
||
else if(!/legend.*/.test(item.groupName)){
|
||
if(item.parent && !item.parent.zoom_size){
|
||
item.parent.zoom_size = zoom_size;
|
||
}
|
||
if(item.type == "textbox"){
|
||
canvas.setActiveObject(item);
|
||
}
|
||
}
|
||
if(canvas.isDrawingMode == 1){
|
||
item.groupName = "shape_pencil" + index;
|
||
item.parent = item;
|
||
item.perPixelTargetFind = true;
|
||
item.parent.zoom_size = zoom_size;
|
||
}
|
||
let shape_type = /shape.*/.test(item.groupName); // если groupName shape, то это примитив
|
||
if(shape_type && !item.parent.added){ // если примитив, объект создается после загрузки сцены
|
||
index++;
|
||
item.index = index;
|
||
shape[index] = item;
|
||
}
|
||
shape_type = /shape_img.*/.test(item.groupName);
|
||
if((shape_type || canvas.isDrawingMode == 1) && !item.parent.added){ // если создали картинку или
|
||
// карандашную линию, то есть объекты которые создаются без срабатывания обработчика canvas.on('mouse:down'),
|
||
// записываем в истории тут - для остальных см. controls.js функцию endOfCreating
|
||
item.parent.added = true;
|
||
oldParam(item);
|
||
changes(item, "4");
|
||
actionsHist[actionsIndex].flag = 'add';
|
||
actionsHist.index = item.index;
|
||
}
|
||
// возможно так будет быстрее, чем через groupName, потому что в последнем применяется регулярка (пока реализовано только в геометрических ф-ях)
|
||
item.groupType = /[a-zA-Z\_]+/.exec(item.groupName)[0];
|
||
}
|
||
function onObjectSelected(obj){
|
||
let item = obj.target;
|
||
// // выделена или нажата группа
|
||
if(item != undefined){
|
||
if(item.type == "activeSelection"){ // объект является выделением
|
||
item.hasControls = false;
|
||
item.lockScalingX = true;
|
||
item.lockScalingY = true;
|
||
item.lockRotation = true;
|
||
item.parent.zoom_size = item._objects[0].parent.zoom_size;
|
||
}
|
||
if(canvas.isDrawingMode == 0 && item != null && (item.type != "activeSelection" || item.shapes == 1) ){
|
||
if(palette.active){
|
||
palette.active.classList.remove("color-cell-active");
|
||
}
|
||
|
||
palette.active = document.querySelector("[color='" + item.parent.stroke + "']") || document.querySelector("[color='" + item.parent.fill + "']");
|
||
|
||
if(palette.active){
|
||
palette.active.classList.add("color-cell-active");
|
||
}
|
||
|
||
if(item.parent && item.parent.zoom_size != undefined){
|
||
var size = item.parent.zoom_size + 1;
|
||
setTimeout(function(){
|
||
scale_indicator.setAttribute("scale_value", size + "x");
|
||
}, 10);
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
function calcObjects(item, obj){
|
||
let prop = "_objects";
|
||
let array = obj[prop];
|
||
for(var i = 0; i < array.length; i++){
|
||
item.objects_temp.push(array[i]);
|
||
if(array[i][prop] != undefined){
|
||
calcObjects(item, array[i]);
|
||
}
|
||
}
|
||
}
|
||
|
||
function changes(item, num){
|
||
if(item.index != undefined || item.type == "activeSelection" ){
|
||
//console.log("num: " + num);
|
||
actionsIndex++;
|
||
actionsHist.splice(actionsIndex, actionsHist.length - actionsIndex);
|
||
histAdd(item);
|
||
}
|
||
group.param_saved = false;
|
||
}
|
||
|
||
function onObjectModified(obj){
|
||
if(!/back/.test(obj.target.groupName) && !/legend/.test(obj.target.groupName)){
|
||
changes(obj.target, "2");
|
||
}
|
||
}
|
||
|
||
function onObjectRemoved(item){
|
||
if(item != undefined){
|
||
changes(item, "3");
|
||
actionsHist.index = item.index;
|
||
}
|
||
}
|
||
function onSelectionCleared(item){
|
||
if(typeof selection_temp2 != "undefined" && selection_temp2 ){
|
||
var line = item.deselected[0].parent;
|
||
line.x1 = line.arrow.left;
|
||
line.y1 = line.arrow.top;
|
||
line.x2 = line.arrow2.left;
|
||
line.y2 = line.arrow2.top;
|
||
selection_temp2 = null;
|
||
}
|
||
poupup.classList.add("mfp-hide");
|
||
}
|
||
document.addEventListener("click", function(e){
|
||
// алгоритм для выделения нескольких объектов находится в fabric.js
|
||
let item = canvas.getActiveObject();
|
||
if(item != undefined && item.type == "activeSelection"){
|
||
item.parent = item;
|
||
// oldParam(item);
|
||
}
|
||
if(e.target.className == "upper-canvas " && !move_flag && item != undefined
|
||
&& item.parent.objects != undefined && item.type != "i-text"){
|
||
}
|
||
else if(move_flag){
|
||
let obj = {};
|
||
obj.target = item;
|
||
// onObjectSelected(obj);
|
||
}
|
||
move_flag = false;
|
||
});
|
||
canvas.on('mouse:down:before', function(e){
|
||
var obj = e.target;
|
||
if(obj && editor_command || text_editing){
|
||
drawing_object = true;
|
||
}
|
||
if(obj){
|
||
if(drawing_object){
|
||
let array = obj.parent.objects;
|
||
for(var i in array){
|
||
obj.parent[array[i]].selectable = false;
|
||
}
|
||
}
|
||
else{
|
||
let array = obj.parent.objects;
|
||
for(var i in array){
|
||
var name = obj.parent[array[i]].name;
|
||
if( (name == "rect" && obj.parent[array[i]].groupType == "socket")
|
||
|| name == "arrow" || name == "arrow2" || name == "arrow_part1" || name == "arrow_part2" || name == "line"){
|
||
obj.parent[array[i]].selectable = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if(group.cloneOne){ // __onMouseDown в fabric.js, там установлен getActiveObject().setCoords()
|
||
let item = canvas.getActiveObject();
|
||
editor_obj.setClone(item);
|
||
// item.hasControls = true;
|
||
// canvas.setActiveObject(item);
|
||
canvas.renderAll();
|
||
element_cursor();
|
||
}
|
||
});
|
||
canvas.on('selection:created', onObjectSelected);
|
||
canvas.on('selection:updated', onObjectSelected);
|
||
canvas.on('selection:cleared', onSelectionCleared);
|
||
canvas.on('mouse:down', onObjectSelected);
|
||
canvas.on('object:modified', onObjectModified);
|
||
canvas.on('object:changed', onObjectModified);
|
||
canvas.on('object:added', onObjectAdded);
|
||
///////////////////////////////// oldParam /////////////////////////////////
|
||
/* Записывает в свойства с посфиксом old текущие значения - при отмене в них можно будет вернуться */
|
||
// Параметр old нужен потому, что предыдущее действик могло быть с другим объектом, поэтому
|
||
// нельзя просто взять старое свойство из actionIndex -1
|
||
function oldParam(item){
|
||
if (item != null){
|
||
let shape_type = /shape.*/.test(item.groupName);
|
||
if(item.parent.objects || item.parent._objects){
|
||
if(item.type == "activeSelection"){
|
||
var group_deltaX = item.width / 2 + item.left; // у объектов в группе отсчет координат относительно центра выделения
|
||
var group_deltaY = item.height / 2 + item.top; // у объектов в группе отсчет координат относительно центра выделения
|
||
var prop = "_objects";
|
||
}
|
||
else{
|
||
var group_deltaX = 0;
|
||
var group_deltaY = 0;
|
||
var prop = "objects";
|
||
}
|
||
let array = item.parent[prop]; // записываем части составного объекта в массив
|
||
for(var i in array){
|
||
if(item.type == "activeSelection"){ // у объектов в группе отсчет координат относительно центра выделения
|
||
var obj = array[i];
|
||
}
|
||
else{
|
||
var obj = item.parent[array[i]];
|
||
}
|
||
obj.set({
|
||
"x1_old": obj.x1,
|
||
"x2_old": obj.x2,
|
||
"y1_old": obj.y1,
|
||
"y2_old": obj.y2,
|
||
"left_old": obj.left + group_deltaX,
|
||
"top_old": obj.top + group_deltaY,
|
||
"width_old": obj.width,
|
||
"height_old": obj.height,
|
||
"originX_old": obj.originX,
|
||
"originY_old": obj.originY,
|
||
"scaleX_old": obj.scaleX,
|
||
"scaleY_old": obj.scaleY,
|
||
"angle_old": obj.angle,
|
||
"text_old": obj.text,
|
||
"fill_old": obj.fill,
|
||
"fontWeight_old": obj.fontWeight,
|
||
"fontSize_old": obj.fontSize,
|
||
"stroke_old": obj.stroke,
|
||
"strokeWidth_old": obj.strokeWidth,
|
||
"visible_old": obj.visible,
|
||
"zoom_size_old": obj.zoom_size
|
||
})
|
||
}
|
||
}
|
||
else{
|
||
if(item.x1){
|
||
item.set({
|
||
"x1_old": item.x1,
|
||
"x2_old": item.x2,
|
||
"y1_old": item.y1,
|
||
"y2_old": item.y2
|
||
})
|
||
}
|
||
item.set({
|
||
"left_old": item.left,
|
||
"top_old": item.top,
|
||
"width_old": item.width,
|
||
"height_old": item.height,
|
||
"originX_old": item.originX,
|
||
"originY_old": item.originY,
|
||
"scaleX_old": item.scaleX,
|
||
"scaleY_old": item.scaleY,
|
||
"angle_old": item.angle,
|
||
"text_old": item.text,
|
||
"fill_old": item.fill,
|
||
"fontWeight_old": item.fontWeight,
|
||
"fontSize_old": item.fontSize,
|
||
"stroke_old": item.stroke,
|
||
"strokeWidth_old": item.strokeWidth,
|
||
"visible_old": item.visible,
|
||
"zoom_size_old": item.zoom_size
|
||
})
|
||
}
|
||
}
|
||
}
|
||
///////////////////////////////// histAdd /////////////////////////////////
|
||
/* Добавляет в историю объект, с текущими параметрами объекта fabric */
|
||
function histAdd(item){
|
||
if (item != undefined){
|
||
let shape_type = /shape.*/.test(item.groupName);
|
||
// Пушим в историю все составные части
|
||
if(!shape_type || item.type == "activeSelection"){ // если не примитив
|
||
actionsHist.push([]); // создаем новый элемент в истории
|
||
|
||
if(item.type == "activeSelection"){
|
||
var group_deltaX = item.width / 2 + item.left; // у объектов в группе отсчет координат относительно центра выделения
|
||
var group_deltaY = item.height / 2 + item.top; // у объектов в группе отсчет координат относительно центра выделения
|
||
var prop = "_objects";
|
||
}
|
||
else{
|
||
var group_deltaX = 0;
|
||
var group_deltaY = 0;
|
||
var prop = "objects";
|
||
}
|
||
|
||
let array = item.parent[prop]; // записываем части составного объекта в массив
|
||
let actionsHistEl = actionsHist[actionsHist.length-1]; // даем новому эелементу истории название
|
||
// actionsHistEl.objects = []; // в это свойсто будут записываться старые и текущие параметры части
|
||
// составного объекта
|
||
|
||
for(var i in array){
|
||
if(item.type == "activeSelection"){ // у объектов в группе отсчет координат относительно центра выделения
|
||
var obj = array[i];
|
||
}
|
||
else{
|
||
var obj = item.parent[array[i]];
|
||
}
|
||
actionsHistEl.push({
|
||
"name": obj.name,
|
||
"index": obj.parent.index,
|
||
"left_old": obj.left_old,
|
||
"top_old": obj.top_old,
|
||
"width_old": obj.width_old,
|
||
"height_old": obj.height_old,
|
||
"originX_old": obj.originX_old,
|
||
"originY_old": obj.originY_old,
|
||
"scaleX_old": obj.scaleX_old,
|
||
"scaleY_old": obj.scaleY_old,
|
||
"angle_old": obj.angle_old,
|
||
'x1_old': obj.x1_old,
|
||
'y1_old': obj.y1_old,
|
||
'x2_old': obj.x2_old,
|
||
'y2_old': obj.y2_old,
|
||
"text_old": obj.text_old,
|
||
"fill_old": obj.fill_old,
|
||
"fontWeight_old": obj.fontWeight_old,
|
||
"fontSize_old": obj.fontSize_old,
|
||
"stroke_old": obj.stroke_old,
|
||
"strokeWidth_old": obj.strokeWidth_old,
|
||
"visible_old": obj.visible_old,
|
||
"zoom_size_old": obj.zoom_size_old,
|
||
"left": obj.left + group_deltaX,
|
||
"top": obj.top + group_deltaY,
|
||
"width": obj.width,
|
||
"height": obj.height,
|
||
"originX": obj.originX,
|
||
"originY": obj.originY,
|
||
"scaleX": obj.scaleX,
|
||
"scaleY": obj.scaleY,
|
||
"angle": obj.angle,
|
||
'x1': obj.x1,
|
||
'y1': obj.y1,
|
||
'x2': obj.x2,
|
||
'y2': obj.y2,
|
||
"text": obj.text,
|
||
"fill": obj.fill,
|
||
"fontWeight": obj.fontWeight,
|
||
"fontSize": obj.fontSize,
|
||
"stroke": obj.stroke,
|
||
"strokeWidth": obj.strokeWidth,
|
||
"visible": obj.visible,
|
||
"zoom_size": obj.zoom_size
|
||
});
|
||
}
|
||
}
|
||
else{
|
||
actionsHist.push([]); // создаем новый элемент в истории
|
||
|
||
let actionsHistEl = actionsHist[actionsHist.length-1];
|
||
actionsHistEl.push({
|
||
"index": item.index,
|
||
"left_old": item.left_old,
|
||
"top_old": item.top_old,
|
||
"width_old": item.width_old,
|
||
"height_old": item.height_old,
|
||
"scaleX_old": item.scaleX_old,
|
||
"scaleY_old": item.scaleY_old,
|
||
"originX_old": item.originX_old,
|
||
"originY_old": item.originY_old,
|
||
"angle_old": item.angle_old,
|
||
"text_old": item.text_old,
|
||
"fill_old": item.fill_old,
|
||
"fontWeight_old": item.fontWeight_old,
|
||
"fontSize_old": item.fontSize_old,
|
||
"stroke_old": item.stroke_old,
|
||
"strokeWidth_old": item.strokeWidth_old,
|
||
"visible_old": item.visible_old,
|
||
"zoom_size_old": item.zoom_size_old,
|
||
"left": item.left,
|
||
"top": item.top,
|
||
"width": item.width,
|
||
"height": item.height,
|
||
"originX": item.originX,
|
||
"originY": item.originY,
|
||
"scaleX": item.scaleX,
|
||
"scaleY": item.scaleY,
|
||
"angle": item.angle,
|
||
"text": item.text,
|
||
"fill": item.fill,
|
||
"fontWeight": item.fontWeight,
|
||
"fontSize": item.fontSize,
|
||
"stroke": item.stroke,
|
||
"strokeWidth": item.strokeWidth,
|
||
"visible": item.visible,
|
||
"zoom_size": item.zoom_size
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
///////////////////////////////// undo_redo /////////////////////////////////
|
||
/* Возврат - повтор */
|
||
function undo_redo(flag){
|
||
if(Boolean(actionsHist[actionsIndex])){
|
||
// let item = shape[actionsHist[actionsIndex].index];
|
||
for (var obj of actionsHist[actionsIndex]){
|
||
if(obj.name){
|
||
var item = shape[obj.index][obj.name];
|
||
}
|
||
else{
|
||
var item = shape[obj.index];
|
||
}
|
||
if(actionsHist[actionsIndex].flag == "add" && flag == 'undo'){ // если объект был создан в этот момент истории
|
||
deleteObj(item, true);
|
||
}
|
||
else{
|
||
canvas.discardActiveObject();
|
||
canvas.requestRenderAll();
|
||
if(flag == 'undo'){
|
||
setHistoryParam(item, "_old", obj);
|
||
}
|
||
else{
|
||
setHistoryParam(item, "", obj);
|
||
}
|
||
}
|
||
}
|
||
|
||
// shape[actionsHist[actionsIndex].index].setCoords();
|
||
}
|
||
canvas.discardActiveObject().renderAll();
|
||
}
|
||
///////////////////////////////// setHistoryParam /////////////////////////////////
|
||
/* Устанавливает значения , записанные при помощи oldParam */
|
||
function setHistoryParam(item, postfix, obj){
|
||
if(item.name){
|
||
item.set({
|
||
"x1": obj["x1" + postfix],
|
||
"x2": obj["x2" + postfix],
|
||
"y1": obj["y1" + postfix],
|
||
"y2": obj["y2" + postfix],
|
||
"left": obj["left" + postfix],
|
||
"top": obj["top" + postfix],
|
||
"width": obj["width" + postfix],
|
||
"height": obj["height" + postfix],
|
||
"originX": obj["originX" + postfix],
|
||
"originY": obj["originY" + postfix],
|
||
"scaleX": obj["scaleX" + postfix],
|
||
"scaleY": obj["scaleY" + postfix],
|
||
"angle": obj["angle" + postfix],
|
||
"text": obj["text" + postfix],
|
||
"fill": obj["fill" + postfix],
|
||
"fontWeight": obj["fontWeight" + postfix],
|
||
"fontSize": obj["fontSize" + postfix],
|
||
"stroke": obj["stroke" + postfix],
|
||
"strokeWidth": obj["strokeWidth" + postfix],
|
||
"visible": obj["visible" + postfix],
|
||
"zoom_size": obj["zoom_size" + postfix]
|
||
});
|
||
item.setCoords();
|
||
}
|
||
// Примитивы:
|
||
// Если выделено несколько объектов, втом числе составных,
|
||
// то все будут расчитываться как сумма примитиввов, потому что обсчет идет
|
||
// для item, в который записывается результат canvas.getActiveObject() - это будет выделение
|
||
// или (activeSelection)
|
||
else{
|
||
item.set({
|
||
"left": obj["left" + postfix],
|
||
"top": obj["top" + postfix],
|
||
"width": obj["width" + postfix],
|
||
"height": obj["height" + postfix],
|
||
"originX": obj["originX" + postfix],
|
||
"originY": obj["originY" + postfix],
|
||
"scaleX": obj["scaleX" + postfix],
|
||
"scaleY": obj["scaleY" + postfix],
|
||
"angle": obj["angle" + postfix],
|
||
"text": obj["text" + postfix],
|
||
"fill": obj["fill" + postfix],
|
||
"fontWeight": obj["fontWeight" + postfix],
|
||
"fontSize": obj["fontSize" + postfix],
|
||
"stroke": obj["stroke" + postfix],
|
||
"strokeWidth": obj["strokeWidth" + postfix],
|
||
"visible": obj["visible" + postfix],
|
||
"zoom_size": obj["zoom_size" + postfix]
|
||
});
|
||
shape_type = /shape_svg.*/.test(item.groupName);
|
||
if(shape_type){
|
||
editor_obj.add_legend();
|
||
}
|
||
canvas.renderAll();
|
||
}
|
||
// if(item.parent._objects != undefined){ // выделение или группа
|
||
// setHistoryParam_subfunction(item, postfix);
|
||
// }
|
||
}
|
||
function setHistoryParam_subfunction(item, postfix, array){
|
||
/* подфункция для объектов, создаваемых с помощью выделения или группы */
|
||
// if(shape[actionsHist[actionsIndex].index].type == "activeSelection"){
|
||
// var obj = shape[actionsHist[actionsIndex].index].objects_temp;
|
||
// }
|
||
// else{
|
||
var obj = shape[actionsHist[actionsIndex].index]._objects;
|
||
// }
|
||
if(array == undefined){
|
||
var array = actionsHist[actionsIndex]["_objects"];
|
||
}
|
||
for(var i in array){
|
||
obj[i].set({
|
||
"fill": array[i]["fill" + postfix],
|
||
"fontWeight": array[i]["fontWeight" + postfix],
|
||
"fontSize": array[i]["fontSize" + postfix],
|
||
"stroke": array[i]["stroke" + postfix],
|
||
"strokeWidth": array[i]["strokeWidth" + postfix],
|
||
"scaleX": array[i]["scaleX" + postfix],
|
||
"scaleY": array[i]["scaleY" + postfix],
|
||
"visible": array[i]["visible" + postfix],
|
||
"zoom_size": array[i]["zoom_size" + postfix]
|
||
});
|
||
shape_type = /shape_svg.*/.test(obj[i].groupName);
|
||
if(shape_type){
|
||
editor_obj.add_legend();
|
||
}
|
||
}
|
||
}
|