uil
Version:
JavaScript gui library
1,765 lines (1,157 loc) • 240 kB
JavaScript
'use strict';
/**
* @author lth / https://github.com/lo-th
*/
const REVISION = '4.4.0';
// INTENAL FUNCTION
/*const observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
console.log(entry)
//const bounds = entry.boundingClientRect;
entry.target.bounds = entry.boundingClientRect;
}
observer.disconnect();
})*/
const R = {
ui: [],
debug:false,
dom:null,
ID: null,
lock:false,
wlock:false,
current:-1,
needReZone: true,
needResize:false,
forceZone:false,
isEventsInit: false,
isLeave:false,
downTime:0,
prevTime:0,
//prevDefault: ['contextmenu', 'wheel'],
prevDefault: ['contextmenu'],
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,
injectCss (css, styleName, parent) {
const CSS_ID = styleName || 'codeflask-style';
const PARENT = parent || document.head;
if (!css) return false
if (document.getElementById(CSS_ID)) return true
const style = document.createElement('style');
style.innerHTML = css;
style.id = CSS_ID;
PARENT.appendChild(style);
return true
},
getTime: function() {
return ( self.performance && self.performance.now ) ? self.performance.now.bind( performance ) : Date.now;
},
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;
},
// ----------------------
// ADD / REMOVE
// ----------------------
add: function ( o ) {
R.ui.push( o );
R.getZone( o );
if( !R.isEventsInit ) R.initEvents();
},
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();
}
//console.log('remove:', R.ui.length)
},
// ----------------------
// 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;
//console.log('event is add !')
},
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;
//console.log('event is remove !')
},
resize: function () {
//console.log('resize !!')
let i = R.ui.length, u;
while( i-- ){
u = R.ui[i];
if( u.isGui && !u.isCanvasOnly && u.autoResize ) u.calc();
}
R.needReZone = true;
R.needResize = false;
},
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();
if( R.needResize ) R.resize();
R.findZone( R.forceZone );
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;
R.forceZone = false;
}
// 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;
}
//if( R.ID.marginDiv ) e.clientY -= R.ID.margin * 0.5
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
// need update if zone change !!
// ----------------------
calcUis: ( uis, zone, py, group = false ) => {
if( R.debug ) console.log('calc_uis !!');
let i = uis.length, u, px = 0, n = 0, tw;
let height = 0;
while( i-- ){
u = uis[n];
n++;
if( !group && u.isGroup ) u.calcUis();
let m = u.margin || 0;
u.zone.w = u.w;
u.zone.h = u.h + m;
if( !u.autoWidth ){
if( px === 0 ) height += u.h + m;
u.zone.x = zone.x + px;
u.zone.y = py;// + u.mtop
//if(div) u.zone.y += m * 0.5
tw = R.getWidth(u);
if( tw ) u.zone.w = u.w = tw;
else if( u.fw ) u.zone.w = u.w = u.fw;
px += u.zone.w;
if( px >= zone.w ) {
py += u.h + m;
//if(div) py += m * 0.5
px = 0;
}
} else {
px = 0;
u.zone.x = zone.x + u.dx;
u.zone.y = py;
py += u.h + m;
height += (u.h + m); //-0.5;// ???
}
}
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 = false ) {
if( force ) R.needReZone = force;
if( !R.needReZone ) return;
let i = R.ui.length, u;
while( i-- ){
u = R.ui[i];
R.getZone( u );
// TODO need for group open at start !!!
if( u.isGui ) u.calcUis();
}
R.needReZone = false;
},
onZone: function ( o, x, y ) {
//console.log(o, x, y)
if( x === undefined || y === undefined ) return false;
let z = o.zone;
let mx = x - z.x;// - o.dx;
let my = y - z.y;
//if( this.marginDiv ) e.clientY -= this.margin * 0.5
//if( o.group && o.group.marginDiv ) my += o.group.margin * 0.5
//if( o.group !== null ) mx -= o.dx
let over = ( mx >= 0 ) && ( my >= 0 ) && ( mx <= z.w ) && ( my <= z.h );
//if( o.marginDiv ) my -= o.margin * 0.5
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;
if( o.isEmpty ) return;
const element = o.getDom();
const r = element.getBoundingClientRect();
o.zone = { x:r.left, y:r.top, w:r.width, h:r.height };
if( o.isBottom ) o.zone.y = o.realTop;
},
// ----------------------
// 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
*/
//import { PixelFont } from './PixelFont.js';
const T = {
size: { w:320, h:24, p:30, s:8 },
// three reference class
texture: null,
transition: 0.1,
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: ( v, min, max ) => {
v = v < min ? min : v;
v = v > max ? max : v;
return v;
},
isDivid: ( v ) => ( v*0.5 === Math.floor(v*0.5) ),
// ----------------------
// COLOR
// ----------------------
defineColor: ( o, cc = T.colors ) => {
//Roots.injectCss(PixelFont, null)
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]!==undefined) color[m] = o[m];
}
for( let m in o ){
if( textChange.indexOf(m) !== -1 ) changeText = true;
}
if( changeText ) T.defineText( color );
return color
},
colors: {
sx: 4,//4
sy: 0,//2
radius:6,//2
showOver : 1,
//groupOver : 1,
content:'#37383d',//#28292e',//'none',
background: '#28292e',//'rgba(30,30,30,0)',
backgroundOver: 'rgba(40,40,40,0)',
title : '#CCC',
titleoff : '#BBB',
text : '#DDD',
textOver : '#EEE',
textSelect : '#FFF',
back:'rgba(0,0,0,0.2)',
backoff:'rgba(0,0,0,0.3)',
// input and button border
border : '#4c4c4c',
borderSize : 1,
gborder : 'none',
groups : 'none',
button : '#3c3c3c',
overoff : '#5c5c5c',
over : '#024699',
select : '#308AFF',
action: '#FF3300',
//fontFamily: 'Tahoma',
//fontFamily: 'Consolas, monospace',
//fontFamily:"'SegoeUI', 'Segoe UI', 'Helvetica Neue', -apple-system, BlinkMacSystemFont, Roboto, Oxygen-Sans, Ubuntu, Cantarell, sans-serif",
fontFamily:"Roboto Mono, Source Code Pro, Menlo, Courier, monospace",
//fontFamily: "'Roboto Mono', 'Source Code Pro', Menlo, Courier, monospace",
fontWeight: 'normal',
fontShadow: 'none',//'#000',
fontSize:11,
joyOver:'rgba(48,138,255,0.25)',
joyOut: 'rgba(100,100,100,0.5)',
joySelect: '#308AFF',
hide: 'rgba(0,0,0,0)',
},
// style css
css : {
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; align-items:center; justify-content:center; text-align:center;',
middle:'display:flex; align-items:center; justify-content:left; text-align:left; flex-direction: row-reverse;'
},
// svg path
svgs: {
g1:'M 6 4 L 0 4 0 6 6 6 6 4 M 6 0 L 0 0 0 2 6 2 6 0 Z',
g2:'M 6 0 L 4 0 4 6 6 6 6 0 M 2 0 L 0 0 0 6 2 6 2 0 Z',
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',
load:'M 13 8 L 11.5 6.5 9 9 9 3 5 3 5 9 2.5 6.5 1 8 7 14 13 8 M 9 2 L 9 0 5 0 5 2 9 2 Z',
save:'M 9 12 L 5 12 5 14 9 14 9 12 M 11.5 7.5 L 13 6 7 0 1 6 2.5 7.5 5 5 5 11 9 11 9 5 11.5 7.5 Z',
extern:'M 14 14 L 14 0 0 0 0 14 14 14 M 12 6 L 12 12 2 12 2 6 12 6 M 12 2 L 12 4 2 4 2 2 12 2 Z',
},
setDebug ( v ) {
Roots.debug = v;
},
rezone () {
Roots.needReZone = true;
},
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;
if( isNaN(size) ){ if( size.search('em')===-1 ) size += 'px';}
else size += 'px';
//let align = 'display:flex; justify-content:left; align-items:center; text-align:left;'
T.css.txt = T.css.basic + T.css.middle + ' font-family:'+ font +'; font-weight:'+weight+'; font-size:'+size+'; color:'+cc.text+'; padding:0px 8px; left:0; top:2px; height:16px; width:100px; overflow:hidden; white-space: nowrap; letter-spacing:normal;';//letter-spacing: normal;
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 + 'padding:0px 4px; position:relative; margin-bottom:1px; ';
},
// 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.substring(0, 3) === 'rgba' ) hex = '#000';
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 ] );
},
htmlRgba: function( c, a ){
c = T.unpack(c);
return 'rgba(' + Math.round(c[0] * 255) + ','+ Math.round(c[1] * 255) + ','+ Math.round(c[2] * 255) + ','+ a + ')';
},
htmlRgb: function( c, a ){
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+"' stro