mirror of
https://github.com/Cola-Echo/memory-manager-concurrent.git
synced 2026-06-06 08:55:52 +00:00
8678 lines
213 KiB
JavaScript
8678 lines
213 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2010-2021 Uil.js Authors
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
/**
|
|
* @author lth / https://github.com/lo-th
|
|
*/
|
|
|
|
// INTENAL FUNCTION
|
|
|
|
const R = {
|
|
|
|
ui: [],
|
|
|
|
dom:null,
|
|
|
|
ID: null,
|
|
lock:false,
|
|
wlock:false,
|
|
current:-1,
|
|
|
|
needReZone: true,
|
|
isEventsInit: false,
|
|
isLeave:false,
|
|
|
|
downTime:0,
|
|
prevTime:0,
|
|
|
|
prevDefault: ['contextmenu', 'wheel'],
|
|
pointerEvent: ['pointerdown', 'pointermove', 'pointerup'],
|
|
eventOut: ['pointercancel', 'pointerout', 'pointerleave'],
|
|
|
|
xmlserializer: null,
|
|
tmpTime: null,
|
|
tmpImage: null,
|
|
|
|
oldCursor:'auto',
|
|
|
|
input: null,
|
|
parent: null,
|
|
firstImput: true,
|
|
|
|
hiddenImput:null,
|
|
hiddenSizer:null,
|
|
hasFocus:false,
|
|
startInput:false,
|
|
inputRange : [0,0],
|
|
cursorId : 0,
|
|
str:'',
|
|
pos:0,
|
|
startX:-1,
|
|
moveX:-1,
|
|
|
|
debugInput:false,
|
|
|
|
isLoop: false,
|
|
listens: [],
|
|
|
|
e:{
|
|
type:null,
|
|
clientX:0,
|
|
clientY:0,
|
|
keyCode:NaN,
|
|
key:null,
|
|
delta:0,
|
|
},
|
|
|
|
isMobile: false,
|
|
|
|
now: null,
|
|
|
|
getTime: function() {
|
|
return ( self.performance && self.performance.now ) ? self.performance.now.bind( performance ) : Date.now;
|
|
},
|
|
|
|
add: function ( o ) {
|
|
|
|
R.ui.push( o );
|
|
R.getZone( o );
|
|
|
|
if( !R.isEventsInit ) R.initEvents();
|
|
|
|
},
|
|
|
|
testMobile: function () {
|
|
|
|
let n = navigator.userAgent;
|
|
if (n.match(/Android/i) || n.match(/webOS/i) || n.match(/iPhone/i) || n.match(/iPad/i) || n.match(/iPod/i) || n.match(/BlackBerry/i) || n.match(/Windows Phone/i)) return true;
|
|
else return false;
|
|
|
|
},
|
|
|
|
remove: function ( o ) {
|
|
|
|
let i = R.ui.indexOf( o );
|
|
|
|
if ( i !== -1 ) {
|
|
R.removeListen( o );
|
|
R.ui.splice( i, 1 );
|
|
}
|
|
|
|
if( R.ui.length === 0 ){
|
|
R.removeEvents();
|
|
}
|
|
|
|
},
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
initEvents: function () {
|
|
|
|
if( R.isEventsInit ) return;
|
|
|
|
let dom = document.body;
|
|
|
|
R.isMobile = R.testMobile();
|
|
R.now = R.getTime();
|
|
|
|
|
|
if(!R.isMobile){
|
|
dom.addEventListener( 'wheel', R, { passive: false } );
|
|
} else {
|
|
dom.style.touchAction = 'none';
|
|
}
|
|
|
|
|
|
dom.addEventListener( 'pointercancel', R );
|
|
dom.addEventListener( 'pointerleave', R );
|
|
//dom.addEventListener( 'pointerout', R )
|
|
|
|
dom.addEventListener( 'pointermove', R );
|
|
dom.addEventListener( 'pointerdown', R );
|
|
dom.addEventListener( 'pointerup', R );
|
|
|
|
|
|
dom.addEventListener( 'keydown', R, false );
|
|
dom.addEventListener( 'keyup', R, false );
|
|
window.addEventListener( 'resize', R.resize , false );
|
|
|
|
//window.onblur = R.out;
|
|
//window.onfocus = R.in;
|
|
|
|
|
|
R.isEventsInit = true;
|
|
R.dom = dom;
|
|
|
|
},
|
|
|
|
removeEvents: function () {
|
|
|
|
if( !R.isEventsInit ) return;
|
|
|
|
let dom = document.body;
|
|
|
|
if(!R.isMobile){
|
|
dom.removeEventListener( 'wheel', R );
|
|
}
|
|
|
|
|
|
dom.removeEventListener( 'pointercancel', R );
|
|
dom.removeEventListener( 'pointerleave', R );
|
|
//dom.removeEventListener( 'pointerout', R );
|
|
|
|
dom.removeEventListener( 'pointermove', R );
|
|
dom.removeEventListener( 'pointerdown', R );
|
|
dom.removeEventListener( 'pointerup', R );
|
|
|
|
|
|
dom.removeEventListener( 'keydown', R );
|
|
dom.removeEventListener( 'keyup', R );
|
|
window.removeEventListener( 'resize', R.resize );
|
|
|
|
R.isEventsInit = false;
|
|
|
|
},
|
|
|
|
resize: function () {
|
|
|
|
R.needReZone = true;
|
|
|
|
let i = R.ui.length, u;
|
|
|
|
while( i-- ){
|
|
|
|
u = R.ui[i];
|
|
if( u.isGui && !u.isCanvasOnly && u.autoResize ) u.calc();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
out: function () {
|
|
|
|
console.log('im am out');
|
|
R.clearOldID();
|
|
|
|
},
|
|
|
|
in: function () {
|
|
|
|
console.log('im am in');
|
|
// R.clearOldID();
|
|
|
|
},
|
|
|
|
// ----------------------
|
|
// HANDLE EVENTS
|
|
// ----------------------
|
|
|
|
fakeUp: function(){
|
|
|
|
this.handleEvent( {type:'pointerup'} );
|
|
|
|
},
|
|
|
|
|
|
handleEvent: function ( event ) {
|
|
|
|
//if(!event.type) return;
|
|
|
|
if( R.prevDefault.indexOf( event.type ) !== -1 ) event.preventDefault();
|
|
|
|
R.findZone();
|
|
|
|
let e = R.e;
|
|
let leave = false;
|
|
|
|
if( event.type === 'keydown') R.keydown( event );
|
|
if( event.type === 'keyup') R.keyup( event );
|
|
|
|
if( event.type === 'wheel' ) e.delta = event.deltaY > 0 ? 1 : -1;
|
|
else e.delta = 0;
|
|
|
|
let ptype = event.pointerType; // mouse, pen, touch
|
|
|
|
e.clientX = ( ptype === 'touch' ? event.pageX : event.clientX ) || 0;
|
|
e.clientY = ( ptype === 'touch' ? event.pageY : event.clientY ) || 0;
|
|
|
|
e.type = event.type;
|
|
|
|
if( R.eventOut.indexOf( event.type ) !== -1 ){
|
|
leave = true;
|
|
e.type = 'mouseup';
|
|
}
|
|
|
|
if( event.type === 'pointerleave'){ R.isLeave = true; }
|
|
|
|
if( event.type === 'pointerdown') e.type = 'mousedown';
|
|
if( event.type === 'pointerup') e.type = 'mouseup';
|
|
if( event.type === 'pointermove'){
|
|
if( R.isLeave ){
|
|
// if user resize outside this document
|
|
R.isLeave = false;
|
|
R.resize();
|
|
}
|
|
e.type = 'mousemove';
|
|
}
|
|
|
|
// double click test
|
|
if( e.type === 'mousedown' ) {
|
|
R.downTime = R.now();
|
|
let time = R.downTime - R.prevTime;
|
|
|
|
// double click on imput
|
|
if( time < 200 ) { R.selectAll(); return false }
|
|
|
|
R.prevTime = R.downTime;
|
|
}
|
|
|
|
// for imput
|
|
if( e.type === 'mousedown' ) R.clearInput();
|
|
|
|
// mouse lock
|
|
if( e.type === 'mousedown' ) R.lock = true;
|
|
if( e.type === 'mouseup' ) R.lock = false;
|
|
|
|
//if( R.current !== null && R.current.neverlock ) R.lock = false;
|
|
|
|
/*if( e.type === 'mousedown' && event.button === 1){
|
|
R.cursor()
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}*/
|
|
|
|
if( R.isMobile && e.type === 'mousedown' ) R.findID( e );
|
|
if( e.type === 'mousemove' && !R.lock ) R.findID( e );
|
|
|
|
if( R.ID !== null ){
|
|
|
|
if( R.ID.isCanvasOnly ) {
|
|
|
|
e.clientX = R.ID.mouse.x;
|
|
e.clientY = R.ID.mouse.y;
|
|
|
|
}
|
|
|
|
R.ID.handleEvent( e );
|
|
|
|
}
|
|
|
|
if( R.isMobile && e.type === 'mouseup' ) R.clearOldID();
|
|
if( leave ) R.clearOldID();
|
|
|
|
|
|
},
|
|
|
|
// ----------------------
|
|
// ID
|
|
// ----------------------
|
|
|
|
findID: function ( e ) {
|
|
|
|
let i = R.ui.length, next = -1, u, x, y;
|
|
|
|
while( i-- ){
|
|
|
|
u = R.ui[i];
|
|
|
|
if( u.isCanvasOnly ) {
|
|
|
|
x = u.mouse.x;
|
|
y = u.mouse.y;
|
|
|
|
} else {
|
|
|
|
x = e.clientX;
|
|
y = e.clientY;
|
|
|
|
}
|
|
|
|
if( R.onZone( u, x, y ) ){
|
|
|
|
next = i;
|
|
|
|
if( next !== R.current ){
|
|
R.clearOldID();
|
|
R.current = next;
|
|
R.ID = u;
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if( next === -1 ) R.clearOldID();
|
|
|
|
},
|
|
|
|
clearOldID: function () {
|
|
|
|
if( !R.ID ) return;
|
|
R.current = -1;
|
|
R.ID.reset();
|
|
R.ID = null;
|
|
R.cursor();
|
|
|
|
},
|
|
|
|
// ----------------------
|
|
// GUI / GROUP FUNCTION
|
|
// ----------------------
|
|
|
|
calcUis: function ( uis, zone, py ) {
|
|
|
|
//console.log('calc_uis')
|
|
|
|
let i = uis.length, u, px = 0, n = 0, tw;
|
|
let height = 0;
|
|
let m = 1;
|
|
|
|
while( i-- ){
|
|
|
|
u = uis[n];
|
|
n++;
|
|
|
|
if( u.isGroup ) u.calcUis();
|
|
|
|
u.zone.w = u.w;
|
|
u.zone.h = u.h;
|
|
m = u.margin;
|
|
|
|
if( !u.autoWidth ){
|
|
|
|
if( px===0 ){
|
|
height += u.h + m;
|
|
|
|
}
|
|
|
|
u.zone.x = zone.x + px;
|
|
u.zone.y = py;
|
|
|
|
tw = R.getWidth(u);
|
|
if( tw ) u.zone.w = u.w = tw;
|
|
// focrce width if content is canvas
|
|
else if( u.fw ) u.zone.w = u.w = u.fw;
|
|
|
|
|
|
//console.log( u.name, u.zone.w, u.w, zone, tw )
|
|
//console.log( tw )
|
|
px += u.zone.w;
|
|
|
|
if( px >= zone.w ) {
|
|
py += u.h + m;
|
|
px = 0;
|
|
}
|
|
|
|
} else {
|
|
|
|
px = 0;
|
|
|
|
u.zone.x = zone.x;
|
|
u.zone.y = py;
|
|
py += u.h + m;
|
|
|
|
height += u.h + m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return height
|
|
|
|
},
|
|
|
|
|
|
findTarget: function ( uis, e ) {
|
|
|
|
let i = uis.length;
|
|
|
|
while( i-- ){
|
|
if( R.onZone( uis[i], e.clientX, e.clientY ) ) return i
|
|
}
|
|
|
|
return -1;
|
|
|
|
},
|
|
|
|
// ----------------------
|
|
// ZONE
|
|
// ----------------------
|
|
|
|
findZone: function ( force ) {
|
|
|
|
if( !R.needReZone && !force ) return;
|
|
|
|
var i = R.ui.length, u;
|
|
|
|
while( i-- ){
|
|
|
|
u = R.ui[i];
|
|
R.getZone( u );
|
|
if( u.isGui ) u.calcUis();
|
|
|
|
}
|
|
|
|
R.needReZone = false;
|
|
|
|
},
|
|
|
|
onZone: function ( o, x, y ) {
|
|
|
|
if( x === undefined || y === undefined ) return false;
|
|
|
|
let z = o.zone;
|
|
let mx = x - z.x;
|
|
let my = y - z.y;
|
|
|
|
let over = ( mx >= 0 ) && ( my >= 0 ) && ( mx <= z.w ) && ( my <= z.h );
|
|
|
|
if( over ) o.local.set( mx, my );
|
|
else o.local.neg();
|
|
|
|
return over;
|
|
|
|
},
|
|
|
|
getWidth: function ( o ) {
|
|
|
|
|
|
|
|
//return o.getDom().offsetWidth
|
|
return o.getDom().clientWidth
|
|
|
|
//let r = o.getDom().getBoundingClientRect();
|
|
//return (r.width)
|
|
//return Math.floor(r.width)
|
|
|
|
},
|
|
|
|
getZone: function ( o ) {
|
|
|
|
if( o.isCanvasOnly ) return;
|
|
let r = o.getDom().getBoundingClientRect();
|
|
|
|
//if( !r.width ) return
|
|
//o.zone = { x:Math.floor(r.left), y:Math.floor(r.top), w:Math.floor(r.width), h:Math.floor(r.height) };
|
|
//o.zone = { x:Math.round(r.left), y:Math.round(r.top), w:Math.round(r.width), h:Math.round(r.height) };
|
|
o.zone = { x:r.left, y:r.top, w:r.width, h:r.height };
|
|
|
|
//console.log(o.name, o.zone)
|
|
|
|
},
|
|
|
|
// ----------------------
|
|
// CURSOR
|
|
// ----------------------
|
|
|
|
cursor: function ( name ) {
|
|
|
|
name = name ? name : 'auto';
|
|
if( name !== R.oldCursor ){
|
|
document.body.style.cursor = name;
|
|
R.oldCursor = name;
|
|
}
|
|
|
|
},
|
|
|
|
// ----------------------
|
|
// CANVAS
|
|
// ----------------------
|
|
|
|
toCanvas: function ( o, w, h, force ) {
|
|
|
|
if( !R.xmlserializer ) R.xmlserializer = new XMLSerializer();
|
|
|
|
// prevent exesive redraw
|
|
|
|
if( force && R.tmpTime !== null ) { clearTimeout(R.tmpTime); R.tmpTime = null; }
|
|
|
|
if( R.tmpTime !== null ) return;
|
|
|
|
if( R.lock ) R.tmpTime = setTimeout( function(){ R.tmpTime = null; }, 10 );
|
|
|
|
///
|
|
|
|
let isNewSize = false;
|
|
if( w !== o.canvas.width || h !== o.canvas.height ) isNewSize = true;
|
|
|
|
if( R.tmpImage === null ) R.tmpImage = new Image();
|
|
|
|
let img = R.tmpImage; //new Image();
|
|
|
|
let htmlString = R.xmlserializer.serializeToString( o.content );
|
|
|
|
let svg = '<svg xmlns="http://www.w3.org/2000/svg" width="'+w+'" height="'+h+'"><foreignObject style="pointer-events: none; left:0;" width="100%" height="100%">'+ htmlString +'</foreignObject></svg>';
|
|
|
|
img.onload = function() {
|
|
|
|
let ctx = o.canvas.getContext("2d");
|
|
|
|
if( isNewSize ){
|
|
o.canvas.width = w;
|
|
o.canvas.height = h;
|
|
}else {
|
|
ctx.clearRect( 0, 0, w, h );
|
|
}
|
|
ctx.drawImage( this, 0, 0 );
|
|
|
|
o.onDraw();
|
|
|
|
};
|
|
|
|
img.src = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svg);
|
|
//img.src = 'data:image/svg+xml;base64,'+ window.btoa( svg );
|
|
img.crossOrigin = '';
|
|
|
|
|
|
},
|
|
|
|
// ----------------------
|
|
// INPUT
|
|
// ----------------------
|
|
|
|
setHidden: function () {
|
|
|
|
|
|
if( R.hiddenImput === null ){
|
|
|
|
//let css = R.parent.css.txtselect + 'padding:0; width:auto; height:auto; '
|
|
//let css = R.parent.css.txt + 'padding:0; width:auto; height:auto; text-shadow:none;'
|
|
//css += 'left:10px; top:auto; border:none; color:#FFF; background:#000;' + hide;
|
|
|
|
R.hiddenImput = document.createElement('input');
|
|
R.hiddenImput.type = 'text';
|
|
//R.hiddenImput.style.cssText = css + 'bottom:30px;' + (R.debugInput ? '' : 'transform:scale(0);');
|
|
|
|
R.hiddenSizer = document.createElement('div');
|
|
//R.hiddenSizer.style.cssText = css + 'bottom:60px;';
|
|
|
|
document.body.appendChild( R.hiddenImput );
|
|
document.body.appendChild( R.hiddenSizer );
|
|
|
|
}
|
|
|
|
let hide = R.debugInput ? '' : 'opacity:0; zIndex:0;';
|
|
let css = R.parent.css.txtselect + 'padding:0; width:auto; height:auto; left:10px; top:auto; color:#FFF; background:#000;'+ hide;
|
|
R.hiddenImput.style.cssText = css + 'bottom:10px;' + (R.debugInput ? '' : 'transform:scale(0);');
|
|
R.hiddenSizer.style.cssText = css + 'bottom:40px;';
|
|
|
|
R.hiddenImput.style.width = R.input.clientWidth + 'px';
|
|
R.hiddenImput.value = R.str;
|
|
R.hiddenSizer.innerHTML = R.str;
|
|
|
|
R.hasFocus = true;
|
|
|
|
},
|
|
|
|
clearHidden: function ( p ) {
|
|
|
|
if( R.hiddenImput === null ) return;
|
|
R.hasFocus = false;
|
|
|
|
},
|
|
|
|
clickPos: function( x ){
|
|
|
|
let i = R.str.length, l = 0, n = 0;
|
|
while( i-- ){
|
|
l += R.textWidth( R.str[n] );
|
|
if( l >= x ) break;
|
|
n++;
|
|
}
|
|
return n;
|
|
|
|
},
|
|
|
|
upInput: function ( x, down ) {
|
|
|
|
if( R.parent === null ) return false;
|
|
|
|
let up = false;
|
|
|
|
if( down ){
|
|
|
|
let id = R.clickPos( x );
|
|
|
|
R.moveX = id;
|
|
|
|
if( R.startX === -1 ){
|
|
|
|
R.startX = id;
|
|
R.cursorId = id;
|
|
R.inputRange = [ R.startX, R.startX ];
|
|
|
|
} else {
|
|
|
|
let isSelection = R.moveX !== R.startX;
|
|
|
|
if( isSelection ){
|
|
if( R.startX > R.moveX ) R.inputRange = [ R.moveX, R.startX ];
|
|
else R.inputRange = [ R.startX, R.moveX ];
|
|
}
|
|
}
|
|
|
|
up = true;
|
|
|
|
} else {
|
|
|
|
if( R.startX !== -1 ){
|
|
|
|
R.hasFocus = true;
|
|
R.hiddenImput.focus();
|
|
R.hiddenImput.selectionStart = R.inputRange[0];
|
|
R.hiddenImput.selectionEnd = R.inputRange[1];
|
|
R.startX = -1;
|
|
|
|
up = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( up ) R.selectParent();
|
|
|
|
return up;
|
|
|
|
},
|
|
|
|
selectAll: function (){
|
|
|
|
if(!R.parent) return
|
|
|
|
R.str = R.input.textContent;
|
|
R.inputRange = [0, R.str.length ];
|
|
R.hasFocus = true;
|
|
R.hiddenImput.focus();
|
|
R.hiddenImput.selectionStart = R.inputRange[0];
|
|
R.hiddenImput.selectionEnd = R.inputRange[1];
|
|
R.cursorId = R.inputRange[1];
|
|
R.selectParent();
|
|
|
|
},
|
|
|
|
selectParent: function (){
|
|
|
|
var c = R.textWidth( R.str.substring( 0, R.cursorId ));
|
|
var e = R.textWidth( R.str.substring( 0, R.inputRange[0] ));
|
|
var s = R.textWidth( R.str.substring( R.inputRange[0], R.inputRange[1] ));
|
|
|
|
R.parent.select( c, e, s, R.hiddenSizer.innerHTML );
|
|
|
|
},
|
|
|
|
textWidth: function ( text ){
|
|
|
|
if( R.hiddenSizer === null ) return 0;
|
|
text = text.replace(/ /g, ' ');
|
|
R.hiddenSizer.innerHTML = text;
|
|
return R.hiddenSizer.clientWidth;
|
|
|
|
},
|
|
|
|
|
|
clearInput: function () {
|
|
|
|
if( R.parent === null ) return;
|
|
if( !R.firstImput ) R.parent.validate( true );
|
|
|
|
R.clearHidden();
|
|
R.parent.unselect();
|
|
|
|
//R.input.style.background = 'none';
|
|
R.input.style.background = R.parent.colors.back;
|
|
R.input.style.borderColor = R.parent.colors.border;
|
|
//R.input.style.color = R.parent.colors.text;
|
|
R.parent.isEdit = false;
|
|
|
|
R.input = null;
|
|
R.parent = null;
|
|
R.str = '',
|
|
R.firstImput = true;
|
|
|
|
},
|
|
|
|
setInput: function ( Input, parent ) {
|
|
|
|
R.clearInput();
|
|
|
|
R.input = Input;
|
|
R.parent = parent;
|
|
|
|
R.input.style.background = R.parent.colors.backoff;
|
|
R.input.style.borderColor = R.parent.colors.select;
|
|
//R.input.style.color = R.parent.colors.textSelect;
|
|
R.str = R.input.textContent;
|
|
|
|
R.setHidden();
|
|
|
|
},
|
|
|
|
keydown: function ( e ) {
|
|
|
|
if( R.parent === null ) return;
|
|
|
|
let keyCode = e.which; e.shiftKey;
|
|
|
|
//console.log( keyCode )
|
|
|
|
R.firstImput = false;
|
|
|
|
|
|
if (R.hasFocus) {
|
|
// hack to fix touch event bug in iOS Safari
|
|
window.focus();
|
|
R.hiddenImput.focus();
|
|
|
|
}
|
|
|
|
|
|
R.parent.isEdit = true;
|
|
|
|
// e.preventDefault();
|
|
|
|
// add support for Ctrl/Cmd+A selection
|
|
//if ( keyCode === 65 && (e.ctrlKey || e.metaKey )) {
|
|
//R.selectText();
|
|
//e.preventDefault();
|
|
//return self.render();
|
|
//}
|
|
|
|
if( keyCode === 13 ){ //enter
|
|
|
|
R.clearInput();
|
|
|
|
//} else if( keyCode === 9 ){ //tab key
|
|
|
|
// R.input.textContent = '';
|
|
|
|
} else {
|
|
|
|
if( R.input.isNum ){
|
|
if ( ((e.keyCode > 47) && (e.keyCode < 58)) || ((e.keyCode > 95) && (e.keyCode < 106)) || e.keyCode === 190 || e.keyCode === 110 || e.keyCode === 8 || e.keyCode === 109 ){
|
|
R.hiddenImput.readOnly = false;
|
|
} else {
|
|
R.hiddenImput.readOnly = true;
|
|
}
|
|
} else {
|
|
R.hiddenImput.readOnly = false;
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
keyup: function ( e ) {
|
|
|
|
if( R.parent === null ) return;
|
|
|
|
R.str = R.hiddenImput.value;
|
|
|
|
if( R.parent.allEqual ) R.parent.sameStr( R.str );// numeric samùe value
|
|
else R.input.textContent = R.str;
|
|
|
|
R.cursorId = R.hiddenImput.selectionStart;
|
|
R.inputRange = [ R.hiddenImput.selectionStart, R.hiddenImput.selectionEnd ];
|
|
|
|
R.selectParent();
|
|
|
|
//if( R.parent.allway )
|
|
R.parent.validate();
|
|
|
|
},
|
|
|
|
// ----------------------
|
|
//
|
|
// LISTENING
|
|
//
|
|
// ----------------------
|
|
|
|
loop: function () {
|
|
|
|
if( R.isLoop ) requestAnimationFrame( R.loop );
|
|
R.update();
|
|
|
|
},
|
|
|
|
update: function () {
|
|
|
|
let i = R.listens.length;
|
|
while( i-- ) R.listens[i].listening();
|
|
|
|
},
|
|
|
|
removeListen: function ( proto ) {
|
|
|
|
let id = R.listens.indexOf( proto );
|
|
if( id !== -1 ) R.listens.splice(id, 1);
|
|
if( R.listens.length === 0 ) R.isLoop = false;
|
|
|
|
},
|
|
|
|
addListen: function ( proto ) {
|
|
|
|
let id = R.listens.indexOf( proto );
|
|
|
|
if( id !== -1 ) return false;
|
|
|
|
R.listens.push( proto );
|
|
|
|
if( !R.isLoop ){
|
|
R.isLoop = true;
|
|
R.loop();
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
const Roots = R;
|
|
|
|
/**
|
|
* @author lth / https://github.com/lo-th
|
|
*/
|
|
|
|
const T = {
|
|
|
|
transition: 0.2,
|
|
|
|
frag: document.createDocumentFragment(),
|
|
|
|
colorRing: null,
|
|
joystick_0: null,
|
|
joystick_1: null,
|
|
circular: null,
|
|
knob: null,
|
|
pad2d: null,
|
|
|
|
svgns: "http://www.w3.org/2000/svg",
|
|
links: "http://www.w3.org/1999/xlink",
|
|
htmls: "http://www.w3.org/1999/xhtml",
|
|
|
|
DOM_SIZE: [ 'height', 'width', 'top', 'left', 'bottom', 'right', 'margin-left', 'margin-right', 'margin-top', 'margin-bottom'],
|
|
SVG_TYPE_D: [ 'pattern', 'defs', 'transform', 'stop', 'animate', 'radialGradient', 'linearGradient', 'animateMotion', 'use', 'filter', 'feColorMatrix' ],
|
|
SVG_TYPE_G: [ 'svg', 'rect', 'circle', 'path', 'polygon', 'text', 'g', 'line', 'foreignObject' ],
|
|
|
|
PI: Math.PI,
|
|
TwoPI: Math.PI*2,
|
|
pi90: Math.PI * 0.5,
|
|
pi60: Math.PI/3,
|
|
|
|
torad: Math.PI / 180,
|
|
todeg: 180 / Math.PI,
|
|
|
|
clamp: function (v, min, max) {
|
|
|
|
v = v < min ? min : v;
|
|
v = v > max ? max : v;
|
|
return v;
|
|
|
|
},
|
|
|
|
size: { w: 240, h: 20, p: 30, s: 8 },
|
|
|
|
// ----------------------
|
|
// COLOR
|
|
// ----------------------
|
|
|
|
defineColor: function( o, cc = T.colors ) {
|
|
|
|
let color = { ...cc };
|
|
|
|
let textChange = ['fontFamily', 'fontWeight', 'fontShadow', 'fontSize' ];
|
|
let changeText = false;
|
|
|
|
if( o.font ) o.fontFamily = o.font;
|
|
if( o.shadow ) o.fontShadow = o.shadow;
|
|
if( o.weight ) o.fontWeight = o.weight;
|
|
|
|
if( o.fontColor ) o.text = o.fontColor;
|
|
if( o.color ) o.text = o.color;
|
|
|
|
if( o.text ){
|
|
color.text = o.text;
|
|
if( !o.fontColor && !o.color ){
|
|
color.title = T.ColorLuma( o.text, -0.25 );
|
|
color.titleoff = T.ColorLuma( o.text, -0.5 );
|
|
}
|
|
color.textOver = T.ColorLuma( o.text, 0.25 );
|
|
color.textSelect = T.ColorLuma( o.text, 0.5 );
|
|
}
|
|
|
|
if( o.button ){
|
|
color.button = o.button;
|
|
color.border = T.ColorLuma( o.button, 0.1 );
|
|
color.overoff = T.ColorLuma( o.button, 0.2 );
|
|
}
|
|
|
|
if( o.select ){
|
|
color.select = o.select;
|
|
color.over = T.ColorLuma( o.select, -0.1 );
|
|
}
|
|
|
|
if( o.itemBg ) o.back = o.itemBg;
|
|
|
|
if( o.back ){
|
|
color.back = o.back;
|
|
color.backoff = T.ColorLuma( o.back, -0.1 );
|
|
}
|
|
|
|
if( o.fontSelect ) color.textSelect = o.fontSelect;
|
|
if( o.groupBorder ) color.gborder = o.groupBorder;
|
|
|
|
if( o.transparent ) o.bg = 'none';
|
|
if( o.bg ) color.background = color.backgroundOver = o.bg;
|
|
if( o.bgOver ) color.backgroundOver = o.bgOver;
|
|
|
|
for( let m in color ){
|
|
if(o[m]) color[m] = o[m];
|
|
}
|
|
|
|
for( let m in o ){
|
|
if( textChange.indexOf(m) !== -1 ) changeText = true;
|
|
}
|
|
|
|
if( changeText ) T.defineText( color );
|
|
|
|
return color
|
|
|
|
},
|
|
|
|
colors: {
|
|
|
|
content:'none',
|
|
background: 'rgba(50,50,50,0.3)',
|
|
backgroundOver: 'rgba(50,50,50,0.4)',
|
|
|
|
title : '#CCC',
|
|
titleoff : '#BBB',
|
|
text : '#DDD',
|
|
textOver : '#EEE',
|
|
textSelect : '#FFF',
|
|
|
|
//inputBg: 'rgba(0,0,0,0.25)',
|
|
//itemBg:'rgba(0,0,0,0.25)',
|
|
|
|
back:'rgba(0,0,0,0.2)',
|
|
backoff:'rgba(0,0,0,0.3)',
|
|
//inputOver: 'rgba(0,0,0,0.2)',
|
|
|
|
// input and button border
|
|
border : '#4c4c4c',
|
|
borderSize : 1,
|
|
gborder : 'none',
|
|
|
|
button : '#3c3c3c',
|
|
overoff : '#5c5c5c',
|
|
over : '#024699',
|
|
select : '#308AFF',
|
|
action: '#FF3300',
|
|
|
|
|
|
//fontFamily: 'Tahoma',
|
|
fontFamily: 'Consolas,monaco,monospace',
|
|
fontWeight: 'normal',
|
|
fontShadow: '#000',
|
|
fontSize:12,
|
|
|
|
|
|
radius:4,
|
|
hide: 'rgba(0,0,0,0)',
|
|
|
|
},
|
|
|
|
// style css
|
|
|
|
css : {
|
|
|
|
//unselect: '-o-user-select:none; -ms-user-select:none; -khtml-user-select:none; -webkit-user-select:none; -moz-user-select:none;',
|
|
basic: 'position:absolute; pointer-events:none; box-sizing:border-box; margin:0; padding:0; overflow:hidden; ' + '-o-user-select:none; -ms-user-select:none; -khtml-user-select:none; -webkit-user-select:none; -moz-user-select:none;',
|
|
button:'display:flex; justify-content:center; align-items:center; text-align:center;',
|
|
|
|
/*txt: T.css.basic + 'font-family:'+ T.colors.fontFamily +'; font-size:'+T.colors.fontSize+'px; color:'+T.colors.text+'; padding:2px 10px; left:0; top:2px; height:16px; width:100px; overflow:hidden; white-space: nowrap;',
|
|
txtselect: T.css.txt + 'display:flex; justify-content:left; align-items:center; text-align:left;' +'padding:2px 5px; border:1px dashed ' + T.colors.border + '; background:'+ T.colors.txtselectbg+';',
|
|
item: T.css.txt + 'position:relative; background:rgba(0,0,0,0.2); margin-bottom:1px;',*/
|
|
},
|
|
|
|
// svg path
|
|
|
|
svgs: {
|
|
|
|
group:'M 7 7 L 7 8 8 8 8 7 7 7 M 5 7 L 5 8 6 8 6 7 5 7 M 3 7 L 3 8 4 8 4 7 3 7 M 7 5 L 7 6 8 6 8 5 7 5 M 6 6 L 6 5 5 5 5 6 6 6 M 7 3 L 7 4 8 4 8 3 7 3 M 6 4 L 6 3 5 3 5 4 6 4 M 3 5 L 3 6 4 6 4 5 3 5 M 3 3 L 3 4 4 4 4 3 3 3 Z',
|
|
arrow:'M 3 8 L 8 5 3 2 3 8 Z',
|
|
arrowDown:'M 5 8 L 8 3 2 3 5 8 Z',
|
|
arrowUp:'M 5 2 L 2 7 8 7 5 2 Z',
|
|
|
|
solid:'M 13 10 L 13 1 4 1 1 4 1 13 10 13 13 10 M 11 3 L 11 9 9 11 3 11 3 5 5 3 11 3 Z',
|
|
body:'M 13 10 L 13 1 4 1 1 4 1 13 10 13 13 10 M 11 3 L 11 9 9 11 3 11 3 5 5 3 11 3 M 5 4 L 4 5 4 10 9 10 10 9 10 4 5 4 Z',
|
|
vehicle:'M 13 6 L 11 1 3 1 1 6 1 13 3 13 3 11 11 11 11 13 13 13 13 6 M 2.4 6 L 4 2 10 2 11.6 6 2.4 6 M 12 8 L 12 10 10 10 10 8 12 8 M 4 8 L 4 10 2 10 2 8 4 8 Z',
|
|
articulation:'M 13 9 L 12 9 9 2 9 1 5 1 5 2 2 9 1 9 1 13 5 13 5 9 4 9 6 5 8 5 10 9 9 9 9 13 13 13 13 9 Z',
|
|
character:'M 13 4 L 12 3 9 4 5 4 2 3 1 4 5 6 5 8 4 13 6 13 7 9 8 13 10 13 9 8 9 6 13 4 M 6 1 L 6 3 8 3 8 1 6 1 Z',
|
|
terrain:'M 13 8 L 12 7 Q 9.06 -3.67 5.95 4.85 4.04 3.27 2 7 L 1 8 7 13 13 8 M 3 8 Q 3.78 5.420 5.4 6.6 5.20 7.25 5 8 L 7 8 Q 8.39 -0.16 11 8 L 7 11 3 8 Z',
|
|
joint:'M 7.7 7.7 Q 8 7.45 8 7 8 6.6 7.7 6.3 7.45 6 7 6 6.6 6 6.3 6.3 6 6.6 6 7 6 7.45 6.3 7.7 6.6 8 7 8 7.45 8 7.7 7.7 M 3.35 8.65 L 1 11 3 13 5.35 10.65 Q 6.1 11 7 11 8.28 11 9.25 10.25 L 7.8 8.8 Q 7.45 9 7 9 6.15 9 5.55 8.4 5 7.85 5 7 5 6.54 5.15 6.15 L 3.7 4.7 Q 3 5.712 3 7 3 7.9 3.35 8.65 M 10.25 9.25 Q 11 8.28 11 7 11 6.1 10.65 5.35 L 13 3 11 1 8.65 3.35 Q 7.9 3 7 3 5.7 3 4.7 3.7 L 6.15 5.15 Q 6.54 5 7 5 7.85 5 8.4 5.55 9 6.15 9 7 9 7.45 8.8 7.8 L 10.25 9.25 Z',
|
|
ray:'M 9 11 L 5 11 5 12 9 12 9 11 M 12 5 L 11 5 11 9 12 9 12 5 M 11.5 10 Q 10.9 10 10.45 10.45 10 10.9 10 11.5 10 12.2 10.45 12.55 10.9 13 11.5 13 12.2 13 12.55 12.55 13 12.2 13 11.5 13 10.9 12.55 10.45 12.2 10 11.5 10 M 9 10 L 10 9 2 1 1 2 9 10 Z',
|
|
collision:'M 11 12 L 13 10 10 7 13 4 11 2 7.5 5.5 9 7 7.5 8.5 11 12 M 3 2 L 1 4 4 7 1 10 3 12 8 7 3 2 Z',
|
|
map:'M 13 1 L 1 1 1 13 13 13 13 1 M 12 2 L 12 7 7 7 7 12 2 12 2 7 7 7 7 2 12 2 Z',
|
|
material:'M 13 1 L 1 1 1 13 13 13 13 1 M 12 2 L 12 7 7 7 7 12 2 12 2 7 7 7 7 2 12 2 Z',
|
|
texture:'M 13 4 L 13 1 1 1 1 4 5 4 5 13 9 13 9 4 13 4 Z',
|
|
object:'M 10 1 L 7 4 4 1 1 1 1 13 4 13 4 5 7 8 10 5 10 13 13 13 13 1 10 1 Z',
|
|
none:'M 9 5 L 5 5 5 9 9 9 9 5 Z',
|
|
cursor:'M 4 7 L 1 10 1 12 2 13 4 13 7 10 9 14 14 0 0 5 4 7 Z',
|
|
|
|
},
|
|
|
|
|
|
getImput: function(){
|
|
|
|
return Roots.input ? true : false
|
|
|
|
},
|
|
|
|
setStyle : function ( data ){
|
|
|
|
for ( var o in data ){
|
|
if( T.colors[o] ) T.colors[o] = data[o];
|
|
}
|
|
|
|
T.setText();
|
|
|
|
},
|
|
|
|
// ----------------------
|
|
// custom text
|
|
// ----------------------
|
|
|
|
defineText: function( o ){
|
|
|
|
T.setText( o.fontSize, o.text, o.fontFamily, o.fontShadow, o.fontWeight );
|
|
|
|
},
|
|
|
|
setText: function( size, color, font, shadow, weight ){
|
|
|
|
let cc = T.colors;
|
|
|
|
if( font === undefined ) font = cc.fontFamily;
|
|
if( size === undefined ) size = cc.fontSize;
|
|
if( shadow === undefined ) shadow = cc.fontShadow;
|
|
if( weight === undefined ) weight = cc.fontWeight;
|
|
if( color === undefined ) color = cc.text;
|
|
|
|
|
|
let align = 'display:flex; justify-content:left; align-items:center; text-align:left;';
|
|
|
|
T.css.txt = T.css.basic + align + 'font-family:'+ font +'; font-weight:'+weight+'; font-size:'+size+'px; color:'+cc.text+'; padding:0px 10px; left:0; top:2px; height:16px; width:100px; overflow:hidden; white-space: nowrap;';
|
|
if( shadow !== 'none' ) T.css.txt += ' text-shadow: 1px 1px 1px '+shadow+';';
|
|
|
|
T.css.txtselect = T.css.txt + 'padding:0px 4px; border:1px dashed ' + cc.border + ';';
|
|
//T.css.item = T.css.txt + ' position:relative; margin-bottom:1px; '//display:block; padding:4px 4px;';//
|
|
T.css.item = T.css.txt + ' position:relative; margin-bottom:1px; display:block; padding:2px 4px;';//
|
|
|
|
},
|
|
|
|
|
|
// note
|
|
|
|
//https://developer.mozilla.org/fr/docs/Web/CSS/css_flexible_box_layout/aligning_items_in_a_flex_container
|
|
|
|
/*cloneColor: function () {
|
|
|
|
let cc = Object.assign({}, T.colors );
|
|
return cc;
|
|
|
|
},*/
|
|
|
|
// intern function
|
|
|
|
cloneCss: function () {
|
|
|
|
//let cc = Object.assign({}, T.css );
|
|
return { ...T.css };
|
|
|
|
},
|
|
|
|
clone: function ( o ) {
|
|
|
|
return o.cloneNode( true );
|
|
|
|
},
|
|
|
|
setSvg: function( dom, type, value, id, id2 ){
|
|
|
|
if( id === -1 ) dom.setAttributeNS( null, type, value );
|
|
else if( id2 !== undefined ) dom.childNodes[ id || 0 ].childNodes[ id2 || 0 ].setAttributeNS( null, type, value );
|
|
else dom.childNodes[ id || 0 ].setAttributeNS( null, type, value );
|
|
|
|
},
|
|
|
|
setCss: function( dom, css ){
|
|
|
|
for( let r in css ){
|
|
if( T.DOM_SIZE.indexOf(r) !== -1 ) dom.style[r] = css[r] + 'px';
|
|
else dom.style[r] = css[r];
|
|
}
|
|
|
|
},
|
|
|
|
set: function( g, o ){
|
|
|
|
for( let att in o ){
|
|
if( att === 'txt' ) g.textContent = o[ att ];
|
|
if( att === 'link' ) g.setAttributeNS( T.links, 'xlink:href', o[ att ] );
|
|
else g.setAttributeNS( null, att, o[ att ] );
|
|
}
|
|
|
|
},
|
|
|
|
get: function( dom, id ){
|
|
|
|
if( id === undefined ) return dom; // root
|
|
else if( !isNaN( id ) ) return dom.childNodes[ id ]; // first child
|
|
else if( id instanceof Array ){
|
|
if(id.length === 2) return dom.childNodes[ id[0] ].childNodes[ id[1] ];
|
|
if(id.length === 3) return dom.childNodes[ id[0] ].childNodes[ id[1] ].childNodes[ id[2] ];
|
|
}
|
|
|
|
},
|
|
|
|
dom : function ( type, css, obj, dom, id ) {
|
|
|
|
type = type || 'div';
|
|
|
|
if( T.SVG_TYPE_D.indexOf(type) !== -1 || T.SVG_TYPE_G.indexOf(type) !== -1 ){ // is svg element
|
|
|
|
if( type ==='svg' ){
|
|
|
|
dom = document.createElementNS( T.svgns, 'svg' );
|
|
T.set( dom, obj );
|
|
|
|
/* } else if ( type === 'use' ) {
|
|
|
|
dom = document.createElementNS( T.svgns, 'use' );
|
|
T.set( dom, obj );
|
|
*/
|
|
} else {
|
|
// create new svg if not def
|
|
if( dom === undefined ) dom = document.createElementNS( T.svgns, 'svg' );
|
|
T.addAttributes( dom, type, obj, id );
|
|
|
|
}
|
|
|
|
} else { // is html element
|
|
|
|
if( dom === undefined ) dom = document.createElementNS( T.htmls, type );
|
|
else dom = dom.appendChild( document.createElementNS( T.htmls, type ) );
|
|
|
|
}
|
|
|
|
if( css ) dom.style.cssText = css;
|
|
|
|
if( id === undefined ) return dom;
|
|
else return dom.childNodes[ id || 0 ];
|
|
|
|
},
|
|
|
|
addAttributes : function( dom, type, o, id ){
|
|
|
|
let g = document.createElementNS( T.svgns, type );
|
|
T.set( g, o );
|
|
T.get( dom, id ).appendChild( g );
|
|
if( T.SVG_TYPE_G.indexOf(type) !== -1 ) g.style.pointerEvents = 'none';
|
|
return g;
|
|
|
|
},
|
|
|
|
clear : function( dom ){
|
|
|
|
T.purge( dom );
|
|
while (dom.firstChild) {
|
|
if ( dom.firstChild.firstChild ) T.clear( dom.firstChild );
|
|
dom.removeChild( dom.firstChild );
|
|
}
|
|
|
|
},
|
|
|
|
purge : function ( dom ) {
|
|
|
|
let a = dom.attributes, i, n;
|
|
if (a) {
|
|
i = a.length;
|
|
while(i--){
|
|
n = a[i].name;
|
|
if (typeof dom[n] === 'function') dom[n] = null;
|
|
}
|
|
}
|
|
a = dom.childNodes;
|
|
if (a) {
|
|
i = a.length;
|
|
while(i--){
|
|
T.purge( dom.childNodes[i] );
|
|
}
|
|
}
|
|
|
|
},
|
|
|
|
// ----------------------
|
|
// SVG Effects function
|
|
// ----------------------
|
|
|
|
addSVGGlowEffect: function () {
|
|
|
|
if ( document.getElementById( 'UILGlow') !== null ) return;
|
|
|
|
let svgFilter = T.initUILEffects();
|
|
|
|
let filter = T.addAttributes( svgFilter, 'filter', { id: 'UILGlow', x: '-20%', y: '-20%', width: '140%', height: '140%' } );
|
|
T.addAttributes( filter, 'feGaussianBlur', { in: 'SourceGraphic', stdDeviation: '3', result: 'uilBlur' } );
|
|
let feMerge = T.addAttributes( filter, 'feMerge', { } );
|
|
|
|
for( let i = 0; i <= 3; i++ ) {
|
|
|
|
T.addAttributes( feMerge, 'feMergeNode', { in: 'uilBlur' } );
|
|
|
|
}
|
|
|
|
T.addAttributes( feMerge, 'feMergeNode', { in: 'SourceGraphic' } );
|
|
|
|
},
|
|
|
|
initUILEffects: function () {
|
|
|
|
let svgFilter = document.getElementById( 'UILSVGEffects');
|
|
|
|
if ( svgFilter === null ) {
|
|
|
|
svgFilter = T.dom( 'svg', undefined , { id: 'UILSVGEffects', width: '0', height: '0' } );
|
|
document.body.appendChild( svgFilter );
|
|
|
|
}
|
|
|
|
return svgFilter;
|
|
|
|
},
|
|
|
|
// ----------------------
|
|
// Color function
|
|
// ----------------------
|
|
|
|
ColorLuma : function ( hex, l ) {
|
|
|
|
if( hex === 'n' ) hex = '#000';
|
|
|
|
// validate hex string
|
|
hex = String(hex).replace(/[^0-9a-f]/gi, '');
|
|
if (hex.length < 6) {
|
|
hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
|
|
}
|
|
l = l || 0;
|
|
|
|
// convert to decimal and change luminosity
|
|
let rgb = "#", c, i;
|
|
for (i = 0; i < 3; i++) {
|
|
c = parseInt(hex.substr(i*2,2), 16);
|
|
c = Math.round(Math.min(Math.max(0, c + (c * l)), 255)).toString(16);
|
|
rgb += ("00"+c).substr(c.length);
|
|
}
|
|
|
|
return rgb;
|
|
|
|
},
|
|
|
|
findDeepInver: function ( c ) {
|
|
|
|
return (c[0] * 0.3 + c[1] * .59 + c[2] * .11) <= 0.6;
|
|
|
|
},
|
|
|
|
lerpColor: function( c1, c2, factor ) {
|
|
let newColor = {};
|
|
for ( let i = 0; i < 3; i++ ) {
|
|
newColor[i] = c1[ i ] + ( c2[ i ] - c1[ i ] ) * factor;
|
|
}
|
|
return newColor;
|
|
},
|
|
|
|
hexToHtml: function ( v ) {
|
|
v = v === undefined ? 0x000000 : v;
|
|
return "#" + ("000000" + v.toString(16)).substr(-6);
|
|
|
|
},
|
|
|
|
htmlToHex: function ( v ) {
|
|
|
|
return v.toUpperCase().replace("#", "0x");
|
|
|
|
},
|
|
|
|
u255: function (c, i) {
|
|
|
|
return parseInt(c.substring(i, i + 2), 16) / 255;
|
|
|
|
},
|
|
|
|
u16: function ( c, i ) {
|
|
|
|
return parseInt(c.substring(i, i + 1), 16) / 15;
|
|
|
|
},
|
|
|
|
unpack: function( c ){
|
|
|
|
if (c.length == 7) return [ T.u255(c, 1), T.u255(c, 3), T.u255(c, 5) ];
|
|
else if (c.length == 4) return [ T.u16(c,1), T.u16(c,2), T.u16(c,3) ];
|
|
|
|
},
|
|
|
|
p255: function ( c ) {
|
|
let h = Math.round( ( c * 255 ) ).toString( 16 );
|
|
if ( h.length < 2 ) h = '0' + h;
|
|
return h;
|
|
},
|
|
|
|
pack: function ( c ) {
|
|
|
|
return '#' + T.p255( c[ 0 ] ) + T.p255( c[ 1 ] ) + T.p255( c[ 2 ] );
|
|
|
|
},
|
|
|
|
htmlRgb: function( c ){
|
|
|
|
return 'rgb(' + Math.round(c[0] * 255) + ','+ Math.round(c[1] * 255) + ','+ Math.round(c[2] * 255) + ')';
|
|
|
|
},
|
|
|
|
pad: function( n ){
|
|
if(n.length == 1)n = '0' + n;
|
|
return n;
|
|
},
|
|
|
|
rgbToHex : function( c ){
|
|
|
|
let r = Math.round(c[0] * 255).toString(16);
|
|
let g = Math.round(c[1] * 255).toString(16);
|
|
let b = Math.round(c[2] * 255).toString(16);
|
|
return '#' + T.pad(r) + T.pad(g) + T.pad(b);
|
|
|
|
// return '#' + ( '000000' + ( ( c[0] * 255 ) << 16 ^ ( c[1] * 255 ) << 8 ^ ( c[2] * 255 ) << 0 ).toString( 16 ) ).slice( - 6 );
|
|
|
|
},
|
|
|
|
hueToRgb: function( p, q, t ){
|
|
|
|
if ( t < 0 ) t += 1;
|
|
if ( t > 1 ) t -= 1;
|
|
if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
|
|
if ( t < 1 / 2 ) return q;
|
|
if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
|
|
return p;
|
|
|
|
},
|
|
|
|
rgbToHsl: function ( c ) {
|
|
|
|
let r = c[0], g = c[1], b = c[2], min = Math.min(r, g, b), max = Math.max(r, g, b), delta = max - min, h = 0, s = 0, l = (min + max) / 2;
|
|
if (l > 0 && l < 1) s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l));
|
|
if (delta > 0) {
|
|
if (max == r && max != g) h += (g - b) / delta;
|
|
if (max == g && max != b) h += (2 + (b - r) / delta);
|
|
if (max == b && max != r) h += (4 + (r - g) / delta);
|
|
h /= 6;
|
|
}
|
|
return [ h, s, l ];
|
|
|
|
},
|
|
|
|
hslToRgb: function ( c ) {
|
|
|
|
let p, q, h = c[0], s = c[1], l = c[2];
|
|
|
|
if ( s === 0 ) return [ l, l, l ];
|
|
else {
|
|
q = l <= 0.5 ? l * (s + 1) : l + s - ( l * s );
|
|
p = l * 2 - q;
|
|
return [ T.hueToRgb(p, q, h + 0.33333), T.hueToRgb(p, q, h), T.hueToRgb(p, q, h - 0.33333) ];
|
|
}
|
|
|
|
},
|
|
|
|
// ----------------------
|
|
// SVG MODEL
|
|
// ----------------------
|
|
|
|
makeGradiant: function ( type, settings, parent, colors ) {
|
|
|
|
T.dom( type, null, settings, parent, 0 );
|
|
|
|
let n = parent.childNodes[0].childNodes.length - 1, c;
|
|
|
|
for( let i = 0; i < colors.length; i++ ){
|
|
|
|
c = colors[i];
|
|
//T.dom( 'stop', null, { offset:c[0]+'%', style:'stop-color:'+c[1]+'; stop-opacity:'+c[2]+';' }, parent, [0,n] );
|
|
T.dom( 'stop', null, { offset:c[0]+'%', 'stop-color':c[1], 'stop-opacity':c[2] }, parent, [0,n] );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/*makeGraph: function () {
|
|
|
|
let w = 128;
|
|
let radius = 34;
|
|
let svg = T.dom( 'svg', T.css.basic , { viewBox:'0 0 '+w+' '+w, width:w, height:w, preserveAspectRatio:'none' } );
|
|
T.dom( 'path', '', { d:'', stroke:T.colors.text, 'stroke-width':4, fill:'none', 'stroke-linecap':'butt' }, svg );//0
|
|
//T.dom( 'rect', '', { x:10, y:10, width:108, height:108, stroke:'rgba(0,0,0,0.3)', 'stroke-width':2 , fill:'none'}, svg );//1
|
|
//T.dom( 'circle', '', { cx:64, cy:64, r:radius, fill:T.colors.button, stroke:'rgba(0,0,0,0.3)', 'stroke-width':8 }, svg );//0
|
|
|
|
//T.dom( 'circle', '', { cx:64, cy:64, r:radius+7, stroke:'rgba(0,0,0,0.3)', 'stroke-width':7 , fill:'none'}, svg );//2
|
|
//T.dom( 'path', '', { d:'', stroke:'rgba(255,255,255,0.3)', 'stroke-width':2, fill:'none', 'stroke-linecap':'round', 'stroke-opacity':0.5 }, svg );//3
|
|
T.graph = svg;
|
|
|
|
},*/
|
|
|
|
makePad: function ( model ) {
|
|
|
|
let ww = 256;
|
|
let svg = T.dom( 'svg', T.css.basic + 'position:relative;', { viewBox:'0 0 '+ww+' '+ww, width:ww, height:ww, preserveAspectRatio:'none' } );
|
|
let w = 200;
|
|
let d = (ww-w)*0.5, m = 20;
|
|
Tools.dom( 'rect', '', { x: d, y: d, width: w, height: w, fill:T.colors.back }, svg ); // 0
|
|
Tools.dom( 'rect', '', { x: d+m*0.5, y: d+m*0.5, width: w - m , height: w - m, fill:T.colors.button }, svg ); // 1
|
|
// Pointer
|
|
Tools.dom( 'line', '', { x1: d+(m*0.5), y1: ww *0.5, x2: d+(w-m*0.5), y2: ww * 0.5, stroke:T.colors.back, 'stroke-width': 2 }, svg ); // 2
|
|
Tools.dom( 'line', '', { x1: ww * 0.5, x2: ww * 0.5, y1: d+(m*0.5), y2: d+(w-m*0.5), stroke:T.colors.back, 'stroke-width': 2 }, svg ); // 3
|
|
Tools.dom( 'circle', '', { cx: ww * 0.5, cy: ww * 0.5, r:5, stroke: T.colors.text, 'stroke-width': 5, fill:'none' }, svg ); // 4
|
|
T.pad2d = svg;
|
|
|
|
},
|
|
|
|
makeKnob: function ( model ) {
|
|
|
|
let w = 128;
|
|
let radius = 34;
|
|
let svg = T.dom( 'svg', T.css.basic + 'position:relative;', { viewBox:'0 0 '+w+' '+w, width:w, height:w, preserveAspectRatio:'none' } );
|
|
T.dom( 'circle', '', { cx:64, cy:64, r:radius, fill:T.colors.button, stroke:'rgba(0,0,0,0.3)', 'stroke-width':8 }, svg );//0
|
|
T.dom( 'path', '', { d:'', stroke:T.colors.text, 'stroke-width':4, fill:'none', 'stroke-linecap':'round' }, svg );//1
|
|
T.dom( 'circle', '', { cx:64, cy:64, r:radius+7, stroke:'rgba(0,0,0,0.1)', 'stroke-width':7 , fill:'none'}, svg );//2
|
|
T.dom( 'path', '', { d:'', stroke:'rgba(255,255,255,0.3)', 'stroke-width':2, fill:'none', 'stroke-linecap':'round', 'stroke-opacity':0.5 }, svg );//3
|
|
T.knob = svg;
|
|
|
|
},
|
|
|
|
makeCircular: function ( model ) {
|
|
|
|
let w = 128;
|
|
let radius = 40;
|
|
let svg = T.dom( 'svg', T.css.basic + 'position:relative;', { viewBox:'0 0 '+w+' '+w, width:w, height:w, preserveAspectRatio:'none' } );
|
|
T.dom( 'circle', '', { cx:64, cy:64, r:radius, stroke:'rgba(0,0,0,0.1)', 'stroke-width':10, fill:'none' }, svg );//0
|
|
T.dom( 'path', '', { d:'', stroke:T.colors.text, 'stroke-width':7, fill:'none', 'stroke-linecap':'butt' }, svg );//1
|
|
T.circular = svg;
|
|
|
|
},
|
|
|
|
makeJoystick: function ( model ) {
|
|
|
|
//+' background:#f00;'
|
|
|
|
let w = 128, ccc;
|
|
let radius = Math.floor((w-30)*0.5);
|
|
let innerRadius = Math.floor(radius*0.6);
|
|
let svg = T.dom( 'svg', T.css.basic + 'position:relative;', { viewBox:'0 0 '+w+' '+w, width:w, height:w, preserveAspectRatio:'none' } );
|
|
T.dom( 'defs', null, {}, svg );
|
|
T.dom( 'g', null, {}, svg );
|
|
|
|
if( model === 0 ){
|
|
|
|
|
|
|
|
// gradian background
|
|
ccc = [ [40, 'rgb(0,0,0)', 0.3], [80, 'rgb(0,0,0)', 0], [90, 'rgb(50,50,50)', 0.4], [100, 'rgb(50,50,50)', 0] ];
|
|
T.makeGradiant( 'radialGradient', { id:'grad', cx:'50%', cy:'50%', r:'50%', fx:'50%', fy:'50%' }, svg, ccc );
|
|
|
|
// gradian shadow
|
|
ccc = [ [60, 'rgb(0,0,0)', 0.5], [100, 'rgb(0,0,0)', 0] ];
|
|
T.makeGradiant( 'radialGradient', { id:'gradS', cx:'50%', cy:'50%', r:'50%', fx:'50%', fy:'50%' }, svg, ccc );
|
|
|
|
// gradian stick
|
|
let cc0 = ['rgb(40,40,40)', 'rgb(48,48,48)', 'rgb(30,30,30)'];
|
|
let cc1 = ['rgb(1,90,197)', 'rgb(3,95,207)', 'rgb(0,65,167)'];
|
|
|
|
ccc = [ [30, cc0[0], 1], [60, cc0[1], 1], [80, cc0[1], 1], [100, cc0[2], 1] ];
|
|
T.makeGradiant( 'radialGradient', { id:'gradIn', cx:'50%', cy:'50%', r:'50%', fx:'50%', fy:'50%' }, svg, ccc );
|
|
|
|
ccc = [ [30, cc1[0], 1], [60, cc1[1], 1], [80, cc1[1], 1], [100, cc1[2], 1] ];
|
|
T.makeGradiant( 'radialGradient', { id:'gradIn2', cx:'50%', cy:'50%', r:'50%', fx:'50%', fy:'50%' }, svg, ccc );
|
|
|
|
// graph
|
|
|
|
T.dom( 'circle', '', { cx:64, cy:64, r:radius, fill:'url(#grad)' }, svg );//2
|
|
T.dom( 'circle', '', { cx:64+5, cy:64+10, r:innerRadius+10, fill:'url(#gradS)' }, svg );//3
|
|
T.dom( 'circle', '', { cx:64, cy:64, r:innerRadius, fill:'url(#gradIn)' }, svg );//4
|
|
|
|
T.joystick_0 = svg;
|
|
|
|
} else {
|
|
// gradian shadow
|
|
ccc = [ [69, 'rgb(0,0,0)', 0],[70, 'rgb(0,0,0)', 0.3], [100, 'rgb(0,0,0)', 0] ];
|
|
T.makeGradiant( 'radialGradient', { id:'gradX', cx:'50%', cy:'50%', r:'50%', fx:'50%', fy:'50%' }, svg, ccc );
|
|
|
|
T.dom( 'circle', '', { cx:64, cy:64, r:radius, fill:'none', stroke:'rgba(100,100,100,0.25)', 'stroke-width':'4' }, svg );//2
|
|
T.dom( 'circle', '', { cx:64, cy:64, r:innerRadius+14, fill:'url(#gradX)' }, svg );//3
|
|
T.dom( 'circle', '', { cx:64, cy:64, r:innerRadius, fill:'none', stroke:'rgb(100,100,100)', 'stroke-width':'4' }, svg );//4
|
|
|
|
T.joystick_1 = svg;
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
makeColorRing: function () {
|
|
|
|
let w = 256;
|
|
let svg = T.dom( 'svg', T.css.basic + 'position:relative;', { viewBox:'0 0 '+w+' '+w, width:w, height:w, preserveAspectRatio:'none' } );
|
|
T.dom( 'defs', null, {}, svg );
|
|
T.dom( 'g', null, {}, svg );
|
|
|
|
let s = 30;//stroke
|
|
let r =( w-s )*0.5;
|
|
let mid = w*0.5;
|
|
let n = 24, nudge = 8 / r / n * Math.PI, a1 = 0;
|
|
let am, tan, d2, a2, ar, i, j, path, ccc;
|
|
let color = [];
|
|
|
|
for ( i = 0; i <= n; ++i) {
|
|
|
|
d2 = i / n;
|
|
a2 = d2 * T.TwoPI;
|
|
am = (a1 + a2) * 0.5;
|
|
tan = 1 / Math.cos((a2 - a1) * 0.5);
|
|
|
|
ar = [
|
|
Math.sin(a1), -Math.cos(a1),
|
|
Math.sin(am) * tan, -Math.cos(am) * tan,
|
|
Math.sin(a2), -Math.cos(a2)
|
|
];
|
|
|
|
color[1] = T.rgbToHex( T.hslToRgb([d2, 1, 0.5]) );
|
|
|
|
if (i > 0) {
|
|
|
|
j = 6;
|
|
while(j--){
|
|
ar[j] = ((ar[j]*r)+mid).toFixed(2);
|
|
}
|
|
|
|
path = ' M' + ar[0] + ' ' + ar[1] + ' Q' + ar[2] + ' ' + ar[3] + ' ' + ar[4] + ' ' + ar[5];
|
|
|
|
ccc = [ [0,color[0],1], [100,color[1],1] ];
|
|
T.makeGradiant( 'linearGradient', { id:'G'+i, x1:ar[0], y1:ar[1], x2:ar[4], y2:ar[5], gradientUnits:"userSpaceOnUse" }, svg, ccc );
|
|
|
|
T.dom( 'path', '', { d:path, 'stroke-width':s, stroke:'url(#G'+i+')', 'stroke-linecap':"butt" }, svg, 1 );
|
|
|
|
}
|
|
a1 = a2 - nudge;
|
|
color[0] = color[1];
|
|
}
|
|
|
|
let tw = 84.90;
|
|
|
|
// black / white
|
|
ccc = [ [0, '#FFFFFF', 1], [50, '#FFFFFF', 0], [50, '#000000', 0], [100, '#000000', 1] ];
|
|
T.makeGradiant( 'linearGradient', { id:'GL0', x1:0, y1:mid-tw, x2:0, y2:mid+tw, gradientUnits:"userSpaceOnUse" }, svg, ccc );
|
|
|
|
ccc = [ [0, '#7f7f7f', 1], [50, '#7f7f7f', 0.5], [100, '#7f7f7f', 0] ];
|
|
T.makeGradiant( 'linearGradient', { id:'GL1', x1:mid-49.05, y1:0, x2:mid+98, y2:0, gradientUnits:"userSpaceOnUse" }, svg, ccc );
|
|
|
|
T.dom( 'g', null, { 'transform-origin': '128px 128px', 'transform':'rotate(0)' }, svg );//2
|
|
T.dom( 'polygon', '', { points:'78.95 43.1 78.95 212.85 226 128', fill:'red' }, svg, 2 );// 2,0
|
|
T.dom( 'polygon', '', { points:'78.95 43.1 78.95 212.85 226 128', fill:'url(#GL1)','stroke-width':1, stroke:'url(#GL1)' }, svg, 2 );//2,1
|
|
T.dom( 'polygon', '', { points:'78.95 43.1 78.95 212.85 226 128', fill:'url(#GL0)','stroke-width':1, stroke:'url(#GL0)' }, svg, 2 );//2,2
|
|
T.dom( 'path', '', { d:'M 255.75 136.5 Q 256 132.3 256 128 256 123.7 255.75 119.5 L 241 128 255.75 136.5 Z', fill:'none','stroke-width':2, stroke:'#000' }, svg, 2 );//2,3
|
|
//T.dom( 'circle', '', { cx:128+113, cy:128, r:6, 'stroke-width':3, stroke:'#000', fill:'none' }, svg, 2 );//2.3
|
|
|
|
T.dom( 'circle', '', { cx:128, cy:128, r:6, 'stroke-width':2, stroke:'#000', fill:'none' }, svg );//3
|
|
|
|
T.colorRing = svg;
|
|
|
|
},
|
|
|
|
icon: function ( type, color, w ){
|
|
|
|
w = w || 40;
|
|
//color = color || '#DEDEDE';
|
|
let viewBox = '0 0 256 256';
|
|
//let viewBox = '0 0 '+ w +' '+ w;
|
|
let t = ["<svg xmlns='"+T.svgns+"' version='1.1' xmlns:xlink='"+T.htmls+"' style='pointer-events:none;' preserveAspectRatio='xMinYMax meet' x='0px' y='0px' width='"+w+"px' height='"+w+"px' viewBox='"+viewBox+"'><g>"];
|
|
switch(type){
|
|
case 'logo':
|
|
t[1]="<path id='logoin' fill='"+color+"' stroke='none' d='"+T.logoFill_d+"'/>";
|
|
break;
|
|
case 'donate':
|
|
t[1]="<path id='logoin' fill='"+color+"' stroke='none' d='"+T.logo_donate+"'/>";
|
|
break;
|
|
case 'neo':
|
|
t[1]="<path id='logoin' fill='"+color+"' stroke='none' d='"+T.logo_neo+"'/>";
|
|
break;
|
|
case 'github':
|
|
t[1]="<path id='logoin' fill='"+color+"' stroke='none' d='"+T.logo_github+"'/>";
|
|
break;
|
|
case 'save':
|
|
t[1]="<path stroke='"+color+"' stroke-width='4' stroke-linejoin='round' stroke-linecap='round' fill='none' d='M 26.125 17 L 20 22.95 14.05 17 M 20 9.95 L 20 22.95'/><path stroke='"+color;
|
|
t[1]+="' stroke-width='2.5' stroke-linejoin='round' stroke-linecap='round' fill='none' d='M 32.6 23 L 32.6 25.5 Q 32.6 28.5 29.6 28.5 L 10.6 28.5 Q 7.6 28.5 7.6 25.5 L 7.6 23'/>";
|
|
break;
|
|
}
|
|
t[2] = "</g></svg>";
|
|
return t.join("\n");
|
|
|
|
},
|
|
|
|
logoFill_d:`
|
|
M 171 150.75 L 171 33.25 155.5 33.25 155.5 150.75 Q 155.5 162.2 147.45 170.2 139.45 178.25 128 178.25 116.6 178.25 108.55 170.2 100.5 162.2 100.5 150.75
|
|
L 100.5 33.25 85 33.25 85 150.75 Q 85 168.65 97.55 181.15 110.15 193.75 128 193.75 145.9 193.75 158.4 181.15 171 168.65 171 150.75
|
|
M 200 33.25 L 184 33.25 184 150.8 Q 184 174.1 167.6 190.4 151.3 206.8 128 206.8 104.75 206.8 88.3 190.4 72 174.1 72 150.8 L 72 33.25 56 33.25 56 150.75
|
|
Q 56 180.55 77.05 201.6 98.2 222.75 128 222.75 157.8 222.75 178.9 201.6 200 180.55 200 150.75 L 200 33.25 Z
|
|
`,
|
|
|
|
logo_github:`
|
|
M 180.5 70 Q 186.3 82.4 181.55 96.55 196.5 111.5 189.7 140.65 183.65 168.35 146 172.7 152.5 178.7 152.55 185.9 L 152.55 218.15 Q 152.84 224.56 159.15 223.3
|
|
159.21 223.3 159.25 223.3 181.14 216.25 198.7 198.7 228 169.4 228 128 228 86.6 198.7 57.3 169.4 28 128 28 86.6 28 57.3 57.3 28 86.6 28 128 28 169.4 57.3 198.7 74.85
|
|
216.25 96.75 223.3 96.78 223.3 96.8 223.3 103.16 224.54 103.45 218.15 L 103.45 200 Q 82.97 203.1 75.1 196.35 69.85 191.65 68.4 185.45 64.27 177.055 59.4 174.15 49.20
|
|
166.87 60.8 167.8 69.85 169.61 75.7 180 81.13 188.09 90 188.55 98.18 188.86 103.45 185.9 103.49 178.67 110 172.7 72.33 168.33 66.3 140.65 59.48 111.49 74.45 96.55 69.7
|
|
82.41 75.5 70 84.87 68.74 103.15 80 115.125 76.635 128 76.85 140.85 76.65 152.85 80 171.1 68.75 180.5 70 Z
|
|
`,
|
|
|
|
logo_neo:`
|
|
M 219 52 L 206 52 206 166 Q 206 183.4 193.75 195.65 181.4 208 164 208 146.6 208 134.35 195.65 122 183.4 122 166 L 122 90 Q 122 77.6 113.15 68.85 104.4 60 92 60 79.55
|
|
60 70.75 68.85 62 77.6 62 90 L 62 204 75 204 75 90 Q 75 83 79.95 78 84.95 73 92 73 99 73 104 78 109 83 109 90 L 109 166 Q 109 188.8 125.15 204.85 141.2 221 164 221
|
|
186.75 221 202.95 204.85 219 188.8 219 166 L 219 52 M 194 52 L 181 52 181 166 Q 181 173 176.05 178 171.05 183 164 183 157 183 152 178 147 173 147 166 L 147 90 Q 147
|
|
67.2 130.85 51.15 114.8 35 92 35 69.25 35 53.05 51.15 37 67.2 37 90 L 37 204 50 204 50 90 Q 50 72.6 62.25 60.35 74.6 48 92 48 109.4 48 121.65 60.35 134 72.6 134 90 L
|
|
134 166 Q 134 178.4 142.85 187.15 151.6 196 164 196 176.45 196 185.25 187.15 194 178.4 194 166 L 194 52 Z
|
|
`,
|
|
|
|
logo_donate:`
|
|
M 171.3 80.3 Q 179.5 62.15 171.3 45.8 164.1 32.5 141.35 30.1 L 94.35 30.1 Q 89.35 30.4 88.3 35.15 L 70.5 148.05 Q 70.2 152.5 73.7 152.6 L 100.95 152.6 107 111.6 Q 108.75
|
|
106.55 112.6 106.45 130.45 108.05 145.3 103.9 163.35 98.75 171.3 80.3 M 179.8 71.5 Q 178.6 79.75 174.9 87.85 168.45 102.9 151.9 109.15 140.65 113.95 117.55 113 113.15
|
|
112.75 111 117.45 L 102.7 169.95 Q 102.45 173.8 105.5 173.85 L 128.95 173.85 Q 132.2 174.2 133.35 169.65 L 138.3 139.95 Q 139.75 135.6 143.1 135.5 146.6 135.75 150.6 135.65
|
|
154.55 135.5 157.35 135.1 160.15 134.7 166.75 132.35 181.35 127.4 187.9 111.2 194.25 95.75 189.5 81.95 186.75 74.85 179.8 71.5 M 103.5 209.9 Q 103.5 202.85 99.7 198.85 95.95
|
|
194.75 89.4 194.75 82.8 194.75 79.05 198.85 75.3 202.9 75.3 209.9 75.3 216.85 79.05 220.95 82.8 225.05 89.4 225.05 95.95 225.05 99.7 221 103.5 216.95 103.5 209.9 M 95.45 205.5
|
|
Q 95.95 207.3 95.95 209.9 95.95 212.65 95.45 214.35 94.95 216 94 217.3 93.1 218.45 91.9 219 90.7 219.55 89.4 219.55 88.15 219.55 86.95 219.05 85.75 218.55 84.8 217.3 83.9 216.15
|
|
83.4 214.35 82.85 212.6 82.85 209.9 82.85 207.3 83.4 205.45 83.95 203.55 84.85 202.45 85.9 201.2 86.95 200.75 88.05 200.25 89.4 200.25 90.7 200.25 91.85 200.8 93.05 201.3 94 202.5
|
|
94.9 203.65 95.45 205.5 M 153.3 195.35 L 145.3 195.35 135.5 224.45 142.8 224.45 144.6 218.5 153.75 218.5 155.6 224.45 163.1 224.45 153.3 195.35 M 152.15 213.25 L 146.25 213.25
|
|
149.2 203.65 152.15 213.25 M 116.75 195.35 L 107.8 195.35 107.8 224.45 114.5 224.45 114.5 204.2 125.7 224.45 132.75 224.45 132.75 195.35 126.05 195.35 126.05 212.05 116.75 195.35 M
|
|
66.5 197.65 Q 64.15 196.15 61.45 195.75 58.8 195.35 55.75 195.35 L 46.7 195.35 46.7 224.45 55.8 224.45 Q 58.8 224.45 61.5 224.05 64.15 223.6 66.4 222.15 69.15 220.45 70.9 217.2
|
|
72.7 214 72.7 209.95 72.7 205.7 71 202.6 69.35 199.5 66.5 197.65 M 64.2 205 Q 65.2 207 65.2 209.9 65.2 212.75 64.25 214.75 63.3 216.75 61.5 217.85 60 218.85 58.3 218.9 56.6 219
|
|
54.15 219 L 54 219 54 200.8 54.15 200.8 Q 56.4 200.8 58.05 200.9 59.7 200.95 61.15 201.75 63.2 202.95 64.2 205 M 210.2 195.35 L 190.5 195.35 190.5 224.45 210.2 224.45 210.2 218.9
|
|
197.75 218.9 197.75 211.55 209.2 211.55 209.2 206 197.75 206 197.75 200.9 210.2 200.9 210.2 195.35 M 187.5 195.35 L 163 195.35 163 200.9 171.6 200.9 171.6 224.45 178.9 224.45 178.9
|
|
200.9 187.5 200.9 187.5 195.35 Z
|
|
`,
|
|
|
|
};
|
|
|
|
T.setText();
|
|
|
|
const Tools = T;
|
|
|
|
///https://wicg.github.io/file-system-access/#api-filesystemfilehandle-getfile
|
|
|
|
|
|
class Files {
|
|
|
|
//-----------------------------
|
|
// FILE TYPE
|
|
//-----------------------------
|
|
|
|
static autoTypes( type ) {
|
|
|
|
let t = [];
|
|
|
|
switch( type ){
|
|
case 'json':
|
|
t = [ { accept: { 'image/svg+xml': '.svg'} }, ];
|
|
break;
|
|
case 'text':
|
|
t = [ { description: 'Text Files', accept: { 'text/plain': ['.txt', '.text'], 'text/html': ['.html', '.htm'] } }, ];
|
|
break;
|
|
case 'json':
|
|
t = [ { description: 'JSON Files', accept: { 'text/plain': ['.json'] } }, ];
|
|
break;
|
|
case 'image':
|
|
t = [ { description: 'Images', accept: { 'image/*': ['.png', '.gif', '.jpeg', '.jpg'] } }, ];
|
|
break;
|
|
|
|
}
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
|
|
//-----------------------------
|
|
// LOAD
|
|
//-----------------------------
|
|
|
|
static async load( o = {} ) {
|
|
|
|
if (typeof window.showOpenFilePicker !== 'function') {
|
|
window.showOpenFilePicker = this.showOpenFilePickerPolyfill;
|
|
}
|
|
|
|
try {
|
|
|
|
let type = o.type || '';
|
|
|
|
const options = {
|
|
excludeAcceptAllOption: type ? true : false,
|
|
multiple: false,
|
|
//startIn:'./assets'
|
|
};
|
|
|
|
options.types = this.autoTypes( type );
|
|
|
|
// create a new handle
|
|
const handle = await window.showOpenFilePicker( options );
|
|
const file = await handle[0].getFile();
|
|
//let content = await file.text()
|
|
|
|
if( !file ) return null
|
|
|
|
let fname = file.name;
|
|
let ftype = fname.substring( fname.lastIndexOf('.')+1, fname.length );
|
|
|
|
const dataUrl = [ 'png', 'jpg', 'jpeg', 'mp4', 'webm', 'ogg', 'mp3' ];
|
|
const dataBuf = [ 'sea', 'z', 'hex', 'bvh', 'BVH', 'glb', 'gltf' ];
|
|
const reader = new FileReader();
|
|
|
|
if( dataUrl.indexOf( ftype ) !== -1 ) reader.readAsDataURL( file );
|
|
else if( dataBuf.indexOf( ftype ) !== -1 ) reader.readAsArrayBuffer( file );
|
|
else reader.readAsText( file );
|
|
|
|
reader.onload = function(e) {
|
|
|
|
let content = e.target.result;
|
|
|
|
if( type === 'image' ){
|
|
var img = new Image;
|
|
img.onload = function() {
|
|
if( o.callback ) o.callback( img, fname );
|
|
};
|
|
img.src = content;
|
|
} else {
|
|
if( o.callback ) o.callback( content, fname );
|
|
}
|
|
|
|
};
|
|
|
|
} catch(e) {
|
|
|
|
console.log(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static showOpenFilePickerPolyfill( options ) {
|
|
return new Promise((resolve) => {
|
|
const input = document.createElement("input");
|
|
input.type = "file";
|
|
input.multiple = options.multiple;
|
|
input.accept = options.types
|
|
.map((type) => type.accept)
|
|
.flatMap((inst) => Object.keys(inst).flatMap((key) => inst[key]))
|
|
.join(",");
|
|
|
|
input.addEventListener("change", () => {
|
|
resolve(
|
|
[...input.files].map((file) => {
|
|
return {
|
|
getFile: async () =>
|
|
new Promise((resolve) => {
|
|
resolve(file);
|
|
}),
|
|
};
|
|
})
|
|
);
|
|
});
|
|
|
|
input.click();
|
|
})
|
|
}
|
|
|
|
|
|
//-----------------------------
|
|
// SAVE
|
|
//-----------------------------
|
|
|
|
static async save( o = {} ) {
|
|
|
|
this.usePoly = false;
|
|
|
|
if (typeof window.showSaveFilePicker !== 'function') {
|
|
window.showSaveFilePicker = this.showSaveFilePickerPolyfill;
|
|
this.usePoly = true;
|
|
}
|
|
|
|
try {
|
|
|
|
let type = o.type || '';
|
|
|
|
const options = {
|
|
suggestedName: o.name || 'hello',
|
|
data: o.data || ''
|
|
};
|
|
|
|
|
|
options.types = this.autoTypes( type );
|
|
options.finalType = Object.keys(options.types[0].accept )[0];
|
|
options.suggestedName += options.types[0].accept[options.finalType][0];
|
|
|
|
|
|
// create a new handle
|
|
const handle = await window.showSaveFilePicker( options );
|
|
|
|
if( this.usePoly ) return
|
|
|
|
// create a FileSystemWritableFileStream to write to
|
|
const file = await handle.createWritable();
|
|
|
|
let blob = new Blob([ options.data ], { type: option.finalType });
|
|
|
|
// write our file
|
|
await file.write(blob);
|
|
|
|
// close the file and write the contents to disk.
|
|
await file.close();
|
|
|
|
} catch(e) {
|
|
|
|
console.log(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static showSaveFilePickerPolyfill( options ) {
|
|
return new Promise((resolve) => {
|
|
const a = document.createElement("a");
|
|
a.download = options.suggestedName || "my-file.txt";
|
|
let blob = new Blob([ options.data ], { type:options.finalType });
|
|
a.href = URL.createObjectURL( blob );
|
|
|
|
a.addEventListener("click", () => {
|
|
resolve(
|
|
setTimeout( () => URL.revokeObjectURL(a.href), 1000 )
|
|
);
|
|
});
|
|
a.click();
|
|
})
|
|
}
|
|
|
|
|
|
//-----------------------------
|
|
// FOLDER not possible in poly
|
|
//-----------------------------
|
|
|
|
static async getFolder() {
|
|
|
|
try {
|
|
|
|
const handle = await window.showDirectoryPicker();
|
|
const files = [];
|
|
for await (const entry of handle.values()) {
|
|
const file = await entry.getFile();
|
|
files.push(file);
|
|
}
|
|
|
|
console.log(files);
|
|
return files;
|
|
|
|
} catch(e) {
|
|
|
|
console.log(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
class V2 {
|
|
|
|
constructor( x = 0, y = 0 ) {
|
|
|
|
this.x = x;
|
|
this.y = y;
|
|
|
|
}
|
|
|
|
set ( x, y ) {
|
|
|
|
this.x = x;
|
|
this.y = y;
|
|
return this;
|
|
|
|
}
|
|
|
|
divide ( v ) {
|
|
|
|
this.x /= v.x;
|
|
this.y /= v.y;
|
|
return this;
|
|
|
|
}
|
|
|
|
multiply ( v ) {
|
|
|
|
this.x *= v.x;
|
|
this.y *= v.y;
|
|
return this;
|
|
|
|
}
|
|
|
|
multiplyScalar ( scalar ) {
|
|
|
|
this.x *= scalar;
|
|
this.y *= scalar;
|
|
return this;
|
|
|
|
}
|
|
|
|
divideScalar ( scalar ) {
|
|
|
|
return this.multiplyScalar( 1 / scalar );
|
|
|
|
}
|
|
|
|
length () {
|
|
|
|
return Math.sqrt( this.x * this.x + this.y * this.y );
|
|
|
|
}
|
|
|
|
angle () {
|
|
|
|
// computes the angle in radians with respect to the positive x-axis
|
|
|
|
var angle = Math.atan2( this.y, this.x );
|
|
|
|
if ( angle < 0 ) angle += 2 * Math.PI;
|
|
|
|
return angle;
|
|
|
|
}
|
|
|
|
addScalar ( s ) {
|
|
|
|
this.x += s;
|
|
this.y += s;
|
|
return this;
|
|
|
|
}
|
|
|
|
negate () {
|
|
|
|
this.x *= -1;
|
|
this.y *= -1;
|
|
return this;
|
|
|
|
}
|
|
|
|
neg () {
|
|
|
|
this.x = -1;
|
|
this.y = -1;
|
|
return this;
|
|
|
|
}
|
|
|
|
isZero () {
|
|
|
|
return ( this.x === 0 && this.y === 0 );
|
|
|
|
}
|
|
|
|
copy ( v ) {
|
|
|
|
this.x = v.x;
|
|
this.y = v.y;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
equals ( v ) {
|
|
|
|
return ( ( v.x === this.x ) && ( v.y === this.y ) );
|
|
|
|
}
|
|
|
|
nearEquals ( v, n ) {
|
|
|
|
return ( ( v.x.toFixed(n) === this.x.toFixed(n) ) && ( v.y.toFixed(n) === this.y.toFixed(n) ) );
|
|
|
|
}
|
|
|
|
lerp ( v, alpha ) {
|
|
|
|
if( v === null ){
|
|
this.x -= this.x * alpha;
|
|
this.y -= this.y * alpha;
|
|
} else {
|
|
this.x += ( v.x - this.x ) * alpha;
|
|
this.y += ( v.y - this.y ) * alpha;
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* @author lth / https://github.com/lo-th
|
|
*/
|
|
|
|
class Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
|
|
|
|
// disable mouse controle
|
|
this.lock = o.lock || false;
|
|
|
|
// for button
|
|
this.neverlock = false;
|
|
|
|
// only simple space
|
|
this.isSpace = o.isSpace || false;
|
|
|
|
// if is on gui or group
|
|
this.main = o.main || null;
|
|
this.isUI = o.isUI || false;
|
|
this.group = o.group || null;
|
|
|
|
this.isListen = false;
|
|
|
|
this.isSelectable = o.selectable !== undefined ? o.selectable : false;
|
|
this.unselectable = o.unselect !== undefined ? o.unselect : this.isSelectable;
|
|
|
|
this.ontop = o.ontop ? o.ontop : false; // 'beforebegin' 'afterbegin' 'beforeend' 'afterend'
|
|
|
|
this.css = this.main ? this.main.css : Tools.css;
|
|
|
|
this.colors = Tools.defineColor( o, this.main ? ( this.group ? this.group.colors : this.main.colors ) : Tools.colors );
|
|
|
|
this.svgs = Tools.svgs;
|
|
|
|
this.zone = { x:0, y:0, w:0, h:0 };
|
|
this.local = new V2().neg();
|
|
|
|
this.isCanvasOnly = false;
|
|
this.isSelect = false;
|
|
|
|
// percent of title
|
|
this.p = o.p !== undefined ? o.p : Tools.size.p;
|
|
|
|
this.w = this.isUI ? this.main.size.w : Tools.size.w;
|
|
if( o.w !== undefined ) this.w = o.w;
|
|
|
|
this.h = this.isUI ? this.main.size.h : Tools.size.h;
|
|
if( o.h !== undefined ) this.h = o.h;
|
|
if( !this.isSpace ) this.h = this.h < 11 ? 11 : this.h;
|
|
else this.lock = true;
|
|
|
|
|
|
// decale for canvas only
|
|
this.fw = o.fw || 0;
|
|
|
|
this.autoWidth = o.auto || true;// auto width or flex
|
|
this.isOpen = false;// open statu
|
|
|
|
// radius for toolbox
|
|
this.radius = o.radius || this.colors.radius;
|
|
|
|
this.transition = o.transition || Tools.transition;
|
|
|
|
// only for number
|
|
this.isNumber = false;
|
|
this.noNeg = o.noNeg || false;
|
|
this.allEqual = o.allEqual || false;
|
|
|
|
// only most simple
|
|
this.mono = false;
|
|
|
|
// stop listening for edit slide text
|
|
this.isEdit = false;
|
|
|
|
// no title
|
|
this.simple = o.simple || false;
|
|
if( this.simple ) this.sa = 0;
|
|
|
|
|
|
// define obj size
|
|
this.setSize( this.w );
|
|
|
|
// title size
|
|
if( o.sa !== undefined ) this.sa = o.sa;
|
|
if( o.sb !== undefined ) this.sb = o.sb;
|
|
if( this.simple ) this.sb = this.w - this.sa;
|
|
|
|
// last number size for slide
|
|
this.sc = o.sc === undefined ? 47 : o.sc;
|
|
|
|
// for listening object
|
|
this.objectLink = null;
|
|
this.isSend = false;
|
|
this.val = null;
|
|
|
|
this.txt = o.name || '';
|
|
this.name = o.rename || this.txt;
|
|
this.target = o.target || null;
|
|
|
|
// callback
|
|
this.callback = o.callback === undefined ? null : o.callback;
|
|
this.endCallback = null;
|
|
this.openCallback = o.openCallback === undefined ? null : o.openCallback;
|
|
this.closeCallback = o.closeCallback === undefined ? null : o.closeCallback;
|
|
|
|
// if no callback take one from group or gui
|
|
if( this.callback === null && this.isUI && this.main.callback !== null ){
|
|
this.callback = this.group ? this.group.callback : this.main.callback;
|
|
}
|
|
|
|
// elements
|
|
this.c = [];
|
|
|
|
// style
|
|
this.s = [];
|
|
|
|
|
|
this.useFlex = this.isUI ? this.main.useFlex : false;
|
|
let flexible = this.useFlex ? 'display:flex; justify-content:center; align-items:center; text-align:center; flex: 1 100%;' : 'float:left;';
|
|
|
|
this.c[0] = Tools.dom( 'div', this.css.basic + flexible + 'position:relative; height:20px;');
|
|
|
|
|
|
this.s[0] = this.c[0].style;
|
|
|
|
// bottom margin
|
|
this.margin = o.margin || 1;
|
|
if( this.isUI && this.margin ){
|
|
this.s[0].boxSizing = 'content-box';
|
|
//this.s[0].marginBottom = this.margin + 'px';
|
|
if( this.margin*0.5===Math.floor(this.margin*0.5) ){
|
|
this.s[0].borderTop = (this.margin*0.5) + 'px solid transparent';
|
|
this.s[0].borderBottom = (this.margin*0.5) + 'px solid transparent';
|
|
} else {
|
|
this.s[0].borderBottom = this.margin + 'px solid transparent';
|
|
}
|
|
|
|
}
|
|
|
|
// with title
|
|
if( !this.simple ){
|
|
this.c[1] = Tools.dom( 'div', this.css.txt );
|
|
this.s[1] = this.c[1].style;
|
|
this.c[1].textContent = this.name;
|
|
this.s[1].color = this.lock ? this.colors.titleoff : this.colors.title;
|
|
}
|
|
|
|
if( o.pos ){
|
|
this.s[0].position = 'absolute';
|
|
for(let p in o.pos){
|
|
this.s[0][p] = o.pos[p];
|
|
}
|
|
this.mono = true;
|
|
}
|
|
|
|
|
|
|
|
|
|
if( o.css ) this.s[0].cssText = o.css;
|
|
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// make the node
|
|
// ----------------------
|
|
|
|
init() {
|
|
|
|
this.zone.h = this.h;
|
|
this.zone.w = this.w;
|
|
|
|
let s = this.s; // style cache
|
|
let c = this.c; // div cach
|
|
|
|
s[0].height = this.h + 'px';
|
|
|
|
if( this.isUI ) s[0].background = this.colors.background;
|
|
|
|
if(!this.autoWidth && this.useFlex ){
|
|
s[0].flex = '1 0 auto';
|
|
s[0].minWidth = this.minw+'px';
|
|
s[0].textAlign = 'center';
|
|
} else {
|
|
if( this.isUI ) s[0].width = '100%';
|
|
}
|
|
|
|
//if( this.autoHeight ) s[0].transition = 'height 0.01s ease-out';
|
|
if( c[1] !== undefined && this.autoWidth ){
|
|
s[1] = c[1].style;
|
|
s[1].height = (this.h-4) + 'px';
|
|
s[1].lineHeight = (this.h-8) + 'px';
|
|
}
|
|
|
|
let frag = Tools.frag;
|
|
|
|
for( let i = 1, lng = c.length; i !== lng; i++ ){
|
|
if( c[i] !== undefined ) {
|
|
frag.appendChild( c[i] );
|
|
s[i] = c[i].style;
|
|
}
|
|
}
|
|
|
|
let pp = this.target !== null ? this.target : ( this.isUI ? this.main.inner : document.body );
|
|
|
|
if( this.ontop ) pp.insertAdjacentElement( 'afterbegin', c[0] );
|
|
else pp.appendChild( c[0] );
|
|
|
|
c[0].appendChild( frag );
|
|
|
|
this.rSize();
|
|
|
|
// ! solo proto
|
|
if( !this.isUI ){
|
|
|
|
this.c[0].style.pointerEvents = 'auto';
|
|
Roots.add( this );
|
|
|
|
}
|
|
|
|
|
|
if( this.baseH && this.transition && this.isUI ){
|
|
this.c[0].style.transition = 'height '+this.transition+'s ease-out';
|
|
}
|
|
|
|
}
|
|
|
|
// from Tools
|
|
|
|
dom( type, css, obj, dom, id ) {
|
|
|
|
return Tools.dom( type, css, obj, dom, id );
|
|
|
|
}
|
|
|
|
setSvg( dom, type, value, id, id2 ) {
|
|
|
|
Tools.setSvg( dom, type, value, id, id2 );
|
|
|
|
}
|
|
|
|
setCss( dom, css ) {
|
|
|
|
Tools.setCss( dom, css );
|
|
|
|
}
|
|
|
|
clamp( value, min, max ) {
|
|
|
|
return Tools.clamp( value, min, max );
|
|
|
|
}
|
|
|
|
getColorRing() {
|
|
|
|
if( !Tools.colorRing ) Tools.makeColorRing();
|
|
return Tools.clone( Tools.colorRing );
|
|
|
|
}
|
|
|
|
getJoystick( model ) {
|
|
|
|
if( !Tools[ 'joystick_'+ model ] ) Tools.makeJoystick( model );
|
|
return Tools.clone( Tools[ 'joystick_'+ model ] )
|
|
|
|
}
|
|
|
|
getCircular( model ) {
|
|
|
|
if( !Tools.circular ) Tools.makeCircular( model );
|
|
return Tools.clone( Tools.circular )
|
|
|
|
}
|
|
|
|
getKnob( model ) {
|
|
|
|
if( !Tools.knob ) Tools.makeKnob( model );
|
|
return Tools.clone( Tools.knob )
|
|
|
|
}
|
|
|
|
getPad2d( model ) {
|
|
|
|
if( !Tools.pad2d ) Tools.makePad( model );
|
|
return Tools.clone( Tools.pad2d )
|
|
|
|
}
|
|
|
|
// from Roots
|
|
|
|
cursor( name ) {
|
|
|
|
Roots.cursor( name );
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////
|
|
|
|
update() {}
|
|
|
|
reset() {}
|
|
|
|
/////////
|
|
|
|
getDom() {
|
|
|
|
return this.c[0]
|
|
|
|
}
|
|
|
|
uiout() {
|
|
|
|
if( this.lock ) return;
|
|
|
|
if(this.s) this.s[0].background = this.colors.background;
|
|
|
|
}
|
|
|
|
uiover() {
|
|
|
|
if( this.lock ) return;
|
|
|
|
if(this.s) this.s[0].background = this.colors.backgroundOver;
|
|
|
|
}
|
|
|
|
rename( s ) {
|
|
|
|
if( this.c[1] !== undefined) this.c[1].textContent = s;
|
|
|
|
}
|
|
|
|
listen() {
|
|
|
|
this.isListen = Roots.addListen( this );
|
|
return this;
|
|
|
|
}
|
|
|
|
listening() {
|
|
|
|
if( this.objectLink === null ) return;
|
|
if( this.isSend ) return;
|
|
if( this.isEdit ) return;
|
|
|
|
this.setValue( this.objectLink[ this.val ] );
|
|
|
|
}
|
|
|
|
setValue( v ) {
|
|
|
|
if( this.isNumber ) this.value = this.numValue( v );
|
|
//else if( v instanceof Array && v.length === 1 ) v = v[0];
|
|
else this.value = v;
|
|
this.update();
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// update every change
|
|
// ----------------------
|
|
|
|
onChange( f ) {
|
|
|
|
if( this.isSpace ) return
|
|
this.callback = f || null;
|
|
return this
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// update only on end
|
|
// ----------------------
|
|
|
|
onFinishChange( f ) {
|
|
|
|
if( this.isSpace ) return;
|
|
this.callback = null;
|
|
this.endCallback = f;
|
|
return this
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// event on open close
|
|
// ----------------------
|
|
|
|
onOpen( f ) {
|
|
|
|
this.openCallback = f;
|
|
return this
|
|
|
|
}
|
|
|
|
onClose( f ) {
|
|
|
|
this.closeCallback = f;
|
|
return this
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// send back value
|
|
// ----------------------
|
|
|
|
send( v ) {
|
|
|
|
v = v || this.value;
|
|
if( v instanceof Array && v.length === 1 ) v = v[0];
|
|
|
|
this.isSend = true;
|
|
if( this.objectLink !== null ) this.objectLink[ this.val ] = v;
|
|
if( this.callback ) this.callback( v, this.val );
|
|
this.isSend = false;
|
|
|
|
}
|
|
|
|
sendEnd( v ) {
|
|
|
|
v = v || this.value;
|
|
if( v instanceof Array && v.length === 1 ) v = v[0];
|
|
|
|
if( this.endCallback ) this.endCallback( v );
|
|
if( this.objectLink !== null ) this.objectLink[ this.val ] = v;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// clear node
|
|
// ----------------------
|
|
|
|
dispose(){
|
|
|
|
if( this.isListen ) Roots.removeListen( this );
|
|
|
|
Tools.clear( this.c[0] );
|
|
|
|
if( this.target !== null ){
|
|
|
|
if( this.group !== null ) this.group.clearOne( this );
|
|
else this.target.removeChild( this.c[0] );
|
|
|
|
} else {
|
|
|
|
if( this.isUI ) this.main.clearOne( this );
|
|
else document.body.removeChild( this.c[0] );
|
|
|
|
}
|
|
|
|
if( !this.isUI ) Roots.remove( this );
|
|
|
|
this.c = null;
|
|
this.s = null;
|
|
this.callback = null;
|
|
this.target = null;
|
|
this.isListen = false;
|
|
|
|
}
|
|
|
|
clear() {
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// change size
|
|
// ----------------------
|
|
|
|
getWidth() {
|
|
|
|
let nw = Roots.getWidth( this );
|
|
if(nw) this.w = nw;
|
|
|
|
}
|
|
|
|
setSize( sx ) {
|
|
|
|
if( !this.autoWidth ) return;
|
|
|
|
this.w = sx;
|
|
|
|
if( this.simple ){
|
|
this.sb = this.w - this.sa;
|
|
} else {
|
|
let pp = this.w * ( this.p / 100 );
|
|
this.sa = Math.floor( pp + 10 );
|
|
this.sb = Math.floor( this.w - pp - 20 );
|
|
}
|
|
|
|
}
|
|
|
|
rSize() {
|
|
|
|
if( !this.autoWidth ) return;
|
|
|
|
if( !this.isUI ) this.s[0].width = this.w + 'px';
|
|
if( !this.simple ) this.s[1].width = this.sa + 'px';
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// for numeric value
|
|
// ----------------------
|
|
|
|
setTypeNumber( o ) {
|
|
|
|
this.isNumber = true;
|
|
|
|
this.value = 0;
|
|
if( o.value !== undefined ){
|
|
if( typeof o.value === 'string' ) this.value = o.value * 1;
|
|
else this.value = o.value;
|
|
}
|
|
|
|
this.min = o.min === undefined ? -Infinity : o.min;
|
|
this.max = o.max === undefined ? Infinity : o.max;
|
|
this.precision = o.precision === undefined ? 2 : o.precision;
|
|
|
|
let s;
|
|
|
|
switch(this.precision){
|
|
case 0: s = 1; break;
|
|
case 1: s = 0.1; break;
|
|
case 2: s = 0.01; break;
|
|
case 3: s = 0.001; break;
|
|
case 4: s = 0.0001; break;
|
|
case 5: s = 0.00001; break;
|
|
}
|
|
|
|
this.step = o.step === undefined ? s : o.step;
|
|
this.range = this.max - this.min;
|
|
this.value = this.numValue( this.value );
|
|
|
|
}
|
|
|
|
numValue( n ) {
|
|
|
|
if( this.noNeg ) n = Math.abs( n );
|
|
return Math.min( this.max, Math.max( this.min, n ) ).toFixed( this.precision ) * 1;
|
|
|
|
}
|
|
|
|
|
|
// ----------------------
|
|
// EVENTS DEFAULT
|
|
// ----------------------
|
|
|
|
handleEvent( e ) {
|
|
|
|
if( this.lock ) return
|
|
|
|
if( this.neverlock ) Roots.lock = false;
|
|
|
|
if( !this[e.type] ) return console.error(e.type, 'this type of event no existe !')
|
|
|
|
return this[e.type](e)
|
|
|
|
}
|
|
|
|
wheel( e ) { return false; }
|
|
mousedown( e ) { return false; }
|
|
mousemove( e ) { return false; }
|
|
mouseup( e ) { return false; }
|
|
keydown( e ) { return false; }
|
|
keyup( e ) { return false; }
|
|
|
|
|
|
// ----------------------
|
|
// object referency
|
|
// ----------------------
|
|
|
|
setReferency( obj, val ) {
|
|
|
|
this.objectLink = obj;
|
|
this.val = val;
|
|
|
|
}
|
|
|
|
display( v = false ) {
|
|
this.s[0].visibility = v ? 'visible' : 'hidden';
|
|
}
|
|
|
|
// ----------------------
|
|
// resize height
|
|
// ----------------------
|
|
|
|
open () {
|
|
|
|
if( this.isOpen ) return;
|
|
this.isOpen = true;
|
|
if( this.openCallback ) this.openCallback();
|
|
|
|
}
|
|
|
|
close () {
|
|
|
|
if( !this.isOpen ) return
|
|
this.isOpen = false;
|
|
if( this.closeCallback ) this.closeCallback();
|
|
|
|
}
|
|
|
|
needZone() {
|
|
|
|
Roots.needReZone = true;
|
|
|
|
}
|
|
|
|
rezone() {
|
|
|
|
Roots.needReZone = true;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// INPUT
|
|
// ----------------------
|
|
|
|
select() {
|
|
|
|
}
|
|
|
|
unselect() {
|
|
|
|
}
|
|
|
|
setInput( Input ) {
|
|
|
|
Roots.setInput( Input, this );
|
|
|
|
}
|
|
|
|
upInput( x, down ) {
|
|
|
|
return Roots.upInput( x, down );
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// special item
|
|
// ----------------------
|
|
|
|
selected( b ){
|
|
|
|
this.isSelect = b || false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Bool extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.value = o.value || false;
|
|
this.model = o.mode !== undefined ? o.mode : 0;
|
|
|
|
this.onName = o.rename || this.txt;
|
|
if( o.onName ) o.onname = o.onName;
|
|
if( o.onname ) this.onName = o.onname;
|
|
|
|
this.inh = o.inh || Math.floor( this.h*0.8 );
|
|
this.inw = o.inw || 36;
|
|
|
|
let cc = this.colors;
|
|
|
|
if( this.model === 0 ){
|
|
let t = Math.floor(this.h*0.5)-((this.inh-2)*0.5);
|
|
this.c[2] = this.dom( 'div', this.css.basic + 'background:'+ cc.inputBg +'; height:'+(this.inh-2)+'px; width:'+this.inw+'px; top:'+t+'px; border-radius:10px; border:2px solid '+ cc.back );
|
|
this.c[3] = this.dom( 'div', this.css.basic + 'height:'+(this.inh-6)+'px; width:16px; top:'+(t+2)+'px; border-radius:10px; background:'+ cc.button+';' );
|
|
} else {
|
|
this.p = 0;
|
|
if( this.c[1] !== undefined ) this.c[1].textContent = '';
|
|
this.c[2] = this.dom( 'div', this.css.txt + this.css.button + 'top:1px; background:'+cc.button+'; height:'+(this.h-2)+'px; border:1px solid '+cc.border+'; border-radius:'+this.radius+'px;' );
|
|
}
|
|
|
|
this.stat = -1;
|
|
|
|
this.init();
|
|
this.update();
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
mousedown ( e ) {
|
|
|
|
this.value = !this.value;
|
|
this.update( true );
|
|
return this.mousemove( e )
|
|
|
|
}
|
|
|
|
mousemove ( e ) {
|
|
|
|
this.cursor('pointer');
|
|
return this.mode( true )
|
|
|
|
}
|
|
|
|
reset () {
|
|
|
|
this.cursor();
|
|
return this.mode()
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// MODE
|
|
// ----------------------
|
|
|
|
mode ( over ) {
|
|
|
|
let change = false;
|
|
let cc = this.colors, s, s2, n, v = this.value;
|
|
|
|
if( over ) n = v ? 4 : 3;
|
|
else n = v ? 2 : 1;
|
|
|
|
if( this.stat !== n ){
|
|
|
|
this.stat = n;
|
|
|
|
if( this.model !== 0 ){
|
|
|
|
s = this.s[2];
|
|
|
|
switch( n ){
|
|
|
|
case 1: s.color = cc.text; s.background = cc.button; break;
|
|
case 2: s.color = cc.textSelect; s.background = cc.select; break;
|
|
case 3: s.color = cc.textOver; s.background = cc.overoff; break;
|
|
case 4: s.color = cc.textOver; s.background = cc.over; break;
|
|
|
|
}
|
|
|
|
this.c[2].innerHTML = v ? this.onName : this.name;
|
|
|
|
} else {
|
|
|
|
s = this.s[2];
|
|
s2 = this.s[3];
|
|
|
|
switch( n ){
|
|
|
|
case 1: s.background = s.borderColor = cc.back; s2.background = cc.button; break;
|
|
case 2: s.background = s.borderColor = cc.select; s2.background = cc.button; break;
|
|
case 3: s.background = s.borderColor = cc.back; s2.background = cc.overoff; break;
|
|
case 4: s.background = s.borderColor = cc.select; s2.background = cc.over; break;
|
|
|
|
}
|
|
|
|
this.s[3].marginLeft = v ? '17px' : '2px';
|
|
this.c[1].textContent = v ? this.onName : this.name;
|
|
|
|
}
|
|
|
|
change = true;
|
|
|
|
}
|
|
|
|
return change
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
|
|
update ( up ) {
|
|
|
|
this.mode();
|
|
if( up ) this.send();
|
|
|
|
}
|
|
|
|
rSize () {
|
|
|
|
super.rSize();
|
|
|
|
let s = this.s;
|
|
let w = (this.w - 10 ) - this.inw;
|
|
if( this.model === 0 ){
|
|
s[2].left = w + 'px';
|
|
s[3].left = w + 'px';
|
|
} else {
|
|
s[2].left = this.sa + 'px';
|
|
s[2].width = (this.w- 20) + 'px';
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Button extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.value = o.value || '';
|
|
|
|
this.values = o.value || this.txt;
|
|
if( o.values ) this.values = o.values;
|
|
|
|
|
|
|
|
this.onName = o.onName || null;
|
|
|
|
this.on = false;
|
|
|
|
// force button width
|
|
this.bw = o.forceWidth || 0;
|
|
if(o.bw) this.bw = o.bw;
|
|
this.space = o.space || 3;
|
|
|
|
if( typeof this.values === 'string' ) this.values = [ this.values ];
|
|
|
|
this.isDown = false;
|
|
this.neverlock = true;
|
|
this.res = 0;
|
|
|
|
this.lng = this.values.length;
|
|
this.tmp = [];
|
|
this.stat = [];
|
|
|
|
let sel, cc = this.colors;
|
|
|
|
for( let i = 0; i < this.lng; i++ ){
|
|
|
|
sel = false;
|
|
if( this.values[i] === this.value && this.isSelectable ) sel = true;
|
|
|
|
this.c[i+2] = this.dom( 'div', this.css.txt + this.css.button + 'top:1px; height:'+(this.h-2)+'px; border:'+cc.borderSize+'px solid '+cc.border+'; border-radius:'+this.radius+'px;' );
|
|
this.c[i+2].style.background = sel ? cc.select : cc.button;
|
|
this.c[i+2].style.color = sel ? cc.textSelect : cc.text;
|
|
this.c[i+2].innerHTML = this.values[i];
|
|
this.stat[i] = sel ? 3:1;
|
|
|
|
}
|
|
|
|
if( !o.value && !o.values ){
|
|
if( this.c[1] !== undefined ) {
|
|
this.c[1].textContent = '';
|
|
this.txt = '';
|
|
}
|
|
}
|
|
if( !this.txt ) this.p = 0;
|
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
onOff() {
|
|
|
|
this.on = !this.on;
|
|
this.label( this.on ? this.onName : this.txt );
|
|
|
|
}
|
|
|
|
testZone ( e ) {
|
|
|
|
let l = this.local;
|
|
if( l.x === -1 && l.y === -1 ) return -1
|
|
|
|
let i = this.lng;
|
|
let t = this.tmp;
|
|
|
|
while( i-- ){
|
|
if( l.x>t[i][0] && l.x<t[i][2] ) return i
|
|
}
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
mouseup ( e ) {
|
|
|
|
if( !this.isDown ) return false
|
|
|
|
this.isDown = false;
|
|
if( this.res !== -1 ){
|
|
if( this.value === this.values[this.res] && this.unselectable ) this.value = '';
|
|
else this.value = this.values[this.res];
|
|
if( this.onName !== null ) this.onOff();
|
|
this.send();
|
|
}
|
|
|
|
return this.mousemove( e )
|
|
|
|
}
|
|
|
|
mousedown ( e ) {
|
|
|
|
if( this.isDown ) return false
|
|
this.isDown = true;
|
|
return this.mousemove( e )
|
|
|
|
}
|
|
|
|
mousemove ( e ) {
|
|
|
|
let up = false;
|
|
this.res = this.testZone( e );
|
|
|
|
if( this.res !== -1 ){
|
|
this.cursor('pointer');
|
|
up = this.modes( this.isDown ? 3 : 2, this.res );
|
|
} else {
|
|
up = this.reset();
|
|
}
|
|
|
|
return up
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
|
|
modes ( N = 1, id = -1 ) {
|
|
|
|
let i = this.lng, w, n, r = false;
|
|
|
|
while( i-- ){
|
|
|
|
n = N;
|
|
w = this.isSelectable ? this.values[ i ] === this.value : false;
|
|
|
|
if( i === id ){
|
|
if( w && n === 2 ) n = 3;
|
|
} else {
|
|
n = 1;
|
|
if( w ) n = 4;
|
|
}
|
|
|
|
//if( this.mode( n, i ) ) r = true
|
|
r = this.mode( n, i );
|
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
mode ( n, id ) {
|
|
|
|
//if(!this.s) return false
|
|
|
|
let change = false;
|
|
let cc = this.colors, s = this.s;
|
|
let i = id+2;
|
|
|
|
if( this.stat[id] !== n ){
|
|
|
|
this.stat[id] = n;
|
|
|
|
switch( n ){
|
|
|
|
case 1: s[i].color = cc.text; s[i].background = cc.button; break;
|
|
case 2: s[i].color = cc.textOver; s[i].background = cc.overoff; break;
|
|
case 3: s[i].color = cc.textOver; s[i].background = cc.over; break;
|
|
case 4: s[i].color = cc.textSelect; s[i].background = cc.select; break;
|
|
|
|
}
|
|
|
|
change = true;
|
|
|
|
}
|
|
|
|
return change
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
|
|
reset () {
|
|
|
|
this.res = -1;
|
|
this.cursor();
|
|
return this.modes()
|
|
|
|
}
|
|
|
|
label ( string, n ) {
|
|
|
|
n = n || 2;
|
|
this.c[n].textContent = string;
|
|
|
|
}
|
|
|
|
icon ( string, y = 0, n = 2 ) {
|
|
|
|
//if(y) this.s[n].margin = ( y ) +'px 0px';
|
|
this.s[n].padding = ( y ) +'px 0px';
|
|
this.c[n].innerHTML = string;
|
|
|
|
return this
|
|
|
|
}
|
|
|
|
rSize () {
|
|
|
|
super.rSize();
|
|
|
|
let s = this.s;
|
|
let w = this.sb;
|
|
let d = this.sa;
|
|
|
|
let i = this.lng;
|
|
let dc = this.space;
|
|
let size = Math.floor( ( w-(dc*(i-1)) ) / i );
|
|
|
|
if( this.bw ){
|
|
size = this.bw < size ? this.bw : size;
|
|
d = Math.floor((this.w-( (size * i) + (dc * (i-1)) ))*0.5);
|
|
}
|
|
|
|
while( i-- ){
|
|
|
|
this.tmp[i] = [ Math.floor( d + ( size * i ) + ( dc * i )), size ];
|
|
this.tmp[i][2] = this.tmp[i][0] + this.tmp[i][1];
|
|
|
|
s[i+2].left = this.tmp[i][0] + 'px';
|
|
s[i+2].width = this.tmp[i][1] + 'px';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Circular extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.isCyclic = o.cyclic || false;
|
|
this.model = o.stype || 0;
|
|
if( o.mode !== undefined ) this.model = o.mode;
|
|
|
|
this.autoWidth = false;
|
|
this.minw = this.w;
|
|
this.diam = o.diam || this.w;
|
|
|
|
this.setTypeNumber( o );
|
|
|
|
this.twoPi = Tools.TwoPI;
|
|
this.pi90 = Tools.pi90;
|
|
|
|
this.offset = new V2();
|
|
|
|
this.h = o.h || this.w + 10;
|
|
this.top = 0;
|
|
|
|
this.c[0].style.width = this.w +'px';
|
|
|
|
if(this.c[1] !== undefined) {
|
|
|
|
this.c[1].style.width = '100%';
|
|
this.c[1].style.justifyContent = 'center';
|
|
this.top = 10;
|
|
this.h += 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.percent = 0;
|
|
this.cmode = 0;
|
|
let cc = this.colors;
|
|
|
|
this.c[2] = this.dom( 'div', this.css.txt + 'justify-content:center; top:'+(this.h-20)+'px; width:100%; color:'+ cc.text );
|
|
|
|
// svg
|
|
|
|
this.c[3] = this.getCircular();
|
|
|
|
this.setSvg( this.c[3], 'stroke', cc.back, 0 );
|
|
this.setSvg( this.c[3], 'd', this.makePath(), 1 );
|
|
this.setSvg( this.c[3], 'stroke', cc.text, 1 );
|
|
|
|
this.setSvg( this.c[3], 'viewBox', '0 0 '+this.diam+' '+this.diam );
|
|
this.setCss( this.c[3], { width:this.diam, height:this.diam, left:0, top:this.top });
|
|
|
|
this.init();
|
|
this.update();
|
|
|
|
}
|
|
|
|
mode ( mode ) {
|
|
|
|
if( this.cmode === mode ) return false;
|
|
|
|
let cc = this.colors;
|
|
let color;
|
|
|
|
switch( mode ){
|
|
case 0: // base
|
|
|
|
this.s[2].color = cc.text;
|
|
this.setSvg( this.c[3], 'stroke', cc.back, 0);
|
|
color = this.model > 0 ? Tools.pack( Tools.lerpColor( Tools.unpack( Tools.ColorLuma( cc.text, -0.75) ), Tools.unpack( cc.text ), this.percent ) ) : cc.text;
|
|
this.setSvg( this.c[3], 'stroke', color, 1 );
|
|
|
|
break;
|
|
case 1: // down
|
|
|
|
this.s[2].color = cc.textOver;
|
|
this.setSvg( this.c[3], 'stroke', cc.backoff, 0);
|
|
color = this.model > 0 ? Tools.pack( Tools.lerpColor( Tools.unpack( Tools.ColorLuma( cc.text, -0.75) ), Tools.unpack( cc.text ), this.percent ) ) : cc.textOver;
|
|
this.setSvg( this.c[3], 'stroke', color, 1 );
|
|
|
|
break;
|
|
}
|
|
|
|
this.cmode = mode;
|
|
return true;
|
|
|
|
}
|
|
|
|
reset () {
|
|
|
|
this.isDown = false;
|
|
|
|
}
|
|
|
|
testZone ( e ) {
|
|
|
|
let l = this.local;
|
|
if( l.x === -1 && l.y === -1 ) return '';
|
|
|
|
if( l.y <= this.c[ 1 ].offsetHeight ) return 'title';
|
|
else if ( l.y > this.h - this.c[ 2 ].offsetHeight ) return 'text';
|
|
else return 'circular';
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
mouseup ( e ) {
|
|
|
|
this.isDown = false;
|
|
this.sendEnd();
|
|
return this.mode(0);
|
|
|
|
}
|
|
|
|
mousedown ( e ) {
|
|
|
|
this.isDown = true;
|
|
this.old = this.value;
|
|
this.oldr = null;
|
|
this.mousemove( e );
|
|
return this.mode(1);
|
|
|
|
}
|
|
|
|
mousemove ( e ) {
|
|
|
|
if( !this.isDown ) return;
|
|
|
|
//console.log('over')
|
|
|
|
let off = this.offset;
|
|
off.x = (this.w*0.5) - ( e.clientX - this.zone.x );
|
|
off.y = (this.diam*0.5) - ( e.clientY - this.zone.y - this.top );
|
|
|
|
this.r = off.angle() - this.pi90;
|
|
this.r = (((this.r%this.twoPi)+this.twoPi)%this.twoPi);
|
|
|
|
if( this.oldr !== null ){
|
|
|
|
let dif = this.r - this.oldr;
|
|
this.r = Math.abs(dif) > Math.PI ? this.oldr : this.r;
|
|
|
|
if( dif > 6 ) this.r = 0;
|
|
if( dif < -6 ) this.r = this.twoPi;
|
|
|
|
}
|
|
|
|
let steps = 1 / this.twoPi;
|
|
let value = this.r * steps;
|
|
|
|
let n = ( ( this.range * value ) + this.min ) - this.old;
|
|
|
|
if(n >= this.step || n <= this.step){
|
|
n = ~~ ( n / this.step );
|
|
this.value = this.numValue( this.old + ( n * this.step ) );
|
|
this.update( true );
|
|
this.old = this.value;
|
|
this.oldr = this.r;
|
|
}
|
|
|
|
}
|
|
|
|
wheel ( e ) {
|
|
|
|
let name = this.testZone( e );
|
|
|
|
if( name === 'circular' ) {
|
|
|
|
let v = this.value - this.step * e.delta;
|
|
|
|
if ( v > this.max ) {
|
|
v = this.isCyclic ? this.min : this.max;
|
|
} else if ( v < this.min ) {
|
|
v = this.isCyclic ? this.max : this.min;
|
|
}
|
|
|
|
this.setValue( v );
|
|
this.old = v;
|
|
this.update( true );
|
|
|
|
return true;
|
|
|
|
}
|
|
return false;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
|
|
makePath () {
|
|
|
|
let r = 40;
|
|
let d = 24;
|
|
let a = this.percent * this.twoPi - 0.001;
|
|
let x2 = (r + r * Math.sin(a)) + d;
|
|
let y2 = (r - r * Math.cos(a)) + d;
|
|
let big = a > Math.PI ? 1 : 0;
|
|
return "M " + (r+d) + "," + d + " A " + r + "," + r + " 0 " + big + " 1 " + x2 + "," + y2;
|
|
|
|
}
|
|
|
|
update ( up ) {
|
|
|
|
this.c[2].textContent = this.value;
|
|
this.percent = ( this.value - this.min ) / this.range;
|
|
|
|
this.setSvg( this.c[3], 'd', this.makePath(), 1 );
|
|
|
|
if ( this.model > 0 ) {
|
|
|
|
let cc = this.colors;
|
|
let color = Tools.pack( Tools.lerpColor( Tools.unpack( Tools.ColorLuma( cc.text, -0.75) ), Tools.unpack( cc.text ), this.percent ) );
|
|
this.setSvg( this.c[3], 'stroke', color, 1 );
|
|
|
|
}
|
|
|
|
if( up ) this.send();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Color extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
//this.autoHeight = true;
|
|
|
|
this.ctype = o.ctype || 'hex';
|
|
|
|
this.wfixe = 256;
|
|
|
|
this.cw = this.sb > 256 ? 256 : this.sb;
|
|
if(o.cw != undefined ) this.cw = o.cw;
|
|
|
|
// color up or down
|
|
this.side = o.side || 'down';
|
|
this.up = this.side === 'down' ? 0 : 1;
|
|
|
|
this.baseH = this.h;
|
|
|
|
this.offset = new V2();
|
|
this.decal = new V2();
|
|
this.pp = new V2();
|
|
|
|
this.c[2] = this.dom( 'div', this.css.txt + 'height:'+(this.h-4)+'px;' + 'border-radius:'+this.radius+'px; line-height:'+(this.h-8)+'px;' );
|
|
this.s[2] = this.c[2].style;
|
|
|
|
this.s[2].textShadow = 'none';
|
|
|
|
if( this.up ){
|
|
this.s[2].top = 'auto';
|
|
this.s[2].bottom = '2px';
|
|
}
|
|
|
|
//this.c[0].style.textAlign = 'center';
|
|
//this.c[0].style.flex = '1 0 auto'
|
|
|
|
this.c[3] = this.getColorRing();
|
|
this.c[3].style.visibility = 'hidden';
|
|
|
|
this.hsl = null;
|
|
this.value = '#ffffff';
|
|
if( o.value !== undefined ){
|
|
if( o.value instanceof Array ) this.value = Tools.rgbToHex( o.value );
|
|
else if(!isNaN(o.value)) this.value = Tools.hexToHtml( o.value );
|
|
else this.value = o.value;
|
|
}
|
|
|
|
this.bcolor = null;
|
|
this.isDown = false;
|
|
this.fistDown = false;
|
|
|
|
this.notext = o.notext || false;
|
|
|
|
this.tr = 98;
|
|
this.tsl = Math.sqrt(3) * this.tr;
|
|
|
|
this.hue = 0;
|
|
this.d = 256;
|
|
|
|
this.setColor( this.value );
|
|
|
|
this.init();
|
|
|
|
if( o.open !== undefined ) this.open();
|
|
|
|
}
|
|
|
|
testZone ( mx, my ) {
|
|
|
|
let l = this.local;
|
|
if( l.x === -1 && l.y === -1 ) return '';
|
|
|
|
|
|
|
|
if( this.up && this.isOpen ){
|
|
|
|
if( l.y > this.wfixe ) return 'title';
|
|
else return 'color';
|
|
|
|
} else {
|
|
|
|
if( l.y < this.baseH+2 ) return 'title';
|
|
else if( this.isOpen ) return 'color';
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
mouseup ( e ) {
|
|
|
|
this.isDown = false;
|
|
this.d = 256;
|
|
|
|
}
|
|
|
|
mousedown ( e ) {
|
|
|
|
|
|
let name = this.testZone( e.clientX, e.clientY );
|
|
|
|
|
|
//if( !name ) return;
|
|
if(name === 'title'){
|
|
if( !this.isOpen ) this.open();
|
|
else this.close();
|
|
return true;
|
|
}
|
|
|
|
|
|
if( name === 'color' ){
|
|
|
|
this.isDown = true;
|
|
this.fistDown = true;
|
|
this.mousemove( e );
|
|
}
|
|
}
|
|
|
|
mousemove ( e ) {
|
|
|
|
let name = this.testZone( e.clientX, e.clientY );
|
|
|
|
let off, d, hue, sat, lum, rad, x, y, rr, T = Tools;
|
|
|
|
if( name === 'title' ) this.cursor('pointer');
|
|
|
|
if( name === 'color' ){
|
|
|
|
off = this.offset;
|
|
off.x = e.clientX - ( this.zone.x + this.decal.x + this.mid );
|
|
off.y = e.clientY - ( this.zone.y + this.decal.y + this.mid );
|
|
d = off.length() * this.ratio;
|
|
rr = off.angle();
|
|
if(rr < 0) rr += 2 * T.PI;
|
|
|
|
|
|
if ( d < 128 ) this.cursor('crosshair');
|
|
else if( !this.isDown ) this.cursor();
|
|
|
|
if( this.isDown ){
|
|
|
|
if( this.fistDown ){
|
|
this.d = d;
|
|
this.fistDown = false;
|
|
}
|
|
|
|
if ( this.d < 128 ) {
|
|
|
|
if ( this.d > this.tr ) { // outside hue
|
|
|
|
hue = ( rr + T.pi90 ) / T.TwoPI;
|
|
this.hue = (hue + 1) % 1;
|
|
this.setHSL([(hue + 1) % 1, this.hsl[1], this.hsl[2]]);
|
|
|
|
} else { // triangle
|
|
|
|
x = off.x * this.ratio;
|
|
y = off.y * this.ratio;
|
|
|
|
let rr = (this.hue * T.TwoPI) + T.PI;
|
|
if(rr < 0) rr += 2 * T.PI;
|
|
|
|
rad = Math.atan2(-y, x);
|
|
if(rad < 0) rad += 2 * T.PI;
|
|
|
|
let rad0 = ( rad + T.pi90 + T.TwoPI + rr ) % (T.TwoPI),
|
|
rad1 = rad0 % ((2/3) * T.PI) - (T.pi60),
|
|
a = 0.5 * this.tr,
|
|
b = Math.tan(rad1) * a,
|
|
r = Math.sqrt(x*x + y*y),
|
|
maxR = Math.sqrt(a*a + b*b);
|
|
|
|
if( r > maxR ) {
|
|
let dx = Math.tan(rad1) * r;
|
|
let rad2 = Math.atan(dx / maxR);
|
|
if(rad2 > T.pi60) rad2 = T.pi60;
|
|
else if( rad2 < -T.pi60 ) rad2 = -T.pi60;
|
|
|
|
rad += rad2 - rad1;
|
|
|
|
rad0 = (rad + T.pi90 + T.TwoPI + rr) % (T.TwoPI),
|
|
rad1 = rad0 % ((2/3) * T.PI) - (T.pi60);
|
|
b = Math.tan(rad1) * a;
|
|
r = maxR = Math.sqrt(a*a + b*b);
|
|
}
|
|
|
|
lum = ((Math.sin(rad0) * r) / this.tsl) + 0.5;
|
|
|
|
let w = 1 - (Math.abs(lum - 0.5) * 2);
|
|
sat = (((Math.cos(rad0) * r) + (this.tr / 2)) / (1.5 * this.tr)) / w;
|
|
sat = T.clamp( sat, 0, 1 );
|
|
|
|
this.setHSL([this.hsl[0], sat, lum]);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
|
|
setHeight () {
|
|
|
|
this.h = this.isOpen ? this.wfixe + this.baseH + 5 : this.baseH;
|
|
this.s[0].height = this.h + 'px';
|
|
this.zone.h = this.h;
|
|
|
|
}
|
|
|
|
parentHeight ( t ) {
|
|
|
|
if ( this.group !== null ) this.group.calc( t );
|
|
else if ( this.isUI ) this.main.calc( t );
|
|
|
|
}
|
|
|
|
open () {
|
|
|
|
super.open();
|
|
|
|
this.setHeight();
|
|
|
|
if( this.up ) this.zone.y -= this.wfixe + 5;
|
|
|
|
let t = this.h - this.baseH;
|
|
|
|
this.s[3].visibility = 'visible';
|
|
//this.s[3].display = 'block';
|
|
this.parentHeight( t );
|
|
|
|
}
|
|
|
|
close () {
|
|
|
|
super.close();
|
|
|
|
if( this.up ) this.zone.y += this.wfixe + 5;
|
|
|
|
let t = this.h - this.baseH;
|
|
|
|
this.setHeight();
|
|
|
|
this.s[3].visibility = 'hidden';
|
|
//this.s[3].display = 'none';
|
|
this.parentHeight( -t );
|
|
|
|
}
|
|
|
|
update ( up ) {
|
|
|
|
let cc = Tools.rgbToHex( Tools.hslToRgb([ this.hsl[0], 1, 0.5 ]) );
|
|
|
|
this.moveMarkers();
|
|
|
|
this.value = this.bcolor;
|
|
|
|
this.setSvg( this.c[3], 'fill', cc, 2, 0 );
|
|
|
|
|
|
this.s[2].background = this.bcolor;
|
|
if(!this.notext) this.c[2].textContent = Tools.htmlToHex( this.bcolor );
|
|
|
|
this.invert = Tools.findDeepInver( this.rgb );
|
|
this.s[2].color = this.invert ? '#fff' : '#000';
|
|
|
|
if(!up) return;
|
|
|
|
if( this.ctype === 'array' ) this.send( this.rgb );
|
|
if( this.ctype === 'rgb' ) this.send( Tools.htmlRgb( this.rgb ) );
|
|
if( this.ctype === 'hex' ) this.send( Tools.htmlToHex( this.value ) );
|
|
if( this.ctype === 'html' ) this.send();
|
|
|
|
}
|
|
|
|
setValue ( v ){
|
|
|
|
if( v instanceof Array ) this.value = Tools.rgbToHex( v );
|
|
else if(!isNaN(v)) this.value = Tools.hexToHtml( v );
|
|
else this.value = v;
|
|
|
|
this.setColor( this.value );
|
|
this.update();
|
|
|
|
}
|
|
|
|
setColor ( color ) {
|
|
|
|
let unpack = Tools.unpack(color);
|
|
if (this.bcolor !== color && unpack) {
|
|
|
|
this.bcolor = color;
|
|
this.rgb = unpack;
|
|
this.hsl = Tools.rgbToHsl( this.rgb );
|
|
|
|
this.hue = this.hsl[0];
|
|
|
|
this.update();
|
|
}
|
|
return this;
|
|
|
|
}
|
|
|
|
setHSL ( hsl ) {
|
|
|
|
this.hsl = hsl;
|
|
this.rgb = Tools.hslToRgb( hsl );
|
|
this.bcolor = Tools.rgbToHex( this.rgb );
|
|
this.update( true );
|
|
return this;
|
|
|
|
}
|
|
|
|
moveMarkers () {
|
|
|
|
let p = this.pp;
|
|
let T = Tools;
|
|
|
|
this.invert ? '#fff' : '#000';
|
|
let a = this.hsl[0] * T.TwoPI;
|
|
let third = (2/3) * T.PI;
|
|
let r = this.tr;
|
|
let h = this.hsl[0];
|
|
let s = this.hsl[1];
|
|
let l = this.hsl[2];
|
|
|
|
let angle = ( a - T.pi90 ) * T.todeg;
|
|
|
|
h = - a + T.pi90;
|
|
|
|
let hx = Math.cos(h) * r;
|
|
let hy = -Math.sin(h) * r;
|
|
let sx = Math.cos(h - third) * r;
|
|
let sy = -Math.sin(h - third) * r;
|
|
let vx = Math.cos(h + third) * r;
|
|
let vy = -Math.sin(h + third) * r;
|
|
let mx = (sx + vx) / 2, my = (sy + vy) / 2;
|
|
a = (1 - 2 * Math.abs(l - .5)) * s;
|
|
let x = sx + (vx - sx) * l + (hx - mx) * a;
|
|
let y = sy + (vy - sy) * l + (hy - my) * a;
|
|
|
|
p.set( x, y ).addScalar(128);
|
|
|
|
//let ff = (1-l)*255;
|
|
// this.setSvg( this.c[3], 'stroke', 'rgb('+ff+','+ff+','+ff+')', 3 );
|
|
|
|
this.setSvg( this.c[3], 'transform', 'rotate('+angle+' )', 2 );
|
|
|
|
this.setSvg( this.c[3], 'cx', p.x, 3 );
|
|
this.setSvg( this.c[3], 'cy', p.y, 3 );
|
|
|
|
this.setSvg( this.c[3], 'stroke', this.invert ? '#fff' : '#000', 2, 3 );
|
|
this.setSvg( this.c[3], 'stroke', this.invert ? '#fff' : '#000', 3 );
|
|
this.setSvg( this.c[3], 'fill',this.bcolor, 3 );
|
|
|
|
}
|
|
|
|
rSize () {
|
|
|
|
//Proto.prototype.rSize.call( this );
|
|
super.rSize();
|
|
|
|
let s = this.s;
|
|
|
|
s[2].width = this.sb + 'px';
|
|
s[2].left = this.sa + 'px';
|
|
|
|
this.rSizeColor( this.cw );
|
|
|
|
this.decal.x = Math.floor((this.w - this.wfixe) * 0.5);
|
|
//s[3].left = this.decal.x + 'px';
|
|
|
|
}
|
|
|
|
rSizeColor ( w ) {
|
|
|
|
if( w === this.wfixe ) return;
|
|
|
|
this.wfixe = w;
|
|
|
|
let s = this.s;
|
|
|
|
//this.decal.x = Math.floor((this.w - this.wfixe) * 0.5);
|
|
this.decal.y = this.side === 'up' ? 2 : this.baseH + 2;
|
|
this.mid = Math.floor( this.wfixe * 0.5 );
|
|
|
|
this.setSvg( this.c[3], 'viewBox', '0 0 '+ this.wfixe + ' '+ this.wfixe );
|
|
s[3].width = this.wfixe + 'px';
|
|
s[3].height = this.wfixe + 'px';
|
|
//s[3].left = this.decal.x + 'px';
|
|
s[3].top = this.decal.y + 'px';
|
|
|
|
this.ratio = 256 / this.wfixe;
|
|
this.square = 1 / (60*(this.wfixe/256));
|
|
this.setHeight();
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
class Fps extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.round = Math.round;
|
|
|
|
//this.autoHeight = true;
|
|
|
|
this.baseH = this.h;
|
|
this.hplus = o.hplus || 50;
|
|
|
|
this.res = o.res || 40;
|
|
this.l = 1;
|
|
|
|
this.precision = o.precision || 0;
|
|
|
|
|
|
this.custom = o.custom || false;
|
|
this.names = o.names || ['FPS', 'MS'];
|
|
let cc = o.cc || ['220,220,220', '255,255,0'];
|
|
|
|
// this.divid = [ 100, 100, 100 ];
|
|
// this.multy = [ 30, 30, 30 ];
|
|
|
|
this.adding = o.adding || false;
|
|
|
|
this.range = o.range || [ 165, 100, 100 ];
|
|
|
|
this.alpha = o.alpha || 0.25;
|
|
|
|
this.values = [];
|
|
this.points = [];
|
|
this.textDisplay = [];
|
|
|
|
if(!this.custom){
|
|
|
|
this.now = Roots.getTime();
|
|
this.startTime = 0;//this.now()
|
|
this.prevTime = 0;//this.startTime;
|
|
this.frames = 0;
|
|
|
|
this.ms = 0;
|
|
this.fps = 0;
|
|
this.mem = 0;
|
|
this.mm = 0;
|
|
|
|
this.isMem = ( self.performance && self.performance.memory ) ? true : false;
|
|
|
|
// this.divid = [ 100, 200, 1 ];
|
|
// this.multy = [ 30, 30, 30 ];
|
|
|
|
if( this.isMem ){
|
|
|
|
this.names.push('MEM');
|
|
cc.push('0,255,255');
|
|
|
|
}
|
|
|
|
this.txt = o.name || 'Fps';
|
|
|
|
}
|
|
|
|
|
|
let fltop = Math.floor(this.h*0.5)-6;
|
|
|
|
this.c[1].textContent = this.txt;
|
|
this.c[0].style.cursor = 'pointer';
|
|
this.c[0].style.pointerEvents = 'auto';
|
|
|
|
let panelCss = 'display:none; left:10px; top:'+ this.h + 'px; height:'+(this.hplus - 8)+'px; box-sizing:border-box; background: rgba(0, 0, 0, 0.2); border:1px solid '+ this.colors.border +';';
|
|
|
|
if( this.radius !== 0 ) panelCss += 'border-radius:' + this.radius+'px;';
|
|
|
|
this.c[2] = this.dom( 'path', this.css.basic + panelCss , {} );
|
|
|
|
this.c[2].setAttribute('viewBox', '0 0 '+this.res+' 50' );
|
|
this.c[2].setAttribute('height', '100%' );
|
|
this.c[2].setAttribute('width', '100%' );
|
|
this.c[2].setAttribute('preserveAspectRatio', 'none' );
|
|
|
|
|
|
//this.dom( 'path', null, { fill:'rgba(255,255,0,0.3)', 'stroke-width':1, stroke:'#FF0', 'vector-effect':'non-scaling-stroke' }, this.c[2] );
|
|
//this.dom( 'path', null, { fill:'rgba(0,255,255,0.3)', 'stroke-width':1, stroke:'#0FF', 'vector-effect':'non-scaling-stroke' }, this.c[2] );
|
|
|
|
// arrow
|
|
this.c[3] = this.dom( 'path', this.css.basic + 'position:absolute; width:10px; height:10px; left:4px; top:'+fltop+'px;', { d:this.svgs.arrow, fill:this.colors.text, stroke:'none'});
|
|
|
|
// result test
|
|
this.c[4] = this.dom( 'div', this.css.txt + 'position:absolute; left:10px; top:'+(this.h+2) +'px; display:none; width:100%; text-align:center;' );
|
|
|
|
// bottom line
|
|
if( o.bottomLine ) this.c[4] = this.dom( 'div', this.css.basic + 'width:100%; bottom:0px; height:1px; background: rgba(255, 255, 255, 0.2);');
|
|
|
|
this.isShow = false;
|
|
|
|
let s = this.s;
|
|
|
|
s[1].marginLeft = '10px';
|
|
s[1].lineHeight = this.h-4;
|
|
s[1].color = this.colors.text;
|
|
s[1].fontWeight = 'bold';
|
|
|
|
if( this.radius !== 0 ) s[0].borderRadius = this.radius+'px';
|
|
if( this.colors.gborder!=='none') s[0].border = '1px solid ' + this.colors.gborder;
|
|
|
|
|
|
|
|
|
|
let j = 0;
|
|
|
|
for( j=0; j<this.names.length; j++ ){
|
|
|
|
let base = [];
|
|
let i = this.res+1;
|
|
while( i-- ) base.push(50);
|
|
|
|
this.range[j] = ( 1 / this.range[j] ) * 49;
|
|
|
|
this.points.push( base );
|
|
this.values.push(0);
|
|
// this.dom( 'path', null, { fill:'rgba('+cc[j]+',0.5)', 'stroke-width':1, stroke:'rgba('+cc[j]+',1)', 'vector-effect':'non-scaling-stroke' }, this.c[2] );
|
|
this.textDisplay.push( "<span style='color:rgb("+cc[j]+")'> " + this.names[j] +" ");
|
|
|
|
}
|
|
|
|
j = this.names.length;
|
|
while(j--){
|
|
this.dom( 'path', null, { fill:'rgba('+cc[j]+','+this.alpha+')', 'stroke-width':1, stroke:'rgba('+cc[j]+',1)', 'vector-effect':'non-scaling-stroke' }, this.c[2] );
|
|
}
|
|
|
|
|
|
this.init();
|
|
|
|
//if( this.isShow ) this.show();
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
mousedown ( e ) {
|
|
|
|
if( this.isShow ) this.close();
|
|
else this.open();
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
|
|
/*mode: function ( mode ) {
|
|
|
|
let s = this.s;
|
|
|
|
switch(mode){
|
|
case 0: // base
|
|
s[1].color = this.colors.text;
|
|
//s[1].background = 'none';
|
|
break;
|
|
case 1: // over
|
|
s[1].color = '#FFF';
|
|
//s[1].background = UIL.SELECT;
|
|
break;
|
|
case 2: // edit / down
|
|
s[1].color = this.colors.text;
|
|
//s[1].background = UIL.SELECTDOWN;
|
|
break;
|
|
|
|
}
|
|
},*/
|
|
|
|
tick ( v ) {
|
|
|
|
this.values = v;
|
|
if( !this.isShow ) return;
|
|
this.drawGraph();
|
|
this.upText();
|
|
|
|
}
|
|
|
|
makePath ( point ) {
|
|
|
|
let p = '';
|
|
p += 'M ' + (-1) + ' ' + 50;
|
|
for ( let i = 0; i < this.res + 1; i ++ ) { p += ' L ' + i + ' ' + point[i]; }
|
|
p += ' L ' + (this.res + 1) + ' ' + 50;
|
|
return p;
|
|
|
|
}
|
|
|
|
upText ( val ) {
|
|
|
|
let v = val || this.values, t = '';
|
|
for( let j=0, lng =this.names.length; j<lng; j++ ) t += this.textDisplay[j] + (v[j]).toFixed(this.precision) + '</span>';
|
|
this.c[4].innerHTML = t;
|
|
|
|
}
|
|
|
|
drawGraph () {
|
|
|
|
let svg = this.c[2];
|
|
let i = this.names.length, v, old = 0, n = 0;
|
|
|
|
while( i-- ){
|
|
if( this.adding ) v = (this.values[n]+old) * this.range[n];
|
|
else v = (this.values[n] * this.range[n]);
|
|
this.points[n].shift();
|
|
this.points[n].push( 50 - v );
|
|
this.setSvg( svg, 'd', this.makePath( this.points[n] ), i+1 );
|
|
old += this.values[n];
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
open () {
|
|
|
|
super.open();
|
|
|
|
this.h = this.hplus + this.baseH;
|
|
|
|
this.setSvg( this.c[3], 'd', this.svgs.arrowDown );
|
|
|
|
if( this.group !== null ){ this.group.calc( this.hplus );}
|
|
else if( this.isUI ) this.main.calc( this.hplus );
|
|
|
|
this.s[0].height = this.h +'px';
|
|
this.s[2].display = 'block';
|
|
this.s[4].display = 'block';
|
|
this.isShow = true;
|
|
|
|
if( !this.custom ) Roots.addListen( this );
|
|
|
|
}
|
|
|
|
close () {
|
|
|
|
super.close();
|
|
|
|
this.h = this.baseH;
|
|
|
|
this.setSvg( this.c[3], 'd', this.svgs.arrow );
|
|
|
|
if( this.group !== null ){ this.group.calc( -this.hplus );}
|
|
else if( this.isUI ) this.main.calc( -this.hplus );
|
|
|
|
this.s[0].height = this.h +'px';
|
|
this.s[2].display = 'none';
|
|
this.s[4].display = 'none';
|
|
this.isShow = false;
|
|
|
|
if( !this.custom ) Roots.removeListen( this );
|
|
|
|
this.c[4].innerHTML = '';
|
|
|
|
}
|
|
|
|
|
|
///// AUTO FPS //////
|
|
|
|
begin () {
|
|
|
|
this.startTime = this.now();
|
|
|
|
}
|
|
|
|
end () {
|
|
|
|
let time = this.now();
|
|
this.ms = time - this.startTime;
|
|
|
|
this.frames ++;
|
|
|
|
if ( time > this.prevTime + 1000 ) {
|
|
|
|
this.fps = this.round( ( this.frames * 1000 ) / ( time - this.prevTime ) );
|
|
|
|
this.prevTime = time;
|
|
this.frames = 0;
|
|
|
|
if ( this.isMem ) {
|
|
|
|
let heapSize = performance.memory.usedJSHeapSize;
|
|
let heapSizeLimit = performance.memory.jsHeapSizeLimit;
|
|
|
|
this.mem = this.round( heapSize * 0.000000954 );
|
|
this.mm = heapSize / heapSizeLimit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.values = [ this.fps, this.ms , this.mm ];
|
|
|
|
this.drawGraph();
|
|
this.upText( [ this.fps, this.ms, this.mem ] );
|
|
|
|
return time;
|
|
|
|
}
|
|
|
|
listening () {
|
|
|
|
if( !this.custom ) this.startTime = this.end();
|
|
|
|
}
|
|
|
|
rSize () {
|
|
|
|
let s = this.s;
|
|
let w = this.w;
|
|
|
|
s[0].width = w + 'px';
|
|
s[1].width = w + 'px';
|
|
s[2].left = 10 + 'px';
|
|
s[2].width = (w-20) + 'px';
|
|
s[4].width = (w-20) + 'px';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Graph extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.value = o.value !== undefined ? o.value : [0,0,0];
|
|
this.lng = this.value.length;
|
|
|
|
this.precision = o.precision !== undefined ? o.precision : 2;
|
|
this.multiplicator = o.multiplicator || 1;
|
|
this.neg = o.neg || false;
|
|
|
|
this.line = o.line !== undefined ? o.line : true;
|
|
|
|
//if(this.neg)this.multiplicator*=2;
|
|
|
|
this.autoWidth = o.autoWidth !== undefined ? o.autoWidth : true;
|
|
this.isNumber = false;
|
|
|
|
this.isDown = false;
|
|
|
|
this.h = o.h || 128 + 10;
|
|
this.rh = this.h - 10;
|
|
this.top = 0;
|
|
|
|
this.c[0].style.width = this.w +'px';
|
|
|
|
if( this.c[1] !== undefined ) { // with title
|
|
|
|
this.c[1].style.width = this.w +'px';
|
|
|
|
if(!this.autoWidth){
|
|
this.c[1].style.width = '100%';
|
|
this.c[1].style.justifyContent = 'center';
|
|
}
|
|
|
|
|
|
//this.c[1].style.background = '#ff0000';
|
|
//this.c[1].style.textAlign = 'center';
|
|
this.top = 10;
|
|
this.h += 10;
|
|
|
|
}
|
|
|
|
this.gh = this.rh - 28;
|
|
this.gw = this.w - 28;
|
|
|
|
//this.c[2] = this.dom( 'div', this.css.txt + 'justify-content:center; text-align: justify; column-count:'+this.lng+'; top:'+(this.h-20)+'px; width:100%; color:'+ this.colors.text );
|
|
|
|
//let colum = 'column-count:'+this.lng+'; column:'+this.lng+'; break-inside: column; top:'
|
|
this.c[2] = this.dom( 'div', this.css.txt + 'display:block; text-align:center; padding:0px 0px; top:'+(this.h-20)+'px; left:14px; width:'+this.gw+'px; color:'+ this.colors.text );
|
|
|
|
//this.c[2].textContent = this.value;
|
|
this.c[2].innerHTML = this.valueToHtml();
|
|
|
|
let svg = this.dom( 'svg', this.css.basic , { viewBox:'0 0 '+this.w+' '+this.rh, width:this.w, height:this.rh, preserveAspectRatio:'none' } );
|
|
this.setCss( svg, { width:this.w, height:this.rh, left:0, top:this.top });
|
|
|
|
this.dom( 'path', '', { d:'', stroke:this.colors.text, 'stroke-width':2, fill:'none', 'stroke-linecap':'butt' }, svg );
|
|
this.dom( 'rect', '', { x:10, y:10, width:this.gw+8, height:this.gh+8, stroke:'rgba(0,0,0,0.3)', 'stroke-width':1 , fill:'none'}, svg );
|
|
|
|
this.iw = ((this.gw-(4*(this.lng-1)))/this.lng);
|
|
let t = [];
|
|
this.cMode = [];
|
|
|
|
this.v = [];
|
|
|
|
for( let i = 0; i < this.lng; i++ ){
|
|
|
|
t[i] = [ 14 + (i*this.iw) + (i*4), this.iw ];
|
|
t[i][2] = t[i][0] + t[i][1];
|
|
this.cMode[i] = 0;
|
|
|
|
if( this.neg ) this.v[i] = ((1+(this.value[i] / this.multiplicator))*0.5);
|
|
else this.v[i] = this.value[i] / this.multiplicator;
|
|
|
|
this.dom( 'rect', '', { x:t[i][0], y:14, width:t[i][1], height:1, fill:this.colors.text, 'fill-opacity':0.3 }, svg );
|
|
|
|
}
|
|
|
|
this.tmp = t;
|
|
this.c[3] = svg;
|
|
|
|
//console.log(this.w)
|
|
|
|
this.init();
|
|
|
|
if( this.c[1] !== undefined ){
|
|
this.c[1].style.top = 0 +'px';
|
|
this.c[1].style.height = 20 +'px';
|
|
this.s[1].lineHeight = (20-5)+'px';
|
|
}
|
|
|
|
this.update( false );
|
|
|
|
}
|
|
|
|
setValue ( value ) {
|
|
|
|
this.value = value;
|
|
this.lng = this.value.length;
|
|
for (var i = 0; i < this.lng; i++) {
|
|
if (this.neg) this.v[i] = (1 + value[i] / this.multiplicator) * 0.5;
|
|
else this.v[i] = value[i] / this.multiplicator;
|
|
}
|
|
this.update();
|
|
|
|
}
|
|
|
|
valueToHtml() {
|
|
|
|
let i = this.lng, n=0, r = '<table style="width:100%;"><tr>';
|
|
let w = 100 / this.lng;
|
|
let style = 'width:'+ w +'%;';//' text-align:center;'
|
|
while(i--){
|
|
if(n===this.lng-1) r += '<td style='+style+'>' + this.value[n] + '</td></tr></table>';
|
|
else r += '<td style='+style+'>' + this.value[n] + '</td>';
|
|
n++;
|
|
}
|
|
return r
|
|
}
|
|
|
|
updateSVG () {
|
|
|
|
if( this.line ) this.setSvg( this.c[3], 'd', this.makePath(), 0 );
|
|
|
|
for(let i = 0; i<this.lng; i++ ){
|
|
|
|
this.setSvg( this.c[3], 'height', this.v[i]*this.gh, i+2 );
|
|
this.setSvg( this.c[3], 'y', 14 + (this.gh - this.v[i]*this.gh), i+2 );
|
|
if( this.neg ) this.value[i] = ( ((this.v[i]*2)-1) * this.multiplicator ).toFixed( this.precision ) * 1;
|
|
else this.value[i] = ( (this.v[i] * this.multiplicator) ).toFixed( this.precision ) * 1;
|
|
|
|
}
|
|
|
|
//this.c[2].textContent = this.value;
|
|
this.c[2].innerHTML = this.valueToHtml();
|
|
|
|
}
|
|
|
|
testZone ( e ) {
|
|
|
|
let l = this.local;
|
|
if( l.x === -1 && l.y === -1 ) return '';
|
|
|
|
let i = this.lng;
|
|
let t = this.tmp;
|
|
|
|
if( l.y>this.top && l.y<this.h-20 ){
|
|
while( i-- ){
|
|
if( l.x>t[i][0] && l.x<t[i][2] ) return i;
|
|
}
|
|
}
|
|
|
|
return ''
|
|
|
|
}
|
|
|
|
mode ( n, name ) {
|
|
|
|
if( n === this.cMode[name] ) return false;
|
|
|
|
let a;
|
|
|
|
switch(n){
|
|
case 0: a=0.3; break;
|
|
case 1: a=0.6; break;
|
|
case 2: a=1; break;
|
|
}
|
|
|
|
this.reset();
|
|
|
|
this.setSvg( this.c[3], 'fill-opacity', a, name + 2 );
|
|
this.cMode[name] = n;
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
reset () {
|
|
|
|
let nup = false;
|
|
//this.isDown = false;
|
|
|
|
let i = this.lng;
|
|
while(i--){
|
|
if( this.cMode[i] !== 0 ){
|
|
this.cMode[i] = 0;
|
|
this.setSvg( this.c[3], 'fill-opacity', 0.3, i + 2 );
|
|
nup = true;
|
|
}
|
|
}
|
|
|
|
return nup;
|
|
|
|
}
|
|
|
|
mouseup ( e ) {
|
|
|
|
this.isDown = false;
|
|
if( this.current !== -1 ) return this.reset();
|
|
|
|
}
|
|
|
|
mousedown ( e ) {
|
|
|
|
this.isDown = true;
|
|
return this.mousemove( e );
|
|
|
|
}
|
|
|
|
mousemove ( e ) {
|
|
|
|
let nup = false;
|
|
|
|
let name = this.testZone(e);
|
|
|
|
if( name === '' ){
|
|
|
|
nup = this.reset();
|
|
//this.cursor();
|
|
|
|
} else {
|
|
|
|
nup = this.mode( this.isDown ? 2 : 1, name );
|
|
//this.cursor( this.current !== -1 ? 'move' : 'pointer' );
|
|
if(this.isDown){
|
|
this.v[name] = this.clamp( 1 - (( e.clientY - this.zone.y - this.top - 10 ) / this.gh) , 0, 1 );
|
|
this.update( true );
|
|
}
|
|
|
|
}
|
|
|
|
return nup;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
|
|
update ( up ) {
|
|
|
|
this.updateSVG();
|
|
|
|
if( up ) this.send();
|
|
|
|
}
|
|
|
|
makePath () {
|
|
|
|
let p = "", h, w, wn, wm, ow, oh;
|
|
//let g = this.iw*0.5
|
|
|
|
for(let i = 0; i<this.lng; i++ ){
|
|
|
|
h = 14 + (this.gh - this.v[i]*this.gh);
|
|
w = (14 + (i*this.iw) + (i*4));
|
|
|
|
wm = w + this.iw*0.5;
|
|
wn = w + this.iw;
|
|
|
|
if(i===0) p+='M '+w+' '+ h + ' T ' + wm +' '+ h;
|
|
else p += ' C ' + ow +' '+ oh + ',' + w +' '+ h + ',' + wm +' '+ h;
|
|
if(i === this.lng-1) p+=' T ' + wn +' '+ h;
|
|
|
|
ow = wn;
|
|
oh = h;
|
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
rSize () {
|
|
|
|
super.rSize();
|
|
|
|
let s = this.s;
|
|
if( this.c[1] !== undefined ) s[1].width = this.w + 'px';
|
|
s[3].width = this.w + 'px';
|
|
|
|
let gw = this.w - 28;
|
|
let iw = ((gw-(4*(this.lng-1)))/this.lng);
|
|
|
|
let t = [];
|
|
|
|
s[2].width = gw + 'px';
|
|
|
|
for( let i = 0; i < this.lng; i++ ){
|
|
|
|
t[i] = [ 14 + (i*iw) + (i*4), iw ];
|
|
t[i][2] = t[i][0] + t[i][1];
|
|
|
|
}
|
|
|
|
this.tmp = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Group extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.isGroup = true;
|
|
|
|
this.ADD = o.add;
|
|
|
|
this.autoHeight = true;
|
|
|
|
this.uis = [];
|
|
this.current = -1;
|
|
this.proto = null;
|
|
this.isEmpty = true;
|
|
this.decal = 0;
|
|
|
|
this.baseH = this.h;
|
|
|
|
let fltop = Math.floor(this.h*0.5)-6;
|
|
|
|
this.isLine = o.line !== undefined ? o.line : false;
|
|
|
|
this.decal = 0;
|
|
|
|
if( o.group ){
|
|
this.decal = o.group.decal ? o.group.decal : 0;
|
|
this.decal += 6;
|
|
}
|
|
|
|
this.useFlex = true;
|
|
let flexible = this.useFlex ? 'display:flex; flex-flow: row wrap;' : '';
|
|
|
|
this.c[2] = this.dom( 'div', this.css.basic + flexible + 'width:100%; left:0; height:auto; overflow:hidden; top:'+this.h+'px');//
|
|
this.c[3] = this.dom( 'path', this.css.basic + 'position:absolute; width:10px; height:10px; left:0; top:'+fltop+'px;', { d:this.svgs.group, fill:this.colors.text, stroke:'none'});
|
|
this.c[4] = this.dom( 'path', this.css.basic + 'position:absolute; width:10px; height:10px; left:'+(4+this.decal)+'px; top:'+fltop+'px;', { d:this.svgs.arrow, fill:this.colors.text, stroke:'none'});
|
|
// bottom line
|
|
if( this.isLine ) this.c[5] = this.dom( 'div', this.css.basic + 'background:rgba(255, 255, 255, 0.2); width:100%; left:0; height:1px; bottom:0px');
|
|
|
|
let s = this.s;
|
|
s[0].height = this.h + 'px';
|
|
s[1].height = this.h + 'px';
|
|
this.c[1].name = 'group';
|
|
|
|
s[1].marginLeft = (10+this.decal)+'px';
|
|
s[1].lineHeight = this.h-4;
|
|
s[1].color = this.colors.text;
|
|
s[1].fontWeight = 'bold';
|
|
|
|
if( this.radius !== 0 ) s[0].borderRadius = this.radius+'px';
|
|
this.init();
|
|
|
|
this.setBG( o.bg );
|
|
|
|
if( o.open !== undefined ) this.open();
|
|
|
|
}
|
|
|
|
testZone ( e ) {
|
|
|
|
let l = this.local;
|
|
if( l.x === -1 && l.y === -1 ) return '';
|
|
|
|
let name = '';
|
|
|
|
if( l.y < this.baseH ) name = 'title';
|
|
else {
|
|
if( this.isOpen ) name = 'content';
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
clearTarget () {
|
|
|
|
if( this.current === -1 ) return false;
|
|
if( this.proto.s ){
|
|
// if no s target is delete !!
|
|
this.proto.uiout();
|
|
this.proto.reset();
|
|
}
|
|
this.proto = null;
|
|
this.current = -1;
|
|
this.cursor();
|
|
return true;
|
|
|
|
}
|
|
|
|
reset () {
|
|
|
|
this.clearTarget();
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
handleEvent ( e ) {
|
|
|
|
let type = e.type;
|
|
|
|
let change = false;
|
|
let protoChange = false;
|
|
|
|
let name = this.testZone( e );
|
|
|
|
if( !name ) return;
|
|
|
|
switch( name ){
|
|
|
|
case 'content':
|
|
this.cursor();
|
|
|
|
if( Roots.isMobile && type === 'mousedown' ) this.getNext( e, change );
|
|
|
|
if( this.proto ) protoChange = this.proto.handleEvent( e );
|
|
|
|
if( !Roots.lock ) this.getNext( e, change );
|
|
|
|
break;
|
|
case 'title':
|
|
this.cursor('pointer');
|
|
if( type === 'mousedown' ){
|
|
if( this.isOpen ) this.close();
|
|
else this.open();
|
|
}
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
if( this.isDown ) change = true;
|
|
if( protoChange ) change = true;
|
|
|
|
return change;
|
|
|
|
}
|
|
|
|
getNext ( e, change ) {
|
|
|
|
let next = Roots.findTarget( this.uis, e );
|
|
|
|
if( next !== this.current ){
|
|
this.clearTarget();
|
|
this.current = next;
|
|
}
|
|
|
|
if( next !== -1 ){
|
|
this.proto = this.uis[ this.current ];
|
|
this.proto.uiover();
|
|
}
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
|
|
setBG ( bg ) {
|
|
|
|
if( bg !== undefined ) this.colors.background = bg;
|
|
|
|
this.c[0].style.background = this.colors.background;
|
|
|
|
let i = this.uis.length;
|
|
while(i--){
|
|
this.uis[i].setBG( this.colors.background );
|
|
}
|
|
|
|
}
|
|
|
|
add() {
|
|
|
|
let a = arguments;
|
|
|
|
if( typeof a[1] === 'object' ){
|
|
a[1].isUI = this.isUI;
|
|
a[1].target = this.c[2];
|
|
a[1].main = this.main;
|
|
a[1].group = this;
|
|
} else if( typeof arguments[1] === 'string' ){
|
|
if( a[2] === undefined ) [].push.call( a, { isUI:true, target:this.c[2], main:this.main });
|
|
else {
|
|
a[2].isUI = true;
|
|
a[2].target = this.c[2];
|
|
a[2].main = this.main;
|
|
a[2].group = this;
|
|
}
|
|
}
|
|
|
|
let u = this.ADD.apply( this, a );
|
|
|
|
this.uis.push( u );
|
|
|
|
this.isEmpty = false;
|
|
|
|
return u;
|
|
|
|
}
|
|
|
|
// remove one node
|
|
|
|
remove ( n ) {
|
|
|
|
if( n.dispose ) n.dispose();
|
|
|
|
}
|
|
|
|
// clear all iner
|
|
|
|
dispose() {
|
|
|
|
this.clear();
|
|
if( this.isUI ) this.main.calc();
|
|
super.dispose();
|
|
|
|
}
|
|
|
|
clear() {
|
|
|
|
this.empty();
|
|
|
|
}
|
|
|
|
empty () {
|
|
|
|
this.close();
|
|
|
|
let i = this.uis.length, item;
|
|
|
|
while( i-- ){
|
|
item = this.uis.pop();
|
|
this.c[2].removeChild( item.c[0] );
|
|
item.clear( true );
|
|
|
|
//this.uis[i].clear()
|
|
}
|
|
|
|
this.isEmpty = true;
|
|
this.h = this.baseH;
|
|
|
|
}
|
|
|
|
// clear one element
|
|
|
|
clearOne ( n ) {
|
|
|
|
let id = this.uis.indexOf( n );
|
|
|
|
if ( id !== -1 ) {
|
|
this.calc( - ( this.uis[ id ].h + 1 ) );
|
|
this.c[2].removeChild( this.uis[ id ].c[0] );
|
|
this.uis.splice( id, 1 );
|
|
|
|
if( this.uis.length === 0 ){
|
|
this.isEmpty = true;
|
|
this.close();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
open () {
|
|
|
|
super.open();
|
|
|
|
this.setSvg( this.c[4], 'd', this.svgs.arrowDown );
|
|
this.rSizeContent();
|
|
|
|
this.h - this.baseH;
|
|
|
|
this.parentHeight();
|
|
|
|
}
|
|
|
|
close () {
|
|
|
|
super.close();
|
|
|
|
this.h - this.baseH;
|
|
|
|
this.setSvg( this.c[4], 'd', this.svgs.arrow );
|
|
this.h = this.baseH;
|
|
this.s[0].height = this.h + 'px';
|
|
|
|
this.parentHeight();
|
|
|
|
}
|
|
|
|
calcUis () {
|
|
|
|
if( !this.isOpen ) this.h = this.baseH;
|
|
else this.h = Roots.calcUis( this.uis, this.zone, this.zone.y + this.baseH ) + this.baseH;
|
|
|
|
this.s[0].height = this.h + 'px';
|
|
|
|
}
|
|
|
|
parentHeight ( t ) {
|
|
|
|
if ( this.group !== null ) this.group.calc( t );
|
|
else if ( this.isUI ) this.main.calc( t );
|
|
|
|
}
|
|
|
|
calc ( y ) {
|
|
|
|
if( !this.isOpen ) return
|
|
if( this.isUI ) this.main.calc();
|
|
else this.calcUis();
|
|
this.s[0].height = this.h + 'px';
|
|
|
|
}
|
|
|
|
rSizeContent () {
|
|
|
|
let i = this.uis.length;
|
|
while(i--){
|
|
this.uis[i].setSize( this.w );
|
|
this.uis[i].rSize();
|
|
}
|
|
|
|
}
|
|
|
|
rSize () {
|
|
|
|
super.rSize();
|
|
|
|
let s = this.s;
|
|
|
|
s[3].left = ( this.sa + this.sb - 17 ) + 'px';
|
|
s[1].width = this.w + 'px';
|
|
s[2].width = this.w + 'px';
|
|
|
|
if( this.isOpen ) this.rSizeContent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Joystick extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.autoWidth = false;
|
|
|
|
this.value = [0,0];
|
|
|
|
this.minw = this.w;
|
|
this.diam = o.diam || this.w;
|
|
|
|
this.joyType = 'analogique';
|
|
this.model = o.mode !== undefined ? o.mode : 0;
|
|
|
|
this.precision = o.precision || 2;
|
|
this.multiplicator = o.multiplicator || 1;
|
|
|
|
this.pos = new V2();
|
|
this.tmp = new V2();
|
|
|
|
this.interval = null;
|
|
|
|
//this.radius = this.w * 0.5;
|
|
//this.distance = this.radius*0.25;
|
|
this.distance = (this.diam*0.5)*0.25;
|
|
|
|
this.h = o.h || this.w + 10;
|
|
this.top = 0;
|
|
|
|
this.c[0].style.width = this.w +'px';
|
|
|
|
if( this.c[1] !== undefined ) { // with title
|
|
|
|
this.c[1].style.width = '100%';
|
|
this.c[1].style.justifyContent = 'center';
|
|
this.top = 10;
|
|
this.h += 10;
|
|
|
|
}
|
|
|
|
let cc = this.colors;
|
|
|
|
this.c[2] = this.dom( 'div', this.css.txt + 'justify-content:center; top:'+(this.h-20)+'px; width:100%; color:'+ cc.text );
|
|
this.c[2].textContent = this.value;
|
|
|
|
this.c[3] = this.getJoystick( this.model );
|
|
this.setSvg( this.c[3], 'viewBox', '0 0 '+this.diam+' '+this.diam );
|
|
this.setCss( this.c[3], { width:this.diam, height:this.diam, left:0, top:this.top });
|
|
|
|
|
|
this.ratio = 128/this.w;
|
|
|
|
this.init();
|
|
|
|
this.update(false);
|
|
|
|
}
|
|
|
|
mode ( mode ) {
|
|
|
|
let cc = this.colors;
|
|
|
|
switch(mode){
|
|
case 0: // base
|
|
if(this.model===0){
|
|
this.setSvg( this.c[3], 'fill', 'url(#gradIn)', 4 );
|
|
this.setSvg( this.c[3], 'stroke', '#000', 4 );
|
|
} else {
|
|
this.setSvg( this.c[3], 'stroke', 'rgba(100,100,100,0.25)', 2 );
|
|
//this.setSvg( this.c[3], 'stroke', 'rgb(0,0,0,0.1)', 3 );
|
|
this.setSvg( this.c[3], 'stroke', '#666', 4 );
|
|
this.setSvg( this.c[3], 'fill', 'none', 4 );
|
|
}
|
|
|
|
break;
|
|
case 1: // over
|
|
if(this.model===0){
|
|
this.setSvg( this.c[3], 'fill', 'url(#gradIn2)', 4 );
|
|
this.setSvg( this.c[3], 'stroke', 'rgba(0,0,0,0)', 4 );
|
|
} else {
|
|
this.setSvg( this.c[3], 'stroke', 'rgba(48,138,255,0.25)', 2 );
|
|
//this.setSvg( this.c[3], 'stroke', 'rgb(0,0,0,0.3)', 3 );
|
|
this.setSvg( this.c[3], 'stroke', cc.select, 4 );
|
|
this.setSvg( this.c[3], 'fill', 'rgba(48,138,255,0.25)', 4 );
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
addInterval (){
|
|
if( this.interval !== null ) this.stopInterval();
|
|
if( this.pos.isZero() ) return;
|
|
this.interval = setInterval( function(){ this.update(); }.bind(this), 10 );
|
|
|
|
}
|
|
|
|
stopInterval (){
|
|
|
|
if( this.interval === null ) return;
|
|
clearInterval( this.interval );
|
|
this.interval = null;
|
|
|
|
}
|
|
|
|
reset () {
|
|
|
|
this.addInterval();
|
|
this.mode(0);
|
|
|
|
}
|
|
|
|
mouseup ( e ) {
|
|
|
|
this.addInterval();
|
|
this.isDown = false;
|
|
|
|
}
|
|
|
|
mousedown ( e ) {
|
|
|
|
this.isDown = true;
|
|
this.mousemove( e );
|
|
this.mode( 2 );
|
|
|
|
}
|
|
|
|
mousemove ( e ) {
|
|
|
|
this.mode(1);
|
|
|
|
if( !this.isDown ) return;
|
|
|
|
//this.tmp.x = this.radius - ( e.clientX - this.zone.x );
|
|
//this.tmp.y = this.radius - ( e.clientY - this.zone.y - this.top );
|
|
|
|
this.tmp.x = (this.w*0.5) - ( e.clientX - this.zone.x );
|
|
this.tmp.y = (this.diam*0.5) - ( e.clientY - this.zone.y - this.top );
|
|
|
|
let distance = this.tmp.length();
|
|
|
|
if ( distance > this.distance ) {
|
|
let angle = Math.atan2(this.tmp.x, this.tmp.y);
|
|
this.tmp.x = Math.sin( angle ) * this.distance;
|
|
this.tmp.y = Math.cos( angle ) * this.distance;
|
|
}
|
|
|
|
this.pos.copy( this.tmp ).divideScalar( this.distance ).negate();
|
|
|
|
this.update();
|
|
|
|
}
|
|
|
|
setValue ( v ) {
|
|
|
|
if(v===undefined) v=[0,0];
|
|
|
|
this.pos.set( v[0] || 0, v[1] || 0 );
|
|
this.updateSVG();
|
|
|
|
}
|
|
|
|
update ( up ) {
|
|
|
|
if( up === undefined ) up = true;
|
|
|
|
if( this.interval !== null ){
|
|
|
|
if( !this.isDown ){
|
|
|
|
this.pos.lerp( null, 0.3 );
|
|
|
|
this.pos.x = Math.abs( this.pos.x ) < 0.01 ? 0 : this.pos.x;
|
|
this.pos.y = Math.abs( this.pos.y ) < 0.01 ? 0 : this.pos.y;
|
|
|
|
if( this.isUI && this.main.isCanvas ) this.main.draw();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.updateSVG();
|
|
|
|
if( up ) this.send();
|
|
|
|
|
|
if( this.pos.isZero() ) this.stopInterval();
|
|
|
|
}
|
|
|
|
updateSVG () {
|
|
|
|
//let x = this.radius - ( -this.pos.x * this.distance );
|
|
//let y = this.radius - ( -this.pos.y * this.distance );
|
|
|
|
let x = (this.diam*0.5) - ( -this.pos.x * this.distance );
|
|
let y = (this.diam*0.5) - ( -this.pos.y * this.distance );
|
|
|
|
if(this.model === 0){
|
|
|
|
let sx = x + ((this.pos.x)*5) + 5;
|
|
let sy = y + ((this.pos.y)*5) + 10;
|
|
|
|
this.setSvg( this.c[3], 'cx', sx*this.ratio, 3 );
|
|
this.setSvg( this.c[3], 'cy', sy*this.ratio, 3 );
|
|
} else {
|
|
this.setSvg( this.c[3], 'cx', x*this.ratio, 3 );
|
|
this.setSvg( this.c[3], 'cy', y*this.ratio, 3 );
|
|
}
|
|
|
|
|
|
|
|
this.setSvg( this.c[3], 'cx', x*this.ratio, 4 );
|
|
this.setSvg( this.c[3], 'cy', y*this.ratio, 4 );
|
|
|
|
this.value[0] = ( this.pos.x * this.multiplicator ).toFixed( this.precision ) * 1;
|
|
this.value[1] = ( this.pos.y * this.multiplicator ).toFixed( this.precision ) * 1;
|
|
|
|
this.c[2].textContent = this.value;
|
|
|
|
}
|
|
|
|
clear () {
|
|
|
|
this.stopInterval();
|
|
super.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Knob extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.isCyclic = o.cyclic || false;
|
|
this.model = o.stype || 0;
|
|
if( o.mode !== undefined ) this.model = o.mode;
|
|
|
|
this.autoWidth = false;
|
|
|
|
this.setTypeNumber( o );
|
|
|
|
this.minw = this.w;
|
|
this.diam = o.diam || this.w;
|
|
|
|
this.mPI = Math.PI * 0.8;
|
|
this.toDeg = 180 / Math.PI;
|
|
this.cirRange = this.mPI * 2;
|
|
|
|
this.offset = new V2();
|
|
|
|
this.h = o.h || this.w + 10;
|
|
this.top = 0;
|
|
|
|
this.c[0].style.width = this.w +'px';
|
|
|
|
if(this.c[1] !== undefined) {
|
|
|
|
this.c[1].style.width = '100%';
|
|
this.c[1].style.justifyContent = 'center';
|
|
this.top = 10;
|
|
this.h += 10;
|
|
|
|
}
|
|
|
|
this.percent = 0;
|
|
|
|
this.cmode = 0;
|
|
let cc = this.colors;
|
|
|
|
this.c[2] = this.dom( 'div', this.css.txt + 'justify-content:center; top:'+(this.h-20)+'px; width:100%; color:'+ cc.text );
|
|
|
|
this.c[3] = this.getKnob();
|
|
this.setSvg( this.c[3], 'fill', cc.button, 0 );
|
|
this.setSvg( this.c[3], 'stroke', cc.text, 1 );
|
|
this.setSvg( this.c[3], 'stroke', cc.text, 3 );
|
|
this.setSvg( this.c[3], 'd', this.makeGrad(), 3 );
|
|
|
|
this.setSvg( this.c[3], 'viewBox', '0 0 ' + this.diam + ' ' + this.diam );
|
|
this.setCss( this.c[3], { width:this.diam, height:this.diam, left:0, top:this.top });
|
|
|
|
if ( this.model > 0 ) {
|
|
|
|
Tools.dom( 'path', '', { d: '', stroke:cc.text, 'stroke-width': 2, fill: 'none', 'stroke-linecap': 'round' }, this.c[3] ); //4
|
|
|
|
if ( this.model == 2) {
|
|
|
|
Tools.addSVGGlowEffect();
|
|
this.setSvg( this.c[3], 'style', 'filter: url("#UILGlow");', 4 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.r = 0;
|
|
|
|
this.init();
|
|
|
|
this.update();
|
|
|
|
}
|
|
|
|
mode ( mode ) {
|
|
|
|
let cc = this.colors;
|
|
|
|
if( this.cmode === mode ) return false;
|
|
|
|
switch( mode ) {
|
|
case 0: // base
|
|
this.s[2].color = cc.text;
|
|
this.setSvg( this.c[3], 'fill', cc.button, 0);
|
|
//this.setSvg( this.c[3], 'stroke','rgba(255,0,0,0.2)', 2);
|
|
this.setSvg( this.c[3], 'stroke', cc.text, 1 );
|
|
break;
|
|
case 1: // down
|
|
this.s[2].color = cc.textOver;
|
|
this.setSvg( this.c[3], 'fill', cc.select, 0);
|
|
//this.setSvg( this.c[3], 'stroke','rgba(0,0,0,0.6)', 2);
|
|
this.setSvg( this.c[3], 'stroke', cc.textOver, 1 );
|
|
break;
|
|
}
|
|
|
|
this.cmode = mode;
|
|
return true;
|
|
|
|
}
|
|
|
|
testZone ( e ) {
|
|
|
|
let l = this.local;
|
|
if( l.x === -1 && l.y === -1 ) return '';
|
|
if( l.y <= this.c[ 1 ].offsetHeight ) return 'title';
|
|
else if ( l.y > this.h - this.c[ 2 ].offsetHeight ) return 'text';
|
|
else return 'knob';
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
mouseup ( e ) {
|
|
|
|
this.isDown = false;
|
|
this.sendEnd();
|
|
return this.mode(0)
|
|
|
|
}
|
|
|
|
mousedown ( e ) {
|
|
|
|
this.isDown = true;
|
|
this.old = this.value;
|
|
this.oldr = null;
|
|
this.mousemove( e );
|
|
return this.mode(1)
|
|
|
|
}
|
|
|
|
mousemove ( e ) {
|
|
|
|
if( !this.isDown ) return;
|
|
|
|
let off = this.offset;
|
|
|
|
//off.x = this.radius - ( e.clientX - this.zone.x );
|
|
//off.y = this.radius - ( e.clientY - this.zone.y - this.top );
|
|
|
|
off.x = (this.w*0.5) - ( e.clientX - this.zone.x );
|
|
off.y = (this.diam*0.5) - ( e.clientY - this.zone.y - this.top );
|
|
|
|
this.r = - Math.atan2( off.x, off.y );
|
|
|
|
if( this.oldr !== null ) this.r = Math.abs(this.r - this.oldr) > Math.PI ? this.oldr : this.r;
|
|
|
|
this.r = this.r > this.mPI ? this.mPI : this.r;
|
|
this.r = this.r < -this.mPI ? -this.mPI : this.r;
|
|
|
|
let steps = 1 / this.cirRange;
|
|
let value = (this.r + this.mPI) * steps;
|
|
|
|
let n = ( ( this.range * value ) + this.min ) - this.old;
|
|
|
|
if(n >= this.step || n <= this.step){
|
|
n = Math.floor( n / this.step );
|
|
this.value = this.numValue( this.old + ( n * this.step ) );
|
|
this.update( true );
|
|
this.old = this.value;
|
|
this.oldr = this.r;
|
|
}
|
|
|
|
}
|
|
|
|
wheel ( e ) {
|
|
|
|
let name = this.testZone( e );
|
|
|
|
if( name === 'knob' ) {
|
|
|
|
let v = this.value - this.step * e.delta;
|
|
|
|
if ( v > this.max ) {
|
|
v = this.isCyclic ? this.min : this.max;
|
|
} else if ( v < this.min ) {
|
|
v = this.isCyclic ? this.max : this.min;
|
|
}
|
|
|
|
this.setValue( v );
|
|
this.old = v;
|
|
this.update( true );
|
|
|
|
return true;
|
|
|
|
}
|
|
return false;
|
|
|
|
}
|
|
|
|
makeGrad () {
|
|
|
|
let d = '', step, range, a, x, y, x2, y2, r = 64;
|
|
let startangle = Math.PI + this.mPI;
|
|
let endangle = Math.PI - this.mPI;
|
|
//let step = this.step>5 ? this.step : 1;
|
|
|
|
if(this.step>5){
|
|
range = this.range / this.step;
|
|
step = ( startangle - endangle ) / range;
|
|
} else {
|
|
step = (( startangle - endangle ) / r)*2;
|
|
range = r*0.5;
|
|
}
|
|
|
|
for ( let i = 0; i <= range; ++i ) {
|
|
|
|
a = startangle - ( step * i );
|
|
x = r + Math.sin( a ) * ( r - 20 );
|
|
y = r + Math.cos( a ) * ( r - 20 );
|
|
x2 = r + Math.sin( a ) * ( r - 24 );
|
|
y2 = r + Math.cos( a ) * ( r - 24 );
|
|
d += 'M' + x + ' ' + y + ' L' + x2 + ' '+y2 + ' ';
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
update ( up ) {
|
|
|
|
this.c[2].textContent = this.value;
|
|
this.percent = (this.value - this.min) / this.range;
|
|
|
|
let sa = Math.PI + this.mPI;
|
|
let ea = ( ( this.percent * this.cirRange ) - ( this.mPI ) );
|
|
|
|
let sin = Math.sin( ea );
|
|
let cos = Math.cos( ea );
|
|
|
|
let x1 = ( 25 * sin ) + 64;
|
|
let y1 = -( 25 * cos ) + 64;
|
|
let x2 = ( 20 * sin ) + 64;
|
|
let y2 = -( 20 * cos ) + 64;
|
|
|
|
this.setSvg( this.c[3], 'd', 'M ' + x1 +' ' + y1 + ' L ' + x2 +' ' + y2, 1 );
|
|
|
|
if ( this.model > 0 ) {
|
|
|
|
let x1 = 36 * Math.sin( sa ) + 64;
|
|
let y1 = 36 * Math.cos( sa ) + 64;
|
|
let x2 = 36 * sin + 64;
|
|
let y2 = -36 * cos + 64;
|
|
let big = ea <= Math.PI - this.mPI ? 0 : 1;
|
|
this.setSvg( this.c[3], 'd', 'M ' + x1 + ',' + y1 + ' A ' + 36 + ',' + 36 + ' 1 ' + big + ' 1 ' + x2 + ',' + y2, 4 );
|
|
|
|
let color = Tools.pack( Tools.lerpColor( Tools.unpack( Tools.ColorLuma( this.colors.text, -0.75) ), Tools.unpack( this.colors.text ), this.percent ) );
|
|
this.setSvg( this.c[3], 'stroke', color, 4 );
|
|
|
|
}
|
|
|
|
if( up ) this.send();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class List extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
// images
|
|
this.path = o.path || '';
|
|
this.format = o.format || '';
|
|
|
|
|
|
this.isWithImage = this.path !== '' ? true:false;
|
|
this.preLoadComplete = false;
|
|
|
|
this.tmpImage = {};
|
|
this.tmpUrl = [];
|
|
|
|
//this.autoHeight = false;
|
|
|
|
let align = o.align || 'center';
|
|
|
|
// scroll size
|
|
let ss = o.scrollSize || 10;
|
|
this.ss = ss+1;
|
|
|
|
this.sMode = 0;
|
|
this.tMode = 0;
|
|
|
|
this.listOnly = o.listOnly || false;
|
|
this.staticTop = o.staticTop || false;
|
|
|
|
this.isSelectable = this.listOnly;
|
|
if( o.select !== undefined ) o.selectable = o.select;
|
|
if( o.selectable !== undefined ) this.isSelectable = o.selectable;
|
|
|
|
if( this.txt === '' ) this.p = 0;
|
|
|
|
|
|
let fltop = Math.floor(this.h*0.5)-5;
|
|
let cc = this.colors;
|
|
|
|
|
|
|
|
this.c[2] = this.dom( 'div', this.css.basic + 'top:0; display:none; border-radius:'+this.radius+'px;' );
|
|
this.c[3] = this.dom( 'div', this.css.item + 'position:absolute; text-align:'+align+'; line-height:'+(this.h-4)+'px; top:1px; background:'+cc.button+'; height:'+(this.h-2)+'px; border:1px solid '+cc.border+'; border-radius:'+this.radius+'px;' );
|
|
this.c[4] = this.dom( 'path', this.css.basic + 'position:absolute; width:10px; height:10px; top:'+fltop+'px;', { d:this.svgs.arrow, fill:cc.text, stroke:'none'});
|
|
|
|
this.scrollerBack = this.dom( 'div', this.css.basic + 'right:0px; width:'+ss+'px; background:'+cc.back+'; display:none;');
|
|
this.scroller = this.dom( 'div', this.css.basic + 'right:'+((ss-(ss*0.25))*0.5)+'px; width:'+(ss*0.25)+'px; background:'+cc.text+'; display:none; ');
|
|
|
|
this.c[3].style.color = cc.text;
|
|
|
|
|
|
this.list = [];
|
|
this.refObject = null;
|
|
|
|
if(o.list){
|
|
if( o.list instanceof Array ){
|
|
this.list = o.list;
|
|
} else {
|
|
this.refObject = o.list;
|
|
for( let g in this.refObject ) this.list.push(g);
|
|
}
|
|
}
|
|
|
|
this.items = [];
|
|
|
|
this.prevName = '';
|
|
|
|
this.baseH = this.h;
|
|
|
|
this.itemHeight = o.itemHeight || (this.h-3);
|
|
|
|
// force full list
|
|
this.full = o.full || false;
|
|
|
|
this.py = 0;
|
|
this.ww = this.sb;
|
|
this.scroll = false;
|
|
this.isDown = false;
|
|
|
|
this.current = null;
|
|
|
|
// list up or down
|
|
this.side = o.side || 'down';
|
|
this.up = this.side === 'down' ? 0 : 1;
|
|
|
|
if( this.up ){
|
|
|
|
this.c[2].style.top = 'auto';
|
|
this.c[3].style.top = 'auto';
|
|
this.c[4].style.top = 'auto';
|
|
//this.c[5].style.top = 'auto';
|
|
|
|
this.c[2].style.bottom = this.h-2 + 'px';
|
|
this.c[3].style.bottom = '1px';
|
|
this.c[4].style.bottom = fltop + 'px';
|
|
|
|
} else {
|
|
this.c[2].style.top = this.baseH + 'px';
|
|
}
|
|
|
|
this.listIn = this.dom( 'div', this.css.basic + 'left:0; top:0; width:100%; background:none;');
|
|
this.listIn.name = 'list';
|
|
|
|
|
|
|
|
this.topList = 0;
|
|
|
|
this.c[2].appendChild( this.listIn );
|
|
this.c[2].appendChild( this.scrollerBack );
|
|
this.c[2].appendChild( this.scroller );
|
|
|
|
if( o.value !== undefined ){
|
|
if(!isNaN(o.value)) this.value = this.list[ o.value ];
|
|
else this.value = o.value;
|
|
}else {
|
|
this.value = this.list[0];
|
|
}
|
|
|
|
this.isOpenOnStart = o.open || false;
|
|
|
|
if( this.listOnly ){
|
|
this.baseH = 5;
|
|
this.c[3].style.display = 'none';
|
|
this.c[4].style.display = 'none';
|
|
this.c[2].style.top = this.baseH+'px';
|
|
this.isOpenOnStart = true;
|
|
}
|
|
|
|
|
|
this.miniCanvas = o.miniCanvas || false;
|
|
this.canvasBg = o.canvasBg || 'rgba(0,0,0,0)';
|
|
this.imageSize = o.imageSize || [20,20];
|
|
|
|
// dragout function
|
|
this.drag = o.drag || false;
|
|
this.dragout = o.dragout || false;
|
|
this.dragstart = o.dragstart || null;
|
|
this.dragend = o.dragend || null;
|
|
|
|
|
|
|
|
//this.c[0].style.background = '#FF0000'
|
|
if( this.isWithImage ) this.preloadImage();
|
|
// } else {
|
|
// populate list
|
|
this.setList( this.list );
|
|
this.init();
|
|
if( this.isOpenOnStart ) this.open( true );
|
|
// }
|
|
|
|
}
|
|
|
|
/*send ( v ) {
|
|
|
|
super.send( v );
|
|
|
|
//Proto.prototype.send.call( this, v );
|
|
}*/
|
|
|
|
// image list
|
|
|
|
preloadImage () {
|
|
|
|
this.preLoadComplete = false;
|
|
|
|
this.tmpImage = {};
|
|
for( let i=0; i<this.list.length; i++ ) this.tmpUrl.push( this.list[i] );
|
|
this.loadOne();
|
|
|
|
}
|
|
|
|
nextImg () {
|
|
|
|
this.tmpUrl.shift();
|
|
if( this.tmpUrl.length === 0 ){
|
|
|
|
this.preLoadComplete = true;
|
|
|
|
this.addImages();
|
|
/*this.setList( this.list );
|
|
this.init();
|
|
if( this.isOpenOnStart ) this.open();*/
|
|
|
|
}
|
|
else this.loadOne();
|
|
|
|
}
|
|
|
|
loadOne(){
|
|
|
|
let self = this;
|
|
let name = this.tmpUrl[0];
|
|
let img = document.createElement('img');
|
|
img.style.cssText = 'position:absolute; width:'+self.imageSize[0]+'px; height:'+self.imageSize[1]+'px';
|
|
img.setAttribute('src', this.path + name + this.format );
|
|
|
|
img.addEventListener('load', function() {
|
|
|
|
self.imageSize[2] = img.width;
|
|
self.imageSize[3] = img.height;
|
|
self.tmpImage[name] = img;
|
|
self.nextImg();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
//
|
|
|
|
testZone ( e ) {
|
|
|
|
let l = this.local;
|
|
if( l.x === -1 && l.y === -1 ) return '';
|
|
|
|
if( this.up && this.isOpen ){
|
|
if( l.y > this.h - this.baseH ) return 'title';
|
|
else {
|
|
if( this.scroll && ( l.x > (this.sa+this.sb-this.ss)) ) return 'scroll';
|
|
if(l.x > this.sa) return this.testItems( l.y-this.baseH );
|
|
}
|
|
|
|
} else {
|
|
if( l.y < this.baseH+2 ) return 'title';
|
|
else {
|
|
if( this.isOpen ){
|
|
if( this.scroll && ( l.x > (this.sa+this.sb-this.ss)) ) return 'scroll';
|
|
if(l.x > this.sa) return this.testItems( l.y-this.baseH );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
testItems ( y ) {
|
|
|
|
let name = '';
|
|
|
|
let i = this.items.length, item, a, b;
|
|
while(i--){
|
|
item = this.items[i];
|
|
a = item.posy + this.topList;
|
|
b = item.posy + this.itemHeight + 1 + this.topList;
|
|
if( y >= a && y <= b ){
|
|
name = 'item' + i;
|
|
this.modeItem(0);
|
|
this.current = item;
|
|
this.modeItem(1);
|
|
return name;
|
|
}
|
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
modeItem ( mode ) {
|
|
|
|
if( !this.current ) return
|
|
|
|
if( this.current.select && mode===0) mode = 2;
|
|
let cc = this.colors;
|
|
|
|
switch( mode ){
|
|
|
|
case 0: // base
|
|
this.current.style.background = cc.back;
|
|
this.current.style.color = cc.text;
|
|
break;
|
|
case 1: // over
|
|
this.current.style.background = cc.over;
|
|
this.current.style.color = cc.textOver;
|
|
break;
|
|
case 2: // edit / down
|
|
this.current.style.background = cc.select;
|
|
this.current.style.color = cc.textSelect;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
unSelected() {
|
|
|
|
if( !this.current ) return
|
|
this.modeItem(0);
|
|
this.current = null;
|
|
|
|
}
|
|
|
|
selected() {
|
|
|
|
if( !this.current ) return
|
|
this.resetItems();
|
|
this.modeItem(2);
|
|
this.current.select = true;
|
|
|
|
}
|
|
|
|
resetItems() {
|
|
|
|
let i = this.items.length;
|
|
while(i--){
|
|
this.items[i].select = false;
|
|
this.items[i].style.background = this.colors.back;
|
|
this.items[i].style.color = this.colors.text;
|
|
}
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
|
|
mouseup ( e ) {
|
|
|
|
this.isDown = false;
|
|
|
|
}
|
|
|
|
mousedown ( e ) {
|
|
|
|
let name = this.testZone( e );
|
|
|
|
if( !name ) return false;
|
|
|
|
if( name === 'scroll' ){
|
|
|
|
this.isDown = true;
|
|
this.mousemove( e );
|
|
|
|
} else if( name === 'title' ){
|
|
|
|
this.modeTitle(2);
|
|
if( !this.listOnly ){
|
|
if( !this.isOpen ) this.open();
|
|
else this.close();
|
|
}
|
|
} else {
|
|
// is item
|
|
if( this.current ){
|
|
|
|
this.value = this.list[ this.current.id ];
|
|
|
|
if( this.isSelectable ) this.selected();
|
|
//this.value = this.refObject !== null ? this.refObject[this.list[this.current.id]] : this.list[this.current.id]
|
|
//this.value = this.current.textContent;
|
|
this.send( this.refObject !== null ? this.refObject[this.list[this.current.id]] : this.value );
|
|
|
|
if( !this.listOnly ) {
|
|
this.close();
|
|
this.setTopItem();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
mousemove ( e ) {
|
|
|
|
let nup = false;
|
|
let name = this.testZone( e );
|
|
|
|
if( !name ) return nup;
|
|
|
|
if( name === 'title' ){
|
|
this.unSelected();
|
|
this.modeTitle(1);
|
|
this.cursor('pointer');
|
|
|
|
} else if( name === 'scroll' ){
|
|
|
|
this.cursor('s-resize');
|
|
this.modeScroll(1);
|
|
if( this.isDown ){
|
|
this.modeScroll(2);
|
|
let top = this.zone.y+this.baseH-2;
|
|
this.update( ( e.clientY - top ) - ( this.sh*0.5 ) );
|
|
}
|
|
//if(this.isDown) this.listmove(e);
|
|
} else {
|
|
|
|
// is item
|
|
this.modeTitle(0);
|
|
this.modeScroll(0);
|
|
this.cursor('pointer');
|
|
|
|
}
|
|
|
|
if( name !== this.prevName ) nup = true;
|
|
this.prevName = name;
|
|
|
|
return nup;
|
|
|
|
}
|
|
|
|
wheel ( e ) {
|
|
|
|
let name = this.testZone( e );
|
|
if( name === 'title' ) return false;
|
|
this.py += e.delta*10;
|
|
this.update(this.py);
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------
|
|
|
|
reset () {
|
|
|
|
this.prevName = '';
|
|
this.unSelected();
|
|
this.modeTitle(0);
|
|
this.modeScroll(0);
|
|
|
|
//console.log('this is reset')
|
|
|
|
}
|
|
|
|
modeScroll ( mode ) {
|
|
|
|
if( mode === this.sMode ) return;
|
|
|
|
let s = this.scroller.style;
|
|
let cc = this.colors;
|
|
|
|
switch(mode){
|
|
case 0: // base
|
|
s.background = cc.text;
|
|
break;
|
|
case 1: // over
|
|
s.background = cc.select;
|
|
break;
|
|
case 2: // edit / down
|
|
s.background = cc.select;
|
|
break;
|
|
|
|
}
|
|
|
|
this.sMode = mode;
|
|
}
|
|
|
|
modeTitle ( mode ) {
|
|
|
|
if( mode === this.tMode ) return;
|
|
|
|
let s = this.s;
|
|
let cc = this.colors;
|
|
|
|
switch(mode){
|
|
case 0: // base
|
|
s[3].color = cc.text;
|
|
s[3].background = cc.button;
|
|
break;
|
|
case 1: // over
|
|
s[3].color = cc.textOver;
|
|
s[3].background = cc.overoff;
|
|
break;
|
|
case 2: // edit / down
|
|
s[3].color = cc.textSelect;
|
|
s[3].background = cc.overoff;
|
|
break;
|
|
|
|
}
|
|
|
|
this.tMode = mode;
|
|
|
|
}
|
|
|
|
clearList () {
|
|
|
|
while ( this.listIn.children.length ) this.listIn.removeChild( this.listIn.lastChild );
|
|
this.items = [];
|
|
|
|
}
|
|
|
|
setList ( list ) {
|
|
|
|
this.clearList();
|
|
|
|
this.list = list;
|
|
this.length = this.list.length;
|
|
|
|
this.maxItem = this.full ? this.length : 5;
|
|
this.maxItem = this.length < this.maxItem ? this.length : this.maxItem;
|
|
|
|
this.maxHeight = this.maxItem * (this.itemHeight+1) + 2;
|
|
|
|
this.max = this.length * (this.itemHeight+1) + 2;
|
|
this.ratio = this.maxHeight / this.max;
|
|
this.sh = this.maxHeight * this.ratio;
|
|
this.range = this.maxHeight - this.sh;
|
|
|
|
this.c[2].style.height = this.maxHeight + 'px';
|
|
this.scrollerBack.style.height = this.maxHeight + 'px';
|
|
this.scroller.style.height = this.sh + 'px';
|
|
|
|
if( this.max > this.maxHeight ){
|
|
this.ww = this.sb - this.ss;
|
|
this.scroll = true;
|
|
}
|
|
|
|
if( this.miniCanvas ) {
|
|
|
|
this.tmpCanvas = document.createElement('canvas');
|
|
this.tmpCanvas.width = this.imageSize[0];
|
|
this.tmpCanvas.height = this.imageSize[1];
|
|
this.tmpCtx = this.tmpCanvas.getContext("2d");
|
|
this.tmpCtx.fillStyle = this.canvasBg;
|
|
this.tmpCtx.fillRect(0, 0, this.imageSize[0], this.imageSize[1]);
|
|
|
|
}
|
|
|
|
let item, n;//, l = this.sb;
|
|
for( let i=0; i<this.length; i++ ){
|
|
|
|
n = this.list[i];
|
|
item = this.dom( 'div', this.css.item + 'width:'+this.ww+'px; height:'+this.itemHeight+'px; line-height:'+(this.itemHeight-5)+'px; color:'+this.colors.text+'; background:'+this.colors.back+';' );
|
|
item.name = 'item'+i;
|
|
item.id = i;
|
|
item.select = false;
|
|
item.posy = (this.itemHeight+1)*i;
|
|
this.listIn.appendChild( item );
|
|
this.items.push( item );
|
|
|
|
if( n === this.value ) this.current = item;
|
|
|
|
//if( this.isWithImage ) item.appendChild( this.tmpImage[n] );
|
|
if( !this.isWithImage ) item.textContent = n;
|
|
|
|
if( this.miniCanvas ){
|
|
|
|
let c = new Image();
|
|
c.src = this.tmpCanvas.toDataURL();
|
|
|
|
|
|
/*let c = document.createElement('canvas')
|
|
|
|
c.width = this.imageSize[0]
|
|
c.height = this.imageSize[1]
|
|
let ctx = c.getContext("2d")
|
|
ctx.fillStyle = this.canvasBg
|
|
ctx.fillRect(0, 0, this.imageSize[0], this.imageSize[1])*/
|
|
c.style.cssText = 'position:relative; pointer-events:none; display:inline-block; float:left; margin-left:0px; margin-right:5px; top:2px';
|
|
|
|
|
|
//c.style.cssText = 'display:flex; align-content: flex-start; flex-wrap: wrap;'
|
|
//item.style.float = 'right'
|
|
item.appendChild( c );
|
|
|
|
this.tmpImage[n] = c;
|
|
|
|
}
|
|
|
|
if(this.dragout){
|
|
|
|
item.img = this.tmpImage[n];
|
|
|
|
item.style.pointerEvents = 'auto';
|
|
item.draggable="true";
|
|
|
|
item.addEventListener('dragstart', this.dragstart || function(){ /*console.log('drag start')*/});
|
|
item.addEventListener('drag', this.drag || function(){ /*console.log('drag start')*/});
|
|
//item.addEventListener('dragover', this);
|
|
//item.addEventListener('dragenter', this);
|
|
item.addEventListener('dragleave', function(){ Roots.fakeUp(); } );
|
|
item.addEventListener('dragend', this.dragend || function(){ /*console.log('drag end')*/ }.bind(this) );
|
|
//item.addEventListener('drop', function(){console.log('drop')})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.setTopItem();
|
|
if( this.isSelectable ) this.selected();
|
|
|
|
}
|
|
|
|
drawImage( name, image, x,y,w,h ){
|
|
this.tmpCtx.clearRect(0, 0, this.imageSize[0], this.imageSize[1]);
|
|
this.tmpCtx.drawImage(image, x, y, w, h, 0, 0, this.imageSize[0], this.imageSize[1]);
|
|
this.tmpImage[name].src = this.tmpCanvas.toDataURL();
|
|
|
|
|
|
/*let c = this.tmpImage[name]
|
|
let ctx = c.getContext("2d")
|
|
ctx.drawImage(image, x, y, w, h, 0, 0, this.imageSize[0], this.imageSize[1])*/
|
|
|
|
}
|
|
|
|
addImages (){
|
|
let lng = this.list.length;
|
|
for( let i=0; i<lng; i++ ){
|
|
this.items[i].appendChild( this.tmpImage[this.list[i]] );
|
|
}
|
|
this.setTopItem();
|
|
}
|
|
|
|
setValue ( value ) {
|
|
|
|
if(!isNaN(value)) this.value = this.list[ value ];
|
|
else this.value = value;
|
|
|
|
this.setTopItem();
|
|
|
|
}
|
|
|
|
setTopItem (){
|
|
|
|
if(this.staticTop) return;
|
|
|
|
if( this.isWithImage ){
|
|
|
|
if( !this.preLoadComplete ) return;
|
|
|
|
if(!this.c[3].children.length){
|
|
this.canvas = document.createElement('canvas');
|
|
this.canvas.width = this.imageSize[0];
|
|
this.canvas.height = this.imageSize[1];
|
|
this.canvas.style.cssText = 'position:absolute; top:0px; left:0px;';
|
|
this.ctx = this.canvas.getContext("2d");
|
|
this.c[3].appendChild( this.canvas );
|
|
}
|
|
|
|
this.tmpImage[ this.value ];
|
|
this.ctx.drawImage( this.tmpImage[ this.value ], 0, 0, this.imageSize[2], this.imageSize[3], 0,0, this.imageSize[0], this.imageSize[1] );
|
|
|
|
}
|
|
else this.c[3].textContent = this.value;
|
|
|
|
|
|
if( this.miniCanvas ){
|
|
|
|
if(!this.c[3].children.length){
|
|
this.canvas = document.createElement('canvas');
|
|
this.canvas.width = this.imageSize[0];
|
|
this.canvas.height = this.imageSize[1];
|
|
( this.h - this.imageSize[1] ) * 0.5;
|
|
this.canvas.style.cssText = 'position:relative; pointer-events:none; display:inline-block; float:left; margin-left:0px; margin-right:5px; top:2px';
|
|
//this.canvas.style.cssText = 'position:absolute; top:'+h+'px; left:5px;'
|
|
this.ctx = this.canvas.getContext("2d");
|
|
this.c[3].style.textAlign = 'left';
|
|
this.c[3].appendChild( this.canvas );
|
|
|
|
}
|
|
|
|
this.ctx.drawImage( this.tmpImage[ this.value ], 0, 0 );
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// ----- LIST
|
|
|
|
update ( y ) {
|
|
|
|
if( !this.scroll ) return;
|
|
|
|
y = y < 0 ? 0 : y;
|
|
y = y > this.range ? this.range : y;
|
|
|
|
this.topList = -Math.floor( y / this.ratio );
|
|
|
|
this.listIn.style.top = this.topList+'px';
|
|
this.scroller.style.top = Math.floor( y ) + 'px';
|
|
|
|
this.py = y;
|
|
|
|
}
|
|
|
|
parentHeight ( t ) {
|
|
|
|
if ( this.group !== null ) this.group.calc( t );
|
|
else if ( this.isUI ) this.main.calc( t );
|
|
|
|
}
|
|
|
|
open ( first ) {
|
|
|
|
super.open();
|
|
|
|
this.update( 0 );
|
|
|
|
this.h = this.maxHeight + this.baseH + 5;
|
|
if( !this.scroll ){
|
|
this.topList = 0;
|
|
this.h = this.baseH + 5 + this.max;
|
|
this.scroller.style.display = 'none';
|
|
this.scrollerBack.style.display = 'none';
|
|
} else {
|
|
this.scroller.style.display = 'block';
|
|
this.scrollerBack.style.display = 'block';
|
|
}
|
|
this.s[0].height = this.h + 'px';
|
|
this.s[2].display = 'block';
|
|
|
|
if( this.up ){
|
|
this.zone.y -= this.h - (this.baseH-10);
|
|
this.setSvg( this.c[4], 'd', this.svgs.arrowUp );
|
|
} else {
|
|
this.setSvg( this.c[4], 'd', this.svgs.arrowDown );
|
|
}
|
|
|
|
this.rSizeContent();
|
|
|
|
let t = this.h - this.baseH;
|
|
|
|
this.zone.h = this.h;
|
|
|
|
if(!first) this.parentHeight( t );
|
|
|
|
}
|
|
|
|
close () {
|
|
|
|
super.close();
|
|
|
|
if( this.up ) this.zone.y += this.h - (this.baseH-10);
|
|
|
|
let t = this.h - this.baseH;
|
|
|
|
this.h = this.baseH;
|
|
this.s[0].height = this.h + 'px';
|
|
this.s[2].display = 'none';
|
|
this.setSvg( this.c[4], 'd', this.svgs.arrow );
|
|
|
|
this.zone.h = this.h;
|
|
|
|
this.parentHeight( -t );
|
|
|
|
}
|
|
|
|
// -----
|
|
|
|
text ( txt ) {
|
|
|
|
this.c[3].textContent = txt;
|
|
|
|
}
|
|
|
|
rSizeContent () {
|
|
|
|
let i = this.length;
|
|
while(i--) this.listIn.children[i].style.width = this.ww + 'px';
|
|
|
|
}
|
|
|
|
rSize () {
|
|
|
|
super.rSize();
|
|
|
|
//Proto.prototype.rSize.call( this );
|
|
|
|
let s = this.s;
|
|
let w = this.sb;
|
|
let d = this.sa;
|
|
|
|
if(s[2]=== undefined) return;
|
|
|
|
s[2].width = w + 'px';
|
|
s[2].left = d +'px';
|
|
|
|
s[3].width = w + 'px';
|
|
s[3].left = d + 'px';
|
|
|
|
s[4].left = d + w - 17 + 'px';
|
|
|
|
this.ww = w;
|
|
if( this.max > this.maxHeight ) this.ww = w-this.ss;
|
|
if(this.isOpen) this.rSizeContent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Numeric extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.setTypeNumber( o );
|
|
|
|
this.allway = o.allway || false;
|
|
|
|
this.isDown = false;
|
|
|
|
this.value = [0];
|
|
this.multy = 1;
|
|
this.invmulty = 1;
|
|
this.isSingle = true;
|
|
this.isAngle = false;
|
|
this.isVector = false;
|
|
|
|
if( o.isAngle ){
|
|
this.isAngle = true;
|
|
this.multy = Tools.torad;
|
|
this.invmulty = Tools.todeg;
|
|
}
|
|
|
|
this.isDrag = o.drag || false;
|
|
|
|
if( o.value !== undefined ){
|
|
if(!isNaN(o.value)){
|
|
this.value = [o.value];
|
|
} else if( o.value instanceof Array ){
|
|
this.value = o.value;
|
|
this.isSingle = false;
|
|
} else if( o.value instanceof Object ){
|
|
this.value = [];
|
|
if( o.value.x !== undefined ) this.value[0] = o.value.x;
|
|
if( o.value.y !== undefined ) this.value[1] = o.value.y;
|
|
if( o.value.z !== undefined ) this.value[2] = o.value.z;
|
|
if( o.value.w !== undefined ) this.value[3] = o.value.w;
|
|
this.isVector = true;
|
|
this.isSingle = false;
|
|
}
|
|
}
|
|
|
|
this.lng = this.value.length;
|
|
this.tmp = [];
|
|
|
|
|
|
|
|
this.current = -1;
|
|
this.prev = { x:0, y:0, d:0, v:0 };
|
|
|
|
let cc = this.colors;
|
|
|
|
// bg
|
|
this.c[2] = this.dom( 'div', this.css.basic + ' background:' + cc.select + '; top:4px; width:0px; height:' + (this.h-8) + 'px;' );
|
|
|
|
this.cMode = [];
|
|
|
|
let i = this.lng;
|
|
while(i--){
|
|
|
|
if(this.isAngle) this.value[i] = (this.value[i] * 180 / Math.PI).toFixed( this.precision );
|
|
this.c[3+i] = this.dom( 'div', this.css.txtselect + ' height:'+(this.h-4)+'px; color:' + cc.text + '; background:' + cc.back + '; borderColor:' + cc.border+'; border-radius:'+this.radius+'px;');
|
|
if(o.center) this.c[2+i].style.textAlign = 'center';
|
|
this.c[3+i].textContent = this.value[i];
|
|
this.c[3+i].style.color = this.colors.text;
|
|
this.c[3+i].isNum = true;
|
|
|
|
this.cMode[i] = 0;
|
|
|
|
}
|
|
|
|
// selection
|
|
this.selectId = 3 + this.lng;
|
|
this.c[this.selectId] = this.dom( 'div', this.css.txtselect + 'position:absolute; top:4px; height:' + (this.h-8) + 'px; padding:0px 0px; width:0px; color:' + cc.textSelect + '; background:' + cc.select + '; border:none; border-radius:0px;');
|
|
|
|
// cursor
|
|
this.cursorId = 4 + this.lng;
|
|
this.c[ this.cursorId ] = this.dom( 'div', this.css.basic + 'top:4px; height:' + (this.h-8) + 'px; width:0px; background:'+cc.text+';' );
|
|
|
|
this.init();
|
|
}
|
|
|
|
testZone ( e ) {
|
|
|
|
let l = this.local;
|
|
if( l.x === -1 && l.y === -1 ) return '';
|
|
|
|
let i = this.lng;
|
|
let t = this.tmp;
|
|
|
|
|
|
while( i-- ){
|
|
if( l.x>t[i][0] && l.x<t[i][2] ) return i;
|
|
}
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
/* mode: function ( n, name ) {
|
|
|
|
if( n === this.cMode[name] ) return false;
|
|
|
|
//let m;
|
|
|
|
/*switch(n){
|
|
|
|
case 0: m = this.colors.border; break;
|
|
case 1: m = this.colors.borderOver; break;
|
|
case 2: m = this.colors.borderSelect; break;
|
|
|
|
}*/
|
|
|
|
/* this.reset();
|
|
//this.c[name+2].style.borderColor = m;
|
|
this.cMode[name] = n;
|
|
|
|
return true;
|
|
|
|
},*/
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
mousedown ( e ) {
|
|
|
|
let name = this.testZone( e );
|
|
|
|
if( !this.isDown ){
|
|
this.isDown = true;
|
|
if( name !== '' ){
|
|
this.current = name;
|
|
this.prev = { x:e.clientX, y:e.clientY, d:0, v: this.isSingle ? parseFloat(this.value) : parseFloat( this.value[ this.current ] ) };
|
|
this.setInput( this.c[ 3 + this.current ] );
|
|
}
|
|
return this.mousemove( e );
|
|
}
|
|
|
|
return false;
|
|
/*
|
|
|
|
if( name === '' ) return false;
|
|
|
|
|
|
this.current = name;
|
|
this.isDown = true;
|
|
|
|
this.prev = { x:e.clientX, y:e.clientY, d:0, v: this.isSingle ? parseFloat(this.value) : parseFloat( this.value[ this.current ] ) };
|
|
|
|
|
|
return this.mode( 2, name );*/
|
|
|
|
}
|
|
|
|
mouseup ( e ) {
|
|
|
|
if( this.isDown ){
|
|
|
|
this.isDown = false;
|
|
//this.current = -1;
|
|
this.prev = { x:0, y:0, d:0, v:0 };
|
|
|
|
return this.mousemove( e );
|
|
}
|
|
|
|
return false;
|
|
|
|
/*let name = this.testZone( e );
|
|
this.isDown = false;
|
|
|
|
if( this.current !== -1 ){
|
|
|
|
//let tm = this.current;
|
|
let td = this.prev.d;
|
|
|
|
this.current = -1;
|
|
this.prev = { x:0, y:0, d:0, v:0 };
|
|
|
|
if( !td ){
|
|
|
|
this.setInput( this.c[ 3 + name ] );
|
|
return true;//this.mode( 2, name );
|
|
|
|
} else {
|
|
return this.reset();//this.mode( 0, tm );
|
|
}
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
mousemove ( e ) {
|
|
|
|
let nup = false;
|
|
let x = 0;
|
|
|
|
let name = this.testZone( e );
|
|
|
|
if( name === '' ) this.cursor();
|
|
else {
|
|
if(!this.isDrag) this.cursor('text');
|
|
else this.cursor( this.current !== -1 ? 'move' : 'pointer' );
|
|
}
|
|
|
|
|
|
|
|
if( this.isDrag ){
|
|
|
|
if( this.current !== -1 ){
|
|
|
|
this.prev.d += ( e.clientX - this.prev.x ) - ( e.clientY - this.prev.y );
|
|
|
|
let n = this.prev.v + ( this.prev.d * this.step);
|
|
|
|
this.value[ this.current ] = this.numValue(n);
|
|
this.c[ 3 + this.current ].textContent = this.value[this.current];
|
|
|
|
this.validate();
|
|
|
|
this.prev.x = e.clientX;
|
|
this.prev.y = e.clientY;
|
|
|
|
nup = true;
|
|
}
|
|
|
|
} else {
|
|
|
|
if( this.isDown ) x = e.clientX - this.zone.x -3;
|
|
if( this.current !== -1 ) x -= this.tmp[this.current][0];
|
|
return this.upInput( x, this.isDown );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nup;
|
|
|
|
}
|
|
|
|
//keydown: function ( e ) { return true; },
|
|
|
|
// ----------------------
|
|
|
|
reset () {
|
|
|
|
let nup = false;
|
|
//this.isDown = false;
|
|
|
|
//this.current = 0;
|
|
|
|
/* let i = this.lng;
|
|
while(i--){
|
|
if(this.cMode[i]!==0){
|
|
this.cMode[i] = 0;
|
|
//this.c[2+i].style.borderColor = this.colors.border;
|
|
nup = true;
|
|
}
|
|
}*/
|
|
|
|
return nup;
|
|
|
|
}
|
|
|
|
|
|
setValue ( v ) {
|
|
|
|
if( this.isVector ){
|
|
|
|
if( v.x !== undefined ) this.value[0] = v.x;
|
|
if( v.y !== undefined ) this.value[1] = v.y;
|
|
if( v.z !== undefined ) this.value[2] = v.z;
|
|
if( v.w !== undefined ) this.value[3] = v.w;
|
|
|
|
} else {
|
|
|
|
if( this.isSingle ) this.value = [v];
|
|
else this.value = v;
|
|
|
|
}
|
|
|
|
this.update();
|
|
|
|
}
|
|
|
|
sameStr ( str ){
|
|
|
|
let i = this.value.length;
|
|
while(i--) this.c[ 3 + i ].textContent = str;
|
|
|
|
}
|
|
|
|
update ( up ) {
|
|
|
|
let i = this.value.length;
|
|
|
|
while(i--){
|
|
this.value[i] = this.numValue( this.value[i] * this.invmulty );
|
|
this.c[ 3 + i ].textContent = this.value[i];
|
|
}
|
|
|
|
if( up ) this.send();
|
|
|
|
}
|
|
|
|
send ( v ) {
|
|
|
|
v = v || this.value;
|
|
|
|
this.isSend = true;
|
|
|
|
if( this.objectLink !== null ){
|
|
|
|
if( this.isVector ){
|
|
|
|
this.objectLink[ this.val ].fromArray( v );
|
|
|
|
/*this.objectLink[ this.val ].x = v[0];
|
|
this.objectLink[ this.val ].y = v[1];
|
|
this.objectLink[ this.val ].z = v[2];
|
|
if( v[3] ) this.objectLink[ this.val ].w = v[3];*/
|
|
|
|
} else {
|
|
this.objectLink[ this.val ] = v;
|
|
}
|
|
|
|
}
|
|
|
|
if( this.callback ) this.callback( v, this.val );
|
|
|
|
this.isSend = false;
|
|
|
|
}
|
|
|
|
|
|
// ----------------------
|
|
// INPUT
|
|
// ----------------------
|
|
|
|
select ( c, e, w, t ) {
|
|
|
|
let s = this.s;
|
|
let d = this.current !== -1 ? this.tmp[this.current][0] + 5 : 0;
|
|
s[this.cursorId].width = '1px';
|
|
s[this.cursorId].left = ( d + c ) + 'px';
|
|
//s[2].left = ( d + e ) + 'px';
|
|
//s[2].width = w + 'px';
|
|
|
|
s[this.selectId].left = ( d + e ) + 'px';
|
|
s[this.selectId].width = w + 'px';
|
|
this.c[this.selectId].innerHTML = t;
|
|
|
|
}
|
|
|
|
unselect () {
|
|
|
|
let s = this.s;
|
|
if(!s) return;
|
|
this.c[this.selectId].innerHTML = '';
|
|
s[this.selectId].width = 0 + 'px';
|
|
s[this.cursorId].width = 0 + 'px';
|
|
|
|
}
|
|
|
|
validate ( force ) {
|
|
|
|
let ar = [];
|
|
let i = this.lng;
|
|
|
|
if( this.allway ) force = true;
|
|
|
|
while(i--){
|
|
if(!isNaN( this.c[ 3 + i ].textContent )){
|
|
let nx = this.numValue( this.c[ 3 + i ].textContent );
|
|
this.c[ 3 + i ].textContent = nx;
|
|
this.value[i] = nx;
|
|
} else { // not number
|
|
this.c[ 3 + i ].textContent = this.value[i];
|
|
}
|
|
|
|
ar[i] = this.value[i] * this.multy;
|
|
}
|
|
|
|
if( !force ) return;
|
|
|
|
if( this.isSingle ) this.send( ar[0] );
|
|
else this.send( ar );
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// REZISE
|
|
// ----------------------
|
|
|
|
rSize () {
|
|
|
|
super.rSize();
|
|
|
|
let w = Math.floor( ( this.sb + 5 ) / this.lng )-5;
|
|
let s = this.s;
|
|
let i = this.lng;
|
|
while(i--){
|
|
this.tmp[i] = [ Math.floor( this.sa + ( w * i )+( 5 * i )), w ];
|
|
this.tmp[i][2] = this.tmp[i][0] + this.tmp[i][1];
|
|
s[ 3 + i ].left = this.tmp[i][0] + 'px';
|
|
s[ 3 + i ].width = this.tmp[i][1] + 'px';
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Slide extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.setTypeNumber( o );
|
|
|
|
|
|
this.model = o.stype || 0;
|
|
if( o.mode !== undefined ) this.model = o.mode;
|
|
|
|
//this.defaultBorderColor = this.colors.hide;
|
|
|
|
this.isDown = false;
|
|
this.isOver = false;
|
|
this.allway = o.allway || false;
|
|
|
|
this.isDeg = o.isDeg || false;
|
|
this.isCyclic = o.cyclic || false;
|
|
|
|
this.firstImput = false;
|
|
|
|
let cc = this.colors;
|
|
|
|
//this.c[2] = this.dom( 'div', this.css.txtselect + 'letter-spacing:-1px; text-align:right; width:47px; border:1px dashed '+this.defaultBorderColor+'; color:'+ this.colors.text );
|
|
//this.c[2] = this.dom( 'div', this.css.txtselect + 'text-align:right; width:47px; border:1px dashed '+this.defaultBorderColor+'; color:'+ this.colors.text );
|
|
this.c[2] = this.dom( 'div', this.css.txtselect + 'border:none; background:none; width:47px; color:'+ cc.text +';' );
|
|
//this.c[2] = this.dom( 'div', this.css.txtselect + 'letter-spacing:-1px; text-align:right; width:47px; color:'+ this.colors.text );
|
|
this.c[3] = this.dom( 'div', this.css.basic + ' top:0; height:'+this.h+'px;' );
|
|
this.c[4] = this.dom( 'div', this.css.basic + 'background:'+cc.back+'; top:2px; height:'+(this.h-4)+'px;' );
|
|
this.c[5] = this.dom( 'div', this.css.basic + 'left:4px; top:5px; height:'+(this.h-10)+'px; background:' + cc.text +';' );
|
|
|
|
this.c[2].isNum = true;
|
|
//this.c[2].style.height = (this.h-4) + 'px';
|
|
//this.c[2].style.lineHeight = (this.h-8) + 'px';
|
|
this.c[2].style.height = (this.h-2) + 'px';
|
|
this.c[2].style.lineHeight = (this.h-10) + 'px';
|
|
|
|
if(this.model !== 0){
|
|
|
|
let h1 = 4, h2 = 8, ww = this.h-4, ra = 20;
|
|
|
|
if( this.model === 2 ){
|
|
h1 = 4;//2
|
|
h2 = 8;
|
|
ra = 2;
|
|
ww = (this.h-4)*0.5;
|
|
}
|
|
|
|
if(this.model === 3) this.c[5].style.visible = 'none';
|
|
|
|
this.c[4].style.borderRadius = h1 + 'px';
|
|
this.c[4].style.height = h2 + 'px';
|
|
this.c[4].style.top = (this.h*0.5) - h1 + 'px';
|
|
this.c[5].style.borderRadius = (h1*0.5) + 'px';
|
|
this.c[5].style.height = h1 + 'px';
|
|
this.c[5].style.top = (this.h*0.5)-(h1*0.5) + 'px';
|
|
|
|
this.c[6] = this.dom( 'div', this.css.basic + 'border-radius:'+ra+'px; margin-left:'+(-ww*0.5)+'px; border:1px solid '+cc.border+'; background:'+cc.button+'; left:4px; top:2px; height:'+(this.h-4)+'px; width:'+ww+'px;' );
|
|
}
|
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
testZone ( e ) {
|
|
|
|
let l = this.local;
|
|
if( l.x === -1 && l.y === -1 ) return '';
|
|
|
|
if( l.x >= this.txl ) return 'text';
|
|
else if( l.x >= this.sa ) return 'scroll';
|
|
else return '';
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
mouseup ( e ) {
|
|
|
|
if( this.isDown ) this.isDown = false;
|
|
|
|
}
|
|
|
|
mousedown ( e ) {
|
|
|
|
let name = this.testZone( e );
|
|
|
|
if( !name ) return false;
|
|
|
|
if( name === 'scroll' ){
|
|
this.isDown = true;
|
|
this.old = this.value;
|
|
this.mousemove( e );
|
|
|
|
}
|
|
|
|
/*if( name === 'text' ){
|
|
this.setInput( this.c[2], function(){ this.validate() }.bind(this) );
|
|
}*/
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
mousemove ( e ) {
|
|
|
|
let nup = false;
|
|
|
|
let name = this.testZone( e );
|
|
|
|
if( name === 'scroll' ) {
|
|
this.mode(1);
|
|
this.cursor('w-resize');
|
|
//} else if(name === 'text'){
|
|
//this.cursor('pointer');
|
|
} else {
|
|
this.cursor();
|
|
}
|
|
|
|
if( this.isDown ){
|
|
|
|
let n = ((( e.clientX - (this.zone.x+this.sa) - 3 ) / this.ww ) * this.range + this.min ) - this.old;
|
|
if(n >= this.step || n <= this.step){
|
|
n = Math.floor( n / this.step );
|
|
this.value = this.numValue( this.old + ( n * this.step ) );
|
|
this.update( true );
|
|
this.old = this.value;
|
|
}
|
|
nup = true;
|
|
}
|
|
|
|
return nup;
|
|
|
|
}
|
|
|
|
wheel ( e ) {
|
|
|
|
let name = this.testZone( e );
|
|
|
|
if( name === 'scroll' ) {
|
|
|
|
let v = this.value - this.step * e.delta;
|
|
|
|
if ( v > this.max ) {
|
|
v = this.isCyclic ? this.min : this.max;
|
|
} else if ( v < this.min ) {
|
|
v = this.isCyclic ? this.max : this.min;
|
|
}
|
|
|
|
this.setValue(v);
|
|
this.old = v;
|
|
this.update( true );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
//keydown: function ( e ) { return true; },
|
|
|
|
// ----------------------
|
|
|
|
validate () {
|
|
|
|
let n = this.c[2].textContent;
|
|
|
|
if(!isNaN( n )){
|
|
this.value = this.numValue( n );
|
|
this.update(true);
|
|
}
|
|
|
|
else this.c[2].textContent = this.value + (this.isDeg ? '°':'');
|
|
|
|
}
|
|
|
|
|
|
reset () {
|
|
|
|
//this.clearInput();
|
|
this.isDown = false;
|
|
this.mode(0);
|
|
|
|
}
|
|
|
|
mode ( mode ) {
|
|
|
|
let s = this.s;
|
|
let cc = this.colors;
|
|
|
|
switch(mode){
|
|
case 0: // base
|
|
// s[2].border = '1px solid ' + this.colors.hide;
|
|
s[2].color = cc.text;
|
|
s[4].background = cc.back;
|
|
s[5].background = cc.text;
|
|
break;
|
|
case 1: // scroll over
|
|
//s[2].border = '1px dashed ' + this.colors.hide;
|
|
s[2].color = cc.textOver;
|
|
s[4].background = cc.back;
|
|
s[5].background = cc.textOver;
|
|
break;
|
|
/* case 2:
|
|
s[2].border = '1px solid ' + this.colors.borderSelect;
|
|
break;
|
|
case 3:
|
|
s[2].border = '1px dashed ' + this.colors.text;//this.colors.borderSelect;
|
|
break;
|
|
case 4:
|
|
s[2].border = '1px dashed ' + this.colors.hide;
|
|
break;*/
|
|
|
|
|
|
}
|
|
}
|
|
|
|
update ( up ) {
|
|
|
|
let ww = Math.floor( this.ww * (( this.value - this.min ) / this.range ));
|
|
|
|
if(this.model !== 3) this.s[5].width = ww + 'px';
|
|
if(this.s[6]) this.s[6].left = ( this.sa + ww + 3 ) + 'px';
|
|
this.c[2].textContent = this.value + (this.isDeg ? '°':'');
|
|
|
|
if( up ) this.send();
|
|
|
|
}
|
|
|
|
rSize () {
|
|
|
|
super.rSize();
|
|
|
|
let w = this.sb - this.sc;
|
|
this.ww = w - 6;
|
|
|
|
let tx = this.sc;
|
|
if(this.isUI || !this.simple) tx = this.sc+10;
|
|
this.txl = this.w - tx + 2;
|
|
|
|
//let ty = Math.floor(this.h * 0.5) - 8;
|
|
|
|
let s = this.s;
|
|
|
|
s[2].width = (this.sc -6 )+ 'px';
|
|
s[2].left = (this.txl +4) + 'px';
|
|
//s[2].top = ty + 'px';
|
|
s[3].left = this.sa + 'px';
|
|
s[3].width = w + 'px';
|
|
s[4].left = this.sa + 'px';
|
|
s[4].width = w + 'px';
|
|
s[5].left = (this.sa + 3) + 'px';
|
|
|
|
this.update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class TextInput extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.cmode = 0;
|
|
|
|
this.value = o.value || '';
|
|
this.placeHolder = o.placeHolder || '';
|
|
|
|
this.allway = o.allway || false;
|
|
this.editable = o.edit !== undefined ? o.edit : true;
|
|
|
|
this.isDown = false;
|
|
|
|
let cc = this.colors;
|
|
|
|
// text
|
|
this.c[2] = this.dom( 'div', this.css.txtselect + 'height:' + (this.h-4) + 'px; color:' + cc.text + '; background:' + cc.back + '; borderColor:' + cc.border+'; border-radius:'+this.radius+'px;' );
|
|
this.c[2].textContent = this.value;
|
|
|
|
// selection
|
|
this.c[3] = this.dom( 'div', this.css.txtselect + 'position:absolute; top:4px; height:' + (this.h-8) + 'px; padding:0px 0px; width:0px; color:' + cc.textSelect + '; background:' + cc.select + '; border:none; border-radius:0px;');
|
|
|
|
// cursor
|
|
this.c[4] = this.dom( 'div', this.css.basic + 'top:4px; height:' + (this.h-8) + 'px; width:0px; background:'+cc.text+';' );
|
|
|
|
// fake
|
|
this.c[5] = this.dom( 'div', this.css.txtselect + 'height:' + (this.h-4) + 'px; justify-content: center; font-style: italic; color:'+cc.border+';' );
|
|
if( this.value === '' ) this.c[5].textContent = this.placeHolder;
|
|
|
|
|
|
|
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
testZone ( e ) {
|
|
|
|
let l = this.local;
|
|
if( l.x === -1 && l.y === -1 ) return '';
|
|
if( l.x >= this.sa ) return 'text';
|
|
return '';
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
mouseup ( e ) {
|
|
|
|
if(!this.editable) return;
|
|
|
|
if( this.isDown ){
|
|
this.isDown = false;
|
|
return this.mousemove( e );
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
mousedown ( e ) {
|
|
|
|
if(!this.editable) return;
|
|
|
|
let name = this.testZone( e );
|
|
|
|
if( !this.isDown ){
|
|
this.isDown = true;
|
|
if( name === 'text' ) this.setInput( this.c[2] );
|
|
return this.mousemove( e );
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
mousemove ( e ) {
|
|
|
|
if(!this.editable) return;
|
|
|
|
let name = this.testZone( e );
|
|
|
|
//let l = this.local;
|
|
//if( l.x === -1 && l.y === -1 ){ return;}
|
|
|
|
//if( l.x >= this.sa ) this.cursor('text');
|
|
//else this.cursor();
|
|
|
|
let x = 0;
|
|
|
|
if( name === 'text' ) this.cursor('text');
|
|
else this.cursor();
|
|
|
|
if( this.isDown ) x = e.clientX - this.zone.x;
|
|
|
|
return this.upInput( x - this.sa -3, this.isDown );
|
|
|
|
}
|
|
|
|
update ( ) {
|
|
|
|
this.c[2].textContent = this.value;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
|
|
reset () {
|
|
|
|
this.cursor();
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// INPUT
|
|
// ----------------------
|
|
|
|
select ( c, e, w, t ) {
|
|
|
|
let s = this.s;
|
|
let d = this.sa + 5;
|
|
s[4].width = '1px';
|
|
s[4].left = ( d + e ) + 'px';
|
|
|
|
s[3].left = ( d + e ) + 'px';
|
|
s[3].width = w + 'px';
|
|
this.c[3].innerHTML = t;
|
|
|
|
}
|
|
|
|
unselect () {
|
|
|
|
let s = this.s;
|
|
if(!s) return;
|
|
s[3].width = 0 + 'px';
|
|
this.c[3].innerHTML = 't';
|
|
s[4].width = 0 + 'px';
|
|
|
|
}
|
|
|
|
validate ( force ) {
|
|
|
|
if( this.allway ) force = true;
|
|
|
|
this.value = this.c[2].textContent;
|
|
|
|
if(this.value !== '') this.c[5].textContent = '';
|
|
else this.c[5].textContent = this.placeHolder;
|
|
|
|
if( !force ) return;
|
|
|
|
this.send();
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// REZISE
|
|
// ----------------------
|
|
|
|
rSize () {
|
|
|
|
super.rSize();
|
|
|
|
let s = this.s;
|
|
s[2].left = this.sa + 'px';
|
|
s[2].width = this.sb + 'px';
|
|
|
|
s[5].left = this.sa + 'px';
|
|
s[5].width = this.sb + 'px';
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
class Title extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
let prefix = o.prefix || '';
|
|
|
|
this.c[2] = this.dom( 'div', this.css.txt + 'justify-content:right; width:60px; line-height:'+ (this.h-8) + 'px; color:' + this.colors.text );
|
|
|
|
if( this.h === 31 ){
|
|
|
|
this.s[0].height = this.h + 'px';
|
|
this.s[1].top = 8 + 'px';
|
|
this.c[2].style.top = 8 + 'px';
|
|
|
|
}
|
|
|
|
let s = this.s;
|
|
|
|
s[1].justifyContent = o.align || 'left';
|
|
//s[1].textAlign = o.align || 'left';
|
|
s[1].fontWeight = o.fontWeight || 'bold';
|
|
|
|
|
|
this.c[1].textContent = this.txt.substring(0,1).toUpperCase() + this.txt.substring(1).replace("-", " ");
|
|
this.c[2].textContent = prefix;
|
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
text( txt ) {
|
|
|
|
this.c[1].textContent = txt;
|
|
|
|
}
|
|
|
|
text2( txt ) {
|
|
|
|
this.c[2].textContent = txt;
|
|
|
|
}
|
|
|
|
rSize() {
|
|
|
|
super.rSize();
|
|
this.s[1].width = this.w + 'px'; //- 50 + 'px';
|
|
this.s[2].left = this.w + 'px';//- ( 50 + 26 ) + 'px';
|
|
|
|
}
|
|
|
|
setColor( c ) {
|
|
this.s[1].color = c;
|
|
this.s[2].color = c;
|
|
}
|
|
|
|
}
|
|
|
|
class Select extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.value = o.value || '';
|
|
|
|
this.isDown = false;
|
|
|
|
this.onActif = o.onActif || function(){};
|
|
|
|
o.prefix || '';
|
|
|
|
this.c[2] = this.dom( 'div', this.css.txt + this.css.button + ' top:1px; background:'+this.colors.button+'; height:'+(this.h-2)+'px; border:'+this.colors.buttonBorder+'; border-radius:15px; width:30px; left:10px;' );
|
|
this.c[2].style.color = this.fontColor;
|
|
|
|
this.c[3] = this.dom( 'div', this.css.txtselect + 'height:' + (this.h-4) + 'px; background:' + this.colors.inputBg + '; borderColor:' + this.colors.inputBorder+'; border-radius:'+this.radius+'px;' );
|
|
this.c[3].textContent = this.value;
|
|
|
|
let fltop = Math.floor(this.h*0.5)-7;
|
|
this.c[4] = this.dom( 'path', this.css.basic + 'position:absolute; width:14px; height:14px; left:5px; top:'+fltop+'px;', { d:this.svgs[ 'cursor' ], fill:this.fontColor, stroke:'none'});
|
|
|
|
this.stat = 1;
|
|
this.isActif = false;
|
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
testZone ( e ) {
|
|
|
|
let l = this.local;
|
|
if( l.x === -1 && l.y === -1 ) return '';
|
|
if( l.x > this.sa && l.x < this.sa+30 ) return 'over';
|
|
return '0'
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
mouseup ( e ) {
|
|
|
|
if( this.isDown ){
|
|
//this.value = false;
|
|
this.isDown = false;
|
|
//this.send();
|
|
return this.mousemove( e );
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
mousedown ( e ) {
|
|
|
|
let name = this.testZone( e );
|
|
|
|
if( !name ) return false;
|
|
|
|
this.isDown = true;
|
|
//this.value = this.values[ name-2 ];
|
|
//this.send();
|
|
return this.mousemove( e );
|
|
|
|
}
|
|
|
|
mousemove ( e ) {
|
|
|
|
let up = false;
|
|
|
|
let name = this.testZone( e );
|
|
//let sel = false;
|
|
|
|
|
|
|
|
//console.log(name)
|
|
|
|
if( name === 'over' ){
|
|
this.cursor('pointer');
|
|
up = this.mode( this.isDown ? 3 : 2 );
|
|
} else {
|
|
up = this.reset();
|
|
}
|
|
|
|
return up;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
|
|
apply ( v ) {
|
|
|
|
v = v || '';
|
|
|
|
if( v !== this.value ) {
|
|
this.value = v;
|
|
this.c[3].textContent = this.value;
|
|
this.send();
|
|
}
|
|
|
|
this.mode(1);
|
|
|
|
}
|
|
|
|
update () {
|
|
|
|
this.mode( 3 );
|
|
|
|
}
|
|
|
|
mode ( n ) {
|
|
|
|
let change = false;
|
|
let cc = this.colors;
|
|
|
|
if( this.stat !== n ){
|
|
|
|
if( n===1 ) this.isActif = false;
|
|
if( n===3 ){
|
|
if( !this.isActif ){ this.isActif = true; n=4; this.onActif( this ); }
|
|
else { this.isActif = false; }
|
|
}
|
|
|
|
if( n===2 && this.isActif ) n = 4;
|
|
|
|
this.stat = n;
|
|
|
|
switch( n ){
|
|
|
|
case 1: this.s[ 2 ].color = cc.text; this.s[ 2 ].background = cc.button; break; // base
|
|
case 2: this.s[ 2 ].color = cc.textOver; this.s[ 2 ].background = cc.over; break; // over
|
|
case 3: this.s[ 2 ].color = cc.textSelect; this.s[ 2 ].background = cc.select; break; // down
|
|
case 4: this.s[ 2 ].color = cc.textSelect; this.s[ 2 ].background = cc.action; break; // actif
|
|
|
|
}
|
|
|
|
change = true;
|
|
|
|
}
|
|
|
|
return change;
|
|
|
|
|
|
|
|
}
|
|
|
|
reset () {
|
|
|
|
this.cursor();
|
|
return this.mode( this.isActif ? 4 : 1 );
|
|
|
|
}
|
|
|
|
text ( txt ) {
|
|
|
|
this.c[3].textContent = txt;
|
|
|
|
}
|
|
|
|
rSize () {
|
|
|
|
super.rSize();
|
|
|
|
let s = this.s;
|
|
s[2].left = this.sa + 'px';
|
|
s[3].left = (this.sa + 40) + 'px';
|
|
s[3].width = (this.sb - 40) + 'px';
|
|
s[4].left = (this.sa+8) + 'px';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//import { Proto } from '../core/Proto.js';
|
|
|
|
class Selector extends Button {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
if( o.selectable === undefined ) o.selectable = true;
|
|
super( o );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Empty extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
o.isSpace = true;
|
|
o.margin = 0;
|
|
if(!o.h) o.h = 10;
|
|
super( o );
|
|
this.init();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Item extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.p = 100;
|
|
this.value = this.txt;
|
|
this.status = 1;
|
|
|
|
this.itype = o.itype || 'none';
|
|
this.val = this.itype;
|
|
|
|
this.graph = this.svgs[ this.itype ];
|
|
|
|
let fltop = Math.floor(this.h*0.5)-7;
|
|
|
|
this.c[2] = this.dom( 'path', this.css.basic + 'position:absolute; width:14px; height:14px; left:5px; top:'+fltop+'px;', { d:this.graph, fill:this.colors.text, stroke:'none'});
|
|
|
|
this.s[1].marginLeft = 20 + 'px';
|
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
mousemove ( e ) {
|
|
|
|
this.cursor('pointer');
|
|
|
|
//up = this.modes( this.isDown ? 3 : 2, name );
|
|
|
|
}
|
|
|
|
mousedown ( e ) {
|
|
|
|
if( this.isUI ) this.main.resetItem();
|
|
|
|
this.selected( true );
|
|
|
|
this.send();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
uiout () {
|
|
|
|
if( this.isSelect ) this.mode(3);
|
|
else this.mode(1);
|
|
|
|
}
|
|
|
|
uiover () {
|
|
|
|
if( this.isSelect ) this.mode(4);
|
|
else this.mode(2);
|
|
|
|
}
|
|
|
|
update () {
|
|
|
|
}
|
|
|
|
/*rSize () {
|
|
|
|
super.rSize();
|
|
|
|
}*/
|
|
|
|
mode ( n ) {
|
|
|
|
let change = false;
|
|
|
|
if( this.status !== n ){
|
|
|
|
this.status = n;
|
|
let s = this.s, cc = this.colors;
|
|
|
|
switch( n ){
|
|
|
|
case 1: this.status = 1; s[1].color = cc.text; s[0].background = 'none'; break;
|
|
case 2: this.status = 2; s[1].color = cc.textOver; s[0].background = cc.back; break;
|
|
case 3: this.status = 3; s[1].color = cc.textSelect; s[0].background = cc.select; break;
|
|
case 4: this.status = 4; s[1].color = cc.textOver; s[0].background = cc.over; break;
|
|
|
|
}
|
|
|
|
change = true;
|
|
|
|
}
|
|
|
|
return change;
|
|
|
|
}
|
|
|
|
reset () {
|
|
|
|
this.cursor();
|
|
// return this.mode( 1 );
|
|
|
|
}
|
|
|
|
selected ( b ){
|
|
|
|
if( this.isSelect ) this.mode(1);
|
|
|
|
this.isSelect = b || false;
|
|
|
|
if( this.isSelect ) this.mode(3);
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
class Grid extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.values = o.values || [];
|
|
|
|
if( typeof this.values === 'string' ) this.values = [ this.values ];
|
|
this.lng = this.values.length;
|
|
|
|
this.value = o.value || null;
|
|
|
|
|
|
this.isSelectable = o.selectable || false;
|
|
this.spaces = o.spaces || [5,3];
|
|
this.bsize = o.bsize || [90,20];
|
|
|
|
if(o.h) this.bsize[1] = o.h;
|
|
this.bsizeMax = this.bsize[0];
|
|
|
|
|
|
this.tmp = [];
|
|
this.stat = [];
|
|
this.grid = [ 2, Math.round( this.lng * 0.5 ) ];
|
|
this.h = this.grid[1] * ( this.bsize[1] + this.spaces[1] ) + this.spaces[1];
|
|
|
|
this.c[1].textContent = '';
|
|
this.c[2] = this.dom( 'table', this.css.basic + 'width:100%; top:'+(this.spaces[1]-2)+'px; height:auto; border-collapse:separate; border:none; border-spacing: '+(this.spaces[0]-2)+'px '+(this.spaces[1]-2)+'px;' );
|
|
|
|
let n = 0, b, td, tr, sel;
|
|
|
|
this.res = -1;
|
|
this.isDown = false;
|
|
this.neverlock = true;
|
|
|
|
this.buttons = [];
|
|
this.stat = [];
|
|
this.tmpX = [];
|
|
this.tmpY = [];
|
|
|
|
let cc = this.colors;
|
|
|
|
for( let i = 0; i < this.grid[1]; i++ ){
|
|
|
|
tr = this.c[2].insertRow();
|
|
tr.style.cssText = 'pointer-events:none;';
|
|
for( let j = 0; j < this.grid[0]; j++ ){
|
|
|
|
td = tr.insertCell();
|
|
td.style.cssText = 'pointer-events:none;';
|
|
|
|
if( this.values[n] ){
|
|
|
|
sel = false;
|
|
if( this.values[n] === this.value && this.isSelectable ) sel = true;
|
|
|
|
b = document.createElement( 'div' );
|
|
b.style.cssText = this.css.txt + this.css.button + 'position:static; width:'+this.bsize[0]+'px; height:'+this.bsize[1]+'px; border:'+cc.borderSize+'px solid '+cc.border+'; left:auto; right:auto; border-radius:'+this.radius+'px;';
|
|
b.style.background = sel ? cc.select : cc.button;
|
|
b.style.color = sel ? cc.textSelect : cc.text;
|
|
b.innerHTML = this.values[n];
|
|
td.appendChild( b );
|
|
|
|
this.buttons.push(b);
|
|
this.stat.push(1);
|
|
|
|
} else {
|
|
|
|
b = document.createElement( 'div' );
|
|
b.style.cssText = this.css.txt + 'position:static; width:'+this.bsize[0]+'px; height:'+this.bsize[1]+'px; text-align:center; left:auto; right:auto; background:none;';
|
|
td.appendChild( b );
|
|
|
|
}
|
|
|
|
if(j===0) b.style.cssText += 'float:right;';
|
|
else b.style.cssText += 'float:left;';
|
|
|
|
n++;
|
|
|
|
}
|
|
}
|
|
|
|
this.init();
|
|
|
|
}
|
|
|
|
testZone ( e ) {
|
|
|
|
let l = this.local;
|
|
if( l.x === -1 && l.y === -1 ) return -1;
|
|
|
|
let tx = this.tmpX;
|
|
let ty = this.tmpY;
|
|
|
|
let id = -1;
|
|
let c = -1;
|
|
let line = -1;
|
|
let i = this.grid[0];
|
|
while( i-- ){
|
|
if( l.x > tx[i][0] && l.x < tx[i][1] ) c = i;
|
|
}
|
|
|
|
i = this.grid[1];
|
|
while( i-- ){
|
|
if( l.y > ty[i][0] && l.y < ty[i][1] ) line = i;
|
|
}
|
|
|
|
if(c!==-1 && line!==-1){
|
|
id = c + (line*2);
|
|
if(id>this.lng-1) id = -1;
|
|
}
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
mouseup ( e ) {
|
|
|
|
if( !this.isDown ) return false
|
|
|
|
this.isDown = false;
|
|
if( this.res !== -1 ){
|
|
this.value = this.values[this.res];
|
|
this.send();
|
|
}
|
|
|
|
return this.mousemove( e )
|
|
|
|
}
|
|
|
|
mousedown ( e ) {
|
|
|
|
if( this.isDown ) return false
|
|
this.isDown = true;
|
|
return this.mousemove( e )
|
|
|
|
}
|
|
|
|
mousemove ( e ) {
|
|
|
|
let up = false;
|
|
this.res = this.testZone( e );
|
|
|
|
if( this.res !== -1 ){
|
|
this.cursor('pointer');
|
|
up = this.modes( this.isDown ? 3 : 2, this.res );
|
|
} else {
|
|
up = this.reset();
|
|
}
|
|
|
|
return up;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// MODE
|
|
// -----------------------
|
|
|
|
modes ( N = 1, id = -1 ) {
|
|
|
|
let i = this.lng, w, n, r = false;
|
|
|
|
while( i-- ){
|
|
|
|
n = N;
|
|
w = this.isSelectable ? this.values[ i ] === this.value : false;
|
|
|
|
if( i === id ){
|
|
if( w && n === 2 ) n = 3;
|
|
} else {
|
|
n = 1;
|
|
if( w ) n = 4;
|
|
}
|
|
|
|
if( this.mode( n, i ) ) r = true;
|
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
mode ( n, id ) {
|
|
|
|
let change = false;
|
|
let cc = this.colors, s = this.buttons;
|
|
let i = id;
|
|
|
|
if( this.stat[id] !== n ){
|
|
|
|
this.stat[id] = n;
|
|
|
|
switch( n ){
|
|
|
|
case 1: s[i].style.color = cc.text; s[i].style.background = cc.button; break;
|
|
case 2: s[i].style.color = cc.textOver; s[i].style.background = cc.overoff; break;
|
|
case 3: s[i].style.color = cc.textOver; s[i].style.background = cc.over; break;
|
|
case 4: s[i].style.color = cc.textSelect; s[i].style.background = cc.select; break;
|
|
|
|
}
|
|
|
|
change = true;
|
|
|
|
}
|
|
|
|
return change;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
|
|
reset () {
|
|
|
|
this.res = -1;
|
|
this.cursor();
|
|
return this.modes()
|
|
|
|
}
|
|
|
|
|
|
label ( string, n ) {
|
|
|
|
this.buttons[n].textContent = string;
|
|
|
|
}
|
|
|
|
icon ( string, y, n ) {
|
|
|
|
this.buttons[n].style.padding = ( y || 0 ) +'px 0px';
|
|
this.buttons[n].innerHTML = string;
|
|
|
|
}
|
|
|
|
testW () {
|
|
|
|
let vw = this.spaces[0]*3 + this.bsizeMax*2, rz = false;
|
|
if( vw > this.w ) {
|
|
this.bsize[0] = ( this.w-(this.spaces[0]*3) ) * 0.5;
|
|
rz = true;
|
|
} else {
|
|
if( this.bsize[0] !== this.bsizeMax ) {
|
|
this.bsize[0] = this.bsizeMax;
|
|
rz = true;
|
|
}
|
|
}
|
|
|
|
if( !rz ) return;
|
|
|
|
let i = this.buttons.length;
|
|
while(i--) this.buttons[i].style.width = this.bsize[0] + 'px';
|
|
|
|
}
|
|
|
|
rSize () {
|
|
|
|
super.rSize();
|
|
|
|
this.testW();
|
|
|
|
let mid;
|
|
|
|
this.tmpX = [];
|
|
this.tmpY = [];
|
|
|
|
for( let j = 0; j < this.grid[0]; j++ ){
|
|
|
|
if(j===0){
|
|
mid = ( this.w*0.5 ) - ( this.spaces[0]*0.5 );
|
|
this.tmpX.push( [ mid-this.bsize[0], mid ] );
|
|
} else {
|
|
mid = ( this.w*0.5 ) + ( this.spaces[0]*0.5 );
|
|
this.tmpX.push( [ mid, mid+this.bsize[0] ] );
|
|
}
|
|
|
|
}
|
|
|
|
mid = this.spaces[1];
|
|
|
|
for( let i = 0; i < this.grid[1]; i++ ){
|
|
|
|
this.tmpY.push( [ mid, mid + this.bsize[1] ] );
|
|
mid += this.bsize[1] + this.spaces[1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class Pad2D extends Proto {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
super( o );
|
|
|
|
this.autoWidth = false;
|
|
this.minw = this.w;
|
|
this.diam = o.diam || this.w;
|
|
|
|
//this.margin = 15;
|
|
this.pos = new V2(0,0);
|
|
this.maxPos = 90;
|
|
|
|
this.model = o.stype || 0;
|
|
if( o.mode !== undefined ) this.model = o.mode;
|
|
|
|
this.min = o.min === undefined ? -1 : o.min;
|
|
this.max = o.max === undefined ? 1 : o.max;
|
|
|
|
this.range = (this.max - this.min)*0.5;
|
|
|
|
this.cmode = 0;
|
|
|
|
|
|
//console.log(this.range)
|
|
|
|
|
|
|
|
|
|
|
|
this.precision = o.precision === undefined ? 2 : o.precision;
|
|
|
|
/*this.bounds = {};
|
|
this.bounds.x1 = o.x1 || -1;
|
|
this.bounds.x2 = o.x2 || 1;
|
|
this.bounds.y1 = o.y1 || -1;
|
|
this.bounds.y2 = o.y2 || 1;
|
|
|
|
this.lerpX = this.lerp( this.margin, this.w - this.margin , this.bounds.x1, this.bounds.x2 );
|
|
this.lerpY = this.lerp( this.margin, this.w - this.margin , this.bounds.y1, this.bounds.y2 );
|
|
|
|
this.alerpX = this.lerp( this.bounds.x1, this.bounds.x2, this.margin, this.w - this.margin );
|
|
this.alerpY = this.lerp( this.bounds.y1, this.bounds.y2, this.margin, this.w - this.margin );*/
|
|
|
|
this.value = ( Array.isArray( o.value ) && o.value.length == 2 ) ? o.value : [ 0, 0 ];
|
|
|
|
|
|
this.h = o.h || this.w + 10;
|
|
this.top = 0;
|
|
|
|
this.c[0].style.width = this.w + 'px';
|
|
|
|
// Title
|
|
if( this.c[1] !== undefined ) { // with title
|
|
|
|
this.c[1].style.width = '100%';
|
|
this.c[1].style.justifyContent = 'center';
|
|
this.top = 10;
|
|
this.h += 10;
|
|
|
|
}
|
|
|
|
let cc = this.colors;
|
|
|
|
|
|
// Value
|
|
this.c[2] = this.dom( 'div', this.css.txt + 'justify-content:center; top:'+ ( this.h - 20 ) + 'px; width:100%; color:' + cc.text );
|
|
this.c[2].textContent = this.value;
|
|
|
|
// Pad
|
|
|
|
let pad = this.getPad2d();
|
|
|
|
this.setSvg( pad, 'fill', cc.back, 0 );
|
|
this.setSvg( pad, 'fill', cc.button, 1 );
|
|
this.setSvg( pad, 'stroke', cc.back, 2 );
|
|
this.setSvg( pad, 'stroke', cc.back, 3 );
|
|
this.setSvg( pad, 'stroke', cc.text, 4 );
|
|
|
|
this.setSvg( pad, 'viewBox', '0 0 '+this.diam+' '+this.diam );
|
|
this.setCss( pad, { width:this.diam, height:this.diam, left:0, top:this.top });
|
|
|
|
this.c[3] = pad;
|
|
|
|
this.init();
|
|
this.setValue();
|
|
|
|
}
|
|
|
|
testZone ( e ) {
|
|
|
|
let l = this.local;
|
|
|
|
if( l.x === -1 && l.y === -1 ) return '';
|
|
|
|
if( l.y <= this.c[ 1 ].offsetHeight ) return 'title';
|
|
else if ( l.y > this.h - this.c[ 2 ].offsetHeight ) return 'text';
|
|
else return 'pad';
|
|
|
|
/*if( ( l.x >= this.margin ) && ( l.x <= this.w - this.margin ) && ( l.y >= this.top + this.margin ) && ( l.y <= this.top + this.w - this.margin ) ) {
|
|
return 'pad';
|
|
}*/
|
|
|
|
//return '';
|
|
|
|
}
|
|
|
|
mouseup ( e ) {
|
|
|
|
this.isDown = false;
|
|
return this.mode(0);
|
|
|
|
}
|
|
|
|
mousedown ( e ) {
|
|
|
|
if ( this.testZone(e) === 'pad' ) {
|
|
|
|
this.isDown = true;
|
|
this.mousemove( e );
|
|
return this.mode(1);
|
|
}
|
|
|
|
}
|
|
|
|
mousemove ( e ) {
|
|
|
|
if( !this.isDown ) return;
|
|
|
|
let x = (this.w*0.5) - ( e.clientX - this.zone.x );
|
|
let y = (this.diam*0.5) - ( e.clientY - this.zone.y - this.top );
|
|
let r = 256 / this.diam;
|
|
|
|
x = -(x*r);
|
|
y = -(y*r);
|
|
|
|
x = Tools.clamp( x, -this.maxPos, this.maxPos );
|
|
y = Tools.clamp( y, -this.maxPos, this.maxPos );
|
|
|
|
//let x = e.clientX - this.zone.x;
|
|
//let y = e.clientY - this.zone.y - this.top;
|
|
|
|
/*if( x < this.margin ) x = this.margin;
|
|
if( x > this.w - this.margin ) x = this.w - this.margin;
|
|
if( y < this.margin ) y = this.margin;
|
|
if( y > this.w - this.margin ) y = this.w - this.margin;*/
|
|
|
|
//console.log(x,y)
|
|
|
|
this.setPos( [ x , y ] );
|
|
|
|
this.update( true );
|
|
|
|
}
|
|
|
|
mode ( mode ) {
|
|
|
|
if( this.cmode === mode ) return false;
|
|
|
|
let cc = this.colors;
|
|
|
|
switch( mode ){
|
|
case 0: // base
|
|
|
|
this.s[2].color = cc.text;
|
|
this.setSvg( this.c[3], 'fill', cc.back, 0);
|
|
this.setSvg( this.c[3], 'fill', cc.button, 1);
|
|
this.setSvg( this.c[3], 'stroke', cc.back, 2);
|
|
this.setSvg( this.c[3], 'stroke', cc.back, 3);
|
|
this.setSvg( this.c[3], 'stroke', cc.text, 4 );
|
|
|
|
break;
|
|
case 1: // down
|
|
|
|
this.s[2].color = cc.textSelect;
|
|
this.setSvg( this.c[3], 'fill', cc.backoff, 0);
|
|
this.setSvg( this.c[3], 'fill', cc.overoff, 1);
|
|
this.setSvg( this.c[3], 'stroke', cc.backoff, 2);
|
|
this.setSvg( this.c[3], 'stroke', cc.backoff, 3);
|
|
this.setSvg( this.c[3], 'stroke', cc.textSelect, 4 );
|
|
|
|
break;
|
|
}
|
|
|
|
this.cmode = mode;
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
update ( up ) {
|
|
|
|
//if( up === undefined ) up = true;
|
|
|
|
this.c[2].textContent = this.value;
|
|
|
|
this.updateSVG();
|
|
|
|
if( up ) this.send();
|
|
|
|
}
|
|
|
|
updateSVG() {
|
|
|
|
if ( this.model == 1 ) {
|
|
|
|
this.setSvg( this.c[3], 'y1', this.pos.y, 2 );
|
|
this.setSvg( this.c[3], 'y2', this.pos.y, 2 );
|
|
|
|
this.setSvg( this.c[3], 'x1', this.pos.x, 3 );
|
|
this.setSvg( this.c[3], 'x2', this.pos.x, 3 );
|
|
|
|
}
|
|
|
|
this.setSvg( this.c[3], 'cx', this.pos.x, 4 );
|
|
this.setSvg( this.c[3], 'cy', this.pos.y, 4 );
|
|
|
|
}
|
|
|
|
setPos ( p ) {
|
|
|
|
//if( p === undefined ) p = [ this.w / 2, this.w / 2 ];
|
|
|
|
this.pos.set( p[0]+128 , p[1]+128 );
|
|
|
|
let r = 1/this.maxPos;
|
|
|
|
this.value[0] = ((p[0]*r)*this.range).toFixed( this.precision );
|
|
this.value[1] = ((p[1]*r)*this.range).toFixed( this.precision );
|
|
|
|
}
|
|
|
|
setValue ( v, up = false ) {
|
|
|
|
if( v === undefined ) v = this.value;
|
|
|
|
/*if ( v[0] < this.bounds.x1 ) v[0] = this.bounds.x1;
|
|
if ( v[0] > this.bounds.x2 ) v[0] = this.bounds.x2;
|
|
if ( v[1] < this.bounds.y1 ) v[1] = this.bounds.y1;
|
|
if ( v[1] > this.bounds.y2 ) v[1] = this.bounds.y2;*/
|
|
|
|
this.value[0] = Math.min( this.max, Math.max( this.min, v[0] ) ).toFixed( this.precision ) * 1;
|
|
this.value[1] = Math.min( this.max, Math.max( this.min, v[1] ) ).toFixed( this.precision ) * 1;
|
|
|
|
this.pos.set( ((this.value[0]/this.range)*this.maxPos)+128 , ((this.value[1]/this.range)*this.maxPos)+128 );
|
|
|
|
//console.log(this.pos)
|
|
|
|
this.update( up );
|
|
|
|
}
|
|
|
|
/*lerp( s1, s2, d1, d2, c = true ) {
|
|
|
|
let s = ( d2 - d1 ) / ( s2 - s1 );
|
|
|
|
return c ? ( v ) => {
|
|
return ( ( v < s1 ? s1 : v > s2 ? s2 : v ) - s1 ) * s + d1
|
|
} : ( v ) => {
|
|
return ( v - s1 ) * s + d1
|
|
}
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
const add = function () {
|
|
|
|
let a = arguments;
|
|
|
|
let type, o, ref = false, n = null;
|
|
|
|
if( typeof a[0] === 'string' ){
|
|
|
|
type = a[0];
|
|
o = a[1] || {};
|
|
|
|
} else if ( typeof a[0] === 'object' ){ // like dat gui
|
|
|
|
ref = true;
|
|
if( a[2] === undefined ) [].push.call(a, {});
|
|
|
|
type = a[2].type ? a[2].type : autoType( a[0][a[1]], a[2] );
|
|
|
|
o = a[2];
|
|
o.name = a[1];
|
|
if( type === 'list' ){ o.list = a[0][a[1]]; }
|
|
else o.value = a[0][a[1]];
|
|
|
|
}
|
|
|
|
|
|
|
|
let name = type.toLowerCase();
|
|
|
|
if( name === 'group' ) o.add = add;
|
|
|
|
switch( name ){
|
|
|
|
case 'bool': case 'boolean': n = new Bool(o); break;
|
|
case 'button': n = new Button(o); break;
|
|
case 'circular': n = new Circular(o); break;
|
|
case 'color': n = new Color(o); break;
|
|
case 'fps': n = new Fps(o); break;
|
|
case 'graph': n = new Graph(o); break;
|
|
case 'group': n = new Group(o); break;
|
|
case 'joystick': n = new Joystick(o); break;
|
|
case 'knob': n = new Knob(o); break;
|
|
case 'list': n = new List(o); break;
|
|
case 'numeric': case 'number': n = new Numeric(o); break;
|
|
case 'slide': n = new Slide(o); break;
|
|
case 'textInput': case 'string': n = new TextInput(o); break;
|
|
case 'title': case 'text': n = new Title(o); break;
|
|
case 'select': n = new Select(o); break;
|
|
case 'selector': n = new Selector(o); break;
|
|
case 'empty': case 'space': n = new Empty(o); break;
|
|
case 'item': n = new Item(o); break;
|
|
case 'grid': n = new Grid(o); break;
|
|
case 'pad2d': case 'pad': n = new Pad2D(o); break;
|
|
|
|
}
|
|
|
|
if( n !== null ){
|
|
|
|
if( ref ) n.setReferency( a[0], a[1] );
|
|
return n;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
const autoType = function ( v, o ) {
|
|
|
|
let type = 'slide';
|
|
|
|
if( typeof v === 'boolean' ) type = 'bool';
|
|
else if( typeof v === 'string' ){
|
|
|
|
if( v.substring(0,1) === '#' ) type = 'color';
|
|
else type = 'string';
|
|
|
|
} else if( typeof v === 'number' ){
|
|
|
|
if( o.ctype ) type = 'color';
|
|
else type = 'slide';
|
|
|
|
} else if( typeof v === 'array' && v instanceof Array ){
|
|
|
|
if( typeof v[0] === 'number' ) type = 'number';
|
|
else if( typeof v[0] === 'string' ) type = 'list';
|
|
|
|
} else if( typeof v === 'object' && v instanceof Object ){
|
|
|
|
if( v.x !== undefined ) type = 'number';
|
|
else type = 'list';
|
|
|
|
}
|
|
|
|
return type
|
|
|
|
};
|
|
|
|
/**
|
|
* @author lth / https://github.com/lo-th
|
|
*/
|
|
|
|
class Gui {
|
|
|
|
constructor( o = {} ) {
|
|
|
|
this.isGui = true;
|
|
|
|
this.name = 'gui';
|
|
|
|
// for 3d
|
|
this.canvas = null;
|
|
this.screen = null;
|
|
this.plane = o.plane || null;
|
|
|
|
|
|
|
|
// color
|
|
if( o.config ) o.colors = o.config;
|
|
|
|
if ( o.colors ) this.setConfig( o.colors );
|
|
else this.colors = Tools.defineColor( o );
|
|
|
|
// style
|
|
this.css = Tools.cloneCss();
|
|
|
|
this.isReset = true;
|
|
this.tmpAdd = null;
|
|
//this.tmpH = 0
|
|
|
|
this.isCanvas = o.isCanvas || false;
|
|
this.isCanvasOnly = false;
|
|
|
|
this.callback = o.callback === undefined ? null : o.callback;
|
|
|
|
this.forceHeight = o.maxHeight || 0;
|
|
this.lockHeight = o.lockHeight || false;
|
|
|
|
this.isItemMode = o.itemMode !== undefined ? o.itemMode : false;
|
|
|
|
this.cn = '';
|
|
|
|
// size define
|
|
this.size = Tools.size;
|
|
if( o.p !== undefined ) this.size.p = o.p;
|
|
if( o.w !== undefined ) this.size.w = o.w;
|
|
if( o.h !== undefined ) this.size.h = o.h;
|
|
if( o.s !== undefined ) this.size.s = o.s;
|
|
|
|
this.size.h = this.size.h < 11 ? 11 : this.size.h;
|
|
|
|
// local mouse and zone
|
|
this.local = new V2().neg();
|
|
this.zone = { x:0, y:0, w:this.size.w, h:0 };
|
|
|
|
// virtual mouse
|
|
this.mouse = new V2().neg();
|
|
|
|
this.h = 0;
|
|
//this.prevY = -1;
|
|
this.sw = 0;
|
|
|
|
|
|
|
|
// bottom and close height
|
|
this.isWithClose = o.close !== undefined ? o.close : true;
|
|
this.bh = !this.isWithClose ? 0 : this.size.h;
|
|
|
|
this.autoResize = o.autoResize === undefined ? true : o.autoResize;
|
|
|
|
// default position
|
|
this.isCenter = o.center || false;
|
|
this.cssGui = o.css !== undefined ? o.css : (this.isCenter ? '' : 'right:10px;');
|
|
|
|
this.isOpen = o.open !== undefined ? o.open : true;
|
|
this.isDown = false;
|
|
this.isScroll = false;
|
|
|
|
this.uis = [];
|
|
this.current = -1;
|
|
this.proto = null;
|
|
this.isEmpty = true;
|
|
this.decal = 0;
|
|
this.ratio = 1;
|
|
this.oy = 0;
|
|
|
|
|
|
this.isNewTarget = false;
|
|
|
|
let cc = this.colors;
|
|
|
|
this.content = Tools.dom( 'div', this.css.basic + ' width:0px; height:auto; top:0px; background:'+cc.content+'; ' + this.cssGui );
|
|
|
|
this.innerContent = Tools.dom( 'div', this.css.basic + 'width:100%; top:0; left:0; height:auto; overflow:hidden;');
|
|
//this.innerContent = Tools.dom( 'div', this.css.basic + this.css.button + 'width:100%; top:0; left:0; height:auto; overflow:hidden;');
|
|
this.content.appendChild( this.innerContent );
|
|
|
|
//this.inner = Tools.dom( 'div', this.css.basic + 'width:100%; left:0; ')
|
|
this.useFlex = true;
|
|
let flexible = this.useFlex ? 'display:flex; flex-flow: row wrap;' : ''; //' display:flex; justify-content:start; align-items:start;flex-direction: column; justify-content: center; align-items: center;';
|
|
this.inner = Tools.dom( 'div', this.css.basic + flexible + 'width:100%; left:0; ');
|
|
this.innerContent.appendChild(this.inner);
|
|
|
|
// scroll
|
|
this.scrollBG = Tools.dom( 'div', this.css.basic + 'right:0; top:0; width:'+ (this.size.s - 1) +'px; height:10px; display:none; background:'+cc.background+';');
|
|
this.content.appendChild( this.scrollBG );
|
|
|
|
this.scroll = Tools.dom( 'div', this.css.basic + 'background:'+cc.button+'; right:2px; top:0; width:'+(this.size.s-4)+'px; height:10px;');
|
|
this.scrollBG.appendChild( this.scroll );
|
|
|
|
// bottom button
|
|
this.bottomText = o.bottomText || ['open', 'close'];
|
|
|
|
let r = cc.radius;
|
|
this.bottom = Tools.dom( 'div', this.css.txt + 'width:100%; top:auto; bottom:0; left:0; border-bottom-right-radius:'+r+'px; border-bottom-left-radius:'+r+'px; justify-content:center; height:'+this.bh+'px; line-height:'+(this.bh-5)+'px; color:' + cc.text+';' );// border-top:1px solid '+Tools.colors.stroke+';');
|
|
this.content.appendChild( this.bottom );
|
|
this.bottom.textContent = this.isOpen ? this.bottomText[1] : this.bottomText[0];
|
|
this.bottom.style.background = cc.background;
|
|
|
|
//
|
|
|
|
this.parent = o.parent !== undefined ? o.parent : null;
|
|
this.parent = o.target !== undefined ? o.target : this.parent;
|
|
|
|
if( this.parent === null && !this.isCanvas ){
|
|
this.parent = document.body;
|
|
}
|
|
|
|
if( this.parent !== null ) this.parent.appendChild( this.content );
|
|
|
|
if( this.isCanvas && this.parent === null ) this.isCanvasOnly = true;
|
|
|
|
if( !this.isCanvasOnly ){
|
|
this.content.style.pointerEvents = 'auto';
|
|
} else {
|
|
this.content.style.left = '0px';
|
|
this.content.style.right = 'auto';
|
|
o.transition = 0;
|
|
}
|
|
|
|
|
|
// height transition
|
|
this.transition = o.transition || Tools.transition;
|
|
if( this.transition ) setTimeout( this.addTransition.bind( this ), 0 );
|
|
|
|
|
|
this.setWidth();
|
|
|
|
if( this.isCanvas ) this.makeCanvas();
|
|
|
|
Roots.add( this );
|
|
|
|
}
|
|
|
|
setTop( t, h ) {
|
|
|
|
this.content.style.top = t + 'px';
|
|
if( h !== undefined ) this.forceHeight = h;
|
|
this.calc();
|
|
|
|
Roots.needReZone = true;
|
|
|
|
}
|
|
|
|
addTransition(){
|
|
|
|
if( this.transition && !this.isCanvas ){
|
|
this.innerContent.style.transition = 'height '+this.transition+'s ease-out';
|
|
this.content.style.transition = 'height '+this.transition+'s ease-out';
|
|
this.bottom.style.transition = 'top '+this.transition+'s ease-out';
|
|
//this.bottom.addEventListener("transitionend", Roots.resize, true);
|
|
}
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// CANVAS
|
|
// ----------------------
|
|
|
|
onDraw () {}
|
|
|
|
makeCanvas () {
|
|
|
|
this.canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', "canvas" );
|
|
this.canvas.width = this.zone.w;
|
|
this.canvas.height = this.forceHeight ? this.forceHeight : this.zone.h;
|
|
|
|
//console.log( this.canvas.width, this.canvas.height )
|
|
|
|
}
|
|
|
|
draw ( force ) {
|
|
|
|
if( this.canvas === null ) return;
|
|
|
|
let w = this.zone.w;
|
|
let h = this.forceHeight ? this.forceHeight : this.zone.h;
|
|
Roots.toCanvas( this, w, h, force );
|
|
|
|
}
|
|
|
|
//////
|
|
|
|
getDom () {
|
|
|
|
return this.content;
|
|
|
|
}
|
|
|
|
noMouse () {
|
|
|
|
this.mouse.neg();
|
|
|
|
}
|
|
|
|
setMouse ( uv, flip = true ) {
|
|
|
|
if(flip) this.mouse.set( Math.round( uv.x * this.canvas.width ), this.canvas.height - Math.round( uv.y * this.canvas.height ) );
|
|
else this.mouse.set( Math.round( uv.x * this.canvas.width ), Math.round( uv.y * this.canvas.height ) );
|
|
//this.mouse.set( m.x, m.y );
|
|
|
|
}
|
|
|
|
setConfig ( o ) {
|
|
|
|
// reset to default text
|
|
Tools.setText();
|
|
this.colors = Tools.defineColor( o );
|
|
|
|
}
|
|
|
|
setColors ( o ) {
|
|
|
|
for( let c in o ){
|
|
if( this.colors[c] ) this.colors[c] = o[c];
|
|
}
|
|
|
|
}
|
|
|
|
setText ( size, color, font, shadow ) {
|
|
|
|
Tools.setText( size, color, font, shadow );
|
|
|
|
}
|
|
|
|
hide ( b ) {
|
|
this.content.style.visibility = b ? 'hidden' : 'visible';
|
|
}
|
|
|
|
display( v = false ) {
|
|
this.content.style.visibility = v ? 'visible' : 'hidden';
|
|
}
|
|
|
|
onChange ( f ) {
|
|
|
|
this.callback = f || null;
|
|
return this;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// STYLES
|
|
// ----------------------
|
|
|
|
mode ( n ) {
|
|
|
|
let needChange = false;
|
|
let cc = this.colors;
|
|
|
|
if( n !== this.cn ){
|
|
|
|
this.cn = n;
|
|
|
|
switch( n ){
|
|
|
|
case 'def':
|
|
Roots.cursor();
|
|
this.scroll.style.background = cc.button;
|
|
this.bottom.style.background = cc.background;
|
|
this.bottom.style.color = cc.text;
|
|
break;
|
|
|
|
//case 'scrollDef': this.scroll.style.background = this.colors.scroll; break;
|
|
case 'scrollOver':
|
|
Roots.cursor('ns-resize');
|
|
this.scroll.style.background = cc.select;
|
|
break;
|
|
case 'scrollDown':
|
|
this.scroll.style.background = cc.select;
|
|
break;
|
|
|
|
//case 'bottomDef': this.bottom.style.background = this.colors.background; break;
|
|
case 'bottomOver':
|
|
Roots.cursor('pointer');
|
|
this.bottom.style.background = cc.backgroundOver;
|
|
this.bottom.style.color = cc.textOver;
|
|
break;
|
|
//case 'bottomDown': this.bottom.style.background = this.colors.select; this.bottom.style.color = '#000'; break;
|
|
|
|
}
|
|
|
|
needChange = true;
|
|
|
|
}
|
|
|
|
return needChange;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// TARGET
|
|
// ----------------------
|
|
|
|
clearTarget () {
|
|
|
|
if( this.current === -1 ) return false;
|
|
if( this.proto.s ){
|
|
// if no s target is delete !!
|
|
this.proto.uiout();
|
|
this.proto.reset();
|
|
}
|
|
|
|
this.proto = null;
|
|
this.current = -1;
|
|
|
|
///console.log(this.isDown)//if(this.isDown)Roots.clearInput();
|
|
|
|
|
|
|
|
Roots.cursor();
|
|
return true;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// ZONE TEST
|
|
// ----------------------
|
|
|
|
testZone ( e ) {
|
|
|
|
let l = this.local;
|
|
if( l.x === -1 && l.y === -1 ) return '';
|
|
|
|
this.isReset = false;
|
|
|
|
let name = '';
|
|
|
|
let s = this.isScroll ? this.zone.w - this.size.s : this.zone.w;
|
|
|
|
if( l.y > this.zone.h - this.bh && l.y < this.zone.h ) name = 'bottom';
|
|
else name = l.x > s ? 'scroll' : 'content';
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// EVENTS
|
|
// ----------------------
|
|
|
|
handleEvent ( e ) {
|
|
|
|
let type = e.type;
|
|
|
|
let change = false;
|
|
let protoChange = false;
|
|
|
|
let name = this.testZone( e );
|
|
|
|
if( type === 'mouseup' && this.isDown ) this.isDown = false;
|
|
if( type === 'mousedown' && !this.isDown ) this.isDown = true;
|
|
|
|
if( this.isDown && this.isNewTarget ){ Roots.clearInput(); this.isNewTarget=false; }
|
|
|
|
if( !name ) return;
|
|
|
|
switch( name ){
|
|
|
|
case 'content':
|
|
|
|
e.clientY = this.isScroll ? e.clientY + this.decal : e.clientY;
|
|
|
|
if( Roots.isMobile && type === 'mousedown' ) this.getNext( e, change );
|
|
|
|
if( this.proto ) protoChange = this.proto.handleEvent( e );
|
|
|
|
if( type === 'mousemove' ) change = this.mode('def');
|
|
if( type === 'wheel' && !protoChange && this.isScroll ) change = this.onWheel( e );
|
|
|
|
if( !Roots.lock ) {
|
|
this.getNext( e, change );
|
|
}
|
|
|
|
break;
|
|
case 'bottom':
|
|
|
|
this.clearTarget();
|
|
if( type === 'mousemove' ) change = this.mode('bottomOver');
|
|
if( type === 'mousedown' ) {
|
|
this.isOpen = this.isOpen ? false : true;
|
|
this.bottom.textContent = this.isOpen ? this.bottomText[1] : this.bottomText[0];
|
|
//this.setHeight();
|
|
this.calc();
|
|
this.mode('def');
|
|
change = true;
|
|
}
|
|
|
|
break;
|
|
case 'scroll':
|
|
|
|
this.clearTarget();
|
|
if( type === 'mousemove' ) change = this.mode('scrollOver');
|
|
if( type === 'mousedown' ) change = this.mode('scrollDown');
|
|
if( type === 'wheel' ) change = this.onWheel( e );
|
|
if( this.isDown ) this.update( (e.clientY-this.zone.y)-(this.sh*0.5) );
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
if( this.isDown ) change = true;
|
|
if( protoChange ) change = true;
|
|
|
|
if( type === 'keyup' ) change = true;
|
|
if( type === 'keydown' ) change = true;
|
|
|
|
if( change ) this.draw();
|
|
|
|
}
|
|
|
|
getNext ( e, change ) {
|
|
|
|
|
|
|
|
let next = Roots.findTarget( this.uis, e );
|
|
|
|
if( next !== this.current ){
|
|
this.clearTarget();
|
|
this.current = next;
|
|
|
|
this.isNewTarget = true;
|
|
|
|
}
|
|
|
|
if( next !== -1 ){
|
|
this.proto = this.uis[ this.current ];
|
|
this.proto.uiover();
|
|
}
|
|
|
|
}
|
|
|
|
onWheel ( e ) {
|
|
|
|
this.oy += 20*e.delta;
|
|
this.update( this.oy );
|
|
return true;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// RESET
|
|
// ----------------------
|
|
|
|
reset ( force ) {
|
|
|
|
if( this.isReset ) return;
|
|
|
|
//this.resetItem();
|
|
|
|
this.mouse.neg();
|
|
this.isDown = false;
|
|
|
|
//Roots.clearInput();
|
|
let r = this.mode('def');
|
|
let r2 = this.clearTarget();
|
|
|
|
if( r || r2 ) this.draw( true );
|
|
|
|
this.isReset = true;
|
|
|
|
//Roots.lock = false;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// ADD NODE
|
|
// ----------------------
|
|
|
|
add () {
|
|
|
|
let a = arguments;
|
|
let ontop = false;
|
|
|
|
if( typeof a[1] === 'object' ){
|
|
|
|
a[1].isUI = true;
|
|
a[1].main = this;
|
|
|
|
ontop = a[1].ontop ? a[1].ontop : false;
|
|
|
|
} else if( typeof a[1] === 'string' ){
|
|
|
|
if( a[2] === undefined ) [].push.call(a, { isUI:true, main:this });
|
|
else {
|
|
a[2].isUI = true;
|
|
a[2].main = this;
|
|
//ontop = a[1].ontop ? a[1].ontop : false;
|
|
ontop = a[2].ontop ? a[2].ontop : false;
|
|
}
|
|
|
|
}
|
|
|
|
let u = add.apply( this, a );
|
|
|
|
if( u === null ) return;
|
|
|
|
if( ontop ) this.uis.unshift( u );
|
|
else this.uis.push( u );
|
|
|
|
this.calc();
|
|
|
|
this.isEmpty = false;
|
|
|
|
return u
|
|
|
|
}
|
|
|
|
// remove one node
|
|
|
|
remove ( n ) {
|
|
|
|
if( n.dispose ) n.dispose();
|
|
|
|
}
|
|
|
|
// call after uis clear
|
|
|
|
clearOne ( n ) {
|
|
|
|
let id = this.uis.indexOf( n );
|
|
if ( id !== -1 ) {
|
|
//this.calc( - (this.uis[ id ].h + 1 ) );
|
|
this.inner.removeChild( this.uis[ id ].c[0] );
|
|
this.uis.splice( id, 1 );
|
|
this.calc();
|
|
}
|
|
|
|
}
|
|
|
|
// clear all gui
|
|
|
|
empty() {
|
|
|
|
//this.close();
|
|
|
|
let i = this.uis.length, item;
|
|
|
|
while( i-- ){
|
|
item = this.uis.pop();
|
|
this.inner.removeChild( item.c[0] );
|
|
item.dispose();
|
|
}
|
|
|
|
this.uis = [];
|
|
this.isEmpty = true;
|
|
this.calc();
|
|
|
|
}
|
|
|
|
clear() {
|
|
|
|
this.empty();
|
|
|
|
}
|
|
|
|
dispose() {
|
|
|
|
this.clear();
|
|
if( this.parent !== null ) this.parent.removeChild( this.content );
|
|
Roots.remove( this );
|
|
|
|
}
|
|
|
|
|
|
// ----------------------
|
|
// ITEMS SPECIAL
|
|
// ----------------------
|
|
|
|
resetItem () {
|
|
|
|
if( !this.isItemMode ) return;
|
|
|
|
let i = this.uis.length;
|
|
while(i--) this.uis[i].selected();
|
|
|
|
}
|
|
|
|
setItem ( name ) {
|
|
|
|
if( !this.isItemMode ) return;
|
|
|
|
name = name || '';
|
|
this.resetItem();
|
|
|
|
if( !name ){
|
|
this.update(0);
|
|
return
|
|
}
|
|
|
|
let i = this.uis.length;
|
|
while(i--){
|
|
if( this.uis[i].value === name ){
|
|
this.uis[i].selected( true );
|
|
if( this.isScroll ) this.update( ( i*(this.uis[i].h+1) )*this.ratio );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------
|
|
// SCROLL
|
|
// ----------------------
|
|
|
|
upScroll ( b ) {
|
|
|
|
this.sw = b ? this.size.s : 0;
|
|
this.oy = b ? this.oy : 0;
|
|
this.scrollBG.style.display = b ? 'block' : 'none';
|
|
|
|
if( b ){
|
|
|
|
this.total = this.h;
|
|
|
|
this.maxView = this.maxHeight;
|
|
|
|
this.ratio = this.maxView / this.total;
|
|
this.sh = this.maxView * this.ratio;
|
|
|
|
this.range = this.maxView - this.sh;
|
|
|
|
this.oy = Tools.clamp( this.oy, 0, this.range );
|
|
|
|
this.scrollBG.style.height = this.maxView + 'px';
|
|
this.scroll.style.height = this.sh + 'px';
|
|
|
|
}
|
|
|
|
this.setItemWidth( this.zone.w - this.sw );
|
|
this.update( this.oy );
|
|
|
|
}
|
|
|
|
update ( y ) {
|
|
|
|
y = Tools.clamp( y, 0, this.range );
|
|
|
|
this.decal = Math.floor( y / this.ratio );
|
|
this.inner.style.top = - this.decal + 'px';
|
|
this.scroll.style.top = Math.floor( y ) + 'px';
|
|
this.oy = y;
|
|
|
|
}
|
|
|
|
// ----------------------
|
|
// RESIZE FUNCTION
|
|
// ----------------------
|
|
|
|
calcUis() {
|
|
|
|
return Roots.calcUis( this.uis, this.zone, this.zone.y )
|
|
}
|
|
|
|
calc() {
|
|
|
|
clearTimeout( this.tmp );
|
|
this.tmp = setTimeout( this.setHeight.bind( this ), 10 );
|
|
|
|
}
|
|
|
|
setHeight() {
|
|
|
|
if( this.tmp ) clearTimeout( this.tmp );
|
|
|
|
this.zone.h = this.bh;
|
|
this.isScroll = false;
|
|
|
|
if( this.isOpen ){
|
|
|
|
this.h = this.calcUis();
|
|
|
|
let hhh = this.forceHeight ? this.forceHeight + this.zone.y : window.innerHeight;
|
|
|
|
this.maxHeight = hhh - this.zone.y - this.bh;
|
|
|
|
let diff = this.h - this.maxHeight;
|
|
|
|
if( diff > 1 ){
|
|
|
|
this.isScroll = true;
|
|
this.zone.h = this.maxHeight + this.bh;
|
|
|
|
} else {
|
|
|
|
this.zone.h = this.h + this.bh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.upScroll( this.isScroll );
|
|
|
|
this.innerContent.style.height = this.zone.h - this.bh + 'px';
|
|
this.content.style.height = this.zone.h + 'px';
|
|
this.bottom.style.top = this.zone.h - this.bh + 'px';
|
|
|
|
|
|
if( this.forceHeight && this.lockHeight ) this.content.style.height = this.forceHeight + 'px';
|
|
|
|
if( this.isCanvas ) this.draw( true );
|
|
|
|
}
|
|
|
|
rezone () {
|
|
Roots.needReZone = true;
|
|
}
|
|
|
|
setWidth ( w ) {
|
|
|
|
if( w ) this.zone.w = w;
|
|
|
|
this.zone.w = Math.floor( this.zone.w );
|
|
|
|
this.content.style.width = this.zone.w + 'px';
|
|
|
|
if( this.isCenter ) this.content.style.marginLeft = -(Math.floor(this.zone.w*0.5)) + 'px';
|
|
|
|
this.setItemWidth( this.zone.w - this.sw );
|
|
|
|
}
|
|
|
|
setItemWidth ( w ) {
|
|
|
|
let i = this.uis.length;
|
|
while(i--){
|
|
this.uis[i].setSize( w );
|
|
this.uis[i].rSize();
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const REVISION = '4.0.8';
|
|
|
|
export { Files, Gui, Proto, REVISION, Tools, add };
|