Parse
File Parse stroke.js
This tree is parsed live from the source file.
Classes
-
{{ item.name }}
- {{ key }}
Not Classes
{{ getTree() }}
Comments
{{ getTreeComments() }}
Source
// const drawPointLine = function(pointsArray, position) {
// // To 'close' the old drawing.
// ctx.beginPath();
// let {x, y} = position
// for(let i=0; i < pointsArray.length-1; i++) {
// let segment = pointsArray[i]
// ctx.lineTo(segment.x + x, segment.y + y);
// }
// ctx.strokeStyle = 'white'
// ctx.stroke()
// }
const UNSET = {}
const quickStroke = function(color='green', lineWidth=UNSET, f) {
ctx.strokeStyle = color.call? color(): color
if(lineWidth != UNSET) {
ctx.lineWidth = lineWidth
}
f && f()
ctx.stroke()
}
const quickStrokeWithCtx = function(ctx, color='green', lineWidth=UNSET, f) {
ctx.strokeStyle = color.call? color(): color
if(lineWidth != UNSET) {
ctx.lineWidth = lineWidth
}
f && f()
ctx.stroke()
}
class Stroke extends SetUnset {
getOpts() {
/* ctx properties of which don't need map adapting, */
let supported = new Set([
"strokeStyle"
, "lineWidth"
, "lineCap"
, "lineJoin"
, "lineDashOffset"
])
/* Convenience names to real names */
let map = {
color: 'strokeStyle'
, style: 'strokeStyle'
, offset: 'lineDashOffset'
, width: 'lineWidth'
, cap: 'lineCap'
, join: 'lineJoin'
}
/* Special methods to perform _more than_ a prop key.*/
let functional = {
dash: 'lineDashKeyApply'
, lineDash: 'lineDashKeyApply'
, march: ['marchKeyPrepare', 'marchKeyApply','marchKeyStep']
// dash: 'lineDashKeyPrepare'
// , lineDash: 'lineDashKeyPrepare'
// , march: 'marchKeyPrepare'
}
return { supported, map, functional }
}
march(delta=1) {
/* Performing a dashoffset (if applied)
This is simply a more specific _step_ function
*/
let v = this.settings?.march
if(v == undefined) {
v = 1
}
return this._march += delta * v
}
step(delta=1) {
return this.march(delta)
}
marchKeyPrepare() {
if(this._march == undefined) {
this._march = 0
}
// return this.marchKeyApply.apply(this, arguments)
}
marchKeyStep(ref){
this._march += ref.v
}
marchKeyApply(ctx, key, newValue) {
/* The given key should be the "march" param, and the value applied
within the setup. Apply marching ants by applying the internal stepper
value as the lineDashOffset.
*/
let v = this._cache?.lineDashKeyApply.v
if(v) {
this._march %= v.reduce((a,b)=>a+b)
}
return this.genericKeyApply(ctx, 'lineDashOffset', this._march)
}
lineDashKeyApply(ctx, key, newValue, k) {
let existing = ctx.getLineDash()
try {
ctx.setLineDash(newValue)
}catch(e) {
if(typeof(newValue) == 'number') {
console.warn('dash property should be of type Array: [1]')
}
throw e
}
return {v: existing, f: this.lineDashKeyRemove, k:k }
}
lineDashKeyRemove(ctx, key, cachedValue) {
/* To remove the line dash we call setLineDash with the inverse of the
previously applied value `cachedValue`. */
ctx.setLineDash(cachedValue)
return cachedValue
}
}
class StageStrokeMap {
/*
Create and and manage Strokes, using a name.
const fooStroke = stage.strokes.create('foo',{
dash: [3,3]
, color: 'grey'
, width: 2
})
Call set to apply, unset to unapply:
fooStroke.set(ctx)
fooStroke.set()
fooStroke.set(ctx)
fooStroke.unset()
Fetch the same stroker:
let fooStroke = stage.strokes.get('fooStroke')
Or call the stroke object directly:
stage.strokes.fooStroke.set()
stage.strokes.fooStroke.unset()
Call 'set' on the stroke object to perform the same as above:
stage.strokes.set('line')
stage.line.render(ctx)
stage.strokes.unset('line')
Run in place, immediately enabling the stroke styles:
let off = stage.strokes.line()
stage.line.render(ctx)
off()
Or for less code, provide a function to the immediate caller, to run inline:
// set 'line'
// run the given function
// unset 'line'
stage.strokes.line(()=>stage.line.render(ctx))
*/
constructor(stage) {
this.stage = stage;
this.cache = new Map
}
get(name) {
return this.cache.get(name)
}
has(name) {
return this.cache.has(name)
}
create(name, options) {
let stroke = new Stroke(options)
this.cache.set(name, stroke)
return stroke
}
set(name, ctx=this.stage.ctx) {
let stroke = this.get(name)
stroke.set(ctx)
return stroke
}
unset(name, ctx=this.stage.ctx) {
let stroke = this.get(name)
stroke.unset(ctx)
return stroke
}
remove(name) {
let stroke = this.get(name)
this.cache.delete(name)
return stroke
}
delete(name) {
return this.remove(name)
}
propHook(prop) {
/* Given a name (and potentially options), return a handler of
which can be a function.
The handler returns a _off_ function for disabling this same stroke. */
return (func)=> {
let unit = this.set(prop)
if(func) { func(unit) }
let unsetHook = (unit)=>{
return this.unset(prop)
}
if(func) {
return unsetHook(unit)
}
return unit
}
}
}
Polypoint.head.deferredProp('Stage', function strokes() {
/* Return an instance of the Strok map object for the stage.
This returns a proxy of the instance, providing access to the special calling methods.
*/
let item = new StageStrokeMap(this)
/* This hansler is designed to check for the property name given to the stroke map.
If the name is a stroke name (within the map), return the prop hook, a function
to enable to the named stroke.
This allows:
stage.strokes.line(()=>renderFunc(ctx))
over:
var stroke = stage.strokes..get('line')
stroke.set()
renderFunc(ctx)
stroke.unset()
*/
let handler = {
get(target, prop, receiver) {
if(item.has(prop)) {
// console.log("stroke prop", target, prop, receiver)
return item.propHook(prop)
}
return Reflect.get(...arguments)
}
, count: ()=> item.map.size()
}
let proxy = new Proxy(item, handler)
return proxy
})
Polypoint.head.install(Stroke)
const example = function() {
s = new Stroke({
name: 'customName'
// ctx identical
, strokeStyle: '#color'
, lineWidth: 1
, lineCap: 'miter'
, lineJoin: 'miter'
, lineDashOffset: 0
// functional special
, lineDash: [3, 3]
// custom function special
, march: .03 // A dash stroke addon per step (march * delta)
// sugar
, dash: 'lineDash'
, color: 'red'
, style: '#color'
, offset: 0
, width: 3
, cap: 'miter'
, join: 'miter'
})
s = new Stroke(style, width, dash, offset, cap, join)
s = new Stroke({
dash: [3,3]
, color: 'grey'
, width: 2
})
s.set(ctx)
s.unset(ctx)
}
copy