Moved into /desktop
This commit is contained in:
556
desktop/sources/scripts/dotgrid.js
Normal file
556
desktop/sources/scripts/dotgrid.js
Normal file
@@ -0,0 +1,556 @@
|
||||
function Dotgrid(width,height,grid_x,grid_y,block_x,block_y,thickness = 3,linecap = "round",linejoin = "round", color = "#000000")
|
||||
{
|
||||
this.controller = new Controller();
|
||||
this.theme = new Theme();
|
||||
this.interface = new Interface();
|
||||
this.history = new History();
|
||||
this.guide = new Guide();
|
||||
this.render = new Render();
|
||||
this.tool = new Tool();
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.grid_x = grid_x;
|
||||
this.grid_y = grid_y;
|
||||
this.block_x = block_x;
|
||||
this.block_y = block_y;
|
||||
|
||||
this.thickness = thickness;
|
||||
this.linecap = linecap;
|
||||
this.linejoin = linejoin;
|
||||
this.color = color;
|
||||
this.offset = new Pos(0,0);
|
||||
|
||||
// Dotgrid
|
||||
this.element = document.createElement("div");
|
||||
this.element.id = "dotgrid";
|
||||
this.element.style.width = this.width;
|
||||
this.element.style.height = this.height;
|
||||
|
||||
this.wrapper = document.createElement("div");
|
||||
this.wrapper.id = "wrapper";
|
||||
|
||||
this.grid_width = this.width/this.grid_x;
|
||||
this.grid_height = this.height/this.grid_y;
|
||||
|
||||
var cursor = null;
|
||||
|
||||
this.svg_el = null;
|
||||
this.mirror_el = null;
|
||||
this.mirror = false;
|
||||
this.fill = false;
|
||||
this.layer_1 = document.createElementNS("http://www.w3.org/2000/svg", "path"); this.layer_1.id = "layer_1"; this.layer_1.style.stroke = "black";
|
||||
this.layer_2 = document.createElementNS("http://www.w3.org/2000/svg", "path"); this.layer_2.id = "layer_2"; this.layer_2.style.stroke = "#999";
|
||||
this.layer_3 = document.createElementNS("http://www.w3.org/2000/svg", "path"); this.layer_3.id = "layer_3"; this.layer_3.style.stroke = "#ccc";
|
||||
this.mirror_layer_1 = document.createElementNS("http://www.w3.org/2000/svg", "path"); this.mirror_layer_1.id = "mirror_layer_1"; this.mirror_layer_1.style.stroke = "black";
|
||||
this.mirror_layer_2 = document.createElementNS("http://www.w3.org/2000/svg", "path"); this.mirror_layer_2.id = "mirror_layer_2"; this.mirror_layer_2.style.stroke = "#999";
|
||||
this.mirror_layer_3 = document.createElementNS("http://www.w3.org/2000/svg", "path"); this.mirror_layer_3.id = "mirror_layer_3"; this.mirror_layer_3.style.stroke = "#ccc";
|
||||
this.scale = 1;
|
||||
|
||||
this.install = function()
|
||||
{
|
||||
document.getElementById("app").appendChild(this.wrapper);
|
||||
this.wrapper.appendChild(this.element);
|
||||
this.element.appendChild(this.guide.el);
|
||||
this.element.appendChild(this.guide.widgets);
|
||||
this.wrapper.appendChild(this.render.el);
|
||||
|
||||
// Cursors
|
||||
this.cursor = document.createElement("div");
|
||||
this.cursor.id = "cursor";
|
||||
this.element.appendChild(this.cursor);
|
||||
|
||||
this.cursor_x = document.createElement("t");
|
||||
this.cursor_x.id = "cursor_x";
|
||||
this.cursor_x.className = "fl"
|
||||
this.element.appendChild(this.cursor_x);
|
||||
|
||||
this.cursor_y = document.createElement("t");
|
||||
this.cursor_y.id = "cursor_y";
|
||||
this.cursor_y.className = "fl"
|
||||
this.element.appendChild(this.cursor_y);
|
||||
|
||||
this.offset_el = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
||||
this.mirror_el = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
||||
// Vector
|
||||
this.svg_el = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
this.svg_el.setAttribute("class","vector");
|
||||
this.svg_el.setAttribute("width",this.width+"px");
|
||||
this.svg_el.setAttribute("height",this.height+"px");
|
||||
this.svg_el.setAttribute("xmlns","http://www.w3.org/2000/svg");
|
||||
this.svg_el.setAttribute("baseProfile","full");
|
||||
this.svg_el.setAttribute("version","1.1");
|
||||
this.svg_el.style.width = this.width;
|
||||
this.svg_el.style.height = this.height;
|
||||
this.svg_el.style.stroke = this.color;
|
||||
this.svg_el.style.strokeWidth = this.thickness;
|
||||
this.svg_el.style.fill = "none";
|
||||
this.svg_el.style.strokeLinecap = this.linecap;
|
||||
this.svg_el.style.strokeLinejoin = this.linejoin;
|
||||
this.element.appendChild(this.svg_el);
|
||||
// Preview
|
||||
this.preview_el = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
this.preview_el.id = "preview"
|
||||
this.preview_el.setAttribute("class","vector");
|
||||
this.preview_el.setAttribute("width",this.width+"px");
|
||||
this.preview_el.setAttribute("height",this.height+"px");
|
||||
this.preview_el.setAttribute("xmlns","http://www.w3.org/2000/svg");
|
||||
this.preview_el.setAttribute("baseProfile","full");
|
||||
this.preview_el.setAttribute("version","1.1");
|
||||
this.preview_el.style.width = this.width;
|
||||
this.preview_el.style.height = this.height;
|
||||
this.preview_el.style.strokeWidth = 2;
|
||||
this.preview_el.style.fill = "none";
|
||||
this.preview_el.style.strokeLinecap = "round";
|
||||
this.element.appendChild(this.preview_el);
|
||||
|
||||
this.mirror_el.appendChild(this.mirror_layer_3)
|
||||
this.offset_el.appendChild(this.layer_3)
|
||||
this.mirror_el.appendChild(this.mirror_layer_2)
|
||||
this.offset_el.appendChild(this.layer_2)
|
||||
this.mirror_el.appendChild(this.mirror_layer_1)
|
||||
this.offset_el.appendChild(this.layer_1)
|
||||
this.svg_el.appendChild(this.offset_el);
|
||||
this.svg_el.appendChild(this.mirror_el);
|
||||
|
||||
this.theme.start();
|
||||
this.guide.start();
|
||||
this.interface.start();
|
||||
|
||||
this.controller.add("default","*","About",() => { require('electron').shell.openExternal('https://github.com/hundredrabbits/Dotgrid'); },"CmdOrCtrl+,");
|
||||
this.controller.add("default","*","Fullscreen",() => { app.toggle_fullscreen(); },"CmdOrCtrl+Enter");
|
||||
this.controller.add("default","*","Hide",() => { app.toggle_visible(); },"CmdOrCtrl+H");
|
||||
this.controller.add("default","*","Inspect",() => { app.inspect(); },"CmdOrCtrl+.");
|
||||
this.controller.add("default","*","Documentation",() => { dotgrid.controller.docs(); },"CmdOrCtrl+Esc");
|
||||
this.controller.add("default","*","Reset",() => { dotgrid.reset(); dotgrid.theme.reset(); },"CmdOrCtrl+Backspace");
|
||||
this.controller.add("default","*","Quit",() => { app.exit(); },"CmdOrCtrl+Q");
|
||||
|
||||
this.controller.add("default","File","New",() => { dotgrid.new(); },"CmdOrCtrl+N");
|
||||
this.controller.add("default","File","Open",() => { dotgrid.open(); },"CmdOrCtrl+O");
|
||||
this.controller.add("default","File","Save",() => { dotgrid.save(); },"CmdOrCtrl+S");
|
||||
|
||||
this.controller.add("default","Edit","Copy",() => { document.execCommand('copy'); },"CmdOrCtrl+C");
|
||||
this.controller.add("default","Edit","Cut",() => { document.execCommand('cut'); },"CmdOrCtrl+X");
|
||||
this.controller.add("default","Edit","Paste",() => { document.execCommand('paste'); },"CmdOrCtrl+V");
|
||||
this.controller.add("default","Edit","Undo",() => { dotgrid.tool.undo(); },"CmdOrCtrl+Z");
|
||||
this.controller.add("default","Edit","Redo",() => { dotgrid.tool.redo(); },"CmdOrCtrl+Shift+Z");
|
||||
this.controller.add("default","Edit","Delete",() => { dotgrid.tool.remove_segment(); },"Backspace");
|
||||
this.controller.add("default","Edit","Deselect",() => { dotgrid.tool.clear(); },"Esc");
|
||||
|
||||
this.controller.add("default","Select","Foreground",() => { dotgrid.tool.select_layer(0); },"1");
|
||||
this.controller.add("default","Select","Middleground",() => { dotgrid.tool.select_layer(1); },"2");
|
||||
this.controller.add("default","Select","Background",() => { dotgrid.tool.select_layer(2); },"3");
|
||||
|
||||
this.controller.add("default","Stroke","Line",() => { dotgrid.tool.cast("line"); },"A");
|
||||
this.controller.add("default","Stroke","Arc",() => { dotgrid.tool.cast("arc_c"); },"S"); // 0,1
|
||||
this.controller.add("default","Stroke","Arc Rev",() => { dotgrid.tool.cast("arc_r")},"D"); // 0,0
|
||||
this.controller.add("default","Stroke","Bezier",() => { dotgrid.tool.cast("bezier") },"F");
|
||||
this.controller.add("default","Stroke","Connect",() => { dotgrid.tool.cast("close") },"Z");
|
||||
|
||||
this.controller.add("default","Effect","Linecap",() => { dotgrid.mod_linecap(); },"Q");
|
||||
this.controller.add("default","Effect","Linejoin",() => { dotgrid.mod_linejoin(); },"W");
|
||||
this.controller.add("default","Effect","Mirror",() => { dotgrid.mod_mirror(); },"E");
|
||||
this.controller.add("default","Effect","Fill",() => { dotgrid.toggle_fill(); },"R");
|
||||
|
||||
this.controller.add("default","Effect","Thicker",() => { dotgrid.mod_thickness(1) },"}");
|
||||
this.controller.add("default","Effect","Thinner",() => { dotgrid.mod_thickness(-1) },"{");
|
||||
this.controller.add("default","Effect","Thicker +5",() => { dotgrid.mod_thickness(5,true) },"]");
|
||||
this.controller.add("default","Effect","Thinner -5",() => { dotgrid.mod_thickness(-5,true) },"[");
|
||||
|
||||
this.controller.add("default","Layers","Move Above",() => { dotgrid.tool.layer_up() },"Up");
|
||||
this.controller.add("default","Layers","Move Below",() => { dotgrid.tool.layer_down() },"Down");
|
||||
|
||||
this.controller.add("default","View","Tools",() => { dotgrid.interface.toggle(); },"U");
|
||||
this.controller.add("default","View","Grid",() => { dotgrid.guide.toggle(); },"H");
|
||||
this.controller.add("default","View","Control Points",() => { dotgrid.guide.toggle_widgets(); },"J");
|
||||
this.controller.add("default","View","Expert Mode",() => { dotgrid.interface.toggle_zoom(); },":");
|
||||
|
||||
this.controller.commit();
|
||||
|
||||
document.addEventListener('mousedown', function(e){ dotgrid.mouse_down(e); }, false);
|
||||
document.addEventListener('mousemove', function(e){ dotgrid.mouse_move(e); }, false);
|
||||
document.addEventListener('contextmenu', function(e){ dotgrid.mouse_alt(e); }, false);
|
||||
document.addEventListener('mouseup', function(e){ dotgrid.mouse_up(e);}, false);
|
||||
document.addEventListener('copy', function(e){ dotgrid.copy(e); e.preventDefault(); }, false);
|
||||
document.addEventListener('cut', function(e){ dotgrid.cut(e); e.preventDefault(); }, false);
|
||||
document.addEventListener('paste', function(e){ dotgrid.paste(e); e.preventDefault(); }, false);
|
||||
|
||||
window.addEventListener('drop', dotgrid.drag);
|
||||
|
||||
dotgrid.set_size({width:300,height:300});
|
||||
|
||||
this.new();
|
||||
}
|
||||
|
||||
// FILE
|
||||
|
||||
this.new = function()
|
||||
{
|
||||
this.history.push(this.tool.layers);
|
||||
dotgrid.clear();
|
||||
}
|
||||
|
||||
this.save = function()
|
||||
{
|
||||
this.scale = 1
|
||||
this.draw();
|
||||
|
||||
if(dotgrid.fill){ dotgrid.svg_el.style.fill = "black"; dotgrid.render.draw(); }
|
||||
|
||||
var svg = dotgrid.svg_el.outerHTML;
|
||||
|
||||
dialog.showSaveDialog((fileName) => {
|
||||
if (fileName === undefined){ return; }
|
||||
fs.writeFile(fileName+".svg", svg);
|
||||
fs.writeFile(fileName+'.png', dotgrid.render.buffer());
|
||||
fs.writeFile(fileName+'.dot', dotgrid.tool.export());
|
||||
dotgrid.draw()
|
||||
});
|
||||
}
|
||||
|
||||
this.open = function()
|
||||
{
|
||||
var paths = dialog.showOpenDialog({properties: ['openFile'],filters:[{name:"Dotgrid Image",extensions:["dot"]}]});
|
||||
|
||||
if(!paths){ console.log("Nothing to load"); return; }
|
||||
|
||||
fs.readFile(paths[0], 'utf-8', (err, data) => {
|
||||
if(err){ alert("An error ocurred reading the file :" + err.message); return; }
|
||||
dotgrid.tool.replace(JSON.parse(data.toString().trim()));
|
||||
dotgrid.draw();
|
||||
});
|
||||
}
|
||||
|
||||
// Cursor
|
||||
|
||||
this.translation = null;
|
||||
|
||||
this.mouse_down = function(e)
|
||||
{
|
||||
var pos = this.position_in_grid(new Pos(e.clientX+5,e.clientY-5)); pos = this.position_on_grid(pos);
|
||||
|
||||
if(e.altKey){ dotgrid.tool.remove_segments_at(pos); return; }
|
||||
if(dotgrid.tool.vertex_at(pos)){ console.log("Begin translation"); dotgrid.translation = {from:pos,to:pos}; return; }
|
||||
|
||||
var o = e.target.getAttribute("ar");
|
||||
if(!o){ return; }
|
||||
|
||||
if(o == "line"){ this.tool.cast("line"); }
|
||||
if(o == "arc_c"){ this.tool.cast("arc_c"); }
|
||||
if(o == "arc_r"){ this.tool.cast("arc_r"); }
|
||||
if(o == "bezier"){ this.tool.cast("bezier"); }
|
||||
if(o == "close"){ this.tool.cast("close"); }
|
||||
|
||||
if(o == "thickness"){ this.mod_thickness(); }
|
||||
if(o == "linecap"){ this.mod_linecap(); }
|
||||
if(o == "linejoin"){ this.mod_linejoin(); }
|
||||
if(o == "mirror"){ this.mod_mirror(); }
|
||||
if(o == "fill"){ this.toggle_fill(); }
|
||||
if(o == "export"){ this.save(); }
|
||||
}
|
||||
|
||||
this.mouse_move = function(e)
|
||||
{
|
||||
var pos = this.position_in_grid(new Pos(e.clientX+5,e.clientY-5)); pos = this.position_on_grid(pos);
|
||||
|
||||
if(dotgrid.translation && (Math.abs(dotgrid.translation.from.x) != Math.abs(pos.x) || Math.abs(dotgrid.translation.from.y) != Math.abs(pos.y))){ dotgrid.translation.to = pos; }
|
||||
|
||||
dotgrid.preview(e.target.getAttribute("ar"));
|
||||
dotgrid.move_cursor(pos)
|
||||
dotgrid.guide.update();
|
||||
}
|
||||
|
||||
this.mouse_up = function(e)
|
||||
{
|
||||
var pos = this.position_in_grid(new Pos(e.clientX+5,e.clientY-5)); pos = this.position_on_grid(pos);
|
||||
|
||||
if(e.altKey){ return; }
|
||||
|
||||
if(pos.x > 0) { dotgrid.translation = null; return; }
|
||||
|
||||
if(dotgrid.translation && (Math.abs(dotgrid.translation.from.x) != Math.abs(dotgrid.translation.to.x) || Math.abs(dotgrid.translation.from.y) != Math.abs(dotgrid.translation.to.y))){
|
||||
dotgrid.tool.translate(dotgrid.translation.from,dotgrid.translation.to);
|
||||
dotgrid.translation = null;
|
||||
this.draw();
|
||||
return;
|
||||
}
|
||||
|
||||
this.tool.add_vertex({x:pos.x * -1,y:pos.y});
|
||||
dotgrid.translation = null;
|
||||
this.draw();
|
||||
}
|
||||
|
||||
this.mouse_alt = function(e)
|
||||
{
|
||||
var pos = this.position_in_grid(new Pos(e.clientX+5,e.clientY-5)); pos = this.position_on_grid(pos);
|
||||
dotgrid.tool.remove_segments_at(pos);
|
||||
e.preventDefault();
|
||||
setTimeout(() => { dotgrid.tool.clear(); },150);
|
||||
}
|
||||
|
||||
this.move_cursor = function(pos)
|
||||
{
|
||||
if(pos.x>0) {
|
||||
this.cursor.style.visibility = "hidden"
|
||||
} else {
|
||||
if(this.cursor.style.visibility == "hidden") {
|
||||
this.cursor.style.transition = "initial"
|
||||
}
|
||||
this.cursor.style.visibility = "visible"
|
||||
this.cursor.style.left = Math.floor(-(pos.x-this.grid_width));
|
||||
this.cursor.style.top = Math.floor(pos.y+this.grid_height);
|
||||
this.update_cursor(pos);
|
||||
window.setTimeout(() => dotgrid.cursor.style.transition = "all 50ms", 17 /*one frame*/)
|
||||
}
|
||||
}
|
||||
|
||||
this.update_cursor = function(pos)
|
||||
{
|
||||
this.cursor_x.style.left = `${-pos.x}px`;
|
||||
this.cursor_x.textContent = parseInt(-pos.x/this.grid_width)
|
||||
this.cursor_y.style.top = `${pos.y}px`;
|
||||
this.cursor_y.textContent = parseInt(pos.y/this.grid_width)
|
||||
}
|
||||
|
||||
this.preview = function(operation)
|
||||
{
|
||||
if(!operation){ return `<path d='M0,0'></path>`;}
|
||||
if(operation != "line" && operation != "arc_c" && operation != "arc_r" && operation != "bezier" && operation != "close"){ return `<path d='M0,0'></path>`; }
|
||||
|
||||
this.preview_el.innerHTML = `<path d='${dotgrid.tool.path([{type:operation,verteces:dotgrid.tool.verteces}])}'></path>`;
|
||||
}
|
||||
|
||||
// Toggles
|
||||
|
||||
this.mod_thickness = function(mod,step = false)
|
||||
{
|
||||
if(!mod){ mod = 1; this.thickness = this.thickness > 30 ? 1 : this.thickness }
|
||||
|
||||
if(step){
|
||||
this.thickness = parseInt(this.thickness/5) * 5;
|
||||
}
|
||||
|
||||
this.thickness = Math.max(this.thickness+mod,0);
|
||||
this.cursor_x.textContent = this.thickness;
|
||||
this.draw();
|
||||
}
|
||||
|
||||
this.mod_linecap_index = 1;
|
||||
|
||||
this.mod_linecap = function(mod)
|
||||
{
|
||||
var a = ["butt","square","round"];
|
||||
this.mod_linecap_index += 1;
|
||||
this.linecap = a[this.mod_linecap_index % a.length];
|
||||
this.draw();
|
||||
}
|
||||
|
||||
this.mod_linejoin_index = 1;
|
||||
|
||||
this.mod_linejoin = function(mod)
|
||||
{
|
||||
var a = ["miter","round","bevel"];
|
||||
this.mod_linejoin_index += 1;
|
||||
this.linejoin = a[this.mod_linejoin_index % a.length];
|
||||
this.draw();
|
||||
}
|
||||
|
||||
this.mirror_index = 0;
|
||||
|
||||
this.mod_mirror = function()
|
||||
{
|
||||
this.mirror_index += 1;
|
||||
this.mirror_index = this.mirror_index > 3 ? 0 : this.mirror_index;
|
||||
this.draw();
|
||||
}
|
||||
|
||||
this.toggle_fill = function()
|
||||
{
|
||||
dotgrid.fill = dotgrid.fill ? false : true;
|
||||
this.draw();
|
||||
}
|
||||
|
||||
this.set_size = function(size = {width:300,height:300},interface = true)
|
||||
{
|
||||
var win = require('electron').remote.getCurrentWindow();
|
||||
win.setSize(size.width+100,size.height+100+(interface ? 10 : 0),true);
|
||||
|
||||
this.width = size.width
|
||||
this.height = size.height
|
||||
this.element.style.width = size.width+10
|
||||
this.element.style.height = size.height+10
|
||||
this.grid_x = size.width/15
|
||||
this.grid_y = size.height/15
|
||||
this.svg_el.setAttribute("width",size.width+"px");
|
||||
this.svg_el.setAttribute("height",size.height+"px");
|
||||
this.preview_el.style.width = size.width+10
|
||||
this.preview_el.style.height = size.height+10
|
||||
this.preview_el.setAttribute("width",size.width+"px");
|
||||
this.preview_el.setAttribute("height",size.height+"px");
|
||||
|
||||
dotgrid.guide.resize(size);
|
||||
this.interface.update();
|
||||
this.draw();
|
||||
}
|
||||
|
||||
this.draw = function(exp = false)
|
||||
{
|
||||
var paths = this.tool.paths();
|
||||
var d = this.tool.path();
|
||||
this.layer_1.setAttribute("d",paths[0]);
|
||||
this.layer_2.setAttribute("d",paths[1]);
|
||||
this.layer_3.setAttribute("d",paths[2]);
|
||||
|
||||
this.mirror_layer_1.setAttribute("d",this.mirror_index > 0 ? paths[0] : "M0,0");
|
||||
this.mirror_layer_2.setAttribute("d",this.mirror_index > 0 ? paths[1] : "M0,0");
|
||||
this.mirror_layer_3.setAttribute("d",this.mirror_index > 0 ? paths[2] : "M0,0");
|
||||
|
||||
this.svg_el.style.width = this.width;
|
||||
this.svg_el.style.height = this.height;
|
||||
this.svg_el.style.stroke = this.color;
|
||||
this.svg_el.style.strokeLinecap = this.linecap;
|
||||
this.svg_el.style.strokeLinejoin = this.linejoin;
|
||||
this.svg_el.style.strokeWidth = this.thickness*this.scale;
|
||||
this.svg_el.style.fill = this.fill ? this.theme.active.f_high : "none";
|
||||
|
||||
// Draw Mirror
|
||||
if(this.mirror_index == 1){
|
||||
this.mirror_layer_1.setAttribute("transform","translate("+(this.width - (this.offset.x*this.scale))+","+(this.offset.y*this.scale)+"),scale(-1,1)")
|
||||
this.mirror_layer_2.setAttribute("transform","translate("+(this.width - (this.offset.x*this.scale))+","+(this.offset.y*this.scale)+"),scale(-1,1)")
|
||||
this.mirror_layer_3.setAttribute("transform","translate("+(this.width - (this.offset.x*this.scale))+","+(this.offset.y*this.scale)+"),scale(-1,1)")
|
||||
}
|
||||
else if(this.mirror_index == 2){
|
||||
this.mirror_layer_1.setAttribute("transform","translate("+((this.offset.x*this.scale))+","+(this.height - (this.offset.y*this.scale))+"),scale(1,-1)")
|
||||
this.mirror_layer_2.setAttribute("transform","translate("+((this.offset.x*this.scale))+","+(this.height - (this.offset.y*this.scale))+"),scale(1,-1)")
|
||||
this.mirror_layer_3.setAttribute("transform","translate("+((this.offset.x*this.scale))+","+(this.height - (this.offset.y*this.scale))+"),scale(1,-1)")
|
||||
}
|
||||
else if(this.mirror_index == 3){
|
||||
this.mirror_layer_1.setAttribute("transform","translate("+(this.width -(this.offset.x*this.scale))+","+(this.height - (this.offset.y*this.scale))+"),scale(-1,-1)")
|
||||
this.mirror_layer_2.setAttribute("transform","translate("+(this.width -(this.offset.x*this.scale))+","+(this.height - (this.offset.y*this.scale))+"),scale(-1,-1)")
|
||||
this.mirror_layer_3.setAttribute("transform","translate("+(this.width -(this.offset.x*this.scale))+","+(this.height - (this.offset.y*this.scale))+"),scale(-1,-1)")
|
||||
}
|
||||
else{
|
||||
this.mirror_layer_1.setAttribute("transform","")
|
||||
this.mirror_layer_2.setAttribute("transform","")
|
||||
this.mirror_layer_3.setAttribute("transform","")
|
||||
}
|
||||
|
||||
this.offset_el.setAttribute("transform","translate("+(this.offset.x*this.scale)+","+(this.offset.y*this.scale)+")")
|
||||
|
||||
this.preview();
|
||||
this.render.draw();
|
||||
this.interface.update();
|
||||
this.guide.update();
|
||||
}
|
||||
|
||||
// Draw
|
||||
|
||||
this.reset = function()
|
||||
{
|
||||
this.tool.clear();
|
||||
}
|
||||
|
||||
this.clear = function()
|
||||
{
|
||||
this.history.clear();
|
||||
this.tool.reset();
|
||||
this.reset();
|
||||
this.thickness = 10
|
||||
this.linecap = "round"
|
||||
this.linejoin = "round"
|
||||
this.color = "#000000"
|
||||
this.draw();
|
||||
}
|
||||
|
||||
this.drag = function(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
var file = e.dataTransfer.files[0];
|
||||
|
||||
if(!file.path || file.path.indexOf(".dot") < 0){ console.log("Dotgrid","Not a dot file"); return; }
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e){
|
||||
dotgrid.tool.replace(JSON.parse(e.target.result.toString().trim()));
|
||||
dotgrid.draw();
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
||||
this.copy = function(e)
|
||||
{
|
||||
dotgrid.scale = 1
|
||||
dotgrid.width = 300
|
||||
dotgrid.height = 300
|
||||
dotgrid.draw();
|
||||
|
||||
var svg = dotgrid.svg_el.outerHTML;
|
||||
|
||||
e.clipboardData.setData('text/plain', dotgrid.tool.export(dotgrid.tool.layer()));
|
||||
e.clipboardData.setData('text/html', svg);
|
||||
e.clipboardData.setData('text/svg+xml', svg);
|
||||
|
||||
this.draw();
|
||||
}
|
||||
|
||||
this.cut = function(e)
|
||||
{
|
||||
dotgrid.scale = 1
|
||||
dotgrid.width = 300
|
||||
dotgrid.height = 300
|
||||
dotgrid.draw();
|
||||
|
||||
var svg = dotgrid.svg_el.outerHTML;
|
||||
|
||||
e.clipboardData.setData('text/plain', dotgrid.tool.export(dotgrid.tool.layer()));
|
||||
e.clipboardData.setData('text/html', svg);
|
||||
e.clipboardData.setData('text/svg+xml', svg);
|
||||
|
||||
dotgrid.tool.layers[dotgrid.tool.index] = [];
|
||||
|
||||
this.draw();
|
||||
}
|
||||
|
||||
this.paste = function(e)
|
||||
{
|
||||
var data = e.clipboardData.getData("text/plain");
|
||||
data = JSON.parse(data.trim());
|
||||
dotgrid.tool.import(data);
|
||||
this.draw();
|
||||
}
|
||||
|
||||
// Normalizers
|
||||
|
||||
this.position_in_grid = function(pos)
|
||||
{
|
||||
return new Pos((window.innerWidth/2) - (this.width/2) - pos.x,pos.y - (30+10*(this.scale)))
|
||||
}
|
||||
|
||||
this.position_on_grid = function(pos)
|
||||
{
|
||||
pos.y = pos.y - 7.5
|
||||
pos.x = pos.x + 7.5
|
||||
x = Math.round(pos.x/this.grid_width)*this.grid_width
|
||||
y = Math.round(pos.y/this.grid_height)*this.grid_height
|
||||
off = (x<-this.width || x>0 || y>this.height || y<0)
|
||||
if(off) {
|
||||
x = 50
|
||||
y = -50
|
||||
}
|
||||
return new Pos(x,y);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('resize', function(e)
|
||||
{
|
||||
dotgrid.draw()
|
||||
}, false);
|
||||
|
||||
window.addEventListener('dragover',function(e)
|
||||
{
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = 'copy';
|
||||
});
|
||||
147
desktop/sources/scripts/guide.js
Normal file
147
desktop/sources/scripts/guide.js
Normal file
@@ -0,0 +1,147 @@
|
||||
function Guide()
|
||||
{
|
||||
this.el = document.createElement("canvas");
|
||||
this.el.id = "guide";
|
||||
this.el.width = 640;
|
||||
this.el.height = 640;
|
||||
this.el.style.width = "320px";
|
||||
this.el.style.height = "320px";
|
||||
|
||||
this.widgets = document.createElement("canvas");
|
||||
this.widgets.id = "widgets";
|
||||
this.widgets.width = 640;
|
||||
this.widgets.height = 640;
|
||||
this.widgets.style.width = "320px";
|
||||
this.widgets.style.height = "320px";
|
||||
|
||||
this.start = function()
|
||||
{
|
||||
this.clear();
|
||||
this.draw();
|
||||
}
|
||||
|
||||
this.toggle = function()
|
||||
{
|
||||
this.el.style.opacity = !this.el.style.opacity || this.el.style.opacity == 1 ? 0 : 1;
|
||||
}
|
||||
|
||||
this.toggle_widgets = function()
|
||||
{
|
||||
this.widgets.style.opacity = !this.widgets.style.opacity || this.widgets.style.opacity == 1 ? 0 : 1;
|
||||
}
|
||||
|
||||
this.draw = function()
|
||||
{
|
||||
for (var x = dotgrid.grid_x; x >= 0; x--) {
|
||||
for (var y = dotgrid.grid_y; y >= 0; y--) {
|
||||
var pos_x = parseInt(x * dotgrid.grid_width) + dotgrid.grid_width ;
|
||||
var pos_y = parseInt(y * dotgrid.grid_height) + dotgrid.grid_height ;
|
||||
var is_step = x % dotgrid.block_x == 0 && y % dotgrid.block_y == 0;
|
||||
var radius = is_step ? 2.5 : 1.5;
|
||||
dotgrid.guide.draw_marker({x:pos_x,y:pos_y},radius,is_step);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.resize = function(size)
|
||||
{
|
||||
this.el.width = (size.width+40)*2;
|
||||
this.el.height = (size.height+40)*2;
|
||||
this.el.style.width = (size.width+40)+"px";
|
||||
this.el.style.height = (size.height+40)+"px";
|
||||
|
||||
this.widgets.width = (size.width+20)*2;
|
||||
this.widgets.height = (size.height+20)*2;
|
||||
this.widgets.style.width = (size.width+20)+"px";
|
||||
this.widgets.style.height = (size.height+20)+"px";
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
this.clear = function()
|
||||
{
|
||||
this.el.getContext('2d').clearRect(0, 0, 1280, 1280);
|
||||
this.widgets.getContext('2d').clearRect(0, 0, 1280, 1280);
|
||||
}
|
||||
|
||||
this.update = function()
|
||||
{
|
||||
this.clear();
|
||||
|
||||
for(id in dotgrid.tool.verteces){
|
||||
this.draw_vertex(dotgrid.tool.verteces[id]);
|
||||
}
|
||||
|
||||
for(segment_id in dotgrid.tool.layer()){
|
||||
var segment = dotgrid.tool.layer()[segment_id];
|
||||
for(vertex_id in segment.verteces){
|
||||
var vertex = segment.verteces[vertex_id];
|
||||
this.draw_handle(vertex);
|
||||
}
|
||||
}
|
||||
|
||||
// Translations
|
||||
if(dotgrid.translation){
|
||||
this.draw_translation();
|
||||
}
|
||||
this.draw();
|
||||
}
|
||||
|
||||
this.draw_vertex = function(pos, radius = 5)
|
||||
{
|
||||
var ctx = this.el.getContext('2d');
|
||||
ctx.beginPath();
|
||||
ctx.arc((pos.x * 2)+30, (pos.y * 2)+30, radius, 0, 2 * Math.PI, false);
|
||||
ctx.fillStyle = dotgrid.theme.active.f_med;
|
||||
ctx.fill();
|
||||
ctx.closePath();
|
||||
}
|
||||
|
||||
this.draw_marker = function(pos,radius = 1,step)
|
||||
{
|
||||
var ctx = this.el.getContext('2d');
|
||||
ctx.beginPath();
|
||||
ctx.arc(pos.x * 2, pos.y * 2, radius, 0, 2 * Math.PI, false);
|
||||
ctx.fillStyle = step ? dotgrid.theme.active.f_med : dotgrid.theme.active.f_low;
|
||||
ctx.fill();
|
||||
ctx.closePath();
|
||||
}
|
||||
|
||||
this.draw_handle = function(pos,radius = 5)
|
||||
{
|
||||
var ctx = this.widgets.getContext('2d');
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc((pos.x * 2)+20, (pos.y * 2)+20, 10, 0, 2 * Math.PI, false);
|
||||
ctx.fillStyle = dotgrid.theme.active.f_high;
|
||||
ctx.fill();
|
||||
ctx.closePath();
|
||||
ctx.beginPath();
|
||||
ctx.arc((pos.x * 2)+20, (pos.y * 2)+20, radius, 0, 2 * Math.PI, false);
|
||||
ctx.fillStyle = dotgrid.theme.active.f_high;
|
||||
ctx.fill();
|
||||
ctx.lineWidth = 3;
|
||||
ctx.strokeStyle = dotgrid.theme.active.background;
|
||||
ctx.stroke();
|
||||
ctx.closePath();
|
||||
}
|
||||
|
||||
this.draw_translation = function()
|
||||
{
|
||||
// From
|
||||
var ctx = this.widgets.getContext('2d');
|
||||
var from = dotgrid.translation.from;
|
||||
var to = dotgrid.translation.to;
|
||||
|
||||
if(to.x<=0) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo((from.x * -2)+20,(from.y * 2)+20);
|
||||
ctx.lineTo((to.x * -2)+20,(to.y * 2)+20);
|
||||
ctx.lineCap="round";
|
||||
ctx.lineWidth = 5;
|
||||
ctx.strokeStyle = dotgrid.theme.active.b_inv;
|
||||
ctx.stroke();
|
||||
ctx.closePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
79
desktop/sources/scripts/interface.js
Normal file
79
desktop/sources/scripts/interface.js
Normal file
@@ -0,0 +1,79 @@
|
||||
function Interface()
|
||||
{
|
||||
this.el = document.createElement("div");
|
||||
this.el.id = "interface";
|
||||
|
||||
this.is_visible = true;
|
||||
this.zoom = false;
|
||||
|
||||
this.start = function()
|
||||
{
|
||||
document.getElementById("app").appendChild(this.el);
|
||||
var html = ""
|
||||
var tools = {
|
||||
line: ["line","M60,60 L240,240",""],
|
||||
arc_c: ["arc clockwise","M60,60 A180,180 0 0,1 240,240",""],
|
||||
arc_r: ["arc reverse","M60,60 A180,180 0 0,0 240,240",""],
|
||||
bezier: ["bezier","M60,60 Q60,150 150,150 Q240,150 240,240",""],
|
||||
close: ["close","M60,60 A180,180 0 0,1 240,240 M60,60 A180,180 0 0,0 240,240",""],
|
||||
|
||||
thickness: ["thickness","M60,60 L240,240","stroke-dasharray: 30,15"],
|
||||
linecap: ["linecap","M60,60 L240,240 M240,180 L240,240 M180,240 L240,240"],
|
||||
linejoin: ["linejoin","M60,60 L120,120 L180,120 M120,180 L180,180 L240,240"],
|
||||
mirror: ["mirror","M60,60 L240,240 M180,120 L210,90 M120,180 L90,210"],
|
||||
fill: ["fill","M60,60 L60,150 L150,150 L240,150 L240,240 Z"],
|
||||
|
||||
export: ["export","M150,50 L50,150 L150,250 L250,150 L150,50 Z"]
|
||||
}
|
||||
|
||||
for(id in tools){
|
||||
var tool = tools[id];
|
||||
html += `<svg id="${id}" ar="${id}" title="${tool[0]}" viewBox="0 0 300 300" class="icon"><path class="icon_path" d="${tool[1]}" stroke-linecap: round; stroke-width="12px" fill="none" /><rect ar="${id}" width="300" height="300" opacity="0"><title>${id}</title></rect></svg>`
|
||||
}
|
||||
this.el.innerHTML = html
|
||||
}
|
||||
|
||||
this.update = function()
|
||||
{
|
||||
var layer_path = "M150,50 L50,150 L150,250 L250,150 L150,50 Z ";
|
||||
|
||||
layer_path += dotgrid.tool.index == 0 ? "M105,150 L105,150 L150,105 L195,150" : "";
|
||||
layer_path += dotgrid.tool.index == 1 ? "M105,150 L195,150" : "";
|
||||
layer_path += dotgrid.tool.index == 2 ? "M105,150 L105,150 L150,195 L195,150" : "";
|
||||
|
||||
document.getElementById("export").children[0].setAttribute("d",layer_path);
|
||||
|
||||
document.getElementById("line").className.baseVal = !dotgrid.tool.can_cast("line") ? "icon inactive" : "icon";
|
||||
document.getElementById("arc_c").className.baseVal = !dotgrid.tool.can_cast("arc_c") ? "icon inactive" : "icon";
|
||||
document.getElementById("arc_r").className.baseVal = !dotgrid.tool.can_cast("arc_r") ? "icon inactive" : "icon";
|
||||
document.getElementById("bezier").className.baseVal = !dotgrid.tool.can_cast("bezier") ? "icon inactive" : "icon";
|
||||
document.getElementById("close").className.baseVal = !dotgrid.tool.can_cast("close") ? "icon inactive" : "icon";
|
||||
|
||||
document.getElementById("thickness").className.baseVal = dotgrid.tool.layer().length < 1 ? "icon inactive" : "icon";
|
||||
document.getElementById("linecap").className.baseVal = dotgrid.tool.layer().length < 1 ? "icon inactive" : "icon";
|
||||
document.getElementById("linejoin").className.baseVal = dotgrid.tool.layer().length < 1 ? "icon inactive" : "icon";
|
||||
document.getElementById("mirror").className.baseVal = dotgrid.tool.layer().length < 1 ? "icon inactive" : "icon";
|
||||
document.getElementById("fill").className.baseVal = dotgrid.tool.layer().length < 1 ? "icon inactive" : "icon";
|
||||
|
||||
document.getElementById("export").className.baseVal = "icon";
|
||||
}
|
||||
|
||||
this.update_size = function()
|
||||
{
|
||||
var size = this.zoom ? {width:600,height:600} : {width:300,height:300};
|
||||
dotgrid.set_size(size,this.is_visible);
|
||||
}
|
||||
|
||||
this.toggle = function()
|
||||
{
|
||||
this.is_visible = this.is_visible ? false : true;
|
||||
this.el.className = this.is_visible ? "visible" : "hidden";
|
||||
this.update_size();
|
||||
}
|
||||
|
||||
this.toggle_zoom = function()
|
||||
{
|
||||
this.zoom = this.zoom ? false : true;
|
||||
this.update_size();
|
||||
}
|
||||
}
|
||||
196
desktop/sources/scripts/lib/controller.js
Normal file
196
desktop/sources/scripts/lib/controller.js
Normal file
@@ -0,0 +1,196 @@
|
||||
function Controller()
|
||||
{
|
||||
this.menu = {default:{}};
|
||||
this.mode = "default";
|
||||
|
||||
this.app = require('electron').remote.app;
|
||||
|
||||
this.start = function()
|
||||
{
|
||||
}
|
||||
|
||||
this.add = function(mode,cat,label,fn,accelerator)
|
||||
{
|
||||
if(!this.menu[mode]){ this.menu[mode] = {}; }
|
||||
if(!this.menu[mode][cat]){ this.menu[mode][cat] = {}; }
|
||||
this.menu[mode][cat][label] = {fn:fn,accelerator:accelerator};
|
||||
console.log(`${mode}/${cat}/${label} <${accelerator}>`);
|
||||
}
|
||||
|
||||
this.add_role = function(mode,cat,label)
|
||||
{
|
||||
if(!this.menu[mode]){ this.menu[mode] = {}; }
|
||||
if(!this.menu[mode][cat]){ this.menu[mode][cat] = {}; }
|
||||
this.menu[mode][cat][label] = {role:label};
|
||||
}
|
||||
|
||||
this.set = function(mode = "default")
|
||||
{
|
||||
this.mode = mode;
|
||||
this.commit();
|
||||
}
|
||||
|
||||
this.format = function()
|
||||
{
|
||||
var f = [];
|
||||
var m = this.menu[this.mode];
|
||||
for(cat in m){
|
||||
var submenu = [];
|
||||
for(name in m[cat]){
|
||||
var option = m[cat][name];
|
||||
if(option.role){
|
||||
submenu.push({role:option.role})
|
||||
}
|
||||
else{
|
||||
submenu.push({label:name,accelerator:option.accelerator,click:option.fn})
|
||||
}
|
||||
}
|
||||
f.push({label:cat,submenu:submenu});
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
this.commit = function()
|
||||
{
|
||||
this.app.inject_menu(this.format());
|
||||
}
|
||||
|
||||
this.docs = function()
|
||||
{
|
||||
console.log("Generating docs..");
|
||||
var svg = this.generate_svg(this.format())
|
||||
var txt = this.documentation(this.format());
|
||||
dialog.showSaveDialog((fileName) => {
|
||||
if (fileName === undefined){ return; }
|
||||
fileName = fileName.substr(-4,4) != ".svg" ? fileName+".svg" : fileName;
|
||||
fs.writeFile(fileName,svg);
|
||||
fs.writeFile(fileName.replace(".svg",".md"),txt);
|
||||
});
|
||||
}
|
||||
|
||||
this.generate_svg = function(m)
|
||||
{
|
||||
var svg_html = "";
|
||||
|
||||
for(id in this.layout){
|
||||
var key = this.layout[id];
|
||||
var acc = this.accelerator_for_key(key.name,m);
|
||||
svg_html += `<rect x="${key.x + 1}" y="${key.y + 1}" width="${key.width - 2}" height="${key.height - 2}" rx="4" ry="4" title="${key.name}" stroke="#ccc" fill="none" stroke-width="1"/>`;
|
||||
svg_html += `<rect x="${key.x + 3}" y="${key.y + 3}" width="${key.width - 6}" height="${key.height - 12}" rx="3" ry="3" title="${key.name}" stroke="${acc.basic ? '#000' : acc.ctrl ? '#ccc' : '#fff'}" fill="${acc.basic ? '#000' : acc.ctrl ? '#ccc' : '#fff'}" stroke-width="1"/>`;
|
||||
svg_html += `<text x="${key.x + 10}" y="${key.y + 20}" font-size='11' font-family='Input Mono' stroke-width='0' fill='${acc.basic ? '#fff' : '#000'}'>${key.name.toUpperCase()}</text>`;
|
||||
svg_html += acc && acc.basic ? `<text x="${key.x + 10}" y="${key.y + 35}" font-size='7' font-family='Input Mono' stroke-width='0' fill='#fff'>${acc.basic}</text>` : '';
|
||||
svg_html += acc && acc.ctrl ? `<text x="${key.x + 10}" y="${key.y + 45}" font-size='7' font-family='Input Mono' stroke-width='0' fill='#000'>${acc.ctrl}</text>` : '';
|
||||
}
|
||||
return `<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" width="900" height="300" version="1.0" style="fill:none;stroke:black;stroke-width:2px;">${svg_html}</svg>`;
|
||||
}
|
||||
|
||||
this.documentation = function()
|
||||
{
|
||||
var txt = "";
|
||||
|
||||
txt += this.documentation_for_mode("default",this.menu.default);
|
||||
|
||||
for(name in this.menu){
|
||||
if(name == "default"){ continue; }
|
||||
txt += this.documentation_for_mode(name,this.menu[name]);
|
||||
}
|
||||
return txt;
|
||||
}
|
||||
|
||||
this.documentation_for_mode = function(name,mode)
|
||||
{
|
||||
var txt = `## ${name} Mode\n\n`;
|
||||
|
||||
for(id in mode){
|
||||
if(id == "*"){ continue; }
|
||||
txt += `### ${id}\n`;
|
||||
for(name in mode[id]){
|
||||
var option = mode[id][name];
|
||||
txt += `- ${name}: \`${option.accelerator}\`\n`;
|
||||
}
|
||||
txt += "\n"
|
||||
}
|
||||
|
||||
return txt+"\n";
|
||||
}
|
||||
|
||||
this.accelerator_for_key = function(key,menu)
|
||||
{
|
||||
var acc = {basic:null,ctrl:null}
|
||||
for(cat in menu){
|
||||
var options = menu[cat];
|
||||
for(id in options.submenu){
|
||||
var option = options.submenu[id]; if(option.role){ continue; }
|
||||
acc.basic = (option.accelerator.toLowerCase() == key.toLowerCase()) ? option.label.toUpperCase().replace("TOGGLE ","").substr(0,8).trim() : acc.basic;
|
||||
acc.ctrl = (option.accelerator.toLowerCase() == ("CmdOrCtrl+"+key).toLowerCase()) ? option.label.toUpperCase().replace("TOGGLE ","").substr(0,8).trim() : acc.ctrl;
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
this.layout = [
|
||||
{x:0, y:0, width:60, height:60, name:"esc"},
|
||||
{x:60, y:0, width:60, height:60, name:"1"},
|
||||
{x:120, y:0, width:60, height:60, name:"2"},
|
||||
{x:180, y:0, width:60, height:60, name:"3"},
|
||||
{x:240, y:0, width:60, height:60, name:"4"},
|
||||
{x:300, y:0, width:60, height:60, name:"5"},
|
||||
{x:360, y:0, width:60, height:60, name:"6"},
|
||||
{x:420, y:0, width:60, height:60, name:"7"},
|
||||
{x:480, y:0, width:60, height:60, name:"8"},
|
||||
{x:540, y:0, width:60, height:60, name:"9"},
|
||||
{x:600, y:0, width:60, height:60, name:"0"},
|
||||
{x:660, y:0, width:60, height:60, name:"-"},
|
||||
{x:720, y:0, width:60, height:60, name:"plus"},
|
||||
{x:780, y:0, width:120, height:60, name:"backspace"},
|
||||
{x:0, y:60, width:90, height:60, name:"tab"},
|
||||
{x:90, y:60, width:60, height:60, name:"q"},
|
||||
{x:150, y:60, width:60, height:60, name:"w"},
|
||||
{x:210, y:60, width:60, height:60, name:"e"},
|
||||
{x:270, y:60, width:60, height:60, name:"r"},
|
||||
{x:330, y:60, width:60, height:60, name:"t"},
|
||||
{x:390, y:60, width:60, height:60, name:"y"},
|
||||
{x:450, y:60, width:60, height:60, name:"u"},
|
||||
{x:510, y:60, width:60, height:60, name:"i"},
|
||||
{x:570, y:60, width:60, height:60, name:"o"},
|
||||
{x:630, y:60, width:60, height:60, name:"p"},
|
||||
{x:690, y:60, width:60, height:60, name:"["},
|
||||
{x:750, y:60, width:60, height:60, name:"]"},
|
||||
{x:810, y:60, width:90, height:60, name:"|"},
|
||||
{x:0, y:120, width:105, height:60, name:"caps"},
|
||||
{x:105, y:120, width:60, height:60, name:"a"},
|
||||
{x:165, y:120, width:60, height:60, name:"s"},
|
||||
{x:225, y:120, width:60, height:60, name:"d"},
|
||||
{x:285, y:120, width:60, height:60, name:"f"},
|
||||
{x:345, y:120, width:60, height:60, name:"g"},
|
||||
{x:405, y:120, width:60, height:60, name:"h"},
|
||||
{x:465, y:120, width:60, height:60, name:"j"},
|
||||
{x:525, y:120, width:60, height:60, name:"k"},
|
||||
{x:585, y:120, width:60, height:60, name:"l"},
|
||||
{x:645, y:120, width:60, height:60, name:";"},
|
||||
{x:705, y:120, width:60, height:60, name:"'"},
|
||||
{x:765, y:120, width:135, height:60, name:"enter"},
|
||||
{x:0, y:180, width:135, height:60, name:"shift"},
|
||||
{x:135, y:180, width:60, height:60, name:"z"},
|
||||
{x:195, y:180, width:60, height:60, name:"x"},
|
||||
{x:255, y:180, width:60, height:60, name:"c"},
|
||||
{x:315, y:180, width:60, height:60, name:"v"},
|
||||
{x:375, y:180, width:60, height:60, name:"b"},
|
||||
{x:435, y:180, width:60, height:60, name:"n"},
|
||||
{x:495, y:180, width:60, height:60, name:"m"},
|
||||
{x:555, y:180, width:60, height:60, name:","},
|
||||
{x:615, y:180, width:60, height:60, name:"."},
|
||||
{x:675, y:180, width:60, height:60, name:"/"},
|
||||
{x:735, y:180, width:165, height:60, name:"capslock"},
|
||||
{x:0, y:240, width:90, height:60, name:"ctrl"},
|
||||
{x:90, y:240, width:90, height:60, name:"cmd"},
|
||||
{x:180, y:240, width:90, height:60, name:"alt"},
|
||||
{x:270, y:240, width:270, height:60, name:"space"},
|
||||
{x:810, y:240, width:90, height:60, name:"ctrl"},
|
||||
{x:720, y:240, width:90, height:60, name:"pn"},
|
||||
{x:630, y:240, width:90, height:60, name:"fn"},
|
||||
{x:540, y:240, width:90, height:60, name:"alt"}
|
||||
];
|
||||
}
|
||||
|
||||
module.exports = new Controller();
|
||||
50
desktop/sources/scripts/lib/history.js
Normal file
50
desktop/sources/scripts/lib/history.js
Normal file
@@ -0,0 +1,50 @@
|
||||
function History()
|
||||
{
|
||||
this.index = 0;
|
||||
this.a = [];
|
||||
|
||||
this.clear = function()
|
||||
{
|
||||
this.a = [];
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
this.push = function(data)
|
||||
{
|
||||
if(this.index < this.a.length-1){
|
||||
this.fork();
|
||||
}
|
||||
this.index = this.a.length;
|
||||
this.a = this.a.slice(0,this.index);
|
||||
this.a.push(copy(data));
|
||||
|
||||
if(this.a.length > 20){
|
||||
this.a.shift();
|
||||
}
|
||||
}
|
||||
|
||||
this.fork = function()
|
||||
{
|
||||
this.a = this.a.slice(0,this.index+1);
|
||||
}
|
||||
|
||||
this.pop = function()
|
||||
{
|
||||
return this.a.pop();
|
||||
}
|
||||
|
||||
this.prev = function()
|
||||
{
|
||||
this.index = clamp(this.index-1,0,this.a.length-1);
|
||||
return copy(this.a[this.index]);
|
||||
}
|
||||
|
||||
this.next = function()
|
||||
{
|
||||
this.index = clamp(this.index+1,0,this.a.length-1);
|
||||
return copy(this.a[this.index]);
|
||||
}
|
||||
|
||||
function copy(data){ return data ? JSON.parse(JSON.stringify(data)) : []; }
|
||||
function clamp(v, min, max) { return v < min ? min : v > max ? max : v; }
|
||||
}
|
||||
80
desktop/sources/scripts/lib/theme.js
Normal file
80
desktop/sources/scripts/lib/theme.js
Normal file
@@ -0,0 +1,80 @@
|
||||
function Theme()
|
||||
{
|
||||
var app = this;
|
||||
|
||||
this.el = document.createElement("style");
|
||||
this.el.type = 'text/css';
|
||||
this.default = {meta:{}, data: { background: "#222", f_high: "#fff", f_med: "#777", f_low: "#444", f_inv: "#000", b_high: "#000", b_med: "#affec7", b_low: "#000", b_inv: "#affec7" }}
|
||||
this.active = this.default;
|
||||
|
||||
this.start = function()
|
||||
{
|
||||
this.load(localStorage.theme && localStorage.theme.background ? localStorage.theme : this.default);
|
||||
window.addEventListener('dragover',this.drag_enter);
|
||||
window.addEventListener('drop', this.drag);
|
||||
document.head.appendChild(this.el)
|
||||
}
|
||||
|
||||
this.load = function(t)
|
||||
{
|
||||
var theme = is_json(t) ? JSON.parse(t).data : t.data;
|
||||
|
||||
if(!theme.background){ return; }
|
||||
|
||||
var css = `
|
||||
:root {
|
||||
--background: ${theme.background};
|
||||
--f_high: ${theme.f_high};
|
||||
--f_med: ${theme.f_med};
|
||||
--f_low: ${theme.f_low};
|
||||
--f_inv: ${theme.f_inv};
|
||||
--b_high: ${theme.b_high};
|
||||
--b_med: ${theme.b_med};
|
||||
--b_low: ${theme.b_low};
|
||||
--b_inv: ${theme.b_inv};
|
||||
}`;
|
||||
|
||||
this.active = theme;
|
||||
this.el.textContent = css;
|
||||
localStorage.setItem("theme", JSON.stringify(theme));
|
||||
}
|
||||
|
||||
this.reset = function()
|
||||
{
|
||||
this.load(this.default);
|
||||
}
|
||||
|
||||
this.drag_enter = function(e)
|
||||
{
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = 'copy';
|
||||
}
|
||||
|
||||
this.drag = function(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
var file = e.dataTransfer.files[0];
|
||||
|
||||
if(!file.name || !file.name.indexOf(".thm") < 0){ console.log("Theme","Not a theme"); return; }
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e){
|
||||
app.load(e.target.result);
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
||||
function is_json(text)
|
||||
{
|
||||
try{
|
||||
JSON.parse(text);
|
||||
return true;
|
||||
}
|
||||
catch (error){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
desktop/sources/scripts/pos.js
Normal file
47
desktop/sources/scripts/pos.js
Normal file
@@ -0,0 +1,47 @@
|
||||
function Pos(x,y)
|
||||
{
|
||||
this.__serialized_name__ = ".";
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
this.toString = function()
|
||||
{
|
||||
return x+","+y;
|
||||
}
|
||||
|
||||
this.sub = function(pos2)
|
||||
{
|
||||
return new Pos(this.x - pos2.x,this.y - pos2.y)
|
||||
}
|
||||
|
||||
this.add = function(pos2)
|
||||
{
|
||||
return new Pos(this.x + pos2.x,this.y + pos2.y)
|
||||
}
|
||||
|
||||
this.is_equal = function(pos2)
|
||||
{
|
||||
return Math.abs(pos2.x) == Math.abs(this.x) && Math.abs(pos2.y) == Math.abs(this.y);
|
||||
}
|
||||
|
||||
this.scale = function(a)
|
||||
{
|
||||
return new Pos(this.x*a,this.y*a)
|
||||
}
|
||||
|
||||
this.mirror = function(x = -1,y = 1)
|
||||
{
|
||||
return new Pos(this.x * x,this.y * y);
|
||||
}
|
||||
|
||||
this.clamp = function(min,max)
|
||||
{
|
||||
return new Pos(clamp(this.x,min,max),clamp(this.y,min,max));
|
||||
}
|
||||
|
||||
function clamp(v, min, max) { return v < min ? min : v > max ? max : v; }
|
||||
}
|
||||
|
||||
// This is ugly, but Pos.__serialized_name__ == ".";
|
||||
// Let's keep the character count low.
|
||||
window["."] = Pos;
|
||||
27
desktop/sources/scripts/render.js
Normal file
27
desktop/sources/scripts/render.js
Normal file
@@ -0,0 +1,27 @@
|
||||
function Render()
|
||||
{
|
||||
this.el = document.createElement("canvas"); this.el.id = "render";
|
||||
this.img = document.createElement("img");
|
||||
|
||||
this.el.width = 1280; this.el.height = 1280;
|
||||
|
||||
this.draw = function()
|
||||
{
|
||||
var xml = new XMLSerializer().serializeToString(dotgrid.svg_el);
|
||||
var svg64 = btoa(xml);
|
||||
var b64Start = 'data:image/svg+xml;base64,';
|
||||
var image64 = b64Start + svg64;
|
||||
this.img.src = image64;
|
||||
this.el.getContext('2d').clearRect(0, 0, 1280, 1280);
|
||||
this.el.getContext('2d').drawImage(this.img, 0, 0, 1280, 1280);
|
||||
}
|
||||
|
||||
this.buffer = function()
|
||||
{
|
||||
var fs = require('fs');
|
||||
var data = this.el.toDataURL('image/png').replace(/^data:image\/\w+;base64,/, "");
|
||||
var buf = new Buffer(data, 'base64');
|
||||
|
||||
return buf
|
||||
}
|
||||
}
|
||||
241
desktop/sources/scripts/tool.js
Normal file
241
desktop/sources/scripts/tool.js
Normal file
@@ -0,0 +1,241 @@
|
||||
function Tool()
|
||||
{
|
||||
this.index = 0;
|
||||
this.layers = [[],[],[]];
|
||||
this.verteces = [];
|
||||
this.reqs = {line:2,arc_c:2,arc_r:2,bezier:3,close:0};
|
||||
|
||||
this.reset = function()
|
||||
{
|
||||
this.layers = [[],[],[]];
|
||||
this.verteces = [];
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
this.layer = function()
|
||||
{
|
||||
if(!this.layers[this.index]){
|
||||
this.layers[this.index] = [];
|
||||
}
|
||||
return this.layers[this.index];
|
||||
}
|
||||
|
||||
this.remove_segment = function()
|
||||
{
|
||||
if(this.verteces.length > 0){ this.clear(); return; }
|
||||
|
||||
this.layer().pop();
|
||||
this.clear();
|
||||
dotgrid.draw();
|
||||
}
|
||||
|
||||
this.remove_segments_at = function(pos)
|
||||
{
|
||||
for(segment_id in this.layer()){
|
||||
var segment = this.layer()[segment_id];
|
||||
for(vertex_id in segment.verteces){
|
||||
var vertex = segment.verteces[vertex_id];
|
||||
if(Math.abs(pos.x) == Math.abs(vertex.x) && Math.abs(pos.y) == Math.abs(vertex.y)){
|
||||
segment.verteces.splice(vertex_id,1)
|
||||
}
|
||||
}
|
||||
if(segment.verteces.length < 2){
|
||||
this.layers[this.index].splice(segment_id,1)
|
||||
}
|
||||
}
|
||||
this.clear();
|
||||
dotgrid.draw();
|
||||
}
|
||||
|
||||
this.add_vertex = function(pos)
|
||||
{
|
||||
this.verteces.push(pos);
|
||||
}
|
||||
|
||||
this.vertex_at = function(pos)
|
||||
{
|
||||
for(segment_id in this.layer()){
|
||||
var segment = this.layer()[segment_id];
|
||||
for(vertex_id in segment.verteces){
|
||||
var vertex = segment.verteces[vertex_id];
|
||||
if(vertex.x == Math.abs(pos.x) && vertex.y == Math.abs(pos.y)){
|
||||
return vertex;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
this.cast = function(type)
|
||||
{
|
||||
if(!this.layer()){ this.layers[this.index] = []; }
|
||||
if(!this.can_cast(type)){ console.warn("Cannot cast"); return; }
|
||||
|
||||
var append_target = this.can_append({type:type,verteces:this.verteces.slice()})
|
||||
|
||||
if(append_target){
|
||||
this.layers[this.index][append_target].verteces = this.layers[this.index][append_target].verteces.concat(this.verteces.slice())
|
||||
}
|
||||
else{
|
||||
this.layer().push({type:type,verteces:this.verteces.slice()})
|
||||
}
|
||||
|
||||
this.clear();
|
||||
dotgrid.draw();
|
||||
dotgrid.history.push(this.layers);
|
||||
|
||||
console.log(`Casted ${type} -> ${this.layer().length} elements`);
|
||||
}
|
||||
|
||||
this.can_append = function(content)
|
||||
{
|
||||
for(id in this.layer()){
|
||||
var stroke = this.layer()[id];
|
||||
if(stroke.type != content.type){ continue; }
|
||||
if(stroke.verteces[stroke.verteces.length-1].x != content.verteces[0].x){ continue; }
|
||||
if(stroke.verteces[stroke.verteces.length-1].y != content.verteces[0].y){ continue; }
|
||||
return id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
this.can_cast = function(type)
|
||||
{
|
||||
if(!type){ return false; }
|
||||
// Cannot cast close twice
|
||||
if(type == "close"){
|
||||
var prev = this.layer()[this.layer().length-1];
|
||||
if(!prev || prev.type == "close"){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return this.verteces.length >= this.reqs[type];
|
||||
}
|
||||
|
||||
this.path = function(layer = this.layer())
|
||||
{
|
||||
if(layer.length > 0 && layer[0].type == "close"){ return ""; }
|
||||
|
||||
var html = "";
|
||||
for(id in layer){
|
||||
var segment = layer[id];
|
||||
html += segment.type == "close" ? "Z " : this.render(segment);
|
||||
}
|
||||
return html
|
||||
}
|
||||
|
||||
this.paths = function()
|
||||
{
|
||||
return [this.path(this.layers[0]),this.path(this.layers[1]),this.path(this.layers[2])]
|
||||
}
|
||||
|
||||
this.render = function(segment)
|
||||
{
|
||||
var type = segment.type;
|
||||
var verteces = segment.verteces;
|
||||
var html = ``;
|
||||
var skip = 0;
|
||||
|
||||
for(id in verteces){
|
||||
if(skip > 0){ skip -= 1; continue; }
|
||||
if(id == 0){ html += `M${verteces[id].x},${verteces[id].y} `; }
|
||||
var vertex = verteces[id];
|
||||
var next = verteces[parseInt(id)+1]
|
||||
var after_next = verteces[parseInt(id)+2]
|
||||
|
||||
if(type == "line"){
|
||||
html += `L${vertex.x},${vertex.y} `;
|
||||
}
|
||||
else if(type == "arc_c" && next){
|
||||
html += `A${next.x - vertex.x},${next.y - vertex.y} 0 0,1 ${next.x},${next.y} `;
|
||||
}
|
||||
else if(type == "arc_r" && next){
|
||||
html += `A${next.x - vertex.x},${next.y - vertex.y} 0 0,0 ${next.x},${next.y} `;
|
||||
}
|
||||
else if(type == "bezier" && next && after_next){
|
||||
html += `Q${next.x},${next.y} ${after_next.x},${after_next.y} `;
|
||||
skip = 1
|
||||
}
|
||||
}
|
||||
|
||||
return html
|
||||
}
|
||||
|
||||
this.translate = function(a,b)
|
||||
{
|
||||
for(segment_id in this.layer()){
|
||||
var segment = this.layer()[segment_id];
|
||||
for(vertex_id in segment.verteces){
|
||||
var vertex = segment.verteces[vertex_id];
|
||||
if(vertex.x == Math.abs(a.x) && vertex.y == Math.abs(a.y)){
|
||||
segment.verteces[vertex_id] = {x:Math.abs(b.x),y:Math.abs(b.y)};
|
||||
}
|
||||
}
|
||||
}
|
||||
dotgrid.history.push(this.layers);
|
||||
this.clear();
|
||||
dotgrid.draw();
|
||||
}
|
||||
|
||||
this.clear = function()
|
||||
{
|
||||
this.verteces = [];
|
||||
dotgrid.draw();
|
||||
}
|
||||
|
||||
this.undo = function()
|
||||
{
|
||||
this.layers = dotgrid.history.prev();
|
||||
dotgrid.draw();
|
||||
}
|
||||
|
||||
this.redo = function()
|
||||
{
|
||||
this.layers = dotgrid.history.next();
|
||||
dotgrid.draw();
|
||||
}
|
||||
|
||||
this.export = function(target = this.layers)
|
||||
{
|
||||
return JSON.stringify(copy(target), null, 2);
|
||||
}
|
||||
|
||||
this.replace = function(layers)
|
||||
{
|
||||
if(layers.length != 3){ console.log("Incompatible"); return; }
|
||||
|
||||
this.layers = layers;
|
||||
this.clear();
|
||||
dotgrid.draw();
|
||||
dotgrid.history.push(this.layers);
|
||||
}
|
||||
|
||||
this.import = function(layer)
|
||||
{
|
||||
this.layers[this.index] = this.layers[this.index].concat(layer)
|
||||
dotgrid.history.push(this.layers);
|
||||
this.clear();
|
||||
dotgrid.draw();
|
||||
}
|
||||
|
||||
this.select_layer = function(id)
|
||||
{
|
||||
this.index = clamp(id,0,2);
|
||||
this.clear();
|
||||
dotgrid.draw();
|
||||
console.log(`layer:${this.index}`)
|
||||
}
|
||||
|
||||
this.layer_up = function()
|
||||
{
|
||||
this.select_layer(this.index-1);
|
||||
}
|
||||
|
||||
this.layer_down = function()
|
||||
{
|
||||
this.select_layer(this.index+1);
|
||||
}
|
||||
|
||||
function copy(data){ return data ? JSON.parse(JSON.stringify(data)) : []; }
|
||||
function clamp(v, min, max) { return v < min ? min : v > max ? max : v; }
|
||||
}
|
||||
Reference in New Issue
Block a user