import { settings, internals, browser, gStyle, isBatchMode, isNodeJs, isObject, isFunc, isStr, source_dir, atob_func, btoa_func } from '../core.mjs';
import { select as d3_select, pointer as d3_pointer, drag as d3_drag, color as d3_color } from '../d3.mjs';
import { prSVG, BasePainter } from '../base/BasePainter.mjs';
import { resize } from '../base/ObjectPainter.mjs';
import { getRootColors } from '../base/colors.mjs';
/** @summary Display progress message in the left bottom corner.
* @desc Previous message will be overwritten
* if no argument specified, any shown messages will be removed
* @param {string} msg - message to display
* @param {number} [tmout] - optional timeout in milliseconds, after message will disappear
* @param {function} [click_handle] - optional handle to process click events
* @private */
function showProgress(msg, tmout, click_handle) {
if (isBatchMode() || (typeof document === 'undefined'))
return;
const id = 'jsroot_progressbox', modal = (settings.ProgressBox === 'modal') && isFunc(internals._modalProgress) ? internals._modalProgress : null;
let box = d3_select('#' + id);
if (!settings.ProgressBox) {
if (modal) modal();
return box.remove();
}
if ((arguments.length === 0) || !msg) {
if ((tmout !== -1) || (!box.empty() && box.property('with_timeout'))) box.remove();
if (modal) modal();
return;
}
if (modal) {
box.remove();
modal(msg, click_handle);
} else {
if (box.empty()) {
box = d3_select(document.body)
.append('div').attr('id', id)
.attr('style', 'position: fixed; min-width: 100px; height: auto; overflow: visible; z-index: 101; border: 1px solid #999; background: #F8F8F8; left: 10px; bottom: 10px;');
box.append('p');
}
box.property('with_timeout', false);
const p = box.select('p');
if (isStr(msg)) {
p.html(msg)
.on('click', isFunc(click_handle) ? click_handle : null)
.attr('title', isFunc(click_handle) ? 'Click element to abort current operation' : '');
}
p.attr('style', 'font-size: 10px; margin-left: 10px; margin-right: 10px; margin-top: 3px; margin-bottom: 3px');
}
if (Number.isFinite(tmout) && (tmout > 0)) {
if (!box.empty())
box.property('with_timeout', true);
setTimeout(() => showProgress('', -1), tmout);
}
}
/** @summary Tries to close current browser tab
* @desc Many browsers do not allow simple window.close() call,
* therefore try several workarounds
* @private */
function closeCurrentWindow() {
if (typeof window === 'undefined') return;
window.close();
window.open('', '_self').close();
}
/** @summary Tries to open ui5
* @private */
function tryOpenOpenUI(sources, args) {
if (!sources || (sources.length === 0)) {
if (isFunc(args.rejectFunc)) {
args.rejectFunc(Error('openui5 was not possible to load'));
args.rejectFunc = null;
}
return;
}
// where to take openui5 sources
let src = sources.shift();
if ((src.indexOf('roothandler') === 0) && (src.indexOf('://') < 0))
src = src.replace(/:\//g, '://');
const element = document.createElement('script');
element.setAttribute('type', 'text/javascript');
element.setAttribute('id', 'sap-ui-bootstrap');
// use nojQuery while we are already load jquery and jquery-ui, later one can use directly sap-ui-core.js
// this is location of openui5 scripts when working with THttpServer or when scripts are installed inside JSROOT
element.setAttribute('src', src + (args.ui5dbg ? 'resources/sap-ui-core-dbg.js' : 'resources/sap-ui-core.js')); // latest openui5 version
element.setAttribute('data-sap-ui-libs', args.openui5libs ?? 'sap.m, sap.ui.layout, sap.ui.unified, sap.ui.commons');
element.setAttribute('data-sap-ui-theme', args.openui5theme || 'sap_belize');
element.setAttribute('data-sap-ui-compatVersion', 'edge');
element.setAttribute('data-sap-ui-async', 'true');
// element.setAttribute('data-sap-ui-bindingSyntax', 'complex');
element.setAttribute('data-sap-ui-preload', 'async'); // '' to disable Component-preload.js
element.setAttribute('data-sap-ui-evt-oninit', 'completeUI5Loading()');
element.onerror = function() {
// remove failed element
element.parentNode.removeChild(element);
// and try next
tryOpenOpenUI(sources, args);
};
element.onload = function() {
console.log(`Load openui5 from ${src}`);
};
document.head.appendChild(element);
}
/** @summary load openui5
* @return {Promise} for loading ready
* @private */
async function loadOpenui5(args) {
// very simple - openui5 was loaded before and will be used as is
if (typeof globalThis.sap === 'object')
return globalThis.sap;
if (!args) args = {};
let rootui5sys = source_dir.replace(/jsrootsys/g, 'rootui5sys');
if (rootui5sys === source_dir) {
// if jsrootsys location not detected, try to guess it
if (window.location.port && (window.location.pathname.indexOf('/win') >= 0) && (!args.openui5src || args.openui5src === 'nojsroot' || args.openui5src === 'jsroot'))
rootui5sys = window.location.origin + window.location.pathname + '../rootui5sys/';
else
rootui5sys = undefined;
}
const openui5_sources = [];
let openui5_dflt = 'https://openui5.hana.ondemand.com/' + (browser.qt5 ? '1.108.35/' : '1.128.0/'),
openui5_root = rootui5sys ? rootui5sys + 'distribution/' : '';
if (isStr(args.openui5src)) {
switch (args.openui5src) {
case 'nodefault': openui5_dflt = ''; break;
case 'default': openui5_sources.push(openui5_dflt); openui5_dflt = ''; break;
case 'nojsroot': /* openui5_root = ''; */ break;
case 'jsroot': openui5_sources.push(openui5_root); openui5_root = ''; break;
default: openui5_sources.push(args.openui5src); break;
}
} else if (args.ui5dbg)
openui5_root = ''; // exclude ROOT version in debug mode
if (openui5_root && (openui5_sources.indexOf(openui5_root) < 0) && !browser.qt5)
openui5_sources.push(openui5_root);
if (openui5_dflt && (openui5_sources.indexOf(openui5_dflt) < 0))
openui5_sources.push(openui5_dflt);
return new Promise((resolve, reject) => {
args.resolveFunc = resolve;
args.rejectFunc = reject;
globalThis.completeUI5Loading = function() {
globalThis.sap.ui.loader.config({
paths: {
jsroot: source_dir,
rootui5: rootui5sys
}
});
if (args.resolveFunc) {
args.resolveFunc(globalThis.sap);
args.resolveFunc = null;
}
};
tryOpenOpenUI(openui5_sources, args);
});
}
/* eslint-disable @stylistic/js/key-spacing */
/* eslint-disable @stylistic/js/comma-spacing */
/* eslint-disable @stylistic/js/object-curly-spacing */
// some icons taken from http://uxrepo.com/
const ToolbarIcons = {
camera: { path: 'M 152.00,304.00c0.00,57.438, 46.562,104.00, 104.00,104.00s 104.00-46.562, 104.00-104.00s-46.562-104.00-104.00-104.00S 152.00,246.562, 152.00,304.00z M 480.00,128.00L 368.00,128.00 c-8.00-32.00-16.00-64.00-48.00-64.00L 192.00,64.00 c-32.00,0.00-40.00,32.00-48.00,64.00L 32.00,128.00 c-17.60,0.00-32.00,14.40-32.00,32.00l0.00,288.00 c0.00,17.60, 14.40,32.00, 32.00,32.00l 448.00,0.00 c 17.60,0.00, 32.00-14.40, 32.00-32.00L 512.00,160.00 C 512.00,142.40, 497.60,128.00, 480.00,128.00z M 256.00,446.00c-78.425,0.00-142.00-63.574-142.00-142.00c0.00-78.425, 63.575-142.00, 142.00-142.00c 78.426,0.00, 142.00,63.575, 142.00,142.00 C 398.00,382.426, 334.427,446.00, 256.00,446.00z M 480.00,224.00l-64.00,0.00 l0.00-32.00 l 64.00,0.00 L 480.00,224.00 z' },
disk: { path: 'M384,0H128H32C14.336,0,0,14.336,0,32v448c0,17.656,14.336,32,32,32h448c17.656,0,32-14.344,32-32V96L416,0H384z M352,160 V32h32v128c0,17.664-14.344,32-32,32H160c-17.664,0-32-14.336-32-32V32h128v128H352z M96,288c0-17.656,14.336-32,32-32h256 c17.656,0,32,14.344,32,32v192H96V288z' },
question: { path: 'M256,512c141.375,0,256-114.625,256-256S397.375,0,256,0S0,114.625,0,256S114.625,512,256,512z M256,64 c63.719,0,128,36.484,128,118.016c0,47.453-23.531,84.516-69.891,110.016C300.672,299.422,288,314.047,288,320 c0,17.656-14.344,32-32,32c-17.664,0-32-14.344-32-32c0-40.609,37.25-71.938,59.266-84.031 C315.625,218.109,320,198.656,320,182.016C320,135.008,279.906,128,256,128c-30.812,0-64,20.227-64,64.672 c0,17.664-14.336,32-32,32s-32-14.336-32-32C128,109.086,193.953,64,256,64z M256,449.406c-18.211,0-32.961-14.75-32.961-32.969 c0-18.188,14.75-32.953,32.961-32.953c18.219,0,32.969,14.766,32.969,32.953C288.969,434.656,274.219,449.406,256,449.406z' },
undo: { path: 'M450.159,48.042c8.791,9.032,16.983,18.898,24.59,29.604c7.594,10.706,14.146,22.207,19.668,34.489 c5.509,12.296,9.82,25.269,12.92,38.938c3.113,13.669,4.663,27.834,4.663,42.499c0,14.256-1.511,28.863-4.532,43.822 c-3.009,14.952-7.997,30.217-14.953,45.795c-6.955,15.577-16.202,31.52-27.755,47.826s-25.88,32.9-42.942,49.807 c-5.51,5.444-11.787,11.67-18.834,18.651c-7.033,6.98-14.496,14.366-22.39,22.168c-7.88,7.802-15.955,15.825-24.187,24.069 c-8.258,8.231-16.333,16.203-24.252,23.888c-18.3,18.13-37.354,37.016-57.191,56.65l-56.84-57.445 c19.596-19.472,38.54-38.279,56.84-56.41c7.75-7.685,15.772-15.604,24.108-23.757s16.438-16.163,24.33-24.057 c7.894-7.893,15.356-15.33,22.402-22.312c7.034-6.98,13.312-13.193,18.821-18.651c22.351-22.402,39.165-44.648,50.471-66.738 c11.279-22.09,16.932-43.567,16.932-64.446c0-15.785-3.217-31.005-9.638-45.671c-6.422-14.665-16.229-28.504-29.437-41.529 c-3.282-3.282-7.358-6.395-12.217-9.325c-4.871-2.938-10.381-5.503-16.516-7.697c-6.121-2.201-12.815-3.992-20.058-5.373 c-7.242-1.374-14.9-2.064-23.002-2.064c-8.218,0-16.802,0.834-25.788,2.507c-8.961,1.674-18.053,4.429-27.222,8.271 c-9.189,3.842-18.456,8.869-27.808,15.089c-9.358,6.219-18.521,13.819-27.502,22.793l-59.92,60.271l93.797,94.058H0V40.91 l93.27,91.597l60.181-60.532c13.376-15.018,27.222-27.248,41.536-36.697c14.308-9.443,28.608-16.776,42.89-21.992 c14.288-5.223,28.505-8.74,42.623-10.557C294.645,0.905,308.189,0,321.162,0c13.429,0,26.389,1.185,38.84,3.562 c12.478,2.377,24.2,5.718,35.192,10.029c11.006,4.311,21.126,9.404,30.374,15.265C434.79,34.724,442.995,41.119,450.159,48.042z' },
arrow_right: { path: 'M30.796,226.318h377.533L294.938,339.682c-11.899,11.906-11.899,31.184,0,43.084c11.887,11.899,31.19,11.893,43.077,0 l165.393-165.386c5.725-5.712,8.924-13.453,8.924-21.539c0-8.092-3.213-15.84-8.924-21.551L338.016,8.925 C332.065,2.975,324.278,0,316.478,0c-7.802,0-15.603,2.968-21.539,8.918c-11.899,11.906-11.899,31.184,0,43.084l113.391,113.384 H30.796c-16.822,0-30.463,13.645-30.463,30.463C0.333,212.674,13.974,226.318,30.796,226.318z' },
arrow_up: { path: 'M295.505,629.446V135.957l148.193,148.206c15.555,15.559,40.753,15.559,56.308,0c15.555-15.538,15.546-40.767,0-56.304 L283.83,11.662C276.372,4.204,266.236,0,255.68,0c-10.568,0-20.705,4.204-28.172,11.662L11.333,227.859 c-7.777,7.777-11.666,17.965-11.666,28.158c0,10.192,3.88,20.385,11.657,28.158c15.563,15.555,40.762,15.555,56.317,0 l148.201-148.219v493.489c0,21.993,17.837,39.82,39.82,39.82C277.669,669.267,295.505,651.439,295.505,629.446z' },
arrow_diag: { path: 'M279.875,511.994c-1.292,0-2.607-0.102-3.924-0.312c-10.944-1.771-19.333-10.676-20.457-21.71L233.97,278.348 L22.345,256.823c-11.029-1.119-19.928-9.51-21.698-20.461c-1.776-10.944,4.031-21.716,14.145-26.262L477.792,2.149 c9.282-4.163,20.167-2.165,27.355,5.024c7.201,7.189,9.199,18.086,5.024,27.356L302.22,497.527 C298.224,506.426,289.397,511.994,279.875,511.994z M118.277,217.332l140.534,14.294c11.567,1.178,20.718,10.335,21.878,21.896 l14.294,140.519l144.09-320.792L118.277,217.332z' },
auto_zoom: { path: 'M505.441,242.47l-78.303-78.291c-9.18-9.177-24.048-9.171-33.216,0c-9.169,9.172-9.169,24.045,0.006,33.217l38.193,38.188 H280.088V80.194l38.188,38.199c4.587,4.584,10.596,6.881,16.605,6.881c6.003,0,12.018-2.297,16.605-6.875 c9.174-9.172,9.174-24.039,0.011-33.217L273.219,6.881C268.803,2.471,262.834,0,256.596,0c-6.229,0-12.202,2.471-16.605,6.881 l-78.296,78.302c-9.178,9.172-9.178,24.045,0,33.217c9.177,9.171,24.051,9.171,33.21,0l38.205-38.205v155.4H80.521l38.2-38.188 c9.177-9.171,9.177-24.039,0.005-33.216c-9.171-9.172-24.039-9.178-33.216,0L7.208,242.464c-4.404,4.403-6.881,10.381-6.881,16.611 c0,6.227,2.477,12.207,6.881,16.61l78.302,78.291c4.587,4.581,10.599,6.875,16.605,6.875c6.006,0,12.023-2.294,16.61-6.881 c9.172-9.174,9.172-24.036-0.005-33.211l-38.205-38.199h152.593v152.063l-38.199-38.211c-9.171-9.18-24.039-9.18-33.216-0.022 c-9.178,9.18-9.178,24.059-0.006,33.222l78.284,78.302c4.41,4.404,10.382,6.881,16.611,6.881c6.233,0,12.208-2.477,16.611-6.881 l78.302-78.296c9.181-9.18,9.181-24.048,0-33.205c-9.174-9.174-24.054-9.174-33.21,0l-38.199,38.188v-152.04h152.051l-38.205,38.199 c-9.18,9.175-9.18,24.037-0.005,33.211c4.587,4.587,10.596,6.881,16.604,6.881c6.01,0,12.024-2.294,16.605-6.875l78.303-78.285 c4.403-4.403,6.887-10.378,6.887-16.611C512.328,252.851,509.845,246.873,505.441,242.47z' },
statbox: {
path: 'M28.782,56.902H483.88c15.707,0,28.451-12.74,28.451-28.451C512.331,12.741,499.599,0,483.885,0H28.782 C13.074,0,0.331,12.741,0.331,28.451C0.331,44.162,13.074,56.902,28.782,56.902z' +
'M483.885,136.845H28.782c-15.708,0-28.451,12.741-28.451,28.451c0,15.711,12.744,28.451,28.451,28.451H483.88 c15.707,0,28.451-12.74,28.451-28.451C512.331,149.586,499.599,136.845,483.885,136.845z' +
'M483.885,273.275H28.782c-15.708,0-28.451,12.731-28.451,28.452c0,15.707,12.744,28.451,28.451,28.451H483.88 c15.707,0,28.451-12.744,28.451-28.451C512.337,286.007,499.599,273.275,483.885,273.275z' +
'M256.065,409.704H30.492c-15.708,0-28.451,12.731-28.451,28.451c0,15.707,12.744,28.451,28.451,28.451h225.585 c15.707,0,28.451-12.744,28.451-28.451C284.516,422.436,271.785,409.704,256.065,409.704z'
},
circle: { path: 'M256,256 m-150,0 a150,150 0 1,0 300,0 a150,150 0 1,0 -300,0' },
three_circles: { path: 'M256,85 m-70,0 a70,70 0 1,0 140,0 a70,70 0 1,0 -140,0 M256,255 m-70,0 a70,70 0 1,0 140,0 a70,70 0 1,0 -140,0 M256,425 m-70,0 a70,70 0 1,0 140,0 a70,70 0 1,0 -140,0 ' },
diamand: { path: 'M256,0L384,256L256,511L128,256z' },
rect: { path: 'M90,90h352v352h-352z' },
cross: { path: 'M80,40l176,176l176,-176l40,40l-176,176l176,176l-40,40l-176,-176l-176,176l-40,-40l176,-176l-176,-176z' },
vrgoggles: { size: '245.82 141.73', path: 'M175.56,111.37c-22.52,0-40.77-18.84-40.77-42.07S153,27.24,175.56,27.24s40.77,18.84,40.77,42.07S198.08,111.37,175.56,111.37ZM26.84,69.31c0-23.23,18.25-42.07,40.77-42.07s40.77,18.84,40.77,42.07-18.26,42.07-40.77,42.07S26.84,92.54,26.84,69.31ZM27.27,0C11.54,0,0,12.34,0,28.58V110.9c0,16.24,11.54,30.83,27.27,30.83H99.57c2.17,0,4.19-1.83,5.4-3.7L116.47,118a8,8,0,0,1,12.52-.18l11.51,20.34c1.2,1.86,3.22,3.61,5.39,3.61h72.29c15.74,0,27.63-14.6,27.63-30.83V28.58C245.82,12.34,233.93,0,218.19,0H27.27Z' },
th2colorz: { recs: [{ x: 128, y: 486, w: 256, h: 26, f: 'rgb(38,62,168)' }, { y: 461, f: 'rgb(22,82,205)' }, { y: 435, f: 'rgb(16,100,220)' }, { y: 410, f: 'rgb(18,114,217)' }, { y: 384, f: 'rgb(20,129,214)' }, { y: 358, f: 'rgb(14,143,209)' }, { y: 333, f: 'rgb(9,157,204)' }, { y: 307, f: 'rgb(13,167,195)' }, { y: 282, f: 'rgb(30,175,179)' }, { y: 256, f: 'rgb(46,183,164)' }, { y: 230, f: 'rgb(82,186,146)' }, { y: 205, f: 'rgb(116,189,129)' }, { y: 179, f: 'rgb(149,190,113)' }, { y: 154, f: 'rgb(179,189,101)' }, { y: 128, f: 'rgb(209,187,89)' }, { y: 102, f: 'rgb(226,192,75)' }, { y: 77, f: 'rgb(244,198,59)' }, { y: 51, f: 'rgb(253,210,43)' }, { y: 26, f: 'rgb(251,230,29)' }, { y: 0, f: 'rgb(249,249,15)' }] },
th2color: { recs: [{x:0,y:256,w:13,h:39,f:'rgb(38,62,168)'},{x:13,y:371,w:39,h:39},{y:294,h:39},{y:256,h:39},{y:218,h:39},{x:51,y:410,w:39,h:39},{y:371,h:39},{y:333,h:39},{y:294},{y:256,h:39},{y:218,h:39},{y:179,h:39},{y:141,h:39},{y:102,h:39},{y:64},{x:90,y:448,w:39,h:39},{y:410},{y:371,h:39},{y:333,h:39,f:'rgb(22,82,205)'},{y:294},{y:256,h:39,f:'rgb(16,100,220)'},{y:218,h:39},{y:179,h:39,f:'rgb(22,82,205)'},{y:141,h:39},{y:102,h:39,f:'rgb(38,62,168)'},{y:64},{y:0,h:27},{x:128,y:448,w:39,h:39},{y:410},{y:371,h:39},{y:333,h:39,f:'rgb(22,82,205)'},{y:294,f:'rgb(20,129,214)'},{y:256,h:39,f:'rgb(9,157,204)'},{y:218,h:39,f:'rgb(14,143,209)'},{y:179,h:39,f:'rgb(20,129,214)'},{y:141,h:39,f:'rgb(16,100,220)'},{y:102,h:39,f:'rgb(22,82,205)'},{y:64,f:'rgb(38,62,168)'},{y:26,h:39},{y:0,h:27},{x:166,y:486,h:14},{y:448,h:39},{y:410},{y:371,h:39,f:'rgb(22,82,205)'},{y:333,h:39,f:'rgb(20,129,214)'},{y:294,f:'rgb(82,186,146)'},{y:256,h:39,f:'rgb(179,189,101)'},{y:218,h:39,f:'rgb(116,189,129)'},{y:179,h:39,f:'rgb(82,186,146)'},{y:141,h:39,f:'rgb(14,143,209)'},{y:102,h:39,f:'rgb(16,100,220)'},{y:64,f:'rgb(38,62,168)'},{y:26,h:39},{x:205,y:486,w:39,h:14},{y:448,h:39},{y:410},{y:371,h:39,f:'rgb(16,100,220)'},{y:333,h:39,f:'rgb(9,157,204)'},{y:294,f:'rgb(149,190,113)'},{y:256,h:39,f:'rgb(244,198,59)'},{y:218,h:39},{y:179,h:39,f:'rgb(226,192,75)'},{y:141,h:39,f:'rgb(13,167,195)'},{y:102,h:39,f:'rgb(18,114,217)'},{y:64,f:'rgb(22,82,205)'},{y:26,h:39,f:'rgb(38,62,168)'},{x:243,y:448,w:39,h:39},{y:410},{y:371,h:39,f:'rgb(18,114,217)'},{y:333,h:39,f:'rgb(30,175,179)'},{y:294,f:'rgb(209,187,89)'},{y:256,h:39,f:'rgb(251,230,29)'},{y:218,h:39,f:'rgb(249,249,15)'},{y:179,h:39,f:'rgb(226,192,75)'},{y:141,h:39,f:'rgb(30,175,179)'},{y:102,h:39,f:'rgb(18,114,217)'},{y:64,f:'rgb(38,62,168)'},{y:26,h:39},{x:282,y:448,h:39},{y:410},{y:371,h:39,f:'rgb(18,114,217)'},{y:333,h:39,f:'rgb(14,143,209)'},{y:294,f:'rgb(149,190,113)'},{y:256,h:39,f:'rgb(226,192,75)'},{y:218,h:39,f:'rgb(244,198,59)'},{y:179,h:39,f:'rgb(149,190,113)'},{y:141,h:39,f:'rgb(9,157,204)'},{y:102,h:39,f:'rgb(18,114,217)'},{y:64,f:'rgb(38,62,168)'},{y:26,h:39},{x:320,y:448,w:39,h:39},{y:410},{y:371,h:39,f:'rgb(22,82,205)'},{y:333,h:39,f:'rgb(20,129,214)'},{y:294,f:'rgb(46,183,164)'},{y:256,h:39},{y:218,h:39,f:'rgb(82,186,146)'},{y:179,h:39,f:'rgb(9,157,204)'},{y:141,h:39,f:'rgb(20,129,214)'},{y:102,h:39,f:'rgb(16,100,220)'},{y:64,f:'rgb(38,62,168)'},{y:26,h:39},{x:358,y:448,h:39},{y:410},{y:371,h:39,f:'rgb(22,82,205)'},{y:333,h:39},{y:294,f:'rgb(16,100,220)'},{y:256,h:39,f:'rgb(20,129,214)'},{y:218,h:39,f:'rgb(14,143,209)'},{y:179,h:39,f:'rgb(18,114,217)'},{y:141,h:39,f:'rgb(22,82,205)'},{y:102,h:39,f:'rgb(38,62,168)'},{y:64},{y:26,h:39},{x:397,y:448,w:39,h:39},{y:371,h:39},{y:333,h:39},{y:294,f:'rgb(22,82,205)'},{y:256,h:39},{y:218,h:39},{y:179,h:39,f:'rgb(38,62,168)'},{y:141,h:39},{y:102,h:39},{y:64},{y:26,h:39},{x:435,y:410,h:39},{y:371,h:39},{y:333,h:39},{y:294},{y:256,h:39},{y:218,h:39},{y:179,h:39},{y:141,h:39},{y:102,h:39},{y:64},{x:474,y:256,h:39},{y:179,h:39}] },
th2draw3d: {
path: 'M172.768,0H51.726C23.202,0,0.002,23.194,0.002,51.712v89.918c0,28.512,23.2,51.718,51.724,51.718h121.042 c28.518,0,51.724-23.2,51.724-51.718V51.712C224.486,23.194,201.286,0,172.768,0z M177.512,141.63c0,2.611-2.124,4.745-4.75,4.745 H51.726c-2.626,0-4.751-2.134-4.751-4.745V51.712c0-2.614,2.125-4.739,4.751-4.739h121.042c2.62,0,4.75,2.125,4.75,4.739 L177.512,141.63L177.512,141.63z '+
'M460.293,0H339.237c-28.521,0-51.721,23.194-51.721,51.712v89.918c0,28.512,23.2,51.718,51.721,51.718h121.045 c28.521,0,51.721-23.2,51.721-51.718V51.712C512.002,23.194,488.802,0,460.293,0z M465.03,141.63c0,2.611-2.122,4.745-4.748,4.745 H339.237c-2.614,0-4.747-2.128-4.747-4.745V51.712c0-2.614,2.133-4.739,4.747-4.739h121.045c2.626,0,4.748,2.125,4.748,4.739 V141.63z '+
'M172.768,256.149H51.726c-28.524,0-51.724,23.205-51.724,51.726v89.915c0,28.504,23.2,51.715,51.724,51.715h121.042 c28.518,0,51.724-23.199,51.724-51.715v-89.915C224.486,279.354,201.286,256.149,172.768,256.149z M177.512,397.784 c0,2.615-2.124,4.736-4.75,4.736H51.726c-2.626-0.006-4.751-2.121-4.751-4.736v-89.909c0-2.626,2.125-4.753,4.751-4.753h121.042 c2.62,0,4.75,2.116,4.75,4.753L177.512,397.784L177.512,397.784z '+
'M460.293,256.149H339.237c-28.521,0-51.721,23.199-51.721,51.726v89.915c0,28.504,23.2,51.715,51.721,51.715h121.045 c28.521,0,51.721-23.199,51.721-51.715v-89.915C512.002,279.354,488.802,256.149,460.293,256.149z M465.03,397.784 c0,2.615-2.122,4.736-4.748,4.736H339.237c-2.614,0-4.747-2.121-4.747-4.736v-89.909c0-2.626,2.121-4.753,4.747-4.753h121.045 c2.615,0,4.748,2.116,4.748,4.753V397.784z'
},
createSVG(group, btn, size, title, arg) {
const use_dark = (arg === true) || (arg === false) ? arg : settings.DarkMode,
opacity0 = (arg === 'browser') ? (browser.touches ? 0.2 : 0) : (use_dark ? 0.8 : 0.2),
svg = group.append('svg:svg')
.attr('width', size + 'px')
.attr('height', size + 'px')
.attr('viewBox', '0 0 512 512')
.style('overflow', 'hidden')
.style('cursor', 'pointer')
.style('fill', use_dark ? 'rgba(255, 224, 160)' : 'steelblue')
.style('opacity', opacity0)
.property('opacity0', opacity0)
.property('opacity1', use_dark ? 1 : 0.8)
.on('mouseenter', function() {
const elem = d3_select(this);
elem.style('opacity', elem.property('opacity1'));
const func = elem.node()._mouseenter;
if (isFunc(func)) func();
})
.on('mouseleave', function() {
const elem = d3_select(this);
elem.style('opacity', elem.property('opacity0'));
const func = elem.node()._mouseleave;
if (isFunc(func)) func();
});
if ('recs' in btn) {
const rec = {};
for (let n = 0; n < btn.recs.length; ++n) {
Object.assign(rec, btn.recs[n]);
svg.append('rect').attr('x', rec.x).attr('y', rec.y)
.attr('width', rec.w).attr('height', rec.h)
.style('fill', rec.f);
}
} else
svg.append('svg:path').attr('d', btn.path);
// special rect to correctly get mouse events for whole button area
svg.append('svg:rect').attr('x', 0).attr('y', 0).attr('width', 512).attr('height', 512)
.style('opacity', 0).style('fill', 'none').style('pointer-events', 'visibleFill')
.append('svg:title').text(title);
return svg;
}
}; // ToolbarIcons
/** @summary Register handle to react on window resize
* @desc function used to react on browser window resize event
* While many resize events could come in short time,
* resize will be handled with delay after last resize event
* @param {object|string} handle can be function or object with checkResize function or dom where painting was done
* @param {number} [delay] - one could specify delay after which resize event will be handled
* @protected */
function registerForResize(handle, delay) {
if (!handle || isBatchMode() || (typeof window === 'undefined') || (typeof document === 'undefined')) return;
let myInterval = null, myDelay = delay || 300;
if (myDelay < 20) myDelay = 20;
function ResizeTimer() {
myInterval = null;
document.body.style.cursor = 'wait';
if (isFunc(handle))
handle();
else if (isFunc(handle?.checkResize))
handle.checkResize();
else {
const node = new BasePainter(handle).selectDom();
if (!node.empty()) {
const mdi = node.property('mdi');
if (isFunc(mdi?.checkMDIResize))
mdi.checkMDIResize();
else
resize(node.node());
}
}
document.body.style.cursor = 'auto';
}
window.addEventListener('resize', () => {
if (myInterval !== null) clearTimeout(myInterval);
myInterval = setTimeout(ResizeTimer, myDelay);
});
}
/** @summary Detect mouse right button
* @private */
function detectRightButton(event) {
return (event?.buttons === 2) || (event?.button === 2);
}
/** @summary Add move handlers for drawn element
* @private */
function addMoveHandler(painter, enabled = true, hover_handler = false) {
if (!settings.MoveResize || painter.isBatchMode() || !painter.draw_g) return;
if (painter.getPadPainter()?.isEditable() === false)
enabled = false;
if (!enabled) {
if (painter.draw_g.property('assigned_move')) {
const drag_move = d3_drag().subject(Object);
drag_move.on('start', null).on('drag', null).on('end', null);
painter.draw_g
.style('cursor', null)
.property('assigned_move', null)
.call(drag_move);
}
return;
}
if (painter.draw_g.property('assigned_move')) return;
const drag_move = d3_drag().subject(Object);
let not_changed = true, move_disabled = false;
drag_move
.on('start', function(evnt) {
move_disabled = this.moveEnabled ? !this.moveEnabled() : false;
if (move_disabled) return;
if (detectRightButton(evnt.sourceEvent)) return;
evnt.sourceEvent.preventDefault();
evnt.sourceEvent.stopPropagation();
const pos = d3_pointer(evnt, this.draw_g.node());
not_changed = true;
if (this.moveStart)
this.moveStart(pos[0], pos[1]);
}.bind(painter)).on('drag', function(evnt) {
if (move_disabled) return;
evnt.sourceEvent.preventDefault();
evnt.sourceEvent.stopPropagation();
not_changed = false;
if (this.moveDrag)
this.moveDrag(evnt.dx, evnt.dy);
}.bind(painter)).on('end', function(evnt) {
if (move_disabled) return;
evnt.sourceEvent.preventDefault();
evnt.sourceEvent.stopPropagation();
if (this.moveEnd)
this.moveEnd(not_changed);
let arg = null;
if (not_changed) {
// if not changed - provide click position
const pos = d3_pointer(evnt, this.draw_g.node());
arg = { x: pos[0], y: pos[1], dbl: false };
}
this.getPadPainter()?.selectObjectPainter(this, arg);
}.bind(painter));
painter.draw_g
.style('cursor', hover_handler ? 'pointer' : 'move')
.property('assigned_move', true)
.call(drag_move);
if (hover_handler) {
painter.draw_g.on('mouseenter', () => painter.draw_g.style('text-decoration', 'underline'))
.on('mouseleave', () => painter.draw_g.style('text-decoration', null));
}
}
/** @summary Inject style
* @param {String} code - css string
* @private */
function injectStyle(code, node, tag) {
if (isBatchMode() || !code || (typeof document === 'undefined'))
return true;
const styles = (node || document).getElementsByTagName('style');
for (let n = 0; n < styles.length; ++n) {
if (tag && styles[n].getAttribute('tag') === tag) {
styles[n].innerHTML = code;
return true;
}
if (styles[n].innerHTML === code)
return true;
}
const element = document.createElement('style');
if (tag) element.setAttribute('tag', tag);
element.innerHTML = code;
(node || document.head).appendChild(element);
return true;
}
/** @summary Select predefined style
* @private */
function selectgStyle(name) {
gStyle.fName = name;
switch (name) {
case 'Modern': Object.assign(gStyle, { fFrameBorderMode: 0, fFrameFillColor: 0,
fCanvasBorderMode: 0, fCanvasColor: 0, fPadBorderMode: 0, fPadColor: 0, fStatColor: 0,
fTitleAlign: 23, fTitleX: 0.5, fTitleBorderSize: 0, fTitleColor: 0, fTitleStyle: 0,
fOptStat: 1111, fStatY: 0.935,
fLegendBorderSize: 1, fLegendFont: 42, fLegendTextSize: 0, fLegendFillColor: 0 });
break;
case 'Plain': Object.assign(gStyle, { fFrameBorderMode: 0,
fCanvasBorderMode: 0, fPadBorderMode: 0, fPadColor: 0, fCanvasColor: 0,
fTitleColor: 0, fTitleBorderSize: 0, fStatColor: 0, fStatBorderSize: 1, fLegendBorderSize: 1 });
break;
case 'Bold': Object.assign(gStyle, { fCanvasColor: 10, fCanvasBorderMode: 0,
fFrameLineWidth: 3, fFrameFillColor: 10,
fPadColor: 10, fPadTickX: 1, fPadTickY: 1, fPadBottomMargin: 0.15, fPadLeftMargin: 0.15,
fTitleColor: 10, fTitleTextColor: 600, fStatColor: 10 });
break;
}
}
let _storage_prefix = 'jsroot_';
/** @summary Set custom prefix for the local storage
* @private */
function setStoragePrefix(prefix) {
_storage_prefix = prefix || 'jsroot_';
}
/** @summary Save object in local storage
* @private */
function saveLocalStorage(obj, expires, name) {
if (typeof localStorage === 'undefined')
return;
if (Number.isFinite(expires) && (expires < 0))
localStorage.removeItem(_storage_prefix + name);
else
localStorage.setItem(_storage_prefix + name, btoa_func(JSON.stringify(obj)));
}
/** @summary Read object from storage with specified name
* @private */
function readLocalStorage(name) {
if (typeof localStorage === 'undefined')
return null;
const v = localStorage.getItem(_storage_prefix + name),
s = v ? JSON.parse(atob_func(v)) : null;
return isObject(s) ? s : null;
}
/** @summary Save JSROOT settings in local storage
* @param {Number} [expires] - delete settings when negative
* @param {String} [name] - storage name, 'settings' by default
* @private */
function saveSettings(expires = 365, name = 'settings') {
saveLocalStorage(settings, expires, name);
}
/** @summary Read JSROOT settings from specified cookie parameter
* @param {Boolean} only_check - when true just checks if settings were stored before with provided name
* @param {String} [name] - storage name, 'settings' by default
* @private */
function readSettings(only_check = false, name = 'settings') {
const s = readLocalStorage(name);
if (!s) return false;
if (!only_check)
Object.assign(settings, s);
return true;
}
/** @summary Save JSROOT gStyle object in local storage
* @param {Number} [expires] - delete style when negative
* @param {String} [name] - storage name, 'style' by default
* @private */
function saveStyle(expires = 365, name = 'style') {
saveLocalStorage(gStyle, expires, name);
}
/** @summary Read JSROOT gStyle object from local storage
* @param {Boolean} [only_check] - when true just checks if settings were stored before with provided name
* @param {String} [name] - storage name, 'style' by default
* @private */
function readStyle(only_check = false, name = 'style') {
const s = readLocalStorage(name);
if (!s) return false;
if (!only_check)
Object.assign(gStyle, s);
return true;
}
let _saveFileFunc = null;
/** @summary Returns image file content as it should be stored on the disc
* @desc Replaces all kind of base64 coding
* @private */
function getBinFileContent(content) {
if (content.indexOf(prSVG) === 0)
return decodeURIComponent(content.slice(prSVG.length));
if (content.indexOf('data:image/') === 0) {
const p = content.indexOf('base64,');
if (p > 0) {
const base64 = content.slice(p + 7);
return atob_func(base64);
}
}
return content;
}
/** @summary Function store content as file with filename
* @private */
async function saveFile(filename, content) {
if (isFunc(_saveFileFunc))
return _saveFileFunc(filename, getBinFileContent(content));
if (isNodeJs()) {
return import('fs').then(fs => {
fs.writeFileSync(filename, getBinFileContent(content));
return true;
});
} else if (typeof document !== 'undefined') {
const a = document.createElement('a');
a.download = filename;
a.href = content;
document.body.appendChild(a);
return new Promise(resolve => {
a.addEventListener('click', () => { a.parentNode.removeChild(a); resolve(true); });
a.click();
});
}
return false;
}
/** @summary Function store content as file with filename
* @private */
function setSaveFile(func) {
_saveFileFunc = func;
}
/** @summary Returns color id for the color
* @private */
function getColorId(col) {
const arr = getRootColors();
let id = -1;
if (isStr(col)) {
if (!col || (col === 'none'))
id = 0;
else {
for (let k = 1; k < arr.length; ++k)
if (arr[k] === col) { id = k; break; }
}
if ((id < 0) && (col.indexOf('rgb') === 0))
id = 9999;
} else if (Number.isInteger(col) && arr[col]) {
id = col;
col = arr[id];
}
return { id, col };
}
/** @summary Produce exec string for WebCanvas to set color value
* @desc Color can be id or string, but should belong to list of known colors
* For higher color numbers TColor::GetColor(r,g,b) will be invoked to ensure color is exists
* @private */
function getColorExec(col, method) {
const d = getColorId(col);
if (d.id < 0)
return '';
// for higher color numbers ensure that such color exists
if (d.id >= 50) {
const c = d3_color(d.col);
d.id = `TColor::GetColor(${c.r},${c.g},${c.b})`;
}
return `exec:${method}(${d.id})`;
}
/** @summary Change object member in the painter
* @desc Used when interactively change in the menu
* Special handling for color is provided
* @private */
function changeObjectMember(painter, member, val, is_color) {
if (is_color) {
const d = getColorId(val);
if ((d.id < 0) || (d.id === 9999))
return;
val = d.id;
}
const obj = painter?.getObject();
if (obj && (obj[member] !== undefined))
obj[member] = val;
}
Object.assign(internals.jsroot, { addMoveHandler, registerForResize });
export { showProgress, closeCurrentWindow, loadOpenui5, ToolbarIcons, registerForResize,
detectRightButton, addMoveHandler, injectStyle,
selectgStyle, setStoragePrefix, saveSettings, readSettings, saveStyle, readStyle,
saveFile, setSaveFile, getBinFileContent, getColorExec, changeObjectMember };