265 lines
7.3 KiB
JavaScript
265 lines
7.3 KiB
JavaScript
import { EventojLancilo } from './EventojLancilo.js'
|
|
EventojLancilo( EventTarget ) // same event handler for everybody
|
|
|
|
String.merge = (ss,...pp)=> [].concat(ss).map( (s,i)=> s+(i in pp?pp[i]:'') ).join('')
|
|
const logNpass = o=> console.log(o)||o
|
|
// const ss_pp = (ss,...pp)=> [].concat(ss).map( (s,i)=> s+(i in pp?pp[i]:'') ).join('')
|
|
// const $ = (ss,...pp)=> document.querySelector( ss_pp(ss,...pp) )
|
|
// const $$ = (ss,...pp)=> [...document.querySelectorAll( ss_pp(ss,...pp) )]
|
|
const DOM = (ss,...pp)=> {
|
|
let t = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'template' )
|
|
t.innerHTML = String.merge(ss,...pp)
|
|
return t.content
|
|
}
|
|
const SVG = (ss,...pp)=> DOM`<svg xmlns="http://www.w3.org/2000/svg">${String.merge(ss,...pp)}</svg>`
|
|
.children[0].childNodes
|
|
|
|
const CSS = (ss,...pp)=> {
|
|
let styles = new CSSStyleSheet()
|
|
styles.replaceSync( String.merge(ss,...pp) )
|
|
return styles
|
|
}
|
|
|
|
const $ = (ss,...pp)=> document.$( ss,...pp )
|
|
const $$ = (ss,...pp)=> document.$$( ss,...pp )
|
|
Node.prototype.$ = function(ss,...pp)
|
|
{
|
|
return this.querySelector( String.merge(ss,...pp) )
|
|
}
|
|
Node.prototype.$$ = function(ss,...pp)
|
|
{
|
|
return [...this.querySelectorAll( String.merge(ss,...pp) )]
|
|
}
|
|
Node.prototype.add = function( ...args )
|
|
{
|
|
this.append( ...args )
|
|
return this
|
|
}
|
|
// Node.prototype.on = function(ss,...pp)
|
|
// {
|
|
// return (...args)=> ( this.addEventListener( ss_pp(ss,...pp), ...args ), this )
|
|
// }
|
|
|
|
|
|
|
|
Object.defineProperties( SVGRect.prototype, {
|
|
center: {
|
|
get(){ return {
|
|
x: this.x + ( this.width/2 )
|
|
, y: this.y + ( this.height/2 )
|
|
}}
|
|
, set( v ){}
|
|
}
|
|
})
|
|
|
|
/** <line> **/
|
|
|
|
// @see https://cp-algorithms.com/geometry/segment-to-line.html
|
|
// SVGLineElement.prototype.getCoef = function line()
|
|
// {
|
|
// let P = { x: this.x1.baseVal.value, y: this.y1.baseVal.value }
|
|
// let Q = { x: this.x2.baseVal.value, y: this.y2.baseVal.value }
|
|
// //console.log(P,Q)
|
|
// let A = P.y - Q.y
|
|
// let B = Q.x - P.x
|
|
// let C = ( -A * P.x ) - ( B * P.y )
|
|
// return [A,B,C]
|
|
// }
|
|
// // @see https://cp-algorithms.com/geometry/lines-intersection.html
|
|
// SVGLineElement.prototype.intersect = function intersect( line )
|
|
// {
|
|
// let [ a1,b1,c1 ] = this.getCoef()
|
|
// // console.log(this.getCoef())
|
|
// let [ a2,b2,c2 ] = line.getCoef()
|
|
// // console.log(line.getCoef())
|
|
// let x = - ((c1*b2)-(c2*b1))/((a1*b2)-(a2*b1))
|
|
// let y = - ((a1*c2)-(a2*c1))/((a1*b2)-(a2*b1))
|
|
// return { x, y }
|
|
// }
|
|
//PointProperty('_p1','x1','y1')
|
|
const PointProperty = ( _, x, y )=> ({
|
|
get(){ return this[_] = this[_] || new DOMPoint(
|
|
this[x].baseVal.value,
|
|
this[y].baseVal.value
|
|
)}
|
|
, set( obj ){
|
|
if( 'x' in obj && 'y' in obj )
|
|
{
|
|
const ev = e=> {
|
|
this.setAttribute( x, obj.x )
|
|
this.setAttribute( y, obj.y )
|
|
this.dispatchEvent( new Event('move') )
|
|
}
|
|
this[_]
|
|
&& this[_].removeEventListener
|
|
&& this[_].removeEventListener('move', ev)
|
|
this[_] = obj
|
|
obj.addEventListener && obj.addEventListener('move', ev)
|
|
ev()
|
|
this.dispatchEvent( new Event('pointchange') )
|
|
}
|
|
}
|
|
})
|
|
Object.defineProperties(SVGLineElement.prototype, {
|
|
p1: PointProperty('_p1','x1','y1')
|
|
// {
|
|
// get(){ return this._p1 = this._p1 || new DOMPoint(
|
|
// this.x1.baseVal.value,
|
|
// this.y1.baseVal.value
|
|
// )
|
|
// }
|
|
// , set( obj ){
|
|
// if( 'x' in obj && 'y' in obj )
|
|
// {
|
|
// const ev = e=> {
|
|
// this.setAttribute('x1', obj.x)
|
|
// this.setAttribute('y1', obj.y)
|
|
// this.dispatchEvent( new Event('move') )
|
|
// }
|
|
// this._p1
|
|
// && this._p1.removeEventListener
|
|
// && this._p1.removeEventListener('move', ev)
|
|
// this._p1 = obj
|
|
// obj.addEventListener && obj.addEventListener('move', ev)
|
|
// ev()
|
|
// this.dispatchEvent( new Event('pointchange') )
|
|
// }
|
|
// }
|
|
// }
|
|
, p2: PointProperty('_p2','x2','y2')
|
|
// {
|
|
// get(){ return this._p2 = this._p2 || new DOMPoint(
|
|
// this.x2.baseVal.value,
|
|
// this.y2.baseVal.value
|
|
// )}
|
|
// , set( obj ){
|
|
// if( 'x' in obj && 'y' in obj )
|
|
// {
|
|
// const ev = e=> {
|
|
// this.setAttribute('x2', obj.x)
|
|
// this.setAttribute('y2', obj.y)
|
|
// this.dispatchEvent( new Event('move') )
|
|
// }
|
|
// this._p2
|
|
// && this._p2.removeEventListener
|
|
// && this._p2.removeEventListener('move', ev)
|
|
// this._p2 = obj
|
|
// obj.addEventListener && obj.addEventListener('move', ev)
|
|
// ev()
|
|
// this.dispatchEvent( new Event('pointchange') )
|
|
// }
|
|
// }
|
|
// }
|
|
})
|
|
|
|
//@TODO Debounce move event fired twice when changing x and y
|
|
//@TODO Adapt which attribute is set ( x, cx, x1, transform ), depending on localName ( <rect>, <circle>, <g>, ... )
|
|
Object.defineProperties(SVGElement.prototype, {
|
|
x: {
|
|
get(){ return parseFloat((this.attributes.x||this.attributes.cx||this.attributes.x1||{value:0}).value) }
|
|
, set( v ){
|
|
if( !isFinite(v) ) return v
|
|
if( this.localName == 'g' )
|
|
this.setAttribute('transform',`translate(${v},${this.y})`)
|
|
this.setAttribute('x',v)
|
|
this.setAttribute('cx',v)
|
|
this.setAttribute('x1',v)
|
|
}
|
|
}
|
|
, y: {
|
|
get(){ return parseFloat((this.attributes.y||this.attributes.cy||this.attributes.y1||{value:0}).value) }
|
|
, set( v ){
|
|
if( !isFinite(v) ) return v
|
|
if( this.localName == 'g' )
|
|
this.setAttribute('transform',`translate(${this.x},${v})`)
|
|
this.setAttribute('y',v)
|
|
this.setAttribute('cy',v)
|
|
this.setAttribute('y1',v)
|
|
}
|
|
}
|
|
, moveTo: {
|
|
value: function({ x, y }){
|
|
this.x = x
|
|
this.y = y
|
|
this.dispatchEvent( new Event('move') )
|
|
return this
|
|
}
|
|
}
|
|
, moveBy: {
|
|
value: function({ x, y }){
|
|
this.x += x
|
|
this.y += y
|
|
this.dispatchEvent( new Event('move') )
|
|
return this
|
|
}
|
|
}
|
|
|
|
})
|
|
|
|
|
|
Object.defineProperties(SVGSVGElement.prototype, {
|
|
zoom: {
|
|
get(){ return parseFloat((this.attributes.x||this.attributes.cx||this.attributes.x1||{value:0}).value) }
|
|
, set( v ){
|
|
if( !isFinite(v) ) return v
|
|
if( this.localName == 'g' )
|
|
this.setAttribute('transform',`translate(${v},${this.y})`)
|
|
this.setAttribute('x',v)
|
|
this.setAttribute('cx',v)
|
|
this.setAttribute('x1',v)
|
|
}
|
|
}
|
|
, pan: //PointProperty('_pan','pan-x','pan-y')
|
|
{
|
|
get(){ return this._pan = this._pan || new DOMPoint(
|
|
this.x2.baseVal.value,
|
|
this.y2.baseVal.value
|
|
)}
|
|
, set( obj ){
|
|
if( 'x' in obj && 'y' in obj )
|
|
{
|
|
const ev = e=> {
|
|
this.setAttribute('x2', obj.x)
|
|
this.setAttribute('y2', obj.y)
|
|
this.dispatchEvent( new Event('move') )
|
|
}
|
|
this._p2
|
|
&& this._p2.removeEventListener
|
|
&& this._p2.removeEventListener('move', ev)
|
|
this._p2 = obj
|
|
obj.addEventListener && obj.addEventListener('move', ev)
|
|
ev()
|
|
this.dispatchEvent( new Event('pointchange') )
|
|
}
|
|
}
|
|
}
|
|
, panAndZoom: {
|
|
value( x, y, z )
|
|
{
|
|
let { x:vx, y:vy, width:vw, height:vh } = this.viewBox.baseVal
|
|
, vz
|
|
vz = Math.min( vw, vh ) / 2
|
|
vx = vx + ( vw / 2 )
|
|
vy = vy + ( vh / 2 )
|
|
|
|
requestAnimationFrame( ()=> {
|
|
// this.setAttribute('viewBox', `${typeof x == 'number' ? x-(z||vz) : vx} ${typeof y == 'number' ? y-(z||vz) : vy} ${z ? z*2 : vw} ${z ? z*2 : vh}`)
|
|
this.setAttribute('viewBox', `${(x||vx)-(z||vz)} ${(y||vy)-(z||vz)} ${(z||vz)*2} ${(z||vz)*2}`)
|
|
console.log('viewBox', `${(x||vx)-(z||vz)} ${(y||vy)-(z||vz)} ${(z||vz)*2} ${(z||vz)*2}`)
|
|
|
|
// this.setAttribute('pan', `${x} ${y}`)
|
|
// this.setAttribute('zoom', `${z}`)
|
|
})
|
|
}
|
|
}
|
|
})
|
|
|
|
|
|
export {
|
|
logNpass
|
|
, DOM
|
|
, SVG
|
|
, CSS
|
|
, $
|
|
, $$
|
|
} |