Progress toward new controls

This commit is contained in:
neauoire 2019-11-03 13:36:58 -05:00
parent 9a7149edb3
commit ec3fee9ec2
15 changed files with 399 additions and 307 deletions

View File

@ -1,6 +1,6 @@
'use strict' 'use strict'
function Cursor () { function Cursor (dotgrid) {
this.pos = { x: 0, y: 0 } this.pos = { x: 0, y: 0 }
this.translation = null this.translation = null
this.operation = null this.operation = null
@ -96,4 +96,6 @@ function Cursor () {
} }
function isEqual (a, b) { return a.x === b.x && a.y === b.y } function isEqual (a, b) { return a.x === b.x && a.y === b.y }
function clamp (v, min, max) { return v < min ? min : v > max ? max : v }
function step (v, s) { return Math.round(v / s) * s }
} }

View File

@ -1,23 +1,28 @@
'use strict' 'use strict'
function Dotgrid () { /* global Acels */
const defaultTheme = { /* global Theme */
background: '#eee', /* global Source */
f_high: '#000', /* global History */
f_med: '#999',
f_low: '#ccc',
f_inv: '#000',
b_high: '#000',
b_med: '#888',
b_low: '#aaa',
b_inv: '#ffb545'
}
/* global Manager */
/* global Renderer */
/* global Tool */
/* global Interface */
/* global Picker */
/* global Cursor */
/* global webFrame */
/* global FileReader */
function Dotgrid () {
// ISU // ISU
this.install = function (host) { this.install = function (host) {
console.info('Dotgrid', 'Installing..') console.info('Dotgrid', 'Installing..')
this.theme = new Theme(defaultTheme)
this.acels = new Acels()
this.theme = new Theme()
this.history = new History() this.history = new History()
this.source = new Source(this) this.source = new Source(this)
@ -27,47 +32,86 @@ function Dotgrid () {
this.interface = new Interface(this) this.interface = new Interface(this)
this.picker = new Picker(this) this.picker = new Picker(this)
this.cursor = new Cursor(this) this.cursor = new Cursor(this)
this.listener = new Listener(this)
host.appendChild(this.renderer.el) host.appendChild(this.renderer.el)
// Add events
document.addEventListener('mousedown', (e) => { this.cursor.down(e) }, false)
document.addEventListener('mousemove', (e) => { this.cursor.move(e) }, false)
document.addEventListener('contextmenu', (e) => { this.cursor.alt(e) }, false)
document.addEventListener('mouseup', (e) => { this.cursor.up(e) }, false)
document.addEventListener('copy', (e) => { this.copy(e) }, false)
document.addEventListener('cut', (e) => { this.cut(e) }, false)
document.addEventListener('paste', (e) => { this.paste(e) }, false)
window.addEventListener('resize', (e) => { this.onResize() }, false)
window.addEventListener('dragover', (e) => { e.stopPropagation(); e.preventDefault(); e.dataTransfer.dropEffect = 'copy' })
window.addEventListener('drop', this.drag)
this.acels.set('File', 'New', 'CmdOrCtrl+N', () => { this.source.new() })
this.acels.set('File', 'Save', 'CmdOrCtrl+S', () => { this.source.save('export.grid', this.commander._input.value, 'text/plain') })
this.acels.set('File', 'Export Image', 'CmdOrCtrl+E', () => { this.source.download('export.png', this.surface.el.toDataURL('image/png', 1.0), 'image/png') })
this.acels.set('File', 'Open', 'CmdOrCtrl+O', () => { this.source.open('grid', this.whenOpen) })
this.acels.set('File', 'Revert', 'CmdOrCtrl+W', () => { this.source.revert() })
this.acels.set('History', 'Undo', 'CmdOrCtrl+Z', () => { this.history.undo() })
this.acels.set('History', 'Redo', 'CmdOrCtrl+Shift+Z', () => { this.history.redo() })
this.acels.set('Stroke', 'Line', 'A', () => { this.tool.cast('line') })
this.acels.set('Stroke', 'Arc', 'S', () => { this.tool.cast('arc_c') })
this.acels.set('Stroke', 'Arc Rev', 'D', () => { this.tool.cast('arc_r') })
this.acels.set('Stroke', 'Bezier', 'F', () => { this.tool.cast('bezier') })
this.acels.set('Stroke', 'Close', 'Z', () => { this.tool.cast('close') })
this.acels.set('Stroke', 'Arc(full)', 'T', () => { this.tool.cast('arc_c_full') })
this.acels.set('Stroke', 'Arc Rev(full)', 'Y', () => { this.tool.cast('arc_r_full') })
this.acels.set('Stroke', 'Clear Selection', 'Escape', () => { this.tool.clear() })
this.acels.set('Effect', 'Linecap', 'Q', () => { this.tool.toggle('linecap') })
this.acels.set('Effect', 'Linejoin', 'W', () => { this.tool.toggle('linejoin') })
this.acels.set('Effect', 'Mirror', 'E', () => { this.tool.toggle('mirror') })
this.acels.set('Effect', 'Fill', 'R', () => { this.tool.toggle('fill') })
this.acels.set('Effect', 'Thicker', '}', () => { this.tool.toggle('thickness', 1) })
this.acels.set('Effect', 'Thinner', '{', () => { this.tool.toggle('thickness', -1) })
this.acels.set('Effect', 'Thicker +5', ']', () => { this.tool.toggle('thickness', 5) })
this.acels.set('Effect', 'Thinner -5', '[', () => { this.tool.toggle('thickness', -5) })
this.acels.set('Manual', 'Add Point', 'Enter', () => { this.tool.addVertex(this.cursor.pos); this.renderer.update() })
this.acels.set('Manual', 'Move Up', 'Up', () => { this.cursor.pos.y -= 15; this.renderer.update() })
this.acels.set('Manual', 'Move Right', 'Right', () => { this.cursor.pos.x += 15; this.renderer.update() })
this.acels.set('Manual', 'Move Down', 'Down', () => { this.cursor.pos.y += 15; this.renderer.update() })
this.acels.set('Manual', 'Move Left', 'Left', () => { this.cursor.pos.x -= 15; this.renderer.update() })
this.acels.set('Manual', 'Remove Point', 'Shift+Backspace', () => { this.tool.removeSegmentsAt(this.cursor.pos) })
this.acels.set('Manual', 'Remove Segment', 'Backspace', () => { this.tool.removeSegment() })
this.acels.set('Layers', 'Foreground', 'CmdOrCtrl+1', () => { this.tool.selectLayer(0) })
this.acels.set('Layers', 'Middleground', 'CmdOrCtrl+2', () => { this.tool.selectLayer(1) })
this.acels.set('Layers', 'Background', 'CmdOrCtrl+3', () => { this.tool.selectLayer(2) })
this.acels.set('Layers', 'Merge Layers', 'CmdOrCtrl+M', () => { this.tool.merge() })
this.acels.set('View', 'Color Picker', 'G', () => { this.picker.start() })
this.acels.set('View', 'Toggle Grid', 'H', () => { this.renderer.toggle() })
this.acels.install(window)
this.manager.install() this.manager.install()
this.interface.install(host) this.interface.install(host)
this.theme.install(host, () => { this.update() }) this.theme.install(host, () => { this.update() })
} }
this.start = function () { this.start = () => {
console.info('Dotgrid', 'Starting..') console.log('Ronin', 'Starting..')
console.info(`${this.acels}`)
this.theme.start() this.theme.start()
this.tool.start() this.tool.start()
this.renderer.start() this.renderer.start()
this.interface.start() this.interface.start()
// Add events
document.addEventListener('mousedown', function (e) { dotgrid.cursor.down(e) }, false)
document.addEventListener('mousemove', function (e) { dotgrid.cursor.move(e) }, false)
document.addEventListener('contextmenu', function (e) { dotgrid.cursor.alt(e) }, false)
document.addEventListener('mouseup', function (e) { dotgrid.cursor.up(e) }, false)
document.addEventListener('copy', function (e) { dotgrid.copy(e) }, false)
document.addEventListener('cut', function (e) { dotgrid.cut(e) }, false)
document.addEventListener('paste', function (e) { dotgrid.paste(e) }, false)
window.addEventListener('resize', function (e) { dotgrid.onResize() }, false)
window.addEventListener('dragover', function (e) { e.stopPropagation(); e.preventDefault(); e.dataTransfer.dropEffect = 'copy' })
window.addEventListener('drop', dotgrid.drag)
this.source.new() this.source.new()
this.onResize() this.onResize()
setTimeout(() => { document.body.className += ' ready' }, 250) setTimeout(() => { document.body.className += ' ready' }, 250)
} }
this.update = function () { this.update = () => {
this.manager.update() this.manager.update()
this.interface.update() this.interface.update()
this.renderer.update() this.renderer.update()
} }
this.clear = function () { this.clear = () => {
this.history.clear() this.history.clear()
this.tool.reset() this.tool.reset()
this.reset() this.reset()
@ -75,7 +119,7 @@ function Dotgrid () {
this.interface.update(true) this.interface.update(true)
} }
this.reset = function () { this.reset = () => {
this.tool.clear() this.tool.clear()
this.update() this.update()
} }
@ -103,7 +147,7 @@ function Dotgrid () {
// Resize Tools // Resize Tools
this.fitSize = function () { this.fitSize = () => {
if (this.requireResize() === false) { return } if (this.requireResize() === false) { return }
console.log('Dotgrid', `Will resize to: ${printSize(this.getRequiredSize())}`) console.log('Dotgrid', `Will resize to: ${printSize(this.getRequiredSize())}`)
this.setWindowSize(this.getRequiredSize()) this.setWindowSize(this.getRequiredSize())
@ -118,47 +162,47 @@ function Dotgrid () {
this.update() this.update()
} }
this.getPadding = function () { this.getPadding = () => {
return { x: 60, y: 90 } return { x: 60, y: 90 }
} }
this.getWindowSize = function () { this.getWindowSize = () => {
return { width: window.innerWidth, height: window.innerHeight } return { width: window.innerWidth, height: window.innerHeight }
} }
this.getProjectSize = function () { this.getProjectSize = () => {
return this.tool.settings.size return this.tool.settings.size
} }
this.getPaddedSize = function () { this.getPaddedSize = () => {
const rect = this.getWindowSize() const rect = this.getWindowSize()
const pad = this.getPadding() const pad = this.getPadding()
return { width: step(rect.width - pad.x, 15), height: step(rect.height - pad.y, 15) } return { width: step(rect.width - pad.x, 15), height: step(rect.height - pad.y, 15) }
} }
this.getRequiredSize = function () { this.getRequiredSize = () => {
const rect = this.getProjectSize() const rect = this.getProjectSize()
const pad = this.getPadding() const pad = this.getPadding()
return { width: step(rect.width, 15) + pad.x, height: step(rect.height, 15) + pad.y } return { width: step(rect.width, 15) + pad.x, height: step(rect.height, 15) + pad.y }
} }
this.requireResize = function () { this.requireResize = () => {
const _window = this.getWindowSize() const _window = this.getWindowSize()
const _required = this.getRequiredSize() const _required = this.getRequiredSize()
const offset = sizeOffset(_window, _required) const offset = sizeOffset(_window, _required)
if (offset.width !== 0 || offset.height !== 0) { if (offset.width !== 0 || offset.height !== 0) {
console.log(`Dotgrid`, `Require ${printSize(_required)}, but window is ${printSize(_window)}(${printSize(offset)})`) console.log('Dotgrid', `Require ${printSize(_required)}, but window is ${printSize(_window)}(${printSize(offset)})`)
return true return true
} }
return false return false
} }
this.onResize = function () { this.onResize = () => {
const _project = this.getProjectSize() const _project = this.getProjectSize()
const _padded = this.getPaddedSize() const _padded = this.getPaddedSize()
const offset = sizeOffset(_padded, _project) const offset = sizeOffset(_padded, _project)
if (offset.width !== 0 || offset.height !== 0) { if (offset.width !== 0 || offset.height !== 0) {
console.log(`Dotgrid`, `Resize project to ${printSize(_padded)}`) console.log('Dotgrid', `Resize project to ${printSize(_padded)}`)
this.tool.settings.size = _padded this.tool.settings.size = _padded
} }
this.update() this.update()
@ -179,39 +223,39 @@ function Dotgrid () {
reader.onload = function (e) { reader.onload = function (e) {
const data = e.target && e.target.result ? e.target.result : '' const data = e.target && e.target.result ? e.target.result : ''
dotgrid.source.load(filename, data) this.source.load(filename, data)
dotgrid.fitSize() this.fitSize()
} }
reader.readAsText(file) reader.readAsText(file)
} }
this.copy = function (e) { this.copy = function (e) {
dotgrid.renderer.update() this.renderer.update()
if (e.target !== this.picker.input) { if (e.target !== this.picker.input) {
e.clipboardData.setData('text/source', dotgrid.tool.export(dotgrid.tool.layer())) e.clipboardData.setData('text/source', this.tool.export(this.tool.layer()))
e.clipboardData.setData('text/plain', dotgrid.tool.path()) e.clipboardData.setData('text/plain', this.tool.path())
e.clipboardData.setData('text/html', dotgrid.manager.el.outerHTML) e.clipboardData.setData('text/html', this.manager.el.outerHTML)
e.clipboardData.setData('text/svg+xml', dotgrid.manager.el.outerHTML) e.clipboardData.setData('text/svg+xml', this.manager.el.outerHTML)
e.preventDefault() e.preventDefault()
} }
dotgrid.renderer.update() this.renderer.update()
} }
this.cut = function (e) { this.cut = function (e) {
dotgrid.renderer.update() this.renderer.update()
if (e.target !== this.picker.input) { if (e.target !== this.picker.input) {
e.clipboardData.setData('text/source', dotgrid.tool.export(dotgrid.tool.layer())) e.clipboardData.setData('text/source', this.tool.export(this.tool.layer()))
e.clipboardData.setData('text/plain', dotgrid.tool.export(dotgrid.tool.layer())) e.clipboardData.setData('text/plain', this.tool.export(this.tool.layer()))
e.clipboardData.setData('text/html', dotgrid.manager.el.outerHTML) e.clipboardData.setData('text/html', this.manager.el.outerHTML)
e.clipboardData.setData('text/svg+xml', dotgrid.manager.el.outerHTML) e.clipboardData.setData('text/svg+xml', this.manager.el.outerHTML)
dotgrid.tool.layers[dotgrid.tool.index] = [] this.tool.layers[this.tool.index] = []
e.preventDefault() e.preventDefault()
} }
dotgrid.renderer.update() this.renderer.update()
} }
this.paste = function (e) { this.paste = function (e) {
@ -219,12 +263,12 @@ function Dotgrid () {
let data = e.clipboardData.getData('text/source') let data = e.clipboardData.getData('text/source')
if (isJson(data)) { if (isJson(data)) {
data = JSON.parse(data.trim()) data = JSON.parse(data.trim())
dotgrid.tool.import(data) this.tool.import(data)
} }
e.preventDefault() e.preventDefault()
} }
dotgrid.renderer.update() this.renderer.update()
} }
} }

View File

@ -38,9 +38,9 @@ function Generator (layer, style) {
for (const id in vertices) { for (const id in vertices) {
if (skip > 0) { skip -= 1; continue } if (skip > 0) { skip -= 1; continue }
let vertex = vertices[parseInt(id)] const vertex = vertices[parseInt(id)]
let next = vertices[parseInt(id) + 1] const next = vertices[parseInt(id) + 1]
let afterNext = vertices[parseInt(id) + 2] const afterNext = vertices[parseInt(id) + 2]
if (parseInt(id) === 0 && !prev || parseInt(id) === 0 && prev && (prev.x !== vertex.x || prev.y !== vertex.y)) { if (parseInt(id) === 0 && !prev || parseInt(id) === 0 && prev && (prev.x !== vertex.x || prev.y !== vertex.y)) {
html += `M${vertex.x},${vertex.y} ` html += `M${vertex.x},${vertex.y} `
@ -49,16 +49,16 @@ function Generator (layer, style) {
if (type === 'line') { if (type === 'line') {
html += this._line(vertex) html += this._line(vertex)
} else if (type === 'arc_c') { } else if (type === 'arc_c') {
let clock = mirror > 0 && mirror < 3 ? '0,0' : '0,1' const clock = mirror > 0 && mirror < 3 ? '0,0' : '0,1'
html += this._arc(vertex, next, clock) html += this._arc(vertex, next, clock)
} else if (type === 'arc_r') { } else if (type === 'arc_r') {
let clock = mirror > 0 && mirror < 3 ? '0,1' : '0,0' const clock = mirror > 0 && mirror < 3 ? '0,1' : '0,0'
html += this._arc(vertex, next, clock) html += this._arc(vertex, next, clock)
} else if (type === 'arc_c_full') { } else if (type === 'arc_c_full') {
let clock = mirror > 0 ? '1,0' : '1,1' const clock = mirror > 0 ? '1,0' : '1,1'
html += this._arc(vertex, next, clock) html += this._arc(vertex, next, clock)
} else if (type === 'arc_r_full') { } else if (type === 'arc_r_full') {
let clock = mirror > 0 ? '1,1' : '1,0' const clock = mirror > 0 ? '1,1' : '1,0'
html += this._arc(vertex, next, clock) html += this._arc(vertex, next, clock)
} else if (type === 'bezier') { } else if (type === 'bezier') {
html += this._bezier(next, afterNext) html += this._bezier(next, afterNext)

View File

@ -16,7 +16,7 @@ function Interface (dotgrid) {
this.start = function (host) { this.start = function (host) {
let html = '' let html = ''
let options = { const options = {
cast: { cast: {
line: { key: 'A', icon: 'M60,60 L240,240' }, line: { key: 'A', icon: 'M60,60 L240,240' },
arc_c: { key: 'S', icon: 'M60,60 A180,180 0 0,1 240,240' }, arc_c: { key: 'S', icon: 'M60,60 A180,180 0 0,1 240,240' },
@ -57,7 +57,7 @@ function Interface (dotgrid) {
onmouseover="dotgrid.interface.over('${type}','${name}')" onmouseover="dotgrid.interface.over('${type}','${name}')"
viewBox="0 0 300 300" viewBox="0 0 300 300"
class="icon ${type}"> class="icon ${type}">
<path id="${name}_path" class="icon_path" d="${tool.icon}"/>${name === 'depth' ? `<path class="icon_path inactive" d=""/>` : ''} <path id="${name}_path" class="icon_path" d="${tool.icon}"/>${name === 'depth' ? '<path class="icon_path inactive" d=""/>' : ''}
<rect ar="${name}" width="300" height="300" opacity="0"> <rect ar="${name}" width="300" height="300" opacity="0">
<title>${name.capitalize()}${tool.key ? '(' + tool.key + ')' : ''}</title> <title>${name.capitalize()}${tool.key ? '(' + tool.key + ')' : ''}</title>
</rect> </rect>
@ -89,7 +89,7 @@ function Interface (dotgrid) {
this.down = function (type, name, event) { this.down = function (type, name, event) {
if (!dotgrid.tool[type]) { console.warn(`Unknown option(type): ${type}.${name}`, dotgrid.tool); return } if (!dotgrid.tool[type]) { console.warn(`Unknown option(type): ${type}.${name}`, dotgrid.tool); return }
const mod = event.button == 2 ? -1 : 1; const mod = event.button === 2 ? -1 : 1
dotgrid.tool[type](name, mod) dotgrid.tool[type](name, mod)
this.update(true) this.update(true)
dotgrid.renderer.update(true) dotgrid.renderer.update(true)
@ -101,7 +101,7 @@ function Interface (dotgrid) {
if (this.prev_operation === dotgrid.cursor.operation && force === false) { return } if (this.prev_operation === dotgrid.cursor.operation && force === false) { return }
let multiVertices = null let multiVertices = null
let segments = dotgrid.tool.layer() const segments = dotgrid.tool.layer()
const sumSegments = dotgrid.tool.length() const sumSegments = dotgrid.tool.length()
for (const i in segments) { for (const i in segments) {

View File

@ -0,0 +1,115 @@
'use strict'
function Acels () {
this.all = {}
this.install = (host = window) => {
host.addEventListener('keydown', this.onKeyDown, false)
host.addEventListener('keyup', this.onKeyUp, false)
}
this.set = (cat, name, accelerator, downfn, upfn) => {
if (this.all[accelerator]) { console.warn('Acels', `Trying to overwrite ${this.all[accelerator].name}, with ${name}.`) }
this.all[accelerator] = { cat, name, downfn, upfn, accelerator }
}
this.get = (accelerator) => {
return this.all[accelerator]
}
this.sort = () => {
const h = {}
for (const item of Object.values(this.all)) {
if (!h[item.cat]) { h[item.cat] = [] }
h[item.cat].push(item)
}
return h
}
this.convert = (event) => {
const accelerator = event.key.substr(0, 1).toUpperCase() + event.key.substr(1)
if ((event.ctrlKey || event.metaKey) && event.shiftKey) {
return `CmdOrCtrl+Shift+${accelerator}`
}
if (event.shiftKey) {
return `Shift+${accelerator}`
}
if (event.ctrlKey || event.metaKey) {
return `CmdOrCtrl+${accelerator}`
}
return accelerator
}
this.onKeyDown = (e) => {
const target = this.get(this.convert(e))
if (!target || !target.downfn) { return }
target.downfn()
e.preventDefault()
}
this.onKeyUp = (e) => {
const target = this.get(this.convert(e))
if (!target || !target.upfn) { return }
target.upfn()
e.preventDefault()
}
this.toMarkdown = () => {
const cats = this.sort()
let text = ''
for (const cat in cats) {
text += `\n### ${cat}\n\n`
for (const item of cats[cat]) {
text += `- \`${item.accelerator}\`: ${item.info}\n`
}
}
return text.trim()
}
this.toString = () => {
const cats = this.sort()
let text = ''
for (const cat in cats) {
for (const item of cats[cat]) {
text += `${cat}: ${item.name} | ${item.accelerator}\n`
}
}
return text.trim()
}
// Electron specifics
this.inject = (name = 'Untitled') => {
const app = require('electron').remote.app
const injection = []
injection.push({
label: name,
submenu: [
{ label: 'About', click: () => { require('electron').shell.openExternal('https://github.com/hundredrabbits/' + name) } },
{ label: 'Download Themes', click: () => { require('electron').shell.openExternal('https://github.com/hundredrabbits/Themes') } },
{ label: 'Fullscreen', accelerator: 'CmdOrCtrl+Enter', click: () => { app.toggleFullscreen() } },
{ label: 'Hide', accelerator: 'CmdOrCtrl+H', click: () => { app.toggleVisible() } },
{ label: 'Toggle Menubar', accelerator: 'Alt+H', click: () => { app.toggleMenubar() } },
{ label: 'Inspect', accelerator: 'CmdOrCtrl+.', click: () => { app.inspect() } },
{ label: 'Quit', accelerator: 'CmdOrCtrl+Q', click: () => { app.exit() } }
]
})
const sorted = this.sort()
for (const cat of Object.keys(sorted)) {
const submenu = []
for (const option of sorted[cat]) {
if (option.role) {
submenu.push({ role: option.role })
} else if (option.type) {
submenu.push({ type: option.type })
} else {
submenu.push({ label: option.name, accelerator: option.accelerator, click: option.downfn })
}
}
injection.push({ label: cat, submenu: submenu })
}
app.injectMenu(injection)
}
}

View File

@ -1,72 +0,0 @@
'use strict'
function Controller () {
const fs = require('fs')
const { dialog, app } = require('electron').remote
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 }
}
this.addRole = 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.clearCat = function (mode, cat) {
if (this.menu[mode]) { this.menu[mode][cat] = {} }
}
this.set = function (mode = 'default') {
this.mode = mode
this.commit()
}
this.format = function () {
const f = []
const m = this.menu[this.mode]
for (const cat in m) {
const submenu = []
for (const name in m[cat]) {
const 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.injectMenu(this.format())
}
this.accelerator_for_key = function (key, menu) {
const acc = { basic: null, ctrl: null }
for (cat in menu) {
const options = menu[cat]
for (const id in options.submenu) {
const 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
}
}
module.exports = new Controller()

View File

@ -0,0 +1,69 @@
'use strict'
/* global FileReader */
/* global MouseEvent */
function Source () {
this.cache = {}
this.install = () => {
}
this.start = () => {
this.new()
}
this.new = () => {
console.log('Source', 'New file..')
this.cache = {}
}
this.open = (ext, callback) => {
console.log('Source', 'Open file..')
const input = document.createElement('input')
input.type = 'file'
input.onchange = (e) => {
const file = e.target.files[0]
if (file.name.indexOf(ext) < 0) { console.warn('Source', 'File is not ' + ext); return }
this.cache = file
this.load(this.cache, callback)
}
input.click()
}
this.save = (name, content, type = 'text/plain', callback) => {
this.saveAs(name, content, type, callback)
}
this.saveAs = (name, content, type = 'text/plain', callback) => {
console.log('Source', 'Save new file..')
this.download(name, content, type, callback)
}
this.revert = () => {
}
// I/O
this.load = (file, callback) => {
const reader = new FileReader()
reader.onload = (event) => {
const res = event.target.result
callback(res)
}
reader.readAsText(file, 'UTF-8')
}
this.download = (name, content, type) => {
console.info('Source', `Downloading ${name}(${type})`)
const link = document.createElement('a')
link.setAttribute('download', name)
if (type === 'image/png' || type === 'image/jpeg') {
link.setAttribute('href', content)
} else {
link.setAttribute('href', 'data:' + type + ';charset=utf-8,' + encodeURIComponent(content))
}
link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }))
}
}

View File

@ -1,19 +1,25 @@
'use strict' 'use strict'
function Theme (_default) { /* global localStorage */
/* global FileReader */
/* global DOMParser */
function Theme () {
const themer = this const themer = this
this.active = _default this.default = { background: '#eee', f_high: '#000', f_med: '#999', f_low: '#ccc', f_inv: '#000', b_high: '#000', b_med: '#888', b_low: '#aaa', b_inv: '#ffb545' }
this.active = {}
this.el = document.createElement('style') this.el = document.createElement('style')
this.el.type = 'text/css' this.el.type = 'text/css'
this.install = function (host = document.body, callback) { this.install = (host = document.body, callback) => {
host.appendChild(this.el) host.appendChild(this.el)
this.callback = callback this.callback = callback
} }
this.start = function () { this.start = () => {
this.active = this.default
console.log('Theme', 'Starting..') console.log('Theme', 'Starting..')
if (isJson(localStorage.theme)) { if (isJson(localStorage.theme)) {
const storage = JSON.parse(localStorage.theme) const storage = JSON.parse(localStorage.theme)
@ -23,13 +29,13 @@ function Theme (_default) {
return return
} }
} }
this.load(_default) this.load(this.active)
} }
this.load = function (data) { this.load = (data) => {
const theme = parse(data) const theme = parse(data)
if (!validate(theme)) { console.warn('Theme', 'Not a theme', theme); return } if (!validate(theme)) { return }
console.log('Theme', `Loaded theme!`) console.log('Theme', 'Loaded theme!')
this.el.innerHTML = `: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.el.innerHTML = `: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}; }`
localStorage.setItem('theme', JSON.stringify(theme)) localStorage.setItem('theme', JSON.stringify(theme))
this.active = theme this.active = theme
@ -38,8 +44,12 @@ function Theme (_default) {
} }
} }
this.reset = function () { this.reset = () => {
this.load(_default) this.load(this.default)
}
this.get = (key) => {
return this.active[key]
} }
function parse (any) { function parse (any) {
@ -49,18 +59,18 @@ function Theme (_default) {
// Drag // Drag
this.drag = function (e) { this.drag = (e) => {
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
e.dataTransfer.dropEffect = 'copy' e.dataTransfer.dropEffect = 'copy'
} }
this.drop = function (e) { this.drop = (e) => {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
const file = e.dataTransfer.files[0] const file = e.dataTransfer.files[0]
if (!file || !file.name) { console.warn('Theme', 'Unnamed file.'); return } if (!file || !file.name) { console.warn('Theme', 'Unnamed file.'); return }
if (file.name.indexOf('.thm') < 0 && file.name.indexOf('.svg') < 0) { console.warn('Theme', 'Skipped, not a theme'); return } if (file.name.indexOf('.thm') < 0 && file.name.indexOf('.svg') < 0) { return }
const reader = new FileReader() const reader = new FileReader()
reader.onload = function (e) { reader.onload = function (e) {
themer.load(e.target.result) themer.load(e.target.result)
@ -68,10 +78,10 @@ function Theme (_default) {
reader.readAsText(file) reader.readAsText(file)
} }
this.open = function () { this.open = () => {
const fs = require('fs') const fs = require('fs')
const { dialog, app } = require('electron').remote const { dialog, app } = require('electron').remote
let paths = dialog.showOpenDialog(app.win, { properties: ['openFile'], filters: [{ name: 'Themes', extensions: ['svg'] }] }) const paths = dialog.showOpenDialog(app.win, { properties: ['openFile'], filters: [{ name: 'Themes', extensions: ['svg'] }] })
if (!paths) { console.log('Nothing to load'); return } if (!paths) { console.log('Nothing to load'); return }
fs.readFile(paths[0], 'utf8', function (err, data) { fs.readFile(paths[0], 'utf8', function (err, data) {
if (err) throw err if (err) throw err
@ -102,15 +112,15 @@ function Theme (_default) {
const svg = new DOMParser().parseFromString(text, 'text/xml') const svg = new DOMParser().parseFromString(text, 'text/xml')
try { try {
return { return {
'background': svg.getElementById('background').getAttribute('fill'), background: svg.getElementById('background').getAttribute('fill'),
'f_high': svg.getElementById('f_high').getAttribute('fill'), f_high: svg.getElementById('f_high').getAttribute('fill'),
'f_med': svg.getElementById('f_med').getAttribute('fill'), f_med: svg.getElementById('f_med').getAttribute('fill'),
'f_low': svg.getElementById('f_low').getAttribute('fill'), f_low: svg.getElementById('f_low').getAttribute('fill'),
'f_inv': svg.getElementById('f_inv').getAttribute('fill'), f_inv: svg.getElementById('f_inv').getAttribute('fill'),
'b_high': svg.getElementById('b_high').getAttribute('fill'), b_high: svg.getElementById('b_high').getAttribute('fill'),
'b_med': svg.getElementById('b_med').getAttribute('fill'), b_med: svg.getElementById('b_med').getAttribute('fill'),
'b_low': svg.getElementById('b_low').getAttribute('fill'), b_low: svg.getElementById('b_low').getAttribute('fill'),
'b_inv': svg.getElementById('b_inv').getAttribute('fill') b_inv: svg.getElementById('b_inv').getAttribute('fill')
} }
} catch (err) { } catch (err) {
console.warn('Theme', 'Incomplete SVG Theme', err) console.warn('Theme', 'Incomplete SVG Theme', err)

View File

@ -1,69 +0,0 @@
'use strict'
// Dotgrid UDP Listener
// Ex: 1a0156(6 characters 0-9a-z)
// 0 layer[0-2]
// 1 type[lcrd*]
// 2 from[0-z][0-z]
// 4 to[0-z][0-z]
const dgram = require('dgram')
function Listener (dotgrid) {
this.server = dgram.createSocket('udp4')
function base36 (c) {
return clamp(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y'].indexOf(c.toLowerCase()), 0, 36) * 15 + 15
}
function clear () {
dotgrid.tool.erase()
}
function operate (data) {
if (!data) { return }
if (!dotgrid.tool.layers[data.layer]) { return }
dotgrid.tool.addSegment(data.type, [data.from, data.to], data.layer)
}
function draw () {
dotgrid.renderer.update(true)
}
function parse (msg) {
if (msg === '' || msg === '*') {
return draw()
}
if (['0', '1', '2'].indexOf(msg) > -1) {
return clear()
}
const layer = parseInt(msg.substr(0, 1))
const type = { 'l': 'line', 'c': 'arc_c', 'r': 'arc_r', '*': 'draw' }[msg.substr(1, 1).toLowerCase()]
const from = { x: base36(msg.substr(2, 1)), y: base36(msg.substr(3, 1)) }
const to = { x: base36(msg.substr(4, 1)), y: base36(msg.substr(5, 1)) }
return { layer: layer, type: type, from: from, to: to }
}
function clamp (v, min, max) {
return v < min ? min : v > max ? max : v
}
// Server
this.server.on('message', (msg, rinfo) => {
operate(parse(`${msg}`))
})
this.server.on('listening', () => {
const address = this.server.address()
console.log(`Server listening for UDP:\n ${address.address}:${address.port}`)
})
this.server.on('error', (err) => {
console.log(`Server error:\n ${err.stack}`)
server.close()
})
this.server.bind(49161)
}

View File

@ -30,7 +30,7 @@ function Manager (dotgrid) {
for (const id in this.layers) { for (const id in this.layers) {
let style = styles[id] let style = styles[id]
let path = paths[id] let path = paths[id]
let layer = this.layers[id] const layer = this.layers[id]
// Easter Egg // Easter Egg
if (dotgrid.tool.settings.crest === true) { if (dotgrid.tool.settings.crest === true) {
style = styles[0] style = styles[0]
@ -49,9 +49,9 @@ function Manager (dotgrid) {
} }
this.svg64 = function () { this.svg64 = function () {
let xml = new XMLSerializer().serializeToString(this.el) const xml = new XMLSerializer().serializeToString(this.el)
let svg64 = btoa(xml) const svg64 = btoa(xml)
let b64Start = 'data:image/svg+xml;base64,' const b64Start = 'data:image/svg+xml;base64,'
return b64Start + svg64 return b64Start + svg64
} }
@ -60,9 +60,9 @@ function Manager (dotgrid) {
this.toPNG = function (size = dotgrid.tool.settings.size, callback) { this.toPNG = function (size = dotgrid.tool.settings.size, callback) {
this.update() this.update()
let image64 = this.svg64() const image64 = this.svg64()
let img = new Image() const img = new Image()
let canvas = document.createElement('canvas') const canvas = document.createElement('canvas')
canvas.width = (size.width) * 2 canvas.width = (size.width) * 2
canvas.height = (size.height) * 2 canvas.height = (size.height) * 2
img.onload = function () { img.onload = function () {

View File

@ -18,6 +18,9 @@ function Picker (dotgrid) {
this.input.setAttribute('placeholder', `${dotgrid.tool.style().color.replace('#', '').trim()}`) this.input.setAttribute('placeholder', `${dotgrid.tool.style().color.replace('#', '').trim()}`)
this.input.setAttribute('maxlength', 6) this.input.setAttribute('maxlength', 6)
this.input.addEventListener('keydown', this.onKeyDown, false)
this.input.addEventListener('keyup', this.onKeyUp, false)
dotgrid.interface.el.className = 'picker' dotgrid.interface.el.className = 'picker'
this.input.focus() this.input.focus()
this.input.value = '' this.input.value = ''
@ -27,7 +30,7 @@ function Picker (dotgrid) {
this.update = function () { this.update = function () {
if (!this.isActive) { return } if (!this.isActive) { return }
if (!is_color(this.input.value)) { return } if (!isColor(this.input.value)) { return }
const hex = `#${this.input.value}` const hex = `#${this.input.value}`
@ -50,7 +53,7 @@ function Picker (dotgrid) {
} }
this.validate = function () { this.validate = function () {
if (!is_color(this.input.value)) { return } if (!isColor(this.input.value)) { return }
const hex = `#${this.input.value}` const hex = `#${this.input.value}`
@ -60,28 +63,7 @@ function Picker (dotgrid) {
this.stop() this.stop()
} }
this.listen = function (e, is_down = false) { function isColor (val) {
if (is_down && !isColorChar(e.key)) {
e.preventDefault()
return
}
if (e.key === 'Enter') {
this.validate()
e.preventDefault()
return
}
if (e.key === 'Escape') {
this.stop()
e.preventDefault()
return
}
this.update()
}
function is_color (val) {
if (val.length !== 3 && val.length !== 6) { if (val.length !== 3 && val.length !== 6) {
return false return false
} }
@ -90,11 +72,22 @@ function Picker (dotgrid) {
return re.test(val) return re.test(val)
} }
function isColorChar (val) { this.onKeyDown = (e) => {
const re = /[0-9A-Fa-f]/g if (e.key === 'Enter') {
return re.test(val) this.validate()
e.preventDefault()
return
}
if (e.key === 'Escape') {
this.stop()
e.preventDefault()
return
}
e.stopPropagation()
} }
this.input.onkeydown = function (event) { dotgrid.picker.listen(event, true) } this.onKeyUp = (e) => {
this.input.onkeyup = function (event) { dotgrid.picker.listen(event) } e.stopPropagation()
this.update()
}
} }

View File

@ -19,7 +19,7 @@ function Renderer (dotgrid) {
this.update = function (force = false) { this.update = function (force = false) {
this.resize() this.resize()
dotgrid.manager.update() dotgrid.manager.update()
let render = new Image() const render = new Image()
render.onload = () => { render.onload = () => {
this.draw(render) this.draw(render)
} }
@ -106,7 +106,7 @@ function Renderer (dotgrid) {
for (let x = markers.w - 1; x >= 0; x--) { for (let x = markers.w - 1; x >= 0; x--) {
for (let y = markers.h - 1; y >= 0; y--) { for (let y = markers.h - 1; y >= 0; y--) {
let isStep = x % 4 === 0 && y % 4 === 0 const isStep = x % 4 === 0 && y % 4 === 0
// Don't draw margins // Don't draw margins
if (x === 0 || y === 0) { continue } if (x === 0 || y === 0) { continue }
this.drawMarker({ this.drawMarker({
@ -129,13 +129,13 @@ function Renderer (dotgrid) {
} }
this.drawPreview = function () { this.drawPreview = function () {
let operation = dotgrid.cursor.operation && dotgrid.cursor.operation.cast ? dotgrid.cursor.operation.cast : null const operation = dotgrid.cursor.operation && dotgrid.cursor.operation.cast ? dotgrid.cursor.operation.cast : null
if (!dotgrid.tool.canCast(operation)) { return } if (!dotgrid.tool.canCast(operation)) { return }
if (operation === 'close') { return } if (operation === 'close') { return }
let path = new Generator([{ vertices: dotgrid.tool.vertices, type: operation }]).toString({ x: 0, y: 0 }, 2) const path = new Generator([{ vertices: dotgrid.tool.vertices, type: operation }]).toString({ x: 0, y: 0 }, 2)
let style = { const style = {
color: dotgrid.theme.active.f_med, color: dotgrid.theme.active.f_med,
thickness: 2, thickness: 2,
strokeLinecap: 'round', strokeLinecap: 'round',
@ -201,7 +201,7 @@ function Renderer (dotgrid) {
} }
this.drawPath = function (path, style) { this.drawPath = function (path, style) {
let p = new Path2D(path) const p = new Path2D(path)
this.context.strokeStyle = style.color this.context.strokeStyle = style.color
this.context.lineWidth = style.thickness * this.scale this.context.lineWidth = style.thickness * this.scale

View File

@ -65,7 +65,7 @@ function Source (dotgrid) {
const link = document.createElement('a') const link = document.createElement('a')
link.setAttribute('href', base64) link.setAttribute('href', base64)
link.setAttribute('download', name) link.setAttribute('download', name)
link.dispatchEvent(new MouseEvent(`click`, { bubbles: true, cancelable: true, view: window })) link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }))
} }
function isJson (text) { try { JSON.parse(text); return true } catch (error) { return false } } function isJson (text) { try { JSON.parse(text); return true } catch (error) { return false } }

View File

@ -102,9 +102,9 @@ function Tool (dotgrid) {
this.removeSegmentsAt = function (pos) { this.removeSegmentsAt = function (pos) {
for (const segmentId in this.layer()) { for (const segmentId in this.layer()) {
let segment = this.layer()[segmentId] const segment = this.layer()[segmentId]
for (const vertexId in segment.vertices) { for (const vertexId in segment.vertices) {
let vertex = segment.vertices[vertexId] const vertex = segment.vertices[vertexId]
if (Math.abs(pos.x) === Math.abs(vertex.x) && Math.abs(pos.y) === Math.abs(vertex.y)) { if (Math.abs(pos.x) === Math.abs(vertex.x) && Math.abs(pos.y) === Math.abs(vertex.y)) {
segment.vertices.splice(vertexId, 1) segment.vertices.splice(vertexId, 1)
} }
@ -119,11 +119,11 @@ function Tool (dotgrid) {
} }
this.selectSegmentAt = function (pos, source = this.layer()) { this.selectSegmentAt = function (pos, source = this.layer()) {
let target_segment = null const target_segment = null
for (const segmentId in source) { for (const segmentId in source) {
let segment = source[segmentId] const segment = source[segmentId]
for (const vertexId in segment.vertices) { for (const vertexId in segment.vertices) {
let vertex = segment.vertices[vertexId] const vertex = segment.vertices[vertexId]
if (vertex.x === Math.abs(pos.x) && vertex.y === Math.abs(pos.y)) { if (vertex.x === Math.abs(pos.x) && vertex.y === Math.abs(pos.y)) {
return segment return segment
} }
@ -140,9 +140,9 @@ function Tool (dotgrid) {
this.vertexAt = function (pos) { this.vertexAt = function (pos) {
for (const segmentId in this.layer()) { for (const segmentId in this.layer()) {
let segment = this.layer()[segmentId] const segment = this.layer()[segmentId]
for (const vertexId in segment.vertices) { for (const vertexId in segment.vertices) {
let vertex = segment.vertices[vertexId] const vertex = segment.vertices[vertexId]
if (vertex.x === Math.abs(pos.x) && vertex.y === Math.abs(pos.y)) { if (vertex.x === Math.abs(pos.x) && vertex.y === Math.abs(pos.y)) {
return vertex return vertex
} }
@ -152,7 +152,7 @@ function Tool (dotgrid) {
} }
this.addSegment = function (type, vertices, index = this.index) { this.addSegment = function (type, vertices, index = this.index) {
let append_target = this.canAppend({ type: type, vertices: vertices }, index) const append_target = this.canAppend({ type: type, vertices: vertices }, index)
if (append_target) { if (append_target) {
this.layer(index)[append_target].vertices = this.layer(index)[append_target].vertices.concat(vertices) this.layer(index)[append_target].vertices = this.layer(index)[append_target].vertices.concat(vertices)
} else { } else {
@ -179,11 +179,11 @@ function Tool (dotgrid) {
this.toggle = function (type, mod = 1) { this.toggle = function (type, mod = 1) {
if (type === 'linecap') { if (type === 'linecap') {
let a = ['butt', 'square', 'round'] const a = ['butt', 'square', 'round']
this.i.linecap += mod this.i.linecap += mod
this.style().strokeLinecap = a[this.i.linecap % a.length] this.style().strokeLinecap = a[this.i.linecap % a.length]
} else if (type === 'linejoin') { } else if (type === 'linejoin') {
let a = ['miter', 'round', 'bevel'] const a = ['miter', 'round', 'bevel']
this.i.linejoin += mod this.i.linejoin += mod
this.style().strokeLinejoin = a[this.i.linejoin % a.length] this.style().strokeLinejoin = a[this.i.linejoin % a.length]
} else if (type === 'fill') { } else if (type === 'fill') {
@ -221,7 +221,7 @@ function Tool (dotgrid) {
this.canAppend = function (content, index = this.index) { this.canAppend = function (content, index = this.index) {
for (const id in this.layer(index)) { for (const id in this.layer(index)) {
let stroke = this.layer(index)[id] const stroke = this.layer(index)[id]
if (stroke.type !== content.type) { continue } if (stroke.type !== content.type) { continue }
if (!stroke.vertices) { continue } if (!stroke.vertices) { continue }
if (!stroke.vertices[stroke.vertices.length - 1]) { continue } if (!stroke.vertices[stroke.vertices.length - 1]) { continue }
@ -236,7 +236,7 @@ function Tool (dotgrid) {
if (!type) { return false } if (!type) { return false }
// Cannot cast close twice // Cannot cast close twice
if (type === 'close') { if (type === 'close') {
let prev = this.layer()[this.layer().length - 1] const prev = this.layer()[this.layer().length - 1]
if (!prev || prev.type === 'close') { if (!prev || prev.type === 'close') {
return false return false
} }
@ -250,9 +250,9 @@ function Tool (dotgrid) {
} }
this.paths = function () { this.paths = function () {
let l1 = new Generator(dotgrid.tool.layers[0], dotgrid.tool.styles[0]).toString({ x: 0, y: 0 }, 1) const l1 = new Generator(dotgrid.tool.layers[0], dotgrid.tool.styles[0]).toString({ x: 0, y: 0 }, 1)
let l2 = new Generator(dotgrid.tool.layers[1], dotgrid.tool.styles[1]).toString({ x: 0, y: 0 }, 1) const l2 = new Generator(dotgrid.tool.layers[1], dotgrid.tool.styles[1]).toString({ x: 0, y: 0 }, 1)
let l3 = new Generator(dotgrid.tool.layers[2], dotgrid.tool.styles[2]).toString({ x: 0, y: 0 }, 1) const l3 = new Generator(dotgrid.tool.layers[2], dotgrid.tool.styles[2]).toString({ x: 0, y: 0 }, 1)
return [l1, l2, l3] return [l1, l2, l3]
} }
@ -263,9 +263,9 @@ function Tool (dotgrid) {
this.translate = function (a, b) { this.translate = function (a, b) {
for (const segmentId in this.layer()) { for (const segmentId in this.layer()) {
let segment = this.layer()[segmentId] const segment = this.layer()[segmentId]
for (const vertexId in segment.vertices) { for (const vertexId in segment.vertices) {
let vertex = segment.vertices[vertexId] const vertex = segment.vertices[vertexId]
if (vertex.x === Math.abs(a.x) && vertex.y === Math.abs(a.y)) { if (vertex.x === Math.abs(a.x) && vertex.y === Math.abs(a.y)) {
segment.vertices[vertexId] = { x: Math.abs(b.x), y: Math.abs(b.y) } segment.vertices[vertexId] = { x: Math.abs(b.x), y: Math.abs(b.y) }
} }
@ -283,7 +283,7 @@ function Tool (dotgrid) {
if (!segment) { return } if (!segment) { return }
for (const vertexId in segment.vertices) { for (const vertexId in segment.vertices) {
let vertex = segment.vertices[vertexId] const vertex = segment.vertices[vertexId]
segment.vertices[vertexId] = { x: vertex.x - offset.x, y: vertex.y - offset.y } segment.vertices[vertexId] = { x: vertex.x - offset.x, y: vertex.y - offset.y }
} }
@ -295,9 +295,9 @@ function Tool (dotgrid) {
this.translateLayer = function (a, b) { this.translateLayer = function (a, b) {
const offset = { x: a.x - b.x, y: a.y - b.y } const offset = { x: a.x - b.x, y: a.y - b.y }
for (const segmentId in this.layer()) { for (const segmentId in this.layer()) {
let segment = this.layer()[segmentId] const segment = this.layer()[segmentId]
for (const vertexId in segment.vertices) { for (const vertexId in segment.vertices) {
let vertex = segment.vertices[vertexId] const vertex = segment.vertices[vertexId]
segment.vertices[vertexId] = { x: vertex.x - offset.x, y: vertex.y - offset.y } segment.vertices[vertexId] = { x: vertex.x - offset.x, y: vertex.y - offset.y }
} }
} }
@ -313,7 +313,7 @@ function Tool (dotgrid) {
if (!segment) { return } if (!segment) { return }
for (const vertexId in segment.vertices) { for (const vertexId in segment.vertices) {
let vertex = segment.vertices[vertexId] const vertex = segment.vertices[vertexId]
segment.vertices[vertexId] = { x: vertex.x - offset.x, y: vertex.y - offset.y } segment.vertices[vertexId] = { x: vertex.x - offset.x, y: vertex.y - offset.y }
} }
this.layer().push(segment) this.layer().push(segment)

View File

@ -19,6 +19,7 @@
<meta property="og:description" content="A minimalist vector graphics tool." /> <meta property="og:description" content="A minimalist vector graphics tool." />
<meta property="og:site_name" content="Dotgrid" /> <meta property="og:site_name" content="Dotgrid" />
<!-- Generics --> <!-- Generics -->
<script type="text/javascript" src="desktop/sources/scripts/lib/acels.js"></script>
<script type="text/javascript" src="desktop/sources/scripts/lib/theme.js"></script> <script type="text/javascript" src="desktop/sources/scripts/lib/theme.js"></script>
<script type="text/javascript" src="desktop/sources/scripts/lib/history.js"></script> <script type="text/javascript" src="desktop/sources/scripts/lib/history.js"></script>
<!-- Dotgrid --> <!-- Dotgrid -->
@ -30,9 +31,7 @@
<script type="text/javascript" src="desktop/sources/scripts/tool.js"></script> <script type="text/javascript" src="desktop/sources/scripts/tool.js"></script>
<script type="text/javascript" src="desktop/sources/scripts/generator.js"></script> <script type="text/javascript" src="desktop/sources/scripts/generator.js"></script>
<script type="text/javascript" src="desktop/sources/scripts/picker.js"></script> <script type="text/javascript" src="desktop/sources/scripts/picker.js"></script>
<script type="text/javascript" src="desktop/sources/scripts//source.js"></script> <script type="text/javascript" src="desktop/sources/scripts/source.js"></script>
<!-- Web Specific -->
<script type="text/javascript" src="web/events.js"></script>
<!-- Styles --> <!-- Styles -->
<link rel="stylesheet" type="text/css" href="desktop/sources/links/reset.css"/> <link rel="stylesheet" type="text/css" href="desktop/sources/links/reset.css"/>
<link rel="stylesheet" type="text/css" href="desktop/sources/links/fonts.css"/> <link rel="stylesheet" type="text/css" href="desktop/sources/links/fonts.css"/>
@ -42,14 +41,15 @@
</head> </head>
<body class='web'> <body class='web'>
<script> <script>
'use strict'; 'use strict'
function Listener(){}
const dialog = null;
const dotgrid = new Dotgrid() const dotgrid = new Dotgrid()
dotgrid.install(document.body);
window.addEventListener('load', () => { dotgrid.start(); }) dotgrid.install(document.body)
window.addEventListener('load', () => {
dotgrid.start()
})
</script> </script>
</body> </body>
</html> </html>