Improved helpers
This commit is contained in:
parent
12bba32b5d
commit
66c436b567
20
README.txt
20
README.txt
@ -29,23 +29,29 @@ Project Clean Escape
|
||||
|
||||
Example
|
||||
|
||||
; clear screen
|
||||
(clear)
|
||||
|
||||
; draw red square
|
||||
(stroke
|
||||
(rect 30 30 100 100) "red" 2)
|
||||
|
||||
; download result
|
||||
(export)
|
||||
|
||||
Helpers
|
||||
|
||||
Ronin helpers are keywords that facilitates adding coordinates from the canvas into your script. The currently supported helpers are `$rect`, `$pos`, `$circle`, `$line`, `$drag` and `$view`. Holding right-click while using a $helper will run the script as the mouse is injecting coordinates into the script. Paste the following script, and trace a shape in the canvas:
|
||||
Ronin helpers are keywords that facilitates adding coordinates from the canvas into your script. The currently supported helpers are $rect, $pos, $line, $circle & $arc. Holding right-click while using a $helper will run the script as the mouse is injecting coordinates into the script. Paste the following script, and trace a shape in the canvas:
|
||||
|
||||
; draw a red circle
|
||||
(fill $circle "red")
|
||||
|
||||
Additional helpers are also available to change parts of a shape, these are as follow: $x, $y, $xy, $wh, $a & $r. Paste the following script, and change the position and radius of a circle:
|
||||
|
||||
(clear)
|
||||
(fill
|
||||
(circle $xy $r) "red")
|
||||
|
||||
Extra helpers are available for various transformations, these are as follow: $drag, $view, $poly, $move & $rotate. Paste the following script, and draw the vertices of a line, press escape to stop:
|
||||
|
||||
(clear)
|
||||
(stroke
|
||||
$poly "red")
|
||||
|
||||
Import/Export
|
||||
|
||||
To save an image in memory, open an image file with Ronin, or drag an image file on the window. You will then be able to import it by using the file image's name. If the image file is `preview.png`, you can import it as follow:
|
||||
|
@ -10,12 +10,13 @@
|
||||
<link rel="stylesheet" type="text/css" href="./links/theme.css"/>
|
||||
|
||||
<script type="text/javascript" src="./scripts/lib/acels.js"></script>
|
||||
<script type="text/javascript" src="./scripts/lib/lisp.js"></script>
|
||||
<script type="text/javascript" src="./scripts/lib/lain.js"></script>
|
||||
<script type="text/javascript" src="./scripts/lib/source.js"></script>
|
||||
<script type="text/javascript" src="./scripts/lib/theme.js"></script>
|
||||
|
||||
<script type="text/javascript" src="./scripts/client.js"></script>
|
||||
<script type="text/javascript" src="./scripts/commander.js"></script>
|
||||
<script type="text/javascript" src="./scripts/lain(old).js"></script>
|
||||
<script type="text/javascript" src="./scripts/library.js"></script>
|
||||
<script type="text/javascript" src="./scripts/surface.js"></script>
|
||||
|
||||
|
@ -1,80 +1,78 @@
|
||||
(clear)
|
||||
;
|
||||
(open $path)
|
||||
(open $path 0.75)
|
||||
|
||||
; picker to elementary
|
||||
|
||||
(def unit 40)
|
||||
(def unit 10)
|
||||
(def f
|
||||
(get-frame))
|
||||
(def pos-row-1
|
||||
(sub f:h
|
||||
(mul unit 4)))
|
||||
(sub f:h 80))
|
||||
(def pos-row-2
|
||||
(sub f:h
|
||||
(mul unit 2)))
|
||||
(sub f:h 45))
|
||||
|
||||
; color picker
|
||||
|
||||
(def color-1
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(rect 846 220 unit unit))))
|
||||
(def color-2
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(rect 584 364 unit unit))))
|
||||
(def color-3
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(rect 70 538 unit unit))))
|
||||
(def color-4
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(rect 468 650 unit unit))))
|
||||
(def color-5
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(rect 254 246 unit unit))))
|
||||
(def color-6
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(rect 190 502 unit unit))))
|
||||
(def color-7
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(rect 1084 446 unit unit))))
|
||||
(def color-8
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(rect 1068 730 unit unit))))
|
||||
|
||||
; display
|
||||
|
||||
(fill
|
||||
(circle
|
||||
(mul unit 2) pos-row-1 unit) color-1)
|
||||
(mul 20 2) pos-row-1 18) color-1)
|
||||
(fill
|
||||
(circle
|
||||
(mul unit 4) pos-row-1 unit) color-2)
|
||||
(mul 20 4) pos-row-1 18) color-2)
|
||||
(fill
|
||||
(circle
|
||||
(mul unit 6) pos-row-1 unit) color-3)
|
||||
(mul 20 6) pos-row-1 18) color-3)
|
||||
(fill
|
||||
(circle
|
||||
(mul unit 8) pos-row-1 unit) color-4)
|
||||
(mul 20 8) pos-row-1 18) color-4)
|
||||
(fill
|
||||
(circle
|
||||
(mul unit 3) pos-row-2 unit) color-5)
|
||||
(mul 20 3) pos-row-2 18) color-5)
|
||||
(fill
|
||||
(circle
|
||||
(mul unit 5) pos-row-2 unit) color-6)
|
||||
(mul 20 5) pos-row-2 18) color-6)
|
||||
(fill
|
||||
(circle
|
||||
(mul unit 7) pos-row-2 unit) color-7)
|
||||
(mul 20 7) pos-row-2 18) color-7)
|
||||
(fill
|
||||
(circle
|
||||
(mul unit 9) pos-row-2 unit) color-8)
|
||||
(mul 20 9) pos-row-2 18) color-8)
|
||||
;
|
||||
(def res
|
||||
(add color-1:hex ":" color-2:hex ":" color-3:hex ":" color-4:hex ":" color-5:hex ":" color-6:hex ":" color-7:hex ":" color-8:hex))
|
||||
|
1499
index.html
1499
index.html
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,7 @@ body { margin:0px; padding:0px; overflow:hidden; font-family:"input_mono_regular
|
||||
#ronin #wrapper #commander textarea { background: none; width: 100%; height: calc(100vh - 105px); resize: none; font-size: 12px;line-height: 15px; padding-right: 15px}
|
||||
#ronin #wrapper #commander #status { position: absolute; bottom: 0px; line-height: 15px; height: 30px; overflow: hidden; width: calc(100% - 75px); padding-left:45px;}
|
||||
#ronin #wrapper #commander #status #run { display: block; width: 26px; height: 26px; position: absolute; top: 0px; border-radius: 15px; left:0px; cursor: pointer; border:2px solid #fff; transition: background-color 250ms, border-color 250ms}
|
||||
#ronin #wrapper #commander #status #run:hover { background: none }
|
||||
#ronin.expand #wrapper #commander { width:100%; }
|
||||
#ronin #surface, #ronin #guide { position: absolute; top:0px; -webkit-user-select: none;-webkit-app-region: no-drag; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20'><circle cx='10' cy='10' r='1' fill='%23555'></circle></svg>"); background-size: 10px 10px; background-position: -4px -4px; width:100%; height:100%; transition: left 250ms, opacity 250ms; opacity: 1; }
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
/* global Commander */
|
||||
/* global Surface */
|
||||
/* global Library */
|
||||
/* global Lisp */
|
||||
/* global Lain */
|
||||
/* global Image */
|
||||
/* global requestAnimationFrame */
|
||||
|
||||
@ -21,7 +21,7 @@ function Client () {
|
||||
this.commander = new Commander(this)
|
||||
this.surface = new Surface(this)
|
||||
this.library = new Library(this)
|
||||
this.lisp = new Lisp(this.library)
|
||||
this.lain = new Lain(this.library)
|
||||
|
||||
this.bindings = {}
|
||||
|
||||
@ -226,6 +226,7 @@ function Client () {
|
||||
}
|
||||
const wh = rect.w + ' ' + rect.h
|
||||
const d = Math.sqrt(((line.a.x - line.b.x) * (line.a.x - line.b.x)) + ((line.a.y - line.b.y) * (line.a.y - line.b.y))).toFixed(2)
|
||||
const r = d
|
||||
const a = Math.atan2(pos.y - line.a.y, pos.x - line.a.x).toFixed(2)
|
||||
const circle = {
|
||||
cx: line.a.x,
|
||||
@ -239,6 +240,6 @@ function Client () {
|
||||
sa: 0,
|
||||
ea: a
|
||||
}
|
||||
return { x, y, xy, wh, d, a, line, rect, pos, size, circle, arc, type, 'is-down': type !== 'mouse-up' ? true : null }
|
||||
return { x, y, xy, wh, d, r, a, line, rect, pos, size, circle, arc, type, 'is-down': type !== 'mouse-up' ? true : null }
|
||||
}
|
||||
}
|
||||
|
@ -30,21 +30,23 @@ function Commander (client) {
|
||||
this._input.onkeydown = (e) => {
|
||||
if (e.keyCode === 9 || e.which === 9) { e.preventDefault(); this.inject(' ') }
|
||||
}
|
||||
client.surface.maximize()
|
||||
}
|
||||
|
||||
this.start = function () {
|
||||
this.setStatus('Ready.')
|
||||
this.load(this.splash)
|
||||
this.show()
|
||||
this._input.value = this.splash
|
||||
setTimeout(() => { this.run() }, 1000)
|
||||
this.setStatus('Ready.')
|
||||
}
|
||||
|
||||
this.run = (txt = this._input.value) => {
|
||||
if (this._input.value.indexOf('$') > -1) { txt = this.clean(txt) }
|
||||
client.bindings = {}
|
||||
if (this._input.value.trim() === '') {
|
||||
client.surface.maximize()
|
||||
|
||||
}
|
||||
client.lisp.run(txt)
|
||||
client.lain.run(`(${txt})`)
|
||||
this.feedback()
|
||||
}
|
||||
|
||||
@ -180,7 +182,7 @@ function Commander (client) {
|
||||
if (word === 'line') { return `(line ${shape.a.x} ${shape.a.y} ${shape.b.x} ${shape.b.y})` }
|
||||
if (word === 'circle') { return `(circle ${shape.cx} ${shape.cy} ${shape.r})` }
|
||||
if (word === 'arc') { return `(arc ${shape.cx} ${shape.cy} ${shape.r} ${shape.sa} ${shape.ea})` }
|
||||
if (word === 'x' || word === 'y' || word === 'xy' || word === 'wh' || word === 'a') { return `${shape}` }
|
||||
if (word === 'x' || word === 'y' || word === 'xy' || word === 'wh' || word === 'a' || word === 'r') { return `${shape}` }
|
||||
return ''
|
||||
}
|
||||
|
||||
@ -240,7 +242,7 @@ function Commander (client) {
|
||||
const name = this.getCurrentFunction()
|
||||
const fn = client.library[name]
|
||||
if (!fn) { return }
|
||||
const fnString = fn.toString().replace('async ', '')
|
||||
const fnString = fn.toString()
|
||||
if (fnString.indexOf(') => {') < 0) { return }
|
||||
const fnParams = fnString.split(') => {')[0].substr(1).split(',').reduce((acc, item) => { return `${acc}${item.indexOf('=') > -1 ? '~' + item.split('=')[0].trim() : item} ` }, '').trim()
|
||||
return `(${(name + ' ' + fnParams).trim()})`
|
||||
@ -248,17 +250,14 @@ function Commander (client) {
|
||||
|
||||
// Splash
|
||||
|
||||
this.splash = `
|
||||
; Ronin v2.40
|
||||
(clear)
|
||||
this.splash = `; Ronin v2.50
|
||||
|
||||
(def logo-path "M60,60 L195,60 A45,45 0 0,1 240,105 A45,45 0 0,1 195,150 L60,150 M195,150 A45,45 0 0,1 240,195 L240,240 ")
|
||||
(def pos-x
|
||||
(mul frame:c 0.25))
|
||||
(def pos-y
|
||||
(sub frame:m 150))
|
||||
;
|
||||
(clear)
|
||||
(resize 600 600)
|
||||
(stroke
|
||||
(svg pos-x pos-y logo-path) theme:f_high 5)
|
||||
`
|
||||
(svg 140 140 logo-path) "black" 7)`
|
||||
|
||||
function insert (str, add, i) {
|
||||
return [str.slice(0, i), `${add}`, str.slice(i)].join('')
|
||||
|
145
scripts/lib/lain.js
Normal file
145
scripts/lib/lain.js
Normal file
@ -0,0 +1,145 @@
|
||||
'use strict'
|
||||
|
||||
// In the real world, it didn’t matter if I was there or not.
|
||||
// When I realized that, I was no longer afraid of losing my body.
|
||||
|
||||
function Lain (lib = {}) {
|
||||
const TYPES = { identifier: 0, number: 1, string: 2, bool: 3, symbol: 4 }
|
||||
|
||||
const Context = function (scope, parent) {
|
||||
this.scope = scope
|
||||
this.parent = parent
|
||||
this.get = function (identifier) {
|
||||
if (identifier in this.scope) {
|
||||
return this.scope[identifier]
|
||||
} else if (this.parent !== undefined) {
|
||||
return this.parent.get(identifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const special = {
|
||||
let: function (input, context) {
|
||||
const letContext = input[1].reduce(function (acc, x) {
|
||||
acc.scope[x[0].value] = interpret(x[1], context)
|
||||
return acc
|
||||
}, new Context({}, context))
|
||||
return interpret(input[2], letContext)
|
||||
},
|
||||
def: function (input, context) {
|
||||
if (input.length !== 3) { console.warn('Lain', 'Invalid definition.'); return }
|
||||
const identifier = input[1].host ? input[1].host : input[1].value
|
||||
if (input[1].host) {
|
||||
if (!context.scope[identifier]) { context.scope[identifier] = {} }
|
||||
context.scope[identifier][input[1].value] = interpret(input[2], context)
|
||||
return context.scope[identifier][input[1].value]
|
||||
}
|
||||
context.scope[identifier] = interpret(input[2], context)
|
||||
return context.scope[identifier]
|
||||
},
|
||||
defn: function (input, context) {
|
||||
const identifier = input[1].value
|
||||
if (context.scope[identifier]) { console.warn('Lain', `Redefining function: ${identifier}`) }
|
||||
const fnParams = input[2].type === TYPES.string && input[3] ? input[3] : input[2]
|
||||
const fnBody = input[2].type === TYPES.string && input[4] ? input[4] : input[3]
|
||||
context.scope[identifier] = function () {
|
||||
const lambdaArguments = arguments
|
||||
const lambdaScope = fnParams.reduce(function (acc, x, i) {
|
||||
acc[x.value] = lambdaArguments[i]
|
||||
return acc
|
||||
}, {})
|
||||
return interpret(fnBody, new Context(lambdaScope, context))
|
||||
}
|
||||
},
|
||||
λ: function (input, context) {
|
||||
return function () {
|
||||
const lambdaArguments = arguments
|
||||
const lambdaScope = input[1].reduce(function (acc, x, i) {
|
||||
acc[x.value] = lambdaArguments[i]
|
||||
return acc
|
||||
}, {})
|
||||
return interpret(input[2], new Context(lambdaScope, context))
|
||||
}
|
||||
},
|
||||
if: function (input, context) {
|
||||
return interpret(input[1], context) ? interpret(input[2], context) : input[3] ? interpret(input[3], context) : []
|
||||
}
|
||||
}
|
||||
|
||||
const interpretList = function (input, context) {
|
||||
if (input.length > 0 && input[0].value in special) {
|
||||
return special[input[0].value](input, context)
|
||||
}
|
||||
const list = []
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
if (input[i].type === TYPES.symbol) {
|
||||
if (input[i].host) {
|
||||
const host = context.get(input[i].host)
|
||||
if (host) {
|
||||
list.push(host[input[i].value])
|
||||
}
|
||||
} else {
|
||||
list.push(obj => obj[input[i].value])
|
||||
}
|
||||
} else {
|
||||
list.push(interpret(input[i], context))
|
||||
}
|
||||
}
|
||||
return list[0] instanceof Function ? list[0].apply(undefined, list.slice(1)) : list
|
||||
}
|
||||
|
||||
const interpret = function (input, context) {
|
||||
if (!input) { console.warn('Lain', context.scope); return null }
|
||||
if (context === undefined) {
|
||||
return interpret(input, new Context(lib))
|
||||
} else if (input instanceof Array) {
|
||||
return interpretList(input, context)
|
||||
} else if (input.type === TYPES.identifier) {
|
||||
return context.get(input.value)
|
||||
} else if (input.type === TYPES.number || input.type === TYPES.symbol || input.type === TYPES.string || input.type === TYPES.bool) {
|
||||
return input.value
|
||||
}
|
||||
}
|
||||
|
||||
const categorize = function (input) {
|
||||
if (!isNaN(parseFloat(input))) {
|
||||
return { type: TYPES.number, value: parseFloat(input) }
|
||||
} else if (input[0] === '"' && input.slice(-1) === '"') {
|
||||
return { type: TYPES.string, value: input.slice(1, -1) }
|
||||
} else if (input[0] === ':') {
|
||||
return { type: TYPES.symbol, value: input.slice(1) }
|
||||
} else if (input.indexOf(':') > 0) {
|
||||
return { type: TYPES.symbol, host: input.split(':')[0], value: input.split(':')[1] }
|
||||
} else if (input === 'true' || input === 'false') {
|
||||
return { type: TYPES.bool, value: input === 'true' }
|
||||
} else {
|
||||
return { type: TYPES.identifier, value: input }
|
||||
}
|
||||
}
|
||||
|
||||
const parenthesize = function (input, list) {
|
||||
if (list === undefined) { return parenthesize(input, []) }
|
||||
const token = input.shift()
|
||||
if (token === undefined) {
|
||||
return list.pop()
|
||||
} else if (token === '(') {
|
||||
list.push(parenthesize(input, []))
|
||||
return parenthesize(input, list)
|
||||
} else if (token === ')') {
|
||||
return list
|
||||
} else {
|
||||
return parenthesize(input, list.concat(categorize(token)))
|
||||
}
|
||||
}
|
||||
|
||||
const tokenize = function (input) {
|
||||
const i = input.replace(/^[\s]*;.*\n?/gm, '').split('"')
|
||||
return i.map(function (x, i) {
|
||||
return i % 2 === 0 ? x.replace(/\(/g, ' ( ').replace(/\)/g, ' ) ') : x.replace(/ /g, '!ws!')
|
||||
}).join('"').trim().split(/\s+/).map(function (x) { return x.replace(/!ws!/g, ' ') })
|
||||
}
|
||||
|
||||
this.run = (input) => {
|
||||
return interpret(parenthesize(tokenize(input)))
|
||||
}
|
||||
}
|
@ -86,7 +86,7 @@ function Theme (client) {
|
||||
this.active[key] = hex
|
||||
}
|
||||
|
||||
this.read = (key) => {
|
||||
this.get = (key) => {
|
||||
return this.active[key]
|
||||
}
|
||||
|
||||
|
@ -5,22 +5,23 @@
|
||||
|
||||
function Library (client) {
|
||||
// IO
|
||||
this.open = async (name, scale = 1) => { // Import a graphic and scale canvas to fit.
|
||||
this.open = (name, scale = 1) => { // Import a graphic and scale canvas to fit.
|
||||
const img = client.cache.get(name)
|
||||
if (!img) { client.log('No data for ' + name); return }
|
||||
const rect = this.rect(0, 0, img.width * scale, img.height * scale)
|
||||
await this.resize(rect.w, rect.h).then(this.import(name, rect))
|
||||
this.resize(rect.w, rect.h)
|
||||
this.import(name, rect)
|
||||
return rect
|
||||
}
|
||||
|
||||
this.import = async (name, shape, alpha = 1) => { // Imports a graphic file with format.
|
||||
this.import = (name, shape, alpha = 1) => { // Imports a graphic file with format.
|
||||
const img = client.cache.get(name)
|
||||
if (!img) { client.log('No data for ' + name); return }
|
||||
client.surface.draw(img, shape, alpha)
|
||||
return shape || this.rect(0, 0, img.width, img.height)
|
||||
}
|
||||
|
||||
this.export = async (name = 'ronin', type = 'image/png', quality = 1.0) => { // Exports a graphic file with format.
|
||||
this.export = (name = 'ronin', type = 'image/png', quality = 1.0) => { // Exports a graphic file with format.
|
||||
const ext = type === 'image/png' ? name + '.png' : name + '.jpg'
|
||||
client.source.write(name, ext, client.surface.el.toDataURL(type, 1.0), type)
|
||||
}
|
||||
@ -79,36 +80,36 @@ function Library (client) {
|
||||
|
||||
// Frame
|
||||
|
||||
this.resize = async (w = client.surface.bounds().w, h = client.surface.bounds().h, fit = true) => { // Resizes the canvas to target w and h, returns the rect.
|
||||
this.resize = (w = client.surface.bounds().w, h = client.surface.bounds().h, fit = true) => { // Resizes the canvas to target w and h, returns the rect.
|
||||
if (w === this['get-frame']().w && h === this['get-frame']().h) { return }
|
||||
const rect = { x: 0, y: 0, w, h }
|
||||
const a = document.createElement('img')
|
||||
const b = document.createElement('img')
|
||||
a.src = client.surface.el.toDataURL()
|
||||
await client.surface.resizeImage(a, b)
|
||||
client.surface.resizeImage(a, b)
|
||||
client.surface.resize(rect, fit)
|
||||
return client.surface.draw(b, rect)
|
||||
}
|
||||
|
||||
this.rescale = async (w = 1, h) => { // Rescales the canvas to target ratio of w and h, returns the rect.
|
||||
this.rescale = (w = 1, h) => { // Rescales the canvas to target ratio of w and h, returns the rect.
|
||||
const rect = { x: 0, y: 0, w: this['get-frame']().w * w, h: this['get-frame']().h * (h || w) }
|
||||
const a = document.createElement('img')
|
||||
const b = document.createElement('img')
|
||||
a.src = client.surface.el.toDataURL()
|
||||
await client.surface.resizeImage(a, b)
|
||||
client.surface.resizeImage(a, b)
|
||||
client.surface.resize(rect, true)
|
||||
return client.surface.draw(b, rect)
|
||||
}
|
||||
|
||||
this.crop = async (rect = this['get-frame']()) => { // Crop canvas to rect.
|
||||
this.crop = (rect = this['get-frame']()) => { // Crop canvas to rect.
|
||||
return client.surface.crop(rect)
|
||||
}
|
||||
|
||||
this.copy = async (rect = this['get-frame']()) => { // Copy a section of the canvas.
|
||||
this.copy = (rect = this['get-frame']()) => { // Copy a section of the canvas.
|
||||
return client.surface.copy(rect)
|
||||
}
|
||||
|
||||
this.paste = async (copy, rect = this['get-frame']()) => { // Paste a section of the canvas.
|
||||
this.paste = (copy, rect = this['get-frame']()) => { // Paste a section of the canvas.
|
||||
return client.surface.paste(copy, rect)
|
||||
}
|
||||
|
||||
@ -123,6 +124,7 @@ function Library (client) {
|
||||
}
|
||||
|
||||
this.view = (a, b) => { // View a part of the canvas.
|
||||
if (!a || !b) { return }
|
||||
this.guide({ a: { x: a.x, y: a.y }, b: { x: b.x, y: b.y } })
|
||||
this.guide(a)
|
||||
this.guide(b)
|
||||
@ -142,8 +144,8 @@ function Library (client) {
|
||||
return this.color(this.floor(sum[0] / count), this.floor(sum[1] / count), this.floor(sum[2] / count))
|
||||
}
|
||||
|
||||
this.orient = async (deg = 0) => { // Orient canvas with angle in degrees.
|
||||
const copy = await this.copy()
|
||||
this.orient = (deg = 0) => { // Orient canvas with angle in degrees.
|
||||
const copy = this.copy()
|
||||
const frame = this['get-frame']()
|
||||
const mode = Math.floor(deg / 90) % 4
|
||||
const offset = { x: [0, 0, -frame.w, -frame.w], y: [0, -frame.h, -frame.h, 0] }
|
||||
@ -157,8 +159,8 @@ function Library (client) {
|
||||
}
|
||||
|
||||
this.mirror = { // Mirror canvas, methods: `x`, `y`.
|
||||
x: async (j = 0) => {
|
||||
const copy = await this.copy()
|
||||
x: (j = 0) => {
|
||||
const copy = this.copy()
|
||||
const frame = this['get-frame']()
|
||||
client.surface.context.save()
|
||||
client.surface.context.translate(frame.w, 0)
|
||||
@ -166,8 +168,8 @@ function Library (client) {
|
||||
client.surface.context.drawImage(copy, 0, 0)
|
||||
client.surface.context.restore()
|
||||
},
|
||||
y: async (j = 0) => {
|
||||
const copy = await this.copy()
|
||||
y: (j = 0) => {
|
||||
const copy = this.copy()
|
||||
const frame = this['get-frame']()
|
||||
client.surface.context.save()
|
||||
client.surface.context.translate(0, frame.h)
|
||||
@ -240,12 +242,12 @@ function Library (client) {
|
||||
|
||||
// Pixels
|
||||
|
||||
this.pixels = async (fn, q = 1, rect = this['get-frame']()) => {
|
||||
this.pixels = (fn, q = 1, rect = this['get-frame']()) => {
|
||||
if (!fn) { console.warn('Unknown function'); return rect }
|
||||
const img = client.surface.context.getImageData(rect.x, rect.y, rect.w, rect.h)
|
||||
for (let i = 0, loop = img.data.length; i < loop; i += 4) {
|
||||
const pixel = [img.data[i], img.data[i + 1], img.data[i + 2], img.data[i + 3]]
|
||||
const processed = await fn(pixel, q)
|
||||
const processed = fn(pixel, q)
|
||||
img.data[i] = this.clamp(parseInt(processed[0]), 0, 255)
|
||||
img.data[i + 1] = this.clamp(parseInt(processed[1]), 0, 255)
|
||||
img.data[i + 2] = this.clamp(parseInt(processed[2]), 0, 255)
|
||||
@ -412,10 +414,10 @@ function Library (client) {
|
||||
|
||||
// Arrays
|
||||
|
||||
this.each = async (arr, fn) => { // Run a function for each element in a list.
|
||||
this.each = (arr, fn) => { // Run a function for each element in a list.
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const arg = arr[i]
|
||||
await fn(arg)
|
||||
fn(arg)
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,11 +435,11 @@ function Library (client) {
|
||||
})
|
||||
}
|
||||
|
||||
this.reduce = async (arr, fn, acc) => {
|
||||
this.reduce = (arr, fn, acc) => {
|
||||
const length = arr.length
|
||||
let result = acc === undefined ? arr[0] : acc
|
||||
for (let i = acc === undefined ? 1 : 0; i < length; i++) {
|
||||
result = await fn(result, arr[i], i, arr)
|
||||
result = fn(result, arr[i], i, arr)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -589,9 +591,9 @@ function Library (client) {
|
||||
return a === b
|
||||
}
|
||||
|
||||
this.benchmark = async (fn) => { // Logs time taken to execute a function.
|
||||
this.benchmark = (fn) => { // Logs time taken to execute a function.
|
||||
const start = Date.now()
|
||||
const result = await fn()
|
||||
const result = fn()
|
||||
console.log(`time taken: ${Date.now() - start}ms`)
|
||||
return result
|
||||
}
|
||||
|
@ -174,24 +174,21 @@ function Surface (client) {
|
||||
// IO
|
||||
|
||||
this.draw = function (img, shape = this.getFrame(), alpha = 1) {
|
||||
return new Promise(resolve => {
|
||||
this.context.globalAlpha = alpha
|
||||
if (isLine(shape)) {
|
||||
this.context.drawImage(img, shape.a.x, shape.a.y, shape.b.x - shape.a.x, shape.b.y - shape.a.y)
|
||||
} else if (isRect(shape)) {
|
||||
const fit = fitRect({ w: img.width, h: img.height }, { w: shape.w, h: shape.h })
|
||||
this.context.drawImage(img, shape.x, shape.y, fit.w, fit.h)
|
||||
} else if (isCircle(shape)) {
|
||||
const side = Math.sqrt(Math.pow(shape.r, 2) / 2)
|
||||
const rect = { x: shape.cx - (side), y: shape.cy - (side), w: side * 2, h: side * 2 }
|
||||
const fit = fitRect({ w: img.width, h: img.height }, { w: rect.w, h: rect.h })
|
||||
this.context.drawImage(img, rect.x, rect.y, fit.w, fit.h)
|
||||
} else {
|
||||
this.context.drawImage(img, shape.x, shape.y, img.width, img.height)
|
||||
}
|
||||
this.context.globalAlpha = 1
|
||||
resolve()
|
||||
})
|
||||
this.context.globalAlpha = alpha
|
||||
if (isLine(shape)) {
|
||||
this.context.drawImage(img, shape.a.x, shape.a.y, shape.b.x - shape.a.x, shape.b.y - shape.a.y)
|
||||
} else if (isRect(shape)) {
|
||||
const fit = fitRect({ w: img.width, h: img.height }, { w: shape.w, h: shape.h })
|
||||
this.context.drawImage(img, shape.x, shape.y, fit.w, fit.h)
|
||||
} else if (isCircle(shape)) {
|
||||
const side = Math.sqrt(Math.pow(shape.r, 2) / 2)
|
||||
const rect = { x: shape.cx - (side), y: shape.cy - (side), w: side * 2, h: side * 2 }
|
||||
const fit = fitRect({ w: img.width, h: img.height }, { w: rect.w, h: rect.h })
|
||||
this.context.drawImage(img, rect.x, rect.y, fit.w, fit.h)
|
||||
} else {
|
||||
this.context.drawImage(img, shape.x, shape.y, img.width, img.height)
|
||||
}
|
||||
this.context.globalAlpha = 1
|
||||
}
|
||||
|
||||
this.crop = function (rect) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user