Add miniPaint as new frontend base
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import GUI_tools_class from './../core/gui/gui-tools.js';
|
||||
import Base_gui_class from './../core/base-gui.js';
|
||||
import Base_selection_class from './../core/base-selection.js';
|
||||
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
|
||||
class Animation_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.GUI_tools = new GUI_tools_class();
|
||||
this.Base_gui = new Base_gui_class();
|
||||
this.name = 'animation';
|
||||
this.intervalID = null;
|
||||
this.index = 0;
|
||||
this.toggle_layer_visibility_action = new app.Actions.Toggle_layer_visibility_action();
|
||||
|
||||
this.disable_selection(ctx);
|
||||
}
|
||||
|
||||
load() {
|
||||
//nothing
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
//nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* disable_selection
|
||||
*/
|
||||
disable_selection(ctx) {
|
||||
var sel_config = {
|
||||
enable_background: false,
|
||||
enable_borders: false,
|
||||
enable_controls: false,
|
||||
enable_rotation: false,
|
||||
enable_move: false,
|
||||
data_function: function () {
|
||||
return null;
|
||||
},
|
||||
};
|
||||
this.Base_selection = new Base_selection_class(ctx, sel_config, this.name);
|
||||
}
|
||||
|
||||
on_params_update(data) {
|
||||
if(data.key != "play")
|
||||
return;
|
||||
|
||||
var params = this.getParams();
|
||||
if (config.layers.length == 1) {
|
||||
alertify.error('Can not animate 1 layer.');
|
||||
return;
|
||||
}
|
||||
this.stop();
|
||||
|
||||
if (params.play == true) {
|
||||
this.start(params.delay);
|
||||
}
|
||||
}
|
||||
|
||||
on_activate() {
|
||||
return [
|
||||
new app.Actions.Stop_animation_action(false)
|
||||
];
|
||||
}
|
||||
|
||||
on_leave() {
|
||||
return [
|
||||
new app.Actions.Stop_animation_action(true)
|
||||
];
|
||||
}
|
||||
|
||||
start(delay) {
|
||||
var _this = this;
|
||||
delay = parseInt(delay);
|
||||
if (delay < 0)
|
||||
delay = 50;
|
||||
|
||||
this.intervalID = window.setInterval(function () {
|
||||
_this.play(_this);
|
||||
}, delay);
|
||||
}
|
||||
|
||||
stop() {
|
||||
new app.Actions.Stop_animation_action(true).do();
|
||||
}
|
||||
|
||||
play(_this) {
|
||||
|
||||
for (var i in config.layers) {
|
||||
config.layers[i].visible = false;
|
||||
}
|
||||
|
||||
//show 1
|
||||
if (config.layers[this.index] != undefined) {
|
||||
this.toggle_layer_visibility_action.layer_id = config.layers[this.index].id;
|
||||
this.toggle_layer_visibility_action.do();
|
||||
}
|
||||
|
||||
//change index
|
||||
if (config.layers[this.index + 1] != undefined) {
|
||||
this.index++;
|
||||
}
|
||||
else {
|
||||
this.index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
;
|
||||
export default Animation_class;
|
||||
@@ -0,0 +1,140 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
import ImageFilters from './../libs/imagefilters.js';
|
||||
import Helper_class from './../libs/helpers.js';
|
||||
|
||||
class Blur_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.Helper = new Helper_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'blur';
|
||||
this.tmpCanvas = null;
|
||||
this.tmpCanvasCtx = null;
|
||||
this.started = false;
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
default_dragMove(event) {
|
||||
if (config.TOOL.name != this.name)
|
||||
return;
|
||||
this.mousemove(event);
|
||||
|
||||
//mouse cursor
|
||||
var mouse = this.get_mouse_info(event);
|
||||
var params = this.getParams();
|
||||
this.show_mouse_cursor(mouse.x, mouse.y, params.size, 'circle');
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.started = false;
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (config.layer.type != 'image') {
|
||||
alertify.error('This layer must contain an image. Please convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
if (config.layer.rotate || 0 > 0) {
|
||||
alertify.error('Erase on rotate object is disabled. Please rasterize first.');
|
||||
return;
|
||||
}
|
||||
this.started = true;
|
||||
|
||||
//get canvas from layer
|
||||
this.tmpCanvas = document.createElement('canvas');
|
||||
this.tmpCanvasCtx = this.tmpCanvas.getContext("2d");
|
||||
this.tmpCanvas.width = config.layer.width_original;
|
||||
this.tmpCanvas.height = config.layer.height_original;
|
||||
this.tmpCanvasCtx.drawImage(config.layer.link, 0, 0);
|
||||
|
||||
//do blur
|
||||
this.blur_general('click', mouse, params.size, params.strength);
|
||||
|
||||
//register tmp canvas for faster redraw
|
||||
config.layer.link_canvas = this.tmpCanvas;
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (this.started == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
//do blur
|
||||
this.blur_general('move', mouse, params.size, params.strength);
|
||||
|
||||
//draw draft preview
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
if (this.started == false) {
|
||||
return;
|
||||
}
|
||||
delete config.layer.link_canvas;
|
||||
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('blur_tool', 'Blur Tool', [
|
||||
new app.Actions.Update_layer_image_action(this.tmpCanvas)
|
||||
])
|
||||
);
|
||||
|
||||
//decrease memory
|
||||
this.tmpCanvas.width = 1;
|
||||
this.tmpCanvas.height = 1;
|
||||
this.tmpCanvas = null;
|
||||
this.tmpCanvasCtx = null;
|
||||
}
|
||||
|
||||
blur_general(type, mouse, size, strength) {
|
||||
var ctx = this.tmpCanvasCtx;
|
||||
var mouse_x = Math.round(mouse.x) - config.layer.x;
|
||||
var mouse_y = Math.round(mouse.y) - config.layer.y;
|
||||
|
||||
//adapt to origin size
|
||||
mouse_x = this.adaptSize(mouse_x, 'width');
|
||||
mouse_y = this.adaptSize(mouse_y, 'height');
|
||||
var size_w = this.adaptSize(size, 'width');
|
||||
var size_h = this.adaptSize(size, 'height');
|
||||
|
||||
//find center
|
||||
var center_x = mouse_x - Math.round(size_w / 2);
|
||||
var center_y = mouse_y - Math.round(size_h / 2);
|
||||
|
||||
//convert float coords to integers
|
||||
center_x = Math.round(center_x);
|
||||
center_y = Math.round(center_y);
|
||||
mouse_x = Math.round(mouse_x);
|
||||
mouse_y = Math.round(mouse_y);
|
||||
|
||||
if (type == 'move') {
|
||||
strength = strength / 2;
|
||||
if (strength < 1)
|
||||
strength = 1;
|
||||
}
|
||||
|
||||
var imageData = ctx.getImageData(center_x, center_y, size_w, size_h);
|
||||
var filtered = ImageFilters.StackBlur(imageData, strength); //add effect
|
||||
this.Helper.image_round(this.tmpCanvasCtx, mouse_x, mouse_y, size_w, size_h, filtered);
|
||||
}
|
||||
|
||||
}
|
||||
export default Blur_class;
|
||||
@@ -0,0 +1,570 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
|
||||
class Brush_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.name = 'brush';
|
||||
this.layer = {};
|
||||
this.params_hash = false;
|
||||
this.pressure_supported = false;
|
||||
this.pointer_pressure = 0; // has range [0 - 1]
|
||||
this.max_speed = 20;
|
||||
this.power = 2; //how speed affects size
|
||||
this.event_links = [];
|
||||
this.data_index = 0;
|
||||
}
|
||||
|
||||
load() {
|
||||
var _this = this;
|
||||
var is_touch = false;
|
||||
|
||||
//pointer events
|
||||
document.addEventListener('pointerdown', function (event) {
|
||||
_this.pointerdown(event);
|
||||
});
|
||||
document.addEventListener('pointermove', function (event) {
|
||||
_this.pointermove(event);
|
||||
});
|
||||
|
||||
//mouse events
|
||||
document.addEventListener('mousedown', function (event) {
|
||||
if(is_touch)
|
||||
return;
|
||||
_this.dragStart(event);
|
||||
});
|
||||
document.addEventListener('mousemove', function (event) {
|
||||
if(is_touch)
|
||||
return;
|
||||
_this.dragMove(event);
|
||||
});
|
||||
document.addEventListener('mouseup', function (event) {
|
||||
if(is_touch)
|
||||
return;
|
||||
_this.dragEnd(event);
|
||||
});
|
||||
|
||||
// collect touch events
|
||||
document.addEventListener('touchstart', function (event) {
|
||||
is_touch = true;
|
||||
_this.dragStart(event);
|
||||
});
|
||||
document.addEventListener('touchmove', function (event) {
|
||||
_this.dragMove(event);
|
||||
});
|
||||
document.addEventListener('touchend', function (event) {
|
||||
_this.dragEnd(event);
|
||||
});
|
||||
}
|
||||
|
||||
pointerdown(e) {
|
||||
// Devices that don't actually support pen pressure can give 0.5 as a false reading.
|
||||
// It is highly unlikely a real pen will read exactly 0.5 at the start of a stroke.
|
||||
if (e.pressure && e.pressure !== 0 && e.pressure !== 0.5 && e.pressure <= 1) {
|
||||
this.pressure_supported = true;
|
||||
this.pointer_pressure = e.pressure;
|
||||
} else {
|
||||
this.pressure_supported = false;
|
||||
}
|
||||
}
|
||||
|
||||
pointermove(e) {
|
||||
// Pressure of exactly 1 seems to be an input error, sometimes I see it when lifting the pen
|
||||
// off the screen when pressure reading should be near 0.
|
||||
if (this.pressure_supported && e.pressure < 1) {
|
||||
this.pointer_pressure = e.pressure;
|
||||
}
|
||||
}
|
||||
|
||||
dragStart(event) {
|
||||
var _this = this;
|
||||
if (config.TOOL.name != _this.name)
|
||||
return;
|
||||
this.click_counter++;
|
||||
|
||||
var mouse = this.get_mouse_info(event);
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var events = [];
|
||||
if (event.changedTouches) {
|
||||
events = event.changedTouches;
|
||||
}
|
||||
else{
|
||||
events.push(event);
|
||||
}
|
||||
for(var i = 0; i < events.length; i++){
|
||||
var identifier = null;
|
||||
if(typeof events[i].identifier != "undefined") {
|
||||
identifier = events[i].identifier;
|
||||
}
|
||||
|
||||
this.event_links.push({
|
||||
identifier: identifier,
|
||||
index: this.data_index,
|
||||
});
|
||||
|
||||
_this.mousedown_action(events[i], this.data_index, identifier);
|
||||
|
||||
this.data_index++;
|
||||
}
|
||||
}
|
||||
|
||||
dragMove(event) {
|
||||
var _this = this;
|
||||
if (config.TOOL.name != _this.name)
|
||||
return;
|
||||
|
||||
if (typeof event.changedTouches == "undefined") {
|
||||
//mouse cursor
|
||||
var mouse = _this.get_mouse_info(event);
|
||||
var params = _this.getParams();
|
||||
_this.show_mouse_cursor(mouse.x, mouse.y, params.size, 'circle');
|
||||
}
|
||||
|
||||
var mouse = this.get_mouse_info(event);
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var events = [];
|
||||
if (event.changedTouches) {
|
||||
events = event.changedTouches;
|
||||
}
|
||||
else{
|
||||
events.push(event);
|
||||
}
|
||||
for(var i = 0; i < events.length; i++){
|
||||
var identifier = null;
|
||||
if(typeof events[i].identifier != "undefined") {
|
||||
identifier = events[i].identifier;
|
||||
}
|
||||
|
||||
for(var j = 0; i < this.event_links.length; j++){
|
||||
if(this.event_links[j].identifier == identifier){
|
||||
//found link
|
||||
_this.mousemove_action(events[i], this.event_links[j].index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dragEnd(event) {
|
||||
var _this = this;
|
||||
if (config.TOOL.name != _this.name)
|
||||
return;
|
||||
|
||||
var mouse = this.get_mouse_info(event);
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var events = [];
|
||||
if (event.changedTouches) {
|
||||
events = event.changedTouches;
|
||||
}
|
||||
else{
|
||||
events.push(event);
|
||||
}
|
||||
for(var i = 0; i < events.length; i++){
|
||||
var identifier = null;
|
||||
if(typeof events[i].identifier != "undefined") {
|
||||
//unlink
|
||||
identifier = events[i].identifier;
|
||||
}
|
||||
|
||||
for(var j = 0; i < this.event_links.length; j++){
|
||||
if(this.event_links[j].identifier == identifier){
|
||||
this.event_links.splice(j, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_this.mouseup_action(events[i]);
|
||||
}
|
||||
}
|
||||
|
||||
mousedown_action(e, index, event_identifier) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false)
|
||||
return;
|
||||
|
||||
var params_hash = this.get_params_hash();
|
||||
|
||||
if (config.layer.type != this.name || params_hash != this.params_hash) {
|
||||
//register new object - current layer is not ours or params changed
|
||||
this.layer = {
|
||||
type: this.name,
|
||||
data: [[]],
|
||||
params: this.clone(this.getParams()),
|
||||
status: 'draft',
|
||||
render_function: [this.name, 'render'],
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: config.WIDTH,
|
||||
height: config.HEIGHT,
|
||||
hide_selection_if_active: true,
|
||||
rotate: null,
|
||||
is_vector: true,
|
||||
color: config.COLOR
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('new_brush_layer', 'New Brush Layer', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
this.params_hash = params_hash;
|
||||
|
||||
//reset event links index
|
||||
this.data_index = 0;
|
||||
index = 0;
|
||||
this.event_links = [];
|
||||
this.event_links.push({
|
||||
identifier: event_identifier,
|
||||
index: this.data_index,
|
||||
});
|
||||
}
|
||||
else {
|
||||
const new_data = JSON.parse(JSON.stringify(config.layer.data));
|
||||
new_data.push([]);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('update_brush_layer', 'Update Brush Layer', [
|
||||
new app.Actions.Update_layer_action(config.layer.id, {
|
||||
data: new_data
|
||||
})
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
//in case of undo, recalculate index
|
||||
for(var i = index; i >= 0; i++){
|
||||
if(typeof config.layer.data[index] != "undefined"){
|
||||
break;
|
||||
}
|
||||
index--;
|
||||
}
|
||||
|
||||
var current_group = config.layer.data[index];
|
||||
var params = this.getParams();
|
||||
|
||||
//detect line size
|
||||
var size = params.size;
|
||||
var new_size = size;
|
||||
|
||||
if (params.pressure == true) {
|
||||
if (this.pressure_supported) {
|
||||
new_size = size * this.pointer_pressure * 2;
|
||||
}
|
||||
else {
|
||||
new_size = size + size / this.max_speed * mouse.speed_average * this.power;
|
||||
new_size = Math.max(new_size, size / 4);
|
||||
new_size = Math.round(new_size);
|
||||
}
|
||||
}
|
||||
|
||||
var mouse_coords = this.get_mouse_coordinates_from_event(e);
|
||||
var mouse_x = mouse_coords.x;
|
||||
var mouse_y = mouse_coords.y;
|
||||
|
||||
current_group.push([mouse_x - config.layer.x, mouse_y - config.layer.y, new_size]);
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
mousemove_action(e, index) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
//in case of undo, recalculate index
|
||||
for(var i = index; i >= 0; i++){
|
||||
if(typeof config.layer.data[index] != "undefined"){
|
||||
break;
|
||||
}
|
||||
index--;
|
||||
}
|
||||
|
||||
var params = this.getParams();
|
||||
var current_group = config.layer.data[index];
|
||||
|
||||
//detect line size
|
||||
var size = params.size;
|
||||
var new_size = size;
|
||||
|
||||
if (params.pressure == true) {
|
||||
if (this.pressure_supported) {
|
||||
new_size = size * this.pointer_pressure * 2;
|
||||
}
|
||||
else {
|
||||
new_size = size + size / this.max_speed * mouse.speed_average * this.power;
|
||||
new_size = Math.max(new_size, size / 4);
|
||||
new_size = Math.round(new_size);
|
||||
}
|
||||
}
|
||||
|
||||
var mouse_coords = this.get_mouse_coordinates_from_event(e);
|
||||
var mouse_x = mouse_coords.x;
|
||||
var mouse_y = mouse_coords.y;
|
||||
|
||||
current_group.push([mouse_x - config.layer.x, mouse_y - config.layer.y, new_size]);
|
||||
config.layer.status = 'draft';
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
mouseup_action(e, index) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false) {
|
||||
config.layer.status = null;
|
||||
return;
|
||||
}
|
||||
|
||||
config.layer.status = null;
|
||||
|
||||
this.check_dimensions();
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
if (layer.data.length == 0)
|
||||
return;
|
||||
|
||||
var params = layer.params;
|
||||
var size = params.size;
|
||||
|
||||
//set styles
|
||||
ctx.save();
|
||||
ctx.fillStyle = layer.color;
|
||||
ctx.strokeStyle = layer.color;
|
||||
ctx.lineWidth = params.size;
|
||||
ctx.lineCap = 'round';
|
||||
ctx.lineJoin = 'round';
|
||||
|
||||
ctx.translate(layer.x, layer.y);
|
||||
|
||||
var data = layer.data;
|
||||
|
||||
//check for legacy format
|
||||
data = this.check_legacy_format(data);
|
||||
|
||||
var n = data.length;
|
||||
for (var k = 0; k < n; k++) {
|
||||
var group_data = data[k]; //data from mouse down till mouse release
|
||||
var group_n = group_data.length;
|
||||
|
||||
if (params.pressure == false) {
|
||||
//stabilized lines method does not support multiple line sizes
|
||||
this.render_stabilized(ctx, group_data);
|
||||
}
|
||||
else {
|
||||
if (group_data[0]) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(group_data[0][0], group_data[0][1]);
|
||||
for (var i = 1; i < group_n; i++) {
|
||||
if (group_data[i] === null) {
|
||||
//break
|
||||
ctx.beginPath();
|
||||
}
|
||||
else {
|
||||
//line
|
||||
|
||||
ctx.lineWidth = group_data[i][2];
|
||||
|
||||
if (group_data[i - 1] == null && group_data[i + 1] == null) {
|
||||
//exception - point
|
||||
ctx.arc(group_data[i][0], group_data[i][1], size / 2, 0, 2 * Math.PI, false);
|
||||
ctx.fill();
|
||||
}
|
||||
else if (group_data[i - 1] != null) {
|
||||
//lines
|
||||
ctx.lineWidth = group_data[i][2];
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(group_data[i - 1][0], group_data[i - 1][1]);
|
||||
ctx.lineTo(group_data[i][0], group_data[i][1]);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (group_data[1] == null) {
|
||||
//point
|
||||
ctx.beginPath();
|
||||
ctx.arc(group_data[0][0], group_data[0][1], size / 2, 0, 2 * Math.PI, false);
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.translate(-layer.x, -layer.y);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
/**
|
||||
* draw stabilized lines
|
||||
* author: Manoj Verma
|
||||
* source: https://stackoverflow.com/questions/7891740/drawing-smooth-lines-with-canvas/44810470#44810470
|
||||
*
|
||||
* @param ctx
|
||||
* @param queue
|
||||
*/
|
||||
render_stabilized(ctx, queue) {
|
||||
var data = JSON.parse(JSON.stringify(queue));
|
||||
var n = data.length;
|
||||
|
||||
if (data.length == 1) {
|
||||
//point
|
||||
var point = data[0];
|
||||
ctx.beginPath();
|
||||
ctx.arc(point[0], point[1], point[2] / 2, 0, 2 * Math.PI, false);
|
||||
ctx.fill();
|
||||
return;
|
||||
}
|
||||
else if (data.length <= 5) {
|
||||
//not enough points yet
|
||||
|
||||
for (var i = 1; i < n; i++) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(data[i - 1][0], data[i - 1][1]);
|
||||
ctx.lineTo(data[i][0], data[i][1]);
|
||||
ctx.stroke();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//fix for loose ending, so lets duplicate last point
|
||||
data.push([data[n - 1][0], data[n - 1][1]]);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(data[0][0], data[0][1]);
|
||||
|
||||
//prepare
|
||||
var temp_data1 = [data[0]];
|
||||
var c, d;
|
||||
for (var i = 1; i < data.length - 1; i = i+1) {
|
||||
c = (data[i][0] + data[i + 1][0]) / 2;
|
||||
d = (data[i][1] + data[i + 1][1]) / 2;
|
||||
temp_data1.push([c, d]);
|
||||
}
|
||||
|
||||
var temp_data2 = [temp_data1[0]];
|
||||
for (var i = 1; i < temp_data1.length - 1; i = i+1) {
|
||||
c = (temp_data1[i][0] + temp_data1[i + 1][0]) / 2;
|
||||
d = (temp_data1[i][1] + temp_data1[i + 1][1]) / 2;
|
||||
temp_data2.push([c, d]);
|
||||
}
|
||||
|
||||
var temp_data = [temp_data2[0]];
|
||||
for (var i = 1; i < temp_data2.length - 1; i = i+1) {
|
||||
c = (temp_data2[i][0] + temp_data2[i + 1][0]) / 2;
|
||||
d = (temp_data2[i][1] + temp_data2[i + 1][1]) / 2;
|
||||
temp_data.push([c, d]);
|
||||
}
|
||||
|
||||
//draw
|
||||
for (var i = 1; i < temp_data.length - 2; i = i+1) {
|
||||
c = (temp_data[i][0] + temp_data[i + 1][0]) / 2;
|
||||
d = (temp_data[i][1] + temp_data[i + 1][1]) / 2;
|
||||
ctx.quadraticCurveTo(temp_data[i][0], temp_data[i][1], c, d);
|
||||
}
|
||||
|
||||
// For the last 2 points
|
||||
ctx.quadraticCurveTo(
|
||||
temp_data[i][0],
|
||||
temp_data[i][1],
|
||||
temp_data[i+1][0],
|
||||
temp_data[i+1][1]
|
||||
);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
check_legacy_format(data) {
|
||||
//check for legacy format
|
||||
if(data.length > 0 && typeof data[0][0] == "number"){
|
||||
//convert
|
||||
var legacy = JSON.parse(JSON.stringify(data));
|
||||
data = [];
|
||||
data.push([]);
|
||||
var group_index = 0;
|
||||
for(var i in legacy){
|
||||
if(legacy[i] === null){
|
||||
data.push([]);
|
||||
group_index++;
|
||||
}
|
||||
else {
|
||||
data[group_index].push([legacy[i][0], legacy[i][1], legacy[i][2]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* recalculate layer x, y, width and height values.
|
||||
*/
|
||||
check_dimensions() {
|
||||
var data = JSON.parse(JSON.stringify(config.layer.data)); // Deep copy for history
|
||||
this.check_legacy_format(data);
|
||||
|
||||
if(config.layer.data.length == 0 || data[0].length == 0)
|
||||
return;
|
||||
|
||||
//find bounds
|
||||
var min_x = data[0][0][0];
|
||||
var min_y = data[0][0][1];
|
||||
var max_x = data[0][0][0];
|
||||
var max_y = data[0][0][1];
|
||||
|
||||
var n = data.length;
|
||||
for (var k = 0; k < n; k++) {
|
||||
var group_data = data[k];
|
||||
var group_n = group_data.length;
|
||||
|
||||
for (var i = 1; i < group_n; i++) {
|
||||
min_x = Math.min(min_x, group_data[i][0]);
|
||||
min_y = Math.min(min_y, group_data[i][1]);
|
||||
max_x = Math.max(max_x, group_data[i][0]);
|
||||
max_y = Math.max(max_y, group_data[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
//move current data
|
||||
for (var k = 0; k < n; k++) {
|
||||
var group_data = data[k];
|
||||
var group_n = group_data.length;
|
||||
|
||||
for (var i = 0; i < group_n; i++) {
|
||||
group_data[i][0] = group_data[i][0] - min_x;
|
||||
group_data[i][1] = group_data[i][1] - min_y;
|
||||
}
|
||||
}
|
||||
|
||||
//change layers bounds
|
||||
app.State.do_action(
|
||||
new app.Actions.Update_layer_action(config.layer.id, {
|
||||
x: config.layer.x + min_x,
|
||||
y: config.layer.y + min_y,
|
||||
width: max_x - min_x,
|
||||
height: max_y - min_y,
|
||||
data
|
||||
}),
|
||||
{
|
||||
merge_with_history: ['new_brush_layer', 'update_brush_layer']
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Brush_class;
|
||||
@@ -0,0 +1,118 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
import glfx from './../libs/glfx.js';
|
||||
import Helper_class from './../libs/helpers.js';
|
||||
|
||||
class BulgePinch_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.fx_filter = false;
|
||||
this.Helper = new Helper_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'bulge_pinch';
|
||||
this.tmpCanvas = null;
|
||||
this.tmpCanvasCtx = null;
|
||||
this.started = false;
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
default_dragMove(event) {
|
||||
if (config.TOOL.name != this.name)
|
||||
return;
|
||||
|
||||
//mouse cursor
|
||||
var mouse = this.get_mouse_info(event);
|
||||
var params = this.getParams();
|
||||
this.show_mouse_cursor(mouse.x, mouse.y, params.radius, 'circle');
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.started = false;
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (config.layer.type != 'image') {
|
||||
alertify.error('This layer must contain an image. Please convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
this.started = true;
|
||||
|
||||
//get canvas from layer
|
||||
this.tmpCanvas = document.createElement('canvas');
|
||||
this.tmpCanvasCtx = this.tmpCanvas.getContext("2d");
|
||||
this.tmpCanvas.width = config.layer.width_original;
|
||||
this.tmpCanvas.height = config.layer.height_original;
|
||||
this.tmpCanvasCtx.drawImage(config.layer.link, 0, 0);
|
||||
|
||||
//apply
|
||||
this.bulgePinch_general(mouse, params.power, params.radius, params.bulge);
|
||||
|
||||
//register tmp canvas for faster redraw
|
||||
config.layer.link_canvas = this.tmpCanvas;
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
if (this.started == false) {
|
||||
return;
|
||||
}
|
||||
delete config.layer.link_canvas;
|
||||
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('bulge_pinch_tool', 'Bulge/Pinch Tool', [
|
||||
new app.Actions.Update_layer_image_action(this.tmpCanvas)
|
||||
])
|
||||
);
|
||||
|
||||
//decrease memory
|
||||
this.tmpCanvas.width = 1;
|
||||
this.tmpCanvas.height = 1;
|
||||
this.tmpCanvas = null;
|
||||
this.tmpCanvasCtx = null;
|
||||
}
|
||||
|
||||
bulgePinch_general(mouse, power, radius, bulge) {
|
||||
if (this.fx_filter == false) {
|
||||
//init glfx lib
|
||||
this.fx_filter = glfx.canvas();
|
||||
}
|
||||
|
||||
var ctx = this.tmpCanvasCtx;
|
||||
var mouse_x = Math.round(mouse.x) - config.layer.x;
|
||||
var mouse_y = Math.round(mouse.y) - config.layer.y;
|
||||
|
||||
//adapt to origin size
|
||||
mouse_x = this.adaptSize(mouse_x, 'width');
|
||||
mouse_y = this.adaptSize(mouse_y, 'height');
|
||||
|
||||
//convert float coords to integers
|
||||
mouse_x = Math.round(mouse_x);
|
||||
mouse_y = Math.round(mouse_y);
|
||||
|
||||
power = power / 100;
|
||||
if (power > 1) {
|
||||
//max 100%
|
||||
power = 1;
|
||||
}
|
||||
|
||||
if (bulge == false)
|
||||
power = -1 * power;
|
||||
|
||||
var texture = this.fx_filter.texture(this.tmpCanvas);
|
||||
this.fx_filter.draw(texture).bulgePinch(mouse_x, mouse_y, radius, power).update(); //effect
|
||||
this.tmpCanvasCtx.clearRect(0, 0, this.tmpCanvas.width, this.tmpCanvas.height);
|
||||
this.tmpCanvasCtx.drawImage(this.fx_filter, 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
export default BulgePinch_class;
|
||||
@@ -0,0 +1,335 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import Layer_raster_class from './../modules/layer/raster.js';
|
||||
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
|
||||
class Clone_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.Layer_raster = new Layer_raster_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'clone';
|
||||
this.tmpCanvas = null;
|
||||
this.tmpCanvasCtx = null;
|
||||
this.started = false;
|
||||
this.clone_coords = null;
|
||||
this.pressTimer = null;
|
||||
}
|
||||
|
||||
load() {
|
||||
var _this = this;
|
||||
var is_touch = false;
|
||||
|
||||
//mouse events
|
||||
document.addEventListener('mousedown', function (event) {
|
||||
if(is_touch)
|
||||
return;
|
||||
_this.dragStart(event);
|
||||
});
|
||||
document.addEventListener('mousemove', function (event) {
|
||||
if(is_touch)
|
||||
return;
|
||||
_this.dragMove(event);
|
||||
});
|
||||
document.addEventListener('mouseup', function (event) {
|
||||
if(is_touch)
|
||||
return;
|
||||
_this.dragEnd(event);
|
||||
});
|
||||
|
||||
// collect touch events
|
||||
document.addEventListener('touchstart', function (event) {
|
||||
is_touch = true;
|
||||
_this.dragStart(event);
|
||||
});
|
||||
document.addEventListener('touchmove', function (event) {
|
||||
_this.dragMove(event);
|
||||
});
|
||||
document.addEventListener('touchend', function (event) {
|
||||
_this.dragEnd(event);
|
||||
});
|
||||
|
||||
document.addEventListener('contextmenu', function (event) {
|
||||
_this.mouseRightClick(event);
|
||||
});
|
||||
}
|
||||
|
||||
dragStart(event) {
|
||||
var _this = this;
|
||||
if (config.TOOL.name != _this.name)
|
||||
return;
|
||||
_this.mousedown(event);
|
||||
|
||||
var mouse = this.get_mouse_info(event);
|
||||
if (mouse.click_valid == true) {
|
||||
this.pressTimer = window.setTimeout(function() {
|
||||
//long press success
|
||||
_this.mouseLongClick();
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
dragMove(event) {
|
||||
var _this = this;
|
||||
if (config.TOOL.name != _this.name)
|
||||
return;
|
||||
_this.mousemove(event);
|
||||
|
||||
//mouse cursor
|
||||
var mouse = _this.get_mouse_info(event);
|
||||
var params = _this.getParams();
|
||||
_this.show_mouse_cursor(mouse.x, mouse.y, params.size, 'circle');
|
||||
|
||||
clearTimeout(this.pressTimer);
|
||||
}
|
||||
|
||||
dragEnd(event) {
|
||||
var _this = this;
|
||||
if (config.TOOL.name != _this.name)
|
||||
return;
|
||||
_this.mouseup(event);
|
||||
|
||||
clearTimeout(this.pressTimer);
|
||||
}
|
||||
|
||||
on_params_update() {
|
||||
var params = this.getParams();
|
||||
var strict_element = document.getElementById('strict');
|
||||
|
||||
if (params.circle == false) {
|
||||
//hide strict controls
|
||||
strict_element.style.display = 'none';
|
||||
}
|
||||
else {
|
||||
//show strict controls
|
||||
strict_element.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
mouseRightClick(e) {
|
||||
if (config.TOOL.name != this.name)
|
||||
return;
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
|
||||
if (e.which == 3 && mouse.valid == true) {
|
||||
e.preventDefault();
|
||||
}
|
||||
if (params.source_layer.value == 'Previous' && config.layer.type === null) {
|
||||
this.Layer_raster.raster();
|
||||
}
|
||||
if (config.layer.type != 'image') {
|
||||
alertify.error('This layer must contain an image. Please convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
if (config.layer.rotate || 0 > 0) {
|
||||
alertify.error('Erase on rotate object is disabled. Please rasterize first.');
|
||||
return;
|
||||
}
|
||||
if (e.which == 3 && mouse.valid == true) {
|
||||
//right click - save coords
|
||||
|
||||
var mouse_x = this.adaptSize(mouse.x, 'width');
|
||||
var mouse_y = this.adaptSize(mouse.y, 'height');
|
||||
|
||||
this.clone_coords = {
|
||||
x: mouse_x,
|
||||
y: mouse_y,
|
||||
};
|
||||
alertify.success('Source coordinates saved.');
|
||||
}
|
||||
}
|
||||
|
||||
mouseLongClick(){
|
||||
var params = this.getParams();
|
||||
var mouse = this.get_mouse_info();
|
||||
|
||||
if (params.source_layer.value == 'Previous' && config.layer.type === null) {
|
||||
this.Layer_raster.raster();
|
||||
}
|
||||
if (config.layer.type != 'image') {
|
||||
alertify.error('This layer must contain an image. Please convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
if (config.layer.rotate || 0 > 0) {
|
||||
alertify.error('Erase on rotate object is disabled. Please rasterize first.');
|
||||
return;
|
||||
}
|
||||
|
||||
var mouse_x = this.adaptSize(mouse.x, 'width');
|
||||
var mouse_y = this.adaptSize(mouse.y, 'height');
|
||||
|
||||
this.clone_coords = {
|
||||
x: mouse_x,
|
||||
y: mouse_y,
|
||||
};
|
||||
alertify.success('Source coordinates saved.');
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.started = false;
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
var layer = config.layer;
|
||||
var previous_layer = this.Base_layers.find_previous(config.layer.id);
|
||||
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.source_layer.value == 'Previous' && config.layer.type === null) {
|
||||
this.Layer_raster.raster();
|
||||
}
|
||||
if (config.layer.type != 'image') {
|
||||
alertify.error('This layer must contain an image. Please convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
if (config.layer.rotate || 0 > 0) {
|
||||
alertify.error('Erase on rotate object is disabled. Please rasterize first.');
|
||||
return;
|
||||
}
|
||||
if (this.clone_coords === null) {
|
||||
alertify.error('Source is empty, right click on image or use long press to save source position.');
|
||||
return;
|
||||
}
|
||||
if (layer.width != layer.width_original || layer.height != layer.height_original) {
|
||||
alertify.error('Clone tool disabled for resized image. Please rasterize first.');
|
||||
return;
|
||||
}
|
||||
if (params.source_layer.value == 'Previous' &&
|
||||
(previous_layer.width != previous_layer.width_original
|
||||
|| previous_layer.height != previous_layer.height_original)) {
|
||||
alertify.error('Clone tool disabled for resized image. Please rasterize first.');
|
||||
return;
|
||||
}
|
||||
if (params.source_layer.value == 'Previous') {
|
||||
if (previous_layer == null) {
|
||||
alertify.error('Can not find previous layer.');
|
||||
return;
|
||||
}
|
||||
if (previous_layer.type != 'image') {
|
||||
alertify.error('Previous layer must be image, convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.started = true;
|
||||
|
||||
//get canvas from layer
|
||||
this.tmpCanvas = document.createElement('canvas');
|
||||
this.tmpCanvasCtx = this.tmpCanvas.getContext("2d");
|
||||
this.tmpCanvas.width = config.layer.width_original;
|
||||
this.tmpCanvas.height = config.layer.height_original;
|
||||
this.tmpCanvasCtx.drawImage(config.layer.link, 0, 0);
|
||||
|
||||
//clone
|
||||
this.clone_general(this.tmpCanvas, this.tmpCanvas, 'click', mouse);
|
||||
|
||||
//register tmp canvas for progress redraw
|
||||
config.layer.link_canvas = this.tmpCanvas;
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (this.started == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
//clone
|
||||
this.clone_general(this.tmpCanvas, this.tmpCanvas, 'move', mouse);
|
||||
|
||||
//draw draft preview
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
if (this.started == false) {
|
||||
return;
|
||||
}
|
||||
delete config.layer.link_canvas;
|
||||
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('clone_tool', 'Clone Tool', [
|
||||
new app.Actions.Update_layer_image_action(this.tmpCanvas)
|
||||
])
|
||||
);
|
||||
|
||||
//decrease memory
|
||||
this.tmpCanvas.width = 1;
|
||||
this.tmpCanvas.height = 1;
|
||||
this.tmpCanvas = null;
|
||||
this.tmpCanvasCtx = null;
|
||||
}
|
||||
|
||||
clone_general(canvas_from, canvas_to, type, mouse) {
|
||||
var params = this.getParams();
|
||||
|
||||
var mouse_x = Math.round(mouse.x) - config.layer.x;
|
||||
var mouse_y = Math.round(mouse.y) - config.layer.y;
|
||||
var half = Math.round(params.size / 2);
|
||||
|
||||
//adapt to origin size
|
||||
mouse_x = this.adaptSize(mouse_x, 'width');
|
||||
mouse_y = this.adaptSize(mouse_y, 'height');
|
||||
|
||||
//convert float coords to integers
|
||||
mouse_x = Math.round(mouse_x);
|
||||
mouse_y = Math.round(mouse_y);
|
||||
|
||||
//create source canvas
|
||||
var canvas_source = document.createElement("canvas");
|
||||
var ctx_source = canvas_source.getContext("2d");
|
||||
var w = Math.ceil(params.size);
|
||||
var h = Math.ceil(params.size);
|
||||
canvas_source.width = w;
|
||||
canvas_source.height = h;
|
||||
|
||||
//add data
|
||||
var x_from = Math.round(this.clone_coords.x - (mouse.click_x - mouse_x));
|
||||
var y_from = Math.round(this.clone_coords.y - (mouse.click_y - mouse_y));
|
||||
if (params.anti_aliasing == false) {
|
||||
ctx_source.arc(half, half, half, 0, Math.PI * 2, false);
|
||||
ctx_source.clip();
|
||||
}
|
||||
if (params.source_layer.value == 'Previous') {
|
||||
var previous_layer = this.Base_layers.find_previous(config.layer.id);
|
||||
|
||||
x_from = Math.round(this.clone_coords.x - (mouse.click_x - mouse_x)) - previous_layer.x + config.layer.x;
|
||||
y_from = Math.round(this.clone_coords.y - (mouse.click_y - mouse_y)) - previous_layer.y + config.layer.y;
|
||||
|
||||
ctx_source.drawImage(previous_layer.link, x_from - half, y_from - half, w, h, 0, 0, w, h);
|
||||
}
|
||||
else {
|
||||
ctx_source.drawImage(canvas_from, x_from - half, y_from - half, w, h, 0, 0, w, h);
|
||||
}
|
||||
|
||||
//apply anti aliasing
|
||||
if (params.anti_aliasing == true) {
|
||||
var gradient = ctx_source.createRadialGradient(half, half, 0, half, half, half + 1);
|
||||
gradient.addColorStop(0, 'white');
|
||||
gradient.addColorStop(0.3, 'white');
|
||||
gradient.addColorStop(1, 'transparent');
|
||||
ctx_source.fillStyle = gradient;
|
||||
|
||||
ctx_source.globalCompositeOperation = 'destination-in';
|
||||
ctx_source.fillRect(0, 0, params.size, params.size);
|
||||
ctx_source.globalCompositeOperation = 'source-over';
|
||||
}
|
||||
|
||||
//finish
|
||||
canvas_to.getContext("2d").drawImage(canvas_source, mouse_x - half, mouse_y - half);
|
||||
}
|
||||
|
||||
}
|
||||
export default Clone_class;
|
||||
@@ -0,0 +1,306 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import GUI_tools_class from './../core/gui/gui-tools.js';
|
||||
import Base_gui_class from './../core/base-gui.js';
|
||||
import Base_selection_class from './../core/base-selection.js';
|
||||
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
|
||||
class Crop_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
var _this = this;
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.Base_gui = new Base_gui_class();
|
||||
this.GUI_tools = new GUI_tools_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'crop';
|
||||
this.selection = {
|
||||
x: null,
|
||||
y: null,
|
||||
width: null,
|
||||
height: null,
|
||||
};
|
||||
var sel_config = {
|
||||
enable_background: true,
|
||||
enable_borders: true,
|
||||
enable_controls: true,
|
||||
crop_lines: true,
|
||||
enable_rotation: false,
|
||||
enable_move: false,
|
||||
data_function: function () {
|
||||
return _this.selection;
|
||||
},
|
||||
};
|
||||
this.mousedown_selection = null;
|
||||
this.Base_selection = new Base_selection_class(ctx, sel_config, this.name);
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
default_dragStart(event) {
|
||||
this.is_mousedown_canvas = false;
|
||||
if (config.TOOL.name != this.name)
|
||||
return;
|
||||
if (!event.target.closest('#main_wrapper'))
|
||||
return;
|
||||
|
||||
this.is_mousedown_canvas = true;
|
||||
this.mousedown(event);
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (this.Base_selection.is_drag == false || mouse.click_valid == false)
|
||||
return;
|
||||
|
||||
this.mousedown_selection = JSON.parse(JSON.stringify(this.selection));
|
||||
|
||||
if (this.Base_selection.mouse_lock !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
//create new selection
|
||||
this.Base_selection.set_selection(mouse.x, mouse.y, 0, 0);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (this.Base_selection.is_drag == false || mouse.is_drag == false) {
|
||||
return;
|
||||
}
|
||||
if (e.type == 'mousedown' && mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (this.Base_selection.mouse_lock !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var width = mouse.x - mouse.click_x;
|
||||
var height = mouse.y - mouse.click_y;
|
||||
|
||||
if(e.ctrlKey == true || e.metaKey){
|
||||
//ctrl is pressed - crop will be calculated based on global width and height ratio
|
||||
var ratio = config.WIDTH / config.HEIGHT;
|
||||
var width_new = Math.round(height * ratio);
|
||||
var height_new = Math.round(width / ratio);
|
||||
|
||||
if(Math.abs(width * 100 / width_new) > Math.abs(height * 100 / height_new)){
|
||||
if (width * 100 / width_new > 0)
|
||||
height = height_new;
|
||||
else
|
||||
height = -height_new;
|
||||
}
|
||||
else{
|
||||
if (height * 100 / height_new > 0)
|
||||
width = width_new;
|
||||
else
|
||||
width = -width_new;
|
||||
}
|
||||
}
|
||||
|
||||
this.Base_selection.set_selection(null, null, width, height);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
|
||||
if (!this.Base_selection.is_drag) {
|
||||
return;
|
||||
}
|
||||
if (e.type == 'mousedown' && mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var width = mouse.x - this.selection.x;
|
||||
var height = mouse.y - this.selection.y;
|
||||
|
||||
if (width == 0 || height == 0) {
|
||||
//cancel selection
|
||||
this.Base_selection.reset_selection();
|
||||
config.need_render = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.selection.width != null) {
|
||||
//make sure coords not negative
|
||||
var details = this.selection;
|
||||
var x = details.x;
|
||||
var y = details.y;
|
||||
if (details.width < 0) {
|
||||
x = x + details.width;
|
||||
}
|
||||
if (details.height < 0) {
|
||||
y = y + details.height;
|
||||
}
|
||||
this.selection = {
|
||||
x: x,
|
||||
y: y,
|
||||
width: Math.abs(details.width),
|
||||
height: Math.abs(details.height),
|
||||
};
|
||||
}
|
||||
|
||||
//control boundaries
|
||||
if (this.selection.x < 0) {
|
||||
this.selection.width += this.selection.x;
|
||||
this.selection.x = 0;
|
||||
}
|
||||
if (this.selection.y < 0) {
|
||||
this.selection.height += this.selection.y;
|
||||
this.selection.y = 0;
|
||||
}
|
||||
if (this.selection.x + this.selection.width > config.WIDTH) {
|
||||
this.selection.width = config.WIDTH - this.selection.x;
|
||||
}
|
||||
if (this.selection.y + this.selection.height > config.HEIGHT) {
|
||||
this.selection.height = config.HEIGHT - this.selection.y;
|
||||
}
|
||||
|
||||
app.State.do_action(
|
||||
new app.Actions.Set_selection_action(this.selection.x, this.selection.y, this.selection.width, this.selection.height, this.mousedown_selection)
|
||||
);
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
//nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* do actual crop
|
||||
*/
|
||||
async on_params_update() {
|
||||
var params = this.getParams();
|
||||
var selection = this.selection;
|
||||
params.crop = true;
|
||||
this.GUI_tools.show_action_attributes();
|
||||
|
||||
if (selection.width == null || selection.width == 0 || selection.height == 0) {
|
||||
alertify.error('Empty selection');
|
||||
return;
|
||||
}
|
||||
|
||||
//check for rotation
|
||||
var rotated_name = false;
|
||||
for (var i in config.layers) {
|
||||
var link = config.layers[i];
|
||||
if (link.type == null)
|
||||
continue;
|
||||
|
||||
if(link.rotate > 0){
|
||||
rotated_name = link.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rotated_name !== false) {
|
||||
alertify.error('Crop on rotated layer is not supported. Convert it to raster to continue.' + '('+ rotated_name + ')');
|
||||
return;
|
||||
}
|
||||
|
||||
//controll boundaries
|
||||
selection.x = Math.max(selection.x, 0);
|
||||
selection.y = Math.max(selection.y, 0);
|
||||
selection.width = Math.min(selection.width, config.WIDTH);
|
||||
selection.height = Math.min(selection.height, config.HEIGHT);
|
||||
|
||||
let actions = [];
|
||||
|
||||
for (var i in config.layers) {
|
||||
var link = config.layers[i];
|
||||
if (link.type == null)
|
||||
continue;
|
||||
|
||||
let x = link.x;
|
||||
let y = link.y;
|
||||
let width = link.width;
|
||||
let height = link.height;
|
||||
let width_original = link.width_original;
|
||||
let height_original = link.height_original;
|
||||
|
||||
//move
|
||||
x -= parseInt(selection.x);
|
||||
y -= parseInt(selection.y);
|
||||
|
||||
if (link.type == 'image') {
|
||||
//also remove unvisible data
|
||||
let left = 0;
|
||||
if (x < 0)
|
||||
left = -x;
|
||||
let top = 0;
|
||||
if (y < 0)
|
||||
top = -y;
|
||||
let right = 0;
|
||||
if (x + width > selection.width)
|
||||
right = x + width - selection.width;
|
||||
let bottom = 0;
|
||||
if (y + height > selection.height)
|
||||
bottom = y + height - selection.height;
|
||||
let crop_width = width - left - right;
|
||||
let crop_height = height - top - bottom;
|
||||
|
||||
//if image was streched
|
||||
let width_ratio = (width / width_original);
|
||||
let height_ratio = (height / height_original);
|
||||
|
||||
//create smaller canvas
|
||||
let canvas = document.createElement('canvas');
|
||||
let ctx = canvas.getContext("2d");
|
||||
canvas.width = crop_width / width_ratio;
|
||||
canvas.height = crop_height / height_ratio;
|
||||
|
||||
//cut required part
|
||||
ctx.translate(-left / width_ratio, -top / height_ratio);
|
||||
canvas.getContext("2d").drawImage(link.link, 0, 0);
|
||||
ctx.translate(0, 0);
|
||||
actions.push(
|
||||
new app.Actions.Update_layer_image_action(canvas, link.id)
|
||||
);
|
||||
|
||||
//update attributes
|
||||
width = Math.ceil(canvas.width * width_ratio);
|
||||
height = Math.ceil(canvas.height * height_ratio);
|
||||
x += left;
|
||||
y += top;
|
||||
width_original = canvas.width;
|
||||
height_original = canvas.height;
|
||||
}
|
||||
|
||||
actions.push(
|
||||
new app.Actions.Update_layer_action(link.id, {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
width_original,
|
||||
height_original
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
actions.push(
|
||||
new app.Actions.Prepare_canvas_action('undo'),
|
||||
new app.Actions.Update_config_action({
|
||||
WIDTH: parseInt(selection.width),
|
||||
HEIGHT: parseInt(selection.height)
|
||||
}),
|
||||
new app.Actions.Prepare_canvas_action('do'),
|
||||
new app.Actions.Reset_selection_action(this.selection)
|
||||
);
|
||||
await app.State.do_action(
|
||||
new app.Actions.Bundle_action('crop_tool', 'Crop Tool', actions)
|
||||
);
|
||||
}
|
||||
|
||||
on_leave() {
|
||||
return [
|
||||
new app.Actions.Reset_selection_action()
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Crop_class;
|
||||
@@ -0,0 +1,135 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
import ImageFilters from './../libs/imagefilters.js';
|
||||
import Helper_class from './../libs/helpers.js';
|
||||
|
||||
class Desaturate_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.Helper = new Helper_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'desaturate';
|
||||
this.tmpCanvas = null;
|
||||
this.tmpCanvasCtx = null;
|
||||
this.started = false;
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
default_dragMove(event) {
|
||||
if (config.TOOL.name != this.name)
|
||||
return;
|
||||
this.mousemove(event);
|
||||
|
||||
//mouse cursor
|
||||
var mouse = this.get_mouse_info(event);
|
||||
var params = this.getParams();
|
||||
this.show_mouse_cursor(mouse.x, mouse.y, params.size, 'circle');
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.started = false;
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (config.layer.type != 'image') {
|
||||
alertify.error('This layer must contain an image. Please convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
if (config.layer.rotate || 0 > 0) {
|
||||
alertify.error('Erase on rotate object is disabled. Please rasterize first.');
|
||||
return;
|
||||
}
|
||||
this.started = true;
|
||||
|
||||
//get canvas from layer
|
||||
this.tmpCanvas = document.createElement('canvas');
|
||||
this.tmpCanvasCtx = this.tmpCanvas.getContext("2d");
|
||||
this.tmpCanvas.width = config.layer.width_original;
|
||||
this.tmpCanvas.height = config.layer.height_original;
|
||||
|
||||
this.tmpCanvasCtx.drawImage(config.layer.link, 0, 0);
|
||||
|
||||
//do desaturate
|
||||
this.desaturate_general('click', mouse, params.size, params.anti_aliasing);
|
||||
|
||||
//register tmp canvas for faster redraw
|
||||
config.layer.link_canvas = this.tmpCanvas;
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (this.started == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
//do desaturate
|
||||
this.desaturate_general('move', mouse, params.size, params.anti_aliasing);
|
||||
|
||||
//draw draft preview
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
if (this.started == false) {
|
||||
return;
|
||||
}
|
||||
delete config.layer.link_canvas;
|
||||
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('desaturate_tool', 'Desaturate Tool', [
|
||||
new app.Actions.Update_layer_image_action(this.tmpCanvas)
|
||||
])
|
||||
);
|
||||
|
||||
//decrease memory
|
||||
this.tmpCanvas.width = 1;
|
||||
this.tmpCanvas.height = 1;
|
||||
this.tmpCanvas = null;
|
||||
this.tmpCanvasCtx = null;
|
||||
}
|
||||
|
||||
desaturate_general(type, mouse, size, anti_aliasing) {
|
||||
var ctx = this.tmpCanvasCtx;
|
||||
var mouse_x = Math.round(mouse.x) - config.layer.x;
|
||||
var mouse_y = Math.round(mouse.y) - config.layer.y;
|
||||
|
||||
//adapt to origin size
|
||||
mouse_x = this.adaptSize(mouse_x, 'width');
|
||||
mouse_y = this.adaptSize(mouse_y, 'height');
|
||||
var size_w = this.adaptSize(size, 'width');
|
||||
var size_h = this.adaptSize(size, 'height');
|
||||
|
||||
//find center
|
||||
var center_x = mouse_x - Math.round(size_w / 2);
|
||||
var center_y = mouse_y - Math.round(size_h / 2);
|
||||
|
||||
//convert float coords to integers
|
||||
center_x = Math.round(center_x);
|
||||
center_y = Math.round(center_y);
|
||||
mouse_x = Math.round(mouse_x);
|
||||
mouse_y = Math.round(mouse_y);
|
||||
|
||||
var imageData = ctx.getImageData(center_x, center_y, size_w, size_h);
|
||||
var filtered = ImageFilters.GrayScale(imageData); //add effect
|
||||
this.Helper.image_round(this.tmpCanvasCtx, mouse_x, mouse_y, size_w, size_h, filtered, anti_aliasing);
|
||||
}
|
||||
|
||||
}
|
||||
export default Desaturate_class;
|
||||
@@ -0,0 +1,207 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
|
||||
class Erase_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'erase';
|
||||
this.tmpCanvas = null;
|
||||
this.tmpCanvasCtx = null;
|
||||
this.started = false;
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
default_dragMove(event, is_touch) {
|
||||
if (config.TOOL.name != this.name)
|
||||
return;
|
||||
this.mousemove(event, is_touch);
|
||||
|
||||
//mouse cursor
|
||||
var mouse = this.get_mouse_info(event);
|
||||
var params = this.getParams();
|
||||
if (params.circle == true)
|
||||
this.show_mouse_cursor(mouse.x, mouse.y, params.size, 'circle');
|
||||
else
|
||||
this.show_mouse_cursor(mouse.x, mouse.y, params.size, 'rect');
|
||||
}
|
||||
|
||||
on_params_update() {
|
||||
var params = this.getParams();
|
||||
var strict_element = document.querySelector('.attributes #strict');
|
||||
|
||||
if (params.circle == false) {
|
||||
//hide strict controls
|
||||
strict_element.style.display = 'none';
|
||||
}
|
||||
else {
|
||||
//show strict controls
|
||||
strict_element.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.started = false;
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (config.layer.type != 'image') {
|
||||
alertify.error('This layer must contain an image. Please convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
if (config.layer.is_vector == true) {
|
||||
alertify.error('Layer is vector, convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
if (config.layer.rotate || 0 > 0) {
|
||||
alertify.error('Erase on rotate object is disabled. Please rasterize first.');
|
||||
return;
|
||||
}
|
||||
this.started = true;
|
||||
|
||||
//get canvas from layer
|
||||
this.tmpCanvas = document.createElement('canvas');
|
||||
this.tmpCanvasCtx = this.tmpCanvas.getContext("2d");
|
||||
this.tmpCanvas.width = config.layer.width_original;
|
||||
this.tmpCanvas.height = config.layer.height_original;
|
||||
this.tmpCanvasCtx.drawImage(config.layer.link, 0, 0);
|
||||
|
||||
this.tmpCanvasCtx.scale(
|
||||
config.layer.width_original / config.layer.width,
|
||||
config.layer.height_original / config.layer.height
|
||||
);
|
||||
|
||||
//do erase
|
||||
this.erase_general(this.tmpCanvasCtx, 'click', mouse, params.size, params.strict, params.circle);
|
||||
|
||||
//register tmp canvas for faster redraw
|
||||
config.layer.link_canvas = this.tmpCanvas;
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
mousemove(e, is_touch) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (this.started == false) {
|
||||
return;
|
||||
}
|
||||
if (mouse.click_x == mouse.x && mouse.click_y == mouse.y) {
|
||||
//same coordinates
|
||||
return;
|
||||
}
|
||||
|
||||
//do erase
|
||||
this.erase_general(this.tmpCanvasCtx, 'move', mouse, params.size, params.strict, params.circle, is_touch);
|
||||
|
||||
//draw draft preview
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
if (this.started == false) {
|
||||
return;
|
||||
}
|
||||
delete config.layer.link_canvas;
|
||||
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('erase_tool', 'Erase Tool', [
|
||||
new app.Actions.Update_layer_image_action(this.tmpCanvas)
|
||||
])
|
||||
);
|
||||
|
||||
//decrease memory
|
||||
this.tmpCanvas.width = 1;
|
||||
this.tmpCanvas.height = 1;
|
||||
this.tmpCanvas = null;
|
||||
this.tmpCanvasCtx = null;
|
||||
}
|
||||
|
||||
erase_general(ctx, type, mouse, size, strict, is_circle, is_touch) {
|
||||
var mouse_x = Math.round(mouse.x) - config.layer.x;
|
||||
var mouse_y = Math.round(mouse.y) - config.layer.y;
|
||||
var alpha = config.ALPHA;
|
||||
var mouse_last_x = parseInt(mouse.last_x) - config.layer.x;
|
||||
var mouse_last_y = parseInt(mouse.last_y) - config.layer.y;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = size;
|
||||
ctx.lineCap = 'round';
|
||||
ctx.lineJoin = 'round';
|
||||
if (alpha < 255)
|
||||
ctx.strokeStyle = "rgba(255, 255, 255, " + alpha / 255 / 10 + ")";
|
||||
else
|
||||
ctx.strokeStyle = "rgba(255, 255, 255, 1)";
|
||||
|
||||
if (is_circle == false) {
|
||||
//rectangle
|
||||
var size_half = Math.ceil(size / 2);
|
||||
if (size == 1) {
|
||||
//single cell mode
|
||||
mouse_x = Math.floor(mouse.x) - config.layer.x;
|
||||
mouse_y = Math.floor(mouse.y) - config.layer.y;
|
||||
size_half = 0;
|
||||
}
|
||||
ctx.save();
|
||||
ctx.globalCompositeOperation = 'destination-out';
|
||||
ctx.fillStyle = "rgba(255, 255, 255, " + alpha / 255 + ")";
|
||||
ctx.fillRect(mouse_x - size_half, mouse_y - size_half, size, size);
|
||||
ctx.restore();
|
||||
}
|
||||
else {
|
||||
//circle
|
||||
ctx.save();
|
||||
|
||||
if (strict == false) {
|
||||
var radgrad = ctx.createRadialGradient(
|
||||
mouse_x, mouse_y, size / 8,
|
||||
mouse_x, mouse_y, size / 2);
|
||||
if (type == 'click')
|
||||
radgrad.addColorStop(0, "rgba(255, 255, 255, " + alpha / 255 + ")");
|
||||
else if (type == 'move')
|
||||
radgrad.addColorStop(0, "rgba(255, 255, 255, " + alpha / 255 / 2 + ")");
|
||||
radgrad.addColorStop(1, "rgba(255, 255, 255, 0)");
|
||||
}
|
||||
|
||||
//set Composite
|
||||
ctx.globalCompositeOperation = 'destination-out';
|
||||
if (strict == true)
|
||||
ctx.fillStyle = "rgba(255, 255, 255, " + alpha / 255 + ")";
|
||||
else
|
||||
ctx.fillStyle = radgrad;
|
||||
ctx.beginPath();
|
||||
ctx.arc(mouse_x, mouse_y, size / 2, 0, Math.PI * 2, true);
|
||||
ctx.fill();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
//extra work if mouse moving fast - fill gaps
|
||||
if (type == 'move' && is_circle == true && mouse_last_x != false && mouse_last_y != false && is_touch !== true) {
|
||||
ctx.save();
|
||||
ctx.globalCompositeOperation = 'destination-out';
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(mouse_last_x, mouse_last_y);
|
||||
ctx.lineTo(mouse_x, mouse_y);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
export default Erase_class;
|
||||
@@ -0,0 +1,231 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import Helper_class from './../libs/helpers.js';
|
||||
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
|
||||
class Fill_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.Helper = new Helper_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'fill';
|
||||
this.working = false;
|
||||
}
|
||||
|
||||
dragStart(event) {
|
||||
var _this = this;
|
||||
if (config.TOOL.name != _this.name)
|
||||
return;
|
||||
_this.mousedown(event);
|
||||
}
|
||||
|
||||
load() {
|
||||
var _this = this;
|
||||
|
||||
//mouse events
|
||||
document.addEventListener('mousedown', function (event) {
|
||||
_this.dragStart(event);
|
||||
});
|
||||
|
||||
// collect touch events
|
||||
document.addEventListener('touchstart', function (event) {
|
||||
_this.dragStart(event);
|
||||
});
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (config.layer.rotate || 0 > 0) {
|
||||
alertify.error('Erase on rotate object is disabled. Please rasterize first.');
|
||||
return;
|
||||
}
|
||||
|
||||
this.fill(mouse);
|
||||
}
|
||||
|
||||
async fill(mouse) {
|
||||
var params = this.getParams();
|
||||
|
||||
if(this.working == true){
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.layer.type != 'image' && config.layer.type !== null) {
|
||||
alertify.error('This layer must contain an image. Please convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
if (config.layer.is_vector == true) {
|
||||
alertify.error('Layer is vector, convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
if (config.ALPHA == 0) {
|
||||
alertify.error('Color alpha value can not be zero.');
|
||||
return;
|
||||
}
|
||||
|
||||
//get canvas from layer
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext("2d");
|
||||
if (config.layer.type !== null) {
|
||||
canvas.width = config.layer.width_original;
|
||||
canvas.height = config.layer.height_original;
|
||||
ctx.drawImage(config.layer.link, 0, 0);
|
||||
}
|
||||
else {
|
||||
canvas.width = config.WIDTH;
|
||||
canvas.height = config.HEIGHT;
|
||||
}
|
||||
|
||||
var mouse_x = Math.round(mouse.x) - config.layer.x;
|
||||
var mouse_y = Math.round(mouse.y) - config.layer.y;
|
||||
|
||||
//adapt to origin size
|
||||
mouse_x = this.adaptSize(mouse_x, 'width');
|
||||
mouse_y = this.adaptSize(mouse_y, 'height');
|
||||
|
||||
//convert float coords to integers
|
||||
mouse_x = Math.round(mouse_x);
|
||||
mouse_y = Math.round(mouse_y);
|
||||
|
||||
var color_to = this.Helper.hexToRgb(config.COLOR);
|
||||
color_to.a = config.ALPHA;
|
||||
|
||||
//change
|
||||
this.working = true;
|
||||
this.fill_general(ctx, config.WIDTH, config.HEIGHT,
|
||||
mouse_x, mouse_y, color_to, params.power, params.anti_aliasing, params.contiguous);
|
||||
|
||||
if (config.layer.type != null) {
|
||||
//update
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('fill_tool', 'Fill Tool', [
|
||||
new app.Actions.Update_layer_image_action(canvas)
|
||||
])
|
||||
);
|
||||
}
|
||||
else {
|
||||
//create new
|
||||
var params = [];
|
||||
params.type = 'image';
|
||||
params.name = 'Fill';
|
||||
params.data = canvas.toDataURL("image/png");
|
||||
params.x = parseInt(canvas.dataset.x) || 0;
|
||||
params.y = parseInt(canvas.dataset.y) || 0;
|
||||
params.width = canvas.width;
|
||||
params.height = canvas.height;
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('fill_tool', 'Fill Tool', [
|
||||
new app.Actions.Insert_layer_action(params)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
//prevent crash bug on touch screen - hard to explain and debug
|
||||
await new Promise(r => setTimeout(r, 10));
|
||||
this.working = false;
|
||||
}
|
||||
|
||||
fill_general(context, W, H, x, y, color_to, sensitivity, anti_aliasing, contiguous = false) {
|
||||
sensitivity = sensitivity * 255 / 100; //convert to 0-255 interval
|
||||
x = parseInt(x);
|
||||
y = parseInt(y);
|
||||
var canvasTemp = document.createElement('canvas');
|
||||
canvasTemp.width = W;
|
||||
canvasTemp.height = H;
|
||||
var ctxTemp = canvasTemp.getContext("2d");
|
||||
|
||||
ctxTemp.rect(0, 0, W, H);
|
||||
ctxTemp.fillStyle = "rgba(255, 255, 255, 0)";
|
||||
ctxTemp.fill();
|
||||
|
||||
var img_tmp = ctxTemp.getImageData(0, 0, W, H);
|
||||
var imgData_tmp = img_tmp.data;
|
||||
|
||||
var img = context.getImageData(0, 0, W, H);
|
||||
var imgData = img.data;
|
||||
var k = ((y * (img.width * 4)) + (x * 4));
|
||||
var dx = [0, -1, +1, 0];
|
||||
var dy = [-1, 0, 0, +1];
|
||||
var color_from = {
|
||||
r: imgData[k + 0],
|
||||
g: imgData[k + 1],
|
||||
b: imgData[k + 2],
|
||||
a: imgData[k + 3]
|
||||
};
|
||||
if (color_from.r == color_to.r && color_from.g == color_to.g
|
||||
&& color_from.b == color_to.b && color_from.a == color_to.a) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (contiguous == false) {
|
||||
//check only nearest pixels
|
||||
var stack = [];
|
||||
stack.push([x, y]);
|
||||
while (stack.length > 0) {
|
||||
var curPoint = stack.pop();
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var nextPointX = curPoint[0] + dx[i];
|
||||
var nextPointY = curPoint[1] + dy[i];
|
||||
if (nextPointX < 0 || nextPointY < 0 || nextPointX >= W || nextPointY >= H)
|
||||
continue;
|
||||
var k = (nextPointY * W + nextPointX) * 4;
|
||||
if (imgData_tmp[k + 3] != 0)
|
||||
continue; //already parsed
|
||||
|
||||
//check
|
||||
if (Math.abs(imgData[k + 0] - color_from.r) <= sensitivity &&
|
||||
Math.abs(imgData[k + 1] - color_from.g) <= sensitivity &&
|
||||
Math.abs(imgData[k + 2] - color_from.b) <= sensitivity &&
|
||||
Math.abs(imgData[k + 3] - color_from.a) <= sensitivity) {
|
||||
|
||||
//fill pixel
|
||||
imgData_tmp[k] = color_to.r; //r
|
||||
imgData_tmp[k + 1] = color_to.g; //g
|
||||
imgData_tmp[k + 2] = color_to.b; //b
|
||||
imgData_tmp[k + 3] = color_to.a; //a
|
||||
|
||||
stack.push([nextPointX, nextPointY]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
//global mode - contiguous
|
||||
for (var i = 0; i < imgData.length; i += 4) {
|
||||
if (imgData[i + 3] == 0)
|
||||
continue; //transparent
|
||||
|
||||
//imgData[i] + 0.7152 * imgData[i + 1] + 0.0722 * imgData[i + 2]);
|
||||
|
||||
for (var j = 0; j < 4; j++) {
|
||||
var k = i + j;
|
||||
|
||||
if (Math.abs(imgData[k] - color_from.r) <= sensitivity
|
||||
&& Math.abs(imgData[k + 1] - color_from.g) <= sensitivity
|
||||
&& Math.abs(imgData[k + 2] - color_from.b) <= sensitivity
|
||||
&& Math.abs(imgData[k + 3] - color_from.a) <= sensitivity) {
|
||||
imgData_tmp[k] = color_to.r; //r
|
||||
imgData_tmp[k + 1] = color_to.g; //g
|
||||
imgData_tmp[k + 2] = color_to.b; //b
|
||||
imgData_tmp[k + 3] = color_to.a; //a
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctxTemp.putImageData(img_tmp, 0, 0);
|
||||
if (anti_aliasing == true) {
|
||||
context.filter = 'blur(1px)';
|
||||
}
|
||||
context.drawImage(canvasTemp, 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
export default Fill_class;
|
||||
@@ -0,0 +1,184 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import Helper_class from './../libs/helpers.js';
|
||||
|
||||
class Gradient_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.Helper = new Helper_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'gradient';
|
||||
this.layer = {};
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.click_valid == false)
|
||||
return;
|
||||
|
||||
var name = this.name;
|
||||
var is_vector = false;
|
||||
if (params.radial == true) {
|
||||
name = 'Radial gradient';
|
||||
is_vector = true;
|
||||
}
|
||||
|
||||
//register new object - current layer is not ours or params changed
|
||||
this.layer = {
|
||||
type: this.name,
|
||||
name: this.Helper.ucfirst(name) + ' #' + this.Base_layers.auto_increment,
|
||||
params: this.clone(this.getParams()),
|
||||
status: 'draft',
|
||||
render_function: [this.name, 'render'],
|
||||
x: mouse.x,
|
||||
y: mouse.y,
|
||||
rotate: null,
|
||||
is_vector: is_vector,
|
||||
color: null,
|
||||
data: {
|
||||
center_x: mouse.x,
|
||||
center_y: mouse.y,
|
||||
},
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('new_gradient_layer', 'New Gradient Layer', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var width = mouse.x - this.layer.x;
|
||||
var height = mouse.y - this.layer.y;
|
||||
|
||||
if (params.radial == true) {
|
||||
config.layer.x = this.layer.data.center_x - width;
|
||||
config.layer.y = this.layer.data.center_y - height;
|
||||
config.layer.width = width * 2;
|
||||
config.layer.height = height * 2;
|
||||
}
|
||||
else {
|
||||
config.layer.width = width;
|
||||
config.layer.height = height;
|
||||
}
|
||||
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.click_valid == false) {
|
||||
config.layer.status = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var width = mouse.x - this.layer.x;
|
||||
var height = mouse.y - this.layer.y;
|
||||
|
||||
if (width == 0 && height == 0) {
|
||||
//same coordinates - cancel
|
||||
app.State.scrap_last_action();
|
||||
return;
|
||||
}
|
||||
|
||||
let new_settings = {};
|
||||
if (params.radial == true) {
|
||||
new_settings = {
|
||||
x: this.layer.data.center_x - width,
|
||||
y: this.layer.data.center_y - height,
|
||||
width: width * 2,
|
||||
height: height * 2
|
||||
}
|
||||
}
|
||||
else {
|
||||
new_settings = {
|
||||
width,
|
||||
height
|
||||
}
|
||||
}
|
||||
new_settings.status = null;
|
||||
|
||||
app.State.do_action(
|
||||
new app.Actions.Update_layer_action(config.layer.id, new_settings),
|
||||
{ merge_with_history: 'new_gradient_layer' }
|
||||
);
|
||||
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
if (layer.width == 0 && layer.height == 0)
|
||||
return;
|
||||
|
||||
var params = layer.params;
|
||||
var power = params.radial_power;
|
||||
if(power > 99){
|
||||
power = 99;
|
||||
}
|
||||
var alpha = params.alpha / 100 * 255;
|
||||
if(power > 255){
|
||||
power = 255;
|
||||
}
|
||||
|
||||
var color1 = params.color_1;
|
||||
var color2 = params.color_2;
|
||||
var radial = params.radial;
|
||||
|
||||
var color2_rgb = this.Helper.hexToRgb(color2);
|
||||
|
||||
var width = layer.x + layer.width - 1;
|
||||
var height = layer.y + layer.height - 1;
|
||||
|
||||
if (radial == false) {
|
||||
//linear
|
||||
ctx.beginPath();
|
||||
ctx.rect(0, 0, config.WIDTH, config.HEIGHT);
|
||||
var grd = ctx.createLinearGradient(
|
||||
layer.x, layer.y,
|
||||
width, height);
|
||||
|
||||
grd.addColorStop(0, color1);
|
||||
grd.addColorStop(1, "rgba(" + color2_rgb.r + ", " + color2_rgb.g + ", "
|
||||
+ color2_rgb.b + ", " + alpha / 255 + ")");
|
||||
ctx.fillStyle = grd;
|
||||
ctx.fill();
|
||||
}
|
||||
else {
|
||||
//radial
|
||||
var dist_x = layer.width;
|
||||
var dist_y = layer.height;
|
||||
var center_x = layer.x + Math.round(layer.width / 2);
|
||||
var center_y = layer.y + Math.round(layer.height / 2);
|
||||
var distance = Math.sqrt((dist_x * dist_x) + (dist_y * dist_y));
|
||||
var radgrad = ctx.createRadialGradient(
|
||||
center_x, center_y, distance * power / 100,
|
||||
center_x, center_y, distance);
|
||||
|
||||
radgrad.addColorStop(0, color1);
|
||||
radgrad.addColorStop(1, "rgba(" + color2_rgb.r + ", " + color2_rgb.g + ", "
|
||||
+ color2_rgb.b + ", " + alpha / 255 + ")");
|
||||
ctx.fillStyle = radgrad;
|
||||
ctx.fillRect(0, 0, config.WIDTH, config.HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
export default Gradient_class;
|
||||
@@ -0,0 +1,214 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
|
||||
class Magic_erase_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'magic_erase';
|
||||
this.working = false;
|
||||
}
|
||||
|
||||
dragStart(event) {
|
||||
var _this = this;
|
||||
if (config.TOOL.name != _this.name)
|
||||
return;
|
||||
_this.mousedown(event);
|
||||
}
|
||||
|
||||
load() {
|
||||
var _this = this;
|
||||
|
||||
//mouse events
|
||||
document.addEventListener('mousedown', function (event) {
|
||||
_this.dragStart(event);
|
||||
});
|
||||
|
||||
// collect touch events
|
||||
document.addEventListener('touchstart', function (event) {
|
||||
_this.dragStart(event);
|
||||
});
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (config.layer.rotate || 0 > 0) {
|
||||
alertify.error('Erase on rotate object is disabled. Please rasterize first.');
|
||||
return;
|
||||
}
|
||||
|
||||
this.magic_erase(mouse);
|
||||
}
|
||||
|
||||
async magic_erase(mouse) {
|
||||
var params = this.getParams();
|
||||
|
||||
if(this.working == true){
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.layer.type != 'image') {
|
||||
alertify.error('This layer must contain an image. Please convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
if (config.layer.is_vector == true) {
|
||||
alertify.error('Layer is vector, convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
|
||||
//get canvas from layer
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext("2d");
|
||||
canvas.width = config.layer.width_original;
|
||||
canvas.height = config.layer.height_original;
|
||||
ctx.drawImage(config.layer.link, 0, 0);
|
||||
|
||||
var mouse_x = Math.round(mouse.x) - config.layer.x;
|
||||
var mouse_y = Math.round(mouse.y) - config.layer.y;
|
||||
|
||||
//adapt to origin size
|
||||
mouse_x = this.adaptSize(mouse_x, 'width');
|
||||
mouse_y = this.adaptSize(mouse_y, 'height');
|
||||
|
||||
//convert float coords to integers
|
||||
mouse_x = Math.round(mouse_x);
|
||||
mouse_y = Math.round(mouse_y);
|
||||
|
||||
//change
|
||||
this.working = true;
|
||||
this.magic_erase_general(ctx, config.WIDTH, config.HEIGHT,
|
||||
mouse_x, mouse_y, params.power, params.anti_aliasing, params.contiguous);
|
||||
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('magic_erase_tool', 'Magic Eraser Tool', [
|
||||
new app.Actions.Update_layer_image_action(canvas)
|
||||
])
|
||||
);
|
||||
//prevent crash bug on touch screen - hard to explain and debug
|
||||
await new Promise(r => setTimeout(r, 10));
|
||||
this.working = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* apply magic erase
|
||||
*
|
||||
* @param {ctx} context
|
||||
* @param {int} W
|
||||
* @param {int} H
|
||||
* @param {int} x
|
||||
* @param {int} y
|
||||
* @param {int} sensitivity max 100
|
||||
* @param {Boolean} anti_aliasing
|
||||
*/
|
||||
magic_erase_general(context, W, H, x, y, sensitivity, anti_aliasing, contiguous = false) {
|
||||
sensitivity = sensitivity * 255 / 100; //convert to 0-255 interval
|
||||
x = parseInt(x);
|
||||
y = parseInt(y);
|
||||
var canvasTemp = document.createElement('canvas');
|
||||
canvasTemp.width = W;
|
||||
canvasTemp.height = H;
|
||||
var ctxTemp = canvasTemp.getContext("2d");
|
||||
|
||||
ctxTemp.rect(0, 0, W, H);
|
||||
ctxTemp.fillStyle = "rgba(255, 255, 255, 0)";
|
||||
ctxTemp.fill();
|
||||
|
||||
var img_tmp = ctxTemp.getImageData(0, 0, W, H);
|
||||
var imgData_tmp = img_tmp.data;
|
||||
|
||||
var img = context.getImageData(0, 0, W, H);
|
||||
var imgData = img.data;
|
||||
var k = ((y * (img.width * 4)) + (x * 4));
|
||||
var dx = [0, -1, +1, 0];
|
||||
var dy = [-1, 0, 0, +1];
|
||||
var color_to = {
|
||||
r: 255,
|
||||
g: 255,
|
||||
b: 255,
|
||||
a: 255
|
||||
};
|
||||
var color_from = {
|
||||
r: imgData[k + 0],
|
||||
g: imgData[k + 1],
|
||||
b: imgData[k + 2],
|
||||
a: imgData[k + 3]
|
||||
};
|
||||
if (color_from.r == color_to.r &&
|
||||
color_from.g == color_to.g &&
|
||||
color_from.b == color_to.b &&
|
||||
color_from.a == 0) {
|
||||
return false;
|
||||
}
|
||||
if (contiguous == false) {
|
||||
//check only nearest pixels
|
||||
var stack = [];
|
||||
stack.push([x, y]);
|
||||
while (stack.length > 0) {
|
||||
var curPoint = stack.pop();
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var nextPointX = curPoint[0] + dx[i];
|
||||
var nextPointY = curPoint[1] + dy[i];
|
||||
if (nextPointX < 0 || nextPointY < 0 || nextPointX >= W || nextPointY >= H)
|
||||
continue;
|
||||
var k = (nextPointY * W + nextPointX) * 4;
|
||||
if (imgData_tmp[k + 3] != 0)
|
||||
continue; //already parsed
|
||||
|
||||
if (Math.abs(imgData[k] - color_from.r) <= sensitivity
|
||||
&& Math.abs(imgData[k + 1] - color_from.g) <= sensitivity
|
||||
&& Math.abs(imgData[k + 2] - color_from.b) <= sensitivity
|
||||
&& Math.abs(imgData[k + 3] - color_from.a) <= sensitivity) {
|
||||
//erase
|
||||
imgData_tmp[k] = color_to.r; //r
|
||||
imgData_tmp[k + 1] = color_to.g; //g
|
||||
imgData_tmp[k + 2] = color_to.b; //b
|
||||
imgData_tmp[k + 3] = color_to.a; //a
|
||||
|
||||
stack.push([nextPointX, nextPointY]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
//global mode - contiguous
|
||||
for (var i = 0; i < imgData.length; i += 4) {
|
||||
if (imgData[i + 3] == 0)
|
||||
continue; //transparent
|
||||
|
||||
//imgData[i] + 0.7152 * imgData[i + 1] + 0.0722 * imgData[i + 2]);
|
||||
|
||||
for (var j = 0; j < 4; j++) {
|
||||
var k = i + j;
|
||||
|
||||
if (Math.abs(imgData[k] - color_from.r) <= sensitivity
|
||||
&& Math.abs(imgData[k + 1] - color_from.g) <= sensitivity
|
||||
&& Math.abs(imgData[k + 2] - color_from.b) <= sensitivity
|
||||
&& Math.abs(imgData[k + 3] - color_from.a) <= sensitivity) {
|
||||
imgData_tmp[k] = color_to.r; //r
|
||||
imgData_tmp[k + 1] = color_to.g; //g
|
||||
imgData_tmp[k + 2] = color_to.b; //b
|
||||
imgData_tmp[k + 3] = color_to.a; //a
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//destination-out + blur = anti-aliasing
|
||||
ctxTemp.putImageData(img_tmp, 0, 0);
|
||||
context.globalCompositeOperation = "destination-out";
|
||||
if (anti_aliasing == true) {
|
||||
context.filter = 'blur(1px)';
|
||||
}
|
||||
context.drawImage(canvasTemp, 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
export default Magic_erase_class;
|
||||
@@ -0,0 +1,164 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import File_open_class from './../modules/file/open.js';
|
||||
import Tools_settings_class from './../modules/tools/settings.js';
|
||||
import Dialog_class from './../libs/popup.js';
|
||||
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
|
||||
class Media_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.File_open = new File_open_class();
|
||||
this.Tools_settings = new Tools_settings_class();
|
||||
this.POP = new Dialog_class();
|
||||
this.name = 'media';
|
||||
this.cache = [];
|
||||
this.page = 1;
|
||||
this.per_page = 50;
|
||||
}
|
||||
|
||||
load() {
|
||||
//nothing
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
//nothing
|
||||
}
|
||||
|
||||
on_activate() {
|
||||
this.search();
|
||||
}
|
||||
|
||||
/**
|
||||
* Image search api
|
||||
*
|
||||
* @param {string} query
|
||||
* @param {array} data
|
||||
* @param pages
|
||||
*/
|
||||
search(query = '', data = [], pages = null) {
|
||||
var _this = this;
|
||||
var html = '';
|
||||
var html_paging = '';
|
||||
|
||||
var key = config.pixabay_key;
|
||||
key = key.split("").reverse().join("");
|
||||
|
||||
var safe_search = this.Tools_settings.get_setting('safe_search');
|
||||
|
||||
if (data.length > 0) {
|
||||
for (var i in data) {
|
||||
html += '<div class="item">';
|
||||
html += ' <img class="displayBlock pointer" alt="" src="' + data[i].previewURL + '" data-url="' + data[i].webformatURL + '" />';
|
||||
html += '</div>';
|
||||
}
|
||||
//fix for last line
|
||||
html += '<div class="item"></div>';
|
||||
html += '<div class="item"></div>';
|
||||
html += '<div class="item"></div>';
|
||||
html += '<div class="item"></div>';
|
||||
|
||||
//paging
|
||||
html_paging += '<div class="media-paging" id="media_paging">';
|
||||
html_paging += '<button type="button" data-value="1" title="Previous"><</button> ';
|
||||
for(var i = 1; i <= Math.min(10, pages); i++) {
|
||||
var selected = '';
|
||||
if(this.page == i){
|
||||
var selected = 'selected';
|
||||
}
|
||||
html_paging += '<button type="button" class="'+selected+'" data-value="'+i+'">'+i+'</button> ';
|
||||
}
|
||||
html_paging += '<button type="button" data-value="'+Math.min(this.page + 1, pages)+'" title="Next">></button> ';
|
||||
html_paging += '</div>';
|
||||
}
|
||||
else{
|
||||
this.page = 1;
|
||||
}
|
||||
|
||||
var settings = {
|
||||
title: 'Search',
|
||||
//comment: 'Source: <a class="text_muted" href="https://pixabay.com/">pixabay.com</a>.',
|
||||
className: 'wide',
|
||||
params: [
|
||||
{name: "query", title: "Keyword:", value: query},
|
||||
],
|
||||
on_load: function (params, popup) {
|
||||
var node = document.createElement("div");
|
||||
node.classList.add('flex-container');
|
||||
node.innerHTML = html + html_paging;
|
||||
popup.el.querySelector('.dialog_content').appendChild(node);
|
||||
//events
|
||||
var targets = popup.el.querySelectorAll('.item img');
|
||||
for (var i = 0; i < targets.length; i++) {
|
||||
targets[i].addEventListener('click', function (event) {
|
||||
//we have click
|
||||
var data = {
|
||||
url: this.dataset.url,
|
||||
};
|
||||
_this.File_open.file_open_url_handler(data);
|
||||
_this.POP.hide();
|
||||
|
||||
new app.Actions.Activate_tool_action('select', true).do();
|
||||
});
|
||||
}
|
||||
var targets = popup.el.querySelectorAll('#media_paging button');
|
||||
for (var i = 0; i < targets.length; i++) {
|
||||
targets[i].addEventListener('click', function (event) {
|
||||
//we have click
|
||||
_this.page = parseInt(this.dataset.value);
|
||||
_this.POP.save();
|
||||
});
|
||||
}
|
||||
},
|
||||
on_finish: function (params) {
|
||||
if (params.query == '')
|
||||
return;
|
||||
|
||||
var URL = "https://pixabay.com/api/?key=" + key
|
||||
+ "&page=" + _this.page
|
||||
+ "&per_page=" + _this.per_page
|
||||
+ "&safesearch=" + safe_search
|
||||
+ "&q=" + encodeURIComponent(params.query);
|
||||
|
||||
if (_this.cache[URL] != undefined) {
|
||||
//using cache
|
||||
|
||||
setTimeout(function () {
|
||||
//only call same function after all handlers finishes
|
||||
var data = _this.cache[URL];
|
||||
|
||||
if (parseInt(data.totalHits) == 0) {
|
||||
alertify.error('Your search did not match any images.');
|
||||
}
|
||||
|
||||
var pages = Math.ceil(data.totalHits / _this.per_page);
|
||||
_this.search(params.query, data.hits, pages);
|
||||
}, 100);
|
||||
}
|
||||
else {
|
||||
//query to service
|
||||
$.getJSON(URL, function (data) {
|
||||
_this.cache[URL] = data;
|
||||
|
||||
if (parseInt(data.totalHits) == 0) {
|
||||
alertify.error('Your search did not match any images.');
|
||||
}
|
||||
|
||||
var pages = Math.ceil(data.totalHits / _this.per_page);
|
||||
_this.search(params.query, data.hits, pages);
|
||||
})
|
||||
.fail(function () {
|
||||
alertify.error('Error connecting to service.');
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
this.POP.show(settings);
|
||||
|
||||
document.getElementById("pop_data_query").select();
|
||||
}
|
||||
}
|
||||
|
||||
export default Media_class;
|
||||
@@ -0,0 +1,306 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
|
||||
class Pencil_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.name = 'pencil';
|
||||
this.layer = {};
|
||||
this.params_hash = false;
|
||||
this.pressure_supported = false;
|
||||
this.pointer_pressure = 0; // has range [0 - 1]
|
||||
}
|
||||
|
||||
load() {
|
||||
var _this = this;
|
||||
|
||||
//pointer events
|
||||
document.addEventListener('pointerdown', function (event) {
|
||||
_this.pointerdown(event);
|
||||
});
|
||||
document.addEventListener('pointermove', function (event) {
|
||||
_this.pointermove(event);
|
||||
});
|
||||
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
dragMove(event) {
|
||||
if (config.TOOL.name != this.name)
|
||||
return;
|
||||
this.mousemove(event);
|
||||
}
|
||||
|
||||
pointerdown(e) {
|
||||
// Devices that don't actually support pen pressure can give 0.5 as a false reading.
|
||||
// It is highly unlikely a real pen will read exactly 0.5 at the start of a stroke.
|
||||
if (e.pressure && e.pressure !== 0 && e.pressure !== 0.5 && e.pressure <= 1) {
|
||||
this.pressure_supported = true;
|
||||
this.pointer_pressure = e.pressure;
|
||||
} else {
|
||||
this.pressure_supported = false;
|
||||
}
|
||||
}
|
||||
|
||||
pointermove(e) {
|
||||
// Pressure of exactly 1 seems to be an input error, sometimes I see it when lifting the pen
|
||||
// off the screen when pressure reading should be near 0.
|
||||
if (this.pressure_supported && e.pressure < 1) {
|
||||
this.pointer_pressure = e.pressure;
|
||||
}
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false)
|
||||
return;
|
||||
|
||||
var params_hash = this.get_params_hash();
|
||||
var opacity = Math.round(config.ALPHA / 255 * 100);
|
||||
|
||||
if (config.layer.type != this.name || params_hash != this.params_hash) {
|
||||
//register new object - current layer is not ours or params changed
|
||||
this.layer = {
|
||||
type: this.name,
|
||||
data: [],
|
||||
opacity: opacity,
|
||||
params: this.clone(this.getParams()),
|
||||
status: 'draft',
|
||||
render_function: [this.name, 'render'],
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: config.WIDTH,
|
||||
height: config.HEIGHT,
|
||||
hide_selection_if_active: true,
|
||||
rotate: null,
|
||||
is_vector: true,
|
||||
color: config.COLOR
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('new_pencil_layer', 'New Pencil Layer', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
this.params_hash = params_hash;
|
||||
}
|
||||
else {
|
||||
//continue adding layer data, just register break
|
||||
const new_data = JSON.parse(JSON.stringify(config.layer.data));
|
||||
new_data.push(null);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('update_pencil_layer', 'Update Pencil Layer', [
|
||||
new app.Actions.Update_layer_action(config.layer.id, {
|
||||
data: new_data
|
||||
})
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
//detect line size
|
||||
var size = params.size;
|
||||
var new_size = size;
|
||||
|
||||
if (params.pressure == true && this.pressure_supported) {
|
||||
new_size = size * this.pointer_pressure * 2;
|
||||
}
|
||||
|
||||
//more data
|
||||
config.layer.data.push([
|
||||
Math.ceil(mouse.x - config.layer.x),
|
||||
Math.ceil(mouse.y - config.layer.y),
|
||||
new_size
|
||||
]);
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.click_valid == false) {
|
||||
config.layer.status = null;
|
||||
return;
|
||||
}
|
||||
|
||||
//detect line size
|
||||
var size = params.size;
|
||||
var new_size = size;
|
||||
|
||||
if (params.pressure == true && this.pressure_supported) {
|
||||
new_size = size * this.pointer_pressure * 2;
|
||||
}
|
||||
|
||||
//more data
|
||||
config.layer.data.push([
|
||||
Math.ceil(mouse.x - config.layer.x),
|
||||
Math.ceil(mouse.y - config.layer.y),
|
||||
new_size
|
||||
]);
|
||||
|
||||
this.check_dimensions();
|
||||
|
||||
config.layer.status = null;
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
this.render_aliased(ctx, layer);
|
||||
}
|
||||
|
||||
/**
|
||||
* draw without antialiasing, sharp, ugly mode.
|
||||
*
|
||||
* @param {object} ctx
|
||||
* @param {object} layer
|
||||
*/
|
||||
render_aliased(ctx, layer) {
|
||||
if (layer.data.length == 0)
|
||||
return;
|
||||
|
||||
var params = layer.params;
|
||||
var data = layer.data;
|
||||
var n = data.length;
|
||||
var size = params.size;
|
||||
|
||||
//set styles
|
||||
ctx.fillStyle = layer.color;
|
||||
ctx.strokeStyle = layer.color;
|
||||
ctx.translate(layer.x, layer.y);
|
||||
|
||||
//draw
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(data[0][0], data[0][1]);
|
||||
for (var i = 1; i < n; i++) {
|
||||
if (data[i] === null) {
|
||||
//break
|
||||
ctx.beginPath();
|
||||
}
|
||||
else {
|
||||
//line
|
||||
size = data[i][2];
|
||||
if(size == undefined){
|
||||
size = 1;
|
||||
}
|
||||
|
||||
if (data[i - 1] == null) {
|
||||
//exception - point
|
||||
ctx.fillRect(
|
||||
data[i][0] - Math.floor(size / 2) - 1,
|
||||
data[i][1] - Math.floor(size / 2) - 1,
|
||||
size,
|
||||
size
|
||||
);
|
||||
}
|
||||
else {
|
||||
//lines
|
||||
ctx.beginPath();
|
||||
this.draw_simple_line(
|
||||
ctx,
|
||||
data[i - 1][0],
|
||||
data[i - 1][1],
|
||||
data[i][0],
|
||||
data[i][1],
|
||||
size
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n == 1 || data[1] == null) {
|
||||
//point
|
||||
ctx.beginPath();
|
||||
ctx.fillRect(
|
||||
data[0][0] - Math.floor(size / 2) - 1,
|
||||
data[0][1] - Math.floor(size / 2) - 1,
|
||||
size,
|
||||
size
|
||||
);
|
||||
}
|
||||
|
||||
ctx.translate(-layer.x, -layer.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* draws line without aliasing
|
||||
*
|
||||
* @param {object} ctx
|
||||
* @param {int} from_x
|
||||
* @param {int} from_y
|
||||
* @param {int} to_x
|
||||
* @param {int} to_y
|
||||
* @param {int} size
|
||||
*/
|
||||
draw_simple_line(ctx, from_x, from_y, to_x, to_y, size) {
|
||||
var dist_x = from_x - to_x;
|
||||
var dist_y = from_y - to_y;
|
||||
var distance = Math.sqrt((dist_x * dist_x) + (dist_y * dist_y));
|
||||
var radiance = Math.atan2(dist_y, dist_x);
|
||||
|
||||
for (var j = 0; j < distance; j++) {
|
||||
var x_tmp = Math.round(to_x + Math.cos(radiance) * j) - Math.floor(size / 2) - 1;
|
||||
var y_tmp = Math.round(to_y + Math.sin(radiance) * j) - Math.floor(size / 2) - 1;
|
||||
|
||||
ctx.fillRect(x_tmp, y_tmp, size, size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* recalculate layer x, y, width and height values.
|
||||
*/
|
||||
check_dimensions() {
|
||||
if(config.layer.data.length == 0)
|
||||
return;
|
||||
|
||||
//find bounds
|
||||
var data = JSON.parse(JSON.stringify(config.layer.data)); // Deep copy for history
|
||||
var min_x = data[0][0];
|
||||
var min_y = data[0][1];
|
||||
var max_x = data[0][0];
|
||||
var max_y = data[0][1];
|
||||
for(var i in data){
|
||||
if(data[i] === null)
|
||||
continue;
|
||||
min_x = Math.min(min_x, data[i][0]);
|
||||
min_y = Math.min(min_y, data[i][1]);
|
||||
max_x = Math.max(max_x, data[i][0]);
|
||||
max_y = Math.max(max_y, data[i][1]);
|
||||
}
|
||||
|
||||
//move current data
|
||||
for(var i in data){
|
||||
if(data[i] === null)
|
||||
continue;
|
||||
data[i][0] = data[i][0] - min_x;
|
||||
data[i][1] = data[i][1] - min_y;
|
||||
}
|
||||
|
||||
//change layers bounds
|
||||
app.State.do_action(
|
||||
new app.Actions.Update_layer_action(config.layer.id, {
|
||||
x: config.layer.x + min_x,
|
||||
y: config.layer.y + min_y,
|
||||
width: max_x - min_x,
|
||||
height: max_y - min_y,
|
||||
data
|
||||
}),
|
||||
{
|
||||
merge_with_history: ['new_pencil_layer', 'update_pencil_layer']
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Pencil_class;
|
||||
@@ -0,0 +1,111 @@
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import Helper_class from './../libs/helpers.js';
|
||||
import Base_gui_class from './../core/base-gui.js';
|
||||
|
||||
class Pick_color_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.Helper = new Helper_class();
|
||||
this.Base_gui = new Base_gui_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'pick_color';
|
||||
}
|
||||
|
||||
dragStart(event) {
|
||||
var _this = this;
|
||||
if (config.TOOL.name != _this.name)
|
||||
return;
|
||||
_this.mousedown(event);
|
||||
}
|
||||
|
||||
dragMove(event) {
|
||||
var _this = this;
|
||||
if (config.TOOL.name != _this.name)
|
||||
return;
|
||||
_this.mousemove(event);
|
||||
}
|
||||
|
||||
load() {
|
||||
var _this = this;
|
||||
|
||||
//mouse events
|
||||
document.addEventListener('mousedown', function (event) {
|
||||
_this.dragStart(event);
|
||||
});
|
||||
document.addEventListener('mousemove', function (event) {
|
||||
_this.dragMove(event);
|
||||
});
|
||||
document.addEventListener('mouseup', function (event) {
|
||||
var mouse = _this.get_mouse_info(event);
|
||||
if (config.TOOL.name != _this.name || mouse.click_valid == false)
|
||||
return;
|
||||
_this.copy_color_to_clipboard();
|
||||
});
|
||||
|
||||
// collect touch events
|
||||
document.addEventListener('touchstart', function (event) {
|
||||
_this.dragStart(event);
|
||||
});
|
||||
document.addEventListener('touchmove', function (event) {
|
||||
_this.dragMove(event);
|
||||
});
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pick_color(mouse);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.is_drag == false || mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pick_color(mouse);
|
||||
}
|
||||
|
||||
pick_color(mouse) {
|
||||
var params = this.getParams();
|
||||
|
||||
//get canvas from layer
|
||||
if (params.global == false) {
|
||||
//active layer
|
||||
var canvas = this.Base_layers.convert_layer_to_canvas(config.layer.id, null, false);
|
||||
var ctx = canvas.getContext("2d");
|
||||
}
|
||||
else {
|
||||
//global
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext("2d");
|
||||
canvas.width = config.WIDTH;
|
||||
canvas.height = config.HEIGHT;
|
||||
this.Base_layers.convert_layers_to_canvas(ctx, null, false);
|
||||
}
|
||||
//find color
|
||||
var c = ctx.getImageData(mouse.x, mouse.y, 1, 1).data;
|
||||
var hex = this.Helper.rgbToHex(c[0], c[1], c[2]);
|
||||
|
||||
const newColorDefinition = { hex };
|
||||
if (c[3] > 0) {
|
||||
//set alpha
|
||||
newColorDefinition.a = c[3];
|
||||
}
|
||||
this.Base_gui.GUI_colors.set_color(newColorDefinition);
|
||||
}
|
||||
|
||||
copy_color_to_clipboard() {
|
||||
navigator.clipboard.writeText(config.COLOR);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Pick_color_class;
|
||||
@@ -0,0 +1,577 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import Base_selection_class from './../core/base-selection.js';
|
||||
import Helper_class from './../libs/helpers.js';
|
||||
import Dialog_class from './../libs/popup.js';
|
||||
|
||||
class Select_tool_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.POP = new Dialog_class();
|
||||
this.Helper = new Helper_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'select';
|
||||
this.saved = false;
|
||||
this.mousedown_dimensions = { x: null, y: null, width: null, height: null };
|
||||
this.keyboard_move_start_position = null;
|
||||
this.moving = false;
|
||||
this.resizing = false;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.rotate_initial = null;
|
||||
|
||||
var sel_config = {
|
||||
enable_background: false,
|
||||
enable_borders: true,
|
||||
enable_controls: true,
|
||||
keep_ratio: true,
|
||||
enable_rotation: true,
|
||||
enable_move: true,
|
||||
data_function: function () {
|
||||
return config.layer;
|
||||
},
|
||||
};
|
||||
this.Base_selection = new Base_selection_class(ctx, sel_config, this.name);
|
||||
}
|
||||
|
||||
load() {
|
||||
var _this = this;
|
||||
|
||||
//mouse events
|
||||
document.addEventListener('mousedown', function (e) {
|
||||
_this.dragStart(e);
|
||||
});
|
||||
document.addEventListener('mousemove', function (e) {
|
||||
_this.dragMove(e);
|
||||
});
|
||||
document.addEventListener('mouseup', function (e) {
|
||||
_this.dragEnd(e);
|
||||
});
|
||||
|
||||
// collect touch events
|
||||
document.addEventListener('touchstart', function (e) {
|
||||
_this.dragStart(e);
|
||||
});
|
||||
document.addEventListener('touchmove', function (e) {
|
||||
_this.dragMove(e);
|
||||
});
|
||||
document.addEventListener('touchend', function (e) {
|
||||
_this.dragEnd(e);
|
||||
});
|
||||
|
||||
//keyboard actions
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if (config.TOOL.name != this.name)
|
||||
return;
|
||||
if (this.POP.get_active_instances() > 0) {
|
||||
return;
|
||||
}
|
||||
if (this.Helper.is_input(event.target))
|
||||
return;
|
||||
var k = event.key;
|
||||
|
||||
if (k == "ArrowUp") {
|
||||
this.move(0, -1, event);
|
||||
}
|
||||
else if (k == "ArrowDown") {
|
||||
this.move(0, 1, event);
|
||||
}
|
||||
else if (k == "ArrowRight") {
|
||||
this.move(1, 0, event);
|
||||
}
|
||||
else if (k == "ArrowLeft") {
|
||||
this.move(-1, 0, event);
|
||||
}
|
||||
if (k == "Delete") {
|
||||
if (config.TOOL.name == this.name) {
|
||||
app.State.do_action(
|
||||
new app.Actions.Delete_layer_action(config.layer.id)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
document.addEventListener('keyup', (event) => {
|
||||
if (config.TOOL.name != this.name)
|
||||
return;
|
||||
if (this.POP.active == true)
|
||||
return;
|
||||
if (this.Helper.is_input(event.target))
|
||||
return;
|
||||
var k = event.key;
|
||||
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(k)) {
|
||||
if (this.keyboard_move_start_position) {
|
||||
let x = config.layer.x;
|
||||
let y = config.layer.y;
|
||||
config.layer.x = this.keyboard_move_start_position.x;
|
||||
config.layer.y = this.keyboard_move_start_position.y;
|
||||
app.State.do_action(
|
||||
new app.Actions.Update_layer_action(config.layer.id, { x, y })
|
||||
);
|
||||
this.keyboard_move_start_position = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dragStart(event) {
|
||||
var mouse = this.get_mouse_info(event);
|
||||
if (config.TOOL.name != this.name)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.mousedown(event);
|
||||
}
|
||||
|
||||
dragMove(event) {
|
||||
var mouse = this.get_mouse_info(event);
|
||||
if (config.TOOL.name != this.name)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.mousemove(event);
|
||||
}
|
||||
|
||||
dragEnd(event) {
|
||||
var mouse = this.get_mouse_info(event);
|
||||
if (config.TOOL.name != this.name)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.mouseup(event);
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
async mousedown(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false || config.mouse_lock === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.rotate_initial = config.layer.rotate;
|
||||
|
||||
if (this.Base_selection.mouse_lock != null) {
|
||||
this.resizing = true;
|
||||
this.Base_selection.find_settings().keep_ratio = config.layer.type === 'image';
|
||||
if (config.layer.type === 'text' && config.layer.params && config.layer.params.boundary === 'dynamic') {
|
||||
config.layer.params.boundary = 'box';
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.moving = true;
|
||||
await this.auto_select_object(e);
|
||||
this.Base_selection.find_settings().keep_ratio = config.layer.type === 'image';
|
||||
this.saved = false;
|
||||
}
|
||||
|
||||
this.mousedown_dimensions = {
|
||||
x: Math.round(config.layer.x),
|
||||
y: Math.round(config.layer.y),
|
||||
width: Math.round(config.layer.width),
|
||||
height: Math.round(config.layer.height)
|
||||
};
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.is_drag == false || mouse.click_valid == false || config.mouse_lock === true) {
|
||||
return;
|
||||
}
|
||||
if (this.resizing) {
|
||||
|
||||
//also handle rotation
|
||||
let rotate = this.Base_selection.current_angle
|
||||
if(config.layer.rotate != rotate && rotate !== null){
|
||||
config.layer.rotate = rotate;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if (this.moving) {
|
||||
//move object
|
||||
config.layer.x = Math.round(mouse.x - mouse.click_x + this.mousedown_dimensions.x);
|
||||
config.layer.y = Math.round(mouse.y - mouse.click_y + this.mousedown_dimensions.y);
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap(e, config.layer.x, config.layer.y);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
config.layer.x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
config.layer.y = snap_info.y;
|
||||
}
|
||||
}
|
||||
|
||||
config.need_render = true;
|
||||
}
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false || config.mouse_lock === true) {
|
||||
return;
|
||||
}
|
||||
if (this.resizing) {
|
||||
let x = config.layer.x;
|
||||
let y = config.layer.y;
|
||||
let width = config.layer.width;
|
||||
let height = config.layer.height;
|
||||
|
||||
//reset values
|
||||
config.layer.x = this.mousedown_dimensions.x;
|
||||
config.layer.y = this.mousedown_dimensions.y;
|
||||
config.layer.width = this.mousedown_dimensions.width;
|
||||
config.layer.height = this.mousedown_dimensions.height;
|
||||
if (
|
||||
this.mousedown_dimensions.x !== x || this.mousedown_dimensions.y !== y ||
|
||||
this.mousedown_dimensions.width !== width || this.mousedown_dimensions.height !== height
|
||||
) {
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('resize_layer', 'Resize Layer', [
|
||||
new app.Actions.Update_layer_action(config.layer.id, {
|
||||
x, y, width, height
|
||||
})
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
//also handle rotation
|
||||
let rotate = this.Base_selection.current_angle;
|
||||
if(this.rotate_initial != rotate && rotate !== null){
|
||||
//save state
|
||||
config.layer.rotate = this.rotate_initial;
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('resize_layer', 'Resize Layer', [
|
||||
new app.Actions.Update_layer_action(config.layer.id, {
|
||||
rotate
|
||||
})
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (this.moving) {
|
||||
var new_x = Math.round(mouse.x - mouse.click_x + this.mousedown_dimensions.x);
|
||||
var new_y = Math.round(mouse.y - mouse.click_y + this.mousedown_dimensions.y);
|
||||
config.layer.x = this.mousedown_dimensions.x;
|
||||
config.layer.y = this.mousedown_dimensions.y;
|
||||
|
||||
if(mouse.x - mouse.click_x || mouse.y - mouse.click_y) {
|
||||
var snap_info = this.calc_snap(e, new_x, new_y);
|
||||
if (snap_info != null) {
|
||||
if (snap_info.x != null) {
|
||||
new_x = snap_info.x;
|
||||
}
|
||||
if (snap_info.y != null) {
|
||||
new_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.mousedown_dimensions.x !== new_x || this.mousedown_dimensions.y !== new_y) {
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('move_layer', 'Move Layer', [
|
||||
new app.Actions.Update_layer_action(config.layer.id, {
|
||||
x: new_x,
|
||||
y: new_y
|
||||
})
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
this.moving = false;
|
||||
this.resizing = false;
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
var mouse = this.get_mouse_info(event);
|
||||
|
||||
//maybe related tool have additional overlay render handlers?
|
||||
if(config.layer.render_function != null) {
|
||||
var render_class = config.layer.render_function[0];
|
||||
var render_function = 'select';
|
||||
if (
|
||||
typeof this.Base_gui.GUI_tools.tools_modules[render_class].object[
|
||||
render_function
|
||||
] != "undefined"
|
||||
) {
|
||||
this.Base_gui.GUI_tools.tools_modules[render_class].object[
|
||||
render_function
|
||||
](this.ctx);
|
||||
}
|
||||
}
|
||||
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* calculates current object snap coordinates and returns it. One of coordinates can be null.
|
||||
*
|
||||
* @param event
|
||||
* @param pos_x
|
||||
* @param pos_y
|
||||
* @returns object|null
|
||||
*/
|
||||
calc_snap(event, pos_x, pos_y) {
|
||||
var snap_position = { x: null, y: null };
|
||||
var params = this.getParams();
|
||||
|
||||
if(config.SNAP === false || event.shiftKey == true){
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
return null;
|
||||
}
|
||||
|
||||
//settings
|
||||
var sensitivity = 0.01;
|
||||
var max_distance = (config.WIDTH + config.HEIGHT) / 2 * sensitivity / config.ZOOM;
|
||||
|
||||
//collect snap positions
|
||||
var snap_positions = this.get_snap_positions(config.layer.id);
|
||||
|
||||
//find closest snap positions
|
||||
var min_group = {
|
||||
x: {
|
||||
start: null,
|
||||
center: null,
|
||||
end: null,
|
||||
},
|
||||
y: {
|
||||
start: null,
|
||||
center: null,
|
||||
end: null,
|
||||
},
|
||||
};
|
||||
var min_group_distance = {
|
||||
x: {
|
||||
start: null,
|
||||
center: null,
|
||||
end: null,
|
||||
},
|
||||
y: {
|
||||
start: null,
|
||||
center: null,
|
||||
end: null,
|
||||
},
|
||||
};
|
||||
//x
|
||||
for(var i in snap_positions.x){
|
||||
var distance = Math.abs(pos_x - snap_positions.x[i]);
|
||||
if(distance < max_distance && (distance < min_group_distance.x.start || min_group_distance.x.start === null)){
|
||||
min_group_distance.x.start = distance;
|
||||
min_group.x.start = snap_positions.x[i];
|
||||
}
|
||||
|
||||
var distance = Math.abs(pos_x + config.layer.width/2 - snap_positions.x[i]);
|
||||
if(distance < max_distance && (distance < min_group_distance.x.center || min_group_distance.x.center === null)){
|
||||
min_group_distance.x.center = distance;
|
||||
min_group.x.center = snap_positions.x[i];
|
||||
}
|
||||
|
||||
var distance = Math.abs(pos_x + config.layer.width - snap_positions.x[i]);
|
||||
if(distance < max_distance && (distance < min_group_distance.x.end || min_group_distance.x.end === null)){
|
||||
min_group_distance.x.end = distance;
|
||||
min_group.x.end = snap_positions.x[i];
|
||||
}
|
||||
}
|
||||
//y
|
||||
for(var i in snap_positions.y){
|
||||
var distance = Math.abs(pos_y - snap_positions.y[i]);
|
||||
if(distance < max_distance && (distance < min_group_distance.y.start || min_group_distance.y.start === null)){
|
||||
min_group_distance.y.start = distance;
|
||||
min_group.y.start = snap_positions.y[i];
|
||||
}
|
||||
|
||||
var distance = Math.abs(pos_y + config.layer.height/2 - snap_positions.y[i]);
|
||||
if(distance < max_distance && (distance < min_group_distance.y.center || min_group_distance.y.center === null)){
|
||||
min_group_distance.y.center = distance;
|
||||
min_group.y.center = snap_positions.y[i];
|
||||
}
|
||||
|
||||
var distance = Math.abs(pos_y + config.layer.height - snap_positions.y[i]);
|
||||
if(distance < max_distance && (distance < min_group_distance.y.end || min_group_distance.y.end === null)){
|
||||
min_group_distance.y.end = distance;
|
||||
min_group.y.end = snap_positions.y[i];
|
||||
}
|
||||
}
|
||||
|
||||
//find best begin, center, end
|
||||
var min_distance = {
|
||||
x: null,
|
||||
y: null,
|
||||
};
|
||||
//x
|
||||
if(min_group_distance.x.start != null)
|
||||
min_distance.x = min_group_distance.x.start;
|
||||
if(min_group_distance.x.center != null && (min_group_distance.x.center < min_distance.x || min_distance.x === null))
|
||||
min_distance.x = min_group_distance.x.center;
|
||||
if(min_group_distance.x.end != null && (min_group_distance.x.end < min_distance.x || min_distance.x === null))
|
||||
min_distance.x = min_group_distance.x.end;
|
||||
//y
|
||||
if(min_group_distance.y.start != null)
|
||||
min_distance.y = min_group_distance.y.start;
|
||||
if(min_group_distance.y.center != null && (min_group_distance.y.center < min_distance.y || min_distance.y === null))
|
||||
min_distance.y = min_group_distance.y.center;
|
||||
if(min_group_distance.y.end != null && (min_group_distance.y.end < min_distance.y || min_distance.y === null))
|
||||
min_distance.y = min_group_distance.y.end;
|
||||
|
||||
//apply snap
|
||||
var success = false;
|
||||
//x
|
||||
if(min_group.x.center != null && min_group_distance.x.center == min_distance.x) {
|
||||
snap_position.x = Math.round(min_group.x.center - config.layer.width / 2);
|
||||
success = true;
|
||||
this.snap_line_info.x = {
|
||||
start_x: min_group.x.center,
|
||||
start_y: 0,
|
||||
end_x: min_group.x.center,
|
||||
end_y: config.HEIGHT
|
||||
};
|
||||
}
|
||||
else if(min_group.x.start != null && min_group_distance.x.start == min_distance.x) {
|
||||
snap_position.x = Math.round(min_group.x.start);
|
||||
success = true;
|
||||
this.snap_line_info.x = {
|
||||
start_x: min_group.x.start,
|
||||
start_y: 0,
|
||||
end_x: min_group.x.start,
|
||||
end_y: config.HEIGHT,
|
||||
};
|
||||
}
|
||||
else if(min_group.x.end != null && min_group_distance.x.end == min_distance.x) {
|
||||
snap_position.x = Math.round(min_group.x.end - config.layer.width);
|
||||
success = true;
|
||||
this.snap_line_info.x = {
|
||||
start_x: min_group.x.end,
|
||||
start_y: 0,
|
||||
end_x: min_group.x.end,
|
||||
end_y: config.HEIGHT
|
||||
};
|
||||
}
|
||||
else{
|
||||
this.snap_line_info.x = null;
|
||||
}
|
||||
//y
|
||||
if(min_group.y.center != null && min_group_distance.y.center == min_distance.y) {
|
||||
snap_position.y = Math.round(min_group.y.center - config.layer.height / 2);
|
||||
success = true;
|
||||
this.snap_line_info.y = {
|
||||
start_x: 0,
|
||||
start_y: min_group.y.center,
|
||||
end_x: config.WIDTH,
|
||||
end_y: min_group.y.center,
|
||||
};
|
||||
}
|
||||
else if(min_group.y.start != null && min_group_distance.y.start == min_distance.y) {
|
||||
snap_position.y = Math.round(min_group.y.start);
|
||||
success = true;
|
||||
this.snap_line_info.y = {
|
||||
start_x: 0,
|
||||
start_y: min_group.y.start,
|
||||
end_x: config.WIDTH,
|
||||
end_y: min_group.y.start,
|
||||
};
|
||||
}
|
||||
else if(min_group.y.end != null && min_group_distance.y.end == min_distance.y) {
|
||||
snap_position.y = Math.round(min_group.y.end - config.layer.height);
|
||||
success = true;
|
||||
this.snap_line_info.y = {
|
||||
start_x: 0,
|
||||
start_y: min_group.y.end,
|
||||
end_x: config.WIDTH,
|
||||
end_y: min_group.y.end,
|
||||
};
|
||||
}
|
||||
else{
|
||||
this.snap_line_info.y = null;
|
||||
}
|
||||
|
||||
if(success) {
|
||||
return snap_position;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
move(direction_x, direction_y, event) {
|
||||
if (!this.keyboard_move_start_position) {
|
||||
this.keyboard_move_start_position = {
|
||||
x: config.layer.x,
|
||||
y: config.layer.y
|
||||
}
|
||||
}
|
||||
var power = 10;
|
||||
if (event.ctrlKey == true || event.metaKey)
|
||||
power = 50;
|
||||
if (event.shiftKey == true)
|
||||
power = 1;
|
||||
|
||||
config.layer.x += direction_x * power;
|
||||
config.layer.y += direction_y * power;
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
async auto_select_object(e) {
|
||||
var params = this.getParams();
|
||||
if (params.auto_select == false)
|
||||
return;
|
||||
|
||||
var layers_sorted = this.Base_layers.get_sorted_layers();
|
||||
|
||||
//render main canvas
|
||||
for (var i = 0; i < layers_sorted.length; i++) {
|
||||
var value = layers_sorted[i];
|
||||
var canvas = this.Base_layers.convert_layer_to_canvas(value.id, null, false);
|
||||
|
||||
if (this.check_hit_region(e, canvas.getContext("2d"), value) == true) {
|
||||
await app.State.do_action(
|
||||
new app.Actions.Select_layer_action(value.id)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check_hit_region(e, ctx, layer) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
|
||||
if(layer.type == 'image' && Math.abs(layer.width * layer.height / 1000000) > 5){
|
||||
//too big to check using getImageData - use simple way
|
||||
if (mouse.x > layer.x && mouse.x < layer.x + layer.width &&
|
||||
mouse.y > layer.y && mouse.y < layer.y + layer.height) {
|
||||
//hit
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = ctx.getImageData(mouse.x, mouse.y, 1, 1).data;
|
||||
var blank = [0, 0, 0, 0];
|
||||
if (config.TRANSPARENCY == false) {
|
||||
blank = [0, 0, 0, 0];
|
||||
}
|
||||
|
||||
if (data[0] != blank[0] || data[1] != blank[1] || data[2] != blank[2]
|
||||
|| data[3] != blank[3]) {
|
||||
//hit
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Select_tool_class;
|
||||
@@ -0,0 +1,348 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import Base_selection_class from './../core/base-selection.js';
|
||||
import GUI_tools_class from './../core/gui/gui-tools.js';
|
||||
import Helper_class from './../libs/helpers.js';
|
||||
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
|
||||
var instance = null;
|
||||
|
||||
class Selection_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
|
||||
//singleton
|
||||
if (instance) {
|
||||
return instance;
|
||||
}
|
||||
instance = this;
|
||||
|
||||
var _this = this;
|
||||
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.Helper = new Helper_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'selection';
|
||||
this.type = null;
|
||||
this.tmpCanvas = null;
|
||||
this.tmpCanvasCtx = null;
|
||||
this.selection_coords_from = null;
|
||||
this.selection = {
|
||||
x: null,
|
||||
y: null,
|
||||
width: null,
|
||||
height: null,
|
||||
};
|
||||
|
||||
var sel_config = {
|
||||
enable_background: true,
|
||||
enable_borders: true,
|
||||
enable_controls: false,
|
||||
enable_rotation: false,
|
||||
enable_move: false,
|
||||
data_function: function () {
|
||||
return _this.selection;
|
||||
},
|
||||
};
|
||||
this.mousedown_selection = null;
|
||||
this.Base_selection = new Base_selection_class(ctx, sel_config, this.name);
|
||||
this.GUI_tools = new GUI_tools_class();
|
||||
}
|
||||
|
||||
load() {
|
||||
var _this = this;
|
||||
|
||||
//mouse events
|
||||
document.addEventListener('mousedown', function (event) {
|
||||
_this.dragStart(event);
|
||||
});
|
||||
document.addEventListener('mousemove', function (event) {
|
||||
_this.dragMove(event);
|
||||
});
|
||||
document.addEventListener('mouseup', function (event) {
|
||||
_this.dragEnd(event);
|
||||
});
|
||||
|
||||
// collect touch events
|
||||
document.addEventListener('touchstart', function (event) {
|
||||
_this.dragStart(event);
|
||||
});
|
||||
document.addEventListener('touchmove', function (event) {
|
||||
_this.dragMove(event);
|
||||
});
|
||||
document.addEventListener('touchend', function (event) {
|
||||
_this.dragEnd(event);
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
var code = e.keyCode;
|
||||
if (this.Helper.is_input(e.target))
|
||||
return;
|
||||
|
||||
if (code == 27) {
|
||||
//escape
|
||||
app.State.do_action(new app.Actions.Bundle_action('clear_selection', 'Clear Selection', this.on_leave()));
|
||||
}
|
||||
if (code == 46) {
|
||||
//delete
|
||||
if (config.TOOL.name == this.name) {
|
||||
this.delete_selection();
|
||||
}
|
||||
}
|
||||
if (code == 65 && (e.ctrlKey == true || e.metaKey)) {
|
||||
//A
|
||||
e.preventDefault();
|
||||
this.select_all();
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
dragStart(event) {
|
||||
var _this = this;
|
||||
if (config.TOOL.name != _this.name)
|
||||
return;
|
||||
_this.mousedown(event);
|
||||
}
|
||||
|
||||
dragMove(event) {
|
||||
var _this = this;
|
||||
if (config.TOOL.name != _this.name)
|
||||
return;
|
||||
_this.mousemove(event);
|
||||
}
|
||||
|
||||
dragEnd(event) {
|
||||
var _this = this;
|
||||
if (config.TOOL.name != _this.name)
|
||||
return;
|
||||
_this.mouseup(event);
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var layer = config.layer;
|
||||
if (this.Base_selection.is_drag == false || mouse.click_valid == false)
|
||||
return;
|
||||
|
||||
if (config.layer.type != 'image') {
|
||||
alertify.error('This layer must contain an image. Please convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
|
||||
this.mousedown_selection = JSON.parse(JSON.stringify(this.selection));
|
||||
|
||||
if (this.selection.width != null && this.selection.height != null
|
||||
&& mouse.x > this.selection.x
|
||||
&& mouse.x < this.selection.x + this.selection.width
|
||||
&& mouse.y > this.selection.y
|
||||
&& mouse.y < this.selection.y + this.selection.height
|
||||
&& layer.width == layer.width_original && layer.height == layer.height_original
|
||||
) {
|
||||
//move
|
||||
this.type = 'move';
|
||||
|
||||
if (this.tmpCanvas == null) {
|
||||
this.init_tmp_canvas();
|
||||
|
||||
//register tmp canvas for faster redraw
|
||||
config.layer.link_canvas = this.tmpCanvas;
|
||||
config.need_render = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//create new selection
|
||||
this.selection = {
|
||||
x: mouse.x,
|
||||
y: mouse.y,
|
||||
width: 0,
|
||||
height: 0,
|
||||
};
|
||||
this.type = 'create';
|
||||
this.selection_coords_from = {x: mouse.x, y: mouse.y};
|
||||
}
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (this.Base_selection.is_drag == false || mouse.is_drag == false)
|
||||
return;
|
||||
if (e.type == 'mousedown' && (mouse.click_valid == false) || config.layer.type != 'image') {
|
||||
return;
|
||||
}
|
||||
if (this.selection_coords_from === null) {
|
||||
return;
|
||||
}
|
||||
if (this.type == 'create') {
|
||||
//create new selection
|
||||
this.selection.width = mouse.x - mouse.click_x;
|
||||
this.selection.height = mouse.y - mouse.click_y;
|
||||
config.need_render = true;
|
||||
}
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
|
||||
if (!this.Base_selection.is_drag) {
|
||||
return;
|
||||
}
|
||||
if ((e.type == 'mousedown' && mouse.click_valid == false) || config.layer.type != 'image') {
|
||||
return;
|
||||
}
|
||||
if (this.type === 'move') {
|
||||
return; // Translate appears to not work at the moment
|
||||
}
|
||||
|
||||
var width = mouse.x - this.selection.x;
|
||||
var height = mouse.y - this.selection.y;
|
||||
|
||||
if (width == 0 || height == 0) {
|
||||
//cancel selection
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('clear_selection', 'Clear Selection', this.on_leave())
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.selection.width != null && this.selection.height != null) {
|
||||
//make sure coords not negative
|
||||
var details = this.selection;
|
||||
var x = details.x;
|
||||
var y = details.y;
|
||||
if (details.width < 0) {
|
||||
x = x + details.width;
|
||||
this.selection_coords_from.x = x;
|
||||
}
|
||||
if (details.height < 0) {
|
||||
y = y + details.height;
|
||||
this.selection_coords_from.y = y;
|
||||
}
|
||||
this.selection = {
|
||||
x: x,
|
||||
y: y,
|
||||
width: Math.abs(details.width),
|
||||
height: Math.abs(details.height),
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Set_selection_action(this.selection.x, this.selection.y, this.selection.width, this.selection.height, this.mousedown_selection)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
select_all() {
|
||||
if (config.layer.type != 'image') {
|
||||
alertify.error('This layer must contain an image. Please convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
let actions = [];
|
||||
|
||||
if (config.TOOL.name != this.name) {
|
||||
actions.push(
|
||||
new app.Actions.Activate_tool_action(this.name)
|
||||
);
|
||||
}
|
||||
actions.push(
|
||||
new app.Actions.Set_selection_action(0, 0, config.WIDTH, config.HEIGHT, this.selection)
|
||||
);
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('select_all', 'Select All', actions)
|
||||
);
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
//nothing
|
||||
}
|
||||
|
||||
save_translate() {
|
||||
if (this.tmpCanvas == null)
|
||||
return;
|
||||
|
||||
delete config.layer.link_canvas;
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('selection_tool', 'Selection Tool', [
|
||||
new app.Actions.Update_layer_image_action(this.tmpCanvas)
|
||||
])
|
||||
);
|
||||
|
||||
this.reset_tmp_canvas();
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
delete_selection() {
|
||||
var selection = this.selection;
|
||||
var layer = config.layer;
|
||||
|
||||
if (config.layer.type != 'image') {
|
||||
alertify.error('This layer must contain an image. Please convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (selection == null) {
|
||||
alertify.error('Nothing is selected.');
|
||||
return;
|
||||
}
|
||||
|
||||
this.init_tmp_canvas();
|
||||
|
||||
var mouse_x = selection.x - layer.x;
|
||||
var mouse_y = selection.y - layer.y;
|
||||
|
||||
//adapt to origin size
|
||||
mouse_x = this.adaptSize(mouse_x, 'width');
|
||||
mouse_y = this.adaptSize(mouse_y, 'height');
|
||||
selection.width = this.adaptSize(selection.width, 'width');
|
||||
selection.height = this.adaptSize(selection.height, 'height');
|
||||
|
||||
//do erase
|
||||
this.tmpCanvasCtx.clearRect(mouse_x, mouse_y, selection.width, selection.height);
|
||||
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('delete_selection', 'Delete Selection', [
|
||||
new app.Actions.Update_layer_image_action(this.tmpCanvas),
|
||||
new app.Actions.Reset_selection_action(this.selection)
|
||||
])
|
||||
);
|
||||
|
||||
this.reset_tmp_canvas();
|
||||
delete config.layer.link_canvas;
|
||||
this.reset_tmp_canvas();
|
||||
}
|
||||
|
||||
init_tmp_canvas() {
|
||||
this.tmpCanvas = document.createElement('canvas');
|
||||
this.tmpCanvasCtx = this.tmpCanvas.getContext("2d");
|
||||
this.tmpCanvas.width = config.layer.width_original;
|
||||
this.tmpCanvas.height = config.layer.height_original;
|
||||
this.tmpCanvasCtx.drawImage(config.layer.link, 0, 0);
|
||||
}
|
||||
|
||||
on_leave() {
|
||||
let actions = [
|
||||
new app.Actions.Reset_selection_action(this.selection)
|
||||
];
|
||||
delete config.layer.link_canvas;
|
||||
this.reset_tmp_canvas();
|
||||
return actions;
|
||||
}
|
||||
|
||||
clear_selection() {
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('clear_selection', 'Clear Selection', this.on_leave())
|
||||
);
|
||||
}
|
||||
|
||||
reset_tmp_canvas() {
|
||||
if (this.tmpCanvas == null)
|
||||
return;
|
||||
this.tmpCanvas.width = 1;
|
||||
this.tmpCanvas.height = 1;
|
||||
this.tmpCanvas = null;
|
||||
this.tmpCanvasCtx = null;
|
||||
}
|
||||
|
||||
}
|
||||
;
|
||||
export default Selection_class;
|
||||
@@ -0,0 +1,137 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import Dialog_class from './../libs/popup.js';
|
||||
import GUI_tools_class from './../core/gui/gui-tools.js';
|
||||
|
||||
var instance = null;
|
||||
|
||||
class Shape_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
|
||||
//singleton
|
||||
if (instance) {
|
||||
return instance;
|
||||
}
|
||||
instance = this;
|
||||
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.GUI_tools = new GUI_tools_class();
|
||||
this.POP = new Dialog_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'shape';
|
||||
this.layer = {};
|
||||
this.preview_width = 150;
|
||||
this.preview_height = 120;
|
||||
|
||||
this.set_events();
|
||||
}
|
||||
|
||||
set_events() {
|
||||
document.addEventListener('keydown', (event) => {
|
||||
var code = event.keyCode;
|
||||
if (this.Helper.is_input(event.target))
|
||||
return;
|
||||
|
||||
if (code == 72) {
|
||||
//H
|
||||
this.show_shapes();
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
load() {
|
||||
|
||||
}
|
||||
|
||||
on_activate() {
|
||||
this.show_shapes();
|
||||
}
|
||||
|
||||
async show_shapes(){
|
||||
var _this = this;
|
||||
var html = '';
|
||||
|
||||
var data = this.get_shapes();
|
||||
|
||||
for (var i in data) {
|
||||
html += '<div class="item">';
|
||||
html += ' <canvas id="c_' + data[i].key + '" width="' + this.preview_width + '" height="'
|
||||
+ this.preview_height + '" class="effectsPreview" data-key="'
|
||||
+ data[i].key + '"></canvas>';
|
||||
html += '<div class="preview-item-title">' + data[i].title + '</div>';
|
||||
html += '</div>';
|
||||
}
|
||||
for (var i = 0; i < 4; i++) {
|
||||
html += '<div class="item"></div>';
|
||||
}
|
||||
|
||||
var settings = {
|
||||
title: 'Shapes',
|
||||
className: 'wide',
|
||||
on_load: function (params, popup) {
|
||||
var node = document.createElement("div");
|
||||
node.classList.add('flex-container');
|
||||
node.innerHTML = html;
|
||||
popup.el.querySelector('.dialog_content').appendChild(node);
|
||||
//events
|
||||
var targets = popup.el.querySelectorAll('.item canvas');
|
||||
for (var i = 0; i < targets.length; i++) {
|
||||
targets[i].addEventListener('click', function (event) {
|
||||
//we have click
|
||||
_this.GUI_tools.activate_tool(this.dataset.key);
|
||||
_this.POP.hide();
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
this.POP.show(settings);
|
||||
|
||||
//sleep, lets wait till DOM is finished
|
||||
await new Promise(r => setTimeout(r, 10));
|
||||
|
||||
//draw demo thumbs
|
||||
for (var i in data) {
|
||||
var function_name = 'demo';
|
||||
var canvas = document.getElementById('c_'+data[i].key);
|
||||
var ctx = canvas.getContext("2d");
|
||||
|
||||
if(typeof data[i].object[function_name] == "undefined")
|
||||
continue;
|
||||
|
||||
data[i].object[function_name](ctx, 20, 20, this.preview_width - 40, this.preview_height - 40, null);
|
||||
}
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
|
||||
}
|
||||
|
||||
get_shapes(){
|
||||
var list = [];
|
||||
|
||||
for (var i in this.Base_gui.GUI_tools.tools_modules) {
|
||||
var object = this.Base_gui.GUI_tools.tools_modules[i];
|
||||
if (object.full_key.indexOf("shapes/") == -1 )
|
||||
continue;
|
||||
|
||||
list.push(object);
|
||||
}
|
||||
|
||||
list.sort(function(a, b) {
|
||||
var nameA = a.title.toUpperCase();
|
||||
var nameB = b.title.toUpperCase();
|
||||
if (nameA < nameB) return -1;
|
||||
if (nameA > nameB) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Shape_class;
|
||||
@@ -0,0 +1,212 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Arrow_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'arrow';
|
||||
this.layer = {};
|
||||
this.best_ratio = 1;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.mouse_click = {x: null, y: null};
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var mouse_x = mouse.x;
|
||||
var mouse_y = mouse.y;
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
|
||||
this.mouse_click.x = mouse_x;
|
||||
this.mouse_click.y = mouse_y;
|
||||
|
||||
//register new object - current layer is not ours or params changed
|
||||
this.layer = {
|
||||
type: this.name,
|
||||
params: this.clone(this.getParams()),
|
||||
status: 'draft',
|
||||
render_function: [this.name, 'render'],
|
||||
x: Math.round(mouse_x),
|
||||
y: Math.round(mouse_y),
|
||||
rotate: null,
|
||||
is_vector: true,
|
||||
color: config.COLOR
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('new_line_layer', 'New Line Layer', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var mouse_x = Math.round(mouse.x);
|
||||
var mouse_y = Math.round(mouse.y);
|
||||
var click_x = Math.round(this.mouse_click.x);
|
||||
var click_y = Math.round(this.mouse_click.y);
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y, config.layer.id);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
|
||||
var width = mouse_x - this.layer.x;
|
||||
var height = mouse_y - this.layer.y;
|
||||
if (e.ctrlKey == true || e.metaKey) {
|
||||
//one direction only
|
||||
if (Math.abs(width) < Math.abs(height))
|
||||
width = 0;
|
||||
else
|
||||
height = 0;
|
||||
}
|
||||
|
||||
//more data
|
||||
config.layer.width = width;
|
||||
config.layer.height = height;
|
||||
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false) {
|
||||
config.layer.status = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var mouse_x = Math.round(mouse.x);
|
||||
var mouse_y = Math.round(mouse.y);
|
||||
var click_x = Math.round(this.mouse_click.x);
|
||||
var click_y = Math.round(this.mouse_click.y);
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y, config.layer.id);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
|
||||
var width = mouse_x - this.layer.x;
|
||||
var height = mouse_y - this.layer.y;
|
||||
|
||||
if (width == 0 && height == 0) {
|
||||
//same coordinates - cancel
|
||||
app.State.scrap_last_action();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.ctrlKey == true || e.metaKey) {
|
||||
//one direction only
|
||||
if (Math.abs(width) < Math.abs(height))
|
||||
width = 0;
|
||||
else
|
||||
height = 0;
|
||||
}
|
||||
|
||||
//more data
|
||||
app.State.do_action(
|
||||
new app.Actions.Update_layer_action(config.layer.id, {
|
||||
width,
|
||||
height,
|
||||
status: null
|
||||
}),
|
||||
{ merge_with_history: 'new_line_layer' }
|
||||
);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
ctx.fillStyle = '#aaa';
|
||||
ctx.strokeStyle = '#555';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
this.arrow(ctx, x, y, x + width, y + height, 15);
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
if (layer.width == 0 && layer.height == 0)
|
||||
return;
|
||||
|
||||
var params = layer.params;
|
||||
|
||||
//set styles
|
||||
ctx.fillStyle = layer.color;
|
||||
ctx.strokeStyle = layer.color;
|
||||
ctx.lineWidth = params.size;
|
||||
ctx.lineCap = 'round';
|
||||
|
||||
var width = layer.x + layer.width;
|
||||
var height = layer.y + layer.height;
|
||||
|
||||
var headlen = params.size * 7;
|
||||
if (headlen < 15)
|
||||
headlen = 15;
|
||||
this.arrow(ctx,
|
||||
layer.x, layer.y,
|
||||
width, height,
|
||||
headlen);
|
||||
}
|
||||
|
||||
arrow(ctx, fromx, fromy, tox, toy, headlen) {
|
||||
var dx = tox - fromx;
|
||||
var dy = toy - fromy;
|
||||
var angle = Math.atan2(dy, dx);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(fromx, fromy);
|
||||
ctx.lineTo(tox, toy);
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(tox - headlen * Math.cos(angle - Math.PI / 6), toy - headlen * Math.sin(angle - Math.PI / 6));
|
||||
ctx.lineTo(tox, toy);
|
||||
ctx.lineTo(tox - headlen * Math.cos(angle + Math.PI / 6), toy - headlen * Math.sin(angle + Math.PI / 6));
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Arrow_class;
|
||||
@@ -0,0 +1,482 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
import Helper_class from './../../libs/helpers.js';
|
||||
|
||||
class Bezier_Curve_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.Helper = new Helper_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'bezier_curve';
|
||||
this.layer = {};
|
||||
this.best_ratio = 1;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.params_hash = false;
|
||||
this.selected_obj_positions = {};
|
||||
this.mouse_lock = null;
|
||||
this.selected_object_drag_type = null;
|
||||
this.old_data = null;
|
||||
|
||||
this.events();
|
||||
}
|
||||
|
||||
load() {
|
||||
var _this = this;
|
||||
this.default_events();
|
||||
document.addEventListener('keydown', function (event) {
|
||||
if (config.TOOL.name != _this.name) {
|
||||
return;
|
||||
}
|
||||
var code = event.code;
|
||||
if (code == "Escape") {
|
||||
//escape
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* events for handling helping lines only
|
||||
*/
|
||||
events() {
|
||||
document.addEventListener('mousedown', (e) => {
|
||||
this.selected_object_actions(e);
|
||||
});
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
this.selected_object_actions(e);
|
||||
});
|
||||
document.addEventListener('mouseup', (e) => {
|
||||
this.selected_object_actions(e);
|
||||
});
|
||||
|
||||
// touch
|
||||
document.addEventListener('touchstart', (event) => {
|
||||
this.selected_object_actions(event);
|
||||
});
|
||||
document.addEventListener('touchmove', (event) => {
|
||||
this.selected_object_actions(event);
|
||||
}, {passive: false});
|
||||
document.addEventListener('touchend', (event) => {
|
||||
this.selected_object_actions(event);
|
||||
});
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var params_hash = this.get_params_hash();
|
||||
|
||||
var mouse_x = mouse.x;
|
||||
var mouse_y = mouse.y;
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
|
||||
const data_clone = JSON.parse(JSON.stringify(config.layer.data));
|
||||
|
||||
if (config.layer.type != this.name || params_hash != this.params_hash
|
||||
|| (data_clone != null && data_clone.cp2.x !== null)) {
|
||||
//register new object - current layer is not ours or params changed
|
||||
this.layer = {
|
||||
type: this.name,
|
||||
data: {
|
||||
start: {x: mouse_x, y: mouse_y},
|
||||
cp1: {x: null, y: null},
|
||||
cp2: {x: null, y: null},
|
||||
end: {x: null, y: null}
|
||||
},
|
||||
params: this.clone(this.getParams()),
|
||||
render_function: [this.name, 'render'],
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: null,
|
||||
height: null,
|
||||
hide_selection_if_active: true,
|
||||
rotate: null,
|
||||
is_vector: true,
|
||||
color: config.COLOR,
|
||||
status: 'draft',
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('new_bezier_layer', 'New Bezier Layer', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
this.params_hash = params_hash;
|
||||
}
|
||||
else {
|
||||
//add more data
|
||||
config.layer.data.end.x = mouse_x;
|
||||
config.layer.data.end.y = mouse_y;
|
||||
}
|
||||
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var mouse_x = Math.round(mouse.x);
|
||||
var mouse_y = Math.round(mouse.y);
|
||||
var click_x = Math.round(mouse.click_x);
|
||||
var click_y = Math.round(mouse.click_y);
|
||||
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (mouse.is_drag == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.ctrlKey == true || e.metaKey) {
|
||||
//one direction only
|
||||
var width = mouse_x - click_x;
|
||||
var height = mouse_y - click_y;
|
||||
|
||||
if (Math.abs(width) > Math.abs(height))
|
||||
mouse_y = click_y;
|
||||
else
|
||||
mouse_x = click_x;
|
||||
}
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y, config.layer.id);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
|
||||
//add more data
|
||||
if(config.layer.data.end.x === null){
|
||||
//still first step
|
||||
config.layer.data.cp1.x = mouse_x;
|
||||
config.layer.data.cp1.y = mouse_y;
|
||||
}
|
||||
else{
|
||||
config.layer.data.cp2.x = mouse_x;
|
||||
config.layer.data.cp2.y = mouse_y;
|
||||
}
|
||||
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var mouse_x = Math.round(mouse.x);
|
||||
var mouse_y = Math.round(mouse.y);
|
||||
var click_x = Math.round(mouse.click_x);
|
||||
var click_y = Math.round(mouse.click_y);
|
||||
|
||||
if (e.ctrlKey == true || e.metaKey) {
|
||||
//one direction only
|
||||
var width = mouse_x - click_x;
|
||||
var height = mouse_y - click_y;
|
||||
|
||||
if (Math.abs(width) > Math.abs(height))
|
||||
mouse_y = click_y;
|
||||
else
|
||||
mouse_x = click_x;
|
||||
}
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y, config.layer.id);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
|
||||
//add more data
|
||||
if(config.layer.data.end.x === null){
|
||||
//still first step
|
||||
config.layer.data.cp1.x = mouse_x;
|
||||
config.layer.data.cp1.y = mouse_y;
|
||||
}
|
||||
else{
|
||||
config.layer.data.cp2.x = mouse_x;
|
||||
config.layer.data.cp2.y = mouse_y;
|
||||
config.layer.status = null;
|
||||
}
|
||||
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
|
||||
//also draw control lines
|
||||
if(config.layer.type == this.name){
|
||||
var bezier = config.layer.data;
|
||||
this.selected_obj_positions = {};
|
||||
|
||||
var x = config.layer.x;
|
||||
var y = config.layer.y;
|
||||
|
||||
//draw corners
|
||||
if (bezier.start.x != null) {
|
||||
this.Helper.draw_special_line(
|
||||
this.ctx,
|
||||
x + bezier.start.x,
|
||||
y + bezier.start.y,
|
||||
x + bezier.cp1.x,
|
||||
y + bezier.cp1.y
|
||||
);
|
||||
if(config.TOOL.name == 'select') {
|
||||
this.selected_obj_positions.cp1_start = this.Helper.draw_control_point(
|
||||
this.ctx,
|
||||
x + bezier.start.x,
|
||||
y + bezier.start.y
|
||||
);
|
||||
this.selected_obj_positions.cp1_end = this.Helper.draw_control_point(
|
||||
this.ctx,
|
||||
x + bezier.cp1.x,
|
||||
y + bezier.cp1.y
|
||||
);
|
||||
}
|
||||
}
|
||||
if (bezier.end.x != null && bezier.cp2.x != null) {
|
||||
this.Helper.draw_special_line(
|
||||
this.ctx,
|
||||
x + bezier.end.x,
|
||||
y + bezier.end.y,
|
||||
x + bezier.cp2.x,
|
||||
y + bezier.cp2.y
|
||||
);
|
||||
if(config.TOOL.name == 'select') {
|
||||
this.selected_obj_positions.cp2_start = this.Helper.draw_control_point(
|
||||
this.ctx,
|
||||
x + bezier.end.x,
|
||||
y + bezier.end.y
|
||||
);
|
||||
this.selected_obj_positions.cp2_end = this.Helper.draw_control_point(
|
||||
this.ctx,
|
||||
x + bezier.cp2.x,
|
||||
y + bezier.cp2.y
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
select(ctx) {
|
||||
this.render_overlay(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
var data = {
|
||||
start: {x: x, y: y},
|
||||
cp1: {x: x + width, y: y},
|
||||
cp2: {x: x, y: y + height},
|
||||
end: {x: x + width, y: y + height}
|
||||
};
|
||||
|
||||
this.draw_bezier(ctx, 0, 0, data, 2, '#555');
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
this.draw_bezier(ctx, layer.x, layer.y, layer.data, params.size, layer.color);
|
||||
}
|
||||
|
||||
draw_bezier(ctx, x, y, data, lineWidth, color) {
|
||||
if(data.end.x == null || data.cp2.x == null){
|
||||
return;
|
||||
}
|
||||
|
||||
//set styles
|
||||
ctx.fillStyle = color;
|
||||
ctx.strokeStyle = color;
|
||||
ctx.lineWidth = lineWidth;
|
||||
ctx.lineCap = 'round';
|
||||
|
||||
//draw bezier
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + data.start.x, y + data.start.y);
|
||||
ctx.bezierCurveTo(
|
||||
x + data.cp1.x, y + data.cp1.y,
|
||||
x + data.cp2.x, y + data.cp2.y,
|
||||
x + data.end.x, y + data.end.y
|
||||
);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
selected_object_actions(e) {
|
||||
if(config.TOOL.name != 'select' || config.layer.type != this.name || config.layer.status == 'draft'){
|
||||
return;
|
||||
}
|
||||
|
||||
var ctx = this.Base_layers.ctx;
|
||||
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var mouse_x = Math.round(mouse.x);
|
||||
var mouse_y = Math.round(mouse.y);
|
||||
var click_x = Math.round(mouse.click_x);
|
||||
var click_y = Math.round(mouse.click_y);
|
||||
|
||||
const mainWrapper = document.getElementById('main_wrapper');
|
||||
|
||||
//simplify checks
|
||||
var event_type = e.type;
|
||||
if(event_type == 'touchstart') event_type = 'mousedown';
|
||||
if(event_type == 'touchmove') event_type = 'mousemove';
|
||||
if(event_type == 'touchend') event_type = 'mouseup';
|
||||
|
||||
if (event_type == 'mouseup') {
|
||||
//reset
|
||||
config.mouse_lock = null;
|
||||
if (mainWrapper.style.cursor != 'default') {
|
||||
mainWrapper.style.cursor = 'default';
|
||||
}
|
||||
}
|
||||
|
||||
if (event_type == 'mousedown' && config.mouse.valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event_type == 'mousemove' && this.mouse_lock == 'move_point' && mouse.is_drag) {
|
||||
mainWrapper.style.cursor = "move";
|
||||
|
||||
if (e.buttons == 1 || typeof e.buttons == "undefined") {
|
||||
var type = this.selected_object_drag_type;
|
||||
var bezier = config.layer.data;
|
||||
|
||||
// Do transformations
|
||||
var dx = Math.round(mouse.x - mouse.click_x) - config.layer.x;
|
||||
var dy = Math.round(mouse.y - mouse.click_y) - config.layer.y;
|
||||
|
||||
// Set values
|
||||
if(type == 'cp1_start') {
|
||||
bezier.start.x = mouse.click_x + dx;
|
||||
bezier.start.y = mouse.click_y + dy;
|
||||
|
||||
if (e.ctrlKey == true || e.metaKey) {
|
||||
//one direction only
|
||||
var width = mouse_x - bezier.cp1.x;
|
||||
var height = mouse_y - bezier.cp1.y;
|
||||
if (Math.abs(width) > Math.abs(height))
|
||||
bezier.start.y = bezier.cp1.y;
|
||||
else
|
||||
bezier.start.x = bezier.cp1.x;
|
||||
}
|
||||
}
|
||||
else if(type == 'cp1_end') {
|
||||
bezier.cp1.x = mouse.click_x + dx;
|
||||
bezier.cp1.y = mouse.click_y + dy;
|
||||
|
||||
if (e.ctrlKey == true || e.metaKey) {
|
||||
//one direction only
|
||||
var width = mouse_x -bezier.start.x;
|
||||
var height = mouse_y - bezier.start.y;
|
||||
if (Math.abs(width) > Math.abs(height))
|
||||
bezier.cp1.y = bezier.start.y;
|
||||
else
|
||||
bezier.cp1.x = bezier.start.x;
|
||||
}
|
||||
}
|
||||
else if(type == 'cp2_start') {
|
||||
bezier.end.x = mouse.click_x+ dx;
|
||||
bezier.end.y = mouse.click_y + dy;
|
||||
|
||||
if (e.ctrlKey == true || e.metaKey) {
|
||||
//one direction only
|
||||
var width = mouse_x - bezier.cp2.x;
|
||||
var height = mouse_y - bezier.cp2.y;
|
||||
if (Math.abs(width) > Math.abs(height))
|
||||
bezier.end.y = bezier.cp2.y;
|
||||
else
|
||||
bezier.end.x = bezier.cp2.x;
|
||||
}
|
||||
}
|
||||
else if(type == 'cp2_end') {
|
||||
bezier.cp2.x = mouse.click_x + dx;
|
||||
bezier.cp2.y = mouse.click_y + dy;
|
||||
|
||||
if (e.ctrlKey == true || e.metaKey) {
|
||||
//one direction only
|
||||
var width = mouse_x - bezier.end.x;
|
||||
var height = mouse_y - bezier.end.y;
|
||||
if (Math.abs(width) > Math.abs(height))
|
||||
bezier.cp2.y = bezier.end.y;
|
||||
else
|
||||
bezier.cp2.x = bezier.end.x;
|
||||
}
|
||||
}
|
||||
|
||||
config.need_render = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (event_type == 'mouseup' && this.mouse_lock == 'move_point') {
|
||||
this.mouse_lock = null;
|
||||
var type = this.selected_object_drag_type;
|
||||
var bezier = config.layer.data;
|
||||
|
||||
//reset sate
|
||||
config.layer.data = this.old_data;
|
||||
|
||||
//save state
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('change_layer_details', 'Change Layer Details', [
|
||||
new app.Actions.Update_layer_action(config.layer.id, {
|
||||
data: bezier,
|
||||
})
|
||||
])
|
||||
);
|
||||
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
if (!mouse.is_drag && ['mousedown', 'mouseup'].includes(event_type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.mouse_lock) {
|
||||
for (let current_drag_type in this.selected_obj_positions) {
|
||||
const position = this.selected_obj_positions[current_drag_type];
|
||||
if (position && this.ctx.isPointInPath(position, mouse.x, mouse.y)) {
|
||||
// match
|
||||
if (event_type == 'mousedown') {
|
||||
if (e.buttons == 1 || typeof e.buttons == "undefined") {
|
||||
this.mouse_lock = 'move_point';
|
||||
this.selected_object_drag_type = current_drag_type;
|
||||
}
|
||||
config.mouse_lock = true;
|
||||
this.old_data = JSON.parse(JSON.stringify(config.layer.data));
|
||||
}
|
||||
if (event_type == 'mousemove') {
|
||||
mainWrapper.style.cursor = 'move';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Bezier_Curve_class;
|
||||
@@ -0,0 +1,99 @@
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Callout_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'callout';
|
||||
this.layer = {};
|
||||
this.best_ratio = 1.3;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
ctx.fillStyle = '#aaa';
|
||||
ctx.strokeStyle = '#555';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
var width_all = width + x * 2;
|
||||
width = height * this.best_ratio;
|
||||
x = (width_all - width) / 2;
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(x + width / 2, y + height / 2);
|
||||
this.draw_shape(ctx, -width / 2, -height / 2, width, height);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
var fill = params.fill;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
draw_shape(ctx, x, y, width, height, coords) {
|
||||
ctx.lineJoin = "round";
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.moveTo(x, y);
|
||||
ctx.lineTo(x + width, y);
|
||||
ctx.lineTo(x + width, y + height * 0.6);
|
||||
|
||||
ctx.lineTo(x + width / 2 + width / 10, y + height * 0.6);
|
||||
ctx.lineTo(x + width / 8, y + height);
|
||||
ctx.lineTo(x + width / 2 - width / 10, y + height * 0.6);
|
||||
|
||||
ctx.lineTo(x, y + height * 0.6);
|
||||
ctx.lineTo(x, y);
|
||||
|
||||
ctx.closePath();
|
||||
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Callout_class;
|
||||
@@ -0,0 +1,82 @@
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Cog_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'cog';
|
||||
this.layer = {};
|
||||
this.best_ratio = 1;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
ctx.fillStyle = '#777';
|
||||
ctx.lineWidth = 1;
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(x + width / 2, y + height / 2);
|
||||
this.draw_shape(ctx, -width / 2, -height / 2, width, height);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = 1;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
draw_shape(ctx, x, y, width, height, coords) {
|
||||
ctx.lineJoin = "round";
|
||||
ctx.beginPath();
|
||||
|
||||
//better dont do this, there will be issues with border size
|
||||
ctx.scale(width/512, height/500);
|
||||
ctx.translate(-256, -252);
|
||||
|
||||
//SVG path
|
||||
var p = new Path2D("M190.883 502.932c-4.517 0-9.082-.991-13.368-3.055l-63.216-30.438c-13.348-6.426-20.255-21.479-16.422-35.794 3.684-13.757 8.609-29.81 14.376-46.879a195.425 195.425 0 0 1-15.733-19.711c-17.979 1.837-34.736 3.07-48.937 3.594-14.773.515-27.899-9.536-31.195-23.975L.776 278.273c-3.297-14.444 4.167-29.229 17.748-35.156 13.056-5.697 28.669-11.851 45.59-17.977a193.78 193.78 0 0 1 5.601-24.614c-12.655-12.922-24.061-25.246-33.297-35.989-9.643-11.217-9.939-27.761-.706-39.339l43.744-54.854c9.239-11.584 25.453-14.963 38.552-8.043 12.556 6.636 27.096 15.004 42.466 24.433a194.25 194.25 0 0 1 22.746-10.969c2.209-17.923 4.735-34.522 7.381-48.468 2.757-14.532 15.506-25.079 30.315-25.079h70.161c14.815 0 27.569 10.567 30.325 25.126 2.646 13.983 5.17 30.564 7.377 48.422a193.854 193.854 0 0 1 22.75 10.971c15.42-9.466 29.975-17.843 42.506-24.458 13.079-6.901 29.275-3.512 38.509 8.066l43.743 54.855c9.237 11.582 8.928 28.142-.738 39.374-9.254 10.756-20.646 23.066-33.263 35.957a193.79 193.79 0 0 1 5.601 24.62c16.986 6.145 32.615 12.304 45.634 17.992h.001c13.553 5.923 20.997 20.699 17.701 35.137l-15.615 68.4c-3.299 14.446-16.455 24.532-31.247 23.972-14.229-.531-30.97-1.762-48.889-3.588a195.251 195.251 0 0 1-15.728 19.703c5.791 17.122 10.723 33.189 14.394 46.921 3.819 14.291-3.093 29.324-16.436 35.748l-63.214 30.438c-13.351 6.428-29.426 2.438-38.224-9.484-8.455-11.455-17.931-25.313-27.679-40.466-8.425.548-16.745.548-25.176 0-9.772 15.201-19.257 29.075-27.702 40.508-5.964 8.075-15.283 12.499-24.824 12.5zm-61.851-61.915l61.516 29.619c15.437-20.988 29.097-42.937 36.43-54.579 26.665 3.104 31.829 3.053 58.035.001 6.932 10.997 20.8 33.291 36.445 54.576l61.515-29.619c-6.794-25.207-15.471-49.669-19.957-62.54 19.028-18.834 22.066-22.637 36.219-45.367 13.048 1.451 39.007 4.495 65.388 5.533l15.195-66.562c-24.034-10.441-48.695-18.946-61.337-23.387-2.824-26.58-3.888-31.341-12.882-56.619 9.27-9.299 27.886-27.753 45.083-47.657l-42.566-53.381c-22.622 12.001-44 25.528-56.513 33.37-22.495-14.328-26.889-16.481-52.31-25.228-1.474-12.904-4.292-38.972-9.156-64.958H221.86c-4.53 24.145-7.144 47.395-9.144 64.955-25.185 8.667-29.587 10.755-52.309 25.223-11.055-6.923-33.256-21.009-56.521-33.362l-42.568 53.379c16.896 19.57 35.133 37.669 45.088 47.647-8.943 25.131-10.043 29.878-12.885 56.613-12.366 4.348-37.104 12.879-61.339 23.397l15.192 66.562c25.642-.998 50.721-3.907 65.381-5.542 14.147 22.727 17.192 26.54 36.221 45.377-4.265 12.257-13.059 37.034-19.944 62.549zm351.667-168.554l.009.004-.009-.004zM256 347.486c-50.446 0-91.486-41.041-91.486-91.486s41.041-91.486 91.486-91.486c50.445 0 91.486 41.041 91.486 91.486S306.445 347.486 256 347.486zm0-150.972c-32.801 0-59.486 26.686-59.486 59.486S223.2 315.486 256 315.486 315.486 288.8 315.486 256 288.801 196.514 256 196.514z");
|
||||
|
||||
ctx.closePath();
|
||||
ctx.fill(p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Cog_class;
|
||||
@@ -0,0 +1,100 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Cylinder_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'cylinder';
|
||||
this.layer = {};
|
||||
this.best_ratio = 0.7;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
ctx.fillStyle = '#aaa';
|
||||
ctx.strokeStyle = '#555';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
var width_all = width + x * 2;
|
||||
width = height * this.best_ratio;
|
||||
x = (width_all - width) / 2;
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(x + width / 2, y + height / 2);
|
||||
this.draw_shape(ctx, -width / 2, -height / 2, width, height);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
var fill = params.fill;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
draw_shape(ctx, x, y, width, height, coords) {
|
||||
ctx.lineJoin = "round";
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.scale(1, 1.20);
|
||||
ctx.translate(-width / 2, -height / 2);
|
||||
|
||||
var dh = height/3;
|
||||
|
||||
ctx.moveTo(0, dh);
|
||||
ctx.bezierCurveTo(0,dh+dh, width,dh+dh, width,dh);
|
||||
ctx.bezierCurveTo(width,dh-dh, 0,dh-dh, 0,dh);
|
||||
ctx.lineTo(0, height-dh);
|
||||
ctx.bezierCurveTo(0,height-dh+dh, width,height-dh+dh, width,height-dh);
|
||||
ctx.lineTo(width, dh);
|
||||
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Cylinder_class;
|
||||
@@ -0,0 +1,262 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Ellipse_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'ellipse';
|
||||
this.layer = {};
|
||||
this.best_ratio = 1;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.mouse_click = {x: null, y: null};
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.click_valid == false)
|
||||
return;
|
||||
|
||||
var mouse_x = mouse.x;
|
||||
var mouse_y = mouse.y;
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
|
||||
this.mouse_click.x = mouse_x;
|
||||
this.mouse_click.y = mouse_y;
|
||||
|
||||
//register new object - current layer is not ours or params changed
|
||||
this.layer = {
|
||||
type: this.name,
|
||||
params: this.clone(this.getParams()),
|
||||
status: 'draft',
|
||||
render_function: [this.name, 'render'],
|
||||
x: mouse_x,
|
||||
y: mouse_y,
|
||||
color: null,
|
||||
is_vector: true,
|
||||
};
|
||||
if (params.circle == true) {
|
||||
//disable rotate
|
||||
this.layer.rotate = null;
|
||||
}
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('new_ellipse_layer', 'New Ellipse Layer', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var mouse_x = Math.round(mouse.x);
|
||||
var mouse_y = Math.round(mouse.y);
|
||||
var click_x = Math.round(this.mouse_click.x);
|
||||
var click_y = Math.round(this.mouse_click.y);
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y, config.layer.id);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
|
||||
var x = Math.min(mouse_x, click_x);
|
||||
var y = Math.min(mouse_y, click_y);
|
||||
var width = Math.abs(mouse_x - click_x);
|
||||
var height = Math.abs(mouse_y - click_y);
|
||||
|
||||
if (params.circle == true || e.ctrlKey == true || e.metaKey) {
|
||||
if (width < height) {
|
||||
width = height;
|
||||
}
|
||||
else {
|
||||
height = width;
|
||||
}
|
||||
if (mouse_x < click_x) {
|
||||
x = click_x - width;
|
||||
}
|
||||
if (mouse_y < click_y) {
|
||||
y = click_y - height;
|
||||
}
|
||||
}
|
||||
|
||||
//more data
|
||||
config.layer.x = x;
|
||||
config.layer.y = y;
|
||||
config.layer.width = width;
|
||||
config.layer.height = height;
|
||||
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
|
||||
if (mouse.click_valid == false) {
|
||||
config.layer.status = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var mouse_x = Math.round(mouse.x);
|
||||
var mouse_y = Math.round(mouse.y);
|
||||
var click_x = Math.round(this.mouse_click.x);
|
||||
var click_y = Math.round(this.mouse_click.y);
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y, config.layer.id);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
|
||||
var x = Math.min(mouse_x, click_x);
|
||||
var y = Math.min(mouse_y, click_y);
|
||||
var width = Math.abs(mouse_x - click_x);
|
||||
var height = Math.abs(mouse_y - click_y);
|
||||
|
||||
if (params.circle == true || e.ctrlKey == true || e.metaKey) {
|
||||
if (width < height) {
|
||||
width = height;
|
||||
}
|
||||
else {
|
||||
height = width;
|
||||
}
|
||||
if (mouse_x < click_x) {
|
||||
x = click_x - width;
|
||||
}
|
||||
if (mouse_y < click_y) {
|
||||
y = click_y - height;
|
||||
}
|
||||
}
|
||||
|
||||
if (width == 0 && height == 0) {
|
||||
//same coordinates - cancel
|
||||
app.State.scrap_last_action();
|
||||
return;
|
||||
}
|
||||
|
||||
//more data
|
||||
app.State.do_action(
|
||||
new app.Actions.Update_layer_action(config.layer.id, {
|
||||
x: x,
|
||||
y: y,
|
||||
width: width,
|
||||
height: height,
|
||||
status: null
|
||||
}),
|
||||
{ merge_with_history: 'new_ellipse_layer' }
|
||||
);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
x = parseInt(x);
|
||||
y = parseInt(y);
|
||||
width = parseInt(width);
|
||||
height = parseInt(height);
|
||||
|
||||
ctx.fillStyle = '#aaa';
|
||||
ctx.strokeStyle = '#555';
|
||||
ctx.lineWidth = 3;
|
||||
|
||||
this.ellipse(
|
||||
ctx,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
true,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
var dist_x = layer.width;
|
||||
var dist_y = layer.height;
|
||||
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.ellipse(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height, params.border, params.fill);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
ellipse(ctx, x, y, w, h, stroke, fill) {
|
||||
var kappa = .5522848,
|
||||
ox = (w / 2) * kappa, // control point offset horizontal
|
||||
oy = (h / 2) * kappa, // control point offset vertical
|
||||
xe = x + w, // x-end
|
||||
ye = y + h, // y-end
|
||||
xm = x + w / 2, // x-middle
|
||||
ym = y + h / 2; // y-middle
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, ym);
|
||||
ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
|
||||
ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
|
||||
ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
|
||||
ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
|
||||
ctx.closePath();
|
||||
if ( stroke == true)
|
||||
ctx.stroke();
|
||||
if (fill == true)
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Ellipse_class;
|
||||
@@ -0,0 +1,106 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Heart_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'heart';
|
||||
this.layer = {};
|
||||
this.best_ratio = 1.2;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
ctx.fillStyle = '#aaa';
|
||||
ctx.strokeStyle = '#555';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(x + width / 2, y + height / 2);
|
||||
this.draw_shape(ctx, -width / 2, -height / 2, width, height);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
var fill = params.fill;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
draw_shape(ctx, x, y, width, height, coords) {
|
||||
ctx.lineJoin = "round";
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.scale(1.071, 1.1);
|
||||
ctx.translate(-width / 2, -height / 1.85);
|
||||
|
||||
ctx.moveTo(width/2, height/5);
|
||||
ctx.bezierCurveTo(5 * width / 14, 0,
|
||||
0, height / 15,
|
||||
width / 28, 2 * height / 5);
|
||||
|
||||
ctx.bezierCurveTo(width / 14, 2 * height / 3,
|
||||
3 * width / 7, 5 * height / 6,
|
||||
width / 2, height);
|
||||
|
||||
ctx.bezierCurveTo(4 * width / 7, 5 * height / 6,
|
||||
13 * width / 14, 2 * height / 3,
|
||||
27 * width / 28, 2 * height / 5);
|
||||
|
||||
ctx.bezierCurveTo(width, height / 15,
|
||||
9 * width / 14, 0,
|
||||
width / 2, height / 5);
|
||||
|
||||
ctx.closePath();
|
||||
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Heart_class;
|
||||
@@ -0,0 +1,114 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Hexagon_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'hexagon';
|
||||
this.layer = {};
|
||||
this.best_ratio = 1.1547005;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.coords = [
|
||||
[75, 6.698729810778069],
|
||||
[100, 50],
|
||||
[75, 93.30127018922192],
|
||||
[24.99999999999999, 93.30127018922192],
|
||||
[0, 50.00000000000001],
|
||||
[24.99999999999998, 6.698729810778076],
|
||||
[75, 6.698729810778069],
|
||||
[75, 6.698729810778069],
|
||||
];
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
ctx.fillStyle = '#aaa';
|
||||
ctx.strokeStyle = '#555';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
this.draw_shape(ctx, x, y - 5, width, height, this.coords);
|
||||
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
var fill = params.fill;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height, this.coords);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
draw_shape(ctx, x, y, width, height, coords) {
|
||||
ctx.lineJoin = "round";
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.scale(1, this.best_ratio);
|
||||
|
||||
for(var i in coords){
|
||||
if(coords[i] === null){
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
continue;
|
||||
}
|
||||
|
||||
//coords in 100x100 box
|
||||
var pos_x = x + coords[i][0] * width / 100;
|
||||
var pos_y = y + coords[i][1] * height / 100;
|
||||
|
||||
if(i == '0')
|
||||
ctx.moveTo(pos_x, pos_y);
|
||||
else
|
||||
ctx.lineTo(pos_x, pos_y);
|
||||
}
|
||||
ctx.closePath();
|
||||
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Hexagon_class;
|
||||
@@ -0,0 +1,110 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Human_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'human';
|
||||
this.layer = {};
|
||||
this.best_ratio = 0.35;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
ctx.fillStyle = '#aaa';
|
||||
ctx.strokeStyle = '#555';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
var width_all = width + x * 2;
|
||||
width = height * this.best_ratio;
|
||||
x = (width_all - width) / 2;
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(x + width / 2, y + height / 2);
|
||||
this.draw_shape(ctx, -width / 2, -height / 2, width, height);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
var fill = params.fill;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
draw_shape(ctx, x, y, width, height) {
|
||||
ctx.lineJoin = "round";
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.translate(-width / 2, -height / 2);
|
||||
|
||||
var radius = Math.sqrt(width * height) * 0.28;
|
||||
var neck_height = height * 0.07;
|
||||
var leg_height = height * 0.3;
|
||||
if(radius * 2 + neck_height + leg_height > height){
|
||||
radius = (height - leg_height - neck_height) / 2;
|
||||
}
|
||||
|
||||
ctx.arc(width / 2, radius, radius, 0, 2 * Math.PI);
|
||||
//body
|
||||
ctx.moveTo(width / 2, radius * 2);
|
||||
ctx.lineTo(width / 2, height - leg_height);
|
||||
//arm
|
||||
ctx.moveTo(0, radius*2 + neck_height);
|
||||
ctx.lineTo(width, radius*2 + neck_height);
|
||||
//left leg
|
||||
ctx.moveTo(width / 2, height - leg_height);
|
||||
ctx.lineTo(0, height);
|
||||
//right leg
|
||||
ctx.moveTo(width / 2, height - leg_height);
|
||||
ctx.lineTo(width, height);
|
||||
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Human_class;
|
||||
@@ -0,0 +1,195 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Line_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'line';
|
||||
this.layer = {};
|
||||
this.best_ratio = 1;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.mouse_click = {x: null, y: null};
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false)
|
||||
return;
|
||||
|
||||
var mouse_x = mouse.x;
|
||||
var mouse_y = mouse.y;
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
|
||||
this.mouse_click.x = mouse_x;
|
||||
this.mouse_click.y = mouse_y;
|
||||
|
||||
//register new object - current layer is not ours or params changed
|
||||
this.layer = {
|
||||
type: this.name,
|
||||
params: this.clone(this.getParams()),
|
||||
status: 'draft',
|
||||
render_function: [this.name, 'render'],
|
||||
x: mouse_x,
|
||||
y: mouse_y,
|
||||
rotate: null,
|
||||
is_vector: true,
|
||||
color: config.COLOR
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('new_line_layer', 'New Line Layer', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var mouse_x = Math.round(mouse.x);
|
||||
var mouse_y = Math.round(mouse.y);
|
||||
var click_x = Math.round(this.mouse_click.x);
|
||||
var click_y = Math.round(this.mouse_click.y);
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y, config.layer.id);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
|
||||
var width = mouse_x - this.layer.x;
|
||||
var height = mouse_y - this.layer.y;
|
||||
if (e.ctrlKey == true || e.metaKey) {
|
||||
//one direction only
|
||||
if (Math.abs(width) < Math.abs(height))
|
||||
width = 0;
|
||||
else
|
||||
height = 0;
|
||||
}
|
||||
|
||||
//more data
|
||||
config.layer.width = width;
|
||||
config.layer.height = height;
|
||||
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false) {
|
||||
config.layer.status = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var mouse_x = Math.round(mouse.x);
|
||||
var mouse_y = Math.round(mouse.y);
|
||||
var click_x = Math.round(this.mouse_click.x);
|
||||
var click_y = Math.round(this.mouse_click.y);
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y, config.layer.id);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
|
||||
|
||||
var width = mouse_x - this.layer.x;
|
||||
var height = mouse_y - this.layer.y;
|
||||
|
||||
if (width == 0 && height == 0) {
|
||||
//same coordinates - cancel
|
||||
app.State.scrap_last_action();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.ctrlKey == true || e.metaKey) {
|
||||
//one direction only
|
||||
if (Math.abs(width) < Math.abs(height))
|
||||
width = 0;
|
||||
else
|
||||
height = 0;
|
||||
}
|
||||
|
||||
//more data
|
||||
app.State.do_action(
|
||||
new app.Actions.Update_layer_action(config.layer.id, {
|
||||
width,
|
||||
height,
|
||||
status: null
|
||||
}),
|
||||
{ merge_with_history: 'new_line_layer' }
|
||||
);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
var coords = [
|
||||
[0, 0],
|
||||
[100, 100],
|
||||
];
|
||||
this.draw_shape(ctx, x, y, width, height, coords);
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
if (layer.width == 0 && layer.height == 0)
|
||||
return;
|
||||
|
||||
var params = layer.params;
|
||||
|
||||
//set styles
|
||||
ctx.fillStyle = layer.color;
|
||||
ctx.strokeStyle = layer.color;
|
||||
ctx.lineWidth = params.size;
|
||||
ctx.lineCap = 'round';
|
||||
|
||||
var width = layer.x + layer.width;
|
||||
var height = layer.y + layer.height;
|
||||
|
||||
//draw line
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(layer.x, layer.y);
|
||||
ctx.lineTo(width, height);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Line_class;
|
||||
@@ -0,0 +1,120 @@
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Moon_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'moon';
|
||||
this.layer = {};
|
||||
this.best_ratio = 0.8;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
ctx.fillStyle = '#aaa';
|
||||
ctx.strokeStyle = '#555';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
var width_all = width + x * 2;
|
||||
width = height * this.best_ratio;
|
||||
x = (width_all - width) / 2;
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(x + width / 2, y + height / 2);
|
||||
this.draw_shape(ctx, -width / 2, -height / 2, width, height, true, true);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height, params.fill, params.border);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
draw_shape(ctx, x, y, width, height, fill, stroke) {
|
||||
var left = parseInt(x);
|
||||
var top = parseInt(y);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(left + width * 0.512, top + height / 2);
|
||||
ctx.bezierCurveTo(
|
||||
left + width * 51.2 / 100, top + height * 28.4 / 100,
|
||||
left + width * 71.5 / 100, top + height * 10.1 / 100,
|
||||
left + width * 100 / 100, top + height * 3.1 / 100
|
||||
);
|
||||
ctx.bezierCurveTo(
|
||||
left + width * 92 / 100, top + height * 1.1 / 100,
|
||||
left + width * 83.4 / 100, top + height * 0 / 100,
|
||||
left + width * 74.4 / 100, top + height * 0 / 100
|
||||
);
|
||||
ctx.bezierCurveTo(
|
||||
left + width * 33.3 / 100, top + height * 0 / 100,
|
||||
left + width * 0 / 100, top + height * 22.4 / 100,
|
||||
left + width * 0 / 100, top + height * 50 / 100
|
||||
);
|
||||
ctx.bezierCurveTo(
|
||||
left + width * 0 / 100, top + height * 77.6 / 100,
|
||||
left + width * 33.3 / 100, top + height * 100 / 100,
|
||||
left + width * 74.4 / 100, top + height * 100 / 100
|
||||
);
|
||||
ctx.bezierCurveTo(
|
||||
left + width * 83.4 / 100, top + height * 100 / 100,
|
||||
left + width * 92 / 100, top + height * 98.9 / 100,
|
||||
left + width * 100 / 100, top + height * 96.9 / 100
|
||||
);
|
||||
ctx.bezierCurveTo(
|
||||
left + width * 71.5 / 100, top + height * 89.9 / 100,
|
||||
left + width * 51.2 / 100, top + height * 71.6 / 100,
|
||||
left + width * 51.2 / 100, top + height * 50 / 100
|
||||
);
|
||||
ctx.closePath();
|
||||
if (fill) {
|
||||
ctx.fill();
|
||||
}
|
||||
if (stroke) {
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Moon_class;
|
||||
@@ -0,0 +1,75 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Parallelogram_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'parallelogram';
|
||||
this.layer = {};
|
||||
this.best_ratio = 2;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.coords = [
|
||||
[25, 0],
|
||||
[100, 0],
|
||||
[75, 100],
|
||||
[0, 100],
|
||||
[25, 0],
|
||||
];
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
this.draw_shape(ctx, x, y, width, height, this.coords);
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
var fill = params.fill;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height, this.coords, false);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Parallelogram_class;
|
||||
@@ -0,0 +1,112 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Pentagon_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'pentagon';
|
||||
this.layer = {};
|
||||
this.best_ratio = 1.051;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.coords = [
|
||||
[100.40599536364314, 38.90073974812779],
|
||||
[81.15261837150108, 98.1565411518722],
|
||||
[18.84738162849893, 98.1565411518722],
|
||||
[-0.40599536364314304, 38.90073974812779],
|
||||
[49.99999999999999, 2.2786404499999975],
|
||||
[100.40599536364314, 38.900739748127776],
|
||||
[100.40599536364314, 38.90073974812779],
|
||||
];
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
ctx.fillStyle = '#aaa';
|
||||
ctx.strokeStyle = '#555';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
this.draw_shape(ctx, x, y, width, height, this.coords);
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
var fill = params.fill;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height, this.coords);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
draw_shape(ctx, x, y, width, height, coords) {
|
||||
ctx.lineJoin = "round";
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.scale(1, 1.051);
|
||||
|
||||
for(var i in coords){
|
||||
if(coords[i] === null){
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
continue;
|
||||
}
|
||||
|
||||
//coords in 100x100 box
|
||||
var pos_x = x + coords[i][0] * width / 100;
|
||||
var pos_y = y + coords[i][1] * height / 100;
|
||||
|
||||
if(i == '0')
|
||||
ctx.moveTo(pos_x, pos_y);
|
||||
else
|
||||
ctx.lineTo(pos_x, pos_y);
|
||||
}
|
||||
ctx.closePath();
|
||||
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Pentagon_class;
|
||||
@@ -0,0 +1,85 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
import Helper_class from './../../libs/helpers.js';
|
||||
|
||||
class Plus_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.Helper = new Helper_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'plus';
|
||||
this.layer = {};
|
||||
this.best_ratio = 1;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.coords = [
|
||||
[35, 0],
|
||||
[65, 0],
|
||||
[65, 35],
|
||||
[100, 35],
|
||||
[100, 65],
|
||||
[65, 65],
|
||||
[65, 100],
|
||||
[35, 100],
|
||||
[35, 65],
|
||||
[0, 65],
|
||||
[0, 35],
|
||||
[35, 35],
|
||||
[35, 0],
|
||||
];
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
this.draw_shape(ctx, x, y, width, height, this.coords);
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
var fill = params.fill;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height, this.coords, false);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Plus_class;
|
||||
@@ -0,0 +1,369 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
import Helper_class from './../../libs/helpers.js';
|
||||
|
||||
class Polygon_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.Helper = new Helper_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'polygon';
|
||||
this.layer = {};
|
||||
this.best_ratio = 1;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.params_hash = false;
|
||||
this.selected_obj_positions = {};
|
||||
this.mouse_lock = null;
|
||||
this.selected_object_drag_type = null;
|
||||
this.old_data = null;
|
||||
|
||||
this.events();
|
||||
}
|
||||
|
||||
load() {
|
||||
var _this = this;
|
||||
this.default_events();
|
||||
document.addEventListener('keydown', function (event) {
|
||||
var code = event.code;
|
||||
if (config.TOOL.name == _this.name && code == "Escape") {
|
||||
//escape
|
||||
config.layer.status = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* events for handling helping lines only
|
||||
*/
|
||||
events() {
|
||||
document.addEventListener('mousedown', (e) => {
|
||||
this.selected_object_actions(e);
|
||||
});
|
||||
document.addEventListener('mousemove', (e) => {
|
||||
this.selected_object_actions(e);
|
||||
});
|
||||
document.addEventListener('mouseup', (e) => {
|
||||
this.selected_object_actions(e);
|
||||
});
|
||||
|
||||
// touch
|
||||
document.addEventListener('touchstart', (event) => {
|
||||
this.selected_object_actions(event);
|
||||
});
|
||||
document.addEventListener('touchmove', (event) => {
|
||||
this.selected_object_actions(event);
|
||||
}, {passive: false});
|
||||
document.addEventListener('touchend', (event) => {
|
||||
this.selected_object_actions(event);
|
||||
});
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var params_hash = this.get_params_hash();
|
||||
|
||||
var mouse_x = mouse.x;
|
||||
var mouse_y = mouse.y;
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.layer.type != this.name || params_hash != this.params_hash
|
||||
|| (config.layer.data != null && config.layer.status != 'draft')) {
|
||||
//register new object - current layer is not ours or params changed
|
||||
this.layer = {
|
||||
type: this.name,
|
||||
data: [
|
||||
{x: mouse_x, y: mouse_y}
|
||||
],
|
||||
params: this.clone(this.getParams()),
|
||||
render_function: [this.name, 'render'],
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: null,
|
||||
height: null,
|
||||
hide_selection_if_active: true,
|
||||
rotate: null,
|
||||
is_vector: true,
|
||||
color: null,
|
||||
status: 'draft',
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('new_polygon_layer', 'New Polygon Layer', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
this.params_hash = params_hash;
|
||||
}
|
||||
else {
|
||||
//add more data
|
||||
config.layer.data.push(
|
||||
{x: mouse_x, y: mouse_y}
|
||||
);
|
||||
}
|
||||
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var mouse_x = Math.round(mouse.x);
|
||||
var mouse_y = Math.round(mouse.y);
|
||||
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (mouse.is_drag == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y, config.layer.id);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
|
||||
//add more data
|
||||
config.layer.data[config.layer.data.length - 1] = {x: mouse_x, y: mouse_y};
|
||||
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var mouse_x = Math.round(mouse.x);
|
||||
var mouse_y = Math.round(mouse.y);
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y, config.layer.id);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
|
||||
//add more data
|
||||
config.layer.data[config.layer.data.length - 1] = {x: mouse_x, y: mouse_y};
|
||||
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
|
||||
if(config.TOOL.name != 'select'){
|
||||
return;
|
||||
}
|
||||
|
||||
//also draw control lines
|
||||
if(config.layer.type == this.name){
|
||||
var data = config.layer.data;
|
||||
this.selected_obj_positions = {};
|
||||
|
||||
//draw corners
|
||||
for(var i in data) {
|
||||
var point = data[i];
|
||||
|
||||
this.selected_obj_positions[i] = this.Helper.draw_control_point(
|
||||
this.ctx,
|
||||
config.layer.x + point.x,
|
||||
config.layer.y + point.y
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
select(ctx) {
|
||||
this.render_overlay(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
ctx.fillStyle = '#aaa';
|
||||
ctx.strokeStyle = '#555';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
var width_all = width + x * 2;
|
||||
width = height * this.best_ratio;
|
||||
x = (width_all - width) / 2;
|
||||
|
||||
var data = [
|
||||
{x: 0, y: 0},
|
||||
{x: width, y: 0},
|
||||
{x: width * 1.1, y: height * 2 / 3},
|
||||
{x: width / 2, y: height / 3},
|
||||
{x: -1 * width * 0.2, y: height},
|
||||
];
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(x + width / 2, y + height / 2);
|
||||
this.draw_polygon(ctx, -width / 2, -height / 2, width, height, data);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_polygon(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height, layer.data);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
draw_polygon(ctx, x, y, width, height, data) {
|
||||
if(data.length == 0){
|
||||
return;
|
||||
}
|
||||
|
||||
//draw
|
||||
ctx.beginPath();
|
||||
for(var i in data) {
|
||||
if(i == 0){
|
||||
ctx.moveTo(x + data[i].x, y + data[i].y);
|
||||
}
|
||||
else{
|
||||
ctx.lineTo(x + data[i].x, y + data[i].y);
|
||||
}
|
||||
}
|
||||
ctx.closePath();
|
||||
ctx.fill()
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
selected_object_actions(e) {
|
||||
if(config.TOOL.name != 'select' || config.layer.type != this.name){
|
||||
return;
|
||||
}
|
||||
|
||||
var ctx = this.Base_layers.ctx;
|
||||
var mouse = this.get_mouse_info(e);
|
||||
const mainWrapper = document.getElementById('main_wrapper');
|
||||
|
||||
//simplify checks
|
||||
var event_type = e.type;
|
||||
if(event_type == 'touchstart') event_type = 'mousedown';
|
||||
if(event_type == 'touchmove') event_type = 'mousemove';
|
||||
if(event_type == 'touchend') event_type = 'mouseup';
|
||||
|
||||
if (event_type == 'mouseup') {
|
||||
//reset
|
||||
config.mouse_lock = null;
|
||||
if (mainWrapper.style.cursor != 'default') {
|
||||
mainWrapper.style.cursor = 'default';
|
||||
}
|
||||
}
|
||||
|
||||
if (event_type == 'mousedown' && config.mouse.valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event_type == 'mousemove' && this.mouse_lock == 'move_point' && mouse.is_drag) {
|
||||
mainWrapper.style.cursor = "move";
|
||||
|
||||
if (e.buttons == 1 || typeof e.buttons == "undefined") {
|
||||
var type = this.selected_object_drag_type;
|
||||
var bezier = config.layer.data;
|
||||
|
||||
// Do transformations
|
||||
var dx = Math.round(mouse.x - mouse.click_x) - config.layer.x;
|
||||
var dy = Math.round(mouse.y - mouse.click_y) - config.layer.y;
|
||||
|
||||
// Set values
|
||||
config.layer.data[type] = {
|
||||
x: mouse.click_x + dx,
|
||||
y: mouse.click_y + dy
|
||||
};
|
||||
|
||||
config.need_render = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (event_type == 'mouseup' && this.mouse_lock == 'move_point') {
|
||||
this.mouse_lock = null;
|
||||
var bezier = config.layer.data;
|
||||
|
||||
//reset sate
|
||||
config.layer.data = this.old_data;
|
||||
|
||||
//save state
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('change_layer_details', 'Change Layer Details', [
|
||||
new app.Actions.Update_layer_action(config.layer.id, {
|
||||
data: bezier,
|
||||
})
|
||||
])
|
||||
);
|
||||
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
if (!mouse.is_drag && ['mousedown', 'mouseup'].includes(event_type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.mouse_lock) {
|
||||
for (let current_drag_type in this.selected_obj_positions) {
|
||||
const position = this.selected_obj_positions[current_drag_type];
|
||||
if (position && this.ctx.isPointInPath(position, mouse.x, mouse.y)) {
|
||||
// match
|
||||
if (event_type == 'mousedown') {
|
||||
if (e.buttons == 1 || typeof e.buttons == "undefined") {
|
||||
this.mouse_lock = 'move_point';
|
||||
this.selected_object_drag_type = current_drag_type;
|
||||
}
|
||||
config.mouse_lock = true;
|
||||
this.old_data = JSON.parse(JSON.stringify(config.layer.data));
|
||||
}
|
||||
if (event_type == 'mousemove') {
|
||||
mainWrapper.style.cursor = 'move';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Polygon_class;
|
||||
@@ -0,0 +1,302 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Rectangle_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'rectangle';
|
||||
this.layer = {};
|
||||
this.best_ratio = 1;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.mouse_click = {x: null, y: null};
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
if (mouse.click_valid == false)
|
||||
return;
|
||||
|
||||
var mouse_x = mouse.x;
|
||||
var mouse_y = mouse.y;
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
|
||||
this.mouse_click.x = mouse_x;
|
||||
this.mouse_click.y = mouse_y;
|
||||
|
||||
//register new object - current layer is not ours or params changed
|
||||
this.layer = {
|
||||
type: this.name,
|
||||
params: this.clone(this.getParams()),
|
||||
status: 'draft',
|
||||
render_function: [this.name, 'render'],
|
||||
x: Math.round(mouse_x),
|
||||
y: Math.round(mouse_y),
|
||||
color: null,
|
||||
is_vector: true
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('new_rectangle_layer', 'New Rectangle Layer', [
|
||||
new app.Actions.Insert_layer_action(this.layer)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var mouse_x = Math.round(mouse.x);
|
||||
var mouse_y = Math.round(mouse.y);
|
||||
var click_x = Math.round(this.mouse_click.x);
|
||||
var click_y = Math.round(this.mouse_click.y);
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y, config.layer.id);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
|
||||
var x = Math.min(mouse_x, click_x);
|
||||
var y = Math.min(mouse_y, click_y);
|
||||
var width = Math.abs(mouse_x - click_x);
|
||||
var height = Math.abs(mouse_y - click_y);
|
||||
|
||||
if (params.square == true || e.ctrlKey == true || e.metaKey) {
|
||||
if (width < height) {
|
||||
width = height;
|
||||
}
|
||||
else {
|
||||
height = width;
|
||||
}
|
||||
if (mouse_x < click_x) {
|
||||
x = click_x - width;
|
||||
}
|
||||
if (mouse_y < click_y) {
|
||||
y = click_y - height;
|
||||
}
|
||||
}
|
||||
|
||||
//more data
|
||||
config.layer.x = x;
|
||||
config.layer.y = y;
|
||||
config.layer.width = width;
|
||||
config.layer.height = height;
|
||||
|
||||
this.Base_layers.render();
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
|
||||
if (mouse.click_valid == false) {
|
||||
config.layer.status = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var mouse_x = Math.round(mouse.x);
|
||||
var mouse_y = Math.round(mouse.y);
|
||||
var click_x = Math.round(this.mouse_click.x);
|
||||
var click_y = Math.round(this.mouse_click.y);
|
||||
|
||||
//apply snap
|
||||
var snap_info = this.calc_snap_position(e, mouse_x, mouse_y, config.layer.id);
|
||||
if(snap_info != null){
|
||||
if(snap_info.x != null) {
|
||||
mouse_x = snap_info.x;
|
||||
}
|
||||
if(snap_info.y != null) {
|
||||
mouse_y = snap_info.y;
|
||||
}
|
||||
}
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
|
||||
var x = Math.min(mouse_x, click_x);
|
||||
var y = Math.min(mouse_y, click_y);
|
||||
var width = Math.abs(mouse_x - click_x);
|
||||
var height = Math.abs(mouse_y - click_y);
|
||||
|
||||
if (params.square == true || e.ctrlKey == true || e.metaKey) {
|
||||
if (width < height) {
|
||||
width = height;
|
||||
}
|
||||
else {
|
||||
height = width;
|
||||
}
|
||||
if (mouse_x < click_x) {
|
||||
x = click_x - width;
|
||||
}
|
||||
if (mouse_y < click_y) {
|
||||
y = click_y - height;
|
||||
}
|
||||
}
|
||||
|
||||
if (width == 0 && height == 0) {
|
||||
//same coordinates - cancel
|
||||
app.State.scrap_last_action();
|
||||
return;
|
||||
}
|
||||
|
||||
//more data
|
||||
app.State.do_action(
|
||||
new app.Actions.Update_layer_action(config.layer.id, {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
status: null
|
||||
}),
|
||||
{ merge_with_history: 'new_rectangle_layer' }
|
||||
);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
var coords = [
|
||||
[0, 0],
|
||||
[100, 0],
|
||||
[100, 100],
|
||||
[0, 100],
|
||||
[0, 0],
|
||||
];
|
||||
this.draw_shape(ctx, x, y, width, height, coords);
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
var fill = params.fill;
|
||||
var stroke = params.border;
|
||||
var rotateSupport = true;
|
||||
var radius = params.radius;
|
||||
if(radius == undefined)
|
||||
radius = 0;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
if (rotateSupport == false) {
|
||||
this.roundRect(ctx, layer.x, layer.y, layer.width, layer.height, radius, fill, stroke);
|
||||
}
|
||||
else {
|
||||
//rotate
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.roundRect(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height, radius, fill, stroke);
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a rounded rectangle on canvas.
|
||||
*
|
||||
* @param {CanvasRenderingContext2D} ctx
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @param {Number} width
|
||||
* @param {Number} height
|
||||
* @param {Number} radius
|
||||
* @param {Boolean} fill
|
||||
*/
|
||||
roundRect(ctx, x, y, width, height, radius, fill, stroke) {
|
||||
x = parseInt(x);
|
||||
y = parseInt(y);
|
||||
width = parseInt(width);
|
||||
height = parseInt(height);
|
||||
if(width < 0){
|
||||
width = Math.abs(width);
|
||||
x = x - width;
|
||||
}
|
||||
if(height < 0){
|
||||
height = Math.abs(height);
|
||||
y = y - height;
|
||||
}
|
||||
var smaller_dimension = Math.min(width, height);
|
||||
|
||||
radius = parseInt(radius);
|
||||
if (typeof fill == 'undefined') {
|
||||
fill = false;
|
||||
}
|
||||
if (typeof radius === 'undefined') {
|
||||
radius = 0;
|
||||
}
|
||||
radius = Math.min(radius, width / 2, height / 2);
|
||||
radius = Math.floor(radius);
|
||||
|
||||
// Odd dimensions must draw offset half a pixel
|
||||
if (width % 2 == 1 && config.layer.status != 'draft') {
|
||||
x -= 0.5;
|
||||
}
|
||||
if (height % 2 == 1 && config.layer.status != 'draft') {
|
||||
y -= 0.5;
|
||||
}
|
||||
|
||||
var stroke_offset = !fill && ctx.lineWidth % 2 == 1 && width > 1 && height > 1 ? 0.5 : 0;
|
||||
|
||||
if (smaller_dimension < 2) fill = true;
|
||||
|
||||
radius = {tl: radius, tr: radius, br: radius, bl: radius};
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + radius.tl + stroke_offset, y + stroke_offset);
|
||||
ctx.lineTo(x + width - radius.tr - stroke_offset, y + stroke_offset);
|
||||
ctx.quadraticCurveTo(x + width - stroke_offset, y + stroke_offset, x + width - stroke_offset, y + radius.tr + stroke_offset);
|
||||
ctx.lineTo(x + width - stroke_offset, y + height - radius.br - stroke_offset);
|
||||
ctx.quadraticCurveTo(x + width - stroke_offset, y + height - stroke_offset, x + width - radius.br - stroke_offset, y + height - stroke_offset);
|
||||
ctx.lineTo(x + radius.bl + stroke_offset, y + height - stroke_offset);
|
||||
ctx.quadraticCurveTo(x + stroke_offset, y + height - stroke_offset, x + stroke_offset, y + height - radius.bl - stroke_offset);
|
||||
ctx.lineTo(x + stroke_offset, y + radius.tl + stroke_offset);
|
||||
ctx.quadraticCurveTo(x + stroke_offset, y + stroke_offset, x + radius.tl + stroke_offset, y + stroke_offset);
|
||||
ctx.closePath();
|
||||
if (fill) {
|
||||
ctx.fill();
|
||||
}
|
||||
if (stroke) {
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Rectangle_class;
|
||||
@@ -0,0 +1,74 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Right_Triangle_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'right_triangle';
|
||||
this.layer = {};
|
||||
this.best_ratio = 1;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.coords = [
|
||||
[0, 0],
|
||||
[100, 100],
|
||||
[0, 100],
|
||||
[0, 0],
|
||||
];
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
this.draw_shape(ctx, x, y, width, height, this.coords);
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
var fill = params.fill;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height, this.coords, false);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Right_Triangle_class;
|
||||
@@ -0,0 +1,82 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Romb_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'romb';
|
||||
this.layer = {};
|
||||
this.best_ratio = 0.8;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.coords_demo = [
|
||||
[50, 0],
|
||||
[80, 50],
|
||||
[50, 100],
|
||||
[20, 50],
|
||||
[50, 0],
|
||||
];
|
||||
this.coords = [
|
||||
[50, 0],
|
||||
[100, 50],
|
||||
[50, 100],
|
||||
[0, 50],
|
||||
[50, 0],
|
||||
];
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
this.draw_shape(ctx, x, y, width, height, this.coords_demo);
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
var fill = params.fill;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height, this.coords, false);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Romb_class;
|
||||
@@ -0,0 +1,113 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Star_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'star';
|
||||
this.layer = {};
|
||||
this.best_ratio = 1;
|
||||
this.coords = [];
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
generate_coords(spikes, innerRadius) {
|
||||
//settings
|
||||
|
||||
innerRadius = parseInt(innerRadius) / 2;
|
||||
innerRadius = Math.min(Math.max(innerRadius, 0), 100);
|
||||
|
||||
spikes = parseInt(spikes);
|
||||
spikes = Math.max(spikes, 3);
|
||||
|
||||
var outerRadius = 50;
|
||||
if(spikes == 5){
|
||||
outerRadius = 53;
|
||||
}
|
||||
|
||||
var cx = 50;
|
||||
|
||||
var cy = 50;
|
||||
if(spikes == 5){
|
||||
cy = 55;
|
||||
}
|
||||
|
||||
var rot = Math.PI / 2 * 3;
|
||||
var x = cx;
|
||||
var y = cy;
|
||||
var step = Math.PI / spikes;
|
||||
this.coords = [];
|
||||
this.coords.push([cx, cy - outerRadius]);
|
||||
for (var i = 0; i < spikes; i++) {
|
||||
x = cx + Math.cos(rot) * outerRadius;
|
||||
y = cy + Math.sin(rot) * outerRadius;
|
||||
this.coords.push([x, y]);
|
||||
rot += step;
|
||||
|
||||
x = cx + Math.cos(rot) * innerRadius;
|
||||
y = cy + Math.sin(rot) * innerRadius;
|
||||
this.coords.push([x, y]);
|
||||
rot += step;
|
||||
}
|
||||
this.coords.push([cx, cy - outerRadius]);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
this.generate_coords(5, 40);
|
||||
this.draw_shape(ctx, x, y, width, height, this.coords);
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
var fill = params.fill;
|
||||
|
||||
this.generate_coords(params.corners, params.inner_radius);
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height, this.coords, false);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Star_class;
|
||||
@@ -0,0 +1,115 @@
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Tear_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'tear';
|
||||
this.layer = {};
|
||||
this.best_ratio = 0.7;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
ctx.fillStyle = '#aaa';
|
||||
ctx.strokeStyle = '#555';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
var width_all = width + x * 2;
|
||||
width = height * this.best_ratio;
|
||||
x = (width_all - width) / 2;
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(x + width / 2, y + height / 2);
|
||||
this.draw_shape(ctx, -width / 2, -height / 2, width, height, true, true);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height, params.fill, params.border);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
draw_shape(ctx, x, y, width, height, fill, stroke) {
|
||||
var left = parseInt(x);
|
||||
var top = parseInt(y);
|
||||
|
||||
//settings
|
||||
var curve_height = 29 / 100;
|
||||
var curve_start_x = 28 / 100;
|
||||
var curve_end_x = 1 - curve_start_x;
|
||||
var curve_cdx = 70;
|
||||
var curve_cdy = 58;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(left + width * 0.5, top);
|
||||
ctx.quadraticCurveTo(
|
||||
left + width * 0.5, top + height * 13 / 100,
|
||||
left + width * curve_end_x, top + height * curve_height
|
||||
);
|
||||
ctx.bezierCurveTo(
|
||||
left + width * (50 + curve_cdx) / 100, top + height * curve_cdy / 100,
|
||||
left + width * 100 / 100, top + height * 100 / 100,
|
||||
left + width * 0.5, top + height
|
||||
);
|
||||
ctx.bezierCurveTo(
|
||||
left + width * 0 / 100, top + height * 100 / 100,
|
||||
left + width * (50 - curve_cdx) / 100, top + height * curve_cdy / 100,
|
||||
left + width * curve_start_x, top + height * curve_height
|
||||
);
|
||||
ctx.quadraticCurveTo(
|
||||
left + width * 0.5, top + height * 13 / 100,
|
||||
left + width * 0.5, top
|
||||
);
|
||||
ctx.closePath();
|
||||
if (fill) {
|
||||
ctx.fill();
|
||||
}
|
||||
if (stroke) {
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Tear_class;
|
||||
@@ -0,0 +1,75 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Trapezoid_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'trapezoid';
|
||||
this.layer = {};
|
||||
this.best_ratio = 2;
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.coords = [
|
||||
[20, 0],
|
||||
[80, 0],
|
||||
[100, 100],
|
||||
[0, 100],
|
||||
[20, 0],
|
||||
];
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
this.draw_shape(ctx, x, y, width, height, this.coords);
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
var fill = params.fill;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height, this.coords, false);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Trapezoid_class;
|
||||
@@ -0,0 +1,74 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_tools_class from './../../core/base-tools.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
|
||||
class Triangle_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'triangle';
|
||||
this.layer = {};
|
||||
this.best_ratio = 2 / Math.sqrt(3);
|
||||
this.snap_line_info = {x: null, y: null};
|
||||
this.coords = [
|
||||
[50, 0],
|
||||
[100, 100],
|
||||
[0, 100],
|
||||
[50, 0],
|
||||
];
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.shape_mousedown(e);
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
this.shape_mousemove(e);
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
this.shape_mouseup(e);
|
||||
}
|
||||
|
||||
render_overlay(ctx){
|
||||
var ctx = this.Base_layers.ctx;
|
||||
this.render_overlay_parent(ctx);
|
||||
}
|
||||
|
||||
demo(ctx, x, y, width, height) {
|
||||
this.draw_shape(ctx, x, y, width, height, this.coords);
|
||||
}
|
||||
|
||||
render(ctx, layer) {
|
||||
var params = layer.params;
|
||||
var fill = params.fill;
|
||||
|
||||
ctx.save();
|
||||
|
||||
//set styles
|
||||
ctx.strokeStyle = 'transparent';
|
||||
ctx.fillStyle = 'transparent';
|
||||
if(params.border)
|
||||
ctx.strokeStyle = params.border_color;
|
||||
if(params.fill)
|
||||
ctx.fillStyle = params.fill_color;
|
||||
ctx.lineWidth = params.border_size;
|
||||
|
||||
//draw with rotation support
|
||||
ctx.translate(layer.x + layer.width / 2, layer.y + layer.height / 2);
|
||||
ctx.rotate(layer.rotate * Math.PI / 180);
|
||||
this.draw_shape(ctx, -layer.width / 2, -layer.height / 2, layer.width, layer.height, this.coords, false);
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Triangle_class;
|
||||
@@ -0,0 +1,139 @@
|
||||
import app from './../app.js';
|
||||
import config from './../config.js';
|
||||
import Base_tools_class from './../core/base-tools.js';
|
||||
import Base_layers_class from './../core/base-layers.js';
|
||||
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
import ImageFilters from './../libs/imagefilters.js';
|
||||
import Helper_class from './../libs/helpers.js';
|
||||
|
||||
class Sharpen_class extends Base_tools_class {
|
||||
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.Helper = new Helper_class();
|
||||
this.ctx = ctx;
|
||||
this.name = 'sharpen';
|
||||
this.tmpCanvas = null;
|
||||
this.tmpCanvasCtx = null;
|
||||
this.started = false;
|
||||
}
|
||||
|
||||
load() {
|
||||
this.default_events();
|
||||
}
|
||||
|
||||
default_dragMove(event) {
|
||||
if (config.TOOL.name != this.name)
|
||||
return;
|
||||
this.mousemove(event);
|
||||
|
||||
//mouse cursor
|
||||
var mouse = this.get_mouse_info(event);
|
||||
var params = this.getParams();
|
||||
this.show_mouse_cursor(mouse.x, mouse.y, params.size, 'circle');
|
||||
}
|
||||
|
||||
mousedown(e) {
|
||||
this.started = false;
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (config.layer.type != 'image') {
|
||||
alertify.error('This layer must contain an image. Please convert it to raster to apply this tool.');
|
||||
return;
|
||||
}
|
||||
if (config.layer.rotate || 0 > 0) {
|
||||
alertify.error('Erase on rotate object is disabled. Please rasterize first.');
|
||||
return;
|
||||
}
|
||||
this.started = true;
|
||||
|
||||
//get canvas from layer
|
||||
this.tmpCanvas = document.createElement('canvas');
|
||||
this.tmpCanvasCtx = this.tmpCanvas.getContext("2d");
|
||||
this.tmpCanvas.width = config.layer.width_original;
|
||||
this.tmpCanvas.height = config.layer.height_original;
|
||||
this.tmpCanvasCtx.drawImage(config.layer.link, 0, 0);
|
||||
|
||||
//do sharpen
|
||||
this.sharpen_general('click', mouse, params.size);
|
||||
|
||||
//register tmp canvas for faster redraw
|
||||
config.layer.link_canvas = this.tmpCanvas;
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
mousemove(e) {
|
||||
var mouse = this.get_mouse_info(e);
|
||||
var params = this.getParams();
|
||||
if (mouse.is_drag == false)
|
||||
return;
|
||||
if (mouse.click_valid == false) {
|
||||
return;
|
||||
}
|
||||
if (this.started == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
//do sharpen
|
||||
this.sharpen_general('move', mouse, params.size);
|
||||
|
||||
//draw draft preview
|
||||
config.need_render = true;
|
||||
}
|
||||
|
||||
mouseup(e) {
|
||||
if (this.started == false) {
|
||||
return;
|
||||
}
|
||||
delete config.layer.link_canvas;
|
||||
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('sharpen_tool', 'Sharpen Tool', [
|
||||
new app.Actions.Update_layer_image_action(this.tmpCanvas)
|
||||
])
|
||||
);
|
||||
|
||||
//decrease memory
|
||||
this.tmpCanvas.width = 1;
|
||||
this.tmpCanvas.height = 1;
|
||||
this.tmpCanvas = null;
|
||||
this.tmpCanvasCtx = null;
|
||||
}
|
||||
|
||||
sharpen_general(type, mouse, size) {
|
||||
var ctx = this.tmpCanvasCtx;
|
||||
var mouse_x = Math.round(mouse.x) - config.layer.x;
|
||||
var mouse_y = Math.round(mouse.y) - config.layer.y;
|
||||
|
||||
//adapt to origin size
|
||||
mouse_x = this.adaptSize(mouse_x, 'width');
|
||||
mouse_y = this.adaptSize(mouse_y, 'height');
|
||||
var size_w = this.adaptSize(size, 'width');
|
||||
var size_h = this.adaptSize(size, 'height');
|
||||
|
||||
//find center
|
||||
var center_x = mouse_x - Math.round(size_w / 2);
|
||||
var center_y = mouse_y - Math.round(size_h / 2);
|
||||
|
||||
//convert float coords to integers
|
||||
mouse_x = Math.round(mouse_x);
|
||||
mouse_y = Math.round(mouse_y);
|
||||
center_x = Math.round(center_x);
|
||||
center_y = Math.round(center_y);
|
||||
|
||||
var power = 0.5;
|
||||
if (type == 'move') {
|
||||
power = power / 10;
|
||||
}
|
||||
|
||||
var imageData = ctx.getImageData(center_x, center_y, size_w, size_h);
|
||||
var filtered = ImageFilters.Sharpen(imageData, power); //add effect
|
||||
this.Helper.image_round(this.tmpCanvasCtx, mouse_x, mouse_y, size_w, size_h, filtered);
|
||||
}
|
||||
|
||||
}
|
||||
export default Sharpen_class;
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user