diff --git a/.gitignore b/.gitignore index c992c2c0..287adb9a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,16 @@ node_modules .grunt web/docs/html *~ + +# Build outputs +dist/ +*.worker.js +*.worker.js.map +web/js/dc-graph.js +web/js/dc-graph.js.map +web/css/dc.graph.css +d3v4-force.js +lysenko-interval-tree.js + +# Package manager lock files (keep package-lock.json, ignore yarn) +yarn.lock diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 00000000..2312dc58 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..af5ce55c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "files.associations": { + "*.js": "javascript" + }, + "javascript.suggest.paths": true, + "javascript.validate.enable": true, + "javascript.preferences.importModuleSpecifier": "relative", + "typescript.disableAutomaticTypeAcquisition": false +} diff --git a/CLAUDE.md b/CLAUDE.md index a8b3f17b..0b6a1281 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -19,33 +19,27 @@ dc.graph.js is a JavaScript library for dynamic, interactive graph visualization ## Build System -The project uses Grunt for building. Key commands: +The project uses npm scripts with Rollup for building. Key commands: ```bash -# Build the library (concatenates source files) -grunt build +# Build the library (bundles ES6 modules with Rollup) +npm run build -# Build and copy assets to web directory -grunt copy +# Build and watch for changes during development +npm run dev -# Run development server with live reload on port 8888 -grunt server +# Run development server on port 8888 +npm run serve -# Generate documentation -grunt docs - -# Run linting -grunt lint - -# Build minified version -grunt uglify +# Build and start development server +npm start ``` **Build outputs:** -- `dc.graph.js` - main library file (concatenated from src/ files in order defined in Gruntfile.js) -- `dc.graph.min.js` - minified version +- `dist/dc-graph.js` - main library file (ES6 modules bundled with Rollup) +- `dist/dc-graph.js.map` - source map - `dc.graph.*.worker.js` - web worker files for different layout engines -- Files are also copied to `web/js/` for examples +- **Files automatically copied to `web/js/` via rollup copy plugin** ## Source Architecture @@ -83,25 +77,42 @@ Layout computation can be offloaded to web workers for performance. Worker files - Example files in `web/` directory demonstrate various features - No automated test suite - examples serve as integration tests -- `grunt server` runs local development server for testing examples +- `npm run serve` runs local development server for testing examples ## Dependencies **Runtime dependencies:** -- D3 v3 (core visualization) -- dc.js ~2.1.0 (chart integration) +- D3 v3 (core visualization) - migrating to D3 v5.16.0 +- dc.js 4.0.5 (chart integration) - IMPORTANT: Use 4.0.5, not newer versions - crossfilter2 (data filtering) - Various layout libraries: webcola, dagre, viz.js -**Note:** Project is based on older D3 v3 and is not actively maintained but still functional. +**Note:** Project is being migrated from D3 v3 to D3 v5. Currently using dc.js 4.0.5 for compatibility. ## Development Notes - Use gtimeout because we're on a mac -- Use `npx grunt server` for this repo +- Use `npm run serve` for development server + +## D3 v5 Migration Rules + +**Dispatch API Changes**: In D3 v3→v5, dispatch calls changed from `dispatch.eventName(args...)` to `dispatch.call('eventName', thisArg, args...)`. Always use `null` as the thisArg parameter. + +- ❌ D3 v3: `dispatch.selected(data)` +- ✅ D3 v5: `dispatch.call('selected', null, data)` + +**Event Handling Issues**: +- TODO: SVG mouseup events aren't firing properly in D3 v5 - temporarily using click events for node creation in draw_graphs.js +- Event handling may need further investigation for full mouse interaction compatibility ## Claude Memories - please remove trailing whitespace from your edits -- not necessary to build, we have a server with live reload running -- be terse and avoid purple prose in commit messages \ No newline at end of file +- **Testing workflow**: Gordon runs a dev server with auto-build/reload, so usually no need to manually build. But `npm run build` is safe if needed (rollup copy plugin updates web/js/ automatically) +- be terse and avoid purple prose in commit messages +- do not check artifacts into the repo +- yes but please stop adding useless comments +- use arrow functions wherever possible +- remember to user jsdelivr for d3 imports +- use conditional chaining +- always use let and const not var diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index d2170a5d..00000000 --- a/Gruntfile.js +++ /dev/null @@ -1,482 +0,0 @@ -module.exports = function (grunt) { - 'use strict'; - - require('load-grunt-tasks')(grunt, { - pattern: ['grunt-*'] - }); - require('time-grunt')(grunt); - - var config = { - src: 'src', - spec: 'spec', - web: 'web', - pkg: require('./package.json'), - banner: grunt.file.read('./LICENSE_BANNER'), - jsFiles: module.exports.jsFiles, - colaWorkerFiles: [ - 'src/core.js', - 'src/generate_objects.js', - 'src/graphviz_attrs.js', - 'src/cola_layout.js', - 'src/webworker_message.js' - ], - dagreWorkerFiles: [ - 'src/core.js', - 'src/generate_objects.js', - 'src/graphviz_attrs.js', - 'src/dagre_layout.js', - 'src/webworker_message.js' - ], - d3v4ForceWorkerFiles: [ - 'src/core.js', - 'src/generate_objects.js', - 'src/graphviz_attrs.js', - 'src/d3v4_force_layout.js', - 'src/webworker_message.js' - ], - d3ForceWorkerFiles: [ - 'src/core.js', - 'src/generate_objects.js', - 'src/graphviz_attrs.js', - 'src/d3_force_layout.js', - 'src/webworker_message.js' - ], - dynagraphWorkerFiles: [ - 'src/core.js', - 'src/generate_objects.js', - 'src/graphviz_attrs.js', - 'src/dynagraph_layout.js', - 'src/webworker_message.js' - ] - }; - - grunt.initConfig({ - conf: config, - - concat: { - options : { - process: true, - sourceMap: true, - banner : '<%= conf.banner %>' - }, - main: { - src: '<%= conf.jsFiles %>', - dest: '<%= conf.pkg.name %>.js' - }, - colaWorker: { - src: '<%= conf.colaWorkerFiles %>', - dest: '<%= conf.pkg.name %>.cola.worker.js' - }, - dagreWorker: { - src: '<%= conf.dagreWorkerFiles %>', - dest: '<%= conf.pkg.name %>.dagre.worker.js' - }, - d3v4ForceWorker: { - src: '<%= conf.d3v4ForceWorkerFiles %>', - dest: '<%= conf.pkg.name %>.d3v4-force.worker.js' - }, - d3ForceWorker: { - src: '<%= conf.d3ForceWorkerFiles %>', - dest: '<%= conf.pkg.name %>.d3-force.worker.js' - }, - dynagraphWorker: { - src: '<%= conf.dynagraphWorkerFiles %>', - dest: '<%= conf.pkg.name %>.dynagraph.worker.js' - } - }, - uglify: { - jsmin: { - options: { - mangle: true, - compress: true, - sourceMap: true, - banner : '<%= conf.banner %>' - }, - src: '<%= conf.pkg.name %>.js', - dest: '<%= conf.pkg.name %>.min.js' - } - }, - jscs: { - old: { - src: ['<%= conf.spec %>/**/*.js'], - options: { - validateIndentation: 4 - } - }, - source: { - src: ['<%= conf.src %>/**/*.js', '!<%= conf.src %>/{banner,footer}.js', 'Gruntfile.js', - 'grunt/*.js', '<%= conf.web %>/stock.js'], - options: { - config: '.jscsrc' - } - } - }, - jshint: { - source: { - src: ['<%= conf.src %>/**/*.js', 'Gruntfile.js', 'grunt/*.js', '<%= conf.web %>/stock.js'], - options: { - jshintrc: '.jshintrc', - ignores: ['<%= conf.src %>/banner.js', '<%= conf.src %>/footer.js'] - } - } - }, - watch: { - scripts: { - files: ['<%= conf.src %>/**/*.js', '*.js', 'dc.graph.css', '<%= conf.web %>/js/*.js', '!<%= conf.web %>/js/dc.graph*.js', '!<%= conf.web %>/js/d3*.js', '!<%= conf.web %>/js/crossfilter.js', '!<%= conf.web %>/js/dc.js', '!<%= conf.web %>/js/cola.js', '!<%= conf.web %>/js/dagre.js', '!<%= conf.web %>/js/viz.js', '!<%= conf.web %>/js/jquery*.js', '!<%= conf.web %>/js/lodash.js', '!<%= conf.web %>/js/bootstrap.js', '!<%= conf.web %>/js/metagraph.js', '!<%= conf.web %>/js/queue.js', '!<%= conf.web %>/js/graphlib-dot*.js', '!<%= conf.web %>/js/*-layout.js', '!<%= conf.web %>/js/lysenko-interval-tree.js', '!<%= conf.web %>/js/chart.registry.js', '!<%= conf.web %>/js/timeline.js', '!<%= conf.web %>/js/querystring.js', '!<%= conf.web %>/js/sync-url-options.js', '!<%= conf.web %>/js/promise-polyfill.js', '!<%= conf.web %>/js/classlist-polyfill.js'], - tasks: ['build', 'copy'], - options: { - livereload: true - } - }, - docs: { - files: ['welcome.md', '<%= conf.src %>/**/*.js', 'dc.graph.css'], - tasks: ['docs'] - }, - reload: { - files: ['<%= conf.pkg.name %>.js', - '<%= conf.pkg.name %>css', - '<%= conf.web %>/js/<%= conf.pkg.name %>.js', - '<%= conf.web %>/css/<%= conf.pkg.name %>.css', - '<%= conf.pkg.name %>.min.js'], - options: { - livereload: true - } - }, - html: { - files: ['<%= conf.web %>/**/*.html'], - options: { - livereload: true - } - } - }, - connect: { - server: { - options: { - port: process.env.PORT || 8888, - base: '.', - middleware: function(connect, options, middlewares) { - var fs = require('fs'); - var path = require('path'); - - middlewares.unshift(function(req, res, next) { - if(res.req && /\.wasm$/.test(res.req.url)) - res.setHeader('Content-Type', 'application/wasm'); - return next(); - }); - - // Inject livereload script into HTML files during development - middlewares.unshift(function(req, res, next) { - if (req.url.match(/\.html(\?|$)/)) { - var filePath = path.join('.', req.url.split('?')[0]); - if (fs.existsSync(filePath)) { - var html = fs.readFileSync(filePath, 'utf8'); - // Only inject if not already present - if (html.indexOf('livereload.js') === -1) { - html = html.replace('', - ' \n'); - } - res.setHeader('Content-Type', 'text/html'); - res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); - res.setHeader('Pragma', 'no-cache'); - res.setHeader('Expires', '0'); - res.end(html); - return; - } - } - return next(); - }); - - return middlewares; - }, - } - } - }, - jsdoc: { - dist: { - src: ['welcome.md', '<%= conf.src %>/**/*.js', '!<%= conf.src %>/{banner,footer}.js'], - options: { - destination: 'web/docs/html', - template: 'node_modules/ink-docstrap/template', - configure: 'jsdoc.conf.json' - } - } - }, - jsdoc2md: { - dist: { - src: 'dc.graph.js', - dest: 'web/docs/api-latest.md' - } - }, - copy: { - 'dc-to-gh': { - files: [ - { - nonull: true, - expand: true, - flatten: true, - src: [ - '<%= conf.pkg.name %>.css', - 'node_modules/bootstrap/dist/css/bootstrap.css', - 'node_modules/dc/dc.css', - 'node_modules/jquery-ui-dist/jquery-ui.css', - 'node_modules/x-editable/dist/jqueryui-editable/css/jqueryui-editable.css' - ], - dest: '<%= conf.web %>/css/' - }, - { - expand: true, - flatten: true, - nonull: true, - src: [ - 'node_modules/jquery-ui-dist/images/*' - ], - dest: '<%= conf.web %>/css/images/' - }, - { - expand: true, - flatten: true, - nonull: true, - src: [ - 'node_modules/x-editable/dist/jqueryui-editable/img/*' - ], - dest: '<%= conf.web %>/img/' - }, - { - expand: true, - flatten: true, - nonull: true, - src: [ - 'node_modules/ionicons/dist/svg/*.svg' - ], - dest: '<%= conf.web %>/img/ionicons/', - rename: function(dest, src) { - // Map new ionicons names to old md- prefixed names - return dest + 'md-' + src; - } - }, - { - nonull: true, - expand: true, - flatten: true, - src: [ - '<%= conf.pkg.name %>.js', - '<%= conf.pkg.name %>.js.map', - '<%= conf.pkg.name %>.min.js', - '<%= conf.pkg.name %>.min.js.map', - '<%= conf.pkg.name %>.cola.worker.js', - '<%= conf.pkg.name %>.cola.worker.js.map', - '<%= conf.pkg.name %>.dagre.worker.js', - '<%= conf.pkg.name %>.dagre.worker.js.map', - '<%= conf.pkg.name %>.d3v4-force.worker.js', - '<%= conf.pkg.name %>.d3v4-force.worker.js.map', - '<%= conf.pkg.name %>.d3-force.worker.js', - '<%= conf.pkg.name %>.d3-force.worker.js.map', - '<%= conf.pkg.name %>.dynagraph.worker.js', - '<%= conf.pkg.name %>.dynagraph.worker.js.map', - 'd3.flexdivs.js', - 'dc.graph.tracker.domain.js', - 'd3v4-force.js', - 'lysenko-interval-tree.js', - 'incrface-umd.js', - 'yoga-layout.js', - 'querystring.js', - 'sync-url-options.js', - 'chart.registry.js', - 'timeline.js', - 'node_modules/bootstrap/dist/js/bootstrap.js', - 'node_modules/crossfilter2/crossfilter.js', - 'node_modules/css-layout/dist/css-layout.js', - 'node_modules/d3/d3.js', - 'node_modules/dc/dc.js', - 'node_modules/graphlib-dot/dist/graphlib-dot.js', - 'node_modules/jquery/dist/jquery.js', - 'node_modules/jquery-ui-dist/jquery-ui.js', - 'node_modules/lodash/lodash.js', - 'node_modules/metagraph/metagraph.js', - 'node_modules/queue-async/build/queue.js', - 'node_modules/dagre/dist/dagre.js', - 'node_modules/webcola/WebCola/cola.js', - 'node_modules/viz.js/viz.js', - 'node_modules/x-editable/dist/jqueryui-editable/js/jqueryui-editable.js' - ], - dest: '<%= conf.web %>/js/' - }, - { - nonull: true, - src: 'node_modules/promise-polyfill/dist/polyfill.js', - dest: '<%= conf.web %>/js/promise-polyfill.js' - }, - { - nonull: true, - src: 'node_modules/classlist-polyfill/src/index.js', - dest: '<%= conf.web %>/js/classlist-polyfill.js' - }, - { - nonull: true, - src: 'node_modules/@fortawesome/fontawesome-free/css/all.css', - dest: '<%= conf.web %>/css/fontawesome-all.css' - }, - { - expand: true, - flatten: true, - src: [ - 'node_modules/@fortawesome/fontawesome-free/webfonts/*' - ], - dest: '<%= conf.web %>/webfonts/' - }, - { - nonull: true, - src: 'node_modules/d3-tip/index.js', - dest: '<%= conf.web %>/js/d3-tip.js' - }, - { - nonull: true, - src: 'node_modules/d3-tip/examples/example-styles.css', - dest: '<%= conf.web %>/css/d3-tip.css' - } - ] - } - }, - 'gh-pages': { - options: { - base: '<%= conf.web %>', - message: 'Synced from from master branch.' - }, - src: ['**'] - }, - shell: { - merge: { - command: function (pr) { - return [ - 'git fetch origin', - 'git checkout master', - 'git reset --hard origin/master', - 'git fetch origin', - 'git merge --no-ff origin/pr/' + pr + ' -m \'Merge pull request #' + pr + '\'' - ].join('&&'); - }, - options: { - stdout: true, - failOnError: true - } - }, - amend: { - command: 'git commit -a --amend --no-edit', - options: { - stdout: true, - failOnError: true - } - }, - hooks: { - command: 'cp -n scripts/pre-commit.sh .git/hooks/pre-commit' + - ' || echo \'Cowardly refusing to overwrite your existing git pre-commit hook.\'' - } - } - }); - - // custom tasks - grunt.registerTask('merge', 'Merge a github pull request.', function (pr) { - grunt.log.writeln('Merge Github Pull Request #' + pr); - grunt.task.run(['shell:merge:' + pr, 'test' , 'shell:amend']); - }); - grunt.registerTask('test-stock-example', 'Test a new rendering of the stock example web page against a ' + - 'baseline rendering', function (option) { - require('./regression/stock-regression-test.js').testStockExample(this.async(), option === 'diff'); - }); - grunt.registerTask('update-stock-example', 'Update the baseline stock example web page.', function () { - require('./regression/stock-regression-test.js').updateStockExample(this.async()); - }); - - // task aliases - grunt.registerTask('build', ['concat']); - grunt.registerTask('docs', ['build', 'copy', 'jsdoc', 'jsdoc2md']); - grunt.registerTask('web', ['docs', 'gh-pages']); - grunt.registerTask('server', ['build', 'copy', 'connect:server', 'watch']); - grunt.registerTask('server:docs', ['docs', 'connect:server', 'watch:docs']); - grunt.registerTask('lint', ['build', 'jshint', 'jscs']); - grunt.registerTask('default', ['build', 'shell:hooks']); - grunt.registerTask('doc-debug', ['build', 'jsdoc', 'jsdoc2md', 'connect:server', 'watch:docs']); -}; - -module.exports.jsFiles = [ - 'src/banner.js', // NOTE: keep this first - 'src/core.js', - 'src/utils.js', - 'src/depth_first_traversal.js', - 'src/generate_objects.js', - 'src/shape.js', - 'src/arrows.js', - 'src/node_contents.js', - 'src/diagram.js', - 'src/render_svg.js', - 'src/render_webgl.js', - 'src/engine.js', - 'src/webworker_layout.js', - 'src/graphviz_attrs.js', - 'src/cola_layout.js', - 'src/dagre_layout.js', - 'src/tree_layout.js', - 'src/graphviz_layout.js', - 'src/dynagraph_layout.js', - 'src/d3_force_layout.js', - 'src/d3v4_force_layout.js', - 'src/flexbox_layout.js', - 'src/manual_layout.js', - 'src/layered_layout.js', - 'src/place_ports.js', - 'src/grid.js', - 'src/annotate_layers.js', - 'src/troubleshoot.js', - 'src/validate.js', - 'src/legend.js', - 'src/constraint_pattern.js', - 'src/tree_positions.js', - 'src/tree_constraints.js', - 'src/mode.js', - 'src/tip.js', - 'src/dropdown.js', - 'src/keyboard.js', - 'src/edit_text.js', - 'src/brush.js', - 'src/select_things.js', - 'src/select_nodes.js', - 'src/select_edges.js', - 'src/select_ports.js', - 'src/move_nodes.js', - 'src/fix_nodes.js', - 'src/filter_selection.js', - 'src/delete_things.js', - 'src/delete_nodes.js', - 'src/label_things.js', - 'src/label_nodes.js', - 'src/label_edges.js', - 'src/annotate_nodes.js', - 'src/highlight_things_group.js', - 'src/highlight_things.js', - 'src/highlight_neighbors_group.js', - 'src/highlight_neighbors.js', - 'src/highlight_radius.js', - 'src/highlight_paths_group.js', - 'src/highlight_paths.js', - 'src/spline_paths.js', - 'src/draw_clusters.js', - 'src/expand_collapse.js', - 'src/expanded_hidden.js', - 'src/draw_graphs.js', - 'src/match_ports.js', - 'src/match_opposites.js', - 'src/wildcard_ports.js', - 'src/symbol_port_style.js', - 'src/load_graph.js', - 'src/munge_graph.js', - 'src/flat_group.js', - 'src/convert.js', - 'src/transform.js', - 'src/path_reader.js', - 'src/path_selector.js', - 'src/generate.js', - 'src/supergraph.js', - 'src/line_breaks.js', - 'src/type_graph.js', - 'src/footer.js' // NOTE: keep this last -]; diff --git a/chart.registry.js b/chart.registry.js index 4fcea58d..4ea3ba04 100644 --- a/chart.registry.js +++ b/chart.registry.js @@ -12,16 +12,16 @@ var types = {}; chart_registry.create_type = function(type, constructor) { - if(!types[type]) + if (!types[type]) types[type] = {constructor: constructor, groups: {}}; return types[type]; }; chart_registry.create_group = function(type, groupname) { - if(!types[type]) - throw new Error('chart registry type "' + type + '" not known'); - if(!types[type][groupname]) + if (!types[type]) + throw new Error('chart registry type "'+type+'" not known'); + if (!types[type][groupname]) types[type][groupname] = types[type].constructor(); return types[type][groupname]; }; diff --git a/d3.flexdivs.js b/d3.flexdivs.js index e43411b7..9e9bbf62 100644 --- a/d3.flexdivs.js +++ b/d3.flexdivs.js @@ -4,7 +4,7 @@ function flex_div_helper_mapper(map) { me.style({ flex: function(d) { - if(d.flex) + if (d.flex) return d.flex; var pdat = d3.select(this.parentNode).datum(); return pdat && pdat.deflex || null; @@ -14,7 +14,7 @@ function flex_div_helper_mapper(map) { }, 'flex-direction': function(d) { return d.direction || null; - } + }, }); var divs = me.selectAll(function() { @@ -27,11 +27,13 @@ function flex_div_helper_mapper(map) { return d.class || null; }, id: function(d) { - return d.bring ? 'wrap-' + d.id : d.id; - } + return d.bring ? 'wrap-'+d.id : d.id; + }, }); divs.each(flex_div_helper); - divs.filter(function(d) { return d.bring && !map[d.id]; }) + divs.filter(function(d) { + return d.bring && !map[d.id]; + }) .append('div') .attr('id', function(d) { return d.id; @@ -39,12 +41,12 @@ function flex_div_helper_mapper(map) { }; } function bringover(data, map) { - if(data.id && data.bring) { + if (data.id && data.bring) { var e = document.getElementById(data.id); - if(e) + if (e) map[data.id] = e.parentNode.removeChild(e); } - if(data.divs) + if (data.divs) data.divs.forEach(function(d) { bringover(d, map); }); @@ -57,8 +59,8 @@ function flex_divs(root, data, place) { d3.select(root).data([data]) .each(flex_div_helper); Object.keys(map).forEach(function(k) { - document.getElementById('wrap-' + k).appendChild(map[k]); - if(place) + document.getElementById('wrap-'+k).appendChild(map[k]); + if (place) place(k); }); } diff --git a/d3v4-force.index.js b/d3v4-force.index.js deleted file mode 100644 index ae9fd02f..00000000 --- a/d3v4-force.index.js +++ /dev/null @@ -1,2 +0,0 @@ -export * from "d3-force"; -export * from "d3-force-straighten-paths"; diff --git a/d3v4-force.js b/d3v4-force.js deleted file mode 100644 index d5d78905..00000000 --- a/d3v4-force.js +++ /dev/null @@ -1,1585 +0,0 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : - typeof define === 'function' && define.amd ? define(['exports'], factory) : - (factory((global.d3v4 = {}))); -}(this, (function (exports) { 'use strict'; - -function center(x, y) { - var nodes; - - if (x == null) x = 0; - if (y == null) y = 0; - - function force() { - var i, - n = nodes.length, - node, - sx = 0, - sy = 0; - - for (i = 0; i < n; ++i) { - node = nodes[i], sx += node.x, sy += node.y; - } - - for (sx = sx / n - x, sy = sy / n - y, i = 0; i < n; ++i) { - node = nodes[i], node.x -= sx, node.y -= sy; - } - } - - force.initialize = function(_) { - nodes = _; - }; - - force.x = function(_) { - return arguments.length ? (x = +_, force) : x; - }; - - force.y = function(_) { - return arguments.length ? (y = +_, force) : y; - }; - - return force; -} - -function constant(x) { - return function() { - return x; - }; -} - -function jiggle() { - return (Math.random() - 0.5) * 1e-6; -} - -function tree_add(d) { - var x = +this._x.call(null, d), - y = +this._y.call(null, d); - return add(this.cover(x, y), x, y, d); -} - -function add(tree, x, y, d) { - if (isNaN(x) || isNaN(y)) return tree; // ignore invalid points - - var parent, - node = tree._root, - leaf = {data: d}, - x0 = tree._x0, - y0 = tree._y0, - x1 = tree._x1, - y1 = tree._y1, - xm, - ym, - xp, - yp, - right, - bottom, - i, - j; - - // If the tree is empty, initialize the root as a leaf. - if (!node) return tree._root = leaf, tree; - - // Find the existing leaf for the new point, or add it. - while (node.length) { - if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; - if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; - if (parent = node, !(node = node[i = bottom << 1 | right])) return parent[i] = leaf, tree; - } - - // Is the new point is exactly coincident with the existing point? - xp = +tree._x.call(null, node.data); - yp = +tree._y.call(null, node.data); - if (x === xp && y === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree; - - // Otherwise, split the leaf node until the old and new point are separated. - do { - parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4); - if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; - if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; - } while ((i = bottom << 1 | right) === (j = (yp >= ym) << 1 | (xp >= xm))); - return parent[j] = node, parent[i] = leaf, tree; -} - -function addAll(data) { - var d, i, n = data.length, - x, - y, - xz = new Array(n), - yz = new Array(n), - x0 = Infinity, - y0 = Infinity, - x1 = -Infinity, - y1 = -Infinity; - - // Compute the points and their extent. - for (i = 0; i < n; ++i) { - if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d))) continue; - xz[i] = x; - yz[i] = y; - if (x < x0) x0 = x; - if (x > x1) x1 = x; - if (y < y0) y0 = y; - if (y > y1) y1 = y; - } - - // If there were no (valid) points, inherit the existing extent. - if (x1 < x0) x0 = this._x0, x1 = this._x1; - if (y1 < y0) y0 = this._y0, y1 = this._y1; - - // Expand the tree to cover the new points. - this.cover(x0, y0).cover(x1, y1); - - // Add the new points. - for (i = 0; i < n; ++i) { - add(this, xz[i], yz[i], data[i]); - } - - return this; -} - -function tree_cover(x, y) { - if (isNaN(x = +x) || isNaN(y = +y)) return this; // ignore invalid points - - var x0 = this._x0, - y0 = this._y0, - x1 = this._x1, - y1 = this._y1; - - // If the quadtree has no extent, initialize them. - // Integer extent are necessary so that if we later double the extent, - // the existing quadrant boundaries don’t change due to floating point error! - if (isNaN(x0)) { - x1 = (x0 = Math.floor(x)) + 1; - y1 = (y0 = Math.floor(y)) + 1; - } - - // Otherwise, double repeatedly to cover. - else if (x0 > x || x > x1 || y0 > y || y > y1) { - var z = x1 - x0, - node = this._root, - parent, - i; - - switch (i = (y < (y0 + y1) / 2) << 1 | (x < (x0 + x1) / 2)) { - case 0: { - do parent = new Array(4), parent[i] = node, node = parent; - while (z *= 2, x1 = x0 + z, y1 = y0 + z, x > x1 || y > y1); - break; - } - case 1: { - do parent = new Array(4), parent[i] = node, node = parent; - while (z *= 2, x0 = x1 - z, y1 = y0 + z, x0 > x || y > y1); - break; - } - case 2: { - do parent = new Array(4), parent[i] = node, node = parent; - while (z *= 2, x1 = x0 + z, y0 = y1 - z, x > x1 || y0 > y); - break; - } - case 3: { - do parent = new Array(4), parent[i] = node, node = parent; - while (z *= 2, x0 = x1 - z, y0 = y1 - z, x0 > x || y0 > y); - break; - } - } - - if (this._root && this._root.length) this._root = node; - } - - // If the quadtree covers the point already, just return. - else return this; - - this._x0 = x0; - this._y0 = y0; - this._x1 = x1; - this._y1 = y1; - return this; -} - -function tree_data() { - var data = []; - this.visit(function(node) { - if (!node.length) do data.push(node.data); while (node = node.next) - }); - return data; -} - -function tree_extent(_) { - return arguments.length - ? this.cover(+_[0][0], +_[0][1]).cover(+_[1][0], +_[1][1]) - : isNaN(this._x0) ? undefined : [[this._x0, this._y0], [this._x1, this._y1]]; -} - -function Quad(node, x0, y0, x1, y1) { - this.node = node; - this.x0 = x0; - this.y0 = y0; - this.x1 = x1; - this.y1 = y1; -} - -function tree_find(x, y, radius) { - var data, - x0 = this._x0, - y0 = this._y0, - x1, - y1, - x2, - y2, - x3 = this._x1, - y3 = this._y1, - quads = [], - node = this._root, - q, - i; - - if (node) quads.push(new Quad(node, x0, y0, x3, y3)); - if (radius == null) radius = Infinity; - else { - x0 = x - radius, y0 = y - radius; - x3 = x + radius, y3 = y + radius; - radius *= radius; - } - - while (q = quads.pop()) { - - // Stop searching if this quadrant can’t contain a closer node. - if (!(node = q.node) - || (x1 = q.x0) > x3 - || (y1 = q.y0) > y3 - || (x2 = q.x1) < x0 - || (y2 = q.y1) < y0) continue; - - // Bisect the current quadrant. - if (node.length) { - var xm = (x1 + x2) / 2, - ym = (y1 + y2) / 2; - - quads.push( - new Quad(node[3], xm, ym, x2, y2), - new Quad(node[2], x1, ym, xm, y2), - new Quad(node[1], xm, y1, x2, ym), - new Quad(node[0], x1, y1, xm, ym) - ); - - // Visit the closest quadrant first. - if (i = (y >= ym) << 1 | (x >= xm)) { - q = quads[quads.length - 1]; - quads[quads.length - 1] = quads[quads.length - 1 - i]; - quads[quads.length - 1 - i] = q; - } - } - - // Visit this point. (Visiting coincident points isn’t necessary!) - else { - var dx = x - +this._x.call(null, node.data), - dy = y - +this._y.call(null, node.data), - d2 = dx * dx + dy * dy; - if (d2 < radius) { - var d = Math.sqrt(radius = d2); - x0 = x - d, y0 = y - d; - x3 = x + d, y3 = y + d; - data = node.data; - } - } - } - - return data; -} - -function tree_remove(d) { - if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d))) return this; // ignore invalid points - - var parent, - node = this._root, - retainer, - previous, - next, - x0 = this._x0, - y0 = this._y0, - x1 = this._x1, - y1 = this._y1, - x, - y, - xm, - ym, - right, - bottom, - i, - j; - - // If the tree is empty, initialize the root as a leaf. - if (!node) return this; - - // Find the leaf node for the point. - // While descending, also retain the deepest parent with a non-removed sibling. - if (node.length) while (true) { - if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; - if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; - if (!(parent = node, node = node[i = bottom << 1 | right])) return this; - if (!node.length) break; - if (parent[(i + 1) & 3] || parent[(i + 2) & 3] || parent[(i + 3) & 3]) retainer = parent, j = i; - } - - // Find the point to remove. - while (node.data !== d) if (!(previous = node, node = node.next)) return this; - if (next = node.next) delete node.next; - - // If there are multiple coincident points, remove just the point. - if (previous) return next ? previous.next = next : delete previous.next, this; - - // If this is the root point, remove it. - if (!parent) return this._root = next, this; - - // Remove this leaf. - next ? parent[i] = next : delete parent[i]; - - // If the parent now contains exactly one leaf, collapse superfluous parents. - if ((node = parent[0] || parent[1] || parent[2] || parent[3]) - && node === (parent[3] || parent[2] || parent[1] || parent[0]) - && !node.length) { - if (retainer) retainer[j] = node; - else this._root = node; - } - - return this; -} - -function removeAll(data) { - for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]); - return this; -} - -function tree_root() { - return this._root; -} - -function tree_size() { - var size = 0; - this.visit(function(node) { - if (!node.length) do ++size; while (node = node.next) - }); - return size; -} - -function tree_visit(callback) { - var quads = [], q, node = this._root, child, x0, y0, x1, y1; - if (node) quads.push(new Quad(node, this._x0, this._y0, this._x1, this._y1)); - while (q = quads.pop()) { - if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1) && node.length) { - var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2; - if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1)); - if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1)); - if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym)); - if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym)); - } - } - return this; -} - -function tree_visitAfter(callback) { - var quads = [], next = [], q; - if (this._root) quads.push(new Quad(this._root, this._x0, this._y0, this._x1, this._y1)); - while (q = quads.pop()) { - var node = q.node; - if (node.length) { - var child, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2; - if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym)); - if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym)); - if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1)); - if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1)); - } - next.push(q); - } - while (q = next.pop()) { - callback(q.node, q.x0, q.y0, q.x1, q.y1); - } - return this; -} - -function defaultX(d) { - return d[0]; -} - -function tree_x(_) { - return arguments.length ? (this._x = _, this) : this._x; -} - -function defaultY(d) { - return d[1]; -} - -function tree_y(_) { - return arguments.length ? (this._y = _, this) : this._y; -} - -function quadtree(nodes, x, y) { - var tree = new Quadtree(x == null ? defaultX : x, y == null ? defaultY : y, NaN, NaN, NaN, NaN); - return nodes == null ? tree : tree.addAll(nodes); -} - -function Quadtree(x, y, x0, y0, x1, y1) { - this._x = x; - this._y = y; - this._x0 = x0; - this._y0 = y0; - this._x1 = x1; - this._y1 = y1; - this._root = undefined; -} - -function leaf_copy(leaf) { - var copy = {data: leaf.data}, next = copy; - while (leaf = leaf.next) next = next.next = {data: leaf.data}; - return copy; -} - -var treeProto = quadtree.prototype = Quadtree.prototype; - -treeProto.copy = function() { - var copy = new Quadtree(this._x, this._y, this._x0, this._y0, this._x1, this._y1), - node = this._root, - nodes, - child; - - if (!node) return copy; - - if (!node.length) return copy._root = leaf_copy(node), copy; - - nodes = [{source: node, target: copy._root = new Array(4)}]; - while (node = nodes.pop()) { - for (var i = 0; i < 4; ++i) { - if (child = node.source[i]) { - if (child.length) nodes.push({source: child, target: node.target[i] = new Array(4)}); - else node.target[i] = leaf_copy(child); - } - } - } - - return copy; -}; - -treeProto.add = tree_add; -treeProto.addAll = addAll; -treeProto.cover = tree_cover; -treeProto.data = tree_data; -treeProto.extent = tree_extent; -treeProto.find = tree_find; -treeProto.remove = tree_remove; -treeProto.removeAll = removeAll; -treeProto.root = tree_root; -treeProto.size = tree_size; -treeProto.visit = tree_visit; -treeProto.visitAfter = tree_visitAfter; -treeProto.x = tree_x; -treeProto.y = tree_y; - -function x(d) { - return d.x + d.vx; -} - -function y(d) { - return d.y + d.vy; -} - -function collide(radius) { - var nodes, - radii, - strength = 1, - iterations = 1; - - if (typeof radius !== "function") radius = constant(radius == null ? 1 : +radius); - - function force() { - var i, n = nodes.length, - tree, - node, - xi, - yi, - ri, - ri2; - - for (var k = 0; k < iterations; ++k) { - tree = quadtree(nodes, x, y).visitAfter(prepare); - for (i = 0; i < n; ++i) { - node = nodes[i]; - ri = radii[node.index], ri2 = ri * ri; - xi = node.x + node.vx; - yi = node.y + node.vy; - tree.visit(apply); - } - } - - function apply(quad, x0, y0, x1, y1) { - var data = quad.data, rj = quad.r, r = ri + rj; - if (data) { - if (data.index > node.index) { - var x = xi - data.x - data.vx, - y = yi - data.y - data.vy, - l = x * x + y * y; - if (l < r * r) { - if (x === 0) x = jiggle(), l += x * x; - if (y === 0) y = jiggle(), l += y * y; - l = (r - (l = Math.sqrt(l))) / l * strength; - node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj)); - node.vy += (y *= l) * r; - data.vx -= x * (r = 1 - r); - data.vy -= y * r; - } - } - return; - } - return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r; - } - } - - function prepare(quad) { - if (quad.data) return quad.r = radii[quad.data.index]; - for (var i = quad.r = 0; i < 4; ++i) { - if (quad[i] && quad[i].r > quad.r) { - quad.r = quad[i].r; - } - } - } - - function initialize() { - if (!nodes) return; - var i, n = nodes.length, node; - radii = new Array(n); - for (i = 0; i < n; ++i) node = nodes[i], radii[node.index] = +radius(node, i, nodes); - } - - force.initialize = function(_) { - nodes = _; - initialize(); - }; - - force.iterations = function(_) { - return arguments.length ? (iterations = +_, force) : iterations; - }; - - force.strength = function(_) { - return arguments.length ? (strength = +_, force) : strength; - }; - - force.radius = function(_) { - return arguments.length ? (radius = typeof _ === "function" ? _ : constant(+_), initialize(), force) : radius; - }; - - return force; -} - -var prefix = "$"; - -function Map() {} - -Map.prototype = map.prototype = { - constructor: Map, - has: function(key) { - return (prefix + key) in this; - }, - get: function(key) { - return this[prefix + key]; - }, - set: function(key, value) { - this[prefix + key] = value; - return this; - }, - remove: function(key) { - var property = prefix + key; - return property in this && delete this[property]; - }, - clear: function() { - for (var property in this) if (property[0] === prefix) delete this[property]; - }, - keys: function() { - var keys = []; - for (var property in this) if (property[0] === prefix) keys.push(property.slice(1)); - return keys; - }, - values: function() { - var values = []; - for (var property in this) if (property[0] === prefix) values.push(this[property]); - return values; - }, - entries: function() { - var entries = []; - for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]}); - return entries; - }, - size: function() { - var size = 0; - for (var property in this) if (property[0] === prefix) ++size; - return size; - }, - empty: function() { - for (var property in this) if (property[0] === prefix) return false; - return true; - }, - each: function(f) { - for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this); - } -}; - -function map(object, f) { - var map = new Map; - - // Copy constructor. - if (object instanceof Map) object.each(function(value, key) { map.set(key, value); }); - - // Index array by numeric index or specified key function. - else if (Array.isArray(object)) { - var i = -1, - n = object.length, - o; - - if (f == null) while (++i < n) map.set(i, object[i]); - else while (++i < n) map.set(f(o = object[i], i, object), o); - } - - // Convert object to map. - else if (object) for (var key in object) map.set(key, object[key]); - - return map; -} - -function Set() {} - -var proto = map.prototype; - -Set.prototype = set.prototype = { - constructor: Set, - has: proto.has, - add: function(value) { - value += ""; - this[prefix + value] = value; - return this; - }, - remove: proto.remove, - clear: proto.clear, - values: proto.keys, - size: proto.size, - empty: proto.empty, - each: proto.each -}; - -function set(object, f) { - var set = new Set; - - // Copy constructor. - if (object instanceof Set) object.each(function(value) { set.add(value); }); - - // Otherwise, assume it’s an array. - else if (object) { - var i = -1, n = object.length; - if (f == null) while (++i < n) set.add(object[i]); - else while (++i < n) set.add(f(object[i], i, object)); - } - - return set; -} - -function index(d) { - return d.index; -} - -function find(nodeById, nodeId) { - var node = nodeById.get(nodeId); - if (!node) throw new Error("missing: " + nodeId); - return node; -} - -function link(links) { - var id = index, - strength = defaultStrength, - strengths, - distance = constant(30), - distances, - nodes, - count, - bias, - iterations = 1; - - if (links == null) links = []; - - function defaultStrength(link) { - return 1 / Math.min(count[link.source.index], count[link.target.index]); - } - - function force(alpha) { - for (var k = 0, n = links.length; k < iterations; ++k) { - for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) { - link = links[i], source = link.source, target = link.target; - x = target.x + target.vx - source.x - source.vx || jiggle(); - y = target.y + target.vy - source.y - source.vy || jiggle(); - l = Math.sqrt(x * x + y * y); - l = (l - distances[i]) / l * alpha * strengths[i]; - x *= l, y *= l; - target.vx -= x * (b = bias[i]); - target.vy -= y * b; - source.vx += x * (b = 1 - b); - source.vy += y * b; - } - } - } - - function initialize() { - if (!nodes) return; - - var i, - n = nodes.length, - m = links.length, - nodeById = map(nodes, id), - link; - - for (i = 0, count = new Array(n); i < m; ++i) { - link = links[i], link.index = i; - if (typeof link.source !== "object") link.source = find(nodeById, link.source); - if (typeof link.target !== "object") link.target = find(nodeById, link.target); - count[link.source.index] = (count[link.source.index] || 0) + 1; - count[link.target.index] = (count[link.target.index] || 0) + 1; - } - - for (i = 0, bias = new Array(m); i < m; ++i) { - link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]); - } - - strengths = new Array(m), initializeStrength(); - distances = new Array(m), initializeDistance(); - } - - function initializeStrength() { - if (!nodes) return; - - for (var i = 0, n = links.length; i < n; ++i) { - strengths[i] = +strength(links[i], i, links); - } - } - - function initializeDistance() { - if (!nodes) return; - - for (var i = 0, n = links.length; i < n; ++i) { - distances[i] = +distance(links[i], i, links); - } - } - - force.initialize = function(_) { - nodes = _; - initialize(); - }; - - force.links = function(_) { - return arguments.length ? (links = _, initialize(), force) : links; - }; - - force.id = function(_) { - return arguments.length ? (id = _, force) : id; - }; - - force.iterations = function(_) { - return arguments.length ? (iterations = +_, force) : iterations; - }; - - force.strength = function(_) { - return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initializeStrength(), force) : strength; - }; - - force.distance = function(_) { - return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), initializeDistance(), force) : distance; - }; - - return force; -} - -var noop = {value: function() {}}; - -function dispatch() { - for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) { - if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t); - _[t] = []; - } - return new Dispatch(_); -} - -function Dispatch(_) { - this._ = _; -} - -function parseTypenames(typenames, types) { - return typenames.trim().split(/^|\s+/).map(function(t) { - var name = "", i = t.indexOf("."); - if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i); - if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t); - return {type: t, name: name}; - }); -} - -Dispatch.prototype = dispatch.prototype = { - constructor: Dispatch, - on: function(typename, callback) { - var _ = this._, - T = parseTypenames(typename + "", _), - t, - i = -1, - n = T.length; - - // If no callback was specified, return the callback of the given type and name. - if (arguments.length < 2) { - while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t; - return; - } - - // If a type was specified, set the callback for the given type and name. - // Otherwise, if a null callback was specified, remove callbacks of the given name. - if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback); - while (++i < n) { - if (t = (typename = T[i]).type) _[t] = set$1(_[t], typename.name, callback); - else if (callback == null) for (t in _) _[t] = set$1(_[t], typename.name, null); - } - - return this; - }, - copy: function() { - var copy = {}, _ = this._; - for (var t in _) copy[t] = _[t].slice(); - return new Dispatch(copy); - }, - call: function(type, that) { - if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2]; - if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type); - for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args); - }, - apply: function(type, that, args) { - if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type); - for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args); - } -}; - -function get(type, name) { - for (var i = 0, n = type.length, c; i < n; ++i) { - if ((c = type[i]).name === name) { - return c.value; - } - } -} - -function set$1(type, name, callback) { - for (var i = 0, n = type.length; i < n; ++i) { - if (type[i].name === name) { - type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1)); - break; - } - } - if (callback != null) type.push({name: name, value: callback}); - return type; -} - -var frame = 0, // is an animation frame pending? - timeout = 0, // is a timeout pending? - interval = 0, // are any timers active? - pokeDelay = 1000, // how frequently we check for clock skew - taskHead, - taskTail, - clockLast = 0, - clockNow = 0, - clockSkew = 0, - clock = typeof performance === "object" && performance.now ? performance : Date, - setFrame = typeof window === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function(f) { setTimeout(f, 17); }; - -function now() { - return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew); -} - -function clearNow() { - clockNow = 0; -} - -function Timer() { - this._call = - this._time = - this._next = null; -} - -Timer.prototype = timer.prototype = { - constructor: Timer, - restart: function(callback, delay, time) { - if (typeof callback !== "function") throw new TypeError("callback is not a function"); - time = (time == null ? now() : +time) + (delay == null ? 0 : +delay); - if (!this._next && taskTail !== this) { - if (taskTail) taskTail._next = this; - else taskHead = this; - taskTail = this; - } - this._call = callback; - this._time = time; - sleep(); - }, - stop: function() { - if (this._call) { - this._call = null; - this._time = Infinity; - sleep(); - } - } -}; - -function timer(callback, delay, time) { - var t = new Timer; - t.restart(callback, delay, time); - return t; -} - -function timerFlush() { - now(); // Get the current time, if not already set. - ++frame; // Pretend we’ve set an alarm, if we haven’t already. - var t = taskHead, e; - while (t) { - if ((e = clockNow - t._time) >= 0) t._call.call(null, e); - t = t._next; - } - --frame; -} - -function wake() { - clockNow = (clockLast = clock.now()) + clockSkew; - frame = timeout = 0; - try { - timerFlush(); - } finally { - frame = 0; - nap(); - clockNow = 0; - } -} - -function poke() { - var now = clock.now(), delay = now - clockLast; - if (delay > pokeDelay) clockSkew -= delay, clockLast = now; -} - -function nap() { - var t0, t1 = taskHead, t2, time = Infinity; - while (t1) { - if (t1._call) { - if (time > t1._time) time = t1._time; - t0 = t1, t1 = t1._next; - } else { - t2 = t1._next, t1._next = null; - t1 = t0 ? t0._next = t2 : taskHead = t2; - } - } - taskTail = t0; - sleep(time); -} - -function sleep(time) { - if (frame) return; // Soonest alarm already set, or will be. - if (timeout) timeout = clearTimeout(timeout); - var delay = time - clockNow; // Strictly less than if we recomputed clockNow. - if (delay > 24) { - if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew); - if (interval) interval = clearInterval(interval); - } else { - if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay); - frame = 1, setFrame(wake); - } -} - -function x$1(d) { - return d.x; -} - -function y$1(d) { - return d.y; -} - -var initialRadius = 10, - initialAngle = Math.PI * (3 - Math.sqrt(5)); - -function simulation(nodes) { - var simulation, - alpha = 1, - alphaMin = 0.001, - alphaDecay = 1 - Math.pow(alphaMin, 1 / 300), - alphaTarget = 0, - velocityDecay = 0.6, - forces = map(), - stepper = timer(step), - event = dispatch("tick", "end"); - - if (nodes == null) nodes = []; - - function step() { - tick(); - event.call("tick", simulation); - if (alpha < alphaMin) { - stepper.stop(); - event.call("end", simulation); - } - } - - function tick() { - var i, n = nodes.length, node; - - alpha += (alphaTarget - alpha) * alphaDecay; - - forces.each(function(force) { - force(alpha); - }); - - for (i = 0; i < n; ++i) { - node = nodes[i]; - if (node.fx == null) node.x += node.vx *= velocityDecay; - else node.x = node.fx, node.vx = 0; - if (node.fy == null) node.y += node.vy *= velocityDecay; - else node.y = node.fy, node.vy = 0; - } - } - - function initializeNodes() { - for (var i = 0, n = nodes.length, node; i < n; ++i) { - node = nodes[i], node.index = i; - if (isNaN(node.x) || isNaN(node.y)) { - var radius = initialRadius * Math.sqrt(i), angle = i * initialAngle; - node.x = radius * Math.cos(angle); - node.y = radius * Math.sin(angle); - } - if (isNaN(node.vx) || isNaN(node.vy)) { - node.vx = node.vy = 0; - } - } - } - - function initializeForce(force) { - if (force.initialize) force.initialize(nodes); - return force; - } - - initializeNodes(); - - return simulation = { - tick: tick, - - restart: function() { - return stepper.restart(step), simulation; - }, - - stop: function() { - return stepper.stop(), simulation; - }, - - nodes: function(_) { - return arguments.length ? (nodes = _, initializeNodes(), forces.each(initializeForce), simulation) : nodes; - }, - - alpha: function(_) { - return arguments.length ? (alpha = +_, simulation) : alpha; - }, - - alphaMin: function(_) { - return arguments.length ? (alphaMin = +_, simulation) : alphaMin; - }, - - alphaDecay: function(_) { - return arguments.length ? (alphaDecay = +_, simulation) : +alphaDecay; - }, - - alphaTarget: function(_) { - return arguments.length ? (alphaTarget = +_, simulation) : alphaTarget; - }, - - velocityDecay: function(_) { - return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay; - }, - - force: function(name, _) { - return arguments.length > 1 ? (_ == null ? forces.remove(name) : forces.set(name, initializeForce(_)), simulation) : forces.get(name); - }, - - find: function(x, y, radius) { - var i = 0, - n = nodes.length, - dx, - dy, - d2, - node, - closest; - - if (radius == null) radius = Infinity; - else radius *= radius; - - for (i = 0; i < n; ++i) { - node = nodes[i]; - dx = x - node.x; - dy = y - node.y; - d2 = dx * dx + dy * dy; - if (d2 < radius) closest = node, radius = d2; - } - - return closest; - }, - - on: function(name, _) { - return arguments.length > 1 ? (event.on(name, _), simulation) : event.on(name); - } - }; -} - -function manyBody() { - var nodes, - node, - alpha, - strength = constant(-30), - strengths, - distanceMin2 = 1, - distanceMax2 = Infinity, - theta2 = 0.81; - - function force(_) { - var i, n = nodes.length, tree = quadtree(nodes, x$1, y$1).visitAfter(accumulate); - for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply); - } - - function initialize() { - if (!nodes) return; - var i, n = nodes.length, node; - strengths = new Array(n); - for (i = 0; i < n; ++i) node = nodes[i], strengths[node.index] = +strength(node, i, nodes); - } - - function accumulate(quad) { - var strength = 0, q, c, weight = 0, x, y, i; - - // For internal nodes, accumulate forces from child quadrants. - if (quad.length) { - for (x = y = i = 0; i < 4; ++i) { - if ((q = quad[i]) && (c = Math.abs(q.value))) { - strength += q.value, weight += c, x += c * q.x, y += c * q.y; - } - } - quad.x = x / weight; - quad.y = y / weight; - } - - // For leaf nodes, accumulate forces from coincident quadrants. - else { - q = quad; - q.x = q.data.x; - q.y = q.data.y; - do strength += strengths[q.data.index]; - while (q = q.next); - } - - quad.value = strength; - } - - function apply(quad, x1, _, x2) { - if (!quad.value) return true; - - var x = quad.x - node.x, - y = quad.y - node.y, - w = x2 - x1, - l = x * x + y * y; - - // Apply the Barnes-Hut approximation if possible. - // Limit forces for very close nodes; randomize direction if coincident. - if (w * w / theta2 < l) { - if (l < distanceMax2) { - if (x === 0) x = jiggle(), l += x * x; - if (y === 0) y = jiggle(), l += y * y; - if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l); - node.vx += x * quad.value * alpha / l; - node.vy += y * quad.value * alpha / l; - } - return true; - } - - // Otherwise, process points directly. - else if (quad.length || l >= distanceMax2) return; - - // Limit forces for very close nodes; randomize direction if coincident. - if (quad.data !== node || quad.next) { - if (x === 0) x = jiggle(), l += x * x; - if (y === 0) y = jiggle(), l += y * y; - if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l); - } - - do if (quad.data !== node) { - w = strengths[quad.data.index] * alpha / l; - node.vx += x * w; - node.vy += y * w; - } while (quad = quad.next); - } - - force.initialize = function(_) { - nodes = _; - initialize(); - }; - - force.strength = function(_) { - return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength; - }; - - force.distanceMin = function(_) { - return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2); - }; - - force.distanceMax = function(_) { - return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2); - }; - - force.theta = function(_) { - return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2); - }; - - return force; -} - -function radial(radius, x, y) { - var nodes, - strength = constant(0.1), - strengths, - radiuses; - - if (typeof radius !== "function") radius = constant(+radius); - if (x == null) x = 0; - if (y == null) y = 0; - - function force(alpha) { - for (var i = 0, n = nodes.length; i < n; ++i) { - var node = nodes[i], - dx = node.x - x || 1e-6, - dy = node.y - y || 1e-6, - r = Math.sqrt(dx * dx + dy * dy), - k = (radiuses[i] - r) * strengths[i] * alpha / r; - node.vx += dx * k; - node.vy += dy * k; - } - } - - function initialize() { - if (!nodes) return; - var i, n = nodes.length; - strengths = new Array(n); - radiuses = new Array(n); - for (i = 0; i < n; ++i) { - radiuses[i] = +radius(nodes[i], i, nodes); - strengths[i] = isNaN(radiuses[i]) ? 0 : +strength(nodes[i], i, nodes); - } - } - - force.initialize = function(_) { - nodes = _, initialize(); - }; - - force.strength = function(_) { - return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength; - }; - - force.radius = function(_) { - return arguments.length ? (radius = typeof _ === "function" ? _ : constant(+_), initialize(), force) : radius; - }; - - force.x = function(_) { - return arguments.length ? (x = +_, force) : x; - }; - - force.y = function(_) { - return arguments.length ? (y = +_, force) : y; - }; - - return force; -} - -function x$2(x) { - var strength = constant(0.1), - nodes, - strengths, - xz; - - if (typeof x !== "function") x = constant(x == null ? 0 : +x); - - function force(alpha) { - for (var i = 0, n = nodes.length, node; i < n; ++i) { - node = nodes[i], node.vx += (xz[i] - node.x) * strengths[i] * alpha; - } - } - - function initialize() { - if (!nodes) return; - var i, n = nodes.length; - strengths = new Array(n); - xz = new Array(n); - for (i = 0; i < n; ++i) { - strengths[i] = isNaN(xz[i] = +x(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes); - } - } - - force.initialize = function(_) { - nodes = _; - initialize(); - }; - - force.strength = function(_) { - return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength; - }; - - force.x = function(_) { - return arguments.length ? (x = typeof _ === "function" ? _ : constant(+_), initialize(), force) : x; - }; - - return force; -} - -function y$2(y) { - var strength = constant(0.1), - nodes, - strengths, - yz; - - if (typeof y !== "function") y = constant(y == null ? 0 : +y); - - function force(alpha) { - for (var i = 0, n = nodes.length, node; i < n; ++i) { - node = nodes[i], node.vy += (yz[i] - node.y) * strengths[i] * alpha; - } - } - - function initialize() { - if (!nodes) return; - var i, n = nodes.length; - strengths = new Array(n); - yz = new Array(n); - for (i = 0; i < n; ++i) { - strengths[i] = isNaN(yz[i] = +y(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes); - } - } - - force.initialize = function(_) { - nodes = _; - initialize(); - }; - - force.strength = function(_) { - return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength; - }; - - force.y = function(_) { - return arguments.length ? (y = typeof _ === "function" ? _ : constant(+_), initialize(), force) : y; - }; - - return force; -} - -function forceStraightenPaths(paths) { - var _nodes, - _inputPaths = paths || [], - _paths, _id = function(n) { return n.index; }, - _angleForce = 0.1, - _pathNodes = function(p) { return p.nodes; }, - _pathStrength = function(p) { return typeof p.strength !== 'undefined' ? +p.strength : 1; }, - _debug = false; - var force = function(alpha) { - function _dot(v1, v2) { return v1.x*v2.x + v1.y*v2.y; } function _len(v) { return Math.sqrt(v.x*v.x + v.y*v.y); } function _angle(v1, v2) { - var a = _dot(v1, v2) / (_len(v1)*_len(v2)); - a = Math.min(a, 1); - a = Math.max(a, -1); - return Math.acos(a); - } // perpendicular unit length vector - function _pVec(v) { - var xx = -v.y/v.x, yy = 1; - var length = _len({x: xx, y: yy}); - return {x: xx/length, y: yy/length}; - } - function _displaceAdjacent(node, angle, pVec, k) { - var turn = Math.PI-angle, - turn2 = turn*turn; - return { - kind: 'adjacent', - x: pVec.x*turn2*k, - y: pVec.y*turn2*k - }; - } - - function _displaceCenter(dadj1, dadj2) { - return { - kind: 'center', - x: -(dadj1.x + dadj2.x), - y: -(dadj1.y + dadj2.y) - }; - } - - function _offsetNode(node, disp) { - node.x += disp.x; - node.y += disp.y; - } - var report = []; - _paths.forEach(function(path, i) { - var pnodes = path.nodes, - strength = path.strength; - if(typeof strength !== 'number') - strength = 1; - if(pnodes.length < 3) return; // at least 3 nodes (and 2 edges): A->B->C - if(_debug) { - report.push({ - action: 'init', - nodes: pnodes.map(function(n) { - return { - id: _id(n), - x: n.x, - y: n.y - }; - }), - edges: pnodes.reduce(function(p, n) { - if(!Array.isArray(p)) - return [{source: _id(p), target: _id(n)}]; - p.push({source: p[p.length-1].target, target: _id(n)}); - return p; - }) - }); - } - for(var i = 1; i < pnodes.length-1; ++i) { - var current = pnodes[i]; - var prev = pnodes[i-1]; - var next = pnodes[i+1]; - - // we can't do anything for two-cycles - if(prev === next) - continue; - - // calculate the angle - var vPrev = {x: prev.x - current.x, y: prev.y - current.y}; - var vNext = {x: next.x - current.x, y: next.y - current.y}; - - var angle = _angle(vPrev, vNext); // angle in [0, PI] - - var pvecPrev = _pVec(vPrev); - var pvecNext = _pVec(vNext); - - // make sure the perpendicular vector is in the - // direction that makes the angle more towards 180 degree - // 1. calculate the middle point of node 'prev' and 'next' - var mid = {x: (prev.x+next.x)/2.0, y: (prev.y+next.y)/2.0}; - - // 2. calculate the vectors: 'prev' pointing to 'mid', 'next' pointing to 'mid' - var prev_mid = {x: mid.x-prev.x, y: mid.y-prev.y}; - var next_mid = {x: mid.x-next.x, y: mid.y-next.y}; - - // 3. the 'correct' vector: the angle between pvec and prev_mid(next_mid) should - // be an obtuse angle - pvecPrev = _angle(prev_mid, pvecPrev) >= Math.PI/2.0 ? pvecPrev : {x: -pvecPrev.x, y: -pvecPrev.y}; - pvecNext = _angle(next_mid, pvecNext) >= Math.PI/2.0 ? pvecNext : {x: -pvecNext.x, y: -pvecNext.y}; - - // modify positions of nodes - var prevDisp = _displaceAdjacent(prev, angle, pvecPrev, strength * _angleForce); - var nextDisp = _displaceAdjacent(next, angle, pvecNext, strength * _angleForce); - var centerDisp = _displaceCenter(prevDisp, nextDisp); - if(_debug) { - report.push({ - action: 'force', - nodes: [{ - id: _id(prev), - x: prev.x, - y: prev.y, - force: prevDisp - }, { - id: _id(current), - x: current.x, - y: current.y, - force: centerDisp - }, { - id: _id(next), - x: next.x, - y: next.y, - force: nextDisp - }], - edges: [{ - source: _id(prev), - target: _id(current) - }, { - source: _id(current), - target: _id(next) - }] - }); - } - _offsetNode(prev, prevDisp); - _offsetNode(next, nextDisp); - _offsetNode(current, centerDisp); - } - }); - if(_debug) - console.log(report); - }; - function find(nodeById, nodeId) { - var node = nodeById.get(nodeId); - if(!node) - throw new Error('node missing: ' + nodeId); - return node; - } - function init() { - if(!_nodes) - return; - var nodeById = d3.map(_nodes, _id); - _paths = _inputPaths.map(function(path) { - return { - nodes: _pathNodes(path).map(function(n) { - return typeof n !== 'object' ? - find(nodeById, n) : - n; - }), - strength: _pathStrength(path) - }; - }); - } - force.initialize = function(nodes) { - _nodes = nodes; - init(); - }; - force.paths = function(paths) { - if(!arguments.length) return _paths; - _inputPaths = paths; - init(); - return this; - }; - force.id = function(id) { - if(!arguments.length) return _id; - _id = id; - return this; - }; - force.angleForce = function(angleForce) { - if(!arguments.length) return _angleForce; - _angleForce = angleForce; - return this; - }; - force.pathNodes = function(pathNodes) { - if(!arguments.length) return _pathNodes; - _pathNodes = pathNodes; - return this; - }; - force.pathStrength = function(pathStrength) { - if(!arguments.length) return _pathStrength; - _pathStrength = pathStrength; - return this; - }; - force.debug = function(debug) { - if(!arguments.length) return _debug; - _debug = debug; - return this; - }; - return force; -} - -exports.forceCenter = center; -exports.forceCollide = collide; -exports.forceLink = link; -exports.forceManyBody = manyBody; -exports.forceRadial = radial; -exports.forceSimulation = simulation; -exports.forceX = x$2; -exports.forceY = y$2; -exports.forceStraightenPaths = forceStraightenPaths; - -Object.defineProperty(exports, '__esModule', { value: true }); - -}))); diff --git a/d3v4-force.rollup.config.js b/d3v4-force.rollup.config.js deleted file mode 100644 index b6e52b6a..00000000 --- a/d3v4-force.rollup.config.js +++ /dev/null @@ -1,11 +0,0 @@ -import node from "@rollup/plugin-node-resolve"; - -export default { - input: "d3v4-force.index.js", - output: { - name: "d3v4", - file: "d3v4-force.js", - format: "umd" - }, - plugins: [node()] -}; diff --git a/dc.graph.cola.worker.js b/dc.graph.cola.worker.js deleted file mode 100644 index 30f157f6..00000000 --- a/dc.graph.cola.worker.js +++ /dev/null @@ -1,952 +0,0 @@ -/*! - * dc.graph 0.9.93 - * http://dc-js.github.io/dc.graph.js/ - * Copyright 2015-2019 AT&T Intellectual Property & the dc.graph.js Developers - * https://github.com/dc-js/dc.graph.js/blob/master/AUTHORS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -/** - * The entire dc.graph.js library is scoped under the **dc_graph** name space. It does not introduce - * anything else into the global name space. - * - * Like in dc.js and most libraries built on d3, most `dc_graph` functions are designed to allow function chaining, meaning they return the current diagram - * instance whenever it is appropriate. The getter forms of functions do not participate in function - * chaining because they return values that are not the diagram. - * @namespace dc_graph - * @version 0.9.93 - * @example - * // Example chaining - * diagram.width(600) - * .height(400) - * .nodeDimension(nodeDim) - * .nodeGroup(nodeGroup); - */ - -var dc_graph = { - version: '0.9.93', - constants: { - CHART_CLASS: 'dc-graph' - } -}; - -function get_original(x) { - return x.orig; -} - -function identity(x) { - return x; -}; - -var property = function (defaultValue, unwrap) { - if(unwrap === undefined) - unwrap = get_original; - else if(unwrap === false) - unwrap = identity; - var value = defaultValue, react = null; - var cascade = []; - var ret = function (_) { - if (!arguments.length) { - return value; - } - if(react) - react(_); - value = _; - return this; - }; - ret.cascade = function (n, f) { - for(var i = 0; i n) { - cascade.splice(i, 0, {n: n, f: f}); - return ret; - } - } - cascade.push({n: n, f: f}); - return ret; - }; - ret._eval = function(o, n) { - if(n===0 || !cascade.length) - return dc_graph.functor_wrap(ret(), unwrap)(o); - else { - var last = cascade[n-1]; - return last.f(o, function() { - return ret._eval(o, n-1); - }); - } - }; - ret.eval = function(o) { - return ret._eval(o, cascade.length); - }; - ret.react = function(_) { - if (!arguments.length) { - return react; - } - react = _; - return this; - }; - return ret; -}; - -function named_children() { - var _children = {}; - var f = function(id, object) { - if(arguments.length === 1) - return _children[id]; - if(f.reject) { - var reject = f.reject(id, object); - if(reject) { - console.groupCollapsed(reject); - console.trace(); - console.groupEnd(); - return this; - } - } - // do not notify unnecessarily - if(_children[id] === object) - return this; - if(_children[id]) - _children[id].parent(null); - _children[id] = object; - if(object) - object.parent(this); - return this; - }; - f.enum = function() { - return Object.keys(_children); - }; - f.nameOf = function(o) { - var found = Object.entries(_children).find(function(kv) { - return kv[1] == o; - }); - return found ? found[0] : null; - }; - return f; -} - -function deprecated_property(message, defaultValue) { - var prop = property(defaultValue); - var ret = function() { - if(arguments.length) { - console.warn(message); - prop.apply(property, arguments); - return this; - } - return prop(); - }; - ['cascade', '_eval', 'eval', 'react'].forEach(function(method) { - ret[method] = prop[method]; - }); - return ret; -} - -function onetime_trace(level, message) { - var said = false; - return function() { - if(said) - return; - if(level === 'trace') { - // todo: implement levels? - // console.groupCollapsed(message); - // console.trace(); - // console.groupEnd(); - } - else - console[level](message); - said = true; - }; -} - -function deprecation_warning(message) { - return onetime_trace('warn', message); -} - -function trace_function(level, message, f) { - var dep = onetime_trace(level, message); - return function() { - dep(); - return f.apply(this, arguments); - }; -} -function deprecate_function(message, f) { - return trace_function('warn', message, f); -} - -// http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript -function uuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); - return v.toString(16); - }); -} - -function is_ie() { - var ua = window.navigator.userAgent; - - return(ua.indexOf('MSIE ') > 0 || - ua.indexOf('Trident/') > 0 || - ua.indexOf('Edge/') > 0); -} - -function is_safari() { - return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); -} - -// polyfill Object.assign for IE -// it's just too useful to do without -if (typeof Object.assign != 'function') { - // Must be writable: true, enumerable: false, configurable: true - Object.defineProperty(Object, "assign", { - value: function assign(target, varArgs) { // .length of function is 2 - 'use strict'; - if (target == null) { // TypeError if undefined or null - throw new TypeError('Cannot convert undefined or null to object'); - } - - var to = Object(target); - - for (var index = 1; index < arguments.length; index++) { - var nextSource = arguments[index]; - - if (nextSource != null) { // Skip over if undefined or null - for (var nextKey in nextSource) { - // Avoid bugs when hasOwnProperty is shadowed - if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { - to[nextKey] = nextSource[nextKey]; - } - } - } - } - return to; - }, - writable: true, - configurable: true - }); -} - - -// https://tc39.github.io/ecma262/#sec-array.prototype.includes -if (!Array.prototype.includes) { - Object.defineProperty(Array.prototype, 'includes', { - value: function(valueToFind, fromIndex) { - - if (this == null) { - throw new TypeError('"this" is null or not defined'); - } - - // 1. Let O be ? ToObject(this value). - var o = Object(this); - - // 2. Let len be ? ToLength(? Get(O, "length")). - var len = o.length >>> 0; - - // 3. If len is 0, return false. - if (len === 0) { - return false; - } - - // 4. Let n be ? ToInteger(fromIndex). - // (If fromIndex is undefined, this step produces the value 0.) - var n = fromIndex | 0; - - // 5. If n >= 0, then - // a. Let k be n. - // 6. Else n < 0, - // a. Let k be len + n. - // b. If k < 0, let k be 0. - var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); - - function sameValueZero(x, y) { - return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y)); - } - - // 7. Repeat, while k < len - while (k < len) { - // a. Let elementK be the result of ? Get(O, ! ToString(k)). - // b. If SameValueZero(valueToFind, elementK) is true, return true. - if (sameValueZero(o[k], valueToFind)) { - return true; - } - // c. Increase k by 1. - k++; - } - - // 8. Return false - return false; - } - }); -} - -if (!Object.entries) { - Object.entries = function( obj ){ - var ownProps = Object.keys( obj ), - i = ownProps.length, - resArray = new Array(i); // preallocate the Array - while (i--) - resArray[i] = [ownProps[i], obj[ownProps[i]]]; - return resArray; - }; -} - -// https://github.com/KhaledElAnsari/Object.values -Object.values = Object.values ? Object.values : function(obj) { - var allowedTypes = ["[object String]", "[object Object]", "[object Array]", "[object Function]"]; - var objType = Object.prototype.toString.call(obj); - - if(obj === null || typeof obj === "undefined") { - throw new TypeError("Cannot convert undefined or null to object"); - } else if(!~allowedTypes.indexOf(objType)) { - return []; - } else { - // if ES6 is supported - if (Object.keys) { - return Object.keys(obj).map(function (key) { - return obj[key]; - }); - } - - var result = []; - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - result.push(obj[prop]); - } - } - - return result; - } -}; - -function getBBoxNoThrow(elem) { - // firefox seems to have issues with some of my texts - // just catch for now - try { - return elem.getBBox(); - } catch(xep) { - return {x: 0, y: 0, width:0, height: 0}; - } -} - -// create or re-use objects in a map, delete the ones that were not reused -function regenerate_objects(preserved, list, need, key, assign, create, destroy) { - if(!create) create = function(k, o) { }; - if(!destroy) destroy = function(k) { }; - var keep = {}; - function wrap(o) { - var k = key(o); - if(!preserved[k]) - create(k, preserved[k] = {}, o); - var o1 = preserved[k]; - assign(o1, o); - keep[k] = true; - return o1; - } - var wlist = list.map(wrap); - if(need) - need.forEach(function(k) { - if(!preserved[k]) { // hasn't been created, needs to be - create(k, preserved[k] = {}, null); - assign(preserved[k], null); - } - if(!keep[k]) { // wasn't in list, should be - wlist.push(preserved[k]); - keep[k] = true; - } - }); - // delete any objects from last round that are no longer used - for(var k in preserved) - if(!keep[k]) { - destroy(k, preserved[k]); - delete preserved[k]; - } - return wlist; -} - -/** - * `dc_graph.graphviz_attrs defines a basic set of attributes which layout engines should - * implement - although these are not required, they make it easier for clients and - * modes (like expand_collapse) to work with multiple layout engines. - * - * these attributes are {@link http://www.graphviz.org/doc/info/attrs.html from graphviz} - * @class graphviz_attrs - * @memberof dc_graph - * @return {Object} - **/ -dc_graph.graphviz_attrs = function() { - return { - /** - * Direction to draw ranks. - * @method rankdir - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [rankdir='TB'] 'TB', 'LR', 'BT', or 'RL' - **/ - rankdir: property('TB'), - /** - * Spacing in between nodes in the same rank. - * @method nodesep - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [nodesep=40] - **/ - nodesep: property(40), - /** - * Spacing in between ranks. - * @method ranksep - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [ranksep=40] - **/ - ranksep: property(40) - }; -}; - -// graphlib-dot seems to wrap nodes in an extra {value} -// actually this is quite a common problem with generic libs -function nvalue(n) { - return n.value.value ? n.value.value : n.value; -} - -// apply standard accessors to a diagram in order to style it as graphviz would -// this is a work in progress -dc_graph.apply_graphviz_accessors = function(diagram) { - diagram - .nodeLabel(function(n) { - var label = nvalue(n).label; - if(label === undefined) - label = n.key; - return label && label.split(/\n|\\n/); - }) - .nodeRadius(function(n) { - // should do width & height instead, #25 - return nvalue(n).radius || 25; - }) - .nodeShape(function(n) { return nvalue(n).shape; }) - .nodeFill(function(n) { return nvalue(n).fillcolor || 'white'; }) - .nodeOpacity(function(n) { - // not standard gv - return nvalue(n).opacity || 1; - }) - .nodeLabelFill(function(n) { return nvalue(n).fontcolor || 'black'; }) - .nodeTitle(function(n) { - return (nvalue(n).htmltip || nvalue(n).jsontip) ? null : - nvalue(n).tooltip !== undefined ? - nvalue(n).tooltip : - diagram.nodeLabel()(n); - }) - .nodeStrokeWidth(function(n) { - // it is debatable whether a point === a pixel but they are close - // https://graphicdesign.stackexchange.com/questions/199/point-vs-pixel-what-is-the-difference - var penwidth = nvalue(n).penwidth; - return penwidth !== undefined ? +penwidth : 1; - }) - .edgeLabel(function(e) { return e.value.label ? e.value.label.split(/\n|\\n/) : ''; }) - .edgeStroke(function(e) { return e.value.color || 'black'; }) - .edgeOpacity(function(e) { - // not standard gv - return e.value.opacity || 1; - }) - .edgeArrowSize(function(e) { - return e.value.arrowsize || 1; - }) - // need directedness to default these correctly, see #106 - .edgeArrowhead(function(e) { - var head = e.value.arrowhead; - return head !== undefined ? head : 'vee'; - }) - .edgeArrowtail(function(e) { - var tail = e.value.arrowtail; - return tail !== undefined ? tail : null; - }) - .edgeStrokeDashArray(function(e) { - switch(e.value.style) { - case 'dotted': - return [1,5]; - } - return null; - }); - var draw_clusters = diagram.child('draw-clusters'); - if(draw_clusters) { - draw_clusters - .clusterStroke(function(c) { - return c.value.color || 'black'; - }) - .clusterFill(function(c) { - return c.value.style === 'filled' ? c.value.fillcolor || c.value.color || c.value.bgcolor : null; - }) - .clusterLabel(function(c) { - return c.value.label; - }); - } -}; - -dc_graph.snapshot_graphviz = function(diagram) { - var xDomain = diagram.x().domain(), yDomain = diagram.y().domain(); - return { - nodes: diagram.nodeGroup().all().map(function(n) { - return diagram.getWholeNode(n.key); - }) - .filter(function(x) { return x; }) - .map(function(n) { - return { - key: diagram.nodeKey.eval(n), - label: diagram.nodeLabel.eval(n), - fillcolor: diagram.nodeFillScale()(diagram.nodeFill.eval(n)), - penwidth: diagram.nodeStrokeWidth.eval(n), - // not supported as input, see dc.graph.js#25 - // width: n.cola.dcg_rx*2, - // height: n.cola.dcg_ry*2, - - // not graphviz attributes - // until we have w/h - radius: diagram.nodeRadius.eval(n), - // does not seem to exist in gv - opacity: diagram.nodeOpacity.eval(n), - // should be pos - x: n.cola.x, - y: n.cola.y - }; - }), - edges: diagram.edgeGroup().all().map(function(e) { - return diagram.getWholeEdge(e.key); - }).map(function(e) { - return { - key: diagram.edgeKey.eval(e), - source: diagram.edgeSource.eval(e), - target: diagram.edgeTarget.eval(e), - color: diagram.edgeStroke.eval(e), - arrowsize: diagram.edgeArrowSize.eval(e), - opacity: diagram.edgeOpacity.eval(e), - // should support dir, see dc.graph.js#106 - arrowhead: diagram.edgeArrowhead.eval(e), - arrowtail: diagram.edgeArrowtail.eval(e) - }; - }), - bounds: { - left: xDomain[0], - top: yDomain[0], - right: xDomain[1], - bottom: yDomain[1] - } - }; -}; - -/** - * `dc_graph.cola_layout` is an adaptor for cola.js layouts in dc.graph.js - * @class cola_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.cola_layout} - **/ -dc_graph.cola_layout = function(id) { - var _layoutId = id || uuid(); - var _d3cola = null; - var _setcola_nodes; - var _dispatch = d3.dispatch('tick', 'start', 'end'); - var _flowLayout; - // node and edge objects shared with cola.js, preserved from one iteration - // to the next (as long as the object is still in the layout) - var _nodes = {}, _edges = {}; - var _options; - - function init(options) { - _options = options; - _d3cola = cola.d3adaptor() - .avoidOverlaps(true) - .size([options.width, options.height]) - .handleDisconnected(options.handleDisconnected); - - if(_d3cola.tickSize) // non-standard - _d3cola.tickSize(options.tickSize); - - switch(options.lengthStrategy) { - case 'symmetric': - _d3cola.symmetricDiffLinkLengths(options.baseLength); - break; - case 'jaccard': - _d3cola.jaccardLinkLengths(options.baseLength); - break; - case 'individual': - _d3cola.linkDistance(function(e) { - return e.dcg_edgeLength || options.baseLength; - }); - break; - case 'none': - default: - } - if(options.flowLayout) { - _d3cola.flowLayout(options.flowLayout.axis, options.flowLayout.minSeparation); - } - } - - function data(nodes, edges, clusters, constraints) { - var wnodes = regenerate_objects(_nodes, nodes, null, function(v) { - return v.dcg_nodeKey; - }, function(v1, v) { - v1.dcg_nodeKey = v.dcg_nodeKey; - v1.dcg_nodeParentCluster = v.dcg_nodeParentCluster; - v1.width = v.width; - v1.height = v.height; - v1.fixed = !!v.dcg_nodeFixed; - _options.nodeAttrs.forEach(function(key) { - v1[key] = v[key]; - }); - - if(v1.fixed && typeof v.dcg_nodeFixed === 'object') { - v1.x = v.dcg_nodeFixed.x; - v1.y = v.dcg_nodeFixed.y; - } - else { - // should we support e.g. null to unset x,y? - if(v.x !== undefined) - v1.x = v.x; - if(v.y !== undefined) - v1.y = v.y; - } - }); - var wedges = regenerate_objects(_edges, edges, null, function(e) { - return e.dcg_edgeKey; - }, function(e1, e) { - e1.dcg_edgeKey = e.dcg_edgeKey; - // cola edges can work with indices or with object references - // but it will replace indices with object references - e1.source = _nodes[e.dcg_edgeSource]; - e1.target = _nodes[e.dcg_edgeTarget]; - e1.dcg_edgeLength = e.dcg_edgeLength; - _options.edgeAttrs.forEach(function(key) { - e1[key] = e[key]; - }); - }); - - // cola needs each node object to have an index property - wnodes.forEach(function(v, i) { - v.index = i; - }); - - var groups = null; - if(engine.groupConnected()) { - var components = cola.separateGraphs(wnodes, wedges); - groups = components.map(function(g) { - return { - dcg_autoGroup: true, - leaves: g.array.map(function(n) { return n.index; }) - }; - }); - } else if(clusters) { - var G = {}; - groups = clusters.filter(function(c) { - return /^cluster/.test(c.dcg_clusterKey); - }).map(function(c, i) { - return G[c.dcg_clusterKey] = { - dcg_clusterKey: c.dcg_clusterKey, - index: i, - groups: [], - leaves: [] - }; - }); - clusters.forEach(function(c) { - if(c.dcg_clusterParent && G[c.dcg_clusterParent]) - G[c.dcg_clusterParent].groups.push(G[c.dcg_clusterKey].index); - }); - wnodes.forEach(function(n, i) { - if(n.dcg_nodeParentCluster && G[n.dcg_nodeParentCluster]) - G[n.dcg_nodeParentCluster].leaves.push(i); - }); - } - - function dispatchState(event) { - // clean up extra setcola annotations - wnodes.forEach(function(n) { - Object.keys(n).forEach(function(key) { - if(/^get/.test(key) && typeof n[key] === 'function') - delete n[key]; - }); - }); - _dispatch[event]( - wnodes, - wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }), - groups.filter(function(g) { - return !g.dcg_autoGroup; - }).map(function(g) { - g = Object.assign({}, g); - g.bounds = { - left: g.bounds.x, - top: g.bounds.y, - right: g.bounds.X, - bottom: g.bounds.Y - }; - return g; - }), - _setcola_nodes - ); - } - _d3cola.on('tick', /* _tick = */ function() { - dispatchState('tick'); - }).on('start', function() { - _dispatch.start(); - }).on('end', /* _done = */ function() { - dispatchState('end'); - }); - - if(_options.setcolaSpec && typeof setcola !== 'undefined') { - console.log('generating setcola constrains'); - var setcola_result = setcola - .nodes(wnodes) - .links(wedges) - .constraints(_options.setcolaSpec) - .gap(10) //default value is 10, can be customized in setcolaSpec - .layout(); - - _setcola_nodes = setcola_result.nodes.filter(function(n) { return n._cid; }); - _d3cola.nodes(setcola_result.nodes) - .links(setcola_result.links) - .constraints(setcola_result.constraints) - .groups(groups); - } else { - _d3cola.nodes(wnodes) - .links(wedges) - .constraints(constraints) - .groups(groups); - } - - } - - function start() { - _d3cola.start(engine.unconstrainedIterations(), - engine.userConstraintIterations(), - engine.allConstraintsIterations(), - engine.gridSnapIterations()); - } - - function stop() { - if(_d3cola) - _d3cola.stop(); - } - - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); - graphviz.rankdir(null); - - var engine = Object.assign(graphviz, { - layoutAlgorithm: function() { - return 'cola'; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return true; - }, - supportsMoving: function() { - return true; - }, - parent: property(null), - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - this.propagateOptions(options); - init(options); - return this; - }, - data: function(graph, nodes, edges, clusters, constraints) { - data(nodes, edges, clusters, constraints); - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - optionNames: function() { - return ['handleDisconnected', 'lengthStrategy', 'baseLength', 'flowLayout', - 'tickSize', 'groupConnected', 'setcolaSpec', 'setcolaNodes'] - .concat(graphviz_keys); - }, - passThru: function() { - return ['extractNodeAttrs', 'extractEdgeAttrs']; - }, - propagateOptions: function(options) { - if(!options.nodeAttrs) - options.nodeAttrs = Object.keys(engine.extractNodeAttrs()); - if(!options.edgeAttrs) - options.edgeAttrs = Object.keys(engine.extractEdgeAttrs()); - }, - populateLayoutNode: function() {}, - populateLayoutEdge: function() {}, - /** - * Instructs cola.js to fit the connected components. - * @method handleDisconnected - * @memberof dc_graph.cola_layout - * @instance - * @param {Boolean} [handleDisconnected=true] - * @return {Boolean} - * @return {dc_graph.cola_layout} - **/ - handleDisconnected: property(true), - /** - * Currently, three strategies are supported for specifying the lengths of edges: - * * 'individual' - uses the `edgeLength` for each edge. If it returns falsy, uses the - * `baseLength` - * * 'symmetric', 'jaccard' - compute the edge length based on the graph structure around - * the edge. See - * {@link https://github.com/tgdwyer/WebCola/wiki/link-lengths the cola.js wiki} - * for more details. - * 'none' - no edge lengths will be specified - * @method lengthStrategy - * @memberof dc_graph.cola_layout - * @instance - * @param {Function|String} [lengthStrategy='symmetric'] - * @return {Function|String} - * @return {dc_graph.cola_layout} - **/ - lengthStrategy: property('symmetric'), - /** - * Gets or sets the default edge length (in pixels) when the `.lengthStrategy` is - * 'individual', and the base value to be multiplied for 'symmetric' and 'jaccard' edge - * lengths. - * @method baseLength - * @memberof dc_graph.cola_layout - * @instance - * @param {Number} [baseLength=30] - * @return {Number} - * @return {dc_graph.cola_layout} - **/ - baseLength: property(30), - /** - * If `flowLayout` is set, it determines the axis and separation for - * {@link http://marvl.infotech.monash.edu/webcola/doc/classes/cola.layout.html#flowlayout cola flow layout}. - * If it is not set, `flowLayout` will be calculated from the {@link dc_graph.graphviz_attrs#rankdir rankdir} - * and {@link dc_graph.graphviz_attrs#ranksep ranksep}; if `rankdir` is also null (the - * default for cola layout), then there will be no flow. - * @method flowLayout - * @memberof dc_graph.cola_layout - * @instance - * @param {Object} [flowLayout=null] - * @example - * // No flow (default) - * diagram.flowLayout(null) - * // flow in x with min separation 200 - * diagram.flowLayout({axis: 'x', minSeparation: 200}) - **/ - flowLayout: function(flow) { - if(!arguments.length) { - if(_flowLayout) - return _flowLayout; - var dir = engine.rankdir(); - switch(dir) { - case 'LR': return {axis: 'x', minSeparation: engine.ranksep() + engine.parent().nodeRadius()*2}; - case 'TB': return {axis: 'y', minSeparation: engine.ranksep() + engine.parent().nodeRadius()*2}; - default: return null; // RL, BT do not appear to be possible (negative separation) (?) - } - } - _flowLayout = flow; - return this; - }, - unconstrainedIterations: property(10), - userConstraintIterations: property(20), - allConstraintsIterations: property(20), - gridSnapIterations: property(0), - tickSize: property(1), - groupConnected: property(false), - setcolaSpec: property(null), - setcolaNodes: function() { - return _setcola_nodes; - }, - extractNodeAttrs: property({}), // {attr: function(node)} - extractEdgeAttrs: property({}), - processExtraWorkerResults: function(setcolaNodes) { - _setcola_nodes = setcolaNodes; - } - }); - return engine; -}; - -dc_graph.cola_layout.scripts = ['d3.js', 'cola.js']; -dc_graph.cola_layout.optional_scripts = ['setcola.js']; - -var _layouts; - -function postResponse(event, layoutId) { - return function() { - var message = { - response: event, - layoutId: layoutId - }; - message.args = Array.prototype.slice.call(arguments); - postMessage(message); - }; -} - -onmessage = function(e) { - var args = e.data.args; - switch(e.data.command) { - case 'init': - // find a function under dc_graph that has `scripts` - var layout_name; - for(var name in dc_graph) { - if(typeof dc_graph[name] === 'function' && dc_graph[name].scripts) - layout_name = name; - } - if(!_layouts) { - _layouts = {}; - importScripts.apply(null, dc_graph[layout_name].scripts); - if(dc_graph[layout_name].optional_scripts) { - try { - importScripts.apply(null, dc_graph[layout_name].optional_scripts); - } - catch(xep) { - console.log(xep); - } - } - } - - _layouts[args.layoutId] = dc_graph[layout_name]() - .on('tick', postResponse('tick', args.layoutId)) - .on('start', postResponse('start', args.layoutId)) - .on('end', postResponse('end', args.layoutId)) - .init(args.options); - break; - case 'data': - if(_layouts) - _layouts[args.layoutId].data(args.graph, args.nodes, args.edges, args.clusters, args.constraints); - break; - case 'start': - // if(args.initialOnly) { - // if(args.showLayoutSteps) - // _tick(); - // _done(); - // } - // else - _layouts[args.layoutId].start(); - break; - case 'stop': - if(_layouts) - _layouts[args.layoutId].stop(); - break; - } -}; - - -//# sourceMappingURL=dc.graph.cola.worker.js.map \ No newline at end of file diff --git a/dc.graph.cola.worker.js.map b/dc.graph.cola.worker.js.map deleted file mode 100644 index 664751ba..00000000 --- a/dc.graph.cola.worker.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["src/core.js","src/generate_objects.js","src/graphviz_attrs.js","src/cola_layout.js","src/webworker_message.js"],"names":[],"mappings":"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","file":"dc.graph.cola.worker.js","sourcesContent":["/**\n * The entire dc.graph.js library is scoped under the **dc_graph** name space. It does not introduce\n * anything else into the global name space.\n *\n * Like in dc.js and most libraries built on d3, most `dc_graph` functions are designed to allow function chaining, meaning they return the current diagram\n * instance whenever it is appropriate. The getter forms of functions do not participate in function\n * chaining because they return values that are not the diagram.\n * @namespace dc_graph\n * @version 0.9.93\n * @example\n * // Example chaining\n * diagram.width(600)\n * .height(400)\n * .nodeDimension(nodeDim)\n * .nodeGroup(nodeGroup);\n */\n\nvar dc_graph = {\n version: '0.9.93',\n constants: {\n CHART_CLASS: 'dc-graph'\n }\n};\n\nfunction get_original(x) {\n return x.orig;\n}\n\nfunction identity(x) {\n return x;\n};\n\nvar property = function (defaultValue, unwrap) {\n if(unwrap === undefined)\n unwrap = get_original;\n else if(unwrap === false)\n unwrap = identity;\n var value = defaultValue, react = null;\n var cascade = [];\n var ret = function (_) {\n if (!arguments.length) {\n return value;\n }\n if(react)\n react(_);\n value = _;\n return this;\n };\n ret.cascade = function (n, f) {\n for(var i = 0; i n) {\n cascade.splice(i, 0, {n: n, f: f});\n return ret;\n }\n }\n cascade.push({n: n, f: f});\n return ret;\n };\n ret._eval = function(o, n) {\n if(n===0 || !cascade.length)\n return dc_graph.functor_wrap(ret(), unwrap)(o);\n else {\n var last = cascade[n-1];\n return last.f(o, function() {\n return ret._eval(o, n-1);\n });\n }\n };\n ret.eval = function(o) {\n return ret._eval(o, cascade.length);\n };\n ret.react = function(_) {\n if (!arguments.length) {\n return react;\n }\n react = _;\n return this;\n };\n return ret;\n};\n\nfunction named_children() {\n var _children = {};\n var f = function(id, object) {\n if(arguments.length === 1)\n return _children[id];\n if(f.reject) {\n var reject = f.reject(id, object);\n if(reject) {\n console.groupCollapsed(reject);\n console.trace();\n console.groupEnd();\n return this;\n }\n }\n // do not notify unnecessarily\n if(_children[id] === object)\n return this;\n if(_children[id])\n _children[id].parent(null);\n _children[id] = object;\n if(object)\n object.parent(this);\n return this;\n };\n f.enum = function() {\n return Object.keys(_children);\n };\n f.nameOf = function(o) {\n var found = Object.entries(_children).find(function(kv) {\n return kv[1] == o;\n });\n return found ? found[0] : null;\n };\n return f;\n}\n\nfunction deprecated_property(message, defaultValue) {\n var prop = property(defaultValue);\n var ret = function() {\n if(arguments.length) {\n console.warn(message);\n prop.apply(property, arguments);\n return this;\n }\n return prop();\n };\n ['cascade', '_eval', 'eval', 'react'].forEach(function(method) {\n ret[method] = prop[method];\n });\n return ret;\n}\n\nfunction onetime_trace(level, message) {\n var said = false;\n return function() {\n if(said)\n return;\n if(level === 'trace') {\n // todo: implement levels?\n // console.groupCollapsed(message);\n // console.trace();\n // console.groupEnd();\n }\n else\n console[level](message);\n said = true;\n };\n}\n\nfunction deprecation_warning(message) {\n return onetime_trace('warn', message);\n}\n\nfunction trace_function(level, message, f) {\n var dep = onetime_trace(level, message);\n return function() {\n dep();\n return f.apply(this, arguments);\n };\n}\nfunction deprecate_function(message, f) {\n return trace_function('warn', message, f);\n}\n\n// http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript\nfunction uuid() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {\n var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);\n return v.toString(16);\n });\n}\n\nfunction is_ie() {\n var ua = window.navigator.userAgent;\n\n return(ua.indexOf('MSIE ') > 0 ||\n ua.indexOf('Trident/') > 0 ||\n ua.indexOf('Edge/') > 0);\n}\n\nfunction is_safari() {\n return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n}\n\n// polyfill Object.assign for IE\n// it's just too useful to do without\nif (typeof Object.assign != 'function') {\n // Must be writable: true, enumerable: false, configurable: true\n Object.defineProperty(Object, \"assign\", {\n value: function assign(target, varArgs) { // .length of function is 2\n 'use strict';\n if (target == null) { // TypeError if undefined or null\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n var to = Object(target);\n\n for (var index = 1; index < arguments.length; index++) {\n var nextSource = arguments[index];\n\n if (nextSource != null) { // Skip over if undefined or null\n for (var nextKey in nextSource) {\n // Avoid bugs when hasOwnProperty is shadowed\n if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n }\n return to;\n },\n writable: true,\n configurable: true\n });\n}\n\n\n// https://tc39.github.io/ecma262/#sec-array.prototype.includes\nif (!Array.prototype.includes) {\n Object.defineProperty(Array.prototype, 'includes', {\n value: function(valueToFind, fromIndex) {\n\n if (this == null) {\n throw new TypeError('\"this\" is null or not defined');\n }\n\n // 1. Let O be ? ToObject(this value).\n var o = Object(this);\n\n // 2. Let len be ? ToLength(? Get(O, \"length\")).\n var len = o.length >>> 0;\n\n // 3. If len is 0, return false.\n if (len === 0) {\n return false;\n }\n\n // 4. Let n be ? ToInteger(fromIndex).\n // (If fromIndex is undefined, this step produces the value 0.)\n var n = fromIndex | 0;\n\n // 5. If n >= 0, then\n // a. Let k be n.\n // 6. Else n < 0,\n // a. Let k be len + n.\n // b. If k < 0, let k be 0.\n var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);\n\n function sameValueZero(x, y) {\n return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));\n }\n\n // 7. Repeat, while k < len\n while (k < len) {\n // a. Let elementK be the result of ? Get(O, ! ToString(k)).\n // b. If SameValueZero(valueToFind, elementK) is true, return true.\n if (sameValueZero(o[k], valueToFind)) {\n return true;\n }\n // c. Increase k by 1.\n k++;\n }\n\n // 8. Return false\n return false;\n }\n });\n}\n\nif (!Object.entries) {\n Object.entries = function( obj ){\n var ownProps = Object.keys( obj ),\n i = ownProps.length,\n resArray = new Array(i); // preallocate the Array\n while (i--)\n resArray[i] = [ownProps[i], obj[ownProps[i]]];\n return resArray;\n };\n}\n\n// https://github.com/KhaledElAnsari/Object.values\nObject.values = Object.values ? Object.values : function(obj) {\n var allowedTypes = [\"[object String]\", \"[object Object]\", \"[object Array]\", \"[object Function]\"];\n var objType = Object.prototype.toString.call(obj);\n\n if(obj === null || typeof obj === \"undefined\") {\n\tthrow new TypeError(\"Cannot convert undefined or null to object\");\n } else if(!~allowedTypes.indexOf(objType)) {\n\treturn [];\n } else {\n\t// if ES6 is supported\n\tif (Object.keys) {\n\t return Object.keys(obj).map(function (key) {\n\t\treturn obj[key];\n\t });\n\t}\n\n\tvar result = [];\n\tfor (var prop in obj) {\n\t if (obj.hasOwnProperty(prop)) {\n\t\tresult.push(obj[prop]);\n\t }\n\t}\n\n\treturn result;\n }\n};\n\nfunction getBBoxNoThrow(elem) {\n // firefox seems to have issues with some of my texts\n // just catch for now\n try {\n return elem.getBBox();\n } catch(xep) {\n return {x: 0, y: 0, width:0, height: 0};\n }\n}\n","// create or re-use objects in a map, delete the ones that were not reused\nfunction regenerate_objects(preserved, list, need, key, assign, create, destroy) {\n if(!create) create = function(k, o) { };\n if(!destroy) destroy = function(k) { };\n var keep = {};\n function wrap(o) {\n var k = key(o);\n if(!preserved[k])\n create(k, preserved[k] = {}, o);\n var o1 = preserved[k];\n assign(o1, o);\n keep[k] = true;\n return o1;\n }\n var wlist = list.map(wrap);\n if(need)\n need.forEach(function(k) {\n if(!preserved[k]) { // hasn't been created, needs to be\n create(k, preserved[k] = {}, null);\n assign(preserved[k], null);\n }\n if(!keep[k]) { // wasn't in list, should be\n wlist.push(preserved[k]);\n keep[k] = true;\n }\n });\n // delete any objects from last round that are no longer used\n for(var k in preserved)\n if(!keep[k]) {\n destroy(k, preserved[k]);\n delete preserved[k];\n }\n return wlist;\n}\n","/**\n * `dc_graph.graphviz_attrs defines a basic set of attributes which layout engines should\n * implement - although these are not required, they make it easier for clients and\n * modes (like expand_collapse) to work with multiple layout engines.\n *\n * these attributes are {@link http://www.graphviz.org/doc/info/attrs.html from graphviz}\n * @class graphviz_attrs\n * @memberof dc_graph\n * @return {Object}\n **/\ndc_graph.graphviz_attrs = function() {\n return {\n /**\n * Direction to draw ranks.\n * @method rankdir\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [rankdir='TB'] 'TB', 'LR', 'BT', or 'RL'\n **/\n rankdir: property('TB'),\n /**\n * Spacing in between nodes in the same rank.\n * @method nodesep\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [nodesep=40]\n **/\n nodesep: property(40),\n /**\n * Spacing in between ranks.\n * @method ranksep\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [ranksep=40]\n **/\n ranksep: property(40)\n };\n};\n\n// graphlib-dot seems to wrap nodes in an extra {value}\n// actually this is quite a common problem with generic libs\nfunction nvalue(n) {\n return n.value.value ? n.value.value : n.value;\n}\n\n// apply standard accessors to a diagram in order to style it as graphviz would\n// this is a work in progress\ndc_graph.apply_graphviz_accessors = function(diagram) {\n diagram\n .nodeLabel(function(n) {\n var label = nvalue(n).label;\n if(label === undefined)\n label = n.key;\n return label && label.split(/\\n|\\\\n/);\n })\n .nodeRadius(function(n) {\n // should do width & height instead, #25\n return nvalue(n).radius || 25;\n })\n .nodeShape(function(n) { return nvalue(n).shape; })\n .nodeFill(function(n) { return nvalue(n).fillcolor || 'white'; })\n .nodeOpacity(function(n) {\n // not standard gv\n return nvalue(n).opacity || 1;\n })\n .nodeLabelFill(function(n) { return nvalue(n).fontcolor || 'black'; })\n .nodeTitle(function(n) {\n return (nvalue(n).htmltip || nvalue(n).jsontip) ? null :\n nvalue(n).tooltip !== undefined ?\n nvalue(n).tooltip :\n diagram.nodeLabel()(n);\n })\n .nodeStrokeWidth(function(n) {\n // it is debatable whether a point === a pixel but they are close\n // https://graphicdesign.stackexchange.com/questions/199/point-vs-pixel-what-is-the-difference\n var penwidth = nvalue(n).penwidth;\n return penwidth !== undefined ? +penwidth : 1;\n })\n .edgeLabel(function(e) { return e.value.label ? e.value.label.split(/\\n|\\\\n/) : ''; })\n .edgeStroke(function(e) { return e.value.color || 'black'; })\n .edgeOpacity(function(e) {\n // not standard gv\n return e.value.opacity || 1;\n })\n .edgeArrowSize(function(e) {\n return e.value.arrowsize || 1;\n })\n // need directedness to default these correctly, see #106\n .edgeArrowhead(function(e) {\n var head = e.value.arrowhead;\n return head !== undefined ? head : 'vee';\n })\n .edgeArrowtail(function(e) {\n var tail = e.value.arrowtail;\n return tail !== undefined ? tail : null;\n })\n .edgeStrokeDashArray(function(e) {\n switch(e.value.style) {\n case 'dotted':\n return [1,5];\n }\n return null;\n });\n var draw_clusters = diagram.child('draw-clusters');\n if(draw_clusters) {\n draw_clusters\n .clusterStroke(function(c) {\n return c.value.color || 'black';\n })\n .clusterFill(function(c) {\n return c.value.style === 'filled' ? c.value.fillcolor || c.value.color || c.value.bgcolor : null;\n })\n .clusterLabel(function(c) {\n return c.value.label;\n });\n }\n};\n\ndc_graph.snapshot_graphviz = function(diagram) {\n var xDomain = diagram.x().domain(), yDomain = diagram.y().domain();\n return {\n nodes: diagram.nodeGroup().all().map(function(n) {\n return diagram.getWholeNode(n.key);\n })\n .filter(function(x) { return x; })\n .map(function(n) {\n return {\n key: diagram.nodeKey.eval(n),\n label: diagram.nodeLabel.eval(n),\n fillcolor: diagram.nodeFillScale()(diagram.nodeFill.eval(n)),\n penwidth: diagram.nodeStrokeWidth.eval(n),\n // not supported as input, see dc.graph.js#25\n // width: n.cola.dcg_rx*2,\n // height: n.cola.dcg_ry*2,\n\n // not graphviz attributes\n // until we have w/h\n radius: diagram.nodeRadius.eval(n),\n // does not seem to exist in gv\n opacity: diagram.nodeOpacity.eval(n),\n // should be pos\n x: n.cola.x,\n y: n.cola.y\n };\n }),\n edges: diagram.edgeGroup().all().map(function(e) {\n return diagram.getWholeEdge(e.key);\n }).map(function(e) {\n return {\n key: diagram.edgeKey.eval(e),\n source: diagram.edgeSource.eval(e),\n target: diagram.edgeTarget.eval(e),\n color: diagram.edgeStroke.eval(e),\n arrowsize: diagram.edgeArrowSize.eval(e),\n opacity: diagram.edgeOpacity.eval(e),\n // should support dir, see dc.graph.js#106\n arrowhead: diagram.edgeArrowhead.eval(e),\n arrowtail: diagram.edgeArrowtail.eval(e)\n };\n }),\n bounds: {\n left: xDomain[0],\n top: yDomain[0],\n right: xDomain[1],\n bottom: yDomain[1]\n }\n };\n};\n","/**\n * `dc_graph.cola_layout` is an adaptor for cola.js layouts in dc.graph.js\n * @class cola_layout\n * @memberof dc_graph\n * @param {String} [id=uuid()] - Unique identifier\n * @return {dc_graph.cola_layout}\n **/\ndc_graph.cola_layout = function(id) {\n var _layoutId = id || uuid();\n var _d3cola = null;\n var _setcola_nodes;\n var _dispatch = d3.dispatch('tick', 'start', 'end');\n var _flowLayout;\n // node and edge objects shared with cola.js, preserved from one iteration\n // to the next (as long as the object is still in the layout)\n var _nodes = {}, _edges = {};\n var _options;\n\n function init(options) {\n _options = options;\n _d3cola = cola.d3adaptor()\n .avoidOverlaps(true)\n .size([options.width, options.height])\n .handleDisconnected(options.handleDisconnected);\n\n if(_d3cola.tickSize) // non-standard\n _d3cola.tickSize(options.tickSize);\n\n switch(options.lengthStrategy) {\n case 'symmetric':\n _d3cola.symmetricDiffLinkLengths(options.baseLength);\n break;\n case 'jaccard':\n _d3cola.jaccardLinkLengths(options.baseLength);\n break;\n case 'individual':\n _d3cola.linkDistance(function(e) {\n return e.dcg_edgeLength || options.baseLength;\n });\n break;\n case 'none':\n default:\n }\n if(options.flowLayout) {\n _d3cola.flowLayout(options.flowLayout.axis, options.flowLayout.minSeparation);\n }\n }\n\n function data(nodes, edges, clusters, constraints) {\n var wnodes = regenerate_objects(_nodes, nodes, null, function(v) {\n return v.dcg_nodeKey;\n }, function(v1, v) {\n v1.dcg_nodeKey = v.dcg_nodeKey;\n v1.dcg_nodeParentCluster = v.dcg_nodeParentCluster;\n v1.width = v.width;\n v1.height = v.height;\n v1.fixed = !!v.dcg_nodeFixed;\n _options.nodeAttrs.forEach(function(key) {\n v1[key] = v[key];\n });\n\n if(v1.fixed && typeof v.dcg_nodeFixed === 'object') {\n v1.x = v.dcg_nodeFixed.x;\n v1.y = v.dcg_nodeFixed.y;\n }\n else {\n // should we support e.g. null to unset x,y?\n if(v.x !== undefined)\n v1.x = v.x;\n if(v.y !== undefined)\n v1.y = v.y;\n }\n });\n var wedges = regenerate_objects(_edges, edges, null, function(e) {\n return e.dcg_edgeKey;\n }, function(e1, e) {\n e1.dcg_edgeKey = e.dcg_edgeKey;\n // cola edges can work with indices or with object references\n // but it will replace indices with object references\n e1.source = _nodes[e.dcg_edgeSource];\n e1.target = _nodes[e.dcg_edgeTarget];\n e1.dcg_edgeLength = e.dcg_edgeLength;\n _options.edgeAttrs.forEach(function(key) {\n e1[key] = e[key];\n });\n });\n\n // cola needs each node object to have an index property\n wnodes.forEach(function(v, i) {\n v.index = i;\n });\n\n var groups = null;\n if(engine.groupConnected()) {\n var components = cola.separateGraphs(wnodes, wedges);\n groups = components.map(function(g) {\n return {\n dcg_autoGroup: true,\n leaves: g.array.map(function(n) { return n.index; })\n };\n });\n } else if(clusters) {\n var G = {};\n groups = clusters.filter(function(c) {\n return /^cluster/.test(c.dcg_clusterKey);\n }).map(function(c, i) {\n return G[c.dcg_clusterKey] = {\n dcg_clusterKey: c.dcg_clusterKey,\n index: i,\n groups: [],\n leaves: []\n };\n });\n clusters.forEach(function(c) {\n if(c.dcg_clusterParent && G[c.dcg_clusterParent])\n G[c.dcg_clusterParent].groups.push(G[c.dcg_clusterKey].index);\n });\n wnodes.forEach(function(n, i) {\n if(n.dcg_nodeParentCluster && G[n.dcg_nodeParentCluster])\n G[n.dcg_nodeParentCluster].leaves.push(i);\n });\n }\n\n function dispatchState(event) {\n // clean up extra setcola annotations\n wnodes.forEach(function(n) {\n Object.keys(n).forEach(function(key) {\n if(/^get/.test(key) && typeof n[key] === 'function')\n delete n[key];\n });\n });\n _dispatch[event](\n wnodes,\n wedges.map(function(e) {\n return {dcg_edgeKey: e.dcg_edgeKey};\n }),\n groups.filter(function(g) {\n return !g.dcg_autoGroup;\n }).map(function(g) {\n g = Object.assign({}, g);\n g.bounds = {\n left: g.bounds.x,\n top: g.bounds.y,\n right: g.bounds.X,\n bottom: g.bounds.Y\n };\n return g;\n }),\n _setcola_nodes\n );\n }\n _d3cola.on('tick', /* _tick = */ function() {\n dispatchState('tick');\n }).on('start', function() {\n _dispatch.start();\n }).on('end', /* _done = */ function() {\n dispatchState('end');\n });\n\n if(_options.setcolaSpec && typeof setcola !== 'undefined') {\n console.log('generating setcola constrains');\n var setcola_result = setcola\n .nodes(wnodes)\n .links(wedges)\n .constraints(_options.setcolaSpec)\n .gap(10) //default value is 10, can be customized in setcolaSpec\n .layout();\n\n _setcola_nodes = setcola_result.nodes.filter(function(n) { return n._cid; });\n _d3cola.nodes(setcola_result.nodes)\n .links(setcola_result.links)\n .constraints(setcola_result.constraints)\n .groups(groups);\n } else {\n _d3cola.nodes(wnodes)\n .links(wedges)\n .constraints(constraints)\n .groups(groups);\n }\n\n }\n\n function start() {\n _d3cola.start(engine.unconstrainedIterations(),\n engine.userConstraintIterations(),\n engine.allConstraintsIterations(),\n engine.gridSnapIterations());\n }\n\n function stop() {\n if(_d3cola)\n _d3cola.stop();\n }\n\n var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz);\n graphviz.rankdir(null);\n\n var engine = Object.assign(graphviz, {\n layoutAlgorithm: function() {\n return 'cola';\n },\n layoutId: function() {\n return _layoutId;\n },\n supportsWebworker: function() {\n return true;\n },\n supportsMoving: function() {\n return true;\n },\n parent: property(null),\n on: function(event, f) {\n if(arguments.length === 1)\n return _dispatch.on(event);\n _dispatch.on(event, f);\n return this;\n },\n init: function(options) {\n this.optionNames().forEach(function(option) {\n options[option] = options[option] || this[option]();\n }.bind(this));\n this.propagateOptions(options);\n init(options);\n return this;\n },\n data: function(graph, nodes, edges, clusters, constraints) {\n data(nodes, edges, clusters, constraints);\n },\n start: function() {\n start();\n },\n stop: function() {\n stop();\n },\n optionNames: function() {\n return ['handleDisconnected', 'lengthStrategy', 'baseLength', 'flowLayout',\n 'tickSize', 'groupConnected', 'setcolaSpec', 'setcolaNodes']\n .concat(graphviz_keys);\n },\n passThru: function() {\n return ['extractNodeAttrs', 'extractEdgeAttrs'];\n },\n propagateOptions: function(options) {\n if(!options.nodeAttrs)\n options.nodeAttrs = Object.keys(engine.extractNodeAttrs());\n if(!options.edgeAttrs)\n options.edgeAttrs = Object.keys(engine.extractEdgeAttrs());\n },\n populateLayoutNode: function() {},\n populateLayoutEdge: function() {},\n /**\n * Instructs cola.js to fit the connected components.\n * @method handleDisconnected\n * @memberof dc_graph.cola_layout\n * @instance\n * @param {Boolean} [handleDisconnected=true]\n * @return {Boolean}\n * @return {dc_graph.cola_layout}\n **/\n handleDisconnected: property(true),\n /**\n * Currently, three strategies are supported for specifying the lengths of edges:\n * * 'individual' - uses the `edgeLength` for each edge. If it returns falsy, uses the\n * `baseLength`\n * * 'symmetric', 'jaccard' - compute the edge length based on the graph structure around\n * the edge. See\n * {@link https://github.com/tgdwyer/WebCola/wiki/link-lengths the cola.js wiki}\n * for more details.\n * 'none' - no edge lengths will be specified\n * @method lengthStrategy\n * @memberof dc_graph.cola_layout\n * @instance\n * @param {Function|String} [lengthStrategy='symmetric']\n * @return {Function|String}\n * @return {dc_graph.cola_layout}\n **/\n lengthStrategy: property('symmetric'),\n /**\n * Gets or sets the default edge length (in pixels) when the `.lengthStrategy` is\n * 'individual', and the base value to be multiplied for 'symmetric' and 'jaccard' edge\n * lengths.\n * @method baseLength\n * @memberof dc_graph.cola_layout\n * @instance\n * @param {Number} [baseLength=30]\n * @return {Number}\n * @return {dc_graph.cola_layout}\n **/\n baseLength: property(30),\n /**\n * If `flowLayout` is set, it determines the axis and separation for\n * {@link http://marvl.infotech.monash.edu/webcola/doc/classes/cola.layout.html#flowlayout cola flow layout}.\n * If it is not set, `flowLayout` will be calculated from the {@link dc_graph.graphviz_attrs#rankdir rankdir}\n * and {@link dc_graph.graphviz_attrs#ranksep ranksep}; if `rankdir` is also null (the\n * default for cola layout), then there will be no flow.\n * @method flowLayout\n * @memberof dc_graph.cola_layout\n * @instance\n * @param {Object} [flowLayout=null]\n * @example\n * // No flow (default)\n * diagram.flowLayout(null)\n * // flow in x with min separation 200\n * diagram.flowLayout({axis: 'x', minSeparation: 200})\n **/\n flowLayout: function(flow) {\n if(!arguments.length) {\n if(_flowLayout)\n return _flowLayout;\n var dir = engine.rankdir();\n switch(dir) {\n case 'LR': return {axis: 'x', minSeparation: engine.ranksep() + engine.parent().nodeRadius()*2};\n case 'TB': return {axis: 'y', minSeparation: engine.ranksep() + engine.parent().nodeRadius()*2};\n default: return null; // RL, BT do not appear to be possible (negative separation) (?)\n }\n }\n _flowLayout = flow;\n return this;\n },\n unconstrainedIterations: property(10),\n userConstraintIterations: property(20),\n allConstraintsIterations: property(20),\n gridSnapIterations: property(0),\n tickSize: property(1),\n groupConnected: property(false),\n setcolaSpec: property(null),\n setcolaNodes: function() {\n return _setcola_nodes;\n },\n extractNodeAttrs: property({}), // {attr: function(node)}\n extractEdgeAttrs: property({}),\n processExtraWorkerResults: function(setcolaNodes) {\n _setcola_nodes = setcolaNodes;\n }\n });\n return engine;\n};\n\ndc_graph.cola_layout.scripts = ['d3.js', 'cola.js'];\ndc_graph.cola_layout.optional_scripts = ['setcola.js'];\n","var _layouts;\n\nfunction postResponse(event, layoutId) {\n return function() {\n var message = {\n response: event,\n layoutId: layoutId\n };\n message.args = Array.prototype.slice.call(arguments);\n postMessage(message);\n };\n}\n\nonmessage = function(e) {\n var args = e.data.args;\n switch(e.data.command) {\n case 'init':\n // find a function under dc_graph that has `scripts`\n var layout_name;\n for(var name in dc_graph) {\n if(typeof dc_graph[name] === 'function' && dc_graph[name].scripts)\n layout_name = name;\n }\n if(!_layouts) {\n _layouts = {};\n importScripts.apply(null, dc_graph[layout_name].scripts);\n if(dc_graph[layout_name].optional_scripts) {\n try {\n importScripts.apply(null, dc_graph[layout_name].optional_scripts);\n }\n catch(xep) {\n console.log(xep);\n }\n }\n }\n\n _layouts[args.layoutId] = dc_graph[layout_name]()\n .on('tick', postResponse('tick', args.layoutId))\n .on('start', postResponse('start', args.layoutId))\n .on('end', postResponse('end', args.layoutId))\n .init(args.options);\n break;\n case 'data':\n if(_layouts)\n _layouts[args.layoutId].data(args.graph, args.nodes, args.edges, args.clusters, args.constraints);\n break;\n case 'start':\n // if(args.initialOnly) {\n // if(args.showLayoutSteps)\n // _tick();\n // _done();\n // }\n // else\n _layouts[args.layoutId].start();\n break;\n case 'stop':\n if(_layouts)\n _layouts[args.layoutId].stop();\n break;\n }\n};\n\n"]} \ No newline at end of file diff --git a/dc.graph.css b/dc.graph.css index c34160f4..a9f3c10c 100644 --- a/dc.graph.css +++ b/dc.graph.css @@ -17,6 +17,44 @@ pointer-events: none; } +/* Tippy tooltip styling */ +.tippy-box[data-theme~='light-border'] { + background-color: #fff; + border: 1px solid #ccc; + border-radius: 8px; + box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12); + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + font-size: 13px; + line-height: 1.4; +} + +.tippy-box[data-theme~='light-border'] .tippy-content { + padding: 8px 12px; + color: #333; +} + +.tippy-box[data-theme~='light-border'] .tippy-content table { + border-collapse: collapse; + margin: 0; + font-size: 12px; +} + +.tippy-box[data-theme~='light-border'] .tippy-content table td { + padding: 2px 6px; + border-bottom: 1px solid #eee; + vertical-align: top; +} + +.tippy-box[data-theme~='light-border'] .tippy-content table td:first-child { + font-weight: 500; + color: #666; + padding-right: 12px; +} + +.tippy-box[data-theme~='light-border'] .tippy-arrow { + color: #fff; +} + .dc-graph .edge-label { font: 10px sans-serif; pointer-events: none; diff --git a/dc.graph.d3-force.worker.js b/dc.graph.d3-force.worker.js deleted file mode 100644 index 9903d1c6..00000000 --- a/dc.graph.d3-force.worker.js +++ /dev/null @@ -1,888 +0,0 @@ -/*! - * dc.graph 0.9.93 - * http://dc-js.github.io/dc.graph.js/ - * Copyright 2015-2019 AT&T Intellectual Property & the dc.graph.js Developers - * https://github.com/dc-js/dc.graph.js/blob/master/AUTHORS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -/** - * The entire dc.graph.js library is scoped under the **dc_graph** name space. It does not introduce - * anything else into the global name space. - * - * Like in dc.js and most libraries built on d3, most `dc_graph` functions are designed to allow function chaining, meaning they return the current diagram - * instance whenever it is appropriate. The getter forms of functions do not participate in function - * chaining because they return values that are not the diagram. - * @namespace dc_graph - * @version 0.9.93 - * @example - * // Example chaining - * diagram.width(600) - * .height(400) - * .nodeDimension(nodeDim) - * .nodeGroup(nodeGroup); - */ - -var dc_graph = { - version: '0.9.93', - constants: { - CHART_CLASS: 'dc-graph' - } -}; - -function get_original(x) { - return x.orig; -} - -function identity(x) { - return x; -}; - -var property = function (defaultValue, unwrap) { - if(unwrap === undefined) - unwrap = get_original; - else if(unwrap === false) - unwrap = identity; - var value = defaultValue, react = null; - var cascade = []; - var ret = function (_) { - if (!arguments.length) { - return value; - } - if(react) - react(_); - value = _; - return this; - }; - ret.cascade = function (n, f) { - for(var i = 0; i n) { - cascade.splice(i, 0, {n: n, f: f}); - return ret; - } - } - cascade.push({n: n, f: f}); - return ret; - }; - ret._eval = function(o, n) { - if(n===0 || !cascade.length) - return dc_graph.functor_wrap(ret(), unwrap)(o); - else { - var last = cascade[n-1]; - return last.f(o, function() { - return ret._eval(o, n-1); - }); - } - }; - ret.eval = function(o) { - return ret._eval(o, cascade.length); - }; - ret.react = function(_) { - if (!arguments.length) { - return react; - } - react = _; - return this; - }; - return ret; -}; - -function named_children() { - var _children = {}; - var f = function(id, object) { - if(arguments.length === 1) - return _children[id]; - if(f.reject) { - var reject = f.reject(id, object); - if(reject) { - console.groupCollapsed(reject); - console.trace(); - console.groupEnd(); - return this; - } - } - // do not notify unnecessarily - if(_children[id] === object) - return this; - if(_children[id]) - _children[id].parent(null); - _children[id] = object; - if(object) - object.parent(this); - return this; - }; - f.enum = function() { - return Object.keys(_children); - }; - f.nameOf = function(o) { - var found = Object.entries(_children).find(function(kv) { - return kv[1] == o; - }); - return found ? found[0] : null; - }; - return f; -} - -function deprecated_property(message, defaultValue) { - var prop = property(defaultValue); - var ret = function() { - if(arguments.length) { - console.warn(message); - prop.apply(property, arguments); - return this; - } - return prop(); - }; - ['cascade', '_eval', 'eval', 'react'].forEach(function(method) { - ret[method] = prop[method]; - }); - return ret; -} - -function onetime_trace(level, message) { - var said = false; - return function() { - if(said) - return; - if(level === 'trace') { - // todo: implement levels? - // console.groupCollapsed(message); - // console.trace(); - // console.groupEnd(); - } - else - console[level](message); - said = true; - }; -} - -function deprecation_warning(message) { - return onetime_trace('warn', message); -} - -function trace_function(level, message, f) { - var dep = onetime_trace(level, message); - return function() { - dep(); - return f.apply(this, arguments); - }; -} -function deprecate_function(message, f) { - return trace_function('warn', message, f); -} - -// http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript -function uuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); - return v.toString(16); - }); -} - -function is_ie() { - var ua = window.navigator.userAgent; - - return(ua.indexOf('MSIE ') > 0 || - ua.indexOf('Trident/') > 0 || - ua.indexOf('Edge/') > 0); -} - -function is_safari() { - return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); -} - -// polyfill Object.assign for IE -// it's just too useful to do without -if (typeof Object.assign != 'function') { - // Must be writable: true, enumerable: false, configurable: true - Object.defineProperty(Object, "assign", { - value: function assign(target, varArgs) { // .length of function is 2 - 'use strict'; - if (target == null) { // TypeError if undefined or null - throw new TypeError('Cannot convert undefined or null to object'); - } - - var to = Object(target); - - for (var index = 1; index < arguments.length; index++) { - var nextSource = arguments[index]; - - if (nextSource != null) { // Skip over if undefined or null - for (var nextKey in nextSource) { - // Avoid bugs when hasOwnProperty is shadowed - if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { - to[nextKey] = nextSource[nextKey]; - } - } - } - } - return to; - }, - writable: true, - configurable: true - }); -} - - -// https://tc39.github.io/ecma262/#sec-array.prototype.includes -if (!Array.prototype.includes) { - Object.defineProperty(Array.prototype, 'includes', { - value: function(valueToFind, fromIndex) { - - if (this == null) { - throw new TypeError('"this" is null or not defined'); - } - - // 1. Let O be ? ToObject(this value). - var o = Object(this); - - // 2. Let len be ? ToLength(? Get(O, "length")). - var len = o.length >>> 0; - - // 3. If len is 0, return false. - if (len === 0) { - return false; - } - - // 4. Let n be ? ToInteger(fromIndex). - // (If fromIndex is undefined, this step produces the value 0.) - var n = fromIndex | 0; - - // 5. If n >= 0, then - // a. Let k be n. - // 6. Else n < 0, - // a. Let k be len + n. - // b. If k < 0, let k be 0. - var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); - - function sameValueZero(x, y) { - return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y)); - } - - // 7. Repeat, while k < len - while (k < len) { - // a. Let elementK be the result of ? Get(O, ! ToString(k)). - // b. If SameValueZero(valueToFind, elementK) is true, return true. - if (sameValueZero(o[k], valueToFind)) { - return true; - } - // c. Increase k by 1. - k++; - } - - // 8. Return false - return false; - } - }); -} - -if (!Object.entries) { - Object.entries = function( obj ){ - var ownProps = Object.keys( obj ), - i = ownProps.length, - resArray = new Array(i); // preallocate the Array - while (i--) - resArray[i] = [ownProps[i], obj[ownProps[i]]]; - return resArray; - }; -} - -// https://github.com/KhaledElAnsari/Object.values -Object.values = Object.values ? Object.values : function(obj) { - var allowedTypes = ["[object String]", "[object Object]", "[object Array]", "[object Function]"]; - var objType = Object.prototype.toString.call(obj); - - if(obj === null || typeof obj === "undefined") { - throw new TypeError("Cannot convert undefined or null to object"); - } else if(!~allowedTypes.indexOf(objType)) { - return []; - } else { - // if ES6 is supported - if (Object.keys) { - return Object.keys(obj).map(function (key) { - return obj[key]; - }); - } - - var result = []; - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - result.push(obj[prop]); - } - } - - return result; - } -}; - -function getBBoxNoThrow(elem) { - // firefox seems to have issues with some of my texts - // just catch for now - try { - return elem.getBBox(); - } catch(xep) { - return {x: 0, y: 0, width:0, height: 0}; - } -} - -// create or re-use objects in a map, delete the ones that were not reused -function regenerate_objects(preserved, list, need, key, assign, create, destroy) { - if(!create) create = function(k, o) { }; - if(!destroy) destroy = function(k) { }; - var keep = {}; - function wrap(o) { - var k = key(o); - if(!preserved[k]) - create(k, preserved[k] = {}, o); - var o1 = preserved[k]; - assign(o1, o); - keep[k] = true; - return o1; - } - var wlist = list.map(wrap); - if(need) - need.forEach(function(k) { - if(!preserved[k]) { // hasn't been created, needs to be - create(k, preserved[k] = {}, null); - assign(preserved[k], null); - } - if(!keep[k]) { // wasn't in list, should be - wlist.push(preserved[k]); - keep[k] = true; - } - }); - // delete any objects from last round that are no longer used - for(var k in preserved) - if(!keep[k]) { - destroy(k, preserved[k]); - delete preserved[k]; - } - return wlist; -} - -/** - * `dc_graph.graphviz_attrs defines a basic set of attributes which layout engines should - * implement - although these are not required, they make it easier for clients and - * modes (like expand_collapse) to work with multiple layout engines. - * - * these attributes are {@link http://www.graphviz.org/doc/info/attrs.html from graphviz} - * @class graphviz_attrs - * @memberof dc_graph - * @return {Object} - **/ -dc_graph.graphviz_attrs = function() { - return { - /** - * Direction to draw ranks. - * @method rankdir - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [rankdir='TB'] 'TB', 'LR', 'BT', or 'RL' - **/ - rankdir: property('TB'), - /** - * Spacing in between nodes in the same rank. - * @method nodesep - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [nodesep=40] - **/ - nodesep: property(40), - /** - * Spacing in between ranks. - * @method ranksep - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [ranksep=40] - **/ - ranksep: property(40) - }; -}; - -// graphlib-dot seems to wrap nodes in an extra {value} -// actually this is quite a common problem with generic libs -function nvalue(n) { - return n.value.value ? n.value.value : n.value; -} - -// apply standard accessors to a diagram in order to style it as graphviz would -// this is a work in progress -dc_graph.apply_graphviz_accessors = function(diagram) { - diagram - .nodeLabel(function(n) { - var label = nvalue(n).label; - if(label === undefined) - label = n.key; - return label && label.split(/\n|\\n/); - }) - .nodeRadius(function(n) { - // should do width & height instead, #25 - return nvalue(n).radius || 25; - }) - .nodeShape(function(n) { return nvalue(n).shape; }) - .nodeFill(function(n) { return nvalue(n).fillcolor || 'white'; }) - .nodeOpacity(function(n) { - // not standard gv - return nvalue(n).opacity || 1; - }) - .nodeLabelFill(function(n) { return nvalue(n).fontcolor || 'black'; }) - .nodeTitle(function(n) { - return (nvalue(n).htmltip || nvalue(n).jsontip) ? null : - nvalue(n).tooltip !== undefined ? - nvalue(n).tooltip : - diagram.nodeLabel()(n); - }) - .nodeStrokeWidth(function(n) { - // it is debatable whether a point === a pixel but they are close - // https://graphicdesign.stackexchange.com/questions/199/point-vs-pixel-what-is-the-difference - var penwidth = nvalue(n).penwidth; - return penwidth !== undefined ? +penwidth : 1; - }) - .edgeLabel(function(e) { return e.value.label ? e.value.label.split(/\n|\\n/) : ''; }) - .edgeStroke(function(e) { return e.value.color || 'black'; }) - .edgeOpacity(function(e) { - // not standard gv - return e.value.opacity || 1; - }) - .edgeArrowSize(function(e) { - return e.value.arrowsize || 1; - }) - // need directedness to default these correctly, see #106 - .edgeArrowhead(function(e) { - var head = e.value.arrowhead; - return head !== undefined ? head : 'vee'; - }) - .edgeArrowtail(function(e) { - var tail = e.value.arrowtail; - return tail !== undefined ? tail : null; - }) - .edgeStrokeDashArray(function(e) { - switch(e.value.style) { - case 'dotted': - return [1,5]; - } - return null; - }); - var draw_clusters = diagram.child('draw-clusters'); - if(draw_clusters) { - draw_clusters - .clusterStroke(function(c) { - return c.value.color || 'black'; - }) - .clusterFill(function(c) { - return c.value.style === 'filled' ? c.value.fillcolor || c.value.color || c.value.bgcolor : null; - }) - .clusterLabel(function(c) { - return c.value.label; - }); - } -}; - -dc_graph.snapshot_graphviz = function(diagram) { - var xDomain = diagram.x().domain(), yDomain = diagram.y().domain(); - return { - nodes: diagram.nodeGroup().all().map(function(n) { - return diagram.getWholeNode(n.key); - }) - .filter(function(x) { return x; }) - .map(function(n) { - return { - key: diagram.nodeKey.eval(n), - label: diagram.nodeLabel.eval(n), - fillcolor: diagram.nodeFillScale()(diagram.nodeFill.eval(n)), - penwidth: diagram.nodeStrokeWidth.eval(n), - // not supported as input, see dc.graph.js#25 - // width: n.cola.dcg_rx*2, - // height: n.cola.dcg_ry*2, - - // not graphviz attributes - // until we have w/h - radius: diagram.nodeRadius.eval(n), - // does not seem to exist in gv - opacity: diagram.nodeOpacity.eval(n), - // should be pos - x: n.cola.x, - y: n.cola.y - }; - }), - edges: diagram.edgeGroup().all().map(function(e) { - return diagram.getWholeEdge(e.key); - }).map(function(e) { - return { - key: diagram.edgeKey.eval(e), - source: diagram.edgeSource.eval(e), - target: diagram.edgeTarget.eval(e), - color: diagram.edgeStroke.eval(e), - arrowsize: diagram.edgeArrowSize.eval(e), - opacity: diagram.edgeOpacity.eval(e), - // should support dir, see dc.graph.js#106 - arrowhead: diagram.edgeArrowhead.eval(e), - arrowtail: diagram.edgeArrowtail.eval(e) - }; - }), - bounds: { - left: xDomain[0], - top: yDomain[0], - right: xDomain[1], - bottom: yDomain[1] - } - }; -}; - -/** - * `dc_graph.d3_force_layout` is an adaptor for d3-force layouts in dc.graph.js - * @class d3_force_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.d3_force_layout} - **/ -dc_graph.d3_force_layout = function(id) { - var _layoutId = id || uuid(); - var _simulation = null; // d3-force simulation - var _dispatch = d3.dispatch('tick', 'start', 'end'); - // node and edge objects shared with d3-force, preserved from one iteration - // to the next (as long as the object is still in the layout) - var _nodes = {}, _edges = {}; - var _wnodes = [], _wedges = []; - var _options = null; - var _paths = null; - - function init(options) { - _options = options; - - _simulation = d3.layout.force() - .size([options.width, options.height]); - if(options.linkDistance) { - if(typeof options.linkDistance === 'number') - _simulation.linkDistance(options.linkDistance); - else if(options.linkDistance === 'auto') - _simulation.linkDistance(function(e) { - return e.dcg_edgeLength; - }); - } - - _simulation.on('tick', /* _tick = */ function() { - dispatchState('tick'); - }).on('start', function() { - _dispatch.start(); - }).on('end', /* _done = */ function() { - dispatchState('end'); - }); - } - - function dispatchState(event) { - _dispatch[event]( - _wnodes, - _wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }) - ); - } - - function data(nodes, edges, constraints) { - var nodeIDs = {}; - nodes.forEach(function(d, i) { - nodeIDs[d.dcg_nodeKey] = i; - }); - - _wnodes = regenerate_objects(_nodes, nodes, null, function(v) { - return v.dcg_nodeKey; - }, function(v1, v) { - v1.dcg_nodeKey = v.dcg_nodeKey; - v1.width = v.width; - v1.height = v.height; - v1.id = v.dcg_nodeKey; - if(v.dcg_nodeFixed) { - v1.fixed = true; - v1.x = v.dcg_nodeFixed.x; - v1.y = v.dcg_nodeFixed.y; - } else v1.fixed = false; - }); - - _wedges = regenerate_objects(_edges, edges, null, function(e) { - return e.dcg_edgeKey; - }, function(e1, e) { - e1.dcg_edgeKey = e.dcg_edgeKey; - // cola edges can work with indices or with object references - // but it will replace indices with object references - e1.source = _nodes[e.dcg_edgeSource]; - e1.source.id = nodeIDs[e1.source.dcg_nodeKey]; - e1.target = _nodes[e.dcg_edgeTarget]; - e1.target.id = nodeIDs[e1.target.dcg_nodeKey]; - e1.dcg_edgeLength = e.dcg_edgeLength; - }); - - _simulation.nodes(_wnodes); - _simulation.links(_wedges); - } - - function start() { - installForces(); - runSimulation(_options.iterations); - } - - function stop() { - if(_simulation) - _simulation.stop(); - } - - function savePositions() { - var data = {}; - Object.keys(_nodes).forEach(function(key) { - data[key] = {x: _nodes[key].x, y: _nodes[key].y}; - }); - return data; - } - - function restorePositions(data) { - Object.keys(data).forEach(function(key) { - if(_nodes[key]) { - _nodes[key].fixed = false; - _nodes[key].x = data[key].x; - _nodes[key].y = data[key].y; - } - }); - } - - function installForces() { - if(_paths === null) - _simulation.gravity(_options.gravityStrength) - .charge(_options.initialCharge); - else { - if(_options.fixOffPathNodes) { - var nodesOnPath = d3.set(); // nodes on path - _paths.forEach(function(path) { - path.forEach(function(nid) { - nodesOnPath.add(nid); - }); - }); - - // fix nodes not on paths - Object.keys(_nodes).forEach(function(key) { - if(!nodesOnPath.has(key)) { - _nodes[key].fixed = true; - } else { - _nodes[key].fixed = false; - } - }); - } - - // enlarge charge force to separate nodes on paths - _simulation.charge(_options.chargeForce); - } - }; - - function runSimulation(iterations) { - if(!iterations) { - dispatchState('end'); - return; - } - _simulation.start(); - for (var i = 0; i < 300; ++i) { - _simulation.tick(); - if(_paths) - applyPathAngleForces(); - } - _simulation.stop(); - } - - function applyPathAngleForces() { - function _dot(v1, v2) { return v1.x*v2.x + v1.y*v2.y; }; - function _len(v) { return Math.sqrt(v.x*v.x + v.y*v.y); }; - function _angle(v1, v2) { - var a = _dot(v1, v2) / (_len(v1)*_len(v2)); - a = Math.min(a, 1); - a = Math.max(a, -1); - return Math.acos(a); - }; - // perpendicular unit length vector - function _pVec(v) { - var xx = -v.y/v.x, yy = 1; - var length = _len({x: xx, y: yy}); - return {x: xx/length, y: yy/length}; - }; - - function updateNode(node, angle, pVec, alpha) { - node.x += pVec.x*(Math.PI-angle)*alpha; - node.y += pVec.y*(Math.PI-angle)*alpha; - } - - _paths.forEach(function(path) { - if(path.length < 3) return; // at least 3 nodes (and 2 edges): A->B->C - for(var i = 1; i < path.length-1; ++i) { - var current = _nodes[path[i]]; - var prev = _nodes[path[i-1]]; - var next = _nodes[path[i+1]]; - - // calculate the angle - var vPrev = {x: prev.x - current.x, y: prev.y - current.y}; - var vNext = {x: next.x - current.x, y: next.y - current.y}; - - var angle = _angle(vPrev, vNext); // angle in [0, PI] - - var pvecPrev = _pVec(vPrev); - var pvecNext = _pVec(vNext); - - // make sure the perpendicular vector is in the - // direction that makes the angle more towards 180 degree - // 1. calculate the middle point of node 'prev' and 'next' - var mid = {x: (prev.x+next.x)/2.0, y: (prev.y+next.y)/2.0}; - // 2. calculate the vectors: 'prev' pointing to 'mid', 'next' pointing to 'mid' - var prev_mid = {x: mid.x-prev.x, y: mid.y-prev.y}; - var next_mid = {x: mid.x-next.x, y: mid.y-next.y}; - // 3. the 'correct' vector: the angle between pvec and prev_mid(next_mid) should - // be an obtuse angle - pvecPrev = _angle(prev_mid, pvecPrev) >= Math.PI/2.0 ? pvecPrev : {x: -pvecPrev.x, y: -pvecPrev.y}; - pvecNext = _angle(next_mid, pvecNext) >= Math.PI/2.0 ? pvecNext : {x: -pvecNext.x, y: -pvecNext.y}; - - // modify positions of prev and next - updateNode(prev, angle, pvecPrev, _options.angleForce); - updateNode(next, angle, pvecNext, _options.angleForce); - } - - }); - } - - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); - - var engine = Object.assign(graphviz, { - layoutAlgorithm: function() { - return 'd3-force'; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return true; - }, - supportsMoving: function() { - return true; - }, - parent: property(null), - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - init(options); - return this; - }, - data: function(graph, nodes, edges, constraints) { - data(nodes, edges, constraints); - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - paths: function(paths) { - _paths = paths; - }, - savePositions: savePositions, - restorePositions: restorePositions, - optionNames: function() { - return ['iterations', 'angleForce', 'chargeForce', 'gravityStrength', - 'initialCharge', 'linkDistance', 'fixOffPathNodes'] - .concat(graphviz_keys); - }, - iterations: property(300), - angleForce: property(0.02), - chargeForce: property(-500), - gravityStrength: property(1.0), - initialCharge: property(-400), - linkDistance: property(20), - fixOffPathNodes: property(false), - populateLayoutNode: function() {}, - populateLayoutEdge: function() {} - }); - return engine; -}; - -dc_graph.d3_force_layout.scripts = ['d3.js']; - -var _layouts; - -function postResponse(event, layoutId) { - return function() { - var message = { - response: event, - layoutId: layoutId - }; - message.args = Array.prototype.slice.call(arguments); - postMessage(message); - }; -} - -onmessage = function(e) { - var args = e.data.args; - switch(e.data.command) { - case 'init': - // find a function under dc_graph that has `scripts` - var layout_name; - for(var name in dc_graph) { - if(typeof dc_graph[name] === 'function' && dc_graph[name].scripts) - layout_name = name; - } - if(!_layouts) { - _layouts = {}; - importScripts.apply(null, dc_graph[layout_name].scripts); - if(dc_graph[layout_name].optional_scripts) { - try { - importScripts.apply(null, dc_graph[layout_name].optional_scripts); - } - catch(xep) { - console.log(xep); - } - } - } - - _layouts[args.layoutId] = dc_graph[layout_name]() - .on('tick', postResponse('tick', args.layoutId)) - .on('start', postResponse('start', args.layoutId)) - .on('end', postResponse('end', args.layoutId)) - .init(args.options); - break; - case 'data': - if(_layouts) - _layouts[args.layoutId].data(args.graph, args.nodes, args.edges, args.clusters, args.constraints); - break; - case 'start': - // if(args.initialOnly) { - // if(args.showLayoutSteps) - // _tick(); - // _done(); - // } - // else - _layouts[args.layoutId].start(); - break; - case 'stop': - if(_layouts) - _layouts[args.layoutId].stop(); - break; - } -}; - - -//# sourceMappingURL=dc.graph.d3-force.worker.js.map \ No newline at end of file diff --git a/dc.graph.d3-force.worker.js.map b/dc.graph.d3-force.worker.js.map deleted file mode 100644 index 7b25c7d1..00000000 --- a/dc.graph.d3-force.worker.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["src/core.js","src/generate_objects.js","src/graphviz_attrs.js","src/d3_force_layout.js","src/webworker_message.js"],"names":[],"mappings":"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","file":"dc.graph.d3-force.worker.js","sourcesContent":["/**\n * The entire dc.graph.js library is scoped under the **dc_graph** name space. It does not introduce\n * anything else into the global name space.\n *\n * Like in dc.js and most libraries built on d3, most `dc_graph` functions are designed to allow function chaining, meaning they return the current diagram\n * instance whenever it is appropriate. The getter forms of functions do not participate in function\n * chaining because they return values that are not the diagram.\n * @namespace dc_graph\n * @version 0.9.93\n * @example\n * // Example chaining\n * diagram.width(600)\n * .height(400)\n * .nodeDimension(nodeDim)\n * .nodeGroup(nodeGroup);\n */\n\nvar dc_graph = {\n version: '0.9.93',\n constants: {\n CHART_CLASS: 'dc-graph'\n }\n};\n\nfunction get_original(x) {\n return x.orig;\n}\n\nfunction identity(x) {\n return x;\n};\n\nvar property = function (defaultValue, unwrap) {\n if(unwrap === undefined)\n unwrap = get_original;\n else if(unwrap === false)\n unwrap = identity;\n var value = defaultValue, react = null;\n var cascade = [];\n var ret = function (_) {\n if (!arguments.length) {\n return value;\n }\n if(react)\n react(_);\n value = _;\n return this;\n };\n ret.cascade = function (n, f) {\n for(var i = 0; i n) {\n cascade.splice(i, 0, {n: n, f: f});\n return ret;\n }\n }\n cascade.push({n: n, f: f});\n return ret;\n };\n ret._eval = function(o, n) {\n if(n===0 || !cascade.length)\n return dc_graph.functor_wrap(ret(), unwrap)(o);\n else {\n var last = cascade[n-1];\n return last.f(o, function() {\n return ret._eval(o, n-1);\n });\n }\n };\n ret.eval = function(o) {\n return ret._eval(o, cascade.length);\n };\n ret.react = function(_) {\n if (!arguments.length) {\n return react;\n }\n react = _;\n return this;\n };\n return ret;\n};\n\nfunction named_children() {\n var _children = {};\n var f = function(id, object) {\n if(arguments.length === 1)\n return _children[id];\n if(f.reject) {\n var reject = f.reject(id, object);\n if(reject) {\n console.groupCollapsed(reject);\n console.trace();\n console.groupEnd();\n return this;\n }\n }\n // do not notify unnecessarily\n if(_children[id] === object)\n return this;\n if(_children[id])\n _children[id].parent(null);\n _children[id] = object;\n if(object)\n object.parent(this);\n return this;\n };\n f.enum = function() {\n return Object.keys(_children);\n };\n f.nameOf = function(o) {\n var found = Object.entries(_children).find(function(kv) {\n return kv[1] == o;\n });\n return found ? found[0] : null;\n };\n return f;\n}\n\nfunction deprecated_property(message, defaultValue) {\n var prop = property(defaultValue);\n var ret = function() {\n if(arguments.length) {\n console.warn(message);\n prop.apply(property, arguments);\n return this;\n }\n return prop();\n };\n ['cascade', '_eval', 'eval', 'react'].forEach(function(method) {\n ret[method] = prop[method];\n });\n return ret;\n}\n\nfunction onetime_trace(level, message) {\n var said = false;\n return function() {\n if(said)\n return;\n if(level === 'trace') {\n // todo: implement levels?\n // console.groupCollapsed(message);\n // console.trace();\n // console.groupEnd();\n }\n else\n console[level](message);\n said = true;\n };\n}\n\nfunction deprecation_warning(message) {\n return onetime_trace('warn', message);\n}\n\nfunction trace_function(level, message, f) {\n var dep = onetime_trace(level, message);\n return function() {\n dep();\n return f.apply(this, arguments);\n };\n}\nfunction deprecate_function(message, f) {\n return trace_function('warn', message, f);\n}\n\n// http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript\nfunction uuid() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {\n var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);\n return v.toString(16);\n });\n}\n\nfunction is_ie() {\n var ua = window.navigator.userAgent;\n\n return(ua.indexOf('MSIE ') > 0 ||\n ua.indexOf('Trident/') > 0 ||\n ua.indexOf('Edge/') > 0);\n}\n\nfunction is_safari() {\n return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n}\n\n// polyfill Object.assign for IE\n// it's just too useful to do without\nif (typeof Object.assign != 'function') {\n // Must be writable: true, enumerable: false, configurable: true\n Object.defineProperty(Object, \"assign\", {\n value: function assign(target, varArgs) { // .length of function is 2\n 'use strict';\n if (target == null) { // TypeError if undefined or null\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n var to = Object(target);\n\n for (var index = 1; index < arguments.length; index++) {\n var nextSource = arguments[index];\n\n if (nextSource != null) { // Skip over if undefined or null\n for (var nextKey in nextSource) {\n // Avoid bugs when hasOwnProperty is shadowed\n if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n }\n return to;\n },\n writable: true,\n configurable: true\n });\n}\n\n\n// https://tc39.github.io/ecma262/#sec-array.prototype.includes\nif (!Array.prototype.includes) {\n Object.defineProperty(Array.prototype, 'includes', {\n value: function(valueToFind, fromIndex) {\n\n if (this == null) {\n throw new TypeError('\"this\" is null or not defined');\n }\n\n // 1. Let O be ? ToObject(this value).\n var o = Object(this);\n\n // 2. Let len be ? ToLength(? Get(O, \"length\")).\n var len = o.length >>> 0;\n\n // 3. If len is 0, return false.\n if (len === 0) {\n return false;\n }\n\n // 4. Let n be ? ToInteger(fromIndex).\n // (If fromIndex is undefined, this step produces the value 0.)\n var n = fromIndex | 0;\n\n // 5. If n >= 0, then\n // a. Let k be n.\n // 6. Else n < 0,\n // a. Let k be len + n.\n // b. If k < 0, let k be 0.\n var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);\n\n function sameValueZero(x, y) {\n return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));\n }\n\n // 7. Repeat, while k < len\n while (k < len) {\n // a. Let elementK be the result of ? Get(O, ! ToString(k)).\n // b. If SameValueZero(valueToFind, elementK) is true, return true.\n if (sameValueZero(o[k], valueToFind)) {\n return true;\n }\n // c. Increase k by 1.\n k++;\n }\n\n // 8. Return false\n return false;\n }\n });\n}\n\nif (!Object.entries) {\n Object.entries = function( obj ){\n var ownProps = Object.keys( obj ),\n i = ownProps.length,\n resArray = new Array(i); // preallocate the Array\n while (i--)\n resArray[i] = [ownProps[i], obj[ownProps[i]]];\n return resArray;\n };\n}\n\n// https://github.com/KhaledElAnsari/Object.values\nObject.values = Object.values ? Object.values : function(obj) {\n var allowedTypes = [\"[object String]\", \"[object Object]\", \"[object Array]\", \"[object Function]\"];\n var objType = Object.prototype.toString.call(obj);\n\n if(obj === null || typeof obj === \"undefined\") {\n\tthrow new TypeError(\"Cannot convert undefined or null to object\");\n } else if(!~allowedTypes.indexOf(objType)) {\n\treturn [];\n } else {\n\t// if ES6 is supported\n\tif (Object.keys) {\n\t return Object.keys(obj).map(function (key) {\n\t\treturn obj[key];\n\t });\n\t}\n\n\tvar result = [];\n\tfor (var prop in obj) {\n\t if (obj.hasOwnProperty(prop)) {\n\t\tresult.push(obj[prop]);\n\t }\n\t}\n\n\treturn result;\n }\n};\n\nfunction getBBoxNoThrow(elem) {\n // firefox seems to have issues with some of my texts\n // just catch for now\n try {\n return elem.getBBox();\n } catch(xep) {\n return {x: 0, y: 0, width:0, height: 0};\n }\n}\n","// create or re-use objects in a map, delete the ones that were not reused\nfunction regenerate_objects(preserved, list, need, key, assign, create, destroy) {\n if(!create) create = function(k, o) { };\n if(!destroy) destroy = function(k) { };\n var keep = {};\n function wrap(o) {\n var k = key(o);\n if(!preserved[k])\n create(k, preserved[k] = {}, o);\n var o1 = preserved[k];\n assign(o1, o);\n keep[k] = true;\n return o1;\n }\n var wlist = list.map(wrap);\n if(need)\n need.forEach(function(k) {\n if(!preserved[k]) { // hasn't been created, needs to be\n create(k, preserved[k] = {}, null);\n assign(preserved[k], null);\n }\n if(!keep[k]) { // wasn't in list, should be\n wlist.push(preserved[k]);\n keep[k] = true;\n }\n });\n // delete any objects from last round that are no longer used\n for(var k in preserved)\n if(!keep[k]) {\n destroy(k, preserved[k]);\n delete preserved[k];\n }\n return wlist;\n}\n","/**\n * `dc_graph.graphviz_attrs defines a basic set of attributes which layout engines should\n * implement - although these are not required, they make it easier for clients and\n * modes (like expand_collapse) to work with multiple layout engines.\n *\n * these attributes are {@link http://www.graphviz.org/doc/info/attrs.html from graphviz}\n * @class graphviz_attrs\n * @memberof dc_graph\n * @return {Object}\n **/\ndc_graph.graphviz_attrs = function() {\n return {\n /**\n * Direction to draw ranks.\n * @method rankdir\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [rankdir='TB'] 'TB', 'LR', 'BT', or 'RL'\n **/\n rankdir: property('TB'),\n /**\n * Spacing in between nodes in the same rank.\n * @method nodesep\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [nodesep=40]\n **/\n nodesep: property(40),\n /**\n * Spacing in between ranks.\n * @method ranksep\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [ranksep=40]\n **/\n ranksep: property(40)\n };\n};\n\n// graphlib-dot seems to wrap nodes in an extra {value}\n// actually this is quite a common problem with generic libs\nfunction nvalue(n) {\n return n.value.value ? n.value.value : n.value;\n}\n\n// apply standard accessors to a diagram in order to style it as graphviz would\n// this is a work in progress\ndc_graph.apply_graphviz_accessors = function(diagram) {\n diagram\n .nodeLabel(function(n) {\n var label = nvalue(n).label;\n if(label === undefined)\n label = n.key;\n return label && label.split(/\\n|\\\\n/);\n })\n .nodeRadius(function(n) {\n // should do width & height instead, #25\n return nvalue(n).radius || 25;\n })\n .nodeShape(function(n) { return nvalue(n).shape; })\n .nodeFill(function(n) { return nvalue(n).fillcolor || 'white'; })\n .nodeOpacity(function(n) {\n // not standard gv\n return nvalue(n).opacity || 1;\n })\n .nodeLabelFill(function(n) { return nvalue(n).fontcolor || 'black'; })\n .nodeTitle(function(n) {\n return (nvalue(n).htmltip || nvalue(n).jsontip) ? null :\n nvalue(n).tooltip !== undefined ?\n nvalue(n).tooltip :\n diagram.nodeLabel()(n);\n })\n .nodeStrokeWidth(function(n) {\n // it is debatable whether a point === a pixel but they are close\n // https://graphicdesign.stackexchange.com/questions/199/point-vs-pixel-what-is-the-difference\n var penwidth = nvalue(n).penwidth;\n return penwidth !== undefined ? +penwidth : 1;\n })\n .edgeLabel(function(e) { return e.value.label ? e.value.label.split(/\\n|\\\\n/) : ''; })\n .edgeStroke(function(e) { return e.value.color || 'black'; })\n .edgeOpacity(function(e) {\n // not standard gv\n return e.value.opacity || 1;\n })\n .edgeArrowSize(function(e) {\n return e.value.arrowsize || 1;\n })\n // need directedness to default these correctly, see #106\n .edgeArrowhead(function(e) {\n var head = e.value.arrowhead;\n return head !== undefined ? head : 'vee';\n })\n .edgeArrowtail(function(e) {\n var tail = e.value.arrowtail;\n return tail !== undefined ? tail : null;\n })\n .edgeStrokeDashArray(function(e) {\n switch(e.value.style) {\n case 'dotted':\n return [1,5];\n }\n return null;\n });\n var draw_clusters = diagram.child('draw-clusters');\n if(draw_clusters) {\n draw_clusters\n .clusterStroke(function(c) {\n return c.value.color || 'black';\n })\n .clusterFill(function(c) {\n return c.value.style === 'filled' ? c.value.fillcolor || c.value.color || c.value.bgcolor : null;\n })\n .clusterLabel(function(c) {\n return c.value.label;\n });\n }\n};\n\ndc_graph.snapshot_graphviz = function(diagram) {\n var xDomain = diagram.x().domain(), yDomain = diagram.y().domain();\n return {\n nodes: diagram.nodeGroup().all().map(function(n) {\n return diagram.getWholeNode(n.key);\n })\n .filter(function(x) { return x; })\n .map(function(n) {\n return {\n key: diagram.nodeKey.eval(n),\n label: diagram.nodeLabel.eval(n),\n fillcolor: diagram.nodeFillScale()(diagram.nodeFill.eval(n)),\n penwidth: diagram.nodeStrokeWidth.eval(n),\n // not supported as input, see dc.graph.js#25\n // width: n.cola.dcg_rx*2,\n // height: n.cola.dcg_ry*2,\n\n // not graphviz attributes\n // until we have w/h\n radius: diagram.nodeRadius.eval(n),\n // does not seem to exist in gv\n opacity: diagram.nodeOpacity.eval(n),\n // should be pos\n x: n.cola.x,\n y: n.cola.y\n };\n }),\n edges: diagram.edgeGroup().all().map(function(e) {\n return diagram.getWholeEdge(e.key);\n }).map(function(e) {\n return {\n key: diagram.edgeKey.eval(e),\n source: diagram.edgeSource.eval(e),\n target: diagram.edgeTarget.eval(e),\n color: diagram.edgeStroke.eval(e),\n arrowsize: diagram.edgeArrowSize.eval(e),\n opacity: diagram.edgeOpacity.eval(e),\n // should support dir, see dc.graph.js#106\n arrowhead: diagram.edgeArrowhead.eval(e),\n arrowtail: diagram.edgeArrowtail.eval(e)\n };\n }),\n bounds: {\n left: xDomain[0],\n top: yDomain[0],\n right: xDomain[1],\n bottom: yDomain[1]\n }\n };\n};\n","/**\n * `dc_graph.d3_force_layout` is an adaptor for d3-force layouts in dc.graph.js\n * @class d3_force_layout\n * @memberof dc_graph\n * @param {String} [id=uuid()] - Unique identifier\n * @return {dc_graph.d3_force_layout}\n **/\ndc_graph.d3_force_layout = function(id) {\n var _layoutId = id || uuid();\n var _simulation = null; // d3-force simulation\n var _dispatch = d3.dispatch('tick', 'start', 'end');\n // node and edge objects shared with d3-force, preserved from one iteration\n // to the next (as long as the object is still in the layout)\n var _nodes = {}, _edges = {};\n var _wnodes = [], _wedges = [];\n var _options = null;\n var _paths = null;\n\n function init(options) {\n _options = options;\n\n _simulation = d3.layout.force()\n .size([options.width, options.height]);\n if(options.linkDistance) {\n if(typeof options.linkDistance === 'number')\n _simulation.linkDistance(options.linkDistance);\n else if(options.linkDistance === 'auto')\n _simulation.linkDistance(function(e) {\n return e.dcg_edgeLength;\n });\n }\n\n _simulation.on('tick', /* _tick = */ function() {\n dispatchState('tick');\n }).on('start', function() {\n _dispatch.start();\n }).on('end', /* _done = */ function() {\n dispatchState('end');\n });\n }\n\n function dispatchState(event) {\n _dispatch[event](\n _wnodes,\n _wedges.map(function(e) {\n return {dcg_edgeKey: e.dcg_edgeKey};\n })\n );\n }\n\n function data(nodes, edges, constraints) {\n var nodeIDs = {};\n nodes.forEach(function(d, i) {\n nodeIDs[d.dcg_nodeKey] = i;\n });\n\n _wnodes = regenerate_objects(_nodes, nodes, null, function(v) {\n return v.dcg_nodeKey;\n }, function(v1, v) {\n v1.dcg_nodeKey = v.dcg_nodeKey;\n v1.width = v.width;\n v1.height = v.height;\n v1.id = v.dcg_nodeKey;\n if(v.dcg_nodeFixed) {\n v1.fixed = true;\n v1.x = v.dcg_nodeFixed.x;\n v1.y = v.dcg_nodeFixed.y;\n } else v1.fixed = false;\n });\n\n _wedges = regenerate_objects(_edges, edges, null, function(e) {\n return e.dcg_edgeKey;\n }, function(e1, e) {\n e1.dcg_edgeKey = e.dcg_edgeKey;\n // cola edges can work with indices or with object references\n // but it will replace indices with object references\n e1.source = _nodes[e.dcg_edgeSource];\n e1.source.id = nodeIDs[e1.source.dcg_nodeKey];\n e1.target = _nodes[e.dcg_edgeTarget];\n e1.target.id = nodeIDs[e1.target.dcg_nodeKey];\n e1.dcg_edgeLength = e.dcg_edgeLength;\n });\n\n _simulation.nodes(_wnodes);\n _simulation.links(_wedges);\n }\n\n function start() {\n installForces();\n runSimulation(_options.iterations);\n }\n\n function stop() {\n if(_simulation)\n _simulation.stop();\n }\n\n function savePositions() {\n var data = {};\n Object.keys(_nodes).forEach(function(key) {\n data[key] = {x: _nodes[key].x, y: _nodes[key].y};\n });\n return data;\n }\n\n function restorePositions(data) {\n Object.keys(data).forEach(function(key) {\n if(_nodes[key]) {\n _nodes[key].fixed = false;\n _nodes[key].x = data[key].x;\n _nodes[key].y = data[key].y;\n }\n });\n }\n\n function installForces() {\n if(_paths === null)\n _simulation.gravity(_options.gravityStrength)\n .charge(_options.initialCharge);\n else {\n if(_options.fixOffPathNodes) {\n var nodesOnPath = d3.set(); // nodes on path\n _paths.forEach(function(path) {\n path.forEach(function(nid) {\n nodesOnPath.add(nid);\n });\n });\n\n // fix nodes not on paths\n Object.keys(_nodes).forEach(function(key) {\n if(!nodesOnPath.has(key)) {\n _nodes[key].fixed = true;\n } else {\n _nodes[key].fixed = false;\n }\n });\n }\n\n // enlarge charge force to separate nodes on paths\n _simulation.charge(_options.chargeForce);\n }\n };\n\n function runSimulation(iterations) {\n if(!iterations) {\n dispatchState('end');\n return;\n }\n _simulation.start();\n for (var i = 0; i < 300; ++i) {\n _simulation.tick();\n if(_paths)\n applyPathAngleForces();\n }\n _simulation.stop();\n }\n\n function applyPathAngleForces() {\n function _dot(v1, v2) { return v1.x*v2.x + v1.y*v2.y; };\n function _len(v) { return Math.sqrt(v.x*v.x + v.y*v.y); };\n function _angle(v1, v2) {\n var a = _dot(v1, v2) / (_len(v1)*_len(v2));\n a = Math.min(a, 1);\n a = Math.max(a, -1);\n return Math.acos(a);\n };\n // perpendicular unit length vector\n function _pVec(v) {\n var xx = -v.y/v.x, yy = 1;\n var length = _len({x: xx, y: yy});\n return {x: xx/length, y: yy/length};\n };\n\n function updateNode(node, angle, pVec, alpha) {\n node.x += pVec.x*(Math.PI-angle)*alpha;\n node.y += pVec.y*(Math.PI-angle)*alpha;\n }\n\n _paths.forEach(function(path) {\n if(path.length < 3) return; // at least 3 nodes (and 2 edges): A->B->C\n for(var i = 1; i < path.length-1; ++i) {\n var current = _nodes[path[i]];\n var prev = _nodes[path[i-1]];\n var next = _nodes[path[i+1]];\n\n // calculate the angle\n var vPrev = {x: prev.x - current.x, y: prev.y - current.y};\n var vNext = {x: next.x - current.x, y: next.y - current.y};\n\n var angle = _angle(vPrev, vNext); // angle in [0, PI]\n\n var pvecPrev = _pVec(vPrev);\n var pvecNext = _pVec(vNext);\n\n // make sure the perpendicular vector is in the\n // direction that makes the angle more towards 180 degree\n // 1. calculate the middle point of node 'prev' and 'next'\n var mid = {x: (prev.x+next.x)/2.0, y: (prev.y+next.y)/2.0};\n // 2. calculate the vectors: 'prev' pointing to 'mid', 'next' pointing to 'mid'\n var prev_mid = {x: mid.x-prev.x, y: mid.y-prev.y};\n var next_mid = {x: mid.x-next.x, y: mid.y-next.y};\n // 3. the 'correct' vector: the angle between pvec and prev_mid(next_mid) should\n // be an obtuse angle\n pvecPrev = _angle(prev_mid, pvecPrev) >= Math.PI/2.0 ? pvecPrev : {x: -pvecPrev.x, y: -pvecPrev.y};\n pvecNext = _angle(next_mid, pvecNext) >= Math.PI/2.0 ? pvecNext : {x: -pvecNext.x, y: -pvecNext.y};\n\n // modify positions of prev and next\n updateNode(prev, angle, pvecPrev, _options.angleForce);\n updateNode(next, angle, pvecNext, _options.angleForce);\n }\n\n });\n }\n\n var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz);\n\n var engine = Object.assign(graphviz, {\n layoutAlgorithm: function() {\n return 'd3-force';\n },\n layoutId: function() {\n return _layoutId;\n },\n supportsWebworker: function() {\n return true;\n },\n supportsMoving: function() {\n return true;\n },\n parent: property(null),\n on: function(event, f) {\n if(arguments.length === 1)\n return _dispatch.on(event);\n _dispatch.on(event, f);\n return this;\n },\n init: function(options) {\n this.optionNames().forEach(function(option) {\n options[option] = options[option] || this[option]();\n }.bind(this));\n init(options);\n return this;\n },\n data: function(graph, nodes, edges, constraints) {\n data(nodes, edges, constraints);\n },\n start: function() {\n start();\n },\n stop: function() {\n stop();\n },\n paths: function(paths) {\n _paths = paths;\n },\n savePositions: savePositions,\n restorePositions: restorePositions,\n optionNames: function() {\n return ['iterations', 'angleForce', 'chargeForce', 'gravityStrength',\n 'initialCharge', 'linkDistance', 'fixOffPathNodes']\n .concat(graphviz_keys);\n },\n iterations: property(300),\n angleForce: property(0.02),\n chargeForce: property(-500),\n gravityStrength: property(1.0),\n initialCharge: property(-400),\n linkDistance: property(20),\n fixOffPathNodes: property(false),\n populateLayoutNode: function() {},\n populateLayoutEdge: function() {}\n });\n return engine;\n};\n\ndc_graph.d3_force_layout.scripts = ['d3.js'];\n","var _layouts;\n\nfunction postResponse(event, layoutId) {\n return function() {\n var message = {\n response: event,\n layoutId: layoutId\n };\n message.args = Array.prototype.slice.call(arguments);\n postMessage(message);\n };\n}\n\nonmessage = function(e) {\n var args = e.data.args;\n switch(e.data.command) {\n case 'init':\n // find a function under dc_graph that has `scripts`\n var layout_name;\n for(var name in dc_graph) {\n if(typeof dc_graph[name] === 'function' && dc_graph[name].scripts)\n layout_name = name;\n }\n if(!_layouts) {\n _layouts = {};\n importScripts.apply(null, dc_graph[layout_name].scripts);\n if(dc_graph[layout_name].optional_scripts) {\n try {\n importScripts.apply(null, dc_graph[layout_name].optional_scripts);\n }\n catch(xep) {\n console.log(xep);\n }\n }\n }\n\n _layouts[args.layoutId] = dc_graph[layout_name]()\n .on('tick', postResponse('tick', args.layoutId))\n .on('start', postResponse('start', args.layoutId))\n .on('end', postResponse('end', args.layoutId))\n .init(args.options);\n break;\n case 'data':\n if(_layouts)\n _layouts[args.layoutId].data(args.graph, args.nodes, args.edges, args.clusters, args.constraints);\n break;\n case 'start':\n // if(args.initialOnly) {\n // if(args.showLayoutSteps)\n // _tick();\n // _done();\n // }\n // else\n _layouts[args.layoutId].start();\n break;\n case 'stop':\n if(_layouts)\n _layouts[args.layoutId].stop();\n break;\n }\n};\n\n"]} \ No newline at end of file diff --git a/dc.graph.d3v4-force.worker.js b/dc.graph.d3v4-force.worker.js deleted file mode 100644 index ece678a7..00000000 --- a/dc.graph.d3v4-force.worker.js +++ /dev/null @@ -1,821 +0,0 @@ -/*! - * dc.graph 0.9.93 - * http://dc-js.github.io/dc.graph.js/ - * Copyright 2015-2019 AT&T Intellectual Property & the dc.graph.js Developers - * https://github.com/dc-js/dc.graph.js/blob/master/AUTHORS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -/** - * The entire dc.graph.js library is scoped under the **dc_graph** name space. It does not introduce - * anything else into the global name space. - * - * Like in dc.js and most libraries built on d3, most `dc_graph` functions are designed to allow function chaining, meaning they return the current diagram - * instance whenever it is appropriate. The getter forms of functions do not participate in function - * chaining because they return values that are not the diagram. - * @namespace dc_graph - * @version 0.9.93 - * @example - * // Example chaining - * diagram.width(600) - * .height(400) - * .nodeDimension(nodeDim) - * .nodeGroup(nodeGroup); - */ - -var dc_graph = { - version: '0.9.93', - constants: { - CHART_CLASS: 'dc-graph' - } -}; - -function get_original(x) { - return x.orig; -} - -function identity(x) { - return x; -}; - -var property = function (defaultValue, unwrap) { - if(unwrap === undefined) - unwrap = get_original; - else if(unwrap === false) - unwrap = identity; - var value = defaultValue, react = null; - var cascade = []; - var ret = function (_) { - if (!arguments.length) { - return value; - } - if(react) - react(_); - value = _; - return this; - }; - ret.cascade = function (n, f) { - for(var i = 0; i n) { - cascade.splice(i, 0, {n: n, f: f}); - return ret; - } - } - cascade.push({n: n, f: f}); - return ret; - }; - ret._eval = function(o, n) { - if(n===0 || !cascade.length) - return dc_graph.functor_wrap(ret(), unwrap)(o); - else { - var last = cascade[n-1]; - return last.f(o, function() { - return ret._eval(o, n-1); - }); - } - }; - ret.eval = function(o) { - return ret._eval(o, cascade.length); - }; - ret.react = function(_) { - if (!arguments.length) { - return react; - } - react = _; - return this; - }; - return ret; -}; - -function named_children() { - var _children = {}; - var f = function(id, object) { - if(arguments.length === 1) - return _children[id]; - if(f.reject) { - var reject = f.reject(id, object); - if(reject) { - console.groupCollapsed(reject); - console.trace(); - console.groupEnd(); - return this; - } - } - // do not notify unnecessarily - if(_children[id] === object) - return this; - if(_children[id]) - _children[id].parent(null); - _children[id] = object; - if(object) - object.parent(this); - return this; - }; - f.enum = function() { - return Object.keys(_children); - }; - f.nameOf = function(o) { - var found = Object.entries(_children).find(function(kv) { - return kv[1] == o; - }); - return found ? found[0] : null; - }; - return f; -} - -function deprecated_property(message, defaultValue) { - var prop = property(defaultValue); - var ret = function() { - if(arguments.length) { - console.warn(message); - prop.apply(property, arguments); - return this; - } - return prop(); - }; - ['cascade', '_eval', 'eval', 'react'].forEach(function(method) { - ret[method] = prop[method]; - }); - return ret; -} - -function onetime_trace(level, message) { - var said = false; - return function() { - if(said) - return; - if(level === 'trace') { - // todo: implement levels? - // console.groupCollapsed(message); - // console.trace(); - // console.groupEnd(); - } - else - console[level](message); - said = true; - }; -} - -function deprecation_warning(message) { - return onetime_trace('warn', message); -} - -function trace_function(level, message, f) { - var dep = onetime_trace(level, message); - return function() { - dep(); - return f.apply(this, arguments); - }; -} -function deprecate_function(message, f) { - return trace_function('warn', message, f); -} - -// http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript -function uuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); - return v.toString(16); - }); -} - -function is_ie() { - var ua = window.navigator.userAgent; - - return(ua.indexOf('MSIE ') > 0 || - ua.indexOf('Trident/') > 0 || - ua.indexOf('Edge/') > 0); -} - -function is_safari() { - return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); -} - -// polyfill Object.assign for IE -// it's just too useful to do without -if (typeof Object.assign != 'function') { - // Must be writable: true, enumerable: false, configurable: true - Object.defineProperty(Object, "assign", { - value: function assign(target, varArgs) { // .length of function is 2 - 'use strict'; - if (target == null) { // TypeError if undefined or null - throw new TypeError('Cannot convert undefined or null to object'); - } - - var to = Object(target); - - for (var index = 1; index < arguments.length; index++) { - var nextSource = arguments[index]; - - if (nextSource != null) { // Skip over if undefined or null - for (var nextKey in nextSource) { - // Avoid bugs when hasOwnProperty is shadowed - if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { - to[nextKey] = nextSource[nextKey]; - } - } - } - } - return to; - }, - writable: true, - configurable: true - }); -} - - -// https://tc39.github.io/ecma262/#sec-array.prototype.includes -if (!Array.prototype.includes) { - Object.defineProperty(Array.prototype, 'includes', { - value: function(valueToFind, fromIndex) { - - if (this == null) { - throw new TypeError('"this" is null or not defined'); - } - - // 1. Let O be ? ToObject(this value). - var o = Object(this); - - // 2. Let len be ? ToLength(? Get(O, "length")). - var len = o.length >>> 0; - - // 3. If len is 0, return false. - if (len === 0) { - return false; - } - - // 4. Let n be ? ToInteger(fromIndex). - // (If fromIndex is undefined, this step produces the value 0.) - var n = fromIndex | 0; - - // 5. If n >= 0, then - // a. Let k be n. - // 6. Else n < 0, - // a. Let k be len + n. - // b. If k < 0, let k be 0. - var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); - - function sameValueZero(x, y) { - return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y)); - } - - // 7. Repeat, while k < len - while (k < len) { - // a. Let elementK be the result of ? Get(O, ! ToString(k)). - // b. If SameValueZero(valueToFind, elementK) is true, return true. - if (sameValueZero(o[k], valueToFind)) { - return true; - } - // c. Increase k by 1. - k++; - } - - // 8. Return false - return false; - } - }); -} - -if (!Object.entries) { - Object.entries = function( obj ){ - var ownProps = Object.keys( obj ), - i = ownProps.length, - resArray = new Array(i); // preallocate the Array - while (i--) - resArray[i] = [ownProps[i], obj[ownProps[i]]]; - return resArray; - }; -} - -// https://github.com/KhaledElAnsari/Object.values -Object.values = Object.values ? Object.values : function(obj) { - var allowedTypes = ["[object String]", "[object Object]", "[object Array]", "[object Function]"]; - var objType = Object.prototype.toString.call(obj); - - if(obj === null || typeof obj === "undefined") { - throw new TypeError("Cannot convert undefined or null to object"); - } else if(!~allowedTypes.indexOf(objType)) { - return []; - } else { - // if ES6 is supported - if (Object.keys) { - return Object.keys(obj).map(function (key) { - return obj[key]; - }); - } - - var result = []; - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - result.push(obj[prop]); - } - } - - return result; - } -}; - -function getBBoxNoThrow(elem) { - // firefox seems to have issues with some of my texts - // just catch for now - try { - return elem.getBBox(); - } catch(xep) { - return {x: 0, y: 0, width:0, height: 0}; - } -} - -// create or re-use objects in a map, delete the ones that were not reused -function regenerate_objects(preserved, list, need, key, assign, create, destroy) { - if(!create) create = function(k, o) { }; - if(!destroy) destroy = function(k) { }; - var keep = {}; - function wrap(o) { - var k = key(o); - if(!preserved[k]) - create(k, preserved[k] = {}, o); - var o1 = preserved[k]; - assign(o1, o); - keep[k] = true; - return o1; - } - var wlist = list.map(wrap); - if(need) - need.forEach(function(k) { - if(!preserved[k]) { // hasn't been created, needs to be - create(k, preserved[k] = {}, null); - assign(preserved[k], null); - } - if(!keep[k]) { // wasn't in list, should be - wlist.push(preserved[k]); - keep[k] = true; - } - }); - // delete any objects from last round that are no longer used - for(var k in preserved) - if(!keep[k]) { - destroy(k, preserved[k]); - delete preserved[k]; - } - return wlist; -} - -/** - * `dc_graph.graphviz_attrs defines a basic set of attributes which layout engines should - * implement - although these are not required, they make it easier for clients and - * modes (like expand_collapse) to work with multiple layout engines. - * - * these attributes are {@link http://www.graphviz.org/doc/info/attrs.html from graphviz} - * @class graphviz_attrs - * @memberof dc_graph - * @return {Object} - **/ -dc_graph.graphviz_attrs = function() { - return { - /** - * Direction to draw ranks. - * @method rankdir - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [rankdir='TB'] 'TB', 'LR', 'BT', or 'RL' - **/ - rankdir: property('TB'), - /** - * Spacing in between nodes in the same rank. - * @method nodesep - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [nodesep=40] - **/ - nodesep: property(40), - /** - * Spacing in between ranks. - * @method ranksep - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [ranksep=40] - **/ - ranksep: property(40) - }; -}; - -// graphlib-dot seems to wrap nodes in an extra {value} -// actually this is quite a common problem with generic libs -function nvalue(n) { - return n.value.value ? n.value.value : n.value; -} - -// apply standard accessors to a diagram in order to style it as graphviz would -// this is a work in progress -dc_graph.apply_graphviz_accessors = function(diagram) { - diagram - .nodeLabel(function(n) { - var label = nvalue(n).label; - if(label === undefined) - label = n.key; - return label && label.split(/\n|\\n/); - }) - .nodeRadius(function(n) { - // should do width & height instead, #25 - return nvalue(n).radius || 25; - }) - .nodeShape(function(n) { return nvalue(n).shape; }) - .nodeFill(function(n) { return nvalue(n).fillcolor || 'white'; }) - .nodeOpacity(function(n) { - // not standard gv - return nvalue(n).opacity || 1; - }) - .nodeLabelFill(function(n) { return nvalue(n).fontcolor || 'black'; }) - .nodeTitle(function(n) { - return (nvalue(n).htmltip || nvalue(n).jsontip) ? null : - nvalue(n).tooltip !== undefined ? - nvalue(n).tooltip : - diagram.nodeLabel()(n); - }) - .nodeStrokeWidth(function(n) { - // it is debatable whether a point === a pixel but they are close - // https://graphicdesign.stackexchange.com/questions/199/point-vs-pixel-what-is-the-difference - var penwidth = nvalue(n).penwidth; - return penwidth !== undefined ? +penwidth : 1; - }) - .edgeLabel(function(e) { return e.value.label ? e.value.label.split(/\n|\\n/) : ''; }) - .edgeStroke(function(e) { return e.value.color || 'black'; }) - .edgeOpacity(function(e) { - // not standard gv - return e.value.opacity || 1; - }) - .edgeArrowSize(function(e) { - return e.value.arrowsize || 1; - }) - // need directedness to default these correctly, see #106 - .edgeArrowhead(function(e) { - var head = e.value.arrowhead; - return head !== undefined ? head : 'vee'; - }) - .edgeArrowtail(function(e) { - var tail = e.value.arrowtail; - return tail !== undefined ? tail : null; - }) - .edgeStrokeDashArray(function(e) { - switch(e.value.style) { - case 'dotted': - return [1,5]; - } - return null; - }); - var draw_clusters = diagram.child('draw-clusters'); - if(draw_clusters) { - draw_clusters - .clusterStroke(function(c) { - return c.value.color || 'black'; - }) - .clusterFill(function(c) { - return c.value.style === 'filled' ? c.value.fillcolor || c.value.color || c.value.bgcolor : null; - }) - .clusterLabel(function(c) { - return c.value.label; - }); - } -}; - -dc_graph.snapshot_graphviz = function(diagram) { - var xDomain = diagram.x().domain(), yDomain = diagram.y().domain(); - return { - nodes: diagram.nodeGroup().all().map(function(n) { - return diagram.getWholeNode(n.key); - }) - .filter(function(x) { return x; }) - .map(function(n) { - return { - key: diagram.nodeKey.eval(n), - label: diagram.nodeLabel.eval(n), - fillcolor: diagram.nodeFillScale()(diagram.nodeFill.eval(n)), - penwidth: diagram.nodeStrokeWidth.eval(n), - // not supported as input, see dc.graph.js#25 - // width: n.cola.dcg_rx*2, - // height: n.cola.dcg_ry*2, - - // not graphviz attributes - // until we have w/h - radius: diagram.nodeRadius.eval(n), - // does not seem to exist in gv - opacity: diagram.nodeOpacity.eval(n), - // should be pos - x: n.cola.x, - y: n.cola.y - }; - }), - edges: diagram.edgeGroup().all().map(function(e) { - return diagram.getWholeEdge(e.key); - }).map(function(e) { - return { - key: diagram.edgeKey.eval(e), - source: diagram.edgeSource.eval(e), - target: diagram.edgeTarget.eval(e), - color: diagram.edgeStroke.eval(e), - arrowsize: diagram.edgeArrowSize.eval(e), - opacity: diagram.edgeOpacity.eval(e), - // should support dir, see dc.graph.js#106 - arrowhead: diagram.edgeArrowhead.eval(e), - arrowtail: diagram.edgeArrowtail.eval(e) - }; - }), - bounds: { - left: xDomain[0], - top: yDomain[0], - right: xDomain[1], - bottom: yDomain[1] - } - }; -}; - -/** - * `dc_graph.d3v4_force_layout` is an adaptor for d3-force version 4 layouts in dc.graph.js - * @class d3v4_force_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.d3v4_force_layout} - **/ -dc_graph.d3v4_force_layout = function(id) { - var _layoutId = id || uuid(); - var _simulation = null; // d3-force simulation - var _dispatch = d3.dispatch('tick', 'start', 'end'); - // node and edge objects shared with d3-force, preserved from one iteration - // to the next (as long as the object is still in the layout) - var _nodes = {}, _edges = {}; - var _wnodes = [], _wedges = []; - var _options = null; - var _paths = null; - - function init(options) { - _options = options; - - _simulation = d3v4.forceSimulation() - .force('link', d3v4.forceLink()) - .force('center', d3v4.forceCenter(options.width / 2, options.height / 2)) - .force('gravityX', d3v4.forceX(options.width / 2).strength(_options.gravityStrength)) - .force('gravityY', d3v4.forceY(options.height / 2).strength(_options.gravityStrength)) - .force('collision', d3v4.forceCollide(_options.collisionRadius)) - .force('charge', d3v4.forceManyBody()) - .stop(); - } - - function dispatchState(event) { - _dispatch[event]( - _wnodes, - _wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }) - ); - } - - function data(nodes, edges) { - var nodeIDs = {}; - nodes.forEach(function(d, i) { - nodeIDs[d.dcg_nodeKey] = i; - }); - - _wnodes = regenerate_objects(_nodes, nodes, null, function(v) { - return v.dcg_nodeKey; - }, function(v1, v) { - v1.dcg_nodeKey = v.dcg_nodeKey; - v1.width = v.width; - v1.height = v.height; - v1.id = v.dcg_nodeKey; - if(v.dcg_nodeFixed) { - v1.fx = v.dcg_nodeFixed.x; - v1.fy = v.dcg_nodeFixed.y; - } else v1.fx = v1.fy = null; - }); - - _wedges = regenerate_objects(_edges, edges, null, function(e) { - return e.dcg_edgeKey; - }, function(e1, e) { - e1.dcg_edgeKey = e.dcg_edgeKey; - e1.source = nodeIDs[_nodes[e.dcg_edgeSource].dcg_nodeKey]; - e1.target = nodeIDs[_nodes[e.dcg_edgeTarget].dcg_nodeKey]; - e1.dcg_edgeLength = e.dcg_edgeLength; - }); - - _simulation.force('straighten', null); - _simulation.nodes(_wnodes); - _simulation.force('link').links(_wedges); - } - - function start() { - _dispatch.start(); - installForces(_paths); - runSimulation(_options.iterations); - } - - function stop() { - // not running asynchronously, no _simulation.stop(); - } - - function savePositions() { - var data = {}; - Object.keys(_nodes).forEach(function(key) { - data[key] = {x: _nodes[key].x, y: _nodes[key].y}; - }); - return data; - } - function restorePositions(data) { - Object.keys(data).forEach(function(key) { - if(_nodes[key]) { - _nodes[key].fx = data[key].x; - _nodes[key].fy = data[key].y; - } - }); - } - function installForces(paths) { - if(paths) - paths = paths.filter(function(path) { - return path.nodes.every(function(nk) { return _nodes[nk]; }); - }); - if(paths === null || !paths.length) { - _simulation.force('charge').strength(_options.initialCharge); - } else { - var nodesOnPath; - if(_options.fixOffPathNodes) { - nodesOnPath = d3.set(); - paths.forEach(function(path) { - path.nodes.forEach(function(nid) { - nodesOnPath.add(nid); - }); - }); - } - - // fix nodes not on paths - Object.keys(_nodes).forEach(function(key) { - if(_options.fixOffPathNodes && !nodesOnPath.has(key)) { - _nodes[key].fx = _nodes[key].x; - _nodes[key].fy = _nodes[key].y; - } else { - _nodes[key].fx = null; - _nodes[key].fy = null; - } - }); - - _simulation.force('charge').strength(_options.chargeForce); - _simulation.force('straighten', d3v4.forceStraightenPaths() - .id(function(n) { return n.dcg_nodeKey; }) - .angleForce(_options.angleForce) - .pathNodes(function(p) { return p.nodes; }) - .pathStrength(function(p) { return p.strength; }) - .paths(paths)); - } - }; - - function runSimulation(iterations) { - _simulation.alpha(1); - for (var i = 0; i < iterations; ++i) { - _simulation.tick(); - dispatchState('tick'); - } - dispatchState('end'); - } - - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); - - var engine = Object.assign(graphviz, { - layoutAlgorithm: function() { - return 'd3v4-force'; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return true; - }, - supportsMoving: function() { - return true; - }, - parent: property(null), - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - init(options); - return this; - }, - data: function(graph, nodes, edges, constraints) { - data(nodes, edges, constraints); - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - paths: function(paths) { - _paths = paths; - }, - savePositions: savePositions, - restorePositions: restorePositions, - optionNames: function() { - return ['iterations', 'angleForce', 'chargeForce', 'gravityStrength', 'collisionRadius', - 'initialCharge', 'fixOffPathNodes'] - .concat(graphviz_keys); - }, - iterations: property(300), - angleForce: property(0.01), - chargeForce: property(-600), - gravityStrength: property(0.3), - collisionRadius: property(8), - initialCharge: property(-100), - fixOffPathNodes: property(false), - populateLayoutNode: function() {}, - populateLayoutEdge: function() {} - }); - engine.pathStraightenForce = engine.angleForce; - return engine; -}; - -dc_graph.d3v4_force_layout.scripts = ['d3.js', 'd3v4-force.js']; - -var _layouts; - -function postResponse(event, layoutId) { - return function() { - var message = { - response: event, - layoutId: layoutId - }; - message.args = Array.prototype.slice.call(arguments); - postMessage(message); - }; -} - -onmessage = function(e) { - var args = e.data.args; - switch(e.data.command) { - case 'init': - // find a function under dc_graph that has `scripts` - var layout_name; - for(var name in dc_graph) { - if(typeof dc_graph[name] === 'function' && dc_graph[name].scripts) - layout_name = name; - } - if(!_layouts) { - _layouts = {}; - importScripts.apply(null, dc_graph[layout_name].scripts); - if(dc_graph[layout_name].optional_scripts) { - try { - importScripts.apply(null, dc_graph[layout_name].optional_scripts); - } - catch(xep) { - console.log(xep); - } - } - } - - _layouts[args.layoutId] = dc_graph[layout_name]() - .on('tick', postResponse('tick', args.layoutId)) - .on('start', postResponse('start', args.layoutId)) - .on('end', postResponse('end', args.layoutId)) - .init(args.options); - break; - case 'data': - if(_layouts) - _layouts[args.layoutId].data(args.graph, args.nodes, args.edges, args.clusters, args.constraints); - break; - case 'start': - // if(args.initialOnly) { - // if(args.showLayoutSteps) - // _tick(); - // _done(); - // } - // else - _layouts[args.layoutId].start(); - break; - case 'stop': - if(_layouts) - _layouts[args.layoutId].stop(); - break; - } -}; - - -//# sourceMappingURL=dc.graph.d3v4-force.worker.js.map \ No newline at end of file diff --git a/dc.graph.d3v4-force.worker.js.map b/dc.graph.d3v4-force.worker.js.map deleted file mode 100644 index 4bb58305..00000000 --- a/dc.graph.d3v4-force.worker.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["src/core.js","src/generate_objects.js","src/graphviz_attrs.js","src/d3v4_force_layout.js","src/webworker_message.js"],"names":[],"mappings":"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","file":"dc.graph.d3v4-force.worker.js","sourcesContent":["/**\n * The entire dc.graph.js library is scoped under the **dc_graph** name space. It does not introduce\n * anything else into the global name space.\n *\n * Like in dc.js and most libraries built on d3, most `dc_graph` functions are designed to allow function chaining, meaning they return the current diagram\n * instance whenever it is appropriate. The getter forms of functions do not participate in function\n * chaining because they return values that are not the diagram.\n * @namespace dc_graph\n * @version 0.9.93\n * @example\n * // Example chaining\n * diagram.width(600)\n * .height(400)\n * .nodeDimension(nodeDim)\n * .nodeGroup(nodeGroup);\n */\n\nvar dc_graph = {\n version: '0.9.93',\n constants: {\n CHART_CLASS: 'dc-graph'\n }\n};\n\nfunction get_original(x) {\n return x.orig;\n}\n\nfunction identity(x) {\n return x;\n};\n\nvar property = function (defaultValue, unwrap) {\n if(unwrap === undefined)\n unwrap = get_original;\n else if(unwrap === false)\n unwrap = identity;\n var value = defaultValue, react = null;\n var cascade = [];\n var ret = function (_) {\n if (!arguments.length) {\n return value;\n }\n if(react)\n react(_);\n value = _;\n return this;\n };\n ret.cascade = function (n, f) {\n for(var i = 0; i n) {\n cascade.splice(i, 0, {n: n, f: f});\n return ret;\n }\n }\n cascade.push({n: n, f: f});\n return ret;\n };\n ret._eval = function(o, n) {\n if(n===0 || !cascade.length)\n return dc_graph.functor_wrap(ret(), unwrap)(o);\n else {\n var last = cascade[n-1];\n return last.f(o, function() {\n return ret._eval(o, n-1);\n });\n }\n };\n ret.eval = function(o) {\n return ret._eval(o, cascade.length);\n };\n ret.react = function(_) {\n if (!arguments.length) {\n return react;\n }\n react = _;\n return this;\n };\n return ret;\n};\n\nfunction named_children() {\n var _children = {};\n var f = function(id, object) {\n if(arguments.length === 1)\n return _children[id];\n if(f.reject) {\n var reject = f.reject(id, object);\n if(reject) {\n console.groupCollapsed(reject);\n console.trace();\n console.groupEnd();\n return this;\n }\n }\n // do not notify unnecessarily\n if(_children[id] === object)\n return this;\n if(_children[id])\n _children[id].parent(null);\n _children[id] = object;\n if(object)\n object.parent(this);\n return this;\n };\n f.enum = function() {\n return Object.keys(_children);\n };\n f.nameOf = function(o) {\n var found = Object.entries(_children).find(function(kv) {\n return kv[1] == o;\n });\n return found ? found[0] : null;\n };\n return f;\n}\n\nfunction deprecated_property(message, defaultValue) {\n var prop = property(defaultValue);\n var ret = function() {\n if(arguments.length) {\n console.warn(message);\n prop.apply(property, arguments);\n return this;\n }\n return prop();\n };\n ['cascade', '_eval', 'eval', 'react'].forEach(function(method) {\n ret[method] = prop[method];\n });\n return ret;\n}\n\nfunction onetime_trace(level, message) {\n var said = false;\n return function() {\n if(said)\n return;\n if(level === 'trace') {\n // todo: implement levels?\n // console.groupCollapsed(message);\n // console.trace();\n // console.groupEnd();\n }\n else\n console[level](message);\n said = true;\n };\n}\n\nfunction deprecation_warning(message) {\n return onetime_trace('warn', message);\n}\n\nfunction trace_function(level, message, f) {\n var dep = onetime_trace(level, message);\n return function() {\n dep();\n return f.apply(this, arguments);\n };\n}\nfunction deprecate_function(message, f) {\n return trace_function('warn', message, f);\n}\n\n// http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript\nfunction uuid() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {\n var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);\n return v.toString(16);\n });\n}\n\nfunction is_ie() {\n var ua = window.navigator.userAgent;\n\n return(ua.indexOf('MSIE ') > 0 ||\n ua.indexOf('Trident/') > 0 ||\n ua.indexOf('Edge/') > 0);\n}\n\nfunction is_safari() {\n return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n}\n\n// polyfill Object.assign for IE\n// it's just too useful to do without\nif (typeof Object.assign != 'function') {\n // Must be writable: true, enumerable: false, configurable: true\n Object.defineProperty(Object, \"assign\", {\n value: function assign(target, varArgs) { // .length of function is 2\n 'use strict';\n if (target == null) { // TypeError if undefined or null\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n var to = Object(target);\n\n for (var index = 1; index < arguments.length; index++) {\n var nextSource = arguments[index];\n\n if (nextSource != null) { // Skip over if undefined or null\n for (var nextKey in nextSource) {\n // Avoid bugs when hasOwnProperty is shadowed\n if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n }\n return to;\n },\n writable: true,\n configurable: true\n });\n}\n\n\n// https://tc39.github.io/ecma262/#sec-array.prototype.includes\nif (!Array.prototype.includes) {\n Object.defineProperty(Array.prototype, 'includes', {\n value: function(valueToFind, fromIndex) {\n\n if (this == null) {\n throw new TypeError('\"this\" is null or not defined');\n }\n\n // 1. Let O be ? ToObject(this value).\n var o = Object(this);\n\n // 2. Let len be ? ToLength(? Get(O, \"length\")).\n var len = o.length >>> 0;\n\n // 3. If len is 0, return false.\n if (len === 0) {\n return false;\n }\n\n // 4. Let n be ? ToInteger(fromIndex).\n // (If fromIndex is undefined, this step produces the value 0.)\n var n = fromIndex | 0;\n\n // 5. If n >= 0, then\n // a. Let k be n.\n // 6. Else n < 0,\n // a. Let k be len + n.\n // b. If k < 0, let k be 0.\n var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);\n\n function sameValueZero(x, y) {\n return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));\n }\n\n // 7. Repeat, while k < len\n while (k < len) {\n // a. Let elementK be the result of ? Get(O, ! ToString(k)).\n // b. If SameValueZero(valueToFind, elementK) is true, return true.\n if (sameValueZero(o[k], valueToFind)) {\n return true;\n }\n // c. Increase k by 1.\n k++;\n }\n\n // 8. Return false\n return false;\n }\n });\n}\n\nif (!Object.entries) {\n Object.entries = function( obj ){\n var ownProps = Object.keys( obj ),\n i = ownProps.length,\n resArray = new Array(i); // preallocate the Array\n while (i--)\n resArray[i] = [ownProps[i], obj[ownProps[i]]];\n return resArray;\n };\n}\n\n// https://github.com/KhaledElAnsari/Object.values\nObject.values = Object.values ? Object.values : function(obj) {\n var allowedTypes = [\"[object String]\", \"[object Object]\", \"[object Array]\", \"[object Function]\"];\n var objType = Object.prototype.toString.call(obj);\n\n if(obj === null || typeof obj === \"undefined\") {\n\tthrow new TypeError(\"Cannot convert undefined or null to object\");\n } else if(!~allowedTypes.indexOf(objType)) {\n\treturn [];\n } else {\n\t// if ES6 is supported\n\tif (Object.keys) {\n\t return Object.keys(obj).map(function (key) {\n\t\treturn obj[key];\n\t });\n\t}\n\n\tvar result = [];\n\tfor (var prop in obj) {\n\t if (obj.hasOwnProperty(prop)) {\n\t\tresult.push(obj[prop]);\n\t }\n\t}\n\n\treturn result;\n }\n};\n\nfunction getBBoxNoThrow(elem) {\n // firefox seems to have issues with some of my texts\n // just catch for now\n try {\n return elem.getBBox();\n } catch(xep) {\n return {x: 0, y: 0, width:0, height: 0};\n }\n}\n","// create or re-use objects in a map, delete the ones that were not reused\nfunction regenerate_objects(preserved, list, need, key, assign, create, destroy) {\n if(!create) create = function(k, o) { };\n if(!destroy) destroy = function(k) { };\n var keep = {};\n function wrap(o) {\n var k = key(o);\n if(!preserved[k])\n create(k, preserved[k] = {}, o);\n var o1 = preserved[k];\n assign(o1, o);\n keep[k] = true;\n return o1;\n }\n var wlist = list.map(wrap);\n if(need)\n need.forEach(function(k) {\n if(!preserved[k]) { // hasn't been created, needs to be\n create(k, preserved[k] = {}, null);\n assign(preserved[k], null);\n }\n if(!keep[k]) { // wasn't in list, should be\n wlist.push(preserved[k]);\n keep[k] = true;\n }\n });\n // delete any objects from last round that are no longer used\n for(var k in preserved)\n if(!keep[k]) {\n destroy(k, preserved[k]);\n delete preserved[k];\n }\n return wlist;\n}\n","/**\n * `dc_graph.graphviz_attrs defines a basic set of attributes which layout engines should\n * implement - although these are not required, they make it easier for clients and\n * modes (like expand_collapse) to work with multiple layout engines.\n *\n * these attributes are {@link http://www.graphviz.org/doc/info/attrs.html from graphviz}\n * @class graphviz_attrs\n * @memberof dc_graph\n * @return {Object}\n **/\ndc_graph.graphviz_attrs = function() {\n return {\n /**\n * Direction to draw ranks.\n * @method rankdir\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [rankdir='TB'] 'TB', 'LR', 'BT', or 'RL'\n **/\n rankdir: property('TB'),\n /**\n * Spacing in between nodes in the same rank.\n * @method nodesep\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [nodesep=40]\n **/\n nodesep: property(40),\n /**\n * Spacing in between ranks.\n * @method ranksep\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [ranksep=40]\n **/\n ranksep: property(40)\n };\n};\n\n// graphlib-dot seems to wrap nodes in an extra {value}\n// actually this is quite a common problem with generic libs\nfunction nvalue(n) {\n return n.value.value ? n.value.value : n.value;\n}\n\n// apply standard accessors to a diagram in order to style it as graphviz would\n// this is a work in progress\ndc_graph.apply_graphviz_accessors = function(diagram) {\n diagram\n .nodeLabel(function(n) {\n var label = nvalue(n).label;\n if(label === undefined)\n label = n.key;\n return label && label.split(/\\n|\\\\n/);\n })\n .nodeRadius(function(n) {\n // should do width & height instead, #25\n return nvalue(n).radius || 25;\n })\n .nodeShape(function(n) { return nvalue(n).shape; })\n .nodeFill(function(n) { return nvalue(n).fillcolor || 'white'; })\n .nodeOpacity(function(n) {\n // not standard gv\n return nvalue(n).opacity || 1;\n })\n .nodeLabelFill(function(n) { return nvalue(n).fontcolor || 'black'; })\n .nodeTitle(function(n) {\n return (nvalue(n).htmltip || nvalue(n).jsontip) ? null :\n nvalue(n).tooltip !== undefined ?\n nvalue(n).tooltip :\n diagram.nodeLabel()(n);\n })\n .nodeStrokeWidth(function(n) {\n // it is debatable whether a point === a pixel but they are close\n // https://graphicdesign.stackexchange.com/questions/199/point-vs-pixel-what-is-the-difference\n var penwidth = nvalue(n).penwidth;\n return penwidth !== undefined ? +penwidth : 1;\n })\n .edgeLabel(function(e) { return e.value.label ? e.value.label.split(/\\n|\\\\n/) : ''; })\n .edgeStroke(function(e) { return e.value.color || 'black'; })\n .edgeOpacity(function(e) {\n // not standard gv\n return e.value.opacity || 1;\n })\n .edgeArrowSize(function(e) {\n return e.value.arrowsize || 1;\n })\n // need directedness to default these correctly, see #106\n .edgeArrowhead(function(e) {\n var head = e.value.arrowhead;\n return head !== undefined ? head : 'vee';\n })\n .edgeArrowtail(function(e) {\n var tail = e.value.arrowtail;\n return tail !== undefined ? tail : null;\n })\n .edgeStrokeDashArray(function(e) {\n switch(e.value.style) {\n case 'dotted':\n return [1,5];\n }\n return null;\n });\n var draw_clusters = diagram.child('draw-clusters');\n if(draw_clusters) {\n draw_clusters\n .clusterStroke(function(c) {\n return c.value.color || 'black';\n })\n .clusterFill(function(c) {\n return c.value.style === 'filled' ? c.value.fillcolor || c.value.color || c.value.bgcolor : null;\n })\n .clusterLabel(function(c) {\n return c.value.label;\n });\n }\n};\n\ndc_graph.snapshot_graphviz = function(diagram) {\n var xDomain = diagram.x().domain(), yDomain = diagram.y().domain();\n return {\n nodes: diagram.nodeGroup().all().map(function(n) {\n return diagram.getWholeNode(n.key);\n })\n .filter(function(x) { return x; })\n .map(function(n) {\n return {\n key: diagram.nodeKey.eval(n),\n label: diagram.nodeLabel.eval(n),\n fillcolor: diagram.nodeFillScale()(diagram.nodeFill.eval(n)),\n penwidth: diagram.nodeStrokeWidth.eval(n),\n // not supported as input, see dc.graph.js#25\n // width: n.cola.dcg_rx*2,\n // height: n.cola.dcg_ry*2,\n\n // not graphviz attributes\n // until we have w/h\n radius: diagram.nodeRadius.eval(n),\n // does not seem to exist in gv\n opacity: diagram.nodeOpacity.eval(n),\n // should be pos\n x: n.cola.x,\n y: n.cola.y\n };\n }),\n edges: diagram.edgeGroup().all().map(function(e) {\n return diagram.getWholeEdge(e.key);\n }).map(function(e) {\n return {\n key: diagram.edgeKey.eval(e),\n source: diagram.edgeSource.eval(e),\n target: diagram.edgeTarget.eval(e),\n color: diagram.edgeStroke.eval(e),\n arrowsize: diagram.edgeArrowSize.eval(e),\n opacity: diagram.edgeOpacity.eval(e),\n // should support dir, see dc.graph.js#106\n arrowhead: diagram.edgeArrowhead.eval(e),\n arrowtail: diagram.edgeArrowtail.eval(e)\n };\n }),\n bounds: {\n left: xDomain[0],\n top: yDomain[0],\n right: xDomain[1],\n bottom: yDomain[1]\n }\n };\n};\n","/**\n * `dc_graph.d3v4_force_layout` is an adaptor for d3-force version 4 layouts in dc.graph.js\n * @class d3v4_force_layout\n * @memberof dc_graph\n * @param {String} [id=uuid()] - Unique identifier\n * @return {dc_graph.d3v4_force_layout}\n **/\ndc_graph.d3v4_force_layout = function(id) {\n var _layoutId = id || uuid();\n var _simulation = null; // d3-force simulation\n var _dispatch = d3.dispatch('tick', 'start', 'end');\n // node and edge objects shared with d3-force, preserved from one iteration\n // to the next (as long as the object is still in the layout)\n var _nodes = {}, _edges = {};\n var _wnodes = [], _wedges = [];\n var _options = null;\n var _paths = null;\n\n function init(options) {\n _options = options;\n\n _simulation = d3v4.forceSimulation()\n .force('link', d3v4.forceLink())\n .force('center', d3v4.forceCenter(options.width / 2, options.height / 2))\n .force('gravityX', d3v4.forceX(options.width / 2).strength(_options.gravityStrength))\n .force('gravityY', d3v4.forceY(options.height / 2).strength(_options.gravityStrength))\n .force('collision', d3v4.forceCollide(_options.collisionRadius))\n .force('charge', d3v4.forceManyBody())\n .stop();\n }\n\n function dispatchState(event) {\n _dispatch[event](\n _wnodes,\n _wedges.map(function(e) {\n return {dcg_edgeKey: e.dcg_edgeKey};\n })\n );\n }\n\n function data(nodes, edges) {\n var nodeIDs = {};\n nodes.forEach(function(d, i) {\n nodeIDs[d.dcg_nodeKey] = i;\n });\n\n _wnodes = regenerate_objects(_nodes, nodes, null, function(v) {\n return v.dcg_nodeKey;\n }, function(v1, v) {\n v1.dcg_nodeKey = v.dcg_nodeKey;\n v1.width = v.width;\n v1.height = v.height;\n v1.id = v.dcg_nodeKey;\n if(v.dcg_nodeFixed) {\n v1.fx = v.dcg_nodeFixed.x;\n v1.fy = v.dcg_nodeFixed.y;\n } else v1.fx = v1.fy = null;\n });\n\n _wedges = regenerate_objects(_edges, edges, null, function(e) {\n return e.dcg_edgeKey;\n }, function(e1, e) {\n e1.dcg_edgeKey = e.dcg_edgeKey;\n e1.source = nodeIDs[_nodes[e.dcg_edgeSource].dcg_nodeKey];\n e1.target = nodeIDs[_nodes[e.dcg_edgeTarget].dcg_nodeKey];\n e1.dcg_edgeLength = e.dcg_edgeLength;\n });\n\n _simulation.force('straighten', null);\n _simulation.nodes(_wnodes);\n _simulation.force('link').links(_wedges);\n }\n\n function start() {\n _dispatch.start();\n installForces(_paths);\n runSimulation(_options.iterations);\n }\n\n function stop() {\n // not running asynchronously, no _simulation.stop();\n }\n\n function savePositions() {\n var data = {};\n Object.keys(_nodes).forEach(function(key) {\n data[key] = {x: _nodes[key].x, y: _nodes[key].y};\n });\n return data;\n }\n function restorePositions(data) {\n Object.keys(data).forEach(function(key) {\n if(_nodes[key]) {\n _nodes[key].fx = data[key].x;\n _nodes[key].fy = data[key].y;\n }\n });\n }\n function installForces(paths) {\n if(paths)\n paths = paths.filter(function(path) {\n return path.nodes.every(function(nk) { return _nodes[nk]; });\n });\n if(paths === null || !paths.length) {\n _simulation.force('charge').strength(_options.initialCharge);\n } else {\n var nodesOnPath;\n if(_options.fixOffPathNodes) {\n nodesOnPath = d3.set();\n paths.forEach(function(path) {\n path.nodes.forEach(function(nid) {\n nodesOnPath.add(nid);\n });\n });\n }\n\n // fix nodes not on paths\n Object.keys(_nodes).forEach(function(key) {\n if(_options.fixOffPathNodes && !nodesOnPath.has(key)) {\n _nodes[key].fx = _nodes[key].x;\n _nodes[key].fy = _nodes[key].y;\n } else {\n _nodes[key].fx = null;\n _nodes[key].fy = null;\n }\n });\n\n _simulation.force('charge').strength(_options.chargeForce);\n _simulation.force('straighten', d3v4.forceStraightenPaths()\n .id(function(n) { return n.dcg_nodeKey; })\n .angleForce(_options.angleForce)\n .pathNodes(function(p) { return p.nodes; })\n .pathStrength(function(p) { return p.strength; })\n .paths(paths));\n }\n };\n\n function runSimulation(iterations) {\n _simulation.alpha(1);\n for (var i = 0; i < iterations; ++i) {\n _simulation.tick();\n dispatchState('tick');\n }\n dispatchState('end');\n }\n\n var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz);\n\n var engine = Object.assign(graphviz, {\n layoutAlgorithm: function() {\n return 'd3v4-force';\n },\n layoutId: function() {\n return _layoutId;\n },\n supportsWebworker: function() {\n return true;\n },\n supportsMoving: function() {\n return true;\n },\n parent: property(null),\n on: function(event, f) {\n if(arguments.length === 1)\n return _dispatch.on(event);\n _dispatch.on(event, f);\n return this;\n },\n init: function(options) {\n this.optionNames().forEach(function(option) {\n options[option] = options[option] || this[option]();\n }.bind(this));\n init(options);\n return this;\n },\n data: function(graph, nodes, edges, constraints) {\n data(nodes, edges, constraints);\n },\n start: function() {\n start();\n },\n stop: function() {\n stop();\n },\n paths: function(paths) {\n _paths = paths;\n },\n savePositions: savePositions,\n restorePositions: restorePositions,\n optionNames: function() {\n return ['iterations', 'angleForce', 'chargeForce', 'gravityStrength', 'collisionRadius',\n 'initialCharge', 'fixOffPathNodes']\n .concat(graphviz_keys);\n },\n iterations: property(300),\n angleForce: property(0.01),\n chargeForce: property(-600),\n gravityStrength: property(0.3),\n collisionRadius: property(8),\n initialCharge: property(-100),\n fixOffPathNodes: property(false),\n populateLayoutNode: function() {},\n populateLayoutEdge: function() {}\n });\n engine.pathStraightenForce = engine.angleForce;\n return engine;\n};\n\ndc_graph.d3v4_force_layout.scripts = ['d3.js', 'd3v4-force.js'];\n","var _layouts;\n\nfunction postResponse(event, layoutId) {\n return function() {\n var message = {\n response: event,\n layoutId: layoutId\n };\n message.args = Array.prototype.slice.call(arguments);\n postMessage(message);\n };\n}\n\nonmessage = function(e) {\n var args = e.data.args;\n switch(e.data.command) {\n case 'init':\n // find a function under dc_graph that has `scripts`\n var layout_name;\n for(var name in dc_graph) {\n if(typeof dc_graph[name] === 'function' && dc_graph[name].scripts)\n layout_name = name;\n }\n if(!_layouts) {\n _layouts = {};\n importScripts.apply(null, dc_graph[layout_name].scripts);\n if(dc_graph[layout_name].optional_scripts) {\n try {\n importScripts.apply(null, dc_graph[layout_name].optional_scripts);\n }\n catch(xep) {\n console.log(xep);\n }\n }\n }\n\n _layouts[args.layoutId] = dc_graph[layout_name]()\n .on('tick', postResponse('tick', args.layoutId))\n .on('start', postResponse('start', args.layoutId))\n .on('end', postResponse('end', args.layoutId))\n .init(args.options);\n break;\n case 'data':\n if(_layouts)\n _layouts[args.layoutId].data(args.graph, args.nodes, args.edges, args.clusters, args.constraints);\n break;\n case 'start':\n // if(args.initialOnly) {\n // if(args.showLayoutSteps)\n // _tick();\n // _done();\n // }\n // else\n _layouts[args.layoutId].start();\n break;\n case 'stop':\n if(_layouts)\n _layouts[args.layoutId].stop();\n break;\n }\n};\n\n"]} \ No newline at end of file diff --git a/dc.graph.dagre.worker.js b/dc.graph.dagre.worker.js deleted file mode 100644 index c2eaf57c..00000000 --- a/dc.graph.dagre.worker.js +++ /dev/null @@ -1,763 +0,0 @@ -/*! - * dc.graph 0.9.93 - * http://dc-js.github.io/dc.graph.js/ - * Copyright 2015-2019 AT&T Intellectual Property & the dc.graph.js Developers - * https://github.com/dc-js/dc.graph.js/blob/master/AUTHORS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -/** - * The entire dc.graph.js library is scoped under the **dc_graph** name space. It does not introduce - * anything else into the global name space. - * - * Like in dc.js and most libraries built on d3, most `dc_graph` functions are designed to allow function chaining, meaning they return the current diagram - * instance whenever it is appropriate. The getter forms of functions do not participate in function - * chaining because they return values that are not the diagram. - * @namespace dc_graph - * @version 0.9.93 - * @example - * // Example chaining - * diagram.width(600) - * .height(400) - * .nodeDimension(nodeDim) - * .nodeGroup(nodeGroup); - */ - -var dc_graph = { - version: '0.9.93', - constants: { - CHART_CLASS: 'dc-graph' - } -}; - -function get_original(x) { - return x.orig; -} - -function identity(x) { - return x; -}; - -var property = function (defaultValue, unwrap) { - if(unwrap === undefined) - unwrap = get_original; - else if(unwrap === false) - unwrap = identity; - var value = defaultValue, react = null; - var cascade = []; - var ret = function (_) { - if (!arguments.length) { - return value; - } - if(react) - react(_); - value = _; - return this; - }; - ret.cascade = function (n, f) { - for(var i = 0; i n) { - cascade.splice(i, 0, {n: n, f: f}); - return ret; - } - } - cascade.push({n: n, f: f}); - return ret; - }; - ret._eval = function(o, n) { - if(n===0 || !cascade.length) - return dc_graph.functor_wrap(ret(), unwrap)(o); - else { - var last = cascade[n-1]; - return last.f(o, function() { - return ret._eval(o, n-1); - }); - } - }; - ret.eval = function(o) { - return ret._eval(o, cascade.length); - }; - ret.react = function(_) { - if (!arguments.length) { - return react; - } - react = _; - return this; - }; - return ret; -}; - -function named_children() { - var _children = {}; - var f = function(id, object) { - if(arguments.length === 1) - return _children[id]; - if(f.reject) { - var reject = f.reject(id, object); - if(reject) { - console.groupCollapsed(reject); - console.trace(); - console.groupEnd(); - return this; - } - } - // do not notify unnecessarily - if(_children[id] === object) - return this; - if(_children[id]) - _children[id].parent(null); - _children[id] = object; - if(object) - object.parent(this); - return this; - }; - f.enum = function() { - return Object.keys(_children); - }; - f.nameOf = function(o) { - var found = Object.entries(_children).find(function(kv) { - return kv[1] == o; - }); - return found ? found[0] : null; - }; - return f; -} - -function deprecated_property(message, defaultValue) { - var prop = property(defaultValue); - var ret = function() { - if(arguments.length) { - console.warn(message); - prop.apply(property, arguments); - return this; - } - return prop(); - }; - ['cascade', '_eval', 'eval', 'react'].forEach(function(method) { - ret[method] = prop[method]; - }); - return ret; -} - -function onetime_trace(level, message) { - var said = false; - return function() { - if(said) - return; - if(level === 'trace') { - // todo: implement levels? - // console.groupCollapsed(message); - // console.trace(); - // console.groupEnd(); - } - else - console[level](message); - said = true; - }; -} - -function deprecation_warning(message) { - return onetime_trace('warn', message); -} - -function trace_function(level, message, f) { - var dep = onetime_trace(level, message); - return function() { - dep(); - return f.apply(this, arguments); - }; -} -function deprecate_function(message, f) { - return trace_function('warn', message, f); -} - -// http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript -function uuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); - return v.toString(16); - }); -} - -function is_ie() { - var ua = window.navigator.userAgent; - - return(ua.indexOf('MSIE ') > 0 || - ua.indexOf('Trident/') > 0 || - ua.indexOf('Edge/') > 0); -} - -function is_safari() { - return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); -} - -// polyfill Object.assign for IE -// it's just too useful to do without -if (typeof Object.assign != 'function') { - // Must be writable: true, enumerable: false, configurable: true - Object.defineProperty(Object, "assign", { - value: function assign(target, varArgs) { // .length of function is 2 - 'use strict'; - if (target == null) { // TypeError if undefined or null - throw new TypeError('Cannot convert undefined or null to object'); - } - - var to = Object(target); - - for (var index = 1; index < arguments.length; index++) { - var nextSource = arguments[index]; - - if (nextSource != null) { // Skip over if undefined or null - for (var nextKey in nextSource) { - // Avoid bugs when hasOwnProperty is shadowed - if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { - to[nextKey] = nextSource[nextKey]; - } - } - } - } - return to; - }, - writable: true, - configurable: true - }); -} - - -// https://tc39.github.io/ecma262/#sec-array.prototype.includes -if (!Array.prototype.includes) { - Object.defineProperty(Array.prototype, 'includes', { - value: function(valueToFind, fromIndex) { - - if (this == null) { - throw new TypeError('"this" is null or not defined'); - } - - // 1. Let O be ? ToObject(this value). - var o = Object(this); - - // 2. Let len be ? ToLength(? Get(O, "length")). - var len = o.length >>> 0; - - // 3. If len is 0, return false. - if (len === 0) { - return false; - } - - // 4. Let n be ? ToInteger(fromIndex). - // (If fromIndex is undefined, this step produces the value 0.) - var n = fromIndex | 0; - - // 5. If n >= 0, then - // a. Let k be n. - // 6. Else n < 0, - // a. Let k be len + n. - // b. If k < 0, let k be 0. - var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); - - function sameValueZero(x, y) { - return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y)); - } - - // 7. Repeat, while k < len - while (k < len) { - // a. Let elementK be the result of ? Get(O, ! ToString(k)). - // b. If SameValueZero(valueToFind, elementK) is true, return true. - if (sameValueZero(o[k], valueToFind)) { - return true; - } - // c. Increase k by 1. - k++; - } - - // 8. Return false - return false; - } - }); -} - -if (!Object.entries) { - Object.entries = function( obj ){ - var ownProps = Object.keys( obj ), - i = ownProps.length, - resArray = new Array(i); // preallocate the Array - while (i--) - resArray[i] = [ownProps[i], obj[ownProps[i]]]; - return resArray; - }; -} - -// https://github.com/KhaledElAnsari/Object.values -Object.values = Object.values ? Object.values : function(obj) { - var allowedTypes = ["[object String]", "[object Object]", "[object Array]", "[object Function]"]; - var objType = Object.prototype.toString.call(obj); - - if(obj === null || typeof obj === "undefined") { - throw new TypeError("Cannot convert undefined or null to object"); - } else if(!~allowedTypes.indexOf(objType)) { - return []; - } else { - // if ES6 is supported - if (Object.keys) { - return Object.keys(obj).map(function (key) { - return obj[key]; - }); - } - - var result = []; - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - result.push(obj[prop]); - } - } - - return result; - } -}; - -function getBBoxNoThrow(elem) { - // firefox seems to have issues with some of my texts - // just catch for now - try { - return elem.getBBox(); - } catch(xep) { - return {x: 0, y: 0, width:0, height: 0}; - } -} - -// create or re-use objects in a map, delete the ones that were not reused -function regenerate_objects(preserved, list, need, key, assign, create, destroy) { - if(!create) create = function(k, o) { }; - if(!destroy) destroy = function(k) { }; - var keep = {}; - function wrap(o) { - var k = key(o); - if(!preserved[k]) - create(k, preserved[k] = {}, o); - var o1 = preserved[k]; - assign(o1, o); - keep[k] = true; - return o1; - } - var wlist = list.map(wrap); - if(need) - need.forEach(function(k) { - if(!preserved[k]) { // hasn't been created, needs to be - create(k, preserved[k] = {}, null); - assign(preserved[k], null); - } - if(!keep[k]) { // wasn't in list, should be - wlist.push(preserved[k]); - keep[k] = true; - } - }); - // delete any objects from last round that are no longer used - for(var k in preserved) - if(!keep[k]) { - destroy(k, preserved[k]); - delete preserved[k]; - } - return wlist; -} - -/** - * `dc_graph.graphviz_attrs defines a basic set of attributes which layout engines should - * implement - although these are not required, they make it easier for clients and - * modes (like expand_collapse) to work with multiple layout engines. - * - * these attributes are {@link http://www.graphviz.org/doc/info/attrs.html from graphviz} - * @class graphviz_attrs - * @memberof dc_graph - * @return {Object} - **/ -dc_graph.graphviz_attrs = function() { - return { - /** - * Direction to draw ranks. - * @method rankdir - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [rankdir='TB'] 'TB', 'LR', 'BT', or 'RL' - **/ - rankdir: property('TB'), - /** - * Spacing in between nodes in the same rank. - * @method nodesep - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [nodesep=40] - **/ - nodesep: property(40), - /** - * Spacing in between ranks. - * @method ranksep - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [ranksep=40] - **/ - ranksep: property(40) - }; -}; - -// graphlib-dot seems to wrap nodes in an extra {value} -// actually this is quite a common problem with generic libs -function nvalue(n) { - return n.value.value ? n.value.value : n.value; -} - -// apply standard accessors to a diagram in order to style it as graphviz would -// this is a work in progress -dc_graph.apply_graphviz_accessors = function(diagram) { - diagram - .nodeLabel(function(n) { - var label = nvalue(n).label; - if(label === undefined) - label = n.key; - return label && label.split(/\n|\\n/); - }) - .nodeRadius(function(n) { - // should do width & height instead, #25 - return nvalue(n).radius || 25; - }) - .nodeShape(function(n) { return nvalue(n).shape; }) - .nodeFill(function(n) { return nvalue(n).fillcolor || 'white'; }) - .nodeOpacity(function(n) { - // not standard gv - return nvalue(n).opacity || 1; - }) - .nodeLabelFill(function(n) { return nvalue(n).fontcolor || 'black'; }) - .nodeTitle(function(n) { - return (nvalue(n).htmltip || nvalue(n).jsontip) ? null : - nvalue(n).tooltip !== undefined ? - nvalue(n).tooltip : - diagram.nodeLabel()(n); - }) - .nodeStrokeWidth(function(n) { - // it is debatable whether a point === a pixel but they are close - // https://graphicdesign.stackexchange.com/questions/199/point-vs-pixel-what-is-the-difference - var penwidth = nvalue(n).penwidth; - return penwidth !== undefined ? +penwidth : 1; - }) - .edgeLabel(function(e) { return e.value.label ? e.value.label.split(/\n|\\n/) : ''; }) - .edgeStroke(function(e) { return e.value.color || 'black'; }) - .edgeOpacity(function(e) { - // not standard gv - return e.value.opacity || 1; - }) - .edgeArrowSize(function(e) { - return e.value.arrowsize || 1; - }) - // need directedness to default these correctly, see #106 - .edgeArrowhead(function(e) { - var head = e.value.arrowhead; - return head !== undefined ? head : 'vee'; - }) - .edgeArrowtail(function(e) { - var tail = e.value.arrowtail; - return tail !== undefined ? tail : null; - }) - .edgeStrokeDashArray(function(e) { - switch(e.value.style) { - case 'dotted': - return [1,5]; - } - return null; - }); - var draw_clusters = diagram.child('draw-clusters'); - if(draw_clusters) { - draw_clusters - .clusterStroke(function(c) { - return c.value.color || 'black'; - }) - .clusterFill(function(c) { - return c.value.style === 'filled' ? c.value.fillcolor || c.value.color || c.value.bgcolor : null; - }) - .clusterLabel(function(c) { - return c.value.label; - }); - } -}; - -dc_graph.snapshot_graphviz = function(diagram) { - var xDomain = diagram.x().domain(), yDomain = diagram.y().domain(); - return { - nodes: diagram.nodeGroup().all().map(function(n) { - return diagram.getWholeNode(n.key); - }) - .filter(function(x) { return x; }) - .map(function(n) { - return { - key: diagram.nodeKey.eval(n), - label: diagram.nodeLabel.eval(n), - fillcolor: diagram.nodeFillScale()(diagram.nodeFill.eval(n)), - penwidth: diagram.nodeStrokeWidth.eval(n), - // not supported as input, see dc.graph.js#25 - // width: n.cola.dcg_rx*2, - // height: n.cola.dcg_ry*2, - - // not graphviz attributes - // until we have w/h - radius: diagram.nodeRadius.eval(n), - // does not seem to exist in gv - opacity: diagram.nodeOpacity.eval(n), - // should be pos - x: n.cola.x, - y: n.cola.y - }; - }), - edges: diagram.edgeGroup().all().map(function(e) { - return diagram.getWholeEdge(e.key); - }).map(function(e) { - return { - key: diagram.edgeKey.eval(e), - source: diagram.edgeSource.eval(e), - target: diagram.edgeTarget.eval(e), - color: diagram.edgeStroke.eval(e), - arrowsize: diagram.edgeArrowSize.eval(e), - opacity: diagram.edgeOpacity.eval(e), - // should support dir, see dc.graph.js#106 - arrowhead: diagram.edgeArrowhead.eval(e), - arrowtail: diagram.edgeArrowtail.eval(e) - }; - }), - bounds: { - left: xDomain[0], - top: yDomain[0], - right: xDomain[1], - bottom: yDomain[1] - } - }; -}; - -/** - * `dc_graph.dagre_layout` is an adaptor for dagre.js layouts in dc.graph.js - * - * In addition to the below layout attributes, `dagre_layout` also implements the attributes from - * {@link dc_graph.graphviz_attrs graphviz_attrs} - * @class dagre_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.dagre_layout} - **/ -dc_graph.dagre_layout = function(id) { - var _layoutId = id || uuid(); - var _dagreGraph = null, _tick, _done; - var _dispatch = d3.dispatch('tick', 'start', 'end'); - // node and edge objects preserved from one iteration - // to the next (as long as the object is still in the layout) - var _nodes = {}, _edges = {}; - - function init(options) { - // Create a new directed graph - _dagreGraph = new dagre.graphlib.Graph({multigraph: true, compound: true}); - - // Set an object for the graph label - _dagreGraph.setGraph({rankdir: options.rankdir, nodesep: options.nodesep, ranksep: options.ranksep}); - - // Default to assigning a new object as a label for each new edge. - _dagreGraph.setDefaultEdgeLabel(function() { return {}; }); - } - - function data(nodes, edges, clusters) { - var wnodes = regenerate_objects(_nodes, nodes, null, function(v) { - return v.dcg_nodeKey; - }, function(v1, v) { - v1.dcg_nodeKey = v.dcg_nodeKey; - v1.width = v.width; - v1.height = v.height; - /* - dagre does not seem to accept input positions - if(v.dcg_nodeFixed) { - v1.x = v.dcg_nodeFixed.x; - v1.y = v.dcg_nodeFixed.y; - } - */ - }, function(k, o) { - _dagreGraph.setNode(k, o); - }, function(k) { - _dagreGraph.removeNode(k); - }); - var wedges = regenerate_objects(_edges, edges, null, function(e) { - return e.dcg_edgeKey; - }, function(e1, e) { - e1.dcg_edgeKey = e.dcg_edgeKey; - e1.dcg_edgeSource = e.dcg_edgeSource; - e1.dcg_edgeTarget = e.dcg_edgeTarget; - }, function(k, o, e) { - _dagreGraph.setEdge(e.dcg_edgeSource, e.dcg_edgeTarget, o); - }, function(k, e) { - _dagreGraph.removeEdge(e.dcg_edgeSource, e.dcg_edgeTarget, e.dcg_edgeKey); - }); - clusters = clusters.filter(function(c) { - return /^cluster/.test(c.dcg_clusterKey); - }); - clusters.forEach(function(c) { - _dagreGraph.setNode(c.dcg_clusterKey, c); - }); - clusters.forEach(function(c) { - if(c.dcg_clusterParent) - _dagreGraph.setParent(c.dcg_clusterKey, c.dcg_clusterParent); - }); - nodes.forEach(function(n) { - if(n.dcg_nodeParentCluster) - _dagreGraph.setParent(n.dcg_nodeKey, n.dcg_nodeParentCluster); - }); - - function dispatchState(event) { - _dispatch[event]( - wnodes, - wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }), - clusters.map(function(c) { - var c = Object.assign({}, _dagreGraph.node(c.dcg_clusterKey)); - c.bounds = { - left: c.x - c.width/2, - top: c.y - c.height/2, - right: c.x + c.width/2, - bottom: c.y + c.height/2 - }; - return c; - }) - ); - } - _tick = function() { - dispatchState('tick'); - }; - _done = function() { - dispatchState('end'); - }; - } - - function start(options) { - _dispatch.start(); - dagre.layout(_dagreGraph); - _done(); - } - - function stop() { - } - - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); - return Object.assign(graphviz, { - layoutAlgorithm: function() { - return 'dagre'; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return true; - }, - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - init(options); - return this; - }, - data: function(graph, nodes, edges, clusters) { - data(nodes, edges, clusters); - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - optionNames: function() { - return graphviz_keys; - }, - populateLayoutNode: function() {}, - populateLayoutEdge: function() {} - }); -}; - -dc_graph.dagre_layout.scripts = ['d3.js', 'dagre.js']; - -var _layouts; - -function postResponse(event, layoutId) { - return function() { - var message = { - response: event, - layoutId: layoutId - }; - message.args = Array.prototype.slice.call(arguments); - postMessage(message); - }; -} - -onmessage = function(e) { - var args = e.data.args; - switch(e.data.command) { - case 'init': - // find a function under dc_graph that has `scripts` - var layout_name; - for(var name in dc_graph) { - if(typeof dc_graph[name] === 'function' && dc_graph[name].scripts) - layout_name = name; - } - if(!_layouts) { - _layouts = {}; - importScripts.apply(null, dc_graph[layout_name].scripts); - if(dc_graph[layout_name].optional_scripts) { - try { - importScripts.apply(null, dc_graph[layout_name].optional_scripts); - } - catch(xep) { - console.log(xep); - } - } - } - - _layouts[args.layoutId] = dc_graph[layout_name]() - .on('tick', postResponse('tick', args.layoutId)) - .on('start', postResponse('start', args.layoutId)) - .on('end', postResponse('end', args.layoutId)) - .init(args.options); - break; - case 'data': - if(_layouts) - _layouts[args.layoutId].data(args.graph, args.nodes, args.edges, args.clusters, args.constraints); - break; - case 'start': - // if(args.initialOnly) { - // if(args.showLayoutSteps) - // _tick(); - // _done(); - // } - // else - _layouts[args.layoutId].start(); - break; - case 'stop': - if(_layouts) - _layouts[args.layoutId].stop(); - break; - } -}; - - -//# sourceMappingURL=dc.graph.dagre.worker.js.map \ No newline at end of file diff --git a/dc.graph.dagre.worker.js.map b/dc.graph.dagre.worker.js.map deleted file mode 100644 index 0e6a1fc4..00000000 --- a/dc.graph.dagre.worker.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["src/core.js","src/generate_objects.js","src/graphviz_attrs.js","src/dagre_layout.js","src/webworker_message.js"],"names":[],"mappings":"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","file":"dc.graph.dagre.worker.js","sourcesContent":["/**\n * The entire dc.graph.js library is scoped under the **dc_graph** name space. It does not introduce\n * anything else into the global name space.\n *\n * Like in dc.js and most libraries built on d3, most `dc_graph` functions are designed to allow function chaining, meaning they return the current diagram\n * instance whenever it is appropriate. The getter forms of functions do not participate in function\n * chaining because they return values that are not the diagram.\n * @namespace dc_graph\n * @version 0.9.93\n * @example\n * // Example chaining\n * diagram.width(600)\n * .height(400)\n * .nodeDimension(nodeDim)\n * .nodeGroup(nodeGroup);\n */\n\nvar dc_graph = {\n version: '0.9.93',\n constants: {\n CHART_CLASS: 'dc-graph'\n }\n};\n\nfunction get_original(x) {\n return x.orig;\n}\n\nfunction identity(x) {\n return x;\n};\n\nvar property = function (defaultValue, unwrap) {\n if(unwrap === undefined)\n unwrap = get_original;\n else if(unwrap === false)\n unwrap = identity;\n var value = defaultValue, react = null;\n var cascade = [];\n var ret = function (_) {\n if (!arguments.length) {\n return value;\n }\n if(react)\n react(_);\n value = _;\n return this;\n };\n ret.cascade = function (n, f) {\n for(var i = 0; i n) {\n cascade.splice(i, 0, {n: n, f: f});\n return ret;\n }\n }\n cascade.push({n: n, f: f});\n return ret;\n };\n ret._eval = function(o, n) {\n if(n===0 || !cascade.length)\n return dc_graph.functor_wrap(ret(), unwrap)(o);\n else {\n var last = cascade[n-1];\n return last.f(o, function() {\n return ret._eval(o, n-1);\n });\n }\n };\n ret.eval = function(o) {\n return ret._eval(o, cascade.length);\n };\n ret.react = function(_) {\n if (!arguments.length) {\n return react;\n }\n react = _;\n return this;\n };\n return ret;\n};\n\nfunction named_children() {\n var _children = {};\n var f = function(id, object) {\n if(arguments.length === 1)\n return _children[id];\n if(f.reject) {\n var reject = f.reject(id, object);\n if(reject) {\n console.groupCollapsed(reject);\n console.trace();\n console.groupEnd();\n return this;\n }\n }\n // do not notify unnecessarily\n if(_children[id] === object)\n return this;\n if(_children[id])\n _children[id].parent(null);\n _children[id] = object;\n if(object)\n object.parent(this);\n return this;\n };\n f.enum = function() {\n return Object.keys(_children);\n };\n f.nameOf = function(o) {\n var found = Object.entries(_children).find(function(kv) {\n return kv[1] == o;\n });\n return found ? found[0] : null;\n };\n return f;\n}\n\nfunction deprecated_property(message, defaultValue) {\n var prop = property(defaultValue);\n var ret = function() {\n if(arguments.length) {\n console.warn(message);\n prop.apply(property, arguments);\n return this;\n }\n return prop();\n };\n ['cascade', '_eval', 'eval', 'react'].forEach(function(method) {\n ret[method] = prop[method];\n });\n return ret;\n}\n\nfunction onetime_trace(level, message) {\n var said = false;\n return function() {\n if(said)\n return;\n if(level === 'trace') {\n // todo: implement levels?\n // console.groupCollapsed(message);\n // console.trace();\n // console.groupEnd();\n }\n else\n console[level](message);\n said = true;\n };\n}\n\nfunction deprecation_warning(message) {\n return onetime_trace('warn', message);\n}\n\nfunction trace_function(level, message, f) {\n var dep = onetime_trace(level, message);\n return function() {\n dep();\n return f.apply(this, arguments);\n };\n}\nfunction deprecate_function(message, f) {\n return trace_function('warn', message, f);\n}\n\n// http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript\nfunction uuid() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {\n var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);\n return v.toString(16);\n });\n}\n\nfunction is_ie() {\n var ua = window.navigator.userAgent;\n\n return(ua.indexOf('MSIE ') > 0 ||\n ua.indexOf('Trident/') > 0 ||\n ua.indexOf('Edge/') > 0);\n}\n\nfunction is_safari() {\n return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n}\n\n// polyfill Object.assign for IE\n// it's just too useful to do without\nif (typeof Object.assign != 'function') {\n // Must be writable: true, enumerable: false, configurable: true\n Object.defineProperty(Object, \"assign\", {\n value: function assign(target, varArgs) { // .length of function is 2\n 'use strict';\n if (target == null) { // TypeError if undefined or null\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n var to = Object(target);\n\n for (var index = 1; index < arguments.length; index++) {\n var nextSource = arguments[index];\n\n if (nextSource != null) { // Skip over if undefined or null\n for (var nextKey in nextSource) {\n // Avoid bugs when hasOwnProperty is shadowed\n if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n }\n return to;\n },\n writable: true,\n configurable: true\n });\n}\n\n\n// https://tc39.github.io/ecma262/#sec-array.prototype.includes\nif (!Array.prototype.includes) {\n Object.defineProperty(Array.prototype, 'includes', {\n value: function(valueToFind, fromIndex) {\n\n if (this == null) {\n throw new TypeError('\"this\" is null or not defined');\n }\n\n // 1. Let O be ? ToObject(this value).\n var o = Object(this);\n\n // 2. Let len be ? ToLength(? Get(O, \"length\")).\n var len = o.length >>> 0;\n\n // 3. If len is 0, return false.\n if (len === 0) {\n return false;\n }\n\n // 4. Let n be ? ToInteger(fromIndex).\n // (If fromIndex is undefined, this step produces the value 0.)\n var n = fromIndex | 0;\n\n // 5. If n >= 0, then\n // a. Let k be n.\n // 6. Else n < 0,\n // a. Let k be len + n.\n // b. If k < 0, let k be 0.\n var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);\n\n function sameValueZero(x, y) {\n return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));\n }\n\n // 7. Repeat, while k < len\n while (k < len) {\n // a. Let elementK be the result of ? Get(O, ! ToString(k)).\n // b. If SameValueZero(valueToFind, elementK) is true, return true.\n if (sameValueZero(o[k], valueToFind)) {\n return true;\n }\n // c. Increase k by 1.\n k++;\n }\n\n // 8. Return false\n return false;\n }\n });\n}\n\nif (!Object.entries) {\n Object.entries = function( obj ){\n var ownProps = Object.keys( obj ),\n i = ownProps.length,\n resArray = new Array(i); // preallocate the Array\n while (i--)\n resArray[i] = [ownProps[i], obj[ownProps[i]]];\n return resArray;\n };\n}\n\n// https://github.com/KhaledElAnsari/Object.values\nObject.values = Object.values ? Object.values : function(obj) {\n var allowedTypes = [\"[object String]\", \"[object Object]\", \"[object Array]\", \"[object Function]\"];\n var objType = Object.prototype.toString.call(obj);\n\n if(obj === null || typeof obj === \"undefined\") {\n\tthrow new TypeError(\"Cannot convert undefined or null to object\");\n } else if(!~allowedTypes.indexOf(objType)) {\n\treturn [];\n } else {\n\t// if ES6 is supported\n\tif (Object.keys) {\n\t return Object.keys(obj).map(function (key) {\n\t\treturn obj[key];\n\t });\n\t}\n\n\tvar result = [];\n\tfor (var prop in obj) {\n\t if (obj.hasOwnProperty(prop)) {\n\t\tresult.push(obj[prop]);\n\t }\n\t}\n\n\treturn result;\n }\n};\n\nfunction getBBoxNoThrow(elem) {\n // firefox seems to have issues with some of my texts\n // just catch for now\n try {\n return elem.getBBox();\n } catch(xep) {\n return {x: 0, y: 0, width:0, height: 0};\n }\n}\n","// create or re-use objects in a map, delete the ones that were not reused\nfunction regenerate_objects(preserved, list, need, key, assign, create, destroy) {\n if(!create) create = function(k, o) { };\n if(!destroy) destroy = function(k) { };\n var keep = {};\n function wrap(o) {\n var k = key(o);\n if(!preserved[k])\n create(k, preserved[k] = {}, o);\n var o1 = preserved[k];\n assign(o1, o);\n keep[k] = true;\n return o1;\n }\n var wlist = list.map(wrap);\n if(need)\n need.forEach(function(k) {\n if(!preserved[k]) { // hasn't been created, needs to be\n create(k, preserved[k] = {}, null);\n assign(preserved[k], null);\n }\n if(!keep[k]) { // wasn't in list, should be\n wlist.push(preserved[k]);\n keep[k] = true;\n }\n });\n // delete any objects from last round that are no longer used\n for(var k in preserved)\n if(!keep[k]) {\n destroy(k, preserved[k]);\n delete preserved[k];\n }\n return wlist;\n}\n","/**\n * `dc_graph.graphviz_attrs defines a basic set of attributes which layout engines should\n * implement - although these are not required, they make it easier for clients and\n * modes (like expand_collapse) to work with multiple layout engines.\n *\n * these attributes are {@link http://www.graphviz.org/doc/info/attrs.html from graphviz}\n * @class graphviz_attrs\n * @memberof dc_graph\n * @return {Object}\n **/\ndc_graph.graphviz_attrs = function() {\n return {\n /**\n * Direction to draw ranks.\n * @method rankdir\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [rankdir='TB'] 'TB', 'LR', 'BT', or 'RL'\n **/\n rankdir: property('TB'),\n /**\n * Spacing in between nodes in the same rank.\n * @method nodesep\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [nodesep=40]\n **/\n nodesep: property(40),\n /**\n * Spacing in between ranks.\n * @method ranksep\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [ranksep=40]\n **/\n ranksep: property(40)\n };\n};\n\n// graphlib-dot seems to wrap nodes in an extra {value}\n// actually this is quite a common problem with generic libs\nfunction nvalue(n) {\n return n.value.value ? n.value.value : n.value;\n}\n\n// apply standard accessors to a diagram in order to style it as graphviz would\n// this is a work in progress\ndc_graph.apply_graphviz_accessors = function(diagram) {\n diagram\n .nodeLabel(function(n) {\n var label = nvalue(n).label;\n if(label === undefined)\n label = n.key;\n return label && label.split(/\\n|\\\\n/);\n })\n .nodeRadius(function(n) {\n // should do width & height instead, #25\n return nvalue(n).radius || 25;\n })\n .nodeShape(function(n) { return nvalue(n).shape; })\n .nodeFill(function(n) { return nvalue(n).fillcolor || 'white'; })\n .nodeOpacity(function(n) {\n // not standard gv\n return nvalue(n).opacity || 1;\n })\n .nodeLabelFill(function(n) { return nvalue(n).fontcolor || 'black'; })\n .nodeTitle(function(n) {\n return (nvalue(n).htmltip || nvalue(n).jsontip) ? null :\n nvalue(n).tooltip !== undefined ?\n nvalue(n).tooltip :\n diagram.nodeLabel()(n);\n })\n .nodeStrokeWidth(function(n) {\n // it is debatable whether a point === a pixel but they are close\n // https://graphicdesign.stackexchange.com/questions/199/point-vs-pixel-what-is-the-difference\n var penwidth = nvalue(n).penwidth;\n return penwidth !== undefined ? +penwidth : 1;\n })\n .edgeLabel(function(e) { return e.value.label ? e.value.label.split(/\\n|\\\\n/) : ''; })\n .edgeStroke(function(e) { return e.value.color || 'black'; })\n .edgeOpacity(function(e) {\n // not standard gv\n return e.value.opacity || 1;\n })\n .edgeArrowSize(function(e) {\n return e.value.arrowsize || 1;\n })\n // need directedness to default these correctly, see #106\n .edgeArrowhead(function(e) {\n var head = e.value.arrowhead;\n return head !== undefined ? head : 'vee';\n })\n .edgeArrowtail(function(e) {\n var tail = e.value.arrowtail;\n return tail !== undefined ? tail : null;\n })\n .edgeStrokeDashArray(function(e) {\n switch(e.value.style) {\n case 'dotted':\n return [1,5];\n }\n return null;\n });\n var draw_clusters = diagram.child('draw-clusters');\n if(draw_clusters) {\n draw_clusters\n .clusterStroke(function(c) {\n return c.value.color || 'black';\n })\n .clusterFill(function(c) {\n return c.value.style === 'filled' ? c.value.fillcolor || c.value.color || c.value.bgcolor : null;\n })\n .clusterLabel(function(c) {\n return c.value.label;\n });\n }\n};\n\ndc_graph.snapshot_graphviz = function(diagram) {\n var xDomain = diagram.x().domain(), yDomain = diagram.y().domain();\n return {\n nodes: diagram.nodeGroup().all().map(function(n) {\n return diagram.getWholeNode(n.key);\n })\n .filter(function(x) { return x; })\n .map(function(n) {\n return {\n key: diagram.nodeKey.eval(n),\n label: diagram.nodeLabel.eval(n),\n fillcolor: diagram.nodeFillScale()(diagram.nodeFill.eval(n)),\n penwidth: diagram.nodeStrokeWidth.eval(n),\n // not supported as input, see dc.graph.js#25\n // width: n.cola.dcg_rx*2,\n // height: n.cola.dcg_ry*2,\n\n // not graphviz attributes\n // until we have w/h\n radius: diagram.nodeRadius.eval(n),\n // does not seem to exist in gv\n opacity: diagram.nodeOpacity.eval(n),\n // should be pos\n x: n.cola.x,\n y: n.cola.y\n };\n }),\n edges: diagram.edgeGroup().all().map(function(e) {\n return diagram.getWholeEdge(e.key);\n }).map(function(e) {\n return {\n key: diagram.edgeKey.eval(e),\n source: diagram.edgeSource.eval(e),\n target: diagram.edgeTarget.eval(e),\n color: diagram.edgeStroke.eval(e),\n arrowsize: diagram.edgeArrowSize.eval(e),\n opacity: diagram.edgeOpacity.eval(e),\n // should support dir, see dc.graph.js#106\n arrowhead: diagram.edgeArrowhead.eval(e),\n arrowtail: diagram.edgeArrowtail.eval(e)\n };\n }),\n bounds: {\n left: xDomain[0],\n top: yDomain[0],\n right: xDomain[1],\n bottom: yDomain[1]\n }\n };\n};\n","/**\n * `dc_graph.dagre_layout` is an adaptor for dagre.js layouts in dc.graph.js\n *\n * In addition to the below layout attributes, `dagre_layout` also implements the attributes from\n * {@link dc_graph.graphviz_attrs graphviz_attrs}\n * @class dagre_layout\n * @memberof dc_graph\n * @param {String} [id=uuid()] - Unique identifier\n * @return {dc_graph.dagre_layout}\n **/\ndc_graph.dagre_layout = function(id) {\n var _layoutId = id || uuid();\n var _dagreGraph = null, _tick, _done;\n var _dispatch = d3.dispatch('tick', 'start', 'end');\n // node and edge objects preserved from one iteration\n // to the next (as long as the object is still in the layout)\n var _nodes = {}, _edges = {};\n\n function init(options) {\n // Create a new directed graph\n _dagreGraph = new dagre.graphlib.Graph({multigraph: true, compound: true});\n\n // Set an object for the graph label\n _dagreGraph.setGraph({rankdir: options.rankdir, nodesep: options.nodesep, ranksep: options.ranksep});\n\n // Default to assigning a new object as a label for each new edge.\n _dagreGraph.setDefaultEdgeLabel(function() { return {}; });\n }\n\n function data(nodes, edges, clusters) {\n var wnodes = regenerate_objects(_nodes, nodes, null, function(v) {\n return v.dcg_nodeKey;\n }, function(v1, v) {\n v1.dcg_nodeKey = v.dcg_nodeKey;\n v1.width = v.width;\n v1.height = v.height;\n /*\n dagre does not seem to accept input positions\n if(v.dcg_nodeFixed) {\n v1.x = v.dcg_nodeFixed.x;\n v1.y = v.dcg_nodeFixed.y;\n }\n */\n }, function(k, o) {\n _dagreGraph.setNode(k, o);\n }, function(k) {\n _dagreGraph.removeNode(k);\n });\n var wedges = regenerate_objects(_edges, edges, null, function(e) {\n return e.dcg_edgeKey;\n }, function(e1, e) {\n e1.dcg_edgeKey = e.dcg_edgeKey;\n e1.dcg_edgeSource = e.dcg_edgeSource;\n e1.dcg_edgeTarget = e.dcg_edgeTarget;\n }, function(k, o, e) {\n _dagreGraph.setEdge(e.dcg_edgeSource, e.dcg_edgeTarget, o);\n }, function(k, e) {\n _dagreGraph.removeEdge(e.dcg_edgeSource, e.dcg_edgeTarget, e.dcg_edgeKey);\n });\n clusters = clusters.filter(function(c) {\n return /^cluster/.test(c.dcg_clusterKey);\n });\n clusters.forEach(function(c) {\n _dagreGraph.setNode(c.dcg_clusterKey, c);\n });\n clusters.forEach(function(c) {\n if(c.dcg_clusterParent)\n _dagreGraph.setParent(c.dcg_clusterKey, c.dcg_clusterParent);\n });\n nodes.forEach(function(n) {\n if(n.dcg_nodeParentCluster)\n _dagreGraph.setParent(n.dcg_nodeKey, n.dcg_nodeParentCluster);\n });\n\n function dispatchState(event) {\n _dispatch[event](\n wnodes,\n wedges.map(function(e) {\n return {dcg_edgeKey: e.dcg_edgeKey};\n }),\n clusters.map(function(c) {\n var c = Object.assign({}, _dagreGraph.node(c.dcg_clusterKey));\n c.bounds = {\n left: c.x - c.width/2,\n top: c.y - c.height/2,\n right: c.x + c.width/2,\n bottom: c.y + c.height/2\n };\n return c;\n })\n );\n }\n _tick = function() {\n dispatchState('tick');\n };\n _done = function() {\n dispatchState('end');\n };\n }\n\n function start(options) {\n _dispatch.start();\n dagre.layout(_dagreGraph);\n _done();\n }\n\n function stop() {\n }\n\n var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz);\n return Object.assign(graphviz, {\n layoutAlgorithm: function() {\n return 'dagre';\n },\n layoutId: function() {\n return _layoutId;\n },\n supportsWebworker: function() {\n return true;\n },\n on: function(event, f) {\n if(arguments.length === 1)\n return _dispatch.on(event);\n _dispatch.on(event, f);\n return this;\n },\n init: function(options) {\n this.optionNames().forEach(function(option) {\n options[option] = options[option] || this[option]();\n }.bind(this));\n init(options);\n return this;\n },\n data: function(graph, nodes, edges, clusters) {\n data(nodes, edges, clusters);\n },\n start: function() {\n start();\n },\n stop: function() {\n stop();\n },\n optionNames: function() {\n return graphviz_keys;\n },\n populateLayoutNode: function() {},\n populateLayoutEdge: function() {}\n });\n};\n\ndc_graph.dagre_layout.scripts = ['d3.js', 'dagre.js'];\n","var _layouts;\n\nfunction postResponse(event, layoutId) {\n return function() {\n var message = {\n response: event,\n layoutId: layoutId\n };\n message.args = Array.prototype.slice.call(arguments);\n postMessage(message);\n };\n}\n\nonmessage = function(e) {\n var args = e.data.args;\n switch(e.data.command) {\n case 'init':\n // find a function under dc_graph that has `scripts`\n var layout_name;\n for(var name in dc_graph) {\n if(typeof dc_graph[name] === 'function' && dc_graph[name].scripts)\n layout_name = name;\n }\n if(!_layouts) {\n _layouts = {};\n importScripts.apply(null, dc_graph[layout_name].scripts);\n if(dc_graph[layout_name].optional_scripts) {\n try {\n importScripts.apply(null, dc_graph[layout_name].optional_scripts);\n }\n catch(xep) {\n console.log(xep);\n }\n }\n }\n\n _layouts[args.layoutId] = dc_graph[layout_name]()\n .on('tick', postResponse('tick', args.layoutId))\n .on('start', postResponse('start', args.layoutId))\n .on('end', postResponse('end', args.layoutId))\n .init(args.options);\n break;\n case 'data':\n if(_layouts)\n _layouts[args.layoutId].data(args.graph, args.nodes, args.edges, args.clusters, args.constraints);\n break;\n case 'start':\n // if(args.initialOnly) {\n // if(args.showLayoutSteps)\n // _tick();\n // _done();\n // }\n // else\n _layouts[args.layoutId].start();\n break;\n case 'stop':\n if(_layouts)\n _layouts[args.layoutId].stop();\n break;\n }\n};\n\n"]} \ No newline at end of file diff --git a/dc.graph.dynagraph.worker.js b/dc.graph.dynagraph.worker.js deleted file mode 100644 index d7acaf24..00000000 --- a/dc.graph.dynagraph.worker.js +++ /dev/null @@ -1,938 +0,0 @@ -/*! - * dc.graph 0.9.93 - * http://dc-js.github.io/dc.graph.js/ - * Copyright 2015-2019 AT&T Intellectual Property & the dc.graph.js Developers - * https://github.com/dc-js/dc.graph.js/blob/master/AUTHORS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -/** - * The entire dc.graph.js library is scoped under the **dc_graph** name space. It does not introduce - * anything else into the global name space. - * - * Like in dc.js and most libraries built on d3, most `dc_graph` functions are designed to allow function chaining, meaning they return the current diagram - * instance whenever it is appropriate. The getter forms of functions do not participate in function - * chaining because they return values that are not the diagram. - * @namespace dc_graph - * @version 0.9.93 - * @example - * // Example chaining - * diagram.width(600) - * .height(400) - * .nodeDimension(nodeDim) - * .nodeGroup(nodeGroup); - */ - -var dc_graph = { - version: '0.9.93', - constants: { - CHART_CLASS: 'dc-graph' - } -}; - -function get_original(x) { - return x.orig; -} - -function identity(x) { - return x; -}; - -var property = function (defaultValue, unwrap) { - if(unwrap === undefined) - unwrap = get_original; - else if(unwrap === false) - unwrap = identity; - var value = defaultValue, react = null; - var cascade = []; - var ret = function (_) { - if (!arguments.length) { - return value; - } - if(react) - react(_); - value = _; - return this; - }; - ret.cascade = function (n, f) { - for(var i = 0; i n) { - cascade.splice(i, 0, {n: n, f: f}); - return ret; - } - } - cascade.push({n: n, f: f}); - return ret; - }; - ret._eval = function(o, n) { - if(n===0 || !cascade.length) - return dc_graph.functor_wrap(ret(), unwrap)(o); - else { - var last = cascade[n-1]; - return last.f(o, function() { - return ret._eval(o, n-1); - }); - } - }; - ret.eval = function(o) { - return ret._eval(o, cascade.length); - }; - ret.react = function(_) { - if (!arguments.length) { - return react; - } - react = _; - return this; - }; - return ret; -}; - -function named_children() { - var _children = {}; - var f = function(id, object) { - if(arguments.length === 1) - return _children[id]; - if(f.reject) { - var reject = f.reject(id, object); - if(reject) { - console.groupCollapsed(reject); - console.trace(); - console.groupEnd(); - return this; - } - } - // do not notify unnecessarily - if(_children[id] === object) - return this; - if(_children[id]) - _children[id].parent(null); - _children[id] = object; - if(object) - object.parent(this); - return this; - }; - f.enum = function() { - return Object.keys(_children); - }; - f.nameOf = function(o) { - var found = Object.entries(_children).find(function(kv) { - return kv[1] == o; - }); - return found ? found[0] : null; - }; - return f; -} - -function deprecated_property(message, defaultValue) { - var prop = property(defaultValue); - var ret = function() { - if(arguments.length) { - console.warn(message); - prop.apply(property, arguments); - return this; - } - return prop(); - }; - ['cascade', '_eval', 'eval', 'react'].forEach(function(method) { - ret[method] = prop[method]; - }); - return ret; -} - -function onetime_trace(level, message) { - var said = false; - return function() { - if(said) - return; - if(level === 'trace') { - // todo: implement levels? - // console.groupCollapsed(message); - // console.trace(); - // console.groupEnd(); - } - else - console[level](message); - said = true; - }; -} - -function deprecation_warning(message) { - return onetime_trace('warn', message); -} - -function trace_function(level, message, f) { - var dep = onetime_trace(level, message); - return function() { - dep(); - return f.apply(this, arguments); - }; -} -function deprecate_function(message, f) { - return trace_function('warn', message, f); -} - -// http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript -function uuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); - return v.toString(16); - }); -} - -function is_ie() { - var ua = window.navigator.userAgent; - - return(ua.indexOf('MSIE ') > 0 || - ua.indexOf('Trident/') > 0 || - ua.indexOf('Edge/') > 0); -} - -function is_safari() { - return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); -} - -// polyfill Object.assign for IE -// it's just too useful to do without -if (typeof Object.assign != 'function') { - // Must be writable: true, enumerable: false, configurable: true - Object.defineProperty(Object, "assign", { - value: function assign(target, varArgs) { // .length of function is 2 - 'use strict'; - if (target == null) { // TypeError if undefined or null - throw new TypeError('Cannot convert undefined or null to object'); - } - - var to = Object(target); - - for (var index = 1; index < arguments.length; index++) { - var nextSource = arguments[index]; - - if (nextSource != null) { // Skip over if undefined or null - for (var nextKey in nextSource) { - // Avoid bugs when hasOwnProperty is shadowed - if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { - to[nextKey] = nextSource[nextKey]; - } - } - } - } - return to; - }, - writable: true, - configurable: true - }); -} - - -// https://tc39.github.io/ecma262/#sec-array.prototype.includes -if (!Array.prototype.includes) { - Object.defineProperty(Array.prototype, 'includes', { - value: function(valueToFind, fromIndex) { - - if (this == null) { - throw new TypeError('"this" is null or not defined'); - } - - // 1. Let O be ? ToObject(this value). - var o = Object(this); - - // 2. Let len be ? ToLength(? Get(O, "length")). - var len = o.length >>> 0; - - // 3. If len is 0, return false. - if (len === 0) { - return false; - } - - // 4. Let n be ? ToInteger(fromIndex). - // (If fromIndex is undefined, this step produces the value 0.) - var n = fromIndex | 0; - - // 5. If n >= 0, then - // a. Let k be n. - // 6. Else n < 0, - // a. Let k be len + n. - // b. If k < 0, let k be 0. - var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); - - function sameValueZero(x, y) { - return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y)); - } - - // 7. Repeat, while k < len - while (k < len) { - // a. Let elementK be the result of ? Get(O, ! ToString(k)). - // b. If SameValueZero(valueToFind, elementK) is true, return true. - if (sameValueZero(o[k], valueToFind)) { - return true; - } - // c. Increase k by 1. - k++; - } - - // 8. Return false - return false; - } - }); -} - -if (!Object.entries) { - Object.entries = function( obj ){ - var ownProps = Object.keys( obj ), - i = ownProps.length, - resArray = new Array(i); // preallocate the Array - while (i--) - resArray[i] = [ownProps[i], obj[ownProps[i]]]; - return resArray; - }; -} - -// https://github.com/KhaledElAnsari/Object.values -Object.values = Object.values ? Object.values : function(obj) { - var allowedTypes = ["[object String]", "[object Object]", "[object Array]", "[object Function]"]; - var objType = Object.prototype.toString.call(obj); - - if(obj === null || typeof obj === "undefined") { - throw new TypeError("Cannot convert undefined or null to object"); - } else if(!~allowedTypes.indexOf(objType)) { - return []; - } else { - // if ES6 is supported - if (Object.keys) { - return Object.keys(obj).map(function (key) { - return obj[key]; - }); - } - - var result = []; - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - result.push(obj[prop]); - } - } - - return result; - } -}; - -function getBBoxNoThrow(elem) { - // firefox seems to have issues with some of my texts - // just catch for now - try { - return elem.getBBox(); - } catch(xep) { - return {x: 0, y: 0, width:0, height: 0}; - } -} - -// create or re-use objects in a map, delete the ones that were not reused -function regenerate_objects(preserved, list, need, key, assign, create, destroy) { - if(!create) create = function(k, o) { }; - if(!destroy) destroy = function(k) { }; - var keep = {}; - function wrap(o) { - var k = key(o); - if(!preserved[k]) - create(k, preserved[k] = {}, o); - var o1 = preserved[k]; - assign(o1, o); - keep[k] = true; - return o1; - } - var wlist = list.map(wrap); - if(need) - need.forEach(function(k) { - if(!preserved[k]) { // hasn't been created, needs to be - create(k, preserved[k] = {}, null); - assign(preserved[k], null); - } - if(!keep[k]) { // wasn't in list, should be - wlist.push(preserved[k]); - keep[k] = true; - } - }); - // delete any objects from last round that are no longer used - for(var k in preserved) - if(!keep[k]) { - destroy(k, preserved[k]); - delete preserved[k]; - } - return wlist; -} - -/** - * `dc_graph.graphviz_attrs defines a basic set of attributes which layout engines should - * implement - although these are not required, they make it easier for clients and - * modes (like expand_collapse) to work with multiple layout engines. - * - * these attributes are {@link http://www.graphviz.org/doc/info/attrs.html from graphviz} - * @class graphviz_attrs - * @memberof dc_graph - * @return {Object} - **/ -dc_graph.graphviz_attrs = function() { - return { - /** - * Direction to draw ranks. - * @method rankdir - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [rankdir='TB'] 'TB', 'LR', 'BT', or 'RL' - **/ - rankdir: property('TB'), - /** - * Spacing in between nodes in the same rank. - * @method nodesep - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [nodesep=40] - **/ - nodesep: property(40), - /** - * Spacing in between ranks. - * @method ranksep - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [ranksep=40] - **/ - ranksep: property(40) - }; -}; - -// graphlib-dot seems to wrap nodes in an extra {value} -// actually this is quite a common problem with generic libs -function nvalue(n) { - return n.value.value ? n.value.value : n.value; -} - -// apply standard accessors to a diagram in order to style it as graphviz would -// this is a work in progress -dc_graph.apply_graphviz_accessors = function(diagram) { - diagram - .nodeLabel(function(n) { - var label = nvalue(n).label; - if(label === undefined) - label = n.key; - return label && label.split(/\n|\\n/); - }) - .nodeRadius(function(n) { - // should do width & height instead, #25 - return nvalue(n).radius || 25; - }) - .nodeShape(function(n) { return nvalue(n).shape; }) - .nodeFill(function(n) { return nvalue(n).fillcolor || 'white'; }) - .nodeOpacity(function(n) { - // not standard gv - return nvalue(n).opacity || 1; - }) - .nodeLabelFill(function(n) { return nvalue(n).fontcolor || 'black'; }) - .nodeTitle(function(n) { - return (nvalue(n).htmltip || nvalue(n).jsontip) ? null : - nvalue(n).tooltip !== undefined ? - nvalue(n).tooltip : - diagram.nodeLabel()(n); - }) - .nodeStrokeWidth(function(n) { - // it is debatable whether a point === a pixel but they are close - // https://graphicdesign.stackexchange.com/questions/199/point-vs-pixel-what-is-the-difference - var penwidth = nvalue(n).penwidth; - return penwidth !== undefined ? +penwidth : 1; - }) - .edgeLabel(function(e) { return e.value.label ? e.value.label.split(/\n|\\n/) : ''; }) - .edgeStroke(function(e) { return e.value.color || 'black'; }) - .edgeOpacity(function(e) { - // not standard gv - return e.value.opacity || 1; - }) - .edgeArrowSize(function(e) { - return e.value.arrowsize || 1; - }) - // need directedness to default these correctly, see #106 - .edgeArrowhead(function(e) { - var head = e.value.arrowhead; - return head !== undefined ? head : 'vee'; - }) - .edgeArrowtail(function(e) { - var tail = e.value.arrowtail; - return tail !== undefined ? tail : null; - }) - .edgeStrokeDashArray(function(e) { - switch(e.value.style) { - case 'dotted': - return [1,5]; - } - return null; - }); - var draw_clusters = diagram.child('draw-clusters'); - if(draw_clusters) { - draw_clusters - .clusterStroke(function(c) { - return c.value.color || 'black'; - }) - .clusterFill(function(c) { - return c.value.style === 'filled' ? c.value.fillcolor || c.value.color || c.value.bgcolor : null; - }) - .clusterLabel(function(c) { - return c.value.label; - }); - } -}; - -dc_graph.snapshot_graphviz = function(diagram) { - var xDomain = diagram.x().domain(), yDomain = diagram.y().domain(); - return { - nodes: diagram.nodeGroup().all().map(function(n) { - return diagram.getWholeNode(n.key); - }) - .filter(function(x) { return x; }) - .map(function(n) { - return { - key: diagram.nodeKey.eval(n), - label: diagram.nodeLabel.eval(n), - fillcolor: diagram.nodeFillScale()(diagram.nodeFill.eval(n)), - penwidth: diagram.nodeStrokeWidth.eval(n), - // not supported as input, see dc.graph.js#25 - // width: n.cola.dcg_rx*2, - // height: n.cola.dcg_ry*2, - - // not graphviz attributes - // until we have w/h - radius: diagram.nodeRadius.eval(n), - // does not seem to exist in gv - opacity: diagram.nodeOpacity.eval(n), - // should be pos - x: n.cola.x, - y: n.cola.y - }; - }), - edges: diagram.edgeGroup().all().map(function(e) { - return diagram.getWholeEdge(e.key); - }).map(function(e) { - return { - key: diagram.edgeKey.eval(e), - source: diagram.edgeSource.eval(e), - target: diagram.edgeTarget.eval(e), - color: diagram.edgeStroke.eval(e), - arrowsize: diagram.edgeArrowSize.eval(e), - opacity: diagram.edgeOpacity.eval(e), - // should support dir, see dc.graph.js#106 - arrowhead: diagram.edgeArrowhead.eval(e), - arrowtail: diagram.edgeArrowtail.eval(e) - }; - }), - bounds: { - left: xDomain[0], - top: yDomain[0], - right: xDomain[1], - bottom: yDomain[1] - } - }; -}; - -/** - * `dc_graph.dynagraph_layout` connects to dynagraph-wasm and does dynamic directed graph layout. - * @class dynagraph_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.dynagraph_layout} - **/ -dc_graph.dynagraph_layout = function(id, layout) { - var _layoutId = id || uuid(); - const _Gname = _layoutId; - var _layout; - var _dispatch = d3.dispatch('tick', 'start', 'end'); - var _tick, _done; - var _nodes = {}, _edges = {}; - var _linesOut = [], _incrIn = [], _opened = false, _open_graph; - var _lock = 0; - - - - let bb = null; - // dg2incr - function dg2incr_coord(c) { - const [x, y] = c; - return [x, /*(bb && bb[0][1] || 0)*/ - y]; - } - - - function dg2incr_graph_attrs() { - return [ - ['rankdir', _layout.rankdir()], - ['resolution', [_layout.resolution().x, _layout.resolution().y]], - ['defaultsize', [_layout.defaultsize().width, _layout.defaultsize().height]], - ['separation', [_layout.separation().x, _layout.separation().y]], - ]; - } - - function dg2incr_node_attrs(n) { - const attr_pairs = []; - if(n.x !== undefined && n.y !== undefined) - attr_pairs.push(['pos', dg2incr_coord([n.x, n.y]).map(String).join(',')]); - return attr_pairs; - } - - function dg2incr_node_attrs_changed(n, n2) { - const attr_pairs = []; - if(n2.x !== undefined && n2.y !== undefined && (n2.x !== n.x || n2.y !== n.y)) - attr_pairs.push(['pos', dg2incr_coord([n2.x, n2.y]).map(String).join(',')]); - return attr_pairs; - } - - function dg2incr_edge_attrs(e) { - return []; - } - - function mq(x) { // maybe quote - if(x === +x) // isNumber - return x; - else if(/^[A-Za-z_][A-Za-z0-9_]*$/.test(x)) - return x; - else return '"' + x + '"'; - } - - function print_incr_attrs(attr_pairs) { - return '[' + attr_pairs.map(([a,b]) => `${mq(a)}=${mq(b)}`).join(', ') + ']'; - } - - // incr2dg - function incr2dg_coord(c) { - const [x, y] = c; - return [+x, /*(bb && bb[0][1] || 0)*/ - y]; - } - function incr2dg_bb(bb) { - const [x1,y1,x2,y2] = bb.split(','); - return [incr2dg_coord([x1,y1]), incr2dg_coord([x2,y2])]; - } - function incr2dg_node_attrs(n) { - const attrs = {}; - if(n.pos) - [attrs.x, attrs.y] = incr2dg_coord(n.pos.split(',').map(Number)); - return attrs; - } - function incr2dg_edge_attrs(e) { - const attrs = {}; - if(e.pos) - attrs.points = e.pos.split(' ') - .map(coord => coord.split(',').map(Number)) - .map(incr2dg_coord) - .map(([x,y]) => ({x,y})); - return attrs; - } - - function runCommands(cmds) { - for(const cmd of cmds) { - const {action, kind} = cmd; - switch(`${action}_${kind}`) { - case 'open_graph': { - const {attrs} = cmd; - console.log('open graph', attrs); - console.log('open graph bb', bb) - bb = incr2dg_bb(attrs.bb) - console.log('open graph bb', bb) - break; - } - case 'modify_graph': { - const {attrs} = cmd; - console.log('modify graph', attrs); - console.log('modify graph bb', bb) - bb = incr2dg_bb(attrs.bb) - console.log('modify graph bb', bb) - break; - } - case 'close_graph': { - console.log('close graph'); - break; - } - case 'insert_node': { - const {node, attrs} = cmd; - console.log('insert node', node, attrs); - console.log('insert node2', _nodes[node]) - Object.assign(_nodes[node], incr2dg_node_attrs(attrs)); - console.log('insert node3', _nodes[node]) - break; - } - case 'modify_node': { - const {node, attrs} = cmd; - console.log('modify node', node, attrs); - console.log('modify node2', _nodes[node]) - Object.assign(_nodes[node], incr2dg_node_attrs(attrs)); - console.log('modify node3', _nodes[node]) - break; - } - case 'delete_node': { - const {node} = cmd; - console.log('delete node', node); - break; - } - case 'insert_edge': { - const {edge, source, target, attrs} = cmd; - console.log('insert edge', edge, source, target, attrs); - console.log('insert edge2', _edges[edge]) - Object.assign(_edges[edge], incr2dg_edge_attrs(attrs)); - console.log('insert edge3', _edges[edge]) - break; - } - case 'modify_edge': { - const {edge, attrs} = cmd; - console.log('modify edge', edge, attrs); - console.log('modify edge2', _edges[edge]) - Object.assign(_edges[edge], incr2dg_edge_attrs(attrs)); - console.log('modify edge3', _edges[edge]) - break; - } - case 'delete_edge': { - const {edge} = cmd; - console.log('delete edge', edge); - break; - } - } - } - } - function receiveIncr(text) { - console.log(text); - let cmds = null; - try { - const parseIncrface = self.parseIncrface || (self.incrface && self.incrface.parse); - if(!parseIncrface) { - console.log('parseIncrface not available, skipping'); - return; - } - cmds = parseIncrface(text); - } catch(xep) { - console.log('incrface parse failed', xep) - } - if (!cmds) - return; - for(const cmd of cmds) { - const {action, kind, graph} = cmd; - if(action === 'message') { - console.warn('dynagraph message', cmd.message); - continue; - } - if(graph !== _Gname) { - console.warn('graph name mismatch', _Gname, graph); - continue; - } - switch(`${action}_${kind}`) { - case 'lock_graph': - _lock++; - break; - case 'unlock_graph': - // maybe error on negative lock? - if(--_lock <= 0) { - runCommands(_incrIn); - _incrIn = [] - } - break; - default: - if(_lock > 0) - _incrIn.push(cmd); - else - runCommands([cmd]); - } - } - _done(); - } - - function init(options) { - self.receiveIncr = receiveIncr; - _opened = false; - _open_graph = `open graph ${mq(_Gname)} ${print_incr_attrs(dg2incr_graph_attrs())}` - } - - function data(nodes, edges, clusters) { - const linesOutDeleteNode = []; - var wnodes = regenerate_objects(_nodes, nodes, null, - function key(v) { - return v.dcg_nodeKey; - }, function assign(v1, v) { - v1.dcg_nodeKey = v.dcg_nodeKey; - v1.width = v.width; - v1.height = v.height; - if(v.dcg_nodeFixed) { - v1.x = v.dcg_nodeFixed.x; - v1.y = v.dcg_nodeFixed.y; - } - const na = dg2incr_node_attrs_changed(v1, v); - if(na.length) - _linesOut.push(`modify node ${mq(_Gname)} ${mq(v1.dcg_nodeKey)} ${print_incr_attrs(na)}`); - }, function create(k, o) { - _linesOut.push(`insert node ${mq(_Gname)} ${mq(k)} ${print_incr_attrs(dg2incr_node_attrs(o))}`); - }, function destroy(k) { - linesOutDeleteNode.push(`delete node ${mq(_Gname)} ${mq(k)}`); - }); - var wedges = regenerate_objects(_edges, edges, null, function key(e) { - return e.dcg_edgeKey; - }, function assign(e1, e) { - e1.dcg_edgeKey = e.dcg_edgeKey; - e1.dcg_edgeSource = e.dcg_edgeSource; - e1.dcg_edgeTarget = e.dcg_edgeTarget; - }, function create(k, o, e) { - _linesOut.push(`insert edge ${mq(_Gname)} ${mq(k)} ${mq(e.dcg_edgeSource)} ${mq(e.dcg_edgeTarget)} ${print_incr_attrs(dg2incr_edge_attrs(e))}`); - }, function destroy(k, e) { - _linesOut.push(`delete edge ${mq(_Gname)} ${k}`); - }); - _linesOut.push(...linesOutDeleteNode); - - function dispatchState(event) { - _dispatch[event]( - wnodes, - wedges - ); - } - _tick = function() { - dispatchState('tick'); - }; - _done = function() { - dispatchState('end'); - }; - } - - function start() { - if(_linesOut.length) { - const open = _opened ? [] : [_open_graph]; - _opened = true; - const actions = _linesOut.length > 1 ? [ - `lock graph ${mq(_Gname)}`, - ... _linesOut, - `unlock graph ${mq(_Gname)}` - ] : _linesOut; - const input = [...open, ...actions].join('\n'); - console.log('dynagraph input:', input); - self.incrface_input = input; - _linesOut = []; - } - else _done(); - } - - function stop() { - } - - _layout = { - ...dc_graph.graphviz_attrs(), - layoutAlgorithm: function() { - return layout; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return true; - }, - resolution: property({x: 5, y: 5}), - defaultsize: property({width: 50, height: 50}), - separation: property({x: 20, y: 20}), - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - init(options); - return this; - }, - data: function(graph, nodes, edges) { - data(nodes, edges); - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - optionNames: function() { - return ['resolution', 'defaultsize', 'separation']; - }, - populateLayoutNode: function(layout, node) {}, - populateLayoutEdge: function() {} - }; - return _layout; -}; - -dc_graph.dynagraph_layout.scripts = ['d3.js', 'dynagraph-wasm.js', 'incrface-umd.js']; - -var _layouts; - -function postResponse(event, layoutId) { - return function() { - var message = { - response: event, - layoutId: layoutId - }; - message.args = Array.prototype.slice.call(arguments); - postMessage(message); - }; -} - -onmessage = function(e) { - var args = e.data.args; - switch(e.data.command) { - case 'init': - // find a function under dc_graph that has `scripts` - var layout_name; - for(var name in dc_graph) { - if(typeof dc_graph[name] === 'function' && dc_graph[name].scripts) - layout_name = name; - } - if(!_layouts) { - _layouts = {}; - importScripts.apply(null, dc_graph[layout_name].scripts); - if(dc_graph[layout_name].optional_scripts) { - try { - importScripts.apply(null, dc_graph[layout_name].optional_scripts); - } - catch(xep) { - console.log(xep); - } - } - } - - _layouts[args.layoutId] = dc_graph[layout_name]() - .on('tick', postResponse('tick', args.layoutId)) - .on('start', postResponse('start', args.layoutId)) - .on('end', postResponse('end', args.layoutId)) - .init(args.options); - break; - case 'data': - if(_layouts) - _layouts[args.layoutId].data(args.graph, args.nodes, args.edges, args.clusters, args.constraints); - break; - case 'start': - // if(args.initialOnly) { - // if(args.showLayoutSteps) - // _tick(); - // _done(); - // } - // else - _layouts[args.layoutId].start(); - break; - case 'stop': - if(_layouts) - _layouts[args.layoutId].stop(); - break; - } -}; - - -//# sourceMappingURL=dc.graph.dynagraph.worker.js.map \ No newline at end of file diff --git a/dc.graph.dynagraph.worker.js.map b/dc.graph.dynagraph.worker.js.map deleted file mode 100644 index 1f98b0f8..00000000 --- a/dc.graph.dynagraph.worker.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["src/core.js","src/generate_objects.js","src/graphviz_attrs.js","src/dynagraph_layout.js","src/webworker_message.js"],"names":[],"mappings":"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","file":"dc.graph.dynagraph.worker.js","sourcesContent":["/**\n * The entire dc.graph.js library is scoped under the **dc_graph** name space. It does not introduce\n * anything else into the global name space.\n *\n * Like in dc.js and most libraries built on d3, most `dc_graph` functions are designed to allow function chaining, meaning they return the current diagram\n * instance whenever it is appropriate. The getter forms of functions do not participate in function\n * chaining because they return values that are not the diagram.\n * @namespace dc_graph\n * @version 0.9.93\n * @example\n * // Example chaining\n * diagram.width(600)\n * .height(400)\n * .nodeDimension(nodeDim)\n * .nodeGroup(nodeGroup);\n */\n\nvar dc_graph = {\n version: '0.9.93',\n constants: {\n CHART_CLASS: 'dc-graph'\n }\n};\n\nfunction get_original(x) {\n return x.orig;\n}\n\nfunction identity(x) {\n return x;\n};\n\nvar property = function (defaultValue, unwrap) {\n if(unwrap === undefined)\n unwrap = get_original;\n else if(unwrap === false)\n unwrap = identity;\n var value = defaultValue, react = null;\n var cascade = [];\n var ret = function (_) {\n if (!arguments.length) {\n return value;\n }\n if(react)\n react(_);\n value = _;\n return this;\n };\n ret.cascade = function (n, f) {\n for(var i = 0; i n) {\n cascade.splice(i, 0, {n: n, f: f});\n return ret;\n }\n }\n cascade.push({n: n, f: f});\n return ret;\n };\n ret._eval = function(o, n) {\n if(n===0 || !cascade.length)\n return dc_graph.functor_wrap(ret(), unwrap)(o);\n else {\n var last = cascade[n-1];\n return last.f(o, function() {\n return ret._eval(o, n-1);\n });\n }\n };\n ret.eval = function(o) {\n return ret._eval(o, cascade.length);\n };\n ret.react = function(_) {\n if (!arguments.length) {\n return react;\n }\n react = _;\n return this;\n };\n return ret;\n};\n\nfunction named_children() {\n var _children = {};\n var f = function(id, object) {\n if(arguments.length === 1)\n return _children[id];\n if(f.reject) {\n var reject = f.reject(id, object);\n if(reject) {\n console.groupCollapsed(reject);\n console.trace();\n console.groupEnd();\n return this;\n }\n }\n // do not notify unnecessarily\n if(_children[id] === object)\n return this;\n if(_children[id])\n _children[id].parent(null);\n _children[id] = object;\n if(object)\n object.parent(this);\n return this;\n };\n f.enum = function() {\n return Object.keys(_children);\n };\n f.nameOf = function(o) {\n var found = Object.entries(_children).find(function(kv) {\n return kv[1] == o;\n });\n return found ? found[0] : null;\n };\n return f;\n}\n\nfunction deprecated_property(message, defaultValue) {\n var prop = property(defaultValue);\n var ret = function() {\n if(arguments.length) {\n console.warn(message);\n prop.apply(property, arguments);\n return this;\n }\n return prop();\n };\n ['cascade', '_eval', 'eval', 'react'].forEach(function(method) {\n ret[method] = prop[method];\n });\n return ret;\n}\n\nfunction onetime_trace(level, message) {\n var said = false;\n return function() {\n if(said)\n return;\n if(level === 'trace') {\n // todo: implement levels?\n // console.groupCollapsed(message);\n // console.trace();\n // console.groupEnd();\n }\n else\n console[level](message);\n said = true;\n };\n}\n\nfunction deprecation_warning(message) {\n return onetime_trace('warn', message);\n}\n\nfunction trace_function(level, message, f) {\n var dep = onetime_trace(level, message);\n return function() {\n dep();\n return f.apply(this, arguments);\n };\n}\nfunction deprecate_function(message, f) {\n return trace_function('warn', message, f);\n}\n\n// http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript\nfunction uuid() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {\n var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);\n return v.toString(16);\n });\n}\n\nfunction is_ie() {\n var ua = window.navigator.userAgent;\n\n return(ua.indexOf('MSIE ') > 0 ||\n ua.indexOf('Trident/') > 0 ||\n ua.indexOf('Edge/') > 0);\n}\n\nfunction is_safari() {\n return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n}\n\n// polyfill Object.assign for IE\n// it's just too useful to do without\nif (typeof Object.assign != 'function') {\n // Must be writable: true, enumerable: false, configurable: true\n Object.defineProperty(Object, \"assign\", {\n value: function assign(target, varArgs) { // .length of function is 2\n 'use strict';\n if (target == null) { // TypeError if undefined or null\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n var to = Object(target);\n\n for (var index = 1; index < arguments.length; index++) {\n var nextSource = arguments[index];\n\n if (nextSource != null) { // Skip over if undefined or null\n for (var nextKey in nextSource) {\n // Avoid bugs when hasOwnProperty is shadowed\n if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n }\n return to;\n },\n writable: true,\n configurable: true\n });\n}\n\n\n// https://tc39.github.io/ecma262/#sec-array.prototype.includes\nif (!Array.prototype.includes) {\n Object.defineProperty(Array.prototype, 'includes', {\n value: function(valueToFind, fromIndex) {\n\n if (this == null) {\n throw new TypeError('\"this\" is null or not defined');\n }\n\n // 1. Let O be ? ToObject(this value).\n var o = Object(this);\n\n // 2. Let len be ? ToLength(? Get(O, \"length\")).\n var len = o.length >>> 0;\n\n // 3. If len is 0, return false.\n if (len === 0) {\n return false;\n }\n\n // 4. Let n be ? ToInteger(fromIndex).\n // (If fromIndex is undefined, this step produces the value 0.)\n var n = fromIndex | 0;\n\n // 5. If n >= 0, then\n // a. Let k be n.\n // 6. Else n < 0,\n // a. Let k be len + n.\n // b. If k < 0, let k be 0.\n var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);\n\n function sameValueZero(x, y) {\n return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));\n }\n\n // 7. Repeat, while k < len\n while (k < len) {\n // a. Let elementK be the result of ? Get(O, ! ToString(k)).\n // b. If SameValueZero(valueToFind, elementK) is true, return true.\n if (sameValueZero(o[k], valueToFind)) {\n return true;\n }\n // c. Increase k by 1.\n k++;\n }\n\n // 8. Return false\n return false;\n }\n });\n}\n\nif (!Object.entries) {\n Object.entries = function( obj ){\n var ownProps = Object.keys( obj ),\n i = ownProps.length,\n resArray = new Array(i); // preallocate the Array\n while (i--)\n resArray[i] = [ownProps[i], obj[ownProps[i]]];\n return resArray;\n };\n}\n\n// https://github.com/KhaledElAnsari/Object.values\nObject.values = Object.values ? Object.values : function(obj) {\n var allowedTypes = [\"[object String]\", \"[object Object]\", \"[object Array]\", \"[object Function]\"];\n var objType = Object.prototype.toString.call(obj);\n\n if(obj === null || typeof obj === \"undefined\") {\n\tthrow new TypeError(\"Cannot convert undefined or null to object\");\n } else if(!~allowedTypes.indexOf(objType)) {\n\treturn [];\n } else {\n\t// if ES6 is supported\n\tif (Object.keys) {\n\t return Object.keys(obj).map(function (key) {\n\t\treturn obj[key];\n\t });\n\t}\n\n\tvar result = [];\n\tfor (var prop in obj) {\n\t if (obj.hasOwnProperty(prop)) {\n\t\tresult.push(obj[prop]);\n\t }\n\t}\n\n\treturn result;\n }\n};\n\nfunction getBBoxNoThrow(elem) {\n // firefox seems to have issues with some of my texts\n // just catch for now\n try {\n return elem.getBBox();\n } catch(xep) {\n return {x: 0, y: 0, width:0, height: 0};\n }\n}\n","// create or re-use objects in a map, delete the ones that were not reused\nfunction regenerate_objects(preserved, list, need, key, assign, create, destroy) {\n if(!create) create = function(k, o) { };\n if(!destroy) destroy = function(k) { };\n var keep = {};\n function wrap(o) {\n var k = key(o);\n if(!preserved[k])\n create(k, preserved[k] = {}, o);\n var o1 = preserved[k];\n assign(o1, o);\n keep[k] = true;\n return o1;\n }\n var wlist = list.map(wrap);\n if(need)\n need.forEach(function(k) {\n if(!preserved[k]) { // hasn't been created, needs to be\n create(k, preserved[k] = {}, null);\n assign(preserved[k], null);\n }\n if(!keep[k]) { // wasn't in list, should be\n wlist.push(preserved[k]);\n keep[k] = true;\n }\n });\n // delete any objects from last round that are no longer used\n for(var k in preserved)\n if(!keep[k]) {\n destroy(k, preserved[k]);\n delete preserved[k];\n }\n return wlist;\n}\n","/**\n * `dc_graph.graphviz_attrs defines a basic set of attributes which layout engines should\n * implement - although these are not required, they make it easier for clients and\n * modes (like expand_collapse) to work with multiple layout engines.\n *\n * these attributes are {@link http://www.graphviz.org/doc/info/attrs.html from graphviz}\n * @class graphviz_attrs\n * @memberof dc_graph\n * @return {Object}\n **/\ndc_graph.graphviz_attrs = function() {\n return {\n /**\n * Direction to draw ranks.\n * @method rankdir\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [rankdir='TB'] 'TB', 'LR', 'BT', or 'RL'\n **/\n rankdir: property('TB'),\n /**\n * Spacing in between nodes in the same rank.\n * @method nodesep\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [nodesep=40]\n **/\n nodesep: property(40),\n /**\n * Spacing in between ranks.\n * @method ranksep\n * @memberof dc_graph.graphviz_attrs\n * @instance\n * @param {String} [ranksep=40]\n **/\n ranksep: property(40)\n };\n};\n\n// graphlib-dot seems to wrap nodes in an extra {value}\n// actually this is quite a common problem with generic libs\nfunction nvalue(n) {\n return n.value.value ? n.value.value : n.value;\n}\n\n// apply standard accessors to a diagram in order to style it as graphviz would\n// this is a work in progress\ndc_graph.apply_graphviz_accessors = function(diagram) {\n diagram\n .nodeLabel(function(n) {\n var label = nvalue(n).label;\n if(label === undefined)\n label = n.key;\n return label && label.split(/\\n|\\\\n/);\n })\n .nodeRadius(function(n) {\n // should do width & height instead, #25\n return nvalue(n).radius || 25;\n })\n .nodeShape(function(n) { return nvalue(n).shape; })\n .nodeFill(function(n) { return nvalue(n).fillcolor || 'white'; })\n .nodeOpacity(function(n) {\n // not standard gv\n return nvalue(n).opacity || 1;\n })\n .nodeLabelFill(function(n) { return nvalue(n).fontcolor || 'black'; })\n .nodeTitle(function(n) {\n return (nvalue(n).htmltip || nvalue(n).jsontip) ? null :\n nvalue(n).tooltip !== undefined ?\n nvalue(n).tooltip :\n diagram.nodeLabel()(n);\n })\n .nodeStrokeWidth(function(n) {\n // it is debatable whether a point === a pixel but they are close\n // https://graphicdesign.stackexchange.com/questions/199/point-vs-pixel-what-is-the-difference\n var penwidth = nvalue(n).penwidth;\n return penwidth !== undefined ? +penwidth : 1;\n })\n .edgeLabel(function(e) { return e.value.label ? e.value.label.split(/\\n|\\\\n/) : ''; })\n .edgeStroke(function(e) { return e.value.color || 'black'; })\n .edgeOpacity(function(e) {\n // not standard gv\n return e.value.opacity || 1;\n })\n .edgeArrowSize(function(e) {\n return e.value.arrowsize || 1;\n })\n // need directedness to default these correctly, see #106\n .edgeArrowhead(function(e) {\n var head = e.value.arrowhead;\n return head !== undefined ? head : 'vee';\n })\n .edgeArrowtail(function(e) {\n var tail = e.value.arrowtail;\n return tail !== undefined ? tail : null;\n })\n .edgeStrokeDashArray(function(e) {\n switch(e.value.style) {\n case 'dotted':\n return [1,5];\n }\n return null;\n });\n var draw_clusters = diagram.child('draw-clusters');\n if(draw_clusters) {\n draw_clusters\n .clusterStroke(function(c) {\n return c.value.color || 'black';\n })\n .clusterFill(function(c) {\n return c.value.style === 'filled' ? c.value.fillcolor || c.value.color || c.value.bgcolor : null;\n })\n .clusterLabel(function(c) {\n return c.value.label;\n });\n }\n};\n\ndc_graph.snapshot_graphviz = function(diagram) {\n var xDomain = diagram.x().domain(), yDomain = diagram.y().domain();\n return {\n nodes: diagram.nodeGroup().all().map(function(n) {\n return diagram.getWholeNode(n.key);\n })\n .filter(function(x) { return x; })\n .map(function(n) {\n return {\n key: diagram.nodeKey.eval(n),\n label: diagram.nodeLabel.eval(n),\n fillcolor: diagram.nodeFillScale()(diagram.nodeFill.eval(n)),\n penwidth: diagram.nodeStrokeWidth.eval(n),\n // not supported as input, see dc.graph.js#25\n // width: n.cola.dcg_rx*2,\n // height: n.cola.dcg_ry*2,\n\n // not graphviz attributes\n // until we have w/h\n radius: diagram.nodeRadius.eval(n),\n // does not seem to exist in gv\n opacity: diagram.nodeOpacity.eval(n),\n // should be pos\n x: n.cola.x,\n y: n.cola.y\n };\n }),\n edges: diagram.edgeGroup().all().map(function(e) {\n return diagram.getWholeEdge(e.key);\n }).map(function(e) {\n return {\n key: diagram.edgeKey.eval(e),\n source: diagram.edgeSource.eval(e),\n target: diagram.edgeTarget.eval(e),\n color: diagram.edgeStroke.eval(e),\n arrowsize: diagram.edgeArrowSize.eval(e),\n opacity: diagram.edgeOpacity.eval(e),\n // should support dir, see dc.graph.js#106\n arrowhead: diagram.edgeArrowhead.eval(e),\n arrowtail: diagram.edgeArrowtail.eval(e)\n };\n }),\n bounds: {\n left: xDomain[0],\n top: yDomain[0],\n right: xDomain[1],\n bottom: yDomain[1]\n }\n };\n};\n","/**\n * `dc_graph.dynagraph_layout` connects to dynagraph-wasm and does dynamic directed graph layout.\n * @class dynagraph_layout\n * @memberof dc_graph\n * @param {String} [id=uuid()] - Unique identifier\n * @return {dc_graph.dynagraph_layout}\n **/\ndc_graph.dynagraph_layout = function(id, layout) {\n var _layoutId = id || uuid();\n const _Gname = _layoutId;\n var _layout;\n var _dispatch = d3.dispatch('tick', 'start', 'end');\n var _tick, _done;\n var _nodes = {}, _edges = {};\n var _linesOut = [], _incrIn = [], _opened = false, _open_graph;\n var _lock = 0;\n\n\n\n let bb = null;\n // dg2incr\n function dg2incr_coord(c) {\n const [x, y] = c;\n return [x, /*(bb && bb[0][1] || 0)*/ - y];\n }\n\n\n function dg2incr_graph_attrs() {\n return [\n ['rankdir', _layout.rankdir()],\n ['resolution', [_layout.resolution().x, _layout.resolution().y]],\n ['defaultsize', [_layout.defaultsize().width, _layout.defaultsize().height]],\n ['separation', [_layout.separation().x, _layout.separation().y]],\n ];\n }\n\n function dg2incr_node_attrs(n) {\n const attr_pairs = [];\n if(n.x !== undefined && n.y !== undefined)\n attr_pairs.push(['pos', dg2incr_coord([n.x, n.y]).map(String).join(',')]);\n return attr_pairs;\n }\n\n function dg2incr_node_attrs_changed(n, n2) {\n const attr_pairs = [];\n if(n2.x !== undefined && n2.y !== undefined && (n2.x !== n.x || n2.y !== n.y))\n attr_pairs.push(['pos', dg2incr_coord([n2.x, n2.y]).map(String).join(',')]);\n return attr_pairs;\n }\n\n function dg2incr_edge_attrs(e) {\n return [];\n }\n\n function mq(x) { // maybe quote\n if(x === +x) // isNumber\n return x;\n else if(/^[A-Za-z_][A-Za-z0-9_]*$/.test(x))\n return x;\n else return '\"' + x + '\"';\n }\n\n function print_incr_attrs(attr_pairs) {\n return '[' + attr_pairs.map(([a,b]) => `${mq(a)}=${mq(b)}`).join(', ') + ']';\n }\n\n // incr2dg\n function incr2dg_coord(c) {\n const [x, y] = c;\n return [+x, /*(bb && bb[0][1] || 0)*/ - y];\n }\n function incr2dg_bb(bb) {\n const [x1,y1,x2,y2] = bb.split(',');\n return [incr2dg_coord([x1,y1]), incr2dg_coord([x2,y2])];\n }\n function incr2dg_node_attrs(n) {\n const attrs = {};\n if(n.pos)\n [attrs.x, attrs.y] = incr2dg_coord(n.pos.split(',').map(Number));\n return attrs;\n }\n function incr2dg_edge_attrs(e) {\n const attrs = {};\n if(e.pos)\n attrs.points = e.pos.split(' ')\n .map(coord => coord.split(',').map(Number))\n .map(incr2dg_coord)\n .map(([x,y]) => ({x,y}));\n return attrs;\n }\n\n function runCommands(cmds) {\n for(const cmd of cmds) {\n const {action, kind} = cmd;\n switch(`${action}_${kind}`) {\n case 'open_graph': {\n const {attrs} = cmd;\n console.log('open graph', attrs);\n console.log('open graph bb', bb)\n bb = incr2dg_bb(attrs.bb)\n console.log('open graph bb', bb)\n break;\n }\n case 'modify_graph': {\n const {attrs} = cmd;\n console.log('modify graph', attrs);\n console.log('modify graph bb', bb)\n bb = incr2dg_bb(attrs.bb)\n console.log('modify graph bb', bb)\n break;\n }\n case 'close_graph': {\n console.log('close graph');\n break;\n }\n case 'insert_node': {\n const {node, attrs} = cmd;\n console.log('insert node', node, attrs);\n console.log('insert node2', _nodes[node])\n Object.assign(_nodes[node], incr2dg_node_attrs(attrs));\n console.log('insert node3', _nodes[node])\n break;\n }\n case 'modify_node': {\n const {node, attrs} = cmd;\n console.log('modify node', node, attrs);\n console.log('modify node2', _nodes[node])\n Object.assign(_nodes[node], incr2dg_node_attrs(attrs));\n console.log('modify node3', _nodes[node])\n break;\n }\n case 'delete_node': {\n const {node} = cmd;\n console.log('delete node', node);\n break;\n }\n case 'insert_edge': {\n const {edge, source, target, attrs} = cmd;\n console.log('insert edge', edge, source, target, attrs);\n console.log('insert edge2', _edges[edge])\n Object.assign(_edges[edge], incr2dg_edge_attrs(attrs));\n console.log('insert edge3', _edges[edge])\n break;\n }\n case 'modify_edge': {\n const {edge, attrs} = cmd;\n console.log('modify edge', edge, attrs);\n console.log('modify edge2', _edges[edge])\n Object.assign(_edges[edge], incr2dg_edge_attrs(attrs));\n console.log('modify edge3', _edges[edge])\n break;\n }\n case 'delete_edge': {\n const {edge} = cmd;\n console.log('delete edge', edge);\n break;\n }\n }\n }\n }\n function receiveIncr(text) {\n console.log(text);\n let cmds = null;\n try {\n const parseIncrface = self.parseIncrface || (self.incrface && self.incrface.parse);\n if(!parseIncrface) {\n console.log('parseIncrface not available, skipping');\n return;\n }\n cmds = parseIncrface(text);\n } catch(xep) {\n console.log('incrface parse failed', xep)\n }\n if (!cmds)\n return;\n for(const cmd of cmds) {\n const {action, kind, graph} = cmd;\n if(action === 'message') {\n console.warn('dynagraph message', cmd.message);\n continue;\n }\n if(graph !== _Gname) {\n console.warn('graph name mismatch', _Gname, graph);\n continue;\n }\n switch(`${action}_${kind}`) {\n case 'lock_graph':\n _lock++;\n break;\n case 'unlock_graph':\n // maybe error on negative lock?\n if(--_lock <= 0) {\n runCommands(_incrIn);\n _incrIn = []\n }\n break;\n default:\n if(_lock > 0)\n _incrIn.push(cmd);\n else\n runCommands([cmd]);\n }\n }\n _done();\n }\n\n function init(options) {\n self.receiveIncr = receiveIncr;\n _opened = false;\n _open_graph = `open graph ${mq(_Gname)} ${print_incr_attrs(dg2incr_graph_attrs())}`\n }\n\n function data(nodes, edges, clusters) {\n const linesOutDeleteNode = [];\n var wnodes = regenerate_objects(_nodes, nodes, null,\n function key(v) {\n return v.dcg_nodeKey;\n }, function assign(v1, v) {\n v1.dcg_nodeKey = v.dcg_nodeKey;\n v1.width = v.width;\n v1.height = v.height;\n if(v.dcg_nodeFixed) {\n v1.x = v.dcg_nodeFixed.x;\n v1.y = v.dcg_nodeFixed.y;\n }\n const na = dg2incr_node_attrs_changed(v1, v);\n if(na.length)\n _linesOut.push(`modify node ${mq(_Gname)} ${mq(v1.dcg_nodeKey)} ${print_incr_attrs(na)}`);\n }, function create(k, o) {\n _linesOut.push(`insert node ${mq(_Gname)} ${mq(k)} ${print_incr_attrs(dg2incr_node_attrs(o))}`);\n }, function destroy(k) {\n linesOutDeleteNode.push(`delete node ${mq(_Gname)} ${mq(k)}`);\n });\n var wedges = regenerate_objects(_edges, edges, null, function key(e) {\n return e.dcg_edgeKey;\n }, function assign(e1, e) {\n e1.dcg_edgeKey = e.dcg_edgeKey;\n e1.dcg_edgeSource = e.dcg_edgeSource;\n e1.dcg_edgeTarget = e.dcg_edgeTarget;\n }, function create(k, o, e) {\n _linesOut.push(`insert edge ${mq(_Gname)} ${mq(k)} ${mq(e.dcg_edgeSource)} ${mq(e.dcg_edgeTarget)} ${print_incr_attrs(dg2incr_edge_attrs(e))}`);\n }, function destroy(k, e) {\n _linesOut.push(`delete edge ${mq(_Gname)} ${k}`);\n });\n _linesOut.push(...linesOutDeleteNode);\n\n function dispatchState(event) {\n _dispatch[event](\n wnodes,\n wedges\n );\n }\n _tick = function() {\n dispatchState('tick');\n };\n _done = function() {\n dispatchState('end');\n };\n }\n\n function start() {\n if(_linesOut.length) {\n const open = _opened ? [] : [_open_graph];\n _opened = true;\n const actions = _linesOut.length > 1 ? [\n `lock graph ${mq(_Gname)}`,\n ... _linesOut,\n `unlock graph ${mq(_Gname)}`\n ] : _linesOut;\n const input = [...open, ...actions].join('\\n');\n console.log('dynagraph input:', input);\n self.incrface_input = input;\n _linesOut = [];\n }\n else _done();\n }\n\n function stop() {\n }\n\n _layout = {\n ...dc_graph.graphviz_attrs(),\n layoutAlgorithm: function() {\n return layout;\n },\n layoutId: function() {\n return _layoutId;\n },\n supportsWebworker: function() {\n return true;\n },\n resolution: property({x: 5, y: 5}),\n defaultsize: property({width: 50, height: 50}),\n separation: property({x: 20, y: 20}),\n on: function(event, f) {\n if(arguments.length === 1)\n return _dispatch.on(event);\n _dispatch.on(event, f);\n return this;\n },\n init: function(options) {\n this.optionNames().forEach(function(option) {\n options[option] = options[option] || this[option]();\n }.bind(this));\n init(options);\n return this;\n },\n data: function(graph, nodes, edges) {\n data(nodes, edges);\n },\n start: function() {\n start();\n },\n stop: function() {\n stop();\n },\n optionNames: function() {\n return ['resolution', 'defaultsize', 'separation'];\n },\n populateLayoutNode: function(layout, node) {},\n populateLayoutEdge: function() {}\n };\n return _layout;\n};\n\ndc_graph.dynagraph_layout.scripts = ['d3.js', 'dynagraph-wasm.js', 'incrface-umd.js'];\n","var _layouts;\n\nfunction postResponse(event, layoutId) {\n return function() {\n var message = {\n response: event,\n layoutId: layoutId\n };\n message.args = Array.prototype.slice.call(arguments);\n postMessage(message);\n };\n}\n\nonmessage = function(e) {\n var args = e.data.args;\n switch(e.data.command) {\n case 'init':\n // find a function under dc_graph that has `scripts`\n var layout_name;\n for(var name in dc_graph) {\n if(typeof dc_graph[name] === 'function' && dc_graph[name].scripts)\n layout_name = name;\n }\n if(!_layouts) {\n _layouts = {};\n importScripts.apply(null, dc_graph[layout_name].scripts);\n if(dc_graph[layout_name].optional_scripts) {\n try {\n importScripts.apply(null, dc_graph[layout_name].optional_scripts);\n }\n catch(xep) {\n console.log(xep);\n }\n }\n }\n\n _layouts[args.layoutId] = dc_graph[layout_name]()\n .on('tick', postResponse('tick', args.layoutId))\n .on('start', postResponse('start', args.layoutId))\n .on('end', postResponse('end', args.layoutId))\n .init(args.options);\n break;\n case 'data':\n if(_layouts)\n _layouts[args.layoutId].data(args.graph, args.nodes, args.edges, args.clusters, args.constraints);\n break;\n case 'start':\n // if(args.initialOnly) {\n // if(args.showLayoutSteps)\n // _tick();\n // _done();\n // }\n // else\n _layouts[args.layoutId].start();\n break;\n case 'stop':\n if(_layouts)\n _layouts[args.layoutId].stop();\n break;\n }\n};\n\n"]} \ No newline at end of file diff --git a/dc.graph.js b/dc.graph.js deleted file mode 100644 index 55e2a880..00000000 --- a/dc.graph.js +++ /dev/null @@ -1,16199 +0,0 @@ -/*! - * dc.graph 0.9.93 - * http://dc-js.github.io/dc.graph.js/ - * Copyright 2015-2019 AT&T Intellectual Property & the dc.graph.js Developers - * https://github.com/dc-js/dc.graph.js/blob/master/AUTHORS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -(function() { function _dc_graph(d3, crossfilter, dc) { -'use strict'; - -/** - * The entire dc.graph.js library is scoped under the **dc_graph** name space. It does not introduce - * anything else into the global name space. - * - * Like in dc.js and most libraries built on d3, most `dc_graph` functions are designed to allow function chaining, meaning they return the current diagram - * instance whenever it is appropriate. The getter forms of functions do not participate in function - * chaining because they return values that are not the diagram. - * @namespace dc_graph - * @version 0.9.93 - * @example - * // Example chaining - * diagram.width(600) - * .height(400) - * .nodeDimension(nodeDim) - * .nodeGroup(nodeGroup); - */ - -var dc_graph = { - version: '0.9.93', - constants: { - CHART_CLASS: 'dc-graph' - } -}; - -function get_original(x) { - return x.orig; -} - -function identity(x) { - return x; -}; - -var property = function (defaultValue, unwrap) { - if(unwrap === undefined) - unwrap = get_original; - else if(unwrap === false) - unwrap = identity; - var value = defaultValue, react = null; - var cascade = []; - var ret = function (_) { - if (!arguments.length) { - return value; - } - if(react) - react(_); - value = _; - return this; - }; - ret.cascade = function (n, f) { - for(var i = 0; i n) { - cascade.splice(i, 0, {n: n, f: f}); - return ret; - } - } - cascade.push({n: n, f: f}); - return ret; - }; - ret._eval = function(o, n) { - if(n===0 || !cascade.length) - return dc_graph.functor_wrap(ret(), unwrap)(o); - else { - var last = cascade[n-1]; - return last.f(o, function() { - return ret._eval(o, n-1); - }); - } - }; - ret.eval = function(o) { - return ret._eval(o, cascade.length); - }; - ret.react = function(_) { - if (!arguments.length) { - return react; - } - react = _; - return this; - }; - return ret; -}; - -function named_children() { - var _children = {}; - var f = function(id, object) { - if(arguments.length === 1) - return _children[id]; - if(f.reject) { - var reject = f.reject(id, object); - if(reject) { - console.groupCollapsed(reject); - console.trace(); - console.groupEnd(); - return this; - } - } - // do not notify unnecessarily - if(_children[id] === object) - return this; - if(_children[id]) - _children[id].parent(null); - _children[id] = object; - if(object) - object.parent(this); - return this; - }; - f.enum = function() { - return Object.keys(_children); - }; - f.nameOf = function(o) { - var found = Object.entries(_children).find(function(kv) { - return kv[1] == o; - }); - return found ? found[0] : null; - }; - return f; -} - -function deprecated_property(message, defaultValue) { - var prop = property(defaultValue); - var ret = function() { - if(arguments.length) { - console.warn(message); - prop.apply(property, arguments); - return this; - } - return prop(); - }; - ['cascade', '_eval', 'eval', 'react'].forEach(function(method) { - ret[method] = prop[method]; - }); - return ret; -} - -function onetime_trace(level, message) { - var said = false; - return function() { - if(said) - return; - if(level === 'trace') { - // todo: implement levels? - // console.groupCollapsed(message); - // console.trace(); - // console.groupEnd(); - } - else - console[level](message); - said = true; - }; -} - -function deprecation_warning(message) { - return onetime_trace('warn', message); -} - -function trace_function(level, message, f) { - var dep = onetime_trace(level, message); - return function() { - dep(); - return f.apply(this, arguments); - }; -} -function deprecate_function(message, f) { - return trace_function('warn', message, f); -} - -// http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript -function uuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); - return v.toString(16); - }); -} - -function is_ie() { - var ua = window.navigator.userAgent; - - return(ua.indexOf('MSIE ') > 0 || - ua.indexOf('Trident/') > 0 || - ua.indexOf('Edge/') > 0); -} - -function is_safari() { - return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); -} - -// polyfill Object.assign for IE -// it's just too useful to do without -if (typeof Object.assign != 'function') { - // Must be writable: true, enumerable: false, configurable: true - Object.defineProperty(Object, "assign", { - value: function assign(target, varArgs) { // .length of function is 2 - 'use strict'; - if (target == null) { // TypeError if undefined or null - throw new TypeError('Cannot convert undefined or null to object'); - } - - var to = Object(target); - - for (var index = 1; index < arguments.length; index++) { - var nextSource = arguments[index]; - - if (nextSource != null) { // Skip over if undefined or null - for (var nextKey in nextSource) { - // Avoid bugs when hasOwnProperty is shadowed - if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { - to[nextKey] = nextSource[nextKey]; - } - } - } - } - return to; - }, - writable: true, - configurable: true - }); -} - - -// https://tc39.github.io/ecma262/#sec-array.prototype.includes -if (!Array.prototype.includes) { - Object.defineProperty(Array.prototype, 'includes', { - value: function(valueToFind, fromIndex) { - - if (this == null) { - throw new TypeError('"this" is null or not defined'); - } - - // 1. Let O be ? ToObject(this value). - var o = Object(this); - - // 2. Let len be ? ToLength(? Get(O, "length")). - var len = o.length >>> 0; - - // 3. If len is 0, return false. - if (len === 0) { - return false; - } - - // 4. Let n be ? ToInteger(fromIndex). - // (If fromIndex is undefined, this step produces the value 0.) - var n = fromIndex | 0; - - // 5. If n >= 0, then - // a. Let k be n. - // 6. Else n < 0, - // a. Let k be len + n. - // b. If k < 0, let k be 0. - var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); - - function sameValueZero(x, y) { - return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y)); - } - - // 7. Repeat, while k < len - while (k < len) { - // a. Let elementK be the result of ? Get(O, ! ToString(k)). - // b. If SameValueZero(valueToFind, elementK) is true, return true. - if (sameValueZero(o[k], valueToFind)) { - return true; - } - // c. Increase k by 1. - k++; - } - - // 8. Return false - return false; - } - }); -} - -if (!Object.entries) { - Object.entries = function( obj ){ - var ownProps = Object.keys( obj ), - i = ownProps.length, - resArray = new Array(i); // preallocate the Array - while (i--) - resArray[i] = [ownProps[i], obj[ownProps[i]]]; - return resArray; - }; -} - -// https://github.com/KhaledElAnsari/Object.values -Object.values = Object.values ? Object.values : function(obj) { - var allowedTypes = ["[object String]", "[object Object]", "[object Array]", "[object Function]"]; - var objType = Object.prototype.toString.call(obj); - - if(obj === null || typeof obj === "undefined") { - throw new TypeError("Cannot convert undefined or null to object"); - } else if(!~allowedTypes.indexOf(objType)) { - return []; - } else { - // if ES6 is supported - if (Object.keys) { - return Object.keys(obj).map(function (key) { - return obj[key]; - }); - } - - var result = []; - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - result.push(obj[prop]); - } - } - - return result; - } -}; - -function getBBoxNoThrow(elem) { - // firefox seems to have issues with some of my texts - // just catch for now - try { - return elem.getBBox(); - } catch(xep) { - return {x: 0, y: 0, width:0, height: 0}; - } -} - -function property_if(pred, curr) { - return function(o, last) { - return pred(o) ? curr(o) : last(); - }; -} - -function property_interpolate(value, curr) { - return function(o, last) { - return d3.interpolate(last(o), curr(o))(value(o)); - }; -} - -function multiply_properties(pred, props, blend) { - var props2 = {}; - for(var p in props) - props2[p] = blend(pred, param(props[p])); - return props2; -} - -function conditional_properties(pred, props) { - return multiply_properties(pred, props, property_if); -} - -function node_edge_conditions(npred, epred, props) { - var nprops = {}, eprops = {}, badprops = []; - for(var p in props) { - if(/^node/.test(p)) - nprops[p] = props[p]; - else if(/^edge/.test(p)) - eprops[p] = props[p]; - else badprops.push(p); - } - if(badprops.length) - console.error('only know how to deal with properties that start with "node" or "edge"', badprops); - var props2 = npred ? conditional_properties(npred, nprops) : {}; - if(epred) - Object.assign(props2, conditional_properties(epred, eprops)); - return props2; -} - -function cascade(parent) { - return function(level, add, props) { - for(var p in props) { - if(!parent[p]) - throw new Error('unknown attribute ' + p); - parent[p].cascade(level, add ? props[p] : null); - } - return parent; - }; -} - -function compose(f, g) { - return function() { - return f(g.apply(null, arguments)); - }; -} - -// version of d3.functor that optionally wraps the function with another -// one, if the parameter is a function -dc_graph.functor_wrap = function (v, wrap) { - if(typeof v === "function") { - return wrap ? function(x) { - return v(wrap(x)); - } : v; - } - else return function() { - return v; - }; -}; - -// we want to allow either values or functions to be passed to specify parameters. -// if a function, the function needs a preprocessor to extract the original key/value -// pair from the wrapper object we put it in. -function param(v) { - return dc_graph.functor_wrap(v, get_original); -} - -// http://jsperf.com/cloning-an-object/101 -function clone(obj) { - var target = {}; - for(var i in obj) { - if(obj.hasOwnProperty(i)) { - target[i] = obj[i]; - } - } - return target; -} - -// because i don't think we need to bind edge point data (yet!) -var bez_cmds = { - 1: 'L', 2: 'Q', 3: 'C' -}; - -function generate_path(pts, bezDegree, close) { - var cats = ['M', pts[0].x, ',', pts[0].y], remain = bezDegree; - var hasNaN = false; - for(var i = 1; i < pts.length; ++i) { - if(isNaN(pts[i].x) || isNaN(pts[i].y)) - hasNaN = true; - cats.push(remain===bezDegree ? bez_cmds[bezDegree] : ' ', pts[i].x, ',', pts[i].y); - if(--remain===0) - remain = bezDegree; - } - if(remain!=bezDegree) - console.log("warning: pts.length didn't match bezian degree", pts, bezDegree); - if(close) - cats.push('Z'); - return cats.join(''); -} - -// for IE (do we care really?) -Math.hypot = Math.hypot || function() { - var y = 0; - var length = arguments.length; - - for (var i = 0; i < length; i++) { - if (arguments[i] === Infinity || arguments[i] === -Infinity) { - return Infinity; - } - y += arguments[i] * arguments[i]; - } - return Math.sqrt(y); -}; - -// outputs the array with adjacent identical lines collapsed to one -function uniq(a) { - var ret = []; - a.forEach(function(x, i) { - if(i === 0 || x !== a[i-1]) - ret.push(x); - }); - return ret; -} - -// https://tc39.github.io/ecma262/#sec-array.prototype.find -if (!Array.prototype.find) { - Object.defineProperty(Array.prototype, 'find', { - value: function(predicate) { - // 1. Let O be ? ToObject(this value). - if (this == null) { - throw new TypeError('"this" is null or not defined'); - } - - var o = Object(this); - - // 2. Let len be ? ToLength(? Get(O, "length")). - var len = o.length >>> 0; - - // 3. If IsCallable(predicate) is false, throw a TypeError exception. - if (typeof predicate !== 'function') { - throw new TypeError('predicate must be a function'); - } - - // 4. If thisArg was supplied, let T be thisArg; else let T be undefined. - var thisArg = arguments[1]; - - // 5. Let k be 0. - var k = 0; - - // 6. Repeat, while k < len - while (k < len) { - // a. Let Pk be ! ToString(k). - // b. Let kValue be ? Get(O, Pk). - // c. Let testResult be ToBoolean(? Call(predicate, T, << kValue, k, O >>)). - // d. If testResult is true, return kValue. - var kValue = o[k]; - if (predicate.call(thisArg, kValue, k, o)) { - return kValue; - } - // e. Increase k by 1. - k++; - } - - // 7. Return undefined. - return undefined; - } - }); -} - -var script_path = function() { - var _path; - return function() { - if(_path === undefined) { - // adapted from http://stackoverflow.com/a/18283141/676195 - _path = null; // only try once - var filename = 'dc.graph.js'; - var scripts = document.getElementsByTagName('script'); - if (scripts && scripts.length > 0) { - for (var i in scripts) { - if (scripts[i].src && scripts[i].src.match(new RegExp(filename+'$'))) { - _path = scripts[i].src.replace(new RegExp('(.*)'+filename+'$'), '$1'); - break; - } - } - } - } - return _path; - }; -}(); - -dc_graph.event_coords = function(diagram) { - var bound = diagram.root().node().getBoundingClientRect(); - return diagram.invertCoord([d3.event.clientX - bound.left, - d3.event.clientY - bound.top]); -}; - -function promise_identity(x) { - return Promise.resolve(x); -} - -// http://stackoverflow.com/questions/7044944/jquery-javascript-to-detect-os-without-a-plugin -var is_a_mac = navigator.platform.toUpperCase().indexOf('MAC')!==-1; - -// https://stackoverflow.com/questions/16863917/check-if-class-exists-somewhere-in-parent-vanilla-js -function ancestor_has_class(element, classname) { - if(d3.select(element).classed(classname)) - return true; - return element.parentElement && ancestor_has_class(element.parentElement, classname); -} - -if (typeof SVGElement.prototype.contains == 'undefined') { - SVGElement.prototype.contains = HTMLDivElement.prototype.contains; -} - -// arguably depth first search is a stupid algorithm to modularize - -// there are many, many interesting moments to insert a behavior -// and those end up being almost bigger than the function itself - -// this is an argument for providing a graph API which could make it -// easy to just write a recursive function instead of using this -dc_graph.depth_first_traversal = function(callbacks) { // {[init, root, row, tree, place, sib, push, pop, skip,] finish, nodeid, sourceid, targetid} - return function(nodes, edges) { - callbacks.init && callbacks.init(); - if(callbacks.tree) - edges = edges.filter(function(e) { return callbacks.tree(e); }); - var indegree = {}; - var outmap = edges.reduce(function(m, e) { - var tail = callbacks.sourceid(e), - head = callbacks.targetid(e); - if(!m[tail]) m[tail] = []; - m[tail].push(e); - indegree[head] = (indegree[head] || 0) + 1; - return m; - }, {}); - var nmap = nodes.reduce(function(m, n) { - var key = callbacks.nodeid(n); - m[key] = n; - return m; - }, {}); - - var rows = []; - var placed = {}; - function place_tree(n, r) { - var key = callbacks.nodeid(n); - if(placed[key]) { - callbacks.skip && callbacks.skip(n, indegree[key]); - return; - } - if(!rows[r]) - rows[r] = []; - callbacks.place && callbacks.place(n, r, rows[r]); - rows[r].push(n); - placed[key] = true; - if(outmap[key]) - outmap[key].forEach(function(e, ei) { - var target = nmap[callbacks.targetid(e)]; - if(ei && callbacks.sib) - callbacks.sib(false, nmap[callbacks.targetid(outmap[key][ei-1])], target); - callbacks.push && callbacks.push(); - place_tree(target, r+1); - }); - callbacks.pop && callbacks.pop(n); - } - - var roots; - if(callbacks.root) - roots = nodes.filter(function(n) { return callbacks.root(n); }); - else { - roots = nodes.filter(function(n) { return !indegree[callbacks.nodeid(n)]; }); - if(nodes.length && !roots.length) // all nodes are in a cycle - roots = [nodes[0]]; - } - roots.forEach(function(n, ni) { - if(ni && callbacks.sib) - callbacks.sib(true, roots[ni-1], n); - callbacks.push && callbacks.push(); - place_tree(n, callbacks.row && callbacks.row(n) || 0); - }); - callbacks.finish(rows); - }; -}; - -// basically, see if it's any simpler if we start from scratch -// (well, of course it's simpler because we have less callbacks) -// same caveats as above -dc_graph.undirected_dfs = function(callbacks) { // {[comp, node], nodeid, sourceid, targetid} - return function(nodes, edges) { - var adjacencies = edges.reduce(function(m, e) { - var tail = callbacks.sourceid(e), - head = callbacks.targetid(e); - if(!m[tail]) m[tail] = []; - if(!m[head]) m[head] = []; - m[tail].push(head); - m[head].push(tail); - return m; - }, {}); - var nmap = nodes.reduce(function(m, n) { - var key = callbacks.nodeid(n); - m[key] = n; - return m; - }, {}); - var found = {}; - function recurse(n) { - var nid = callbacks.nodeid(n); - callbacks.node(compid, n); - found[nid] = true; - if(adjacencies[nid]) - adjacencies[nid].forEach(function(adj) { - if(!found[adj]) - recurse(nmap[adj]); - }); - } - var compid = 0; - nodes.forEach(function(n) { - if(!found[callbacks.nodeid(n)]) { - callbacks.comp && callbacks.comp(compid); - recurse(n); - ++compid; - } - }); - }; -}; - -// create or re-use objects in a map, delete the ones that were not reused -function regenerate_objects(preserved, list, need, key, assign, create, destroy) { - if(!create) create = function(k, o) { }; - if(!destroy) destroy = function(k) { }; - var keep = {}; - function wrap(o) { - var k = key(o); - if(!preserved[k]) - create(k, preserved[k] = {}, o); - var o1 = preserved[k]; - assign(o1, o); - keep[k] = true; - return o1; - } - var wlist = list.map(wrap); - if(need) - need.forEach(function(k) { - if(!preserved[k]) { // hasn't been created, needs to be - create(k, preserved[k] = {}, null); - assign(preserved[k], null); - } - if(!keep[k]) { // wasn't in list, should be - wlist.push(preserved[k]); - keep[k] = true; - } - }); - // delete any objects from last round that are no longer used - for(var k in preserved) - if(!keep[k]) { - destroy(k, preserved[k]); - delete preserved[k]; - } - return wlist; -} - -function point_on_ellipse(A, B, dx, dy) { - var tansq = Math.tan(Math.atan2(dy, dx)); - tansq = tansq*tansq; // why is this not just dy*dy/dx*dx ? ? - var ret = {x: A*B/Math.sqrt(B*B + A*A*tansq), y: A*B/Math.sqrt(A*A + B*B/tansq)}; - if(dx<0) - ret.x = -ret.x; - if(dy<0) - ret.y = -ret.y; - return ret; -} - -var eps = 0.0000001; -function between(a, b, c) { - return a-eps <= b && b <= c+eps; -} - -// Adapted from http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect/1968345#1968345 -function segment_intersection(x1,y1,x2,y2, x3,y3,x4,y4) { - var x=((x1*y2-y1*x2)*(x3-x4)-(x1-x2)*(x3*y4-y3*x4)) / - ((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)); - var y=((x1*y2-y1*x2)*(y3-y4)-(y1-y2)*(x3*y4-y3*x4)) / - ((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)); - if (isNaN(x)||isNaN(y)) { - return false; - } else { - if (x1>=x2) { - if (!between(x2, x, x1)) {return false;} - } else { - if (!between(x1, x, x2)) {return false;} - } - if (y1>=y2) { - if (!between(y2, y, y1)) {return false;} - } else { - if (!between(y1, y, y2)) {return false;} - } - if (x3>=x4) { - if (!between(x4, x, x3)) {return false;} - } else { - if (!between(x3, x, x4)) {return false;} - } - if (y3>=y4) { - if (!between(y4, y, y3)) {return false;} - } else { - if (!between(y3, y, y4)) {return false;} - } - } - return {x: x, y: y}; -} - - -function point_on_polygon(points, x0, y0, x1, y1) { - for(var i = 0; i < points.length; ++i) { - var next = i===points.length-1 ? 0 : i+1; - var isect = segment_intersection(points[i].x, points[i].y, points[next].x, points[next].y, - x0, y0, x1, y1); - if(isect) - return isect; - } - return null; -} - -// as many as we can get from -// http://www.graphviz.org/doc/info/shapes.html -dc_graph.shape_presets = { - egg: { - // not really: an ovoid should be two half-ellipses stuck together - // https://en.wikipedia.org/wiki/Oval - generator: 'polygon', - preset: function() { - return {sides: 100, distortion: -0.25}; - } - }, - triangle: { - generator: 'polygon', - preset: function() { - return {sides: 3}; - } - }, - rectangle: { - generator: 'polygon', - preset: function() { - return {sides: 4}; - } - }, - diamond: { - generator: 'polygon', - preset: function() { - return {sides: 4, rotation: 45}; - } - }, - trapezium: { - generator: 'polygon', - preset: function() { - return {sides: 4, distortion: -0.5}; - } - }, - parallelogram: { - generator: 'polygon', - preset: function() { - return {sides: 4, skew: 0.5}; - } - }, - pentagon: { - generator: 'polygon', - preset: function() { - return {sides: 5}; - } - }, - hexagon: { - generator: 'polygon', - preset: function() { - return {sides: 6}; - } - }, - septagon: { - generator: 'polygon', - preset: function() { - return {sides: 7}; - } - }, - octagon: { - generator: 'polygon', - preset: function() { - return {sides: 8}; - } - }, - invtriangle: { - generator: 'polygon', - preset: function() { - return {sides: 3, rotation: 180}; - } - }, - invtrapezium: { - generator: 'polygon', - preset: function() { - return {sides: 4, distortion: 0.5}; - } - }, - square: { - generator: 'polygon', - preset: function() { - return { - sides: 4, - regular: true - }; - } - }, - plain: { - generator: 'rounded-rect', - preset: function() { - return { - noshape: true - }; - } - }, - house: { - generator: 'elaborated-rect', - preset: function() { - return { - get_points: function(rx, ry) { - return [ - {x: rx, y: ry*2/3}, - {x: rx, y: -ry/2}, - {x: 0, y: -ry}, - {x: -rx, y: -ry/2}, - {x: -rx, y: ry*2/3} - ]; - }, - minrx: 30 - }; - } - }, - invhouse: { - generator: 'elaborated-rect', - preset: function() { - return { - get_points: function(rx, ry) { - return [ - {x: rx, y: ry/2}, - {x: rx, y: -ry*2/3}, - {x: -rx, y: -ry*2/3}, - {x: -rx, y: ry/2}, - {x: 0, y: ry} - ]; - }, - minrx: 30 - }; - } - }, - rarrow: { - generator: 'elaborated-rect', - preset: function() { - return { - get_points: function(rx, ry) { - return [ - {x: rx, y: ry}, - {x: rx, y: ry*1.5}, - {x: rx + ry*1.5, y: 0}, - {x: rx, y: -ry*1.5}, - {x: rx, y: -ry}, - {x: -rx, y: -ry}, - {x: -rx, y: ry} - ]; - }, - minrx: 30 - }; - } - }, - larrow: { - generator: 'elaborated-rect', - preset: function() { - return { - get_points: function(rx, ry) { - return [ - {x: -rx, y: ry}, - {x: -rx, y: ry*1.5}, - {x: -rx - ry*1.5, y: 0}, - {x: -rx, y: -ry*1.5}, - {x: -rx, y: -ry}, - {x: rx, y: -ry}, - {x: rx, y: ry} - ]; - }, - minrx: 30 - }; - } - }, - rpromoter: { - generator: 'elaborated-rect', - preset: function() { - return { - get_points: function(rx, ry) { - return [ - {x: rx, y: ry}, - {x: rx, y: ry*1.5}, - {x: rx + ry*1.5, y: 0}, - {x: rx, y: -ry*1.5}, - {x: rx, y: -ry}, - {x: -rx, y: -ry}, - {x: -rx, y: ry*1.5}, - {x: 0, y: ry*1.5}, - {x: 0, y: ry}, - ]; - }, - minrx: 30 - }; - } - }, - lpromoter: { - generator: 'elaborated-rect', - preset: function() { - return { - get_points: function(rx, ry) { - return [ - {x: -rx, y: ry}, - {x: -rx, y: ry*1.5}, - {x: -rx - ry*1.5, y: 0}, - {x: -rx, y: -ry*1.5}, - {x: -rx, y: -ry}, - {x: rx, y: -ry}, - {x: rx, y: ry*1.5}, - {x: 0, y: ry*1.5}, - {x: 0, y: ry} - ]; - }, - minrx: 30 - }; - } - }, - cds: { - generator: 'elaborated-rect', - preset: function() { - return { - get_points: function(rx, ry) { - return [ - {x: rx, y: ry}, - {x: rx + ry, y: 0}, - {x: rx, y: -ry}, - {x: -rx, y: -ry}, - {x: -rx, y: ry} - ]; - }, - minrx: 30 - }; - } - }, -}; - -dc_graph.shape_presets.box = dc_graph.shape_presets.rect = dc_graph.shape_presets.rectangle; - -dc_graph.available_shapes = function() { - var shapes = Object.keys(dc_graph.shape_presets); - return shapes.slice(0, shapes.length-1); // not including polygon -}; - -var default_shape = {shape: 'ellipse'}; - -function normalize_shape_def(diagram, n) { - var def = diagram.nodeShape.eval(n); - if(!def) - def = {...default_shape}; - else if(typeof def === 'string') - def = {shape: def}; - def.nodeOutlineClip = diagram.nodeOutlineClip.eval(n); - return def; -} - -function elaborate_shape(diagram, def) { - var shape = def.shape, def2 = Object.assign({}, def); - delete def2.shape; - if(shape === 'random') { - var available = dc_graph.available_shapes(); // could include diagram.shape !== ellipse, polygon - shape = available[Math.floor(Math.random()*available.length)]; - } - else if(diagram.shape.enum().indexOf(shape) !== -1) - return diagram.shape(shape).elaborate({shape: shape}, def2); - if(!dc_graph.shape_presets[shape]) { - console.warn('unknown shape ', shape); - return default_shape; - } - var preset = dc_graph.shape_presets[shape].preset(def2); - preset.shape = dc_graph.shape_presets[shape].generator; - return diagram.shape(preset.shape).elaborate(preset, def2); -} - -function infer_shape(diagram) { - return function(n) { - var def = normalize_shape_def(diagram, n); - n.dcg_shape = elaborate_shape(diagram, def); - n.dcg_shape.abstract = def; - }; -} - -function shape_changed(diagram) { - return function(n) { - var def = normalize_shape_def(diagram, n); - var old = n.dcg_shape.abstract; - if(def.shape !== old.shape) - return true; - else if(def.nodeOutlineClip !== old.nodeOutlineClip) - return true; - else if(def.shape === 'polygon') { - return def.shape.sides !== old.sides || def.shape.skew !== old.skew || - def.shape.distortion !== old.distortion || def.shape.rotation !== old.rotation; - } - else return false; - }; -} - -function node_label_padding(diagram, n) { - var nlp = diagram.nodeLabelPadding.eval(n); - if(typeof nlp === 'number' || typeof nlp === 'string') - return {x: +nlp, y: +nlp}; - else return nlp; -} - -function fit_shape(shape, diagram) { - return function(content) { - content.each(function(n) { - var bbox = null; - if((!shape.useTextSize || shape.useTextSize(n.dcg_shape)) && diagram.nodeFitLabel.eval(n)) { - bbox = getBBoxNoThrow(this); - bbox = {x: bbox.x, y: bbox.y, width: bbox.width, height: bbox.height}; - var padding; - var content = diagram.nodeContent.eval(n); - if(content && diagram.content(content).padding) - padding = diagram.content(content).padding(n); - else { - var padding2 = node_label_padding(diagram, n); - padding = { - x: padding2.x*2, - y: padding2.y*2 - }; - } - bbox.width += padding.x; - bbox.height += padding.y; - n.bbox = bbox; - } - var r = 0, radii; - if(!shape.useRadius || shape.useRadius(n.dcg_shape)) - r = diagram.nodeRadius.eval(n); - if(bbox && bbox.width && bbox.height || shape.useTextSize && !shape.useTextSize(n.dcg_shape)) - radii = shape.calc_radii(n, r, bbox); - else - radii = {rx: r, ry: r}; - n.dcg_rx = radii.rx; - n.dcg_ry = radii.ry; - - var w = radii.rx*2, h = radii.ry*2; - // fixme: this is only consistent if regular || !squeeze - // but we'd need to calculate polygon first in order to find out - // (not a bad idea, just no time right now) - // if(w= 0) - throw new Error("f(a) must be less than 0"); - if(f(b).val <= 0) - throw new Error("f(b) must be greater than 0"); - while(true) { - if(!--patience) - throw new Error("patience ran out"); - var c = (a+b)/2, - f_c = f(c), fv = f_c.val; - if(Math.abs(fv) < 0.5) - return f_c; - if(fv > 0) - b = c; - else - a = c; - } -} - -function draw_edge_to_shapes(diagram, e, sx, sy, tx, ty, - neighbor, dir, offset, source_padding, target_padding) { - var deltaX, deltaY, - sp, tp, points, bezDegree, - headAng, retPath; - if(!neighbor) { - sp = e.sourcePort.pos; - tp = e.targetPort.pos; - if(!sp) sp = {x: 0, y: 0}; - if(!tp) tp = {x: 0, y: 0}; - points = [{ - x: sx + sp.x, - y: sy + sp.y - }, { - x: tx + tp.x, - y: ty + tp.y - }]; - bezDegree = 1; - } - else { - var p_on_s = function(node, ang) { - return diagram.shape(node.dcg_shape.shape).intersect_vec(node, Math.cos(ang)*1000, Math.sin(ang)*1000); - }; - var compare_dist = function(node, port0, goal) { - return function(ang) { - var port = p_on_s(node, ang); - if(!port) - return { - port: {x: 0, y: 0}, - val: 0, - ang: ang - }; - else - return { - port: port, - val: Math.hypot(port.x - port0.x, port.y - port0.y) - goal, - ang: ang - }; - }; - }; - var srcang = Math.atan2(neighbor.sourcePort.y, neighbor.sourcePort.x), - tarang = Math.atan2(neighbor.targetPort.y, neighbor.targetPort.x); - var bss, bst; - - // don't like this but throwing is unacceptable - try { - bss = binary_search(compare_dist(e.source, neighbor.sourcePort, offset), - srcang, srcang + 2 * dir * offset / source_padding); - } - catch(x) { - bss = {ang: srcang, port: neighbor.sourcePort}; - } - try { - bst = binary_search(compare_dist(e.target, neighbor.targetPort, offset), - tarang, tarang - 2 * dir * offset / source_padding); - } - catch(x) { - bst = {ang: tarang, port: neighbor.targetPort}; - } - - sp = bss.port; - tp = bst.port; - var sdist = Math.hypot(sp.x, sp.y), - tdist = Math.hypot(tp.x, tp.y), - c1dist = sdist+source_padding/2, - c2dist = tdist+target_padding/2; - var c1X = sx + c1dist * Math.cos(bss.ang), - c1Y = sy + c1dist * Math.sin(bss.ang), - c2X = tx + c2dist * Math.cos(bst.ang), - c2Y = ty + c2dist * Math.sin(bst.ang); - points = [ - {x: sx + sp.x, y: sy + sp.y}, - {x: c1X, y: c1Y}, - {x: c2X, y: c2Y}, - {x: tx + tp.x, y: ty + tp.y} - ]; - bezDegree = 3; - } - return { - sourcePort: sp, - targetPort: tp, - points: points, - bezDegree: bezDegree - }; -} - -function is_one_segment(path) { - return path.bezDegree === 1 && path.points.length === 2 || - path.bezDegree === 3 && path.points.length === 4; -} - -function as_bezier3(path) { - var p = path.points; - if(path.bezDegree === 3) return p; - else if(path.bezDegree === 1) - return [ - { - x: p[0].x, - y: p[0].y - }, - { - x: p[0].x + (p[1].x - p[0].x)/3, - y: p[0].y + (p[1].y - p[0].y)/3 - }, - { - x: p[0].x + 2*(p[1].x - p[0].x)/3, - y: p[0].y + 2*(p[1].y - p[0].y)/3 - }, - { - x: p[1].x, - y: p[1].y - } - ]; - else throw new Error('unknown bezDegree ' + path.bezDegree); -} - -// from https://www.jasondavies.com/animated-bezier/ -function interpolate(d, p) { - var r = []; - for (var i=1; i 1) { - var parts = split_bezier(p, 1/n); - ret.push(parts[0][0], parts[0][1], parts[0][2]); - p = parts[1]; - --n; - } - ret.push.apply(ret, p); - return ret; -} - -// binary search for a point along a bezier that is a certain distance from one of the end points -// return the bezier cut at that point. -function chop_bezier(points, end, dist) { - var EPS = 0.1, dist2 = dist*dist; - var ref, dir, segment; - if(end === 'head') { - ref = points[points.length-1]; - segment = points.slice(points.length-4); - dir = -1; - } else { - ref = points[0]; - segment = points.slice(0, 4); - dir = 1; - } - var parts, d2, t = 0.5, dt = 0.5, dx, dy; - do { - parts = split_bezier(segment, t); - dx = ref.x - parts[1][0].x; - dy = ref.y - parts[1][0].y; - d2 = dx*dx + dy*dy; - dt /= 2; - if(d2 > dist2) - t -= dt*dir; - else - t += dt*dir; - //console.log('dist', dist, 'dir', dir, 'd', d, 't', t, 'dt', dt); - } - while(dt > 0.0000001 && Math.abs(d2 - dist2) > EPS); - points = points.slice(); - if(end === 'head') - return points.slice(0, points.length-4).concat(parts[0]); - else - return parts[1].concat(points.slice(4)); -} - -function angle_between_points(p0, p1) { - return Math.atan2(p1.y - p0.y, p1.x - p0.x); -} - -dc_graph.no_shape = function() { - var _shape = { - parent: property(null), - elaborate: function(preset, def) { - return Object.assign(preset, def); - }, - useTextSize: function() { return false; }, - useRadius: function() { return false; }, - usePaddingAndStroke: function() { return false; }, - intersect_vec: function(n, deltaX, deltaY) { - return {x: 0, y: 0}; - }, - calc_radii: function(n, ry, bbox) { - return {rx: 0, ry: 0}; - }, - create: function(nodeEnter) { - }, - replace: function(nodeChanged) { - }, - update: function(node) { - } - }; - return _shape; -}; - -function create_maybe_clipped(diagram, nodeEnter, element) { - const clipped = nodeEnter.filter(n => diagram.nodeOutlineClip.eval(n)); - const unclipped = nodeEnter.filter(n => !diagram.nodeOutlineClip.eval(n)); - clipped.insert(element, ':first-child') - .attr('class', 'node-outline') - .attr('fill', 'none') - .attr('clip-path', n => `url(#node-clip-${diagram.nodeOutlineClip.eval(n)})`); - clipped.insert(element, ':first-child') - .attr('class', 'node-fill'); - unclipped.insert(element, ':first-child') - .attr('class', 'node-outline node-fill'); -} - -dc_graph.ellipse_shape = function() { - var _shape = { - parent: property(null), - elaborate: function(preset, def) { - return Object.assign(preset, def); - }, - intersect_vec: function(n, deltaX, deltaY) { - return point_on_ellipse(n.dcg_rx, n.dcg_ry, deltaX, deltaY); - }, - calc_radii: function(n, ry, bbox) { - // make sure we can fit height in r - ry = Math.max(ry, bbox.height/2 + 5); - var rx = bbox.width/2; - - // solve (x/A)^2 + (y/B)^2) = 1 for A, with B=r, to fit text in ellipse - // http://stackoverflow.com/a/433438/676195 - var y_over_B = bbox.height/2/ry; - rx = rx/Math.sqrt(1 - y_over_B*y_over_B); - rx = Math.max(rx, ry); - - return {rx: rx, ry: ry}; - }, - create: function(nodeEnter) { - create_maybe_clipped(_shape.parent(), nodeEnter, 'ellipse'); - }, - update: function(node) { - node.selectAll('ellipse.node-fill,ellipse.node-outline') - .attr(ellipse_attrs(_shape.parent())); - } - }; - return _shape; -}; - -dc_graph.polygon_shape = function() { - var _shape = { - parent: property(null), - elaborate: function(preset, def) { - return Object.assign(preset, def); - }, - intersect_vec: function(n, deltaX, deltaY) { - return point_on_polygon(n.dcg_points, 0, 0, deltaX, deltaY); - }, - calc_radii: function(n, ry, bbox) { - // make sure we can fit height in r - ry = Math.max(ry, bbox.height/2 + 5); - var rx = bbox.width/2; - - // this is cribbed from graphviz but there is much i don't understand - // and any errors are mine - // https://github.com/ellson/graphviz/blob/6acd566eab716c899ef3c4ddc87eceb9b428b627/lib/common/shapes.c#L1996 - rx = rx*Math.sqrt(2)/Math.cos(Math.PI/(n.dcg_shape.sides||4)); - - return {rx: rx, ry: ry}; - }, - create: function(nodeEnter) { - create_maybe_clipped(_shape.parent(), nodeEnter, 'path'); - }, - update: function(node) { - node.selectAll('path.node-fill,path.node-outline') - .attr(polygon_attrs(_shape.parent())); - } - }; - return _shape; -}; - -dc_graph.rounded_rectangle_shape = function() { - var _shape = { - parent: property(null), - elaborate: function(preset, def) { - preset = Object.assign({rx: 10, ry: 10}, preset); - return Object.assign(preset, def); - }, - intersect_vec: function(n, deltaX, deltaY) { - var points = [ - {x: n.dcg_rx, y: n.dcg_ry}, - {x: n.dcg_rx, y: -n.dcg_ry}, - {x: -n.dcg_rx, y: -n.dcg_ry}, - {x: -n.dcg_rx, y: n.dcg_ry} - ]; - return point_on_polygon(points, 0, 0, deltaX, deltaY); // not rounded - }, - useRadius: function(shape) { - return !shape.noshape; - }, - calc_radii: function(n, ry, bbox) { - var fity = bbox.height/2; - // fixme: fudge to make sure text is not too tall for node - if(!n.dcg_shape.noshape) - fity += 5; - return { - rx: bbox.width / 2, - ry: Math.max(ry, fity) - }; - }, - create: function(nodeEnter) { - create_maybe_clipped(_shape.parent(), nodeEnter.filter(function(n) { - return !n.dcg_shape.noshape; - }), 'rect'); - }, - update: function(node) { - node.selectAll('rect.node-fill,rect.node-outline') - .attr({ - x: function(n) { - return -n.dcg_rx; - }, - y: function(n) { - return -n.dcg_ry; - }, - width: function(n) { - return 2*n.dcg_rx; - }, - height: function(n) { - return 2*n.dcg_ry; - }, - rx: function(n) { - return n.dcg_shape.rx + 'px'; - }, - ry: function(n) { - return n.dcg_shape.ry + 'px'; - } - }); - } - }; - return _shape; -}; - -// this is not all that accurate - idea is that arrows, houses, etc, are rectangles -// in terms of sizing, but elaborated drawing & clipping. refine until done. -dc_graph.elaborated_rectangle_shape = function() { - var _shape = dc_graph.rounded_rectangle_shape(); - _shape.intersect_vec = function(n, deltaX, deltaY) { - var points = n.dcg_shape.get_points(n.dcg_rx, n.dcg_ry); - return point_on_polygon(points, 0, 0, deltaX, deltaY); - }; - delete _shape.useRadius; - var orig_radii = _shape.calc_radii; - _shape.calc_radii = function(n, ry, bbox) { - var ret = orig_radii(n, ry, bbox); - return { - rx: Math.max(ret.rx, n.dcg_shape.minrx), - ry: ret.ry - }; - }; - _shape.create = function(nodeEnter) { - create_maybe_clipped(_shape.parent(), nodeEnter, 'path'); - }; - _shape.update = function(node) { - node.selectAll('path.node-fill,path.node-outline') - .attr('d', function(n) { - return generate_path(n.dcg_shape.get_points(n.dcg_rx, n.dcg_ry), 1, true); - }); - }; - return _shape; -}; - - -function offsetx(ofsx) { - return function(p) { - return {x: p.x + ofsx, y: p.y}; - }; -} - -dc_graph.builtin_arrows = { - box: function(open, side) { - if(!open) return { - frontRef: [8,0], - drawFunction: function(marker, ofs, stemWidth) { - marker.append('rect') - .attr({ - x: ofs[0], - y: side==='right' ? -stemWidth/2 : -4, - width: 8, - height: side ? 4+stemWidth/2 : 8, - 'stroke-width': 0 - }); - } - }; - else return { - frontRef: [8,0], - drawFunction: function(marker, ofs, stemWidth) { - marker.append('rect') - .attr({ - x: ofs[0] + 0.5, - y: side==='right' ? 0 : -3.5, - width: 7, - height: side ? 3.5 : 7, - 'stroke-width': 1, - fill: 'none' - }); - if(side) - marker.append('svg:path') - .attr({ - d: ['M', ofs[0], 0, 'h',8].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - }; - }, - curve: function(open, side) { - return { - stems: [true,false], - kernstems: [0, 0.25], - frontRef: [8,0], - drawFunction: function(marker, ofs, stemWidth) { - var instrs = []; - instrs.push('M', (side==='left' ? 7.5 : 4) + ofs[0], side==='left' ? stemWidth/2 : 3.5); - if(side==='left') - instrs.push('v', -stemWidth/2); - instrs.push('A', 3.5, 3.5, 0, 0, 0, - (side==='right' ? 7.5 : 4) + ofs[0], side==='right' ? 0 : -3.5); - if(side==='right') - instrs.push('v', -stemWidth/2); - marker.append('svg:path') - .attr({ - d: instrs.join(' '), - 'stroke-width': 1, - fill: 'none' - }); - marker.append('svg:path') - .attr({ - d: ['M', 7 + ofs[0], 0, - 'h -7'].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - }; - }, - icurve: function(open, side) { - return { - stems: [false,true], - kernstems: [0.25,0], - frontRef: [8,0], - drawFunction: function(marker, ofs, stemWidth) { - var instrs = []; - instrs.push('M', (side==='left' ? 0.5 : 4) + ofs[0], side==='left' ? stemWidth/2 : 3.5); - if(side==='left') - instrs.push('v', -stemWidth/2); - instrs.push('A', 3.5, 3.5, 0, 0, 1, - (side==='right' ? 0.5 : 4) + ofs[0], side==='right' ? 0 : -3.5); - if(side==='right') - instrs.push('v', -stemWidth/2); - marker.append('svg:path') - .attr({ - d: instrs.join(' '), - 'stroke-width': 1, - fill: 'none' - }); - marker.append('svg:path') - .attr({ - d: ['M', 1 + ofs[0], 0, - 'h 7'].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - }; - }, - diamond: function(open, side) { - if(!open) return { - frontRef: [side ? 11.25 : 12, 0], - backRef: [side ? 0.75 : 0, 0], - viewBox: [0, -4, 12, 8], - stems: [!!side, !!side], - kernstems: function(stemWidth) { - return [side ? 0 : .75*stemWidth, side ? 0 : .75*stemWidth]; - }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = [{x: 0, y: 0}]; - if(side !== 'left') - upoints.push({x: 6, y: 4}); - else - upoints.push({x: 6, y: -4}); - upoints.push({x: 12, y: 0}); - if(!side) - upoints.push({x: 6, y: -4}); - var points = upoints.map(offsetx(ofs[0])); - marker.append('svg:path') - .attr({ - d: generate_path(points, 1, true), - 'stroke-width': 0 - }); - if(side) { - marker.append('svg:path') - .attr({ - d: ['M', 0.75 + ofs[0], 0, - 'h 10.5'].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - } - }; - else return { - frontRef: [side ? 11.25 : 12, 0], - backRef: [side ? 0.75 : 0, 0], - viewBox: [0, -4, 12, 8], - stems: [!!side, !!side], - kernstems: function(stemWidth) { - return [side ? 0 : .75*stemWidth, side ? 0 : .75*stemWidth]; - }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = [{x: 0.9, y: 0}]; - if(side !== 'left') - upoints.push({x: 6, y: 3.4}); - else - upoints.push({x: 6, y: -3.4}); - upoints.push({x: 11.1, y: 0}); - if(!side) - upoints.push({x: 6, y: -3.4}); - var points = upoints.map(offsetx(ofs[0])); - marker.append('svg:path') - .attr({ - d: generate_path(points, 1, !side), - 'stroke-width': 1, - fill: 'none' - }); - if(side) { - marker.append('svg:path') - .attr({ - d: ['M', 0.75 + ofs[0], 0, - 'h 10.5'].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - } - }; - }, - dot: function(open, side) { - if(!open) return { - frontRef: [8,0], - stems: [!!side, !!side], - drawFunction: function(marker, ofs, stemWidth) { - if(side) { - marker.append('svg:path') - .attr({ - d: ['M', ofs[0], 0, - 'A', 4, 4, 0, 0, side==='left'?1:0, 8 + ofs[0], 0].join(' '), - 'stroke-width': 0 - }); - marker.append('svg:path') - .attr({ - d: ['M', ofs[0], 0, - 'h 8'].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - else { - marker.append('svg:circle') - .attr('r', 4) - .attr('cx', 4 + ofs[0]) - .attr('cy', 0) - .attr('stroke-width', '0px'); - } - } - }; - else return { - frontRef: [8,0], - stems: [!!side, !!side], - drawFunction: function(marker, ofs, stemWidth) { - if(side) { - marker.append('svg:path') - .attr({ - d: ['M', 0.5 + ofs[0], 0, - 'A', 3.5, 3.5, 0, 0, side==='left'?1:0, 7.5 + ofs[0], 0].join(' '), - 'stroke-width': 1, - fill: 'none' - }); - marker.append('svg:path') - .attr({ - d: ['M', ofs[0], 0, - 'h 8'].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } else { - marker.append('svg:circle') - .attr('r', 3.5) - .attr('cx', 4 + ofs[0]) - .attr('cy', 0) - .attr('fill', 'none') - .attr('stroke-width', '1px'); - } - } - }; - }, - normal: function(open, side) { - if(!open) return { - frontRef: [side ? 8-4/3 : 8, 0], - viewBox: [0, -3, 8, 6], - kernstems: function(stemWidth) { - return [0,stemWidth*4/3]; - }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = []; - if(side === 'left') - upoints.push({x: 0, y: 0}); - else - upoints.push({x: 0, y: 3}); - switch(side) { - case 'left': - upoints.push({x: 8 - stemWidth*4/3, y: -stemWidth/2}); - break; - case 'right': - upoints.push({x: 8 - stemWidth*4/3, y: stemWidth/2}); - break; - default: - upoints.push({x: 8, y: 0}); - } - if(side === 'right') - upoints.push({x: 0, y: 0}); - else - upoints.push({x: 0, y: -3}); - var points = upoints.map(offsetx(ofs[0])); - marker.append('svg:path') - .attr('d', generate_path(points, 1, true)) - .attr('stroke-width', '0px'); - if(side) { - marker.append('svg:path') - .attr({ - d: ['M', ofs[0], 0, - 'h', 8-4*stemWidth/3].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - } - }; - else return { - frontRef: [side ? 8-4/3 : 8, 0], - viewBox: [0, -3, 8, 6], - kernstems: function(stemWidth) { - return [0,stemWidth*4/3]; - }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = []; - if(!side) { - upoints = [ - {x: 0.5, y: 2.28}, - {x: 6.57, y: 0}, - {x: 0.5, y: -2.28} - ]; - } else { - upoints = [ - {x: 0.5, y: 0}, - {x: 0.5, y: side === 'left' ? -2.28 : 2.28}, - {x: 8-4/3, y: 0} - ]; - } - var points = upoints.map(offsetx(ofs[0])); - marker.append('svg:path') - .attr({ - d: generate_path(points, 1, !side), - 'stroke-width': 1, - fill: 'none' - }); - if(side) { - marker.append('svg:path') - .attr({ - d: ['M', ofs[0], 0, - 'h', 8-4/3].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - } - }; - }, - inv: function(open, side) { - if(!open) return { - frontRef: [8,0], - backRef: [side ? 4/3 : 0, 0], - viewBox: [0, -3, 8, 6], - kernstems: function(stemWidth) { - return [stemWidth*4/3,0]; - }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = []; - if(side === 'left') - upoints.push({x: 8, y: 0}); - else - upoints.push({x: 8, y: 3}); - switch(side) { - case 'left': - upoints.push({x: stemWidth*4/3, y: -stemWidth/2}); - break; - case 'right': - upoints.push({x: stemWidth*4/3, y: stemWidth/2}); - break; - default: - upoints.push({x: 0, y: 0}); - } - if(side === 'right') - upoints.push({x: 8, y: 0}); - else - upoints.push({x: 8, y: -3}); - var points = upoints.map(offsetx(ofs[0])); - marker.append('svg:path') - .attr('d', generate_path(points, 1, true)) - .attr('stroke-width', '0px'); - if(side) { - marker.append('svg:path') - .attr({ - d: ['M', 4*stemWidth/3 + ofs[0], 0, - 'h', 8-4*stemWidth/3].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - } - }; - else return { - frontRef: [8,0], - backRef: [side ? 4/3 : 0, 0], - viewBox: [0, -3, 8, 6], - kernstems: function(stemWidth) { - return [stemWidth*4/3,0]; - }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = []; - if(!side) { - upoints = [ - {x: 7.5, y: 2.28}, - {x: 1.43, y: 0}, - {x: 7.5, y: -2.28} - ]; - } else { - upoints = [ - {x: 7.5, y: 0}, - {x: 7.5, y: side === 'left' ? -2.28 : 2.28}, - {x: 1.43, y: 0} - ]; - } - var points = upoints.map(offsetx(ofs[0])); - marker.append('svg:path') - .attr({ - d: generate_path(points, 1, !side), - 'stroke-width': 1, - fill: 'none' - }); - if(side) { - marker.append('svg:path') - .attr({ - d: ['M', 4*stemWidth/3 + ofs[0], 0, - 'h', 8-4/3].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - } - }; - }, - tee: function(open, side) { - return { - frontRef: [5,0], - viewBox: [0, -5, 5, 10], - stems: [true,false], - drawFunction: function(marker, ofs, stemWidth) { - var b = side === 'right' ? 0 : -5, - t = side === 'left' ? 0 : 5; - var points = [ - {x: 2, y: t}, - {x: 5, y: t}, - {x: 5, y: b}, - {x: 2, y: b} - ].map(offsetx(ofs[0])); - marker.append('svg:path') - .attr('d', generate_path(points, 1, true)) - .attr('stroke-width', '0px'); - marker.append('svg:path') - .attr('d', ['M', ofs[0], 0, 'h', 5].join(' ')) - .attr('stroke-width', stemWidth) - .attr('fill', 'none'); - } - }; - }, - vee: function(open, side) { - return { - stems: [true,false], - kernstems: function(stemWidth) { - return [0,stemWidth]; - }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = [ - {x: 0, y: -5}, - {x: 10, y: 0}, - {x: 0, y: 5}, - {x: 5, y: 0} - ]; - if(side==='right') - upoints.splice(0, 1, - {x: 5, y: -stemWidth/2}, - {x: 10, y: -stemWidth/2}); - else if(side==='left') - upoints.splice(2, 1, - {x: 10, y: stemWidth/2}, - {x: 5, y: stemWidth/2}); - var points = upoints.map(offsetx(ofs[0])); - marker.append('svg:path') - .attr('d', generate_path(points, 1, true)) - .attr('stroke-width', '0px'); - marker.append('svg:path') - .attr('d', ['M', ofs[0]+5, 0, 'h',-5].join(' ')) - .attr('stroke-width', stemWidth); - } - }; - }, - crow: function(open, side) { - return { - stems: [false,true], - kernstems: function(stemWidth) { - return [stemWidth,0]; - }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = [ - {x: 10, y: -5}, - {x: 0, y: 0}, - {x: 10, y: 5}, - {x: 5, y: 0} - ]; - if(side==='right') - upoints.splice(0, 1, - {x: 5, y: -stemWidth/2}, - {x: 0, y: -stemWidth/2}); - else if(side==='left') - upoints.splice(2, 1, - {x: 0, y: stemWidth/2}, - {x: 5, y: stemWidth/2}); - var points = upoints.map(offsetx(ofs[0])); - marker.append('svg:path') - .attr('d', generate_path(points, 1, true)) - .attr('stroke-width', '0px'); - marker.append('svg:path') - .attr('d', ['M', ofs[0]+5, 0, 'h',5].join(' ')) - .attr('stroke-width', stemWidth); - } - }; - } -}; - -function arrow_def(arrdefs, shape, open, side) { - return arrdefs[shape](open, side); -} - -function arrow_parts(arrdefs, desc) { - // graphviz appears to use a real parser for this - var parts = []; - while(desc && desc.length) { - var mods = /^o?(?:l|r)?/.exec(desc); - var open = false, side = null; - if(mods[0]) { - mods = mods[0]; - desc = desc.slice(mods.length); - open = mods[0] === 'o'; - switch(mods[mods.length-1]) { - case 'l': - side='left'; - break; - case 'r': - side='right'; - } - } - var ok = false; - for(var aname in arrdefs) - if(desc.substring(0, aname.length) === aname) { - ok = true; - parts.push(arrow_def(arrdefs, aname, open, side)); - desc = desc.slice(aname.length); - break; - } - if(!ok) { - console.warn("couldn't find arrow name in " + desc); - break; - } - } - return parts; -} - -function union_viewbox(vb1, vb2) { - var left = Math.min(vb1[0], vb2[0]), - bottom = Math.min(vb1[1], vb2[1]), - right = Math.max(vb1[0] + vb1[2], vb2[0] + vb2[2]), - top = Math.max(vb1[1] + vb1[3], vb2[1] + vb2[3]); - return [left, bottom, right - left, top - bottom]; -} - -function subtract_points(p1, p2) { - return [p1[0] - p2[0], p1[1] - p2[1]]; -} - -function add_points(p1, p2) { - return [p1[0] + p2[0], p1[1] + p2[1]]; -} - -function mult_point(p, s) { - return p.map(function(x) { return x*s; }); -} - -function defaulted(def) { - return function(x) { - return x || def; - }; -} - -var view_box = defaulted([0, -5, 10, 10]), - front_ref = defaulted([10, 0]), - back_ref = defaulted([0, 0]); - -function arrow_offsets(parts, stemWidth) { - var frontRef = null, backRef = null; - return parts.map(function(p, i) { - var fr = front_ref(p.frontRef).slice(), - br = back_ref(p.backRef).slice(); - if(p.kernstems) { - var kernstems = p.kernstems; - if(typeof kernstems === 'function') - kernstems = kernstems(stemWidth); - if(i !== 0 && kernstems[1]) { - var last = parts[i-1]; - if(last.stems && last.stems[0]) - fr[0] -= kernstems[1]; - } - if(kernstems[0]) { - var kern = false; - if(i === parts.length-1) - kern = true; - else { - var next = parts[i+1]; - if(next.stems && next.stems[1]) - kern = true; - } - if(kern) - br[0] += kernstems[0]; - } - } - if(i === 0) { - frontRef = fr; - backRef = br; - return {backRef: backRef, offset: [0, 0]}; - } else { - var ofs = subtract_points(backRef, fr); - backRef = add_points(br, ofs); - return {backRef: backRef, offset: ofs}; - } - }); -} - -function arrow_bounds(parts, stemWidth) { - var viewBox = null, offsets = arrow_offsets(parts, stemWidth); - parts.forEach(function(p, i) { - var vb = view_box(p.viewBox); - var ofs = offsets[i].offset; - if(!viewBox) - viewBox = vb.slice(); - else - viewBox = union_viewbox(viewBox, [vb[0] + ofs[0], vb[1] + ofs[1], vb[2], vb[3]]); - }); - return {offsets: offsets, viewBox: viewBox}; -} - -function arrow_length(parts, stemWidth) { - if(!parts.length) - return 0; - var offsets = arrow_offsets(parts, stemWidth); - return front_ref(parts[0].frontRef)[0] - offsets[parts.length-1].backRef[0]; -} - - -function scaled_arrow_lengths(diagram, e) { - var arrowSize = diagram.edgeArrowSize.eval(e), - stemWidth = diagram.edgeStrokeWidth.eval(e) / arrowSize; - var headLength = arrowSize * - (arrow_length(arrow_parts(diagram.arrows(), diagram.edgeArrowhead.eval(e)), stemWidth) + - diagram.nodeStrokeWidth.eval(e.target) / 2), - tailLength = arrowSize * - (arrow_length(arrow_parts(diagram.arrows(), diagram.edgeArrowtail.eval(e)), stemWidth) + - diagram.nodeStrokeWidth.eval(e.source) / 2); - return {headLength: headLength, tailLength: tailLength}; -} - -function clip_path_to_arrows(headLength, tailLength, path) { - var points0 = as_bezier3(path), - points = chop_bezier(points0, 'head', headLength); - return { - bezDegree: 3, - points: chop_bezier(points, 'tail', tailLength), - sourcePort: path.sourcePort, - targetPort: path.targetPort - }; -} - -function place_arrows_on_spline(diagram, e, points) { - var alengths = scaled_arrow_lengths(diagram, e); - var path0 = { - points: points, - bezDegree: 3 - }; - var path = clip_path_to_arrows(alengths.headLength, alengths.tailLength, path0); - return { - path: path, - full: path0, - orienthead: angle_between_points(path.points[path.points.length-1], path0.points[path0.points.length-1]) + 'rad', //calculate_arrowhead_orientation(e.cola.points, 'head'), - orienttail: angle_between_points(path.points[0], path0.points[0]) + 'rad' //calculate_arrowhead_orientation(e.cola.points, 'tail') - }; -} - - -// determine pre-transition orientation that won't spin a lot going to new orientation -function unsurprising_orient(oldorient, neworient) { - var oldang = +oldorient.slice(0, -3), - newang = +neworient.slice(0, -3); - if(Math.abs(oldang - newang) > Math.PI) { - if(newang > oldang) - oldang += 2*Math.PI; - else oldang -= 2*Math.PI; - } - return oldang; -} - - -function edgeArrow(diagram, arrdefs, e, kind, desc) { - var id = diagram.arrowId(e, kind); - var strokeOfs, edgeStroke; - function arrow_sig() { - return desc + '-' + strokeOfs + '-' + edgeStroke; - } - if(desc) { - strokeOfs = diagram.nodeStrokeWidth.eval(kind==='tail' ? e.source : e.target)/2; - edgeStroke = diagram.edgeStroke.eval(e); - if(e[kind + 'ArrowLast'] === arrow_sig()) - return id; - } - var parts = arrow_parts(arrdefs, desc), - marker = diagram.addOrRemoveDef(id, !!parts.length, 'svg:marker'); - - if(parts.length) { - var arrowSize = diagram.edgeArrowSize.eval(e), - stemWidth = diagram.edgeStrokeWidth.eval(e) / arrowSize, - bounds = arrow_bounds(parts, stemWidth), - frontRef = front_ref(parts[0].frontRef); - bounds.viewBox[0] -= strokeOfs/arrowSize; - bounds.viewBox[3] += strokeOfs/arrowSize; - marker - .attr('viewBox', bounds.viewBox.join(' ')) - .attr('refX', frontRef[0]) - .attr('refY', frontRef[1]) - .attr('markerUnits', 'userSpaceOnUse') - .attr('markerWidth', bounds.viewBox[2]*arrowSize) - .attr('markerHeight', bounds.viewBox[3]*arrowSize) - .attr('stroke', edgeStroke) - .attr('fill', edgeStroke); - marker.html(null); - parts.forEach(function(p, i) { - marker - .call(p.drawFunction, - add_points([-strokeOfs/arrowSize,0], bounds.offsets[i].offset), - stemWidth); - }); - } - e[kind + 'ArrowLast'] = arrow_sig(); - return desc ? id : null; -} - -dc_graph.text_contents = function() { - var _contents = { - parent: property(null), - update: function(container) { - var text = container.selectAll('text.node-label') - .data(function(n) { return [n]; }); - text.enter().append('text') - .attr('class', 'node-label'); - var tspan = text.selectAll('tspan').data(function(n) { - var lines = _contents.parent().nodeLabel.eval(n); - if(!lines) - return []; - else if(typeof lines === 'string') - lines = [lines]; - var lineHeight = _contents.parent().nodeLineHeight(); - var first = 0.5 - ((lines.length - 1) * lineHeight + 1)/2; - // IE, Edge, and Safari do not seem to support - // dominant-baseline: central although they say they do - if(is_ie() || is_safari()) - first += 0.3; - return lines.map(function(line, i) { return {node: n, line: line, yofs: (i==0 ? first : lineHeight) + 'em'}; }); - }); - tspan.enter().append('tspan'); - tspan.attr({ - 'text-anchor': 'start', - 'text-decoration': function(line) { - return _contents.parent().nodeLabelDecoration.eval(line.node); - }, - x: 0 - }).html(function(s) { return s.line; }); - text - .each(function(n) { - n.xofs = 0; - }) - .filter(function(n) { - return _contents.parent().nodeLabelAlignment.eval(n) !== 'center'; - }) - .each(function(n) { - var bbox = getBBoxNoThrow(this); - n.bbox = {x: bbox.x, y: bbox.y, width: bbox.width, height: bbox.height}; - switch(_contents.parent().nodeLabelAlignment.eval(n)) { - case 'left': n.xofs = -n.bbox.width/2; - break; - case 'right': n.xofs = n.bbox.width/2; - break; - } - }) - .selectAll('tspan'); - tspan.attr({ - 'text-anchor': function(s) { - switch(_contents.parent().nodeLabelAlignment.eval(s.node)) { - case 'left': return 'start'; - case 'center': return 'middle'; - case 'right': return 'end'; - } - return null; - }, - x: function(s) { - return s.node.xofs; - }, - dy: function(d) { return d.yofs; } - }); - - tspan.exit().remove(); - text - .attr('fill', _contents.parent().nodeLabelFill.eval); - }, - textbox: function(container) { - var bbox = getBBoxNoThrow(this.selectContent(container).node()); - return {x: bbox.x, y: bbox.y, width: bbox.width, height: bbox.height}; - }, - selectContent: function(container) { - return container.select('text.node-label'); - }, - selectText: function(container) { - return this.selectContent(container); - } - }; - return _contents; -}; - -dc_graph.with_icon_contents = function(contents, width, height) { - var _contents = { - parent: property(null).react(function(parent) { - contents.parent(parent); - }), - padding: function(n) { - var padding = node_label_padding(_contents.parent(), n); - return { - x: padding.x * 3, - y: padding.y * 3 - }; - }, - update: function(container) { - var g = container.selectAll('g.with-icon') - .data(function(n) { return [n]; }); - var gEnter = g.enter(); - gEnter.append('g') - .attr('class', 'with-icon') - .append('image').attr({ - class: 'icon', - width: width + 'px', - height: height + 'px' - }); - g.call(contents.update); - contents.selectContent(g) - .attr('transform', 'translate(' + width/2 + ')'); - g.selectAll('image.icon').attr({ - href: _contents.parent().nodeIcon.eval, - x: function(n) { - var totwid = width + contents.textbox(d3.select(this.parentNode)).width; - return -totwid/2 - node_label_padding(_contents.parent(), n).x; - }, - y: -height/2 - }); - }, - textbox: function(container) { - var box = contents.textbox(container); - box.x += width/2; - return box; - }, - selectContent: function(container) { - return container.select('g.with-icon'); - }, - selectText: function(container) { - return this.selectContent(container).select('text.node-label'); - } - }; - return _contents; -}; - - -/** - * `dc_graph.diagram` is a dc.js-compatible network visualization component. It registers in - * the dc.js chart registry and its nodes and edges are generated from crossfilter groups. It - * logically derives from the dc.js - * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin}, - * but it does not physically derive from it since so much is different about network - * visualization versus conventional charts. - * @class diagram - * @memberof dc_graph - * @param {String|node} parent - Any valid - * {@link https://github.com/mbostock/d3/wiki/Selections#selecting-elements d3 single selector} - * specifying a dom block element such as a div; or a dom element. - * @param {String} [chartGroup] - The name of the dc.js chart group this diagram instance - * should be placed in. Filter interaction with a diagram will only trigger events and redraws - * within the diagram's group. - * @return {dc_graph.diagram} - **/ -dc_graph.diagram = function (parent, chartGroup) { - // different enough from regular dc charts that we don't use dc.baseMixin - // but attempt to implement most of that interface, copying some of the most basic stuff - var _diagram = dc.marginMixin({}); - _diagram.__dcFlag__ = dc.utils.uniqueId(); - _diagram.margins({left: 10, top: 10, right: 10, bottom: 10}); - var _dispatch = d3.dispatch('preDraw', 'data', 'end', 'start', 'render', 'drawn', 'receivedLayout', 'transitionsStarted', 'zoomed', 'reset'); - var _nodes = {}, _edges = {}; // hold state between runs - var _ports = {}; // id = node|edge/id/name - var _clusters = {}; - var _nodePorts; // ports sorted by node id - var _stats = {}; - var _nodes_snapshot, _edges_snapshot; - var _arrows = {}; - var _running = false; // for detecting concurrency issues - var _anchor, _chartGroup; - var _animateZoom; - - var _minWidth = 200; - var _defaultWidthCalc = function (element) { - var width = element && element.getBoundingClientRect && element.getBoundingClientRect().width; - return (width && width > _minWidth) ? width : _minWidth; - }; - var _widthCalc = _defaultWidthCalc; - - var _minHeight = 200; - var _defaultHeightCalc = function (element) { - var height = element && element.getBoundingClientRect && element.getBoundingClientRect().height; - return (height && height > _minHeight) ? height : _minHeight; - }; - var _heightCalc = _defaultHeightCalc; - var _width, _height, _lastWidth, _lastHeight; - - function deprecate_layout_algo_parameter(name) { - return function(value) { - if(!_diagram.layoutEngine()) - _diagram.layoutAlgorithm('cola', true); - var engine = _diagram.layoutEngine(); - if(engine.getEngine) - engine = engine.getEngine(); - if(engine[name]) { - console.warn('property is deprecated, call on layout engine instead: dc_graph.diagram.%c' + name, - 'font-weight: bold'); - if(!arguments.length) - return engine[name](); - engine[name](value); - } else { - console.warn('property is deprecated, and is not supported for Warning: dc_graph.diagram.' + name + ' is deprecated, and it is not supported for the "' + engine.layoutAlgorithm() + '" layout algorithm: ignored.'); - if(!arguments.length) - return null; - } - return this; - }; - } - - /** - * Set or get the height attribute of the diagram. If a value is given, then the diagram is - * returned for method chaining. If no value is given, then the current value of the height - * attribute will be returned. - * - * The width and height are applied to the SVG element generated by the diagram on render, or - * when `resizeSvg` is called. - * - * If the value is falsy or a function, the height will be calculated the first time it is - * needed, using the provided function or default height calculator, and then cached. The - * default calculator uses the client rect of the element specified when constructing the chart, - * with a minimum of `minHeight`. A custom calculator will be passed the element. - * - * If the value is `'auto'`, the height will be calculated every time the diagram is drawn, and - * it will not be set on the `` element. Instead, the element will be pinned to the same - * rectangle as its containing div using CSS. - * - * @method height - * @memberof dc_graph.diagram - * @instance - * @param {Number} [height=200] - * @return {Number} - * @return {dc_graph.diagram} - **/ - _diagram.height = function (height) { - if (!arguments.length) { - if (!dc.utils.isNumber(_height)) { - _lastHeight = _heightCalc(_diagram.root().node()); - if(_height === 'auto') // 'auto' => calculate every time - return _lastHeight; - // null/undefined => calculate once only - _height = _lastHeight; - } - return _height; - } - if(dc.utils.isNumber(height) || !height || height === 'auto') - _height = height; - else if(typeof height === 'function') { - _heightCalc = height; - _height = undefined; - } - else throw new Error("don't know what to do with height type " + typeof height + " value " + height); - return _diagram; - }; - _diagram.minHeight = function(height) { - if(!arguments.length) - return _minHeight; - _minHeight = height; - return _diagram; - }; - /** - * Set or get the width attribute of the diagram. If a value is given, then the diagram is - * returned for method chaining. If no value is given, then the current value of the width - * attribute will be returned. - * - * The width and height are applied to the SVG element generated by the diagram on render, or - * when `resizeSvg` is called. - * - * If the value is falsy or a function, the width will be calculated the first time it is - * needed, using the provided function or default width calculator, and then cached. The default - * calculator uses the client rect of the element specified when constructing the chart, with a - * minimum of `minWidth`. A custom calculator will be passed the element. - * - * If the value is `'auto'`, the width will be calculated every time the diagram is drawn, and - * it will not be set on the `` element. Instead, the element will be pinned to the same - * rectangle as its containing div using CSS. - * - * @method width - * @memberof dc_graph.diagram - * @instance - * @param {Number} [width=200] - * @return {Number} - * @return {dc_graph.diagram} - **/ - _diagram.width = function (width) { - if (!arguments.length) { - if (!dc.utils.isNumber(_width)) { - _lastWidth = _widthCalc(_diagram.root().node()); - if(_width === 'auto') // 'auto' => calculate every time - return _lastWidth; - // null/undefined => calculate once only - _width = _lastWidth; - } - return _width; - } - if(dc.utils.isNumber(width) || !width || width === 'auto') - _width = width; - else if(typeof width === 'function') { - _widthCalc = width; - _width = undefined; - } - else throw new Error("don't know what to do with width type " + typeof width + " value " + width); - return _diagram; - }; - _diagram.minWidth = function(width) { - if(!arguments.length) - return _minWidth; - _minWidth = width; - return _diagram; - }; - - /** - * Get or set the root element, which is usually the parent div. Normally the root is set - * when the diagram is constructed; setting it later may have unexpected consequences. - * @method root - * @memberof dc_graph.diagram - * @instance - * @param {node} [root=null] - * @return {node} - * @return {dc_graph.diagram} - **/ - _diagram.root = property(null).react(function(e) { - if(e.empty()) - console.log('Warning: parent selector ' + parent + " doesn't seem to exist"); - }); - - /** - * Get or set whether mouse wheel rotation or touchpad gestures will zoom the diagram, and - * whether dragging on the background pans the diagram. - * @method mouseZoomable - * @memberof dc_graph.diagram - * @instance - * @param {Boolean} [mouseZoomable=true] - * @return {Boolean} - * @return {dc_graph.diagram} - **/ - _diagram.mouseZoomable = property(true); - - _diagram.zoomExtent = property([.1, 2]); - - /** - * Whether zooming should only be enabled when the alt key is pressed. - * @method altKeyZoom - * @memberof dc_graph.diagram - * @instance - * @param {Boolean} [altKeyZoom=true] - * @return {Boolean} - * @return {dc_graph.diagram} - **/ - _diagram.modKeyZoom = _diagram.altKeyZoom = property(false); - - /** - * Set or get the fitting strategy for the canvas, which affects how the translate - * and scale get calculated when `autoZoom` is triggered. - * - * * `'default'` - simulates the preserveAspectRatio behavior of `xMidYMid meet`, but - * with margins - the content is stretched or squished in the more constrained - * direction, and centered in the other direction - * * `'vertical'` - fits the canvas vertically (with vertical margins) and centers - * it horizontally. If the canvas is taller than the viewport, it will meet - * vertically and there will be blank areas to the left and right. If the canvas - * is wider than the viewport, it will be sliced. - * * `'horizontal'` - fits the canvas horizontally (with horizontal margins) and - * centers it vertically. If the canvas is wider than the viewport, it will meet - * horizontally and there will be blank areas above and below. If the canvas is - * taller than the viewport, it will be sliced. - * - * Other options - * * `null` - no attempt is made to fit the content in the viewport - * * `'zoom'` - does not scale the content, but attempts to bring as much content - * into view as possible, using using the same algorithm as `restrictPan` - * * `'align_{tlbrc}[2]'` - does not scale; aligns up to two sides or centers them - * @method fitStrategy - * @memberof dc_graph.diagram - * @instance - * @param {String} [fitStrategy='default'] - * @return {String} - * @return {dc_graph.diagram} - **/ - _diagram.fitStrategy = property('default'); - - /** - * Do not allow panning (scrolling) to push the diagram out of the viewable area, if there - * is space for it to be shown. */ - _diagram.restrictPan = property(false); - - /** - * Auto-zoom behavior. - * * `'always'` - zoom every time layout happens - * * `'once'` - zoom the next time layout happens - * * `null` - manual, call `zoomToFit` to fit - * @method autoZoom - * @memberof dc_graph.diagram - * @instance - * @param {String} [autoZoom=null] - * @return {String} - * @return {dc_graph.diagram} - **/ - _diagram.autoZoom = property(null); - _diagram.zoomToFit = function(animate) { - // if(!(_nodeLayer && _edgeLayer)) - // return; - auto_zoom(animate); - }; - _diagram.zoomDuration = property(500); - - /** - * Set or get the crossfilter dimension which represents the nodes (vertices) in the - * diagram. Typically there will be a crossfilter instance for the nodes, and another for - * the edges. - * - * *Dimensions are included on the diagram for similarity to dc.js, however the diagram - * itself does not use them - but {@link dc_graph.filter_selection filter_selection} will.* - * @method nodeDimension - * @memberof dc_graph.diagram - * @instance - * @param {crossfilter.dimension} [nodeDimension] - * @return {crossfilter.dimension} - * @return {dc_graph.diagram} - **/ - _diagram.nodeDimension = property(); - - /** - * Set or get the crossfilter group which is the data source for the nodes in the - * diagram. The diagram will use the group's `.all()` method to get an array of `{key, - * value}` pairs, where the key is a unique identifier, and the value is usually an object - * containing the node's attributes. All accessors work with these key/value pairs. - * - * If the group is changed or returns different values, the next call to `.redraw()` will - * reflect the changes incrementally. - * - * It is possible to pass another object with the same `.all()` interface instead of a - * crossfilter group. - * @method nodeGroup - * @memberof dc_graph.diagram - * @instance - * @param {crossfilter.group} [nodeGroup] - * @return {crossfilter.group} - * @return {dc_graph.diagram} - **/ - _diagram.nodeGroup = property(); - - /** - * Set or get the crossfilter dimension which represents the edges in the - * diagram. Typically there will be a crossfilter instance for the nodes, and another for - * the edges. - * - * *Dimensions are included on the diagram for similarity to dc.js, however the diagram - * itself does not use them - but {@link dc_graph.filter_selection filter_selection} will.* - * @method edgeDimension - * @memberof dc_graph.diagram - * @instance - * @param {crossfilter.dimension} [edgeDimension] - * @return {crossfilter.dimension} - * @return {dc_graph.diagram} - **/ - _diagram.edgeDimension = property(); - - /** - * Set or get the crossfilter group which is the data source for the edges in the - * diagram. See `.nodeGroup` above for the way data is loaded from a crossfilter group. - * - * The values in the key/value pairs returned by `diagram.edgeGroup().all()` need to - * support, at a minimum, the {@link dc_graph.diagram#nodeSource nodeSource} and - * {@link dc_graph.diagram#nodeTarget nodeTarget}, which should return the same - * keys as the {@link dc_graph.diagram#nodeKey nodeKey} - * - * @method edgeGroup - * @memberof dc_graph.diagram - * @instance - * @param {crossfilter.group} [edgeGroup] - * @return {crossfilter.group} - * @return {dc_graph.diagram} - **/ - _diagram.edgeGroup = property(); - - _diagram.edgesInFront = property(false); - - /** - * Set or get the function which will be used to retrieve the unique key for each node. By - * default, this accesses the `key` field of the object passed to it. The keys should match - * the keys returned by the {@link dc_graph.diagram#edgeSource edgeSource} and - * {@link dc_graph.diagram#edgeTarget edgeTarget}. - * - * @method nodeKey - * @memberof dc_graph.diagram - * @instance - * @param {Function} [nodeKey=function(kv) { return kv.key }] - * @return {Function} - * @return {dc_graph.diagram} - **/ - _diagram.nodeKey = _diagram.nodeKeyAccessor = property(function(kv) { - return kv.key; - }); - - /** - * Set or get the function which will be used to retrieve the unique key for each edge. By - * default, this accesses the `key` field of the object passed to it. - * - * @method edgeKey - * @memberof dc_graph.diagram - * @instance - * @param {Function} [edgeKey=function(kv) { return kv.key }] - * @return {Function} - * @return {dc_graph.diagram} - **/ - _diagram.edgeKey = _diagram.edgeKeyAccessor = property(function(kv) { - return kv.key; - }); - - /** - * Set or get the function which will be used to retrieve the source (origin/tail) key of - * the edge objects. The key must equal the key returned by the `.nodeKey` for one of the - * nodes; if it does not, or if the node is currently filtered out, the edge will not be - * displayed. By default, looks for `.value.sourcename`. - * - * @method edgeSource - * @memberof dc_graph.diagram - * @instance - * @param {Function} [edgeSource=function(kv) { return kv.value.sourcename; }] - * @return {Function} - * @return {dc_graph.diagram} - **/ - _diagram.edgeSource = _diagram.sourceAccessor = property(function(kv) { - return kv.value.sourcename; - }); - - /** - * Set or get the function which will be used to retrieve the target (destination/head) key - * of the edge objects. The key must equal the key returned by the - * {@link dc_graph.diagram#nodeKey nodeKey} for one of the nodes; if it does not, or if the node - * is currently filtered out, the edge will not be displayed. By default, looks for - * `.value.targetname`. - * @method edgeTarget - * @memberof dc_graph.diagram - * @instance - * @param {Function} [edgeTarget=function(kv) { return kv.value.targetname; }] - * @return {Function} - * @return {dc_graph.diagram} - **/ - _diagram.edgeTarget = _diagram.targetAccessor = property(function(kv) { - return kv.value.targetname; - }); - - _diagram.portDimension = property(null); - _diagram.portGroup = property(null); - _diagram.portNodeKey = property(null); - _diagram.portEdgeKey = property(null); - _diagram.portName = property(null); - _diagram.portStyleName = property(null); - _diagram.portElastic = property(true); - - _diagram.portStyle = named_children(); - - _diagram.portBounds = property(null); // position limits, in radians - - _diagram.edgeSourcePortName = property(null); - _diagram.edgeTargetPortName = property(null); - - /** - * Set or get the crossfilter dimension which represents the edges in the - * diagram. Typically there will be a crossfilter instance for the nodes, and another for - * the edges. - * - * *As with node and edge dimensions, the diagram will itself not filter on cluster dimensions; - * this is included for symmetry, and for modes which may want to filter clusters.* - * @method clusterDimension - * @memberof dc_graph.diagram - * @instance - * @param {crossfilter.dimension} [clusterDimension] - * @return {crossfilter.dimension} - * @return {dc_graph.diagram} - **/ - _diagram.clusterDimension = property(null); - - /** - * Set or get the crossfilter group which is the data source for clusters in the - * diagram. - * - * The key/value pairs returned by `diagram.clusterGroup().all()` need to support, at a minimum, - * the {@link dc_graph.diagram#clusterKey clusterKey} and {@link dc_graph.diagram#clusterParent clusterParent} - * accessors, which should return keys in this group. - * - * @method clusterGroup - * @memberof dc_graph.diagram - * @instance - * @param {crossfilter.group} [clusterGroup] - * @return {crossfilter.group} - * @return {dc_graph.diagram} - **/ - _diagram.clusterGroup = property(null); - - // cluster accessors - /** - * Set or get the function which will be used to retrieve the unique key for each cluster. By - * default, this accesses the `key` field of the object passed to it. - * - * @method clusterKey - * @memberof dc_graph.diagram - * @instance - * @param {Function} [clusterKey=function(kv) { return kv.key }] - * @return {Function} - * @return {dc_graph.diagram} - **/ - _diagram.clusterKey = property(dc.pluck('key')); - - /** - * Set or get the function which will be used to retrieve the key of the parent of a cluster, - * which is another cluster. - * - * @method clusterParent - * @memberof dc_graph.diagram - * @instance - * @param {Function} [clusterParent=function(kv) { return kv.key }] - * @return {Function} - * @return {dc_graph.diagram} - **/ - _diagram.clusterParent = property(null); - - /** - * Set or get the function which will be used to retrieve the padding, in pixels, around a cluster. - * - * **To be implemented.** If a single value is returned, it will be used on all sides; if two - * values are returned they will be interpreted as the vertical and horizontal padding. - * - * @method clusterPadding - * @memberof dc_graph.diagram - * @instance - * @param {Function} [clusterPadding=function(kv) { return kv.key }] - * @return {Function} - * @return {dc_graph.diagram} - **/ - _diagram.clusterPadding = property(8); - - // node accessor - /** - * Set or get the function which will be used to retrieve the parent cluster of a node, or - * `null` if the node is not in a cluster. - * - * @method nodeParentCluster - * @memberof dc_graph.diagram - * @instance - * @param {Function} [nodeParentCluster=function(kv) { return kv.key }] - * @return {Function} - * @return {dc_graph.diagram} - **/ - _diagram.nodeParentCluster = property(null); - - /** - * Set or get the function which will be used to retrieve the radius, in pixels, for each - * node. This determines the height of nodes,and if `nodeFitLabel` is false, the width too. - * @method nodeRadius - * @memberof dc_graph.diagram - * @instance - * @param {Function|Number} [nodeRadius=25] - * @return {Function|Number} - * @return {dc_graph.diagram} - **/ - _diagram.nodeRadius = _diagram.nodeRadiusAccessor = property(25); - - /** - * Set or get the function which will be used to retrieve the stroke width, in pixels, for - * drawing the outline of each node. According to the SVG specification, the outline will - * be drawn half on top of the fill, and half outside. Default: 1 - * @method nodeStrokeWidth - * @memberof dc_graph.diagram - * @instance - * @param {Function|Number} [nodeStrokeWidth=1] - * @return {Function|Number} - * @return {dc_graph.diagram} - **/ - _diagram.nodeStrokeWidth = _diagram.nodeStrokeWidthAccessor = property(1); - - /** - * Set or get the function which will be used to retrieve the stroke color for the outline - * of each node. - * @method nodeStroke - * @memberof dc_graph.diagram - * @instance - * @param {Function|String} [nodeStroke='black'] - * @return {Function|String} - * @return {dc_graph.diagram} - **/ - _diagram.nodeStroke = _diagram.nodeStrokeAccessor = property('black'); - - _diagram.nodeStrokeDashArray = property(null); - - /** - * If set, the value returned from `nodeFill` will be processed through this - * {@link https://github.com/mbostock/d3/wiki/Scales d3.scale} - * to return the fill color. If falsy, uses the identity function (no scale). - * @method nodeFillScale - * @memberof dc_graph.diagram - * @instance - * @param {Function|d3.scale} [nodeFillScale] - * @return {Function|d3.scale} - * @return {dc_graph.diagram} - **/ - _diagram.nodeFillScale = property(null); - - /** - * Set or get the function which will be used to retrieve the fill color for the body of each - * node. - * @method nodeFill - * @memberof dc_graph.diagram - * @instance - * @param {Function|String} [nodeFill='white'] - * @return {Function|String} - * @return {dc_graph.diagram} - **/ - _diagram.nodeFill = _diagram.nodeFillAccessor = property('white'); - - /** - * Set or get the function which will be used to retrieve the opacity of each node. - * @method nodeOpacity - * @memberof dc_graph.diagram - * @instance - * @param {Function|Number} [nodeOpacity=1] - * @return {Function|Number} - * @return {dc_graph.diagram} - **/ - _diagram.nodeOpacity = property(1); - - /** - * Set or get the padding or minimum distance, in pixels, for a node. (Will be distributed - * to both sides of the node.) - * @method nodePadding - * @memberof dc_graph.diagram - * @instance - * @param {Function|Number} [nodePadding=6] - * @return {Function|Number} - * @return {dc_graph.diagram} - **/ - _diagram.nodePadding = property(6); - - - /** - * Set or get the padding, in pixels, for a node's label. If an object, should contain fields - * `x` and `y`. If a number, will be applied to both x and y. - * @method nodeLabelPadding - * @memberof dc_graph.diagram - * @instance - * @param {Function|Number|Object} [nodeLabelPadding=0] - * @return {Function|Number} - * @return {dc_graph.diagram} - **/ - _diagram.nodeLabelPadding = property(0); - - /** - * Set or get the line height for nodes with multiple lines of text, in ems. - * @method nodeLineHeight - * @memberof dc_graph.diagram - * @instance - * @param {Function|Number} [nodeLineHeight=1] - * @return {Function|Number} - * @return {dc_graph.diagram} - **/ - _diagram.nodeLineHeight = property(1); - - /** - * Set or get the function which will be used to retrieve the label text to display in each - * node. By default, looks for a field `label` or `name` inside the `value` field. - * @method nodeLabel - * @memberof dc_graph.diagram - * @instance - * @param {Function|String} [nodeLabel] - * @return {Function|String} - * @example - * // Default behavior - * diagram.nodeLabel(function(kv) { - * return kv.value.label || kv.value.name; - * }); - * @return {dc_graph.diagram} - **/ - _diagram.nodeLabel = _diagram.nodeLabelAccessor = property(function(kv) { - return kv.value.label || kv.value.name; - }); - - _diagram.nodeLabelAlignment = property('center'); - _diagram.nodeLabelDecoration = property(null); - - /** - * Set or get the function which will be used to retrieve the label fill color. Default: null - * @method nodeLabelFill - * @memberof dc_graph.diagram - * @instance - * @param {Function|String} [nodeLabelFill=null] - * @return {Function|String} - * @return {dc_graph.diagram} - **/ - _diagram.nodeLabelFill = _diagram.nodeLabelFillAccessor = property(null); - - /** - * Whether to fit the node shape around the label - * @method nodeFitLabel - * @memberof dc_graph.diagram - * @instance - * @param {Function|Boolean} [nodeFitLabel=true] - * @return {Function|Boolean} - * @return {dc_graph.diagram} - **/ - _diagram.nodeFitLabel = _diagram.nodeFitLabelAccessor = property(true); - - /** - * The shape to use for drawing each node, specified as an object with at least the field - * `shape`. The names of shapes are mostly taken - * [from graphviz](http://www.graphviz.org/doc/info/shapes.html); currently ellipse, egg, - * triangle, rectangle, diamond, trapezium, parallelogram, pentagon, hexagon, septagon, octagon, - * invtriangle, invtrapezium, square, polygon are supported. - * - * If `shape = polygon`: - * * `sides`: number of sides for a polygon - * @method nodeShape - * @memberof dc_graph.diagram - * @instance - * @param {Function|Object} [nodeShape={shape: 'ellipse'}] - * @return {Function|Object} - * @return {dc_graph.diagram} - * @example - * // set shape to diamond or parallelogram based on flag - * diagram.nodeShape(function(kv) { - * return {shape: kv.value.flag ? 'diamond' : 'parallelogram'}; - * }); - **/ - _diagram.nodeShape = property(default_shape); - - // for defining custom (and standard) shapes - _diagram.shape = named_children(); - - _diagram.shape('nothing', dc_graph.no_shape()); - _diagram.shape('ellipse', dc_graph.ellipse_shape()); - _diagram.shape('polygon', dc_graph.polygon_shape()); - _diagram.shape('rounded-rect', dc_graph.rounded_rectangle_shape()); - _diagram.shape('elaborated-rect', dc_graph.elaborated_rectangle_shape()); - - _diagram.nodeOutlineClip = property(null); - - _diagram.nodeContent = property('text'); - _diagram.content = named_children(); - _diagram.content('text', dc_graph.text_contents()); - - // really looks like these should reside in an open namespace - this used only by an extension - // but it's no less real than any other computed property - _diagram.nodeIcon = property(null); - - /** - * Set or get the function which will be used to retrieve the node title, usually rendered - * as a tooltip. By default, uses the key of the node. - * @method nodeTitle - * @memberof dc_graph.diagram - * @instance - * @param {Function|String} [nodeTitle] - * @return {Function|String} - * @example - * // Default behavior - * diagram.nodeTitle(function(kv) { - * return _diagram.nodeKey()(kv); - * }); - * @return {dc_graph.diagram} - **/ - _diagram.nodeTitle = _diagram.nodeTitleAccessor = property(function(kv) { - return _diagram.nodeKey()(kv); - }); - - /** - * By default, nodes are added to the layout in the order that `.nodeGroup().all()` returns - * them. If specified, `.nodeOrdering` provides an accessor that returns a key to sort the - * nodes on. *It would be better not to rely on ordering to affect layout, but it may - * affect the layout in some cases.* - * @method nodeOrdering - * @memberof dc_graph.diagram - * @instance - * @param {Function} [nodeOrdering=null] - * @return {Function} - * @return {dc_graph.diagram} - **/ - _diagram.nodeOrdering = property(null); - - /** - * Specify an accessor that returns an {x,y} coordinate for a node that should be - * {@link https://github.com/tgdwyer/WebCola/wiki/Fixed-Node-Positions fixed in place}, - * and returns falsy for other nodes. - * @method nodeFixed - * @memberof dc_graph.diagram - * @instance - * @param {Function|Object} [nodeFixed=null] - * @return {Function|Object} - * @return {dc_graph.diagram} - **/ - _diagram.nodeFixed = _diagram.nodeFixedAccessor = property(null); - - - /** - * Set or get the function which will be used to retrieve the stroke color for the edges. - * @method edgeStroke - * @memberof dc_graph.diagram - * @instance - * @param {Function|String} [edgeStroke='black'] - * @return {Function|String} - * @return {dc_graph.diagram} - **/ - _diagram.edgeStroke = _diagram.edgeStrokeAccessor = property('black'); - - /** - * Set or get the function which will be used to retrieve the stroke width for the edges. - * @method edgeStrokeWidth - * @memberof dc_graph.diagram - * @instance - * @param {Function|Number} [edgeStrokeWidth=1] - * @return {Function|Number} - * @return {dc_graph.diagram} - **/ - _diagram.edgeStrokeWidth = _diagram.edgeStrokeWidthAccessor = property(1); - - _diagram.edgeStrokeDashArray = property(null); - - /** - * Set or get the function which will be used to retrieve the edge opacity, a number from 0 - * to 1. - * @method edgeOpacity - * @memberof dc_graph.diagram - * @instance - * @param {Function|Number} [edgeOpacity=1] - * @return {Function|Number} - * @return {dc_graph.diagram} - **/ - _diagram.edgeOpacity = _diagram.edgeOpacityAccessor = property(1); - - /** - * Set or get the function which will be used to retrieve the edge label text. The label is - * displayed when an edge is hovered over. By default, uses the `edgeKey`. - * @method edgeLabel - * @memberof dc_graph.diagram - * @instance - * @param {Function|String} [edgeLabel] - * @example - * // Default behavior - * diagram.edgeLabel(function(e) { - * return _diagram.edgeKey()(e); - * }); - * @return {Function|String} - * @return {dc_graph.diagram} - **/ - _diagram.edgeLabel = _diagram.edgeLabelAccessor = property(function(e) { - return _diagram.edgeKey()(e); - }); - // vertical spacing when there are multiple lines of edge label - _diagram.edgeLabelSpacing = property(12); - - /** - * Set or get the function which will be used to retrieve the name of the arrowhead to use - * for the target/ head/destination of the edge. Arrow symbols can be specified with - * `.defineArrow()`. Return null to display no arrowhead. - * @method edgeArrowhead - * @memberof dc_graph.diagram - * @instance - * @param {Function|String} [edgeArrowhead='vee'] - * @return {Function|String} - * @return {dc_graph.diagram} - **/ - _diagram.edgeArrowhead = _diagram.edgeArrowheadAccessor = property('vee'); - - /** - * Set or get the function which will be used to retrieve the name of the arrow tail to use - * for the tail/source of the edge. Arrow symbols can be specified with - * `.defineArrow()`. Return null to display no arrowtail. - * @method edgeArrowtail - * @memberof dc_graph.diagram - * @instance - * @param {Function|String} [edgeArrowtail=null] - * @return {Function|String} - * @return {dc_graph.diagram} - **/ - _diagram.edgeArrowtail = _diagram.edgeArrowtailAccessor = property(null); - - /** - * Multiplier for arrow size. - * @method edgeArrowSize - * @memberof dc_graph.diagram - * @instance - * @param {Function|Number} [edgeArrowSize=1] - * @return {Function|Number} - * @return {dc_graph.diagram} - **/ - _diagram.edgeArrowSize = property(1); - - /** - * To draw an edge but not have it affect the layout, specify a function which returns - * false for that edge. By default, will return false if the `notLayout` field of the edge - * value is truthy, true otherwise. - * @method edgeIsLayout - * @memberof dc_graph.diagram - * @instance - * @param {Function|Boolean} [edgeIsLayout] - * @example - * // Default behavior - * diagram.edgeIsLayout(function(kv) { - * return !kv.value.notLayout; - * }); - * @return {Function|Boolean} - * @return {dc_graph.diagram} - **/ - _diagram.edgeIsLayout = _diagram.edgeIsLayoutAccessor = property(function(kv) { - return !kv.value.notLayout; - }); - - // if false, don't draw or layout the edge. this is not documented because it seems like - // the interface could be better and this combined with edgeIsLayout. (currently there is - // no way to layout but not draw an edge.) - _diagram.edgeIsShown = property(true); - - /** - * Currently, three strategies are supported for specifying the lengths of edges: - * * 'individual' - uses the `edgeLength` for each edge. If it returns falsy, uses the - * `baseLength` - * * 'symmetric', 'jaccard' - compute the edge length based on the graph structure around - * the edge. See - * {@link https://github.com/tgdwyer/WebCola/wiki/link-lengths the cola.js wiki} - * for more details. - * 'none' - no edge lengths will be specified - * - * **Deprecated**: Use {@link dc_graph.cola_layout#lengthStrategy cola_layout.lengthStrategy} instead. - * @method lengthStrategy - * @memberof dc_graph.diagram - * @instance - * @param {Function|String} [lengthStrategy='symmetric'] - * @return {Function|String} - * @return {dc_graph.diagram} - **/ - _diagram.lengthStrategy = deprecate_layout_algo_parameter('lengthStrategy'); - - /** - * When the `.lengthStrategy` is 'individual', this accessor will be used to read the - * length of each edge. By default, reads the `distance` field of the edge. If the - * distance is falsy, uses the `baseLength`. - * @method edgeLength - * @memberof dc_graph.diagram - * @instance - * @param {Function|Number} [edgeLength] - * @example - * // Default behavior - * diagram.edgeLength(function(kv) { - * return kv.value.distance; - * }); - * @return {Function|Number} - * @return {dc_graph.diagram} - **/ - _diagram.edgeLength = _diagram.edgeDistanceAccessor = property(function(kv) { - return kv.value.distance; - }); - - /** - * This should be equivalent to rankdir and ranksep in the dagre/graphviz nomenclature, but for - * now it is separate. - * - * **Deprecated**: use {@link dc_graph.cola_layout#flowLayout cola_layout.flowLayout} instead. - * @method flowLayout - * @memberof dc_graph.diagram - * @instance - * @param {Object} [flowLayout] - * @example - * // No flow (default) - * diagram.flowLayout(null) - * // flow in x with min separation 200 - * diagram.flowLayout({axis: 'x', minSeparation: 200}) - **/ - _diagram.flowLayout = deprecate_layout_algo_parameter('flowLayout'); - - /** - * Direction to draw ranks. Currently for dagre and expand_collapse, but I think cola could be - * generated from graphviz-style since it is more general. - * - * **Deprecated**: use {@link dc_graph.dagre_layout#rankdir dagre_layout.rankdir} instead. - * @method rankdir - * @memberof dc_graph.diagram - * @instance - * @param {String} [rankdir] - **/ - _diagram.rankdir = deprecate_layout_algo_parameter('rankdir'); - - /** - * Gets or sets the default edge length (in pixels) when the `.lengthStrategy` is - * 'individual', and the base value to be multiplied for 'symmetric' and 'jaccard' edge - * lengths. - * - * **Deprecated**: use {@link dc_graph.cola_layout#baseLength cola_layout.baseLength} instead. - * @method baseLength - * @memberof dc_graph.diagram - * @instance - * @param {Number} [baseLength] - * @return {Number} - * @return {dc_graph.diagram} - **/ - _diagram.baseLength = deprecate_layout_algo_parameter('baseLength'); - - /** - * Gets or sets the transition duration, the length of time each change to the diagram will - * be animated. - * @method transitionDuration - * @memberof dc_graph.diagram - * @instance - * @param {Number} [transitionDuration=500] - * @return {Number} - * @return {dc_graph.diagram} - **/ - _diagram.transitionDuration = property(500); - - /** - * How transitions should be split into separate animations to emphasize - * the delete, modify, and insert operations: - * * `none`: modify and insert operations animate at the same time - * * `modins`: modify operations happen before inserts - * * `insmod`: insert operations happen before modifies - * - * Deletions always happen before/during layout computation. - * @method stageTransitions - * @memberof dc_graph.diagram - * @instance - * @param {String} [stageTransitions='none'] - * @return {String} - * @return {dc_graph.diagram} - **/ - _diagram.stageTransitions = property('none'); - - /** - * The delete transition happens simultaneously with layout, which can take longer - * than the transition duration. Delaying it can bring it closer to the other - * staged transitions. - * @method deleteDelay - * @memberof dc_graph.diagram - * @instance - * @param {Number} [deleteDelay=0] - * @return {Number} - * @return {dc_graph.diagram} - **/ - _diagram.deleteDelay = property(0); - - /** - * Whether to put connected components each in their own group, to stabilize layout. - * @method groupConnected - * @memberof dc_graph.diagram - * @instance - * @param {String} [groupConnected=false] - * @return {String} - * @return {dc_graph.diagram} - **/ - _diagram.groupConnected = deprecate_layout_algo_parameter('groupConnected'); - - /** - * Gets or sets the maximum time spent doing layout for a render or redraw. Set to 0 for no - * limit. - * @method timeLimit - * @memberof dc_graph.diagram - * @instance - * @param {Function|Number} [timeLimit=0] - * @return {Function|Number} - * @return {dc_graph.diagram} - **/ - _diagram.timeLimit = property(0); - - /** - * Gets or sets a function which will be called with the current nodes and edges on each - * redraw in order to derive new layout constraints. The constraints are built from scratch - * on each redraw. - * - * This can be used to generate alignment (rank) or axis constraints. By default, no - * constraints will be added, although cola.js uses constraints internally to implement - * flow and overlap prevention. See - * {@link https://github.com/tgdwyer/WebCola/wiki/Constraints the cola.js wiki} - * for more details. - * - * For convenience, dc.graph.js implements a other constraints on top of those implemented - * by cola.js: - * * 'ordering' - the nodes will be ordered on the specified `axis` according to the keys - * returned by the `ordering` function, by creating separation constraints using the - * specified `gap`. - * * 'circle' - (experimental) the nodes will be placed in a circle using "wheel" - * edge lengths similar to those described in - * {@link http://www.csse.monash.edu.au/~tdwyer/Dwyer2009FastConstraints.pdf Scalable, Versatile, and Simple Constrained Graph Layout} - * *Although this is not as performant or stable as might be desired, it may work for - * simple cases. In particular, it should use edge length *constraints*, which don't yet - * exist in cola.js.* - * - * Because it is tedious to write code to generate constraints for a graph, **dc.graph.js** - * also includes a {@link #dc_graph+constraint_pattern constraint generator} to produce - * this constrain function, specifying the constraints themselves in a graph. - * @method constrain - * @memberof dc_graph.diagram - * @instance - * @param {Function} [constrain] - * @return {Function} - * @return {dc_graph.diagram} - **/ - _diagram.constrain = property(function(nodes, edges) { - return []; - }); - - /** - * If there are multiple edges between the same two nodes, start them this many pixels away - * from the original so they don't overlap. - * @method parallelEdgeOffset - * @memberof dc_graph.diagram - * @instance - * @param {Number} [parallelEdgeOffset=10] - * @return {Number} - * @return {dc_graph.diagram} - **/ - _diagram.parallelEdgeOffset = property(10); - - /** - * By default, edges are added to the layout in the order that `.edgeGroup().all()` returns - * them. If specified, `.edgeOrdering` provides an accessor that returns a key to sort the - * edges on. - * - * *It would be better not to rely on ordering to affect layout, but it may affect the - * layout in some cases. (Probably less than node ordering, but it does affect which - * parallel edge is which.)* - * @method edgeOrdering - * @memberof dc_graph.diagram - * @instance - * @param {Function} [edgeOrdering=null] - * @return {Function} - * @return {dc_graph.diagram} - **/ - _diagram.edgeOrdering = property(null); - - _diagram.edgeSort = property(null); - - _diagram.cascade = cascade(_diagram); - - /** - * Currently there are some bugs when the same instance of cola.js is used multiple - * times. (In particular, overlaps between nodes may not be eliminated - * {@link https://github.com/tgdwyer/WebCola/issues/118 if cola is not reinitialized} - * This flag can be set true to construct a new cola layout object on each redraw. However, - * layout seems to be more stable if this is set false, so hopefully this will be fixed - * soon. - * @method initLayoutOnRedraw - * @memberof dc_graph.diagram - * @instance - * @param {Boolean} [initLayoutOnRedraw=false] - * @return {Boolean} - * @return {dc_graph.diagram} - **/ - _diagram.initLayoutOnRedraw = property(false); - - /** - * Whether to perform layout when the data is unchanged from the last redraw. - * @method layoutUnchanged - * @memberof dc_graph.diagram - * @instance - * @param {Boolean} [layoutUnchanged=false] - * @return {Boolean} - * @return {dc_graph.diagram} - **/ - _diagram.layoutUnchanged = property(false); - _diagram.nodeChangeSelect = property(function() { - if(_diagram.layoutEngine().supportsMoving && _diagram.layoutEngine().supportsMoving()) - return topology_node; - else - return basic_node; - }); - _diagram.edgeChangeSelect = property(function() { - if(_diagram.layoutEngine().supportsMoving && _diagram.layoutEngine().supportsMoving()) - return topology_edge; - else - return basic_edge; - }); - - /** - * When `layoutUnchanged` is false, this will force layout to happen again. This may be needed - * when changing a parameter but not changing the topology of the graph. (Yes, probably should - * not be necessary.) - * @method relayout - * @memberof dc_graph.diagram - * @instance - * @return {dc_graph.diagram} - **/ - _diagram.relayout = function() { - _nodes_snapshot = _edges_snapshot = null; - return this; - }; - - /** - * Function to call to generate an initial layout. Takes (diagram, nodes, edges) - * - * **Deprecated**: The only layout that was using this was `tree_positions` and it never - * worked as an initialization step for cola, as was originally intended. Now that - * `tree_layout` is a layout algorithm, this should go away. - * - * In the future, there will be support for chaining layout algorithms. But that will be a - * matter of composing them into a super-algorithm, not a special step like this was. - * @method initialLayout - * @memberof dc_graph.diagram - * @instance - * @param {Function} [initialLayout=null] - * @return {Function} - * @return {dc_graph.diagram} - **/ - _diagram.initialLayout = deprecated_property('initialLayout is deprecated - use layout algorithms instead', null); - - _diagram.initialOnly = deprecated_property('initialOnly is deprecated - see the initialLayout deprecation notice in the documentation', false); - - /** - * By default, all nodes are included, and edges are only included if both end-nodes are - * visible. If `.induceNodes` is set, then only nodes which have at least one edge will be - * shown. - * @method induceNodes - * @memberof dc_graph.diagram - * @instance - * @param {Boolean} [induceNodes=false] - * @return {Boolean} - * @return {dc_graph.diagram} - **/ - _diagram.induceNodes = property(false); - - /** - * If this flag is true, the positions of nodes and will be updated while layout is - * iterating. If false, the positions will only be updated once layout has - * stabilized. Note: this may not be compatible with transitionDuration. - * @method showLayoutSteps - * @memberof dc_graph.diagram - * @instance - * @param {Boolean} [showLayoutSteps=false] - * @return {Boolean} - * @return {dc_graph.diagram} - **/ - _diagram.showLayoutSteps = property(false); - - /** - * Assigns a legend object which will be displayed within the same SVG element and - * according to the visual encoding of this diagram. - * @method legend - * @memberof dc_graph.diagram - * @instance - * @param {Object} [legend=null] - * @return {Object} - * @return {dc_graph.diagram} - **/ - // (pre-deprecated; see below) - - /** - * Specifies another kind of child layer or interface. For example, this can - * be used to display tooltips on nodes using `dc_graph.tip`. - - * The child needs to support a `parent` method, the diagram to modify. - * @method child - * @memberof dc_graph.diagram - * @instance - * @param {String} [id] - the name of the child to modify or add - * @param {Object} [object] - the child object to add, or null to remove - * @example - * // Display tooltips on node hover, via the d3-tip library - * var tip = dc_graph.tip() - * tip.content(function(n, k) { - * // you can do an asynchronous call here, e.g. d3.json, if you need - * // to fetch data to show the tooltip - just call k() with the content - * k("This is " + n.orig.value.name + ""); - * }); - * diagram.child('tip', tip); - * @return {dc_graph.diagram} - **/ - _diagram.mode = _diagram.child = named_children(); - - _diagram.mode.reject = function(id, object) { - var rtype = _diagram.renderer().rendererType(); - if(!object) - return false; // null is always a valid mode for any renderer - if(!object.supportsRenderer) - onetime_trace('trace', 'could not check if "' + id + '" is compatible with ' + rtype); - else if(!object.supportsRenderer(rtype)) - return 'not installing "' + id + '" because it is not compatible with renderer ' + rtype; - return false; - }; - - _diagram.legend = deprecate_function(".legend() is deprecated; use .child() for more control & multiple legends", function(_) { - if(!arguments.length) - return _diagram.child('node-legend'); - _diagram.child('node-legend', _); - return _diagram; - }); - - /** - * Specify 'cola' (the default) or 'dagre' as the Layout Algorithm and it will replace the - * back-end. - * - * **Deprecated**: use {@link dc_graph.diagram#layoutEngine diagram.layoutEngine} with the engine - * object instead - * @method layoutAlgorithm - * @memberof dc_graph.diagram - * @instance - * @param {String} [algo='cola'] - the name of the layout algorithm to use - * @example - * // use dagre for layout - * diagram.layoutAlgorithm('dagre'); - * @return {dc_graph.diagram} - **/ - _diagram.layoutAlgorithm = function(value, skipWarning) { - if(!arguments.length) - return _diagram.layoutEngine() ? _diagram.layoutEngine().layoutAlgorithm() : 'cola'; - if(!skipWarning) - console.warn('dc.graph.diagram.layoutAlgorithm is deprecated - pass the layout engine object to dc_graph.diagram.layoutEngine instead'); - - var engine; - switch(value) { - case 'cola': - engine = dc_graph.cola_layout(); - break; - case 'dagre': - engine = dc_graph.dagre_layout(); - } - engine = dc_graph.webworker_layout(engine); - _diagram.layoutEngine(engine); - return this; - }; - - /** - * The layout engine determines positions of nodes and edges. - * @method layoutEngine - * @memberof dc_graph.diagram - * @instance - * @param {Object} [engine=null] - the layout engine to use - * @example - * // use cola with no webworker - * diagram.layoutEngine(dc_graph.cola_layout()); - * // use dagre with a webworker - * diagram.layoutEngine(dc_graph.webworker_layout(dc_graph.dagre_layout())); - **/ - _diagram.layoutEngine = property(null).react(function(val) { - if(val && val.parent) - val.parent(_diagram); - if(_diagram.renderer().isRendered()) { - // remove any calculated points, if engine did that - Object.keys(_edges).forEach(function(k) { - _edges[k].cola.points = null; - }); - // initialize engine - initLayout(val); - } - }); - - _diagram.renderer = property(dc_graph.render_svg().parent(_diagram)).react(function(r) { - if(_diagram.renderer()) - _diagram.renderer().parent(null); - r.parent(_diagram); - }); - - // S-spline any edges that are not going in this direction - _diagram.enforceEdgeDirection = property(null); - - _diagram.tickSize = deprecate_layout_algo_parameter('tickSize'); - - - _diagram.uniqueId = function() { - return _diagram.anchorName().replace(/[ .#=\[\]"]/g, '-'); - }; - - _diagram.edgeId = function(e) { - return 'edge-' + _diagram.edgeKey.eval(e).replace(/[^\w-_]/g, '-'); - }; - - _diagram.arrowId = function(e, kind) { - return 'arrow-' + kind + '-' + _diagram.uniqueId() + '-' + _diagram.edgeId(e); - }; - _diagram.textpathId = function(e) { - return 'textpath-' + _diagram.uniqueId() + '-' + _diagram.edgeId(e); - }; - - // this kind of begs a (meta)graph ADT - // instead of munging this into the diagram - _diagram.getNode = function(id) { - return _nodes[id] ? _nodes[id].orig : null; - }; - - _diagram.getWholeNode = function(id) { - return _nodes[id] ? _nodes[id] : null; - }; - - _diagram.getEdge = function(id) { - return _edges[id] ? _edges[id].orig : null; - }; - - _diagram.getWholeEdge = function(id) { - return _edges[id] ? _edges[id] : null; - }; - - // again, awful, we need an ADT - _diagram.getPort = function(nid, eid, name) { - return _ports[port_name(nid, eid, name)]; - }; - - _diagram.nodePorts = function() { - return _nodePorts; - }; - - _diagram.getWholeCluster = function(id) { - return _clusters[id] || null; - }; - - /** - * Instructs cola.js to fit the connected components. - * - * **Deprecated**: Use - * {@link dc_graph.cola_layout#handleDisconnected cola_layout.handleDisconnected} instead. - * @method handleDisconnected - * @memberof dc_graph.diagram - * @instance - * @param {Boolean} [handleDisconnected=true] - * @return {Boolean} - * @return {dc_graph.diagram} - **/ - _diagram.handleDisconnected = deprecate_layout_algo_parameter('handleDisconnected'); - - function initLayout(engine) { - if(!_diagram.layoutEngine()) - _diagram.layoutAlgorithm('cola', true); - (engine || _diagram.layoutEngine()).init({ - width: _diagram.width(), - height: _diagram.height() - }); - } - - _diagram.forEachChild = function(node, children, idf, f) { - children.enum().forEach(function(key) { - f(children(key), - node.filter(function(n) { return idf(n) === key; })); - }); - }; - _diagram.forEachShape = function(node, f) { - _diagram.forEachChild(node, _diagram.shape, function(n) { return n.dcg_shape.shape; }, f); - }; - _diagram.forEachContent = function(node, f) { - _diagram.forEachChild(node, _diagram.content, _diagram.nodeContent.eval, f); - }; - - function has_source_and_target(e) { - return !!e.source && !!e.target; - } - - // three stages: delete before layout, and modify & insert split the transitionDuration - _diagram.stagedDuration = function() { - return (_diagram.stageTransitions() !== 'none') ? - _diagram.transitionDuration() / 2 : - _diagram.transitionDuration(); - }; - - _diagram.stagedDelay = function(is_enter) { - return _diagram.stageTransitions() === 'none' || - _diagram.stageTransitions() === 'modins' === !is_enter ? - 0 : - _diagram.transitionDuration() / 2; - }; - - _diagram.isRunning = function() { - return _running; - }; - - function svg_specific(name) { - return trace_function('trace', name + '() is specific to the SVG renderer', function() { - return _diagram.renderer()[name].apply(this, arguments); - }); - } - - function call_on_renderer(name) { - return trace_function('trace', 'calling ' + name + '() on renderer', function() { - return _diagram.renderer()[name].apply(this, arguments); - }); - } - - _diagram.svg = svg_specific('svg'); - _diagram.g = svg_specific('g'); - _diagram.select = svg_specific('select'); - _diagram.selectAll = svg_specific('selectAll'); - _diagram.addOrRemoveDef = svg_specific('addOrRemoveDef'); - _diagram.selectAllNodes = svg_specific('selectAllNodes'); - _diagram.selectAllEdges = svg_specific('selectAllEdges'); - _diagram.selectNodePortsOfStyle = svg_specific('selectNodePortsOfStyle'); - _diagram.zoom = svg_specific('zoom'); - _diagram.translate = svg_specific('translate'); - _diagram.scale = svg_specific('scale'); - - function renderer_specific(name) { - return trace_function('trace', name + '() will have renderer-specific arguments', function() { - return _diagram.renderer()[name].apply(this, arguments); - }); - } - _diagram.renderNode = svg_specific('renderNode'); - _diagram.renderEdge = svg_specific('renderEdge'); - _diagram.redrawNode = svg_specific('redrawNode'); - _diagram.redrawEdge = svg_specific('redrawEdge'); - _diagram.reposition = call_on_renderer('reposition'); - - - /** - * Standard dc.js - * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin} - * method. Computes a new layout based on the nodes and edges in the edge groups, and - * displays the diagram. To the extent possible, the diagram will minimize changes in - * positions from the previous layout. `.render()` must be called the first time, and - * `.redraw()` can be called after that. - * - * `.redraw()` will be triggered by changes to the filters in any other charts in the same - * dc.js chart group. - * - * Unlike in dc.js, `redraw` executes asynchronously, because drawing can be computationally - * intensive, and the diagram will be drawn multiple times if - * {@link #dc_graph.diagram+showLayoutSteps showLayoutSteps} - * is enabled. Watch the {@link #dc_graph.diagram+on 'end'} event to know when layout is - * complete. - * @method redraw - * @memberof dc_graph.diagram - * @instance - * @return {dc_graph.diagram} - **/ - var _needsRedraw = false; - _diagram.redraw = function () { - // since dc.js can receive UI events and trigger redraws whenever it wants, - // and cola absolutely will not tolerate being poked while it's doing layout, - // we need to guard the startLayout call. - if(_running) { - _needsRedraw = true; - return this; - } - else return _diagram.startLayout(); - }; - - /** - * Standard dc.js - * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin} - * method. Erases any existing SVG elements and draws the diagram from scratch. `.render()` - * must be called the first time, and `.redraw()` can be called after that. - * @method render - * @memberof dc_graph.diagram - * @instance - * @return {dc_graph.diagram} - **/ - _diagram.render = function() { - if(_diagram.renderer().isRendered()) - _dispatch.reset(); - if(!_diagram.initLayoutOnRedraw()) - initLayout(); - - _nodes = {}; - _edges = {}; - _ports = {}; - _clusters = {}; - - // start out with 1:1 zoom - _diagram.x(d3.scale.linear() - .domain([0, _diagram.width()]) - .range([0, _diagram.width()])); - _diagram.y(d3.scale.linear() - .domain([0, _diagram.height()]) - .range([0, _diagram.height()])); - _diagram.renderer().initializeDrawing(); - _dispatch.render(); - _diagram.redraw(); - return this; - }; - - _diagram.refresh = call_on_renderer('refresh'); - - _diagram.width_is_automatic = function() { - return _width === 'auto'; - }; - - _diagram.height_is_automatic = function() { - return _height === 'auto'; - }; - - function detect_size_change() { - var oldWidth = _lastWidth, oldHeight = _lastHeight; - var newWidth = _diagram.width(), newHeight = _diagram.height(); - if(oldWidth !== newWidth || oldHeight !== newHeight) - _diagram.renderer().rezoom(oldWidth, oldHeight, newWidth, newHeight); - } - - // extract just the topology-related parts of nodes & edges to see if - // graph has changed wrt layout. imperfect heuristic: assume that the original - // data as well as all cola fields starting with dcg_ are related to topology - function dcg_fields(cola) { - var entries = Object.entries(cola) - .filter(function(entry) { return /^dcg_/.test(entry[0]); }); - return entries.reduce(function(p, entry) { - p[entry[0]] = entry[1]; - return p; - }, {}); - } - function topology_node(n) { - return {orig: get_original(n), cola: dcg_fields(n.cola)}; - } - function topology_edge(e) { - return {orig: get_original(e), cola: dcg_fields(e.cola)}; - } - function basic_node(n) { - var n0 = get_original(n); - return { - orig: { - key: n0.key, - value: Object.fromEntries( - Object.entries(n0.value) - .filter(function(kv) { return kv[0] !== 'fixedPos'; })) - } - }; - } - function basic_edge(e) { - return {orig: get_original(e)}; - } - - _diagram.startLayout = function () { - var nodes = _diagram.nodeGroup().all(); - var edges = _diagram.edgeGroup().all(); - var ports = _diagram.portGroup() ? _diagram.portGroup().all() : []; - var clusters = _diagram.clusterGroup() ? _diagram.clusterGroup().all() : []; - if(_running) { - throw new Error('dc_graph.diagram.redraw already running!'); - } - _running = true; - - if(_diagram.width_is_automatic() || _diagram.height_is_automatic()) - detect_size_change(); - else - _diagram.renderer().resize(); - - if(_diagram.initLayoutOnRedraw()) - initLayout(); - _diagram.layoutEngine().stop(); - _dispatch.preDraw(); - - // ordering shouldn't matter, but we support ordering in case it does - if(_diagram.nodeOrdering()) { - nodes = nodes.slice(0).sort(function(a, b) { - return d3.ascending(_diagram.nodeOrdering()(a), _diagram.nodeOrdering()(b)); - }); - } - if(_diagram.edgeOrdering()) { - edges = edges.slice(0).sort(function(a, b) { - return d3.ascending(_diagram.edgeOrdering()(a), _diagram.edgeOrdering()(b)); - }); - } - - var wnodes = regenerate_objects(_nodes, nodes, null, function(v) { - return _diagram.nodeKey()(v); - }, function(v1, v) { - v1.orig = v; - v1.cola = v1.cola || {}; - v1.cola.dcg_nodeKey = _diagram.nodeKey.eval(v1); - v1.cola.dcg_nodeParentCluster = _diagram.nodeParentCluster.eval(v1); - _diagram.layoutEngine().populateLayoutNode(v1.cola, v1); - }); - var wedges = regenerate_objects(_edges, edges, null, function(e) { - return _diagram.edgeKey()(e); - }, function(e1, e) { - e1.orig = e; - e1.cola = e1.cola || {}; - e1.cola.dcg_edgeKey = _diagram.edgeKey.eval(e1); - e1.cola.dcg_edgeSource = _diagram.edgeSource.eval(e1); - e1.cola.dcg_edgeTarget = _diagram.edgeTarget.eval(e1); - e1.source = _nodes[e1.cola.dcg_edgeSource]; - e1.target = _nodes[e1.cola.dcg_edgeTarget]; - e1.sourcePort = e1.sourcePort || {}; - e1.targetPort = e1.targetPort || {}; - _diagram.layoutEngine().populateLayoutEdge(e1.cola, e1); - }); - - // remove edges that don't have both end nodes - wedges = wedges.filter(has_source_and_target); - - // remove self-edges (since we can't draw them - will be option later) - wedges = wedges.filter(function(e) { return e.source !== e.target; }); - - wedges = wedges.filter(_diagram.edgeIsShown.eval); - - // now we know which ports should exist - var needports = wedges.map(function(e) { - if(_diagram.edgeSourcePortName.eval(e)) - return port_name(_diagram.edgeSource.eval(e), null, _diagram.edgeSourcePortName.eval(e)); - else return port_name(null, _diagram.edgeKey.eval(e), 'source'); - }); - needports = needports.concat(wedges.map(function(e) { - if(_diagram.edgeTargetPortName.eval(e)) - return port_name(_diagram.edgeTarget.eval(e), null, _diagram.edgeTargetPortName.eval(e)); - else return port_name(null, _diagram.edgeKey.eval(e), 'target'); - })); - // remove any invalid ports so they don't crash in confusing ways later - ports = ports.filter(function(p) { - return _diagram.portNodeKey() && _diagram.portNodeKey()(p) || - _diagram.portEdgeKey() && _diagram.portEdgeKey()(p); - }); - var wports = regenerate_objects(_ports, ports, needports, function(p) { - return port_name(_diagram.portNodeKey() && _diagram.portNodeKey()(p), - _diagram.portEdgeKey() && _diagram.portEdgeKey()(p), - _diagram.portName()(p)); - }, function(p1, p) { - p1.orig = p; - if(p1.named) - p1.edges = []; - }, function(k, p) { - console.assert(k, 'should have screened out invalid ports'); - // it's dumb to parse the id we just created. as usual, i blame the lack of metagraphs - var parse = split_port_name(k); - if(parse.nodeKey) { - p.node = _nodes[parse.nodeKey]; - p.named = true; - } - else { - var e = _edges[parse.edgeKey]; - p.node = e[parse.name]; - p.edges = [e]; - p.named = false; - } - p.name = parse.name; - }); - // remove any ports where the end-node was not found, to avoid crashing elsewhere - wports = wports.filter(function(p) { return p.node; }); - - // find all edges for named ports - wedges.forEach(function(e) { - var name = _diagram.edgeSourcePortName.eval(e); - if(name) - _ports[port_name(_diagram.nodeKey.eval(e.source), null, name)].edges.push(e); - name = _diagram.edgeTargetPortName.eval(e); - if(name) - _ports[port_name(_diagram.nodeKey.eval(e.target), null, name)].edges.push(e); - }); - - // optionally, delete nodes that have no edges - if(_diagram.induceNodes()) { - var keeps = {}; - wedges.forEach(function(e) { - keeps[e.cola.dcg_edgeSource] = true; - keeps[e.cola.dcg_edgeTarget] = true; - }); - wnodes = wnodes.filter(function(n) { return keeps[n.cola.dcg_nodeKey]; }); - for(var k in _nodes) - if(!keeps[k]) - delete _nodes[k]; - } - - var needclusters = d3.set(wnodes.map(function(n) { - return _diagram.nodeParentCluster.eval(n); - }).filter(identity)).values(); - - var wclusters = regenerate_objects(_clusters, clusters, needclusters, function(c) { - return _diagram.clusterKey()(c); - }, function(c1, c) { // assign - c1.orig = c; - c1.cola = c1.cola || { - dcg_clusterKey: _diagram.clusterKey.eval(c1), - dcg_clusterParent: _diagram.clusterParent.eval(c1) - }; - }, function(k, c) { // create - }); - - wnodes.forEach(function(v, i) { - v.index = i; - }); - - // announce new data - _dispatch.data(_diagram, _nodes, wnodes, _edges, wedges, _ports, wports); - _stats = {nnodes: wnodes.length, nedges: wedges.length}; - - // fixed nodes may have been affected by .data() so calculate now - wnodes.forEach(function(v) { - if(_diagram.nodeFixed()) - v.cola.dcg_nodeFixed = _diagram.nodeFixed.eval(v); - }); - - // annotate parallel edges so we can draw them specially - if(_diagram.parallelEdgeOffset()) { - var em = new Array(wnodes.length); - for(var i = 0; i < wnodes.length; ++i) - em[i] = new Array(i); - wedges.forEach(function(e) { - e.pos = e.pos || {}; - var min, max, minattr, maxattr; - if(e.source.index < e.target.index) { - min = e.source.index; max = e.target.index; - minattr = 'edgeSourcePortName'; maxattr = 'edgeTargetPortName'; - } else { - max = e.source.index; min = e.target.index; - maxattr = 'edgeSourcePortName'; minattr = 'edgeTargetPortName'; - } - var minport = _diagram[minattr].eval(e) || 'no port', - maxport = _diagram[maxattr].eval(e) || 'no port'; - em[max][min] = em[max][min] || {}; - em[max][min][maxport] = em[max][min][maxport] || {}; - e.parallel = em[max][min][maxport][minport] = em[max][min][maxport][minport] || { - rev: [], - edges: [] - }; - e.parallel.edges.push(e); - e.parallel.rev.push(min !== e.source.index); - }); - } - - var drawState = _diagram.renderer().startRedraw(_dispatch, wnodes, wedges); - - // really we should have layout chaining like in the good old Dynagraph days - // the ordering of this and the previous 4 statements is somewhat questionable - if(_diagram.initialLayout()) - _diagram.initialLayout()(_diagram, wnodes, wedges); - - // no layout if the topology and layout parameters haven't changed - var skip_layout = false; - if(!_diagram.layoutUnchanged()) { - var node_fields = _diagram.nodeChangeSelect()(), - edge_fields = _diagram.edgeChangeSelect()(); - var nodes_snapshot = JSON.stringify(wnodes.map(node_fields)); - var edges_snapshot = JSON.stringify(wedges.map(edge_fields)); - if(nodes_snapshot === _nodes_snapshot && edges_snapshot === _edges_snapshot) - skip_layout = true; - _nodes_snapshot = nodes_snapshot; - _edges_snapshot = edges_snapshot; - } - - // edge lengths may be affected by node sizes - wedges.forEach(function(e) { - e.cola.dcg_edgeLength = _diagram.edgeLength.eval(e); - }); - - // cola constraints always use indices, but node references - // are more friendly, so translate those - - // i am not satisfied with this constraint generation api... - // https://github.com/dc-js/dc.graph.js/issues/10 - var constraints = _diagram.constrain()(_diagram, wnodes, wedges); - - // warn if there are any loops (before changing names to indices) - // it would be better to do this in webcola - // (for one thing, this duplicates logic in rectangle.ts) - // but by that time it has lost the names of things, - // so the output would be difficult to use - var constraints_by_left = constraints.reduce(function(p, c) { - if(c.type) { - switch(c.type) { - case 'alignment': - var left = c.offsets[0].node; - p[left] = p[left] || []; - c.offsets.slice(1).forEach(function(o) { - p[left].push({node: o.node, in_constraint: c}); - }); - break; - } - } else if(c.axis) { - p[c.left] = p[c.left] || []; - p[c.left].push({node: c.right, in_constraint: c}); - } - return p; - }, {}); - var touched = {}; - function find_constraint_loops(con, stack) { - var left = con.node; - stack = stack || []; - var loop = stack.find(function(con) { return con.node === left; }); - stack = stack.concat([con]); - if(loop) - console.warn('found a loop in constraints', stack); - if(touched[left]) - return; - touched[left] = true; - if(!constraints_by_left[left]) - return; - constraints_by_left[left].forEach(function(right) { - find_constraint_loops(right, stack); - }); - } - Object.keys(constraints_by_left).forEach(function(left) { - if(!touched[left]) - find_constraint_loops({node: left, in_constraint: null}); - }); - - // translate references from names to indices (ugly) - var invalid_constraints = []; - constraints.forEach(function(c) { - if(c.type) { - switch(c.type) { - case 'alignment': - c.offsets.forEach(function(o) { - o.node = _nodes[o.node].index; - }); - break; - case 'circle': - c.nodes.forEach(function(n) { - n.node = _nodes[n.node].index; - }); - break; - } - } else if(c.axis && c.left && c.right) { - c.left = _nodes[c.left].index; - c.right = _nodes[c.right].index; - } - else invalid_constraints.push(c); - }); - - if(invalid_constraints.length) - console.warn(invalid_constraints.length + ' invalid constraints', invalid_constraints); - - // pseudo-cola.js features - - // 1. non-layout edges are drawn but not told to cola.js - var layout_edges = wedges.filter(_diagram.edgeIsLayout.eval); - var nonlayout_edges = wedges.filter(function(x) { - return !_diagram.edgeIsLayout.eval(x); - }); - - // 2. type=circle constraints - var circle_constraints = constraints.filter(function(c) { - return c.type === 'circle'; - }); - constraints = constraints.filter(function(c) { - return c.type !== 'circle'; - }); - circle_constraints.forEach(function(c) { - var R = (c.distance || _diagram.baseLength()*4) / (2*Math.sin(Math.PI/c.nodes.length)); - var nindices = c.nodes.map(function(x) { return x.node; }); - var namef = function(i) { - return _diagram.nodeKey.eval(wnodes[i]); - }; - var wheel = dc_graph.wheel_edges(namef, nindices, R) - .map(function(e) { - var e1 = {internal: e}; - e1.source = _nodes[e.sourcename]; - e1.target = _nodes[e.targetname]; - return e1; - }); - layout_edges = layout_edges.concat(wheel); - }); - - // 3. ordered alignment - var ordered_constraints = constraints.filter(function(c) { - return c.type === 'ordering'; - }); - constraints = constraints.filter(function(c) { - return c.type !== 'ordering'; - }); - ordered_constraints.forEach(function(c) { - var sorted = c.nodes.map(function(n) { return _nodes[n]; }); - if(c.ordering) { - var orderingFn = param(c.ordering); - sorted = sorted.sort(function(a, b) { - return d3.ascending(orderingFn(a), orderingFn(b)); - }); - } - var left; - sorted.forEach(function(n, i) { - if(i===0) - left = n; - else { - constraints.push({ - left: left.index, - right: (left = n).index, - axis: c.axis, - gap: c.gap - }); - } - }); - }); - if(skip_layout) { - _running = false; - // init_node_ports? - _diagram.renderer().draw(drawState, true); - _diagram.renderer().drawPorts(drawState); - _diagram.renderer().fireTSEvent(_dispatch, drawState); - check_zoom(drawState); - return this; - } - var startTime = Date.now(); - - function populate_cola(rnodes, redges, rclusters) { - rnodes.forEach(function(rn) { - var n = _nodes[rn.dcg_nodeKey]; - if(!n) { - console.warn('received node "' + rn.dcg_nodeKey + '" that we did not send, ignored'); - return; - } - n.cola.x = rn.x; - n.cola.y = rn.y; - n.cola.z = rn.z; - }); - redges.forEach(function(re) { - var e = _edges[re.dcg_edgeKey]; - if(!e) { - console.warn('received edge "' + re.dcg_edgeKey + '" that we did not send, ignored'); - return; - } - if(re.points) - e.cola.points = re.points; - }); - wclusters.forEach(function(c) { - c.cola.bounds = null; - }); - if(rclusters) - rclusters.forEach(function(rc) { - var c = _clusters[rc.dcg_clusterKey]; - if(!c) { - console.warn('received cluster "' + rc.dcg_clusterKey + '" that we did not send, ignored'); - return; - } - if(rc.bounds) - c.cola.bounds = rc.bounds; - }); - } - _diagram.layoutEngine() - .on('tick.diagram', function(nodes, edges, clusters) { - var elapsed = Date.now() - startTime; - if(!_diagram.initialOnly()) - populate_cola(nodes, edges, clusters); - if(_diagram.showLayoutSteps()) { - init_node_ports(_nodes, wports); - _dispatch.receivedLayout(_diagram, _nodes, wnodes, _edges, wedges, _ports, wports); - propagate_port_positions(_nodes, wedges, _ports); - _diagram.renderer().draw(drawState, true); - _diagram.renderer().drawPorts(drawState); - // should do this only once - _diagram.renderer().fireTSEvent(_dispatch, drawState); - } - if(_needsRedraw || _diagram.timeLimit() && elapsed > _diagram.timeLimit()) { - console.log('cancelled'); - _diagram.layoutEngine().stop(); - } - }) - .on('end.diagram', function(nodes, edges, clusters) { - if(!_diagram.showLayoutSteps()) { - if(!_diagram.initialOnly()) - populate_cola(nodes, edges, clusters); - init_node_ports(_nodes, wports); - _dispatch.receivedLayout(_diagram, _nodes, wnodes, _edges, wedges, _ports, wports); - propagate_port_positions(_nodes, wedges, _ports); - _diagram.renderer().draw(drawState, true); - _diagram.renderer().drawPorts(drawState); - _diagram.renderer().fireTSEvent(_dispatch, drawState); - } - else _diagram.layoutDone(true); - check_zoom(drawState); - }) - .on('start.diagram', function() { - console.log('algo ' + _diagram.layoutEngine().layoutAlgorithm() + ' started.'); - _dispatch.start(); - }); - - if(_diagram.initialOnly()) - _diagram.layoutEngine().dispatch().end(wnodes, wedges); - else { - _dispatch.start(); // cola doesn't seem to fire this itself? - var engine = _diagram.layoutEngine(); - engine.data( - { width: _diagram.width(), height: _diagram.height() }, - wnodes.map(function(v) { - var lv = Object.assign({}, v.cola, v.dcg_shape); - if(engine.annotateNode) - engine.annotateNode(lv, v); - else if(engine.extractNodeAttrs) - Object.keys(engine.extractNodeAttrs()).forEach(function(key) { - lv[key] = engine.extractNodeAttrs()[key](v.orig); - }); - return lv; - }), - layout_edges.map(function(e) { - var le = e.cola; - if(engine.annotateEdge) - engine.annotateEdge(le, e); - else if(engine.extractEdgeAttrs) - Object.keys(engine.extractEdgeAttrs()).forEach(function(key) { - le[key] = engine.extractEdgeAttrs()[key](e.orig); - }); - return le; - }), - wclusters.map(function(c) { - return c.cola; - }), - constraints - ); - engine.start(); - } - return this; - }; - - function check_zoom(drawState) { - var do_zoom, animate = true; - if(_diagram.width_is_automatic() || _diagram.height_is_automatic()) - detect_size_change(); - switch(_diagram.autoZoom()) { - case 'always-skipanimonce': - animate = false; - _diagram.autoZoom('always'); - case 'always': - do_zoom = true; - break; - case 'once-noanim': - animate = false; - case 'once': - do_zoom = true; - _diagram.autoZoom(null); - break; - default: - do_zoom = false; - } - calc_bounds(drawState); - if(do_zoom) - auto_zoom(animate); - } - - function norm(v) { - var len = Math.hypot(v[0], v[1]); - return [v[0]/len, v[1]/len]; - } - function edge_vec(n, e) { - var dy = e.target.cola.y - e.source.cola.y, - dx = e.target.cola.x - e.source.cola.x; - if(dy === 0 && dx === 0) - return [1, 0]; - if(e.source !== n) - dy = -dy, dx = -dx; - if(e.parallel && e.parallel.edges.length > 1 && e.source.index > e.target.index) - dy = -dy, dx = -dx; - return norm([dx, dy]); - } - function init_node_ports(nodes, wports) { - _nodePorts = {}; - // assemble port-lists for nodes, again because we don't have a metagraph. - wports.forEach(function(p) { - var nid = _diagram.nodeKey.eval(p.node); - var np = _nodePorts[nid] = _nodePorts[nid] || []; - np.push(p); - }); - for(var nid in _nodePorts) { - var n = nodes[nid], - nports = _nodePorts[nid]; - // initial positions: use average of edge vectors, if any, or existing position - nports.forEach(function(p) { - if(_diagram.portElastic.eval(p) && p.edges.length) { - var vecs = p.edges.map(edge_vec.bind(null, n)); - p.vec = [ - d3.sum(vecs, function(v) { return v[0]; })/vecs.length, - d3.sum(vecs, function(v) { return v[1]; })/vecs.length - ]; - } else p.vec = p.vec || undefined; - p.pos = null; - }); - } - } - function propagate_port_positions(nodes, wedges, ports) { - // make sure we have projected vectors to positions - for(var nid in _nodePorts) { - var n = nodes[nid]; - _nodePorts[nid].forEach(function(p) { - if(!p.pos) - project_port(_diagram, n, p); - }); - } - - // propagate port positions to edge endpoints - wedges.forEach(function(e) { - var name = _diagram.edgeSourcePortName.eval(e); - e.sourcePort.pos = name ? ports[port_name(_diagram.nodeKey.eval(e.source), null, name)].pos : - ports[port_name(null, _diagram.edgeKey.eval(e), 'source')].pos; - name = _diagram.edgeTargetPortName.eval(e); - e.targetPort.pos = name ? ports[port_name(_diagram.nodeKey.eval(e.target), null, name)].pos : - ports[port_name(null, _diagram.edgeKey.eval(e), 'target')].pos; - console.assert(e.sourcePort.pos && e.targetPort.pos); - }); - } - - _diagram.requestRefresh = function(durationOverride) { - window.requestAnimationFrame(function() { - var transdur; - if(durationOverride !== undefined) { - transdur = _diagram.transitionDuration(); - _diagram.transitionDuration(durationOverride); - } - _diagram.renderer().refresh(); - if(durationOverride !== undefined) - _diagram.transitionDuration(transdur); - }); - }; - - _diagram.layoutDone = function(happens) { - _dispatch.end(happens); - _running = false; - if(_needsRedraw) { - _needsRedraw = false; - window.setTimeout(function() { - if(!_diagram.isRunning()) // someone else may already have started - _diagram.redraw(); - }, 0); - } - }; - - function enforce_path_direction(path, spos, tpos) { - var points = path.points, first = points[0], last = points[points.length-1]; - switch(_diagram.enforceEdgeDirection()) { - case 'LR': - if(spos.x >= tpos.x) { - var dx = first.x - last.x; - return { - points: [ - first, - {x: first.x + dx, y: first.y - dx/2}, - {x: last.x - dx, y: last.y - dx/2}, - last - ], - bezDegree: 3, - sourcePort: path.sourcePort, - targetPort: path.targetPort - }; - } - break; - case 'TB': - if(spos.y >= tpos.y) { - var dy = first.y - last.y; - return { - points: [ - first, - {x: first.x + dy/2, y: first.y + dy}, - {x: last.x + dy/2, y: last.y - dy}, - last - ], - bezDegree: 3, - sourcePort: path.sourcePort, - targetPort: path.targetPort - }; - } - break; - } - return path; - } - _diagram.calcEdgePath = function(e, age, sx, sy, tx, ty) { - var parallel = e.parallel; - var source = e.source, target = e.target; - if(parallel.edges.length > 1 && e.source.index > e.target.index) { - var t; - t = target; target = source; source = t; - t = tx; tx = sx; sx = t; - t = ty; ty = sy; sy = t; - } - var source_padding = source.dcg_ry + - _diagram.nodeStrokeWidth.eval(source) / 2, - target_padding = target.dcg_ry + - _diagram.nodeStrokeWidth.eval(target) / 2; - for(var p = 0; p < parallel.edges.length; ++p) { - // alternate parallel edges over, then under - var dir = (!!(p%2) === (sx < tx)) ? -1 : 1, - port = Math.floor((p+1)/2), - last = port > 0 ? parallel.edges[p > 2 ? p - 2 : 0].pos[age].path : null; - var path = draw_edge_to_shapes(_diagram, e, sx, sy, tx, ty, - last, dir, _diagram.parallelEdgeOffset(), - source_padding, target_padding - ); - if(parallel.edges.length > 1 && parallel.rev[p]) - path.points.reverse(); - if(_diagram.enforceEdgeDirection()) - path = enforce_path_direction(path, source.cola, target.cola); - var path0 = { - points: path.points, - bezDegree: path.bezDegree - }; - var alengths = scaled_arrow_lengths(_diagram, parallel.edges[p]); - path = clip_path_to_arrows(alengths.headLength, alengths.tailLength, path); - var points = path.points, points0 = path0.points; - parallel.edges[p].pos[age] = { - path: path, - full: path0, - orienthead: angle_between_points(points[points.length-1], points0[points0.length-1]) + 'rad', - orienttail: angle_between_points(points[0], points0[0]) + 'rad' - }; - } - }; - - function node_bounds(n) { - var bounds = {left: n.cola.x - n.dcg_rx, top: n.cola.y - n.dcg_ry, - right: n.cola.x + n.dcg_rx, bottom: n.cola.y + n.dcg_ry}; - if(_diagram.portStyle.enum().length) { - var ports = _nodePorts[_diagram.nodeKey.eval(n)]; - if(ports) - ports.forEach(function(p) { - var portStyle =_diagram.portStyleName.eval(p); - if(!portStyle || !_diagram.portStyle(portStyle)) - return; - var pb = _diagram.portStyle(portStyle).portBounds(p); - pb.left += n.cola.x; pb.top += n.cola.y; - pb.right += n.cola.x; pb.bottom += n.cola.y; - bounds = union_bounds(bounds, pb); - }); - } - return bounds; - } - - function union_bounds(b1, b2) { - return { - left: Math.min(b1.left, b2.left), - top: Math.min(b1.top, b2.top), - right: Math.max(b1.right, b2.right), - bottom: Math.max(b1.bottom, b2.bottom) - }; - } - - function point_to_bounds(p) { - return { - left: p.x, - top: p.y, - right: p.x, - bottom: p.y - }; - } - - function edge_bounds(e) { - // assumption: edge must have some points - var points = e.pos.new.path.points; - return points.map(point_to_bounds).reduce(union_bounds); - } - - _diagram.calculateBounds = function(ndata, edata) { - // assumption: there can be no edges without nodes - var bounds = ndata.map(node_bounds).reduce(union_bounds); - return edata.map(edge_bounds).reduce(union_bounds, bounds); - }; - var _bounds; - function calc_bounds(drawState) { - if((_diagram.fitStrategy() || _diagram.restrictPan())) { - _bounds = _diagram.renderer().calculateBounds(drawState); - } - } - - _diagram.animateZoom = function(_) { - if(!arguments.length) - return _animateZoom; - _animateZoom = _; - return _diagram; - }; - - function auto_zoom(animate) { - if(_diagram.fitStrategy()) { - if(!_bounds) - return; - var vwidth = _bounds.right - _bounds.left, vheight = _bounds.bottom - _bounds.top, - swidth = _diagram.width() - _diagram.margins().left - _diagram.margins().right, - sheight = _diagram.height() - _diagram.margins().top - _diagram.margins().bottom; - var fitS = _diagram.fitStrategy(), translate = [0,0], scale = 1; - if(['default', 'vertical', 'horizontal'].indexOf(fitS) >= 0) { - var sAR = sheight / swidth, vAR = vheight / vwidth, - vrl = vAR 2) - throw new Error("align_ expecting 0-2 sides, not " + sides.length); - var bounds = margined_bounds(); - translate = _diagram.renderer().translate(); - scale = _diagram.renderer().scale(); - var vertalign = false, horzalign = false; - sides.forEach(function(s) { - switch(s) { - case 'l': - translate[0] = align_left(translate, bounds.left); - horzalign = true; - break; - case 't': - translate[1] = align_top(translate, bounds.top); - vertalign = true; - break; - case 'r': - translate[0] = align_right(translate, bounds.right); - horzalign = true; - break; - case 'b': - translate[1] = align_bottom(translate, bounds.bottom); - vertalign = true; - break; - case 'c': // handled below - break; - default: - throw new Error("align_ expecting l t r b or c, not '" + s + "'"); - } - }); - if(sides.includes('c')) { - if(!horzalign) - translate[0] = center_horizontally(translate, bounds); - if(!vertalign) - translate[1] = center_vertically(translate, bounds); - } - } - else if(fitS === 'zoom') { - scale = _diagram.renderer().scale(); - translate = bring_in_bounds(_diagram.renderer().translate()); - } - else - throw new Error('unknown fitStrategy type ' + typeof fitS); - - _animateZoom = animate; - _diagram.renderer().translate(translate).scale(scale).commitTranslateScale(); - _animateZoom = false; - } - } - function namespace_event_reducer(msg_fun) { - return function(p, ev) { - var namespace = {}; - p[ev] = function(ns) { - return namespace[ns] = namespace[ns] || onetime_trace('trace', msg_fun(ns, ev)); - }; - return p; - }; - } - var renderer_specific_events = ['drawn', 'transitionsStarted', 'zoomed'] - .reduce(namespace_event_reducer(function(ns, ev) { - return 'subscribing "' + ns + '" to event "' + ev + '" which takes renderer-specific parameters'; - }), {}); - var inconsistent_arguments = ['end'] - .reduce(namespace_event_reducer(function(ns, ev) { - return 'subscribing "' + ns + '" to event "' + ev + '" which may receive inconsistent arguments'; - }), {}); - - /** - * Standard dc.js - * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin} - * method. Attaches an event handler to the diagram. The currently supported events are - * * `start()` - layout is starting - * * `drawn(nodes, edges)` - the node and edge elements have been rendered to the screen - * and can be modified through the passed d3 selections. - * * `end()` - diagram layout has completed. - * @method on - * @memberof dc_graph.diagram - * @instance - * @param {String} [event] - the event to subscribe to - * @param {Function} [f] - the event handler - * @return {dc_graph.diagram} - **/ - _diagram.on = function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - var evns = event.split('.'), - warning = renderer_specific_events[evns[0]] || inconsistent_arguments[evns[0]]; - if(warning) - warning(evns[1] || '')(); - _dispatch.on(event, f); - return this; - }; - - /** - * Returns an object with current statistics on graph layout. - * * `nnodes` - number of nodes displayed - * * `nedges` - number of edges displayed - * @method getStats - * @memberof dc_graph.diagram - * @instance - * @return {} - * @return {dc_graph.diagram} - **/ - _diagram.getStats = function() { - return _stats; - }; - - /** - * Standard dc.js - * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin} - * method. Gets or sets the x scale. - * @method x - * @memberof dc_graph.diagram - * @instance - * @param {d3.scale} [scale] - * @return {d3.scale} - * @return {dc_graph.diagram} - - **/ - _diagram.x = property(null); - - /** - * Standard dc.js - * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin} - * method. Gets or sets the y scale. - * @method y - * @memberof dc_graph.diagram - * @instance - * @param {d3.scale} [scale] - * @return {d3.scale} - * @return {dc_graph.diagram} - - **/ - _diagram.y = property(null); - - /** - * Standard dc.js - * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin} - * method. Causes all charts in the chart group to be redrawn. - * @method redrawGroup - * @memberof dc_graph.diagram - * @instance - * @return {dc_graph.diagram} - **/ - _diagram.redrawGroup = function () { - dc.redrawAll(_chartGroup); - }; - - /** - * Standard dc.js - * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin} - * method. Causes all charts in the chart group to be rendered. - * @method renderGroup - * @memberof dc_graph.diagram - * @instance - * @return {dc_graph.diagram} - **/ - _diagram.renderGroup = function () { - dc.renderAll(_chartGroup); - }; - - /** - * Creates an svg marker definition for drawing edge arrow tails or heads. - * - * Sorry, this is not currently documented - please see - * [arrows.js](https://github.com/dc-js/dc.graph.js/blob/develop/src/arrows.js) - * for examples - * @return {dc_graph.diagram} - **/ - _diagram.defineArrow = function(name, defn) { - if(typeof defn !== 'function') - throw new Error('sorry, defineArrow no longer takes specific shape parameters, and the parameters have changed too much to convert them. it takes a name and a function returning a definition - please look at arrows.js for new format'); - _arrows[name] = defn; - return _diagram; - }; - - // hmm - _diagram.arrows = function() { - return _arrows; - }; - - Object.keys(dc_graph.builtin_arrows).forEach(function(aname) { - var defn = dc_graph.builtin_arrows[aname]; - _diagram.defineArrow(aname, defn); - }); - - function margined_bounds() { - var bounds = _bounds || {left: 0, top: 0, right: 0, bottom: 0}; - var scale = _diagram.renderer().scale(); - return { - left: bounds.left - _diagram.margins().left/scale, - top: bounds.top - _diagram.margins().top/scale, - right: bounds.right + _diagram.margins().right/scale, - bottom: bounds.bottom + _diagram.margins().bottom/scale - }; - } - - // with thanks to comments in https://github.com/d3/d3/issues/1084 - function align_left(translate, x) { - return translate[0] - _diagram.x()(x) + _diagram.x().range()[0]; - } - function align_top(translate, y) { - return translate[1] - _diagram.y()(y) + _diagram.y().range()[0]; - } - function align_right(translate, x) { - return translate[0] - _diagram.x()(x) + _diagram.x().range()[1]; - } - function align_bottom(translate, y) { - return translate[1] - _diagram.y()(y) + _diagram.y().range()[1];; - } - function center_horizontally(translate, bounds) { - return (align_left(translate, bounds.left) + align_right(translate, bounds.right))/2; - } - function center_vertically(translate, bounds) { - return (align_top(translate, bounds.top) + align_bottom(translate, bounds.bottom))/2; - } - - function bring_in_bounds(translate) { - var xDomain = _diagram.x().domain(), yDomain = _diagram.y().domain(); - var bounds = margined_bounds(); - var less1 = bounds.left < xDomain[0], less2 = bounds.right < xDomain[1], - lessExt = (bounds.right - bounds.left) < (xDomain[1] - xDomain[0]); - var align, nothing = 0; - if(less1 && less2) - if(lessExt) - align = 'left'; - else - align = 'right'; - else if(!less1 && !less2) - if(lessExt) - align = 'right'; - else - align = 'left'; - switch(align) { - case 'left': - translate[0] = align_left(translate, bounds.left); - break; - case 'right': - translate[0] = align_right(translate, bounds.right); - break; - default: - ++nothing; - } - less1 = bounds.top < yDomain[0]; less2 = bounds.bottom < yDomain[1]; - lessExt = (bounds.bottom - bounds.top) < (yDomain[1] - yDomain[0]); - if(less1 && less2) - if(lessExt) - align = 'top'; - else - align = 'bottom'; - else if(!less1 && !less2) - if(lessExt) - align = 'bottom'; - else - align = 'top'; - switch(align) { - case 'top': - translate[1] = align_top(translate, bounds.top); - break; - case 'bottom': - translate[1] = align_bottom(translate, bounds.bottom); - break; - default: - ++nothing; - } - return translate; - - } - - _diagram.doZoom = function() { - if(_diagram.width_is_automatic() || _diagram.height_is_automatic()) - detect_size_change(); - var translate, scale = d3.event.scale; - if(_diagram.restrictPan()) - _diagram.renderer().translate(translate = bring_in_bounds(d3.event.translate)); - else translate = d3.event.translate; - _diagram.renderer().globalTransform(translate, scale, _animateZoom); - _dispatch.zoomed(translate, scale, _diagram.x().domain(), _diagram.y().domain()); - }; - - _diagram.invertCoord = function(clientCoord) { - return [ - _diagram.x().invert(clientCoord[0]), - _diagram.y().invert(clientCoord[1]) - ]; - }; - - /** - * Set the root SVGElement to either be any valid [d3 single - * selector](https://github.com/mbostock/d3/wiki/Selections#selecting-elements) specifying a dom - * block element such as a div; or a dom element or d3 selection. This class is called - * internally on diagram initialization, but be called again to relocate the diagram. However, it - * will orphan any previously created SVGElements. - * @method anchor - * @memberof dc_graph.diagram - * @instance - * @param {anchorSelector|anchorNode|d3.selection} [parent] - * @param {String} [chartGroup] - * @return {String|node|d3.selection} - * @return {dc_graph.diagram} - */ - _diagram.anchor = function(parent, chartGroup) { - if (!arguments.length) { - return _anchor; - } - if (parent) { - if (parent.select && parent.classed) { // detect d3 selection - _anchor = parent.node(); - } else { - _anchor = parent; - } - _diagram.root(d3.select(_anchor)); - _diagram.root().classed(dc_graph.constants.CHART_CLASS, true); - dc.registerChart(_diagram, chartGroup); - } else { - throw new dc.errors.BadArgumentException('parent must be defined'); - } - _chartGroup = chartGroup; - return _diagram; - }; - - /** - * Returns the internal numeric ID of the chart. - * @method chartID - * @memberof dc.baseMixin - * @instance - * @returns {String} - */ - _diagram.chartID = function () { - return _diagram.__dcFlag__; - }; - - /** - * Returns the DOM id for the chart's anchored location. - * @method anchorName - * @memberof dc_graph.diagram - * @instance - * @return {String} - */ - _diagram.anchorName = function () { - var a = _diagram.anchor(); - if (a && a.id) { - return a.id; - } - if (a && a.replace) { - return a.replace('#', ''); - } - return 'dc-graph' + _diagram.chartID(); - }; - - return _diagram.anchor(parent, chartGroup); -}; - -dc_graph.render_svg = function() { - var _svg = null, _defs = null, _g = null, _nodeLayer = null, _edgeLayer = null; - var _animating = false; // do not refresh during animations - var _zoom; - var _renderer = {}; - - _renderer.rendererType = function() { - return 'svg'; - }; - - _renderer.parent = property(null); - - _renderer.renderNode = _renderer._enterNode = function(nodeEnter) { - if(_renderer.parent().nodeTitle()) - nodeEnter.append('title'); - nodeEnter.each(infer_shape(_renderer.parent())); - _renderer.parent().forEachShape(nodeEnter, function(shape, node) { - node.call(shape.create); - }); - return _renderer; - }; - _renderer.redrawNode = _renderer._updateNode = function(node) { - var changedShape = node.filter(shape_changed(_renderer.parent())); - changedShape.selectAll('.node-outline,.node-fill').remove(); - changedShape.each(infer_shape(_renderer.parent())); - _renderer.parent().forEachShape(changedShape, function(shape, node) { - node.call(shape.create); - }); - node.select('title') - .text(_renderer.parent().nodeTitle.eval); - _renderer.parent().forEachContent(node, function(contentType, node) { - node.call(contentType.update); - _renderer.parent().forEachShape(contentType.selectContent(node), function(shape, content) { - content - .call(fit_shape(shape, _renderer.parent())); - }); - }); - _renderer.parent().forEachShape(node, function(shape, node) { - node.call(shape.update); - }); - node.select('.node-fill') - .attr({ - fill: compose(_renderer.parent().nodeFillScale() || identity, _renderer.parent().nodeFill.eval) - }); - node.select('.node-outline') - .attr({ - stroke: _renderer.parent().nodeStroke.eval, - 'stroke-width': _renderer.parent().nodeStrokeWidth.eval, - 'stroke-dasharray': _renderer.parent().nodeStrokeDashArray.eval - }); - return _renderer; - }; - _renderer.redrawEdge = _renderer._updateEdge = function(edge, edgeArrows) { - edge - .attr('stroke', _renderer.parent().edgeStroke.eval) - .attr('stroke-width', _renderer.parent().edgeStrokeWidth.eval) - .attr('stroke-dasharray', _renderer.parent().edgeStrokeDashArray.eval); - edgeArrows - .attr('marker-end', function(e) { - var name = _renderer.parent().edgeArrowhead.eval(e), - id = edgeArrow(_renderer.parent(), _renderer.parent().arrows(), e, 'head', name); - return id ? 'url(#' + id + ')' : null; - }) - .attr('marker-start', function(e) { - var name = _renderer.parent().edgeArrowtail.eval(e), - arrow_id = edgeArrow(_renderer.parent(), _renderer.parent().arrows(), e, 'tail', name); - return name ? 'url(#' + arrow_id + ')' : null; - }) - .each(function(e) { - var fillEdgeStroke = _renderer.parent().edgeStroke.eval(e); - _renderer.selectAll('#' + _renderer.parent().arrowId(e, 'head')) - .attr('fill', _renderer.parent().edgeStroke.eval(e)); - _renderer.selectAll('#' + _renderer.parent().arrowId(e, 'tail')) - .attr('fill', _renderer.parent().edgeStroke.eval(e)); - }); - }; - - _renderer.selectAllNodes = function(selector) { - selector = selector || '.node'; - return _nodeLayer && _nodeLayer.selectAll(selector).filter(function(n) { - return !n.deleted; - }) || d3.selectAll('.foo-this-does-not-exist'); - }; - - _renderer.selectAllEdges = function(selector) { - selector = selector || '.edge'; - return _edgeLayer && _edgeLayer.selectAll(selector).filter(function(e) { - return !e.deleted; - }) || d3.selectAll('.foo-this-does-not-exist'); - }; - - _renderer.selectAllDefs = function(selector) { - return _defs && _defs.selectAll(selector).filter(function(def) { - return !def.deleted; - }) || d3.selectAll('.foo-this-does-not-exist'); - }; - - _renderer.resize = function(w, h) { - if(_svg) { - _svg.attr('width', w || (_renderer.parent().width_is_automatic() ? '100%' : _renderer.parent().width())) - .attr('height', h || (_renderer.parent().height_is_automatic() ? '100%' : _renderer.parent().height())); - } - return _renderer; - }; - - _renderer.rezoom = function(oldWidth, oldHeight, newWidth, newHeight) { - var scale = _zoom.scale(), translate = _zoom.translate(); - _zoom.scale(1).translate([0,0]); - var xDomain = _renderer.parent().x().domain(), yDomain = _renderer.parent().y().domain(); - _renderer.parent().x() - .domain([xDomain[0], xDomain[0] + (xDomain[1] - xDomain[0])*newWidth/oldWidth]) - .range([0, newWidth]); - _renderer.parent().y() - .domain([yDomain[0], yDomain[0] + (yDomain[1] - yDomain[0])*newHeight/oldHeight]) - .range([0, newHeight]); - _zoom - .x(_renderer.parent().x()).y(_renderer.parent().y()) - .translate(translate).scale(scale); - }; - - _renderer.globalTransform = function(pos, scale, animate) { - // _translate = pos; - // _scale = scale; - var obj = _g; - if(animate) - obj = _g.transition().duration(_renderer.parent().zoomDuration()); - obj.attr('transform', 'translate(' + pos + ')' + ' scale(' + scale + ')'); - }; - - _renderer.translate = function(_) { - if(!arguments.length) - return _zoom.translate(); - _zoom.translate(_); - return this; - }; - - _renderer.scale = function(_) { - if(!arguments.length) - return _zoom ? _zoom.scale() : 1; - _zoom.scale(_); - return this; - }; - - // argh - _renderer.commitTranslateScale = function() { - _zoom.event(_svg); - }; - - _renderer.zoom = function(_) { - if(!arguments.length) - return _zoom; - _zoom = _; // is this a good idea? - return _renderer; - }; - - _renderer.startRedraw = function(dispatch, wnodes, wedges) { - // create edge SVG elements - var edge = _edgeLayer.selectAll('.edge') - .data(wedges, _renderer.parent().edgeKey.eval); - var edgeEnter = edge.enter().append('svg:path') - .attr({ - class: 'edge', - id: _renderer.parent().edgeId, - opacity: 0 - }) - .each(function(e) { - e.deleted = false; - }); - edge.exit().each(function(e) { - e.deleted = true; - }).transition() - .duration(_renderer.parent().stagedDuration()) - .delay(_renderer.parent().deleteDelay()) - .attr('opacity', 0) - .remove(); - - var edgeArrows = _edgeLayer.selectAll('.edge-arrows') - .data(wedges, _renderer.parent().edgeKey.eval); - var edgeArrowsEnter = edgeArrows.enter().append('svg:path') - .attr({ - class: 'edge-arrows', - id: function(d) { - return _renderer.parent().edgeId(d) + '-arrows'; - }, - fill: 'none', - opacity: 0 - }); - edgeArrows.exit().transition() - .duration(_renderer.parent().stagedDuration()) - .delay(_renderer.parent().deleteDelay()) - .attr('opacity', 0) - .remove() - .each('end.delarrow', function(e) { - edgeArrow(_renderer.parent(), _renderer.parent().arrows(), e, 'head', null); - edgeArrow(_renderer.parent(), _renderer.parent().arrows(), e, 'tail', null); - }); - - if(_renderer.parent().edgeSort()) { - edge.sort(function(a, b) { - var as = _renderer.parent().edgeSort.eval(a), bs = _renderer.parent().edgeSort.eval(b); - return as < bs ? -1 : bs < as ? 1 : 0; - }); - } - - // another wider copy of the edge just for hover events - var edgeHover = _edgeLayer.selectAll('.edge-hover') - .data(wedges, _renderer.parent().edgeKey.eval); - var edgeHoverEnter = edgeHover.enter().append('svg:path') - .attr('class', 'edge-hover') - .attr('opacity', 0) - .attr('fill', 'none') - .attr('stroke', 'green') - .attr('stroke-width', 10) - .on('mouseover.diagram', function(e) { - _renderer.select('#' + _renderer.parent().edgeId(e) + '-label') - .attr('visibility', 'visible'); - }) - .on('mouseout.diagram', function(e) { - _renderer.select('#' + _renderer.parent().edgeId(e) + '-label') - .attr('visibility', 'hidden'); - }); - edgeHover.exit().remove(); - - var edgeLabels = _edgeLayer.selectAll('g.edge-label-wrapper') - .data(wedges, _renderer.parent().edgeKey.eval); - var edgeLabelsEnter = edgeLabels.enter() - .append('g') - .attr('class', 'edge-label-wrapper') - .attr('visibility', 'hidden') - .attr('id', function(e) { - return _renderer.parent().edgeId(e) + '-label'; - }); - var textPaths = _defs.selectAll('path.edge-label-path') - .data(wedges, _renderer.parent().textpathId); - var textPathsEnter = textPaths.enter() - .append('svg:path').attr({ - class: 'edge-label-path', - id: _renderer.parent().textpathId - }); - edgeLabels.exit().transition() - .duration(_renderer.parent().stagedDuration()) - .delay(_renderer.parent().deleteDelay()) - .attr('opacity', 0).remove(); - - // create node SVG elements - var node = _nodeLayer.selectAll('.node') - .data(wnodes, _renderer.parent().nodeKey.eval); - var nodeEnter = node.enter().append('g') - .attr('class', 'node') - .attr('opacity', '0') // don't show until has layout - .each(function(n) { - n.deleted = false; - }); - // .call(_d3cola.drag); - - _renderer.renderNode(nodeEnter); - - node.exit().each(function(n) { - n.deleted = true; - }).transition() - .duration(_renderer.parent().stagedDuration()) - .delay(_renderer.parent().deleteDelay()) - .attr('opacity', 0) - .remove(); - - dispatch.drawn(node, edge, edgeHover); - - var drawState = { - node: node, - nodeEnter: nodeEnter, - edge: edge, - edgeEnter: edgeEnter, - edgeHover: edgeHover, - edgeHoverEnter: edgeHoverEnter, - edgeLabels: edgeLabels, - edgeLabelsEnter: edgeLabelsEnter, - edgeArrows: edgeArrows, - edgeArrowsEnter: edgeArrowsEnter, - textPaths: textPaths, - textPathsEnter: textPathsEnter - }; - - _refresh(drawState); - - return drawState; - }; - - function _refresh(drawState) { - _renderer.redrawEdge(drawState.edge, drawState.edgeArrows); - _renderer.redrawNode(drawState.node); - _renderer.drawPorts(drawState); - } - - _renderer.refresh = function(node, edge, edgeHover, edgeLabels, textPaths) { - if(_animating) - return this; // but what about changed attributes? - node = node || _renderer.selectAllNodes(); - edge = edge || _renderer.selectAllEdges(); - var edgeArrows = _renderer.selectAllEdges('.edge-arrows'); - _refresh({node: node, edge: edge, edgeArrows: edgeArrows}); - - edgeHover = edgeHover || _renderer.selectAllEdges('.edge-hover'); - edgeLabels = edgeLabels || _renderer.selectAllEdges('.edge-label-wrapper'); - textPaths = textPaths || _renderer.selectAllDefs('path.edge-label-path'); - var nullSel = d3.select(null); // no enters - draw(node, nullSel, edge, nullSel, edgeHover, nullSel, edgeLabels, nullSel, edgeArrows, nullSel, textPaths, nullSel, false); - return this; - }; - - _renderer.reposition = function(node, edge) { - node - .attr('transform', function (n) { - return 'translate(' + n.cola.x + ',' + n.cola.y + ')'; - }); - // reset edge ports - edge.each(function(e) { - e.pos.new = null; - e.pos.old = null; - e.cola.points = null; - _renderer.parent().calcEdgePath(e, 'new', e.source.cola.x, e.source.cola.y, e.target.cola.x, e.target.cola.y); - if(_renderer.parent().edgeArrowhead.eval(e)) - _renderer.select('#' + _renderer.parent().arrowId(e, 'head')) - .attr('orient', function() { - return e.pos.new.orienthead; - }); - if(_renderer.parent().edgeArrowtail.eval(e)) - _renderer.select('#' + _renderer.parent().arrowId(e, 'tail')) - .attr('orient', function() { - return e.pos.new.orienttail; - }); - _renderer.select('#' + _renderer.parent().edgeId(e) + '-arrows') - .attr('d', generate_edge_path('new', true)); - - }) - .attr('d', generate_edge_path('new')); - return this; - }; - - function generate_edge_path(age, full) { - var field = full ? 'full' : 'path'; - return function(e) { - var path = e.pos[age][field]; - return generate_path(path.points, path.bezDegree); - }; - }; - - function generate_edge_label_path(age) { - return function(e) { - var path = e.pos[age].path; - var points = path.points[path.points.length-1].x < path.points[0].x ? - path.points.slice(0).reverse() : path.points; - return generate_path(points, path.bezDegree); - }; - }; - - function with_rad(f) { - return function() { - return f.apply(this, arguments) + 'rad'; - }; - } - - function unsurprising_orient_rad(oldorient, neworient) { - return with_rad(unsurprising_orient)(oldorient, neworient); - } - - function has_source_and_target(e) { - return !!e.source && !!e.target; - } - - _renderer.draw = function(drawState, animatePositions) { - draw(drawState.node, drawState.nodeEnter, - drawState.edge, drawState.edgeEnter, - drawState.edgeHover, drawState.edgeHoverEnter, - drawState.edgeLabels, drawState.edgeLabelsEnter, - drawState.edgeArrows, drawState.edgeArrowsEnter, - drawState.textPaths, drawState.textPathsEnter, - animatePositions); - }; - - function draw(node, nodeEnter, edge, edgeEnter, edgeHover, edgeHoverEnter, - edgeLabels, edgeLabelsEnter, edgeArrows, edgeArrowsEnter, - textPaths, textPathsEnter, animatePositions) { - console.assert(edge.data().every(has_source_and_target)); - - var nodeEntered = {}; - nodeEnter - .each(function(n) { - nodeEntered[_renderer.parent().nodeKey.eval(n)] = true; - }) - .attr('transform', function (n) { - // start new nodes at their final position - return 'translate(' + n.cola.x + ',' + n.cola.y + ')'; - }); - var ntrans = node - .transition() - .duration(_renderer.parent().stagedDuration()) - .delay(function(n) { - return _renderer.parent().stagedDelay(nodeEntered[_renderer.parent().nodeKey.eval(n)]); - }) - .attr('opacity', _renderer.parent().nodeOpacity.eval); - if(animatePositions) - ntrans - .attr('transform', function (n) { - return 'translate(' + n.cola.x + ',' + n.cola.y + ')'; - }) - .each('end.record', function(n) { - n.prevX = n.cola.x; - n.prevY = n.cola.y; - }); - - // recalculate edge positions - edge.each(function(e) { - e.pos.new = null; - }); - edge.each(function(e) { - if(e.cola.points) { - e.pos.new = place_arrows_on_spline(_renderer.parent(), e, e.cola.points); - } - else { - if(!e.pos.old) - _renderer.parent().calcEdgePath(e, 'old', e.source.prevX || e.source.cola.x, e.source.prevY || e.source.cola.y, - e.target.prevX || e.target.cola.x, e.target.prevY || e.target.cola.y); - if(!e.pos.new) - _renderer.parent().calcEdgePath(e, 'new', e.source.cola.x, e.source.cola.y, e.target.cola.x, e.target.cola.y); - } - if(e.pos.old) { - if(e.pos.old.path.bezDegree !== e.pos.new.path.bezDegree || - e.pos.old.path.points.length !== e.pos.new.path.points.length) { - //console.log('old', e.pos.old.path.points.length, 'new', e.pos.new.path.points.length); - if(is_one_segment(e.pos.old.path)) { - e.pos.new.path.points = as_bezier3(e.pos.new.path); - e.pos.old.path.points = split_bezier_n(as_bezier3(e.pos.old.path), - (e.pos.new.path.points.length-1)/3); - e.pos.old.path.bezDegree = e.pos.new.bezDegree = 3; - } - else if(is_one_segment(e.pos.new.path)) { - e.pos.old.path.points = as_bezier3(e.pos.old.path); - e.pos.new.path.points = split_bezier_n(as_bezier3(e.pos.new.path), - (e.pos.old.path.points.length-1)/3); - e.pos.old.path.bezDegree = e.pos.new.bezDegree = 3; - } - else console.warn("don't know how to interpolate two multi-segments"); - } - } - else - e.pos.old = e.pos.new; - }); - - var edgeEntered = {}; - edgeEnter - .each(function(e) { - edgeEntered[_renderer.parent().edgeKey.eval(e)] = true; - }) - .attr('d', generate_edge_path(_renderer.parent().stageTransitions() === 'modins' ? 'new' : 'old')); - - edgeArrowsEnter - .each(function(e) { - // if staging transitions, just fade new edges in at new position - // else start new edges at old positions of nodes, if any, else new positions - var age = _renderer.parent().stageTransitions() === 'modins' ? 'new' : 'old'; - if(_renderer.parent().edgeArrowhead.eval(e)) - _renderer.select('#' + _renderer.parent().arrowId(e, 'head')) - .attr('orient', function() { - return e.pos[age].orienthead; - }); - if(_renderer.parent().edgeArrowtail.eval(e)) - _renderer.select('#' + _renderer.parent().arrowId(e, 'tail')) - .attr('orient', function() { - return e.pos[age].orienttail; - }); - }) - .attr('d', generate_edge_path(_renderer.parent().stageTransitions() === 'modins' ? 'new' : 'old', true)); - - edgeArrows - .each(function(e) { - if(_renderer.parent().edgeArrowhead.eval(e)) - _renderer.select('#' + _renderer.parent().arrowId(e, 'head')) - .attr('orient', unsurprising_orient_rad(e.pos.old.orienthead, e.pos.new.orienthead)) - .transition().duration(_renderer.parent().stagedDuration()) - .delay(_renderer.parent().stagedDelay(false)) - .attr('orient', function() { - return e.pos.new.orienthead; - }); - if(_renderer.parent().edgeArrowtail.eval(e)) - _renderer.select('#' + _renderer.parent().arrowId(e, 'tail')) - .attr('orient', unsurprising_orient_rad(e.pos.old.orienttail, e.pos.new.orienttail)) - .transition().duration(_renderer.parent().stagedDuration()) - .delay(_renderer.parent().stagedDelay(false)) - .attr('orient', function() { - return e.pos.new.orienttail; - }); - }); - - var etrans = edge - .transition() - .duration(_renderer.parent().stagedDuration()) - .delay(function(e) { - return _renderer.parent().stagedDelay(edgeEntered[_renderer.parent().edgeKey.eval(e)]); - }) - .attr('opacity', _renderer.parent().edgeOpacity.eval); - var arrowtrans = edgeArrows - .transition() - .duration(_renderer.parent().stagedDuration()) - .delay(function(e) { - return _renderer.parent().stagedDelay(edgeEntered[_renderer.parent().edgeKey.eval(e)]); - }) - .attr('opacity', _renderer.parent().edgeOpacity.eval); - (animatePositions ? etrans : edge) - .attr('d', function(e) { - var when = _renderer.parent().stageTransitions() === 'insmod' && - edgeEntered[_renderer.parent().edgeKey.eval(e)] ? 'old' : 'new'; - return generate_edge_path(when)(e); - }); - (animatePositions ? arrowtrans : edgeArrows) - .attr('d', function(e) { - var when = _renderer.parent().stageTransitions() === 'insmod' && - edgeEntered[_renderer.parent().edgeKey.eval(e)] ? 'old' : 'new'; - return generate_edge_path(when, true)(e); - }); - var elabels = edgeLabels - .selectAll('text').data(function(e) { - var labels = _renderer.parent().edgeLabel.eval(e); - if(!labels) - return []; - else if(typeof labels === 'string') - return [labels]; - else return labels; - }); - elabels.enter() - .append('text') - .attr({ - 'class': 'edge-label', - 'text-anchor': 'middle', - dy: function(_, i) { - return i * _renderer.parent().edgeLabelSpacing.eval(this.parentNode) -2; - } - }) - .append('textPath') - .attr('startOffset', '50%'); - elabels - .select('textPath') - .html(function(t) { return t; }) - .attr('opacity', function() { - return _renderer.parent().edgeOpacity.eval(d3.select(this.parentNode.parentNode).datum()); - }) - .attr('xlink:href', function(e) { - var id = _renderer.parent().textpathId(d3.select(this.parentNode.parentNode).datum()); - // angular on firefox needs absolute paths for fragments - return window.location.href.split('#')[0] + '#' + id; - }); - textPathsEnter - .attr('d', generate_edge_label_path(_renderer.parent().stageTransitions() === 'modins' ? 'new' : 'old')); - var textTrans = textPaths.transition() - .duration(_renderer.parent().stagedDuration()) - .delay(function(e) { - return _renderer.parent().stagedDelay(edgeEntered[_renderer.parent().edgeKey.eval(e)]); - }); - if(animatePositions) - textTrans - .attr('d', function(e) { - var when = _renderer.parent().stageTransitions() === 'insmod' && - edgeEntered[_renderer.parent().edgeKey.eval(e)] ? 'old' : 'new'; - return generate_edge_label_path(when)(e); - }); - if(_renderer.parent().stageTransitions() === 'insmod' && animatePositions) { - // inserted edges transition twice in insmod mode - if(_renderer.parent().stagedDuration() >= 50) { - etrans = etrans.transition() - .duration(_renderer.parent().stagedDuration()) - .attr('d', generate_edge_path('new')); - textTrans = textTrans.transition() - .duration(_renderer.parent().stagedDuration()) - .attr('d', generate_edge_label_path('new')); - arrowtrans.transition() - .duration(_renderer.parent().stagedDuration()) - .attr('d', generate_edge_path('new', true)); - } else { - // if transitions are too short, we run into various problems, - // from transitions not completing to objects not found - // so don't try to chain in that case - // this also helped once: d3.timer.flush(); - etrans - .attr('d', generate_edge_path('new')); - textTrans - .attr('d', generate_edge_path('new')); - arrowtrans - .attr('d', generate_edge_path('new', true)); - } - } - - // signal layout done when all transitions complete - // because otherwise client might start another layout and lock the processor - _animating = true; - if(!_renderer.parent().showLayoutSteps()) - endall([ntrans, etrans, textTrans], - function() { - _animating = false; - _renderer.parent().layoutDone(true); - }); - - if(animatePositions) - edgeHover.attr('d', generate_edge_path('new')); - - edge.each(function(e) { - e.pos.old = e.pos.new; - }); - } - - // wait on multiple transitions, adapted from - // http://stackoverflow.com/questions/10692100/invoke-a-callback-at-the-end-of-a-transition - function endall(transitions, callback) { - if (transitions.every(function(transition) { return transition.size() === 0; })) - callback(); - var n = 0; - transitions.forEach(function(transition) { - transition - .each(function() { ++n; }) - .each('end.all', function() { if (!--n) callback(); }); - }); - } - - _renderer.isRendered = function() { - return !!_svg; - }; - - _renderer.initializeDrawing = function () { - _renderer.resetSvg(); - _g = _svg.append('g') - .attr('class', 'draw'); - - var layers = ['edge-layer', 'node-layer']; - if(_renderer.parent().edgesInFront()) - layers.reverse(); - _g.selectAll('g').data(layers) - .enter().append('g') - .attr('class', function(l) { return l; }); - _edgeLayer = _g.selectAll('g.edge-layer'); - _nodeLayer = _g.selectAll('g.node-layer'); - return this; - }; - - - /** - * Standard dc.js - * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin} - * method. Execute a d3 single selection in the diagram's scope using the given selector - * and return the d3 selection. Roughly the same as - * ```js - * d3.select('#diagram-id').select(selector) - * ``` - * Since this function returns a d3 selection, it is not chainable. (However, d3 selection - * calls can be chained after it.) - * @method select - * @memberof dc_graph.diagram - * @instance - * @param {String} [selector] - * @return {d3.selection} - * @return {dc_graph.diagram} - **/ - _renderer.select = function (s) { - return _renderer.parent().root().select(s); - }; - - /** - * Standard dc.js - * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin} - * method. Selects all elements that match the d3 single selector in the diagram's scope, - * and return the d3 selection. Roughly the same as - * - * ```js - * d3.select('#diagram-id').selectAll(selector) - * ``` - * - * Since this function returns a d3 selection, it is not chainable. (However, d3 selection - * calls can be chained after it.) - * @method selectAll - * @memberof dc_graph.diagram - * @instance - * @param {String} [selector] - * @return {d3.selection} - * @return {dc_graph.diagram} - **/ - _renderer.selectAll = function (s) { - return _renderer.parent().root() ? _renderer.parent().root().selectAll(s) : null; - }; - - _renderer.selectNodePortsOfStyle = function(node, style) { - return node.selectAll('g.port').filter(function(p) { - return _renderer.parent().portStyleName.eval(p) === style; - }); - }; - - _renderer.drawPorts = function(drawState) { - var nodePorts = _renderer.parent().nodePorts(); - if(!nodePorts) - return; - _renderer.parent().portStyle.enum().forEach(function(style) { - var nodePorts2 = {}; - for(var nid in nodePorts) - nodePorts2[nid] = nodePorts[nid].filter(function(p) { - return _renderer.parent().portStyleName.eval(p) === style; - }); - var port = _renderer.selectNodePortsOfStyle(drawState.node, style); - _renderer.parent().portStyle(style).drawPorts(port, nodePorts2, drawState.node); - }); - }; - - _renderer.fireTSEvent = function(dispatch, drawState) { - dispatch.transitionsStarted(drawState.node, drawState.edge, drawState.edgeHover); - }; - - _renderer.calculateBounds = function(drawState) { - if(!drawState.node.size()) - return null; - return _renderer.parent().calculateBounds(drawState.node.data(), drawState.edge.data()); - }; - - /** - * Standard dc.js - * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin} - * method. Returns the top `svg` element for this specific diagram. You can also pass in a new - * svg element, but setting the svg element on a diagram may have unexpected consequences. - * @method svg - * @memberof dc_graph.diagram - * @instance - * @param {d3.selection} [selection] - * @return {d3.selection} - * @return {dc_graph.diagram} - **/ - _renderer.svg = function (_) { - if (!arguments.length) { - return _svg; - } - _svg = _; - return _renderer; - }; - - /** - * Returns the top `g` element for this specific diagram. This method is usually used to - * retrieve the g element in order to overlay custom svg drawing - * programatically. **Caution**: The root g element is usually generated internally, and - * resetting it might produce unpredictable results. - * @method g - * @memberof dc_graph.diagram - * @instance - * @param {d3.selection} [selection] - * @return {d3.selection} - * @return {dc_graph.diagram} - - **/ - _renderer.g = function (_) { - if (!arguments.length) { - return _g; - } - _g = _; - return _renderer; - }; - - - /** - * Standard dc.js - * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin} - * method. Remove the diagram's SVG elements from the dom and recreate the container SVG - * element. - * @method resetSvg - * @memberof dc_graph.diagram - * @instance - * @return {dc_graph.diagram} - **/ - _renderer.resetSvg = function () { - // we might be re-initialized in a div, in which case - // we already have an element to delete - var svg = _svg || _renderer.select('svg'); - svg.remove(); - _svg = null; - //_renderer.parent().x(null).y(null); - return generateSvg(); - }; - - _renderer.addOrRemoveDef = function(id, whether, tag, onEnter) { - var data = whether ? [0] : []; - var sel = _defs.selectAll('#' + id).data(data); - - var selEnter = sel - .enter().append(tag) - .attr('id', id); - if(selEnter.size() && onEnter) - selEnter.call(onEnter); - sel.exit().remove(); - return sel; - }; - - function enableZoom() { - _svg.call(_zoom); - _svg.on('dblclick.zoom', null); - } - function disableZoom() { - _svg.on('.zoom', null); - } - - function generateSvg() { - _svg = _renderer.parent().root().append('svg'); - _renderer.resize(); - - _defs = _svg.append('svg:defs'); - - // for lack of a better place - _renderer.addOrRemoveDef('node-clip-top', true, 'clipPath', function(clipPath) { - clipPath.selectAll('rect').data([0]) - .enter().append('rect').attr({ - x: -1000, - y: -1000, - width: 2000, - height: 1000 - }); - }); - _renderer.addOrRemoveDef('node-clip-bottom', true, 'clipPath', function(clipPath) { - clipPath.selectAll('rect').data([0]) - .enter().append('rect').attr({ - x: -1000, - y: 0, - width: 2000, - height: 1000 - }); - }); - _renderer.addOrRemoveDef('node-clip-left', true, 'clipPath', function(clipPath) { - clipPath.selectAll('rect').data([0]) - .enter().append('rect').attr({ - x: -1000, - y: -1000, - width: 1000, - height: 2000 - }); - }); - _renderer.addOrRemoveDef('node-clip-right', true, 'clipPath', function(clipPath) { - clipPath.selectAll('rect').data([0]) - .enter().append('rect').attr({ - x: 0, - y: -1000, - width: 1000, - height: 2000 - }); - }); - _renderer.addOrRemoveDef('node-clip-none', true, 'clipPath', function(clipPath) { - clipPath.selectAll('rect').data([0]) - .enter().append('rect').attr({ - x: 0, - y: 0, - width: 0, - height: 0 - }); - }); - - _zoom = d3.behavior.zoom() - .on('zoom.diagram', _renderer.parent().doZoom) - .x(_renderer.parent().x()).y(_renderer.parent().y()) - .scaleExtent(_renderer.parent().zoomExtent()); - if(_renderer.parent().mouseZoomable()) { - var mod, mods; - var brush = _renderer.parent().child('brush'); - var keyboard = _renderer.parent().child('keyboard'); - if(!keyboard) - _renderer.parent().child('keyboard', keyboard = dc_graph.keyboard()); - var modkeyschanged = function() { - if(keyboard.modKeysMatch(_renderer.parent().modKeyZoom())) - enableZoom(); - else - disableZoom(); - }; - keyboard.on('modkeyschanged.zoom', modkeyschanged); - modkeyschanged(); - } - - return _svg; - } - - _renderer.animating = function() { - return _animating; - }; - - return _renderer; -}; - - -dc_graph.render_webgl = function() { - //var _svg = null, _defs = null, _g = null, _nodeLayer = null, _edgeLayer = null; - var _camera, _scene, _webgl_renderer; - var _directionalLight, _ambientLight; - var _controls; - var _sphereGeometry; - var _nodes = {}, _edges = {}; - var _animating = false; // do not refresh during animations - var _renderer = {}; - - _renderer.rendererType = function() { - return 'webgl'; - }; - - _renderer.parent = property(null); - - _renderer.isRendered = function() { - return !!_camera; - }; - - _renderer.resize = function(w, h) { - return _renderer; - }; - - _renderer.rezoom = function(oldWidth, oldHeight, newWidth, newHeight) { - return _renderer; - }; - - _renderer.globalTransform = function(pos, scale, animate) { - return _renderer; - }; - - _renderer.translate = function(_) { - if(!arguments.length) - return [0,0]; - return _renderer; - }; - - _renderer.scale = function(_) { - if(!arguments.length) - return 1; - return _renderer; - }; - - // argh - _renderer.commitTranslateScale = function() { - }; - - _renderer.initializeDrawing = function () { - if(_scene) // just treat it as a redraw - return _renderer; - - _camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000); - _camera.up = new THREE.Vector3(0, 0, 1); - - _scene = new THREE.Scene(); - - _sphereGeometry = new THREE.SphereBufferGeometry(10, 32, 32); - - _directionalLight = new THREE.DirectionalLight(0xffffff, 1); - _directionalLight.position.set(-1, -1, 1).normalize(); - _scene.add(_directionalLight); - - _ambientLight = new THREE.AmbientLight(0xaaaaaa); - _scene.add(_ambientLight); - - _webgl_renderer = new THREE.WebGLRenderer({ antialias: true }); - _webgl_renderer.setPixelRatio(window.devicePixelRatio); - var boundRect = _renderer.parent().root().node().getBoundingClientRect(); - _webgl_renderer.setSize(boundRect.width, boundRect.height); - _renderer.parent().root().node().appendChild(_webgl_renderer.domElement); - - _controls = new THREE.OrbitControls(_camera, _webgl_renderer.domElement); - _controls.minDistance = 300; - _controls.maxDistance = 1000; - return _renderer; - }; - - _renderer.startRedraw = function(dispatch, wnodes, wedges) { - wnodes.forEach(infer_shape(_renderer.parent())); - var rnodes = regenerate_objects(_nodes, wnodes, null, function(n) { - return _renderer.parent().nodeKey.eval(n); - }, function(rn, n) { - rn.wnode = n; - }, null, function(wnode, rnode) { - _scene.remove(rnode.mesh); - //rnode.mesh.dispose(); - rnode.material.dispose(); - }); - var redges = regenerate_objects(_edges, wedges, null, function(e) { - return _renderer.parent().edgeKey.eval(e); - }, function(re, e) { - re.wedge = e; - }, null, function(wedge, redge) { - _scene.remove(redge.mesh); - //redge.mesh.dispose(); - redge.geometry.dispose(); - redge.material.dispose(); - }); - animate(); - return {wnodes: wnodes, wedges: wedges, rnodes: rnodes, redges: redges}; - }; - - function color_to_int(color) { - // it better be 6 byte hex RGB - if(color.length !== 7 || color[0] !== '#') { - console.warn("don't know how to use color " + color); - color = '#888888'; - } - return parseInt(color.slice(1), 16); - } - _renderer.color_to_int = color_to_int; - - _renderer.draw = function(drawState, animatePositions) { - drawState.wedges.forEach(function(e) { - if(!e.pos.old) - _renderer.parent().calcEdgePath(e, 'old', e.source.prevX || e.source.cola.x, e.source.prevY || e.source.cola.y, - e.target.prevX || e.target.cola.x, e.target.prevY || e.target.cola.y); - if(!e.pos.new) - _renderer.parent().calcEdgePath(e, 'new', e.source.cola.x, e.source.cola.y, e.target.cola.x, e.target.cola.y); - }); - - var MULT = _renderer.multiplier(); - drawState.rnodes.forEach(function(rn) { - var color = _renderer.parent().nodeFill.eval(rn.wnode); - var add = false; - if(!rn.mesh) { - add = true; - if(_renderer.parent().nodeFillScale()) - color = _renderer.parent().nodeFillScale()(color); - var cint = color_to_int(color); - rn.material = new THREE.MeshLambertMaterial({color: cint}); - rn.mesh = new THREE.Mesh(_sphereGeometry, rn.material); - rn.mesh.name = _renderer.parent().nodeKey.eval(rn.wnode); - } - rn.mesh.position.x = rn.wnode.cola.x * MULT; - rn.mesh.position.y = -rn.wnode.cola.y * MULT; - rn.mesh.position.z = rn.wnode.cola.z * MULT || 0; - if(add) - _scene.add(rn.mesh); - }); - - var xext = d3.extent(drawState.wnodes, function(n) { return n.cola.x * MULT; }), - yext = d3.extent(drawState.wnodes, function(n) { return -n.cola.y * MULT; }), - zext = d3.extent(drawState.wnodes, function(n) { return n.cola.z * MULT || 0; }); - var cx = (xext[0] + xext[1])/2, - cy = (yext[0] + yext[1])/2, - cz = (zext[0] + zext[1])/2; - - drawState.center = [cx, cy, cz]; - drawState.extents = [xext, yext, zext]; - _controls.target.set(cx, cy, cz); - _controls.update(); - - var vertices = []; - drawState.redges.forEach(function(re) { - if(!re.wedge.source || !re.wedge.target) - return; - var a = re.wedge.source.cola, b = re.wedge.target.cola; - var add = false; - var width = _renderer.parent().edgeStrokeWidth.eval(re.wedge); - if(!re.mesh) { - add = true; - var color = _renderer.parent().edgeStroke.eval(re.wedge); - var cint = color_to_int(color); - re.material = new THREE.MeshLambertMaterial({ color: cint }); - re.curve = new THREE.LineCurve3( - new THREE.Vector3(a.x*MULT, -a.y*MULT, a.z*MULT || 0), - new THREE.Vector3(b.x*MULT, -b.y*MULT, b.z*MULT || 0)); - re.geometry = new THREE.TubeBufferGeometry(re.curve, 20, width/2, 8, false); - re.mesh = new THREE.Mesh(re.geometry, re.material); - re.mesh.name = _renderer.parent().edgeKey.eval(re.wedge); - } else { - re.curve = new THREE.LineCurve3( - new THREE.Vector3(a.x*MULT, -a.y*MULT, a.z*MULT || 0), - new THREE.Vector3(b.x*MULT, -b.y*MULT, b.z*MULT || 0)); - re.geometry.dispose(); - re.geometry = new THREE.TubeBufferGeometry(re.curve, 20, width/2, 8, false); - re.mesh.geometry = re.geometry; - } - if(add) - _scene.add(re.mesh); - }); - _animating = false; - _renderer.parent().layoutDone(true); - return _renderer; - }; - - function animate() { - window.requestAnimationFrame(animate); - render(); - } - - function render() { - _webgl_renderer.render(_scene, _camera); - } - - _renderer.drawPorts = function(drawState) { - var nodePorts = _renderer.parent().nodePorts(); - if(!nodePorts) - return; - _renderer.parent().portStyle.enum().forEach(function(style) { - var nodePorts2 = {}; - for(var nid in nodePorts) - nodePorts2[nid] = nodePorts[nid].filter(function(p) { - return _renderer.parent().portStyleName.eval(p) === style; - }); - // not implemented - var port = _renderer.selectNodePortsOfStyle(drawState.node, style); - //_renderer.parent().portStyle(style).drawPorts(port, nodePorts2, drawState.node); - }); - }; - - _renderer.fireTSEvent = function(dispatch, drawState) { - dispatch.transitionsStarted(_scene, drawState); - }; - - _renderer.calculateBounds = function(drawState) { - if(!drawState.wnodes.length) - return null; - return _renderer.parent().calculateBounds(drawState.wnodes, drawState.wedges); - }; - - _renderer.refresh = function(node, edge, edgeHover, edgeLabels, textPaths) { - if(_animating) - return _renderer; // but what about changed attributes? - return _renderer; - }; - - _renderer.reposition = function(node, edge) { - return _renderer; - }; - - function has_source_and_target(e) { - return !!e.source && !!e.target; - } - - _renderer.animating = function() { - return _animating; - }; - - _renderer.multiplier = property(3); - - return _renderer; -}; - - -dc_graph.spawn_engine = function(layout, args, worker) { - args = args || {}; - worker = worker && !!window.Worker; - var engine = dc_graph.engines.instantiate(layout, args, worker); - if(!engine) { - console.warn('layout engine ' + layout + ' not found; using default ' + dc_graph._default_engine); - engine = dc_graph.engines.instantiate(dc_graph._default_engine, args, worker); - } - return engine; -}; - -dc_graph._engines = [ - { - name: 'dagre', - params: ['rankdir'], - instantiate: function() { - return dc_graph.dagre_layout(); - } - }, - { - name: 'd3force', - instantiate: function() { - return dc_graph.d3_force_layout(); - } - }, - { - name: 'd3v4force', - instantiate: function() { - return dc_graph.d3v4_force_layout(); - } - }, - { - name: 'tree', - instantiate: function() { - return dc_graph.tree_layout(); - } - }, - { - names: ['circo', 'dot', 'neato', 'osage', 'twopi', 'fdp'], - instantiate: function(layout, args) { - return dc_graph.graphviz_layout(null, layout, args.server); - } - }, - { - name: 'cola', - params: ['lengthStrategy'], - instantiate: function() { - return dc_graph.cola_layout(); - } - }, - { - names: ['dynadag'], - workerName: 'dynagraph', - instantiate: function(layout, args) { - return dc_graph.dynagraph_layout(null, layout, args.server); - } - }, - { - name: 'manual', - instantiate: function() { - return dc_graph.manual_layout(); - } - }, - { - name: 'flexbox', - instantiate: function() { - return dc_graph.flexbox_layout(); - } - }, - { - name: 'layered', - instantiate: function() { - return dc_graph.layered_layout(); - } - } -]; -dc_graph._default_engine = 'cola'; - -dc_graph.engines = { - entry_pred: function(layoutName) { - return function(e) { - return e.name && e.name === layoutName || e.names && e.names.includes(layoutName); - }; - }, - get: function(layoutName) { - return dc_graph._engines.find(this.entry_pred(layoutName)); - }, - is_directed: function(layoutName) { - // to a first approximation. cola is sometimes directed - return ['dagre', 'dot'].includes(layoutName); - }, - instantiate: function(layout, args, worker) { - var entry = this.get(layout); - if(!entry) - return null; - var engine = entry.instantiate(layout, args), - params = entry.params || []; - params.forEach(function(p) { - if(args[p]) - engine[p](args[p]); - }); - if(engine.supportsWebworker && engine.supportsWebworker() && worker) - engine = dc_graph.webworker_layout(engine, entry.workerName); - return engine; - }, - available: function() { - return dc_graph._engines.reduce(function(avail, entry) { - return avail.concat(entry.name ? [entry.name] : entry.names); - }, []); - }, - unregister: function(layoutName) { - // meh. this is a bit much. there is such a thing as making the api too "easy". - var i = dc_graph._engines.findIndex(this.entry_pred(layoutName)); - var remove = false; - if(i < 0) - return false; - var entry = dc_graph._engines[i]; - if(entry.name === layoutName) - remove = true; - else { - var j = entry.names.indexOf(layoutName); - if(j >= 0) - entry.names.splice(j, 1); - else - console.warn('search for engine failed', layoutName); - if(entry.names.length === 0) - remove = true; - } - if(remove) - dc_graph._engines.splice(i, 1); - return true; - }, - register: function(entry) { - var that = this; - if(!entry.instantiate) { - console.error('engine definition needs instantiate: function(layout, args) { ... }'); - return this; - } - if(entry.name) - this.unregister(entry.name); - else if(entry.names) - entry.names.forEach(function(layoutName) { - that.unregister(layoutName); - }); - else { - console.error('engine definition needs name or names[]'); - return this; - } - dc_graph._engines.push(entry); - return this; - } -}; - -var _workers = {}; -var NUMBER_RESULTS = 3; -function create_worker(workerName) { - if(!_workers[workerName]) { - var worker = _workers[workerName] = { - worker: new Worker(script_path() + 'dc.graph.' + workerName + '.worker.js'), - layouts: {} - }; - worker.worker.onmessage = function(e) { - var layoutId = e.data.layoutId; - if(!worker.layouts[layoutId]) - throw new Error('layoutId "' + layoutId + '" unknown!'); - var engine = worker.layouts[layoutId].getEngine(); - if(e.data.args.length > NUMBER_RESULTS && engine.processExtraWorkerResults) - engine.processExtraWorkerResults.apply(engine, e.data.args.slice(NUMBER_RESULTS)); - worker.layouts[layoutId].dispatch()[e.data.response].apply(null, e.data.args); - }; - worker.worker.onerror = function(e) { - console.error('Worker error:', e); - }; - } - return _workers[workerName]; -} - -dc_graph.webworker_layout = function(layoutEngine, workerName) { - var _tick, _done, _dispatch = d3.dispatch('init', 'start', 'tick', 'end'); - var _worker = create_worker(workerName || layoutEngine.layoutAlgorithm()); - var engine = {}; - _worker.layouts[layoutEngine.layoutId()] = engine; - - engine.parent = function(parent) { - if(layoutEngine.parent) - layoutEngine.parent(parent); - }; - engine.init = function(options) { - options = layoutEngine.optionNames().reduce( - function(options, option) { - options[option] = layoutEngine[option](); - return options; - }, options); - if(layoutEngine.propagateOptions) - layoutEngine.propagateOptions(options); - _worker.worker.postMessage({ - command: 'init', - args: { - layoutId: layoutEngine.layoutId(), - options: options - } - }); - return this; - }; - engine.data = function(graph, nodes, edges, clusters, constraints) { - _worker.worker.postMessage({ - command: 'data', - args: { - layoutId: layoutEngine.layoutId(), - graph: graph, - nodes: nodes, - edges: edges, - clusters: clusters, - constraints: constraints - } - }); - }; - engine.start = function() { - _worker.worker.postMessage({ - command: 'start', - args: { - layoutId: layoutEngine.layoutId() - } - }); - }; - engine.stop = function() { - _worker.worker.postMessage({ - command: 'stop', - args: { - layoutId: layoutEngine.layoutId() - } - }); - return this; - }; - // stopgap while layout options are still on diagram - engine.getEngine = function() { - return layoutEngine; - }; - // somewhat sketchy - do we want this object to be transparent or not? - var passthroughs = ['layoutAlgorithm', 'populateLayoutNode', 'populateLayoutEdge', - 'rankdir', 'ranksep']; - passthroughs.concat(layoutEngine.optionNames(), - layoutEngine.passThru ? layoutEngine.passThru() : []).forEach(function(name) { - engine[name] = function() { - var ret = layoutEngine[name].apply(layoutEngine, arguments); - return arguments.length ? this : ret; - }; - }); - engine.on = function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }; - engine.dispatch = function() { - return _dispatch; - }; - return engine; -}; - -/** - * `dc_graph.graphviz_attrs defines a basic set of attributes which layout engines should - * implement - although these are not required, they make it easier for clients and - * modes (like expand_collapse) to work with multiple layout engines. - * - * these attributes are {@link http://www.graphviz.org/doc/info/attrs.html from graphviz} - * @class graphviz_attrs - * @memberof dc_graph - * @return {Object} - **/ -dc_graph.graphviz_attrs = function() { - return { - /** - * Direction to draw ranks. - * @method rankdir - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [rankdir='TB'] 'TB', 'LR', 'BT', or 'RL' - **/ - rankdir: property('TB'), - /** - * Spacing in between nodes in the same rank. - * @method nodesep - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [nodesep=40] - **/ - nodesep: property(40), - /** - * Spacing in between ranks. - * @method ranksep - * @memberof dc_graph.graphviz_attrs - * @instance - * @param {String} [ranksep=40] - **/ - ranksep: property(40) - }; -}; - -// graphlib-dot seems to wrap nodes in an extra {value} -// actually this is quite a common problem with generic libs -function nvalue(n) { - return n.value.value ? n.value.value : n.value; -} - -// apply standard accessors to a diagram in order to style it as graphviz would -// this is a work in progress -dc_graph.apply_graphviz_accessors = function(diagram) { - diagram - .nodeLabel(function(n) { - var label = nvalue(n).label; - if(label === undefined) - label = n.key; - return label && label.split(/\n|\\n/); - }) - .nodeRadius(function(n) { - // should do width & height instead, #25 - return nvalue(n).radius || 25; - }) - .nodeShape(function(n) { return nvalue(n).shape; }) - .nodeFill(function(n) { return nvalue(n).fillcolor || 'white'; }) - .nodeOpacity(function(n) { - // not standard gv - return nvalue(n).opacity || 1; - }) - .nodeLabelFill(function(n) { return nvalue(n).fontcolor || 'black'; }) - .nodeTitle(function(n) { - return (nvalue(n).htmltip || nvalue(n).jsontip) ? null : - nvalue(n).tooltip !== undefined ? - nvalue(n).tooltip : - diagram.nodeLabel()(n); - }) - .nodeStrokeWidth(function(n) { - // it is debatable whether a point === a pixel but they are close - // https://graphicdesign.stackexchange.com/questions/199/point-vs-pixel-what-is-the-difference - var penwidth = nvalue(n).penwidth; - return penwidth !== undefined ? +penwidth : 1; - }) - .edgeLabel(function(e) { return e.value.label ? e.value.label.split(/\n|\\n/) : ''; }) - .edgeStroke(function(e) { return e.value.color || 'black'; }) - .edgeOpacity(function(e) { - // not standard gv - return e.value.opacity || 1; - }) - .edgeArrowSize(function(e) { - return e.value.arrowsize || 1; - }) - // need directedness to default these correctly, see #106 - .edgeArrowhead(function(e) { - var head = e.value.arrowhead; - return head !== undefined ? head : 'vee'; - }) - .edgeArrowtail(function(e) { - var tail = e.value.arrowtail; - return tail !== undefined ? tail : null; - }) - .edgeStrokeDashArray(function(e) { - switch(e.value.style) { - case 'dotted': - return [1,5]; - } - return null; - }); - var draw_clusters = diagram.child('draw-clusters'); - if(draw_clusters) { - draw_clusters - .clusterStroke(function(c) { - return c.value.color || 'black'; - }) - .clusterFill(function(c) { - return c.value.style === 'filled' ? c.value.fillcolor || c.value.color || c.value.bgcolor : null; - }) - .clusterLabel(function(c) { - return c.value.label; - }); - } -}; - -dc_graph.snapshot_graphviz = function(diagram) { - var xDomain = diagram.x().domain(), yDomain = diagram.y().domain(); - return { - nodes: diagram.nodeGroup().all().map(function(n) { - return diagram.getWholeNode(n.key); - }) - .filter(function(x) { return x; }) - .map(function(n) { - return { - key: diagram.nodeKey.eval(n), - label: diagram.nodeLabel.eval(n), - fillcolor: diagram.nodeFillScale()(diagram.nodeFill.eval(n)), - penwidth: diagram.nodeStrokeWidth.eval(n), - // not supported as input, see dc.graph.js#25 - // width: n.cola.dcg_rx*2, - // height: n.cola.dcg_ry*2, - - // not graphviz attributes - // until we have w/h - radius: diagram.nodeRadius.eval(n), - // does not seem to exist in gv - opacity: diagram.nodeOpacity.eval(n), - // should be pos - x: n.cola.x, - y: n.cola.y - }; - }), - edges: diagram.edgeGroup().all().map(function(e) { - return diagram.getWholeEdge(e.key); - }).map(function(e) { - return { - key: diagram.edgeKey.eval(e), - source: diagram.edgeSource.eval(e), - target: diagram.edgeTarget.eval(e), - color: diagram.edgeStroke.eval(e), - arrowsize: diagram.edgeArrowSize.eval(e), - opacity: diagram.edgeOpacity.eval(e), - // should support dir, see dc.graph.js#106 - arrowhead: diagram.edgeArrowhead.eval(e), - arrowtail: diagram.edgeArrowtail.eval(e) - }; - }), - bounds: { - left: xDomain[0], - top: yDomain[0], - right: xDomain[1], - bottom: yDomain[1] - } - }; -}; - -/** - * `dc_graph.cola_layout` is an adaptor for cola.js layouts in dc.graph.js - * @class cola_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.cola_layout} - **/ -dc_graph.cola_layout = function(id) { - var _layoutId = id || uuid(); - var _d3cola = null; - var _setcola_nodes; - var _dispatch = d3.dispatch('tick', 'start', 'end'); - var _flowLayout; - // node and edge objects shared with cola.js, preserved from one iteration - // to the next (as long as the object is still in the layout) - var _nodes = {}, _edges = {}; - var _options; - - function init(options) { - _options = options; - _d3cola = cola.d3adaptor() - .avoidOverlaps(true) - .size([options.width, options.height]) - .handleDisconnected(options.handleDisconnected); - - if(_d3cola.tickSize) // non-standard - _d3cola.tickSize(options.tickSize); - - switch(options.lengthStrategy) { - case 'symmetric': - _d3cola.symmetricDiffLinkLengths(options.baseLength); - break; - case 'jaccard': - _d3cola.jaccardLinkLengths(options.baseLength); - break; - case 'individual': - _d3cola.linkDistance(function(e) { - return e.dcg_edgeLength || options.baseLength; - }); - break; - case 'none': - default: - } - if(options.flowLayout) { - _d3cola.flowLayout(options.flowLayout.axis, options.flowLayout.minSeparation); - } - } - - function data(nodes, edges, clusters, constraints) { - var wnodes = regenerate_objects(_nodes, nodes, null, function(v) { - return v.dcg_nodeKey; - }, function(v1, v) { - v1.dcg_nodeKey = v.dcg_nodeKey; - v1.dcg_nodeParentCluster = v.dcg_nodeParentCluster; - v1.width = v.width; - v1.height = v.height; - v1.fixed = !!v.dcg_nodeFixed; - _options.nodeAttrs.forEach(function(key) { - v1[key] = v[key]; - }); - - if(v1.fixed && typeof v.dcg_nodeFixed === 'object') { - v1.x = v.dcg_nodeFixed.x; - v1.y = v.dcg_nodeFixed.y; - } - else { - // should we support e.g. null to unset x,y? - if(v.x !== undefined) - v1.x = v.x; - if(v.y !== undefined) - v1.y = v.y; - } - }); - var wedges = regenerate_objects(_edges, edges, null, function(e) { - return e.dcg_edgeKey; - }, function(e1, e) { - e1.dcg_edgeKey = e.dcg_edgeKey; - // cola edges can work with indices or with object references - // but it will replace indices with object references - e1.source = _nodes[e.dcg_edgeSource]; - e1.target = _nodes[e.dcg_edgeTarget]; - e1.dcg_edgeLength = e.dcg_edgeLength; - _options.edgeAttrs.forEach(function(key) { - e1[key] = e[key]; - }); - }); - - // cola needs each node object to have an index property - wnodes.forEach(function(v, i) { - v.index = i; - }); - - var groups = null; - if(engine.groupConnected()) { - var components = cola.separateGraphs(wnodes, wedges); - groups = components.map(function(g) { - return { - dcg_autoGroup: true, - leaves: g.array.map(function(n) { return n.index; }) - }; - }); - } else if(clusters) { - var G = {}; - groups = clusters.filter(function(c) { - return /^cluster/.test(c.dcg_clusterKey); - }).map(function(c, i) { - return G[c.dcg_clusterKey] = { - dcg_clusterKey: c.dcg_clusterKey, - index: i, - groups: [], - leaves: [] - }; - }); - clusters.forEach(function(c) { - if(c.dcg_clusterParent && G[c.dcg_clusterParent]) - G[c.dcg_clusterParent].groups.push(G[c.dcg_clusterKey].index); - }); - wnodes.forEach(function(n, i) { - if(n.dcg_nodeParentCluster && G[n.dcg_nodeParentCluster]) - G[n.dcg_nodeParentCluster].leaves.push(i); - }); - } - - function dispatchState(event) { - // clean up extra setcola annotations - wnodes.forEach(function(n) { - Object.keys(n).forEach(function(key) { - if(/^get/.test(key) && typeof n[key] === 'function') - delete n[key]; - }); - }); - _dispatch[event]( - wnodes, - wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }), - groups.filter(function(g) { - return !g.dcg_autoGroup; - }).map(function(g) { - g = Object.assign({}, g); - g.bounds = { - left: g.bounds.x, - top: g.bounds.y, - right: g.bounds.X, - bottom: g.bounds.Y - }; - return g; - }), - _setcola_nodes - ); - } - _d3cola.on('tick', /* _tick = */ function() { - dispatchState('tick'); - }).on('start', function() { - _dispatch.start(); - }).on('end', /* _done = */ function() { - dispatchState('end'); - }); - - if(_options.setcolaSpec && typeof setcola !== 'undefined') { - console.log('generating setcola constrains'); - var setcola_result = setcola - .nodes(wnodes) - .links(wedges) - .constraints(_options.setcolaSpec) - .gap(10) //default value is 10, can be customized in setcolaSpec - .layout(); - - _setcola_nodes = setcola_result.nodes.filter(function(n) { return n._cid; }); - _d3cola.nodes(setcola_result.nodes) - .links(setcola_result.links) - .constraints(setcola_result.constraints) - .groups(groups); - } else { - _d3cola.nodes(wnodes) - .links(wedges) - .constraints(constraints) - .groups(groups); - } - - } - - function start() { - _d3cola.start(engine.unconstrainedIterations(), - engine.userConstraintIterations(), - engine.allConstraintsIterations(), - engine.gridSnapIterations()); - } - - function stop() { - if(_d3cola) - _d3cola.stop(); - } - - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); - graphviz.rankdir(null); - - var engine = Object.assign(graphviz, { - layoutAlgorithm: function() { - return 'cola'; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return true; - }, - supportsMoving: function() { - return true; - }, - parent: property(null), - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - this.propagateOptions(options); - init(options); - return this; - }, - data: function(graph, nodes, edges, clusters, constraints) { - data(nodes, edges, clusters, constraints); - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - optionNames: function() { - return ['handleDisconnected', 'lengthStrategy', 'baseLength', 'flowLayout', - 'tickSize', 'groupConnected', 'setcolaSpec', 'setcolaNodes'] - .concat(graphviz_keys); - }, - passThru: function() { - return ['extractNodeAttrs', 'extractEdgeAttrs']; - }, - propagateOptions: function(options) { - if(!options.nodeAttrs) - options.nodeAttrs = Object.keys(engine.extractNodeAttrs()); - if(!options.edgeAttrs) - options.edgeAttrs = Object.keys(engine.extractEdgeAttrs()); - }, - populateLayoutNode: function() {}, - populateLayoutEdge: function() {}, - /** - * Instructs cola.js to fit the connected components. - * @method handleDisconnected - * @memberof dc_graph.cola_layout - * @instance - * @param {Boolean} [handleDisconnected=true] - * @return {Boolean} - * @return {dc_graph.cola_layout} - **/ - handleDisconnected: property(true), - /** - * Currently, three strategies are supported for specifying the lengths of edges: - * * 'individual' - uses the `edgeLength` for each edge. If it returns falsy, uses the - * `baseLength` - * * 'symmetric', 'jaccard' - compute the edge length based on the graph structure around - * the edge. See - * {@link https://github.com/tgdwyer/WebCola/wiki/link-lengths the cola.js wiki} - * for more details. - * 'none' - no edge lengths will be specified - * @method lengthStrategy - * @memberof dc_graph.cola_layout - * @instance - * @param {Function|String} [lengthStrategy='symmetric'] - * @return {Function|String} - * @return {dc_graph.cola_layout} - **/ - lengthStrategy: property('symmetric'), - /** - * Gets or sets the default edge length (in pixels) when the `.lengthStrategy` is - * 'individual', and the base value to be multiplied for 'symmetric' and 'jaccard' edge - * lengths. - * @method baseLength - * @memberof dc_graph.cola_layout - * @instance - * @param {Number} [baseLength=30] - * @return {Number} - * @return {dc_graph.cola_layout} - **/ - baseLength: property(30), - /** - * If `flowLayout` is set, it determines the axis and separation for - * {@link http://marvl.infotech.monash.edu/webcola/doc/classes/cola.layout.html#flowlayout cola flow layout}. - * If it is not set, `flowLayout` will be calculated from the {@link dc_graph.graphviz_attrs#rankdir rankdir} - * and {@link dc_graph.graphviz_attrs#ranksep ranksep}; if `rankdir` is also null (the - * default for cola layout), then there will be no flow. - * @method flowLayout - * @memberof dc_graph.cola_layout - * @instance - * @param {Object} [flowLayout=null] - * @example - * // No flow (default) - * diagram.flowLayout(null) - * // flow in x with min separation 200 - * diagram.flowLayout({axis: 'x', minSeparation: 200}) - **/ - flowLayout: function(flow) { - if(!arguments.length) { - if(_flowLayout) - return _flowLayout; - var dir = engine.rankdir(); - switch(dir) { - case 'LR': return {axis: 'x', minSeparation: engine.ranksep() + engine.parent().nodeRadius()*2}; - case 'TB': return {axis: 'y', minSeparation: engine.ranksep() + engine.parent().nodeRadius()*2}; - default: return null; // RL, BT do not appear to be possible (negative separation) (?) - } - } - _flowLayout = flow; - return this; - }, - unconstrainedIterations: property(10), - userConstraintIterations: property(20), - allConstraintsIterations: property(20), - gridSnapIterations: property(0), - tickSize: property(1), - groupConnected: property(false), - setcolaSpec: property(null), - setcolaNodes: function() { - return _setcola_nodes; - }, - extractNodeAttrs: property({}), // {attr: function(node)} - extractEdgeAttrs: property({}), - processExtraWorkerResults: function(setcolaNodes) { - _setcola_nodes = setcolaNodes; - } - }); - return engine; -}; - -dc_graph.cola_layout.scripts = ['d3.js', 'cola.js']; -dc_graph.cola_layout.optional_scripts = ['setcola.js']; - -/** - * `dc_graph.dagre_layout` is an adaptor for dagre.js layouts in dc.graph.js - * - * In addition to the below layout attributes, `dagre_layout` also implements the attributes from - * {@link dc_graph.graphviz_attrs graphviz_attrs} - * @class dagre_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.dagre_layout} - **/ -dc_graph.dagre_layout = function(id) { - var _layoutId = id || uuid(); - var _dagreGraph = null, _tick, _done; - var _dispatch = d3.dispatch('tick', 'start', 'end'); - // node and edge objects preserved from one iteration - // to the next (as long as the object is still in the layout) - var _nodes = {}, _edges = {}; - - function init(options) { - // Create a new directed graph - _dagreGraph = new dagre.graphlib.Graph({multigraph: true, compound: true}); - - // Set an object for the graph label - _dagreGraph.setGraph({rankdir: options.rankdir, nodesep: options.nodesep, ranksep: options.ranksep}); - - // Default to assigning a new object as a label for each new edge. - _dagreGraph.setDefaultEdgeLabel(function() { return {}; }); - } - - function data(nodes, edges, clusters) { - var wnodes = regenerate_objects(_nodes, nodes, null, function(v) { - return v.dcg_nodeKey; - }, function(v1, v) { - v1.dcg_nodeKey = v.dcg_nodeKey; - v1.width = v.width; - v1.height = v.height; - /* - dagre does not seem to accept input positions - if(v.dcg_nodeFixed) { - v1.x = v.dcg_nodeFixed.x; - v1.y = v.dcg_nodeFixed.y; - } - */ - }, function(k, o) { - _dagreGraph.setNode(k, o); - }, function(k) { - _dagreGraph.removeNode(k); - }); - var wedges = regenerate_objects(_edges, edges, null, function(e) { - return e.dcg_edgeKey; - }, function(e1, e) { - e1.dcg_edgeKey = e.dcg_edgeKey; - e1.dcg_edgeSource = e.dcg_edgeSource; - e1.dcg_edgeTarget = e.dcg_edgeTarget; - }, function(k, o, e) { - _dagreGraph.setEdge(e.dcg_edgeSource, e.dcg_edgeTarget, o); - }, function(k, e) { - _dagreGraph.removeEdge(e.dcg_edgeSource, e.dcg_edgeTarget, e.dcg_edgeKey); - }); - clusters = clusters.filter(function(c) { - return /^cluster/.test(c.dcg_clusterKey); - }); - clusters.forEach(function(c) { - _dagreGraph.setNode(c.dcg_clusterKey, c); - }); - clusters.forEach(function(c) { - if(c.dcg_clusterParent) - _dagreGraph.setParent(c.dcg_clusterKey, c.dcg_clusterParent); - }); - nodes.forEach(function(n) { - if(n.dcg_nodeParentCluster) - _dagreGraph.setParent(n.dcg_nodeKey, n.dcg_nodeParentCluster); - }); - - function dispatchState(event) { - _dispatch[event]( - wnodes, - wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }), - clusters.map(function(c) { - var c = Object.assign({}, _dagreGraph.node(c.dcg_clusterKey)); - c.bounds = { - left: c.x - c.width/2, - top: c.y - c.height/2, - right: c.x + c.width/2, - bottom: c.y + c.height/2 - }; - return c; - }) - ); - } - _tick = function() { - dispatchState('tick'); - }; - _done = function() { - dispatchState('end'); - }; - } - - function start(options) { - _dispatch.start(); - dagre.layout(_dagreGraph); - _done(); - } - - function stop() { - } - - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); - return Object.assign(graphviz, { - layoutAlgorithm: function() { - return 'dagre'; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return true; - }, - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - init(options); - return this; - }, - data: function(graph, nodes, edges, clusters) { - data(nodes, edges, clusters); - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - optionNames: function() { - return graphviz_keys; - }, - populateLayoutNode: function() {}, - populateLayoutEdge: function() {} - }); -}; - -dc_graph.dagre_layout.scripts = ['d3.js', 'dagre.js']; - -/** - * `dc_graph.tree_layout` is a very simple and not very bright tree layout. It can draw any DAG, but - * tries to position the nodes as a tree. - * @class tree_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.tree_layout} - **/ -dc_graph.tree_layout = function(id) { - var _layoutId = id || uuid(); - var _dispatch = d3.dispatch('tick', 'start', 'end'); - var _dfs; - - function init(options) { - var x; - var nodeWidth = d3.functor(options.nodeWidth); - function best_dist(left, right) { - return (nodeWidth(left) + nodeWidth(right)) / 2; - } - _dfs = dc_graph.depth_first_traversal({ - nodeid: function(n) { - return n.dcg_nodeKey; - }, - sourceid: function(n) { - return n.dcg_edgeSource; - }, - targetid: function(n) { - return n.dcg_edgeTarget; - }, - init: function() { - x = options.offsetX; - }, - row: function(n) { - return n.dcg_rank; - }, - place: function(n, r, row) { - if(row.length) { - var left = row[row.length-1]; - var g = (nodeWidth(left) + nodeWidth(n)) / 2; - x = Math.max(x, left.left_x + g); - } - n.left_x = x; - n.hit_ins = 1; - n.y = r*options.gapY + options.offsetY; - }, - sib: function(isroot, left, right) { - var g = best_dist(left, right); - if(isroot) g = g*1.5; - x += g; - }, - pop: function(n) { - n.x = (n.left_x + x)/2; - }, - skip: function(n, indegree) { - // rolling average of in-neighbor x positions - n.x = (n.hit_ins*n.x + x)/++n.hit_ins; - if(n.hit_ins === indegree) - delete n.hit_ins; - }, - finish: function(rows) { - // this is disgusting. patch up any places where nodes overlap by scanning - // right far enough to find the space, then fill from left to right at the - // minimum gap - rows.forEach(function(row) { - var sort = row.sort(function(a, b) { return a.x - b.x; }); - var badi = null, badl = null, want; - for(var i=0; i0) - --badi; // might want to use more left - var l, limit; - if(i < sort.length - 2) { // found space before right - var extra = right.x - (badl + want); - l = sort[badi].x + extra/2; - limit = i+1; - } else { - l = Math.max(sort[badi].x, badl - best_dist(sort[badi], sort[badi+1]) - (want - right.x + badl)/2); - limit = sort.length; - } - for(var j = badi+1; j "' : '" -- "') + - encode_name(e.dcg_edgeTarget) + '" ' + stringize_properties([ - stringize_property('id', encode_name(e.dcg_edgeKey)), - stringize_property('arrowhead', 'none'), - stringize_property('arrowtail', 'none') - ]); - })); - lines.push('}'); - lines.push(''); - _dotString = lines.join('\n'); - } - - function process_response(error, result) { - if(error) { - console.warn("graphviz layout failed: ", error); - return; - } - _dispatch.start(); - var bb = result.bb.split(',').map(function(x) { return +x; }); - var nodes = (result.objects || []).filter(function(n) { - return n.pos; // remove non-nodes like clusters - }).map(function(n) { - var pos = n.pos.split(','); - if(isNaN(pos[0]) || isNaN(pos[1])) { - console.warn('got a NaN position from graphviz'); - pos[0] = pos[1] = 0; - } - return { - dcg_nodeKey: decode_name(n.name), - x: +pos[0], - y: bb[3] - pos[1] - }; - }); - var clusters = (result.objects || []).filter(function(n) { - return /^cluster/.test(n.name) && n.bb; - }); - clusters.forEach(function(c) { - c.dcg_clusterKey = c.name; - - // gv: llx, lly, urx, ury, up-positive - var cbb = c.bb.split(',').map(function(s) { return +s; }); - c.bounds = {left: cbb[0], top: bb[3] - cbb[3], - right: cbb[2], bottom: bb[3] - cbb[1]}; - }); - var edges = (result.edges || []).map(function(e) { - var e2 = { - dcg_edgeKey: decode_name(e.id || 'n' + e._gvid) - }; - if(e._draw_) { - var directive = e._draw_.find(function(d) { return d.op && d.points; }); - e2.points = directive.points.map(function(p) { return {x: p[0], y: bb[3] - p[1]}; }); - } - return e2; - }); - _dispatch.end(nodes, edges, clusters); - } - - function start() { - if(server) { - d3.json(server) - .header("Content-type", "application/x-www-form-urlencoded") - .post('layouttool=' + layout + '&' + encodeURIComponent(_dotString), process_response); - } - else { - var result = Viz(_dotString, {format: 'json', engine: layout, totalMemory: 1 << 25}); - result = JSON.parse(result); - process_response(null, result); - } - } - - function stop() { - } - - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); - return Object.assign(graphviz, { - layoutAlgorithm: function() { - return layout; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return false; - }, - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - init(options); - return this; - }, - data: function(graph, nodes, edges, clusters) { - data(nodes, edges, clusters); - }, - dotInput: function(text) { - _dotInput = text; - return this; - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - optionNames: function() { - return graphviz_keys; - }, - populateLayoutNode: function() {}, - populateLayoutEdge: function() {} - }); -} - - -/** - * `dc_graph.dynagraph_layout` connects to dynagraph-wasm and does dynamic directed graph layout. - * @class dynagraph_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.dynagraph_layout} - **/ -dc_graph.dynagraph_layout = function(id, layout) { - var _layoutId = id || uuid(); - const _Gname = _layoutId; - var _layout; - var _dispatch = d3.dispatch('tick', 'start', 'end'); - var _tick, _done; - var _nodes = {}, _edges = {}; - var _linesOut = [], _incrIn = [], _opened = false, _open_graph; - var _lock = 0; - - - - let bb = null; - // dg2incr - function dg2incr_coord(c) { - const [x, y] = c; - return [x, /*(bb && bb[0][1] || 0)*/ - y]; - } - - - function dg2incr_graph_attrs() { - return [ - ['rankdir', _layout.rankdir()], - ['resolution', [_layout.resolution().x, _layout.resolution().y]], - ['defaultsize', [_layout.defaultsize().width, _layout.defaultsize().height]], - ['separation', [_layout.separation().x, _layout.separation().y]], - ]; - } - - function dg2incr_node_attrs(n) { - const attr_pairs = []; - if(n.x !== undefined && n.y !== undefined) - attr_pairs.push(['pos', dg2incr_coord([n.x, n.y]).map(String).join(',')]); - return attr_pairs; - } - - function dg2incr_node_attrs_changed(n, n2) { - const attr_pairs = []; - if(n2.x !== undefined && n2.y !== undefined && (n2.x !== n.x || n2.y !== n.y)) - attr_pairs.push(['pos', dg2incr_coord([n2.x, n2.y]).map(String).join(',')]); - return attr_pairs; - } - - function dg2incr_edge_attrs(e) { - return []; - } - - function mq(x) { // maybe quote - if(x === +x) // isNumber - return x; - else if(/^[A-Za-z_][A-Za-z0-9_]*$/.test(x)) - return x; - else return '"' + x + '"'; - } - - function print_incr_attrs(attr_pairs) { - return '[' + attr_pairs.map(([a,b]) => `${mq(a)}=${mq(b)}`).join(', ') + ']'; - } - - // incr2dg - function incr2dg_coord(c) { - const [x, y] = c; - return [+x, /*(bb && bb[0][1] || 0)*/ - y]; - } - function incr2dg_bb(bb) { - const [x1,y1,x2,y2] = bb.split(','); - return [incr2dg_coord([x1,y1]), incr2dg_coord([x2,y2])]; - } - function incr2dg_node_attrs(n) { - const attrs = {}; - if(n.pos) - [attrs.x, attrs.y] = incr2dg_coord(n.pos.split(',').map(Number)); - return attrs; - } - function incr2dg_edge_attrs(e) { - const attrs = {}; - if(e.pos) - attrs.points = e.pos.split(' ') - .map(coord => coord.split(',').map(Number)) - .map(incr2dg_coord) - .map(([x,y]) => ({x,y})); - return attrs; - } - - function runCommands(cmds) { - for(const cmd of cmds) { - const {action, kind} = cmd; - switch(`${action}_${kind}`) { - case 'open_graph': { - const {attrs} = cmd; - console.log('open graph', attrs); - console.log('open graph bb', bb) - bb = incr2dg_bb(attrs.bb) - console.log('open graph bb', bb) - break; - } - case 'modify_graph': { - const {attrs} = cmd; - console.log('modify graph', attrs); - console.log('modify graph bb', bb) - bb = incr2dg_bb(attrs.bb) - console.log('modify graph bb', bb) - break; - } - case 'close_graph': { - console.log('close graph'); - break; - } - case 'insert_node': { - const {node, attrs} = cmd; - console.log('insert node', node, attrs); - console.log('insert node2', _nodes[node]) - Object.assign(_nodes[node], incr2dg_node_attrs(attrs)); - console.log('insert node3', _nodes[node]) - break; - } - case 'modify_node': { - const {node, attrs} = cmd; - console.log('modify node', node, attrs); - console.log('modify node2', _nodes[node]) - Object.assign(_nodes[node], incr2dg_node_attrs(attrs)); - console.log('modify node3', _nodes[node]) - break; - } - case 'delete_node': { - const {node} = cmd; - console.log('delete node', node); - break; - } - case 'insert_edge': { - const {edge, source, target, attrs} = cmd; - console.log('insert edge', edge, source, target, attrs); - console.log('insert edge2', _edges[edge]) - Object.assign(_edges[edge], incr2dg_edge_attrs(attrs)); - console.log('insert edge3', _edges[edge]) - break; - } - case 'modify_edge': { - const {edge, attrs} = cmd; - console.log('modify edge', edge, attrs); - console.log('modify edge2', _edges[edge]) - Object.assign(_edges[edge], incr2dg_edge_attrs(attrs)); - console.log('modify edge3', _edges[edge]) - break; - } - case 'delete_edge': { - const {edge} = cmd; - console.log('delete edge', edge); - break; - } - } - } - } - function receiveIncr(text) { - console.log(text); - let cmds = null; - try { - const parseIncrface = self.parseIncrface || (self.incrface && self.incrface.parse); - if(!parseIncrface) { - console.log('parseIncrface not available, skipping'); - return; - } - cmds = parseIncrface(text); - } catch(xep) { - console.log('incrface parse failed', xep) - } - if (!cmds) - return; - for(const cmd of cmds) { - const {action, kind, graph} = cmd; - if(action === 'message') { - console.warn('dynagraph message', cmd.message); - continue; - } - if(graph !== _Gname) { - console.warn('graph name mismatch', _Gname, graph); - continue; - } - switch(`${action}_${kind}`) { - case 'lock_graph': - _lock++; - break; - case 'unlock_graph': - // maybe error on negative lock? - if(--_lock <= 0) { - runCommands(_incrIn); - _incrIn = [] - } - break; - default: - if(_lock > 0) - _incrIn.push(cmd); - else - runCommands([cmd]); - } - } - _done(); - } - - function init(options) { - self.receiveIncr = receiveIncr; - _opened = false; - _open_graph = `open graph ${mq(_Gname)} ${print_incr_attrs(dg2incr_graph_attrs())}` - } - - function data(nodes, edges, clusters) { - const linesOutDeleteNode = []; - var wnodes = regenerate_objects(_nodes, nodes, null, - function key(v) { - return v.dcg_nodeKey; - }, function assign(v1, v) { - v1.dcg_nodeKey = v.dcg_nodeKey; - v1.width = v.width; - v1.height = v.height; - if(v.dcg_nodeFixed) { - v1.x = v.dcg_nodeFixed.x; - v1.y = v.dcg_nodeFixed.y; - } - const na = dg2incr_node_attrs_changed(v1, v); - if(na.length) - _linesOut.push(`modify node ${mq(_Gname)} ${mq(v1.dcg_nodeKey)} ${print_incr_attrs(na)}`); - }, function create(k, o) { - _linesOut.push(`insert node ${mq(_Gname)} ${mq(k)} ${print_incr_attrs(dg2incr_node_attrs(o))}`); - }, function destroy(k) { - linesOutDeleteNode.push(`delete node ${mq(_Gname)} ${mq(k)}`); - }); - var wedges = regenerate_objects(_edges, edges, null, function key(e) { - return e.dcg_edgeKey; - }, function assign(e1, e) { - e1.dcg_edgeKey = e.dcg_edgeKey; - e1.dcg_edgeSource = e.dcg_edgeSource; - e1.dcg_edgeTarget = e.dcg_edgeTarget; - }, function create(k, o, e) { - _linesOut.push(`insert edge ${mq(_Gname)} ${mq(k)} ${mq(e.dcg_edgeSource)} ${mq(e.dcg_edgeTarget)} ${print_incr_attrs(dg2incr_edge_attrs(e))}`); - }, function destroy(k, e) { - _linesOut.push(`delete edge ${mq(_Gname)} ${k}`); - }); - _linesOut.push(...linesOutDeleteNode); - - function dispatchState(event) { - _dispatch[event]( - wnodes, - wedges - ); - } - _tick = function() { - dispatchState('tick'); - }; - _done = function() { - dispatchState('end'); - }; - } - - function start() { - if(_linesOut.length) { - const open = _opened ? [] : [_open_graph]; - _opened = true; - const actions = _linesOut.length > 1 ? [ - `lock graph ${mq(_Gname)}`, - ... _linesOut, - `unlock graph ${mq(_Gname)}` - ] : _linesOut; - const input = [...open, ...actions].join('\n'); - console.log('dynagraph input:', input); - self.incrface_input = input; - _linesOut = []; - } - else _done(); - } - - function stop() { - } - - _layout = { - ...dc_graph.graphviz_attrs(), - layoutAlgorithm: function() { - return layout; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return true; - }, - resolution: property({x: 5, y: 5}), - defaultsize: property({width: 50, height: 50}), - separation: property({x: 20, y: 20}), - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - init(options); - return this; - }, - data: function(graph, nodes, edges) { - data(nodes, edges); - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - optionNames: function() { - return ['resolution', 'defaultsize', 'separation']; - }, - populateLayoutNode: function(layout, node) {}, - populateLayoutEdge: function() {} - }; - return _layout; -}; - -dc_graph.dynagraph_layout.scripts = ['d3.js', 'dynagraph-wasm.js', 'incrface-umd.js']; - -/** - * `dc_graph.d3_force_layout` is an adaptor for d3-force layouts in dc.graph.js - * @class d3_force_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.d3_force_layout} - **/ -dc_graph.d3_force_layout = function(id) { - var _layoutId = id || uuid(); - var _simulation = null; // d3-force simulation - var _dispatch = d3.dispatch('tick', 'start', 'end'); - // node and edge objects shared with d3-force, preserved from one iteration - // to the next (as long as the object is still in the layout) - var _nodes = {}, _edges = {}; - var _wnodes = [], _wedges = []; - var _options = null; - var _paths = null; - - function init(options) { - _options = options; - - _simulation = d3.layout.force() - .size([options.width, options.height]); - if(options.linkDistance) { - if(typeof options.linkDistance === 'number') - _simulation.linkDistance(options.linkDistance); - else if(options.linkDistance === 'auto') - _simulation.linkDistance(function(e) { - return e.dcg_edgeLength; - }); - } - - _simulation.on('tick', /* _tick = */ function() { - dispatchState('tick'); - }).on('start', function() { - _dispatch.start(); - }).on('end', /* _done = */ function() { - dispatchState('end'); - }); - } - - function dispatchState(event) { - _dispatch[event]( - _wnodes, - _wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }) - ); - } - - function data(nodes, edges, constraints) { - var nodeIDs = {}; - nodes.forEach(function(d, i) { - nodeIDs[d.dcg_nodeKey] = i; - }); - - _wnodes = regenerate_objects(_nodes, nodes, null, function(v) { - return v.dcg_nodeKey; - }, function(v1, v) { - v1.dcg_nodeKey = v.dcg_nodeKey; - v1.width = v.width; - v1.height = v.height; - v1.id = v.dcg_nodeKey; - if(v.dcg_nodeFixed) { - v1.fixed = true; - v1.x = v.dcg_nodeFixed.x; - v1.y = v.dcg_nodeFixed.y; - } else v1.fixed = false; - }); - - _wedges = regenerate_objects(_edges, edges, null, function(e) { - return e.dcg_edgeKey; - }, function(e1, e) { - e1.dcg_edgeKey = e.dcg_edgeKey; - // cola edges can work with indices or with object references - // but it will replace indices with object references - e1.source = _nodes[e.dcg_edgeSource]; - e1.source.id = nodeIDs[e1.source.dcg_nodeKey]; - e1.target = _nodes[e.dcg_edgeTarget]; - e1.target.id = nodeIDs[e1.target.dcg_nodeKey]; - e1.dcg_edgeLength = e.dcg_edgeLength; - }); - - _simulation.nodes(_wnodes); - _simulation.links(_wedges); - } - - function start() { - installForces(); - runSimulation(_options.iterations); - } - - function stop() { - if(_simulation) - _simulation.stop(); - } - - function savePositions() { - var data = {}; - Object.keys(_nodes).forEach(function(key) { - data[key] = {x: _nodes[key].x, y: _nodes[key].y}; - }); - return data; - } - - function restorePositions(data) { - Object.keys(data).forEach(function(key) { - if(_nodes[key]) { - _nodes[key].fixed = false; - _nodes[key].x = data[key].x; - _nodes[key].y = data[key].y; - } - }); - } - - function installForces() { - if(_paths === null) - _simulation.gravity(_options.gravityStrength) - .charge(_options.initialCharge); - else { - if(_options.fixOffPathNodes) { - var nodesOnPath = d3.set(); // nodes on path - _paths.forEach(function(path) { - path.forEach(function(nid) { - nodesOnPath.add(nid); - }); - }); - - // fix nodes not on paths - Object.keys(_nodes).forEach(function(key) { - if(!nodesOnPath.has(key)) { - _nodes[key].fixed = true; - } else { - _nodes[key].fixed = false; - } - }); - } - - // enlarge charge force to separate nodes on paths - _simulation.charge(_options.chargeForce); - } - }; - - function runSimulation(iterations) { - if(!iterations) { - dispatchState('end'); - return; - } - _simulation.start(); - for (var i = 0; i < 300; ++i) { - _simulation.tick(); - if(_paths) - applyPathAngleForces(); - } - _simulation.stop(); - } - - function applyPathAngleForces() { - function _dot(v1, v2) { return v1.x*v2.x + v1.y*v2.y; }; - function _len(v) { return Math.sqrt(v.x*v.x + v.y*v.y); }; - function _angle(v1, v2) { - var a = _dot(v1, v2) / (_len(v1)*_len(v2)); - a = Math.min(a, 1); - a = Math.max(a, -1); - return Math.acos(a); - }; - // perpendicular unit length vector - function _pVec(v) { - var xx = -v.y/v.x, yy = 1; - var length = _len({x: xx, y: yy}); - return {x: xx/length, y: yy/length}; - }; - - function updateNode(node, angle, pVec, alpha) { - node.x += pVec.x*(Math.PI-angle)*alpha; - node.y += pVec.y*(Math.PI-angle)*alpha; - } - - _paths.forEach(function(path) { - if(path.length < 3) return; // at least 3 nodes (and 2 edges): A->B->C - for(var i = 1; i < path.length-1; ++i) { - var current = _nodes[path[i]]; - var prev = _nodes[path[i-1]]; - var next = _nodes[path[i+1]]; - - // calculate the angle - var vPrev = {x: prev.x - current.x, y: prev.y - current.y}; - var vNext = {x: next.x - current.x, y: next.y - current.y}; - - var angle = _angle(vPrev, vNext); // angle in [0, PI] - - var pvecPrev = _pVec(vPrev); - var pvecNext = _pVec(vNext); - - // make sure the perpendicular vector is in the - // direction that makes the angle more towards 180 degree - // 1. calculate the middle point of node 'prev' and 'next' - var mid = {x: (prev.x+next.x)/2.0, y: (prev.y+next.y)/2.0}; - // 2. calculate the vectors: 'prev' pointing to 'mid', 'next' pointing to 'mid' - var prev_mid = {x: mid.x-prev.x, y: mid.y-prev.y}; - var next_mid = {x: mid.x-next.x, y: mid.y-next.y}; - // 3. the 'correct' vector: the angle between pvec and prev_mid(next_mid) should - // be an obtuse angle - pvecPrev = _angle(prev_mid, pvecPrev) >= Math.PI/2.0 ? pvecPrev : {x: -pvecPrev.x, y: -pvecPrev.y}; - pvecNext = _angle(next_mid, pvecNext) >= Math.PI/2.0 ? pvecNext : {x: -pvecNext.x, y: -pvecNext.y}; - - // modify positions of prev and next - updateNode(prev, angle, pvecPrev, _options.angleForce); - updateNode(next, angle, pvecNext, _options.angleForce); - } - - }); - } - - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); - - var engine = Object.assign(graphviz, { - layoutAlgorithm: function() { - return 'd3-force'; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return true; - }, - supportsMoving: function() { - return true; - }, - parent: property(null), - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - init(options); - return this; - }, - data: function(graph, nodes, edges, constraints) { - data(nodes, edges, constraints); - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - paths: function(paths) { - _paths = paths; - }, - savePositions: savePositions, - restorePositions: restorePositions, - optionNames: function() { - return ['iterations', 'angleForce', 'chargeForce', 'gravityStrength', - 'initialCharge', 'linkDistance', 'fixOffPathNodes'] - .concat(graphviz_keys); - }, - iterations: property(300), - angleForce: property(0.02), - chargeForce: property(-500), - gravityStrength: property(1.0), - initialCharge: property(-400), - linkDistance: property(20), - fixOffPathNodes: property(false), - populateLayoutNode: function() {}, - populateLayoutEdge: function() {} - }); - return engine; -}; - -dc_graph.d3_force_layout.scripts = ['d3.js']; - -/** - * `dc_graph.d3v4_force_layout` is an adaptor for d3-force version 4 layouts in dc.graph.js - * @class d3v4_force_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.d3v4_force_layout} - **/ -dc_graph.d3v4_force_layout = function(id) { - var _layoutId = id || uuid(); - var _simulation = null; // d3-force simulation - var _dispatch = d3.dispatch('tick', 'start', 'end'); - // node and edge objects shared with d3-force, preserved from one iteration - // to the next (as long as the object is still in the layout) - var _nodes = {}, _edges = {}; - var _wnodes = [], _wedges = []; - var _options = null; - var _paths = null; - - function init(options) { - _options = options; - - _simulation = d3v4.forceSimulation() - .force('link', d3v4.forceLink()) - .force('center', d3v4.forceCenter(options.width / 2, options.height / 2)) - .force('gravityX', d3v4.forceX(options.width / 2).strength(_options.gravityStrength)) - .force('gravityY', d3v4.forceY(options.height / 2).strength(_options.gravityStrength)) - .force('collision', d3v4.forceCollide(_options.collisionRadius)) - .force('charge', d3v4.forceManyBody()) - .stop(); - } - - function dispatchState(event) { - _dispatch[event]( - _wnodes, - _wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }) - ); - } - - function data(nodes, edges) { - var nodeIDs = {}; - nodes.forEach(function(d, i) { - nodeIDs[d.dcg_nodeKey] = i; - }); - - _wnodes = regenerate_objects(_nodes, nodes, null, function(v) { - return v.dcg_nodeKey; - }, function(v1, v) { - v1.dcg_nodeKey = v.dcg_nodeKey; - v1.width = v.width; - v1.height = v.height; - v1.id = v.dcg_nodeKey; - if(v.dcg_nodeFixed) { - v1.fx = v.dcg_nodeFixed.x; - v1.fy = v.dcg_nodeFixed.y; - } else v1.fx = v1.fy = null; - }); - - _wedges = regenerate_objects(_edges, edges, null, function(e) { - return e.dcg_edgeKey; - }, function(e1, e) { - e1.dcg_edgeKey = e.dcg_edgeKey; - e1.source = nodeIDs[_nodes[e.dcg_edgeSource].dcg_nodeKey]; - e1.target = nodeIDs[_nodes[e.dcg_edgeTarget].dcg_nodeKey]; - e1.dcg_edgeLength = e.dcg_edgeLength; - }); - - _simulation.force('straighten', null); - _simulation.nodes(_wnodes); - _simulation.force('link').links(_wedges); - } - - function start() { - _dispatch.start(); - installForces(_paths); - runSimulation(_options.iterations); - } - - function stop() { - // not running asynchronously, no _simulation.stop(); - } - - function savePositions() { - var data = {}; - Object.keys(_nodes).forEach(function(key) { - data[key] = {x: _nodes[key].x, y: _nodes[key].y}; - }); - return data; - } - function restorePositions(data) { - Object.keys(data).forEach(function(key) { - if(_nodes[key]) { - _nodes[key].fx = data[key].x; - _nodes[key].fy = data[key].y; - } - }); - } - function installForces(paths) { - if(paths) - paths = paths.filter(function(path) { - return path.nodes.every(function(nk) { return _nodes[nk]; }); - }); - if(paths === null || !paths.length) { - _simulation.force('charge').strength(_options.initialCharge); - } else { - var nodesOnPath; - if(_options.fixOffPathNodes) { - nodesOnPath = d3.set(); - paths.forEach(function(path) { - path.nodes.forEach(function(nid) { - nodesOnPath.add(nid); - }); - }); - } - - // fix nodes not on paths - Object.keys(_nodes).forEach(function(key) { - if(_options.fixOffPathNodes && !nodesOnPath.has(key)) { - _nodes[key].fx = _nodes[key].x; - _nodes[key].fy = _nodes[key].y; - } else { - _nodes[key].fx = null; - _nodes[key].fy = null; - } - }); - - _simulation.force('charge').strength(_options.chargeForce); - _simulation.force('straighten', d3v4.forceStraightenPaths() - .id(function(n) { return n.dcg_nodeKey; }) - .angleForce(_options.angleForce) - .pathNodes(function(p) { return p.nodes; }) - .pathStrength(function(p) { return p.strength; }) - .paths(paths)); - } - }; - - function runSimulation(iterations) { - _simulation.alpha(1); - for (var i = 0; i < iterations; ++i) { - _simulation.tick(); - dispatchState('tick'); - } - dispatchState('end'); - } - - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); - - var engine = Object.assign(graphviz, { - layoutAlgorithm: function() { - return 'd3v4-force'; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return true; - }, - supportsMoving: function() { - return true; - }, - parent: property(null), - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - init(options); - return this; - }, - data: function(graph, nodes, edges, constraints) { - data(nodes, edges, constraints); - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - paths: function(paths) { - _paths = paths; - }, - savePositions: savePositions, - restorePositions: restorePositions, - optionNames: function() { - return ['iterations', 'angleForce', 'chargeForce', 'gravityStrength', 'collisionRadius', - 'initialCharge', 'fixOffPathNodes'] - .concat(graphviz_keys); - }, - iterations: property(300), - angleForce: property(0.01), - chargeForce: property(-600), - gravityStrength: property(0.3), - collisionRadius: property(8), - initialCharge: property(-100), - fixOffPathNodes: property(false), - populateLayoutNode: function() {}, - populateLayoutEdge: function() {} - }); - engine.pathStraightenForce = engine.angleForce; - return engine; -}; - -dc_graph.d3v4_force_layout.scripts = ['d3.js', 'd3v4-force.js']; - -/** - * `dc_graph.flexbox_layout` lays out nodes in accordance with the - * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox flexbox layout algorithm}. - * Nodes fit into a containment hierarchy based on their keys; edges do not affect the layout but - * are drawn from node to node. - * - * Since the flexbox algorithm is not ordinarily available in SVG, this class uses the - * {@link https://npmjs.com/package/css-layout css-layout} - * package. (It does not currently support css-layout's successor - * {@link https://github.com/facebook/yoga yoga} but that should be straightforward to add if - * there is interest.) - * - * Unlike conventional graph layout, where positions are determined based on a few attributes and - * the topological structure of the eedges, flexbox layout is determined based on the node hierarchy - * and a large number of attributes on the nodes. See css-layout's - * {@link https://npmjs.com/package/css-layout#supported-attributes Supported Attributes} - * for a list of those attributes, and see below to understand how the hierarchy is inferred from - * node keys. - * - * `flexbox_layout` does not require all internal nodes to be specified. The node keys are parsed as - * "addresses" or paths (arrays of strings) and the tree is built from those paths. Wherever a - * node's path terminates is where that node's data will be applied. - * - * Since flexbox supports a vast number of attributes, we don't attempt to create accessors for - * every one. Instead, any attributes in the node data are copied which match the names of flexbox - * attributes. - * - * @class flexbox_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.flexbox_layout} - **/ -dc_graph.flexbox_layout = function(id, options) { - var _layoutId = id || uuid(); - options = options || {algo: 'yoga-layout'}; - var _dispatch = d3.dispatch('tick', 'start', 'end'); - - var _graph, _tree, _nodes = {}, _wnodes; - - function init(options) { - } - // like d3.nest but address can be of arbitrary (and different) length - // probably less efficient too - function add_node(adhead, adtail, n, tree) { - tree.address = adhead.slice(); - tree.children = tree.children || {}; - if(!adtail.length) { - tree.node = n; - return; - } - var t = tree.children[adtail[0]] = tree.children[adtail[0]] || {}; - adhead.push(adtail.shift()); - add_node(adhead, adtail, n, t); - } - function all_keys(tree) { - var key = _engine.addressToKey()(tree.address); - return Array.prototype.concat.apply([key], Object.keys(tree.children || {}).map(function(k) { - return all_keys(tree.children[k]); - })); - } - function data(graph, nodes) { - _graph = graph; - _tree = {address: [], children: {}}; - nodes.forEach(function(n) { - var ad = _engine.keyToAddress()(n.dcg_nodeKey); - add_node([], ad, n, _tree); - }); - var need = all_keys(_tree); - _wnodes = nodes; - } - function ensure_inner_nodes(tree) { - if(!tree.node) - tree.node = {dcg_nodeKey: tree.address.length ? tree.address[tree.address.length-1] : null}; - Object.values(tree.children).forEach(ensure_inner_nodes); - } - function getYogaConstants() { - // Return constants only if yogaLayout is available - if (typeof yogaLayout === 'undefined') return null; - - return { - alignItems: { - stretch: yogaLayout.ALIGN_STRETCH, - 'flex-start': yogaLayout.ALIGN_FLEX_START, - center: yogaLayout.ALIGN_CENTER, - 'flex-end': yogaLayout.ALIGN_FLEX_END, - baseline: yogaLayout.ALIGN_BASELINE - }, - alignSelf: { - stretch: yogaLayout.ALIGN_STRETCH, - 'flex-start': yogaLayout.ALIGN_FLEX_START, - center: yogaLayout.ALIGN_CENTER, - 'flex-end': yogaLayout.ALIGN_FLEX_END, - baseline: yogaLayout.ALIGN_BASELINE - }, - alignContent: { - 'flex-start': yogaLayout.ALIGN_FLEX_START, - 'flex-end': yogaLayout.ALIGN_FLEX_END, - stretch: yogaLayout.ALIGN_STRETCH, - center: yogaLayout.ALIGN_CENTER, - 'space-between': yogaLayout.ALIGN_SPACE_BETWEEN, - 'space-around': yogaLayout.ALIGN_SPACE_AROUND - }, - flexDirection: { - column: yogaLayout.FLEX_DIRECTION_COLUMN, - 'column-reverse': yogaLayout.FLEX_DIRECTION_COLUMN_REVERSE, - row: yogaLayout.FLEX_DIRECTION_ROW, - 'row-reverse': yogaLayout.FLEX_DIRECTION_ROW_REVERSE - }, - justifyContent: { - 'flex-start': yogaLayout.JUSTIFY_FLEX_START, - center: yogaLayout.JUSTIFY_CENTER, - 'flex-end': yogaLayout.JUSTIFY_FLEX_END, - 'space-between': yogaLayout.JUSTIFY_SPACE_BETWEEN, - 'space-around': yogaLayout.JUSTIFY_SPACE_AROUND, - 'space-evenly': yogaLayout.JUSTIFY_SPACE_EVENLY - } - }; - } - function set_yoga_attr(flexnode, attr, value) { - var fname = 'set' + attr.charAt(0).toUpperCase() + attr.slice(1); - if(typeof flexnode[fname] !== 'function') - throw new Error('Could not set yoga attr "' + attr + '" (' + fname + ')'); - var yoga_constants = getYogaConstants(); - if(yoga_constants && yoga_constants[attr]) - value = yoga_constants[attr][value]; - - // Handle attributes that need an edge parameter (padding, margin, border, position) - if(attr === 'padding' || attr === 'margin' || attr === 'border' || attr.endsWith('Padding') || attr.endsWith('Margin')) { - // For generic padding/margin, apply to all edges - flexnode[fname](yogaLayout.EDGE_ALL, value); - } else if(attr === 'width') { - flexnode.setWidth(value); - } else if(attr === 'height') { - flexnode.setHeight(value); - } else { - flexnode[fname](value); - } - } - function get_yoga_attr(flexnode, attr) { - var fname = 'getComputed' + attr.charAt(0).toUpperCase() + attr.slice(1); - if(typeof flexnode[fname] !== 'function') - throw new Error('Could not get yoga attr "' + attr + '" (' + fname + ')'); - return flexnode[fname](); - } - var internal_attrs = ['sort', 'order', 'dcg_nodeKey', 'dcg_nodeParentCluster', 'shape', 'abstract', 'rx', 'ry', 'x', 'y', 'z', 'nodeOutlineClip'], - skip_on_parents = ['width', 'height']; - function create_flextree(attrs, tree) { - var flexnode; - switch(options.algo) { - case 'css-layout': - flexnode = {name: _engine.addressToKey()(tree.address), style: {}}; - break; - case 'yoga-layout': - if (typeof yogaLayout === 'undefined') { - // Return a placeholder that will be replaced when yoga is ready - flexnode = { _yogaPending: true }; - } else { - flexnode = new yogaLayout.Node(); - } - break; - } - var attrs2 = Object.assign({}, attrs); - var isParent = Object.keys(tree.children).length; - if(tree.node) - Object.assign(attrs, tree.node); - for(var attr in attrs) { - if(internal_attrs.includes(attr)) - continue; - if(isParent && skip_on_parents.includes(attr)) - continue; - var value = attrs[attr]; - if(typeof value === 'function') - value = value(tree.node); - switch(options.algo) { - case 'css-layout': - flexnode.style[attr] = value; - break; - case 'yoga-layout': - set_yoga_attr(flexnode, attr, value); - break; - } - } - if(isParent) { - var children = Object.values(tree.children) - .sort(attrs.sort) - .map(function(c) { return c.address[c.address.length-1]; }) - .map(function(key) { - return create_flextree(Object.assign({}, attrs2), tree.children[key]); - }); - switch(options.algo) { - case 'css-layout': - flexnode.children = children; - break; - case 'yoga-layout': - children.forEach(function(child, i) { - flexnode.insertChild(child, i); - }); - break; - } - } - tree.flexnode = flexnode; - return flexnode; - } - function apply_layout(offset, tree) { - var left, top, width, height; - switch(options.algo) { - case 'css-layout': - if(_engine.logStuff()) - console.log(tree.node.dcg_nodeKey + ': '+ JSON.stringify(tree.flexnode.layout)); - left = tree.flexnode.layout.left; width = tree.flexnode.layout.width; - top = tree.flexnode.layout.top; height = tree.flexnode.layout.height; - break; - case 'yoga-layout': - left = get_yoga_attr(tree.flexnode, 'left'); width = get_yoga_attr(tree.flexnode, 'width'); - top = get_yoga_attr(tree.flexnode, 'top'); height = get_yoga_attr(tree.flexnode, 'height'); - break; - } - tree.node.x = offset.x + left + width/2; - tree.node.y = offset.y + top + height/2; - Object.keys(tree.children) - .map(function(key) { return tree.children[key]; }) - .forEach(function(child) { - apply_layout({x: offset.x + left, y: offset.y + top}, child); - }); - } - function dispatchState(wnodes, wedges, event) { - _dispatch[event]( - wnodes, - wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }) - ); - } - function start() { - // If yoga layout is requested but yoga isn't ready yet, wait for it - if (options.algo === 'yoga-layout' && typeof yogaLayout === 'undefined') { - if (typeof loadYogaLayout === 'function') { - loadYogaLayout().then(function() { - start(); // Retry when yoga is ready - }); - return; - } else { - console.warn('yoga-layout requested but yogaLayout not available. Falling back to css-layout.'); - options.algo = 'css-layout'; - } - } - - var defaults = { - sort: function(a, b) { - return d3.ascending(a.node.dcg_nodeKey, b.node.dcg_nodeKey); - } - }; - ensure_inner_nodes(_tree); - var flexTree = create_flextree(defaults, _tree); - switch(options.algo) { - case 'css-layout': - flexTree.style.width = _graph.width; - flexTree.style.height = _graph.height; - break; - case 'yoga-layout': - set_yoga_attr(flexTree, 'width', _graph.width); - set_yoga_attr(flexTree, 'height', _graph.height); - break; - } - if(_engine.logStuff()) - console.log(JSON.stringify(flexTree, null, 2)); - switch(options.algo) { - case 'css-layout': - computeLayout(flexTree); - break; - case 'yoga-layout': - flexTree.calculateLayout(); - break; - } - apply_layout({x: 0, y: 0}, _tree); - dispatchState(_wnodes, [], 'end'); - } - function stop() { - } - - // currently dc.graph populates the "cola" (really "layout") member with the attributes - // needed for layout and does not pass in the original data. flexbox has a huge number of attributes - // and it might be more appropriate for it to look at the original data. - // (Especially because it also computes some attributes based on data.) - var supportedAttributes = [ - 'width', 'height', // positive number - 'minWidth', 'minHeight', // positive number - 'maxWidth', 'maxHeight', // positive number - 'left', 'right', 'top', 'bottom', // number - 'margin', 'marginLeft', 'marginRight', 'marginTop', 'marginBottom', // number - 'padding', 'paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom', // positive number - 'borderWidth', 'borderLeftWidth', 'borderRightWidth', 'borderTopWidth', 'borderBottomWidth', // positive number - 'flexDirection', // 'column', 'row' - 'justifyContent', // 'flex-start', 'center', 'flex-end', 'space-between', 'space-around' - 'alignItems', 'alignSelf', // 'flex-start', 'center', 'flex-end', 'stretch' - 'flex', // positive number - 'flexWrap', // 'wrap', 'nowrap' - 'position' // 'relative', 'absolute' - ]; - - var _engine = { - layoutAlgorithm: function() { - return 'cola'; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return true; - }, - parent: property(null), - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - init(options); - return this; - }, - data: function(graph, nodes) { - data(graph, nodes); - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - optionNames: function() { - return []; - }, - populateLayoutNode: function(n1, n) { - ['sort', 'order'].concat(supportedAttributes).forEach(function(attr) { - if(n.orig.value[attr]) - n1[attr] = n.orig.value[attr]; - }); - }, - populateLayoutEdge: function() {}, - /** - * This function constructs a node key string from an "address". An address is an array of - * strings identifying the path from the root to the node. - * - * By default, it joins the address with commas. - * @method addressToKey - * @memberof dc_graph.flexbox_layout - * @instance - * @param {Function} [addressToKey = function(ad) { return ad.join(','); }] - * @return {Function} - * @return {dc_graph.flexbox_layout} - **/ - addressToKey: property(function(ad) { return ad.join(','); }), - /** - * This function constructs an "address" from a node key string. An address is an array of - * strings identifying the path from the root to the node. - * - * By default, it splits the key by its commas. - * @method keyToAddress - * @memberof dc_graph.flexbox_layout - * @instance - * @param {Function} [keyToAddress = function(nid) { return nid.split(','); }] - * @return {Function} - * @return {dc_graph.flexbox_layout} - **/ - keyToAddress: property(function(nid) { return nid.split(','); }), - yogaConstants: function() { - // in case any are missing, they can be added - // please file PRs for any missing constants! - return yoga_constants; - }, - logStuff: property(false) - }; - return _engine; -}; - -dc_graph.flexbox_layout.scripts = ['css-layout.js']; - -dc_graph.manual_layout = function(id) { - var _layoutId = id || uuid(); - var _dispatch = d3.dispatch('tick', 'start', 'end'); - - var _wnodes; - - function init(options) { - } - function data(nodes) { - _wnodes = nodes; - } - function dispatchState(wnodes, wedges, event) { - _dispatch[event]( - wnodes, - wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }) - ); - } - function start() { - dispatchState(_wnodes, [], 'end'); - } - function stop() { - } - - var _engine = { - layoutAlgorithm: function() { - return 'manual'; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return false; - }, - parent: property(null), - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - init(options); - return this; - }, - data: function(graph, nodes, edges) { - data(nodes); - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - optionNames: function() { - return []; - }, - populateLayoutNode: function(n1, n) { - ['x', 'y'].forEach(function(attr) { - if(n.orig.value[attr] !== undefined) - n1[attr] = n.orig.value[attr]; - }); - }, - populateLayoutEdge: function() {}, - addressToKey: property(function(ad) { return ad.join(','); }), - keyToAddress: property(function(nid) { return nid.split(','); }) - }; - return _engine; -}; - -dc_graph.manual_layout.scripts = ['css-layout.js']; - -/** - * `dc_graph.layered_layout` produces 3D layered layouts, utilizing another layout - * that supports fixed nodes and position hints for the layers - * @class layered_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.layered_layout} - **/ -dc_graph.layered_layout = function(id) { - var _layoutId = id || uuid(); - var _dispatch = d3.dispatch('tick', 'start', 'end'); - var _supergraph, _subgraphs; - var _layers; - var _options = null; - - function init(options) { - _options = options; - - } - - function data(nodes, edges, constraints) { - _supergraph = dc_graph.supergraph({nodes: nodes, edges: edges}, { - nodeKey: function(n) { return n.dcg_nodeKey; }, - edgeKey: function(n) { return n.dcg_edgeKey; }, - nodeValue: function(n) { return n; }, - edgeValue: function(e) { return e; }, - edgeSource: function(e) { return e.dcg_edgeSource; }, - edgeTarget: function(e) { return e.dcg_edgeTarget; } - }); - - // every node belongs natively in one rank - var nranks = _supergraph.nodes().reduce(function(p, n) { - var rank = engine.layerAccessor()(n.value()); - p[rank] = p[rank] || []; - p[rank].push(n); - return p; - }, {}); - var eranks = Object.keys(nranks).reduce(function(p, r) { - p[r] = []; - return p; - }, {}); - - // nodes are shadowed into any layers to which they are adjacent - // edges are induced from the native&shadow nodes in each layer - _supergraph.edges().forEach(function(e) { - var srank = engine.layerAccessor()(e.source().value()), - trank = engine.layerAccessor()(e.target().value()); - if(srank == trank) { - eranks[srank].push(e); - return; - } - nranks[trank].push(e.source()); - eranks[trank].push(e); - nranks[srank].push(e.target()); - eranks[srank].push(e); - }); - - // produce a subgraph for each layer - _subgraphs = Object.keys(nranks).reduce(function(p, r) { - p[r] = _supergraph.subgraph( - nranks[r].map(function(n) { return n.key(); }), - eranks[r].map(function(e) { return e.key(); })); - return p; - }, {}); - - // start from the most populous layer - var max = null; - Object.keys(nranks).forEach(function(r) { - if(max === null || - _subgraphs[r].nodes().length > _subgraphs[max].nodes().length) - max = +r; - }); - - // travel up and down from there, each time fixing the nodes from the last layer - var ranks = Object.keys(nranks).map(function(r) { return +r; }).sort(); - _layers = ranks.map(function(r) { - return { - rank: r, - z: -r * engine.layerSeparationZ() - }; - }); - var mi = ranks.indexOf(max); - var ups = ranks.slice(mi+1), downs = ranks.slice(0, mi).reverse(); - layout_layer(max, -1).then(function(layout) { - Promise.all([ - layout_layers(layout, max, ups), - layout_layers(layout, max, downs) - ]).then(function() { - _dispatch.end( - _supergraph.nodes().map(function(n) { return n.value(); }), - _supergraph.edges().map(function(e) { return e.value(); })); - }); - }); - } - - function layout_layers(layout, last, layers) { - if(layers.length === 0) - return Promise.resolve(layout); - var curr = layers.shift(); - return layout_layer(curr, last).then(function(layout) { - return layout_layers(layout, curr, layers); - }); - } - - function layout_layer(r, last) { - _subgraphs[r].nodes().forEach(function(n) { - if(engine.layerAccessor()(n.value()) !== r && - n.value().x !== undefined && - n.value().y !== undefined) - n.value().dcg_nodeFixed = { - x: n.value().x, - y: n.value().y - }; - else n.value().dcg_nodeFixed = null; - }); - var subengine = engine.engineFactory()(); - subengine.init(_options); - subengine.data( - {}, - _subgraphs[r].nodes().map(function(n) { - return n.value(); - }), - _subgraphs[r].edges().map(function(e) { - return e.value(); - })); - return promise_layout(r, subengine); - } - - function promise_layout(r, subengine) { - // stopgap - engine.start() should return a promise - return new Promise(function(resolve, reject) { - subengine.on('end', function(nodes, edges) { - resolve({nodes: nodes, edges: edges}); - }); - subengine.start(); - }).then(function(layout) { - // copy positions back into the subgraph (and hence supergraph) - layout.nodes.forEach(function(ln) { - var n = _subgraphs[r].node(ln.dcg_nodeKey); - // do not copy positions for shadow nodes - if(engine.layerAccessor()(n.value()) !== r) - return; - n.value().x = ln.x; - n.value().y = ln.y; - n.value().z = -r * engine.layerSeparationZ(); // lowest rank at top - }); - return layout; - }); - } - - function start() { - _dispatch.start(); - } - - function stop() { - } - - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); - - var engine = Object.assign(graphviz, { - layoutAlgorithm: function() { - return 'layered'; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return false; - }, - parent: property(null), - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - init(options); - return this; - }, - data: function(graph, nodes, edges, constraints) { - data(nodes, edges, constraints); - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - optionNames: function() { - return [] - .concat(graphviz_keys); - }, - engineFactory: property(null), - layerAccessor: property(null), - layerSeparationZ: property(50), - layers: function() { - return _layers; - }, - populateLayoutNode: function() {}, - populateLayoutEdge: function() {}, - extractNodeAttrs: property({}), // {attr: function(node)} - extractEdgeAttrs: property({}) - }); - return engine; -}; - - - -function port_name(nodeId, edgeId, portName) { - if(!(nodeId || edgeId)) - return null; // must have one key or the other - if(nodeId) nodeId = nodeId.replace(/\//g, '%2F'); - if(edgeId) edgeId = edgeId.replace(/\//g, '%2F'); - return (nodeId ? 'node/' + nodeId : 'edge/' + edgeId) + '/' + portName; -}; -function split_port_name(portname) { - var parts = portname.split('/'); - console.assert(parts.length === 3); - parts = parts.map(function(p) { - return p.replace(/%2F/g, '/'); - }); - if(parts[0] === 'node') - return { - nodeKey: parts[1], - name: parts[2] - }; - else return { - edgeKey: parts[1], - name: parts[2] - }; -} -function project_port(diagram, n, p) { - if(!p.vec) { - console.assert(!p.edges.length); - throw new Error("port has not been placed, maybe install place_ports? " + p.name); - } - p.pos = diagram.shape(n.dcg_shape.shape).intersect_vec(n, p.vec[0]*1000, p.vec[1]*1000); -} - -dc_graph.place_ports = function() { - function received_layout(diagram, nodes, wnodes, edges, wedges, ports, wports) { - var node_ports = diagram.nodePorts(); - - function is_ccw(u, v) { - return u[0]*v[1] - u[1]*v[0] > 0; - } - function in_bounds(v, bounds) { - // assume bounds are ccw - return is_ccw(bounds[0], v) && is_ccw(v, bounds[1]); - } - function clip(v, bounds) { - if(is_ccw(v, bounds[0])) - return bounds[0]; - else if(is_ccw(bounds[1], v)) - return bounds[1]; - else return v; - } - function a_to_v(a) { - return [Math.cos(a), Math.sin(a)]; - } - function v_to_a(v) { - return Math.atan2(v[1], v[0]); - } - function distance(p, p2) { - return Math.hypot(p2.pos.x - p.pos.x, p2.pos.y - p.pos.y); - } - function misses(p, p2) { - var dist = distance(p, p2); - var misses = dist > _mode.minDistance(); - return misses; - } - function rand_within(a, b) { - return a + Math.random()*(b-a); - } - // calculate port positions - for(var nid in node_ports) { - var n = nodes[nid], - nports = node_ports[nid]; - - // make sure that we have vector and angle bounds for any ports with specification - nports.forEach(function(p) { - var bounds = p.orig && diagram.portBounds.eval(p) || [0, 2*Math.PI]; - if(Array.isArray(bounds[0])) { - p.vbounds = bounds; - p.abounds = bounds.map(v_to_a); - } - else { - p.vbounds = bounds.map(a_to_v); - p.abounds = bounds; - } - if(p.abounds[0] > p.abounds[1]) - p.abounds[1] += 2*Math.PI; - console.assert(p.orig || p.vec, 'unplaced unspecified port'); - }); - - // determine which ports satisfy bounds or are unplaced - var inside = [], outside = [], unplaced = []; - nports.forEach(function(p) { - if(!p.vec) - unplaced.push(p); - else if(p.vbounds && !in_bounds(p.vec, p.vbounds)) - outside.push(p); - else - inside.push(p); - }); - - // shunt outside ports into their bounds - outside.forEach(function(p) { - p.vec = clip(p.vec, p.vbounds); - inside.push(p); - }); - - // for all unplaced ports that share a bounds, evenly distribute them within those bounds. - // assume that bounds are disjoint. - var boundses = {}, boundports = {}; - unplaced.forEach(function(p) { - var boundskey = p.abounds.map(function(x) { return x.toFixed(3); }).join(','); - boundses[boundskey] = p.abounds; - boundports[boundskey] = boundports[boundskey] || []; - boundports[boundskey].push(p); - }); - for(var b in boundports) { - var bounds = boundses[b], bports = boundports[b]; - if(bports.length === 1) - bports[0].vec = a_to_v((bounds[0] + bounds[1])/2); - else { - var slice = (bounds[1] - bounds[0]) / (boundports[b].length - 1); - boundports[b].forEach(function(p, i) { - p.vec = a_to_v(bounds[0] + i*slice); - }); - } - } - inside = inside.concat(unplaced); - unplaced = []; - - // determine positions of all satisfied - inside.forEach(function(p) { - project_port(diagram, n, p); - }); - - // detect any existing collisions, unplace the one without edges or second one - for(var i = 0; i < inside.length; ++i) { - var x = inside[i]; - if(unplaced.includes(x)) - continue; - for(var j = i+1; j < inside.length; ++j) { - var y = inside[j]; - if(unplaced.includes(y)) - continue; - if(!misses(x, y)) { - if(!x.edges.length) { - unplaced.push(x); - continue; - } - else - unplaced.push(y); - } - } - } - inside = inside.filter(function(p) { return !unplaced.includes(p); }); - - // place any remaining by trying random spots within the range until it misses all or we give up - var patience = _mode.patience(), maxdist = 0, maxvec; - while(unplaced.length) { - var p = unplaced[0]; - p.vec = a_to_v(rand_within(p.abounds[0], p.abounds[1])); - project_port(diagram, n, p); - var mindist = d3.min(inside, function(p2) { return distance(p, p2); }); - if(mindist > maxdist) { - maxdist = mindist; - maxvec = p.vec; - } - if(!patience-- || mindist > _mode.minDistance()) { - if(patience<0) { - console.warn('ran out of patience placing a port'); - p.vec = maxvec; - project_port(diagram, n, p); - } - inside.push(p); - unplaced.shift(); - patience = _mode.patience(); - maxdist = 0; - } - } - } - }; - var _mode = { - parent: property(null).react(function(p) { - if(p) { - p.on('receivedLayout.place-ports', received_layout); - } else if(_mode.parent()) - _mode.parent().on('receivedLayout.place-ports', null); - }), - // minimum distance between ports - minDistance: property(20), - // number of random places to try when resolving collision - patience: property(20) - }; - - return _mode; -}; - -dc_graph.grid = function() { - var _gridLayer = null; - var _translate, _scale, _xDomain, _yDomain; - - function draw(diagram, node, edge, ehover) { - //infer_and_draw(diagram); - } - - function remove(diagram, node, edge, ehover) { - if(_gridLayer) - _gridLayer.remove(); - } - - function draw(diagram) { - _gridLayer = diagram.g().selectAll('g.grid-layer').data([0]); - _gridLayer.enter().append('g').attr('class', 'grid-layer'); - var ofs = _mode.wholeOnLines() ? 0 : 0.5; - var vline_data = _scale >= _mode.threshold() ? d3.range(Math.floor(_xDomain[0]), Math.ceil(_xDomain[1]) + 1) : []; - var vlines = _gridLayer.selectAll('line.grid-line.vertical') - .data(vline_data, function(d) { return d - ofs; }); - vlines.exit().remove(); - vlines.enter().append('line') - .attr({ - class: 'grid-line vertical', - x1: function(d) { return d - ofs; }, - x2: function(d) { return d - ofs; } - }); - vlines.attr({ - 'stroke-width': 1/_scale, - y1: _yDomain[0], - y2: _yDomain[1] - }); - var hline_data = _scale >= _mode.threshold() ? d3.range(Math.floor(_yDomain[0]), Math.ceil(_yDomain[1]) + 1) : []; - var hlines = _gridLayer.selectAll('line.grid-line.horizontal') - .data(hline_data, function(d) { return d - ofs; }); - hlines.exit().remove(); - hlines.enter().append('line') - .attr({ - class: 'grid-line horizontal', - y1: function(d) { return d - ofs; }, - y2: function(d) { return d - ofs; } - }); - hlines.attr({ - 'stroke-width': 1/_scale, - x1: _xDomain[0], - x2: _xDomain[1] - }); - } - - function on_zoom(translate, scale, xDomain, yDomain) { - _translate = translate; - _scale = scale; - _xDomain = xDomain, - _yDomain = yDomain; - draw(_mode.parent()); - } - - function infer_and_draw(diagram) { - _translate = diagram.translate(); - _scale = diagram.scale(); - _xDomain = diagram.x().domain(); - _yDomain = diagram.y().domain(); - draw(diagram); - } - - var _mode = dc_graph.mode('highlight-paths', { - draw: draw, - remove: remove, - parent: function(p) { - if(p) { - p.on('zoomed.grid', on_zoom); - infer_and_draw(p); - } - } - }); - - _mode.threshold = property(4); - _mode.wholeOnLines = property(true); - - return _mode; -}; - - - -dc_graph.annotate_layers = function() { - // svg-specific - var _drawLayer; - // wegl-specific - var _planes = []; - var _planeGeometry; - var _mode = dc_graph.mode('annotate-layers', { - laterDraw: true, - renderers: ['svg', 'webgl'], - draw: draw, - remove: remove - }); - function draw(diagram) { - var rendererType = _mode.parent().renderer().rendererType(); - var engine = _mode.parent().layoutEngine(); - if(rendererType === 'svg') { - if(engine.layoutAlgorithm() === 'cola' && - engine.setcolaSpec() && engine.setcolaNodes()) { - _drawLayer = _mode.parent().select('g.draw').selectAll('g.divider-layer').data([0]); - _drawLayer.enter().append('g').attr('class', 'divider-layer'); - var boundary_nodes = engine.setcolaNodes().filter(function(n) { - return /^sort_order_boundary/.test(n.name); - }); - var lines = _drawLayer.selectAll('line.divider').data(boundary_nodes); - lines.exit().remove(); - lines.enter().append('line') - .attr('class', 'divider'); - lines.attr({ - stroke: _mode.stroke(), - 'stroke-width': _mode.strokeWidth(), - 'stroke-dasharray': _mode.strokeDashArray(), - x1: -5000, - y1: function(n) { - return n.y; - }, - x2: 5000, - y2: function(n) { - return n.y; - } - }); - } - } else if(rendererType === 'webgl') { - var MULT = _mode.parent().renderer().multiplier(); - var scene = arguments[1], drawState = arguments[2]; - if(engine.layoutAlgorithm() === 'layered' && engine.layers()) { - var width = drawState.extents[0][1] - drawState.extents[0][0] + _mode.planePadding()*MULT*2, - height = drawState.extents[1][1] - drawState.extents[1][0] + _mode.planePadding()*MULT*2; - var delGeom; - var shape = new THREE.Shape(); - shape.moveTo(0, 0); - shape.lineTo(0, height); - shape.lineTo(width, height); - shape.lineTo(width, 0); - shape.lineTo(0, 0); - if(_planeGeometry) - delGeom = _planeGeometry; - _planeGeometry = new THREE.ShapeBufferGeometry(shape); - - var layers = engine.layers(); - if(layers.length < _planes.length) { - for(var i = layers.length; i < _planes.length; ++i) - scene.remove(_planes[i].mesh); - _planes = _planes.slice(0, layers.length); - } - layers.forEach(function(layer, i) { - if(!_planes[i]) - _planes[i] = Object.assign({}, layer); - if(_planes[i].mesh) - scene.remove(_planes[i].mesh); - var mesh = _planes[i].mesh = new THREE.Mesh(_planeGeometry, new THREE.MeshStandardMaterial({ - opacity: _mode.planeOpacity(), - transparent: true, - color: _mode.parent().renderer().color_to_int(_mode.planeColor()), - side: THREE.DoubleSide - })); - mesh.position.set(drawState.extents[0][0] - _mode.planePadding()*MULT, - drawState.extents[1][0] - _mode.planePadding()*MULT, - layer.z * MULT); - scene.add(mesh); - }); - if(delGeom) - delGeom.dispose(); - } - } else throw new Error("annotate_layers doesn't know how to work with renderer " + rendererType); - } - function remove() { - if(_drawLayer) - _drawLayer.remove(); - } - - // line properties for svg - _mode.stroke = property('black'); - _mode.strokeWidth = property(2); - _mode.strokeDashArray = property([5,5]); - - // plane properties - _mode.planePadding = property(5); - _mode.planeOpacity = property(0.2); - _mode.planeColor = property('#ffffdd'); - return _mode; -}; - -dc_graph.troubleshoot = function() { - var _debugLayer = null; - var _translate, _scale = 1, _xDomain, _yDomain; - - function draw(diagram, node, edge, ehover) { - if(!_debugLayer) - _debugLayer = diagram.g().append('g').attr({ - class: 'troubleshoot', - 'pointer-events': 'none' - }); - var centers = node.data().map(function(n) { - return { - x: n.cola.x, - y: n.cola.y - }; - }); - var crosshairs = _debugLayer.selectAll('path.nodecenter').data(centers); - crosshairs.exit().remove(); - crosshairs.enter().append('path').attr('class', 'nodecenter'); - crosshairs.attr({ - d: function(c) { - return 'M' + (c.x - _mode.xhairWidth()/2) + ',' + c.y + ' h' + _mode.xhairWidth() + - ' M' + c.x + ',' + (c.y - _mode.xhairHeight()/2) + ' v' + _mode.xhairHeight(); - }, - opacity: _mode.xhairOpacity() !== null ? _mode.xhairOpacity() : _mode.opacity(), - stroke: _mode.xhairColor(), - 'stroke-width': 1/_scale - }); - function cola_point(n) { - return {x: n.cola.x, y: n.cola.y}; - } - var colabounds = node.data().map(function(n) { - return boundary(cola_point(n), n.cola.width, n.cola.height); - }); - var colaboundary = _debugLayer.selectAll('path.colaboundary').data(colabounds); - draw_corners(colaboundary, 'colaboundary', _mode.boundsColor()); - - var textbounds = node.data().map(function(n) { - if(!n.bbox || (!n.bbox.width && !n.bbox.height)) - return null; - return boundary(cola_point(n), n.bbox.width, n.bbox.height); - }).filter(function(n) { return !!n; }); - var textboundary = _debugLayer.selectAll('path.textboundary').data(textbounds); - draw_corners(textboundary, 'textboundary', _mode.boundsColor()); - - var radiibounds = node.data().map(function(n) { - if(typeof n.dcg_rx !== 'number') - return null; - return boundary(cola_point(n), n.dcg_rx*2, n.dcg_ry*2); - }).filter(function(n) { return !!n; }); - var radiiboundary = _debugLayer.selectAll('path.radiiboundary').data(radiibounds); - draw_corners(radiiboundary, 'radiiboundary', _mode.boundsColor()); - - diagram.addOrRemoveDef('debug-orient-marker-head', - true, - 'svg:marker', - orient_marker.bind(null, _mode.arrowHeadColor())); - diagram.addOrRemoveDef('debug-orient-marker-tail', - true, - 'svg:marker', - orient_marker.bind(null, _mode.arrowTailColor())); - var heads = _mode.arrowLength() ? edge.data().map(function(e) { - return {pos: e.pos.new.path.points[e.pos.new.path.points.length-1], orient: e.pos.new.orienthead}; - }) : []; - var headOrients = _debugLayer.selectAll('line.heads').data(heads); - draw_arrow_orient(headOrients, 'heads', _mode.arrowHeadColor(), '#debug-orient-marker-head'); - - var tails = _mode.arrowLength() ? edge.data().map(function(e) { - return {pos: e.pos.new.path.points[0], orient: e.pos.new.orienttail}; - }) : []; - var tailOrients = _debugLayer.selectAll('line.tails').data(tails); - draw_arrow_orient(tailOrients, 'tails', _mode.arrowTailColor(), '#debug-orient-marker-tail'); - - var headpts = Array.prototype.concat.apply([], edge.data().map(function(e) { - var arrowSize = diagram.edgeArrowSize.eval(e); - return edge_arrow_points( - diagram.arrows(), - diagram.edgeArrowhead.eval(e), - arrowSize, - diagram.edgeStrokeWidth.eval(e) / arrowSize, - unrad(e.pos.new.orienthead), - e.pos.new.full.points[e.pos.new.full.points.length-1], - diagram.nodeStrokeWidth.eval(e.target) - ); - })); - var hp = _debugLayer.selectAll('path.head-point').data(headpts); - draw_x(hp, 'head-point', _mode.arrowHeadColor()); - - var tailpts = Array.prototype.concat.apply([], edge.data().map(function(e) { - var arrowSize = diagram.edgeArrowSize.eval(e); - return edge_arrow_points( - diagram.arrows(), - diagram.edgeArrowtail.eval(e), - arrowSize, - diagram.edgeStrokeWidth.eval(e) / arrowSize, - unrad(e.pos.new.orienttail), - e.pos.new.full.points[0], - diagram.nodeStrokeWidth.eval(e.source) - ); - })); - var tp = _debugLayer.selectAll('path.tail-point').data(tailpts); - draw_x(tp, 'tail-point', _mode.arrowTailColor()); - - var domain = _debugLayer.selectAll('rect.domain').data([0]); - domain.enter().append('rect'); - var xd = _mode.parent().x().domain(), yd = _mode.parent().y().domain(); - domain.attr({ - class: 'domain', - fill: 'none', - opacity: _mode.domainOpacity(), - stroke: _mode.domainColor(), - 'stroke-width': _mode.domainStrokeWidth()/_scale, - x: xd[0], - y: yd[0], - width: xd[1] - xd[0], - height: yd[1] - yd[0] - }); - } - function on_zoom(translate, scale, xDomain, yDomain) { - _translate = translate; - _scale = scale; - _xDomain = xDomain; - _yDomain = yDomain; - draw(_mode.parent(), _mode.parent().selectAllNodes(), _mode.parent().selectAllEdges()); - } - - function boundary(point, wid, hei) { - return { - left: point.x - wid/2, - top: point.y - hei/2, - right: point.x + wid/2, - bottom: point.y + hei/2 - }; - }; - function bound_tick(x, y, dx, dy) { - return 'M' + x + ',' + (y + dy) + ' v' + -dy + ' h' + dx; - } - function corners(bounds) { - return [ - bound_tick(bounds.left, bounds.top, _mode.boundsWidth(), _mode.boundsHeight()), - bound_tick(bounds.right, bounds.top, -_mode.boundsWidth(), _mode.boundsHeight()), - bound_tick(bounds.right, bounds.bottom, -_mode.boundsWidth(), -_mode.boundsHeight()), - bound_tick(bounds.left, bounds.bottom, _mode.boundsWidth(), -_mode.boundsHeight()), - ].join(' '); - } - function draw_corners(binding, classname, color) { - binding.exit().remove(); - binding.enter().append('path').attr('class', classname); - binding.attr({ - d: corners, - opacity: _mode.boundsOpacity() !== null ? _mode.boundsOpacity() : _mode.opacity(), - stroke: color, - 'stroke-width': 1/_scale, - fill: 'none' - }); - } - function unrad(orient) { - return +orient.replace('rad',''); - } - function draw_arrow_orient(binding, classname, color, markerUrl) { - binding.exit().remove(); - binding.enter().append('line').attr('class', classname); - binding.attr({ - x1: function(d) { return d.pos.x; }, - y1: function(d) { return d.pos.y; }, - x2: function(d) { return d.pos.x - Math.cos(unrad(d.orient))*_mode.arrowLength(); }, - y2: function(d) { return d.pos.y - Math.sin(unrad(d.orient))*_mode.arrowLength(); }, - stroke: color, - 'stroke-width': _mode.arrowStrokeWidth()/_scale, - opacity: _mode.arrowOpacity() !== null ? _mode.arrowOpacity() : _mode.opacity(), - 'marker-end': 'url(' + markerUrl + ')' - }); - } - function orient_marker(color, markerEnter) { - markerEnter - .attr({ - viewBox: '0 -3 3 6', - refX: 3, - refY: 0, - orient: 'auto' - }); - markerEnter.append('path') - .attr('stroke', color) - .attr('fill', 'none') - .attr('d', 'M0,3 L3,0 L0,-3'); - } - function edge_arrow_points(arrows, defn, arrowSize, stemWidth, orient, endp, strokeWidth) { - var parts = arrow_parts(arrows, defn), - offsets = arrow_offsets(parts, stemWidth), - xunit = [Math.cos(orient), Math.sin(orient)]; - endp = [endp.x, endp.y]; - if(!parts.length) - return [[endp[0] - xunit[0]*strokeWidth/2, - endp[1] - xunit[1]*strokeWidth/2]]; - var globofs = add_points( - [-strokeWidth/arrowSize/2,0], - mult_point(front_ref(parts[0].frontRef), -1)); - var pts = offsets.map(function(ofs, i) { - return mult_point([ - globofs, - front_ref(parts[i].frontRef), - ofs.offset - ].reduce(add_points), arrowSize); - }); - pts.push(mult_point([ - globofs, - back_ref(parts[parts.length-1].backRef), - offsets[parts.length-1].offset - ].reduce(add_points), arrowSize)); - return pts.map(function(p) { - return add_points( - endp, - [p[0]*xunit[0] - p[1]*xunit[1], p[0]*xunit[1] + p[1]*xunit[0]] - ); - }); - } - - - function draw_x(binding, classname, color) { - var xw = _mode.xWidth()/2, xh = _mode.xHeight()/2; - binding.exit().remove(); - binding.enter().append('path').attr('class', classname); - binding.attr({ - d: function(pos) { - return [[[-xw,-xh],[xw,xh]], [[xw,-xh], [-xw,xh]]].map(function(seg) { - return 'M' + seg.map(function(p) { - return (pos[0] + p[0]) + ',' + (pos[1] + p[1]); - }).join(' L'); - }).join(' '); - }, - 'stroke-width': 2/_scale, - stroke: color, - opacity: _mode.xOpacity() - }); - } - function remove(diagram, node, edge, ehover) { - if(_debugLayer) - _debugLayer.remove(); - } - - var _mode = dc_graph.mode('highlight-paths', { - laterDraw: true, - draw: draw, - remove: remove, - parent: function(p) { - if(p) { - _translate = p.translate(); - _scale = p.scale(); - p.on('zoomed.troubleshoot', on_zoom); - } - else if(_mode.parent()) - _mode.parent().on('zoomed.troubleshoot', null); - } - }); - _mode.opacity = property(0.75); - - _mode.xhairOpacity = property(null); - _mode.xhairWidth = property(10); - _mode.xhairHeight = property(10); - _mode.xhairColor = property('blue'); - - _mode.boundsOpacity = property(null); - _mode.boundsWidth = property(10); - _mode.boundsHeight = property(10); - _mode.boundsColor = property('green'); - - _mode.arrowOpacity = property(null); - _mode.arrowStrokeWidth = property(3); - _mode.arrowColor = _mode.arrowHeadColor = property('darkorange'); - _mode.arrowTailColor = property('red'); - _mode.arrowLength = property(100); - - _mode.xWidth = property(1); - _mode.xHeight = property(1); - _mode.xOpacity = property(0.8); - - _mode.domainOpacity = property(0.6); - _mode.domainColor = property('darkorange'); - _mode.domainStrokeWidth = property(4); - - return _mode; -}; - - - dc_graph.validate = function(title) { - function falsy(objects, accessor, what, who) { - var f = objects.filter(function(o) { - return !accessor(o); - }); - return f.length ? - [what + ' is empty for ' + f.length + ' of ' + objects.length + ' ' + who, f] : - null; - } - function build_index(objects, accessor) { - return objects.reduce(function(m, o) { - m[accessor(o)] = o; - return m; - }, {}); - } - function not_found(index, objects, accessor, what, where, who) { - var nf = objects.filter(function(o) { - return !index[accessor(o)]; - }).map(function(o) { - return {key: accessor(o), value: o}; - }); - return nf.length ? - [what + ' was not found in ' + where, Object.keys(index), 'for ' + nf.length + ' of ' + objects.length + ' ' + who, nf] : - null; - } - function validate() { - var diagram = _mode.parent(); - var nodes = diagram.nodeGroup().all(), - edges = diagram.edgeGroup().all(), - ports = diagram.portGroup() ? diagram.portGroup().all() : []; - var errors = []; - - function check(error) { - if(error) - errors.push(error); - } - - check(falsy(nodes, diagram.nodeKey(), 'nodeKey', 'nodes')); - check(falsy(edges, diagram.edgeSource(), 'edgeSource', 'edges')); - check(falsy(edges, diagram.edgeTarget(), 'edgeTarget', 'edges')); - - var contentTypes = d3.set(diagram.content.enum()); - var ct = dc_graph.functor_wrap(diagram.nodeContent()); - var noContentNodes = nodes.filter(function(kv) { - return !contentTypes.has(ct(kv)); - }); - if(noContentNodes.length) - errors.push(['there are ' + noContentNodes.length + ' nodes with nodeContent not matching any content', noContentNodes]); - - var nindex = build_index(nodes, diagram.nodeKey()), - eindex = build_index(edges, diagram.edgeKey()); - check(not_found(nindex, edges, diagram.edgeSource(), 'edgeSource', 'nodes', 'edges')); - check(not_found(nindex, edges, diagram.edgeTarget(), 'edgeTarget', 'nodes', 'edges')); - - check(falsy(ports, function(p) { - return diagram.portNodeKey() && diagram.portNodeKey()(p) || - diagram.portEdgeKey() && diagram.portEdgeKey()(p); - }, 'portNodeKey||portEdgeKey', 'ports')); - - var named_ports = !diagram.portNodeKey() && [] || ports.filter(function(p) { - return diagram.portNodeKey()(p); - }); - var anonymous_ports = !diagram.portEdgeKey() && [] || ports.filter(function(p) { - return diagram.portEdgeKey()(p); - }); - check(not_found(nindex, named_ports, diagram.portNodeKey(), 'portNodeKey', 'nodes', 'ports')); - check(not_found(eindex, anonymous_ports, diagram.portEdgeKey(), 'portEdgeKey', 'edges', 'ports')); - - if(diagram.portName()) { - var pindex = build_index(named_ports, function(p) { - return diagram.portNodeKey()(p) + ' - ' + diagram.portName()(p); - }); - if(diagram.edgeSourcePortName()) - check(not_found(pindex, edges, function(e) { - return diagram.edgeSource()(e) + ' - ' + d3.functor(diagram.edgeSourcePortName())(e); - }, 'edgeSourcePortName', 'ports', 'edges')); - if(diagram.edgeTargetPortName()) - check(not_found(pindex, edges, function(e) { - return diagram.edgeTarget()(e) + ' - ' + d3.functor(diagram.edgeTargetPortName())(e); - }, 'edgeTargetPortName', 'ports', 'edges')); - } - - function count_text() { - return nodes.length + ' nodes, ' + edges.length + ' edges, ' + ports.length + ' ports'; - } - if(errors.length) { - console.warn('validation of ' + title + ' failed with ' + count_text() + ':'); - errors.forEach(function(err) { - console.warn.apply(console, err); - }); - } - else - console.log('validation of ' + title + ' succeeded with ' + count_text() + '.'); - } - var _mode = { - parent: property(null).react(function(p) { - if(p) - p.on('data.validate', validate); - else - _mode.parent().on('data.validate', null); - }) - }; - - return _mode; -}; - -/** -## Legend - -The dc_graph.legend shows labeled examples of nodes & edges, within the frame of a dc_graph.diagram. -**/ -dc_graph.legend = function(legend_namespace) { - legend_namespace = legend_namespace || 'node-legend'; - var _items, _included = []; - var _dispatch = d3.dispatch('filtered'); - var _totals, _counts; - - var _svg_renderer; - - function apply_filter() { - if(_legend.customFilter()) - _legend.customFilter()(_included); - else if(_legend.dimension()) { - if(_legend.isTagDimension()) { - _legend.dimension().filterFunction(function(ks) { - return !_included.length || ks.filter(function(k) { - return _included.includes(k); - }).length; - }); - } else { - _legend.dimension().filterFunction(function(k) { - return !_included.length || _included.includes(k); - }); - } - _legend.parent().redraw(); - } - } - - var _legend = dc_graph.mode(legend_namespace, { - renderers: ['svg', 'webgl'], - draw: redraw, - remove: function() {}, - parent: function(p) { - if(p) { - p - .on('render.' + legend_namespace, render) - .on('data.' + legend_namespace, on_data); - } - else { - _legend.parent() - .on('render.' + legend_namespace, null) - .on('data.' + legend_namespace, null); - } - } - }); - - /** - #### .type([value]) - Set or get the handler for the specific type of item to be displayed. Default: dc_graph.legend.node_legend() - **/ - _legend.type = property(dc_graph.legend.node_legend()); - - /** - #### .x([value]) - Set or get x coordinate for legend widget. Default: 0. - **/ - _legend.x = property(0); - - /** - #### .y([value]) - Set or get y coordinate for legend widget. Default: 0. - **/ - _legend.y = property(0); - - /** - #### .gap([value]) - Set or get gap between legend items. Default: 5. - **/ - _legend.gap = property(5); - - /** - #### .itemWidth([value]) - Set or get width to reserve for legend item. Default: 30. - **/ - _legend.itemWidth = _legend.nodeWidth = property(40); - - /** - #### .itemHeight([value]) - Set or get height to reserve for legend item. Default: 30. - **/ - _legend.itemHeight = _legend.nodeHeight = property(40); - - _legend.dyLabel = property('0.3em'); - - _legend.omitEmpty = property(false); - - /** - #### .noLabel([value]) - Remove item labels, since legend labels are displayed outside of the items. Default: true - **/ - _legend.noLabel = property(true); - - _legend.counter = property(null); - - _legend.replaceFilter = function(filter) { - if(filter && filter.length === 1) - _included = filter[0]; - else - _included = []; - return _legend; - }; - - _legend.filters = function() { - return _included; - }; - - _legend.on = function(type, f) { - _dispatch.on(type, f); - return _legend; - }; - - /** - #### .exemplars([object]) - Specifies an object where the keys are the names of items to add to the legend, and the values are - objects which will be passed to the accessors of the attached diagram in order to determine the - drawing attributes. Alternately, if the key needs to be specified separately from the name, the - function can take an array of {name, key, value} objects. - **/ - _legend.exemplars = property({}); - - function on_data(diagram, nodes, wnodes, edges, wedges, ports, wports) { - if(_legend.counter()) - _counts = _legend.counter()(wnodes.map(get_original), wedges.map(get_original), wports.map(get_original), false); - } - - _legend.redraw = deprecate_function("dc_graph.legend is an ordinary mode now; redraw will go away soon", redraw); - function redraw() { - var legend = (_svg_renderer || _legend.parent()).svg() - .selectAll('g.dc-graph-legend.' + legend_namespace) - .data([0]); - legend.enter().append('g') - .attr('class', 'dc-graph-legend ' + legend_namespace) - .attr('transform', 'translate(' + _legend.x() + ',' + _legend.y() + ')'); - - var items = !_legend.omitEmpty() || !_counts ? _items : _items.filter(function(i) { - return _included.length && !_included.includes(i.orig.key) || _counts[i.orig.key]; - }); - var item = legend.selectAll(_legend.type().itemSelector()) - .data(items, function(n) { return n.name; }); - item.exit().remove(); - var itemEnter = _legend.type().create(_legend.parent(), item.enter(), _legend.itemWidth(), _legend.itemHeight()); - itemEnter.append('text') - .attr('dy', _legend.dyLabel()) - .attr('class', 'legend-label'); - item - .attr('transform', function(n, i) { - return 'translate(' + _legend.itemWidth()/2 + ',' + (_legend.itemHeight() + _legend.gap())*(i+0.5) + ')'; - }); - item.select('text.legend-label') - .attr('transform', 'translate(' + (_legend.itemWidth()/2+_legend.gap()) + ',0)') - .attr('pointer-events', _legend.dimension() ? 'auto' : 'none') - .text(function(d) { - return d.name + (_legend.counter() && _legend.filterable()(d) && _counts ? (' (' + (_counts[d.orig.key] || 0) + (_counts[d.orig.key] !== _totals[d.orig.key] ? '/' + (_totals[d.orig.key] || 0) : '') + ')') : ''); - }); - _legend.type().draw(_svg_renderer || _legend.parent(), itemEnter, item); - if(_legend.noLabel()) - item.selectAll(_legend.type().labelSelector()).remove(); - - if(_legend.dropdown()) { - var caret = item.selectAll('text.dropdown-caret').data(function(x) { return [x]; }); - caret - .enter().append('text') - .attr('dy', '0.3em') - .attr('font-size', '75%') - .attr('fill', 'blue') - .attr('class', 'dropdown-caret') - .style('visibility', 'hidden') - .html(' ▼'); - caret - .attr('dx', function(d) { - return (_legend.itemWidth()/2+_legend.gap()) + getBBoxNoThrow(d3.select(this.parentNode).select('text.legend-label').node()).width; - }) - .on('mouseenter.' + legend_namespace, function(n) { - var rect = this.getBoundingClientRect(); - var key = _legend.parent().nodeKey.eval(n); - _legend.dropdown() - .show(key, rect.x, rect.y); - }); - item - .on('mouseenter.' + legend_namespace, function(d) { - if(_counts && _counts[d.orig.key]) { - d3.select(this).selectAll('.dropdown-caret') - .style('visibility', 'visible'); - } - }) - .on('mouseleave.' + legend_namespace, function(d) { - d3.select(this).selectAll('.dropdown-caret') - .style('visibility', 'hidden'); - }); - } - - if(_legend.dimension()) { - item.filter(_legend.filterable()) - .attr('cursor', 'pointer') - .on('click.' + legend_namespace, function(d) { - var key = _legend.parent().nodeKey.eval(d); - if(!_included.length && !_legend.isInclusiveDimension()) - _included = _items.map(_legend.parent().nodeKey.eval); - if(_included.includes(key)) - _included = _included.filter(function(x) { return x !== key; }); - else - _included.push(key); - apply_filter(); - _dispatch.filtered(_legend, key); - if(_svg_renderer) - window.setTimeout(redraw, 250); - }); - } else { - item.attr('cursor', 'auto') - .on('click.' + legend_namespace, null); - } - item.transition().duration(1000) - .attr('opacity', function(d) { - return (!_legend.filterable()(d) || !_included.length || _included.includes(_legend.parent().nodeKey.eval(d))) ? 1 : 0.25; - }); - }; - - _legend.countBaseline = function() { - if(_legend.counter()) - _totals = _legend.counter()( - _legend.parent().nodeGroup().all(), - _legend.parent().edgeGroup().all(), - _legend.parent().portGroup() && _legend.parent().portGroup().all(), - true); - }; - - _legend.render = deprecate_function("dc_graph.legend is an ordinary mode now; render will go away soon", render); - function render() { - if(_legend.parent().renderer().rendererType() !== 'svg') { - _svg_renderer = dc_graph.render_svg(); - _svg_renderer.parent(_legend.parent()) - .svg(_legend.parent().root().append('svg') - .style({ - position: 'absolute', - left: 0, top: 0, - width: '100%', height: '100%', - fill: 'wheat', - 'pointer-events': 'none' - })); - } - - - var exemplars = _legend.exemplars(); - _legend.countBaseline(); - if(exemplars instanceof Array) { - _items = exemplars.map(function(v) { return {name: v.name, orig: {key: v.key, value: v.value}, cola: {}}; }); - } - else { - _items = []; - for(var item in exemplars) - _items.push({name: item, orig: {key: item, value: exemplars[item]}, cola: {}}); - } - redraw(); - }; - - _legend.dropdown = property(null).react(function(v) { - if(!!v !== !!_legend.dropdown() && _legend.parent() && (_svg_renderer || _legend.parent()).svg()) - window.setTimeout(_legend.redraw, 0); - }); - - /* enables filtering */ - _legend.dimension = property(null) - .react(function(v) { - if(!v) { - _included = []; - apply_filter(); - } - }); - _legend.filterable = property(() => true); - _legend.isInclusiveDimension = property(false); - _legend.isTagDimension = property(false); - _legend.customFilter = property(null); - - return _legend; -}; - - -dc_graph.legend.node_legend = function() { - return { - itemSelector: function() { - return '.node'; - }, - labelSelector: function() { - return '.node-label'; - }, - create: function(diagram, selection) { - return selection.append('g') - .attr('class', 'node'); - }, - draw: function(renderer, itemEnter, item) { - renderer - .renderNode(itemEnter) - .redrawNode(item); - } - }; -}; - -dc_graph.legend.edge_legend = function() { - var _type = { - itemSelector: function() { - return '.edge-container'; - }, - labelSelector: function() { - return '.edge-label'; - }, - create: function(diagram, selection, w, h) { - var edgeEnter = selection.append('g') - .attr('class', 'edge-container') - .attr('opacity', 0); - edgeEnter - .append('rect') - .attr({ - x: -w/2, - y: -h/2, - width: w, - height: h, - fill: 'green', - opacity: 0 - }); - edgeEnter - .selectAll('circle') - .data([-1, 1]) - .enter() - .append('circle') - .attr({ - r: _type.fakeNodeRadius(), - fill: 'none', - stroke: 'black', - "stroke-dasharray": "4,4", - opacity: 0.15, - transform: function(d) { - return 'translate(' + [d * _type.length() / 2, 0].join(',') + ')'; - } - }); - var edgex = _type.length()/2 - _type.fakeNodeRadius(); - edgeEnter.append('svg:path') - .attr({ - class: 'edge', - id: function(d) { return d.name; }, - d: 'M' + -edgex + ',0 L' + edgex + ',0', - opacity: diagram.edgeOpacity.eval - }); - - return edgeEnter; - }, - fakeNodeRadius: property(10), - length: property(50), - draw: function(renderer, itemEnter, item) { - renderer.redrawEdge(itemEnter.select('path.edge'), renderer.selectAllEdges('.edge-arrows')); - } - }; - return _type; -}; - -dc_graph.legend.symbol_legend = function(symbolScale) { - return { - itemSelector: function() { - return '.symbol'; - }, - labelSelector: function() { - return '.symbol-label'; - }, - create: function(diagram, selection, w, h) { - var symbolEnter = selection.append('g') - .attr('class', 'symbol'); - return symbolEnter; - }, - draw: function(renderer, symbolEnter, symbol) { - symbolEnter.append('text') - .html(function(d) { - return symbolScale(d.orig.key); - }); - return symbolEnter; - } - }; -}; - -/** - * In cola.js there are three factors which influence the positions of nodes: - * * *edge length* suggestions, controlled by the - * {@link #dc_graph.diagram+lengthStrategy lengthStrategy}, - * {@link #dc_graph.diagram+baseLength baseLength}, and - * {@link #dc_graph.diagram+edgeLength edgeLength} parameters in dc.graph.js - * * *automatic constraints* based on the global edge flow direction (`cola.flowLayout`) and overlap - * avoidance parameters (`cola.avoidOverlaps`) - * * *manual constraints* such as alignment, inequality and equality constraints in a dimension/axis. - * - * Generally when the - * {@link https://github.com/tgdwyer/WebCola/wiki/Constraints cola.js documentation mentions constraints}, - * it means the manual constraints. - * - * dc.graph.js allows generation of manual constraints using - * {@link #dc_graph.diagram+constrain diagram.constrain} but it can be tedious to write these - * functions because it usually means looping over the nodes and edges multiple times to - * determine what classes or types of nodes to apply constraints to, and which edges should - * take additional constraints. - * - * This utility creates a constraint generator function from a *pattern*, a graph where: - * 1. Nodes represent *types* or classes of layout nodes, annotated with a specification - * of how to match the nodes belonging each type. - * 2. Edges represent *rules* to generate constraints. There are two kinds of rules: - *
    - *
  1. To generate additional constraints on edges besides the built-in ones, create a rules - * between two different types. The rule will apply to any edges in the layout which match the - * source and target types, and generate simple "left/right" constraints. (Note that "left" and - * "right" in this context refer to sides of an inequality constraint `left + gap <= right`) - *
  2. To generate constraints on a set of nodes, such as alignment, ordering, or circle - * constraints, create a rule from a type to itself, a self edge. - *
- * (It is also conceivable to want constraints between individual nodes which don't - * have edges between them. This is not directly supported at this time; right now the workaround - * is to create the edge but not draw it, e.g. by setting its {@link #dc_graph.diagram+edgeOpacity} - * to zero. If you have a use-case for this, please - * {@link https://github.com/dc-js/dc.graph.js/issues/new file an issue}. - * - * The pattern syntax is an embedded domain specific language designed to be terse without - * restricting its power. As such, there are complicated rules for defaulting and inferring - * parameters from other parameters. Since most users will want the simplest form, this document - * will start from the highest level and then show how to use more complicated forms in order to - * gain more control. - * - * Then we'll build back up from the ground up and show how inference works. - * @class constraint_pattern - * @memberof dc_graph - * @param {dc_graph.diagram} diagram - the diagram to pull attributes from, mostly to determine - * the keys of nodes and edge sources and targets - * @param {Object} pattern - a graph which defines the constraints to be generated - * @return {Function} - */ -dc_graph.constraint_pattern = function(pattern) { - var types = {}, rules = []; - - pattern.nodes.forEach(function(n) { - var id = n.id; - var type = types[id] || (types[id] = {}); - // partitions could be done more efficiently; this is POC - if(n.partition) { - var partition = n.partition; - var value = n.value || n.id; - if(n.all || n.typename) { - type.match = n.extract ? - function(n2) { return n.extract(n2.value[partition]); } : - function(n2) { return n2.value[partition]; }; - type.typename = n.typename || function(n2) { return partition + '=' + n2.value[partition]; }; - } - else - type.match = function(n2) { return n2.value[partition] === value; }; - } - else if(n.match) - type.match = n.match; - else throw new Error("couldn't determine matcher for type " + JSON.stringify(n)); - }); - pattern.edges.forEach(function(e) { - if(e.disable) - return; - var rule = {source: e.source, target: e.target}; - rule.produce = typeof e.produce === 'function' ? e.produce : function() { - return clone(e.produce); - }; - ['listname', 'wrap', 'reverse'].forEach(function(k) { - if(e[k] !== undefined) rule[k] = e[k]; - }); - rules.push(rule); - }); - - return function(diagram, nodes, edges) { - var constraints = []; - var members = {}; - nodes.forEach(function(n) { - var key = diagram.nodeKey.eval(n); - for(var t in types) { - var type = types[t], value = type.match(n.orig); - if(value) { - var tname = type.typename ? type.typename(t, value) : t; - if(!members[tname]) - members[tname] = { - nodes: [], // original ordering - whether: {} // boolean - }; - members[tname].nodes.push(key); - members[tname].whether[key] = true; - } - } - }); - // traversal of rules could be more efficient, again POC - var edge_rules = rules.filter(function(r) { - return r.source !== r.target; - }); - var type_rules = rules.filter(function(r) { - return r.source === r.target; - }); - edges.forEach(function(e) { - var source = diagram.edgeSource.eval(e), - target = diagram.edgeTarget.eval(e); - edge_rules.forEach(function(r) { - if(members[r.source] && members[r.source].whether[source] && - members[r.target] && members[r.target].whether[target]) { - var constraint = r.produce(members, nodes, edges); - if(r.reverse) { - constraint.left = target; - constraint.right = source; - } - else { - constraint.left = source; - constraint.right = target; - } - constraints.push(constraint); - } - }); - }); - type_rules.forEach(function(r) { - if(!members[r.source]) - return; - var constraint = r.produce(), - listname = r.listname || r.produce.listname || 'nodes', - wrap = r.wrap || r.produce.wrap || function(x) { return x; }; - constraint[listname] = members[r.source].nodes.map(wrap); - constraints.push(constraint); - }); - return constraints; - }; -}; - -// constraint generation convenience functions -dc_graph.gap_y = function(gap, equality) { - return { - axis: 'y', - gap: gap, - equality: !!equality - }; -}; -dc_graph.gap_x = function(gap, equality) { - return { - axis: 'x', - gap: gap, - equality: !!equality - }; -}; - -function align_f(axis) { - var ret = function() { - return { - type: 'alignment', - axis: axis - }; - }; - ret.listname = 'offsets'; - ret.wrap = function(x) { return {node: x, offset: 0}; }; - return ret; -} - -dc_graph.align_y = function() { - return align_f('y'); -}; -dc_graph.align_x = function() { - return align_f('x'); -}; - -dc_graph.order_x = function(gap, ordering) { - return { - type: 'ordering', - axis: 'x', - gap: 60, - ordering: ordering - }; -}; -dc_graph.order_y = function(gap, ordering) { - return { - type: 'ordering', - axis: 'y', - gap: 60, - ordering: ordering - }; -}; - -// this naive tree-drawer is paraphrased from memory from dot -dc_graph.tree_positions = function(rootf, rowf, treef, ofsx, ofsy, nwidth, ygap) { - console.warn('dc_graph.tree_positions is deprecated; use the layout engine tree_layout instead'); - if(rootf || treef) { - console.warn('dc_graph.tree_positions: rootf and treef are ignored'); - } - var x; - nwidth = d3.functor(nwidth); - function best_dist(left, right) { - return (nwidth(left) + nwidth(right)) / 2; - } - var dfs = dc_graph.depth_first_traversal({ - nodeid: function(n) { - return n.cola.dcg_nodeKey; - }, - sourceid: function(n) { - return n.cola.dcg_edgeSource; - }, - targetid: function(n) { - return n.cola.dcg_edgeTarget; - }, - init: function() { - x = ofsx; - }, - row: function(n) { - return rowf(n.orig); - }, - place: function(n, r, row) { - if(row.length) { - var left = row[row.length-1]; - var g = (nwidth(left) + nwidth(n)) / 2; - x = Math.max(x, left.left_x + g); - } - n.left_x = x; - n.hit_ins = 1; - n.cola.y = r*ygap + ofsy; - }, - sib: function(isroot, left, right) { - var g = best_dist(left, right); - if(isroot) g = g*1.5; - x += g; - }, - pop: function(n) { - n.cola.x = (n.left_x + x)/2; - }, - skip: function(n, indegree) { - // rolling average of in-neighbor x positions - n.cola.x = (n.hit_ins*n.cola.x + x)/++n.hit_ins; - if(n.hit_ins === indegree) - delete n.hit_ins; - }, - finish: function(rows) { - // this is disgusting. patch up any places where nodes overlap by scanning - // right far enough to find the space, then fill from left to right at the - // minimum gap - rows.forEach(function(row) { - var sort = row.sort(function(a, b) { return a.cola.x - b.cola.x; }); - var badi = null, badl = null, want; - for(var i=0; i0) - --badi; // might want to use more left - var l, limit; - if(i < sort.length - 2) { // found space before right - var extra = right.cola.x - (badl + want); - l = sort[badi].cola.x + extra/2; - limit = i+1; - } else { - l = Math.max(sort[badi].cola.x, badl - best_dist(sort[badi], sort[badi+1]) - (want - right.cola.x + badl)/2); - limit = sort.length; - } - for(var j = badi+1; j" + d + ""; }) - .direction(_mode.direction()); - if(_mode.offset()) - _d3tip.offset(_mode.offset()); - parent.svg().call(_d3tip); - } - } - function fetch_and_show_content(d) { - if(_mode.disabled() || _mode.selection().exclude && _mode.selection().exclude(d3.event.target)) { - hide_tip.call(this); - return; - } - var target = this, - next = function() { - _mode.content()(d, function(content) { - _d3tip.show.call(target, content, target); - d3.select('div.d3-tip') - .selectAll('a.tip-link') - .on('click.' + _namespace, function() { - d3.event.preventDefault(); - if(_mode.linkCallback()) - _mode.linkCallback()(this.id); - }); - _dispatch.tipped(d); - }); - }; - if(_hideTimeout) - window.clearTimeout(_hideTimeout); - if(_mode.delay()) { - window.clearTimeout(_showTimeout); - _showTimeout = window.setTimeout(next, _mode.delay()); - } - else next(); - } - - function check_hide_tip() { - if(d3.event.relatedTarget && - (!_mode.selection().exclude || !_mode.selection().exclude(d3.event.target)) && - (this && this.contains(d3.event.relatedTarget) || // do not hide when mouse is still over a child - _mode.clickable() && d3.event.relatedTarget.classList.contains('d3-tip'))) - return false; - return true; - } - - function preempt_tip() { - if(_showTimeout) { - window.clearTimeout(_showTimeout); - _showTimeout = null; - } - } - - function hide_tip() { - if(!check_hide_tip.apply(this)) - return; - preempt_tip(); - _d3tip.hide(); - } - - function hide_tip_delay() { - if(!check_hide_tip.apply(this)) - return; - preempt_tip(); - if(_mode.hideDelay()) - _hideTimeout = window.setTimeout(function () { - _d3tip.hide(); - }, _mode.hideDelay()); - else - _d3tip.hide(); - } - - function draw(diagram, node, edge, ehover) { - init(diagram); - _mode.programmatic() || _mode.selection().select(diagram, node, edge, ehover) - .on('mouseover.' + _namespace, fetch_and_show_content) - .on('mouseout.' + _namespace, hide_tip_delay); - if(_mode.clickable()) { - d3.select('div.d3-tip') - .on('mouseover.' + _namespace, function() { - if(_hideTimeout) - window.clearTimeout(_hideTimeout); - }) - .on('mouseout.' + _namespace, hide_tip_delay); - } - } - function remove(diagram, node, edge, ehover) { - _mode.programmatic() || _mode.selection().select(diagram, node, edge, ehover) - .on('mouseover.' + _namespace, null) - .on('mouseout.' + _namespace, null); - } - - var _mode = dc_graph.mode(_namespace, { - draw: draw, - remove: remove, - laterDraw: true - }); - /** - * Specify the direction for tooltips. Currently supports the - * [cardinal and intercardinal directions](https://en.wikipedia.org/wiki/Points_of_the_compass) supported by - * [d3.tip.direction](https://github.com/Caged/d3-tip/blob/master/docs/positioning-tooltips.md#tipdirection): - * `'n'`, `'ne'`, `'e'`, etc. - * @name direction - * @memberof dc_graph.tip - * @instance - * @param {String} [direction='n'] - * @return {String} - * @return {dc_graph.tip} - **/ - _mode.direction = property('n'); - - /** - * Specifies the function to generate content for the tooltip. This function has the - * signature `function(d, k)`, where `d` is the datum of the thing being hovered over, - * and `k` is a continuation. The function should fetch the content, asynchronously if - * needed, and then pass html forward to `k`. - * @name content - * @memberof dc_graph.tip - * @instance - * @param {Function} [content] - * @return {Function} - * @example - * // Default mode: assume it's a node, show node title - * var tip = dc_graph.tip().content(function(n, k) { - * k(_mode.parent() ? _mode.parent().nodeTitle.eval(n) : ''); - * }); - **/ - _mode.content = property(function(n, k) { - k(_mode.parent() ? _mode.parent().nodeTitle.eval(n) : ''); - }); - - _mode.on = function(event, f) { - return _dispatch.on(event, f); - }; - - _mode.disabled = property(false); - _mode.programmatic = property(false); - - _mode.displayTip = function(filter, n, cb) { - if(typeof filter !== 'function') { - var d = filter; - filter = function(d2) { return d2 === d; }; - } - var found = _mode.selection().select(_mode.parent(), _mode.parent().selectAllNodes(), _mode.parent().selectAllEdges(), null) - .filter(filter); - if(found.size() > 0) { - var action = fetch_and_show_content; - // we need to flatten e.g. for ports, which will have nested selections - // .nodes() does this better in D3v4 - var flattened = found.reduce(function(p, v) { - return p.concat(v); - }, []); - var which = (n || 0) % flattened.length; - action.call(flattened[which], d3.select(flattened[which]).datum()); - d = d3.select(flattened[which]).datum(); - if(cb) - cb(d); - if(_mode.programmatic()) - found.on('mouseout.' + _namespace, hide_tip_delay); - } - return _mode; - }; - - _mode.hideTip = function(delay) { - if(_d3tip) { - if(delay) - hide_tip_delay(); - else - hide_tip(); - } - return _mode; - }; - _mode.selection = property(dc_graph.tip.select_node_and_edge()); - _mode.showDelay = _mode.delay = property(0); - _mode.hideDelay = property(200); - _mode.offset = property(null); - _mode.clickable = property(false); - _mode.linkCallback = property(null); - - return _mode; -}; - -/** - * Generates a handler which can be passed to `tip.content` to produce a table of the - * attributes and values of the hovered object. - * - * @name table - * @memberof dc_graph.tip - * @instance - * @return {Function} - * @example - * // show all the attributes and values in the node and edge objects - * var tip = dc_graph.tip(); - * tip.content(dc_graph.tip.table()); - **/ -dc_graph.tip.table = function() { - var gen = function(d, k) { - d = gen.fetch()(d); - if(!d) - return; // don't display tooltip if no content - var data, keys; - if(Array.isArray(d)) - data = d; - else if(typeof d === 'number' || typeof d === 'string') - data = [d]; - else { // object - data = keys = Object.keys(d).filter(d3.functor(gen.filter())) - .filter(function(k) { - return d[k] !== undefined; - }); - } - var table = d3.select(document.createElement('table')); - var rows = table.selectAll('tr').data(data); - var rowsEnter = rows.enter().append('tr'); - rowsEnter.append('td').text(function(item) { - if(keys && typeof item === 'string') - return item; - return JSON.stringify(item); - }); - if(keys) - rowsEnter.append('td').text(function(item) { - return JSON.stringify(d[item]); - }); - k(table.node().outerHTML); // optimizing for clarity over speed (?) - }; - gen.filter = property(true); - gen.fetch = property(function(d) { - return d.orig.value; - }); - return gen; -}; - -dc_graph.tip.json_table = function() { - var table = dc_graph.tip.table().fetch(function(d) { - var jsontip = table.json()(d); - if(!jsontip) return null; - try { - return JSON.parse(jsontip); - } catch(xep) { - return [jsontip]; - } - }); - table.json = property(function(d) { - return (d.orig.value.value || d.orig.value).jsontip; - }); - return table; -}; - -dc_graph.tip.html_or_json_table = function() { - var json_table = dc_graph.tip.json_table(); - var gen = function(d, k) { - var html = gen.html()(d); - if(html) - k(html); - else - json_table(d, k); - }; - gen.json = json_table.json; - gen.html = property(function(d) { - return (d.orig.value.value || d.orig.value).htmltip; - }); - return gen; -}; - -dc_graph.tip.select_node_and_edge = function() { - return { - select: function(diagram, node, edge, ehover) { - // hack to merge selections, not supported d3v3 - var selection = diagram.selectAll('.foo-this-does-not-exist'); - selection[0] = node[0].concat(ehover ? ehover[0] : []); - return selection; - }, - exclude: function(element) { - return ancestor_has_class(element, 'port'); - } - }; -}; - -dc_graph.tip.select_node = function() { - return { - select: function(diagram, node, edge, ehover) { - return node; - }, - exclude: function(element) { - return ancestor_has_class(element, 'port'); - } - }; -}; - -dc_graph.tip.select_edge = function() { - return { - select: function(diagram, node, edge, ehover) { - return edge; - } - }; -}; - -dc_graph.tip.select_port = function() { - return { - select: function(diagram, node, edge, ehover) { - return node.selectAll('g.port'); - } - }; -}; - -dc_graph.dropdown = function() { - dc_graph.dropdown.unique_id = (dc_graph.dropdown.unique_id || 16) + 1; - var _dropdown = { - id: 'id' + dc_graph.dropdown.unique_id, - parent: property(null), - show: function(key, x, y) { - var dropdown = _dropdown.parent().root() - .selectAll('div.dropdown.' + _dropdown.id).data([0]); - var dropdownEnter = dropdown - .enter().append('div') - .attr('class', 'dropdown ' + _dropdown.id); - dropdown - .style('visibility', 'visible') - .style('left', x + 'px') - .style('top', y + 'px'); - var capture; - var hides = _dropdown.hideOn().split('|'); - var selects = _dropdown.selectOn().split('|'); - if(hides.includes('leave')) - dropdown.on('mouseleave', function() { - dropdown.style('visibility', 'hidden'); - }); - else if(hides.includes('clickout')) { - var diagram = _dropdown.parent(); - capture = diagram.svg().append('rect') - .attr('x', 0) - .attr('y', 0) - .attr('width', diagram.width()) - .attr('height', diagram.height()) - .attr('opacity', 0) - .on('click', function() { - capture.remove(); - dropdown.style('visibility', 'hidden'); - }); - } - var container = dropdown; - if(_dropdown.scrollHeight()) { - var height = _dropdown.scrollHeight(); - if(typeof height === 'number') - height = height + 'px'; - dropdown - .style('max-height', height) - .property('scrollTop', 0); - dropdownEnter - .style('overflow-y', 'auto') - .append('div') - .attr('class', 'scroller'); - container = dropdown.selectAll('div.scroller'); - } - var values = _dropdown.fetchValues()(key, function(values) { - var items = container - .selectAll('div.dropdown-item').data(values); - items - .enter().append('div') - .attr('class', 'dropdown-item'); - items.exit().remove(); - var select_event = null; - if(selects.includes('click')) - select_event = 'click'; - else if(selects.includes('hover')) - select_event = 'mouseenter'; - items - .text(function(item) { return _dropdown.itemText()(item); }); - if(select_event) { - items - .on(select_event + '.select', function(d) { - _dropdown.itemSelected()(d); - }); - } - if(hides.includes('clickitem')) { - items - .on('click.hide', function(d) { - capture.remove(); - dropdown.style('visibility', 'hidden'); - }); - } - }); - }, - hideOn: property('clickout|clickitem'), - selectOn: property('click'), - height: property(10), - itemText: property(function(x) { return x; }), - itemSelected: property(function() {}), - fetchValues: property(function(key, k) { k([]); }), - scrollHeight: property('12em') - }; - return _dropdown; -}; - -dc_graph.keyboard = function() { - var _dispatch = d3.dispatch('keydown', 'keyup', 'modkeyschanged'); - var _unique_id = 'keyboard' + Math.floor(Math.random() * 100000); - var _mod_keys = d3.set(['Shift', 'Control', 'Alt', 'Meta']), - _pressed = d3.set(); - - function pressed() { - return _pressed.values().sort(); - } - function keydown() { - if(_mod_keys.has(d3.event.key)) { - _pressed.add(d3.event.key); - _dispatch.modkeyschanged(pressed()); - } - _dispatch.keydown(); - } - function keyup() { - if(_mod_keys.has(d3.event.key)) { - _pressed.remove(d3.event.key); - _dispatch.modkeyschanged(pressed()); - } - _dispatch.keyup(); - } - function clear() { - if(!_pressed.empty()) { - _pressed = d3.set(); - _dispatch.modkeyschanged(pressed()); - } - } - function draw(diagram) { - d3.select(window) - .on('keydown.' + _unique_id, keydown) - .on('keyup.' + _unique_id, keyup) - .on('blur.' + _unique_id, clear); - } - function remove(diagram) { - d3.select(window) - .on('keydown.' + _unique_id, null) - .on('keyup.' + _unique_id, null) - .on('blur.' + _unique_id, null); - } - var _mode = dc_graph.mode('brush', { - draw: draw, - remove: remove - }); - - _mode.on = function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }; - - _mode.modKeysPressed = function() { - return pressed(); - }; - _mode.modKeysMatch = function(keys) { - if(!keys || keys === []) - return _pressed.empty(); - if(!Array.isArray(keys)) - keys = [keys]; - var p = pressed(); - if(p.length !== keys.length) - return false; - return keys.slice().sort().every(function(k, i) { return k === p[i]; }); - }; - - return _mode; -}; - -// adapted from -// http://stackoverflow.com/questions/9308938/inline-text-editing-in-svg/#26644652 - -dc_graph.edit_text = function(parent, options) { - var foreign = parent.append('foreignObject').attr({ - height: '100%', - width: '100%' // don't wrap - }); - var padding = options.padding !== undefined ? options.padding : 2; - function reposition() { - var pos; - switch(options.align) { - case 'left': - pos = [options.box.x-padding, options.box.y-padding]; - break; - default: - case 'center': - pos = [ - options.box.x + (options.box.width - textdiv.node().offsetWidth)/2, - options.box.y + (options.box.height - textdiv.node().offsetHeight)/2 - ]; - break; - } - foreign.attr('transform', 'translate(' + pos.join(' ') + ')'); - } - var textdiv = foreign.append('xhtml:div'); - var text = options.text || "type on me"; - textdiv.text(text).attr({ - contenteditable: true, - width: 'auto', - class: options.class || null - }).style({ - display: 'inline-block', - 'background-color': 'white', - padding: padding + 'px' - }); - - function stopProp() { - d3.event.stopPropagation(); - } - foreign - .on('mousedown.edit-text', stopProp) - .on('mousemove.edit-text', stopProp) - .on('mouseup.edit-text', stopProp) - .on('dblclick.edit-text', stopProp); - - function accept() { - options.accept && options.accept(textdiv.text()); - textdiv.on('blur.edit-text', null); - foreign.remove(); - options.finally && options.finally(); - } - function cancel() { - options.cancel && options.cancel(); - textdiv.on('blur.edit-text', null); - foreign.remove(); - options.finally && options.finally(); - } - - textdiv.on('keydown.edit-text', function() { - // prevent keyboard mode from seeing this (especially delete key!) - d3.event.stopPropagation(); - if(d3.event.keyCode===13) { - d3.event.preventDefault(); - } - }).on('keyup.edit-text', function() { - d3.event.stopPropagation(); - if(d3.event.keyCode===13) { - accept(); - } else if(d3.event.keyCode===27) { - cancel(); - } - reposition(); - }).on('blur.edit-text', cancel); - reposition(); - textdiv.node().focus(); - - var range = document.createRange(); - if(options.selectText) { - range.selectNodeContents(textdiv.node()); - } else { - range.setStart(textdiv.node(), 1); - range.setEnd(textdiv.node(), 1); - } - var sel = window.getSelection(); - sel.removeAllRanges(); - sel.addRange(range); -}; - -/** - * `dc_graph.brush` is a {@link dc_graph.mode mode} providing a simple wrapper over - * [d3.svg.brush](https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Controls.md#brush) - * @class brush - * @memberof dc_graph - * @return {dc_graph.brush} - **/ -dc_graph.brush = function() { - var _brush = null, _gBrush, _dispatch = d3.dispatch('brushstart', 'brushmove', 'brushend'); - - function brushstart() { - _dispatch.brushstart(); - } - function brushmove() { - var ext = _brush.extent(); - _dispatch.brushmove(ext); - } - function brushend() { - _dispatch.brushend(); - _gBrush.call(_brush.clear()); - } - function install_brush(diagram) { - if(!_brush) { - _brush = d3.svg.brush() - .x(diagram.x()).y(diagram.y()) - .on('brushstart.brush-mode', brushstart) - .on('brush.brush-mode', brushmove) - .on('brushend.brush-mode', brushend); - } - if(!_gBrush) { - _gBrush = diagram.svg().insert('g', ':first-child') - .attr('class', 'brush') - .call(_brush); - } - } - function remove_brush() { - if(_gBrush) { - _gBrush.remove(); - _gBrush = null; - } - } - var _mode = dc_graph.mode('brush', { - draw: function() {}, - remove: remove_brush - }); - - /** - * Subscribe to a brush event, currently `brushstart`, `brushmove`, or `brushend` - * @method on - * @memberof dc_graph.brush - * @instance - * @param {String} event the name of the event; please namespace with `'namespace.event'` - * @param {Function} [f] the handler function; if omitted, returns the current handler - * @return {dc_graph.brush} - * @return {Function} - **/ - _mode.on = function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }; - /** - * Add the brush to the parent diagram's SVG - * @method activate - * @memberof dc_graph.brush - * @instance - * @return {dc_graph.brush} - **/ - _mode.activate = function() { - install_brush(_mode.parent()); - return this; - }; - /** - * Remove the brush from the parent diagram's SVG - * @method deactivate - * @memberof dc_graph.brush - * @instance - * @return {dc_graph.brush} - **/ - _mode.deactivate = function() { - remove_brush(); - return this; - }; - /** - * Retrieve whether the brush is currently active - * @method isActive - * @memberof dc_graph.brush - * @instance - * @return {Boolean} - **/ - _mode.isActive = function () { - return !!_gBrush; - }; - - return _mode; -}; - -dc_graph.select_things = function(things_group, things_name, thinginess) { - var _selected = [], _oldSelected; - var _mousedownThing = null; - var _keyboard; - - var contains_predicate = thinginess.keysEqual ? - function(k1) { - return function(k2) { - return thinginess.keysEqual(k1, k2); - }; - } : - function(k1) { - return function(k2) { - return k1 === k2; - }; - }; - function contains(array, key) { - return !!_selected.find(contains_predicate(key)); - } - function isUnion(event) { - return event.shiftKey; - } - function isToggle(event) { - return is_a_mac ? event.metaKey : event.ctrlKey; - } - function add_array(array, key) { - return contains(array, key) ? array : array.concat([key]); - } - function toggle_array(array, key) { - return contains(array, key) ? array.filter(function(x) { return x != key; }) : array.concat([key]); - } - - function selection_changed(diagram) { - return function(selection, refresh) { - if(refresh === undefined) - refresh = true; - _selected = selection; - if(refresh) - diagram.requestRefresh(); - }; - } - var _have_bce = false; - function background_click_event(diagram, v) { - // we seem to have nodes-background interrupting edges-background by reinstalling uselessly - if(_have_bce === v) - return; - diagram.svg().on('click.' + things_name, v ? function(t) { - if(d3.event.target === this) - things_group.set_changed([]); - } : null); - _have_bce = v; - } - function modkeyschanged() { - if(_mode.multipleSelect()) { - var brush_mode = _mode.parent().child('brush'); - if(_keyboard.modKeysMatch(_mode.modKeys())) - brush_mode.activate(); - else - brush_mode.deactivate(); - } - } - function brushstart() { - if(isUnion(d3.event.sourceEvent) || isToggle(d3.event.sourceEvent)) - _oldSelected = _selected.slice(); - else { - _oldSelected = []; - things_group.set_changed([]); - } - } - function brushmove(ext) { - if(!thinginess.intersectRect) - return; - var rectSelect = thinginess.intersectRect(ext); - var newSelected; - if(isUnion(d3.event.sourceEvent)) - newSelected = rectSelect.reduce(add_array, _oldSelected); - else if(isToggle(d3.event.sourceEvent)) - newSelected = rectSelect.reduce(toggle_array, _oldSelected); - else - newSelected = rectSelect; - things_group.set_changed(newSelected); - } - - function draw(diagram, node, edge) { - var condition = _mode.noneIsAll() ? function(t) { - return !_selected.length || contains(_selected, thinginess.key(t)); - } : function(t) { - return contains(_selected, thinginess.key(t)); - }; - thinginess.applyStyles(condition); - - thinginess.clickables(diagram, node, edge).on('mousedown.' + things_name, function(t) { - _mousedownThing = t; - }); - - thinginess.clickables(diagram, node, edge).on('mouseup.' + things_name, function(t) { - if(thinginess.excludeClick && thinginess.excludeClick(d3.event.target)) - return; - // it's only a click if the same target was mousedown & mouseup - // but we can't use click event because things may have been reordered - if(_mousedownThing !== t) - return; - var key = thinginess.key(t), newSelected; - if(_mode.multipleSelect()) { - if(isUnion(d3.event)) - newSelected = add_array(_selected, key); - else if(isToggle(d3.event)) - newSelected = toggle_array(_selected, key); - } - if(!newSelected) - newSelected = [key]; - things_group.set_changed(newSelected); - }); - - if(_mode.multipleSelect()) { - if(_keyboard.modKeysMatch(_mode.modKeys())) - diagram.child('brush').activate(); - } - else - background_click_event(diagram, _mode.clickBackgroundClears()); - - if(_mode.autoCropSelection()) { - // drop any selected which no longer exist in the diagram - var present = thinginess.clickables(diagram, node, edge).data().map(thinginess.key); - var now_selected = _selected.filter(function(k) { return contains(present, k); }); - if(_selected.length !== now_selected.length) - things_group.set_changed(now_selected, false); - } - } - - function remove(diagram, node, edge) { - thinginess.clickables(diagram, node, edge).on('click.' + things_name, null); - diagram.svg().on('click.' + things_name, null); - thinginess.removeStyles(); - } - - var _mode = dc_graph.mode(things_name, { - draw: draw, - remove: remove, - parent: function(p) { - things_group.on('set_changed.' + things_name, p ? selection_changed(p) : null); - if(p && _mode.multipleSelect()) { - var brush_mode = p.child('brush'); - if(!brush_mode) { - brush_mode = dc_graph.brush(); - p.child('brush', brush_mode); - } - brush_mode - .on('brushstart.' + things_name, brushstart) - .on('brushmove.' + things_name, brushmove); - } - _keyboard = p.child('keyboard'); - if(!_keyboard) - p.child('keyboard', _keyboard = dc_graph.keyboard()); - _keyboard.on('modkeyschanged.' + things_name, modkeyschanged); - }, - laterDraw: thinginess.laterDraw || false - }); - - _mode.multipleSelect = property(true); - _mode.modKeys = property(null); - _mode.clickBackgroundClears = property(true, false).react(function(v) { - if(!_mode.multipleSelect() && _mode.parent()) - background_click_event(_mode.parent(), v); - }); - _mode.noneIsAll = property(false); - // if you're replacing the data, you probably want the selection not to be preserved when a thing - // with the same key re-appears later (true). however, if you're filtering dc.js-style, you - // probably want filters to be independent between diagrams (false) - _mode.autoCropSelection = property(true); - // if you want to do the cool things select_things can do - _mode.thinginess = function() { - return thinginess; - }; - return _mode; -}; - -dc_graph.select_things_group = function(brushgroup, type) { - window.chart_registry.create_type(type, function() { - return d3.dispatch('set_changed'); - }); - - return window.chart_registry.create_group(type, brushgroup); -}; - -dc_graph.select_nodes = function(props, options) { - options = options || {}; - var select_nodes_group = dc_graph.select_things_group(options.select_nodes_group || 'select-nodes-group', 'select-nodes'); - - var thinginess = { - intersectRect: function(ext) { - return _mode.parent().selectAllNodes().data().filter(function(n) { - return n && ext[0][0] < n.cola.x && n.cola.x < ext[1][0] && - ext[0][1] < n.cola.y && n.cola.y < ext[1][1]; - }).map(this.key); - }, - clickables: function(diagram, node, edge) { - return node; - }, - excludeClick: function(element) { - return ancestor_has_class(element, 'port'); - }, - key: function(n) { - return _mode.parent().nodeKey.eval(n); - }, - applyStyles: function(pred) { - _mode.parent().cascade(50, true, node_edge_conditions(pred, null, props)); - }, - removeStyles: function() { - _mode.parent().cascade(50, false, props); - } - }; - var _mode = dc_graph.select_things(select_nodes_group, 'select-nodes', thinginess); - return _mode; -}; - -dc_graph.select_edges = function(props, options) { - options = options || {}; - var select_edges_group = dc_graph.select_things_group(options.select_edges_group || 'select-edges-group', 'select-edges'); - var thinginess = { - intersectRect: function(ext) { - return this.clickables().data().filter(function(e) { - // this nonsense because another select_things may have invalidated the edge positions (!!) - var sp = { - x: e.source.cola.x + e.sourcePort.pos.x, - y: e.source.cola.y + e.sourcePort.pos.y - }, - tp = { - x: e.target.cola.x + e.targetPort.pos.x, - y: e.target.cola.y + e.targetPort.pos.y - }; - return [sp, tp].some(function(p) { - return ext[0][0] < p.x && p.x < ext[1][0] && - ext[0][1] < p.y && p.y < ext[1][1]; - }); - }).map(this.key); - }, - clickables: function() { - return _mode.parent().selectAllEdges('.edge-hover'); - }, - key: function(e) { - return _mode.parent().edgeKey.eval(e); - }, - applyStyles: function(pred) { - _mode.parent().cascade(50, true, node_edge_conditions(null, pred, props)); - }, - removeStyles: function() { - _mode.parent().cascade(50, false, props); - } - }; - var _mode = dc_graph.select_things(select_edges_group, 'select-edges', thinginess); - return _mode; -}; - -dc_graph.select_ports = function(props, options) { - options = options || {}; - var port_style = options.portStyle || 'symbols'; - var select_ports_group = dc_graph.select_things_group(options.select_ports_group || 'select-ports-group', 'select-ports'); - var thinginess = { - laterDraw: true, - intersectRect: null, // multiple selection not supported for now - clickables: function() { - return _mode.parent().selectAllNodes('g.port'); - }, - key: function(p) { - // this scheme also won't work with multiselect - return p.named ? - {node: _mode.parent().nodeKey.eval(p.node), name: p.name} : - {edge: _mode.parent().edgeKey.eval(p.edges[0]), name: p.name}; - }, - applyStyles: function(pred) { - _mode.parent().portStyle(port_style).cascade(50, true, conditional_properties(pred, props)); - }, - removeStyles: function() { - _mode.parent().portStyle(port_style).cascade(50, false, props); - }, - keysEqual: function(k1, k2) { - return k1.name === k2.name && (k1.node ? k1.node === k2.node : k1.edge === k2.edge); - } - }; - var _mode = dc_graph.select_things(select_ports_group, 'select-ports', thinginess); - return _mode; -}; - -dc_graph.move_nodes = function(options) { - options = options || {}; - var select_nodes_group = dc_graph.select_things_group(options.select_nodes_group || 'select-nodes-group', 'select-nodes'); - var fix_nodes_group = dc_graph.fix_nodes_group(options.fix_nodes_group || 'fix-nodes-group'); - var _selected = [], _startPos = null, _downNode, _moveStarted; - var _brush, _drawGraphs, _selectNodes, _restoreBackgroundClick, _keyboard; - var _maybeSelect = null; - - function isUnion(event) { - return event.shiftKey; - } - function isToggle(event) { - return is_a_mac ? event.metaKey : event.ctrlKey; - } - - function selection_changed(diagram) { - return function(selection, refresh) { - if(refresh === undefined) - refresh = true; - _selected = selection; - }; - } - function for_each_selected(f, selected) { - selected = selected || _selected; - selected.forEach(function(key) { - var n = _mode.parent().getWholeNode(key); - f(n, key); - }); - } - function draw(diagram, node, edge) { - node.on('mousedown.move-nodes', function(n) { - // Need a more general way for modes to say "I got this" - if(_drawGraphs && _drawGraphs.usePorts() && _drawGraphs.usePorts().eventPort()) - return; - if(!_keyboard.modKeysMatch(_mode.modKeys())) - return; - _startPos = dc_graph.event_coords(diagram); - _downNode = d3.select(this); - // if the node under the mouse is not in the selection, need to - // make that node selected - var key = diagram.nodeKey.eval(n); - var selected = _selected; - if(_selected.indexOf(key)<0) { - selected = [key]; - _maybeSelect = key; - } - else _maybeSelect = null; - for_each_selected(function(n) { - n.original_position = [n.cola.x, n.cola.y]; - }, selected); - if(_brush) - _brush.deactivate(); - }); - function mouse_move() { - if(_startPos) { - if(!(d3.event.buttons & 1)) { - mouse_up(); - return; - } - if(_maybeSelect) - select_nodes_group.set_changed([_maybeSelect]); - var pos = dc_graph.event_coords(diagram); - var dx = pos[0] - _startPos[0], - dy = pos[1] - _startPos[1]; - if(!_moveStarted && Math.hypot(dx, dy) > _mode.dragSize()) { - _moveStarted = true; - // prevent click event for this node setting selection just to this - if(_downNode) - _downNode.style('pointer-events', 'none'); - } - if(_moveStarted) { - for_each_selected(function(n) { - n.cola.x = n.original_position[0] + dx; - n.cola.y = n.original_position[1] + dy; - }); - var node2 = node.filter(function(n) { return _selected.includes(n.orig.key); }), - edge2 = edge.filter(function(e) { - return _selected.includes(e.source.orig.key) || - _selected.includes(e.target.orig.key); - }); - diagram.reposition(node2, edge2); - } - } - } - function mouse_up() { - if(_startPos) { - if(_moveStarted) { - _moveStarted = false; - if(_downNode) { - _downNode.style('pointer-events', null); - _downNode = null; - } - var fixes = []; - for_each_selected(function(n, id) { - fixes.push({ - id: id, - pos: {x: n.cola.x, y: n.cola.y} - }); - }); - fix_nodes_group.request_fixes(fixes); - } - if(_brush) - _brush.activate(); - _startPos = null; - } - } - node - .on('mousemove.move-nodes', mouse_move) - .on('mouseup.move-nodes', mouse_up); - diagram.svg() - .on('mousemove.move-nodes', mouse_move) - .on('mouseup.move-nodes', mouse_up); - } - - function remove(diagram, node, edge) { - node.on('mousedown.move-nodes', null); - node.on('mousemove.move-nodes', null); - node.on('mouseup.move-nodes', null); - } - - var _mode = dc_graph.mode('move-nodes', { - draw: draw, - remove: remove, - parent: function(p) { - select_nodes_group.on('set_changed.move-nodes', p ? selection_changed(p) : null); - if(p) { - _brush = p.child('brush'); - _drawGraphs = p.child('draw-graphs'); - _selectNodes = p.child('select-nodes'); - _keyboard = p.child('keyboard'); - if(!_keyboard) - p.child('keyboard', _keyboard = dc_graph.keyboard()); - } - else _brush = _drawGraphs = _selectNodes = null; - } - }); - - // minimum distance that is considered a drag, not a click - _mode.dragSize = property(5); - _mode.modKeys = property(null); - - return _mode; -}; - -dc_graph.fix_nodes = function(options) { - options = options || {}; - var fix_nodes_group = dc_graph.fix_nodes_group(options.fix_nodes_group || 'fix-nodes-group'); - var _fixedPosTag = options.fixedPosTag || 'fixedPos'; - var _fixes = [], _nodes, _wnodes, _edges, _wedges; - - var _execute = { - nodeid: function(n) { - return _mode.parent().nodeKey.eval(n); - }, - sourceid: function(e) { - return _mode.parent().edgeSource.eval(e); - }, - targetid: function(e) { - return _mode.parent().edgeTarget.eval(e); - }, - get_fix: function(n) { - return _mode.parent().nodeFixed.eval(n); - }, - fix_node: function(n, pos) { - n[_fixedPosTag] = pos; - }, - unfix_node: function(n) { - n[_fixedPosTag] = null; - }, - clear_fixes: function() { - _fixes = {}; - }, - register_fix: function(id, pos) { - _fixes[id] = pos; - } - }; - - function request_fixes(fixes) { - _mode.strategy().request_fixes(_execute, fixes); - tell_then_set(find_changes()).then(function() { - _mode.parent().redraw(); - }); - } - function new_node(nid, n, pos) { - _mode.strategy().new_node(_execute, nid, n, pos); - } - function new_edge(eid, sourceid, targetid) { - var source = _nodes[sourceid], target = _nodes[targetid]; - _mode.strategy().new_edge(_execute, eid, source, target); - } - function find_changes() { - var changes = []; - _wnodes.forEach(function(n) { - var key = _mode.parent().nodeKey.eval(n), - fixPos = _fixes[key], - oldFixed = n.orig.value[_fixedPosTag], - changed = false; - if(oldFixed) { - if(!fixPos || fixPos.x !== oldFixed.x || fixPos.y !== oldFixed.y) - changed = true; - } - else changed = fixPos; - if(changed) - changes.push({n: n, fixed: fixPos ? {x: fixPos.x, y: fixPos.y} : null}); - }); - return changes; - } - function execute_change(n, fixed) { - if(fixed) - _execute.fix_node(n.orig.value, fixed); - else - _execute.unfix_node(n.orig.value); - } - function tell_then_set(changes) { - var callback = _mode.fixNode() || function(n, pos) { return Promise.resolve(pos); }; - var promises = changes.map(function(change) { - var key = _mode.parent().nodeKey.eval(change.n); - return callback(key, change.fixed) - .then(function(fixed) { - execute_change(change.n, fixed); - }); - }); - return Promise.all(promises); - } - function set_changes(changes) { - changes.forEach(function(change) { - execute_change(change.n, change.fixed); - }); - } - function tell_changes(changes) { - var callback = _mode.fixNode() || function(n, pos) { return Promise.resolve(pos); }; - var promises = changes.map(function(change) { - var key = _mode.parent().nodeKey.eval(change.n); - return callback(key, change.fixed); - }); - return Promise.all(promises); - } - function fix_all_nodes(tell) { - if(tell === undefined) - tell = true; - var changes = _wnodes.map(function(n) { - return {n: n, fixed: {x: n.cola.x, y: n.cola.y}}; - }); - if(tell) - return tell_then_set(changes); - else { - set_changes(changes); - return Promise.resolve(undefined); - } - } - function clear_fixes() { - _mode.strategy().clear_all_fixes && _mode.strategy().clear_all_fixes(); - _execute.clear_fixes(); - } - function on_data(diagram, nodes, wnodes, edges, wedges, ports, wports) { - _nodes = nodes; - _wnodes = wnodes; - _edges = edges; - _wedges = wedges; - if(_mode.strategy().on_data) { - _mode.strategy().on_data(_execute, nodes, wnodes, edges, wedges, ports, wports); // ghastly - var changes = find_changes(); - set_changes(changes); - // can't wait for backend to acknowledge/approve so just set then blast - if(_mode.reportOverridesAsynchronously()) - tell_changes(changes); // dangling promise - } - } - - var _mode = { - parent: property(null).react(function(p) { - fix_nodes_group - .on('request_fixes.fix-nodes', p ? request_fixes : null) - .on('new_node.fix_nodes', p ? new_node : null) - .on('new_edge.fix_nodes', p ? new_edge : null); - if(p) { - p.on('data.fix-nodes', on_data); - } else if(_mode.parent()) - _mode.parent().on('data.fix-nodes', null); - }), - // callback for setting & fixing node position - fixNode: property(null), - // save/load may want to nail everything / start from scratch - // (should probably be automatic though) - fixAllNodes: fix_all_nodes, - clearFixes: clear_fixes, - strategy: property(dc_graph.fix_nodes.strategy.fix_last()), - reportOverridesAsynchronously: property(true) - }; - - return _mode; -}; - -dc_graph.fix_nodes.strategy = {}; -dc_graph.fix_nodes.strategy.fix_last = function() { - return { - request_fixes: function(exec, fixes) { - exec.clear_fixes(); - fixes.forEach(function(fix) { - exec.register_fix(fix.id, fix.pos); - }); - }, - new_node: function(exec, nid, n, pos) { - exec.fix_node(n, pos); - }, - new_edge: function(exec, eid, source, target) { - exec.unfix_node(source.orig.value); - exec.unfix_node(target.orig.value); - } - }; -}; -dc_graph.fix_nodes.strategy.last_N_per_component = function(maxf) { - maxf = maxf || 1; - var _age = 0; - var _allFixes = {}; - return { - clear_all_fixes: function() { - _allFixes = {}; - }, - request_fixes: function(exec, fixes) { - ++_age; - fixes.forEach(function(fix) { - _allFixes[fix.id] = {id: fix.id, age: _age, pos: fix.pos}; - }); - }, - new_node: function(exec, nid, n, pos) { - ++_age; - _allFixes[nid] = {id: nid, age: _age, pos: pos}; - exec.fix_node(n, pos); - }, - new_edge: function() {}, - on_data: function(exec, nodes, wnodes, edges, wedges, ports, wports) { - ++_age; - // add any existing fixes as requests - wnodes.forEach(function(n) { - var nid = exec.nodeid(n), pos = exec.get_fix(n); - if(pos && !_allFixes[nid]) - _allFixes[nid] = {id: nid, age: _age, pos: pos}; - }); - // determine components - var components = []; - var dfs = dc_graph.undirected_dfs({ - nodeid: exec.nodeid, - sourceid: exec.sourceid, - targetid: exec.targetid, - comp: function() { - components.push([]); - }, - node: function(compid, n) { - components[compid].push(n); - } - }); - dfs(wnodes, wedges); - // start from scratch - exec.clear_fixes(); - // keep or produce enough fixed nodes per component - components.forEach(function(comp, i) { - var oldcomps = comp.reduce(function(cc, n) { - if(n.last_component) { - var counts = cc[n.last_component] = cc[n.last_component] || { - total: 0, - fixed: 0 - }; - counts.total++; - if(_allFixes[exec.nodeid(n)]) - counts.fixed++; - } - return cc; - }, {}); - var fixed_by_size = Object.keys(oldcomps).reduce(function(ff, compid) { - if(oldcomps[compid].fixed) - ff.push({compid: +compid, total: oldcomps[compid].total, fixed: oldcomps[compid].fixed}); - return ff; - }, []).sort(function(coa, cob) { - return cob.total - coa.total; - }); - var largest_fixed = fixed_by_size.length && fixed_by_size[0].compid; - var fixes = comp.filter(function(n) { - return !n.last_component || n.last_component === largest_fixed; - }).map(function(n) { - return _allFixes[exec.nodeid(n)]; - }).filter(function(fix) { - return fix; - }); - if(fixes.length > maxf) { - fixes.sort(function(f1, f2) { - return f2.age - f1.age; - }); - fixes = fixes.slice(0, maxf); - } - fixes.forEach(function(fix) { - exec.register_fix(fix.id, fix.pos); - }); - var kept = fixes.reduce(function(m, fix) { - m[fix.id] = true; - return m; - }, {}); - comp.forEach(function(n) { - var nid = exec.nodeid(n); - if(!kept[nid]) - _allFixes[nid] = null; - n.last_component = i+1; - }); - }); - } - }; -}; - -dc_graph.fix_nodes_group = function(brushgroup) { - window.chart_registry.create_type('fix-nodes', function() { - return d3.dispatch('request_fixes', 'new_node', 'new_edge'); - }); - - return window.chart_registry.create_group('fix-nodes', brushgroup); -}; - -dc_graph.filter_selection = function(things_group, things_name) { - things_name = things_name || 'select-nodes'; - var select_nodes_group = dc_graph.select_things_group(things_group || 'select-nodes-group', things_name); - - function selection_changed(diagram) { - return function(selection) { - if(selection.length) { - var set = d3.set(selection); - _mode.dimensionAccessor()(diagram).filterFunction(function(k) { - return set.has(k); - }); - } else _mode.dimensionAccessor()(diagram).filter(null); - diagram.redrawGroup(); - }; - } - - var _mode = { - parent: property(null).react(function(p) { - select_nodes_group.on('set_changed.filter-selection-' + things_name, p ? selection_changed(p) : null); - }) - }; - _mode.dimensionAccessor = property(function(diagram) { - return diagram.nodeDimension(); - }); - return _mode; -}; - -dc_graph.delete_things = function(things_group, mode_name, id_tag) { - id_tag = id_tag || 'id'; - var _deleteKey = is_a_mac ? 'Backspace' : 'Delete'; - var _keyboard, _selected = []; - function selection_changed(selection) { - _selected = selection; - } - function row_id(r) { - return r[id_tag]; - } - function delete_selection(selection) { - if(!_mode.crossfilterAccessor()) - throw new Error('need crossfilterAccessor'); - if(!_mode.dimensionAccessor()) - throw new Error('need dimensionAccessor'); - selection = selection || _selected; - if(selection.length === 0) - return Promise.resolve([]); - var promise = _mode.preDelete() ? _mode.preDelete()(selection) : Promise.resolve(selection); - if(_mode.onDelete()) - promise = promise.then(_mode.onDelete()); - return promise.then(function(selection) { - if(selection && selection.length) { - var crossfilter = _mode.crossfilterAccessor()(_mode.parent()), - dimension = _mode.dimensionAccessor()(_mode.parent()); - var all = crossfilter.all().slice(), n = all.length; - dimension.filter(null); - crossfilter.remove(); - var filtered = all.filter(function(r) { - return selection.indexOf(row_id(r)) === -1; - }); - if(all.length !== filtered.length + selection.length) - console.warn('size after deletion is not previous size minus selection size', - filtered.map(row_id), all.map(row_id), selection); - crossfilter.add(filtered); - - _mode.parent().redrawGroup(); - } - return true; - }); - } - function draw(diagram) { - _keyboard.on('keyup.' + mode_name, function() { - if(d3.event.code === _deleteKey) - delete_selection(); - }); - } - function remove(diagram) { - } - var _mode = dc_graph.mode(mode_name, { - draw: draw, - remove: remove, - parent: function(p) { - things_group.on('set_changed.' + mode_name, selection_changed); - if(p) { - _keyboard = p.child('keyboard'); - if(!_keyboard) - p.child('keyboard', _keyboard = dc_graph.keyboard()); - } - } - }); - _mode.preDelete = property(null); - _mode.onDelete = property(null); - _mode.crossfilterAccessor = property(null); - _mode.dimensionAccessor = property(null); - _mode.deleteSelection = delete_selection; - return _mode; -}; - -dc_graph.delete_nodes = function(id_tag, options) { - options = options || {}; - var select_nodes_group = dc_graph.select_things_group(options.select_nodes_group || 'select-nodes-group', 'select-nodes'); - var select_edges_group = dc_graph.select_things_group(options.select_edges_group || 'select-edges-group', 'select-edges'); - var _mode = dc_graph.delete_things(select_nodes_group, 'delete-nodes', id_tag); - - _mode.preDelete(function(nodes) { - // request a delete of all attached edges, using the delete edges mode - // kind of horrible - var diagram = _mode.parent(); - var deleteEdgesMode = diagram.child('delete-edges'); - if(!deleteEdgesMode) - return null; // reject if we can't delete the edges - // it is likely that the delete_edges mode is listening to the same keyup event we - // are. introduce a pause to let it process the delete key now, deleting any selected edges. - // then select any remaining edges connected to the selected nodes and delete those. - // - // more evidence that modes need to be able to say "i got this", or that we should have - // batch deletion. otoh, given the current behavior, delete_nodes deferring to delete_edges - // makes about as much sense as anything - return Promise.resolve(undefined).then(function() { - var deleteEdges = diagram.edgeGroup().all().filter(function(e) { - return nodes.indexOf(diagram.edgeSource()(e)) !== -1 || - nodes.indexOf(diagram.edgeTarget()(e)) !== -1; - }).map(diagram.edgeKey()); - select_edges_group.set_changed(deleteEdges); - return deleteEdgesMode.deleteSelection().then(function() { - return nodes; - }); - }); - }); - return _mode; -}; - -dc_graph.label_things = function(options) { - options = options || {}; - var select_things_group = dc_graph.select_things_group(options.select_group, options.select_type), - label_things_group = dc_graph.label_things_group(options.label_group, options.label_type); - var _selected = []; - var _keyboard, _selectThings; - - function selection_changed_listener(diagram) { - return function(selection) { - _selected = selection; - }; - } - - function edit_label_listener(diagram) { - return function(thing, eventOptions) { - var box = options.thing_box(thing); - options.hide_thing_label(thing, true); - dc_graph.edit_text( - diagram.g(), - { - text: eventOptions.text || options.thing_label(thing) || options.default_label, - align: options.align, - class: options.class, - box: box, - selectText: eventOptions.selectText, - accept: function(text) { - return options.accept(thing, text); - }, - finally: function() { - options.hide_thing_label(thing, false); - } - }); - }; - } - - function edit_selection(node, edge, eventOptions) { - // less than ideal interface. - // what if there are other things? can i blame the missing metagraph? - var thing = options.find_thing(_selected[0], node, edge); - if(thing.empty()) { - console.error("couldn't find thing '" + _selected[0] + "'!"); - return; - } - if(thing.size()>1) { - console.error("found too many things for '" + _selected[0] + "' (" + thing.size() + ")!"); - return; - } - label_things_group.edit_label(thing, eventOptions); - } - function draw(diagram, node, edge) { - _keyboard.on('keyup.' + options.label_type, function() { - if(_selected.length) { - // printable characters should start edit - if(d3.event.key.length !== 1) - return; - edit_selection(node, edge, {text: d3.event.key, selectText: false}); - } - }); - if(_selectThings) - _selectThings.thinginess().clickables(diagram, node, edge).on('dblclick.' + options.label_type, function() { - edit_selection(node, edge, {selectText: true}); - }); - } - - function remove(diagram, node, edge) { - } - - var _mode = dc_graph.mode(options.label_type, { - draw: draw, - remove: remove, - parent: function(p) { - select_things_group.on('set_changed.' + options.label_type, p ? selection_changed_listener(p) : null); - label_things_group.on('edit_label.' + options.label_type, p ? edit_label_listener(p) : null); - if(p) { - _keyboard = p.child('keyboard'); - if(!_keyboard) - p.child('keyboard', _keyboard = dc_graph.keyboard()); - _selectThings = p.child(options.select_type); - } - } - }); - _mode.editSelection = function(eventOptions) { - edit_selection(_mode.parent().selectAllNodes(), _mode.parent().selectAllEdges(), eventOptions); - }; - return _mode; -}; - -dc_graph.label_things_group = function(brushgroup, type) { - window.chart_registry.create_type(type, function() { - return d3.dispatch('edit_label'); - }); - - return window.chart_registry.create_group(type, brushgroup); -}; - -dc_graph.label_nodes = function(options) { - options = options || {}; - var _labelTag = options.labelTag || 'label'; - options.select_group = options.select_group || 'select-nodes-group'; - options.select_type = options.select_type || 'select-nodes'; - options.label_group = options.label_group || 'label-nodes-group'; - options.label_type = options.label_type || 'label-nodes'; - options.default_label = "node name"; - - options.find_thing = function(key, node, edge) { - return node.filter(function(n) { - return _mode.parent().nodeKey.eval(n) === key; - }); - }; - options.hide_thing_label = function(node, whether) { - var contents = _mode.parent().content(_mode.parent().nodeContent.eval(node.datum())); - contents.selectText(node).attr('visibility', whether ? 'hidden' : 'visible'); - }; - options.thing_box = function(node, eventOptions) { - var contents = _mode.parent().content(_mode.parent().nodeContent.eval(node.datum())), - box = contents.textbox(node); - box.x += node.datum().cola.x; - box.y += node.datum().cola.y; - return box; - }; - options.thing_label = function(node) { - return _mode.parent().nodeLabel.eval(node.datum()); - }; - options.accept = function(node, text) { - var callback = _mode.changeNodeLabel() ? - _mode.changeNodeLabel()(_mode.parent().nodeKey.eval(node.datum()), text) : - Promise.resolve(text); - return callback.then(function(text2) { - var n = node.datum(); - n.orig.value[_labelTag] = text2; - _mode.parent().redrawGroup(); - }); - }; - - var _mode = dc_graph.label_things(options); - _mode.changeNodeLabel = property(null); - return _mode; -}; - -dc_graph.label_edges = function(options) { - options = options || {}; - var _labelTag = options.labelTag || 'label'; - options.select_group = options.select_group || 'select-edges-group'; - options.select_type = options.select_type || 'select-edges'; - options.label_group = options.label_group || 'label-edges-group'; - options.label_type = options.label_type || 'label-edges'; - options.default_label = "edge name"; - - options.find_thing = function(key, node, edge) { - return edge.filter(function(e) { - return _mode.parent().edgeKey.eval(e) === key; - }); - }; - options.hide_thing_label = function(edge, whether) { - var label = _mode.parent().selectAll('#' + _mode.parent().edgeId(edge.datum()) + '-label textPath'); - label.attr('visibility', whether ? 'hidden' : 'visible'); - }; - options.thing_box = function(edge, eventOptions) { - var points = edge.datum().pos.new.path.points, - x = (points[0].x + points[1].x)/2, - y = (points[0].y + points[1].y)/2; - return {x: x, y: y-10, width:0, height: 20}; - }; - options.thing_label = function(edge) { - return _mode.parent().edgeLabel.eval(edge.datum()); - }; - options.accept = function(edge, text) { - var callback = _mode.changeEdgeLabel() ? - _mode.changeEdgeLabel()(_mode.parent().edgeKey.eval(edge.datum()), text) : - Promise.resolve(text); - return callback.then(function(text2) { - var e = edge.datum(); - e.orig.value[_labelTag] = text2; - _mode.parent().redrawGroup(); - }); - }; - - var _mode = dc_graph.label_things(options); - _mode.changeEdgeLabel = property(null); - return _mode; -}; - -dc_graph.annotate_nodes = () => { - function draw(diagram) { - const roots = diagram.g().selectAll('g.node-layer g.node'); - const annots = roots.selectAll('text.node-annotation').data(d => d.orig.value.ceq ? [d] : []); - annots.enter().append('text') - .attr({ - class: 'node-annotation', - fill: d => { - const nf = diagram.nodeFill.eval(d); - return diagram.nodeFillScale()(nf - ((nf%2) ? 0 : 1)); - }, - 'font-weight': 750, - 'font-size': '50px', - 'alignment-baseline': 'central', - dx: d => Math.round(d.dcg_rx + 10) + 'px' - }); - annots.exit().remove(); - annots - .text(d => d.orig.value.ceq); - } - function remove() {} - const _mode = dc_graph.mode('annotate-nodes', { - draw, - remove, - laterDraw: true - }); - return _mode; -}; - -dc_graph.register_highlight_things_group = function(thingsgroup) { - window.chart_registry.create_type('highlight-things', function() { - return d3.dispatch('highlight'); - }); - - return window.chart_registry.create_group('highlight-things', thingsgroup); -}; - -dc_graph.highlight_things = function(includeprops, excludeprops, modename, groupname, cascbase) { - var highlight_things_group = dc_graph.register_highlight_things_group(groupname || 'highlight-things-group'); - var _includeprops = {...includeprops}, _excludeprops = {...excludeprops}; - var _active, _nodeset = {}, _edgeset = {}; - cascbase = cascbase || 150; - - function highlight(nodeset, edgeset) { - _active = nodeset || edgeset; - _nodeset = nodeset || {}; - _edgeset = edgeset || {}; - _mode.parent().requestRefresh(_mode.durationOverride()); - } - function draw(diagram) { - diagram.cascade(cascbase, true, node_edge_conditions( - function(n) { - return _nodeset[_mode.parent().nodeKey.eval(n)]; - }, function(e) { - return _edgeset[_mode.parent().edgeKey.eval(e)]; - }, _includeprops)); - diagram.cascade(cascbase+10, true, node_edge_conditions( - function(n) { - return _active && !_nodeset[_mode.parent().nodeKey.eval(n)]; - }, function(e) { - return _active && !_edgeset[_mode.parent().edgeKey.eval(e)]; - }, _excludeprops)); - } - function remove(diagram) { - diagram.cascade(cascbase, false, _includeprops); - diagram.cascade(cascbase + 10, false, _excludeprops); - } - var _mode = dc_graph.mode(modename, { - draw: draw, - remove: remove, - parent: function(p) { - highlight_things_group.on('highlight.' + modename, p ? highlight : null); - } - }); - _mode.includeProps = () => _includeprops; - _mode.excludeProps = () => _excludeprops; - _mode.durationOverride = property(undefined); - return _mode; -}; - -dc_graph.register_highlight_neighbors_group = function(neighborsgroup) { - window.chart_registry.create_type('highlight-neighbors', function() { - return d3.dispatch('highlight_node'); - }); - - return window.chart_registry.create_group('highlight-neighbors', neighborsgroup); -}; - -dc_graph.highlight_neighbors = function(includeprops, excludeprops, neighborsgroup, thingsgroup) { - var highlight_neighbors_group = dc_graph.register_highlight_neighbors_group(neighborsgroup || 'highlight-neighbors-group'); - var highlight_things_group = dc_graph.register_highlight_things_group(thingsgroup || 'highlight-things-group'); - - function highlight_node(nodeid) { - var diagram = _mode.parent(); - var nodeset = {}, edgeset = {}; - if(nodeid) { - nodeset[nodeid] = true; - _mode.parent().selectAllEdges().each(function(e) { - if(diagram.nodeKey.eval(e.source) === nodeid) { - edgeset[diagram.edgeKey.eval(e)] = true; - nodeset[diagram.nodeKey.eval(e.target)] = true; - } - if(diagram.nodeKey.eval(e.target) === nodeid) { - edgeset[diagram.edgeKey.eval(e)] = true; - nodeset[diagram.nodeKey.eval(e.source)] = true; - } - }); - highlight_things_group.highlight(nodeset, edgeset); - } - else highlight_things_group.highlight(null, null); - } - function draw(diagram, node, edge) { - node - .on('mouseover.highlight-neighbors', function(n) { - highlight_neighbors_group.highlight_node(_mode.parent().nodeKey.eval(n)); - }) - .on('mouseout.highlight-neighbors', function(n) { - highlight_neighbors_group.highlight_node(null); - }); - } - - function remove(diagram, node, edge) { - node - .on('mouseover.highlight-neighbors', null) - .on('mouseout.highlight-neighbors', null); - highlight_neighbors_group.highlight_node(null); - } - - var _mode = dc_graph.mode('highlight-neighbors', { - draw: draw, - remove: function(diagram, node, edge) { - remove(diagram, node, edge); - }, - parent: function(p) { - highlight_neighbors_group.on('highlight_node.highlight-neighbors', p ? highlight_node : null); - if(p && !p.child('highlight-things')) - p.child('highlight-things', - dc_graph.highlight_things(includeprops, excludeprops) - .durationOverride(_mode.durationOverride())); - } - }); - _mode.durationOverride = property(undefined); - return _mode; -}; - - -dc_graph.highlight_radius = function(options) { - options = options || {}; - var select_nodes_group = dc_graph.select_things_group(options.select_nodes_group || 'select-nodes-group', 'select-nodes'); - var highlight_things_group = dc_graph.register_highlight_things_group(options.highlight_things_group || 'highlight-things-group'); - var _graph, _selection = []; - - function recurse(n, r, nodeset, edgeset) { - nodeset[n.key()] = true; - if(r) { - n.outs().filter(function(e) { - return !edgeset[e.key()]; - }).forEach(function(e) { - edgeset[e.key()] = true; - recurse(e.target(), r-1, nodeset, edgeset); - }); - n.ins().filter(function(e) { - return !edgeset[e.key()]; - }).forEach(function(e) { - edgeset[e.key()] = true; - recurse(e.source(), r-1, nodeset, edgeset); - }); - } - } - function selection_changed(nodes) { - _selection = nodes; - console.assert(_graph); - var nodeset = {}, edgeset = {}; - nodes.forEach(function(nkey) { - recurse(_graph.node(nkey), _mode.radius(), nodeset, edgeset); - }); - if(!Object.keys(nodeset).length && !Object.keys(edgeset).length) - nodeset = edgeset = null; - highlight_things_group.highlight(nodeset, edgeset); - } - - function on_data(diagram, nodes, wnodes, edges, wedges, ports, wports) { - _graph = metagraph.graph(wnodes, wedges, { - nodeKey: diagram.nodeKey.eval, - edgeKey: diagram.edgeKey.eval, - edgeSource: diagram.edgeSource.eval, - edgeTarget: diagram.edgeTarget.eval - }); - var sel2 = _selection.filter(function(nk) { - return !!_graph.node(nk); - }); - if(sel2.length < _selection.length) - window.setTimeout(function() { - select_nodes_group.set_changed(sel2); - }, 0); - } - var _mode = { - parent: function(p) { - if(p) { - p.on('data.highlight-radius', on_data); - } else if(_mode.parent()) - _mode.parent().on('data.highlight-radius', null); - select_nodes_group.on('set_changed.highlight-radius', selection_changed); - } - }; - _mode.radius = property(1); - return _mode; -}; - -dc_graph.register_highlight_paths_group = function(pathsgroup) { - window.chart_registry.create_type('highlight-paths', function() { - return d3.dispatch('paths_changed', 'hover_changed', 'select_changed'); - }); - - return window.chart_registry.create_group('highlight-paths', pathsgroup); -}; - -dc_graph.highlight_paths = function(pathprops, hoverprops, selectprops, pathsgroup) { - var highlight_paths_group = dc_graph.register_highlight_paths_group(pathsgroup || 'highlight-paths-group'); - pathprops = pathprops || {}; - hoverprops = hoverprops || {}; - selectprops = selectprops || {}; - var node_on_paths = {}, edge_on_paths = {}, selected = null, hoverpaths = null; - var _anchor; - - function refresh() { - if(_mode.doRedraw()) - _mode.parent().relayout().redraw(); - else - _mode.parent().refresh(); - } - - function paths_changed(nop, eop) { - selected = hoverpaths = null; - // it would be difficult to check if no change, but at least check if changing from empty to empty - if(Object.keys(node_on_paths).length === 0 && Object.keys(nop).length === 0 && - Object.keys(edge_on_paths).length === 0 && Object.keys(eop).length === 0) - return; - node_on_paths = nop; - edge_on_paths = eop; - refresh(); - } - - function hover_changed(hp) { - if(hp !== hoverpaths) { - hoverpaths = hp; - refresh(); - } - } - - function select_changed(sp) { - if(sp !== selected) { - selected = sp; - refresh(); - } - } - - function clear_all_highlights() { - node_on_paths = {}; - edge_on_paths = {}; - } - - function contains_path(paths) { - return function(path) { - return paths.indexOf(path)>=0; - }; - } - - // sigh - function doesnt_contain_path(paths) { - var cp = contains_path(paths); - return function(path) { - return !cp(path); - }; - } - - function intersect_paths(pathsA, pathsB) { - if(!pathsA || !pathsB) - return false; - return pathsA.some(contains_path(pathsB)); - } - - function toggle_paths(pathsA, pathsB) { - if(!pathsA) - return pathsB; - else if(!pathsB) - return pathsA; - if(pathsB.every(contains_path(pathsA))) - return pathsA.filter(doesnt_contain_path(pathsB)); - else return pathsA.concat(pathsB.filter(doesnt_contain_path(pathsA))); - } - - function draw(diagram, node, edge, ehover) { - diagram - .cascade(200, true, node_edge_conditions(function(n) { - return !!node_on_paths[diagram.nodeKey.eval(n)]; - }, function(e) { - return !!edge_on_paths[diagram.edgeKey.eval(e)]; - }, pathprops)) - .cascade(300, true, node_edge_conditions(function(n) { - return intersect_paths(node_on_paths[diagram.nodeKey.eval(n)], selected); - }, function(e) { - return intersect_paths(edge_on_paths[diagram.edgeKey.eval(e)], selected); - }, selectprops)) - .cascade(400, true, node_edge_conditions(function(n) { - return intersect_paths(node_on_paths[diagram.nodeKey.eval(n)], hoverpaths); - }, function(e) { - return intersect_paths(edge_on_paths[diagram.edgeKey.eval(e)], hoverpaths); - }, hoverprops)); - - node - .on('mouseover.highlight-paths', function(n) { - highlight_paths_group.hover_changed(node_on_paths[diagram.nodeKey.eval(n)] || null); - }) - .on('mouseout.highlight-paths', function(n) { - highlight_paths_group.hover_changed(null); - }) - .on('click.highlight-paths', function(n) { - highlight_paths_group.select_changed(toggle_paths(selected, node_on_paths[diagram.nodeKey.eval(n)])); - }); - - - ehover - .on('mouseover.highlight-paths', function(e) { - highlight_paths_group.hover_changed(edge_on_paths[diagram.edgeKey.eval(e)] || null); - }) - .on('mouseout.highlight-paths', function(e) { - highlight_paths_group.hover_changed(null); - }) - .on('click.highlight-paths', function(n) { - highlight_paths_group.select_changed(toggle_paths(selected, edge_on_paths[diagram.nodeKey.eval(n)])); - }); - } - - function remove(diagram, node, edge, ehover) { - node - .on('mouseover.highlight-paths', null) - .on('mouseout.highlight-paths', null) - .on('click.highlight-paths', null); - ehover - .on('mouseover.highlight-paths', null) - .on('mouseout.highlight-paths', null) - .on('click.highlight-paths', null); - clear_all_highlights(); - diagram - .cascade(200, false, pathprops) - .cascade(300, false, selectprops) - .cascade(400, false, hoverprops); - } - - var _mode = dc_graph.mode('highlight-paths', { - draw: draw, - remove: function(diagram, node, edge, ehover) { - remove(diagram, node, edge, ehover); - return this; - }, - parent: function(p) { - if(p) - _anchor = p.anchorName(); - // else we should have received anchor earlier - highlight_paths_group.on('paths_changed.highlight-paths-' + _anchor, p ? paths_changed : null); - highlight_paths_group.on('hover_changed.highlight-paths-' + _anchor, p ? hover_changed : null); - highlight_paths_group.on('select_changed.highlight-paths-' + _anchor, p ? select_changed : null); - } - }); - - // whether to do relayout & redraw (true) or just refresh (false) - _mode.doRedraw = property(false); - - return _mode; -}; - - -dc_graph.spline_paths = function(pathreader, pathprops, hoverprops, selectprops, pathsgroup) { - var highlight_paths_group = dc_graph.register_highlight_paths_group(pathsgroup || 'highlight-paths-group'); - pathprops = pathprops || {}; - hoverprops = hoverprops || {}; - var _paths = null, _hoverpaths = null, _selected = null; - var _anchor; - var _layer = null; - var _savedPositions = null; - - function paths_changed(nop, eop, paths) { - _paths = paths; - - var engine = _mode.parent().layoutEngine(), - localPaths = paths.filter(pathIsPresent); - if(localPaths.length) { - var nidpaths = localPaths.map(function(lpath) { - var strength = pathreader.pathStrength.eval(lpath); - if(typeof strength !== 'number') - strength = 1; - if(_selected && _selected.indexOf(lpath) !== -1) - strength *= _mode.selectedStrength(); - return { - nodes: path_keys(lpath), - strength: strength - }; - }); - engine.paths(nidpaths); - } else { - engine.paths(null); - if(_savedPositions) - engine.restorePositions(_savedPositions); - } - if(_selected) - _selected = _selected.filter(function(p) { return localPaths.indexOf(p) !== -1; }); - _mode.parent().redraw(); - } - - function select_changed(sp) { - if(sp !== _selected) { - _selected = sp; - paths_changed(null, null, _paths); - } - } - - function path_keys(path, unique) { - unique = unique !== false; - var keys = pathreader.elementList.eval(path).filter(function(elem) { - return pathreader.elementType.eval(elem) === 'node'; - }).map(function(elem) { - return pathreader.nodeKey.eval(elem); - }); - return unique ? uniq(keys) : keys; - } - - // check if entire path is present in this view - function pathIsPresent(path) { - return pathreader.elementList.eval(path).every(function(element) { - return pathreader.elementType.eval(element) !== 'node' || - _mode.parent().getWholeNode(pathreader.nodeKey.eval(element)); - }); - } - - // get the positions of nodes on path - function getNodePositions(path, old) { - return path_keys(path, false).map(function(key) { - var node = _mode.parent().getWholeNode(key); - return {x: old && node.prevX !== undefined ? node.prevX : node.cola.x, - y: old && node.prevY !== undefined ? node.prevY : node.cola.y}; - }); - }; - - // insert fake nodes to avoid sharp turns - function insertDummyNodes(path_coord) { - function _distance(node1, node2) { - return Math.sqrt(Math.pow((node1.x-node2.x),2) + Math.pow((node1.y-node2.y),2)); - } - - var new_path_coord = []; - - for(var i = 0; i < path_coord.length; i ++) { - if (i-1 >= 0 && i+1 < path_coord.length) { - if (path_coord[i-1].x === path_coord[i+1].x && - path_coord[i-1].y === path_coord[i+1].y ) { - // insert node when the previous and next nodes are the same - var x1 = path_coord[i-1].x, y1 = path_coord[i-1].y; - var x2 = path_coord[i].x, y2 = path_coord[i].y; - var dx = x1 - x2, dy = y1 - y2; - - var v1 = dy / Math.sqrt(dx*dx + dy*dy); - var v2 = - dx / Math.sqrt(dx*dx + dy*dy); - - var insert_p1 = {'x': null, 'y': null}; - var insert_p2 = {'x': null, 'y': null}; - - var offset = 10; - - insert_p1.x = (x1+x2)/2.0 + offset*v1; - insert_p1.y = (y1+y2)/2.0 + offset*v2; - - insert_p2.x = (x1+x2)/2.0 - offset*v1; - insert_p2.y = (y1+y2)/2.0 - offset*v2; - - new_path_coord.push(insert_p1); - new_path_coord.push(path_coord[i]); - new_path_coord.push(insert_p2); - } else if (_distance(path_coord[i-1], path_coord[i+1]) < pathprops.nearNodesDistance){ - // insert node when the previous and next nodes are very close - // first node - var x1 = path_coord[i-1].x, y1 = path_coord[i-1].y; - var x2 = path_coord[i].x, y2 = path_coord[i].y; - var dx = x1 - x2, dy = y1 - y2; - - var v1 = dy / Math.sqrt(dx*dx + dy*dy); - var v2 = - dx / Math.sqrt(dx*dx + dy*dy); - - var insert_p1 = {'x': null, 'y': null}; - - var offset = 10; - - insert_p1.x = (x1+x2)/2.0 + offset*v1; - insert_p1.y = (y1+y2)/2.0 + offset*v2; - - // second node - x1 = path_coord[i].x; - y1 = path_coord[i].y; - x2 = path_coord[i+1].x; - y2 = path_coord[i+1].y; - dx = x1 - x2; - dy = y1 - y2; - - v1 = dy / Math.sqrt(dx*dx + dy*dy); - v2 = - dx / Math.sqrt(dx*dx + dy*dy); - - var insert_p2 = {'x': null, 'y': null}; - - insert_p2.x = (x1+x2)/2.0 + offset*v1; - insert_p2.y = (y1+y2)/2.0 + offset*v2; - - new_path_coord.push(insert_p1); - new_path_coord.push(path_coord[i]); - new_path_coord.push(insert_p2); - - } - else { - new_path_coord.push(path_coord[i]); - } - } else { - new_path_coord.push(path_coord[i]); - } - } - return new_path_coord; - } - - // helper functions - var vecDot = function(v0, v1) { return v0.x*v1.x+v0.y*v1.y; }; - var vecMag = function(v) { return Math.sqrt(v.x*v.x + v.y*v.y); }; - var l2Dist = function(p1, p2) { - return Math.sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); - }; - - function drawCardinalSpline(points, lineTension, avoidSharpTurn, angleThreshold) { - var c = lineTension || 0; - avoidSharpTurn = avoidSharpTurn !== false; - angleThreshold = angleThreshold || 0.02; - - // get the path without self loops - var path_list = [points[0]]; - for(var i = 1; i < points.length; i ++) { - if(l2Dist(points[i], path_list[path_list.length-1]) > 1e-6) { - path_list.push(points[i]); - } - } - - // repeat first and last node - points = [path_list[0]]; - points = points.concat(path_list); - points.push(path_list[path_list.length-1]); - - // a segment is a list of three points: [c0, c1, p1], - // representing the coordinates in "C x0,y0,x1,y1,x,y" in svg:path - var segments = []; // control points - for(var i = 1; i < points.length-2; i ++) { - // generate svg:path - var m_0_x = (1-c)*(points[i+1].x - points[i-1].x)/2; - var m_0_y = (1-c)*(points[i+1].y - points[i-1].y)/2; - - var m_1_x = (1-c)*(points[i+2].x - points[i].x)/2; - var m_1_y = (1-c)*(points[i+2].y - points[i].y)/2; - - var p0 = points[i]; - var p1 = points[i+1]; - var c0 = p0; - if(i !== 1) { - c0 = {x: p0.x+(m_0_x/3), y:p0.y+(m_0_y/3)}; - } - var c1 = p1; - if(i !== points.length-3) { - c1 = {x: p1.x-(m_1_x/3), y:p1.y-(m_1_y/3)}; - } - - // detect special case by calculating the angle - if(avoidSharpTurn) { - var v0 = {x:points[i-1].x - points[i].x, y:points[i-1].y - points[i].y}; - var v1 = {x:points[i+1].x - points[i].x, y:points[i+1].y - points[i].y}; - var acosValue = vecDot(v0,v1) / (vecMag(v0)*vecMag(v1)); - acosValue = Math.max(-1, Math.min(1, acosValue)); - var angle = Math.acos( acosValue ); - - if(angle <= angleThreshold ){ - var m_x = (1-c)*(points[i].x - points[i-1].x)/2; - var m_y = (1-c)*(points[i].y - points[i-1].y)/2; - var k = 2; - - var cp1 = {x: p0.x+k*(-m_y/3), y:p0.y+k*(m_x/3)}; - var cp2 = {x: p0.x-k*(-m_y/3), y:p0.y-k*(m_x/3)}; - // CP_1CP_2 - var vCP = {x: cp1.x-cp2.x, y:cp1.y-cp2.y}; // vector cp1->cp2 - var vPN = {x: points[i-2].x - points[i+2].x, y:points[i-2].y-points[i+2].y}; // vector Previous->Next - if(vecDot(vCP, vPN) > 0) { - c0 = cp1; - segments[segments.length-1][1] = cp2; - } else { - c0 = cp2; - segments[segments.length-1][1] = cp1; - } - } - } - - segments.push([c0,c1,p1]); - } - - var path_d = "M"+points[0].x+","+points[0].y; - for(var i = 0; i < segments.length; i ++) { - var s = segments[i]; - path_d += "C"+s[0].x+","+s[0].y; - path_d += ","+s[1].x+","+s[1].y; - path_d += ","+s[2].x+","+s[2].y; - } - return path_d; - } - - function drawDedicatedLoops(points, lineTension, avoidSharpTurn, angleThreshold) { - // get loops as segments - var p1 = 0, p2 = 1; - var seg_list = []; // (start, end) - while(p1 < points.length-1 && p2 < points.length) { - if(l2Dist(points[p1], points[p2]) < 1e-6) { - var repeated = points[p2]; - while(p2 < points.length && l2Dist(points[p2], repeated) < 1e-6) p2++; - seg_list.push({'start': Math.max(0, p1-1), 'end': Math.min(points.length-1, p2)}); - p1 = p2; - p2 = p1+1; - } else { - p1++; - p2++; - } - } - - var loopCurves = ""; - for(var i = 0; i < seg_list.length; i ++) { - var segment = seg_list[i]; - var loopCount = segment.end - segment.start - 2; - var anchorPoint = points[segment.start+1]; - - // the vector from previous node to next node - var vec_pre_next = { - x: points[segment.end].x-points[segment.start].x, - y: points[segment.end].y-points[segment.start].y - }; - - // when previous node and next node are the same node, we need to handle - // them differently. - // e.g. for a loop segment A->B->B->A, we use the perpendicular vector perp_AB - // instead of vector AA(which is vec_pre_next in this case). - if(vecMag(vec_pre_next) == 0) { - vec_pre_next = { - x: -(points[segment.end].y-anchorPoint.y), - y: points[segment.end].x-anchorPoint.x - }; - } - - // unit length vector - var vec_pre_next_unit = { - x: vec_pre_next.x / vecMag(vec_pre_next), - y: vec_pre_next.y / vecMag(vec_pre_next) - }; - var vec_pre_next_perp = { - x: -vec_pre_next.y / vecMag(vec_pre_next), - y: vec_pre_next.x / vecMag(vec_pre_next) - }; - - var insertP; - for(var j = 0; j < loopCount; j ++) { - var c1,c2,c3,c4; - - // change the control points every time this loop appears - var cp_k = 15+2*j; - - // calculate c1 and c4, their tangent match the tangent at anchorPoint - c1 = { - x: anchorPoint.x + cp_k*vec_pre_next_unit.x, - y: anchorPoint.y + cp_k*vec_pre_next_unit.y - }; - - c4 = { - x: anchorPoint.x - cp_k*vec_pre_next_unit.x, - y: anchorPoint.y - cp_k*vec_pre_next_unit.y - }; - - // change the location of inserted virtual point every time this loop appears - var control_k = 25+5*j; - var insertP1 = { - x: anchorPoint.x+vec_pre_next_perp.x*control_k, - y: anchorPoint.y+vec_pre_next_perp.y*control_k - }; - var insertP2 = { - x: anchorPoint.x-vec_pre_next_perp.x*control_k, - y: anchorPoint.y-vec_pre_next_perp.y*control_k - }; - var vec_i_to_next = { - x: points[segment.end].x - anchorPoint.x, - y: points[segment.end].y - anchorPoint.y - }; - var vec_i_to_insert = { - x: insertP1.x - anchorPoint.x, - y: insertP1.y - anchorPoint.y - }; - insertP = insertP1; - if(vecDot(vec_i_to_insert, vec_i_to_next) > 0) { - insertP = insertP2; - } - - // calculate c2 and c3 based on insertP - c2 = { - x: insertP.x + cp_k*vec_pre_next_unit.x, - y: insertP.y + cp_k*vec_pre_next_unit.y - }; - - c3 = { - x: insertP.x - cp_k*vec_pre_next_unit.x, - y: insertP.y - cp_k*vec_pre_next_unit.y - }; - - var curve = "M"+anchorPoint.x+","+anchorPoint.y; - curve += "C"+c1.x+","+c1.y+","+c2.x+","+c2.y+","+insertP.x+","+insertP.y; - curve += "C"+c3.x+","+c3.y+","+c4.x+","+c4.y+","+anchorPoint.x+","+anchorPoint.y; - - loopCurves += curve; - } - } - return loopCurves; - } - - // convert original path data into - function genPath(originalPoints, old, lineTension, avoidSharpTurn, angleThreshold) { - // get coordinates - var path_coord = getNodePositions(originalPoints, old); - if(path_coord.length < 2) return ""; - - var result = ""; - // process the points and treat them differently: - // 1. sub-path without self loop - result += drawCardinalSpline(path_coord, lineTension, avoidSharpTurn, angleThreshold); - - // 2. a list of loop segments - result += drawDedicatedLoops(path_coord, lineTension, avoidSharpTurn, angleThreshold); - - return result; - } - - // draw the spline for paths - function drawSpline(paths) { - if(paths === null) { - _savedPositions = _mode.parent().layoutEngine().savePositions(); - return; - } - - paths = paths.filter(pathIsPresent); - var hoverpaths = _hoverpaths || [], - selected = _selected || []; - - // edge spline - var edge = _layer.selectAll(".spline-edge").data(paths, function(path) { return path_keys(path).join(','); }); - edge.exit().remove(); - var edgeEnter = edge.enter().append("svg:path") - .attr('class', 'spline-edge') - .attr('id', function(d, i) { return "spline-path-"+i; }) - .attr('stroke-width', pathprops.edgeStrokeWidth || 1) - .attr('fill', 'none') - .attr('d', function(d) { return genPath(d, true, pathprops.lineTension, _mode.avoidSharpTurns()); }); - edge - .attr('stroke', function(p) { - return selected.indexOf(p) !== -1 && selectprops.edgeStroke || - hoverpaths.indexOf(p) !== -1 && hoverprops.edgeStroke || - pathprops.edgeStroke || 'black'; - }) - .attr('opacity', function(p) { - return selected.indexOf(p) !== -1 && selectprops.edgeOpacity || - hoverpaths.indexOf(p) !== -1 && hoverprops.edgeOpacity || - pathprops.edgeOpacity || 1; - }); - function path_order(p) { - return hoverpaths.indexOf(p) !== -1 ? 2 : - selected.indexOf(p) !== -1 ? 1 : - 0; - } - edge.sort(function(a, b) { - return path_order(a) - path_order(b); - }); - _layer.selectAll('.spline-edge-hover') - .each(function() {this.parentNode.appendChild(this);}); - edge.transition().duration(_mode.parent().transitionDuration()) - .attr('d', function(d) { return genPath(d, false, pathprops.lineTension, _mode.avoidSharpTurns()); }); - - // another wider copy of the edge just for hover events - var edgeHover = _layer.selectAll('.spline-edge-hover') - .data(paths, function(path) { return path_keys(path).join(','); }); - edgeHover.exit().remove(); - var edgeHoverEnter = edgeHover.enter().append('svg:path') - .attr('class', 'spline-edge-hover') - .attr('d', function(d) { return genPath(d, true, pathprops.lineTension, _mode.avoidSharpTurns()); }) - .attr('opacity', 0) - .attr('stroke', 'green') - .attr('stroke-width', (pathprops.edgeStrokeWidth || 1) + 4) - .attr('fill', 'none') - .on('mouseover.spline-paths', function(d) { - highlight_paths_group.hover_changed([d]); - }) - .on('mouseout.spline-paths', function(d) { - highlight_paths_group.hover_changed(null); - }) - .on('click.spline-paths', function(d) { - var selected = _selected && _selected.slice(0) || [], - i = selected.indexOf(d); - if(i !== -1) - selected.splice(i, 1); - else if(d3.event.shiftKey) - selected.push(d); - else - selected = [d]; - highlight_paths_group.select_changed(selected); - }); - edgeHover.transition().duration(_mode.parent().transitionDuration()) - .attr('d', function(d) { return genPath(d, false, pathprops.lineTension, _mode.avoidSharpTurns()); }); - }; - - function draw(diagram, node, edge, ehover) { - _layer = _mode.parent().select('g.draw').selectAll('g.spline-layer').data([0]); - _layer.enter().append('g').attr('class', 'spline-layer'); - - drawSpline(_paths); - } - - function remove(diagram, node, edge, ehover) { - } - - var _mode = dc_graph.mode('draw-spline-paths', { - laterDraw: true, - draw: draw, - remove: function(diagram, node, edge, ehover) { - remove(diagram, node, edge, ehover); - return this; - }, - parent: function(p) { - if(p) - _anchor = p.anchorName(); - highlight_paths_group - .on('paths_changed.draw-spline-paths-' + _anchor, p ? paths_changed : null) - .on('select_changed.draw-spline-paths-' + _anchor, p ? select_changed : null) - .on('hover_changed.draw-spline-paths-' + _anchor, p ? function(hpaths) { - _hoverpaths = hpaths; - drawSpline(_paths); - } : null); - } - }); - _mode.selectedStrength = property(1); - _mode.avoidSharpTurns = property(true); - - return _mode; -}; - -dc_graph.draw_spline_paths = deprecate_function("draw_spline_paths has been renamed spline_paths, please update", dc_graph.spline_paths); - -dc_graph.draw_clusters = function() { - - function apply_bounds(rect) { - rect.attr({ - x: function(c) { - return c.cola.bounds.left; - }, - y: function(c) { - return c.cola.bounds.top; - }, - width: function(c) { - return c.cola.bounds.right - c.cola.bounds.left; - }, - height: function(c) { - return c.cola.bounds.bottom - c.cola.bounds.top; - } - }); - } - function draw(diagram) { - if(!diagram.clusterGroup()) - return; - var clayer = diagram.g().selectAll('g.cluster-layer').data([0]); - clayer.enter().insert('g', ':first-child') - .attr('class', 'cluster-layer'); - var clusters = diagram.clusterGroup().all().map(function(kv) { - return _mode.parent().getWholeCluster(kv.key); - }).filter(function(c) { - return c && c.cola.bounds; - }); - var rects = clayer.selectAll('rect.cluster') - .data(clusters, function(c) { return c.orig.key; }); - rects.exit().remove(); - rects.enter().append('rect') - .attr({ - class: 'cluster', - opacity: 0, - stroke: _mode.clusterStroke.eval, - 'stroke-width': _mode.clusterStrokeWidth.eval, - fill: function(c) { - return _mode.clusterFill.eval(c) || 'none'; - } - }) - .call(apply_bounds); - rects.transition() - .duration(_mode.parent().stagedDuration()) - .attr('opacity', _mode.clusterOpacity.eval) - .call(apply_bounds); - } - function remove(diagram, node, edge, ehover) { - } - var _mode = dc_graph.mode('draw-clusters', { - laterDraw: true, - draw: draw, - remove: remove - }); - _mode.clusterOpacity = property(0.25); - _mode.clusterStroke = property('black'); - _mode.clusterStrokeWidth = property(1); - _mode.clusterFill = property(null); - _mode.clusterLabel = property(null); - _mode.clusterLabelFill = property('black'); - _mode.clusterLabelAlignment = property(['bottom','right']); - - return _mode; -}; - - -dc_graph.expand_collapse = function(options) { - if(typeof options === 'function') { - options = { - get_degree: arguments[0], - expand: arguments[1], - collapse: arguments[2], - dirs: arguments[3] - }; - } - var _keyboard, _overNode, _overDir, _overEdge, _expanded = {}, _changing, _ignore = null; - var changing_highlight_group = dc_graph.register_highlight_things_group(options.changing_highlight_group || 'changing-highlight-group'); - var expanded_highlight_group = dc_graph.register_highlight_things_group(options.expanded_highlight_group || 'expanded-highlight-group'); - var collapse_highlight_group = dc_graph.register_highlight_things_group(options.collapse_highlight_group || 'collapse-highlight-group'); - var hide_highlight_group = dc_graph.register_highlight_things_group(options.hide_highlight_group || 'hide-highlight-group'); - options.dirs = options.dirs || ['both']; - options.dirs.forEach(function(dir) { - _expanded[dir] = new Set(); - }); - options.hideKey = options.hideKey || 'Alt'; - options.recurseKey = options.recurseKey || 'Shift'; - options.linkKey = options.linkKey || (is_a_mac ? 'Meta' : 'Control'); - if(options.dirs.length > 2) - throw new Error('there are only two directions to expand in'); - - var _gradients_added = {}; - function add_gradient_def(color, diagram) { - if(_gradients_added[color]) - return; - _gradients_added[color] = true; - diagram.addOrRemoveDef('spike-gradient-' + color, true, 'linearGradient', function(gradient) { - gradient.attr({ - x1: '0%', - y1: '0%', - x2: '100%', - y2: '0%', - spreadMethod: 'pad' - }); - gradient.selectAll('stop').data([[0, color, 1], [100, color, '0']]) - .enter().append('stop').attr({ - offset: function(d) { - return d[0] + '%'; - }, - 'stop-color': function(d) { - return d[1]; - }, - 'stop-opacity': function(d) { - return d[2]; - } - }); - }); - } - - function visible_edges(diagram, edge, dir, key) { - var fil; - switch(dir) { - case 'out': - fil = function(e) { - return diagram.edgeSource.eval(e) === key; - }; - break; - case 'in': - fil = function(e) { - return diagram.edgeTarget.eval(e) === key; - }; - break; - case 'both': - fil = function(e) { - return diagram.edgeSource.eval(e) === key || diagram.edgeTarget.eval(e) === key; - }; - break; - } - return edge.filter(fil).data(); - } - - const sweep_angle = (N, ofs, span = Math.PI) => - i => ofs + ((N-1)*span/N) * (-.5 + (N > 1 ? i / (N-1) : 0)); // avoid 0/0 - - function spike_directioner(rankdir, dir, N) { - if(dir==='both') - return function(i) { - return Math.PI * (2 * i / N - 0.5); - }; - else { - var ofs; - switch(rankdir) { - case 'LR': - ofs = 0; - break; - case 'TB': - ofs = Math.PI/2; - break; - case 'RL': - ofs = Math.PI; - break; - case 'BT': - ofs = -Math.PI/2; - break; - } - if(dir === 'in') - ofs += Math.PI; - return sweep_angle(N, ofs); - } - } - - function produce_spikes_helper(cx, cy, rx, ry, a, spike, span, ret) { - const dx = Math.cos(a) * rx, - dy = Math.sin(a) * ry; - const dash = { - a: a * 180 / Math.PI, - x: cx + dx, - y: cy + dy, - edge: spike.pe - }; - ret.push(dash); - span *= 0.75; - const sweep = sweep_angle(spike.children.length, a, span); - for(const i of d3.range(spike.children.length)) - produce_spikes_helper(cx + 1.5*dx, cy + 1.5*dy, rx, ry, sweep(i), spike.children[i], span, ret); - } - - function produce_spikes(diagram, n, spikeses) { - const ret = []; - Object.keys(spikeses).forEach(dir => { - const sweep = spike_directioner(diagram.layoutEngine().rankdir(), dir, spikeses[dir].length); - for(const i of d3.range(spikeses[dir].length)) - produce_spikes_helper(0, 0, n.dcg_rx * 0.9, n.dcg_ry * 0.9, sweep(i), spikeses[dir][i], Math.PI, ret); - }); - return ret; - } - - function draw_stubs(diagram, node, edge, n, spikeseses) { - var spike = node - .selectAll('g.spikes') - .data(function(n2) { - return spikeseses[diagram.nodeKey.eval(n2)] ? - [n2] : []; - }); - spike.exit().remove(); - spike - .enter().insert('g', ':first-child') - .classed('spikes', true); - var rect = spike - .selectAll('rect.spike') - .data(function(n) { - var key = diagram.nodeKey.eval(n); - return produce_spikes(diagram, n, spikeseses[key]); - }); - rect - .enter().append('rect') - .classed('spike', true) - .attr({ - width: 25, - height: 3, - rx: 1, - ry: 1, - x: 0, - y: 0 - }); - rect.attr({ - fill: function(s) { - var color = s.edge ? dc_graph.functor_wrap(diagram.edgeStroke())(s.edge) : 'black'; - add_gradient_def(color, diagram); - return 'url(#spike-gradient-' + color + ')'; - }, - transform: function(d) { - return 'translate(' + d.x + ',' + d.y + ') rotate(' + d.a + ')'; - } - }); - rect.exit().remove(); - } - - function clear_stubs(diagram, node, edge) { - draw_stubs(diagram, node, edge, null, {}); - } - - function zonedir(diagram, event, dirs, n) { - if(dirs.length === 1) // we assume it's ['out', 'in'] - return dirs[0]; - var bound = diagram.root().node().getBoundingClientRect(); - var invert = diagram.invertCoord([event.clientX - bound.left,event.clientY - bound.top]), - x = invert[0], - y = invert[1]; - switch(diagram.layoutEngine().rankdir()) { - case 'TB': - return y > n.cola.y ? 'out' : 'in'; - case 'BT': - return y < n.cola.y ? 'out' : 'in'; - case 'LR': - return x > n.cola.x ? 'out' : 'in'; - case 'RL': - return x < n.cola.x ? 'out' : 'in'; - } - throw new Error('unknown rankdir ' + diagram.layoutEngine().rankdir()); - } - - function detect_key(key) { - switch(key) { - case 'Alt': - return d3.event.altKey; - case 'Meta': - return d3.event.metaKey; - case 'Shift': - return d3.event.shiftKey; - case 'Control': - return d3.event.ctrlKey; - } - return false; - } - - function highlight_hiding_node(diagram, n, edge) { - var nk = diagram.nodeKey.eval(n); - var hide_nodes_set = {}, hide_edges_set = {}; - hide_nodes_set[nk] = true; - edge.each(function(e) { - if(diagram.edgeSource.eval(e) === nk || diagram.edgeTarget.eval(e) === nk) - hide_edges_set[diagram.edgeKey.eval(e)] = true; - }); - hide_highlight_group.highlight(hide_nodes_set, hide_edges_set); - } - function highlight_hiding_edge(diagram, e) { - var hide_edges_set = {}; - hide_edges_set[diagram.edgeKey.eval(e)] = true; - hide_highlight_group.highlight({}, hide_edges_set); - } - - function partition_among_visible(tree_edges, visible, parts, nk, pe = null, seen = new Set()) { - if(seen.has(nk)) - return []; - seen.add(nk); - let children = tree_edges[nk].nks - .filter(nk => !seen.has(nk)) - .flatMap((nk2, i) => partition_among_visible(tree_edges, visible, parts, nk2, tree_edges[nk].edges[i], seen)) - .filter(({nk}) => !visible.has(nk)); - if(visible.has(nk)) { - parts[nk] = children; - children = []; - } - return [{pe, nk, children}]; - } - - function highlight_expand_collapse(diagram, n, node, edge, dir, recurse) { - var nk = diagram.nodeKey.eval(n); - let tree_edges = options.get_tree_edges(nk, dir, !recurse); - let visible_nodes = new Set(node.data().map(n => diagram.nodeKey.eval(n)).filter(nk => tree_edges[nk])); - const parts = {}; - if(recurse) - partition_among_visible(tree_edges, visible_nodes, parts, nk); - const spikeseses = {}; - if(!_expanded[dir].has(nk)) - Object.keys(tree_edges).forEach(nk => { - let spikes; - if(recurse) { - spikes = parts[nk] || []; - } - else { - const edges = tree_edges[nk].edges; - const degree = edges.length; - const visible_e = visible_edges(diagram, edge, dir, nk); - const shown = new Set(visible_e.map(e => diagram.edgeKey.eval(e))); - const invis = edges.filter(function(e) { return !shown.has(diagram.edgeKey()(e)); }); - spikes = invis.map(e => ({pe: e, children: []})); - if(degree - visible_e.length !== spikes.length) { - console.log('number of stubs', spikes.length, 'does not equal degree - visible edges', degree - visible_e.length); - debugger; - } - } - const spikeses = {}; - if(dir == 'both' && dc_graph.engines.is_directed(diagram.layoutEngine().layoutAlgorithm())) { - spikeses.in = []; - spikeses.out = []; - spikes.forEach(spk => { - if(diagram.edgeSource()(spk.pe) === nk) - spikeses.out.push(spk); - else { - console.assert(diagram.edgeTarget()(spk.pe) === nk); - spikeses.in.push(spk); - } - }); - } - else spikeses[dir] = spikes; - spikeseses[nk] = spikeses; - }); - draw_stubs(diagram, node, edge, n, spikeseses); - var collapse_nodes_set = {}, collapse_edges_set = {}; - if(_expanded[dir].has(nk)) { - // collapse - const will_change = Object.keys(tree_edges).flatMap(nk => _expanded[dir].has(nk) ? [nk] : []); - _changing = Object.fromEntries(will_change.map(nk => [nk, {dir, whether: false}])); - if(options.collapsibles) { - var clps = options.collapsibles(will_change, dir); - collapse_nodes_set = clps.nodes; - collapse_edges_set = clps.edges; - } - changing_highlight_group.highlight(Object.fromEntries(will_change.map(nk => [nk, true])), {}); - } else { - _changing = Object.fromEntries(Object.keys(tree_edges).map(nk => [nk, {dir, whether: true}])); - changing_highlight_group.highlight(Object.fromEntries(Object.keys(tree_edges).map(nk => [nk, true])), {}); - } - collapse_highlight_group.highlight(collapse_nodes_set, collapse_edges_set); - } - - function draw(diagram, node, edge, ehover) { - function over_node(n) { - var dir = zonedir(diagram, d3.event, options.dirs, n); - _overNode = n; - _overDir = dir; - if(_ignore && _ignore !== n) - _ignore = null; - if(_ignore) - return; - if(options.hideNode && detect_key(options.hideKey)) - highlight_hiding_node(diagram, n, edge); - else if(_mode.nodeURL.eval(_overNode) && detect_key(options.linkKey)) { - diagram.selectAllNodes() - .filter(function(n) { - return n === _overNode; - }).attr('cursor', 'pointer'); - diagram.requestRefresh(0); - } - else - highlight_expand_collapse(diagram, n, node, edge, dir, detect_key(options.recurseKey)); - } - function leave_node(n) { - diagram.selectAllNodes() - .filter(function(n) { - return n === _overNode; - }).attr('cursor', null); - _overNode = null; - _ignore = null; - clear_stubs(diagram, node, edge); - _changing = null; - changing_highlight_group.highlight({}, {}); - collapse_highlight_group.highlight({}, {}); - hide_highlight_group.highlight({}, {}); - } - function click_node(n) { - var nk = diagram.nodeKey.eval(n); - if(options.hideNode && detect_key(options.hideKey)) - options.hideNode(nk); - else if(detect_key(options.linkKey)) { - if(_mode.nodeURL.eval(n) && _mode.urlOpener) - _mode.urlOpener()(_mode, n, _mode.nodeURL.eval(n)); - } else { - clear_stubs(diagram, node, edge); - _ignore = n; - _changing = null; - changing_highlight_group.highlight({}, {}); - var dir = zonedir(diagram, d3.event, options.dirs, n); - let tree_nodes = [nk]; - if(detect_key(options.recurseKey) && options.get_tree_edges) - tree_nodes = Object.keys(options.get_tree_edges(nk, dir)); - expand(dir, tree_nodes, !_expanded[dir].has(nk)); - } - } - - function enter_edge(e) { - _overEdge = e; - if(options.hideEdge && detect_key(options.hideKey)) - highlight_hiding_edge(diagram, e); - } - function leave_edge(e) { - _overEdge = null; - hide_highlight_group.highlight({}, {}); - } - function click_edge(e) { - if(options.hideEdge && detect_key(options.hideKey)) - options.hideEdge(diagram.edgeKey.eval(e)); - } - - node - .on('mouseenter.expand-collapse', over_node) - .on('mousemove.expand-collapse', over_node) - .on('mouseout.expand-collapse', leave_node) - .on('click.expand-collapse', click_node) - .on('dblclick.expand-collapse', click_node); - - ehover - .on('mouseenter.expand-collapse', enter_edge) - .on('mouseout.expand-collapse', leave_edge) - .on('click.expand-collapse', click_edge); - - _keyboard - .on('keydown.expand-collapse', function() { - if(d3.event.key === options.hideKey && (_overNode && options.hideNode || _overEdge && options.hideEdge)) { - if(_overNode) - highlight_hiding_node(diagram, _overNode, edge); - if(_overEdge) - highlight_hiding_edge(diagram, _overEdge); - clear_stubs(diagram, node, edge); - _changing = null; - changing_highlight_group.highlight({}, {}); - collapse_highlight_group.highlight({}, {}); - } - else if(d3.event.key === options.linkKey && _overNode) { - if(_overNode && _mode.nodeURL.eval(_overNode)) { - diagram.selectAllNodes() - .filter(function(n) { - return n === _overNode; - }).attr('cursor', 'pointer'); - } - hide_highlight_group.highlight({}, {}); - clear_stubs(diagram, node, edge); - collapse_highlight_group.highlight({}, {}); - } - else if(d3.event.key === options.recurseKey && _overNode) { - highlight_expand_collapse(diagram, _overNode, node, edge, _overDir, true); - } - }) - .on('keyup.expand_collapse', function() { - if((d3.event.key === options.hideKey || d3.event.key === options.linkKey || d3.event.key === options.recurseKey) && (_overNode || _overEdge)) { - hide_highlight_group.highlight({}, {}); - if(_overNode) { - highlight_expand_collapse(diagram, _overNode, node, edge, _overDir, detect_key(options.recurseKey)); - if(_mode.nodeURL.eval(_overNode)) { - diagram.selectAllNodes() - .filter(function(n) { - return n === _overNode; - }).attr('cursor', null); - } - } - } - }); - diagram.cascade(97, true, conditional_properties( - function(n) { - return n === _overNode && n.orig.value.value && n.orig.value.value.URL; - }, - { - nodeLabelDecoration: 'underline' - } - )); - } - - function remove(diagram, node, edge, ehover) { - node - .on('mouseenter.expand-collapse', null) - .on('mousemove.expand-collapse', null) - .on('mouseout.expand-collapse', null) - .on('click.expand-collapse', null) - .on('dblclick.expand-collapse', null); - ehover - .on('mouseenter.expand-collapse', null) - .on('mouseout.expand-collapse', null) - .on('click.expand-collapse', null); - clear_stubs(diagram, node, edge); - } - - function expand(dir, nks, whether) { - nks.forEach(nk => { - if(dir === 'both' && !_expanded.both) - options.dirs.forEach(function(dir2) { - if(whether) - _expanded[dir2].add(nk); - else - _expanded[dir2].delete(nk); - }); - else if(whether) - _expanded[dir].add(nk); - else - _expanded[dir].delete(nk); - }); - var bothmap; - if(_expanded.both) - bothmap = Object.fromEntries( - Array.from(_expanded.both, nk => [nk, true])); - else { - bothmap = Object.fromEntries( - [..._expanded.in, ..._expanded.out] - .map(nk => [nk, true])); - } - expanded_highlight_group.highlight(bothmap, {}); - options.refresh(); - } - - function expandNodes(nks, dir) { - if(!Array.isArray(nks)) { - Object.keys(nks).forEach(dir => { - _expanded[dir] = new Set(nks[dir]); - }); - } else { - var expset = new Set(nks); - const dirs = dir == 'both' ? options.dirs : [dir]; - dirs.forEach(dir => { - _expanded[dir] = new Set(expset); - }); - } - const mm = Object.fromEntries( - Array.prototype.concat.apply([], Object.keys(_expanded).map(dir => Array.from(_expanded[dir]))) - .map(nk => [nk, true])); - expanded_highlight_group.highlight( - mm, - {}); - options.refresh(); - } - - function nodeOutlineClip(n) { - const dirs = _mode.expandedDirs(n.key); - if(dirs.length == 0) // changing from expanded to not - return 'none'; - if(dirs.length == 2 || dirs[0] == 'both') - return null; - switch(_mode.parent().layoutEngine().rankdir()) { - case 'TB': - return dirs[0] == 'in' ? 'top' : 'bottom'; - case 'BT': - return dirs[0] == 'in' ? 'bottom' : 'top'; - case 'LR': - return dirs[0] == 'in' ? 'left' : 'right'; - case 'RL': - return dirs[0] == 'in' ? 'right' : 'left'; - default: - throw new Error('unknown rankdir ' + mode.parent().layoutEngine().rankdir()); - } - } - - var _mode = dc_graph.mode('expand-collapse', { - draw: draw, - remove: remove, - parent: function(p) { - if(p) { - _keyboard = p.child('keyboard'); - if(!_keyboard) - p.child('keyboard', _keyboard = dc_graph.keyboard()); - const highlight_changing = p.child(options.highlight_changing || 'highlight-changing'); - highlight_changing.includeProps()['nodeOutlineClip'] = nodeOutlineClip; - const highlight_expanded = p.child(options.highlight_expanded || 'highlight-expanded'); - highlight_expanded.includeProps()['nodeOutlineClip'] = nodeOutlineClip; - } - } - }); - _mode.getExpanded = function() { - return _expanded; - }; - _mode.expandedDirs = function(nk) { - if(_expanded.both) - return _expanded.both.has(nk) || _changing && _changing[nk] ? ['both'] : []; - else { - const dirs = []; - let has_in = _expanded.in.has(nk); - if(_changing && _changing[nk] && _changing[nk].dir === 'in') - has_in = _changing[nk].whether; - if(has_in) - dirs.push('in'); - let has_out = _expanded.out.has(nk); - if(_changing && _changing[nk] && _changing[nk].dir === 'out') - has_out = _changing[nk].whether; - if(has_out) - dirs.push('out'); - return dirs; - } - }; - - _mode.expand = expand; - _mode.expandNodes = expandNodes; - _mode.clickableLinks = deprecated_property("warning - clickableLinks doesn't belong in collapse_expand and will be moved", false); - _mode.nodeURL = property(function(n) { - return n.value && n.value.value && n.value.value.URL; - }); - _mode.urlTargetWindow = property('dcgraphlink'); - _mode.urlOpener = property(dc_graph.expand_collapse.default_url_opener); - if(options.expandCollapse) - options.expandCollapse(_mode); - return _mode; -}; - -dc_graph.expand_collapse.default_url_opener = function(mode, node, url) { - window.open(mode.nodeURL.eval(node), mode.urlTargetWindow()); -}; - -dc_graph.expand_collapse.expanded_hidden = function(opts) { - var options = Object.assign({ - nodeKey: function(n) { return n.key; }, - edgeKey: function(e) { return e.key; }, - edgeSource: function(e) { return e.value.source; }, - edgeTarget: function(e) { return e.value.target; } - }, opts); - var _nodeHidden = {}, _edgeHidden = {}; - - // independent dimension on keys so that the diagram dimension will observe it - var _nodeDim = options.nodeCrossfilter.dimension(options.nodeKey), - _edgeDim = options.edgeCrossfilter && options.edgeCrossfilter.dimension(options.edgeRawKey); - - function get_shown(expanded) { - return Object.keys(expanded).reduce(function(p, dir) { - return Array.from(expanded[dir]).reduce(function(p, nk) { - p[nk] = true; - let list; - switch(dir) { - case 'in': - list = in_edges(nk).map(e => options.edgeSource(e)); - break; - case 'out': - list = out_edges(nk).map(e => options.edgeTarget(e)); - break; - case 'both': - list = adjacent_nodes(nk); - break; - } - list.forEach(function(nk2) { - if(!_nodeHidden[nk2]) - p[nk2] = true; - }); - return p; - }, p); - }, {}); - } - function apply_filter(ec) { - var _shown = get_shown(ec.getExpanded()); - _nodeDim.filterFunction(function(nk) { - return _shown[nk]; - }); - _edgeDim && _edgeDim.filterFunction(function(ek) { - return !_edgeHidden[ek]; - }); - } - function adjacent_edges(nk) { - return options.edgeGroup.all().filter(function(e) { - return options.edgeSource(e) === nk || options.edgeTarget(e) === nk; - }); - } - function out_edges(nk) { - return options.edgeGroup.all().filter(function(e) { - return options.edgeSource(e) === nk; - }); - } - function in_edges(nk) { - return options.edgeGroup.all().filter(function(e) { - return options.edgeTarget(e) === nk; - }); - } - const other_node = (e, nk) => - options.edgeSource(e) === nk ? options.edgeTarget(e) : options.edgeSource(e); - function adjacent_nodes(nk) { - return adjacent_edges(nk).map(e => other_node(e, nk)); - } - - const dfs_pre_order = (nk, seen, traverse, other, fall, funseen, pe = null, pres = null) => { - fall(pe, pres, nk); - if(seen.has(nk)) - return; - seen.add(nk); - const nres = funseen(pe, pres, nk); - for(const e of traverse(nk)) - dfs_pre_order(other(e, nk), seen, traverse, other, fall, funseen, e, nres); - }; - - var _strategy = { - get_edges: function(nk, dir) { - switch(dir) { - case 'in': - return in_edges(nk); - case 'out': - return out_edges(nk); - case 'both': - return adjacent_edges(nk); - default: - throw new Error(`unknown dir ${dir}`); - } - }, - get_tree_edges: (nk, dir, once = false) => { - const traverse = dir === 'in' ? in_edges : - dir === 'out' ? out_edges : - adjacent_edges; - const other = dir === 'in' ? options.edgeSource : - dir === 'out' ? options.edgeTarget : - other_node; - if(once) { - const edges = traverse(nk), - nks = edges.map(other); - return {[nk]: {edges, nks}}; - } - const nodes = {}, seen = new Set(); - dfs_pre_order(nk, seen, traverse, other, (pe, pres, nk) => { - if(pres) { - pres.edges.push(pe); - pres.nks.push(nk); - } - }, (pe, pres, nk) => { - return nodes[nk] = {edges: [], nks: []}; - }); - return nodes; - }, - partition_among_visible: (tree_edges, visible_nodes) => { - }, - refresh: function() { - apply_filter(_strategy.expandCollapse()); - dc.redrawAll(); - return this; - }, - collapsibles: function(nks, dir) { - const expanded = _strategy.expandCollapse().getExpanded(); - var whatif = structuredClone(expanded); - nks.forEach( - nk => whatif[dir].delete(nk) - ); - var shown = get_shown(expanded), would = get_shown(whatif); - var going = Object.keys(shown) - .filter(function(nk2) { return !would[nk2]; }) - .reduce(function(p, v) { - p[v] = true; - return p; - }, {}); - return { - nodes: going, - edges: options.edgeGroup.all().filter(function(e) { - return going[options.edgeSource(e)] || going[options.edgeTarget(e)]; - }).reduce(function(p, e) { - p[options.edgeKey(e)] = true; - return p; - }, {}) - }; - }, - hideNode: function(nk) { - _nodeHidden[nk] = true; - _strategy.expandCollapse().expand('both', [nk], false); - }, - hideEdge: function(ek) { - if(!options.edgeCrossfilter) - console.warn('expanded_hidden needs edgeCrossfilter to hide edges'); - _edgeHidden[ek] = true; - apply_filter(_strategy.expandCollapse()); - dc.redrawAll(); - }, - expandCollapse: property(null).react(function(ec) { - if(ec) - apply_filter(ec); - - }) - }; - if(options.directional) - _strategy.dirs = ['out', 'in']; - return _strategy; -}; - -dc_graph.draw_graphs = function(options) { - var select_nodes_group = dc_graph.select_things_group(options.select_nodes_group || 'select-nodes-group', 'select-nodes'), - select_edges_group = dc_graph.select_things_group(options.select_edges_group || 'select-edges-group', 'select-edges'), - label_nodes_group = dc_graph.label_things_group('label-nodes-group', 'label-nodes'), - label_edges_group = dc_graph.label_things_group('label-edges-group', 'label-edges'), - fix_nodes_group = dc_graph.fix_nodes_group('fix-nodes-group'); - var _nodeIdTag = options.idTag || 'id', - _edgeIdTag = options.edgeIdTag || _nodeIdTag, - _sourceTag = options.sourceTag || 'source', - _targetTag = options.targetTag || 'target', - _nodeLabelTag = options.labelTag || 'label', - _edgeLabelTag = options.edgeLabelTag || _nodeLabelTag; - - var _sourceDown = null, _targetMove = null, _targetValid = false, _edgeLayer = null, _hintData = [], _crossout; - - function update_hint() { - var data = _hintData.filter(function(h) { - return h.source && h.target; - }); - var line = _edgeLayer.selectAll('line.hint-edge').data(data); - line.exit().remove(); - line.enter().append('line') - .attr('class', 'hint-edge') - .style({ - fill: 'none', - stroke: 'black', - 'pointer-events': 'none' - }); - - line.attr({ - x1: function(n) { return n.source.x; }, - y1: function(n) { return n.source.y; }, - x2: function(n) { return n.target.x; }, - y2: function(n) { return n.target.y; } - }); - } - - function port_pos(p) { - var style = _mode.parent().portStyle(_mode.parent().portStyleName.eval(p)); - var pos = style.portPosition(p); - pos.x += p.node.cola.x; - pos.y += p.node.cola.y; - return pos; - } - - function update_crossout() { - var data; - if(_crossout) { - if(_mode.usePorts()) - data = [port_pos(_crossout)]; - else - data = [{x: _crossout.node.cola.x, y: _crossout.node.cola.y}]; - } - else data = []; - - var size = _mode.crossSize(), wid = _mode.crossWidth(); - var cross = _edgeLayer.selectAll('polygon.graph-draw-crossout').data(data); - cross.exit().remove(); - cross.enter().append('polygon') - .attr('class', 'graph-draw-crossout'); - cross - .attr('points', function(d) { - var x = d.x, y = d.y; - return [ - [x-size/2, y+size/2], [x-size/2+wid, y+size/2], [x, y+wid/2], - [x+size/2-wid, y+size/2], [x+size/2, y+size/2], [x+wid/2, y], - [x+size/2, y-size/2], [x+size/2-wid, y-size/2], [x, y-wid/2], - [x-size/2+wid, y-size/2], [x-size/2, y-size/2], [x-wid/2, y] - ] - .map(function(p) { return p.join(','); }) - .join(' '); - }); - } - function erase_hint() { - _hintData = []; - _targetValid = false; - _sourceDown = _targetMove = null; - update_hint(); - } - - function create_node(diagram, pos, data) { - if(!_mode.nodeCrossfilter()) - throw new Error('need nodeCrossfilter'); - var node, callback = _mode.addNode() || promise_identity; - if(data) - node = data; - else { - node = {}; - node[_nodeIdTag] = uuid(); - node[_nodeLabelTag] = ''; - } - if(pos) - fix_nodes_group.new_node(node[_nodeIdTag], node, {x: pos[0], y: pos[1]}); - callback(node).then(function(node2) { - if(!node2) - return; - _mode.nodeCrossfilter().add([node2]); - diagram.redrawGroup(); - select_nodes_group.set_changed([node2[_nodeIdTag]]); - }); - } - - function create_edge(diagram, source, target) { - if(!_mode.edgeCrossfilter()) - throw new Error('need edgeCrossfilter'); - var edge = {}, callback = _mode.addEdge() || promise_identity; - edge[_edgeIdTag] = uuid(); - edge[_edgeLabelTag] = ''; - if(_mode.conduct().detectReversedEdge && _mode.conduct().detectReversedEdge(edge, source.port, target.port)) { - edge[_sourceTag] = target.node.orig.key; - edge[_targetTag] = source.node.orig.key; - var t; - t = source; source = target; target = t; - } else { - edge[_sourceTag] = source.node.orig.key; - edge[_targetTag] = target.node.orig.key; - } - callback(edge, source.port, target.port).then(function(edge2) { - if(!edge2) - return; - fix_nodes_group.new_edge(edge[_edgeIdTag], edge2[_sourceTag], edge2[_targetTag]); - _mode.edgeCrossfilter().add([edge2]); - select_nodes_group.set_changed([], false); - select_edges_group.set_changed([edge2[_edgeIdTag]], false); - diagram.redrawGroup(); - }); - } - - function check_invalid_drag(coords) { - var msg; - if(!(d3.event.buttons & 1)) { - // mouse button was released but we missed it - _crossout = null; - if(_mode.conduct().cancelDragEdge) - _mode.conduct().cancelDragEdge(_sourceDown); - erase_hint(); - update_crossout(); - return true; - } - if(!_sourceDown.started && Math.hypot(coords[0] - _hintData[0].source.x, coords[1] - _hintData[0].source.y) > _mode.dragSize()) { - if(_mode.conduct().startDragEdge) { - if(_mode.conduct().startDragEdge(_sourceDown)) { - _sourceDown.started = true; - } else { - if(_mode.conduct().invalidSourceMessage) { - msg = _mode.conduct().invalidSourceMessage(_sourceDown); - console.log(msg); - if(options.negativeTip) { - options.negativeTip - .content(function(_, k) { k(msg); }) - .displayTip(_mode.usePorts() ? _sourceDown.port : _sourceDown.node); - } - } - erase_hint(); - return true; - } - } - } - return false; - } - - function draw(diagram, node, edge, ehover) { - var select_nodes = diagram.child('select-nodes'); - if(select_nodes) { - if(_mode.clickCreatesNodes()) - select_nodes.clickBackgroundClears(false); - } - node - .on('mousedown.draw-graphs', function(n) { - d3.event.stopPropagation(); - if(!_mode.dragCreatesEdges()) - return; - if(options.tipsDisable) - options.tipsDisable.forEach(function(tip) { - tip - .hideTip() - .disabled(true); - }); - if(_mode.usePorts()) { - var activePort; - if(typeof _mode.usePorts() === 'object' && _mode.usePorts().eventPort) - activePort = _mode.usePorts().eventPort(); - else activePort = diagram.getPort(diagram.nodeKey.eval(n), null, 'out') - || diagram.getPort(diagram.nodeKey.eval(n), null, 'in'); - if(!activePort) - return; - _sourceDown = {node: n, port: activePort}; - _hintData = [{source: port_pos(activePort)}]; - } else { - _sourceDown = {node: n}; - _hintData = [{source: {x: _sourceDown.node.cola.x, y: _sourceDown.node.cola.y}}]; - } - }) - .on('mousemove.draw-graphs', function(n) { - var msg; - d3.event.stopPropagation(); - if(_sourceDown) { - var coords = dc_graph.event_coords(diagram); - if(check_invalid_drag(coords)) - return; - var oldTarget = _targetMove; - if(n === _sourceDown.node) { - _mode.conduct().invalidTargetMessage && - console.log(_mode.conduct().invalidTargetMessage(_sourceDown, _sourceDown)); - _targetMove = null; - _hintData[0].target = null; - } - else if(_mode.usePorts()) { - var activePort; - if(typeof _mode.usePorts() === 'object' && _mode.usePorts().eventPort) - activePort = _mode.usePorts().eventPort(); - else activePort = diagram.getPort(diagram.nodeKey.eval(n), null, 'in') - || diagram.getPort(diagram.nodeKey.eval(n), null, 'out'); - if(activePort) - _targetMove = {node: n, port: activePort}; - else - _targetMove = null; - } else if(!_targetMove || n !== _targetMove.node) { - _targetMove = {node: n}; - } - if(_mode.conduct().changeDragTarget) { - var change; - if(_mode.usePorts()) { - var oldPort = oldTarget && oldTarget.port, - newPort = _targetMove && _targetMove.port; - change = oldPort !== newPort; - } else { - var oldNode = oldTarget && oldTarget.node, - newNode = _targetMove && _targetMove.node; - change = oldNode !== newNode; - } - if(change) - if(_mode.conduct().changeDragTarget(_sourceDown, _targetMove)) { - _crossout = null; - if(options.negativeTip) - options.negativeTip.hideTip(); - msg = _mode.conduct().validTargetMessage && _mode.conduct().validTargetMessage() || - 'matches'; - if(options.positiveTip) { - options.positiveTip - .content(function(_, k) { k(msg); }) - .displayTip(_mode.usePorts() ? _targetMove.port : _targetMove.node); - } - _targetValid = true; - } else { - _crossout = _mode.usePorts() ? - _targetMove && _targetMove.port : - _targetMove && _targetMove.node; - if(_targetMove && _mode.conduct().invalidTargetMessage) { - if(options.positiveTip) - options.positiveTip.hideTip(); - msg = _mode.conduct().invalidTargetMessage(_sourceDown, _targetMove); - console.log(msg); - if(options.negativeTip) { - options.negativeTip - .content(function(_, k) { k(msg); }) - .displayTip(_mode.usePorts() ? _targetMove.port : _targetMove.node); - } - } - _targetValid = false; - } - } else _targetValid = true; - if(_targetMove) { - if(_targetMove.port) - _hintData[0].target = port_pos(activePort); - else - _hintData[0].target = {x: n.cola.x, y: n.cola.y}; - } - else { - _hintData[0].target = {x: coords[0], y: coords[1]}; - } - update_hint(); - update_crossout(); - } - }) - .on('mouseup.draw-graphs', function(n) { - _crossout = null; - if(options.negativeTip) - options.negativeTip.hideTip(true); - if(options.positiveTip) - options.positiveTip.hideTip(true); - if(options.tipsDisable) - options.tipsDisable.forEach(function(tip) { - tip.disabled(false); - }); - // allow keyboard mode to hear this one (again, we need better cooperation) - // d3.event.stopPropagation(); - if(_sourceDown && _targetValid) { - var finishPromise; - if(_mode.conduct().finishDragEdge) - finishPromise = _mode.conduct().finishDragEdge(_sourceDown, _targetMove); - else finishPromise = Promise.resolve(true); - var source = _sourceDown, target = _targetMove; - finishPromise.then(function(ok) { - if(ok) - create_edge(diagram, source, target); - }); - } - else if(_sourceDown) { - if(_mode.conduct().cancelDragEdge) - _mode.conduct().cancelDragEdge(_sourceDown); - } - erase_hint(); - update_crossout(); - }); - diagram.svg() - .on('mousedown.draw-graphs', function() { - _sourceDown = null; - }) - .on('mousemove.draw-graphs', function() { - var data = []; - if(_sourceDown) { // drawing edge - var coords = dc_graph.event_coords(diagram); - _crossout = null; - if(check_invalid_drag(coords)) - return; - if(_mode.conduct().dragCanvas) - _mode.conduct().dragCanvas(_sourceDown, coords); - if(_mode.conduct().changeDragTarget && _targetMove) - _mode.conduct().changeDragTarget(_sourceDown, null); - _targetMove = null; - _hintData[0].target = {x: coords[0], y: coords[1]}; - update_hint(); - update_crossout(); - } - }) - .on('mouseup.draw-graphs', function() { - _crossout = null; - if(options.negativeTip) - options.negativeTip.hideTip(true); - if(options.positiveTip) - options.positiveTip.hideTip(true); - if(options.tipsDisable) - options.tipsDisable.forEach(function(tip) { - tip.disabled(false); - }); - if(_sourceDown) { // drag-edge - if(_mode.conduct().cancelDragEdge) - _mode.conduct().cancelDragEdge(_sourceDown); - erase_hint(); - } else { // click-node - if(d3.event.target === this && _mode.clickCreatesNodes()) - create_node(diagram, dc_graph.event_coords(diagram)); - } - update_crossout(); - }); - if(!_edgeLayer) - _edgeLayer = diagram.g().append('g').attr('class', 'draw-graphs'); - } - - function remove(diagram, node, edge, ehover) { - node - .on('mousedown.draw-graphs', null) - .on('mousemove.draw-graphs', null) - .on('mouseup.draw-graphs', null); - diagram.svg() - .on('mousedown.draw-graphs', null) - .on('mousemove.draw-graphs', null) - .on('mouseup.draw-graphs', null); - } - - var _mode = dc_graph.mode('highlight-paths', { - draw: draw, - remove: remove - }); - - // update the data source/destination - _mode.nodeCrossfilter = property(options.nodeCrossfilter); - _mode.edgeCrossfilter = property(options.edgeCrossfilter); - - // modeal options - _mode.usePorts = property(null); - _mode.clickCreatesNodes = property(true); - _mode.dragCreatesEdges = property(true); - _mode.dragSize = property(5); - - // draw attributes of indicator for failed edge - _mode.crossSize = property(15); - _mode.crossWidth = property(5); - - // really this is a behavior or strategy - _mode.conduct = property({}); - - // callbacks to modify data as it's being added - // as of 0.6, function returns a promise of the new data - _mode.addNode = property(null); // node -> promise(node2) - _mode.addEdge = property(null); // edge, sourceport, targetport -> promise(edge2) - - // or, if you want to drive.. - _mode.createNode = function(pos, data) { - create_node(_mode.parent(), pos, data); - }; - - return _mode; -}; - - -dc_graph.match_ports = function(diagram, symbolPorts) { - var _ports, _wports, _wedges, _validTargets; - diagram.on('data.match-ports', function(diagram, nodes, wnodes, edges, wedges, ports, wports) { - _ports = ports; - _wports = wports; - _wedges = wedges; - }); - diagram.on('transitionsStarted.match-ports', function() { - symbolPorts.enableHover(true); - }); - function change_state(ports, state) { - return ports.map(function(p) { - p.state = state; - return diagram.portNodeKey.eval(p); - }); - } - function reset_ports(source) { - var nids = change_state(_validTargets, 'small'); - source.port.state = 'small'; - nids.push(diagram.portNodeKey.eval(source.port)); - symbolPorts.animateNodes(nids); - } - function has_parallel(sourcePort, targetPort) { - return _wedges.some(function(e) { - return sourcePort.edges.indexOf(e) >= 0 && targetPort.edges.indexOf(e) >= 0; - }); - } - function is_valid(sourcePort, targetPort) { - return (_strategy.allowParallel() || !has_parallel(sourcePort, targetPort)) - && _strategy.isValid()(sourcePort, targetPort); - } - function why_invalid(sourcePort, targetPort) { - return !_strategy.allowParallel() && has_parallel(sourcePort, targetPort) && "can't connect two edges between the same two ports" || - _strategy.whyInvalid()(sourcePort, targetPort); - } - var _strategy = { - isValid: property(function(sourcePort, targetPort) { - return targetPort !== sourcePort && targetPort.name === sourcePort.name; - }), - whyInvalid: property(function(sourcePort, targetPort) { - return targetPort === sourcePort && "can't connect port to itself" || - targetPort.name !== sourcePort.name && "must connect ports of the same type"; - }), - allowParallel: property(false), - hoverPort: function(port) { - if(port) { - _validTargets = _wports.filter(is_valid.bind(null, port)); - if(_validTargets.length) - return change_state(_validTargets, 'shimmer-medium'); - } else if(_validTargets) - return change_state(_validTargets, 'small'); - return null; - }, - startDragEdge: function(source) { - _validTargets = _wports.filter(is_valid.bind(null, source.port)); - var nids = change_state(_validTargets, 'shimmer'); - if(_validTargets.length) { - symbolPorts.enableHover(false); - source.port.state = 'large'; - nids.push(diagram.portNodeKey.eval(source.port)); - symbolPorts.animateNodes(nids); - } - console.log('valid targets', nids); - return _validTargets.length !== 0; - }, - invalidSourceMessage: function(source) { - return "no valid matches for this port"; - }, - changeDragTarget: function(source, target) { - var nids, valid = target && is_valid(source.port, target.port), before; - if(valid) { - nids = change_state(_validTargets, 'small'); - target.port.state = 'large'; // it's one of the valid - } - else { - nids = change_state(_validTargets, 'small'); - before = symbolPorts.animateNodes(nids); - nids = change_state(_validTargets, 'shimmer'); - } - symbolPorts.animateNodes(nids, before); - return valid; - }, - validTargetMessage: function(source, target) { - return "it's a match!"; - }, - invalidTargetMessage: function(source, target) { - return why_invalid(source.port, target.port); - }, - finishDragEdge: function(source, target) { - symbolPorts.enableHover(true); - reset_ports(source); - return Promise.resolve(is_valid(source.port, target.port)); - }, - cancelDragEdge: function(source) { - symbolPorts.enableHover(true); - reset_ports(source); - return true; - } - }; - return _strategy; -}; - -dc_graph.match_opposites = function(diagram, deleteProps, options) { - options = Object.assign({ - multiplier: 2, - ease: d3.ease('cubic') - }, options); - var _ports, _wports, _wedges, _validTargets; - - diagram.cascade(100, true, multiply_properties(function(e) { - return options.ease(e.deleting || 0); - }, deleteProps, property_interpolate)); - diagram.on('data.match-opposites', function(diagram, nodes, wnodes, edges, wedges, ports, wports) { - _ports = ports; - _wports = wports; - _wedges = wedges; - }); - function port_pos(p) { - return { x: p.node.cola.x + p.pos.x, y: p.node.cola.y + p.pos.y }; - } - function is_valid(sourcePort, targetPort) { - return (_strategy.allowParallel() || !_wedges.some(function(e) { - return sourcePort.edges.indexOf(e) >= 0 && targetPort.edges.indexOf(e) >= 0; - })) && _strategy.isValid()(sourcePort, targetPort); - } - function reset_deletables(source, targets) { - targets.forEach(function(p) { - p.edges.forEach(function(e) { - e.deleting = 0; - }); - }); - if(source) - source.port.edges.forEach(function(e) { - e.deleting = 0; - }); - } - var _strategy = { - isValid: property(function(sourcePort, targetPort) { - // draw_graphs is already enforcing this, but this makes more sense and i use xor any chance i get - return (diagram.portName.eval(sourcePort) === 'in') ^ (diagram.portName.eval(targetPort) === 'in'); - }), - allowParallel: property(false), - hoverPort: function(port) { - // could be called by draw_graphs when node is hovered, isn't - }, - startDragEdge: function(source) { - _validTargets = _wports.filter(is_valid.bind(null, source.port)); - console.log('valid targets', _validTargets.map(diagram.portNodeKey.eval)); - return _validTargets.length !== 0; - }, - dragCanvas: function(source, coords) { - var closest = _validTargets.map(function(p) { - var ppos = port_pos(p); - return { - distance: Math.hypot(coords[0] - ppos.x, coords[1] - ppos.y), - port: p - }; - }).sort(function(a, b) { - return a.distance - b.distance; - }); - var cpos = port_pos(closest[0].port), spos = port_pos(source.port); - closest.forEach(function(c) { - c.port.edges.forEach(function(e) { - e.deleting = 1 - options.multiplier * c.distance / Math.hypot(cpos.x - spos.x, cpos.y - spos.y); - }); - }); - source.port.edges.forEach(function(e) { - e.deleting = 1 - options.multiplier * closest[0].distance / Math.hypot(cpos.x - spos.x, cpos.y - spos.y); - }); - diagram.requestRefresh(0); - }, - changeDragTarget: function(source, target) { - var valid = target && is_valid(source.port, target.port); - if(valid) { - target.port.edges.forEach(function(e) { - e.deleting = 1; - }); - source.port.edges.forEach(function(e) { - e.deleting = 1; - }); - reset_deletables(null, _validTargets.filter(function(p) { - return p !== target.port; - })); - diagram.requestRefresh(0); - } - return valid; - }, - finishDragEdge: function(source, target) { - if(is_valid(source.port, target.port)) { - reset_deletables(null, _validTargets.filter(function(p) { - return p !== target.port; - })); - if(options.delete_edges) { - var edgeKeys = source.port.edges.map(diagram.edgeKey.eval).concat(target.port.edges.map(diagram.edgeKey.eval)); - return options.delete_edges.deleteSelection(edgeKeys); - } - return Promise.resolve(true); - } - reset_deletables(source, _validTargets || []); - return Promise.resolve(false); - }, - cancelDragEdge: function(source) { - reset_deletables(source, _validTargets || []); - return true; - }, - detectReversedEdge: function(edge, sourcePort, targetPort) { - return diagram.portName.eval(sourcePort) === 'in'; - } - }; - return _strategy; -}; - -dc_graph.wildcard_ports = function(options) { - var diagram = options.diagram, - get_type = options.get_type || function(p) { return p.orig.value.type; }, - set_type = options.set_type || function(p, src) { p.orig.value.type = src.orig.value.type; }, - get_name = options.get_name || function(p) { return p.orig.value.name; }, - is_wild = options.is_wild || function(p) { return p.orig.value.wild; }, - update_ports = options.update_ports || function() {}, - get_linked = options.get_linked || function() { return []; }; - function linked_ports(n, port) { - if(!diagram) - return []; - var nid = diagram.nodeKey.eval(n); - var name = get_name(port); - var links = get_linked(n) || []; - var found = links.find(function(set) { - return set.includes(name); - }); - if(!found) return []; - return found.filter(function(link) { return link !== name; }).map(function(link) { - return diagram.getPort(nid, null, link); - }); - } - function no_edges(ports) { - return ports.every(function(lp) { - return lp.edges.length === 0; - }); - } - return { - isValid: function(p1, p2) { - return get_type(p1) === null ^ get_type(p2) === null || - get_type(p1) !== null && get_type(p1) === get_type(p2); - }, - whyInvalid: function(p1, p2) { - return get_type(p1) === null && get_type(p2) === null && "can't connect wildcard to wildcard" || - get_type(p1) !== get_type(p2) && "the types of ports must match"; - }, - copyLinked: function(n, port) { - linked_ports(n, port).forEach(function(lp) { - set_type(lp, port); - }); - }, - copyType: function(e, sport, tport) { - if(get_type(sport) === null) { - set_type(sport, tport); - this.copyLinked(sport.node, sport); - update_ports(); - } else if(get_type(tport) === null) { - set_type(tport, sport); - this.copyLinked(tport.node, tport); - update_ports(); - } - return Promise.resolve(e); - }, - resetTypes: function(edges) { - // backward compatibility: this used to take diagram as - // first arg, which was wrong - var dia = diagram; - if(arguments.length === 2) { - dia = arguments[0]; - edges = arguments[1]; - } - edges.forEach(function(eid) { - var e = dia.getWholeEdge(eid), - spname = dia.edgeSourcePortName.eval(e), - tpname = dia.edgeTargetPortName.eval(e); - var update = false; - var p = dia.getPort(dia.nodeKey.eval(e.source), null, spname); - var linked = linked_ports(e.source, p); - if(is_wild(p) && p.edges.length === 1 && no_edges(linked)) { - set_type(p, null); - linked.forEach(function(lp) { - set_type(lp, null); - update = true; - }); - } - p = dia.getPort(dia.nodeKey.eval(e.target), null, tpname); - linked = linked_ports(e.target, p); - if(is_wild(p) && p.edges.length === 1 && no_edges(linked)) { - set_type(p, null); - linked.forEach(function(lp) { - set_type(lp, null); - update = true; - }); - } - if(update) - update_ports(); - }); - return Promise.resolve(edges); - } - }; -}; - -dc_graph.symbol_port_style = function() { - var _style = {}; - var _nodePorts, _node; - var _drawConduct; - - _style.symbolScale = property(null); - _style.colorScale = property(d3.scale.ordinal().range( - // colorbrewer light qualitative scale - d3.shuffle(['#8dd3c7','#ffffb3','#bebada','#fb8072','#80b1d3','#fdb462', - '#b3de69','#fccde5','#d9d9d9','#bc80bd','#ccebc5','#ffed6f']))); - - function name_or_edge(p) { - return p.named ? p.name : _style.parent().edgeKey.eval(p.edges[0]); - } - _style.symbol = _style.portSymbol = property(name_or_edge, false); // non standard properties taking "outer datum" - _style.color = _style.portColor = property(name_or_edge, false); - _style.outline = property(dc_graph.symbol_port_style.outline.circle()); - _style.content = property(dc_graph.symbol_port_style.content.d3symbol()); - _style.smallRadius = _style.portRadius = property(7); - _style.mediumRadius = _style.portHoverNodeRadius = property(10); - _style.largeRadius = _style.portHoverPortRadius = property(14); - _style.displacement = _style.portDisplacement = property(2); - _style.outlineFillScale = _style.portBackgroundScale = property(null); - _style.outlineFill = _style.portBackgroundFill = property(null); - _style.outlineStroke = _style.portBackgroundStroke = property(null); - _style.outlineStrokeWidth = _style.portBackgroundStrokeWidth = property(null); - _style.padding = _style.portPadding = property(2); - _style.label = _style.portLabel = _style.portText = property(function(p) { - return p.name; - }); - _style.portLabelPadding = property({x: 5, y: 5}); - _style.cascade = cascade(_style); - - _style.portPosition = function(p) { - var l = Math.hypot(p.pos.x, p.pos.y), - u = {x: p.pos.x / l, y: p.pos.y / l}, - disp = _style.displacement.eval(p); - return {x: p.pos.x + disp * u.x, y: p.pos.y + disp * u.y}; - }; - - _style.portBounds = function(p) { - var R = _style.largeRadius.eval(p), - pos = _style.portPosition(p); - return { - left: pos.x - R/2, - top: pos.y - R/2, - right: pos.x + R/2, - bottom: pos.y + R/2 - }; - }; - - function symbol_fill(p) { - var symcolor = _style.color.eval(p); - return symcolor ? - (_style.colorScale() ? _style.colorScale()(symcolor) : symcolor) : - 'none'; - } - function port_transform(p) { - var pos = _style.portPosition(p); - return 'translate(' + pos.x + ',' + pos.y + ')'; - } - function port_symbol(p) { - if(!_style.symbolScale()) - _style.symbolScale(d3.scale.ordinal().range(d3.shuffle(_style.content().enum()))); - var symname = _style.symbol.eval(p); - return symname && (_style.symbolScale() ? _style.symbolScale()(symname) : symname); - } - function is_left(p) { - return p.vec[0] < 0; - } - function hover_radius(p) { - switch(p.state) { - case 'large': - return _style.largeRadius.eval(p); - case 'medium': - return _style.mediumRadius.eval(p); - case 'small': - default: - return _style.smallRadius.eval(p); - } - } - function shimmer_radius(p) { - return /-medium$/.test(p.state) ? - _style.mediumRadius.eval(p) : - _style.largeRadius.eval(p); - } - // fall back to node aesthetics if not defined for port - function outline_fill(p) { - var scale, fill; - if(_style.outlineFill.eval(p)) { - scale = _style.outlineFillScale() || identity; - fill = _style.outlineFill.eval(p); - } - else { - scale = _style.parent().nodeFillScale() || identity; - fill = _style.parent().nodeFill.eval(p.node); - } - return fill === 'none' ? 'none' : scale(fill); - } - function outline_stroke(p) { - return _style.outlineStroke.eval(p) || _style.parent().nodeStroke.eval(p.node); - } - function outline_stroke_width(p) { - var sw = _style.outlineStrokeWidth.eval(p); - return typeof sw === 'number' ? sw : _style.parent().nodeStrokeWidth.eval(p.node); - } - _style.animateNodes = function(nids, before) { - var setn = d3.set(nids); - var node = _node - .filter(function(n) { - return setn.has(_style.parent().nodeKey.eval(n)); - }); - var symbol = _style.parent().selectNodePortsOfStyle(node, _style.parent().portStyle.nameOf(this)); - var shimmer = symbol.filter(function(p) { return /^shimmer/.test(p.state); }), - nonshimmer = symbol.filter(function(p) { return !/^shimmer/.test(p.state); }); - if(shimmer.size()) { - if(before) - before.each('end', repeat); - else repeat(); - } - - function repeat() { - var shimin = shimmer.transition() - .duration(1000) - .ease("bounce"); - shimin.selectAll('.port-outline') - .call(_style.outline().draw(function(p) { - return shimmer_radius(p) + _style.portPadding.eval(p); - })); - shimin.selectAll('.port-symbol') - .call(_style.content().draw(port_symbol, shimmer_radius)); - var shimout = shimin.transition() - .duration(1000) - .ease('sin'); - shimout.selectAll('.port-outline') - .call(_style.outline().draw(function(p) { - return _style.smallRadius.eval(p) + _style.portPadding.eval(p); - })); - shimout.selectAll('.port-symbol') - .call(_style.content().draw(port_symbol, _style.smallRadius.eval)); - shimout.each("end", repeat); - } - - var trans = nonshimmer.transition() - .duration(250); - trans.selectAll('.port-outline') - .call(_style.outline().draw(function(p) { - return hover_radius(p) + _style.portPadding.eval(p); - })); - trans.selectAll('.port-symbol') - .call(_style.content().draw(port_symbol, hover_radius)); - - function text_showing(p) { - return p.state === 'large' || p.state === 'medium'; - } - trans.selectAll('text.port-label') - .attr({ - opacity: function(p) { - return text_showing(p) ? 1 : 0; - }, - 'pointer-events': function(p) { - return text_showing(p) ? 'auto' : 'none'; - } - }); - trans.selectAll('rect.port-label-background') - .attr('opacity', function(p) { - return text_showing(p) ? 1 : 0; - }); - // bring all nodes which have labels showing to the front - _node.filter(function(n) { - var ports = _nodePorts[_style.parent().nodeKey.eval(n)]; - return ports && ports.some(text_showing); - }).each(function() { - this.parentNode.appendChild(this); - }); - // bring all active ports to the front - symbol.filter(function(p) { - return p.state !== 'small'; - }).each(function() { - this.parentNode.appendChild(this); - }); - return trans; - }; - _style.eventPort = function() { - var parent = d3.select(d3.event.target.parentNode); - if(d3.event.target.parentNode.tagName === 'g' && parent.classed('port')) - return parent.datum(); - return null; - }; - _style.drawPorts = function(ports, nodePorts, node) { - _nodePorts = nodePorts; _node = node; - var port = ports.data(function(n) { - return nodePorts[_style.parent().nodeKey.eval(n)] || []; - }, name_or_edge); - port.exit().remove(); - var portEnter = port.enter().append('g') - .attr({ - class: 'port', - transform: port_transform - }); - port.transition('port-position') - .duration(_style.parent().stagedDuration()) - .delay(_style.parent().stagedDelay(false)) // need to account for enters as well - .attr({ - transform: port_transform - }); - - var outline = port.selectAll('.port-outline').data(function(p) { - return outline_fill(p) !== 'none' ? [p] : []; - }); - outline.exit().remove(); - var outlineEnter = outline.enter().append(_style.outline().tag()) - .attr({ - class: 'port-outline', - fill: outline_fill, - 'stroke-width': outline_stroke_width, - stroke: outline_stroke - }); - if(_style.outline().init) - outlineEnter.call(_style.outline().init); - outlineEnter - .call(_style.outline().draw(function(p) { - return _style.smallRadius.eval(p) + _style.portPadding.eval(p); - })); - // only position and size are animated (?) - anyway these are not on the node - // and they are typically used to indicate selection which should be fast - outline - .attr({ - fill: outline_fill, - 'stroke-width': outline_stroke_width, - stroke: outline_stroke - }); - outline.transition() - .duration(_style.parent().stagedDuration()) - .delay(_style.parent().stagedDelay(false)) // need to account for enters as well - .call(_style.outline().draw(function(p) { - return _style.smallRadius.eval(p) + _style.portPadding.eval(p); - })); - - var symbolEnter = portEnter.append(_style.content().tag()) - .attr('class', 'port-symbol') - .call(_style.content().draw(port_symbol, _style.smallRadius.eval)); - - var symbol = port.select('.port-symbol'); - symbol.attr('fill', symbol_fill); - symbol.transition() - .duration(_style.parent().stagedDuration()) - .delay(_style.parent().stagedDelay(false)) // need to account for enters as well - .call(_style.content().draw(port_symbol, _style.smallRadius.eval)); - - var label = port.selectAll('text.port-label').data(function(p) { - return _style.portLabel.eval(p) ? [p] : []; - }); - label.exit().remove(); - var labelEnter = label.enter(); - labelEnter.append('rect') - .attr({ - class: 'port-label-background', - 'pointer-events': 'none' - }); - labelEnter.append('text') - .attr({ - class: 'port-label', - 'dominant-baseline': 'middle', - 'pointer-events': 'none', - cursor: 'default', - opacity: 0 - }); - label - .each(function(p) { - p.offset = (is_left(p) ? -1 : 1) * (_style.largeRadius.eval(p) + _style.portPadding.eval(p)); - }) - .attr({ - 'text-anchor': function(p) { - return is_left(p) ? 'end' : 'start'; - }, - transform: function(p) { - return 'translate(' + p.offset + ',0)'; - } - }) - .text(_style.portLabel.eval) - .each(function(p) { - p.bbox = getBBoxNoThrow(this); - }); - port.selectAll('rect.port-label-background') - .attr({ - x: function(p) { - return (p.offset < 0 ? p.offset - p.bbox.width : p.offset) - _style.portLabelPadding.eval(p).x; - }, - y: function(p) { - return -p.bbox.height/2 - _style.portLabelPadding.eval(p).y; - }, - width: function(p) { - return p.bbox.width + 2*_style.portLabelPadding.eval(p).x; - }, - height: function(p) { - return p.bbox.height + 2*_style.portLabelPadding.eval(p).y; - }, - fill: 'white', - opacity: 0 - }); - return _style; - }; - - _style.enableHover = function(whether) { - if(!_drawConduct) { - if(_style.parent()) { - var draw = _style.parent().child('draw-graphs'); - if(draw) - _drawConduct = draw.conduct(); - } - } - var namespace = 'grow-ports-' + _style.parent().portStyle.nameOf(this); - if(whether) { - _node.on('mouseover.' + namespace, function(n) { - var nid = _style.parent().nodeKey.eval(n); - var activePort = _style.eventPort(); - if(_nodePorts[nid]) - _nodePorts[nid].forEach(function(p) { - p.state = p === activePort ? 'large' : activePort ? 'small' : 'medium'; - }); - var nids = _drawConduct && _drawConduct.hoverPort(activePort) || []; - nids.push(nid); - _style.animateNodes(nids); - }); - _node.on('mouseout.' + namespace, function(n) { - var nid = _style.parent().nodeKey.eval(n); - if(_nodePorts[nid]) - _nodePorts[nid].forEach(function(p) { - p.state = 'small'; - }); - var nids = _drawConduct && _drawConduct.hoverPort(null) || []; - nids.push(nid); - _style.animateNodes(nids); - }); - } else { - _node.on('mouseover.' + namespace, null); - _node.on('mouseout.' + namespace, null); - } - return _style; - }; - - _style.parent = property(null); - return _style; -}; - -dc_graph.symbol_port_style.outline = {}; -dc_graph.symbol_port_style.outline.circle = function() { - return { - tag: function() { - return 'circle'; - }, - draw: function(rf) { - return function(outlines) { - outlines.attr('r', function(p) { return rf(p); }); - }; - } - }; -}; -dc_graph.symbol_port_style.outline.square = function() { - return { - tag: function() { - return 'rect'; - }, - init: function(outlines) { - // crispEdges can make outline off-center from symbols - // outlines.attr('shape-rendering', 'crispEdges'); - }, - draw: function(rf) { - return function(outlines) { - outlines.attr({ - x: function(p) { return -rf(p); }, - y: function(p) { return -rf(p); }, - width: function(p) { return 2*rf(p); }, - height: function(p) { return 2*rf(p); } - }); - }; - } - }; -}; -dc_graph.symbol_port_style.outline.arrow = function() { - // offset needed for body in order to keep centroid at 0,0 - var left_portion = 3/4 - Math.PI/8; - var _outline = { - tag: function() { - return 'path'; - }, - init: function(outlines) { - //outlines.attr('shape-rendering', 'crispEdges'); - }, - draw: function(rf) { - return function(outlines) { - outlines.attr('d', function(p) { - var r = rf(p); - if(!_outline.outie() || _outline.outie()(p.orig)) - return 'M' + -left_portion*r + ',' + -r + ' h' + r + - ' l' + r + ',' + r + ' l' + -r + ',' + r + - ' h' + -r + - ' a' + r + ',' + r + ' 0 1,1 0,' + -2*r; - else - return 'M' + -(2-left_portion)*r + ',' + -r + ' h' + 2*r + - ' a' + r + ',' + r + ' 0 1,1 0,' + 2*r + - ' h' + -2*r + - ' l' + r + ',' + -r + ' l' + -r + ',' + -r; - }); - }; - }, - outie: property(null) - }; - return _outline; -}; - -dc_graph.symbol_port_style.content = {}; -dc_graph.symbol_port_style.content.d3symbol = function() { - var _symbol = { - tag: function() { - return 'path'; - }, - enum: function() { - return d3.svg.symbolTypes; - }, - draw: function(symf, rf) { - return function(symbols) { - symbols.attr('d', function(p) { - var sym = symf(p), r = rf(p); - return sym ? d3.svg.symbol() - .type(sym) - .size(r*r) - () : ''; - }); - symbols.attr('transform', function(p) { - switch(symf(p)) { - case 'triangle-up': - return 'translate(0, -1)'; - case 'triangle-down': - return 'translate(0, 1)'; - default: return null; - } - }); - }; - } - }; - return _symbol; -}; -dc_graph.symbol_port_style.content.letter = function() { - var _symbol = { - tag: function() { - return 'text'; - }, - enum: function() { - return d3.range(65, 91).map(String.fromCharCode); - }, - draw: function(symf, rf) { - return function(symbols) { - symbols.text(symf) - .attr({ - 'dominant-baseline': 'middle', - 'text-anchor': 'middle' - }); - symbols.each(function(p) { - if(!p.symbol_size) - p.symbol_size = getBBoxNoThrow(this); - }); - symbols.attr('transform', function(p) { - return 'scale(' + (2*rf(p)/p.symbol_size.height) + - ') translate(' + [0,2].join(',') + ')'; - }); - }; - } - }; - return _symbol; -}; - -function process_dot(callback, error, text) { - if(error) { - callback(error, null); - return; - } - var nodes, edges, node_cluster = {}, clusters = []; - if(graphlibDot.parse) { // graphlib-dot 1.1.0 (where did i get it from?) - var digraph = graphlibDot.parse(text); - - var nodeNames = digraph.nodes(); - nodes = new Array(nodeNames.length); - nodeNames.forEach(function (name, i) { - var node = nodes[i] = digraph._nodes[nodeNames[i]]; - node.id = i; - node.name = name; - }); - - var edgeNames = digraph.edges(); - edges = []; - edgeNames.forEach(function(e) { - var edge = digraph._edges[e]; - edges.push(Object.assign({}, edge.value, { - source: digraph._nodes[edge.u].id, - target: digraph._nodes[edge.v].id, - sourcename: edge.u, - targetname: edge.v - })); - }); - // TODO: if this version exists in the wild, look at how it does subgraphs/clusters - } else { // graphlib-dot 0.6 - digraph = graphlibDot.read(text); - - nodeNames = digraph.nodes(); - nodes = new Array(nodeNames.length); - nodeNames.forEach(function (name, i) { - var node = nodes[i] = digraph._nodes[nodeNames[i]]; - node.id = i; - node.name = name; - }); - - edges = []; - digraph.edges().forEach(function(e) { - edges.push(Object.assign({}, digraph.edge(e.v, e.w), { - source: digraph._nodes[e.v].id, - target: digraph._nodes[e.w].id, - sourcename: e.v, - targetname: e.w - })); - }); - - // iterative bfs for variety (recursion would work just as well) - var cluster_names = {}; - var queue = digraph.children().map(function(c) { return Object.assign({parent: null, key: c}, digraph.node(c)); }); - while(queue.length) { - var item = queue.shift(), - children = digraph.children(item.key); - if(children.length) { - clusters.push(item); - cluster_names[item.key] = true; - } - else - node_cluster[item.key] = item.parent; - queue = queue.concat(children.map(function(c) { return {parent: item.key, key: c}; })); - } - // clusters as nodes not currently supported - nodes = nodes.filter(function(n) { - return !cluster_names[n.name]; - }); - } - var graph = {nodes: nodes, links: edges, node_cluster: node_cluster, clusters: clusters}; - callback(null, graph); -} - -function process_dsv(callback, error, data) { - if(error) { - callback(error, null); - return; - } - var keys = Object.keys(data[0]); - var source = keys[0], target = keys[1]; - var nodes = d3.set(data.map(function(r) { return r[source]; })); - data.forEach(function(r) { - nodes.add(r[target]); - }); - nodes = nodes.values().map(function(k) { return {name: k}; }); - callback(null, { - nodes: nodes, - links: data.map(function(r, i) { - return { - key: i, - sourcename: r[source], - targetname: r[target] - }; - }) - }); -} - -dc_graph.file_formats = [ - { - exts: 'json', - mimes: 'application/json', - from_url: d3.json, - from_text: function(text, callback) { - callback(null, JSON.parse(text)); - } - }, - { - exts: ['gv', 'dot'], - mimes: 'text/vnd.graphviz', - from_url: function(url, callback) { - d3.text(url, process_dot.bind(null, callback)); - }, - from_text: function(text, callback) { - process_dot(callback, null, text); - } - }, - { - exts: 'psv', - mimes: 'text/psv', - from_url: function(url, callback) { - d3.dsv('|', 'text/plain')(url, process_dsv.bind(null, callback)); - }, - from_text: function(text, callback) { - process_dsv(callback, null, d3.dsv('|').parse(text)); - } - }, - { - exts: 'csv', - mimes: 'text/csv', - from_url: function(url, callback) { - d3.csv(url, process_dsv.bind(null, callback)); - }, - from_text: function(text, callback) { - process_dsv(callback, null, d3.csv.parse(text)); - } - } -]; - -dc_graph.match_file_format = function(filename) { - return dc_graph.file_formats.find(function(format) { - var exts = format.exts; - if(!Array.isArray(exts)) - exts = [exts]; - return exts.find(function(ext) { - return new RegExp('\.' + ext + '$').test(filename); - }); - }); -}; - -dc_graph.match_mime_type = function(mime) { - return dc_graph.file_formats.find(function(format) { - var mimes = format.mimes; - if(!Array.isArray(mimes)) - mimes = [mimes]; - return mimes.includes(mime); - }); -}; - -function unknown_format_error(filename) { - var spl = filename.split('.'); - if(spl.length) - return new Error('do not know how to process graph file extension ' + spl[spl.length-1]); - else - return new Error('need file extension to process graph file automatically, filename ' + filename); -} - -function unknown_mime_error(mime) { - return new Error('do not know how to process mime type ' + mime); -} - -// load a graph from various formats and return the data in consistent {nodes, links} format -dc_graph.load_graph = function() { - // ignore any query parameters for checking extension - function ignore_query(file) { - if(!file) - return null; - return file.replace(/\?.*/, ''); - } - var file1, file2, callback; - file1 = arguments[0]; - if(arguments.length===3) { - file2 = arguments[1]; - callback = arguments[2]; - } - else if(arguments.length===2) { - callback = arguments[1]; - } - else throw new Error('need two or three arguments'); - - if(file2) { - // this is not general - really titan-specific - queue() - .defer(d3.json, file1) - .defer(d3.json, file2) - .await(function(error, nodes, edges) { - if(error) - callback(error, null); - else - callback(null, {nodes: nodes.results, edges: edges.results}); - }); - } - else { - var format; - if(/^data:/.test(file1)) { - var parts = file1.slice(5).split(/,(.+)/); - format = dc_graph.match_mime_type(parts[0]); - if(format) - format.from_text(parts[1], callback); - else callback(unknown_mime_error(parts[0])); - } else { - var file1noq = ignore_query(file1); - format = dc_graph.match_file_format(file1noq); - if(format) - format.from_url(file1, callback); - else callback(unknown_format_error(file1noq)); - } - } -}; - -dc_graph.load_graph_text = function(text, filename, callback) { - var format = dc_graph.match_file_format(filename); - if(format) - format.from_text(text, callback); - else callback(unknown_format_error(filename)); -}; - -dc_graph.data_url = function(data) { - return 'data:application/json,' + JSON.stringify(data); -}; - -function can_get_graph_from_this(data) { - return (data.nodes || data.vertices) && (data.edges || data.links); -} - -// general-purpose reader of various json-based graph formats -// (esp but not limited to titan graph database-like formats) -// this could be generalized a lot -dc_graph.munge_graph = function(data, nodekeyattr, sourceattr, targetattr) { - // we want data = {nodes, edges} and the field names for keys; find those in common json formats - var nodes, edges, nka = nodekeyattr || "name", - sa = sourceattr || "sourcename", ta = targetattr || "targetname"; - - if(!can_get_graph_from_this(data)) { - var wrappers = ['database', 'response']; - var wi = wrappers.findIndex(function(f) { return data[f] && can_get_graph_from_this(data[f]); }); - if(wi<0) - throw new Error("couldn't find the data!"); - data = data[wrappers[wi]]; - } - edges = data.edges || data.links; - nodes = data.nodes || data.vertices; - - function find_attr(o, attrs) { - return attrs.filter(function(a) { return !!o[a]; }); - } - - //var edgekeyattr = "id"; - var edge0 = edges[0]; - if(edge0[sa] === undefined) { - var sourceattrs = sourceattr ? [sourceattr] : ['source_ecomp_uid', "node1", "source", "tail"], - targetattrs = targetattr ? [targetattr] : ['target_ecomp_uid', "node2", "target", "head"]; - //var edgekeyattrs = ['id', '_id', 'ecomp_uid']; - var edgewrappers = ['edge']; - if(edge0.node0 && edge0.node1) { // specific conflict here - sa = 'node0'; - ta = 'node1'; - } - else { - var candidates = find_attr(edge0, sourceattrs); - if(!candidates.length) { - wi = edgewrappers.findIndex(function(w) { - return edge0[w] && find_attr(edge0[w], sourceattrs).length; - }); - if(wi<0) { - if(sourceattr) - throw new Error('sourceattr ' + sa + " didn't work"); - else - throw new Error("didn't find any source attr"); - } - edges = edges.map(function(e) { return e[edgewrappers[wi]]; }); - edge0 = edges[0]; - candidates = find_attr(edge0, sourceattrs); - } - if(candidates.length > 1) - console.warn('found more than one possible source attr', candidates); - sa = candidates[0]; - - candidates = find_attr(edge0, targetattrs); - if(!candidates.length) { - if(targetattr && !edge0[targetattr]) - throw new Error('targetattr ' + ta + " didn't work"); - else - throw new Error("didn't find any target attr"); - } - if(candidates.length > 1) - console.warn('found more than one possible target attr', candidates); - ta = candidates[0]; - - /* - // we're currently assembling our own edgeid - candidates = find_attr(edge0, edgekeyattrs); - if(!candidates.length) - throw new Error("didn't find any edge key"); - if(candidates.length > 1) - console.warn('found more than one edge key attr', candidates); - edgekeyattr = candidates[0]; - */ - } - } - var node0 = nodes[0]; - if(node0[nka] === undefined) { - var nodekeyattrs = nodekeyattr ? [nodekeyattr] : ['ecomp_uid', 'id', '_id', 'key']; - var nodewrappers = ['vertex']; - candidates = find_attr(node0, nodekeyattrs); - if(!candidates.length) { - wi = nodewrappers.findIndex(function(w) { - return node0[w] && find_attr(node0[w], nodekeyattrs).length; - }); - if(wi<0) { - if(nodekeyattr) - throw new Error('nodekeyattr ' + nka + " didn't work"); - else - throw new Error("couldn't find the node data"); - } - nodes = nodes.map(function(n) { return n[nodewrappers[wi]]; }); - node0 = nodes[0]; - candidates = find_attr(node0, nodekeyattrs); - } - if(candidates.length > 1) - console.warn('found more than one possible node key attr', candidates); - nka = candidates[0]; - } - - return { - nodes: nodes, - edges: edges, - nodekeyattr: nka, - sourceattr: sa, - targetattr: ta - }; -} - -/** - * `dc_graph.flat_group` implements a - * ["fake crossfilter group"](https://github.com/dc-js/dc.js/wiki/FAQ#fake-groups) - * for the case of a group which is 1:1 with the rows of the data array. - * - * Although `dc_graph` can be used with aggregated or reduced data, typically the nodes and edges - * are rows of two data arrays, and each row has a column which contains the unique identifier for - * the node or edge. - * - * @namespace flat_group - * @memberof dc_graph - * @type {{}} -**/ - -dc_graph.flat_group = (function() { - var reduce_01 = { - add: function(p, v) { return v; }, - remove: function() { return null; }, - init: function() { return null; } - }; - // now we only really want to see the non-null values, so make a fake group - function non_null(group) { - return { - all: function() { - return group.all().filter(function(kv) { - return kv.value !== null; - }); - } - }; - } - - function dim_group(ndx, id_accessor) { - var dimension = ndx.dimension(id_accessor); - return { - crossfilter: ndx, - dimension: dimension, - group: non_null(dimension.group().reduce(reduce_01.add, - reduce_01.remove, - reduce_01.init)) - }; - } - - return { - /** - * Create a crossfilter, dimension, and flat group. Returns an object containing all three. - * - * 1. If `source` is an array, create a crossfilter from it. Otherwise assume it is a - * crossfilter instance. - * 2. Create a dimension on the crossfilter keyed by `id_accessor` - * 3. Create a group from the dimension, reducing to the row when it's filtered in, or - * `null` when it's out. - * 4. Wrap the group in a fake group which filters out the nulls. - * - * The resulting fake group's `.all()` method returns an array of the currently filtered-in - * `{key, value}` pairs where the key is `id_accessor(row)` and the value is the row. - * @method make - * @memberof dc_graph.flat_group - * @param {Array} source - the data array for crossfilter, or a crossfilter - * @param {Function} id_accessor - accessor function taking a row object and returning its - * unique identifier - * @return {Object} `{crossfilter, dimension, group}` - **/ - make: function(source, id_accessor) { - var cf; - if(Array.isArray(source)) - cf = crossfilter(source); - else cf = source; - return dim_group(cf, id_accessor); - }, - /** - * Create a flat dimension and group from an existing crossfilter. - * - * @method another - * @memberof dc_graph.flat_group - * @deprecated use .make() instead - * @param {Object} ndx - crossfilter instance - * @param {Function} id_accessor - accessor function taking a row object and returning its - * unique identifier - * @return {Object} `{crossfilter, dimension, group}` - **/ - another: deprecate_function('use .make() instead', function(cf, id_accessor) { - return this.make(cf, id_accessor); - }) - }; -})(); - - - -var convert_tree_helper = function(data, attrs, options, parent, level, inherit) { - level = level || 0; - if(attrs.length > (options.valuesByAttr ? 1 : 0)) { - var attr = attrs.shift(); - var nodes = [], edges = []; - var children = data.map(function(v) { - var key = v[options.nestKey]; - var childKey = options.nestKeysUnique ? key : uuid(); - if(childKey) { - var node; - if(options.ancestorKeys) { - inherit = inherit || {}; - if(attr) - inherit[attr] = key; - node = Object.assign({}, inherit); - } else node = {}; - node[options.nodeKey] = childKey; - if(options.label && options.labelFun) - node[options.label] = options.labelFun(key, attr, v); - if(options.level) - node[options.level] = level+1; - nodes.push(node); - if(parent) { - var edge = {}; - edge[options.edgeSource] = parent; - edge[options.edgeTarget] = childKey; - edges.push(edge); - } - } - var children = options.valuesByAttr ? v[attrs[0]] : v.values; - var recurse = convert_tree_helper(children, attrs.slice(0), options, - childKey, level+1, Object.assign({}, inherit)); - return recurse; - }); - return {nodes: Array.prototype.concat.apply(nodes, children.map(dc.pluck('nodes'))), - edges: Array.prototype.concat.apply(edges, children.map(dc.pluck('edges')))}; - } - else return {nodes: data.map(function(v) { - v = Object.assign({}, v); - if(options.level) - v[options.level] = level+1; - return v; - }), edges: data.map(function(v) { - var edge = {}; - edge[options.edgeSource] = parent; - edge[options.edgeTarget] = v[options.nodeKey]; - return edge; - })}; -}; - -dc_graph.convert_tree = function(data, attrs, options) { - options = Object.assign({ - nodeKey: 'key', - edgeKey: 'key', - edgeSource: 'sourcename', - edgeTarget: 'targetname', - nestKey: 'key' - }, options); - if(Array.isArray(data)) - return convert_tree_helper(data, attrs, options, options.root, 0, options.inherit); - else { - attrs = [''].concat(attrs); - return convert_tree_helper([data], attrs, options, options.root, 0, options.inherit); - } -}; - -dc_graph.convert_nest = function(nest, attrs, nodeKeyAttr, edgeSourceAttr, edgeTargetAttr, parent, inherit) { - return dc_graph.convert_tree(nest, attrs, { - nodeKey: nodeKeyAttr, - edgeSource: edgeSourceAttr, - edgeTarget: edgeTargetAttr, - root: parent, - inherit: inherit, - ancestorKeys: true, - label: 'name', - labelFun: function(key, attr, v) { return attr + ':' + key; }, - level: '_level' - }); -}; - -// https://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/ -var type_of = obj => ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase(); -var object_to_keyed_array = obj => Object.entries(obj).map(([key,value]) => ({key, ...value})); - -dc_graph.convert_adjacency_list = function(nodes, namesIn, namesOut) { - if(type_of(nodes) === 'object') { - var graph = namesIn.multipleGraphs ? Object.values(nodes)[0] : nodes; - nodes = object_to_keyed_array(graph); - } - const adjkey = namesIn.adjacencies || namesIn.revAdjacencies, - revadj = !namesIn.adjacencies; - if(!adjkey) - throw new Error('must specify namesIn.adjacencies or namesIn.revAdjacencies'); - var edges = Array.prototype.concat.apply([], nodes.map(function(n) { - return n[adjkey].map(function(adj) { - var e = {}; - if(namesOut.edgeKey) - e[namesOut.edgeKey] = uuid(); - e[namesOut.edgeSource] = n[namesIn.nodeKey]; - e[namesOut.edgeTarget] = (namesIn.targetKey ? adj[namesIn.targetKey] : adj).toString(); - if(revadj) - [e[namesOut.edgeSource], e[namesOut.edgeTarget]] = [e[namesOut.edgeTarget], e[namesOut.edgeSource]]; - if(namesOut.adjacency) - e[namesOut.adjacency] = adj; - return e; - }); - })); - return { - nodes, - edges, - nodekeyattr: namesIn.nodeKey, - sourceattr: namesOut.edgeSource, - targetattr: namesOut.edgeTarget - }; -}; - - -// collapse edges between same source and target -dc_graph.deparallelize = function(group, sourceTag, targetTag, options) { - options = options || {}; - var both = options.both || false, - reduce = options.reduce || null; - return { - all: function() { - var ST = {}; - group.all().forEach(function(kv) { - var source = kv.value[sourceTag], - target = kv.value[targetTag]; - var dir = both ? true : source < target; - var min = dir ? source : target, max = dir ? target : source; - ST[min] = ST[min] || {}; - var entry; - if(ST[min][max]) { - entry = ST[min][max]; - if(reduce) - entry.original = reduce(entry.original, kv); - } else ST[min][max] = entry = {in: 0, out: 0, original: Object.assign({}, kv)}; - if(dir) - ++entry.in; - else - ++entry.out; - }); - var ret = []; - Object.keys(ST).forEach(function(source) { - Object.keys(ST[source]).forEach(function(target) { - var entry = ST[source][target]; - entry[sourceTag] = source; - entry[targetTag] = target; - ret.push({key: entry.original.key, value: entry}); - }); - }); - return ret; - } - }; -}; - -dc_graph.path_reader = function(pathsgroup) { - var highlight_paths_group = dc_graph.register_highlight_paths_group(pathsgroup || 'highlight-paths-group'); - var _intervals, _intervalTree, _time; - - function register_path_objs(path, nop, eop) { - reader.elementList.eval(path).forEach(function(element) { - var key, paths; - switch(reader.elementType.eval(element)) { - case 'node': - key = reader.nodeKey.eval(element); - paths = nop[key] = nop[key] || []; - break; - case 'edge': - key = reader.edgeSource.eval(element) + '-' + reader.edgeTarget.eval(element); - paths = eop[key] = eop[key] || []; - break; - } - paths.push(path); - }); - } - - var reader = { - pathList: property(identity, false), - timeRange: property(null, false), - pathStrength: property(null, false), - elementList: property(identity, false), - elementType: property(null, false), - nodeKey: property(null, false), - edgeSource: property(null, false), - edgeTarget: property(null, false), - clear: function() { - highlight_paths_group.paths_changed({}, {}, []); - }, - data: function(data) { - var nop = {}, eop = {}, allpaths = [], has_ranges; - reader.pathList.eval(data).forEach(function(path) { - if((path._range = reader.timeRange.eval(path))) { // ugh modifying user data - if(has_ranges===false) - throw new Error("can't have a mix of ranged and non-ranged paths"); - has_ranges = true; - } else { - if(has_ranges===true) - throw new Error("can't have a mix of ranged and non-ranged paths"); - has_ranges = false; - register_path_objs(path, nop, eop); - } - allpaths.push(path); - }); - if(has_ranges) { - _intervals = allpaths.map(function(path) { - var interval = [path._range[0].getTime(), path._range[1].getTime()]; - interval.path = path; - return interval; - }); - // currently must include lysenko-interval-tree separately - _intervalTree = lysenkoIntervalTree(_intervals); - if(_time) - this.setTime(_time); - } else { - _intervals = null; - _intervalTree = null; - highlight_paths_group.paths_changed(nop, eop, allpaths); - } - }, - getIntervals: function() { - return _intervals; - }, - setTime: function(t) { - if(t && _intervalTree) { - var paths = [], nop = {}, eop = {}; - _intervalTree.queryPoint(t.getTime(), function(interval) { - paths.push(interval.path); - register_path_objs(interval.path, nop, eop); - }); - highlight_paths_group.paths_changed(nop, eop, paths); - } - _time = t; - } - }; - - return reader; -}; - - -dc_graph.path_selector = function(parent, reader, pathsgroup, chartgroup) { - var highlight_paths_group = dc_graph.register_highlight_paths_group(pathsgroup || 'highlight-paths-group'); - var root = d3.select(parent).append('svg'); - var paths_ = []; - var hovered = null, selected = null; - - // unfortunately these functions are copied from dc_graph.highlight_paths - function contains_path(paths) { - return function(path) { - return paths ? paths.indexOf(path)>=0 : false; - }; - } - - function doesnt_contain_path(paths) { - var cp = contains_path(paths); - return function(path) { - return !cp(path); - }; - } - - function toggle_paths(pathsA, pathsB) { - if(!pathsA) - return pathsB; - else if(!pathsB) - return pathsA; - if(pathsB.every(contains_path(pathsA))) - return pathsA.filter(doesnt_contain_path(pathsB)); - else return pathsA.concat(pathsB.filter(doesnt_contain_path(pathsA))); - } - - // this should use the whole cascading architecture - // and allow customization rather than hardcoding everything - // in fact, you can't even reliably overlap attributes without that (so we don't) - - function draw_paths(diagram, paths) { - if(paths.length === 0) return; - var xpadding = 30; - var space = 30; - var radius = 8; - // set the height of SVG accordingly - root.attr('height', 20*(paths.length+1)) - .attr('width', xpadding+(space+2*radius)*(paths.length/2+1)+20); - - root.selectAll('.path-selector').remove(); - - var pathlist = root.selectAll('g.path-selector').data(paths); - pathlist.enter() - .append('g') - .attr('class', 'path-selector') - .attr("transform", function(path, i) { return "translate(0, " + i*20 + ")"; }) - .each(function(path_data, i) { - var nodes = path_data.element_list.filter(function(d) { return d.element_type === 'node'; }); - // line - var line = d3.select(this).append('line'); - line.attr('x1', xpadding+space) - .attr('y1', radius+1) - .attr('x2', xpadding+space*nodes.length) - .attr('y2', radius+1) - .attr('opacity', 0.4) - .attr('stroke-width', 5) - .attr('stroke', '#bdbdbd'); - - // dots - var path = d3.select(this).selectAll('circle').data(nodes); - path.enter() - .append('circle') - .attr('cx', function(d, i) { return xpadding+space*(i+1); }) - .attr('cy', radius+1) - .attr('r', radius) - .attr('opacity', 0.4) - .attr('fill', function(d) { - // TODO path_selector shouldn't know the data structure of orignal node objects - var regeneratedNode = {key:d.property_map.ecomp_uid, value:d.property_map}; - return diagram.nodeStroke()(regeneratedNode); - }); - - // label - var text = d3.select(this).append('text'); - text.text('Path '+i) - .attr('class', 'path_label') - .attr('x', 0) - .attr('y', radius*1.7) - .on('mouseover.path-selector', function() { - highlight_paths_group.hover_changed([path_data]); - }) - .on('mouseout.path-selector', function() { - highlight_paths_group.hover_changed(null); - }) - .on('click.path-selector', function() { - highlight_paths_group.select_changed(toggle_paths(selected, [path_data])); - }); - }); - pathlist.exit().transition(1000).attr('opacity', 0).remove(); - } - - function draw_hovered() { - var is_hovered = contains_path(hovered); - root.selectAll('g.path-selector') - .each(function(d, i) { - var textColor = is_hovered(d) ? '#e41a1c' : 'black'; - var lineColor = is_hovered(d) ? 'black' : '#bdbdbd'; - var opacity = is_hovered(d) ? '1' : '0.4'; - d3.select(this).select('.path_label').attr('fill', textColor); - d3.select(this).selectAll('line') - .attr('stroke', lineColor) - .attr('opacity', opacity); - d3.select(this).selectAll('circle').attr('opacity', opacity); - }); - } - - function draw_selected() { - var is_selected = contains_path(selected); - root.selectAll('g.path-selector') - .each(function(d, i) { - var textWeight = is_selected(d) ? 'bold' : 'normal'; - var lineColor = is_selected(d) ? 'black' : '#bdbdbd'; - var opacity = is_selected(d) ? '1' : '0.4'; - d3.select(this).select('.path_label') - .attr('font-weight', textWeight); - d3.select(this).selectAll('line') - .attr('stroke', lineColor) - .attr('opacity', opacity); - d3.select(this).selectAll('circle').attr('opacity', opacity); - }); - } - - highlight_paths_group - .on('paths_changed.path-selector', function(nop, eop, paths) { - hovered = selected = null; - paths_ = paths; - selector.redraw(); - }) - .on('hover_changed.path-selector', function(hpaths) { - hovered = hpaths; - draw_hovered(); - }) - .on('select_changed.path-selector', function(spaths) { - selected = spaths; - draw_selected(); - }); - var selector = { - default_text: property('Nothing here'), - zero_text: property('No paths'), - error_text: property(null), - queried: property(false), - redraw: function() { - draw_paths(diagram, paths_); - draw_hovered(); - draw_selected(); - }, - render: function() { - this.redraw(); - return this; - } - }; - dc.registerChart(selector, chartgroup); - return selector; -}; - -dc_graph.node_name = function(i) { - // a-z, A-Z, aa-Zz, then quit - if(i<26) - return String.fromCharCode(97+i); - else if(i<52) - return String.fromCharCode(65+i-26); - else if(i<52*52) - return dc_graph.node_name(Math.floor(i/52)) + dc_graph.node_name(i%52); - else throw new Error("no, that's too large"); -}; -dc_graph.node_object = function(i, attrs) { - attrs = attrs || {}; - return _.extend({ - id: i, - name: dc_graph.node_name(i) - }, attrs); -}; - -dc_graph.edge_object = function(namef, i, j, attrs) { - attrs = attrs || {}; - return _.extend({ - source: i, - target: j, - sourcename: namef(i), - targetname: namef(j) - }, attrs); -}; - -dc_graph.generate = function(type, args, env, callback) { - var nodes, edges, i, j; - var nodePrefix = env.nodePrefix || ''; - var namef = function(i) { - return nodes[i].name; - }; - var N = args[0]; - var linkLength = env.linkLength || 30; - switch(type) { - case 'clique': - case 'cliquestf': - nodes = new Array(N); - edges = []; - for(i = 0; i 0) { - var choice = Math.random(); - var n1, n2; - if(!_nodes.length || choice < options.newComponentProb) { - n1 = new_node(); - N--; - } else - n1 = random_node(); - if(choice < options.newNodeProb) { - n2 = new_node(); - N--; - } else - n2 = random_node(); - if(n1 && n2) { - var edge = {}; - edge[options.edgeKey] = options.edgeKeyGen(_edges.length); - const sourceKey = n1[options.nodeKey], targetKey = n2[options.nodeKey]; - if(!options.allowParallelEdges) { - if(edgeInserted[sourceKey] && edgeInserted[sourceKey][targetKey]) - continue; - edgeInserted[sourceKey] = edgeInserted[sourceKey] || {} - edgeInserted[sourceKey][targetKey] = true; - } - edge[options.sourceKey] = sourceKey; - edge[options.targetKey] = targetKey; - edge[options.dashTag] = Math.floor(Math.random()*options.ndashes); - if(options.log) - console.log(n1[options.nodeKey] + ' -> ' + n2[options.nodeKey]); - _edges.push(edge); - } - } - }, - remove: function(N) { - while(N-- > 0) { - var choice = Math.random(); - if(choice < options.removeEdgeProb) - _edges.splice(Math.floor(Math.random()*_edges.length), 1); - else { - var n = _nodes[Math.floor(Math.random()*_nodes.length)]; - var eis = []; - _edges.forEach(function(e, ei) { - if(e[options.sourceKey] === n[options.nodeKey] || - e[options.targetKey] === n[options.nodeKey]) - eis.push(ei); - }); - eis.reverse().forEach(function(ei) { - _edges.splice(ei, 1); - }); - } - } - } - }; -}; - -dc_graph.supergraph = function(data, options) { - if(!dc_graph.supergraph.pattern) { - var mg = metagraph; - var graph_and_subgraph = { - nodes: { - graph: mg.graph_pattern(options), - sg: mg.subgraph_pattern(options), - subgraph: mg.graph_pattern(options) - }, - edges: { - to_sg: { - source: 'graph', - target: 'sg', - input: 'parent' - }, - from_sg: { - source: 'subgraph', - target: 'sg', - input: 'child' - } - } - }; - dc_graph.supergraph.pattern = mg.compose(mg.graph_detect(graph_and_subgraph)); - } - return dc_graph.supergraph.pattern.node('graph.Graph').value().create(data); -}; - -var dont_use_key = deprecation_warning('dc_graph.line_breaks now takes a string - d.key behavior is deprecated and will be removed in a later version'); - -dc_graph.line_breaks = function(charexp, max_line_length) { - var regexp = new RegExp(charexp, 'g'); - return function(s) { - if(typeof s === 'object') { // backward compatibility - dont_use_key(); - s = s.key; - } - var result; - var line = '', lines = [], part, i = 0; - do { - result = regexp.exec(s); - if(result) - part = s.slice(i, regexp.lastIndex); - else - part = s.slice(i); - if(line.length + part.length > max_line_length && line.length > 0) { - lines.push(line); - line = ''; - } - line += part; - i = regexp.lastIndex; - } - while(result !== null); - lines.push(line); - return lines; - }; -}; - -dc_graph.build_type_graph = function(nodes, edges, nkey, ntype, esource, etarget) { - var nmap = {}, tnodes = {}, tedges = {}; - nodes.forEach(function(n) { - nmap[nkey(n)] = n; - var t = ntype(n); - if(!tnodes[t]) - tnodes[t] = {type: t}; - }); - edges.forEach(function(e) { - var source = esource(e), target = etarget(e), sn, tn; - if(!(sn = nmap[source])) - throw new Error('source key ' + source + ' not found!'); - if(!(tn = nmap[target])) - throw new Error('target key ' + target + ' not found!'); - var etype = ntype(sn) + '/' + ntype(tn); - if(!tedges[etype]) - tedges[etype] = { - type: etype, - source: ntype(sn), - target: ntype(tn) - }; - }); - return { - nodes: Object.keys(tnodes).map(function(k) { return tnodes[k]; }), - edges: Object.keys(tedges).map(function(k) { return tedges[k]; }) - }; -} - -dc_graph.d3 = d3; -dc_graph.crossfilter = crossfilter; -dc_graph.dc = dc; - -return dc_graph; -} - if (typeof define === 'function' && define.amd) { - define(["d3", "crossfilter", "dc"], _dc_graph); - } else if (typeof module == "object" && module.exports) { - var _d3 = require('d3'); - var _crossfilter = require('crossfilter'); - if (typeof _crossfilter !== "function") { - _crossfilter = _crossfilter.crossfilter; - } - var _dc = require('dc'); - module.exports = _dc_graph(_d3, _crossfilter, _dc); - } else { - this.dc_graph = _dc_graph(d3, crossfilter, dc); - } -} -)(); - -//# sourceMappingURL=dc.graph.js.map \ No newline at end of file diff --git a/dc.graph.tracker.domain.js b/dc.graph.tracker.domain.js index 72ef7aab..070d9583 100644 --- a/dc.graph.tracker.domain.js +++ b/dc.graph.tracker.domain.js @@ -1,14 +1,15 @@ function dcgraph_domain(diagram, chartgroup) { return { on_exert: function(opt) { - if(opt.needs_relayout) + if (opt.needs_relayout) diagram.relayout(); - if(opt.needs_relayout || opt.needs_redraw) - if(opt.needs_redraw === 'refresh') + if (opt.needs_relayout || opt.needs_redraw) { + if (opt.needs_redraw === 'refresh') diagram.refresh(); else dc.redrawAll(chartgroup); - } + } + }, }; } @@ -16,13 +17,14 @@ function dcgraph_multi_domain(diagrams, chartgroup) { return { on_exert: function(opt) { var diagram = diagrams[opt.diagram]; - if(opt.needs_relayout) + if (opt.needs_relayout) diagram.relayout(); - if(opt.needs_relayout || opt.needs_redraw) - if(opt.needs_redraw === 'refresh') + if (opt.needs_relayout || opt.needs_redraw) { + if (opt.needs_redraw === 'refresh') diagram.refresh(); else dc.redrawAll(chartgroup); - } + } + }, }; } diff --git a/dprint.json b/dprint.json new file mode 100644 index 00000000..7ccbffb9 --- /dev/null +++ b/dprint.json @@ -0,0 +1,57 @@ +{ + "incremental": true, + "typescript": { + "lineWidth": 100, + "indentWidth": 4, + "useTabs": false, + "semiColons": "always", + "quoteStyle": "preferSingle", + "quoteProps": "preserve", + "newLineKind": "lf", + "useBraces": "maintain", + "bracePosition": "maintain", + "singleBodyPosition": "maintain", + "preferHanging": false, + "preferSingleLine": false, + "arrowFunction.useParentheses": "preferNone", + "binaryExpression.spaceSurroundingBitwiseAndArithmeticOperator": false, + "conditionalExpression.preferSingleLine": false, + "constructorType.spaceAfterNewKeyword": false, + "constructor.spaceBeforeParentheses": false, + "functionDeclaration.spaceBeforeParentheses": false, + "functionExpression.spaceBeforeParentheses": false, + "getAccessor.spaceBeforeParentheses": false, + "jsx.quoteStyle": "preferDouble", + "method.spaceBeforeParentheses": false, + "objectExpression.spaceSurroundingProperties": false, + "objectPattern.spaceSurroundingProperties": false, + "setAccessor.spaceBeforeParentheses": false, + "tupleType.preferSingleLine": false + }, + "json": { + "lineWidth": 100, + "indentWidth": 2, + "useTabs": false, + "newLineKind": "lf", + "preferSingleLine": false, + "array.preferSingleLine": false, + "object.preferSingleLine": false, + "commentLine.forceSpaceAfterSlashes": true, + "ignoreNodeCommentText": "dprint-ignore" + }, + "excludes": [ + "node_modules", + "dist", + "doc", + "web/js/viz.js", + "web/js/d3.js", + "web/js/d3.v3.js", + "web/js/dc.js", + "**/*.min.js", + "**/*.map" + ], + "plugins": [ + "https://plugins.dprint.dev/typescript-0.93.3.wasm", + "https://plugins.dprint.dev/json-0.19.4.wasm" + ] +} diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..45c017fb --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,116 @@ +import js from '@eslint/js'; + +export default [ + js.configs.recommended, + { + languageOptions: { + ecmaVersion: 2022, + sourceType: 'module', + globals: { + // Standard browser/Node.js globals + globalThis: 'readonly', + self: 'readonly', + console: 'readonly', + setTimeout: 'readonly', + clearTimeout: 'readonly', + setInterval: 'readonly', + clearInterval: 'readonly', + window: 'readonly', + navigator: 'readonly', + document: 'readonly', + structuredClone: 'readonly', + Worker: 'readonly', + URL: 'readonly', + SVGElement: 'readonly', + HTMLDivElement: 'readonly', + + // Web Worker globals + postMessage: 'readonly', + onmessage: 'writable', + importScripts: 'readonly', + + // Library-specific globals (consider migrating to imports) + THREE: 'readonly', + setcola: 'readonly', + Viz: 'readonly', + graphlibDot: 'readonly', + '_': 'readonly', + lysenkoIntervalTree: 'readonly', + metagraph: 'readonly', + computeLayout: 'readonly', + dc_graph: 'readonly', + }, + }, + rules: { + // Arrow function conversion rules + 'prefer-arrow-callback': ['error', { + allowNamedFunctions: false, + allowUnboundThis: true, + }], + 'arrow-body-style': ['error', 'as-needed'], + + // Modernization rules (auto-fixable) + 'prefer-const': 'error', + 'no-var': 'error', + 'prefer-object-has-own': 'error', + 'prefer-exponentiation-operator': 'error', + 'prefer-numeric-literals': 'error', + 'prefer-template': 'error', + 'object-shorthand': ['error', 'always'], + + // Unused variables - allow underscore prefix + 'no-unused-vars': ['warn', { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_', + }], + + // Relaxed rules for legacy code + 'no-undef': 'warn', + 'no-prototype-builtins': 'off', + }, + }, + { + files: ['web/**/*.js', 'examples/**/*.js'], + languageOptions: { + globals: { + d3: 'readonly', + dc: 'readonly', + dc_graph: 'readonly', + crossfilter: 'readonly', + cola: 'readonly', + window: 'readonly', + document: 'readonly', + navigator: 'readonly', + }, + }, + }, + { + files: ['**/*.worker.js', 'src/workers/**/*.js'], + languageOptions: { + globals: { + // Web worker specific globals + postMessage: 'readonly', + onmessage: 'writable', + importScripts: 'readonly', + self: 'readonly', + }, + }, + }, + { + files: ['*.config.js', 'scripts/**/*.js'], + languageOptions: { + globals: { + // Node.js globals + process: 'readonly', + Buffer: 'readonly', + __dirname: 'readonly', + __filename: 'readonly', + global: 'readonly', + module: 'readonly', + exports: 'readonly', + require: 'readonly', + }, + }, + }, +]; diff --git a/incrface-umd.js b/incrface-umd.js deleted file mode 100644 index 4dec06c2..00000000 --- a/incrface-umd.js +++ /dev/null @@ -1,1605 +0,0 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : - typeof define === 'function' && define.amd ? define(['exports'], factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.incrface = {})); -})(this, (function (exports) { 'use strict'; - - // @generated by Peggy 5.0.4. - // - // https://peggyjs.org/ - - - class peg$SyntaxError extends SyntaxError { - constructor(message, expected, found, location) { - super(message); - this.expected = expected; - this.found = found; - this.location = location; - this.name = "SyntaxError"; - } - - format(sources) { - let str = "Error: " + this.message; - if (this.location) { - let src = null; - const st = sources.find(s => s.source === this.location.source); - if (st) { - src = st.text.split(/\r\n|\n|\r/g); - } - const s = this.location.start; - const offset_s = (this.location.source && (typeof this.location.source.offset === "function")) - ? this.location.source.offset(s) - : s; - const loc = this.location.source + ":" + offset_s.line + ":" + offset_s.column; - if (src) { - const e = this.location.end; - const filler = "".padEnd(offset_s.line.toString().length, " "); - const line = src[s.line - 1]; - const last = s.line === e.line ? e.column : line.length + 1; - const hatLen = (last - s.column) || 1; - str += "\n --> " + loc + "\n" - + filler + " |\n" - + offset_s.line + " | " + line + "\n" - + filler + " | " + "".padEnd(s.column - 1, " ") - + "".padEnd(hatLen, "^"); - } else { - str += "\n at " + loc; - } - } - return str; - } - - static buildMessage(expected, found) { - function hex(ch) { - return ch.codePointAt(0).toString(16).toUpperCase(); - } - - const nonPrintable = Object.prototype.hasOwnProperty.call(RegExp.prototype, "unicode") - ? new RegExp("[\\p{C}\\p{Mn}\\p{Mc}]", "gu") - : null; - function unicodeEscape(s) { - if (nonPrintable) { - return s.replace(nonPrintable, ch => "\\u{" + hex(ch) + "}"); - } - return s; - } - - function literalEscape(s) { - return unicodeEscape(s - .replace(/\\/g, "\\\\") - .replace(/"/g, "\\\"") - .replace(/\0/g, "\\0") - .replace(/\t/g, "\\t") - .replace(/\n/g, "\\n") - .replace(/\r/g, "\\r") - .replace(/[\x00-\x0F]/g, ch => "\\x0" + hex(ch)) - .replace(/[\x10-\x1F\x7F-\x9F]/g, ch => "\\x" + hex(ch))); - } - - function classEscape(s) { - return unicodeEscape(s - .replace(/\\/g, "\\\\") - .replace(/\]/g, "\\]") - .replace(/\^/g, "\\^") - .replace(/-/g, "\\-") - .replace(/\0/g, "\\0") - .replace(/\t/g, "\\t") - .replace(/\n/g, "\\n") - .replace(/\r/g, "\\r") - .replace(/[\x00-\x0F]/g, ch => "\\x0" + hex(ch)) - .replace(/[\x10-\x1F\x7F-\x9F]/g, ch => "\\x" + hex(ch))); - } - - const DESCRIBE_EXPECTATION_FNS = { - literal(expectation) { - return "\"" + literalEscape(expectation.text) + "\""; - }, - - class(expectation) { - const escapedParts = expectation.parts.map( - part => (Array.isArray(part) - ? classEscape(part[0]) + "-" + classEscape(part[1]) - : classEscape(part)) - ); - - return "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]" + (expectation.unicode ? "u" : ""); - }, - - any() { - return "any character"; - }, - - end() { - return "end of input"; - }, - - other(expectation) { - return expectation.description; - }, - }; - - function describeExpectation(expectation) { - return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation); - } - - function describeExpected(expected) { - const descriptions = expected.map(describeExpectation); - descriptions.sort(); - - if (descriptions.length > 0) { - let j = 1; - for (let i = 1; i < descriptions.length; i++) { - if (descriptions[i - 1] !== descriptions[i]) { - descriptions[j] = descriptions[i]; - j++; - } - } - descriptions.length = j; - } - - switch (descriptions.length) { - case 1: - return descriptions[0]; - - case 2: - return descriptions[0] + " or " + descriptions[1]; - - default: - return descriptions.slice(0, -1).join(", ") - + ", or " - + descriptions[descriptions.length - 1]; - } - } - - function describeFound(found) { - return found ? "\"" + literalEscape(found) + "\"" : "end of input"; - } - - return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found."; - } - } - - function peg$parse(input, options) { - options = options !== undefined ? options : {}; - - const peg$FAILED = {}; - const peg$source = options.grammarSource; - - const peg$startRuleFunctions = { - commands: peg$parsecommands, - }; - let peg$startRuleFunction = peg$parsecommands; - - const peg$c0 = "."; - const peg$c1 = "\""; - const peg$c2 = "\\"; - const peg$c3 = "n"; - const peg$c4 = "t"; - const peg$c5 = "r"; - const peg$c6 = "open"; - const peg$c7 = "graph"; - const peg$c8 = "modify"; - const peg$c9 = "close"; - const peg$c10 = "pulse"; - const peg$c11 = "lock"; - const peg$c12 = "unlock"; - const peg$c13 = "insert"; - const peg$c14 = "node"; - const peg$c15 = "delete"; - const peg$c16 = "edge"; - const peg$c17 = "message"; - const peg$c18 = "["; - const peg$c19 = "]"; - const peg$c20 = ","; - const peg$c21 = "="; - - const peg$r0 = /^[0-9]/; - const peg$r1 = /^[A-Za-z_]/; - const peg$r2 = /^[0-9A-Z_a-z]/; - const peg$r3 = /^[\-]/; - const peg$r4 = /^[^"]/; - const peg$r5 = /^[ \t\n\r]/; - const peg$r6 = /^[\n\r]/; - - const peg$e0 = peg$classExpectation([["0", "9"]], false, false, false); - const peg$e1 = peg$classExpectation([["A", "Z"], ["a", "z"], "_"], false, false, false); - const peg$e2 = peg$classExpectation([["0", "9"], ["A", "Z"], "_", ["a", "z"]], false, false, false); - const peg$e3 = peg$classExpectation(["-"], false, false, false); - const peg$e4 = peg$literalExpectation(".", false); - const peg$e5 = peg$literalExpectation("\"", false); - const peg$e6 = peg$literalExpectation("\\", false); - const peg$e7 = peg$literalExpectation("n", false); - const peg$e8 = peg$literalExpectation("t", false); - const peg$e9 = peg$literalExpectation("r", false); - const peg$e10 = peg$classExpectation(["\""], true, false, false); - const peg$e11 = peg$classExpectation([" ", "\t", "\n", "\r"], false, false, false); - const peg$e12 = peg$classExpectation(["\n", "\r"], false, false, false); - const peg$e13 = peg$literalExpectation("open", false); - const peg$e14 = peg$literalExpectation("graph", false); - const peg$e15 = peg$literalExpectation("modify", false); - const peg$e16 = peg$literalExpectation("close", false); - const peg$e17 = peg$literalExpectation("pulse", false); - const peg$e18 = peg$literalExpectation("lock", false); - const peg$e19 = peg$literalExpectation("unlock", false); - const peg$e20 = peg$literalExpectation("insert", false); - const peg$e21 = peg$literalExpectation("node", false); - const peg$e22 = peg$literalExpectation("delete", false); - const peg$e23 = peg$literalExpectation("edge", false); - const peg$e24 = peg$literalExpectation("message", false); - const peg$e25 = peg$literalExpectation("[", false); - const peg$e26 = peg$literalExpectation("]", false); - const peg$e27 = peg$literalExpectation(",", false); - const peg$e28 = peg$literalExpectation("=", false); - - function peg$f0(a, b) { return a + b.join(''); } - function peg$f1(neg, num) { return (neg ? -1 : 1) * Number(num.flat(3).join('')); } - function peg$f2() { return '"'; } - function peg$f3() { return '\\'; } - function peg$f4() { return '\n'; } - function peg$f5() { return '\t'; } - function peg$f6() { return '\r'; } - function peg$f7(esc) { return esc; } - function peg$f8(char) { return char; } - function peg$f9(str) { return str.flat().join(''); } - function peg$f10(graph, attrs) { return {action: 'open', kind: 'graph', graph, attrs}; } - function peg$f11(graph, attrs) { return {action: 'modify', kind: 'graph', graph, attrs}; } - function peg$f12(graph) { return {action: 'close', kind: 'graph', graph}; } - function peg$f13(graph, attrs) { return {action: 'pulse', kind: 'graph', graph, attrs}; } - function peg$f14(graph) { return {action: 'lock', kind: 'graph', graph}; } - function peg$f15(graph) { return {action: 'unlock', kind: 'graph', graph}; } - function peg$f16(graph, node, attrs) { return {action: 'insert', kind: 'node', graph, node, attrs}; } - function peg$f17(graph, node, attrs) { return {action: 'modify', kind: 'node', graph, node, attrs}; } - function peg$f18(graph, node) { return {action: 'delete', kind: 'node', graph, node}; } - function peg$f19(graph, edge, source, target, attrs) { return {action: 'insert', kind: 'edge', graph, edge, source, target, attrs}; } - function peg$f20(graph, edge, attrs) { return {action: 'modify', kind: 'edge', graph, edge, attrs}; } - function peg$f21(graph, edge) { return {action: 'delete', kind: 'edge', graph, edge}; } - function peg$f22(message) { return {action: 'message', message}; } - function peg$f23(attrs) { return Object.fromEntries(attrs); } - function peg$f24() { return {}; } - function peg$f25(k, v) { return [k,v]; } - let peg$currPos = options.peg$currPos | 0; - const peg$posDetailsCache = [{ line: 1, column: 1 }]; - let peg$maxFailPos = peg$currPos; - let peg$maxFailExpected = options.peg$maxFailExpected || []; - let peg$silentFails = options.peg$silentFails | 0; - - let peg$result; - - if (options.startRule) { - if (!(options.startRule in peg$startRuleFunctions)) { - throw new Error("Can't start parsing from rule \"" + options.startRule + "\"."); - } - - peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; - } - - function peg$getUnicode(pos = peg$currPos) { - const cp = input.codePointAt(pos); - if (cp === undefined) { - return ""; - } - return String.fromCodePoint(cp); - } - - function peg$literalExpectation(text, ignoreCase) { - return { type: "literal", text, ignoreCase }; - } - - function peg$classExpectation(parts, inverted, ignoreCase, unicode) { - return { type: "class", parts, inverted, ignoreCase, unicode }; - } - - function peg$endExpectation() { - return { type: "end" }; - } - - function peg$computePosDetails(pos) { - let details = peg$posDetailsCache[pos]; - let p; - - if (details) { - return details; - } else { - if (pos >= peg$posDetailsCache.length) { - p = peg$posDetailsCache.length - 1; - } else { - p = pos; - while (!peg$posDetailsCache[--p]) {} - } - - details = peg$posDetailsCache[p]; - details = { - line: details.line, - column: details.column, - }; - - while (p < pos) { - if (input.charCodeAt(p) === 10) { - details.line++; - details.column = 1; - } else { - details.column++; - } - - p++; - } - - peg$posDetailsCache[pos] = details; - - return details; - } - } - - function peg$computeLocation(startPos, endPos, offset) { - const startPosDetails = peg$computePosDetails(startPos); - const endPosDetails = peg$computePosDetails(endPos); - - const res = { - source: peg$source, - start: { - offset: startPos, - line: startPosDetails.line, - column: startPosDetails.column, - }, - end: { - offset: endPos, - line: endPosDetails.line, - column: endPosDetails.column, - }, - }; - return res; - } - - function peg$fail(expected) { - if (peg$currPos < peg$maxFailPos) { return; } - - if (peg$currPos > peg$maxFailPos) { - peg$maxFailPos = peg$currPos; - peg$maxFailExpected = []; - } - - peg$maxFailExpected.push(expected); - } - - function peg$buildStructuredError(expected, found, location) { - return new peg$SyntaxError( - peg$SyntaxError.buildMessage(expected, found), - expected, - found, - location - ); - } - - function peg$parsecommands() { - let s0, s1; - - s0 = []; - s1 = peg$parsecommand(); - while (s1 !== peg$FAILED) { - s0.push(s1); - s1 = peg$parsecommand(); - } - - return s0; - } - - function peg$parsecommand() { - let s0; - - s0 = peg$parseopen_graph(); - if (s0 === peg$FAILED) { - s0 = peg$parseclose_graph(); - if (s0 === peg$FAILED) { - s0 = peg$parsemodify_graph(); - if (s0 === peg$FAILED) { - s0 = peg$parsepulse_graph(); - if (s0 === peg$FAILED) { - s0 = peg$parselock_graph(); - if (s0 === peg$FAILED) { - s0 = peg$parseunlock_graph(); - if (s0 === peg$FAILED) { - s0 = peg$parseinsert_node(); - if (s0 === peg$FAILED) { - s0 = peg$parsemodify_node(); - if (s0 === peg$FAILED) { - s0 = peg$parsedelete_node(); - if (s0 === peg$FAILED) { - s0 = peg$parseinsert_edge(); - if (s0 === peg$FAILED) { - s0 = peg$parsemodify_edge(); - if (s0 === peg$FAILED) { - s0 = peg$parsedelete_edge(); - if (s0 === peg$FAILED) { - s0 = peg$parsemessage(); - } - } - } - } - } - } - } - } - } - } - } - } - - return s0; - } - - function peg$parseDIGIT() { - let s0; - - s0 = input.charAt(peg$currPos); - if (peg$r0.test(s0)) { - peg$currPos++; - } else { - s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e0); } - } - - return s0; - } - - function peg$parseLETTER() { - let s0; - - s0 = input.charAt(peg$currPos); - if (peg$r1.test(s0)) { - peg$currPos++; - } else { - s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e1); } - } - - return s0; - } - - function peg$parseNAME() { - let s0, s1, s2, s3; - - s0 = peg$currPos; - s1 = peg$parseLETTER(); - if (s1 !== peg$FAILED) { - s2 = []; - s3 = input.charAt(peg$currPos); - if (peg$r2.test(s3)) { - peg$currPos++; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e2); } - } - while (s3 !== peg$FAILED) { - s2.push(s3); - s3 = input.charAt(peg$currPos); - if (peg$r2.test(s3)) { - peg$currPos++; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e2); } - } - } - s0 = peg$f0(s1, s2); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parseNUMBER() { - let s0, s1, s2, s3, s4, s5, s6, s7; - - s0 = peg$currPos; - s1 = input.charAt(peg$currPos); - if (peg$r3.test(s1)) { - peg$currPos++; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e3); } - } - if (s1 === peg$FAILED) { - s1 = null; - } - s2 = peg$currPos; - s3 = []; - s4 = peg$parseDIGIT(); - if (s4 !== peg$FAILED) { - while (s4 !== peg$FAILED) { - s3.push(s4); - s4 = peg$parseDIGIT(); - } - } else { - s3 = peg$FAILED; - } - if (s3 !== peg$FAILED) { - s4 = peg$currPos; - if (input.charCodeAt(peg$currPos) === 46) { - s5 = peg$c0; - peg$currPos++; - } else { - s5 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e4); } - } - if (s5 !== peg$FAILED) { - s6 = []; - s7 = peg$parseDIGIT(); - while (s7 !== peg$FAILED) { - s6.push(s7); - s7 = peg$parseDIGIT(); - } - s5 = [s5, s6]; - s4 = s5; - } else { - peg$currPos = s4; - s4 = peg$FAILED; - } - if (s4 === peg$FAILED) { - s4 = null; - } - s3 = [s3, s4]; - s2 = s3; - } else { - peg$currPos = s2; - s2 = peg$FAILED; - } - if (s2 === peg$FAILED) { - s2 = peg$currPos; - if (input.charCodeAt(peg$currPos) === 46) { - s3 = peg$c0; - peg$currPos++; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e4); } - } - if (s3 !== peg$FAILED) { - s4 = []; - s5 = peg$parseDIGIT(); - if (s5 !== peg$FAILED) { - while (s5 !== peg$FAILED) { - s4.push(s5); - s5 = peg$parseDIGIT(); - } - } else { - s4 = peg$FAILED; - } - if (s4 !== peg$FAILED) { - s3 = [s3, s4]; - s2 = s3; - } else { - peg$currPos = s2; - s2 = peg$FAILED; - } - } else { - peg$currPos = s2; - s2 = peg$FAILED; - } - } - if (s2 !== peg$FAILED) { - s0 = peg$f1(s1, s2); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parseESCAPED() { - let s0, s1; - - s0 = peg$currPos; - if (input.charCodeAt(peg$currPos) === 34) { - s1 = peg$c1; - peg$currPos++; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e5); } - } - if (s1 !== peg$FAILED) { - s1 = peg$f2(); - } - s0 = s1; - if (s0 === peg$FAILED) { - s0 = peg$currPos; - if (input.charCodeAt(peg$currPos) === 92) { - s1 = peg$c2; - peg$currPos++; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e6); } - } - if (s1 !== peg$FAILED) { - s1 = peg$f3(); - } - s0 = s1; - if (s0 === peg$FAILED) { - s0 = peg$currPos; - if (input.charCodeAt(peg$currPos) === 110) { - s1 = peg$c3; - peg$currPos++; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e7); } - } - if (s1 !== peg$FAILED) { - s1 = peg$f4(); - } - s0 = s1; - if (s0 === peg$FAILED) { - s0 = peg$currPos; - if (input.charCodeAt(peg$currPos) === 116) { - s1 = peg$c4; - peg$currPos++; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e8); } - } - if (s1 !== peg$FAILED) { - s1 = peg$f5(); - } - s0 = s1; - if (s0 === peg$FAILED) { - s0 = peg$currPos; - if (input.charCodeAt(peg$currPos) === 114) { - s1 = peg$c5; - peg$currPos++; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e9); } - } - if (s1 !== peg$FAILED) { - s1 = peg$f6(); - } - s0 = s1; - } - } - } - } - - return s0; - } - - function peg$parseSTRCHAR() { - let s0, s1, s2; - - s0 = peg$currPos; - if (input.charCodeAt(peg$currPos) === 92) { - s1 = peg$c2; - peg$currPos++; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e6); } - } - if (s1 !== peg$FAILED) { - s2 = peg$parseESCAPED(); - if (s2 !== peg$FAILED) { - s0 = peg$f7(s2); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - if (s0 === peg$FAILED) { - s0 = peg$currPos; - s1 = input.charAt(peg$currPos); - if (peg$r4.test(s1)) { - peg$currPos++; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e10); } - } - if (s1 !== peg$FAILED) { - s1 = peg$f8(s1); - } - s0 = s1; - } - - return s0; - } - - function peg$parseQSTRING() { - let s0, s1, s2, s3; - - s0 = peg$currPos; - if (input.charCodeAt(peg$currPos) === 34) { - s1 = peg$c1; - peg$currPos++; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e5); } - } - if (s1 !== peg$FAILED) { - s2 = []; - s3 = peg$parseSTRCHAR(); - while (s3 !== peg$FAILED) { - s2.push(s3); - s3 = peg$parseSTRCHAR(); - } - if (input.charCodeAt(peg$currPos) === 34) { - s3 = peg$c1; - peg$currPos++; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e5); } - } - if (s3 !== peg$FAILED) { - s0 = peg$f9(s2); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parseID() { - let s0; - - s0 = peg$parseNAME(); - if (s0 === peg$FAILED) { - s0 = peg$parseNUMBER(); - if (s0 === peg$FAILED) { - s0 = peg$parseQSTRING(); - } - } - - return s0; - } - - function peg$parse_() { - let s0, s1; - - peg$silentFails++; - s0 = []; - s1 = input.charAt(peg$currPos); - if (peg$r5.test(s1)) { - peg$currPos++; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e11); } - } - while (s1 !== peg$FAILED) { - s0.push(s1); - s1 = input.charAt(peg$currPos); - if (peg$r5.test(s1)) { - peg$currPos++; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e11); } - } - } - peg$silentFails--; - - return s0; - } - - function peg$parsecr() { - let s0, s1; - - s0 = []; - s1 = input.charAt(peg$currPos); - if (peg$r6.test(s1)) { - peg$currPos++; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e12); } - } - while (s1 !== peg$FAILED) { - s0.push(s1); - s1 = input.charAt(peg$currPos); - if (peg$r6.test(s1)) { - peg$currPos++; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e12); } - } - } - - return s0; - } - - function peg$parseopen_graph() { - let s0, s1, s3, s5, s7; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c6) { - s1 = peg$c6; - peg$currPos += 4; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e13); } - } - if (s1 !== peg$FAILED) { - peg$parse_(); - if (input.substr(peg$currPos, 5) === peg$c7) { - s3 = peg$c7; - peg$currPos += 5; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e14); } - } - if (s3 !== peg$FAILED) { - peg$parse_(); - s5 = peg$parseID(); - if (s5 !== peg$FAILED) { - peg$parse_(); - s7 = peg$parseattrlist(); - if (s7 !== peg$FAILED) { - peg$parsecr(); - s0 = peg$f10(s5, s7); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parsemodify_graph() { - let s0, s1, s3, s5, s7; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c8) { - s1 = peg$c8; - peg$currPos += 6; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e15); } - } - if (s1 !== peg$FAILED) { - peg$parse_(); - if (input.substr(peg$currPos, 5) === peg$c7) { - s3 = peg$c7; - peg$currPos += 5; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e14); } - } - if (s3 !== peg$FAILED) { - peg$parse_(); - s5 = peg$parseID(); - if (s5 !== peg$FAILED) { - peg$parse_(); - s7 = peg$parseattrlist(); - if (s7 !== peg$FAILED) { - peg$parsecr(); - s0 = peg$f11(s5, s7); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parseclose_graph() { - let s0, s1, s3, s5; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 5) === peg$c9) { - s1 = peg$c9; - peg$currPos += 5; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e16); } - } - if (s1 !== peg$FAILED) { - peg$parse_(); - if (input.substr(peg$currPos, 5) === peg$c7) { - s3 = peg$c7; - peg$currPos += 5; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e14); } - } - if (s3 !== peg$FAILED) { - peg$parse_(); - s5 = peg$parseID(); - if (s5 !== peg$FAILED) { - peg$parsecr(); - s0 = peg$f12(s5); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parsepulse_graph() { - let s0, s1, s3, s5, s7; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 5) === peg$c10) { - s1 = peg$c10; - peg$currPos += 5; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e17); } - } - if (s1 !== peg$FAILED) { - peg$parse_(); - if (input.substr(peg$currPos, 5) === peg$c7) { - s3 = peg$c7; - peg$currPos += 5; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e14); } - } - if (s3 !== peg$FAILED) { - peg$parse_(); - s5 = peg$parseID(); - if (s5 !== peg$FAILED) { - peg$parse_(); - s7 = peg$parseattrlist(); - if (s7 !== peg$FAILED) { - peg$parsecr(); - s0 = peg$f13(s5, s7); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parselock_graph() { - let s0, s1, s3, s5; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c11) { - s1 = peg$c11; - peg$currPos += 4; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e18); } - } - if (s1 !== peg$FAILED) { - peg$parse_(); - if (input.substr(peg$currPos, 5) === peg$c7) { - s3 = peg$c7; - peg$currPos += 5; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e14); } - } - if (s3 !== peg$FAILED) { - peg$parse_(); - s5 = peg$parseID(); - if (s5 !== peg$FAILED) { - peg$parsecr(); - s0 = peg$f14(s5); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parseunlock_graph() { - let s0, s1, s3, s5; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c12) { - s1 = peg$c12; - peg$currPos += 6; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e19); } - } - if (s1 !== peg$FAILED) { - peg$parse_(); - if (input.substr(peg$currPos, 5) === peg$c7) { - s3 = peg$c7; - peg$currPos += 5; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e14); } - } - if (s3 !== peg$FAILED) { - peg$parse_(); - s5 = peg$parseID(); - if (s5 !== peg$FAILED) { - peg$parsecr(); - s0 = peg$f15(s5); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parseinsert_node() { - let s0, s1, s3, s5, s7, s9; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c13) { - s1 = peg$c13; - peg$currPos += 6; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e20); } - } - if (s1 !== peg$FAILED) { - peg$parse_(); - if (input.substr(peg$currPos, 4) === peg$c14) { - s3 = peg$c14; - peg$currPos += 4; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e21); } - } - if (s3 !== peg$FAILED) { - peg$parse_(); - s5 = peg$parseID(); - if (s5 !== peg$FAILED) { - peg$parse_(); - s7 = peg$parseID(); - if (s7 !== peg$FAILED) { - peg$parse_(); - s9 = peg$parseattrlist(); - if (s9 !== peg$FAILED) { - peg$parsecr(); - s0 = peg$f16(s5, s7, s9); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parsemodify_node() { - let s0, s1, s3, s5, s7, s9; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c8) { - s1 = peg$c8; - peg$currPos += 6; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e15); } - } - if (s1 !== peg$FAILED) { - peg$parse_(); - if (input.substr(peg$currPos, 4) === peg$c14) { - s3 = peg$c14; - peg$currPos += 4; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e21); } - } - if (s3 !== peg$FAILED) { - peg$parse_(); - s5 = peg$parseID(); - if (s5 !== peg$FAILED) { - peg$parse_(); - s7 = peg$parseID(); - if (s7 !== peg$FAILED) { - peg$parse_(); - s9 = peg$parseattrlist(); - if (s9 !== peg$FAILED) { - peg$parsecr(); - s0 = peg$f17(s5, s7, s9); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parsedelete_node() { - let s0, s1, s3, s5, s7; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c15) { - s1 = peg$c15; - peg$currPos += 6; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e22); } - } - if (s1 !== peg$FAILED) { - peg$parse_(); - if (input.substr(peg$currPos, 4) === peg$c14) { - s3 = peg$c14; - peg$currPos += 4; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e21); } - } - if (s3 !== peg$FAILED) { - peg$parse_(); - s5 = peg$parseID(); - if (s5 !== peg$FAILED) { - peg$parse_(); - s7 = peg$parseID(); - if (s7 !== peg$FAILED) { - peg$parsecr(); - s0 = peg$f18(s5, s7); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parseinsert_edge() { - let s0, s1, s3, s5, s7, s9, s11, s13; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c13) { - s1 = peg$c13; - peg$currPos += 6; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e20); } - } - if (s1 !== peg$FAILED) { - peg$parse_(); - if (input.substr(peg$currPos, 4) === peg$c16) { - s3 = peg$c16; - peg$currPos += 4; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e23); } - } - if (s3 !== peg$FAILED) { - peg$parse_(); - s5 = peg$parseID(); - if (s5 !== peg$FAILED) { - peg$parse_(); - s7 = peg$parseID(); - if (s7 !== peg$FAILED) { - peg$parse_(); - s9 = peg$parseID(); - if (s9 !== peg$FAILED) { - peg$parse_(); - s11 = peg$parseID(); - if (s11 !== peg$FAILED) { - peg$parse_(); - s13 = peg$parseattrlist(); - if (s13 !== peg$FAILED) { - peg$parsecr(); - s0 = peg$f19(s5, s7, s9, s11, s13); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parsemodify_edge() { - let s0, s1, s3, s5, s7, s9; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c8) { - s1 = peg$c8; - peg$currPos += 6; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e15); } - } - if (s1 !== peg$FAILED) { - peg$parse_(); - if (input.substr(peg$currPos, 4) === peg$c16) { - s3 = peg$c16; - peg$currPos += 4; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e23); } - } - if (s3 !== peg$FAILED) { - peg$parse_(); - s5 = peg$parseID(); - if (s5 !== peg$FAILED) { - peg$parse_(); - s7 = peg$parseID(); - if (s7 !== peg$FAILED) { - peg$parse_(); - s9 = peg$parseattrlist(); - if (s9 !== peg$FAILED) { - peg$parsecr(); - s0 = peg$f20(s5, s7, s9); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parsedelete_edge() { - let s0, s1, s3, s5, s7; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 6) === peg$c15) { - s1 = peg$c15; - peg$currPos += 6; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e22); } - } - if (s1 !== peg$FAILED) { - peg$parse_(); - if (input.substr(peg$currPos, 4) === peg$c16) { - s3 = peg$c16; - peg$currPos += 4; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e23); } - } - if (s3 !== peg$FAILED) { - peg$parse_(); - s5 = peg$parseID(); - if (s5 !== peg$FAILED) { - peg$parse_(); - s7 = peg$parseID(); - if (s7 !== peg$FAILED) { - peg$parsecr(); - s0 = peg$f21(s5, s7); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parsemessage() { - let s0, s1, s3; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 7) === peg$c17) { - s1 = peg$c17; - peg$currPos += 7; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e24); } - } - if (s1 !== peg$FAILED) { - peg$parse_(); - s3 = peg$parseQSTRING(); - if (s3 !== peg$FAILED) { - s0 = peg$f22(s3); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - function peg$parseattrlist() { - let s0, s1, s2, s3; - - s0 = peg$currPos; - if (input.charCodeAt(peg$currPos) === 91) { - s1 = peg$c18; - peg$currPos++; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e25); } - } - if (s1 !== peg$FAILED) { - s2 = peg$parseattrdefs(); - if (input.charCodeAt(peg$currPos) === 93) { - s3 = peg$c19; - peg$currPos++; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e26); } - } - if (s3 !== peg$FAILED) { - s0 = peg$f23(s2); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - if (s0 === peg$FAILED) { - s0 = peg$currPos; - s1 = ''; - s1 = peg$f24(); - s0 = s1; - } - - return s0; - } - - function peg$parseattrdefs() { - let s0, s1, s2, s3, s4, s5; - - s0 = []; - s1 = peg$parseattritem(); - while (s1 !== peg$FAILED) { - s0.push(s1); - s1 = peg$currPos; - s2 = peg$currPos; - s3 = peg$parse_(); - if (input.charCodeAt(peg$currPos) === 44) { - s4 = peg$c20; - peg$currPos++; - } else { - s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e27); } - } - if (s4 !== peg$FAILED) { - s5 = peg$parse_(); - s3 = [s3, s4, s5]; - s2 = s3; - } else { - peg$currPos = s2; - s2 = peg$FAILED; - } - if (s2 !== peg$FAILED) { - s2 = peg$parseattritem(); - if (s2 === peg$FAILED) { - peg$currPos = s1; - s1 = peg$FAILED; - } else { - s1 = s2; - } - } else { - s1 = s2; - } - } - - return s0; - } - - function peg$parseattritem() { - let s0, s1, s3, s5; - - s0 = peg$currPos; - s1 = peg$parseID(); - if (s1 !== peg$FAILED) { - peg$parse_(); - if (input.charCodeAt(peg$currPos) === 61) { - s3 = peg$c21; - peg$currPos++; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e28); } - } - if (s3 !== peg$FAILED) { - peg$parse_(); - s5 = peg$parseID(); - if (s5 !== peg$FAILED) { - s0 = peg$f25(s1, s5); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - return s0; - } - - peg$result = peg$startRuleFunction(); - - const peg$success = (peg$result !== peg$FAILED && peg$currPos === input.length); - function peg$throw() { - if (peg$result !== peg$FAILED && peg$currPos < input.length) { - peg$fail(peg$endExpectation()); - } - - throw peg$buildStructuredError( - peg$maxFailExpected, - peg$maxFailPos < input.length ? peg$getUnicode(peg$maxFailPos) : null, - peg$maxFailPos < input.length - ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1) - : peg$computeLocation(peg$maxFailPos, peg$maxFailPos) - ); - } - if (options.peg$library) { - return /** @type {any} */ ({ - peg$result, - peg$currPos, - peg$FAILED, - peg$maxFailExpected, - peg$maxFailPos, - peg$success, - peg$throw: peg$success ? undefined : peg$throw, - }); - } - if (peg$success) { - return peg$result; - } else { - peg$throw(); - } - } - - const peg$allowedStartRules = [ - "commands" - ]; - - exports.StartRules = peg$allowedStartRules; - exports.SyntaxError = peg$SyntaxError; - exports.parse = peg$parse; - -})); diff --git a/incrface.rollup.config.js b/incrface.rollup.config.js deleted file mode 100644 index 18a283fe..00000000 --- a/incrface.rollup.config.js +++ /dev/null @@ -1,18 +0,0 @@ -import commonjs from '@rollup/plugin-commonjs'; -import nodeResolve from '@rollup/plugin-node-resolve'; - -export default { - input: "web/js/incrface.mjs", - output: { - name: "incrface", - file: "incrface-umd.js", - format: "umd" - }, - plugins: [ - nodeResolve({ - jsnext: true, - main: true - }), - commonjs() - ] -}; \ No newline at end of file diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 00000000..4f213766 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ES2020", + "moduleResolution": "node", + "allowJs": true, + "checkJs": false, + "baseUrl": ".", + "paths": { + "./dc-graph.js": ["./dist/dc-graph.js"], + "./js/dc-graph.js": ["./dist/dc-graph.js"] + }, + "lib": ["ES2020", "DOM"], + "allowSyntheticDefaultImports": true, + "esModuleInterop": true + }, + "include": [ + "src/**/*.js", + "web/js/**/*.js", + "dist/dc-graph.js", + "types/**/*.d.ts" + ], + "exclude": [ + "node_modules", + "web/docs", + "**/*.worker.js" + ] +} diff --git a/lysenko-interval-tree.js b/lysenko-interval-tree.js deleted file mode 100644 index 67d050ca..00000000 --- a/lysenko-interval-tree.js +++ /dev/null @@ -1,430 +0,0 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global.lysenkoIntervalTree = factory()); -}(this, (function () { 'use strict'; - -function compileSearch(funcName, predicate, reversed, extraArgs, useNdarray, earlyOut) { - var code = [ - "function ", funcName, "(a,l,h,", extraArgs.join(","), "){", -earlyOut ? "" : "var i=", (reversed ? "l-1" : "h+1"), -";while(l<=h){\ -var m=(l+h)>>>1,x=a", useNdarray ? ".get(m)" : "[m]"]; - if(earlyOut) { - if(predicate.indexOf("c") < 0) { - code.push(";if(x===y){return m}else if(x<=y){"); - } else { - code.push(";var p=c(x,y);if(p===0){return m}else if(p<=0){"); - } - } else { - code.push(";if(", predicate, "){i=m;"); - } - if(reversed) { - code.push("l=m+1}else{h=m-1}"); - } else { - code.push("h=m-1}else{l=m+1}"); - } - code.push("}"); - if(earlyOut) { - code.push("return -1};"); - } else { - code.push("return i};"); - } - return code.join("") -} - -function compileBoundsSearch(predicate, reversed, suffix, earlyOut) { - var result = new Function([ - compileSearch("A", "x" + predicate + "y", reversed, ["y"], false, earlyOut), - compileSearch("B", "x" + predicate + "y", reversed, ["y"], true, earlyOut), - compileSearch("P", "c(x,y)" + predicate + "0", reversed, ["y", "c"], false, earlyOut), - compileSearch("Q", "c(x,y)" + predicate + "0", reversed, ["y", "c"], true, earlyOut), -"function dispatchBsearch", suffix, "(a,y,c,l,h){\ -if(a.shape){\ -if(typeof(c)==='function'){\ -return Q(a,(l===undefined)?0:l|0,(h===undefined)?a.shape[0]-1:h|0,y,c)\ -}else{\ -return B(a,(c===undefined)?0:c|0,(l===undefined)?a.shape[0]-1:l|0,y)\ -}}else{\ -if(typeof(c)==='function'){\ -return P(a,(l===undefined)?0:l|0,(h===undefined)?a.length-1:h|0,y,c)\ -}else{\ -return A(a,(c===undefined)?0:c|0,(l===undefined)?a.length-1:l|0,y)\ -}}}\ -return dispatchBsearch", suffix].join("")); - return result() -} - -var searchBounds = { - ge: compileBoundsSearch(">=", false, "GE"), - gt: compileBoundsSearch(">", false, "GT"), - lt: compileBoundsSearch("<", true, "LT"), - le: compileBoundsSearch("<=", true, "LE"), - eq: compileBoundsSearch("-", true, "EQ", true) -}; - -var NOT_FOUND = 0; -var SUCCESS = 1; -var EMPTY = 2; - -var intervalTree = createWrapper; - -function IntervalTreeNode(mid, left, right, leftPoints, rightPoints) { - this.mid = mid; - this.left = left; - this.right = right; - this.leftPoints = leftPoints; - this.rightPoints = rightPoints; - this.count = (left ? left.count : 0) + (right ? right.count : 0) + leftPoints.length; -} - -var proto = IntervalTreeNode.prototype; - -function copy(a, b) { - a.mid = b.mid; - a.left = b.left; - a.right = b.right; - a.leftPoints = b.leftPoints; - a.rightPoints = b.rightPoints; - a.count = b.count; -} - -function rebuild(node, intervals) { - var ntree = createIntervalTree(intervals); - node.mid = ntree.mid; - node.left = ntree.left; - node.right = ntree.right; - node.leftPoints = ntree.leftPoints; - node.rightPoints = ntree.rightPoints; - node.count = ntree.count; -} - -function rebuildWithInterval(node, interval) { - var intervals = node.intervals([]); - intervals.push(interval); - rebuild(node, intervals); -} - -function rebuildWithoutInterval(node, interval) { - var intervals = node.intervals([]); - var idx = intervals.indexOf(interval); - if(idx < 0) { - return NOT_FOUND - } - intervals.splice(idx, 1); - rebuild(node, intervals); - return SUCCESS -} - -proto.intervals = function(result) { - result.push.apply(result, this.leftPoints); - if(this.left) { - this.left.intervals(result); - } - if(this.right) { - this.right.intervals(result); - } - return result -}; - -proto.insert = function(interval) { - var weight = this.count - this.leftPoints.length; - this.count += 1; - if(interval[1] < this.mid) { - if(this.left) { - if(4*(this.left.count+1) > 3*(weight+1)) { - rebuildWithInterval(this, interval); - } else { - this.left.insert(interval); - } - } else { - this.left = createIntervalTree([interval]); - } - } else if(interval[0] > this.mid) { - if(this.right) { - if(4*(this.right.count+1) > 3*(weight+1)) { - rebuildWithInterval(this, interval); - } else { - this.right.insert(interval); - } - } else { - this.right = createIntervalTree([interval]); - } - } else { - var l = searchBounds.ge(this.leftPoints, interval, compareBegin); - var r = searchBounds.ge(this.rightPoints, interval, compareEnd); - this.leftPoints.splice(l, 0, interval); - this.rightPoints.splice(r, 0, interval); - } -}; - -proto.remove = function(interval) { - var weight = this.count - this.leftPoints; - if(interval[1] < this.mid) { - if(!this.left) { - return NOT_FOUND - } - var rw = this.right ? this.right.count : 0; - if(4 * rw > 3 * (weight-1)) { - return rebuildWithoutInterval(this, interval) - } - var r = this.left.remove(interval); - if(r === EMPTY) { - this.left = null; - this.count -= 1; - return SUCCESS - } else if(r === SUCCESS) { - this.count -= 1; - } - return r - } else if(interval[0] > this.mid) { - if(!this.right) { - return NOT_FOUND - } - var lw = this.left ? this.left.count : 0; - if(4 * lw > 3 * (weight-1)) { - return rebuildWithoutInterval(this, interval) - } - var r = this.right.remove(interval); - if(r === EMPTY) { - this.right = null; - this.count -= 1; - return SUCCESS - } else if(r === SUCCESS) { - this.count -= 1; - } - return r - } else { - if(this.count === 1) { - if(this.leftPoints[0] === interval) { - return EMPTY - } else { - return NOT_FOUND - } - } - if(this.leftPoints.length === 1 && this.leftPoints[0] === interval) { - if(this.left && this.right) { - var p = this; - var n = this.left; - while(n.right) { - p = n; - n = n.right; - } - if(p === this) { - n.right = this.right; - } else { - var l = this.left; - var r = this.right; - p.count -= n.count; - p.right = n.left; - n.left = l; - n.right = r; - } - copy(this, n); - this.count = (this.left?this.left.count:0) + (this.right?this.right.count:0) + this.leftPoints.length; - } else if(this.left) { - copy(this, this.left); - } else { - copy(this, this.right); - } - return SUCCESS - } - for(var l = searchBounds.ge(this.leftPoints, interval, compareBegin); l=0 && arr[i][1] >= lo; --i) { - var r = cb(arr[i]); - if(r) { return r } - } -} - -function reportRange(arr, cb) { - for(var i=0; i this.mid) { - if(this.right) { - var r = this.right.queryPoint(x, cb); - if(r) { return r } - } - return reportRightRange(this.rightPoints, x, cb) - } else { - return reportRange(this.leftPoints, cb) - } -}; - -proto.queryInterval = function(lo, hi, cb) { - if(lo < this.mid && this.left) { - var r = this.left.queryInterval(lo, hi, cb); - if(r) { return r } - } - if(hi > this.mid && this.right) { - var r = this.right.queryInterval(lo, hi, cb); - if(r) { return r } - } - if(hi < this.mid) { - return reportLeftRange(this.leftPoints, hi, cb) - } else if(lo > this.mid) { - return reportRightRange(this.rightPoints, lo, cb) - } else { - return reportRange(this.leftPoints, cb) - } -}; - -function compareNumbers(a, b) { - return a - b -} - -function compareBegin(a, b) { - var d = a[0] - b[0]; - if(d) { return d } - return a[1] - b[1] -} - -function compareEnd(a, b) { - var d = a[1] - b[1]; - if(d) { return d } - return a[0] - b[0] -} - -function createIntervalTree(intervals) { - if(intervals.length === 0) { - return null - } - var pts = []; - for(var i=0; i>1]; - - var leftIntervals = []; - var rightIntervals = []; - var centerIntervals = []; - for(var i=0; i=6.0.0" } }, - "node_modules/@fortawesome/fontawesome-free": { - "version": "5.15.4", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.4.tgz", - "integrity": "sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg==", + "node_modules/@dprint/darwin-arm64": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/darwin-arm64/-/darwin-arm64-0.50.1.tgz", + "integrity": "sha512-NNKf3dxXn567pd/hpCVLHLbC0dI7s3YvQnUEwjRTOAQVMp6O7/ME+Tg1RPGsDP1IB+Y2fIYSM4qmG02zQrqjAQ==", + "cpu": [ + "arm64" + ], "dev": true, - "hasInstallScript": true, - "engines": { - "node": ">=6" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@jsdoc/salty": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.2.tgz", - "integrity": "sha512-A1FrVnc7L9qI2gUGsfN0trTiJNK72Y0CL/VAyrmYEmeKI3pnHDawP64CEev31XLyAAOx2xmDo3tbadPxC0CSbw==", + "node_modules/@dprint/darwin-x64": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/darwin-x64/-/darwin-x64-0.50.1.tgz", + "integrity": "sha512-PcY75U3UC/0CLOxWzE0zZJZ2PxzUM5AX2baYL1ovgDGCfqO1H0hINiyxfx/8ncGgPojWBkLs+zrcFiGnXx7BQg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "lodash": "^4.17.21" - }, - "engines": { - "node": ">=v12.0.0" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@ranfdev/deepobj": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@ranfdev/deepobj/-/deepobj-1.0.2.tgz", - "integrity": "sha512-FM3y6kfJaj5MCoAjdv24EDCTDbuFz+4+pgAunbjYfugwIE4O/xx8mPNji1n/ouG8pHCntSnBr1xwTOensF23Gg==" + "node_modules/@dprint/linux-arm64-glibc": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/linux-arm64-glibc/-/linux-arm64-glibc-0.50.1.tgz", + "integrity": "sha512-q0TOGy9FsoSKsEQ4sIMKyFweF5M8rW1S5OfwJDNRR2TU2riWByU9TKYIZUzg53iuwYKRypr/kJ5kdbl516afRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", - "dev": true + "node_modules/@dprint/linux-arm64-musl": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/linux-arm64-musl/-/linux-arm64-musl-0.50.1.tgz", + "integrity": "sha512-XRtxN2cA9rc06WFzzVPDIZYGGLmUXqpVf3F0XhhHV77ikQLJZ5reF4xBOQ+0HjJ/zy8W/HzuGDAHedWyCrRf9g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/linkify-it": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", - "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==", - "dev": true + "node_modules/@dprint/linux-riscv64-glibc": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/linux-riscv64-glibc/-/linux-riscv64-glibc-0.50.1.tgz", + "integrity": "sha512-vAk/eYhSjA3LJ/yuYgxkHamiK8+m6YdqVBO/Ka+i16VxyjQyOdcMKBkrLCIqSxgyXd6b8raf9wM59HJbaIpoOg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/markdown-it": { - "version": "12.2.3", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", - "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "node_modules/@dprint/linux-x64-glibc": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/linux-x64-glibc/-/linux-x64-glibc-0.50.1.tgz", + "integrity": "sha512-EpW5KLekaq4hXmKBWWtfBgZ244S4C+vFmMOd1YaGi8+f0hmPTJzVWLdIgpO2ZwfPQ5iycaVI/JS514PQmXPOvg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@types/linkify-it": "*", - "@types/mdurl": "*" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/mdurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", - "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", - "dev": true + "node_modules/@dprint/linux-x64-musl": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/linux-x64-musl/-/linux-x64-musl-0.50.1.tgz", + "integrity": "sha512-assISBbaKKL8LkjrIy/5tpE157MVW6HbyIKAjTtg3tPNM3lDn1oH3twuGtK9WBsN/VoEP3QMZVauolcUJT/VOg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "license": "ISC" + "node_modules/@dprint/win32-arm64": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/win32-arm64/-/win32-arm64-0.50.1.tgz", + "integrity": "sha512-ZeaRMQYoFjrsO3lvI1SqzDWDGH1GGXWmNSeXvcFuAf2OgYQJWMBlLotCKiHNJ3uyYneoyhTg2tv9QkApNkZV4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/accepts": { - "version": "1.3.5", + "node_modules/@dprint/win32-x64": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/win32-x64/-/win32-x64-0.50.1.tgz", + "integrity": "sha512-pMm8l/hRZ9zYylKw/yCaYkSV3btYB9UyMDbWqyxNthkQ1gckWrk17VTI6WjwwQuHD4Iaz5JgAYLS36hlUzWkxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, "license": "MIT", "dependencies": { - "mime-types": "~2.1.18", - "negotiator": "0.6.1" + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escape-sequences": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-4.1.0.tgz", - "integrity": "sha512-dzW9kHxH011uBsidTXd14JXgzye/YLb2LzeKZ4bsgl/Knwx8AtbSFkkGxagdNOoh0DlqHCmfiEjWKBaqjOanVw==", - "dev": true, - "dependencies": { - "array-back": "^3.0.1" + "url": "https://opencollective.com/eslint" }, - "engines": { - "node": ">=8.0.0" + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/ansi-escape-sequences/node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "license": "ISC" - }, - "node_modules/are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "license": "ISC", + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/@eslint/config-array/node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, + "license": "MIT", "dependencies": { - "sprintf-js": "~1.0.2" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/array-back": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", - "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=12.17" + "node": "*" } }, - "node_modules/array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "node_modules/@eslint/config-array/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "node_modules/@eslint/config-helpers": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=0.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "node_modules/@eslint/core": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, "license": "MIT", "dependencies": { - "array-uniq": "^1.0.1" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=0.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "license": "Python-2.0" }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/asn1": { - "version": "0.2.4", + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": "~2.1.0" + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/assert-plus": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=0.8" + "node": "*" } }, - "node_modules/async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, - "node_modules/asynckit": { - "version": "0.4.0", - "license": "MIT" - }, - "node_modules/autogypi": { - "version": "0.2.2", + "node_modules/@eslint/js": { + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", + "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", + "dev": true, "license": "MIT", - "dependencies": { - "bluebird": "^3.4.0", - "commander": "~2.9.0", - "resolve": "~1.1.7" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "bin": { - "autogypi": "autogypi" + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/autogypi/node_modules/commander": { - "version": "2.9.0", - "license": "MIT", - "dependencies": { - "graceful-readlink": ">= 1.0.0" - }, - "engines": { - "node": ">= 0.6.x" - } - }, - "node_modules/aws-sign2": { - "version": "0.7.0", + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, "license": "Apache-2.0", "engines": { - "node": "*" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/aws4": { - "version": "1.8.0", - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "license": "MIT" - }, - "node_modules/basic-auth": { - "version": "2.0.0", + "node_modules/@eslint/plugin-kit": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz", + "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "safe-buffer": "5.1.1" + "@eslint/core": "^0.15.1", + "levn": "^0.4.1" }, "engines": { - "node": ">= 0.8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/basic-auth/node_modules/safe-buffer": { - "version": "5.1.1", + "node_modules/@fortawesome/fontawesome-free": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.4.tgz", + "integrity": "sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg==", "dev": true, - "license": "MIT" + "hasInstallScript": true, + "engines": { + "node": ">=6" + } }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, - "license": "MIT" - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "license": "BSD-3-Clause", - "dependencies": { - "tweetnacl": "^0.14.3" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" } }, - "node_modules/binary-search-bounds": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/binary-search-bounds/-/binary-search-bounds-2.0.5.tgz", - "integrity": "sha512-H0ea4Fd3lS1+sTEB2TgcLoK21lLhwEJzlQv3IN47pJS976Gx4zoWe0ak3q+uYh60ppQxg9F16Ri4tS1sfD4+jA==", - "dev": true - }, - "node_modules/block-stream": { - "version": "0.0.9", - "license": "ISC", + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "inherits": "~2.0.0" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" }, "engines": { - "node": "0.4 || >=0.5.8" + "node": ">=18.18.0" } }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "node_modules/body": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", - "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, - "dependencies": { - "continuable-cache": "^0.3.1", - "error": "^7.0.0", - "raw-body": "~1.1.0", - "safe-json-parse": "~1.0.1" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/bootstrap": { - "version": "3.4.1", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=6" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/browser-resolve": { - "version": "1.11.2", + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", "dev": true, "license": "MIT", - "dependencies": { - "resolve": "1.1.7" + "engines": { + "node": "20 || >=22" } }, - "node_modules/builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", "dev": true, "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": "20 || >=22" } }, - "node_modules/bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", - "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=", - "dev": true - }, - "node_modules/cache-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-2.0.0.tgz", - "integrity": "sha512-4gkeHlFpSKgm3vm2gJN5sPqfmijYRFYCQ6tv5cLw0xVmT6r1z1vd4FNnpuOREco3cBs1G709sZ72LdgddKvL5w==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "license": "ISC", "dependencies": { - "array-back": "^4.0.1", - "fs-then-native": "^2.0.0", - "mkdirp2": "^1.0.4" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/cache-point/node_modules/array-back": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", - "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "license": "MIT", + "engines": { + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/caseless": { - "version": "0.12.0", - "license": "Apache-2.0" + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" }, - "node_modules/catharsis": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", - "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, + "license": "MIT", "dependencies": { - "lodash": "^4.17.15" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">= 10" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/classlist-polyfill": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/classlist-polyfill/-/classlist-polyfill-1.2.0.tgz", - "integrity": "sha1-k1vC39lFiodrJ5YXUUY4vKqWSi4=", + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, - "license": "Unlicense" - }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/collect-all": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/collect-all/-/collect-all-1.0.4.tgz", - "integrity": "sha512-RKZhRwJtJEP5FWul+gkSMEnaK6H3AGPTTWOiRimCcs+rc/OmQE3Yhy1Q7A7KsdkG3ZXVdZq68Y6ONSdvkeEcKA==", - "dev": true, "dependencies": { - "stream-connect": "^1.0.2", - "stream-via": "^1.0.4" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" }, - "node_modules/colors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha512-ENwblkFQpqqia6b++zLD/KUWafYlVY/UNnAp7oz7LY7E924wmpye416wBOmvv/HMWzl8gL1kJlfvId/1Dg176w==", + "node_modules/@jsdoc/salty": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.2.tgz", + "integrity": "sha512-A1FrVnc7L9qI2gUGsfN0trTiJNK72Y0CL/VAyrmYEmeKI3pnHDawP64CEev31XLyAAOx2xmDo3tbadPxC0CSbw==", "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "license": "MIT", "dependencies": { - "delayed-stream": "~1.0.0" + "lodash": "^4.17.21" }, "engines": { - "node": ">= 0.8" + "node": ">=v12.0.0" } }, - "node_modules/command-line-args": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", - "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { - "array-back": "^3.1.0", - "find-replace": "^3.0.0", - "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/command-line-args/node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", - "dev": true, - "engines": { - "node": ">=6" + "node": ">= 8" } }, - "node_modules/command-line-args/node_modules/typical": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", - "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/command-line-tool": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/command-line-tool/-/command-line-tool-0.8.0.tgz", - "integrity": "sha512-Xw18HVx/QzQV3Sc5k1vy3kgtOeGmsKIqwtFFoyjI4bbcpSgnw2CWVULvtakyw4s6fhyAdI6soQQhXc2OzJy62g==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-escape-sequences": "^4.0.0", - "array-back": "^2.0.0", - "command-line-args": "^5.0.0", - "command-line-usage": "^4.1.0", - "typical": "^2.6.1" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">=4.0.0" + "node": ">= 8" } }, - "node_modules/command-line-tool/node_modules/array-back": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", - "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", - "dev": true, - "dependencies": { - "typical": "^2.6.1" - }, - "engines": { - "node": ">=4" + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" } }, - "node_modules/command-line-usage": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-4.1.0.tgz", - "integrity": "sha512-MxS8Ad995KpdAC0Jopo/ovGIroV/m0KHwzKfXxKag6FHOkGsH8/lv5yjgablcRxCJJC0oJeUMuO/gmaq+Wq46g==", - "dev": true, - "dependencies": { - "ansi-escape-sequences": "^4.0.0", - "array-back": "^2.0.0", - "table-layout": "^0.4.2", - "typical": "^2.6.1" - }, - "engines": { - "node": ">=4.0.0" - } + "node_modules/@ranfdev/deepobj": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@ranfdev/deepobj/-/deepobj-1.0.2.tgz", + "integrity": "sha512-FM3y6kfJaj5MCoAjdv24EDCTDbuFz+4+pgAunbjYfugwIE4O/xx8mPNji1n/ouG8pHCntSnBr1xwTOensF23Gg==", + "license": "MIT" }, - "node_modules/command-line-usage/node_modules/array-back": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", - "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "node_modules/@rollup/plugin-commonjs": { + "version": "28.0.6", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.6.tgz", + "integrity": "sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==", "dev": true, + "license": "MIT", "dependencies": { - "typical": "^2.6.1" + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "fdir": "^6.2.0", + "is-reference": "1.2.1", + "magic-string": "^0.30.3", + "picomatch": "^4.0.2" }, "engines": { - "node": ">=4" + "node": ">=16.0.0 || 14 >= 14.17" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/common-sequence": { + "node_modules/@rollup/plugin-commonjs/node_modules/estree-walker": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-2.0.2.tgz", - "integrity": "sha512-jAg09gkdkrDO9EWTdXfv80WWH3yeZl5oT69fGfedBNS9pXUKYInVJ1bJ+/ht2+Moeei48TmSbQDYMc8EOx9G0g==", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "license": "MIT" }, - "node_modules/config-master": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/config-master/-/config-master-3.1.0.tgz", - "integrity": "sha512-n7LBL1zBzYdTpF1mx5DNcZnZn05CWIdsdvtPL4MosvqbBUK3Rq6VWEtGUuF3Y0s9/CIhMejezqlSkP6TnCJ/9g==", + "node_modules/@rollup/plugin-commonjs/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "dev": true, - "dependencies": { - "walk-back": "^2.0.1" + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/config-master/node_modules/walk-back": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-2.0.1.tgz", - "integrity": "sha512-Nb6GvBR8UWX1D+Le+xUq0+Q1kFmRBIWVrfLnQAOmcpEzA9oAxwJ9gIr36t9TWYfzvWRvuMtjHiVsJYEkXWaTAQ==", + "node_modules/@rollup/plugin-commonjs/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/connect": { - "version": "3.6.6", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", - "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", "dev": true, "license": "MIT", "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.0", - "parseurl": "~1.3.2", - "utils-merge": "1.0.1" + "@rollup/pluginutils": "^5.1.0" }, "engines": { - "node": ">= 0.10.0" + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/connect-livereload": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.5.4.tgz", - "integrity": "sha1-gBV9E3HJ83zBQDmrGJWXDRGdw7w=", + "node_modules/@rollup/plugin-node-resolve": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz", + "integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==", "dev": true, "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, "engines": { - "node": "*" + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "license": "ISC" - }, - "node_modules/continuable-cache": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", - "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", - "dev": true - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/@rollup/plugin-node-resolve/node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, + "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "engines": { - "node": ">= 8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/cross-spawn/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, + "node_modules/@rollup/plugin-replace": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.2.tgz", + "integrity": "sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ==", + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, "engines": { - "node": ">=8" + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, + "node_modules/@rollup/pluginutils": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz", + "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==", + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" }, "engines": { - "node": ">= 8" + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/crossfilter2": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/crossfilter2/-/crossfilter2-1.5.4.tgz", - "integrity": "sha512-oOGqOM0RocwQFOXJnEaUKqYV6Mc1TNCRv3LrNUa0QlofQTutGAXyQaLW1aGKLls2sfnbwBEtsa6tPD3jY+ycqQ==", - "dependencies": { - "@ranfdev/deepobj": "1.0.2" + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/css-layout": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/css-layout/-/css-layout-1.1.1.tgz", - "integrity": "sha1-raW7jJAeR11BBDqI4DSt5U2Tk5I=", - "license": "BSD" + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.0.tgz", + "integrity": "sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/d3": { - "version": "3.5.17", - "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", - "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=", - "license": "BSD-3-Clause" + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.0.tgz", + "integrity": "sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/d3-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.1.tgz", - "integrity": "sha512-CyINJQ0SOUHojDdFDH4JEM0552vCR1utGyLHegJHyYH0JyCpSeTPxi4OBqHMA2jJZq4NH782LtaJWBImqI/HBw==", - "dev": true + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz", + "integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/d3-axis": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.8.tgz", - "integrity": "sha512-K0djTb26iQ6AsuD2d6Ka08wBHf4V30awIxV4XFuB/iLzYtTqqJlE/nIN0DBJJCX7lbOqbt2/oeX3r+sU5k2veg==", - "dev": true + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz", + "integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/d3-brush": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.0.4.tgz", - "integrity": "sha512-nUFueDzOlvwFvuOBynGSyJM7Wt1H9fKgJeoWFSg3ScS4c7FJBch92FKUJKum4xtgPYHdgH2C3bRg3GzSVltCJQ==", + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.0.tgz", + "integrity": "sha512-u5AZzdQJYJXByB8giQ+r4VyfZP+walV+xHWdaFx/1VxsOn6eWJhK2Vl2eElvDJFKQBo/hcYIBg/jaKS8ZmKeNQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" - } + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/d3-chord": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.4.tgz", - "integrity": "sha512-o0ExexkK1N0KikUakKrQwttP5Flu8AYD6iBUh3AdPJqnTh6xlvcX5wFRuuo29sLOAr9+T4yZPUH1S3CCQJ1SlQ==", + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.0.tgz", + "integrity": "sha512-qC0kS48c/s3EtdArkimctY7h3nHicQeEUdjJzYVJYR3ct3kWSafmn6jkNCA8InbUdge6PVx6keqjk5lVGJf99g==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "d3-array": "1", - "d3-path": "1" - } + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/d3-collection": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.4.tgz", - "integrity": "sha1-NC39EoN8kJdPM/HMCnha6lcNzcI=", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.0.tgz", + "integrity": "sha512-x+e/Z9H0RAWckn4V2OZZl6EmV0L2diuX3QB0uM1r6BvhUIv6xBPL5mrAX2E3e8N8rEHVPwFfz/ETUbV4oW9+lQ==", + "cpu": [ + "arm" + ], "dev": true, - "license": "BSD-3-Clause" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/d3-color": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.0.3.tgz", - "integrity": "sha512-t+rSOrshj6m2AUOe8kHvTwfUQ5TFoInEkBfmsHHAHPof58dmbRXNpicB7XAyPbMQbcC7i09p2BxeCEdgBd8xmw==", - "dev": true + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.0.tgz", + "integrity": "sha512-1exwiBFf4PU/8HvI8s80icyCcnAIB86MCBdst51fwFmH5dyeoWVPVgmQPcKrMtBQ0W5pAs7jBCWuRXgEpRzSCg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/d3-dispatch": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.3.tgz", - "integrity": "sha1-RuFJHqqbWMNY/OW+TovtYm54cfg=", - "license": "BSD-3-Clause" + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz", + "integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/d3-drag": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.1.tgz", - "integrity": "sha512-Cg8/K2rTtzxzrb0fmnYOUeZHvwa4PHzwXOLZZPwtEs2SKLLKLXeYwZKBB+DlOxUvFmarOnmt//cU4+3US2lyyQ==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-dispatch": "1", - "d3-selection": "1" - } + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz", + "integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/d3-dsv": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.8.tgz", - "integrity": "sha512-IVCJpQ+YGe3qu6odkPQI0KPqfxkhbP/oM1XhhE/DFiYmcXKfCRub4KXyiuehV1d4drjWVXHUWx4gHqhdZb6n/A==", + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.0.tgz", + "integrity": "sha512-xw+FTGcov/ejdusVOqKgMGW3c4+AgqrfvzWEVXcNP6zq2ue+lsYUgJ+5Rtn/OTJf7e2CbgTFvzLW2j0YAtj0Gg==", + "cpu": [ + "loong64" + ], "dev": true, - "dependencies": { - "commander": "2", - "iconv-lite": "0.4", - "rw": "1" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.0.tgz", + "integrity": "sha512-bKGibTr9IdF0zr21kMvkZT4K6NV+jjRnBoVMt2uNMG0BYWm3qOVmYnXKzx7UhwrviKnmK46IKMByMgvpdQlyJQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.0.tgz", + "integrity": "sha512-vV3cL48U5kDaKZtXrti12YRa7TyxgKAIDoYdqSIOMOFBXqFj2XbChHAtXquEn2+n78ciFgr4KIqEbydEGPxXgA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.0.tgz", + "integrity": "sha512-TDKO8KlHJuvTEdfw5YYFBjhFts2TR0VpZsnLLSYmB7AaohJhM8ctDSdDnUGq77hUh4m/djRafw+9zQpkOanE2Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.0.tgz", + "integrity": "sha512-8541GEyktXaw4lvnGp9m84KENcxInhAt6vPWJ9RodsB/iGjHoMB2Pp5MVBCiKIRxrxzJhGCxmNzdu+oDQ7kwRA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.9.tgz", + "integrity": "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.9.tgz", + "integrity": "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.9.tgz", + "integrity": "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.0.tgz", + "integrity": "sha512-3XJ0NQtMAXTWFW8FqZKcw3gOQwBtVWP/u8TpHP3CRPXD7Pd6s8lLdH3sHWh8vqKCyyiI8xW5ltJScQmBU9j7WA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz", + "integrity": "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@stencil/core": { + "version": "4.35.1", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.35.1.tgz", + "integrity": "sha512-u65m3TbzOtpn679gUV4Yvi8YpInhRJ62js30a7YtXief9Ej/vzrhwDE22U0w4DMWJOYwAsJl133BUaZkWwnmzg==", + "dev": true, + "license": "MIT", "bin": { - "csv2json": "bin/dsv2json", - "csv2tsv": "bin/dsv2dsv", - "dsv2dsv": "bin/dsv2dsv", - "dsv2json": "bin/dsv2json", - "json2csv": "bin/json2dsv", - "json2dsv": "bin/json2dsv", - "json2tsv": "bin/json2dsv", - "tsv2csv": "bin/dsv2dsv", - "tsv2json": "bin/dsv2json" + "stencil": "bin/stencil" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.10.0" + }, + "optionalDependencies": { + "@rollup/rollup-darwin-arm64": "4.34.9", + "@rollup/rollup-darwin-x64": "4.34.9", + "@rollup/rollup-linux-arm64-gnu": "4.34.9", + "@rollup/rollup-linux-arm64-musl": "4.34.9", + "@rollup/rollup-linux-x64-gnu": "4.34.9", + "@rollup/rollup-linux-x64-musl": "4.34.9", + "@rollup/rollup-win32-arm64-msvc": "4.34.9", + "@rollup/rollup-win32-x64-msvc": "4.34.9" } }, - "node_modules/d3-ease": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.3.tgz", - "integrity": "sha512-io3QwOJwVPAxRF2UXpKpCdz2wm/7VLFCQQ1yy+GzX6YCtt3vi2BGnimI8agSF5jyUrHsADyF303d2S+ps7zU8w==", - "dev": true + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" }, - "node_modules/d3-force": { - "version": "1.2.1", + "node_modules/@types/fs-extra": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", + "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-quadtree": "1", - "d3-timer": "1" + "@types/node": "*" } }, - "node_modules/d3-force-straighten-paths": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/d3-force-straighten-paths/-/d3-force-straighten-paths-1.0.2.tgz", - "integrity": "sha512-Wt50N/t1gzkAQjYHRi46Z8EvDcfaEGGBCbxYWAx1wMUvTJZxqVq0uOqng9PdT83yobFDjAuOXuC6gq+zO3CeEg==", + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", "dev": true, "license": "MIT", "dependencies": { - "d3-collection": "1.x" + "@types/minimatch": "*", + "@types/node": "*" } }, - "node_modules/d3-format": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.2.2.tgz", - "integrity": "sha512-zH9CfF/3C8zUI47nsiKfD0+AGDEuM8LwBIP7pBVpyR4l/sKkZqITmMtxRp04rwBrlshIZ17XeFAaovN3++wzkw==", + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/linkify-it": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", + "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==", "dev": true }, - "node_modules/d3-geo": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.9.1.tgz", - "integrity": "sha512-l9wL/cEQkyZQYXw3xbmLsH3eQ5ij+icNfo4r0GrLa5rOCZR/e/3am45IQ0FvQ5uMsv+77zBRunLc9ufTWSQYFA==", + "node_modules/@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", "dev": true, "dependencies": { - "d3-array": "1" + "@types/linkify-it": "*", + "@types/mdurl": "*" } }, - "node_modules/d3-hierarchy": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.5.tgz", - "integrity": "sha512-PcsLIhThc60mWnxlojIOH7Sc0tQ2DgLWfEwEAyzCtej5f3H9wSsRmrg5pEhKZLrwiJnI2zyw/pznJxL9a/Eugw==", + "node_modules/@types/mdurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", + "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", "dev": true }, - "node_modules/d3-interpolate": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.1.6.tgz", - "integrity": "sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==", + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz", + "integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==", "dev": true, + "license": "MIT", "dependencies": { - "d3-color": "1" + "undici-types": "~7.8.0" } }, - "node_modules/d3-path": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.5.tgz", - "integrity": "sha1-JB6xhJvZ6egCHA0KeZ+KDo5EF2Q=", - "license": "BSD-3-Clause" + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true, + "license": "MIT" }, - "node_modules/d3-polygon": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.3.tgz", - "integrity": "sha512-2zP7GOvf4XOWTeQouK7fCO534yQxyhYYTw6GTqcXifIalHgA6qV/es+4GRQii9m6XxEPFcht4loobD/o2iEo1A==", - "dev": true + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true, + "license": "ISC" }, - "node_modules/d3-quadtree": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.3.tgz", - "integrity": "sha1-rHmH4+I/6AWpkPKOG1DTj8uCJDg=", + "node_modules/accepts": { + "version": "1.3.5", "dev": true, - "license": "BSD-3-Clause" + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + }, + "engines": { + "node": ">= 0.6" + } }, - "node_modules/d3-queue": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-3.0.7.tgz", - "integrity": "sha512-2rs+6pNFKkrJhqe1rg5znw7dKJ7KZr62j9aLZfhondkrnz6U7VRmJj1UGcbD8MRc46c7H8m4SWhab8EalBQrkw==", - "dev": true + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } }, - "node_modules/d3-random": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.0.tgz", - "integrity": "sha512-XuMbjx3Jq4EWfJP4g6nR7zns/bZfaVbWHWfR8auDkEiWCzVbWifmasfszV1ZRN3xXK3nY4RUFL2nTIhceGZSFQ==", - "dev": true + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, - "node_modules/d3-request": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-request/-/d3-request-1.0.6.tgz", - "integrity": "sha512-FJj8ySY6GYuAJHZMaCQ83xEYE4KbkPkmxZ3Hu6zA1xxG2GD+z6P+Lyp+zjdsHf0xEbp2xcluDI50rCS855EQ6w==", + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-dsv": "1", - "xmlhttprequest": "1" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escape-sequences": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-4.1.0.tgz", + "integrity": "sha512-dzW9kHxH011uBsidTXd14JXgzye/YLb2LzeKZ4bsgl/Knwx8AtbSFkkGxagdNOoh0DlqHCmfiEjWKBaqjOanVw==", + "dev": true, + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/ansi-escape-sequences/node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-back": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "dev": true, + "engines": { + "node": ">=12.17" + } + }, + "node_modules/array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true, + "license": "MIT" + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true, + "license": "MIT" + }, + "node_modules/binary-search-bounds": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/binary-search-bounds/-/binary-search-bounds-2.0.5.tgz", + "integrity": "sha512-H0ea4Fd3lS1+sTEB2TgcLoK21lLhwEJzlQv3IN47pJS976Gx4zoWe0ak3q+uYh60ppQxg9F16Ri4tS1sfD4+jA==", + "dev": true + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/body": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", + "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", + "dev": true, + "dependencies": { + "continuable-cache": "^0.3.1", + "error": "^7.0.0", + "raw-body": "~1.1.0", + "safe-json-parse": "~1.0.1" + } + }, + "node_modules/bootstrap": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", + "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", + "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=", + "dev": true + }, + "node_modules/cache-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-2.0.0.tgz", + "integrity": "sha512-4gkeHlFpSKgm3vm2gJN5sPqfmijYRFYCQ6tv5cLw0xVmT6r1z1vd4FNnpuOREco3cBs1G709sZ72LdgddKvL5w==", + "dev": true, + "dependencies": { + "array-back": "^4.0.1", + "fs-then-native": "^2.0.0", + "mkdirp2": "^1.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cache-point/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/classlist-polyfill": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/classlist-polyfill/-/classlist-polyfill-1.2.0.tgz", + "integrity": "sha1-k1vC39lFiodrJ5YXUUY4vKqWSi4=", + "dev": true, + "license": "Unlicense" + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/collect-all": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/collect-all/-/collect-all-1.0.4.tgz", + "integrity": "sha512-RKZhRwJtJEP5FWul+gkSMEnaK6H3AGPTTWOiRimCcs+rc/OmQE3Yhy1Q7A7KsdkG3ZXVdZq68Y6ONSdvkeEcKA==", + "dev": true, + "dependencies": { + "stream-connect": "^1.0.2", + "stream-via": "^1.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha512-ENwblkFQpqqia6b++zLD/KUWafYlVY/UNnAp7oz7LY7E924wmpye416wBOmvv/HMWzl8gL1kJlfvId/1Dg176w==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "dev": true, + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-args/node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/command-line-args/node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/command-line-tool": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/command-line-tool/-/command-line-tool-0.8.0.tgz", + "integrity": "sha512-Xw18HVx/QzQV3Sc5k1vy3kgtOeGmsKIqwtFFoyjI4bbcpSgnw2CWVULvtakyw4s6fhyAdI6soQQhXc2OzJy62g==", + "dev": true, + "dependencies": { + "ansi-escape-sequences": "^4.0.0", + "array-back": "^2.0.0", + "command-line-args": "^5.0.0", + "command-line-usage": "^4.1.0", + "typical": "^2.6.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-tool/node_modules/array-back": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", + "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "dev": true, + "dependencies": { + "typical": "^2.6.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-4.1.0.tgz", + "integrity": "sha512-MxS8Ad995KpdAC0Jopo/ovGIroV/m0KHwzKfXxKag6FHOkGsH8/lv5yjgablcRxCJJC0oJeUMuO/gmaq+Wq46g==", + "dev": true, + "dependencies": { + "ansi-escape-sequences": "^4.0.0", + "array-back": "^2.0.0", + "table-layout": "^0.4.2", + "typical": "^2.6.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", + "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "dev": true, + "dependencies": { + "typical": "^2.6.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/common-sequence": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-2.0.2.tgz", + "integrity": "sha512-jAg09gkdkrDO9EWTdXfv80WWH3yeZl5oT69fGfedBNS9pXUKYInVJ1bJ+/ht2+Moeei48TmSbQDYMc8EOx9G0g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true, + "license": "MIT" + }, + "node_modules/config-master": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/config-master/-/config-master-3.1.0.tgz", + "integrity": "sha512-n7LBL1zBzYdTpF1mx5DNcZnZn05CWIdsdvtPL4MosvqbBUK3Rq6VWEtGUuF3Y0s9/CIhMejezqlSkP6TnCJ/9g==", + "dev": true, + "dependencies": { + "walk-back": "^2.0.1" + } + }, + "node_modules/config-master/node_modules/walk-back": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-2.0.1.tgz", + "integrity": "sha512-Nb6GvBR8UWX1D+Le+xUq0+Q1kFmRBIWVrfLnQAOmcpEzA9oAxwJ9gIr36t9TWYfzvWRvuMtjHiVsJYEkXWaTAQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-livereload": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.6.1.tgz", + "integrity": "sha512-3R0kMOdL7CjJpU66fzAkCe6HNtd3AavCS4m+uW4KtJjrdGPT0SQEZieAYd+cm+lJoBznNQ4lqipYWkhBMgk00g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/continuable-cache": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", + "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crossfilter2": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/crossfilter2/-/crossfilter2-1.5.4.tgz", + "integrity": "sha512-oOGqOM0RocwQFOXJnEaUKqYV6Mc1TNCRv3LrNUa0QlofQTutGAXyQaLW1aGKLls2sfnbwBEtsa6tPD3jY+ycqQ==", + "license": "Apache-2.0", + "dependencies": { + "@ranfdev/deepobj": "1.0.2" + } + }, + "node_modules/d3": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-5.16.0.tgz", + "integrity": "sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1", + "d3-axis": "1", + "d3-brush": "1", + "d3-chord": "1", + "d3-collection": "1", + "d3-color": "1", + "d3-contour": "1", + "d3-dispatch": "1", + "d3-drag": "1", + "d3-dsv": "1", + "d3-ease": "1", + "d3-fetch": "1", + "d3-force": "1", + "d3-format": "1", + "d3-geo": "1", + "d3-hierarchy": "1", + "d3-interpolate": "1", + "d3-path": "1", + "d3-polygon": "1", + "d3-quadtree": "1", + "d3-random": "1", + "d3-scale": "2", + "d3-scale-chromatic": "1", + "d3-selection": "1", + "d3-shape": "1", + "d3-time": "1", + "d3-time-format": "2", + "d3-timer": "1", + "d3-transition": "1", + "d3-voronoi": "1", + "d3-zoom": "1" + } + }, + "node_modules/d3-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.1.tgz", + "integrity": "sha512-CyINJQ0SOUHojDdFDH4JEM0552vCR1utGyLHegJHyYH0JyCpSeTPxi4OBqHMA2jJZq4NH782LtaJWBImqI/HBw==" + }, + "node_modules/d3-axis": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.8.tgz", + "integrity": "sha512-K0djTb26iQ6AsuD2d6Ka08wBHf4V30awIxV4XFuB/iLzYtTqqJlE/nIN0DBJJCX7lbOqbt2/oeX3r+sU5k2veg==" + }, + "node_modules/d3-brush": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.0.4.tgz", + "integrity": "sha512-nUFueDzOlvwFvuOBynGSyJM7Wt1H9fKgJeoWFSg3ScS4c7FJBch92FKUJKum4xtgPYHdgH2C3bRg3GzSVltCJQ==", + "dependencies": { + "d3-dispatch": "1", + "d3-drag": "1", + "d3-interpolate": "1", + "d3-selection": "1", + "d3-transition": "1" + } + }, + "node_modules/d3-chord": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.4.tgz", + "integrity": "sha512-o0ExexkK1N0KikUakKrQwttP5Flu8AYD6iBUh3AdPJqnTh6xlvcX5wFRuuo29sLOAr9+T4yZPUH1S3CCQJ1SlQ==", + "dependencies": { + "d3-array": "1", + "d3-path": "1" + } + }, + "node_modules/d3-collection": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.4.tgz", + "integrity": "sha1-NC39EoN8kJdPM/HMCnha6lcNzcI=", + "license": "BSD-3-Clause" + }, + "node_modules/d3-color": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.0.3.tgz", + "integrity": "sha512-t+rSOrshj6m2AUOe8kHvTwfUQ5TFoInEkBfmsHHAHPof58dmbRXNpicB7XAyPbMQbcC7i09p2BxeCEdgBd8xmw==" + }, + "node_modules/d3-contour": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz", + "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^1.1.1" + } + }, + "node_modules/d3-dispatch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.3.tgz", + "integrity": "sha1-RuFJHqqbWMNY/OW+TovtYm54cfg=", + "license": "BSD-3-Clause" + }, + "node_modules/d3-drag": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.1.tgz", + "integrity": "sha512-Cg8/K2rTtzxzrb0fmnYOUeZHvwa4PHzwXOLZZPwtEs2SKLLKLXeYwZKBB+DlOxUvFmarOnmt//cU4+3US2lyyQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-dispatch": "1", + "d3-selection": "1" + } + }, + "node_modules/d3-dsv": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.8.tgz", + "integrity": "sha512-IVCJpQ+YGe3qu6odkPQI0KPqfxkhbP/oM1XhhE/DFiYmcXKfCRub4KXyiuehV1d4drjWVXHUWx4gHqhdZb6n/A==", + "dependencies": { + "commander": "2", + "iconv-lite": "0.4", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json", + "csv2tsv": "bin/dsv2dsv", + "dsv2dsv": "bin/dsv2dsv", + "dsv2json": "bin/dsv2json", + "json2csv": "bin/json2dsv", + "json2dsv": "bin/json2dsv", + "json2tsv": "bin/json2dsv", + "tsv2csv": "bin/dsv2dsv", + "tsv2json": "bin/dsv2json" + } + }, + "node_modules/d3-ease": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.3.tgz", + "integrity": "sha512-io3QwOJwVPAxRF2UXpKpCdz2wm/7VLFCQQ1yy+GzX6YCtt3vi2BGnimI8agSF5jyUrHsADyF303d2S+ps7zU8w==" + }, + "node_modules/d3-fetch": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz", + "integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-dsv": "1" + } + }, + "node_modules/d3-force": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz", + "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-collection": "1", + "d3-dispatch": "1", + "d3-quadtree": "1", + "d3-timer": "1" + } + }, + "node_modules/d3-force-straighten-paths": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d3-force-straighten-paths/-/d3-force-straighten-paths-1.0.2.tgz", + "integrity": "sha512-Wt50N/t1gzkAQjYHRi46Z8EvDcfaEGGBCbxYWAx1wMUvTJZxqVq0uOqng9PdT83yobFDjAuOXuC6gq+zO3CeEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "d3-collection": "1.x" + } + }, + "node_modules/d3-format": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.2.2.tgz", + "integrity": "sha512-zH9CfF/3C8zUI47nsiKfD0+AGDEuM8LwBIP7pBVpyR4l/sKkZqITmMtxRp04rwBrlshIZ17XeFAaovN3++wzkw==" + }, + "node_modules/d3-geo": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.9.1.tgz", + "integrity": "sha512-l9wL/cEQkyZQYXw3xbmLsH3eQ5ij+icNfo4r0GrLa5rOCZR/e/3am45IQ0FvQ5uMsv+77zBRunLc9ufTWSQYFA==", + "dependencies": { + "d3-array": "1" + } + }, + "node_modules/d3-hierarchy": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.5.tgz", + "integrity": "sha512-PcsLIhThc60mWnxlojIOH7Sc0tQ2DgLWfEwEAyzCtej5f3H9wSsRmrg5pEhKZLrwiJnI2zyw/pznJxL9a/Eugw==" + }, + "node_modules/d3-interpolate": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.1.6.tgz", + "integrity": "sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==", + "dependencies": { + "d3-color": "1" + } + }, + "node_modules/d3-path": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.5.tgz", + "integrity": "sha1-JB6xhJvZ6egCHA0KeZ+KDo5EF2Q=", + "license": "BSD-3-Clause" + }, + "node_modules/d3-polygon": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.3.tgz", + "integrity": "sha512-2zP7GOvf4XOWTeQouK7fCO534yQxyhYYTw6GTqcXifIalHgA6qV/es+4GRQii9m6XxEPFcht4loobD/o2iEo1A==" + }, + "node_modules/d3-quadtree": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.3.tgz", + "integrity": "sha1-rHmH4+I/6AWpkPKOG1DTj8uCJDg=", + "license": "BSD-3-Clause" + }, + "node_modules/d3-random": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.0.tgz", + "integrity": "sha512-XuMbjx3Jq4EWfJP4g6nR7zns/bZfaVbWHWfR8auDkEiWCzVbWifmasfszV1ZRN3xXK3nY4RUFL2nTIhceGZSFQ==" + }, + "node_modules/d3-scale-chromatic": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz", + "integrity": "sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-color": "1", + "d3-interpolate": "1" + } + }, + "node_modules/d3-selection": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.3.0.tgz", + "integrity": "sha512-qgpUOg9tl5CirdqESUAu0t9MU/t3O9klYfGfyKsXEmhyxyzLpzpeh08gaxBUTQw1uXIOkr/30Ut2YRjSSxlmHA==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-shape": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.2.0.tgz", + "integrity": "sha512-LP48zJ9ykPKjCdd0vSu5k2l4s8v1vI6vvdDeJtmgtTa+L6Ery0lzvOaV7pMunFuLv11hwSRZQnSnlhFl801aiw==", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-time": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.8.tgz", + "integrity": "sha512-YRZkNhphZh3KcnBfitvF3c6E0JOFGikHZ4YqD+Lzv83ZHn1/u6yGenRU1m+KAk9J1GnZMnKcrtfvSktlA1DXNQ==" + }, + "node_modules/d3-time-format": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.1.tgz", + "integrity": "sha512-8kAkymq2WMfzW7e+s/IUNAtN/y3gZXGRrdGfo6R8NKPAA85UBTxZg5E61bR6nLwjPjj4d3zywSQe1CkYLPFyrw==", + "dependencies": { + "d3-time": "1" + } + }, + "node_modules/d3-timer": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.7.tgz", + "integrity": "sha512-vMZXR88XujmG/L5oB96NNKH5lCWwiLM/S2HyyAQLcjWJCloK5shxta4CwOFYLZoY3AWX73v8Lgv4cCAdWtRmOA==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-transition": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.1.1.tgz", + "integrity": "sha512-xeg8oggyQ+y5eb4J13iDgKIjUcEfIOZs2BqV/eEmXm2twx80wTzJ4tB4vaZ5BKfz7XsI/DFmQL5me6O27/5ykQ==", + "dependencies": { + "d3-color": "1", + "d3-dispatch": "1", + "d3-ease": "1", + "d3-interpolate": "1", + "d3-selection": "^1.1.0", + "d3-timer": "1" + } + }, + "node_modules/d3-voronoi": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.2.tgz", + "integrity": "sha512-RhGS1u2vavcO7ay7ZNAPo4xeDh/VYeGof3x5ZLJBQgYhLegxr3s5IykvWmJ94FTU6mcbtp4sloqZ54mP6R4Utw==" + }, + "node_modules/d3-zoom": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.7.1.tgz", + "integrity": "sha512-sZHQ55DGq5BZBFGnRshUT8tm2sfhPHFnOlmPbbwTkAoPeVdRTkB4Xsf9GCY0TSHrTD8PeJPZGmP/TpGicwJDJQ==", + "dependencies": { + "d3-dispatch": "1", + "d3-drag": "1", + "d3-interpolate": "1", + "d3-selection": "1", + "d3-transition": "1" + } + }, + "node_modules/d3/node_modules/d3-scale": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", + "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "^1.2.0", + "d3-collection": "1", + "d3-format": "1", + "d3-interpolate": "1", + "d3-time": "1", + "d3-time-format": "2" + } + }, + "node_modules/dagre": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", + "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==", + "dependencies": { + "graphlib": "^2.1.8", + "lodash": "^4.17.15" + } + }, + "node_modules/date-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/date-time/-/date-time-1.1.0.tgz", + "integrity": "sha1-GIdtC9pMGf5w3Tv0sDTygbEqQLY=", + "dev": true, + "license": "MIT", + "dependencies": { + "time-zone": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/dc": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/dc/-/dc-4.0.5.tgz", + "integrity": "sha512-4s5iaDSMgZThFlFmOMM6D1KReS2Ui1a7wcbECPgP0pXBGQ4CMcvP6euI3ymF0tER5lK2U6ApIrxJ9czP+NzINw==", + "license": "Apache-2.0", + "dependencies": { + "d3": "^5.15.1" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dmd": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/dmd/-/dmd-6.2.0.tgz", + "integrity": "sha512-uXWxLF1H7TkUAuoHK59/h/ts5cKavm2LnhrIgJWisip4BVzPoXavlwyoprFFn2CzcahKYgvkfaebS6oxzgflkg==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "cache-point": "^2.0.0", + "common-sequence": "^2.0.2", + "file-set": "^4.0.2", + "handlebars": "^4.7.7", + "marked": "^4.2.3", + "object-get": "^2.1.1", + "reduce-flatten": "^3.0.1", + "reduce-unique": "^2.0.1", + "reduce-without": "^1.0.1", + "test-value": "^3.0.0", + "walk-back": "^5.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "dependencies": { + "domelementtype": "^2.0.1" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/domutils/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/dprint": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/dprint/-/dprint-0.50.1.tgz", + "integrity": "sha512-s+kUyQp2rGpwsM3vVmXySOY3v1NjYyRpKfQZdP4rfNTz6zQuICSO6nqIXNm3YdK1MwNFR/EXSFMuE1YPuulhow==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "dprint": "bin.js" + }, + "optionalDependencies": { + "@dprint/darwin-arm64": "0.50.1", + "@dprint/darwin-x64": "0.50.1", + "@dprint/linux-arm64-glibc": "0.50.1", + "@dprint/linux-arm64-musl": "0.50.1", + "@dprint/linux-riscv64-glibc": "0.50.1", + "@dprint/linux-x64-glibc": "0.50.1", + "@dprint/linux-x64-musl": "0.50.1", + "@dprint/win32-arm64": "0.50.1", + "@dprint/win32-x64": "0.50.1" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", + "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", + "dev": true, + "dependencies": { + "string-template": "~0.2.1", + "xtend": "~4.0.0" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true, + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", + "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.15.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.32.0", + "@eslint/plugin-kit": "^0.3.4", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", + "dev": true, + "license": "MIT" + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "license": "MIT", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-set": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/file-set/-/file-set-4.0.2.tgz", + "integrity": "sha512-fuxEgzk4L8waGXaAkd8cMr73Pm0FxOVkn8hztzUW7BAHhOGH90viQNXbiOsnecCWmfInqU6YmAMwxRMdKETceQ==", + "dev": true, + "dependencies": { + "array-back": "^5.0.0", + "glob": "^7.1.6" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/file-set/node_modules/array-back": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-5.0.0.tgz", + "integrity": "sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/file-set/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/file-set/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/file-sync-cmp": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz", + "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=", + "dev": true, + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dev": true, + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/find-replace/node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/findup-sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", + "dev": true, + "dependencies": { + "glob": "~5.0.0" + }, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/findup-sync/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "license": "ISC", + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-then-native": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fs-then-native/-/fs-then-native-2.0.0.tgz", + "integrity": "sha512-X712jAOaWXkemQCAmWeg5rOT2i+KOpWz1Z/txk/cW0qlOu2oQ9H61vc5w3X/iyuUEfq/OyaFJ78/cZAQD1/bgA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "globule": "^1.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getobject": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.2.tgz", + "integrity": "sha512-2zblDBaFcb3rB4rF77XVnuINOE2h2k/OnqXAiy0IrTxUfV1iFp3la33oAQVY9pCpWU268WFYVt2t71hlMuLsOg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/glob": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", + "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.0.3", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/globby/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globby/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globule": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", + "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/globule/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/graphlib": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", + "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/graphlib-dot": { + "version": "0.6.5-pre", + "resolved": "git+ssh://git@github.com/dagrejs/graphlib-dot.git#7d5c09c8b7fb4d5d9441edd7bc58f4d7cbafcaa3", + "dev": true, + "license": "MIT", + "dependencies": { + "graphlib": "2.1.8", + "lodash": "4.17.19" + } + }, + "node_modules/graphlib-dot/node_modules/lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + }, + "node_modules/grunt": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.5.3.tgz", + "integrity": "sha512-mKwmo4X2d8/4c/BmcOETHek675uOqw0RuA/zy12jaspWqvTp4+ZeQF1W+OTpcbncnaBsfbQJ6l0l4j+Sn/GmaQ==", + "dev": true, + "dependencies": { + "dateformat": "~3.0.3", + "eventemitter2": "~0.4.13", + "exit": "~0.1.2", + "findup-sync": "~0.3.0", + "glob": "~7.1.6", + "grunt-cli": "~1.4.3", + "grunt-known-options": "~2.0.0", + "grunt-legacy-log": "~3.0.0", + "grunt-legacy-util": "~2.0.1", + "iconv-lite": "~0.4.13", + "js-yaml": "~3.14.0", + "minimatch": "~3.0.4", + "mkdirp": "~1.0.4", + "nopt": "~3.0.6", + "rimraf": "~3.0.2" + }, + "bin": { + "grunt": "bin/grunt" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/grunt-cli": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.5.0.tgz", + "integrity": "sha512-rILKAFoU0dzlf22SUfDtq2R1fosChXXlJM5j7wI6uoW8gwmXDXzbUvirlKZSYCdXl3LXFbR+8xyS+WFo+b6vlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "grunt-known-options": "~2.0.0", + "interpret": "~1.1.0", + "liftup": "~3.0.1", + "nopt": "~5.0.0", + "v8flags": "^4.0.1" + }, + "bin": { + "grunt": "bin/grunt" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/grunt-cli/node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/grunt-cli/node_modules/v8flags": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-4.0.1.tgz", + "integrity": "sha512-fcRLaS4H/hrZk9hYwbdRM35D0U8IYMfEClhXxCivOojl+yTRAZH3Zy2sSy6qVCiGbV9YAtPssP6jaChqC9vPCg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/grunt-contrib-concat": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-2.1.0.tgz", + "integrity": "sha512-Vnl95JIOxfhEN7bnYIlCgQz41kkbi7tsZ/9a4usZmxNxi1S2YAIOy8ysFmO8u4MN26Apal1O106BwARdaNxXQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "source-map": "^0.5.3" + }, + "engines": { + "node": ">=0.12.0" + }, + "peerDependencies": { + "grunt": ">=1.4.1" + } + }, + "node_modules/grunt-contrib-concat/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/grunt-contrib-concat/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/grunt-contrib-concat/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/grunt-contrib-connect": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/grunt-contrib-connect/-/grunt-contrib-connect-5.0.1.tgz", + "integrity": "sha512-Hfq/0QJl3ddD2N/a/1cDJHkKEOGk6m7W6uxNe0AmYwtf6v0F/4+8q9rvPJ1tl+mrI90lU/89I9T/h48qqeMfQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "async": "^3.2.5", + "connect": "^3.7.0", + "connect-livereload": "^0.6.1", + "http2-wrapper": "^2.2.1", + "morgan": "^1.10.0", + "open": "^8.0.0", + "portscanner": "^2.2.0", + "serve-index": "^1.9.1", + "serve-static": "^1.15.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/grunt-contrib-copy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz", + "integrity": "sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM=", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^1.1.1", + "file-sync-cmp": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/grunt-contrib-uglify": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-5.2.2.tgz", + "integrity": "sha512-ITxiWxrjjP+RZu/aJ5GLvdele+sxlznh+6fK9Qckio5ma8f7Iv8woZjRkGfafvpuygxNefOJNc+hfjjBayRn2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "maxmin": "^3.0.0", + "uglify-js": "^3.16.1", + "uri-path": "^1.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/grunt-contrib-uglify/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/grunt-contrib-uglify/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/grunt-contrib-uglify/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/grunt-contrib-watch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.1.0.tgz", + "integrity": "sha512-yGweN+0DW5yM+oo58fRu/XIRrPcn3r4tQx+nL7eMRwjpvk+rQY6R8o94BPK0i2UhTg9FN21hS+m8vR8v9vXfeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async": "^2.6.0", + "gaze": "^1.1.0", + "lodash": "^4.17.10", + "tiny-lr": "^1.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/grunt-contrib-watch/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/grunt-gh-pages": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/grunt-gh-pages/-/grunt-gh-pages-4.0.0.tgz", + "integrity": "sha512-vuU13G0/my6VM6hLYZwnGzNI8jNJiyJprT3vkMp2S3fjBs+etWTo2ldF9mkiH5MuZYkuS2yJ6B3Fy/Tj7fzRzg==", + "dev": true, + "dependencies": { + "async": "^3.2.0", + "fs-extra": "^8.1.0", + "graceful-fs": "^4.2.3", + "url-safe": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "grunt": ">=0.4.0" + } + }, + "node_modules/grunt-jsdoc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/grunt-jsdoc/-/grunt-jsdoc-2.4.1.tgz", + "integrity": "sha512-S0zxU0wDewRu7z+vijEItOWe/UttxWVmvz0qz2ZVcAYR2GpXjsiski2CAVN0b18t2qeVLdmxZkJaEWCOsKzcAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1", + "jsdoc": "^3.6.3" + }, + "bin": { + "grunt-jsdoc": "bin/grunt-jsdoc" + }, + "engines": { + "node": ">= 8.12.0" + } + }, + "node_modules/grunt-jsdoc-to-markdown": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/grunt-jsdoc-to-markdown/-/grunt-jsdoc-to-markdown-6.0.0.tgz", + "integrity": "sha512-vvanKUErp6CHl4MuLQ9vwJewpMu8Fi7z09lr4OwMLr+GBu3nG5lRNZuu5mkWY8qv1aU8WkX97/rJaVs3A1Wx8g==", + "dev": true, + "dependencies": { + "jsdoc-to-markdown": "^7.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "grunt": ">=1.3.0" + } + }, + "node_modules/grunt-known-options": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", + "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/grunt-legacy-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz", + "integrity": "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==", + "dev": true, + "dependencies": { + "colors": "~1.1.2", + "grunt-legacy-log-utils": "~2.1.0", + "hooker": "~0.2.3", + "lodash": "~4.17.19" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/grunt-legacy-log-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz", + "integrity": "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==", + "dev": true, + "dependencies": { + "chalk": "~4.1.0", + "lodash": "~4.17.19" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/grunt-legacy-log-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/grunt-legacy-log-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/grunt-legacy-log-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/grunt-legacy-util": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz", + "integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==", + "dev": true, + "dependencies": { + "async": "~3.2.0", + "exit": "~0.1.2", + "getobject": "~1.0.0", + "hooker": "~0.2.3", + "lodash": "~4.17.21", + "underscore.string": "~3.3.5", + "which": "~2.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/grunt-legacy-util/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/grunt-shell": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/grunt-shell/-/grunt-shell-4.0.0.tgz", + "integrity": "sha512-dHFy8VZDfWGYLTeNvIHze4PKXGvIlDWuN0UE7hUZstTQeiEyv1VmW1MaDYQ3X5tE3bCi3bEia1gGKH8z/f1czQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^3.0.0", + "npm-run-path": "^2.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + }, + "peerDependencies": { + "grunt": ">=1" + } + }, + "node_modules/grunt-shell/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/d3-scale": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-1.0.7.tgz", - "integrity": "sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==", + "node_modules/grunt-shell/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "d3-array": "^1.2.0", - "d3-collection": "1", - "d3-color": "1", - "d3-format": "1", - "d3-interpolate": "1", - "d3-time": "1", - "d3-time-format": "2" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/d3-selection": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.3.0.tgz", - "integrity": "sha512-qgpUOg9tl5CirdqESUAu0t9MU/t3O9klYfGfyKsXEmhyxyzLpzpeh08gaxBUTQw1uXIOkr/30Ut2YRjSSxlmHA==", - "license": "BSD-3-Clause" - }, - "node_modules/d3-shape": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.2.0.tgz", - "integrity": "sha512-LP48zJ9ykPKjCdd0vSu5k2l4s8v1vI6vvdDeJtmgtTa+L6Ery0lzvOaV7pMunFuLv11hwSRZQnSnlhFl801aiw==", + "node_modules/grunt-shell/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, + "license": "MIT", "dependencies": { - "d3-path": "1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/d3-time": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.8.tgz", - "integrity": "sha512-YRZkNhphZh3KcnBfitvF3c6E0JOFGikHZ4YqD+Lzv83ZHn1/u6yGenRU1m+KAk9J1GnZMnKcrtfvSktlA1DXNQ==", - "dev": true - }, - "node_modules/d3-time-format": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.1.tgz", - "integrity": "sha512-8kAkymq2WMfzW7e+s/IUNAtN/y3gZXGRrdGfo6R8NKPAA85UBTxZg5E61bR6nLwjPjj4d3zywSQe1CkYLPFyrw==", + "node_modules/grunt-shell/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { - "d3-time": "1" + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/d3-timer": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.7.tgz", - "integrity": "sha512-vMZXR88XujmG/L5oB96NNKH5lCWwiLM/S2HyyAQLcjWJCloK5shxta4CwOFYLZoY3AWX73v8Lgv4cCAdWtRmOA==", - "license": "BSD-3-Clause" - }, - "node_modules/d3-tip": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/d3-tip/-/d3-tip-0.7.1.tgz", - "integrity": "sha512-jtVR86jEfpVhfMtJaJBzT3GYYfulID106s9gqiX8o8es2tRcsCeJhoWWZG3sfepP97j1CTxfxPoky014nfJ9Zg==", - "dev": true, - "dependencies": { - "d3": "^4.2" - } - }, - "node_modules/d3-tip/node_modules/d3": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-4.13.0.tgz", - "integrity": "sha512-l8c4+0SldjVKLaE2WG++EQlqD7mh/dmQjvi2L2lKPadAVC+TbJC4ci7Uk9bRi+To0+ansgsS0iWfPjD7DBy+FQ==", - "dev": true, - "dependencies": { - "d3-array": "1.2.1", - "d3-axis": "1.0.8", - "d3-brush": "1.0.4", - "d3-chord": "1.0.4", - "d3-collection": "1.0.4", - "d3-color": "1.0.3", - "d3-dispatch": "1.0.3", - "d3-drag": "1.2.1", - "d3-dsv": "1.0.8", - "d3-ease": "1.0.3", - "d3-force": "1.1.0", - "d3-format": "1.2.2", - "d3-geo": "1.9.1", - "d3-hierarchy": "1.1.5", - "d3-interpolate": "1.1.6", - "d3-path": "1.0.5", - "d3-polygon": "1.0.3", - "d3-quadtree": "1.0.3", - "d3-queue": "3.0.7", - "d3-random": "1.1.0", - "d3-request": "1.0.6", - "d3-scale": "1.0.7", - "d3-selection": "1.3.0", - "d3-shape": "1.2.0", - "d3-time": "1.0.8", - "d3-time-format": "2.1.1", - "d3-timer": "1.0.7", - "d3-transition": "1.1.1", - "d3-voronoi": "1.1.2", - "d3-zoom": "1.7.1" - } - }, - "node_modules/d3-tip/node_modules/d3-force": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.1.0.tgz", - "integrity": "sha512-2HVQz3/VCQs0QeRNZTYb7GxoUCeb6bOzMp/cGcLa87awY9ZsPvXOGeZm0iaGBjXic6I1ysKwMn+g+5jSAdzwcg==", + "node_modules/grunt-shell/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-quadtree": "1", - "d3-timer": "1" + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/d3-transition": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.1.1.tgz", - "integrity": "sha512-xeg8oggyQ+y5eb4J13iDgKIjUcEfIOZs2BqV/eEmXm2twx80wTzJ4tB4vaZ5BKfz7XsI/DFmQL5me6O27/5ykQ==", + "node_modules/grunt/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { - "d3-color": "1", - "d3-dispatch": "1", - "d3-ease": "1", - "d3-interpolate": "1", - "d3-selection": "^1.1.0", - "d3-timer": "1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/d3-voronoi": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.2.tgz", - "integrity": "sha512-RhGS1u2vavcO7ay7ZNAPo4xeDh/VYeGof3x5ZLJBQgYhLegxr3s5IykvWmJ94FTU6mcbtp4sloqZ54mP6R4Utw==", - "dev": true - }, - "node_modules/d3-zoom": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.7.1.tgz", - "integrity": "sha512-sZHQ55DGq5BZBFGnRshUT8tm2sfhPHFnOlmPbbwTkAoPeVdRTkB4Xsf9GCY0TSHrTD8PeJPZGmP/TpGicwJDJQ==", + "node_modules/grunt/node_modules/grunt-cli": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", + "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", "dev": true, "dependencies": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" + "grunt-known-options": "~2.0.0", + "interpret": "~1.1.0", + "liftup": "~3.0.1", + "nopt": "~4.0.1", + "v8flags": "~3.2.0" + }, + "bin": { + "grunt": "bin/grunt" + }, + "engines": { + "node": ">=10" } }, - "node_modules/dagre": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", - "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==", + "node_modules/grunt/node_modules/grunt-cli/node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dev": true, "dependencies": { - "graphlib": "^2.1.8", - "lodash": "^4.17.15" + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" } }, - "node_modules/dashdash": { - "version": "1.14.1", - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0" + "node_modules/grunt/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" }, "engines": { - "node": ">=0.10" + "node": ">=10" } }, - "node_modules/date-time": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/date-time/-/date-time-1.1.0.tgz", - "integrity": "sha1-GIdtC9pMGf5w3Tv0sDTygbEqQLY=", + "node_modules/grunt/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, - "license": "MIT", "dependencies": { - "time-zone": "^0.1.0" + "glob": "^7.1.3" }, - "engines": { - "node": ">=0.10.0" + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "node_modules/gzip-size": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", "dev": true, + "license": "MIT", + "dependencies": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + }, "engines": { - "node": "*" + "node": ">=6" } }, - "node_modules/dc": { - "version": "2.1.10", - "resolved": "https://registry.npmjs.org/dc/-/dc-2.1.10.tgz", - "integrity": "sha512-RCi/vyOjg/fscp/j3jVSzhtABkVu05A1fJmWop/Mx2iASoXKnDhPcUZ2wp0QBXLquGlq0PfGd+TCREBQhUUG5A==", - "license": "Apache-2.0", + "node_modules/handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, "dependencies": { - "crossfilter2": "~1.4", - "d3": "^3" + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" } }, - "node_modules/dc/node_modules/crossfilter2": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/crossfilter2/-/crossfilter2-1.4.8.tgz", - "integrity": "sha512-H3D2AyRGpRYK0pKs6kgwALuNb3J6/PuW/sIckPDxPi2wz+TX1Cp/1+BC7sKkMUF12RGPjV/PNANF/W4TQ+4BLg==", - "dependencies": { - "lodash.result": "^4.4.0" + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" } }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, "engines": { - "node": ">=4.0.0" + "node": ">=0.10.0" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "license": "MIT" - }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, - "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } }, - "node_modules/detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/dmd": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/dmd/-/dmd-6.2.0.tgz", - "integrity": "sha512-uXWxLF1H7TkUAuoHK59/h/ts5cKavm2LnhrIgJWisip4BVzPoXavlwyoprFFn2CzcahKYgvkfaebS6oxzgflkg==", + "node_modules/hooker": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", "dev": true, - "dependencies": { - "array-back": "^6.2.2", - "cache-point": "^2.0.0", - "common-sequence": "^2.0.2", - "file-set": "^4.0.2", - "handlebars": "^4.7.7", - "marked": "^4.2.3", - "object-get": "^2.1.1", - "reduce-flatten": "^3.0.1", - "reduce-unique": "^2.0.1", - "reduce-without": "^1.0.1", - "test-value": "^3.0.0", - "walk-back": "^5.1.0" - }, "engines": { - "node": ">=12" + "node": "*" } }, - "node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "node_modules/htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", "dependencies": { "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/dom-serializer/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "license": "MIT", "dependencies": { - "domelementtype": "^2.2.0" + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" }, "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "node": ">= 0.6" } }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] + "node_modules/http-parser-js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.0.tgz", + "integrity": "sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w==", + "dev": true, + "license": "MIT" }, - "node_modules/domhandler": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", - "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "license": "MIT", "dependencies": { - "domelementtype": "^2.0.1" + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" }, "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "node": ">=10.19.0" } }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" }, "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "url": "https://github.com/sponsors/typicode" } }, - "node_modules/domutils/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "node_modules/iconv-lite": { + "version": "0.4.23", + "license": "MIT", "dependencies": { - "domelementtype": "^2.2.0" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, "license": "MIT", "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "license": "MIT" - }, - "node_modules/emscripten-library-decorator": { - "version": "0.2.2", "license": "MIT", - "bin": { - "dump-em-lib": "dump-em-lib" + "engines": { + "node": ">=4" } }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=0.8.19" } }, - "node_modules/entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/error": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", - "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/ink-docstrap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/ink-docstrap/-/ink-docstrap-1.3.2.tgz", + "integrity": "sha512-STx5orGQU1gfrkoI/fMU7lX6CSP7LBGO10gXNgOZhwKhUqbtNjCkYSewJtNnLmWP1tAGN6oyEpG1HFPw5vpa5Q==", "dependencies": { - "string-template": "~0.2.1", - "xtend": "~4.0.0" + "moment": "^2.14.1", + "sanitize-html": "^1.13.0" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "node_modules/interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha512-CLM8SNMDu7C5psFCn6Wg/tgpj/bKAg7hc2gWqcuR9OD5Ft9PhBpIu8PLicPeis+xDd6YX2ncI8MCA64I9tftIA==", + "dev": true + }, + "node_modules/interval-tree-1d": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/interval-tree-1d/-/interval-tree-1d-1.0.4.tgz", + "integrity": "sha512-wY8QJH+6wNI0uh4pDQzMvl+478Qh7Rl4qLmqiluxALlNvl+I+o5x38Pw3/z7mDPTPS1dQalZJXsmbvxx5gclhQ==", "dev": true, - "license": "MIT" + "dependencies": { + "binary-search-bounds": "^2.0.0" + } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "node_modules/ionicons": { + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-8.0.9.tgz", + "integrity": "sha512-qC8xcTVcrmC9e+4KwigtbfKa9J27rFzsjvi1wQBue178Az6u6mFDpL/Q10w534+RD5PkmiXlqy7my7+h2B/zTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@stencil/core": "^4.30.0" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, "engines": { - "node": ">=0.8.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, + "license": "MIT", "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "is-docker": "cli.js" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/eventemitter2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", - "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", + "node_modules/is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.8.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { - "homedir-polyfill": "^1.0.1" + "is-extglob": "^2.1.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/extend": { - "version": "3.0.2", - "license": "MIT" - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "engines": [ - "node >=0.6.0" - ], + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, "license": "MIT" }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.0.0", - "license": "MIT" + "node_modules/is-number-like": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz", + "integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lodash.isfinite": "^3.3.2" + } }, - "node_modules/faye-websocket": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "license": "MIT", "dependencies": { - "websocket-driver": ">=0.5.1" + "isobject": "^3.0.1" }, "engines": { - "node": ">=0.4.0" + "node": ">=0.10.0" } }, - "node_modules/figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", "dev": true, - "license": "MIT", "dependencies": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" + "@types/estree": "*" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "dependencies": { + "is-unc-path": "^1.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/file-set": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/file-set/-/file-set-4.0.2.tgz", - "integrity": "sha512-fuxEgzk4L8waGXaAkd8cMr73Pm0FxOVkn8hztzUW7BAHhOGH90viQNXbiOsnecCWmfInqU6YmAMwxRMdKETceQ==", + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "dependencies": { - "array-back": "^5.0.0", - "glob": "^7.1.6" + "unc-path-regex": "^0.1.2" }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/file-set/node_modules/array-back": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-5.0.0.tgz", - "integrity": "sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==", + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/file-sync-cmp": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz", - "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=", - "dev": true, - "license": "MIT" - }, - "node_modules/finalhandler": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", - "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, "license": "MIT", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.3.1", - "unpipe": "~1.0.0" + "is-docker": "^2.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/find-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", - "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true, - "dependencies": { - "array-back": "^3.0.1" - }, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "license": "MIT", "engines": { - "node": ">=4.0.0" + "node": ">=0.10.0" } }, - "node_modules/find-replace/node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "node_modules/jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, "engines": { - "node": ">=6" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "node_modules/jquery": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.3.tgz", + "integrity": "sha512-bZ5Sy3YzKo9Fyc8wH2iIQK4JImJ6R0GWI9kL1/k7Z91ZBNgkRXE6U0JfHIizZbort8ZunhSI3jw9I6253ahKfg==", + "dev": true + }, + "node_modules/jquery-ui-dist": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/jquery-ui-dist/-/jquery-ui-dist-1.13.3.tgz", + "integrity": "sha512-qeTR3SOSQ0jgxaNXSFU6+JtxdzNUSJKgp8LCzVrVKntM25+2YBJW1Ea8B2AwjmmSHfPLy2dSlZxJQN06OfVFhg==", "dev": true, "license": "MIT", "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "jquery": ">=1.8.0 <4.0.0" + } + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "engines": { - "node": ">=0.10.0" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/findup-sync": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", - "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", "dev": true, "dependencies": { - "glob": "~5.0.0" + "xmlcreate": "^2.0.4" + } + }, + "node_modules/jsdifflib": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsdifflib/-/jsdifflib-1.1.0.tgz", + "integrity": "sha1-LY1UsqQ+z9aAdKveIlgtixK9q/M=", + "dev": true, + "license": "BSD" + }, + "node_modules/jsdoc": { + "version": "3.6.11", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.11.tgz", + "integrity": "sha512-8UCU0TYeIYD9KeLzEcAu2q8N/mx9O3phAGl32nmHlE0LpaJL71mMkP4d+QE5zWfNt50qheHtOZ0qoxVrsX5TUg==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.9.4", + "@types/markdown-it": "^12.2.3", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "taffydb": "2.6.2", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" }, "engines": { - "node": ">= 0.6.0" + "node": ">=12.0.0" } }, - "node_modules/findup-sync/node_modules/glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "node_modules/jsdoc-api": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-7.2.0.tgz", + "integrity": "sha512-93YDnlm/OYTlLOFeNs4qAv0RBCJ0kGj67xQaWy8wrbk97Rw1EySitoOTHsTHXPEs3uyx2IStPKGrbE7LTnZXbA==", "dev": true, - "license": "ISC", "dependencies": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "array-back": "^6.2.2", + "cache-point": "^2.0.0", + "collect-all": "^1.0.4", + "file-set": "^4.0.2", + "fs-then-native": "^2.0.0", + "jsdoc": "^4.0.0", + "object-to-spawn-args": "^2.0.1", + "temp-path": "^1.0.0", + "walk-back": "^5.1.0" }, "engines": { - "node": "*" + "node": ">=12.17" } }, - "node_modules/fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "node_modules/jsdoc-api/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, - "dependencies": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" - }, "engines": { - "node": ">= 0.10" + "node": ">=8" } }, - "node_modules/flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "node_modules/jsdoc-api/node_modules/jsdoc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.0.tgz", + "integrity": "sha512-tzTgkklbWKrlaQL2+e3NNgLcZu3NaK2vsHRx7tyHQ+H5jcB9Gx0txSd2eJWlMC/xU1+7LQu4s58Ry0RkuaEQVg==", "dev": true, + "dependencies": { + "@babel/parser": "^7.9.4", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^12.2.3", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, "engines": { - "node": ">= 0.10" + "node": ">=12.0.0" } }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "node_modules/jsdoc-api/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, - "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "node_modules/jsdoc-parse": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-6.2.0.tgz", + "integrity": "sha512-Afu1fQBEb7QHt6QWX/6eUWvYHJofB90Fjx7FuJYF7mnG9z5BkAIpms1wsnvYLytfmqpEENHs/fax9p8gvMj7dw==", "dev": true, "dependencies": { - "for-in": "^1.0.1" + "array-back": "^6.2.2", + "lodash.omit": "^4.5.0", + "lodash.pick": "^4.4.0", + "reduce-extract": "^1.0.0", + "sort-array": "^4.1.5", + "test-value": "^3.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "license": "Apache-2.0", - "engines": { - "node": "*" + "node": ">=12" } }, - "node_modules/form-data": { - "version": "2.3.3", - "license": "MIT", + "node_modules/jsdoc-to-markdown": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-7.1.1.tgz", + "integrity": "sha512-CI86d63xAVNO+ENumWwmJ034lYe5iGU5GwjtTA11EuphP9tpnoi4hrKgR/J8uME0D+o4KUpVfwX1fjZhc8dEtg==", + "dev": true, "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "array-back": "^6.2.2", + "command-line-tool": "^0.8.0", + "config-master": "^3.1.0", + "dmd": "^6.1.0", + "jsdoc-api": "^7.1.1", + "jsdoc-parse": "^6.1.0", + "walk-back": "^5.1.0" + }, + "bin": { + "jsdoc2md": "bin/cli.js" }, "engines": { - "node": ">= 0.12" + "node": ">=12.17" } }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "node_modules/jsdoc/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, - "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "node_modules/jsdoc/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "bin": { + "mkdirp": "bin/cmd.js" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=10" } }, - "node_modules/fs-then-native": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fs-then-native/-/fs-then-native-2.0.0.tgz", - "integrity": "sha512-X712jAOaWXkemQCAmWeg5rOT2i+KOpWz1Z/txk/cW0qlOu2oQ9H61vc5w3X/iyuUEfq/OyaFJ78/cZAQD1/bgA==", + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "license": "ISC" + "license": "MIT" }, - "node_modules/fstream": { - "version": "1.0.12", - "license": "ISC", - "dependencies": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "engines": { - "node": ">=0.6" - } + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, "license": "MIT" }, - "node_modules/gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/gaze": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", - "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", "dependencies": { - "globule": "^1.0.0" - }, - "engines": { - "node": ">= 4.0.0" + "json-buffer": "3.0.1" } }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "graceful-fs": "^4.1.9" } }, - "node_modules/getobject": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.2.tgz", - "integrity": "sha512-2zblDBaFcb3rB4rF77XVnuINOE2h2k/OnqXAiy0IrTxUfV1iFp3la33oAQVY9pCpWU268WFYVt2t71hlMuLsOg==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/getpass": { - "version": "0.1.7", "license": "MIT", "dependencies": { - "assert-plus": "^1.0.0" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "node_modules/liftup": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", + "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", + "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "extend": "^3.0.2", + "findup-sync": "^4.0.0", + "fined": "^1.2.0", + "flagged-respawn": "^1.0.1", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.1", + "rechoir": "^0.7.0", + "resolve": "^1.19.0" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=10" } }, - "node_modules/global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "node_modules/liftup/node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", "dev": true, "dependencies": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "node_modules/liftup/node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, "dependencies": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, - "engines": { - "node": ">=0.10.0" + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globule": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", - "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "dev": true, "license": "MIT", - "dependencies": { - "glob": "~7.1.1", - "lodash": "~4.17.10", - "minimatch": "~3.0.2" - }, "engines": { - "node": ">= 0.10" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "node_modules/graceful-readlink": { - "version": "1.0.1", - "license": "MIT" - }, - "node_modules/graphlib": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", - "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", - "dependencies": { - "lodash": "^4.17.15" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, - "node_modules/graphlib-dot": { - "version": "0.6.5-pre", - "resolved": "git+ssh://git@github.com/dagrejs/graphlib-dot.git#7d5c09c8b7fb4d5d9441edd7bc58f4d7cbafcaa3", + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", "dev": true, - "license": "MIT", "dependencies": { - "graphlib": "2.1.8", - "lodash": "4.17.19" + "uc.micro": "^1.0.1" } }, - "node_modules/graphlib-dot/node_modules/lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", - "dev": true - }, - "node_modules/grunt": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.5.3.tgz", - "integrity": "sha512-mKwmo4X2d8/4c/BmcOETHek675uOqw0RuA/zy12jaspWqvTp4+ZeQF1W+OTpcbncnaBsfbQJ6l0l4j+Sn/GmaQ==", + "node_modules/lint-staged": { + "version": "16.1.4", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.1.4.tgz", + "integrity": "sha512-xy7rnzQrhTVGKMpv6+bmIA3C0yET31x8OhKBYfvGo0/byeZ6E0BjGARrir3Kg/RhhYHutpsi01+2J5IpfVoueA==", "dev": true, + "license": "MIT", "dependencies": { - "dateformat": "~3.0.3", - "eventemitter2": "~0.4.13", - "exit": "~0.1.2", - "findup-sync": "~0.3.0", - "glob": "~7.1.6", - "grunt-cli": "~1.4.3", - "grunt-known-options": "~2.0.0", - "grunt-legacy-log": "~3.0.0", - "grunt-legacy-util": "~2.0.1", - "iconv-lite": "~0.4.13", - "js-yaml": "~3.14.0", - "minimatch": "~3.0.4", - "mkdirp": "~1.0.4", - "nopt": "~3.0.6", - "rimraf": "~3.0.2" + "chalk": "^5.4.1", + "commander": "^14.0.0", + "debug": "^4.4.1", + "lilconfig": "^3.1.3", + "listr2": "^9.0.1", + "micromatch": "^4.0.8", + "nano-spawn": "^1.0.2", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.8.0" }, "bin": { - "grunt": "bin/grunt" + "lint-staged": "bin/lint-staged.js" }, "engines": { - "node": ">=8" + "node": ">=20.17" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" } }, - "node_modules/grunt-cli": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", - "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=", + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", "dev": true, "license": "MIT", - "dependencies": { - "findup-sync": "~0.3.0", - "grunt-known-options": "~1.1.0", - "nopt": "~3.0.6", - "resolve": "~1.1.0" - }, - "bin": { - "grunt": "bin/grunt" + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/commander": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.0.tgz", + "integrity": "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=20" } }, - "node_modules/grunt-contrib-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-1.0.1.tgz", - "integrity": "sha1-YVCYYwhOhx1+ht5IwBUlntl3Rb0=", + "node_modules/lint-staged/node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^1.0.0", - "source-map": "^0.5.3" + "ms": "^2.1.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0" }, - "peerDependencies": { - "grunt": ">=0.4.0" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/grunt-contrib-connect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/grunt-contrib-connect/-/grunt-contrib-connect-1.0.2.tgz", - "integrity": "sha1-XPkzuRpnOGBEJzwLJERgPNmIebo=", + "node_modules/lint-staged/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.1.tgz", + "integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==", "dev": true, "license": "MIT", "dependencies": { - "async": "^1.5.2", - "connect": "^3.4.0", - "connect-livereload": "^0.5.0", - "http2": "^3.3.4", - "morgan": "^1.6.1", - "opn": "^4.0.0", - "portscanner": "^1.0.0", - "serve-index": "^1.7.1", - "serve-static": "^1.10.0" + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "grunt": ">=0.4.0" + "node": ">=20.0.0" } }, - "node_modules/grunt-contrib-copy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz", - "integrity": "sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM=", + "node_modules/listr2/node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/livereload-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", + "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", + "dev": true, + "license": "MIT" + }, + "node_modules/load-grunt-tasks": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-5.1.0.tgz", + "integrity": "sha512-oNj0Jlka1TsfDe+9He0kcA1cRln+TMoTsEByW7ij6kyktNLxBKJtslCFEvFrLC2Dj0S19IWJh3fOCIjLby2Xrg==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^1.1.1", - "file-sync-cmp": "^0.1.0" + "arrify": "^2.0.1", + "multimatch": "^4.0.0", + "pkg-up": "^3.1.0", + "resolve-pkg": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "peerDependencies": { + "grunt": ">=1" } }, - "node_modules/grunt-contrib-uglify": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-3.4.0.tgz", - "integrity": "sha512-UXsTpeP0pytpTYlmll3RDndsRXfdwmrf1tI/AtD/PrArQAzGmKMvj83aVt3D8egWlE6KqPjsJBLCCvfC52LI/A==", + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^1.0.0", - "maxmin": "^2.1.0", - "uglify-js": "~3.4.0", - "uri-path": "^1.0.0" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/grunt-contrib-uglify/node_modules/commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, + "node_modules/lodash.isfinite": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", + "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==", "dev": true, "license": "MIT" }, - "node_modules/grunt-contrib-uglify/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" + }, + "node_modules/lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==", + "dev": true + }, + "node_modules/lodash.padend": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", + "integrity": "sha512-sOQs2aqGpbl27tmCS1QNZA09Uqp01ZzWfDUoD+xzTii0E7dSQfRKcRetFwa+uXaxaqL+TKm7CgD2JdKP7aZBSw==", + "dev": true + }, + "node_modules/lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==", + "dev": true }, - "node_modules/grunt-contrib-uglify/node_modules/uglify-js": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", - "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "commander": "~2.19.0", - "source-map": "~0.6.1" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=0.8.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/grunt-contrib-watch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.1.0.tgz", - "integrity": "sha512-yGweN+0DW5yM+oo58fRu/XIRrPcn3r4tQx+nL7eMRwjpvk+rQY6R8o94BPK0i2UhTg9FN21hS+m8vR8v9vXfeg==", + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", - "dependencies": { - "async": "^2.6.0", - "gaze": "^1.1.0", - "lodash": "^4.17.10", - "tiny-lr": "^1.1.1" + "engines": { + "node": ">=12" }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/grunt-contrib-watch/node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", "dev": true, + "license": "MIT", "dependencies": { - "lodash": "^4.17.14" + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/grunt-gh-pages": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/grunt-gh-pages/-/grunt-gh-pages-4.0.0.tgz", - "integrity": "sha512-vuU13G0/my6VM6hLYZwnGzNI8jNJiyJprT3vkMp2S3fjBs+etWTo2ldF9mkiH5MuZYkuS2yJ6B3Fy/Tj7fzRzg==", + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", "dev": true, + "license": "MIT", "dependencies": { - "async": "^3.2.0", - "fs-extra": "^8.1.0", - "graceful-fs": "^4.2.3", - "url-safe": "^2.0.0" + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" }, "engines": { - "node": ">=6" + "node": ">=18" }, - "peerDependencies": { - "grunt": ">=0.4.0" + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/grunt-gh-pages/node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true - }, - "node_modules/grunt-jsdoc": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/grunt-jsdoc/-/grunt-jsdoc-2.4.1.tgz", - "integrity": "sha512-S0zxU0wDewRu7z+vijEItOWe/UttxWVmvz0qz2ZVcAYR2GpXjsiski2CAVN0b18t2qeVLdmxZkJaEWCOsKzcAw==", + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.1", - "jsdoc": "^3.6.3" + "ansi-regex": "^6.0.1" }, - "bin": { - "grunt-jsdoc": "bin/grunt-jsdoc" + "engines": { + "node": ">=12" }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/lru-cache": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", + "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", + "dev": true, + "license": "ISC", "engines": { - "node": ">= 8.12.0" + "node": "20 || >=22" } }, - "node_modules/grunt-jsdoc-to-markdown": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/grunt-jsdoc-to-markdown/-/grunt-jsdoc-to-markdown-6.0.0.tgz", - "integrity": "sha512-vvanKUErp6CHl4MuLQ9vwJewpMu8Fi7z09lr4OwMLr+GBu3nG5lRNZuu5mkWY8qv1aU8WkX97/rJaVs3A1Wx8g==", + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, "dependencies": { - "jsdoc-to-markdown": "^7.0.0" + "kind-of": "^6.0.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "grunt": ">=1.3.0" + "node": ">=0.10.0" } }, - "node_modules/grunt-known-options": { - "version": "1.1.0", + "node_modules/make-iterator/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/grunt-legacy-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz", - "integrity": "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==", + "node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", "dev": true, "dependencies": { - "colors": "~1.1.2", - "grunt-legacy-log-utils": "~2.1.0", - "hooker": "~0.2.3", - "lodash": "~4.17.19" + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.6", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.6.tgz", + "integrity": "sha512-jRW30YGywD2ESXDc+l17AiritL0uVaSnWsb26f+68qaW9zgbIIr1f4v2Nsvc0+s0Z2N3uX6t/yAw7BwCQ1wMsA==", + "dev": true, + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/marked": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.5.tgz", + "integrity": "sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ==", + "dev": true, + "bin": { + "marked": "bin/marked.js" }, "engines": { - "node": ">= 0.10.0" + "node": ">= 12" } }, - "node_modules/grunt-legacy-log-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz", - "integrity": "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==", + "node_modules/maxmin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-3.0.0.tgz", + "integrity": "sha512-wcahMInmGtg/7c6a75fr21Ch/Ks1Tb+Jtoan5Ft4bAI0ZvJqyOw8kkM7e7p8hDSzY805vmxwHT50KcjGwKyJ0g==", "dev": true, + "license": "MIT", "dependencies": { - "chalk": "~4.1.0", - "lodash": "~4.17.19" + "chalk": "^4.1.0", + "figures": "^3.2.0", + "gzip-size": "^5.1.1", + "pretty-bytes": "^5.3.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/grunt-legacy-log-utils/node_modules/ansi-styles": { + "node_modules/maxmin/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2214,11 +5501,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/grunt-legacy-log-utils/node_modules/chalk": { + "node_modules/maxmin/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2230,32 +5518,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/grunt-legacy-log-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/maxmin/node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "escape-string-regexp": "^1.0.5" }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/grunt-legacy-log-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/grunt-legacy-log-utils/node_modules/supports-color": { + "node_modules/maxmin/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -2263,2955 +5547,3184 @@ "node": ">=8" } }, - "node_modules/grunt-legacy-util": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz", - "integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==", - "dev": true, - "dependencies": { - "async": "~3.2.0", - "exit": "~0.1.2", - "getobject": "~1.0.0", - "hooker": "~0.2.3", - "lodash": "~4.17.21", - "underscore.string": "~3.3.5", - "which": "~2.0.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/grunt-legacy-util/node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", "dev": true }, - "node_modules/grunt-legacy-util/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, + "license": "MIT", "engines": { "node": ">= 8" } }, - "node_modules/grunt-shell": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/grunt-shell/-/grunt-shell-2.1.0.tgz", - "integrity": "sha1-Q595FZ7RHmSmUaacyKPQK+v17MI=", + "node_modules/metagraph": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/metagraph/-/metagraph-0.0.7.tgz", + "integrity": "sha512-aA2EvUZIMSbwdscFRyJoG3X5yBbehv6MZXe0bhPO3o1ozVi4hMltljuIssQ0/PEyJrAA/WL72Cf3Bkerx6TuGg==", + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^1.0.0", - "npm-run-path": "^2.0.0" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=4" - }, - "peerDependencies": { - "grunt": ">=0.4.0" + "node": ">=8.6" } }, - "node_modules/grunt/node_modules/grunt-cli": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", - "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, - "dependencies": { - "grunt-known-options": "~2.0.0", - "interpret": "~1.1.0", - "liftup": "~3.0.1", - "nopt": "~4.0.1", - "v8flags": "~3.2.0" - }, + "license": "MIT", "bin": { - "grunt": "bin/grunt" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/grunt/node_modules/grunt-cli/node_modules/nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "dev": true, - "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" + "mime": "cli.js" }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/grunt/node_modules/grunt-known-options": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", - "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", - "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/grunt/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "node_modules/mime-db": { + "version": "1.33.0", "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.6" } }, - "node_modules/grunt/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/mime-types": { + "version": "2.1.18", "dev": true, + "license": "MIT", "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "mime-db": "~1.33.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">= 0.6" } }, - "node_modules/gzip-size": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz", - "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=", + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", "dev": true, "license": "MIT", - "dependencies": { - "duplexer": "^0.1.1" - }, "engines": { - "node": ">=0.12.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", "dev": true, "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" + "node": "*" } }, - "node_modules/handlebars/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/har-schema": { - "version": "2.0.0", + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, "license": "ISC", "engines": { - "node": ">=4" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/har-validator": { - "version": "5.1.3", - "license": "MIT", - "dependencies": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - }, + "node_modules/mkdirp2": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/mkdirp2/-/mkdirp2-1.0.5.tgz", + "integrity": "sha512-xOE9xbICroUDmG1ye2h4bZ8WBie9EGmACaco8K8cx6RlkJJrxGIqjGqztAI+NMhexXBcdGbSEzI6N3EJPevxZw==", + "dev": true + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", "engines": { - "node": ">=6" + "node": "*" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.1" + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" }, "engines": { - "node": ">= 0.4.0" + "node": ">= 0.8.0" } }, - "node_modules/has-ansi": { + "node_modules/morgan/node_modules/depd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "license": "ISC" + "license": "MIT" }, - "node_modules/homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "node_modules/multimatch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz", + "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", "dev": true, + "license": "MIT", "dependencies": { - "parse-passwd": "^1.0.0" + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/hooker": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", - "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", + "node_modules/nano-spawn": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-1.0.2.tgz", + "integrity": "sha512-21t+ozMQDAL/UGgQVBbZ/xXvNO10++ZPuTmKRO8k9V3AClVRht49ahtDjfY8l1q6nSHOrE5ASfthzH3ol6R/hg==", "dev": true, + "license": "MIT", "engines": { - "node": "*" + "node": ">=20.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" } }, - "node_modules/htmlparser2": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", - "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^3.0.0", - "domutils": "^2.0.0", - "entities": "^2.0.0" - } + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" }, - "node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "node_modules/negotiator": { + "version": "0.6.1", "dev": true, "license": "MIT", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, "engines": { "node": ">= 0.6" } }, - "node_modules/http-errors/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" + "license": "ISC", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" } }, - "node_modules/http-parser-js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.0.tgz", - "integrity": "sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w==", + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, - "license": "MIT" - }, - "node_modules/http-signature": { - "version": "1.2.0", "license": "MIT", "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "path-key": "^2.0.0" }, "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" + "node": ">=4" } }, - "node_modules/http2": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/http2/-/http2-3.3.7.tgz", - "integrity": "sha512-puSi8M8WNlFJm9Pk4c/Mbz9Gwparuj3gO9/RRO5zv6piQ0FY+9Qywp0PdWshYgsMJSalixFY7eC6oPu0zRxLAQ==", + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "license": "MIT", "engines": { - "node": ">=0.12.0 <9.0.0" + "node": ">=0.10.0" } }, - "node_modules/iconv-lite": { - "version": "0.4.23", + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } + "node_modules/object-get": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-get/-/object-get-2.1.1.tgz", + "integrity": "sha512-7n4IpLMzGGcLEMiQKsNR7vCe+N5E9LORFrtNUVy4sO3dj9a3HedZCxEL2T7QuLhcHN1NBuBsMOKaOsAYI9IIvg==", + "dev": true }, - "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "license": "ISC" + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "node_modules/object-to-spawn-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object-to-spawn-args/-/object-to-spawn-args-2.0.1.tgz", + "integrity": "sha512-6FuKFQ39cOID+BMZ3QaphcC8Y4cw6LXBLyIgPU+OhIYwviJamPAn+4mITapnSBQrejB+NNp+FMskhD8Cq+Ys3w==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } }, - "node_modules/ink-docstrap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/ink-docstrap/-/ink-docstrap-1.3.2.tgz", - "integrity": "sha512-STx5orGQU1gfrkoI/fMU7lX6CSP7LBGO10gXNgOZhwKhUqbtNjCkYSewJtNnLmWP1tAGN6oyEpG1HFPw5vpa5Q==", + "node_modules/object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "dev": true, "dependencies": { - "moment": "^2.14.1", - "sanitize-html": "^1.13.0" + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha512-CLM8SNMDu7C5psFCn6Wg/tgpj/bKAg7hc2gWqcuR9OD5Ft9PhBpIu8PLicPeis+xDd6YX2ncI8MCA64I9tftIA==", - "dev": true - }, - "node_modules/interval-tree-1d": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/interval-tree-1d/-/interval-tree-1d-1.0.4.tgz", - "integrity": "sha512-wY8QJH+6wNI0uh4pDQzMvl+478Qh7Rl4qLmqiluxALlNvl+I+o5x38Pw3/z7mDPTPS1dQalZJXsmbvxx5gclhQ==", + "node_modules/object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", "dev": true, "dependencies": { - "binary-search-bounds": "^2.0.0" + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/ionicons": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-4.6.3.tgz", - "integrity": "sha512-cgP+VIr2cTJpMfFyVHTerq6n2jeoiGboVoe3GlaAo5zoSBDAEXORwUZhv6m+lCyxlsHCS3nqPUE+MKyZU71t8Q==", - "dev": true - }, - "node_modules/is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "dev": true, + "license": "MIT", "dependencies": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" + "isobject": "^3.0.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, + "license": "MIT", "dependencies": { - "has": "^1.0.3" + "ee-first": "1.1.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 0.8" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", "dev": true, "license": "MIT", "dependencies": { - "number-is-nan": "^1.0.0" + "mimic-function": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, "license": "MIT", "dependencies": { - "number-is-nan": "^1.0.0" + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, + "license": "ISC", "dependencies": { - "@types/estree": "*" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, - "node_modules/is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { - "is-unc-path": "^1.0.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/is-unc-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, + "license": "MIT", "dependencies": { - "unc-path-regex": "^0.1.2" + "p-limit": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "license": "ISC" + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/isstream": { - "version": "0.1.2", - "license": "MIT" - }, - "node_modules/jquery": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.3.tgz", - "integrity": "sha512-bZ5Sy3YzKo9Fyc8wH2iIQK4JImJ6R0GWI9kL1/k7Z91ZBNgkRXE6U0JfHIizZbort8ZunhSI3jw9I6253ahKfg==", - "dev": true - }, - "node_modules/jquery-ui-dist": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/jquery-ui-dist/-/jquery-ui-dist-1.12.1.tgz", - "integrity": "sha1-XAgV08xvkP9fqvWyaKbiO0ypBPo=", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "node_modules/parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=0.8" } }, - "node_modules/js2xmlparser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", - "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "node_modules/parse-ms": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz", + "integrity": "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0=", "dev": true, - "dependencies": { - "xmlcreate": "^2.0.4" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/jsbn": { - "version": "0.1.1", - "license": "MIT" - }, - "node_modules/jsdifflib": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsdifflib/-/jsdifflib-1.1.0.tgz", - "integrity": "sha1-LY1UsqQ+z9aAdKveIlgtixK9q/M=", + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", "dev": true, - "license": "BSD" + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/jsdoc": { - "version": "3.6.11", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.11.tgz", - "integrity": "sha512-8UCU0TYeIYD9KeLzEcAu2q8N/mx9O3phAGl32nmHlE0LpaJL71mMkP4d+QE5zWfNt50qheHtOZ0qoxVrsX5TUg==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.9.4", - "@types/markdown-it": "^12.2.3", - "bluebird": "^3.7.2", - "catharsis": "^0.9.0", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.2", - "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", - "marked": "^4.0.10", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "taffydb": "2.6.2", - "underscore": "~1.13.2" - }, - "bin": { - "jsdoc": "jsdoc.js" - }, + "node_modules/parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12.0.0" + "node": ">= 0.8" } }, - "node_modules/jsdoc-api": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-7.2.0.tgz", - "integrity": "sha512-93YDnlm/OYTlLOFeNs4qAv0RBCJ0kGj67xQaWy8wrbk97Rw1EySitoOTHsTHXPEs3uyx2IStPKGrbE7LTnZXbA==", + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "dev": true, - "dependencies": { - "array-back": "^6.2.2", - "cache-point": "^2.0.0", - "collect-all": "^1.0.4", - "file-set": "^4.0.2", - "fs-then-native": "^2.0.0", - "jsdoc": "^4.0.0", - "object-to-spawn-args": "^2.0.1", - "temp-path": "^1.0.0", - "walk-back": "^5.1.0" - }, + "license": "MIT", "engines": { - "node": ">=12.17" + "node": ">=4" } }, - "node_modules/jsdoc-api/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jsdoc-api/node_modules/jsdoc": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.0.tgz", - "integrity": "sha512-tzTgkklbWKrlaQL2+e3NNgLcZu3NaK2vsHRx7tyHQ+H5jcB9Gx0txSd2eJWlMC/xU1+7LQu4s58Ry0RkuaEQVg==", + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true, - "dependencies": { - "@babel/parser": "^7.9.4", - "@jsdoc/salty": "^0.2.1", - "@types/markdown-it": "^12.2.3", - "bluebird": "^3.7.2", - "catharsis": "^0.9.0", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.2", - "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", - "marked": "^4.0.10", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "underscore": "~1.13.2" - }, - "bin": { - "jsdoc": "jsdoc.js" - }, + "license": "MIT", "engines": { - "node": ">=12.0.0" + "node": ">=4" } }, - "node_modules/jsdoc-api/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" + "dependencies": { + "path-root-regex": "^0.1.0" }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/jsdoc-parse": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-6.2.0.tgz", - "integrity": "sha512-Afu1fQBEb7QHt6QWX/6eUWvYHJofB90Fjx7FuJYF7mnG9z5BkAIpms1wsnvYLytfmqpEENHs/fax9p8gvMj7dw==", + "node_modules/path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", "dev": true, - "dependencies": { - "array-back": "^6.2.2", - "lodash.omit": "^4.5.0", - "lodash.pick": "^4.4.0", - "reduce-extract": "^1.0.0", - "sort-array": "^4.1.5", - "test-value": "^3.0.0" - }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/jsdoc-to-markdown": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-7.1.1.tgz", - "integrity": "sha512-CI86d63xAVNO+ENumWwmJ034lYe5iGU5GwjtTA11EuphP9tpnoi4hrKgR/J8uME0D+o4KUpVfwX1fjZhc8dEtg==", + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "array-back": "^6.2.2", - "command-line-tool": "^0.8.0", - "config-master": "^3.1.0", - "dmd": "^6.1.0", - "jsdoc-api": "^7.1.1", - "jsdoc-parse": "^6.1.0", - "walk-back": "^5.1.0" - }, - "bin": { - "jsdoc2md": "bin/cli.js" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=12.17" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jsdoc/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/jsdoc/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", "dev": true, + "license": "MIT", "bin": { - "mkdirp": "bin/cmd.js" + "pidtree": "bin/pidtree.js" }, "engines": { - "node": ">=10" + "node": ">=0.10" } }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "license": "MIT" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "license": "ISC" - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dev": true, + "license": "MIT", "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" + "find-up": "^3.0.0" }, "engines": { - "node": ">=0.6.0" + "node": ">=8" } }, - "node_modules/klaw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", - "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "node_modules/plur": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/plur/-/plur-1.0.0.tgz", + "integrity": "sha1-24XGgU9eXlo7Se/CjWBP7GKXUVY=", "dev": true, - "dependencies": { - "graceful-fs": "^4.1.9" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/liftup": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", - "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", + "node_modules/portscanner": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.2.0.tgz", + "integrity": "sha512-IFroCz/59Lqa2uBvzK3bKDbDDIEaAY8XJ1jFxcLWTqosrsc32//P4VuSB2vZXoHiHqOmx8B5L5hnKOxL/7FlPw==", "dev": true, + "license": "MIT", "dependencies": { - "extend": "^3.0.2", - "findup-sync": "^4.0.0", - "fined": "^1.2.0", - "flagged-respawn": "^1.0.1", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.1", - "rechoir": "^0.7.0", - "resolve": "^1.19.0" + "async": "^2.6.0", + "is-number-like": "^1.0.3" }, "engines": { - "node": ">=10" + "node": ">=0.4", + "npm": ">=1.0.0" } }, - "node_modules/liftup/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "node_modules/portscanner/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" + "lodash": "^4.17.14" } }, - "node_modules/liftup/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, + "node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dependencies": { - "to-regex-range": "^5.0.1" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">=8" + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/liftup/node_modules/findup-sync": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", - "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "node_modules/postcss/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, - "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^4.0.2", - "resolve-dir": "^1.0.1" - }, + "license": "MIT", "engines": { - "node": ">= 8" + "node": ">= 0.8.0" } }, - "node_modules/liftup/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/liftup/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "node_modules/pretty-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz", + "integrity": "sha1-QlfCVt8/sLRR1q/6qwIYhBJpgdw=", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" + "is-finite": "^1.0.1", + "parse-ms": "^1.0.0", + "plur": "^1.0.0" }, "engines": { - "node": ">=8.6" + "node": ">=0.10.0" } }, - "node_modules/liftup/node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "node_modules/promise-polyfill": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.3.tgz", + "integrity": "sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/liftup/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dev": true, "dependencies": { - "is-number": "^7.0.0" + "side-channel": "^1.0.4" }, "engines": { - "node": ">=8.0" + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "dev": true, - "dependencies": { - "uc.micro": "^1.0.1" - } + "node_modules/queue-async": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/queue-async/-/queue-async-1.2.1.tgz", + "integrity": "sha1-BYLgHa4lMljPV2/Co125b8qEf28=", + "license": "BSD-3-Clause" }, - "node_modules/livereload-js": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", - "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT" }, - "node_modules/load-grunt-tasks": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-3.5.2.tgz", - "integrity": "sha1-ByhWEYD9IP+KaSdQWFL8WKrqDIg=", + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", "dev": true, "license": "MIT", - "dependencies": { - "arrify": "^1.0.0", - "multimatch": "^2.0.0", - "pkg-up": "^1.0.0", - "resolve-pkg": "^0.1.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=10" }, - "peerDependencies": { - "grunt": ">=0.4.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "dev": true - }, - "node_modules/lodash.omit": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", - "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==", - "dev": true - }, - "node_modules/lodash.padend": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", - "integrity": "sha512-sOQs2aqGpbl27tmCS1QNZA09Uqp01ZzWfDUoD+xzTii0E7dSQfRKcRetFwa+uXaxaqL+TKm7CgD2JdKP7aZBSw==", - "dev": true - }, - "node_modules/lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==", - "dev": true - }, - "node_modules/lodash.result": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/lodash.result/-/lodash.result-4.5.2.tgz", - "integrity": "sha512-dlgJvozORK2oE4jXzTGIsJz9Vk6huNAINxYYvWc/R44x3/ah/F7OkNwr9c0wO2poh2cbdjS0jF3j8VgyCEOVfw==" - }, - "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, - "dependencies": { - "sourcemap-codec": "^1.4.8" + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "node_modules/make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "node_modules/raw-body": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", + "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=", "dev": true, + "license": "MIT", "dependencies": { - "kind-of": "^6.0.2" + "bytes": "1", + "string_decoder": "0.10" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/make-iterator/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/raw-body/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", "dev": true, - "license": "MIT", + "dependencies": { + "resolve": "^1.9.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.10" } }, - "node_modules/markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "node_modules/rechoir/node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, "dependencies": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { - "markdown-it": "bin/markdown-it.js" + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/markdown-it-anchor": { - "version": "8.6.6", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.6.tgz", - "integrity": "sha512-jRW30YGywD2ESXDc+l17AiritL0uVaSnWsb26f+68qaW9zgbIIr1f4v2Nsvc0+s0Z2N3uX6t/yAw7BwCQ1wMsA==", + "node_modules/reduce-extract": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/reduce-extract/-/reduce-extract-1.0.0.tgz", + "integrity": "sha512-QF8vjWx3wnRSL5uFMyCjDeDc5EBMiryoT9tz94VvgjKfzecHAVnqmXAwQDcr7X4JmLc2cjkjFGCVzhMqDjgR9g==", "dev": true, - "peerDependencies": { - "@types/markdown-it": "*", - "markdown-it": "*" + "dependencies": { + "test-value": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/markdown-it/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/marked": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.5.tgz", - "integrity": "sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ==", + "node_modules/reduce-extract/node_modules/array-back": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", + "integrity": "sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw==", "dev": true, - "bin": { - "marked": "bin/marked.js" + "dependencies": { + "typical": "^2.6.0" }, "engines": { - "node": ">= 12" + "node": ">=0.12.0" } }, - "node_modules/maxmin": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz", - "integrity": "sha1-TTsiCQPZXu5+t6x/qGTnLcCaMWY=", + "node_modules/reduce-extract/node_modules/test-value": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/test-value/-/test-value-1.1.0.tgz", + "integrity": "sha512-wrsbRo7qP+2Je8x8DsK8ovCGyxe3sYfQwOraIY/09A2gFXU9DYKiTF14W4ki/01AEh56kMzAmlj9CaHGDDUBJA==", "dev": true, - "license": "MIT", "dependencies": { - "chalk": "^1.0.0", - "figures": "^1.0.1", - "gzip-size": "^3.0.0", - "pretty-bytes": "^3.0.0" + "array-back": "^1.0.2", + "typical": "^2.4.2" }, "engines": { - "node": ">=0.12" + "node": ">=0.10.0" } }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true - }, - "node_modules/metagraph": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/metagraph/-/metagraph-0.0.7.tgz", - "integrity": "sha512-aA2EvUZIMSbwdscFRyJoG3X5yBbehv6MZXe0bhPO3o1ozVi4hMltljuIssQ0/PEyJrAA/WL72Cf3Bkerx6TuGg==", - "license": "MIT" - }, - "node_modules/mime": { - "version": "1.4.1", + "node_modules/reduce-flatten": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-3.0.1.tgz", + "integrity": "sha512-bYo+97BmUUOzg09XwfkwALt4PQH1M5L0wzKerBt6WLm3Fhdd43mMS89HiT1B9pJIqko/6lWx3OnV4J9f2Kqp5Q==", "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" + "engines": { + "node": ">=8" } }, - "node_modules/mime-db": { - "version": "1.33.0", - "license": "MIT", + "node_modules/reduce-unique": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/reduce-unique/-/reduce-unique-2.0.1.tgz", + "integrity": "sha512-x4jH/8L1eyZGR785WY+ePtyMNhycl1N2XOLxhCbzZFaqF4AXjLzqSxa2UHgJ2ZVR/HHyPOvl1L7xRnW8ye5MdA==", + "dev": true, "engines": { - "node": ">= 0.6" + "node": ">=6" } }, - "node_modules/mime-types": { - "version": "2.1.18", - "license": "MIT", + "node_modules/reduce-without": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/reduce-without/-/reduce-without-1.0.1.tgz", + "integrity": "sha512-zQv5y/cf85sxvdrKPlfcRzlDn/OqKFThNimYmsS3flmkioKvkUGn2Qg9cJVoQiEvdxFGLE0MQER/9fZ9sUqdxg==", + "dev": true, "dependencies": { - "mime-db": "~1.33.0" + "test-value": "^2.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/minimatch": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", - "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "node_modules/reduce-without/node_modules/array-back": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", + "integrity": "sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw==", + "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "typical": "^2.6.0" }, "engines": { - "node": "*" + "node": ">=0.12.0" } }, - "node_modules/minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/reduce-without/node_modules/test-value": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz", + "integrity": "sha512-+1epbAxtKeXttkGFMTX9H42oqzOTufR1ceCF+GYA5aOmvaPq9wd4PUS8329fn2RRLGNeUkgRLnVpycjx8DsO2w==", + "dev": true, + "dependencies": { + "array-back": "^1.0.3", + "typical": "^2.6.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "node_modules/requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "dev": true, "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" + "lodash": "^4.17.21" } }, - "node_modules/mkdirp2": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/mkdirp2/-/mkdirp2-1.0.5.tgz", - "integrity": "sha512-xOE9xbICroUDmG1ye2h4bZ8WBie9EGmACaco8K8cx6RlkJJrxGIqjGqztAI+NMhexXBcdGbSEzI6N3EJPevxZw==", - "dev": true + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "license": "MIT" }, - "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/morgan": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", - "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "license": "MIT", - "dependencies": { - "basic-auth": "~2.0.0", - "debug": "2.6.9", - "depd": "~1.1.2", - "on-finished": "~2.3.0", - "on-headers": "~1.0.1" - }, "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/ms": { + "node_modules/resolve-pkg": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true, - "license": "MIT" - }, - "node_modules/multimatch": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", - "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", + "resolved": "https://registry.npmjs.org/resolve-pkg/-/resolve-pkg-2.0.0.tgz", + "integrity": "sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ==", "dev": true, "license": "MIT", "dependencies": { - "array-differ": "^1.0.0", - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "minimatch": "^3.0.0" + "resolve-from": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/nan": { - "version": "2.12.1", - "license": "MIT" - }, - "node_modules/nbind": { - "version": "0.3.15", + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, "license": "MIT", - "os": [ - "android", - "darwin", - "linux", - "win32" - ], "dependencies": { - "emscripten-library-decorator": "~0.2.2", - "mkdirp": "~0.5.1", - "nan": "^2.9.2" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, - "bin": { - "copyasm": "bin/copyasm.js", - "emcc-path": "bin/emcc-path.js", - "ndts": "bin/ndts.js" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/negotiator": { - "version": "0.6.1", + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" }, - "node_modules/node-gyp": { - "version": "3.8.0", + "node_modules/rollup": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.0.tgz", + "integrity": "sha512-qHcdEzLCiktQIfwBq420pn2dP+30uzqYxv9ETm91wdt2R9AFcWfjNAmje4NWlnCIQ5RMTzVf0ZyisOKqHR6RwA==", + "devOptional": true, "license": "MIT", "dependencies": { - "fstream": "^1.0.0", - "glob": "^7.0.3", - "graceful-fs": "^4.1.2", - "mkdirp": "^0.5.0", - "nopt": "2 || 3", - "npmlog": "0 || 1 || 2 || 3 || 4", - "osenv": "0", - "request": "^2.87.0", - "rimraf": "2", - "semver": "~5.3.0", - "tar": "^2.0.0", - "which": "1" + "@types/estree": "1.0.8" }, "bin": { - "node-gyp": "bin/node-gyp.js" + "rollup": "dist/bin/rollup" }, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/node-gyp/node_modules/semver": { - "version": "5.3.0", - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "license": "ISC", - "dependencies": { - "abbrev": "1" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, - "bin": { - "nopt": "bin/nopt.js" + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.44.0", + "@rollup/rollup-android-arm64": "4.44.0", + "@rollup/rollup-darwin-arm64": "4.44.0", + "@rollup/rollup-darwin-x64": "4.44.0", + "@rollup/rollup-freebsd-arm64": "4.44.0", + "@rollup/rollup-freebsd-x64": "4.44.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.44.0", + "@rollup/rollup-linux-arm-musleabihf": "4.44.0", + "@rollup/rollup-linux-arm64-gnu": "4.44.0", + "@rollup/rollup-linux-arm64-musl": "4.44.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.44.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.44.0", + "@rollup/rollup-linux-riscv64-gnu": "4.44.0", + "@rollup/rollup-linux-riscv64-musl": "4.44.0", + "@rollup/rollup-linux-s390x-gnu": "4.44.0", + "@rollup/rollup-linux-x64-gnu": "4.44.0", + "@rollup/rollup-linux-x64-musl": "4.44.0", + "@rollup/rollup-win32-arm64-msvc": "4.44.0", + "@rollup/rollup-win32-ia32-msvc": "4.44.0", + "@rollup/rollup-win32-x64-msvc": "4.44.0", + "fsevents": "~2.3.2" } }, - "node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "node_modules/rollup-plugin-copy": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.5.0.tgz", + "integrity": "sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==", "dev": true, "license": "MIT", "dependencies": { - "path-key": "^2.0.0" + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "license": "ISC", - "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "node": ">=8.3" } }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "node_modules/rollup-plugin-copy/node_modules/is-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "license": "Apache-2.0", - "engines": { - "node": "*" - } + "node_modules/rollup/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.0.tgz", + "integrity": "sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "node_modules/rollup/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.0.tgz", + "integrity": "sha512-fBkyrDhwquRvrTxSGH/qqt3/T0w5Rg0L7ZIDypvBPc1/gzjJle6acCpZ36blwuwcKD/u6oCE/sRWlUAcxLWQbQ==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/object-get": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/object-get/-/object-get-2.1.1.tgz", - "integrity": "sha512-7n4IpLMzGGcLEMiQKsNR7vCe+N5E9LORFrtNUVy4sO3dj9a3HedZCxEL2T7QuLhcHN1NBuBsMOKaOsAYI9IIvg==", - "dev": true + "node_modules/rollup/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.0.tgz", + "integrity": "sha512-ZTR2mxBHb4tK4wGf9b8SYg0Y6KQPjGpR4UWwTFdnmjB4qRtoATZ5dWn3KsDwGa5Z2ZBOE7K52L36J9LueKBdOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "node_modules/rollup/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.0.tgz", + "integrity": "sha512-GFWfAhVhWGd4r6UxmnKRTBwP1qmModHtd5gkraeW2G490BpFOZkFtem8yuX2NyafIP/mGpRJgTJ2PwohQkUY/Q==", + "cpu": [ + "arm64" + ], "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/object-to-spawn-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object-to-spawn-args/-/object-to-spawn-args-2.0.1.tgz", - "integrity": "sha512-6FuKFQ39cOID+BMZ3QaphcC8Y4cw6LXBLyIgPU+OhIYwviJamPAn+4mITapnSBQrejB+NNp+FMskhD8Cq+Ys3w==", + "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.0.tgz", + "integrity": "sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==", + "cpu": [ + "x64" + ], "dev": true, - "engines": { - "node": ">=8.0.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/object.defaults": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.0.tgz", + "integrity": "sha512-PQUobbhLTQT5yz/SPg116VJBgz+XOtXt8D1ck+sfJJhuEsMj2jSej5yTdp8CvWBSceu+WW+ibVL6dm0ptG5fcA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/object.map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", + "node_modules/rollup/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.0.tgz", + "integrity": "sha512-M0CpcHf8TWn+4oTxJfh7LQuTuaYeXGbk0eageVjQCKzYLsajWS/lFC94qlRqOlyC2KvRT90ZrfXULYmukeIy7w==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "node_modules/rollup/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.0.tgz", + "integrity": "sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/rollup/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=0.10.0" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" + "queue-microtask": "^1.2.2" } }, - "node_modules/on-headers": { - "version": "1.0.1", + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } + "license": "MIT" }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "license": "ISC", + "node_modules/safe-json-parse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", + "integrity": "sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=", + "dev": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sanitize-html": { + "version": "1.27.5", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-1.27.5.tgz", + "integrity": "sha512-M4M5iXDAUEcZKLXkmk90zSYWEtk5NH3JmojQxKxV371fnMh+x9t1rqdmXaGoyEHw3z/X/8vnFhKjGL5xFGOJ3A==", "dependencies": { - "wrappy": "1" + "htmlparser2": "^4.1.0", + "lodash": "^4.17.15", + "parse-srcset": "^1.0.2", + "postcss": "^7.0.27" } }, - "node_modules/opn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", - "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "license": "MIT", "dependencies": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "node_modules/send/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "node_modules/send/node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "license": "ISC", - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } + "node_modules/send/node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" }, - "node_modules/parse-filepath": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, - "dependencies": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" - }, - "engines": { - "node": ">=0.8" - } + "license": "MIT" }, - "node_modules/parse-ms": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz", - "integrity": "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0=", + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "node_modules/send/node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse-srcset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", - "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" + "license": "ISC" }, - "node_modules/parseurl": { - "version": "1.3.2", + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", "dev": true, "license": "MIT", "dependencies": { - "pinkie-promise": "^2.0.0" + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">= 0.8" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true, + "license": "ISC" }, - "node_modules/path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "dependencies": { - "path-root-regex": "^0.1.0" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dev": true, - "engines": { - "node": ">=0.10.0" + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/performance-now": { - "version": "2.1.0", - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { - "node": ">=8.6" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "dev": true, "license": "MIT", "dependencies": { - "pinkie": "^2.0.0" + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "node_modules/pkg-up": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", - "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, "license": "MIT", - "dependencies": { - "find-up": "^1.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/plur": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/plur/-/plur-1.0.0.tgz", - "integrity": "sha1-24XGgU9eXlo7Se/CjWBP7GKXUVY=", + "node_modules/sort-array": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-4.1.5.tgz", + "integrity": "sha512-Ya4peoS1fgFN42RN1REk2FgdNOeLIEMKFGJvs7VTP3OklF8+kl2SkpVliZ4tk/PurWsrWRsdNdU+tgyOBkB9sA==", "dev": true, - "license": "MIT", + "dependencies": { + "array-back": "^5.0.0", + "typical": "^6.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/portscanner": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-1.2.0.tgz", - "integrity": "sha1-sUu9olfRTDEPqcwJaCrwLUCWGAI=", + "node_modules/sort-array/node_modules/array-back": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-5.0.0.tgz", + "integrity": "sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==", "dev": true, - "dependencies": { - "async": "1.5.2" - }, "engines": { - "node": ">=0.4", - "npm": ">=1.0.0" + "node": ">=10" } }, - "node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, + "node_modules/sort-array/node_modules/typical": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-6.0.1.tgz", + "integrity": "sha512-+g3NEp7fJLe9DPa1TArHm9QAA7YciZmWnfAqEaFrBihQ7epOv9i99rjtgb6Iz0wh3WuQDjsCTDfgRoGnmHN81A==", + "dev": true, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">=10" } }, - "node_modules/postcss/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/pretty-bytes": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz", - "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=", + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stream-connect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-connect/-/stream-connect-1.0.2.tgz", + "integrity": "sha512-68Kl+79cE0RGKemKkhxTSg8+6AGrqBt+cbZAXevg2iJ6Y3zX4JhA/sZeGzLpxW9cXhmqAcE7KnJCisUmIUfnFQ==", + "dev": true, "dependencies": { - "number-is-nan": "^1.0.0" + "array-back": "^1.0.2" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/pretty-ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz", - "integrity": "sha1-QlfCVt8/sLRR1q/6qwIYhBJpgdw=", + "node_modules/stream-connect/node_modules/array-back": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", + "integrity": "sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw==", "dev": true, - "license": "MIT", "dependencies": { - "is-finite": "^1.0.1", - "parse-ms": "^1.0.0", - "plur": "^1.0.0" + "typical": "^2.6.0" }, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/stream-via": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/stream-via/-/stream-via-1.0.4.tgz", + "integrity": "sha512-DBp0lSvX5G9KGRDTkR/R+a29H+Wk2xItOF+MpZLLNDWbEV9tGPnqLPxHEYjmiz8xGtJHRIqmI+hCjmNzqoA4nQ==", + "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "license": "MIT" + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } }, - "node_modules/promise-polyfill": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.3.tgz", - "integrity": "sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg==", + "node_modules/string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", "dev": true }, - "node_modules/psl": { - "version": "1.1.31", - "license": "MIT" - }, - "node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "license": "MIT" - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, + "license": "MIT", "dependencies": { - "side-channel": "^1.0.4" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=0.6" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/queue-async": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/queue-async/-/queue-async-1.2.1.tgz", - "integrity": "sha1-BYLgHa4lMljPV2/Co125b8qEf28=", - "license": "BSD-3-Clause" - }, - "node_modules/range-parser": { - "version": "1.2.0", + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/raw-body": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", - "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=", + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", - "dependencies": { - "bytes": "1", - "string_decoder": "0.10" - }, "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/raw-body/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, - "node_modules/readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "engines": { + "node": ">=8" } }, - "node_modules/readable-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "dependencies": { - "resolve": "^1.9.0" - }, + "license": "MIT", "engines": { - "node": ">= 0.10" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/rechoir/node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "ansi-regex": "^6.0.1" }, - "bin": { - "resolve": "bin/resolve" + "engines": { + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/reduce-extract": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/reduce-extract/-/reduce-extract-1.0.0.tgz", - "integrity": "sha512-QF8vjWx3wnRSL5uFMyCjDeDc5EBMiryoT9tz94VvgjKfzecHAVnqmXAwQDcr7X4JmLc2cjkjFGCVzhMqDjgR9g==", + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, + "license": "MIT", "dependencies": { - "test-value": "^1.0.1" + "ansi-regex": "^2.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/reduce-extract/node_modules/array-back": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", - "integrity": "sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw==", + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { - "typical": "^2.6.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=0.12.0" + "node": ">=8" } }, - "node_modules/reduce-extract/node_modules/test-value": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/test-value/-/test-value-1.1.0.tgz", - "integrity": "sha512-wrsbRo7qP+2Je8x8DsK8ovCGyxe3sYfQwOraIY/09A2gFXU9DYKiTF14W4ki/01AEh56kMzAmlj9CaHGDDUBJA==", + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "dependencies": { - "array-back": "^1.0.2", - "typical": "^2.4.2" - }, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/reduce-flatten": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-3.0.1.tgz", - "integrity": "sha512-bYo+97BmUUOzg09XwfkwALt4PQH1M5L0wzKerBt6WLm3Fhdd43mMS89HiT1B9pJIqko/6lWx3OnV4J9f2Kqp5Q==", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/reduce-unique": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/reduce-unique/-/reduce-unique-2.0.1.tgz", - "integrity": "sha512-x4jH/8L1eyZGR785WY+ePtyMNhycl1N2XOLxhCbzZFaqF4AXjLzqSxa2UHgJ2ZVR/HHyPOvl1L7xRnW8ye5MdA==", + "node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.8.0" } }, - "node_modules/reduce-without": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/reduce-without/-/reduce-without-1.0.1.tgz", - "integrity": "sha512-zQv5y/cf85sxvdrKPlfcRzlDn/OqKFThNimYmsS3flmkioKvkUGn2Qg9cJVoQiEvdxFGLE0MQER/9fZ9sUqdxg==", + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, - "dependencies": { - "test-value": "^2.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/reduce-without/node_modules/array-back": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", - "integrity": "sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw==", + "node_modules/table-layout": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-0.4.5.tgz", + "integrity": "sha512-zTvf0mcggrGeTe/2jJ6ECkJHAQPIYEwDoqsiqBjI24mvRmQbInK5jq33fyypaCBxX08hMkfmdOqj6haT33EqWw==", "dev": true, "dependencies": { - "typical": "^2.6.0" + "array-back": "^2.0.0", + "deep-extend": "~0.6.0", + "lodash.padend": "^4.6.1", + "typical": "^2.6.1", + "wordwrapjs": "^3.0.0" }, "engines": { - "node": ">=0.12.0" + "node": ">=4.0.0" } }, - "node_modules/reduce-without/node_modules/test-value": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz", - "integrity": "sha512-+1epbAxtKeXttkGFMTX9H42oqzOTufR1ceCF+GYA5aOmvaPq9wd4PUS8329fn2RRLGNeUkgRLnVpycjx8DsO2w==", + "node_modules/table-layout/node_modules/array-back": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", + "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", "dev": true, "dependencies": { - "array-back": "^1.0.3", - "typical": "^2.6.0" + "typical": "^2.6.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/request": { - "version": "2.88.0", - "license": "Apache-2.0", + "node_modules/taffydb": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", + "integrity": "sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA==", + "dev": true + }, + "node_modules/temp-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-path/-/temp-path-1.0.0.tgz", + "integrity": "sha512-TvmyH7kC6ZVTYkqCODjJIbgvu0FKiwQpZ4D1aknE7xpcDf/qEOB8KZEK5ef2pfbVoiBhNWs3yx4y+ESMtNYmlg==", + "dev": true + }, + "node_modules/test-value": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/test-value/-/test-value-3.0.0.tgz", + "integrity": "sha512-sVACdAWcZkSU9x7AOmJo5TqE+GyNJknHaHsMrR6ZnhjVlVN9Yx6FjHrsKZ3BjIpPCT68zYesPWkakrNupwfOTQ==", + "dev": true, "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" + "array-back": "^2.0.0", + "typical": "^2.6.1" }, "engines": { - "node": ">= 4" + "node": ">=4.0.0" } }, - "node_modules/request/node_modules/mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", - "license": "MIT", + "node_modules/test-value/node_modules/array-back": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", + "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "dev": true, + "dependencies": { + "typical": "^2.6.1" + }, "engines": { - "node": ">= 0.6" + "node": ">=4" } }, - "node_modules/request/node_modules/mime-types": { - "version": "2.1.24", + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true, + "license": "MIT" + }, + "node_modules/time-grunt": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/time-grunt/-/time-grunt-1.4.0.tgz", + "integrity": "sha1-BiIT5mDJB+hvRAVWwB6mWXtxJCA=", + "dev": true, "license": "MIT", "dependencies": { - "mime-db": "1.40.0" + "chalk": "^1.0.0", + "date-time": "^1.1.0", + "figures": "^1.0.0", + "hooker": "^0.2.3", + "number-is-nan": "^1.0.0", + "pretty-ms": "^2.1.0", + "text-table": "^0.2.0" }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "node_modules/time-zone": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-0.1.0.tgz", + "integrity": "sha1-Sncotqwo2w4Aj1FAQ/1VW9VXO0Y=", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.6" + "node": ">=0.10.0" } }, - "node_modules/requizzle": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", - "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "node_modules/tiny-lr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", + "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", "dev": true, + "license": "MIT", "dependencies": { - "lodash": "^4.17.21" + "body": "^5.1.0", + "debug": "^3.1.0", + "faye-websocket": "~0.10.0", + "livereload-js": "^2.3.0", + "object-assign": "^4.1.0", + "qs": "^6.4.0" } }, - "node_modules/resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "node_modules/tiny-lr/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/tiny-lr/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true, "license": "MIT" }, - "node_modules/resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "node_modules/tippy.js": { + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", + "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", + "license": "MIT", + "dependencies": { + "@popperjs/core": "^2.9.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" + "is-number": "^7.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.0" } }, - "node_modules/resolve-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=0.6" } }, - "node_modules/resolve-pkg": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/resolve-pkg/-/resolve-pkg-0.1.0.tgz", - "integrity": "sha1-AsyZNBDik2livZcWahsHfalyVTE=", + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", "dependencies": { - "resolve-from": "^2.0.0" + "prelude-ls": "^1.2.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/rimraf": { - "version": "2.2.8", - "license": "MIT", - "bin": { - "rimraf": "bin.js" - } + "node_modules/typical": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz", + "integrity": "sha512-ofhi8kjIje6npGozTip9Fr8iecmYfEbS06i0JnIg+rh51KakryWF4+jX8lLKZVhy6N+ID45WYSFCxPOdTWCzNg==", + "dev": true }, - "node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", "dev": true, "bin": { - "rollup": "dist/bin/rollup" + "uglifyjs": "bin/uglifyjs" }, "engines": { - "node": ">=10.0.0" + "node": ">=0.8.0" + } + }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, + "node_modules/underscore.string": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.6.tgz", + "integrity": "sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ==", + "dev": true, + "dependencies": { + "sprintf-js": "^1.1.1", + "util-deprecate": "^1.0.2" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "engines": { + "node": "*" } }, - "node_modules/rollup-plugin-commonjs": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz", - "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-commonjs.", + "node_modules/underscore.string/node_modules/sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, + "node_modules/undici-types": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", "dev": true, - "dependencies": { - "estree-walker": "^0.6.1", - "is-reference": "^1.1.2", - "magic-string": "^0.25.2", - "resolve": "^1.11.0", - "rollup-pluginutils": "^2.8.1" - }, - "peerDependencies": { - "rollup": ">=1.12.0" - } + "license": "MIT" }, - "node_modules/rollup-plugin-commonjs/node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 4.0.0" } }, - "node_modules/rollup-plugin-node-resolve": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-2.1.1.tgz", - "integrity": "sha1-y7eDsNFbAnlNWJFTULLw2QK43cg=", + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, "license": "MIT", - "dependencies": { - "browser-resolve": "^1.11.0", - "builtin-modules": "^1.1.0", - "resolve": "^1.1.6" + "engines": { + "node": ">= 0.8" } }, - "node_modules/rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "estree-walker": "^0.6.1" + "punycode": "^2.1.0" } }, - "node_modules/rollup/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "node_modules/uri-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", + "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], + "license": "WTFPL OR MIT", "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">= 0.10" } }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "dev": true - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "node_modules/url-safe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/url-safe/-/url-safe-2.0.0.tgz", + "integrity": "sha1-3NRt5GZqdUbuQ+qQasF12qYm3p4=", + "dev": true, "license": "MIT" }, - "node_modules/safe-json-parse": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", - "integrity": "sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=", - "dev": true - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true, "license": "MIT" }, - "node_modules/sanitize-html": { - "version": "1.27.5", - "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-1.27.5.tgz", - "integrity": "sha512-M4M5iXDAUEcZKLXkmk90zSYWEtk5NH3JmojQxKxV371fnMh+x9t1rqdmXaGoyEHw3z/X/8vnFhKjGL5xFGOJ3A==", - "dependencies": { - "htmlparser2": "^4.1.0", - "lodash": "^4.17.15", - "parse-srcset": "^1.0.2", - "postcss": "^7.0.27" + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" } }, - "node_modules/send": { - "version": "0.16.2", + "node_modules/v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", "dev": true, - "license": "MIT", "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" + "homedir-polyfill": "^1.0.1" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 0.10" } }, - "node_modules/send/node_modules/statuses": { - "version": "1.4.0", + "node_modules/viz.js": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/viz.js/-/viz.js-1.8.2.tgz", + "integrity": "sha512-W+1+N/hdzLpQZEcvz79n2IgUE9pfx6JLdHh3Kh8RGvLL8P1LdJVQmi2OsDcLdY4QVID4OUy+FPelyerX0nJxIQ==", + "license": "MIT" + }, + "node_modules/walk-back": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-5.1.0.tgz", + "integrity": "sha512-Uhxps5yZcVNbLEAnb+xaEEMdgTXl9qAQDzKYejG2AZ7qPwRQ81lozY9ECDbjLPNWm7YsO1IK5rsP1KoQzXAcGA==", "dev": true, - "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=12.17" } }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dev": true, + "node_modules/webcola": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/webcola/-/webcola-3.4.0.tgz", + "integrity": "sha512-4BiLXjXw3SJHo3Xd+rF+7fyClT6n7I+AR6TkBqyQ4kTsePSAMDLRCXY1f3B/kXJeP9tYn4G1TblxTO+jAt0gaw==", "license": "MIT", "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "engines": { - "node": ">= 0.8.0" + "d3-dispatch": "^1.0.3", + "d3-drag": "^1.0.4", + "d3-shape": "^1.3.5", + "d3-timer": "^1.0.5" } }, - "node_modules/serve-static": { - "version": "1.13.2", - "dev": true, - "license": "MIT", + "node_modules/webcola/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.2", - "send": "0.16.2" - }, - "engines": { - "node": ">= 0.8.0" + "d3-path": "1" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "license": "ISC" - }, - "node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/websocket-driver": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", + "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", "dev": true, + "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "http-parser-js": ">=0.4.0", + "websocket-extensions": ">=0.1.1" }, "engines": { - "node": ">=8" + "node": ">=0.8.0" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=0.8.0" } }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "node_modules/which": { + "version": "1.2.14", "dev": true, + "license": "ISC", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "isexe": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "which": "bin/which" } }, - "node_modules/signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "license": "ISC" - }, - "node_modules/sort-array": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-4.1.5.tgz", - "integrity": "sha512-Ya4peoS1fgFN42RN1REk2FgdNOeLIEMKFGJvs7VTP3OklF8+kl2SkpVliZ4tk/PurWsrWRsdNdU+tgyOBkB9sA==", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, - "dependencies": { - "array-back": "^5.0.0", - "typical": "^6.0.1" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/sort-array/node_modules/array-back": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-5.0.0.tgz", - "integrity": "sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==", - "dev": true, - "engines": { - "node": ">=10" - } + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true }, - "node_modules/sort-array/node_modules/typical": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/typical/-/typical-6.0.1.tgz", - "integrity": "sha512-+g3NEp7fJLe9DPa1TArHm9QAA7YciZmWnfAqEaFrBihQ7epOv9i99rjtgb6Iz0wh3WuQDjsCTDfgRoGnmHN81A==", + "node_modules/wordwrapjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-3.0.0.tgz", + "integrity": "sha512-mO8XtqyPvykVCsrwj5MlOVWvSnCdT+C+QVbm6blradR7JExAhbkZ7hZ9A+9NUtwzSqrlUo9a67ws0EiILrvRpw==", "dev": true, + "dependencies": { + "reduce-flatten": "^1.0.1", + "typical": "^2.6.1" + }, "engines": { - "node": ">=10" + "node": ">=4.0.0" } }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/wordwrapjs/node_modules/reduce-flatten": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-1.0.1.tgz", + "integrity": "sha512-j5WfFJfc9CoXv/WbwVLHq74i/hdTUpy+iNC534LxczMRP67vJeK3V9JOdnL0N1cIRbn9mYhE2yVjvvKXDxvNXQ==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/sshpk": { - "version": "1.16.1", + "node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, "license": "MIT", "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/stream-connect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stream-connect/-/stream-connect-1.0.2.tgz", - "integrity": "sha512-68Kl+79cE0RGKemKkhxTSg8+6AGrqBt+cbZAXevg2iJ6Y3zX4JhA/sZeGzLpxW9cXhmqAcE7KnJCisUmIUfnFQ==", + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "dependencies": { - "array-back": "^1.0.2" - }, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/stream-connect/node_modules/array-back": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", - "integrity": "sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw==", + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "typical": "^2.6.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=0.12.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/stream-via": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/stream-via/-/stream-via-1.0.4.tgz", - "integrity": "sha512-DBp0lSvX5G9KGRDTkR/R+a29H+Wk2xItOF+MpZLLNDWbEV9tGPnqLPxHEYjmiz8xGtJHRIqmI+hCjmNzqoA4nQ==", + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/string-template": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", - "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", - "dev": true - }, - "node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "license": "MIT", "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^2.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/table-layout": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-0.4.5.tgz", - "integrity": "sha512-zTvf0mcggrGeTe/2jJ6ECkJHAQPIYEwDoqsiqBjI24mvRmQbInK5jq33fyypaCBxX08hMkfmdOqj6haT33EqWw==", + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { - "array-back": "^2.0.0", - "deep-extend": "~0.6.0", - "lodash.padend": "^4.6.1", - "typical": "^2.6.1", - "wordwrapjs": "^3.0.0" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=4.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/table-layout/node_modules/array-back": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", - "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, - "dependencies": { - "typical": "^2.6.1" - }, - "engines": { - "node": ">=4" - } + "license": "ISC" }, - "node_modules/taffydb": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", - "integrity": "sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA==", + "node_modules/x-editable": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/x-editable/-/x-editable-1.5.1.tgz", + "integrity": "sha1-Ltu4kR7yxdYfY/BrDPAgvg/MWEk=", "dev": true }, - "node_modules/tar": { - "version": "2.2.2", - "license": "ISC", - "dependencies": { - "block-stream": "*", - "fstream": "^1.0.12", - "inherits": "2" - } - }, - "node_modules/temp-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/temp-path/-/temp-path-1.0.0.tgz", - "integrity": "sha512-TvmyH7kC6ZVTYkqCODjJIbgvu0FKiwQpZ4D1aknE7xpcDf/qEOB8KZEK5ef2pfbVoiBhNWs3yx4y+ESMtNYmlg==", + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", "dev": true }, - "node_modules/test-value": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/test-value/-/test-value-3.0.0.tgz", - "integrity": "sha512-sVACdAWcZkSU9x7AOmJo5TqE+GyNJknHaHsMrR6ZnhjVlVN9Yx6FjHrsKZ3BjIpPCT68zYesPWkakrNupwfOTQ==", + "node_modules/xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", "dev": true, - "dependencies": { - "array-back": "^2.0.0", - "typical": "^2.6.1" - }, + "license": "MIT", "engines": { - "node": ">=4.0.0" + "node": ">=0.4" } }, - "node_modules/test-value/node_modules/array-back": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", - "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "node_modules/yaml": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", "dev": true, - "dependencies": { - "typical": "^2.6.1" + "license": "ISC", + "bin": { + "yaml": "bin.mjs" }, "engines": { - "node": ">=4" + "node": ">= 14.6" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true, - "license": "MIT" - }, - "node_modules/time-grunt": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/time-grunt/-/time-grunt-1.4.0.tgz", - "integrity": "sha1-BiIT5mDJB+hvRAVWwB6mWXtxJCA=", + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", - "dependencies": { - "chalk": "^1.0.0", - "date-time": "^1.1.0", - "figures": "^1.0.0", - "hooker": "^0.2.3", - "number-is-nan": "^1.0.0", - "pretty-ms": "^2.1.0", - "text-table": "^0.2.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/time-zone": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-0.1.0.tgz", - "integrity": "sha1-Sncotqwo2w4Aj1FAQ/1VW9VXO0Y=", + "node_modules/yoga-layout": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz", + "integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==", + "license": "MIT" + } + }, + "dependencies": { + "@babel/parser": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", + "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", + "dev": true + }, + "@dprint/darwin-arm64": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/darwin-arm64/-/darwin-arm64-0.50.1.tgz", + "integrity": "sha512-NNKf3dxXn567pd/hpCVLHLbC0dI7s3YvQnUEwjRTOAQVMp6O7/ME+Tg1RPGsDP1IB+Y2fIYSM4qmG02zQrqjAQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "optional": true }, - "node_modules/tiny-lr": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", - "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", + "@dprint/darwin-x64": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/darwin-x64/-/darwin-x64-0.50.1.tgz", + "integrity": "sha512-PcY75U3UC/0CLOxWzE0zZJZ2PxzUM5AX2baYL1ovgDGCfqO1H0hINiyxfx/8ncGgPojWBkLs+zrcFiGnXx7BQg==", "dev": true, - "license": "MIT", - "dependencies": { - "body": "^5.1.0", - "debug": "^3.1.0", - "faye-websocket": "~0.10.0", - "livereload-js": "^2.3.0", - "object-assign": "^4.1.0", - "qs": "^6.4.0" - } + "optional": true + }, + "@dprint/linux-arm64-glibc": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/linux-arm64-glibc/-/linux-arm64-glibc-0.50.1.tgz", + "integrity": "sha512-q0TOGy9FsoSKsEQ4sIMKyFweF5M8rW1S5OfwJDNRR2TU2riWByU9TKYIZUzg53iuwYKRypr/kJ5kdbl516afRQ==", + "dev": true, + "optional": true + }, + "@dprint/linux-arm64-musl": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/linux-arm64-musl/-/linux-arm64-musl-0.50.1.tgz", + "integrity": "sha512-XRtxN2cA9rc06WFzzVPDIZYGGLmUXqpVf3F0XhhHV77ikQLJZ5reF4xBOQ+0HjJ/zy8W/HzuGDAHedWyCrRf9g==", + "dev": true, + "optional": true + }, + "@dprint/linux-riscv64-glibc": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/linux-riscv64-glibc/-/linux-riscv64-glibc-0.50.1.tgz", + "integrity": "sha512-vAk/eYhSjA3LJ/yuYgxkHamiK8+m6YdqVBO/Ka+i16VxyjQyOdcMKBkrLCIqSxgyXd6b8raf9wM59HJbaIpoOg==", + "dev": true, + "optional": true + }, + "@dprint/linux-x64-glibc": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/linux-x64-glibc/-/linux-x64-glibc-0.50.1.tgz", + "integrity": "sha512-EpW5KLekaq4hXmKBWWtfBgZ244S4C+vFmMOd1YaGi8+f0hmPTJzVWLdIgpO2ZwfPQ5iycaVI/JS514PQmXPOvg==", + "dev": true, + "optional": true + }, + "@dprint/linux-x64-musl": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/linux-x64-musl/-/linux-x64-musl-0.50.1.tgz", + "integrity": "sha512-assISBbaKKL8LkjrIy/5tpE157MVW6HbyIKAjTtg3tPNM3lDn1oH3twuGtK9WBsN/VoEP3QMZVauolcUJT/VOg==", + "dev": true, + "optional": true }, - "node_modules/tiny-lr/node_modules/debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "@dprint/win32-arm64": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/win32-arm64/-/win32-arm64-0.50.1.tgz", + "integrity": "sha512-ZeaRMQYoFjrsO3lvI1SqzDWDGH1GGXWmNSeXvcFuAf2OgYQJWMBlLotCKiHNJ3uyYneoyhTg2tv9QkApNkZV4Q==", "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } + "optional": true }, - "node_modules/tiny-lr/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "@dprint/win32-x64": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@dprint/win32-x64/-/win32-x64-0.50.1.tgz", + "integrity": "sha512-pMm8l/hRZ9zYylKw/yCaYkSV3btYB9UyMDbWqyxNthkQ1gckWrk17VTI6WjwwQuHD4Iaz5JgAYLS36hlUzWkxA==", "dev": true, - "license": "MIT" + "optional": true }, - "node_modules/tough-cookie": { - "version": "2.4.3", - "license": "BSD-3-Clause", - "dependencies": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.4.3" }, - "engines": { - "node": ">=0.8" + "dependencies": { + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + } } }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" + "@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true + }, + "@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "requires": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" }, - "engines": { - "node": "*" + "dependencies": { + "debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "requires": { + "ms": "^2.1.3" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } } }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "license": "Unlicense" - }, - "node_modules/typical": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz", - "integrity": "sha512-ofhi8kjIje6npGozTip9Fr8iecmYfEbS06i0JnIg+rh51KakryWF4+jX8lLKZVhy6N+ID45WYSFCxPOdTWCzNg==", + "@eslint/config-helpers": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", "dev": true }, - "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true + "@eslint/core": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.15" + } }, - "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, - "bin": { - "uglifyjs": "bin/uglifyjs" + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, - "engines": { - "node": ">=0.8.0" + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "requires": { + "ms": "^2.1.3" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } } }, - "node_modules/unc-path-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "@eslint/js": { + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", + "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", + "dev": true + }, + "@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true + }, + "@eslint/plugin-kit": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz", + "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==", "dev": true, - "engines": { - "node": ">=0.10.0" + "requires": { + "@eslint/core": "^0.15.1", + "levn": "^0.4.1" } }, - "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "@fortawesome/fontawesome-free": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.4.tgz", + "integrity": "sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg==", "dev": true }, - "node_modules/underscore.string": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.6.tgz", - "integrity": "sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ==", + "@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true + }, + "@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, - "dependencies": { - "sprintf-js": "^1.1.1", - "util-deprecate": "^1.0.2" + "requires": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" }, - "engines": { - "node": "*" + "dependencies": { + "@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true + } } }, - "node_modules/underscore.string/node_modules/sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } + "@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true + }, + "@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" + "requires": { + "@isaacs/balanced-match": "^4.0.1" } }, - "node_modules/uri-js": { - "version": "4.2.2", - "license": "BSD-2-Clause", + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, "dependencies": { - "punycode": "^2.1.0" + "ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } } }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.1.1", - "license": "MIT", - "engines": { - "node": ">=6" + "@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "@jsdoc/salty": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.2.tgz", + "integrity": "sha512-A1FrVnc7L9qI2gUGsfN0trTiJNK72Y0CL/VAyrmYEmeKI3pnHDawP64CEev31XLyAAOx2xmDo3tbadPxC0CSbw==", + "dev": true, + "requires": { + "lodash": "^4.17.21" } }, - "node_modules/uri-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", - "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, - "license": "WTFPL OR MIT", - "engines": { - "node": ">= 0.10" + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" } }, - "node_modules/url-safe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/url-safe/-/url-safe-2.0.0.tgz", - "integrity": "sha1-3NRt5GZqdUbuQ+qQasF12qYm3p4=", + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, - "license": "MIT" + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } }, - "node_modules/util-deprecate": { + "@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" + }, + "@ranfdev/deepobj": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "license": "MIT" + "resolved": "https://registry.npmjs.org/@ranfdev/deepobj/-/deepobj-1.0.2.tgz", + "integrity": "sha512-FM3y6kfJaj5MCoAjdv24EDCTDbuFz+4+pgAunbjYfugwIE4O/xx8mPNji1n/ouG8pHCntSnBr1xwTOensF23Gg==" }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "@rollup/plugin-commonjs": { + "version": "28.0.6", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.6.tgz", + "integrity": "sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" + "requires": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "fdir": "^6.2.0", + "is-reference": "1.2.1", + "magic-string": "^0.30.3", + "picomatch": "^4.0.2" + }, + "dependencies": { + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "requires": {} + }, + "picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true + } } }, - "node_modules/uuid": { - "version": "3.3.2", - "license": "MIT", - "bin": { - "uuid": "bin/uuid" + "@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.1.0" } }, - "node_modules/v8flags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "@rollup/plugin-node-resolve": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz", + "integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==", "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" + "requires": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" }, - "engines": { - "node": ">= 0.10" + "dependencies": { + "resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "requires": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "@rollup/plugin-replace": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.2.tgz", + "integrity": "sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ==", + "requires": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" } }, - "node_modules/verror": { - "version": "1.10.0", - "engines": [ - "node >=0.6.0" - ], - "license": "MIT", + "@rollup/pluginutils": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz", + "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==", + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==" + } } }, - "node_modules/viz.js": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/viz.js/-/viz.js-1.8.2.tgz", - "integrity": "sha512-W+1+N/hdzLpQZEcvz79n2IgUE9pfx6JLdHh3Kh8RGvLL8P1LdJVQmi2OsDcLdY4QVID4OUy+FPelyerX0nJxIQ==", - "license": "MIT" + "@rollup/rollup-android-arm-eabi": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.0.tgz", + "integrity": "sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA==", + "dev": true, + "optional": true }, - "node_modules/walk-back": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-5.1.0.tgz", - "integrity": "sha512-Uhxps5yZcVNbLEAnb+xaEEMdgTXl9qAQDzKYejG2AZ7qPwRQ81lozY9ECDbjLPNWm7YsO1IK5rsP1KoQzXAcGA==", + "@rollup/rollup-android-arm64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.0.tgz", + "integrity": "sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw==", "dev": true, - "engines": { - "node": ">=12.17" - } + "optional": true }, - "node_modules/webcola": { - "version": "3.4.0", - "license": "MIT", - "dependencies": { - "d3-dispatch": "^1.0.3", - "d3-drag": "^1.0.4", - "d3-shape": "^1.3.5", - "d3-timer": "^1.0.5" - } + "@rollup/rollup-darwin-arm64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz", + "integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==", + "dev": true, + "optional": true }, - "node_modules/webcola/node_modules/d3-shape": { - "version": "1.3.5", - "license": "BSD-3-Clause", - "dependencies": { - "d3-path": "1" - } + "@rollup/rollup-darwin-x64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz", + "integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==", + "dev": true, + "optional": true }, - "node_modules/websocket-driver": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", - "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "@rollup/rollup-freebsd-arm64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.0.tgz", + "integrity": "sha512-u5AZzdQJYJXByB8giQ+r4VyfZP+walV+xHWdaFx/1VxsOn6eWJhK2Vl2eElvDJFKQBo/hcYIBg/jaKS8ZmKeNQ==", "dev": true, - "license": "MIT", - "dependencies": { - "http-parser-js": ">=0.4.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } + "optional": true }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "@rollup/rollup-freebsd-x64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.0.tgz", + "integrity": "sha512-qC0kS48c/s3EtdArkimctY7h3nHicQeEUdjJzYVJYR3ct3kWSafmn6jkNCA8InbUdge6PVx6keqjk5lVGJf99g==", "dev": true, - "engines": { - "node": ">=0.8.0" - } + "optional": true }, - "node_modules/which": { - "version": "1.2.14", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } + "@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.0.tgz", + "integrity": "sha512-x+e/Z9H0RAWckn4V2OZZl6EmV0L2diuX3QB0uM1r6BvhUIv6xBPL5mrAX2E3e8N8rEHVPwFfz/ETUbV4oW9+lQ==", + "dev": true, + "optional": true }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2 || 2" - } + "@rollup/rollup-linux-arm-musleabihf": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.0.tgz", + "integrity": "sha512-1exwiBFf4PU/8HvI8s80icyCcnAIB86MCBdst51fwFmH5dyeoWVPVgmQPcKrMtBQ0W5pAs7jBCWuRXgEpRzSCg==", + "dev": true, + "optional": true }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true + "@rollup/rollup-linux-arm64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz", + "integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==", + "dev": true, + "optional": true }, - "node_modules/wordwrapjs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-3.0.0.tgz", - "integrity": "sha512-mO8XtqyPvykVCsrwj5MlOVWvSnCdT+C+QVbm6blradR7JExAhbkZ7hZ9A+9NUtwzSqrlUo9a67ws0EiILrvRpw==", + "@rollup/rollup-linux-arm64-musl": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz", + "integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==", "dev": true, - "dependencies": { - "reduce-flatten": "^1.0.1", - "typical": "^2.6.1" - }, - "engines": { - "node": ">=4.0.0" - } + "optional": true }, - "node_modules/wordwrapjs/node_modules/reduce-flatten": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-1.0.1.tgz", - "integrity": "sha512-j5WfFJfc9CoXv/WbwVLHq74i/hdTUpy+iNC534LxczMRP67vJeK3V9JOdnL0N1cIRbn9mYhE2yVjvvKXDxvNXQ==", + "@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.0.tgz", + "integrity": "sha512-xw+FTGcov/ejdusVOqKgMGW3c4+AgqrfvzWEVXcNP6zq2ue+lsYUgJ+5Rtn/OTJf7e2CbgTFvzLW2j0YAtj0Gg==", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "optional": true }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "license": "ISC" + "@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.0.tgz", + "integrity": "sha512-bKGibTr9IdF0zr21kMvkZT4K6NV+jjRnBoVMt2uNMG0BYWm3qOVmYnXKzx7UhwrviKnmK46IKMByMgvpdQlyJQ==", + "dev": true, + "optional": true }, - "node_modules/x-editable": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/x-editable/-/x-editable-1.5.1.tgz", - "integrity": "sha1-Ltu4kR7yxdYfY/BrDPAgvg/MWEk=", - "dev": true + "@rollup/rollup-linux-riscv64-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.0.tgz", + "integrity": "sha512-vV3cL48U5kDaKZtXrti12YRa7TyxgKAIDoYdqSIOMOFBXqFj2XbChHAtXquEn2+n78ciFgr4KIqEbydEGPxXgA==", + "dev": true, + "optional": true }, - "node_modules/xmlcreate": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", - "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", - "dev": true + "@rollup/rollup-linux-riscv64-musl": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.0.tgz", + "integrity": "sha512-TDKO8KlHJuvTEdfw5YYFBjhFts2TR0VpZsnLLSYmB7AaohJhM8ctDSdDnUGq77hUh4m/djRafw+9zQpkOanE2Q==", + "dev": true, + "optional": true }, - "node_modules/xmlhttprequest": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", - "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", + "@rollup/rollup-linux-s390x-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.0.tgz", + "integrity": "sha512-8541GEyktXaw4lvnGp9m84KENcxInhAt6vPWJ9RodsB/iGjHoMB2Pp5MVBCiKIRxrxzJhGCxmNzdu+oDQ7kwRA==", "dev": true, - "engines": { - "node": ">=0.4.0" - } + "optional": true }, - "node_modules/xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "@rollup/rollup-linux-x64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.9.tgz", + "integrity": "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4" - } + "optional": true }, - "node_modules/yoga-layout": { - "version": "1.9.3", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "autogypi": "^0.2.2", - "nbind": "^0.3.14", - "node-gyp": "^3.6.2" + "@rollup/rollup-linux-x64-musl": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.9.tgz", + "integrity": "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-arm64-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.9.tgz", + "integrity": "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-ia32-msvc": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.0.tgz", + "integrity": "sha512-3XJ0NQtMAXTWFW8FqZKcw3gOQwBtVWP/u8TpHP3CRPXD7Pd6s8lLdH3sHWh8vqKCyyiI8xW5ltJScQmBU9j7WA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-x64-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz", + "integrity": "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==", + "dev": true, + "optional": true + }, + "@stencil/core": { + "version": "4.35.1", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.35.1.tgz", + "integrity": "sha512-u65m3TbzOtpn679gUV4Yvi8YpInhRJ62js30a7YtXief9Ej/vzrhwDE22U0w4DMWJOYwAsJl133BUaZkWwnmzg==", + "dev": true, + "requires": { + "@rollup/rollup-darwin-arm64": "4.34.9", + "@rollup/rollup-darwin-x64": "4.34.9", + "@rollup/rollup-linux-arm64-gnu": "4.34.9", + "@rollup/rollup-linux-arm64-musl": "4.34.9", + "@rollup/rollup-linux-x64-gnu": "4.34.9", + "@rollup/rollup-linux-x64-musl": "4.34.9", + "@rollup/rollup-win32-arm64-msvc": "4.34.9", + "@rollup/rollup-win32-x64-msvc": "4.34.9" } - } - }, - "dependencies": { - "@babel/parser": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", - "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", - "dev": true }, - "@fortawesome/fontawesome-free": { - "version": "5.15.4", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.4.tgz", - "integrity": "sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg==", - "dev": true + "@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==" }, - "@jsdoc/salty": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.2.tgz", - "integrity": "sha512-A1FrVnc7L9qI2gUGsfN0trTiJNK72Y0CL/VAyrmYEmeKI3pnHDawP64CEev31XLyAAOx2xmDo3tbadPxC0CSbw==", + "@types/fs-extra": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", + "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", "dev": true, "requires": { - "lodash": "^4.17.21" + "@types/node": "*" } }, - "@ranfdev/deepobj": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@ranfdev/deepobj/-/deepobj-1.0.2.tgz", - "integrity": "sha512-FM3y6kfJaj5MCoAjdv24EDCTDbuFz+4+pgAunbjYfugwIE4O/xx8mPNji1n/ouG8pHCntSnBr1xwTOensF23Gg==" + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } }, - "@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "@types/linkify-it": { @@ -5236,10 +8749,32 @@ "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", "dev": true }, + "@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "@types/node": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz", + "integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==", + "dev": true, + "requires": { + "undici-types": "~7.8.0" + } + }, + "@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true }, "accepts": { "version": "1.3.5", @@ -5249,10 +8784,24 @@ "negotiator": "0.6.1" } }, + "acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -5277,10 +8826,20 @@ } } }, + "ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, + "requires": { + "environment": "^1.0.0" + } + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true }, "ansi-styles": { "version": "2.2.1", @@ -5288,20 +8847,6 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -5318,9 +8863,9 @@ "dev": true }, "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", "dev": true }, "array-each": { @@ -5336,82 +8881,36 @@ "dev": true }, "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", "dev": true }, - "asn1": { - "version": "0.2.4", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0" - }, "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "dev": true }, - "asynckit": { - "version": "0.4.0" - }, - "autogypi": { - "version": "0.2.2", - "requires": { - "bluebird": "^3.4.0", - "commander": "~2.9.0", - "resolve": "~1.1.7" - }, - "dependencies": { - "commander": { - "version": "2.9.0", - "requires": { - "graceful-readlink": ">= 1.0.0" - } - } - } - }, - "aws-sign2": { - "version": "0.7.0" - }, - "aws4": { - "version": "1.8.0" - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "basic-auth": { - "version": "2.0.0", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", "dev": true, "requires": { - "safe-buffer": "5.1.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.1", - "dev": true - } + "safe-buffer": "5.1.2" } }, "batch": { @@ -5420,28 +8919,17 @@ "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", "dev": true }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "requires": { - "tweetnacl": "^0.14.3" - } - }, "binary-search-bounds": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/binary-search-bounds/-/binary-search-bounds-2.0.5.tgz", "integrity": "sha512-H0ea4Fd3lS1+sTEB2TgcLoK21lLhwEJzlQv3IN47pJS976Gx4zoWe0ak3q+uYh60ppQxg9F16Ri4tS1sfD4+jA==", "dev": true }, - "block-stream": { - "version": "0.0.9", - "requires": { - "inherits": "~2.0.0" - } - }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true }, "body": { "version": "5.1.0", @@ -5457,30 +8945,29 @@ }, "bootstrap": { "version": "3.4.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", + "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==", "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "browser-resolve": { - "version": "1.11.2", + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "requires": { - "resolve": "1.1.7" + "fill-range": "^7.1.1" } }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, "bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", @@ -5516,8 +9003,11 @@ "get-intrinsic": "^1.0.2" } }, - "caseless": { - "version": "0.12.0" + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true }, "catharsis": { "version": "0.9.0", @@ -5547,10 +9037,24 @@ "integrity": "sha1-k1vC39lFiodrJ5YXUUY4vKqWSi4=", "dev": true }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "requires": { + "restore-cursor": "^5.0.0" + } + }, + "cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "requires": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + } }, "collect-all": { "version": "1.0.4", @@ -5562,24 +9066,33 @@ "stream-via": "^1.0.4" } }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true + }, "colors": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", "integrity": "sha512-ENwblkFQpqqia6b++zLD/KUWafYlVY/UNnAp7oz7LY7E924wmpye416wBOmvv/HMWzl8gL1kJlfvId/1Dg176w==", "dev": true }, - "combined-stream": { - "version": "1.0.8", - "requires": { - "delayed-stream": "~1.0.0" - } - }, "command-line-args": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", @@ -5656,8 +9169,7 @@ "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "common-sequence": { "version": "2.0.2", @@ -5665,10 +9177,17 @@ "integrity": "sha512-jAg09gkdkrDO9EWTdXfv80WWH3yeZl5oT69fGfedBNS9pXUKYInVJ1bJ+/ht2+Moeei48TmSbQDYMc8EOx9G0g==", "dev": true }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "config-master": { "version": "3.1.0", @@ -5688,43 +9207,33 @@ } }, "connect": { - "version": "3.6.6", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", - "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dev": true, "requires": { "debug": "2.6.9", - "finalhandler": "1.1.0", - "parseurl": "~1.3.2", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", "utils-merge": "1.0.1" } }, "connect-livereload": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.5.4.tgz", - "integrity": "sha1-gBV9E3HJ83zBQDmrGJWXDRGdw7w=", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.6.1.tgz", + "integrity": "sha512-3R0kMOdL7CjJpU66fzAkCe6HNtd3AavCS4m+uW4KtJjrdGPT0SQEZieAYd+cm+lJoBznNQ4lqipYWkhBMgk00g==", "dev": true }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" - }, "continuable-cache": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", "dev": true }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "requires": { "path-key": "^3.1.0", @@ -5757,33 +9266,73 @@ "@ranfdev/deepobj": "1.0.2" } }, - "css-layout": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/css-layout/-/css-layout-1.1.1.tgz", - "integrity": "sha1-raW7jJAeR11BBDqI4DSt5U2Tk5I=" - }, "d3": { - "version": "3.5.17", - "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", - "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=" + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-5.16.0.tgz", + "integrity": "sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==", + "requires": { + "d3-array": "1", + "d3-axis": "1", + "d3-brush": "1", + "d3-chord": "1", + "d3-collection": "1", + "d3-color": "1", + "d3-contour": "1", + "d3-dispatch": "1", + "d3-drag": "1", + "d3-dsv": "1", + "d3-ease": "1", + "d3-fetch": "1", + "d3-force": "1", + "d3-format": "1", + "d3-geo": "1", + "d3-hierarchy": "1", + "d3-interpolate": "1", + "d3-path": "1", + "d3-polygon": "1", + "d3-quadtree": "1", + "d3-random": "1", + "d3-scale": "2", + "d3-scale-chromatic": "1", + "d3-selection": "1", + "d3-shape": "1", + "d3-time": "1", + "d3-time-format": "2", + "d3-timer": "1", + "d3-transition": "1", + "d3-voronoi": "1", + "d3-zoom": "1" + }, + "dependencies": { + "d3-scale": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", + "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", + "requires": { + "d3-array": "^1.2.0", + "d3-collection": "1", + "d3-format": "1", + "d3-interpolate": "1", + "d3-time": "1", + "d3-time-format": "2" + } + } + } }, "d3-array": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.1.tgz", - "integrity": "sha512-CyINJQ0SOUHojDdFDH4JEM0552vCR1utGyLHegJHyYH0JyCpSeTPxi4OBqHMA2jJZq4NH782LtaJWBImqI/HBw==", - "dev": true + "integrity": "sha512-CyINJQ0SOUHojDdFDH4JEM0552vCR1utGyLHegJHyYH0JyCpSeTPxi4OBqHMA2jJZq4NH782LtaJWBImqI/HBw==" }, "d3-axis": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.8.tgz", - "integrity": "sha512-K0djTb26iQ6AsuD2d6Ka08wBHf4V30awIxV4XFuB/iLzYtTqqJlE/nIN0DBJJCX7lbOqbt2/oeX3r+sU5k2veg==", - "dev": true + "integrity": "sha512-K0djTb26iQ6AsuD2d6Ka08wBHf4V30awIxV4XFuB/iLzYtTqqJlE/nIN0DBJJCX7lbOqbt2/oeX3r+sU5k2veg==" }, "d3-brush": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.0.4.tgz", "integrity": "sha512-nUFueDzOlvwFvuOBynGSyJM7Wt1H9fKgJeoWFSg3ScS4c7FJBch92FKUJKum4xtgPYHdgH2C3bRg3GzSVltCJQ==", - "dev": true, "requires": { "d3-dispatch": "1", "d3-drag": "1", @@ -5796,7 +9345,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.4.tgz", "integrity": "sha512-o0ExexkK1N0KikUakKrQwttP5Flu8AYD6iBUh3AdPJqnTh6xlvcX5wFRuuo29sLOAr9+T4yZPUH1S3CCQJ1SlQ==", - "dev": true, "requires": { "d3-array": "1", "d3-path": "1" @@ -5805,14 +9353,20 @@ "d3-collection": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.4.tgz", - "integrity": "sha1-NC39EoN8kJdPM/HMCnha6lcNzcI=", - "dev": true + "integrity": "sha1-NC39EoN8kJdPM/HMCnha6lcNzcI=" }, "d3-color": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.0.3.tgz", - "integrity": "sha512-t+rSOrshj6m2AUOe8kHvTwfUQ5TFoInEkBfmsHHAHPof58dmbRXNpicB7XAyPbMQbcC7i09p2BxeCEdgBd8xmw==", - "dev": true + "integrity": "sha512-t+rSOrshj6m2AUOe8kHvTwfUQ5TFoInEkBfmsHHAHPof58dmbRXNpicB7XAyPbMQbcC7i09p2BxeCEdgBd8xmw==" + }, + "d3-contour": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz", + "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==", + "requires": { + "d3-array": "^1.1.1" + } }, "d3-dispatch": { "version": "1.0.3", @@ -5832,7 +9386,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.8.tgz", "integrity": "sha512-IVCJpQ+YGe3qu6odkPQI0KPqfxkhbP/oM1XhhE/DFiYmcXKfCRub4KXyiuehV1d4drjWVXHUWx4gHqhdZb6n/A==", - "dev": true, "requires": { "commander": "2", "iconv-lite": "0.4", @@ -5842,12 +9395,20 @@ "d3-ease": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.3.tgz", - "integrity": "sha512-io3QwOJwVPAxRF2UXpKpCdz2wm/7VLFCQQ1yy+GzX6YCtt3vi2BGnimI8agSF5jyUrHsADyF303d2S+ps7zU8w==", - "dev": true + "integrity": "sha512-io3QwOJwVPAxRF2UXpKpCdz2wm/7VLFCQQ1yy+GzX6YCtt3vi2BGnimI8agSF5jyUrHsADyF303d2S+ps7zU8w==" + }, + "d3-fetch": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz", + "integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==", + "requires": { + "d3-dsv": "1" + } }, "d3-force": { "version": "1.2.1", - "dev": true, + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz", + "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==", "requires": { "d3-collection": "1", "d3-dispatch": "1", @@ -5867,14 +9428,12 @@ "d3-format": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.2.2.tgz", - "integrity": "sha512-zH9CfF/3C8zUI47nsiKfD0+AGDEuM8LwBIP7pBVpyR4l/sKkZqITmMtxRp04rwBrlshIZ17XeFAaovN3++wzkw==", - "dev": true + "integrity": "sha512-zH9CfF/3C8zUI47nsiKfD0+AGDEuM8LwBIP7pBVpyR4l/sKkZqITmMtxRp04rwBrlshIZ17XeFAaovN3++wzkw==" }, "d3-geo": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.9.1.tgz", "integrity": "sha512-l9wL/cEQkyZQYXw3xbmLsH3eQ5ij+icNfo4r0GrLa5rOCZR/e/3am45IQ0FvQ5uMsv+77zBRunLc9ufTWSQYFA==", - "dev": true, "requires": { "d3-array": "1" } @@ -5882,14 +9441,12 @@ "d3-hierarchy": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.5.tgz", - "integrity": "sha512-PcsLIhThc60mWnxlojIOH7Sc0tQ2DgLWfEwEAyzCtej5f3H9wSsRmrg5pEhKZLrwiJnI2zyw/pznJxL9a/Eugw==", - "dev": true + "integrity": "sha512-PcsLIhThc60mWnxlojIOH7Sc0tQ2DgLWfEwEAyzCtej5f3H9wSsRmrg5pEhKZLrwiJnI2zyw/pznJxL9a/Eugw==" }, "d3-interpolate": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.1.6.tgz", "integrity": "sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==", - "dev": true, "requires": { "d3-color": "1" } @@ -5902,52 +9459,25 @@ "d3-polygon": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.3.tgz", - "integrity": "sha512-2zP7GOvf4XOWTeQouK7fCO534yQxyhYYTw6GTqcXifIalHgA6qV/es+4GRQii9m6XxEPFcht4loobD/o2iEo1A==", - "dev": true + "integrity": "sha512-2zP7GOvf4XOWTeQouK7fCO534yQxyhYYTw6GTqcXifIalHgA6qV/es+4GRQii9m6XxEPFcht4loobD/o2iEo1A==" }, "d3-quadtree": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.3.tgz", - "integrity": "sha1-rHmH4+I/6AWpkPKOG1DTj8uCJDg=", - "dev": true - }, - "d3-queue": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-3.0.7.tgz", - "integrity": "sha512-2rs+6pNFKkrJhqe1rg5znw7dKJ7KZr62j9aLZfhondkrnz6U7VRmJj1UGcbD8MRc46c7H8m4SWhab8EalBQrkw==", - "dev": true + "integrity": "sha1-rHmH4+I/6AWpkPKOG1DTj8uCJDg=" }, "d3-random": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.0.tgz", - "integrity": "sha512-XuMbjx3Jq4EWfJP4g6nR7zns/bZfaVbWHWfR8auDkEiWCzVbWifmasfszV1ZRN3xXK3nY4RUFL2nTIhceGZSFQ==", - "dev": true - }, - "d3-request": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-request/-/d3-request-1.0.6.tgz", - "integrity": "sha512-FJj8ySY6GYuAJHZMaCQ83xEYE4KbkPkmxZ3Hu6zA1xxG2GD+z6P+Lyp+zjdsHf0xEbp2xcluDI50rCS855EQ6w==", - "dev": true, - "requires": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-dsv": "1", - "xmlhttprequest": "1" - } + "integrity": "sha512-XuMbjx3Jq4EWfJP4g6nR7zns/bZfaVbWHWfR8auDkEiWCzVbWifmasfszV1ZRN3xXK3nY4RUFL2nTIhceGZSFQ==" }, - "d3-scale": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-1.0.7.tgz", - "integrity": "sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==", - "dev": true, + "d3-scale-chromatic": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz", + "integrity": "sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==", "requires": { - "d3-array": "^1.2.0", - "d3-collection": "1", "d3-color": "1", - "d3-format": "1", - "d3-interpolate": "1", - "d3-time": "1", - "d3-time-format": "2" + "d3-interpolate": "1" } }, "d3-selection": { @@ -5959,7 +9489,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.2.0.tgz", "integrity": "sha512-LP48zJ9ykPKjCdd0vSu5k2l4s8v1vI6vvdDeJtmgtTa+L6Ery0lzvOaV7pMunFuLv11hwSRZQnSnlhFl801aiw==", - "dev": true, "requires": { "d3-path": "1" } @@ -5967,14 +9496,12 @@ "d3-time": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.8.tgz", - "integrity": "sha512-YRZkNhphZh3KcnBfitvF3c6E0JOFGikHZ4YqD+Lzv83ZHn1/u6yGenRU1m+KAk9J1GnZMnKcrtfvSktlA1DXNQ==", - "dev": true + "integrity": "sha512-YRZkNhphZh3KcnBfitvF3c6E0JOFGikHZ4YqD+Lzv83ZHn1/u6yGenRU1m+KAk9J1GnZMnKcrtfvSktlA1DXNQ==" }, "d3-time-format": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.1.tgz", "integrity": "sha512-8kAkymq2WMfzW7e+s/IUNAtN/y3gZXGRrdGfo6R8NKPAA85UBTxZg5E61bR6nLwjPjj4d3zywSQe1CkYLPFyrw==", - "dev": true, "requires": { "d3-time": "1" } @@ -5984,72 +9511,10 @@ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.7.tgz", "integrity": "sha512-vMZXR88XujmG/L5oB96NNKH5lCWwiLM/S2HyyAQLcjWJCloK5shxta4CwOFYLZoY3AWX73v8Lgv4cCAdWtRmOA==" }, - "d3-tip": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/d3-tip/-/d3-tip-0.7.1.tgz", - "integrity": "sha512-jtVR86jEfpVhfMtJaJBzT3GYYfulID106s9gqiX8o8es2tRcsCeJhoWWZG3sfepP97j1CTxfxPoky014nfJ9Zg==", - "dev": true, - "requires": { - "d3": "^4.2" - }, - "dependencies": { - "d3": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-4.13.0.tgz", - "integrity": "sha512-l8c4+0SldjVKLaE2WG++EQlqD7mh/dmQjvi2L2lKPadAVC+TbJC4ci7Uk9bRi+To0+ansgsS0iWfPjD7DBy+FQ==", - "dev": true, - "requires": { - "d3-array": "1.2.1", - "d3-axis": "1.0.8", - "d3-brush": "1.0.4", - "d3-chord": "1.0.4", - "d3-collection": "1.0.4", - "d3-color": "1.0.3", - "d3-dispatch": "1.0.3", - "d3-drag": "1.2.1", - "d3-dsv": "1.0.8", - "d3-ease": "1.0.3", - "d3-force": "1.1.0", - "d3-format": "1.2.2", - "d3-geo": "1.9.1", - "d3-hierarchy": "1.1.5", - "d3-interpolate": "1.1.6", - "d3-path": "1.0.5", - "d3-polygon": "1.0.3", - "d3-quadtree": "1.0.3", - "d3-queue": "3.0.7", - "d3-random": "1.1.0", - "d3-request": "1.0.6", - "d3-scale": "1.0.7", - "d3-selection": "1.3.0", - "d3-shape": "1.2.0", - "d3-time": "1.0.8", - "d3-time-format": "2.1.1", - "d3-timer": "1.0.7", - "d3-transition": "1.1.1", - "d3-voronoi": "1.1.2", - "d3-zoom": "1.7.1" - } - }, - "d3-force": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.1.0.tgz", - "integrity": "sha512-2HVQz3/VCQs0QeRNZTYb7GxoUCeb6bOzMp/cGcLa87awY9ZsPvXOGeZm0iaGBjXic6I1ysKwMn+g+5jSAdzwcg==", - "dev": true, - "requires": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-quadtree": "1", - "d3-timer": "1" - } - } - } - }, "d3-transition": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.1.1.tgz", "integrity": "sha512-xeg8oggyQ+y5eb4J13iDgKIjUcEfIOZs2BqV/eEmXm2twx80wTzJ4tB4vaZ5BKfz7XsI/DFmQL5me6O27/5ykQ==", - "dev": true, "requires": { "d3-color": "1", "d3-dispatch": "1", @@ -6062,14 +9527,12 @@ "d3-voronoi": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.2.tgz", - "integrity": "sha512-RhGS1u2vavcO7ay7ZNAPo4xeDh/VYeGof3x5ZLJBQgYhLegxr3s5IykvWmJ94FTU6mcbtp4sloqZ54mP6R4Utw==", - "dev": true + "integrity": "sha512-RhGS1u2vavcO7ay7ZNAPo4xeDh/VYeGof3x5ZLJBQgYhLegxr3s5IykvWmJ94FTU6mcbtp4sloqZ54mP6R4Utw==" }, "d3-zoom": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.7.1.tgz", "integrity": "sha512-sZHQ55DGq5BZBFGnRshUT8tm2sfhPHFnOlmPbbwTkAoPeVdRTkB4Xsf9GCY0TSHrTD8PeJPZGmP/TpGicwJDJQ==", - "dev": true, "requires": { "d3-dispatch": "1", "d3-drag": "1", @@ -6087,12 +9550,6 @@ "lodash": "^4.17.15" } }, - "dashdash": { - "version": "1.14.1", - "requires": { - "assert-plus": "^1.0.0" - } - }, "date-time": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/date-time/-/date-time-1.1.0.tgz", @@ -6109,22 +9566,11 @@ "dev": true }, "dc": { - "version": "2.1.10", - "resolved": "https://registry.npmjs.org/dc/-/dc-2.1.10.tgz", - "integrity": "sha512-RCi/vyOjg/fscp/j3jVSzhtABkVu05A1fJmWop/Mx2iASoXKnDhPcUZ2wp0QBXLquGlq0PfGd+TCREBQhUUG5A==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/dc/-/dc-4.0.5.tgz", + "integrity": "sha512-4s5iaDSMgZThFlFmOMM6D1KReS2Ui1a7wcbECPgP0pXBGQ4CMcvP6euI3ymF0tER5lK2U6ApIrxJ9czP+NzINw==", "requires": { - "crossfilter2": "~1.4", - "d3": "^3" - }, - "dependencies": { - "crossfilter2": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/crossfilter2/-/crossfilter2-1.4.8.tgz", - "integrity": "sha512-H3D2AyRGpRYK0pKs6kgwALuNb3J6/PuW/sIckPDxPi2wz+TX1Cp/1+BC7sKkMUF12RGPjV/PNANF/W4TQ+4BLg==", - "requires": { - "lodash.result": "^4.4.0" - } - } + "d3": "^5.15.1" } }, "debug": { @@ -6142,13 +9588,23 @@ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true }, - "delayed-stream": { - "version": "1.0.0" + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true }, "depd": { "version": "1.1.2", @@ -6157,9 +9613,9 @@ "dev": true }, "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true }, "detect-file": { @@ -6168,6 +9624,15 @@ "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", "dev": true }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, "dmd": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/dmd/-/dmd-6.2.0.tgz", @@ -6236,82 +9701,313 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "requires": { - "domelementtype": "^2.2.0" + "domelementtype": "^2.2.0" + } + } + } + }, + "dprint": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/dprint/-/dprint-0.50.1.tgz", + "integrity": "sha512-s+kUyQp2rGpwsM3vVmXySOY3v1NjYyRpKfQZdP4rfNTz6zQuICSO6nqIXNm3YdK1MwNFR/EXSFMuE1YPuulhow==", + "dev": true, + "requires": { + "@dprint/darwin-arm64": "0.50.1", + "@dprint/darwin-x64": "0.50.1", + "@dprint/linux-arm64-glibc": "0.50.1", + "@dprint/linux-arm64-musl": "0.50.1", + "@dprint/linux-riscv64-glibc": "0.50.1", + "@dprint/linux-x64-glibc": "0.50.1", + "@dprint/linux-x64-musl": "0.50.1", + "@dprint/win32-arm64": "0.50.1", + "@dprint/win32-x64": "0.50.1" + } + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + }, + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" + }, + "environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true + }, + "error": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", + "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", + "dev": true, + "requires": { + "string-template": "~0.2.1", + "xtend": "~4.0.0" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", + "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.15.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.32.0", + "@eslint/plugin-kit": "^0.3.4", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "requires": { + "ms": "^2.1.3" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" } } } }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.2", + "eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" } }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "emscripten-library-decorator": { - "version": "0.2.2" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true }, - "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" - }, - "error": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", - "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", + "espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "requires": { - "string-template": "~0.2.1", - "xtend": "~4.0.0" + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" } }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, - "estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true }, "eventemitter2": { @@ -6320,6 +10016,12 @@ "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", "dev": true }, + "eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -6336,18 +10038,50 @@ } }, "extend": { - "version": "3.0.2" - }, - "extsprintf": { - "version": "1.3.0" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + } }, "fast-json-stable-stringify": { - "version": "2.0.0" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } }, "faye-websocket": { "version": "0.10.0", @@ -6368,6 +10102,15 @@ "object-assign": "^4.1.0" } }, + "file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "requires": { + "flat-cache": "^4.0.0" + } + }, "file-set": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/file-set/-/file-set-4.0.2.tgz", @@ -6383,6 +10126,29 @@ "resolved": "https://registry.npmjs.org/array-back/-/array-back-5.0.0.tgz", "integrity": "sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==", "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } } } }, @@ -6392,18 +10158,27 @@ "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=", "dev": true }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "finalhandler": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", - "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, "requires": { "debug": "2.6.9", - "encodeurl": "~1.0.1", + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.3.1", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", "unpipe": "~1.0.0" } }, @@ -6425,13 +10200,12 @@ } }, "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "locate-path": "^3.0.0" } }, "findup-sync": { @@ -6477,6 +10251,22 @@ "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", "dev": true }, + "flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + } + }, + "flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -6492,21 +10282,20 @@ "for-in": "^1.0.1" } }, - "forever-agent": { - "version": "0.6.1" - }, - "form-data": { - "version": "2.3.3", + "foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" } }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true }, "fs-extra": { @@ -6529,38 +10318,15 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fstream": { - "version": "1.0.12", - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - } + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, "gaze": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", @@ -6570,6 +10336,12 @@ "globule": "^1.0.0" } }, + "get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "dev": true + }, "get-intrinsic": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", @@ -6587,23 +10359,38 @@ "integrity": "sha512-2zblDBaFcb3rB4rF77XVnuINOE2h2k/OnqXAiy0IrTxUfV1iFp3la33oAQVY9pCpWU268WFYVt2t71hlMuLsOg==", "dev": true }, - "getpass": { - "version": "0.1.7", + "glob": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", + "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", + "dev": true, "requires": { - "assert-plus": "^1.0.0" + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.0.3", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "dependencies": { + "minimatch": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "dev": true, + "requires": { + "@isaacs/brace-expansion": "^5.0.0" + } + } } }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "is-glob": "^4.0.1" } }, "global-modules": { @@ -6630,6 +10417,53 @@ "which": "^1.2.14" } }, + "globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true + }, + "globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, "globule": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", @@ -6639,15 +10473,29 @@ "glob": "~7.1.1", "lodash": "~4.17.10", "minimatch": "~3.0.2" + }, + "dependencies": { + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } } }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "graceful-readlink": { - "version": "1.0.1" + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true }, "graphlib": { "version": "2.1.8", @@ -6660,7 +10508,7 @@ "graphlib-dot": { "version": "git+ssh://git@github.com/dagrejs/graphlib-dot.git#7d5c09c8b7fb4d5d9441edd7bc58f4d7cbafcaa3", "dev": true, - "from": "graphlib-dot@github:dagrejs/graphlib-dot", + "from": "graphlib-dot@dagrejs/graphlib-dot#v0.6.4", "requires": { "graphlib": "2.1.8", "lodash": "4.17.19" @@ -6697,6 +10545,20 @@ "rimraf": "~3.0.2" }, "dependencies": { + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "grunt-cli": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", @@ -6722,12 +10584,6 @@ } } }, - "grunt-known-options": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", - "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", - "dev": true - }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -6740,48 +10596,96 @@ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { - "glob": "^7.1.3" + "glob": "^7.1.3" + } + } + } + }, + "grunt-cli": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.5.0.tgz", + "integrity": "sha512-rILKAFoU0dzlf22SUfDtq2R1fosChXXlJM5j7wI6uoW8gwmXDXzbUvirlKZSYCdXl3LXFbR+8xyS+WFo+b6vlA==", + "dev": true, + "requires": { + "grunt-known-options": "~2.0.0", + "interpret": "~1.1.0", + "liftup": "~3.0.1", + "nopt": "~5.0.0", + "v8flags": "^4.0.1" + }, + "dependencies": { + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "v8flags": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-4.0.1.tgz", + "integrity": "sha512-fcRLaS4H/hrZk9hYwbdRM35D0U8IYMfEClhXxCivOojl+yTRAZH3Zy2sSy6qVCiGbV9YAtPssP6jaChqC9vPCg==", + "dev": true + } + } + }, + "grunt-contrib-concat": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-2.1.0.tgz", + "integrity": "sha512-Vnl95JIOxfhEN7bnYIlCgQz41kkbi7tsZ/9a4usZmxNxi1S2YAIOy8ysFmO8u4MN26Apal1O106BwARdaNxXQw==", + "dev": true, + "requires": { + "chalk": "^4.1.2", + "source-map": "^0.5.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" } } } }, - "grunt-cli": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", - "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=", - "dev": true, - "requires": { - "findup-sync": "~0.3.0", - "grunt-known-options": "~1.1.0", - "nopt": "~3.0.6", - "resolve": "~1.1.0" - } - }, - "grunt-contrib-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-1.0.1.tgz", - "integrity": "sha1-YVCYYwhOhx1+ht5IwBUlntl3Rb0=", - "dev": true, - "requires": { - "chalk": "^1.0.0", - "source-map": "^0.5.3" - } - }, "grunt-contrib-connect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/grunt-contrib-connect/-/grunt-contrib-connect-1.0.2.tgz", - "integrity": "sha1-XPkzuRpnOGBEJzwLJERgPNmIebo=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/grunt-contrib-connect/-/grunt-contrib-connect-5.0.1.tgz", + "integrity": "sha512-Hfq/0QJl3ddD2N/a/1cDJHkKEOGk6m7W6uxNe0AmYwtf6v0F/4+8q9rvPJ1tl+mrI90lU/89I9T/h48qqeMfQA==", "dev": true, "requires": { - "async": "^1.5.2", - "connect": "^3.4.0", - "connect-livereload": "^0.5.0", - "http2": "^3.3.4", - "morgan": "^1.6.1", - "opn": "^4.0.0", - "portscanner": "^1.0.0", - "serve-index": "^1.7.1", - "serve-static": "^1.10.0" + "async": "^3.2.5", + "connect": "^3.7.0", + "connect-livereload": "^0.6.1", + "http2-wrapper": "^2.2.1", + "morgan": "^1.10.0", + "open": "^8.0.0", + "portscanner": "^2.2.0", + "serve-index": "^1.9.1", + "serve-static": "^1.15.0" } }, "grunt-contrib-copy": { @@ -6795,37 +10699,43 @@ } }, "grunt-contrib-uglify": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-3.4.0.tgz", - "integrity": "sha512-UXsTpeP0pytpTYlmll3RDndsRXfdwmrf1tI/AtD/PrArQAzGmKMvj83aVt3D8egWlE6KqPjsJBLCCvfC52LI/A==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-5.2.2.tgz", + "integrity": "sha512-ITxiWxrjjP+RZu/aJ5GLvdele+sxlznh+6fK9Qckio5ma8f7Iv8woZjRkGfafvpuygxNefOJNc+hfjjBayRn2Q==", "dev": true, "requires": { - "chalk": "^1.0.0", - "maxmin": "^2.1.0", - "uglify-js": "~3.4.0", + "chalk": "^4.1.2", + "maxmin": "^3.0.0", + "uglify-js": "^3.16.1", "uri-path": "^1.0.0" }, "dependencies": { - "commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", - "dev": true + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } }, - "uglify-js": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", - "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "commander": "~2.19.0", - "source-map": "~0.6.1" + "has-flag": "^4.0.0" } } } @@ -6863,14 +10773,6 @@ "fs-extra": "^8.1.0", "graceful-fs": "^4.2.3", "url-safe": "^2.0.0" - }, - "dependencies": { - "async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true - } } }, "grunt-jsdoc": { @@ -6893,7 +10795,9 @@ } }, "grunt-known-options": { - "version": "1.1.0", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", + "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", "dev": true }, "grunt-legacy-log": { @@ -6937,21 +10841,6 @@ "supports-color": "^7.1.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6978,12 +10867,6 @@ "which": "~2.0.2" }, "dependencies": { - "async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true - }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6996,22 +10879,69 @@ } }, "grunt-shell": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/grunt-shell/-/grunt-shell-2.1.0.tgz", - "integrity": "sha1-Q595FZ7RHmSmUaacyKPQK+v17MI=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/grunt-shell/-/grunt-shell-4.0.0.tgz", + "integrity": "sha512-dHFy8VZDfWGYLTeNvIHze4PKXGvIlDWuN0UE7hUZstTQeiEyv1VmW1MaDYQ3X5tE3bCi3bEia1gGKH8z/f1czQ==", "dev": true, "requires": { - "chalk": "^1.0.0", - "npm-run-path": "^2.0.0" + "chalk": "^3.0.0", + "npm-run-path": "^2.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "gzip-size": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz", - "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", "dev": true, "requires": { - "duplexer": "^0.1.1" + "duplexer": "^0.1.1", + "pify": "^4.0.1" } }, "handlebars": { @@ -7035,16 +10965,6 @@ } } }, - "har-schema": { - "version": "2.0.0" - }, - "har-validator": { - "version": "5.1.3", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -7063,16 +10983,26 @@ "ansi-regex": "^2.0.0" } }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } }, "homedir-polyfill": { "version": "1.0.3", @@ -7110,14 +11040,6 @@ "inherits": "2.0.3", "setprototypeof": "1.1.0", "statuses": ">= 1.4.0 < 2" - }, - "dependencies": { - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true - } } }, "http-parser-js": { @@ -7126,31 +11048,63 @@ "integrity": "sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w==", "dev": true }, - "http-signature": { - "version": "1.2.0", + "http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" } }, - "http2": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/http2/-/http2-3.3.7.tgz", - "integrity": "sha512-puSi8M8WNlFJm9Pk4c/Mbz9Gwparuj3gO9/RRO5zv6piQ0FY+9Qywp0PdWshYgsMJSalixFY7eC6oPu0zRxLAQ==", + "husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", "dev": true }, "iconv-lite": { "version": "0.4.23", - "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true + }, + "import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -7159,7 +11113,8 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true }, "ini": { "version": "1.3.8", @@ -7192,10 +11147,13 @@ } }, "ionicons": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-4.6.3.tgz", - "integrity": "sha512-cgP+VIr2cTJpMfFyVHTerq6n2jeoiGboVoe3GlaAo5zoSBDAEXORwUZhv6m+lCyxlsHCS3nqPUE+MKyZU71t8Q==", - "dev": true + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-8.0.9.tgz", + "integrity": "sha512-qC8xcTVcrmC9e+4KwigtbfKa9J27rFzsjvi1wQBue178Az6u6mFDpL/Q10w534+RD5PkmiXlqy7my7+h2B/zTw==", + "dev": true, + "requires": { + "@stencil/core": "^4.30.0" + } }, "is-absolute": { "version": "1.0.0", @@ -7208,14 +11166,20 @@ } }, "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "requires": { - "has": "^1.0.3" + "hasown": "^2.0.2" } }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -7232,22 +11196,41 @@ } }, "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" } }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-like": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz", + "integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==", + "dev": true, + "requires": { + "lodash.isfinite": "^3.3.2" + } + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -7275,9 +11258,6 @@ "is-unc-path": "^1.0.0" } }, - "is-typedarray": { - "version": "1.0.0" - }, "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", @@ -7293,15 +11273,20 @@ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true }, "isobject": { "version": "3.0.1", @@ -7309,8 +11294,14 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, - "isstream": { - "version": "0.1.2" + "jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2" + } }, "jquery": { "version": "3.6.3", @@ -7319,10 +11310,13 @@ "dev": true }, "jquery-ui-dist": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/jquery-ui-dist/-/jquery-ui-dist-1.12.1.tgz", - "integrity": "sha1-XAgV08xvkP9fqvWyaKbiO0ypBPo=", - "dev": true + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/jquery-ui-dist/-/jquery-ui-dist-1.13.3.tgz", + "integrity": "sha512-qeTR3SOSQ0jgxaNXSFU6+JtxdzNUSJKgp8LCzVrVKntM25+2YBJW1Ea8B2AwjmmSHfPLy2dSlZxJQN06OfVFhg==", + "dev": true, + "requires": { + "jquery": ">=1.8.0 <4.0.0" + } }, "js-yaml": { "version": "3.14.1", @@ -7343,9 +11337,6 @@ "xmlcreate": "^2.0.4" } }, - "jsbn": { - "version": "0.1.1" - }, "jsdifflib": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsdifflib/-/jsdifflib-1.1.0.tgz", @@ -7472,16 +11463,23 @@ "walk-back": "^5.1.0" } }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true }, "json-schema-traverse": { - "version": "0.4.1" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, - "json-stringify-safe": { - "version": "5.0.1" + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true }, "jsonfile": { "version": "4.0.0", @@ -7492,15 +11490,13 @@ "graceful-fs": "^4.1.6" } }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" + "json-buffer": "3.0.1" } }, "klaw": { @@ -7512,6 +11508,16 @@ "graceful-fs": "^4.1.9" } }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, "liftup": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", @@ -7528,24 +11534,6 @@ "resolve": "^1.19.0" }, "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "findup-sync": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", @@ -7558,22 +11546,6 @@ "resolve-dir": "^1.0.1" } }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -7584,25 +11556,91 @@ "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } + } + } + }, + "lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true + }, + "linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "requires": { + "uc.micro": "^1.0.1" + } + }, + "lint-staged": { + "version": "16.1.4", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.1.4.tgz", + "integrity": "sha512-xy7rnzQrhTVGKMpv6+bmIA3C0yET31x8OhKBYfvGo0/byeZ6E0BjGARrir3Kg/RhhYHutpsi01+2J5IpfVoueA==", + "dev": true, + "requires": { + "chalk": "^5.4.1", + "commander": "^14.0.0", + "debug": "^4.4.1", + "lilconfig": "^3.1.3", + "listr2": "^9.0.1", + "micromatch": "^4.0.8", + "nano-spawn": "^1.0.2", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.8.0" + }, + "dependencies": { + "chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "dev": true }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "commander": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.0.tgz", + "integrity": "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==", + "dev": true + }, + "debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, "requires": { - "is-number": "^7.0.0" + "ms": "^2.1.3" } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true } } }, - "linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "listr2": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.1.tgz", + "integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==", "dev": true, "requires": { - "uc.micro": "^1.0.1" + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "dependencies": { + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + } } }, "livereload-js": { @@ -7612,15 +11650,25 @@ "dev": true }, "load-grunt-tasks": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-3.5.2.tgz", - "integrity": "sha1-ByhWEYD9IP+KaSdQWFL8WKrqDIg=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-5.1.0.tgz", + "integrity": "sha512-oNj0Jlka1TsfDe+9He0kcA1cRln+TMoTsEByW7ij6kyktNLxBKJtslCFEvFrLC2Dj0S19IWJh3fOCIjLby2Xrg==", + "dev": true, + "requires": { + "arrify": "^2.0.1", + "multimatch": "^4.0.0", + "pkg-up": "^3.1.0", + "resolve-pkg": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "arrify": "^1.0.0", - "multimatch": "^2.0.0", - "pkg-up": "^1.0.0", - "resolve-pkg": "^0.1.0" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" } }, "lodash": { @@ -7634,6 +11682,18 @@ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", "dev": true }, + "lodash.isfinite": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", + "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "lodash.omit": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", @@ -7652,18 +11712,73 @@ "integrity": "sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==", "dev": true }, - "lodash.result": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/lodash.result/-/lodash.result-4.5.2.tgz", - "integrity": "sha512-dlgJvozORK2oE4jXzTGIsJz9Vk6huNAINxYYvWc/R44x3/ah/F7OkNwr9c0wO2poh2cbdjS0jF3j8VgyCEOVfw==" + "log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "requires": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "requires": { + "get-east-asian-width": "^1.0.0" + } + }, + "slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "requires": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "lru-cache": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", + "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", + "dev": true }, "magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dev": true, + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "requires": { - "sourcemap-codec": "^1.4.8" + "@jridgewell/sourcemap-codec": "^1.5.0" } }, "make-iterator": { @@ -7724,15 +11839,54 @@ "dev": true }, "maxmin": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz", - "integrity": "sha1-TTsiCQPZXu5+t6x/qGTnLcCaMWY=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-3.0.0.tgz", + "integrity": "sha512-wcahMInmGtg/7c6a75fr21Ch/Ks1Tb+Jtoan5Ft4bAI0ZvJqyOw8kkM7e7p8hDSzY805vmxwHT50KcjGwKyJ0g==", "dev": true, "requires": { - "chalk": "^1.0.0", - "figures": "^1.0.1", - "gzip-size": "^3.0.0", - "pretty-bytes": "^3.0.0" + "chalk": "^4.1.0", + "figures": "^3.2.0", + "gzip-size": "^5.1.1", + "pretty-bytes": "^5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "mdurl": { @@ -7741,28 +11895,55 @@ "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", "dev": true }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, "metagraph": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/metagraph/-/metagraph-0.0.7.tgz", "integrity": "sha512-aA2EvUZIMSbwdscFRyJoG3X5yBbehv6MZXe0bhPO3o1ozVi4hMltljuIssQ0/PEyJrAA/WL72Cf3Bkerx6TuGg==" }, + "micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "requires": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + } + }, "mime": { - "version": "1.4.1", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true }, "mime-db": { - "version": "1.33.0" + "version": "1.33.0", + "dev": true }, "mime-types": { "version": "2.1.18", + "dev": true, "requires": { "mime-db": "~1.33.0" } }, + "mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true + }, "minimatch": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7770,15 +11951,14 @@ "minimist": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "requires": { - "minimist": "^1.2.6" - } + "minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true }, "mkdirp2": { "version": "1.0.5", @@ -7792,16 +11972,24 @@ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" }, "morgan": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", - "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", "dev": true, "requires": { - "basic-auth": "~2.0.0", + "basic-auth": "~2.0.1", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "~2.0.0", "on-finished": "~2.3.0", - "on-headers": "~1.0.1" + "on-headers": "~1.0.2" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + } } }, "ms": { @@ -7811,27 +11999,29 @@ "dev": true }, "multimatch": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", - "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz", + "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", "dev": true, "requires": { - "array-differ": "^1.0.0", - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "minimatch": "^3.0.0" + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" } }, - "nan": { - "version": "2.12.1" + "nano-spawn": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-1.0.2.tgz", + "integrity": "sha512-21t+ozMQDAL/UGgQVBbZ/xXvNO10++ZPuTmKRO8k9V3AClVRht49ahtDjfY8l1q6nSHOrE5ASfthzH3ol6R/hg==", + "dev": true }, - "nbind": { - "version": "0.3.15", - "requires": { - "emscripten-library-decorator": "~0.2.2", - "mkdirp": "~0.5.1", - "nan": "^2.9.2" - } + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true }, "negotiator": { "version": "0.6.1", @@ -7843,32 +12033,11 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "node-gyp": { - "version": "3.8.0", - "requires": { - "fstream": "^1.0.0", - "glob": "^7.0.3", - "graceful-fs": "^4.1.2", - "mkdirp": "^0.5.0", - "nopt": "2 || 3", - "npmlog": "0 || 1 || 2 || 3 || 4", - "osenv": "0", - "request": "^2.87.0", - "rimraf": "2", - "semver": "~5.3.0", - "tar": "^2.0.0", - "which": "1" - }, - "dependencies": { - "semver": { - "version": "5.3.0" - } - } - }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, "requires": { "abbrev": "1" } @@ -7882,29 +12051,17 @@ "path-key": "^2.0.0" } }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "oauth-sign": { - "version": "0.9.0" + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true }, "object-get": { "version": "2.1.1", @@ -7958,53 +12115,122 @@ "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, "requires": { "ee-first": "1.1.1" } }, "on-headers": { - "version": "1.0.1", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1" } }, - "opn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", - "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "requires": { + "mimic-function": "^5.0.0" + } + }, + "open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "requires": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" } }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true }, "osenv": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" } }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", @@ -8034,22 +12260,22 @@ "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" }, "parseurl": { - "version": "1.3.2", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true }, "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, "path-key": { "version": "2.0.1", @@ -8078,8 +12304,21 @@ "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", "dev": true }, - "performance-now": { - "version": "2.1.0" + "path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dev": true, + "requires": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + } + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true }, "picocolors": { "version": "0.2.1", @@ -8092,28 +12331,25 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", "dev": true }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true }, "pkg-up": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", - "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", "dev": true, "requires": { - "find-up": "^1.0.0" + "find-up": "^3.0.0" } }, "plur": { @@ -8123,12 +12359,24 @@ "dev": true }, "portscanner": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-1.2.0.tgz", - "integrity": "sha1-sUu9olfRTDEPqcwJaCrwLUCWGAI=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.2.0.tgz", + "integrity": "sha512-IFroCz/59Lqa2uBvzK3bKDbDDIEaAY8XJ1jFxcLWTqosrsc32//P4VuSB2vZXoHiHqOmx8B5L5hnKOxL/7FlPw==", "dev": true, "requires": { - "async": "1.5.2" + "async": "^2.6.0", + "is-number-like": "^1.0.3" + }, + "dependencies": { + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + } } }, "postcss": { @@ -8147,14 +12395,17 @@ } } }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, "pretty-bytes": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz", - "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true }, "pretty-ms": { "version": "2.1.0", @@ -8167,24 +12418,17 @@ "plur": "^1.0.0" } }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, "promise-polyfill": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.3.tgz", "integrity": "sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg==", "dev": true }, - "psl": { - "version": "1.1.31" - }, "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true }, "qs": { "version": "6.11.0", @@ -8200,8 +12444,22 @@ "resolved": "https://registry.npmjs.org/queue-async/-/queue-async-1.2.1.tgz", "integrity": "sha1-BYLgHa4lMljPV2/Co125b8qEf28=" }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true + }, "range-parser": { - "version": "1.2.0", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true }, "raw-body": { @@ -8222,30 +12480,6 @@ } } }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, "rechoir": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", @@ -8332,54 +12566,11 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz", "integrity": "sha512-+1epbAxtKeXttkGFMTX9H42oqzOTufR1ceCF+GYA5aOmvaPq9wd4PUS8329fn2RRLGNeUkgRLnVpycjx8DsO2w==", - "dev": true, - "requires": { - "array-back": "^1.0.3", - "typical": "^2.6.0" - } - } - } - }, - "request": { - "version": "2.88.0", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" - }, - "mime-types": { - "version": "2.1.24", + "dev": true, "requires": { - "mime-db": "1.40.0" + "array-back": "^1.0.3", + "typical": "^2.6.0" } - }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" } } }, @@ -8392,10 +12583,11 @@ "lodash": "^4.17.21" } }, - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true }, "resolve-dir": { "version": "1.0.1", @@ -8408,32 +12600,128 @@ } }, "resolve-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, "resolve-pkg": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/resolve-pkg/-/resolve-pkg-0.1.0.tgz", - "integrity": "sha1-AsyZNBDik2livZcWahsHfalyVTE=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg/-/resolve-pkg-2.0.0.tgz", + "integrity": "sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ==", "dev": true, "requires": { - "resolve-from": "^2.0.0" + "resolve-from": "^5.0.0" } }, - "rimraf": { - "version": "2.2.8" - }, - "rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, "requires": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + } + }, + "reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true + }, + "rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true + }, + "rollup": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.0.tgz", + "integrity": "sha512-qHcdEzLCiktQIfwBq420pn2dP+30uzqYxv9ETm91wdt2R9AFcWfjNAmje4NWlnCIQ5RMTzVf0ZyisOKqHR6RwA==", + "devOptional": true, + "requires": { + "@rollup/rollup-android-arm-eabi": "4.44.0", + "@rollup/rollup-android-arm64": "4.44.0", + "@rollup/rollup-darwin-arm64": "4.44.0", + "@rollup/rollup-darwin-x64": "4.44.0", + "@rollup/rollup-freebsd-arm64": "4.44.0", + "@rollup/rollup-freebsd-x64": "4.44.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.44.0", + "@rollup/rollup-linux-arm-musleabihf": "4.44.0", + "@rollup/rollup-linux-arm64-gnu": "4.44.0", + "@rollup/rollup-linux-arm64-musl": "4.44.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.44.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.44.0", + "@rollup/rollup-linux-riscv64-gnu": "4.44.0", + "@rollup/rollup-linux-riscv64-musl": "4.44.0", + "@rollup/rollup-linux-s390x-gnu": "4.44.0", + "@rollup/rollup-linux-x64-gnu": "4.44.0", + "@rollup/rollup-linux-x64-musl": "4.44.0", + "@rollup/rollup-win32-arm64-msvc": "4.44.0", + "@rollup/rollup-win32-ia32-msvc": "4.44.0", + "@rollup/rollup-win32-x64-msvc": "4.44.0", + "@types/estree": "1.0.8", "fsevents": "~2.3.2" }, "dependencies": { + "@rollup/rollup-darwin-arm64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.0.tgz", + "integrity": "sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-darwin-x64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.0.tgz", + "integrity": "sha512-fBkyrDhwquRvrTxSGH/qqt3/T0w5Rg0L7ZIDypvBPc1/gzjJle6acCpZ36blwuwcKD/u6oCE/sRWlUAcxLWQbQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.0.tgz", + "integrity": "sha512-ZTR2mxBHb4tK4wGf9b8SYg0Y6KQPjGpR4UWwTFdnmjB4qRtoATZ5dWn3KsDwGa5Z2ZBOE7K52L36J9LueKBdOQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm64-musl": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.0.tgz", + "integrity": "sha512-GFWfAhVhWGd4r6UxmnKRTBwP1qmModHtd5gkraeW2G490BpFOZkFtem8yuX2NyafIP/mGpRJgTJ2PwohQkUY/Q==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.0.tgz", + "integrity": "sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-x64-musl": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.0.tgz", + "integrity": "sha512-PQUobbhLTQT5yz/SPg116VJBgz+XOtXt8D1ck+sfJJhuEsMj2jSej5yTdp8CvWBSceu+WW+ibVL6dm0ptG5fcA==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-arm64-msvc": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.0.tgz", + "integrity": "sha512-M0CpcHf8TWn+4oTxJfh7LQuTuaYeXGbk0eageVjQCKzYLsajWS/lFC94qlRqOlyC2KvRT90ZrfXULYmukeIy7w==", + "dev": true, + "optional": true + }, + "@rollup/rollup-win32-x64-msvc": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.0.tgz", + "integrity": "sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==", + "dev": true, + "optional": true + }, "fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -8443,62 +12731,46 @@ } } }, - "rollup-plugin-commonjs": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz", - "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==", + "rollup-plugin-copy": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.5.0.tgz", + "integrity": "sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==", "dev": true, "requires": { - "estree-walker": "^0.6.1", - "is-reference": "^1.1.2", - "magic-string": "^0.25.2", - "resolve": "^1.11.0", - "rollup-pluginutils": "^2.8.1" + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" }, "dependencies": { - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } + "is-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", + "dev": true } } }, - "rollup-plugin-node-resolve": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-2.1.1.tgz", - "integrity": "sha1-y7eDsNFbAnlNWJFTULLw2QK43cg=", - "dev": true, - "requires": { - "browser-resolve": "^1.11.0", - "builtin-modules": "^1.1.0", - "resolve": "^1.1.6" - } - }, - "rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "requires": { - "estree-walker": "^0.6.1" + "queue-microtask": "^1.2.2" } }, "rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "dev": true + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "safe-json-parse": { "version": "1.0.1", @@ -8523,26 +12795,76 @@ } }, "send": { - "version": "0.16.2", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, "statuses": { - "version": "1.4.0", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true } } @@ -8563,20 +12885,25 @@ } }, "serve-static": { - "version": "1.13.2", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "requires": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", - "parseurl": "~1.3.2", - "send": "0.16.2" + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "dependencies": { + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true + } } }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", @@ -8610,9 +12937,34 @@ } }, "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + } + } }, "sort-array": { "version": "4.1.5", @@ -8644,36 +12996,16 @@ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, - "sshpk": { - "version": "1.16.1", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true }, "stream-connect": { @@ -8702,6 +13034,12 @@ "integrity": "sha512-DBp0lSvX5G9KGRDTkR/R+a29H+Wk2xItOF+MpZLLNDWbEV9tGPnqLPxHEYjmiz8xGtJHRIqmI+hCjmNzqoA4nQ==", "dev": true }, + "string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true + }, "string-template": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", @@ -8709,23 +13047,99 @@ "dev": true }, "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "requires": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } } }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, "requires": { "ansi-regex": "^2.0.0" } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + } + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -8774,14 +13188,6 @@ "integrity": "sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA==", "dev": true }, - "tar": { - "version": "2.2.2", - "requires": { - "block-stream": "*", - "fstream": "^1.0.12", - "inherits": "2" - } - }, "temp-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/temp-path/-/temp-path-1.0.0.tgz", @@ -8867,21 +13273,37 @@ } } }, - "tough-cookie": { - "version": "2.4.3", + "tippy.js": { + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", + "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "@popperjs/core": "^2.9.0" } }, - "tunnel-agent": { - "version": "0.6.0", + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "requires": { - "safe-buffer": "^5.0.1" + "is-number": "^7.0.0" } }, - "tweetnacl": { - "version": "0.14.5" + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } }, "typical": { "version": "2.6.1", @@ -8931,6 +13353,12 @@ } } }, + "undici-types": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "dev": true + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -8940,18 +13368,16 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true }, "uri-js": { - "version": "4.2.2", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "requires": { "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1" - } } }, "uri-path": { @@ -8969,17 +13395,15 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true }, - "uuid": { - "version": "3.3.2" - }, "v8flags": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", @@ -8989,14 +13413,6 @@ "homedir-polyfill": "^1.0.1" } }, - "verror": { - "version": "1.10.0", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "viz.js": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/viz.js/-/viz.js-1.8.2.tgz", @@ -9010,6 +13426,8 @@ }, "webcola": { "version": "3.4.0", + "resolved": "https://registry.npmjs.org/webcola/-/webcola-3.4.0.tgz", + "integrity": "sha512-4BiLXjXw3SJHo3Xd+rF+7fyClT6n7I+AR6TkBqyQ4kTsePSAMDLRCXY1f3B/kXJeP9tYn4G1TblxTO+jAt0gaw==", "requires": { "d3-dispatch": "^1.0.3", "d3-drag": "^1.0.4", @@ -9018,7 +13436,9 @@ }, "dependencies": { "d3-shape": { - "version": "1.3.5", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", "requires": { "d3-path": "1" } @@ -9043,17 +13463,16 @@ }, "which": { "version": "1.2.14", + "dev": true, "requires": { "isexe": "^2.0.0" } }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "requires": { - "string-width": "^1.0.2 || 2" - } + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true }, "wordwrap": { "version": "1.0.0", @@ -9079,10 +13498,105 @@ } } }, + "wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "requires": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "x-editable": { "version": "1.5.1", @@ -9096,25 +13610,28 @@ "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", "dev": true }, - "xmlhttprequest": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", - "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", - "dev": true - }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", "dev": true }, + "yaml": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + }, "yoga-layout": { - "version": "1.9.3", - "requires": { - "autogypi": "^0.2.2", - "nbind": "^0.3.14", - "node-gyp": "^3.6.2" - } + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz", + "integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==" } } } diff --git a/package.json b/package.json index 007f3e37..59fb5b66 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,12 @@ { "name": "dc.graph", - "version": "0.9.93", + "version": "0.9.95", "license": "Apache-2.0", "copyright": "2015-2023", "description": "Graph visualizations integrated with crossfilter and dc.js", + "main": "dist/dc-graph.js", + "module": "dist/dc-graph.js", + "type": "module", "keywords": [ "visualization", "svg", @@ -24,27 +27,32 @@ "url": "https://github.com/dc-js/dc.graph.js.git" }, "dependencies": { - "crossfilter2": "~1.4.8", - "css-layout": "1.x", - "d3": "3.x", + "@rollup/plugin-replace": "^6.0.2", + "crossfilter2": "^1.5.4", + "d3": "^5.8.0", "dagre": "^0.8.5", - "dc": "~2.2.2", + "dc": "4.0.5", "ink-docstrap": "^1.3.2", "metagraph": "^0.0.7", "queue-async": "~1.x", + "tippy.js": "^6.3.7", "viz.js": "^1.8.2", "webcola": "^3.4.0", "yoga-layout": "^3.2.1" }, "devDependencies": { + "@eslint/js": "^9.32.0", "@fortawesome/fontawesome-free": "^5.14.0", "@rollup/plugin-commonjs": "^28.0.0", + "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^16.0.0", "bootstrap": "^3.4.1", "classlist-polyfill": "1.2.x", "d3-force": "^1.2.1", "d3-force-straighten-paths": "^1.0.2", - "d3-tip": "0.7.1", + "dprint": "^0.50.1", + "eslint": "^9.32.0", + "glob": "^11.0.3", "graphlib-dot": "dagrejs/graphlib-dot#v0.6.4", "grunt": "^1.3.0", "grunt-cli": "^1.5.0", @@ -57,25 +65,38 @@ "grunt-jsdoc": "^2.4.1", "grunt-jsdoc-to-markdown": "^6.0.0", "grunt-shell": "^4.0.0", + "husky": "^9.1.7", "interval-tree-1d": "^1.0.4", "ionicons": "^8.0.9", "jquery": "^3.5.1", "jquery-ui-dist": "^1.13.3", "jsdifflib": "^1.1.0", + "lint-staged": "^16.1.4", "load-grunt-tasks": "^5.1.0", "lodash": "^4.17.21", "promise-polyfill": "^8.1.3", "rollup": "^4.42.0", + "rollup-plugin-copy": "^3.5.0", "time-grunt": "^1.4.0", "uglify-js": "^3.10.3", "x-editable": "1.5.x" }, "scripts": { - "test": "grunt test", - "d3v4-force": "rollup -c d3v4-force.rollup.config.js", - "interval-tree": "rollup -c lysenko-interval-tree.rollup.config.js", - "yoga": "rollup -c yoga.rollup.config.js; sed -i .bak 's/_a = _typeModule(_typeModule),/var _a = _typeModule(_typeModule);/' yoga-layout.js", - "incrface": "rollup -c incrface.rollup.config.js" + "vendor": "cp sync-url-options.js web/js/ && cp querystring.js web/js/ && cp dc.graph.css web/css/ && cp incrface.mjs web/js/", + "build": "rollup -c && rollup -c worker.rollup.config.js", + "build:workers": "rollup -c worker.rollup.config.js", + "build:all": "npm run vendor && npm run build", + "build:watch": "rollup -c -w & rollup -c worker.rollup.config.js -w", + "dev": "rollup -c -w & rollup -c worker.rollup.config.js -w", + "serve": "python3 server.py 8888", + "start": "(npm run dev &) && npm run serve", + "lint": "eslint src/ --fix", + "format": "dprint fmt", + "prepare": "husky", + "legacy:test": "grunt test", + "legacy:d3v4-force": "rollup -c d3v4-force.rollup.config.js", + "legacy:interval-tree": "rollup -c lysenko-interval-tree.rollup.config.js", + "legacy:incrface": "rollup -c incrface.rollup.config.js" }, "npmName": "dc.graph", "npmFileMap": [ @@ -89,5 +110,19 @@ "dc.graph.js.map" ] } - ] + ], + "lint-staged": { + "src/**/*.js": [ + "eslint --fix", + "dprint fmt" + ], + "*.config.js": [ + "eslint --fix", + "dprint fmt" + ], + "scripts/**/*.js": [ + "eslint --fix", + "dprint fmt" + ] + } } diff --git a/plans/d3-event-parameter-upgrade.md b/plans/d3-event-parameter-upgrade.md new file mode 100644 index 00000000..c72af90c --- /dev/null +++ b/plans/d3-event-parameter-upgrade.md @@ -0,0 +1,186 @@ +# D3 Event Parameter Upgrade + +## Overview +This document outlines the plan to modernize event handling in dc.graph.js from the deprecated `d3.event` global to the D3 v5+ pattern of receiving events as parameters. + +## Current State +The codebase uses the D3 v3 pattern where `d3.event` is a global property available in event handlers: +```javascript +.on('click', function(d) { + if(d3.event.shiftKey) { + // handle shift-click + } + var coords = [d3.event.clientX, d3.event.clientY]; +}) +``` + +## Target State +Convert to D3 v5+ pattern where event is passed as a parameter: +```javascript +.on('click', function(event, d) { + if(event.shiftKey) { + // handle shift-click + } + var coords = [event.clientX, event.clientY]; +}) +``` + +## Why This Matters +- **D3 v5+ compatibility** - `d3.event` is deprecated and will be removed +- **Better encapsulation** - No reliance on global state +- **Modern pattern** - Follows current D3 best practices +- **TypeScript friendly** - Explicit event typing + +## Files Containing d3.event Usage +Based on analysis, these files use `d3.event`: + +- `src/select_things.js` - Click handling and modifier keys +- `src/utils.js` - Mouse coordinate calculations +- `src/spline_paths.js` - Shift key detection +- `src/keyboard.js` - Key event handling +- `src/diagram.js` - Zoom event handling ✅ **ALREADY FIXED** + +## Common Usage Patterns + +### 1. Modifier Key Detection +```javascript +// Current +if(d3.event.shiftKey) { /* ... */ } +if(isUnion(d3.event)) { /* ... */ } +if(isToggle(d3.event)) { /* ... */ } + +// Target +if(event.shiftKey) { /* ... */ } +if(isUnion(event)) { /* ... */ } +if(isToggle(event)) { /* ... */ } +``` + +### 2. Mouse Coordinates +```javascript +// Current +var coords = [d3.event.clientX, d3.event.clientY]; +var target = d3.event.target; + +// Target +var coords = [event.clientX, event.clientY]; +var target = event.target; +``` + +### 3. Keyboard Events +```javascript +// Current +if(_mod_keys.has(d3.event.key)) { + _pressed.add(d3.event.key); +} + +// Target +if(_mod_keys.has(event.key)) { + _pressed.add(event.key); +} +``` + +### 4. Zoom Events (Already Fixed) +```javascript +// Current (was) +function doZoom() { + var scale = d3.event.scale; + var translate = d3.event.translate; +} + +// Target (done) +function doZoom(event) { + var scale = event.transform.k; + var translate = [event.transform.x, event.transform.y]; +} +``` + +## Implementation Strategy + +### Phase 1: Event Handler Signatures +Update all event handler function signatures to receive event as first parameter: +```javascript +// Before +.on('click', function(d, i) { /* d3.event usage */ }) + +// After +.on('click', function(event, d) { /* event usage */ }) +``` + +### Phase 2: Replace d3.event References +Replace all `d3.event` references with the `event` parameter: +```javascript +// Before +d3.event.shiftKey +d3.event.clientX +d3.event.target + +// After +event.shiftKey +event.clientX +event.target +``` + +### Phase 3: Helper Function Updates +Update utility functions that expect `d3.event` to receive event as parameter: +```javascript +// Before +function eventCoords(diagram) { + return diagram.invertCoord([d3.event.clientX - bound.left, + d3.event.clientY - bound.top]); +} + +// After +function eventCoords(diagram, event) { + return diagram.invertCoord([event.clientX - bound.left, + event.clientY - bound.top]); +} +``` + +## Specific Files and Changes + +### src/select_things.js +- Update click handlers to receive `event` parameter +- Replace `d3.event.target`, `d3.event.shiftKey`, etc. +- Update `isUnion()` and `isToggle()` calls + +### src/utils.js +- Update `eventCoords()` function signature +- Replace mouse coordinate calculations +- Update any event-dependent utilities + +### src/spline_paths.js +- Update shift key detection in path drawing +- Replace `d3.event.shiftKey` references + +### src/keyboard.js +- Update keydown/keyup handlers +- Replace `d3.event.key` references +- Update modifier key tracking + +## Testing Strategy +1. **File-by-file conversion** - Convert one file at a time +2. **Interactive testing** - Test mouse and keyboard interactions +3. **Cross-browser testing** - Ensure event handling works across browsers +4. **Regression testing** - Verify no functionality is lost + +## Temporary Workaround +For the current D3 v5 upgrade, we're using `import { event } from 'd3'` as a temporary bridge, where `event` provides the current event. This allows the upgrade to proceed while maintaining compatibility. The full event parameter conversion should happen after the D3 v5 upgrade is stable. + +## API Compatibility Notes +- **D3 v3**: `d3.event` is always available in event handlers +- **D3 v4**: `d3.event` still available but deprecated +- **D3 v5+**: `d3.event` removed, must use event parameter +- **Modern D3**: Event is first parameter, data is second parameter + +## Prerequisites +- Complete D3 v5.8 upgrade first +- All ES6 imports working +- Basic functionality tested + +## Estimated Effort +- **Analysis and planning**: 1 hour +- **Implementation**: 4-6 hours +- **Testing and refinement**: 2-3 hours +- **Documentation updates**: 1 hour + +**Total**: ~8-11 hours focused work \ No newline at end of file diff --git a/plans/d3-join-syntax-upgrade.md b/plans/d3-join-syntax-upgrade.md new file mode 100644 index 00000000..d00ad174 --- /dev/null +++ b/plans/d3-join-syntax-upgrade.md @@ -0,0 +1,147 @@ +# D3 Join Syntax Upgrade + +## Overview +This document outlines the plan to modernize D3 data binding patterns in dc.graph.js from the traditional enter/update/exit pattern to the new `.join()` syntax introduced in D3 v5.8. + +## Current State +The codebase uses the traditional D3 v3 data binding pattern: +```javascript +var selection = parent.selectAll('.item') + .data(data); + +selection.enter().append('div') + .attr('class', 'item'); + +selection + .text(d => d.name); + +selection.exit().remove(); +``` + +## Target State +Convert to modern D3 join syntax: +```javascript +parent.selectAll('.item') + .data(data) + .join('div') + .attr('class', 'item') + .text(d => d.name); +``` + +## Benefits +- **Cleaner code** - Eliminates verbose enter/update/exit boilerplate +- **Better performance** - D3's join method is optimized internally +- **Easier to teach** - Simpler mental model for newcomers +- **Modern D3 pattern** - Follows current best practices + +## Files to Update +Based on analysis, these 16 files contain enter/exit/update patterns: + +- `src/expand_collapse.js` +- `src/legend.js` +- `src/render_svg.js` +- `src/draw_graphs.js` +- `src/troubleshoot.js` +- `src/tip.js` +- `src/spline_paths.js` +- `src/node_contents.js` +- `src/render_webgl.js` +- `src/draw_clusters.js` +- `src/annotate_layers.js` +- `src/annotate_nodes.js` +- `src/path_selector.js` +- `src/symbol_port_style.js` +- `src/grid.js` +- `src/dropdown.js` + +## Implementation Strategy + +### Phase 1: Simple Patterns +Start with straightforward enter/exit patterns where data doesn't change structure: +```javascript +// Before +var items = container.selectAll('.item').data(data); +items.enter().append('div').attr('class', 'item'); +items.text(d => d.name); +items.exit().remove(); + +// After +container.selectAll('.item') + .data(data) + .join('div') + .attr('class', 'item') + .text(d => d.name); +``` + +### Phase 2: Complex Patterns +Handle more complex patterns with different enter/update behaviors: +```javascript +// Before +var items = container.selectAll('.item').data(data); +items.enter().append('div') + .attr('class', 'item') + .style('opacity', 0); +items + .style('opacity', 1) + .text(d => d.name); +items.exit() + .style('opacity', 0) + .remove(); + +// After +container.selectAll('.item') + .data(data) + .join( + enter => enter.append('div') + .attr('class', 'item') + .style('opacity', 0), + update => update + .style('opacity', 1), + exit => exit + .style('opacity', 0) + .remove() + ) + .text(d => d.name); +``` + +### Phase 3: Animation-Heavy Patterns +Convert complex animations and transitions used in rendering components. + +## Testing Approach +1. **File-by-file conversion** - Convert one file at a time +2. **Visual testing** - Test examples that use the converted patterns +3. **Regression testing** - Ensure no visual or functional changes +4. **Performance validation** - Verify performance improvements + +## Common Patterns in Codebase + +### SVG Element Creation +Common in `render_svg.js` and visualization components: +- Node rendering with shapes and content +- Edge path creation and updates +- Arrow and marker management + +### Dynamic UI Elements +Common in `legend.js`, `dropdown.js`, `tip.js`: +- Legend item creation/removal +- Tooltip content updates +- Interactive element state changes + +### Annotation Systems +Common in `annotate_*.js` files: +- Layer annotation rendering +- Node/edge labeling systems +- Overlay element management + +## Prerequisites +- Complete D3 v5.8 upgrade first +- Ensure all ES6 imports are working +- All examples tested with traditional patterns + +## Estimated Effort +- **Simple patterns**: 8 files, ~2-3 hours +- **Complex patterns**: 6 files, ~4-5 hours +- **Animation patterns**: 2 files, ~2-3 hours +- **Testing & refinement**: ~2-3 hours + +**Total**: ~10-15 hours of focused work \ No newline at end of file diff --git a/plans/d3-selection-lessons-learned.md b/plans/d3-selection-lessons-learned.md new file mode 100644 index 00000000..65858dbf --- /dev/null +++ b/plans/d3-selection-lessons-learned.md @@ -0,0 +1,131 @@ +# D3 v5 Selection Management: Lessons Learned + +## The Problem + +During migration from D3 v3 to D3 v5, we encountered a persistent issue where edge hint lines weren't appearing in the DOM. The `g.draw-graphs` element was being created, but child elements (hint lines) weren't being added to it. + +## Root Cause Analysis + +### 1. Selection Staleness +The core issue was **selection staleness**. We were storing a D3 selection (`_edgeLayer`) that pointed to DOM elements, but when the SVG was recreated (via `resetSvg()`), the selection became stale - it pointed to destroyed DOM nodes. + +```javascript +// ❌ Problematic pattern - selection becomes stale +if(!_edgeLayer) { + _edgeLayer = parent.append('g').attr('class', 'draw-graphs'); +} +``` + +### 2. Parent Chain Issues in D3 v5 +D3 v5 is stricter about parent chain management than D3 v3. Using `select().append()` can break parent chains: + +```javascript +// ❌ Can break parent chains in D3 v5 +const svg = root.select('svg'); // Parent chain gets confused +const g = svg.append('g'); // May have wrong parent reference +``` + +### 3. Data Join Pattern Reliability +The `selectAll().data().enter().append()` pattern maintains proper parent chains because it's part of D3's core data join mechanism: + +```javascript +// ✅ Reliable parent chain management +const svg = root.selectAll('svg').data([1]).enter().append('svg'); +``` + +## The Solution + +### Pattern 1: Fresh Selections (What Works for Other Layers) +The `edge-layer` and `node-layer` work because they get fresh selections each time: + +```javascript +// In initializeDrawing() - called every time SVG is recreated +_edgeLayer = _g.selectAll('g.edge-layer'); // Fresh selection each time +_nodeLayer = _g.selectAll('g.node-layer'); // Fresh selection each time +``` + +### Pattern 2: Full Data Join with Merge (Our Final Solution) +For elements that need to persist and be created as needed: + +```javascript +// ✅ Robust pattern that handles both creation and updates +const diagramG = diagram.g(); +const edgeLayerSelection = diagramG.selectAll('g.draw-graphs') + .data([1]); +_edgeLayer = edgeLayerSelection.enter().append('g') + .attr('class', 'draw-graphs') + .merge(edgeLayerSelection); +``` + +## Key Insights About D3 Selection Types + +### 1. `enter()` Selection +- Returns only **newly created** elements +- Good for initial setup, but doesn't include existing elements +- Becomes empty on subsequent calls if elements already exist + +### 2. `merge()` Selection +- Combines enter and update selections +- Includes **both new and existing** elements +- This is what you usually want for persistent functionality + +### 3. Regular `selectAll()` Selection +- Returns existing elements only +- Empty if elements don't exist yet +- Good for read-only operations or when you know elements exist + +## Migration Guidelines for D3 v3 → v5 + +### ❌ Avoid These Patterns +```javascript +// 1. One-time element creation with persistence +if(!selection) { + selection = parent.append('element'); +} + +// 2. Direct select().append() chains +const child = parent.select('child').append('grandchild'); + +// 3. Storing selections across DOM recreations +``` + +### ✅ Use These Patterns Instead +```javascript +// 1. Always refresh selections or use full data join +const selection = parent.selectAll('.class').data([1]); +const merged = selection.enter().append('element').merge(selection); + +// 2. Data join pattern for single elements +const element = parent.selectAll('.class') + .data([1]) + .enter().append('element') + .attr('class', 'class'); + +// 3. Fresh selections each time +const layer = parent.selectAll('.layer'); // Get fresh each time +``` + +## Why This Matters + +1. **D3 v5 Strictness**: D3 v5 is more strict about parent chain management than v3 +2. **DOM Lifecycle**: Modern web apps often recreate DOM sections, making selection staleness common +3. **Data Join Reliability**: The data join pattern is D3's most robust selection mechanism +4. **Performance**: Merge selections are efficient - D3 optimizes them internally + +## Best Practices + +1. **Always use merge()** when you need both new and existing elements +2. **Refresh selections** after DOM recreation rather than caching them +3. **Prefer data join patterns** over direct append() calls +4. **Test selection staleness** by triggering DOM recreation in your app +5. **Follow patterns from D3 examples** rather than porting D3 v3 code directly + +## Debugging Tips + +1. Check if selections are empty: `selection.empty()` +2. Check selection size: `selection.size()` +3. Inspect parent chains: `selection._parents[0]` +4. Log actual DOM state vs selection state +5. Look for elements being created but not appearing in DOM (staleness indicator) + +This experience reinforces that D3 migrations require understanding the selection model deeply, not just updating syntax. \ No newline at end of file diff --git a/plans/d3v5-upgrade.md b/plans/d3v5-upgrade.md new file mode 100644 index 00000000..43305985 --- /dev/null +++ b/plans/d3v5-upgrade.md @@ -0,0 +1,167 @@ +# D3 v5 Example Upgrade Guide + +## Overview +This document outlines the process for upgrading HTML examples from D3 v3 script tags to D3 v5 ES6 modules with importmaps. + +## Current Status + +### ✅ Completed Examples (13) +Examples already converted to D3 v5 with importmaps: +- explore.html +- drag-drop-composition.html +- compare-layouts.html +- index.html +- brushing-filtering.html +- random.html +- simple-viewer.html +- network-building.html +- arrow-designer.html +- **match-game.html** (completed - fixed D3 v5 exit-before-merge pattern bug) +- **resizing.html** (completed - fixed undefined shape warning) +- **shapes-and-text.html** (completed) +- **flexbox.html** (completed) + +### 🔄 Remaining Examples (0) +All examples have been successfully converted to D3 v5 with ES6 modules! + +### 🗑️ Removed Examples (2) +- collapse-equivalent-subgraphs.html (deleted - no test data) +- original-test-page.html (deleted per user request) + +## Upgrade Process + +### Step 1: HTML Changes +Replace D3 v3 script tags with ES6 importmap: + +**Remove:** +```html + + + + +``` + +**Add:** +```html + +``` + +### Step 2: Common Additional Dependencies + +**For flexbox examples:** +```html +"yoga-layout": "https://cdn.jsdelivr.net/npm/yoga-layout@1.10.0/+esm" +``` + +**For examples with tooltips:** +```html +"tippy.js": "https://cdn.jsdelivr.net/npm/tippy.js@6.3.7/+esm" +``` + +**For examples with multiple layout engines:** +```html +"webcola": "https://cdn.jsdelivr.net/npm/webcola@3.4.0/+esm", +"dagre": "https://cdn.jsdelivr.net/npm/dagre@0.8.5/+esm" +``` + +### Step 3: JavaScript File Updates + +**Add specific imports at top of .js file:** +```javascript +import { range } from 'd3-array'; // for d3.range usage +import { renderAll } from 'dc'; // for dc.renderAll() usage +import { scaleOrdinal } from 'd3-scale'; // for d3.scaleOrdinal usage +``` + +**Update function calls:** +```javascript +// Before +d3.range(10) +dc.renderAll() + +// After +range(10) +renderAll() +``` + +### Step 4: Module Loading Issues + +**Remove conflicting script tags:** +- Remove `querystring.js` from script tags if importing as module +- Keep jQuery/jQuery UI as script tags (not ES6 modules) +- Keep chart.registry.js as script tag + +**Handle global dependencies:** +- querystring: Import as `import querystring from './querystring.js'` +- Other utilities: Import as needed from dc-graph.js + +### Step 5: Common Error Patterns & Fixes + +**"Unexpected token 'export'" Error:** +- Cause: File has `export` but loaded as regular script +- Fix: Either import as module OR remove from script tags + +**"Failed to resolve module specifier" Error:** +- Cause: Missing dependency in importmap +- Fix: Add missing package to importmap + +**"X is not a function" Error:** +- Cause: Global variable not available, need specific import +- Fix: Import specific function from appropriate D3 sub-package + +## Package Versions (Tested & Working) + +```json +{ + "d3": "5.16.0", + "d3-array": "1.2.4", + "d3-collection": "1.0.7", + "d3-scale": "2.2.2", + "d3-selection": "1.4.2", + "crossfilter2": "1.5.4", + "dc": "4.0.5", + "lodash": "4.17.21", + "yoga-layout": "1.10.0", + "tippy.js": "6.3.7", + "webcola": "3.4.0", + "dagre": "0.8.5" +} +``` + +## Testing Checklist + +For each converted example: +- [ ] Page loads without console errors +- [ ] Graph renders correctly +- [ ] Interactions work (hover, click, etc.) +- [ ] Layout algorithms function properly +- [ ] No "Failed to resolve module" errors +- [ ] No "Unexpected token export" errors + +## Notes + +- **Rollup automatically copies** build artifacts to web/js/ - no need to manually copy +- **Order matters**: Converting from most to least complex helps identify all edge cases early +- **Module conflicts**: ES6 modules and script tags don't mix - pick one approach per dependency +- **D3 v5 compatibility**: Use specific sub-package imports, not the full D3 bundle where possible +- **Exit-before-merge pattern**: In D3 v5, must call .exit() before .merge() or exit selection is lost + +## Next Steps + +1. Convert resizing.html (most complex - tackle hardest first) +2. Convert shapes-and-text.html (medium complexity) +3. Convert flexbox.html (simple case) +4. Update this document with any new patterns discovered \ No newline at end of file diff --git a/plans/d3v6-join-syntax-upgrade.md b/plans/d3v6-join-syntax-upgrade.md new file mode 100644 index 00000000..3184eb0b --- /dev/null +++ b/plans/d3v6-join-syntax-upgrade.md @@ -0,0 +1,246 @@ +# D3 v6 Join Syntax Upgrade Plan + +## Overview +This document outlines the plan to modernize D3 data binding patterns in dc.graph.js from the traditional enter/update/exit pattern to the new `.join()` syntax, **after** upgrading to D3 v6+. This plan replaces the previous D3 v5.8 join upgrade plan due to event handling compatibility issues in D3 v5. + +## Strategic Decision: D3 v6 First, Then Join + +### Why D3 v6 Before Join Conversion? +1. **Event Handling**: D3 v6 eliminates the problematic `d3.event` global that causes null reference errors in bundled environments +2. **Clean Event API**: Events are passed as parameters to handlers, eliminating bundler conflicts +3. **Mature Join Support**: D3 v6+ has more stable and feature-complete `.join()` implementation +4. **Future-Proof**: Aligns with modern D3 best practices and long-term library direction + +## D3 v5.8 Event Problems: Lessons Learned + +### Root Cause: `d3.event` + ES6 Bundlers = Chaos +During our D3 v5.8 join conversion, we encountered severe event handling issues that proved intractable: + +**The Problem:** +```javascript +// D3 v5 zoom handlers expect d3.event to exist +zoom.js:260 Cannot read properties of null (reading 'view') +zoom.js:34 Cannot read properties of null (reading 'deltaY') +``` + +**Why This Happens:** +1. **`d3.event` is a live binding** - its value changes during events +2. **ES6 bundlers break this** - Babel/Webpack copy properties, making `d3.event` always null +3. **Modular imports make it worse** - different versions of d3-selection vs d3-zoom +4. **Bundler workarounds are fragile** - require careful import/export configuration + +**What We Tried (All Failed):** +- ✅ Updated all files to import from d3 bundle vs modules +- ✅ Fixed import consistency across 10+ files +- ✅ Removed conflicting d3-zoom/d3-transition imports from HTML +- ❌ Still got null event errors in zoom behaviors +- ❌ Issue persists because D3 v5 zoom/drag/brush internally rely on `d3.event` + +**The Fundamental Issue:** +D3 v5's architecture assumes `d3.event` is available globally during event callbacks. Modern bundlers break this assumption, and there's no clean workaround that doesn't involve fighting the tooling. + +### D3 v6 Solution: Complete Architecture Change +D3 v6 **eliminated `d3.event` entirely**, solving this at the source: + +```javascript +// D3 v5 (broken with bundlers) +.on('zoom', function() { + const transform = d3.event.transform; // d3.event = null +}) + +// D3 v6 (clean, always works) +.on('zoom', function(event) { + const transform = event.transform; // event passed as parameter +}) +``` + +This architectural change makes D3 v6+ **fully compatible** with all modern bundlers (Webpack, Rollup, Vite) without workarounds. + +### D3 v5.8 Work Completed (To Be Rebased) +- ✅ `src/render_svg.js` - **19 join() calls** - Core SVG rendering (MOST COMPLEX) +- ✅ `src/shape.js` - API updated for new pattern +- ✅ `src/symbol_port_style.js` - **4 join() calls** - Complex animations & multi-element creation +- ✅ Fixed D3 import consistency issues (10 files updated to use d3 bundle) +- ✅ Fixed tooltip callback patterns to use modern async/promise API + +## D3 v6 Migration Benefits for Join Conversion + +### Event Handling Improvements +```javascript +// D3 v5 (problematic with bundlers) +.on('zoom', function() { + const transform = d3.event.transform; // d3.event can be null +}) + +// D3 v6+ (clean, always works) +.on('zoom', function(event) { + const transform = event.transform; // event passed as parameter +}) +``` + +### Import Simplification +```javascript +// D3 v5 - needed careful bundle vs modular import management +import { select, selectAll } from 'd3'; // bundle required for .join() +import { event as d3Event } from 'd3'; // event issues + +// D3 v6+ - can use modular imports safely +import { select, selectAll } from 'd3-selection'; // .join() works +import { zoom } from 'd3-zoom'; // no event conflicts +``` + +## Bundler Compatibility Research Summary + +### D3 v6+ Bundler Support +Based on research, D3 v6+ has excellent compatibility with modern bundlers: + +- **Webpack**: Full compatibility with proper configuration +- **Rollup**: Native compatibility (D3 itself uses Rollup) +- **Vite**: Excellent support through Rollup-based production builds +- **ES Modules**: D3 v6+ ships as pure ES modules +- **Tree Shaking**: Modular architecture works well with bundler optimization + +### Import Strategy Post-D3v6 +```javascript +// Can safely use modular imports in D3 v6+ +import { select, selectAll } from 'd3-selection'; // .join() works +import { zoom } from 'd3-zoom'; // no event conflicts +import { drag } from 'd3-drag'; // events passed as parameters +``` + +No more need for careful bundle vs modular import management! + +## Post-D3v6 Upgrade: Join Conversion Plan + +### Files Status After Rebase + +**COMPLETED (will need rebase resolution):** +- ✅ `src/render_svg.js` - Core SVG rendering +- ✅ `src/shape.js` - Shape creation API +- ✅ `src/symbol_port_style.js` - Port animations + +**REMAINING (12 files, 36 enter/exit patterns):** + +**High Priority - Most Complex First:** +- `src/spline_paths.js` - 4 complex patterns with events & path calculations +- `src/legend.js` - 3 medium-complex patterns with interactions +- `src/draw_graphs.js` - 3 medium-complex patterns with hint lines + +**Medium Priority - Standard Patterns:** +- `src/node_contents.js` - 4 medium-complex patterns (text + icons) +- `src/expand_collapse.js` - 2 medium patterns with gradients +- `src/troubleshoot.js` - 6 simple-medium patterns (debug viz) +- `src/tip.js` - 1 medium pattern (table generation) + +**Low Priority - Simple Patterns:** +- `src/dropdown.js` - 3 simple-medium patterns +- `src/draw_clusters.js` - 2 medium patterns +- `src/grid.js` - 4 simple-medium patterns +- `src/annotate_layers.js` - 2 simple-medium patterns +- `src/annotate_nodes.js` - 1 simple pattern + +## D3 v6 Join Conversion Patterns + +### 1. Simple Join (Enhanced in v6) +```javascript +// D3 v6 - cleaner, more reliable +const items = container.selectAll('.item') + .data(data) + .join('div') + .attr('class', 'item') + .text(d => d.name); +``` + +### 2. Complex Join with Event Handling +```javascript +// D3 v6 - events passed as parameters +.join( + enter => enter.append('g') + .attr('class', 'item') + .on('click', function(event, d) { // event parameter + // No more d3.event issues + handleClick(event, d); + }), + update => update, + exit => exit.remove() +) +``` + +### 3. Multi-Element Creation (Unchanged Pattern) +```javascript +// This pattern remains the same in D3 v6 +const labelGroup = items.selectAll('g.label-group').data(data) +.join( + enter => { + const group = enter.append('g').attr('class', 'label-group'); + group.append('rect').attr('class', 'background'); + group.append('text').attr('class', 'label'); + return group; + } +); +``` + +## Implementation Strategy Post-D3v6 + +### Phase 1: Rebase and Verify (1-2 hours) +1. **Rebase join branch** onto D3 v6 branch +2. **Resolve merge conflicts** with help +3. **Update event handling** in converted files to use D3 v6 event parameters +4. **Test converted files** to ensure they work with D3 v6 +5. **Remove D3 bundle import workarounds** - can use modular imports + +### Phase 2: Continue Complex Conversions (4-5 hours) +1. **spline_paths.js** - Complex event handling (now much cleaner in D3 v6) +2. **legend.js** - Interactive elements +3. **draw_graphs.js** - Hint lines and interactions + +### Phase 3: Standard and Simple Patterns (3-4 hours) +Complete remaining files with straightforward conversions. + +## Event Handling Migration Notes + +### Files Requiring Event Parameter Updates +After rebase, these files will need event handling updates: +- `src/render_svg.js` - zoom handlers +- `src/symbol_port_style.js` - hover/click events +- Any other files with event handlers + +### Pattern Migration +```javascript +// Before (D3 v5 style in our converted files) +.on('mouseover', function(d) { + const event = d3Event; // or event import + // ... +}) + +// After (D3 v6 style) +.on('mouseover', function(event, d) { + // event is clean parameter + // ... +}) +``` + +## Benefits of This Approach + +1. **Clean Event Handling** - No more bundler/event conflicts +2. **Reliable Join Syntax** - Mature D3 v6 implementation +3. **Future-Proof** - Following D3's current direction +4. **Consistent Architecture** - All modern D3 patterns at once +5. **Easier Debugging** - No weird bundler-related issues + +## Estimated Effort Post-D3v6 + +- **Rebase and event updates**: 1-2 hours +- **Complex pattern completion**: 4-5 hours +- **Standard/simple patterns**: 3-4 hours +- **Testing and refinement**: 1-2 hours + +**Total**: 9-13 hours (vs fighting D3 v5 bundler issues indefinitely) + +## Success Criteria + +1. All 16 files converted to `.join()` syntax +2. No D3 event-related errors +3. All examples work with modern D3 v6+ patterns +4. Clean, maintainable code following current D3 best practices +5. Foundation set for future D3 feature adoption \ No newline at end of file diff --git a/plans/debug-logs-kept.md b/plans/debug-logs-kept.md new file mode 100644 index 00000000..690bc997 --- /dev/null +++ b/plans/debug-logs-kept.md @@ -0,0 +1,75 @@ +# Debug Logs Kept After ES6 Worker Migration + +This document lists the debug logs that were retained after cleaning up the verbose logging from the ES6 worker migration. + +## Logs Kept + +### 1. Worker Error Handling +**File**: `src/webworker_layout.js:29` +```javascript +console.error('[WORKER] Worker error for layout ' + workerName + ':', e); +``` +**Purpose**: Essential for debugging worker failures, includes layout name for context. + +### 2. WASM Initialization Errors +**File**: `src/workers/dynagraph-worker.js:20` +```javascript +console.error('[DYNAGRAPH WORKER] Failed to initialize WASM module:', error); +``` +**Purpose**: Critical for debugging WASM loading issues in dynagraph worker. + +### 3. Dynagraph Initialization Errors (Main Thread) +**File**: `src/dynagraph_layout.js:310` +```javascript +console.error('[DYNAGRAPH] Failed to initialize dynagraph:', error); +``` +**Purpose**: Essential for debugging main thread dynagraph initialization failures. + +### 4. Missing parseIncrface Warning +**File**: `src/dynagraph_layout.js:208` +```javascript +console.log('[DYNAGRAPH] parseIncrface not available, skipping'); +``` +**Purpose**: Helps debug missing incrface parser dependency. + +### 5. Incrface Parse Errors +**File**: `src/dynagraph_layout.js:213` +```javascript +console.log('[DYNAGRAPH] incrface parse failed', xep); +``` +**Purpose**: Essential for debugging incrface parsing issues. + +### 6. Dynagraph Messages (Warnings) +**File**: `src/dynagraph_layout.js:221` +```javascript +console.warn('[DYNAGRAPH] dynagraph message', cmd.message); +``` +**Purpose**: Important messages from the dynagraph WASM module. + +### 7. Graph Name Mismatch Warnings +**File**: `src/dynagraph_layout.js:225` +```javascript +console.warn('[DYNAGRAPH] graph name mismatch', _Gname, 'vs', graph); +``` +**Purpose**: Helps debug communication protocol issues between components. + +## Logs Removed + +The following types of logs were removed as they were too verbose for production use: + +- Step-by-step worker message tracing +- Command processing details +- Normal operation status messages +- Worker lifecycle startup/ready messages +- Detailed message queue operations +- Line-by-line execution tracing + +## Context + +These logs were added during the migration of dc.graph.js web workers from traditional scripts to ES6 modules with async WASM initialization. The kept logs focus on error conditions and critical warnings that indicate real problems, while removing the verbose tracing that was useful during development but not needed in production. + +The worker system now properly handles: +- Async WASM initialization in dynagraph workers +- Message queuing during initialization +- Cross-browser ES6 module support +- Proper error reporting with context \ No newline at end of file diff --git a/plans/fix-d3-selection-imports.md b/plans/fix-d3-selection-imports.md new file mode 100644 index 00000000..d9a02bc3 --- /dev/null +++ b/plans/fix-d3-selection-imports.md @@ -0,0 +1,150 @@ +# Fix D3 Selection Import Issues for .join() Support + +## Problem Statement + +D3 version conflicts between the main bundle (`d3@5.8.0`) and individual modules (`d3-selection@1.4.2`) are preventing `.join()` method from being available. The join() syntax was introduced in D3 v5.8.0, but modular imports are resolving to incompatible versions. + +## Root Cause + +- D3 v5.8.0 bundle includes d3-selection with `.join()` support +- But `import { select } from 'd3-selection'` resolves to standalone modules that may not match +- Version conflicts cause selections to lack the `.join()` method +- Browser error: `TypeError: modernRoot.selectAll(...).data(...).join is not a function` + +## Solution Strategy + +**Switch from modular d3-selection imports to D3 bundle imports** for all files that use `.join()`. + +This ensures consistent D3 version and avoids module resolution conflicts. + +## Files Requiring Changes + +### High Priority - Files Using Both `select` and `.join()` + +1. **src/render_svg.js** ⭐ CRITICAL + - Imports: `select, selectAll` from d3-selection + - Uses: 19 instances of `.join()` in complex SVG rendering + - Impact: Core rendering functionality + +### Medium Priority - Files Using `select` but Not `.join()` + +2. **src/diagram.js** + - Imports: `select` from d3-selection + - Current: No `.join()` usage + - Risk: May need `.join()` in future + +3. **src/tip.js** + - Imports: `event as d3Event, select` from d3-selection + - Current: No `.join()` usage + +4. **src/symbol_port_style.js** + - Imports: `select, event as d3Event` from d3-selection + - Current: No `.join()` usage (has string joins only) + +5. **src/legend.js** + - Imports: `select` from d3-selection + - Current: No `.join()` usage (has string joins only) + +6. **src/node_contents.js** + - Imports: `select` from d3-selection + - Current: No `.join()` usage + +7. **src/utils.js** + - Imports: `select` from d3-selection + - Current: No `.join()` usage (has string joins only) + +8. **src/draw_graphs.js** + - Imports: `event as d3Event, select` from d3-selection + - Current: No `.join()` usage (has string joins only) + +9. **src/keyboard.js** + - Imports: `select, event` from d3-selection + - Current: No `.join()` usage + +10. **src/path_selector.js** + - Imports: `select` from d3-selection + - Current: No `.join()` usage + +11. **src/move_nodes.js** + - Imports: `select, event as d3Event` from d3-selection + - Current: No `.join()` usage + +### Event-Only Imports (Lower Priority) + +12. **src/select_things.js** - Only imports `event` +13. **src/brush.js** - Only imports `event` +14. **src/spline_paths.js** - Only imports `event` +15. **src/expand_collapse.js** - Only imports `event as d3Event` +16. **src/delete_things.js** - Only imports `event as d3Event` +17. **src/label_things.js** - Only imports `event` + +## Implementation Plan + +### Phase 1: Fix Critical File (render_svg.js) + +1. **Update render_svg.js imports:** + ```javascript + // BEFORE + import { select, selectAll } from 'd3-selection'; + + // AFTER + import { select, selectAll } from 'd3'; + ``` + +2. **Update importmap in web/explore.html:** + ```javascript + // Ensure d3@5.8.0 is available + "d3": "https://cdn.jsdelivr.net/npm/d3@5.8.0/+esm" + ``` + +3. **Test render_svg.js .join() functionality** + +### Phase 2: Update All Select-Using Files + +For files 2-11 above, update imports from: +```javascript +import { select } from 'd3-selection'; +// TO +import { select } from 'd3'; +``` + +For files that import both select and event: +```javascript +import { select, event as d3Event } from 'd3-selection'; +// TO +import { select, event as d3Event } from 'd3'; +``` + +### Phase 3: Event-Only Files (Optional) + +Files 12-17 only import `event` and can remain unchanged unless issues arise. + +## Testing Strategy + +1. **Build test:** `npm run build` should succeed +2. **Browser test:** Load `web/explore.html` - should render without join() errors +3. **Functionality test:** Verify all D3 interactions work (zoom, hover, selection) +4. **Regression test:** Test other examples (simple-viewer.html, etc.) + +## Rollback Plan + +If issues arise: +1. Revert specific file imports back to `d3-selection` +2. Use traditional enter/update/exit pattern instead of `.join()` +3. Document which files need bundle vs modular imports + +## Expected Outcome + +- All `.join()` calls work consistently +- No more "join is not a function" errors +- Unified D3 version across codebase +- Foundation for future D3 join() adoption + +## Estimated Effort + +- **Phase 1:** 30 minutes (critical fix) +- **Phase 2:** 1-2 hours (systematic updates) +- **Phase 3:** 30 minutes (optional cleanup) +- **Testing:** 1 hour + +**Total:** 3-4 hours \ No newline at end of file diff --git a/plans/migrate-globals-to-es-modules.md b/plans/migrate-globals-to-es-modules.md new file mode 100644 index 00000000..46ff2c9f --- /dev/null +++ b/plans/migrate-globals-to-es-modules.md @@ -0,0 +1,301 @@ +# Migrate Global Dependencies to ES Module Imports + +## Overview +This plan outlines the migration of global dependencies currently listed in `eslint.config.js` to proper ES module imports with specific named imports where possible. + +## Current Global Dependencies to Migrate + +From `eslint.config.js` globals section: + +1. **`setcola`** - WebCola integration +2. **`Viz`** - Graphviz visualization +3. **`graphlibDot`** - DOT file parsing +4. **`'_'` (lodash)** - Utility functions +5. **`lysenkoIntervalTree`** - Interval tree operations +6. **`metagraph`** - Graph operations +7. **`computeLayout`** - CSS layout computations +8. **`dc_graph`** - The library itself (special case) + +## Migration Strategy + +### Phase 1: Analysis and Research + +For each dependency, we need to: + +1. **Identify all usage locations** using grep +2. **Determine the source** (npm package, local file, CDN) +3. **Check ES module support** in the dependency +4. **Map global methods to specific imports** +5. **Identify import patterns** (default vs named imports) + +### Phase 2: Individual Dependency Plans + +#### 1. `Viz` (Graphviz) +- **Current usage**: Global `Viz` object +- **Files to check**: `src/*graphviz*.js`, `web/js/*viz*` +- **Target**: `import { render } from '@viz-js/viz'` or similar +- **Notes**: May need to update from viz.js v2 to @viz-js/viz v3 + +#### 2. `graphlibDot` (DOT parser) +- **Current usage**: Global `graphlibDot` object +- **Files to check**: Files that parse .dot/.gv files +- **Target**: `import { parse, write } from 'graphlib-dot'` +- **Notes**: Check if this supports ES modules + +#### 3. `'_'` (lodash) +- **Current usage**: Global `_` object +- **Files to check**: All source files using `_.methodName` +- **Target**: Specific imports like `import { map, filter, forEach } from 'lodash'` +- **Priority**: High - lodash has excellent ES module support + +#### 4. `setcola` (WebCola) +- **Current usage**: Global `setcola` function +- **Files to check**: `src/cola_layout.js`, `src/annotate_layers.js` +- **Target**: `import { d3adaptor } from 'webcola'` +- **Notes**: WebCola may expose this differently in ES modules + +#### 5. `lysenkoIntervalTree` (Interval Tree) +- **Current usage**: Global `lysenkoIntervalTree` object +- **Files to check**: `src/path_reader.js` +- **Target**: `import IntervalTree from 'interval-tree-1d'` +- **Notes**: Check if the rollup config we removed was actually needed + +#### 6. `metagraph` (Graph operations) +- **Current usage**: Global `metagraph` object +- **Files to check**: `src/diagram.js`, `src/supergraph.js`, etc. +- **Target**: May be a local module - `import metagraph from './metagraph.js'` +- **Notes**: This might be defined locally in the codebase + +#### 7. `computeLayout` (CSS Layout) +- **Current usage**: Global `computeLayout` function +- **Files to check**: `src/flexbox_layout.js` +- **Target**: `import { computeLayout } from 'yoga-layout'` or similar +- **Notes**: This is likely from the yoga-layout library + +#### 8. `dc_graph` (Self-reference) +- **Current usage**: Global `dc_graph` object +- **Files to check**: Throughout the codebase +- **Target**: Internal imports from the module system +- **Notes**: Special case - this is the library referencing itself + +### Phase 3: Migration Execution Plan + +#### Step 1: Research Phase +```bash +# For each dependency, run analysis: +grep -r "dependencyName" src/ web/ --include="*.js" +npm info packageName +# Check package.json for current versions +# Check if package supports ES modules +``` + +#### Step 2: Create Migration Scripts +Create helper scripts to: +- Find all usage patterns for each global +- Generate replacement import statements +- Validate that imports work correctly + +#### Step 3: Migration Order (by complexity) + +1. **`'_'` (lodash)** - Start here, well-documented ES module support +2. **`lysenkoIntervalTree`** - Single usage location, straightforward +3. **`computeLayout`** - Single usage location +4. **`graphlibDot`** - Limited usage, specific functionality +5. **`Viz`** - May require version upgrade +6. **`setcola`** - Complex integration with WebCola +7. **`metagraph`** - Need to determine if it's local or external +8. **`dc_graph`** - Most complex, self-referential + +#### Step 4: Testing Strategy + +##### Automated Testing +- Create test files for each migration +- Ensure web workers still function (they may need different import strategies) +- Verify build process still works +- Run eslint to ensure no new errors + +##### Manual Testing Plan (User Validation) + +For each dependency migration, I will: + +1. **Complete the migration** for one dependency at a time +2. **Run the build process** (`npm run build`) to ensure no build errors +3. **Ask you to test** specific functionality using this protocol: + +**Testing Protocol:** +``` +Please test the [DEPENDENCY_NAME] migration: + +Test Files: +- [ ] web/example1.html - Test basic functionality +- [ ] web/example2.html - Test advanced features +- [ ] web/workerExample.html - Test web worker integration (if applicable) + +Specific Tests: +- [ ] Action 1: Description of what to test +- [ ] Action 2: Description of what to test +- [ ] Action 3: Description of what to test + +Expected Behavior: +- Feature X should work as before +- No console errors should appear +- Performance should be similar + +Please report: +✅ PASS: Everything works as expected +❌ FAIL: [Describe what's broken, include console errors, screenshots if helpful] +⚠️ PARTIAL: [Describe what works vs what doesn't] +``` + +4. **Wait for your feedback** before proceeding to the next dependency +5. **Fix any issues** you report before moving on +6. **Document any workarounds** needed + +##### Testing Schedule by Dependency + +**1. Lodash (`'_'`) Migration Test** +- Test files: All examples that use utility functions +- Focus: Array/object manipulation, data processing +- Key examples: `brushing-filtering.html`, `network-building.html` + +**2. Interval Tree (`lysenkoIntervalTree`) Migration Test** +- Test files: Examples using path operations +- Focus: Path finding, graph traversal +- Key examples: Any with path highlighting + +**3. CSS Layout (`computeLayout`) Migration Test** +- Test files: `flexbox.html` and related examples +- Focus: Node positioning, layout algorithms +- Key examples: Flexbox layout examples + +**4. GraphLib DOT (`graphlibDot`) Migration Test** +- Test files: Examples loading `.gv` or `.dot` files +- Focus: File parsing, graph loading +- Key examples: Any example loading graphviz files + +**5. Viz.js (`Viz`) Migration Test** +- Test files: Examples using Graphviz layout +- Focus: Graphviz rendering, DOT processing +- Key examples: Any with graphviz layout engine + +**6. WebCola (`setcola`) Migration Test** +- Test files: Examples using cola layout engine +- Focus: Force-directed layout, constraints +- Key examples: `compare-layouts.html`, `network-building.html` + +**7. Metagraph (`metagraph`) Migration Test** +- Test files: Examples with graph operations +- Focus: Graph manipulation, supergraph features +- Key examples: Complex graph examples + +**8. DC Graph Self-Reference (`dc_graph`) Migration Test** +- Test files: All examples (comprehensive test) +- Focus: Core library functionality +- Key examples: Every HTML file in web/ + +##### Error Reporting Template + +When you find issues, please use this format: + +``` +Migration: [DEPENDENCY_NAME] +Test File: [FILENAME] +Status: ❌ FAIL + +Error Details: +- Console Error: [Copy exact error message] +- Expected: [What should happen] +- Actual: [What actually happened] +- Browser: [Chrome/Firefox/Safari version] +- Steps to Reproduce: + 1. Step one + 2. Step two + 3. Step three + +Additional Notes: [Any other observations] +``` + +##### Rollback Protocol + +If you report critical failures: +1. I will immediately investigate the specific error +2. If it can't be fixed quickly (within 1 hour), I will: + - Rollback the migration for that dependency + - Keep the global in eslint config + - Document the issue for future investigation + - Move to the next dependency + +##### Success Criteria for Each Migration + +Before asking you to test, each migration must: +- [ ] Build without errors (`npm run build`) +- [ ] Pass eslint without new errors (`npm run lint`) +- [ ] Load in browser without immediate console errors +- [ ] Show basic functionality working + +Only then will I request your testing. + +### Phase 4: Benefits + +#### Immediate Benefits +- **Better tree shaking** - Only import what's used +- **Clearer dependencies** - Explicit imports vs globals +- **Better IDE support** - IntelliSense and type checking +- **Smaller bundles** - Dead code elimination + +#### Long-term Benefits +- **Easier maintenance** - Clear dependency graph +- **Better security** - No global namespace pollution +- **Modern tooling** - Works better with bundlers +- **Future-proof** - ES modules are the standard + +### Phase 5: Implementation Notes + +#### Import Style Guidelines +- Use **specific named imports** wherever possible +- Avoid `import *` unless necessary +- Group imports logically (external deps, local modules) +- Use consistent import aliases + +#### Example Transformations +```javascript +// Before (global) +const result = _.map(data, item => item.value); +Viz.render(dotString); + +// After (ES modules) +import { map } from 'lodash'; +import { render } from '@viz-js/viz'; + +const result = map(data, item => item.value); +render(dotString); +``` + +### Phase 6: Rollback Plan +- Keep globals list in eslint config but commented out +- Test each migration in isolation +- Have rollback commits ready +- Document any compatibility issues found + +## Success Criteria +- [ ] All targeted globals removed from eslint.config.js +- [ ] All imports use specific named imports +- [ ] Build process works without errors +- [ ] All examples continue to function +- [ ] Web workers continue to function +- [ ] Bundle size is same or smaller +- [ ] No runtime errors in production + +## Timeline Estimate +- **Research Phase**: 2-3 days +- **Migration Scripts**: 1 day +- **Individual Migrations**: 1-2 days each (8 total = 8-16 days) +- **Testing & Validation**: 2-3 days +- **Total**: ~2-3 weeks + +## Risk Mitigation +- Start with low-risk dependencies (lodash) +- Test each migration thoroughly before proceeding +- Keep detailed logs of changes +- Have working branch for rollback +- Document any breaking changes found \ No newline at end of file diff --git a/plan.txt b/plans/roadmap-2016.txt similarity index 100% rename from plan.txt rename to plans/roadmap-2016.txt diff --git a/plans/web-worker-es6-upgrade.md b/plans/web-worker-es6-upgrade.md new file mode 100644 index 00000000..b31329a0 --- /dev/null +++ b/plans/web-worker-es6-upgrade.md @@ -0,0 +1,134 @@ +# Web Worker ES6 Module Upgrade + +## Overview +This document outlines the plan to modernize the web worker implementation in dc.graph.js to use native ES6 modules instead of the current file concatenation approach. + +## Current State +- Workers are built using Rollup with ES6 modules as input (src/workers/*.js) +- Each layout has a corresponding worker file built to root directory (e.g., `dc.graph.cola.worker.js`) +- Workers use importScripts() to load dependencies (d3.js, cola.js, etc.) in banner +- Build process defined in `worker.rollup.config.js` +- Worker files use IIFE format, not true ES6 modules yet +- ✅ **Fixed**: Workers now integrated with rollup copy plugin +- ✅ **Fixed**: Workers now build automatically with `npm run build` and `npm run dev` + +## Target State +- Workers use native ES6 modules with `{ type: 'module' }` +- Direct imports from modular source files +- Eliminate concatenation-based builds +- Cleaner dependency management + +## Browser Support +As of 2024, all modern browsers support module workers: +- Chrome: Since v80 (Feb 2020) +- Safari: Since v15 +- Firefox: Since July 2024 + +## Implementation Plan + +### Phase 1: ✅ Update Build Process (COMPLETED) +- ✅ **Step 1.1**: Integrate workers with rollup copy plugin +- ✅ **Step 1.2**: Integrate with main build commands +- ✅ Workers now build automatically with `npm run build` and `npm run dev` + +### Phase 2: ✅ Convert Worker Creation (COMPLETED) +- ✅ Updated webworker_layout.js to use `{ type: 'module' }` +- ✅ Workers now load as ES6 modules + +### Phase 3: ✅ Cola Worker ES6 Conversion (COMPLETED) +- ✅ **Step 3.1**: Convert cola worker to ES6 modules + - Uses CDN imports for d3-dispatch, d3-selection, webcola + - Sets up global scope compatibility for WebCola +- ✅ **Step 3.2**: Resolve d3-dispatch import conflicts + - **Solution**: Rollup-plugin-replace to transform dispatch usage at build time + - Comments out ES6 import: `import { dispatch } from 'd3-dispatch';` + - Replaces usage with: `globalThis.d3.dispatch` +- ✅ **Step 3.3**: Fix d3-timer and initialization order issues + - Added d3-timer import to banner for cola.d3adaptor().timer() functionality + - Moved global assignments to banner to ensure proper initialization order + - Fixed "Cannot read properties of undefined (reading 'd3adaptor')" error +- ✅ **Step 3.4**: Fix D3 v5 dispatch API in webworker_layout.js + - **Problem**: webworker_layout.js was using D3 v3 style dispatch calls + - **Solution**: Updated to use `dispatch.call(event, null, ...args)` instead of `dispatch[event]()` + - Fixed "Worker dispatch error - missing handler" errors +- ✅ **Step 3.5**: Fix cola_layout.js dispatch creation + - **Problem**: cola_layout.js was using imported dispatch in worker context + - **Solution**: Use `(globalThis.d3?.dispatch || dispatch)` to fallback to global in worker +- ✅ **Step 3.6**: Test cola worker functionality + - Worker loads successfully without errors + - Compatible with random.html and other examples + +### Phase 4: ✅ Dagre Worker ES6 Conversion (COMPLETED) +- ✅ **Step 4.1**: Convert dagre worker to ES6 modules + - Uses CDN imports for d3-dispatch and @dagrejs/dagre + - Upgraded to modern @dagrejs/dagre package (v1.1.5) instead of legacy dagre + - Sets up minimal global scope for d3.dispatch compatibility +- ✅ **Step 4.2**: Resolve import map conflicts + - **Solution**: Rollup-plugin-replace to transform @dagrejs/dagre import to CDN URL (same architecture as cola worker) + - Source uses clean ES6 import: `import * as dagre from '@dagrejs/dagre';` + - Worker build transforms to: `https://cdn.jsdelivr.net/npm/@dagrejs/dagre@1.1.5/+esm` +- ✅ **Step 4.3**: Test dagre worker functionality + - Worker loads successfully with modern package + - Same clean rollup-replace architecture as cola worker + - Compatible with all existing functionality + +### Phase 5: ✅ D3v4-Force Worker ES6 Conversion (COMPLETED) +- ✅ **Step 5.1**: Convert d3v4-force worker to ES6 modules + - Uses CDN imports for d3-dispatch, d3-collection, d3-force, d3-force-straighten-paths + - Replaced all `d3v4.*` references with direct ES6 imports + - Clean implementation without global scope pollution +- ✅ **Step 5.2**: Test d3v4-force worker functionality + - Worker loads successfully without errors + - Compatible with all force layout examples + +### Phase 6: Convert Remaining Workers (NEXT) +- ⏸️ **PENDING**: Convert dynagraph worker + +### Phase 7: Final Testing (BLOCKED - requires Phase 6 completion) +- Test all workers with various example files +- Ensure performance is maintained + +## Files to Modify +- All `*.worker.js` files +- Worker creation code in main library +- `worker.rollup.config.js` (remove) +- `package.json` build scripts + +## Prerequisites +- ✅ Complete D3 v5 / dc.js v4 upgrade first +- ✅ Ensure main library is stable with new dependencies +- ✅ All examples working with current worker approach +- Test current worker functionality before upgrade + +## Key Learnings + +### Technical Solutions Discovered + +1. **Rollup-Plugin-Replace Pattern**: The most elegant solution for web worker ES6 conversion + - Clean source code with standard ES6 imports + - Build-time transformation to CDN URLs for worker context + - No runtime complexity or global variable pollution + - Works perfectly for both cola and dagre workers + +2. **Package Modernization**: Checking for modern ES6-native packages pays off + - @dagrejs/dagre (v1.1.5) is superior to legacy dagre package + - Native ES6 modules eliminate fetch/eval workarounds + - Modern packages often have better browser compatibility + +3. **Global Scope Setup**: Minimal global scope setup for legacy library compatibility + - Only expose what's absolutely necessary (e.g., `globalThis.d3.dispatch`) + - Prefer build-time solutions over runtime global assignments + +### Architecture Patterns + +- **Best Practice**: Use rollup-plugin-replace for build-time import transformation +- **Fallback**: Use fetch/eval for UMD packages that don't work with ES6 imports +- **Upgrade Path**: Always check for modern package versions before implementing workarounds + +## Benefits +- Cleaner, more maintainable code +- Better development experience +- Explicit dependency management +- Smaller, more efficient bundles +- Elimination of complex concatenation builds +- Consistent architecture across all workers \ No newline at end of file diff --git a/plans/webworker-function-serialization-issue.md b/plans/webworker-function-serialization-issue.md new file mode 100644 index 00000000..0ef7fd3b --- /dev/null +++ b/plans/webworker-function-serialization-issue.md @@ -0,0 +1,162 @@ +# Web Worker Function Serialization Issue Report + +## Current Status: BLOCKED + +**Issue**: DataCloneError when sending options with functions to web workers +**Error**: `Failed to execute 'postMessage' on 'Worker': function could not be cloned` +**Specific Function**: `flowLayout.minSeparation` function from drag-drop-composition.js + +## Problem Analysis + +### Root Cause +Web workers cannot receive function objects via `postMessage()` - only serializable data (JSON-like objects). The `flowLayout` configuration contains a `minSeparation` function: + +```javascript +engine.flowLayout({ + axis: options.rankdir === 'TB' ? 'y' : 'x', + minSeparation: function(e) { + return (e.source.width + e.target.width) / 2 + engine.ranksep(); + } +}) +``` + +### Relationship to Async Changes +**My Assessment: This is NOT directly related to the async init/dynagraph changes.** + +**Why this manifested now:** +1. **Previously**: The old synchronous worker init may have failed silently or handled this differently +2. **Now**: The new async Promise-based init properly surfaces the postMessage error +3. **The async changes exposed an existing bug** - the function serialization issue was always there but wasn't being caught/reported properly + +**Evidence:** +- The error occurs in `webworker_layout.js:init()` when sending options to worker +- This is a data serialization issue, not an async timing issue +- The function objects were always problematic for workers - async changes just made the error visible + +## Attempted Solutions + +### 1. Added `serializeOptions()` function to filter functions +```javascript +function serializeOptions(obj) { + if (typeof obj === 'function') { + console.warn('[WORKER] Filtering out function...'); + return null; + } + // ... recursive serialization +} +``` + +### 2. Applied serialization at multiple points: +- Individual option collection: `options[option] = serializeOptions(layoutEngine[option]())` +- Final options object: `options: serializeOptions(options)` + +### 3. Added debug logging to track function filtering +- No warning logs appear, suggesting functions aren't being caught by serialization + +## Current Issue +**The serialization is not working because:** + +1. **Cache Issue**: Browser may be using cached JavaScript files despite rebuilds +2. **Timing Issue**: Functions may be added to options after serialization +3. **Path Issue**: Functions may be coming through a different code path not covered by serialization +4. **Proxy Issue**: Webworker layout proxy may be interfering with serialization + +## Next Steps Needed + +### Immediate Debugging: +1. **Force cache clear**: Hard refresh, check file timestamps +2. **Add more debugging**: Log the actual options object being sent +3. **Check all postMessage calls**: There are 4 postMessage calls in webworker_layout.js + +### Alternative Solutions: +1. **Exclude flowLayout from worker options**: Remove 'flowLayout' from cola layout's `optionNames()` +2. **Convert functions to string/config**: Replace function with serializable configuration +3. **Handle flowLayout client-side only**: Don't send flowLayout to workers at all + +### Long-term Architecture: +1. **Worker-safe options**: Define which options can/cannot be sent to workers +2. **Function alternative patterns**: Use configuration objects instead of functions for worker-compatible layouts + +## Files Modified +- `src/webworker_layout.js`: Added function serialization logic +- `src/cola_layout.js`: Added missing iteration methods to optionNames +- Multiple example files: Updated render() calls to use await + +## Analysis: This is Likely an Old Design Flaw + +**Key Insight**: The `minSeparation` function was probably **never intended to be serialized**. Looking at the function: + +```javascript +minSeparation: function(e) { + return (e.source.width + e.target.width) / 2 + engine.ranksep(); +} +``` + +This calculates: `(average of node dimensions) + rank separation` + +**This is a standard layout calculation that can be reconstructed on the worker side.** + +## Proposed Solution: Configuration-Based Function Reconstruction + +Instead of trying to serialize functions, convert them to worker-reconstructible configurations: + +### Current (Problematic): +```javascript +flowLayout: { + axis: 'x', + minSeparation: function(e) { + return (e.source.width + e.target.width) / 2 + engine.ranksep(); + } +} +``` + +### Proposed (Worker-Safe): +```javascript +flowLayout: { + axis: 'x', + minSeparation: { + type: 'node-dimension-based', + dimension: 'width', // or 'height' for TB + factor: 0.5, // average (1/2) + addRanksep: true + } +} +``` + +### Implementation Strategy: + +1. **Detect function patterns** in webworker_layout.js +2. **Convert known function types** to configuration objects +3. **Reconstruct functions** in worker based on configuration +4. **Maintain backward compatibility** for non-worker usage + +### Worker-Side Function Factory: +```javascript +function createMinSeparationFunction(config) { + return function(e) { + const dimension = config.dimension; // 'width' or 'height' + const sourceDim = e.source[dimension]; + const targetDim = e.target[dimension]; + let result = (sourceDim + targetDim) * config.factor; + if (config.addRanksep) { + result += ranksep; // worker has access to this + } + return result; + }; +} +``` + +This approach: +- ✅ Fixes the serialization issue +- ✅ Maintains functionality +- ✅ Is backward compatible +- ✅ Follows standard worker patterns +- ✅ Supports future function types + +## Current State +- **ES6 worker conversion**: ✅ Complete +- **Async architecture**: ✅ Complete +- **Function serialization**: 🔧 Solution identified +- **Examples working**: ❌ drag-drop-composition.html fails with DataCloneError + +The project is 95% complete. The remaining issue is architectural - converting function-based APIs to worker-compatible configuration-based APIs. \ No newline at end of file diff --git a/querystring.js b/querystring.js index 44500a02..5d342372 100644 --- a/querystring.js +++ b/querystring.js @@ -4,51 +4,52 @@ License: Apache v2 */ -var querystring = (function() { - var listsep_ = '|'; - return { - listsep: function(s) { - if(!arguments.length) - return listsep_; - listsep_ = s; - return this; - }, - parse: function(opts) { - opts = opts || {}; - return (function(a) { - if (a == "") return {}; - var b = {}; - for (var i = 0; i < a.length; ++i) - { - var p=a[i].split('=', 2); - if (p.length == 1) - b[p[0]] = opts.boolean ? true : ""; - else - b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " ")); - } - return b; - })(window.location.search.substr(1).split('&')); - }, - generate: function(m, encode) { - if(encode===undefined) encode = true; - var parts = []; - for(var k in m) - parts.push(k + '=' + (encode ? encodeURIComponent(m[k]) : m[k])); - return parts.length ? parts.join('&') : ''; - }, - get_url: function(m, encode) { - var url = window.location.protocol + '//' + window.location.host + window.location.pathname; - var params = this.generate(m, encode); - if(params) - url += '?' + params; - return url; - }, - update: function(m, encode) { - window.history.pushState(null, null, this.get_url(m, encode)); - return this; - }, - option_tracker: function() { - throw new Error('use independent url_options library'); - } - }; -})(); +var listsep_ = '|'; + +const querystring = { + listsep: function(s) { + if (!arguments.length) + return listsep_; + listsep_ = s; + return this; + }, + parse: function(opts) { + opts = opts || {}; + return (function(a) { + if (a == '') return {}; + var b = {}; + for (var i = 0; i < a.length; ++i) + { + var p = a[i].split('=', 2); + if (p.length == 1) + b[p[0]] = opts.boolean ? true : ''; + else + b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, ' ')); + } + return b; + })(window.location.search.substr(1).split('&')); + }, + generate: function(m, encode) { + if (encode === undefined) encode = true; + var parts = []; + for (var k in m) + parts.push(k+'='+(encode ? encodeURIComponent(m[k]) : m[k])); + return parts.length ? parts.join('&') : ''; + }, + get_url: function(m, encode) { + var url = window.location.protocol+'//'+window.location.host+window.location.pathname; + var params = this.generate(m, encode); + if (params) + url += '?'+params; + return url; + }, + update: function(m, encode) { + window.history.pushState(null, null, this.get_url(m, encode)); + return this; + }, + option_tracker: function() { + throw new Error('use independent url_options library'); + }, +}; + +export default querystring; diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 00000000..0d17353e --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,39 @@ +import commonjs from '@rollup/plugin-commonjs'; +import json from '@rollup/plugin-json'; +import resolve from '@rollup/plugin-node-resolve'; +import copy from 'rollup-plugin-copy'; + +export default { + input: 'src/index.js', + output: { + file: 'dist/dc-graph.js', + format: 'es', + sourcemap: true, + }, + external: [ + 'd3', + 'dc', + 'crossfilter2', + 'webcola', + 'dagre', + 'viz.js', + 'css-layout', + 'metagraph', + 'queue-async', + 'tippy.js', + ], + plugins: [ + json(), + resolve({ + preferBuiltins: false, + }), + commonjs(), + copy({ + targets: [ + {src: 'dist/dc-graph.js', dest: 'web/js'}, + {src: 'dist/dc-graph.js.map', dest: 'web/js'}, + ], + hook: 'writeBundle', + }), + ], +}; diff --git a/scripts/check-import-map-consistency.js b/scripts/check-import-map-consistency.js new file mode 100755 index 00000000..7f68ed62 --- /dev/null +++ b/scripts/check-import-map-consistency.js @@ -0,0 +1,184 @@ +#!/usr/bin/env node + +/** + * Check import map consistency across all HTML files + * + * This script parses all HTML files in the web/ directory, extracts import maps, + * and reports any inconsistencies in package versions across files. + */ + +import fs from 'fs'; +import { glob } from 'glob'; +import path from 'path'; + +// Colors for console output +const colors = { + red: '\x1b[31m', + green: '\x1b[32m', + yellow: '\x1b[33m', + blue: '\x1b[34m', + magenta: '\x1b[35m', + cyan: '\x1b[36m', + reset: '\x1b[0m', + bold: '\x1b[1m', +}; + +function colorize(text, color) { + return colors[color]+text+colors.reset; +} + +function extractImportMap(htmlContent) { + const importMapRegex = /]*>([\s\S]*?)<\/script>/gi; + const match = importMapRegex.exec(htmlContent); + + if (!match) { + return null; + } + + try { + const importMapContent = match[1].trim(); + return JSON.parse(importMapContent); + } catch (error) { + return {error: `Failed to parse import map: ${error.message}`}; + } +} + +function extractVersionFromUrl(url) { + // Match patterns like @1.2.3, @1.2.3-alpha.1, @^1.2.3, @~1.2.3 + const versionMatch = url.match(/@([^/+]+)/); + return versionMatch ? versionMatch[1] : null; +} + +function extractPackageFromUrl(url) { + // Extract package name from jsdelivr URLs + const jsdelivrMatch = url.match(/jsdelivr\.net\/npm\/([^@/]+)/); + if (jsdelivrMatch) { + return jsdelivrMatch[1]; + } + + // Extract scoped package names like @dagrejs/dagre + const scopedMatch = url.match(/jsdelivr\.net\/npm\/(@[^/]+\/[^@/]+)/); + if (scopedMatch) { + return scopedMatch[1]; + } + + return null; +} + +async function checkImportMapConsistency() { + console.log(colorize('🔍 Checking import map consistency across HTML files...', 'cyan')); + console.log(); + + // Find all HTML files in web directory + const htmlFiles = await glob('web/*.html', {cwd: path.resolve('.')}); + + if (htmlFiles.length === 0) { + console.log(colorize('❌ No HTML files found in web/ directory', 'red')); + return; + } + + const allImportMaps = new Map(); // filename -> import map + const packageVersions = new Map(); // package name -> Map(version -> [files]) + + // Extract import maps from all files + for (const htmlFile of htmlFiles) { + const fullPath = path.resolve(htmlFile); + const content = fs.readFileSync(fullPath, 'utf8'); + const importMap = extractImportMap(content); + + if (importMap) { + if (importMap.error) { + console.log(colorize(`❌ ${path.basename(htmlFile)}: ${importMap.error}`, 'red')); + continue; + } + + allImportMaps.set(htmlFile, importMap); + + // Process imports + if (importMap.imports) { + for (const [importName, url] of Object.entries(importMap.imports)) { + const packageName = extractPackageFromUrl(url); + const version = extractVersionFromUrl(url); + + if (packageName && version) { + if (!packageVersions.has(packageName)) { + packageVersions.set(packageName, new Map()); + } + + const versionMap = packageVersions.get(packageName); + if (!versionMap.has(version)) { + versionMap.set(version, []); + } + + versionMap.get(version).push({ + file: path.basename(htmlFile), + importName, + url, + }); + } + } + } + } + } + + console.log(colorize(`📊 Found ${allImportMaps.size} files with import maps`, 'blue')); + console.log(); + + // Check for version inconsistencies + let hasInconsistencies = false; + + for (const [packageName, versionMap] of packageVersions.entries()) { + if (versionMap.size > 1) { + hasInconsistencies = true; + console.log(colorize(`⚠️ Version inconsistency for ${packageName}:`, 'yellow')); + + for (const [version, usages] of versionMap.entries()) { + console.log(` ${colorize(version, 'magenta')} used in:`); + for (const usage of usages) { + console.log(` - ${colorize(usage.file, 'cyan')} (${usage.importName})`); + } + } + console.log(); + } + } + + if (!hasInconsistencies) { + console.log( + colorize('✅ All package versions are consistent across import maps!', 'green'), + ); + } + + // Summary statistics + console.log(colorize('📈 Summary:', 'bold')); + console.log(` Files with import maps: ${allImportMaps.size}`); + console.log(` Unique packages: ${packageVersions.size}`); + console.log( + ` Packages with version conflicts: ${ + Array.from(packageVersions.values()).filter(vm => vm.size > 1).length + }`, + ); + + // List all packages and their versions for reference + if (packageVersions.size > 0) { + console.log(); + console.log(colorize('📦 All packages and versions:', 'bold')); + + const sortedPackages = Array.from(packageVersions.entries()).sort(([a], [b]) => + a.localeCompare(b) + ); + + for (const [packageName, versionMap] of sortedPackages) { + const versions = Array.from(versionMap.keys()).sort(); + const versionColor = versionMap.size > 1 ? 'yellow' : 'green'; + console.log(` ${packageName}: ${colorize(versions.join(', '), versionColor)}`); + } + } + + process.exit(hasInconsistencies ? 1 : 0); +} + +// Run the check +checkImportMapConsistency().catch(error => { + console.error(colorize(`❌ Error: ${error.message}`, 'red')); + process.exit(1); +}); diff --git a/server.py b/server.py new file mode 100644 index 00000000..6db82abe --- /dev/null +++ b/server.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +""" +Simple HTTP server with WASM MIME type support +""" +import http.server +import socketserver +import mimetypes +import sys +import os + +# Add WASM MIME type +mimetypes.add_type('application/wasm', '.wasm') + +class WASMHTTPRequestHandler(http.server.SimpleHTTPRequestHandler): + def end_headers(self): + # Add CORS headers for local development + self.send_header('Cross-Origin-Embedder-Policy', 'require-corp') + self.send_header('Cross-Origin-Opener-Policy', 'same-origin') + super().end_headers() + +def main(): + port = int(sys.argv[1]) if len(sys.argv) > 1 else 8888 + + # Change to web directory to serve it as root + if os.path.exists('web'): + os.chdir('web') + print("Serving web/ directory as root") + else: + print("Warning: web/ directory not found, serving current directory") + + with socketserver.TCPServer(("", port), WASMHTTPRequestHandler) as httpd: + print(f"Serving at http://localhost:{port}") + print("WASM MIME type support enabled") + httpd.serve_forever() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/src/annotate_layers.js b/src/annotate_layers.js index 155bb545..00f1a81e 100644 --- a/src/annotate_layers.js +++ b/src/annotate_layers.js @@ -1,101 +1,109 @@ -dc_graph.annotate_layers = function() { +import { property } from './core.js'; +import { mode } from './mode.js'; + +export function annotateLayers() { // svg-specific - var _drawLayer; + let _drawLayer; // wegl-specific - var _planes = []; - var _planeGeometry; - var _mode = dc_graph.mode('annotate-layers', { + let _planes = []; + let _planeGeometry; + const _mode = mode('annotate-layers', { laterDraw: true, renderers: ['svg', 'webgl'], - draw: draw, - remove: remove + draw, + remove, }); - function draw(diagram) { - var rendererType = _mode.parent().renderer().rendererType(); - var engine = _mode.parent().layoutEngine(); - if(rendererType === 'svg') { - if(engine.layoutAlgorithm() === 'cola' && - engine.setcolaSpec() && engine.setcolaNodes()) { + function draw(_diagram) { + const rendererType = _mode.parent().renderer().rendererType(); + const engine = _mode.parent().layoutEngine(); + if (rendererType === 'svg') { + if ( + engine.layoutAlgorithm() === 'cola' + && engine.setcolaSpec() && engine.setcolaNodes() + ) { _drawLayer = _mode.parent().select('g.draw').selectAll('g.divider-layer').data([0]); _drawLayer.enter().append('g').attr('class', 'divider-layer'); - var boundary_nodes = engine.setcolaNodes().filter(function(n) { - return /^sort_order_boundary/.test(n.name); - }); - var lines = _drawLayer.selectAll('line.divider').data(boundary_nodes); + const boundary_nodes = engine.setcolaNodes().filter(n => + /^sort_order_boundary/.test(n.name) + ); + const lines = _drawLayer.selectAll('line.divider').data(boundary_nodes); lines.exit().remove(); lines.enter().append('line') .attr('class', 'divider'); - lines.attr({ - stroke: _mode.stroke(), - 'stroke-width': _mode.strokeWidth(), - 'stroke-dasharray': _mode.strokeDashArray(), - x1: -5000, - y1: function(n) { - return n.y; - }, - x2: 5000, - y2: function(n) { - return n.y; - } - }); + lines.attr('stroke', _mode.stroke()) + .attr('stroke-width', _mode.strokeWidth()) + .attr('stroke-dasharray', _mode.strokeDashArray()) + .attr('x1', -5000) + .attr('y1', n => n.y) + .attr('x2', 5000) + .attr('y2', n => n.y); } - } else if(rendererType === 'webgl') { - var MULT = _mode.parent().renderer().multiplier(); - var scene = arguments[1], drawState = arguments[2]; - if(engine.layoutAlgorithm() === 'layered' && engine.layers()) { - var width = drawState.extents[0][1] - drawState.extents[0][0] + _mode.planePadding()*MULT*2, - height = drawState.extents[1][1] - drawState.extents[1][0] + _mode.planePadding()*MULT*2; - var delGeom; - var shape = new THREE.Shape(); + } else if (rendererType === 'webgl') { + const MULT = _mode.parent().renderer().multiplier(); + const scene = arguments[1], drawState = arguments[2]; + if (engine.layoutAlgorithm() === 'layered' && engine.layers()) { + const width = + drawState.extents[0][1]-drawState.extents[0][0]+_mode.planePadding()*MULT*2, + height = + drawState.extents[1][1]-drawState.extents[1][0]+_mode.planePadding()*MULT*2; + let delGeom; + const shape = new THREE.Shape(); shape.moveTo(0, 0); shape.lineTo(0, height); shape.lineTo(width, height); shape.lineTo(width, 0); shape.lineTo(0, 0); - if(_planeGeometry) + if (_planeGeometry) delGeom = _planeGeometry; _planeGeometry = new THREE.ShapeBufferGeometry(shape); - var layers = engine.layers(); - if(layers.length < _planes.length) { - for(var i = layers.length; i < _planes.length; ++i) + const layers = engine.layers(); + if (layers.length < _planes.length) { + for (let i = layers.length; i < _planes.length; ++i) scene.remove(_planes[i].mesh); _planes = _planes.slice(0, layers.length); } - layers.forEach(function(layer, i) { - if(!_planes[i]) + layers.forEach((layer, i) => { + if (!_planes[i]) _planes[i] = Object.assign({}, layer); - if(_planes[i].mesh) + if (_planes[i].mesh) scene.remove(_planes[i].mesh); - var mesh = _planes[i].mesh = new THREE.Mesh(_planeGeometry, new THREE.MeshStandardMaterial({ - opacity: _mode.planeOpacity(), - transparent: true, - color: _mode.parent().renderer().color_to_int(_mode.planeColor()), - side: THREE.DoubleSide - })); - mesh.position.set(drawState.extents[0][0] - _mode.planePadding()*MULT, - drawState.extents[1][0] - _mode.planePadding()*MULT, - layer.z * MULT); + const mesh = _planes[i].mesh = new THREE.Mesh( + _planeGeometry, + new THREE.MeshStandardMaterial({ + opacity: _mode.planeOpacity(), + transparent: true, + color: _mode.parent().renderer().color_to_int(_mode.planeColor()), + side: THREE.DoubleSide, + }), + ); + mesh.position.set( + drawState.extents[0][0]-_mode.planePadding()*MULT, + drawState.extents[1][0]-_mode.planePadding()*MULT, + layer.z*MULT, + ); scene.add(mesh); }); - if(delGeom) + if (delGeom) delGeom.dispose(); } - } else throw new Error("annotate_layers doesn't know how to work with renderer " + rendererType); + } else throw new Error( + `annotate_layers doesn't know how to work with renderer ${rendererType}`, + ); } function remove() { - if(_drawLayer) + if (_drawLayer) _drawLayer.remove(); } // line properties for svg _mode.stroke = property('black'); _mode.strokeWidth = property(2); - _mode.strokeDashArray = property([5,5]); + _mode.strokeDashArray = property([5, 5]); // plane properties _mode.planePadding = property(5); _mode.planeOpacity = property(0.2); _mode.planeColor = property('#ffffdd'); return _mode; -}; +} diff --git a/src/annotate_nodes.js b/src/annotate_nodes.js index e0d80686..69122116 100644 --- a/src/annotate_nodes.js +++ b/src/annotate_nodes.js @@ -1,28 +1,30 @@ -dc_graph.annotate_nodes = () => { +import { mode } from './mode.js'; + +export const annotateNodes = () => { function draw(diagram) { const roots = diagram.g().selectAll('g.node-layer g.node'); - const annots = roots.selectAll('text.node-annotation').data(d => d.orig.value.ceq ? [d] : []); + const annots = roots.selectAll('text.node-annotation').data(d => + d.orig.value.ceq ? [d] : [] + ); annots.enter().append('text') - .attr({ - class: 'node-annotation', - fill: d => { - const nf = diagram.nodeFill.eval(d); - return diagram.nodeFillScale()(nf - ((nf%2) ? 0 : 1)); - }, - 'font-weight': 750, - 'font-size': '50px', - 'alignment-baseline': 'central', - dx: d => Math.round(d.dcg_rx + 10) + 'px' - }); + .attr('class', 'node-annotation') + .attr('fill', d => { + const nf = diagram.nodeFill.eval(d); + return diagram.nodeFillScale()(nf-((nf%2) ? 0 : 1)); + }) + .attr('font-weight', 750) + .attr('font-size', '50px') + .attr('alignment-baseline', 'central') + .attr('dx', d => `${Math.round(d.dcg_rx+10)}px`); annots.exit().remove(); annots .text(d => d.orig.value.ceq); } function remove() {} - const _mode = dc_graph.mode('annotate-nodes', { + const _mode = mode('annotate-nodes', { draw, remove, - laterDraw: true + laterDraw: true, }); return _mode; }; diff --git a/src/arrows.js b/src/arrows.js index d90a8252..cb649607 100644 --- a/src/arrows.js +++ b/src/arrows.js @@ -1,546 +1,536 @@ -function offsetx(ofsx) { - return function(p) { - return {x: p.x + ofsx, y: p.y}; - }; -} +import { angleBetweenPoints, asBezier3, chopBezier } from './shape.js'; +import { generatePath } from './utils.js'; -dc_graph.builtin_arrows = { - box: function(open, side) { - if(!open) return { - frontRef: [8,0], - drawFunction: function(marker, ofs, stemWidth) { - marker.append('rect') - .attr({ - x: ofs[0], - y: side==='right' ? -stemWidth/2 : -4, - width: 8, - height: side ? 4+stemWidth/2 : 8, - 'stroke-width': 0 - }); - } - }; +const offsetx = ofsx => p => ({x: p.x+ofsx, y: p.y}); + +export const builtinArrows = { + box: (open, side) => { + if (!open) + return { + frontRef: [8, 0], + drawFunction: (marker, ofs, stemWidth) => { + marker.append('rect') + .attr('x', ofs[0]) + .attr('y', side === 'right' ? -stemWidth/2 : -4) + .attr('width', 8) + .attr('height', side ? 4+stemWidth/2 : 8) + .attr('stroke-width', 0); + }, + }; else return { - frontRef: [8,0], - drawFunction: function(marker, ofs, stemWidth) { - marker.append('rect') - .attr({ - x: ofs[0] + 0.5, - y: side==='right' ? 0 : -3.5, - width: 7, - height: side ? 3.5 : 7, - 'stroke-width': 1, - fill: 'none' - }); - if(side) - marker.append('svg:path') - .attr({ - d: ['M', ofs[0], 0, 'h',8].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - }; + frontRef: [8, 0], + drawFunction: (marker, ofs, stemWidth) => { + marker.append('rect') + .attr('x', ofs[0]+0.5) + .attr('y', side === 'right' ? 0 : -3.5) + .attr('width', 7) + .attr('height', side ? 3.5 : 7) + .attr('stroke-width', 1) + .attr('fill', 'none'); + if (side) + marker.append('svg:path') + .attr('d', ['M', ofs[0], 0, 'h', 8].join(' ')) + .attr('stroke-width', stemWidth) + .attr('fill', 'none'); + }, + }; }, - curve: function(open, side) { - return { - stems: [true,false], - kernstems: [0, 0.25], - frontRef: [8,0], - drawFunction: function(marker, ofs, stemWidth) { - var instrs = []; - instrs.push('M', (side==='left' ? 7.5 : 4) + ofs[0], side==='left' ? stemWidth/2 : 3.5); - if(side==='left') - instrs.push('v', -stemWidth/2); - instrs.push('A', 3.5, 3.5, 0, 0, 0, - (side==='right' ? 7.5 : 4) + ofs[0], side==='right' ? 0 : -3.5); - if(side==='right') - instrs.push('v', -stemWidth/2); - marker.append('svg:path') - .attr({ - d: instrs.join(' '), - 'stroke-width': 1, - fill: 'none' - }); - marker.append('svg:path') - .attr({ - d: ['M', 7 + ofs[0], 0, - 'h -7'].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - }; - }, - icurve: function(open, side) { - return { - stems: [false,true], - kernstems: [0.25,0], - frontRef: [8,0], - drawFunction: function(marker, ofs, stemWidth) { - var instrs = []; - instrs.push('M', (side==='left' ? 0.5 : 4) + ofs[0], side==='left' ? stemWidth/2 : 3.5); - if(side==='left') - instrs.push('v', -stemWidth/2); - instrs.push('A', 3.5, 3.5, 0, 0, 1, - (side==='right' ? 0.5 : 4) + ofs[0], side==='right' ? 0 : -3.5); - if(side==='right') - instrs.push('v', -stemWidth/2); - marker.append('svg:path') - .attr({ - d: instrs.join(' '), - 'stroke-width': 1, - fill: 'none' - }); - marker.append('svg:path') - .attr({ - d: ['M', 1 + ofs[0], 0, - 'h 7'].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - }; - }, - diamond: function(open, side) { - if(!open) return { - frontRef: [side ? 11.25 : 12, 0], - backRef: [side ? 0.75 : 0, 0], - viewBox: [0, -4, 12, 8], - stems: [!!side, !!side], - kernstems: function(stemWidth) { - return [side ? 0 : .75*stemWidth, side ? 0 : .75*stemWidth]; - }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = [{x: 0, y: 0}]; - if(side !== 'left') - upoints.push({x: 6, y: 4}); - else - upoints.push({x: 6, y: -4}); - upoints.push({x: 12, y: 0}); - if(!side) - upoints.push({x: 6, y: -4}); - var points = upoints.map(offsetx(ofs[0])); - marker.append('svg:path') - .attr({ - d: generate_path(points, 1, true), - 'stroke-width': 0 - }); - if(side) { + curve: (open, side) => ({ + stems: [true, false], + kernstems: [0, 0.25], + frontRef: [8, 0], + drawFunction: (marker, ofs, stemWidth) => { + const instrs = []; + instrs.push( + 'M', + (side === 'left' ? 7.5 : 4)+ofs[0], + side === 'left' ? stemWidth/2 : 3.5, + ); + if (side === 'left') + instrs.push('v', -stemWidth/2); + instrs.push( + 'A', + 3.5, + 3.5, + 0, + 0, + 0, + (side === 'right' ? 7.5 : 4)+ofs[0], + side === 'right' ? 0 : -3.5, + ); + if (side === 'right') + instrs.push('v', -stemWidth/2); + marker.append('svg:path') + .attr('d', instrs.join(' ')) + .attr('stroke-width', 1) + .attr('fill', 'none'); + marker.append('svg:path') + .attr('d', ['M', 7+ofs[0], 0, 'h -7'].join(' ')) + .attr('stroke-width', stemWidth) + .attr('fill', 'none'); + }, + }), + icurve: (open, side) => ({ + stems: [false, true], + kernstems: [0.25, 0], + frontRef: [8, 0], + drawFunction: (marker, ofs, stemWidth) => { + const instrs = []; + instrs.push( + 'M', + (side === 'left' ? 0.5 : 4)+ofs[0], + side === 'left' ? stemWidth/2 : 3.5, + ); + if (side === 'left') + instrs.push('v', -stemWidth/2); + instrs.push( + 'A', + 3.5, + 3.5, + 0, + 0, + 1, + (side === 'right' ? 0.5 : 4)+ofs[0], + side === 'right' ? 0 : -3.5, + ); + if (side === 'right') + instrs.push('v', -stemWidth/2); + marker.append('svg:path') + .attr('d', instrs.join(' ')) + .attr('stroke-width', 1) + .attr('fill', 'none'); + marker.append('svg:path') + .attr('d', ['M', 1+ofs[0], 0, 'h 7'].join(' ')) + .attr('stroke-width', stemWidth) + .attr('fill', 'none'); + }, + }), + diamond: (open, side) => { + if (!open) + return { + frontRef: [side ? 11.25 : 12, 0], + backRef: [side ? 0.75 : 0, 0], + viewBox: [0, -4, 12, 8], + stems: [!!side, !!side], + kernstems: stemWidth => [side ? 0 : .75*stemWidth, side ? 0 : .75*stemWidth], + drawFunction: (marker, ofs, stemWidth) => { + const upoints = [{x: 0, y: 0}]; + if (side !== 'left') + upoints.push({x: 6, y: 4}); + else + upoints.push({x: 6, y: -4}); + upoints.push({x: 12, y: 0}); + if (!side) + upoints.push({x: 6, y: -4}); + const points = upoints.map(offsetx(ofs[0])); marker.append('svg:path') - .attr({ - d: ['M', 0.75 + ofs[0], 0, - 'h 10.5'].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - } - }; + .attr('d', generatePath(points, 1, true)) + .attr('stroke-width', 0); + if (side) { + marker.append('svg:path') + .attr('d', ['M', 0.75+ofs[0], 0, 'h 10.5'].join(' ')) + .attr('stroke-width', stemWidth) + .attr('fill', 'none'); + } + }, + }; else return { - frontRef: [side ? 11.25 : 12, 0], - backRef: [side ? 0.75 : 0, 0], - viewBox: [0, -4, 12, 8], - stems: [!!side, !!side], - kernstems: function(stemWidth) { - return [side ? 0 : .75*stemWidth, side ? 0 : .75*stemWidth]; - }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = [{x: 0.9, y: 0}]; - if(side !== 'left') - upoints.push({x: 6, y: 3.4}); - else - upoints.push({x: 6, y: -3.4}); - upoints.push({x: 11.1, y: 0}); - if(!side) - upoints.push({x: 6, y: -3.4}); - var points = upoints.map(offsetx(ofs[0])); - marker.append('svg:path') - .attr({ - d: generate_path(points, 1, !side), - 'stroke-width': 1, - fill: 'none' - }); - if(side) { + frontRef: [side ? 11.25 : 12, 0], + backRef: [side ? 0.75 : 0, 0], + viewBox: [0, -4, 12, 8], + stems: [!!side, !!side], + kernstems: stemWidth => [side ? 0 : .75*stemWidth, side ? 0 : .75*stemWidth], + drawFunction: (marker, ofs, stemWidth) => { + const upoints = [{x: 0.9, y: 0}]; + if (side !== 'left') + upoints.push({x: 6, y: 3.4}); + else + upoints.push({x: 6, y: -3.4}); + upoints.push({x: 11.1, y: 0}); + if (!side) + upoints.push({x: 6, y: -3.4}); + const points = upoints.map(offsetx(ofs[0])); marker.append('svg:path') - .attr({ - d: ['M', 0.75 + ofs[0], 0, - 'h 10.5'].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - } - }; + .attr('d', generatePath(points, 1, !side)) + .attr('stroke-width', 1) + .attr('fill', 'none'); + if (side) { + marker.append('svg:path') + .attr('d', ['M', 0.75+ofs[0], 0, 'h 10.5'].join(' ')) + .attr('stroke-width', stemWidth) + .attr('fill', 'none'); + } + }, + }; }, - dot: function(open, side) { - if(!open) return { - frontRef: [8,0], - stems: [!!side, !!side], - drawFunction: function(marker, ofs, stemWidth) { - if(side) { - marker.append('svg:path') - .attr({ - d: ['M', ofs[0], 0, - 'A', 4, 4, 0, 0, side==='left'?1:0, 8 + ofs[0], 0].join(' '), - 'stroke-width': 0 - }); - marker.append('svg:path') - .attr({ - d: ['M', ofs[0], 0, - 'h 8'].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - else { - marker.append('svg:circle') - .attr('r', 4) - .attr('cx', 4 + ofs[0]) - .attr('cy', 0) - .attr('stroke-width', '0px'); - } - } - }; + dot(open, side) { + if (!open) + return { + frontRef: [8, 0], + stems: [!!side, !!side], + drawFunction: (marker, ofs, stemWidth) => { + if (side) { + marker.append('svg:path') + .attr( + 'd', + [ + 'M', + ofs[0], + 0, + 'A', + 4, + 4, + 0, + 0, + side === 'left' ? 1 : 0, + 8+ofs[0], + 0, + ].join(' '), + ) + .attr('stroke-width', 0); + marker.append('svg:path') + .attr('d', ['M', ofs[0], 0, 'h 8'].join(' ')) + .attr('stroke-width', stemWidth) + .attr('fill', 'none'); + } else { + marker.append('svg:circle') + .attr('r', 4) + .attr('cx', 4+ofs[0]) + .attr('cy', 0) + .attr('stroke-width', '0px'); + } + }, + }; else return { - frontRef: [8,0], - stems: [!!side, !!side], - drawFunction: function(marker, ofs, stemWidth) { - if(side) { - marker.append('svg:path') - .attr({ - d: ['M', 0.5 + ofs[0], 0, - 'A', 3.5, 3.5, 0, 0, side==='left'?1:0, 7.5 + ofs[0], 0].join(' '), - 'stroke-width': 1, - fill: 'none' - }); - marker.append('svg:path') - .attr({ - d: ['M', ofs[0], 0, - 'h 8'].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } else { - marker.append('svg:circle') - .attr('r', 3.5) - .attr('cx', 4 + ofs[0]) - .attr('cy', 0) - .attr('fill', 'none') - .attr('stroke-width', '1px'); - } - } - }; + frontRef: [8, 0], + stems: [!!side, !!side], + drawFunction: (marker, ofs, stemWidth) => { + if (side) { + marker.append('svg:path') + .attr( + 'd', + [ + 'M', + 0.5+ofs[0], + 0, + 'A', + 3.5, + 3.5, + 0, + 0, + side === 'left' ? 1 : 0, + 7.5+ofs[0], + 0, + ].join(' '), + ) + .attr('stroke-width', 1) + .attr('fill', 'none'); + marker.append('svg:path') + .attr('d', ['M', ofs[0], 0, 'h 8'].join(' ')) + .attr('stroke-width', stemWidth) + .attr('fill', 'none'); + } else { + marker.append('svg:circle') + .attr('r', 3.5) + .attr('cx', 4+ofs[0]) + .attr('cy', 0) + .attr('fill', 'none') + .attr('stroke-width', '1px'); + } + }, + }; }, - normal: function(open, side) { - if(!open) return { - frontRef: [side ? 8-4/3 : 8, 0], - viewBox: [0, -3, 8, 6], - kernstems: function(stemWidth) { - return [0,stemWidth*4/3]; - }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = []; - if(side === 'left') - upoints.push({x: 0, y: 0}); - else - upoints.push({x: 0, y: 3}); - switch(side) { - case 'left': - upoints.push({x: 8 - stemWidth*4/3, y: -stemWidth/2}); - break; - case 'right': - upoints.push({x: 8 - stemWidth*4/3, y: stemWidth/2}); - break; - default: - upoints.push({x: 8, y: 0}); - } - if(side === 'right') - upoints.push({x: 0, y: 0}); - else - upoints.push({x: 0, y: -3}); - var points = upoints.map(offsetx(ofs[0])); - marker.append('svg:path') - .attr('d', generate_path(points, 1, true)) - .attr('stroke-width', '0px'); - if(side) { + normal(open, side) { + if (!open) + return { + frontRef: [side ? 8-4/3 : 8, 0], + viewBox: [0, -3, 8, 6], + kernstems(stemWidth) { + return [0, stemWidth*4/3]; + }, + drawFunction: (marker, ofs, stemWidth) => { + const upoints = []; + if (side === 'left') + upoints.push({x: 0, y: 0}); + else + upoints.push({x: 0, y: 3}); + switch (side) { + case 'left': + upoints.push({x: 8-stemWidth*4/3, y: -stemWidth/2}); + break; + case 'right': + upoints.push({x: 8-stemWidth*4/3, y: stemWidth/2}); + break; + default: + upoints.push({x: 8, y: 0}); + } + if (side === 'right') + upoints.push({x: 0, y: 0}); + else + upoints.push({x: 0, y: -3}); + const points = upoints.map(offsetx(ofs[0])); marker.append('svg:path') - .attr({ - d: ['M', ofs[0], 0, - 'h', 8-4*stemWidth/3].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - } - }; + .attr('d', generatePath(points, 1, true)) + .attr('stroke-width', '0px'); + if (side) { + marker.append('svg:path') + .attr('d', ['M', ofs[0], 0, 'h', 8-4*stemWidth/3].join(' ')) + .attr('stroke-width', stemWidth) + .attr('fill', 'none'); + } + }, + }; else return { - frontRef: [side ? 8-4/3 : 8, 0], - viewBox: [0, -3, 8, 6], - kernstems: function(stemWidth) { - return [0,stemWidth*4/3]; - }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = []; - if(!side) { - upoints = [ - {x: 0.5, y: 2.28}, - {x: 6.57, y: 0}, - {x: 0.5, y: -2.28} - ]; - } else { - upoints = [ - {x: 0.5, y: 0}, - {x: 0.5, y: side === 'left' ? -2.28 : 2.28}, - {x: 8-4/3, y: 0} - ]; - } - var points = upoints.map(offsetx(ofs[0])); - marker.append('svg:path') - .attr({ - d: generate_path(points, 1, !side), - 'stroke-width': 1, - fill: 'none' - }); - if(side) { + frontRef: [side ? 8-4/3 : 8, 0], + viewBox: [0, -3, 8, 6], + kernstems(stemWidth) { + return [0, stemWidth*4/3]; + }, + drawFunction: (marker, ofs, stemWidth) => { + let upoints = []; + if (!side) { + upoints = [ + {x: 0.5, y: 2.28}, + {x: 6.57, y: 0}, + {x: 0.5, y: -2.28}, + ]; + } else { + upoints = [ + {x: 0.5, y: 0}, + {x: 0.5, y: side === 'left' ? -2.28 : 2.28}, + {x: 8-4/3, y: 0}, + ]; + } + const points = upoints.map(offsetx(ofs[0])); marker.append('svg:path') - .attr({ - d: ['M', ofs[0], 0, - 'h', 8-4/3].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - } - }; + .attr('d', generatePath(points, 1, !side)) + .attr('stroke-width', 1) + .attr('fill', 'none'); + if (side) { + marker.append('svg:path') + .attr('d', ['M', ofs[0], 0, 'h', 8-4/3].join(' ')) + .attr('stroke-width', stemWidth) + .attr('fill', 'none'); + } + }, + }; }, - inv: function(open, side) { - if(!open) return { - frontRef: [8,0], - backRef: [side ? 4/3 : 0, 0], - viewBox: [0, -3, 8, 6], - kernstems: function(stemWidth) { - return [stemWidth*4/3,0]; - }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = []; - if(side === 'left') - upoints.push({x: 8, y: 0}); - else - upoints.push({x: 8, y: 3}); - switch(side) { - case 'left': - upoints.push({x: stemWidth*4/3, y: -stemWidth/2}); - break; - case 'right': - upoints.push({x: stemWidth*4/3, y: stemWidth/2}); - break; - default: - upoints.push({x: 0, y: 0}); - } - if(side === 'right') - upoints.push({x: 8, y: 0}); - else - upoints.push({x: 8, y: -3}); - var points = upoints.map(offsetx(ofs[0])); - marker.append('svg:path') - .attr('d', generate_path(points, 1, true)) - .attr('stroke-width', '0px'); - if(side) { + inv(open, side) { + if (!open) + return { + frontRef: [8, 0], + backRef: [side ? 4/3 : 0, 0], + viewBox: [0, -3, 8, 6], + kernstems(stemWidth) { + return [stemWidth*4/3, 0]; + }, + drawFunction: (marker, ofs, stemWidth) => { + const upoints = []; + if (side === 'left') + upoints.push({x: 8, y: 0}); + else + upoints.push({x: 8, y: 3}); + switch (side) { + case 'left': + upoints.push({x: stemWidth*4/3, y: -stemWidth/2}); + break; + case 'right': + upoints.push({x: stemWidth*4/3, y: stemWidth/2}); + break; + default: + upoints.push({x: 0, y: 0}); + } + if (side === 'right') + upoints.push({x: 8, y: 0}); + else + upoints.push({x: 8, y: -3}); + const points = upoints.map(offsetx(ofs[0])); marker.append('svg:path') - .attr({ - d: ['M', 4*stemWidth/3 + ofs[0], 0, - 'h', 8-4*stemWidth/3].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - } - }; + .attr('d', generatePath(points, 1, true)) + .attr('stroke-width', '0px'); + if (side) { + marker.append('svg:path') + .attr( + 'd', + ['M', 4*stemWidth/3+ofs[0], 0, 'h', 8-4*stemWidth/3].join(' '), + ) + .attr('stroke-width', stemWidth) + .attr('fill', 'none'); + } + }, + }; else return { - frontRef: [8,0], - backRef: [side ? 4/3 : 0, 0], - viewBox: [0, -3, 8, 6], - kernstems: function(stemWidth) { - return [stemWidth*4/3,0]; - }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = []; - if(!side) { - upoints = [ - {x: 7.5, y: 2.28}, - {x: 1.43, y: 0}, - {x: 7.5, y: -2.28} - ]; - } else { - upoints = [ - {x: 7.5, y: 0}, - {x: 7.5, y: side === 'left' ? -2.28 : 2.28}, - {x: 1.43, y: 0} - ]; - } - var points = upoints.map(offsetx(ofs[0])); - marker.append('svg:path') - .attr({ - d: generate_path(points, 1, !side), - 'stroke-width': 1, - fill: 'none' - }); - if(side) { + frontRef: [8, 0], + backRef: [side ? 4/3 : 0, 0], + viewBox: [0, -3, 8, 6], + kernstems(stemWidth) { + return [stemWidth*4/3, 0]; + }, + drawFunction: (marker, ofs, stemWidth) => { + let upoints = []; + if (!side) { + upoints = [ + {x: 7.5, y: 2.28}, + {x: 1.43, y: 0}, + {x: 7.5, y: -2.28}, + ]; + } else { + upoints = [ + {x: 7.5, y: 0}, + {x: 7.5, y: side === 'left' ? -2.28 : 2.28}, + {x: 1.43, y: 0}, + ]; + } + const points = upoints.map(offsetx(ofs[0])); marker.append('svg:path') - .attr({ - d: ['M', 4*stemWidth/3 + ofs[0], 0, - 'h', 8-4/3].join(' '), - 'stroke-width': stemWidth, - fill: 'none' - }); - } - } - }; + .attr('d', generatePath(points, 1, !side)) + .attr('stroke-width', 1) + .attr('fill', 'none'); + if (side) { + marker.append('svg:path') + .attr('d', ['M', 4*stemWidth/3+ofs[0], 0, 'h', 8-4/3].join(' ')) + .attr('stroke-width', stemWidth) + .attr('fill', 'none'); + } + }, + }; }, - tee: function(open, side) { + tee(open, side) { return { - frontRef: [5,0], + frontRef: [5, 0], viewBox: [0, -5, 5, 10], - stems: [true,false], - drawFunction: function(marker, ofs, stemWidth) { - var b = side === 'right' ? 0 : -5, + stems: [true, false], + drawFunction: (marker, ofs, stemWidth) => { + const b = side === 'right' ? 0 : -5, t = side === 'left' ? 0 : 5; - var points = [ + const points = [ {x: 2, y: t}, {x: 5, y: t}, {x: 5, y: b}, - {x: 2, y: b} + {x: 2, y: b}, ].map(offsetx(ofs[0])); marker.append('svg:path') - .attr('d', generate_path(points, 1, true)) + .attr('d', generatePath(points, 1, true)) .attr('stroke-width', '0px'); marker.append('svg:path') .attr('d', ['M', ofs[0], 0, 'h', 5].join(' ')) .attr('stroke-width', stemWidth) .attr('fill', 'none'); - } + }, }; }, - vee: function(open, side) { + vee(open, side) { return { - stems: [true,false], - kernstems: function(stemWidth) { - return [0,stemWidth]; + stems: [true, false], + kernstems(stemWidth) { + return [0, stemWidth]; }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = [ + drawFunction: (marker, ofs, stemWidth) => { + const upoints = [ {x: 0, y: -5}, {x: 10, y: 0}, {x: 0, y: 5}, - {x: 5, y: 0} + {x: 5, y: 0}, ]; - if(side==='right') - upoints.splice(0, 1, - {x: 5, y: -stemWidth/2}, - {x: 10, y: -stemWidth/2}); - else if(side==='left') - upoints.splice(2, 1, - {x: 10, y: stemWidth/2}, - {x: 5, y: stemWidth/2}); - var points = upoints.map(offsetx(ofs[0])); + if (side === 'right') + upoints.splice(0, 1, {x: 5, y: -stemWidth/2}, {x: 10, y: -stemWidth/2}); + else if (side === 'left') + upoints.splice(2, 1, {x: 10, y: stemWidth/2}, {x: 5, y: stemWidth/2}); + const points = upoints.map(offsetx(ofs[0])); marker.append('svg:path') - .attr('d', generate_path(points, 1, true)) + .attr('d', generatePath(points, 1, true)) .attr('stroke-width', '0px'); marker.append('svg:path') - .attr('d', ['M', ofs[0]+5, 0, 'h',-5].join(' ')) + .attr('d', ['M', ofs[0]+5, 0, 'h', -5].join(' ')) .attr('stroke-width', stemWidth); - } + }, }; }, - crow: function(open, side) { + crow(open, side) { return { - stems: [false,true], - kernstems: function(stemWidth) { - return [stemWidth,0]; + stems: [false, true], + kernstems(stemWidth) { + return [stemWidth, 0]; }, - drawFunction: function(marker, ofs, stemWidth) { - var upoints = [ + drawFunction: (marker, ofs, stemWidth) => { + const upoints = [ {x: 10, y: -5}, {x: 0, y: 0}, {x: 10, y: 5}, - {x: 5, y: 0} + {x: 5, y: 0}, ]; - if(side==='right') - upoints.splice(0, 1, - {x: 5, y: -stemWidth/2}, - {x: 0, y: -stemWidth/2}); - else if(side==='left') - upoints.splice(2, 1, - {x: 0, y: stemWidth/2}, - {x: 5, y: stemWidth/2}); - var points = upoints.map(offsetx(ofs[0])); + if (side === 'right') + upoints.splice(0, 1, {x: 5, y: -stemWidth/2}, {x: 0, y: -stemWidth/2}); + else if (side === 'left') + upoints.splice(2, 1, {x: 0, y: stemWidth/2}, {x: 5, y: stemWidth/2}); + const points = upoints.map(offsetx(ofs[0])); marker.append('svg:path') - .attr('d', generate_path(points, 1, true)) + .attr('d', generatePath(points, 1, true)) .attr('stroke-width', '0px'); marker.append('svg:path') - .attr('d', ['M', ofs[0]+5, 0, 'h',5].join(' ')) + .attr('d', ['M', ofs[0]+5, 0, 'h', 5].join(' ')) .attr('stroke-width', stemWidth); - } + }, }; - } + }, }; -function arrow_def(arrdefs, shape, open, side) { +function arrowDef(arrdefs, shape, open, side) { return arrdefs[shape](open, side); } -function arrow_parts(arrdefs, desc) { +export function arrowParts(arrdefs, desc) { // graphviz appears to use a real parser for this - var parts = []; - while(desc && desc.length) { - var mods = /^o?(?:l|r)?/.exec(desc); - var open = false, side = null; - if(mods[0]) { + const parts = []; + while (desc && desc.length) { + let mods = /^o?(?:l|r)?/.exec(desc); + let open = false, side = null; + if (mods[0]) { mods = mods[0]; desc = desc.slice(mods.length); open = mods[0] === 'o'; - switch(mods[mods.length-1]) { - case 'l': - side='left'; - break; - case 'r': - side='right'; + switch (mods[mods.length-1]) { + case 'l': + side = 'left'; + break; + case 'r': + side = 'right'; } } - var ok = false; - for(var aname in arrdefs) - if(desc.substring(0, aname.length) === aname) { + let ok = false; + for (const aname in arrdefs) + if (desc.substring(0, aname.length) === aname) { ok = true; - parts.push(arrow_def(arrdefs, aname, open, side)); + parts.push(arrowDef(arrdefs, aname, open, side)); desc = desc.slice(aname.length); break; } - if(!ok) { - console.warn("couldn't find arrow name in " + desc); + if (!ok) { + console.warn(`couldn't find arrow name in ${desc}`); break; } } return parts; } -function union_viewbox(vb1, vb2) { - var left = Math.min(vb1[0], vb2[0]), +function unionViewbox(vb1, vb2) { + const left = Math.min(vb1[0], vb2[0]), bottom = Math.min(vb1[1], vb2[1]), - right = Math.max(vb1[0] + vb1[2], vb2[0] + vb2[2]), - top = Math.max(vb1[1] + vb1[3], vb2[1] + vb2[3]); - return [left, bottom, right - left, top - bottom]; + right = Math.max(vb1[0]+vb1[2], vb2[0]+vb2[2]), + top = Math.max(vb1[1]+vb1[3], vb2[1]+vb2[3]); + return [left, bottom, right-left, top-bottom]; } -function subtract_points(p1, p2) { - return [p1[0] - p2[0], p1[1] - p2[1]]; +function subtractPoints(p1, p2) { + return [p1[0]-p2[0], p1[1]-p2[1]]; } -function add_points(p1, p2) { - return [p1[0] + p2[0], p1[1] + p2[1]]; +export function addPoints(p1, p2) { + return [p1[0]+p2[0], p1[1]+p2[1]]; } -function mult_point(p, s) { - return p.map(function(x) { return x*s; }); +export function multPoint(p, s) { + return p.map(x => x*s); } function defaulted(def) { @@ -549,141 +539,143 @@ function defaulted(def) { }; } -var view_box = defaulted([0, -5, 10, 10]), +const view_box = defaulted([0, -5, 10, 10]), front_ref = defaulted([10, 0]), back_ref = defaulted([0, 0]); -function arrow_offsets(parts, stemWidth) { - var frontRef = null, backRef = null; - return parts.map(function(p, i) { - var fr = front_ref(p.frontRef).slice(), +export function arrowOffsets(parts, stemWidth) { + return parts.map((p, i) => { + const fr = front_ref(p.frontRef).slice(), br = back_ref(p.backRef).slice(); - if(p.kernstems) { - var kernstems = p.kernstems; - if(typeof kernstems === 'function') + if (p.kernstems) { + let kernstems = p.kernstems; + if (typeof kernstems === 'function') kernstems = kernstems(stemWidth); - if(i !== 0 && kernstems[1]) { - var last = parts[i-1]; - if(last.stems && last.stems[0]) + if (i !== 0 && kernstems[1]) { + const last = parts[i-1]; + if (last.stems && last.stems[0]) fr[0] -= kernstems[1]; } - if(kernstems[0]) { - var kern = false; - if(i === parts.length-1) + if (kernstems[0]) { + let kern = false; + if (i === parts.length-1) kern = true; else { - var next = parts[i+1]; - if(next.stems && next.stems[1]) + const next = parts[i+1]; + if (next.stems && next.stems[1]) kern = true; } - if(kern) + if (kern) br[0] += kernstems[0]; } } - if(i === 0) { - frontRef = fr; - backRef = br; - return {backRef: backRef, offset: [0, 0]}; + if (i === 0) { + const backRef = br; + return {backRef, offset: [0, 0]}; } else { - var ofs = subtract_points(backRef, fr); - backRef = add_points(br, ofs); - return {backRef: backRef, offset: ofs}; + let backRef = br; + const ofs = subtractPoints(backRef, fr); + backRef = addPoints(br, ofs); + return {backRef, offset: ofs}; } }); } -function arrow_bounds(parts, stemWidth) { - var viewBox = null, offsets = arrow_offsets(parts, stemWidth); - parts.forEach(function(p, i) { - var vb = view_box(p.viewBox); - var ofs = offsets[i].offset; - if(!viewBox) +function arrowBounds(parts, stemWidth) { + let viewBox = null; + const offsets = arrowOffsets(parts, stemWidth); + parts.forEach((p, i) => { + const vb = view_box(p.viewBox); + const ofs = offsets[i].offset; + if (!viewBox) viewBox = vb.slice(); else - viewBox = union_viewbox(viewBox, [vb[0] + ofs[0], vb[1] + ofs[1], vb[2], vb[3]]); + viewBox = unionViewbox(viewBox, [vb[0]+ofs[0], vb[1]+ofs[1], vb[2], vb[3]]); }); - return {offsets: offsets, viewBox: viewBox}; + return {offsets, viewBox}; } -function arrow_length(parts, stemWidth) { - if(!parts.length) +function arrowLength(parts, stemWidth) { + if (!parts.length) return 0; - var offsets = arrow_offsets(parts, stemWidth); - return front_ref(parts[0].frontRef)[0] - offsets[parts.length-1].backRef[0]; + const offsets = arrowOffsets(parts, stemWidth); + return front_ref(parts[0].frontRef)[0]-offsets[parts.length-1].backRef[0]; } - -function scaled_arrow_lengths(diagram, e) { - var arrowSize = diagram.edgeArrowSize.eval(e), - stemWidth = diagram.edgeStrokeWidth.eval(e) / arrowSize; - var headLength = arrowSize * - (arrow_length(arrow_parts(diagram.arrows(), diagram.edgeArrowhead.eval(e)), stemWidth) + - diagram.nodeStrokeWidth.eval(e.target) / 2), - tailLength = arrowSize * - (arrow_length(arrow_parts(diagram.arrows(), diagram.edgeArrowtail.eval(e)), stemWidth) + - diagram.nodeStrokeWidth.eval(e.source) / 2); - return {headLength: headLength, tailLength: tailLength}; +export function scaledArrowLengths(diagram, e) { + const arrowSize = diagram.edgeArrowSize.eval(e), + stemWidth = diagram.edgeStrokeWidth.eval(e)/arrowSize; + const headLength = arrowSize + *(arrowLength(arrowParts(diagram.arrows(), diagram.edgeArrowhead.eval(e)), stemWidth) + +diagram.nodeStrokeWidth.eval(e.target)/2), + tailLength = arrowSize + *(arrowLength(arrowParts(diagram.arrows(), diagram.edgeArrowtail.eval(e)), stemWidth) + +diagram.nodeStrokeWidth.eval(e.source)/2); + return {headLength, tailLength}; } -function clip_path_to_arrows(headLength, tailLength, path) { - var points0 = as_bezier3(path), - points = chop_bezier(points0, 'head', headLength); +export function clipPathToArrows(headLength, tailLength, path) { + const points0 = asBezier3(path), + points = chopBezier(points0, 'head', headLength); return { bezDegree: 3, - points: chop_bezier(points, 'tail', tailLength), + points: chopBezier(points, 'tail', tailLength), sourcePort: path.sourcePort, - targetPort: path.targetPort + targetPort: path.targetPort, }; } -function place_arrows_on_spline(diagram, e, points) { - var alengths = scaled_arrow_lengths(diagram, e); - var path0 = { - points: points, - bezDegree: 3 +export function placeArrowsOnSpline(diagram, e, points) { + const alengths = scaledArrowLengths(diagram, e); + const path0 = { + points, + bezDegree: 3, }; - var path = clip_path_to_arrows(alengths.headLength, alengths.tailLength, path0); + const path = clipPathToArrows(alengths.headLength, alengths.tailLength, path0); return { - path: path, + path, full: path0, - orienthead: angle_between_points(path.points[path.points.length-1], path0.points[path0.points.length-1]) + 'rad', //calculate_arrowhead_orientation(e.cola.points, 'head'), - orienttail: angle_between_points(path.points[0], path0.points[0]) + 'rad' //calculate_arrowhead_orientation(e.cola.points, 'tail') + orienthead: `${ + angleBetweenPoints( + path.points[path.points.length-1], + path0.points[path0.points.length-1], + ) + }rad`, // calculate_arrowhead_orientation(e.cola.points, 'head'), + orienttail: `${angleBetweenPoints(path.points[0], path0.points[0])}rad`, // calculate_arrowhead_orientation(e.cola.points, 'tail') }; } - // determine pre-transition orientation that won't spin a lot going to new orientation -function unsurprising_orient(oldorient, neworient) { - var oldang = +oldorient.slice(0, -3), - newang = +neworient.slice(0, -3); - if(Math.abs(oldang - newang) > Math.PI) { - if(newang > oldang) +export function unsurprisingOrient(oldorient, neworient) { + let oldang = +oldorient.slice(0, -3); + const newang = +neworient.slice(0, -3); + if (Math.abs(oldang-newang) > Math.PI) { + if (newang > oldang) oldang += 2*Math.PI; else oldang -= 2*Math.PI; } return oldang; } - -function edgeArrow(diagram, arrdefs, e, kind, desc) { - var id = diagram.arrowId(e, kind); - var strokeOfs, edgeStroke; +export function edgeArrow(diagram, arrdefs, e, kind, desc) { + const id = diagram.arrowId(e, kind); + let strokeOfs, edgeStroke; function arrow_sig() { - return desc + '-' + strokeOfs + '-' + edgeStroke; + return `${desc}-${strokeOfs}-${edgeStroke}`; } - if(desc) { - strokeOfs = diagram.nodeStrokeWidth.eval(kind==='tail' ? e.source : e.target)/2; + if (desc) { + strokeOfs = diagram.nodeStrokeWidth.eval(kind === 'tail' ? e.source : e.target)/2; edgeStroke = diagram.edgeStroke.eval(e); - if(e[kind + 'ArrowLast'] === arrow_sig()) + if (e[`${kind}ArrowLast`] === arrow_sig()) return id; } - var parts = arrow_parts(arrdefs, desc), + const parts = arrowParts(arrdefs, desc), marker = diagram.addOrRemoveDef(id, !!parts.length, 'svg:marker'); - if(parts.length) { - var arrowSize = diagram.edgeArrowSize.eval(e), - stemWidth = diagram.edgeStrokeWidth.eval(e) / arrowSize, - bounds = arrow_bounds(parts, stemWidth), + if (parts.length) { + const arrowSize = diagram.edgeArrowSize.eval(e), + stemWidth = diagram.edgeStrokeWidth.eval(e)/arrowSize, + bounds = arrowBounds(parts, stemWidth), frontRef = front_ref(parts[0].frontRef); bounds.viewBox[0] -= strokeOfs/arrowSize; bounds.viewBox[3] += strokeOfs/arrowSize; @@ -697,13 +689,15 @@ function edgeArrow(diagram, arrdefs, e, kind, desc) { .attr('stroke', edgeStroke) .attr('fill', edgeStroke); marker.html(null); - parts.forEach(function(p, i) { + parts.forEach((p, i) => { marker - .call(p.drawFunction, - add_points([-strokeOfs/arrowSize,0], bounds.offsets[i].offset), - stemWidth); + .call( + p.drawFunction, + addPoints([-strokeOfs/arrowSize, 0], bounds.offsets[i].offset), + stemWidth, + ); }); } - e[kind + 'ArrowLast'] = arrow_sig(); + e[`${kind}ArrowLast`] = arrow_sig(); return desc ? id : null; } diff --git a/src/banner.js b/src/banner.js deleted file mode 100644 index edae8e98..00000000 --- a/src/banner.js +++ /dev/null @@ -1,2 +0,0 @@ -(function() { function _dc_graph(d3, crossfilter, dc) { -'use strict'; diff --git a/src/brush.js b/src/brush.js index b476390d..b44851f8 100644 --- a/src/brush.js +++ b/src/brush.js @@ -1,47 +1,65 @@ +import { brush as d3Brush } from 'd3-brush'; +import { dispatch } from 'd3-dispatch'; +import { event } from 'd3-selection'; +import { mode } from './mode.js'; + /** - * `dc_graph.brush` is a {@link dc_graph.mode mode} providing a simple wrapper over + * `brush` is a {@link mode mode} providing a simple wrapper over * [d3.svg.brush](https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Controls.md#brush) * @class brush - * @memberof dc_graph - * @return {dc_graph.brush} - **/ -dc_graph.brush = function() { - var _brush = null, _gBrush, _dispatch = d3.dispatch('brushstart', 'brushmove', 'brushend'); + * @return {brush} + */ +export function brush() { + let _brush = null, _gBrush; + const _dispatch = dispatch('brushstart', 'brushmove', 'brushend'); + let _clearing = false; function brushstart() { - _dispatch.brushstart(); + if (!_clearing) { + _dispatch.call('brushstart'); + } } function brushmove() { - var ext = _brush.extent(); - _dispatch.brushmove(ext); + if (!_clearing) { + const ext = event.selection; + _dispatch.call('brushmove', null, ext); + } } function brushend() { - _dispatch.brushend(); - _gBrush.call(_brush.clear()); + if (!_clearing) { + _dispatch.call('brushend'); + _clearing = true; + _gBrush.call(_brush.move, null); + _clearing = false; + } } function install_brush(diagram) { - if(!_brush) { - _brush = d3.svg.brush() - .x(diagram.x()).y(diagram.y()) - .on('brushstart.brush-mode', brushstart) + if (!_brush) { + const extent = [[diagram.x().range()[0], diagram.y().range()[0]], [ + diagram.x().range()[1], + diagram.y().range()[1], + ]]; + _brush = d3Brush() + .extent(extent) + .on('start.brush-mode', brushstart) .on('brush.brush-mode', brushmove) - .on('brushend.brush-mode', brushend); + .on('end.brush-mode', brushend); } - if(!_gBrush) { + if (!_gBrush) { _gBrush = diagram.svg().insert('g', ':first-child') .attr('class', 'brush') .call(_brush); } } function remove_brush() { - if(_gBrush) { + if (_gBrush) { _gBrush.remove(); _gBrush = null; } } - var _mode = dc_graph.mode('brush', { - draw: function() {}, - remove: remove_brush + const _mode = mode('brush', { + draw() {}, + remove: remove_brush, }); /** @@ -53,9 +71,9 @@ dc_graph.brush = function() { * @param {Function} [f] the handler function; if omitted, returns the current handler * @return {dc_graph.brush} * @return {Function} - **/ + */ _mode.on = function(event, f) { - if(arguments.length === 1) + if (arguments.length === 1) return _dispatch.on(event); _dispatch.on(event, f); return this; @@ -66,7 +84,7 @@ dc_graph.brush = function() { * @memberof dc_graph.brush * @instance * @return {dc_graph.brush} - **/ + */ _mode.activate = function() { install_brush(_mode.parent()); return this; @@ -77,7 +95,7 @@ dc_graph.brush = function() { * @memberof dc_graph.brush * @instance * @return {dc_graph.brush} - **/ + */ _mode.deactivate = function() { remove_brush(); return this; @@ -88,10 +106,10 @@ dc_graph.brush = function() { * @memberof dc_graph.brush * @instance * @return {Boolean} - **/ - _mode.isActive = function () { + */ + _mode.isActive = function() { return !!_gBrush; }; return _mode; -}; +} diff --git a/src/cola_layout.js b/src/cola_layout.js index 4fe60929..0e8f738e 100644 --- a/src/cola_layout.js +++ b/src/cola_layout.js @@ -1,172 +1,173 @@ /** - * `dc_graph.cola_layout` is an adaptor for cola.js layouts in dc.graph.js - * @class cola_layout - * @memberof dc_graph + * Cola.js layout adaptor for dc.graph.js + * @module cola_layout + */ + +import { dispatch } from 'd3-dispatch'; +// webcola is loaded as a global script and expects global d3 +const cola = globalThis.cola; +import { property, uuid } from './core.js'; +import { regenerateObjects } from './generate_objects.js'; +import { graphvizAttrs } from './graphviz_attrs.js'; + +/** + * `colaLayout` is an adaptor for cola.js layouts in dc.graph.js * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.cola_layout} - **/ -dc_graph.cola_layout = function(id) { - var _layoutId = id || uuid(); - var _d3cola = null; - var _setcola_nodes; - var _dispatch = d3.dispatch('tick', 'start', 'end'); - var _flowLayout; + * @return {Object} cola layout engine + */ +export function colaLayout(id) { + const _layoutId = id || uuid(); + let _d3cola = null; + let _setcola_nodes; + const _dispatch = (globalThis.d3?.dispatch || dispatch)('tick', 'start', 'end'); + let _flowLayout; // node and edge objects shared with cola.js, preserved from one iteration // to the next (as long as the object is still in the layout) - var _nodes = {}, _edges = {}; - var _options; + const _nodes = {}, _edges = {}; + let _options; function init(options) { _options = options; - _d3cola = cola.d3adaptor() + _d3cola = cola.d3adaptor(globalThis.d3) .avoidOverlaps(true) .size([options.width, options.height]) .handleDisconnected(options.handleDisconnected); - if(_d3cola.tickSize) // non-standard + if (_d3cola.tickSize) // non-standard _d3cola.tickSize(options.tickSize); - switch(options.lengthStrategy) { - case 'symmetric': - _d3cola.symmetricDiffLinkLengths(options.baseLength); - break; - case 'jaccard': - _d3cola.jaccardLinkLengths(options.baseLength); - break; - case 'individual': - _d3cola.linkDistance(function(e) { - return e.dcg_edgeLength || options.baseLength; - }); - break; - case 'none': - default: + switch (options.lengthStrategy) { + case 'symmetric': + _d3cola.symmetricDiffLinkLengths(options.baseLength); + break; + case 'jaccard': + _d3cola.jaccardLinkLengths(options.baseLength); + break; + case 'individual': + _d3cola.linkDistance(e => e.dcg_edgeLength || options.baseLength); + break; + case 'none': + default: } - if(options.flowLayout) { + if (options.flowLayout) { _d3cola.flowLayout(options.flowLayout.axis, options.flowLayout.minSeparation); } } function data(nodes, edges, clusters, constraints) { - var wnodes = regenerate_objects(_nodes, nodes, null, function(v) { - return v.dcg_nodeKey; - }, function(v1, v) { + let wnodes = regenerateObjects(_nodes, nodes, null, v => v.dcg_nodeKey, (v1, v) => { v1.dcg_nodeKey = v.dcg_nodeKey; v1.dcg_nodeParentCluster = v.dcg_nodeParentCluster; v1.width = v.width; v1.height = v.height; v1.fixed = !!v.dcg_nodeFixed; - _options.nodeAttrs.forEach(function(key) { + _options.nodeAttrs.forEach(key => { v1[key] = v[key]; }); - if(v1.fixed && typeof v.dcg_nodeFixed === 'object') { + if (v1.fixed && typeof v.dcg_nodeFixed === 'object') { v1.x = v.dcg_nodeFixed.x; v1.y = v.dcg_nodeFixed.y; - } - else { + } else { // should we support e.g. null to unset x,y? - if(v.x !== undefined) + if (v.x !== undefined) v1.x = v.x; - if(v.y !== undefined) + if (v.y !== undefined) v1.y = v.y; } }); - var wedges = regenerate_objects(_edges, edges, null, function(e) { - return e.dcg_edgeKey; - }, function(e1, e) { + const wedges = regenerateObjects(_edges, edges, null, e => e.dcg_edgeKey, (e1, e) => { e1.dcg_edgeKey = e.dcg_edgeKey; // cola edges can work with indices or with object references // but it will replace indices with object references e1.source = _nodes[e.dcg_edgeSource]; e1.target = _nodes[e.dcg_edgeTarget]; e1.dcg_edgeLength = e.dcg_edgeLength; - _options.edgeAttrs.forEach(function(key) { + _options.edgeAttrs.forEach(key => { e1[key] = e[key]; }); }); // cola needs each node object to have an index property - wnodes.forEach(function(v, i) { + wnodes.forEach((v, i) => { v.index = i; }); - var groups = null; - if(engine.groupConnected()) { - var components = cola.separateGraphs(wnodes, wedges); - groups = components.map(function(g) { - return { - dcg_autoGroup: true, - leaves: g.array.map(function(n) { return n.index; }) - }; - }); - } else if(clusters) { - var G = {}; - groups = clusters.filter(function(c) { - return /^cluster/.test(c.dcg_clusterKey); - }).map(function(c, i) { - return G[c.dcg_clusterKey] = { + let groups = null; + if (engine.groupConnected()) { + const components = cola.separateGraphs(wnodes, wedges); + groups = components.map(g => ({ + dcg_autoGroup: true, + leaves: g.array.map(n => n.index), + })); + } else if (clusters) { + const G = {}; + groups = clusters.filter(c => /^cluster/.test(c.dcg_clusterKey)).map((c, i) => + G[c.dcg_clusterKey] = { dcg_clusterKey: c.dcg_clusterKey, index: i, groups: [], - leaves: [] - }; - }); - clusters.forEach(function(c) { - if(c.dcg_clusterParent && G[c.dcg_clusterParent]) + leaves: [], + } + ); + clusters.forEach(c => { + if (c.dcg_clusterParent && G[c.dcg_clusterParent]) G[c.dcg_clusterParent].groups.push(G[c.dcg_clusterKey].index); }); - wnodes.forEach(function(n, i) { - if(n.dcg_nodeParentCluster && G[n.dcg_nodeParentCluster]) + wnodes.forEach((n, i) => { + if (n.dcg_nodeParentCluster && G[n.dcg_nodeParentCluster]) G[n.dcg_nodeParentCluster].leaves.push(i); }); } function dispatchState(event) { - // clean up extra setcola annotations - wnodes.forEach(function(n) { - Object.keys(n).forEach(function(key) { - if(/^get/.test(key) && typeof n[key] === 'function') - delete n[key]; + // Get the actual nodes that WebCola is working with and make copies + const currentNodes = _d3cola.nodes().map(n => { + const copy = Object.assign({}, n); + // clean up extra setcola annotations from the copy + Object.keys(copy).forEach(key => { + if (/^get/.test(key) && typeof copy[key] === 'function') + delete copy[key]; }); + return copy; }); - _dispatch[event]( - wnodes, - wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }), - groups.filter(function(g) { - return !g.dcg_autoGroup; - }).map(function(g) { + _dispatch.call( + event, + null, + currentNodes, + wedges.map(e => ({dcg_edgeKey: e.dcg_edgeKey})), + groups.filter(g => !g.dcg_autoGroup).map(g => { g = Object.assign({}, g); g.bounds = { left: g.bounds.x, top: g.bounds.y, right: g.bounds.X, - bottom: g.bounds.Y + bottom: g.bounds.Y, }; return g; }), - _setcola_nodes + _setcola_nodes, ); } - _d3cola.on('tick', /* _tick = */ function() { + _d3cola.on('tick', /* _tick = */ () => { dispatchState('tick'); - }).on('start', function() { - _dispatch.start(); - }).on('end', /* _done = */ function() { + }).on('start', () => { + _dispatch.call('start'); + }).on('end', /* _done = */ () => { dispatchState('end'); }); - if(_options.setcolaSpec && typeof setcola !== 'undefined') { + if (_options.setcolaSpec && typeof setcola !== 'undefined') { console.log('generating setcola constrains'); - var setcola_result = setcola + const setcola_result = setcola .nodes(wnodes) .links(wedges) .constraints(_options.setcolaSpec) - .gap(10) //default value is 10, can be customized in setcolaSpec + .gap(10) // default value is 10, can be customized in setcolaSpec .layout(); - _setcola_nodes = setcola_result.nodes.filter(function(n) { return n._cid; }); + _setcola_nodes = setcola_result.nodes.filter(n => n._cid); + wnodes = setcola_result.nodes; _d3cola.nodes(setcola_result.nodes) .links(setcola_result.links) .constraints(setcola_result.constraints) @@ -177,77 +178,90 @@ dc_graph.cola_layout = function(id) { .constraints(constraints) .groups(groups); } - } function start() { - _d3cola.start(engine.unconstrainedIterations(), - engine.userConstraintIterations(), - engine.allConstraintsIterations(), - engine.gridSnapIterations()); + _d3cola.start( + engine.unconstrainedIterations(), + engine.userConstraintIterations(), + engine.allConstraintsIterations(), + engine.gridSnapIterations(), + ); } function stop() { - if(_d3cola) + if (_d3cola) _d3cola.stop(); } - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); + const graphviz = graphvizAttrs(), graphviz_keys = Object.keys(graphviz); graphviz.rankdir(null); - var engine = Object.assign(graphviz, { - layoutAlgorithm: function() { + const engine = Object.assign(graphviz, { + layoutAlgorithm() { return 'cola'; }, - layoutId: function() { + layoutId() { return _layoutId; }, - supportsWebworker: function() { + supportsWebworker() { return true; }, - supportsMoving: function() { + supportsMoving() { return true; }, parent: property(null), - on: function(event, f) { - if(arguments.length === 1) + on(event, f) { + if (arguments.length === 1) return _dispatch.on(event); _dispatch.on(event, f); return this; }, - init: function(options) { - this.optionNames().forEach(function(option) { + init(options) { + this.optionNames().forEach(option => { options[option] = options[option] || this[option](); - }.bind(this)); + }); this.propagateOptions(options); init(options); return this; }, - data: function(graph, nodes, edges, clusters, constraints) { + data(graph, nodes, edges, clusters, constraints) { data(nodes, edges, clusters, constraints); }, - start: function() { + start() { start(); }, - stop: function() { + stop() { stop(); }, - optionNames: function() { - return ['handleDisconnected', 'lengthStrategy', 'baseLength', 'flowLayout', - 'tickSize', 'groupConnected', 'setcolaSpec', 'setcolaNodes'] + optionNames() { + return [ + 'handleDisconnected', + 'lengthStrategy', + 'baseLength', + 'flowLayout', + 'tickSize', + 'groupConnected', + 'setcolaSpec', + 'setcolaNodes', + 'unconstrainedIterations', + 'userConstraintIterations', + 'allConstraintsIterations', + 'gridSnapIterations', + ] .concat(graphviz_keys); }, - passThru: function() { + passThru() { return ['extractNodeAttrs', 'extractEdgeAttrs']; }, - propagateOptions: function(options) { - if(!options.nodeAttrs) + propagateOptions(options) { + if (!options.nodeAttrs) options.nodeAttrs = Object.keys(engine.extractNodeAttrs()); - if(!options.edgeAttrs) + if (!options.edgeAttrs) options.edgeAttrs = Object.keys(engine.extractEdgeAttrs()); }, - populateLayoutNode: function() {}, - populateLayoutEdge: function() {}, + populateLayoutNode() {}, + populateLayoutEdge() {}, /** * Instructs cola.js to fit the connected components. * @method handleDisconnected @@ -256,7 +270,7 @@ dc_graph.cola_layout = function(id) { * @param {Boolean} [handleDisconnected=true] * @return {Boolean} * @return {dc_graph.cola_layout} - **/ + */ handleDisconnected: property(true), /** * Currently, three strategies are supported for specifying the lengths of edges: @@ -273,7 +287,7 @@ dc_graph.cola_layout = function(id) { * @param {Function|String} [lengthStrategy='symmetric'] * @return {Function|String} * @return {dc_graph.cola_layout} - **/ + */ lengthStrategy: property('symmetric'), /** * Gets or sets the default edge length (in pixels) when the `.lengthStrategy` is @@ -285,7 +299,7 @@ dc_graph.cola_layout = function(id) { * @param {Number} [baseLength=30] * @return {Number} * @return {dc_graph.cola_layout} - **/ + */ baseLength: property(30), /** * If `flowLayout` is set, it determines the axis and separation for @@ -302,16 +316,25 @@ dc_graph.cola_layout = function(id) { * diagram.flowLayout(null) * // flow in x with min separation 200 * diagram.flowLayout({axis: 'x', minSeparation: 200}) - **/ - flowLayout: function(flow) { - if(!arguments.length) { - if(_flowLayout) + */ + flowLayout(flow) { + if (!arguments.length) { + if (_flowLayout) return _flowLayout; - var dir = engine.rankdir(); - switch(dir) { - case 'LR': return {axis: 'x', minSeparation: engine.ranksep() + engine.parent().nodeRadius()*2}; - case 'TB': return {axis: 'y', minSeparation: engine.ranksep() + engine.parent().nodeRadius()*2}; - default: return null; // RL, BT do not appear to be possible (negative separation) (?) + const dir = engine.rankdir(); + switch (dir) { + case 'LR': + return { + axis: 'x', + minSeparation: engine.ranksep()+engine.parent().nodeRadius()*2, + }; + case 'TB': + return { + axis: 'y', + minSeparation: engine.ranksep()+engine.parent().nodeRadius()*2, + }; + default: + return null; // RL, BT do not appear to be possible (negative separation) (?) } } _flowLayout = flow; @@ -324,17 +347,18 @@ dc_graph.cola_layout = function(id) { tickSize: property(1), groupConnected: property(false), setcolaSpec: property(null), - setcolaNodes: function() { + setcolaNodes() { return _setcola_nodes; }, extractNodeAttrs: property({}), // {attr: function(node)} extractEdgeAttrs: property({}), - processExtraWorkerResults: function(setcolaNodes) { + processExtraWorkerResults(setcolaNodes) { _setcola_nodes = setcolaNodes; - } + }, }); return engine; -}; +} -dc_graph.cola_layout.scripts = ['d3.js', 'cola.js']; -dc_graph.cola_layout.optional_scripts = ['setcola.js']; +// Scripts needed for web worker +colaLayout.scripts = ['d3.js', 'cola.js']; +colaLayout.optionalScripts = ['setcola.js']; diff --git a/src/constraint_pattern.js b/src/constraint_pattern.js index 591dd750..c9e38a84 100644 --- a/src/constraint_pattern.js +++ b/src/constraint_pattern.js @@ -1,9 +1,9 @@ +import { clone } from './utils.js'; + /** * In cola.js there are three factors which influence the positions of nodes: * * *edge length* suggestions, controlled by the - * {@link #dc_graph.diagram+lengthStrategy lengthStrategy}, - * {@link #dc_graph.diagram+baseLength baseLength}, and - * {@link #dc_graph.diagram+edgeLength edgeLength} parameters in dc.graph.js + * lengthStrategy, baseLength, and edgeLength parameters * * *automatic constraints* based on the global edge flow direction (`cola.flowLayout`) and overlap * avoidance parameters (`cola.avoidOverlaps`) * * *manual constraints* such as alignment, inequality and equality constraints in a dimension/axis. @@ -12,12 +12,6 @@ * {@link https://github.com/tgdwyer/WebCola/wiki/Constraints cola.js documentation mentions constraints}, * it means the manual constraints. * - * dc.graph.js allows generation of manual constraints using - * {@link #dc_graph.diagram+constrain diagram.constrain} but it can be tedious to write these - * functions because it usually means looping over the nodes and edges multiple times to - * determine what classes or types of nodes to apply constraints to, and which edges should - * take additional constraints. - * * This utility creates a constraint generator function from a *pattern*, a graph where: * 1. Nodes represent *types* or classes of layout nodes, annotated with a specification * of how to match the nodes belonging each type. @@ -32,7 +26,7 @@ * * (It is also conceivable to want constraints between individual nodes which don't * have edges between them. This is not directly supported at this time; right now the workaround - * is to create the edge but not draw it, e.g. by setting its {@link #dc_graph.diagram+edgeOpacity} + * is to create the edge but not draw it, e.g. by setting its edgeOpacity * to zero. If you have a use-case for this, please * {@link https://github.com/dc-js/dc.graph.js/issues/new file an issue}. * @@ -43,62 +37,64 @@ * gain more control. * * Then we'll build back up from the ground up and show how inference works. - * @class constraint_pattern - * @memberof dc_graph - * @param {dc_graph.diagram} diagram - the diagram to pull attributes from, mostly to determine - * the keys of nodes and edge sources and targets * @param {Object} pattern - a graph which defines the constraints to be generated * @return {Function} */ -dc_graph.constraint_pattern = function(pattern) { - var types = {}, rules = []; +export function constraintPattern(pattern) { + const types = {}, rules = []; - pattern.nodes.forEach(function(n) { - var id = n.id; - var type = types[id] || (types[id] = {}); + pattern.nodes.forEach(n => { + const id = n.id; + const type = types[id] || (types[id] = {}); // partitions could be done more efficiently; this is POC - if(n.partition) { - var partition = n.partition; - var value = n.value || n.id; - if(n.all || n.typename) { - type.match = n.extract ? - function(n2) { return n.extract(n2.value[partition]); } : - function(n2) { return n2.value[partition]; }; - type.typename = n.typename || function(n2) { return partition + '=' + n2.value[partition]; }; - } - else - type.match = function(n2) { return n2.value[partition] === value; }; - } - else if(n.match) + if (n.partition) { + const partition = n.partition; + const value = n.value || n.id; + if (n.all || n.typename) { + type.match = n.extract + ? function(n2) { + return n.extract(n2.value[partition]); + } + : function(n2) { + return n2.value[partition]; + }; + type.typename = n.typename || function(n2) { + return `${partition}=${n2.value[partition]}`; + }; + } else + type.match = function(n2) { + return n2.value[partition] === value; + }; + } else if (n.match) type.match = n.match; - else throw new Error("couldn't determine matcher for type " + JSON.stringify(n)); + else throw new Error(`couldn't determine matcher for type ${JSON.stringify(n)}`); }); - pattern.edges.forEach(function(e) { - if(e.disable) + pattern.edges.forEach(e => { + if (e.disable) return; - var rule = {source: e.source, target: e.target}; + const rule = {source: e.source, target: e.target}; rule.produce = typeof e.produce === 'function' ? e.produce : function() { return clone(e.produce); }; - ['listname', 'wrap', 'reverse'].forEach(function(k) { - if(e[k] !== undefined) rule[k] = e[k]; + ['listname', 'wrap', 'reverse'].forEach(k => { + if (e[k] !== undefined) rule[k] = e[k]; }); rules.push(rule); }); return function(diagram, nodes, edges) { - var constraints = []; - var members = {}; - nodes.forEach(function(n) { - var key = diagram.nodeKey.eval(n); - for(var t in types) { - var type = types[t], value = type.match(n.orig); - if(value) { - var tname = type.typename ? type.typename(t, value) : t; - if(!members[tname]) + const constraints = []; + const members = {}; + nodes.forEach(n => { + const key = diagram.nodeKey.eval(n); + for (const t in types) { + const type = types[t], value = type.match(n.orig); + if (value) { + const tname = type.typename ? type.typename(t, value) : t; + if (!members[tname]) members[tname] = { nodes: [], // original ordering - whether: {} // boolean + whether: {}, // boolean }; members[tname].nodes.push(key); members[tname].whether[key] = true; @@ -106,24 +102,21 @@ dc_graph.constraint_pattern = function(pattern) { } }); // traversal of rules could be more efficient, again POC - var edge_rules = rules.filter(function(r) { - return r.source !== r.target; - }); - var type_rules = rules.filter(function(r) { - return r.source === r.target; - }); - edges.forEach(function(e) { - var source = diagram.edgeSource.eval(e), + const edge_rules = rules.filter(r => r.source !== r.target); + const type_rules = rules.filter(r => r.source === r.target); + edges.forEach(e => { + const source = diagram.edgeSource.eval(e), target = diagram.edgeTarget.eval(e); - edge_rules.forEach(function(r) { - if(members[r.source] && members[r.source].whether[source] && - members[r.target] && members[r.target].whether[target]) { - var constraint = r.produce(members, nodes, edges); - if(r.reverse) { + edge_rules.forEach(r => { + if ( + members[r.source] && members[r.source].whether[source] + && members[r.target] && members[r.target].whether[target] + ) { + const constraint = r.produce(members, nodes, edges); + if (r.reverse) { constraint.left = target; constraint.right = source; - } - else { + } else { constraint.left = source; constraint.right = target; } @@ -131,67 +124,71 @@ dc_graph.constraint_pattern = function(pattern) { } }); }); - type_rules.forEach(function(r) { - if(!members[r.source]) + type_rules.forEach(r => { + if (!members[r.source]) return; - var constraint = r.produce(), + const constraint = r.produce(), listname = r.listname || r.produce.listname || 'nodes', - wrap = r.wrap || r.produce.wrap || function(x) { return x; }; + wrap = r.wrap || r.produce.wrap || function(x) { + return x; + }; constraint[listname] = members[r.source].nodes.map(wrap); constraints.push(constraint); }); return constraints; }; -}; +} // constraint generation convenience functions -dc_graph.gap_y = function(gap, equality) { +export function gapY(gap, equality) { return { axis: 'y', - gap: gap, - equality: !!equality + gap, + equality: !!equality, }; -}; -dc_graph.gap_x = function(gap, equality) { +} +export function gapX(gap, equality) { return { axis: 'x', - gap: gap, - equality: !!equality + gap, + equality: !!equality, }; -}; +} -function align_f(axis) { - var ret = function() { +function alignF(axis) { + const ret = function() { return { type: 'alignment', - axis: axis + axis, }; }; ret.listname = 'offsets'; - ret.wrap = function(x) { return {node: x, offset: 0}; }; + ret.wrap = function(x) { + return {node: x, offset: 0}; + }; return ret; } -dc_graph.align_y = function() { - return align_f('y'); -}; -dc_graph.align_x = function() { - return align_f('x'); -}; +export function alignY() { + return alignF('y'); +} +export function alignX() { + return alignF('x'); +} -dc_graph.order_x = function(gap, ordering) { +export function orderX(gap, ordering) { return { type: 'ordering', axis: 'x', gap: 60, - ordering: ordering + ordering, }; -}; -dc_graph.order_y = function(gap, ordering) { +} +export function orderY(gap, ordering) { return { type: 'ordering', axis: 'y', gap: 60, - ordering: ordering + ordering, }; -}; +} diff --git a/src/convert.js b/src/convert.js index 7b9f7f1c..31854799 100644 --- a/src/convert.js +++ b/src/convert.js @@ -1,116 +1,145 @@ -var convert_tree_helper = function(data, attrs, options, parent, level, inherit) { +import { pluck } from 'dc'; +import { uuid } from './core.js'; + +const convert_tree_helper = function(data, attrs, options, parent, level, inherit) { level = level || 0; - if(attrs.length > (options.valuesByAttr ? 1 : 0)) { - var attr = attrs.shift(); - var nodes = [], edges = []; - var children = data.map(function(v) { - var key = v[options.nestKey]; - var childKey = options.nestKeysUnique ? key : uuid(); - if(childKey) { - var node; - if(options.ancestorKeys) { + if (attrs.length > (options.valuesByAttr ? 1 : 0)) { + const attr = attrs.shift(); + const nodes = [], edges = []; + const children = data.map(v => { + const key = v[options.nestKey]; + const childKey = options.nestKeysUnique ? key : uuid(); + if (childKey) { + let node; + if (options.ancestorKeys) { inherit = inherit || {}; - if(attr) + if (attr) inherit[attr] = key; node = Object.assign({}, inherit); } else node = {}; node[options.nodeKey] = childKey; - if(options.label && options.labelFun) + if (options.label && options.labelFun) node[options.label] = options.labelFun(key, attr, v); - if(options.level) + if (options.level) node[options.level] = level+1; nodes.push(node); - if(parent) { - var edge = {}; + if (parent) { + const edge = {}; edge[options.edgeSource] = parent; edge[options.edgeTarget] = childKey; edges.push(edge); } } - var children = options.valuesByAttr ? v[attrs[0]] : v.values; - var recurse = convert_tree_helper(children, attrs.slice(0), options, - childKey, level+1, Object.assign({}, inherit)); + const children = options.valuesByAttr ? v[attrs[0]] : v.values; + const recurse = convert_tree_helper( + children, + attrs.slice(0), + options, + childKey, + level+1, + Object.assign({}, inherit), + ); return recurse; }); - return {nodes: Array.prototype.concat.apply(nodes, children.map(dc.pluck('nodes'))), - edges: Array.prototype.concat.apply(edges, children.map(dc.pluck('edges')))}; - } - else return {nodes: data.map(function(v) { - v = Object.assign({}, v); - if(options.level) - v[options.level] = level+1; - return v; - }), edges: data.map(function(v) { - var edge = {}; - edge[options.edgeSource] = parent; - edge[options.edgeTarget] = v[options.nodeKey]; - return edge; - })}; + return { + nodes: Array.prototype.concat.apply(nodes, children.map(pluck('nodes'))), + edges: Array.prototype.concat.apply(edges, children.map(pluck('edges'))), + }; + } else return { + nodes: data.map(v => { + v = Object.assign({}, v); + if (options.level) + v[options.level] = level+1; + return v; + }), + edges: data.map(v => { + const edge = {}; + edge[options.edgeSource] = parent; + edge[options.edgeTarget] = v[options.nodeKey]; + return edge; + }), + }; }; -dc_graph.convert_tree = function(data, attrs, options) { +export function convertTree(data, attrs, options) { options = Object.assign({ nodeKey: 'key', edgeKey: 'key', edgeSource: 'sourcename', edgeTarget: 'targetname', - nestKey: 'key' + nestKey: 'key', }, options); - if(Array.isArray(data)) + if (Array.isArray(data)) return convert_tree_helper(data, attrs, options, options.root, 0, options.inherit); else { attrs = [''].concat(attrs); return convert_tree_helper([data], attrs, options, options.root, 0, options.inherit); } -}; +} -dc_graph.convert_nest = function(nest, attrs, nodeKeyAttr, edgeSourceAttr, edgeTargetAttr, parent, inherit) { - return dc_graph.convert_tree(nest, attrs, { +export function convertNest( + nest, + attrs, + nodeKeyAttr, + edgeSourceAttr, + edgeTargetAttr, + parent, + inherit, +) { + return convertTree(nest, attrs, { nodeKey: nodeKeyAttr, edgeSource: edgeSourceAttr, edgeTarget: edgeTargetAttr, root: parent, - inherit: inherit, + inherit, ancestorKeys: true, label: 'name', - labelFun: function(key, attr, v) { return attr + ':' + key; }, - level: '_level' + labelFun(key, attr, _v) { + return `${attr}:${key}`; + }, + level: '_level', }); -}; +} // https://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/ -var type_of = obj => ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase(); -var object_to_keyed_array = obj => Object.entries(obj).map(([key,value]) => ({key, ...value})); +const type_of = obj => ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase(); +const object_to_keyed_array = obj => Object.entries(obj).map(([key, value]) => ({key, ...value})); -dc_graph.convert_adjacency_list = function(nodes, namesIn, namesOut) { - if(type_of(nodes) === 'object') { - var graph = namesIn.multipleGraphs ? Object.values(nodes)[0] : nodes; +export function convertAdjacencyList(nodes, namesIn, namesOut) { + if (type_of(nodes) === 'object') { + const graph = namesIn.multipleGraphs ? Object.values(nodes)[0] : nodes; nodes = object_to_keyed_array(graph); } const adjkey = namesIn.adjacencies || namesIn.revAdjacencies, - revadj = !namesIn.adjacencies; - if(!adjkey) + revadj = !namesIn.adjacencies; + if (!adjkey) throw new Error('must specify namesIn.adjacencies or namesIn.revAdjacencies'); - var edges = Array.prototype.concat.apply([], nodes.map(function(n) { - return n[adjkey].map(function(adj) { - var e = {}; - if(namesOut.edgeKey) - e[namesOut.edgeKey] = uuid(); - e[namesOut.edgeSource] = n[namesIn.nodeKey]; - e[namesOut.edgeTarget] = (namesIn.targetKey ? adj[namesIn.targetKey] : adj).toString(); - if(revadj) - [e[namesOut.edgeSource], e[namesOut.edgeTarget]] = [e[namesOut.edgeTarget], e[namesOut.edgeSource]]; - if(namesOut.adjacency) - e[namesOut.adjacency] = adj; - return e; - }); - })); + const edges = Array.prototype.concat.apply( + [], + nodes.map(n => + n[adjkey].map(adj => { + const e = {}; + if (namesOut.edgeKey) + e[namesOut.edgeKey] = uuid(); + e[namesOut.edgeSource] = n[namesIn.nodeKey]; + e[namesOut.edgeTarget] = (namesIn.targetKey ? adj[namesIn.targetKey] : adj) + .toString(); + if (revadj) + [e[namesOut.edgeSource], e[namesOut.edgeTarget]] = [ + e[namesOut.edgeTarget], + e[namesOut.edgeSource], + ]; + if (namesOut.adjacency) + e[namesOut.adjacency] = adj; + return e; + }) + ), + ); return { nodes, edges, nodekeyattr: namesIn.nodeKey, sourceattr: namesOut.edgeSource, - targetattr: namesOut.edgeTarget + targetattr: namesOut.edgeTarget, }; -}; - +} diff --git a/src/core.js b/src/core.js index a1ec1425..5e96e80b 100644 --- a/src/core.js +++ b/src/core.js @@ -1,74 +1,59 @@ /** - * The entire dc.graph.js library is scoped under the **dc_graph** name space. It does not introduce - * anything else into the global name space. - * - * Like in dc.js and most libraries built on d3, most `dc_graph` functions are designed to allow function chaining, meaning they return the current diagram - * instance whenever it is appropriate. The getter forms of functions do not participate in function - * chaining because they return values that are not the diagram. - * @namespace dc_graph - * @version <%= conf.pkg.version %> - * @example - * // Example chaining - * diagram.width(600) - * .height(400) - * .nodeDimension(nodeDim) - * .nodeGroup(nodeGroup); + * Core utilities and functions for dc.graph.js + * @module core */ -var dc_graph = { - version: '<%= conf.pkg.version %>', - constants: { - CHART_CLASS: 'dc-graph' - } +import { version } from '../package.json'; +export { version }; +export const constants = { + CHART_CLASS: 'dc-graph', }; -function get_original(x) { +export function getOriginal(x) { return x.orig; } -function identity(x) { +export function identity(x) { return x; -}; +} -var property = function (defaultValue, unwrap) { - if(unwrap === undefined) - unwrap = get_original; - else if(unwrap === false) +export const property = function(defaultValue, unwrap) { + if (unwrap === undefined) + unwrap = getOriginal; + else if (unwrap === false) unwrap = identity; - var value = defaultValue, react = null; - var cascade = []; - var ret = function (_) { + let value = defaultValue, react = null; + const cascade = []; + const ret = function(_) { if (!arguments.length) { return value; } - if(react) + if (react) react(_); value = _; return this; }; - ret.cascade = function (n, f) { - for(var i = 0; i n) { - cascade.splice(i, 0, {n: n, f: f}); + } else if (cascade[i].n > n) { + cascade.splice(i, 0, {n, f}); return ret; } } - cascade.push({n: n, f: f}); + cascade.push({n, f}); return ret; }; ret._eval = function(o, n) { - if(n===0 || !cascade.length) - return dc_graph.functor_wrap(ret(), unwrap)(o); + if (n === 0 || !cascade.length) + return functorWrap(ret(), unwrap)(o); else { - var last = cascade[n-1]; - return last.f(o, function() { - return ret._eval(o, n-1); - }); + const last = cascade[n-1]; + return last.f(o, () => ret._eval(o, n-1)); } }; ret.eval = function(o) { @@ -84,14 +69,14 @@ var property = function (defaultValue, unwrap) { return ret; }; -function named_children() { - var _children = {}; - var f = function(id, object) { - if(arguments.length === 1) +export function namedChildren() { + const _children = {}; + const f = function(id, object) { + if (arguments.length === 1) return _children[id]; - if(f.reject) { - var reject = f.reject(id, object); - if(reject) { + if (f.reject) { + const reject = f.reject(id, object); + if (reject) { console.groupCollapsed(reject); console.trace(); console.groupEnd(); @@ -99,12 +84,12 @@ function named_children() { } } // do not notify unnecessarily - if(_children[id] === object) + if (_children[id] === object) return this; - if(_children[id]) + if (_children[id]) _children[id].parent(null); _children[id] = object; - if(object) + if (object) object.parent(this); return this; }; @@ -112,212 +97,226 @@ function named_children() { return Object.keys(_children); }; f.nameOf = function(o) { - var found = Object.entries(_children).find(function(kv) { - return kv[1] == o; - }); + const found = Object.entries(_children).find(kv => kv[1] == o); return found ? found[0] : null; }; return f; } -function deprecated_property(message, defaultValue) { - var prop = property(defaultValue); - var ret = function() { - if(arguments.length) { +export function deprecatedProperty(message, defaultValue) { + const prop = property(defaultValue); + const ret = function() { + if (arguments.length) { console.warn(message); prop.apply(property, arguments); return this; } return prop(); }; - ['cascade', '_eval', 'eval', 'react'].forEach(function(method) { + ['cascade', '_eval', 'eval', 'react'].forEach(method => { ret[method] = prop[method]; }); return ret; } -function onetime_trace(level, message) { - var said = false; +export function onetimeTrace(level, message) { + let said = false; return function() { - if(said) + if (said) return; - if(level === 'trace') { + if (level === 'trace') { // todo: implement levels? // console.groupCollapsed(message); // console.trace(); // console.groupEnd(); - } - else + } else console[level](message); said = true; }; } -function deprecation_warning(message) { - return onetime_trace('warn', message); +export function deprecationWarning(message) { + return onetimeTrace('warn', message); } -function trace_function(level, message, f) { - var dep = onetime_trace(level, message); +export function traceFunction(level, message, f) { + const dep = onetimeTrace(level, message); return function() { dep(); return f.apply(this, arguments); }; } -function deprecate_function(message, f) { - return trace_function('warn', message, f); + +export function deprecateFunction(message, f) { + return traceFunction('warn', message, f); } // http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript -function uuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); +export function uuid() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { + const r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); return v.toString(16); }); } -function is_ie() { - var ua = window.navigator.userAgent; +export function isIe() { + const ua = window.navigator.userAgent; - return(ua.indexOf('MSIE ') > 0 || - ua.indexOf('Trident/') > 0 || - ua.indexOf('Edge/') > 0); + return (ua.indexOf('MSIE ') > 0 + || ua.indexOf('Trident/') > 0 + || ua.indexOf('Edge/') > 0); } -function is_safari() { +export function isSafari() { return /^((?!chrome|android).)*safari/i.test(navigator.userAgent); } // polyfill Object.assign for IE // it's just too useful to do without if (typeof Object.assign != 'function') { - // Must be writable: true, enumerable: false, configurable: true - Object.defineProperty(Object, "assign", { - value: function assign(target, varArgs) { // .length of function is 2 - 'use strict'; - if (target == null) { // TypeError if undefined or null - throw new TypeError('Cannot convert undefined or null to object'); - } + // Must be writable: true, enumerable: false, configurable: true + Object.defineProperty(Object, 'assign', { + value: function assign(target, _varArgs) { // .length of function is 2 + 'use strict'; + if (target == null) { // TypeError if undefined or null + throw new TypeError('Cannot convert undefined or null to object'); + } - var to = Object(target); + const to = Object(target); - for (var index = 1; index < arguments.length; index++) { - var nextSource = arguments[index]; + for (let index = 1; index < arguments.length; index++) { + const nextSource = arguments[index]; - if (nextSource != null) { // Skip over if undefined or null - for (var nextKey in nextSource) { - // Avoid bugs when hasOwnProperty is shadowed - if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { - to[nextKey] = nextSource[nextKey]; + if (nextSource != null) { // Skip over if undefined or null + for (const nextKey in nextSource) { + // Avoid bugs when hasOwnProperty is shadowed + if (Object.hasOwn(nextSource, nextKey)) { + to[nextKey] = nextSource[nextKey]; + } + } + } } - } - } - } - return to; - }, - writable: true, - configurable: true - }); + return to; + }, + writable: true, + configurable: true, + }); } - // https://tc39.github.io/ecma262/#sec-array.prototype.includes if (!Array.prototype.includes) { - Object.defineProperty(Array.prototype, 'includes', { - value: function(valueToFind, fromIndex) { - - if (this == null) { - throw new TypeError('"this" is null or not defined'); - } - - // 1. Let O be ? ToObject(this value). - var o = Object(this); - - // 2. Let len be ? ToLength(? Get(O, "length")). - var len = o.length >>> 0; - - // 3. If len is 0, return false. - if (len === 0) { - return false; - } - - // 4. Let n be ? ToInteger(fromIndex). - // (If fromIndex is undefined, this step produces the value 0.) - var n = fromIndex | 0; - - // 5. If n >= 0, then - // a. Let k be n. - // 6. Else n < 0, - // a. Let k be len + n. - // b. If k < 0, let k be 0. - var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); - - function sameValueZero(x, y) { - return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y)); - } - - // 7. Repeat, while k < len - while (k < len) { - // a. Let elementK be the result of ? Get(O, ! ToString(k)). - // b. If SameValueZero(valueToFind, elementK) is true, return true. - if (sameValueZero(o[k], valueToFind)) { - return true; - } - // c. Increase k by 1. - k++; - } + Object.defineProperty(Array.prototype, 'includes', { + value(valueToFind, fromIndex) { + if (this == null) { + throw new TypeError('"this" is null or not defined'); + } - // 8. Return false - return false; - } - }); + // 1. Let O be ? ToObject(this value). + const o = Object(this); + + // 2. Let len be ? ToLength(? Get(O, "length")). + const len = o.length>>>0; + + // 3. If len is 0, return false. + if (len === 0) { + return false; + } + + // 4. Let n be ? ToInteger(fromIndex). + // (If fromIndex is undefined, this step produces the value 0.) + const n = fromIndex|0; + + // 5. If n >= 0, then + // a. Let k be n. + // 6. Else n < 0, + // a. Let k be len + n. + // b. If k < 0, let k be 0. + let k = Math.max(n >= 0 ? n : len-Math.abs(n), 0); + + function sameValueZero(x, y) { + return x === y + || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y)); + } + + // 7. Repeat, while k < len + while (k < len) { + // a. Let elementK be the result of ? Get(O, ! ToString(k)). + // b. If SameValueZero(valueToFind, elementK) is true, return true. + if (sameValueZero(o[k], valueToFind)) { + return true; + } + // c. Increase k by 1. + k++; + } + + // 8. Return false + return false; + }, + }); } if (!Object.entries) { - Object.entries = function( obj ){ - var ownProps = Object.keys( obj ), - i = ownProps.length, - resArray = new Array(i); // preallocate the Array - while (i--) - resArray[i] = [ownProps[i], obj[ownProps[i]]]; - return resArray; - }; + Object.entries = function(obj) { + const ownProps = Object.keys(obj); + let i = ownProps.length; + const resArray = new Array(i); // preallocate the Array + while (i--) + resArray[i] = [ownProps[i], obj[ownProps[i]]]; + return resArray; + }; } // https://github.com/KhaledElAnsari/Object.values Object.values = Object.values ? Object.values : function(obj) { - var allowedTypes = ["[object String]", "[object Object]", "[object Array]", "[object Function]"]; - var objType = Object.prototype.toString.call(obj); - - if(obj === null || typeof obj === "undefined") { - throw new TypeError("Cannot convert undefined or null to object"); - } else if(!~allowedTypes.indexOf(objType)) { - return []; + const allowedTypes = [ + '[object String]', + '[object Object]', + '[object Array]', + '[object Function]', + ]; + const objType = Object.prototype.toString.call(obj); + + if (obj === null || typeof obj === 'undefined') { + throw new TypeError('Cannot convert undefined or null to object'); + } else if (!~allowedTypes.indexOf(objType)) { + return []; } else { - // if ES6 is supported - if (Object.keys) { - return Object.keys(obj).map(function (key) { - return obj[key]; - }); - } - - var result = []; - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - result.push(obj[prop]); - } - } - - return result; + // if ES6 is supported + if (Object.keys) { + return Object.keys(obj).map(key => obj[key]); + } + + const result = []; + for (const prop in obj) { + if (obj.hasOwnProperty(prop)) { + result.push(obj[prop]); + } + } + + return result; } }; -function getBBoxNoThrow(elem) { +export function getBBoxNoThrow(elem) { // firefox seems to have issues with some of my texts // just catch for now try { return elem.getBBox(); - } catch(xep) { - return {x: 0, y: 0, width:0, height: 0}; + } catch (_xep) { + return {x: 0, y: 0, width: 0, height: 0}; } } + +// version of d3.functor that optionally wraps the function with another +// one, if the parameter is a function +export function functorWrap(v, wrap) { + if (typeof v === 'function') { + return wrap + ? function(x) { + return v(wrap(x)); + } + : v; + } else return function() { + return v; + }; +} diff --git a/src/d3_force_layout.js b/src/d3_force_layout.js deleted file mode 100644 index 051c2f43..00000000 --- a/src/d3_force_layout.js +++ /dev/null @@ -1,276 +0,0 @@ -/** - * `dc_graph.d3_force_layout` is an adaptor for d3-force layouts in dc.graph.js - * @class d3_force_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.d3_force_layout} - **/ -dc_graph.d3_force_layout = function(id) { - var _layoutId = id || uuid(); - var _simulation = null; // d3-force simulation - var _dispatch = d3.dispatch('tick', 'start', 'end'); - // node and edge objects shared with d3-force, preserved from one iteration - // to the next (as long as the object is still in the layout) - var _nodes = {}, _edges = {}; - var _wnodes = [], _wedges = []; - var _options = null; - var _paths = null; - - function init(options) { - _options = options; - - _simulation = d3.layout.force() - .size([options.width, options.height]); - if(options.linkDistance) { - if(typeof options.linkDistance === 'number') - _simulation.linkDistance(options.linkDistance); - else if(options.linkDistance === 'auto') - _simulation.linkDistance(function(e) { - return e.dcg_edgeLength; - }); - } - - _simulation.on('tick', /* _tick = */ function() { - dispatchState('tick'); - }).on('start', function() { - _dispatch.start(); - }).on('end', /* _done = */ function() { - dispatchState('end'); - }); - } - - function dispatchState(event) { - _dispatch[event]( - _wnodes, - _wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }) - ); - } - - function data(nodes, edges, constraints) { - var nodeIDs = {}; - nodes.forEach(function(d, i) { - nodeIDs[d.dcg_nodeKey] = i; - }); - - _wnodes = regenerate_objects(_nodes, nodes, null, function(v) { - return v.dcg_nodeKey; - }, function(v1, v) { - v1.dcg_nodeKey = v.dcg_nodeKey; - v1.width = v.width; - v1.height = v.height; - v1.id = v.dcg_nodeKey; - if(v.dcg_nodeFixed) { - v1.fixed = true; - v1.x = v.dcg_nodeFixed.x; - v1.y = v.dcg_nodeFixed.y; - } else v1.fixed = false; - }); - - _wedges = regenerate_objects(_edges, edges, null, function(e) { - return e.dcg_edgeKey; - }, function(e1, e) { - e1.dcg_edgeKey = e.dcg_edgeKey; - // cola edges can work with indices or with object references - // but it will replace indices with object references - e1.source = _nodes[e.dcg_edgeSource]; - e1.source.id = nodeIDs[e1.source.dcg_nodeKey]; - e1.target = _nodes[e.dcg_edgeTarget]; - e1.target.id = nodeIDs[e1.target.dcg_nodeKey]; - e1.dcg_edgeLength = e.dcg_edgeLength; - }); - - _simulation.nodes(_wnodes); - _simulation.links(_wedges); - } - - function start() { - installForces(); - runSimulation(_options.iterations); - } - - function stop() { - if(_simulation) - _simulation.stop(); - } - - function savePositions() { - var data = {}; - Object.keys(_nodes).forEach(function(key) { - data[key] = {x: _nodes[key].x, y: _nodes[key].y}; - }); - return data; - } - - function restorePositions(data) { - Object.keys(data).forEach(function(key) { - if(_nodes[key]) { - _nodes[key].fixed = false; - _nodes[key].x = data[key].x; - _nodes[key].y = data[key].y; - } - }); - } - - function installForces() { - if(_paths === null) - _simulation.gravity(_options.gravityStrength) - .charge(_options.initialCharge); - else { - if(_options.fixOffPathNodes) { - var nodesOnPath = d3.set(); // nodes on path - _paths.forEach(function(path) { - path.forEach(function(nid) { - nodesOnPath.add(nid); - }); - }); - - // fix nodes not on paths - Object.keys(_nodes).forEach(function(key) { - if(!nodesOnPath.has(key)) { - _nodes[key].fixed = true; - } else { - _nodes[key].fixed = false; - } - }); - } - - // enlarge charge force to separate nodes on paths - _simulation.charge(_options.chargeForce); - } - }; - - function runSimulation(iterations) { - if(!iterations) { - dispatchState('end'); - return; - } - _simulation.start(); - for (var i = 0; i < 300; ++i) { - _simulation.tick(); - if(_paths) - applyPathAngleForces(); - } - _simulation.stop(); - } - - function applyPathAngleForces() { - function _dot(v1, v2) { return v1.x*v2.x + v1.y*v2.y; }; - function _len(v) { return Math.sqrt(v.x*v.x + v.y*v.y); }; - function _angle(v1, v2) { - var a = _dot(v1, v2) / (_len(v1)*_len(v2)); - a = Math.min(a, 1); - a = Math.max(a, -1); - return Math.acos(a); - }; - // perpendicular unit length vector - function _pVec(v) { - var xx = -v.y/v.x, yy = 1; - var length = _len({x: xx, y: yy}); - return {x: xx/length, y: yy/length}; - }; - - function updateNode(node, angle, pVec, alpha) { - node.x += pVec.x*(Math.PI-angle)*alpha; - node.y += pVec.y*(Math.PI-angle)*alpha; - } - - _paths.forEach(function(path) { - if(path.length < 3) return; // at least 3 nodes (and 2 edges): A->B->C - for(var i = 1; i < path.length-1; ++i) { - var current = _nodes[path[i]]; - var prev = _nodes[path[i-1]]; - var next = _nodes[path[i+1]]; - - // calculate the angle - var vPrev = {x: prev.x - current.x, y: prev.y - current.y}; - var vNext = {x: next.x - current.x, y: next.y - current.y}; - - var angle = _angle(vPrev, vNext); // angle in [0, PI] - - var pvecPrev = _pVec(vPrev); - var pvecNext = _pVec(vNext); - - // make sure the perpendicular vector is in the - // direction that makes the angle more towards 180 degree - // 1. calculate the middle point of node 'prev' and 'next' - var mid = {x: (prev.x+next.x)/2.0, y: (prev.y+next.y)/2.0}; - // 2. calculate the vectors: 'prev' pointing to 'mid', 'next' pointing to 'mid' - var prev_mid = {x: mid.x-prev.x, y: mid.y-prev.y}; - var next_mid = {x: mid.x-next.x, y: mid.y-next.y}; - // 3. the 'correct' vector: the angle between pvec and prev_mid(next_mid) should - // be an obtuse angle - pvecPrev = _angle(prev_mid, pvecPrev) >= Math.PI/2.0 ? pvecPrev : {x: -pvecPrev.x, y: -pvecPrev.y}; - pvecNext = _angle(next_mid, pvecNext) >= Math.PI/2.0 ? pvecNext : {x: -pvecNext.x, y: -pvecNext.y}; - - // modify positions of prev and next - updateNode(prev, angle, pvecPrev, _options.angleForce); - updateNode(next, angle, pvecNext, _options.angleForce); - } - - }); - } - - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); - - var engine = Object.assign(graphviz, { - layoutAlgorithm: function() { - return 'd3-force'; - }, - layoutId: function() { - return _layoutId; - }, - supportsWebworker: function() { - return true; - }, - supportsMoving: function() { - return true; - }, - parent: property(null), - on: function(event, f) { - if(arguments.length === 1) - return _dispatch.on(event); - _dispatch.on(event, f); - return this; - }, - init: function(options) { - this.optionNames().forEach(function(option) { - options[option] = options[option] || this[option](); - }.bind(this)); - init(options); - return this; - }, - data: function(graph, nodes, edges, constraints) { - data(nodes, edges, constraints); - }, - start: function() { - start(); - }, - stop: function() { - stop(); - }, - paths: function(paths) { - _paths = paths; - }, - savePositions: savePositions, - restorePositions: restorePositions, - optionNames: function() { - return ['iterations', 'angleForce', 'chargeForce', 'gravityStrength', - 'initialCharge', 'linkDistance', 'fixOffPathNodes'] - .concat(graphviz_keys); - }, - iterations: property(300), - angleForce: property(0.02), - chargeForce: property(-500), - gravityStrength: property(1.0), - initialCharge: property(-400), - linkDistance: property(20), - fixOffPathNodes: property(false), - populateLayoutNode: function() {}, - populateLayoutEdge: function() {} - }); - return engine; -}; - -dc_graph.d3_force_layout.scripts = ['d3.js']; diff --git a/src/d3v4_force_layout.js b/src/d3v4_force_layout.js index a966543d..7d91712e 100644 --- a/src/d3v4_force_layout.js +++ b/src/d3v4_force_layout.js @@ -1,65 +1,81 @@ /** - * `dc_graph.d3v4_force_layout` is an adaptor for d3-force version 4 layouts in dc.graph.js - * @class d3v4_force_layout - * @memberof dc_graph + * D3 v4 force layout adaptor for dc.graph.js + * @module d3v4_force_layout + */ + +// External dependencies +import { set } from 'd3-collection'; +import { dispatch } from 'd3-dispatch'; +import { + forceCenter, + forceCollide, + forceLink, + forceManyBody, + forceSimulation, + forceX, + forceY, +} from 'd3-force'; +import { forceStraightenPaths } from 'd3-force-straighten-paths'; +import { property, uuid } from './core.js'; +import { regenerateObjects } from './generate_objects.js'; +import { graphvizAttrs } from './graphviz_attrs.js'; + +/** + * `d3v4ForceLayout` is an adaptor for d3-force version 4 layouts in dc.graph.js * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.d3v4_force_layout} - **/ -dc_graph.d3v4_force_layout = function(id) { - var _layoutId = id || uuid(); - var _simulation = null; // d3-force simulation - var _dispatch = d3.dispatch('tick', 'start', 'end'); + * @return {Object} d3v4 force layout engine + */ +export function d3v4ForceLayout(id) { + const _layoutId = id || uuid(); + let _simulation = null; // d3-force simulation + const _dispatch = dispatch('tick', 'start', 'end'); // node and edge objects shared with d3-force, preserved from one iteration // to the next (as long as the object is still in the layout) - var _nodes = {}, _edges = {}; - var _wnodes = [], _wedges = []; - var _options = null; - var _paths = null; + const _nodes = {}, _edges = {}; + let _wnodes = [], _wedges = []; + let _options = null; + let _paths = null; function init(options) { _options = options; - _simulation = d3v4.forceSimulation() - .force('link', d3v4.forceLink()) - .force('center', d3v4.forceCenter(options.width / 2, options.height / 2)) - .force('gravityX', d3v4.forceX(options.width / 2).strength(_options.gravityStrength)) - .force('gravityY', d3v4.forceY(options.height / 2).strength(_options.gravityStrength)) - .force('collision', d3v4.forceCollide(_options.collisionRadius)) - .force('charge', d3v4.forceManyBody()) + _simulation = forceSimulation() + .force('link', forceLink()) + .force('center', forceCenter(options.width/2, options.height/2)) + .force('gravityX', forceX(options.width/2).strength(_options.gravityStrength)) + .force('gravityY', forceY(options.height/2).strength(_options.gravityStrength)) + .force('collision', forceCollide(_options.collisionRadius)) + .force('charge', forceManyBody()) .stop(); } function dispatchState(event) { - _dispatch[event]( + _dispatch.call( + event, + null, _wnodes, - _wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }) + (_wedges || []).map(e => ({dcg_edgeKey: e.dcg_edgeKey})), ); } function data(nodes, edges) { - var nodeIDs = {}; - nodes.forEach(function(d, i) { + const nodeIDs = {}; + nodes.forEach((d, i) => { nodeIDs[d.dcg_nodeKey] = i; }); - _wnodes = regenerate_objects(_nodes, nodes, null, function(v) { - return v.dcg_nodeKey; - }, function(v1, v) { + _wnodes = regenerateObjects(_nodes, nodes, null, v => v.dcg_nodeKey, (v1, v) => { v1.dcg_nodeKey = v.dcg_nodeKey; v1.width = v.width; v1.height = v.height; v1.id = v.dcg_nodeKey; - if(v.dcg_nodeFixed) { + if (v.dcg_nodeFixed) { v1.fx = v.dcg_nodeFixed.x; v1.fy = v.dcg_nodeFixed.y; } else v1.fx = v1.fy = null; }); - _wedges = regenerate_objects(_edges, edges, null, function(e) { - return e.dcg_edgeKey; - }, function(e1, e) { + _wedges = regenerateObjects(_edges, edges, null, e => e.dcg_edgeKey, (e1, e) => { e1.dcg_edgeKey = e.dcg_edgeKey; e1.source = nodeIDs[_nodes[e.dcg_edgeSource].dcg_nodeKey]; e1.target = nodeIDs[_nodes[e.dcg_edgeTarget].dcg_nodeKey]; @@ -72,7 +88,7 @@ dc_graph.d3v4_force_layout = function(id) { } function start() { - _dispatch.start(); + _dispatch.call('start'); installForces(_paths); runSimulation(_options.iterations); } @@ -82,41 +98,39 @@ dc_graph.d3v4_force_layout = function(id) { } function savePositions() { - var data = {}; - Object.keys(_nodes).forEach(function(key) { + const data = {}; + Object.keys(_nodes).forEach(key => { data[key] = {x: _nodes[key].x, y: _nodes[key].y}; }); return data; } function restorePositions(data) { - Object.keys(data).forEach(function(key) { - if(_nodes[key]) { + Object.keys(data).forEach(key => { + if (_nodes[key]) { _nodes[key].fx = data[key].x; _nodes[key].fy = data[key].y; } }); } function installForces(paths) { - if(paths) - paths = paths.filter(function(path) { - return path.nodes.every(function(nk) { return _nodes[nk]; }); - }); - if(paths === null || !paths.length) { + if (paths) + paths = paths.filter(path => path.nodes.every(nk => _nodes[nk])); + if (paths === null || !paths.length) { _simulation.force('charge').strength(_options.initialCharge); } else { - var nodesOnPath; - if(_options.fixOffPathNodes) { - nodesOnPath = d3.set(); - paths.forEach(function(path) { - path.nodes.forEach(function(nid) { + let nodesOnPath; + if (_options.fixOffPathNodes) { + nodesOnPath = set(); + paths.forEach(path => { + path.nodes.forEach(nid => { nodesOnPath.add(nid); }); }); } // fix nodes not on paths - Object.keys(_nodes).forEach(function(key) { - if(_options.fixOffPathNodes && !nodesOnPath.has(key)) { + Object.keys(_nodes).forEach(key => { + if (_options.fixOffPathNodes && !nodesOnPath.has(key)) { _nodes[key].fx = _nodes[key].x; _nodes[key].fy = _nodes[key].y; } else { @@ -126,70 +140,80 @@ dc_graph.d3v4_force_layout = function(id) { }); _simulation.force('charge').strength(_options.chargeForce); - _simulation.force('straighten', d3v4.forceStraightenPaths() - .id(function(n) { return n.dcg_nodeKey; }) - .angleForce(_options.angleForce) - .pathNodes(function(p) { return p.nodes; }) - .pathStrength(function(p) { return p.strength; }) - .paths(paths)); + _simulation.force( + 'straighten', + forceStraightenPaths() + .id(n => n.dcg_nodeKey) + .angleForce(_options.angleForce) + .pathNodes(p => p.nodes) + .pathStrength(p => p.strength) + .paths(paths), + ); } - }; + } function runSimulation(iterations) { _simulation.alpha(1); - for (var i = 0; i < iterations; ++i) { + for (let i = 0; i < iterations; ++i) { _simulation.tick(); dispatchState('tick'); } dispatchState('end'); } - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); + const graphviz = graphvizAttrs(), graphviz_keys = Object.keys(graphviz); - var engine = Object.assign(graphviz, { - layoutAlgorithm: function() { + const engine = Object.assign(graphviz, { + layoutAlgorithm() { return 'd3v4-force'; }, - layoutId: function() { + layoutId() { return _layoutId; }, - supportsWebworker: function() { + supportsWebworker() { return true; }, - supportsMoving: function() { + supportsMoving() { return true; }, parent: property(null), - on: function(event, f) { - if(arguments.length === 1) + on(event, f) { + if (arguments.length === 1) return _dispatch.on(event); _dispatch.on(event, f); return this; }, - init: function(options) { - this.optionNames().forEach(function(option) { + init(options) { + this.optionNames().forEach(option => { options[option] = options[option] || this[option](); - }.bind(this)); + }); init(options); return this; }, - data: function(graph, nodes, edges, constraints) { + data(graph, nodes, edges, constraints) { data(nodes, edges, constraints); }, - start: function() { + start() { start(); }, - stop: function() { + stop() { stop(); }, - paths: function(paths) { + paths(paths) { _paths = paths; }, - savePositions: savePositions, - restorePositions: restorePositions, - optionNames: function() { - return ['iterations', 'angleForce', 'chargeForce', 'gravityStrength', 'collisionRadius', - 'initialCharge', 'fixOffPathNodes'] + savePositions, + restorePositions, + optionNames() { + return [ + 'iterations', + 'angleForce', + 'chargeForce', + 'gravityStrength', + 'collisionRadius', + 'initialCharge', + 'fixOffPathNodes', + ] .concat(graphviz_keys); }, iterations: property(300), @@ -199,11 +223,12 @@ dc_graph.d3v4_force_layout = function(id) { collisionRadius: property(8), initialCharge: property(-100), fixOffPathNodes: property(false), - populateLayoutNode: function() {}, - populateLayoutEdge: function() {} + populateLayoutNode() {}, + populateLayoutEdge() {}, }); engine.pathStraightenForce = engine.angleForce; return engine; -}; +} -dc_graph.d3v4_force_layout.scripts = ['d3.js', 'd3v4-force.js']; +// Scripts needed for web worker +d3v4ForceLayout.scripts = ['d3.js', 'd3v4-force.js']; diff --git a/src/dagre_layout.js b/src/dagre_layout.js index 5dade323..fc614ab9 100644 --- a/src/dagre_layout.js +++ b/src/dagre_layout.js @@ -1,36 +1,48 @@ /** - * `dc_graph.dagre_layout` is an adaptor for dagre.js layouts in dc.graph.js + * Dagre.js layout adaptor for dc.graph.js + * @module dagre_layout + */ + +// External dependencies +import * as dagre from '@dagrejs/dagre'; +import { dispatch } from 'd3-dispatch'; +import { uuid } from './core.js'; +import { regenerateObjects } from './generate_objects.js'; +import { graphvizAttrs } from './graphviz_attrs.js'; + +/** + * `dagreLayout` is an adaptor for dagre.js layouts in dc.graph.js * - * In addition to the below layout attributes, `dagre_layout` also implements the attributes from - * {@link dc_graph.graphviz_attrs graphviz_attrs} - * @class dagre_layout - * @memberof dc_graph + * In addition to the below layout attributes, `dagreLayout` also implements the attributes from + * {@link graphvizAttrs graphviz_attrs} * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.dagre_layout} - **/ -dc_graph.dagre_layout = function(id) { - var _layoutId = id || uuid(); - var _dagreGraph = null, _tick, _done; - var _dispatch = d3.dispatch('tick', 'start', 'end'); + * @return {Object} dagre layout engine + */ +export function dagreLayout(id) { + const _layoutId = id || uuid(); + let _dagreGraph = null, _tick, _done; + const _dispatch = dispatch('tick', 'start', 'end'); // node and edge objects preserved from one iteration // to the next (as long as the object is still in the layout) - var _nodes = {}, _edges = {}; + const _nodes = {}, _edges = {}; function init(options) { // Create a new directed graph _dagreGraph = new dagre.graphlib.Graph({multigraph: true, compound: true}); // Set an object for the graph label - _dagreGraph.setGraph({rankdir: options.rankdir, nodesep: options.nodesep, ranksep: options.ranksep}); + _dagreGraph.setGraph({ + rankdir: options.rankdir, + nodesep: options.nodesep, + ranksep: options.ranksep, + }); // Default to assigning a new object as a label for each new edge. - _dagreGraph.setDefaultEdgeLabel(function() { return {}; }); + _dagreGraph.setDefaultEdgeLabel(() => ({})); } function data(nodes, edges, clusters) { - var wnodes = regenerate_objects(_nodes, nodes, null, function(v) { - return v.dcg_nodeKey; - }, function(v1, v) { + const wnodes = regenerateObjects(_nodes, nodes, null, v => v.dcg_nodeKey, (v1, v) => { v1.dcg_nodeKey = v.dcg_nodeKey; v1.width = v.width; v1.height = v.height; @@ -41,53 +53,49 @@ dc_graph.dagre_layout = function(id) { v1.y = v.dcg_nodeFixed.y; } */ - }, function(k, o) { + }, (k, o) => { _dagreGraph.setNode(k, o); - }, function(k) { + }, k => { _dagreGraph.removeNode(k); }); - var wedges = regenerate_objects(_edges, edges, null, function(e) { - return e.dcg_edgeKey; - }, function(e1, e) { + const wedges = regenerateObjects(_edges, edges, null, e => e.dcg_edgeKey, (e1, e) => { e1.dcg_edgeKey = e.dcg_edgeKey; e1.dcg_edgeSource = e.dcg_edgeSource; e1.dcg_edgeTarget = e.dcg_edgeTarget; - }, function(k, o, e) { + }, (k, o, e) => { _dagreGraph.setEdge(e.dcg_edgeSource, e.dcg_edgeTarget, o); - }, function(k, e) { + }, (k, e) => { _dagreGraph.removeEdge(e.dcg_edgeSource, e.dcg_edgeTarget, e.dcg_edgeKey); }); - clusters = clusters.filter(function(c) { - return /^cluster/.test(c.dcg_clusterKey); - }); - clusters.forEach(function(c) { + clusters = clusters.filter(c => /^cluster/.test(c.dcg_clusterKey)); + clusters.forEach(c => { _dagreGraph.setNode(c.dcg_clusterKey, c); }); - clusters.forEach(function(c) { - if(c.dcg_clusterParent) + clusters.forEach(c => { + if (c.dcg_clusterParent) _dagreGraph.setParent(c.dcg_clusterKey, c.dcg_clusterParent); }); - nodes.forEach(function(n) { - if(n.dcg_nodeParentCluster) + nodes.forEach(n => { + if (n.dcg_nodeParentCluster) _dagreGraph.setParent(n.dcg_nodeKey, n.dcg_nodeParentCluster); }); function dispatchState(event) { - _dispatch[event]( + _dispatch.call( + event, + null, wnodes, - wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }), - clusters.map(function(c) { - var c = Object.assign({}, _dagreGraph.node(c.dcg_clusterKey)); - c.bounds = { - left: c.x - c.width/2, - top: c.y - c.height/2, - right: c.x + c.width/2, - bottom: c.y + c.height/2 + wedges.map(e => ({dcg_edgeKey: e.dcg_edgeKey})), + clusters.map(c => { + const cluster = Object.assign({}, _dagreGraph.node(c.dcg_clusterKey)); + cluster.bounds = { + left: cluster.x-cluster.width/2, + top: cluster.y-cluster.height/2, + right: cluster.x+cluster.width/2, + bottom: cluster.y+cluster.height/2, }; - return c; - }) + return cluster; + }), ); } _tick = function() { @@ -98,8 +106,8 @@ dc_graph.dagre_layout = function(id) { }; } - function start(options) { - _dispatch.start(); + function start(_options) { + _dispatch.call('start'); dagre.layout(_dagreGraph); _done(); } @@ -107,45 +115,43 @@ dc_graph.dagre_layout = function(id) { function stop() { } - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); + const graphviz = graphvizAttrs(), graphviz_keys = Object.keys(graphviz); return Object.assign(graphviz, { - layoutAlgorithm: function() { + layoutAlgorithm() { return 'dagre'; }, - layoutId: function() { + layoutId() { return _layoutId; }, - supportsWebworker: function() { + supportsWebworker() { return true; }, - on: function(event, f) { - if(arguments.length === 1) + on(event, f) { + if (arguments.length === 1) return _dispatch.on(event); _dispatch.on(event, f); return this; }, - init: function(options) { - this.optionNames().forEach(function(option) { + init(options) { + this.optionNames().forEach(option => { options[option] = options[option] || this[option](); - }.bind(this)); + }); init(options); return this; }, - data: function(graph, nodes, edges, clusters) { + data(graph, nodes, edges, clusters) { data(nodes, edges, clusters); }, - start: function() { + start() { start(); }, - stop: function() { + stop() { stop(); }, - optionNames: function() { + optionNames() { return graphviz_keys; }, - populateLayoutNode: function() {}, - populateLayoutEdge: function() {} + populateLayoutNode() {}, + populateLayoutEdge() {}, }); -}; - -dc_graph.dagre_layout.scripts = ['d3.js', 'dagre.js']; +} diff --git a/src/delete_nodes.js b/src/delete_nodes.js index 5dfa7693..a4d37b2f 100644 --- a/src/delete_nodes.js +++ b/src/delete_nodes.js @@ -1,15 +1,24 @@ -dc_graph.delete_nodes = function(id_tag, options) { +import { deleteThings } from './delete_things.js'; +import { selectThingsGroup } from './select_things.js'; + +export function deleteNodes(id_tag, options) { options = options || {}; - var select_nodes_group = dc_graph.select_things_group(options.select_nodes_group || 'select-nodes-group', 'select-nodes'); - var select_edges_group = dc_graph.select_things_group(options.select_edges_group || 'select-edges-group', 'select-edges'); - var _mode = dc_graph.delete_things(select_nodes_group, 'delete-nodes', id_tag); + const select_nodes_group = selectThingsGroup( + options.select_nodes_group || 'select-nodes-group', + 'select-nodes', + ); + const select_edges_group = selectThingsGroup( + options.select_edges_group || 'select-edges-group', + 'select-edges', + ); + const _mode = deleteThings(select_nodes_group, 'delete-nodes', id_tag); - _mode.preDelete(function(nodes) { + _mode.preDelete(nodes => { // request a delete of all attached edges, using the delete edges mode // kind of horrible - var diagram = _mode.parent(); - var deleteEdgesMode = diagram.child('delete-edges'); - if(!deleteEdgesMode) + const diagram = _mode.parent(); + const deleteEdgesMode = diagram.child('delete-edges'); + if (!deleteEdgesMode) return null; // reject if we can't delete the edges // it is likely that the delete_edges mode is listening to the same keyup event we // are. introduce a pause to let it process the delete key now, deleting any selected edges. @@ -18,16 +27,14 @@ dc_graph.delete_nodes = function(id_tag, options) { // more evidence that modes need to be able to say "i got this", or that we should have // batch deletion. otoh, given the current behavior, delete_nodes deferring to delete_edges // makes about as much sense as anything - return Promise.resolve(undefined).then(function() { - var deleteEdges = diagram.edgeGroup().all().filter(function(e) { - return nodes.indexOf(diagram.edgeSource()(e)) !== -1 || - nodes.indexOf(diagram.edgeTarget()(e)) !== -1; - }).map(diagram.edgeKey()); - select_edges_group.set_changed(deleteEdges); - return deleteEdgesMode.deleteSelection().then(function() { - return nodes; - }); + return Promise.resolve(undefined).then(() => { + const deleteEdges = diagram.edgeGroup().all().filter(e => + nodes.indexOf(diagram.edgeSource()(e)) !== -1 + || nodes.indexOf(diagram.edgeTarget()(e)) !== -1 + ).map(diagram.edgeKey()); + select_edges_group.call('set_changed', null, deleteEdges); + return deleteEdgesMode.deleteSelection().then(() => nodes); }); }); return _mode; -}; +} diff --git a/src/delete_things.js b/src/delete_things.js index 2038e914..f880ea8e 100644 --- a/src/delete_things.js +++ b/src/delete_things.js @@ -1,7 +1,13 @@ -dc_graph.delete_things = function(things_group, mode_name, id_tag) { +import { event as d3Event } from 'd3-selection'; +import { property } from './core.js'; +import { keyboard } from './keyboard.js'; +import { mode } from './mode.js'; +import { is_a_mac } from './utils.js'; + +export function deleteThings(things_group, mode_name, id_tag) { id_tag = id_tag || 'id'; - var _deleteKey = is_a_mac ? 'Backspace' : 'Delete'; - var _keyboard, _selected = []; + const _deleteKey = is_a_mac ? 'Backspace' : 'Delete'; + let _keyboard, _selected = []; function selection_changed(selection) { _selected = selection; } @@ -9,29 +15,31 @@ dc_graph.delete_things = function(things_group, mode_name, id_tag) { return r[id_tag]; } function delete_selection(selection) { - if(!_mode.crossfilterAccessor()) + if (!_mode.crossfilterAccessor()) throw new Error('need crossfilterAccessor'); - if(!_mode.dimensionAccessor()) + if (!_mode.dimensionAccessor()) throw new Error('need dimensionAccessor'); selection = selection || _selected; - if(selection.length === 0) + if (selection.length === 0) return Promise.resolve([]); - var promise = _mode.preDelete() ? _mode.preDelete()(selection) : Promise.resolve(selection); - if(_mode.onDelete()) + let promise = _mode.preDelete() ? _mode.preDelete()(selection) : Promise.resolve(selection); + if (_mode.onDelete()) promise = promise.then(_mode.onDelete()); - return promise.then(function(selection) { - if(selection && selection.length) { - var crossfilter = _mode.crossfilterAccessor()(_mode.parent()), + return promise.then(selection => { + if (selection && selection.length) { + const crossfilter = _mode.crossfilterAccessor()(_mode.parent()), dimension = _mode.dimensionAccessor()(_mode.parent()); - var all = crossfilter.all().slice(), n = all.length; + const all = crossfilter.all().slice(), _n = all.length; dimension.filter(null); crossfilter.remove(); - var filtered = all.filter(function(r) { - return selection.indexOf(row_id(r)) === -1; - }); - if(all.length !== filtered.length + selection.length) - console.warn('size after deletion is not previous size minus selection size', - filtered.map(row_id), all.map(row_id), selection); + const filtered = all.filter(r => selection.indexOf(row_id(r)) === -1); + if (all.length !== filtered.length+selection.length) + console.warn( + 'size after deletion is not previous size minus selection size', + filtered.map(row_id), + all.map(row_id), + selection, + ); crossfilter.add(filtered); _mode.parent().redrawGroup(); @@ -39,25 +47,25 @@ dc_graph.delete_things = function(things_group, mode_name, id_tag) { return true; }); } - function draw(diagram) { - _keyboard.on('keyup.' + mode_name, function() { - if(d3.event.code === _deleteKey) + function draw(_diagram) { + _keyboard.on(`keyup.${mode_name}`, () => { + if (d3Event.code === _deleteKey) delete_selection(); }); } - function remove(diagram) { + function remove(_diagram) { } - var _mode = dc_graph.mode(mode_name, { - draw: draw, - remove: remove, - parent: function(p) { - things_group.on('set_changed.' + mode_name, selection_changed); - if(p) { + const _mode = mode(mode_name, { + draw, + remove, + parent(p) { + things_group.on(`set_changed.${mode_name}`, selection_changed); + if (p) { _keyboard = p.child('keyboard'); - if(!_keyboard) - p.child('keyboard', _keyboard = dc_graph.keyboard()); + if (!_keyboard) + p.child('keyboard', _keyboard = keyboard()); } - } + }, }); _mode.preDelete = property(null); _mode.onDelete = property(null); @@ -65,4 +73,4 @@ dc_graph.delete_things = function(things_group, mode_name, id_tag) { _mode.dimensionAccessor = property(null); _mode.deleteSelection = delete_selection; return _mode; -}; +} diff --git a/src/depth_first_traversal.js b/src/depth_first_traversal.js index 96ee1a24..7778add8 100644 --- a/src/depth_first_traversal.js +++ b/src/depth_first_traversal.js @@ -4,43 +4,48 @@ // this is an argument for providing a graph API which could make it // easy to just write a recursive function instead of using this -dc_graph.depth_first_traversal = function(callbacks) { // {[init, root, row, tree, place, sib, push, pop, skip,] finish, nodeid, sourceid, targetid} +/** + * Depth first traversal utility + * @module depth_first_traversal + */ + +export function depthFirstTraversal(callbacks) { // {[init, root, row, tree, place, sib, push, pop, skip,] finish, nodeid, sourceid, targetid} return function(nodes, edges) { callbacks.init && callbacks.init(); - if(callbacks.tree) - edges = edges.filter(function(e) { return callbacks.tree(e); }); - var indegree = {}; - var outmap = edges.reduce(function(m, e) { - var tail = callbacks.sourceid(e), + if (callbacks.tree) + edges = edges.filter(e => callbacks.tree(e)); + const indegree = {}; + const outmap = edges.reduce((m, e) => { + const tail = callbacks.sourceid(e), head = callbacks.targetid(e); - if(!m[tail]) m[tail] = []; + if (!m[tail]) m[tail] = []; m[tail].push(e); - indegree[head] = (indegree[head] || 0) + 1; + indegree[head] = (indegree[head] || 0)+1; return m; }, {}); - var nmap = nodes.reduce(function(m, n) { - var key = callbacks.nodeid(n); + const nmap = nodes.reduce((m, n) => { + const key = callbacks.nodeid(n); m[key] = n; return m; }, {}); - var rows = []; - var placed = {}; + const rows = []; + const placed = {}; function place_tree(n, r) { - var key = callbacks.nodeid(n); - if(placed[key]) { + const key = callbacks.nodeid(n); + if (placed[key]) { callbacks.skip && callbacks.skip(n, indegree[key]); return; } - if(!rows[r]) + if (!rows[r]) rows[r] = []; callbacks.place && callbacks.place(n, r, rows[r]); rows[r].push(n); placed[key] = true; - if(outmap[key]) - outmap[key].forEach(function(e, ei) { - var target = nmap[callbacks.targetid(e)]; - if(ei && callbacks.sib) + if (outmap[key]) + outmap[key].forEach((e, ei) => { + const target = nmap[callbacks.targetid(e)]; + if (ei && callbacks.sib) callbacks.sib(false, nmap[callbacks.targetid(outmap[key][ei-1])], target); callbacks.push && callbacks.push(); place_tree(target, r+1); @@ -48,61 +53,61 @@ dc_graph.depth_first_traversal = function(callbacks) { // {[init, root, row, tre callbacks.pop && callbacks.pop(n); } - var roots; - if(callbacks.root) - roots = nodes.filter(function(n) { return callbacks.root(n); }); + let roots; + if (callbacks.root) + roots = nodes.filter(n => callbacks.root(n)); else { - roots = nodes.filter(function(n) { return !indegree[callbacks.nodeid(n)]; }); - if(nodes.length && !roots.length) // all nodes are in a cycle + roots = nodes.filter(n => !indegree[callbacks.nodeid(n)]); + if (nodes.length && !roots.length) // all nodes are in a cycle roots = [nodes[0]]; } - roots.forEach(function(n, ni) { - if(ni && callbacks.sib) + roots.forEach((n, ni) => { + if (ni && callbacks.sib) callbacks.sib(true, roots[ni-1], n); callbacks.push && callbacks.push(); place_tree(n, callbacks.row && callbacks.row(n) || 0); }); callbacks.finish(rows); }; -}; +} // basically, see if it's any simpler if we start from scratch // (well, of course it's simpler because we have less callbacks) // same caveats as above -dc_graph.undirected_dfs = function(callbacks) { // {[comp, node], nodeid, sourceid, targetid} +export function undirectedDfs(callbacks) { // {[comp, node], nodeid, sourceid, targetid} return function(nodes, edges) { - var adjacencies = edges.reduce(function(m, e) { - var tail = callbacks.sourceid(e), + const adjacencies = edges.reduce((m, e) => { + const tail = callbacks.sourceid(e), head = callbacks.targetid(e); - if(!m[tail]) m[tail] = []; - if(!m[head]) m[head] = []; + if (!m[tail]) m[tail] = []; + if (!m[head]) m[head] = []; m[tail].push(head); m[head].push(tail); return m; }, {}); - var nmap = nodes.reduce(function(m, n) { - var key = callbacks.nodeid(n); + const nmap = nodes.reduce((m, n) => { + const key = callbacks.nodeid(n); m[key] = n; return m; }, {}); - var found = {}; + const found = {}; function recurse(n) { - var nid = callbacks.nodeid(n); + const nid = callbacks.nodeid(n); callbacks.node(compid, n); found[nid] = true; - if(adjacencies[nid]) - adjacencies[nid].forEach(function(adj) { - if(!found[adj]) + if (adjacencies[nid]) + adjacencies[nid].forEach(adj => { + if (!found[adj]) recurse(nmap[adj]); }); } - var compid = 0; - nodes.forEach(function(n) { - if(!found[callbacks.nodeid(n)]) { + let compid = 0; + nodes.forEach(n => { + if (!found[callbacks.nodeid(n)]) { callbacks.comp && callbacks.comp(compid); recurse(n); ++compid; } }); }; -}; +} diff --git a/src/diagram.js b/src/diagram.js index 3776a225..f4fd5732 100644 --- a/src/diagram.js +++ b/src/diagram.js @@ -1,69 +1,140 @@ /** - * `dc_graph.diagram` is a dc.js-compatible network visualization component. It registers in + * Main diagram component for dc.graph.js + * @module diagram + */ + +// External dependencies as ES6 modules +import { ascending, sum } from 'd3-array'; +import { set } from 'd3-collection'; +import { dispatch } from 'd3-dispatch'; +import { scaleLinear } from 'd3-scale'; +import { select } from 'd3-selection'; +// import { json } from 'd3-fetch'; // unused +import { zoomTransform } from 'd3-zoom'; +import { + BadArgumentException, + MarginMixin, + pluck, + redrawAll, + registerChart, + renderAll, + utils, +} from 'dc'; +// import * as crossfilter from 'crossfilter2'; // unused +import { + constants, + deprecatedProperty, + deprecateFunction, + getOriginal, + identity, + namedChildren, + onetimeTrace, + property, + traceFunction, +} from './core.js'; +import { regenerateObjects } from './generate_objects.js'; +import { textContents } from './node_contents.js'; +import { portName, projectPort, splitPortName } from './place_ports.js'; +import { + angleBetweenPoints, + defaultShape, + drawEdgeToShapes, + elaboratedRectangleShape, + ellipseShape, + noShape, + polygonShape, + roundedRectangleShape, +} from './shape.js'; +// import { spawnEngine } from './engine.js'; // unused +import { builtinArrows, clipPathToArrows, scaledArrowLengths } from './arrows.js'; +import { colaLayout } from './cola_layout.js'; +import { dagreLayout } from './dagre_layout.js'; +import { wheelEdges } from './generate.js'; +import { renderSvg } from './render_svg.js'; +import { cascade, param } from './utils.js'; +import { webworkerLayout } from './webworker_layout.js'; + +/** + * `diagram` is a dc.js-compatible network visualization component. It registers in * the dc.js chart registry and its nodes and edges are generated from crossfilter groups. It * logically derives from the dc.js * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin}, * but it does not physically derive from it since so much is different about network * visualization versus conventional charts. - * @class diagram - * @memberof dc_graph * @param {String|node} parent - Any valid * {@link https://github.com/mbostock/d3/wiki/Selections#selecting-elements d3 single selector} * specifying a dom block element such as a div; or a dom element. * @param {String} [chartGroup] - The name of the dc.js chart group this diagram instance * should be placed in. Filter interaction with a diagram will only trigger events and redraws * within the diagram's group. - * @return {dc_graph.diagram} - **/ -dc_graph.diagram = function (parent, chartGroup) { + * @return {Object} diagram instance + */ +export function diagram(parent, chartGroup) { // different enough from regular dc charts that we don't use dc.baseMixin // but attempt to implement most of that interface, copying some of the most basic stuff - var _diagram = dc.marginMixin({}); - _diagram.__dcFlag__ = dc.utils.uniqueId(); + const _diagram = new MarginMixin({}); + _diagram.__dcFlag__ = utils.uniqueId(); _diagram.margins({left: 10, top: 10, right: 10, bottom: 10}); - var _dispatch = d3.dispatch('preDraw', 'data', 'end', 'start', 'render', 'drawn', 'receivedLayout', 'transitionsStarted', 'zoomed', 'reset'); - var _nodes = {}, _edges = {}; // hold state between runs - var _ports = {}; // id = node|edge/id/name - var _clusters = {}; - var _nodePorts; // ports sorted by node id - var _stats = {}; - var _nodes_snapshot, _edges_snapshot; - var _arrows = {}; - var _running = false; // for detecting concurrency issues - var _anchor, _chartGroup; - var _animateZoom; - - var _minWidth = 200; - var _defaultWidthCalc = function (element) { - var width = element && element.getBoundingClientRect && element.getBoundingClientRect().width; + const _dispatch = dispatch( + 'preDraw', + 'data', + 'end', + 'start', + 'render', + 'drawn', + 'receivedLayout', + 'transitionsStarted', + 'zoomed', + 'reset', + ); + let _nodes = {}, _edges = {}; // hold state between runs + let _ports = {}; // id = node|edge/id/name + let _clusters = {}; + let _nodePorts; // ports sorted by node id + let _stats = {}; + let _nodes_snapshot, _edges_snapshot; + const _arrows = {}; + let _running = false; // for detecting concurrency issues + let _anchor, _chartGroup; + let _animateZoom; + + let _minWidth = 200; + const _defaultWidthCalc = function(element) { + const width = element && element.getBoundingClientRect + && element.getBoundingClientRect().width; return (width && width > _minWidth) ? width : _minWidth; }; - var _widthCalc = _defaultWidthCalc; + let _widthCalc = _defaultWidthCalc; - var _minHeight = 200; - var _defaultHeightCalc = function (element) { - var height = element && element.getBoundingClientRect && element.getBoundingClientRect().height; + let _minHeight = 200; + const _defaultHeightCalc = function(element) { + const height = element && element.getBoundingClientRect + && element.getBoundingClientRect().height; return (height && height > _minHeight) ? height : _minHeight; }; - var _heightCalc = _defaultHeightCalc; - var _width, _height, _lastWidth, _lastHeight; + let _heightCalc = _defaultHeightCalc; + let _width, _height, _lastWidth, _lastHeight; function deprecate_layout_algo_parameter(name) { return function(value) { - if(!_diagram.layoutEngine()) + if (!_diagram.layoutEngine()) _diagram.layoutAlgorithm('cola', true); - var engine = _diagram.layoutEngine(); - if(engine.getEngine) + let engine = _diagram.layoutEngine(); + if (engine.getEngine) engine = engine.getEngine(); - if(engine[name]) { - console.warn('property is deprecated, call on layout engine instead: dc_graph.diagram.%c' + name, - 'font-weight: bold'); - if(!arguments.length) + if (engine[name]) { + console.warn( + `property is deprecated, call on layout engine instead: dc_graph.diagram.%c${name}`, + 'font-weight: bold', + ); + if (!arguments.length) return engine[name](); engine[name](value); } else { - console.warn('property is deprecated, and is not supported for Warning: dc_graph.diagram.' + name + ' is deprecated, and it is not supported for the "' + engine.layoutAlgorithm() + '" layout algorithm: ignored.'); - if(!arguments.length) + console.warn( + `property is deprecated, and is not supported for Warning: dc_graph.diagram.${name} is deprecated, and it is not supported for the "${engine.layoutAlgorithm()}" layout algorithm: ignored.`, + ); + if (!arguments.length) return null; } return this; @@ -93,29 +164,30 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Number} [height=200] * @return {Number} * @return {dc_graph.diagram} - **/ - _diagram.height = function (height) { + */ + _diagram.height = function(height) { if (!arguments.length) { - if (!dc.utils.isNumber(_height)) { + if (!utils.isNumber(_height)) { _lastHeight = _heightCalc(_diagram.root().node()); - if(_height === 'auto') // 'auto' => calculate every time + if (_height === 'auto') // 'auto' => calculate every time return _lastHeight; // null/undefined => calculate once only _height = _lastHeight; } return _height; } - if(dc.utils.isNumber(height) || !height || height === 'auto') + if (utils.isNumber(height) || !height || height === 'auto') _height = height; - else if(typeof height === 'function') { + else if (typeof height === 'function') { _heightCalc = height; _height = undefined; - } - else throw new Error("don't know what to do with height type " + typeof height + " value " + height); + } else throw new Error( + `don't know what to do with height type ${typeof height} value ${height}`, + ); return _diagram; }; _diagram.minHeight = function(height) { - if(!arguments.length) + if (!arguments.length) return _minHeight; _minHeight = height; return _diagram; @@ -143,29 +215,30 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Number} [width=200] * @return {Number} * @return {dc_graph.diagram} - **/ - _diagram.width = function (width) { + */ + _diagram.width = function(width) { if (!arguments.length) { - if (!dc.utils.isNumber(_width)) { + if (!utils.isNumber(_width)) { _lastWidth = _widthCalc(_diagram.root().node()); - if(_width === 'auto') // 'auto' => calculate every time + if (_width === 'auto') // 'auto' => calculate every time return _lastWidth; // null/undefined => calculate once only _width = _lastWidth; } return _width; } - if(dc.utils.isNumber(width) || !width || width === 'auto') + if (utils.isNumber(width) || !width || width === 'auto') _width = width; - else if(typeof width === 'function') { + else if (typeof width === 'function') { _widthCalc = width; _width = undefined; - } - else throw new Error("don't know what to do with width type " + typeof width + " value " + width); + } else throw new Error( + `don't know what to do with width type ${typeof width} value ${width}`, + ); return _diagram; }; _diagram.minWidth = function(width) { - if(!arguments.length) + if (!arguments.length) return _minWidth; _minWidth = width; return _diagram; @@ -180,10 +253,10 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {node} [root=null] * @return {node} * @return {dc_graph.diagram} - **/ - _diagram.root = property(null).react(function(e) { - if(e.empty()) - console.log('Warning: parent selector ' + parent + " doesn't seem to exist"); + */ + _diagram.root = property(null).react(e => { + if (e.empty()) + console.log(`Warning: parent selector ${parent} doesn't seem to exist`); }); /** @@ -195,21 +268,21 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Boolean} [mouseZoomable=true] * @return {Boolean} * @return {dc_graph.diagram} - **/ + */ _diagram.mouseZoomable = property(true); _diagram.zoomExtent = property([.1, 2]); /** - * Whether zooming should only be enabled when the alt key is pressed. - * @method altKeyZoom + * What key or keys should be pressed to enabled zoom. + * @method modKeyZoom * @memberof dc_graph.diagram * @instance - * @param {Boolean} [altKeyZoom=true] - * @return {Boolean} + * @param {String|String[]} [modKeyZoom=true] + * @return {String|String[]} * @return {dc_graph.diagram} - **/ - _diagram.modKeyZoom = _diagram.altKeyZoom = property(false); + */ + _diagram.modKeyZoom = property('Alt'); /** * Set or get the fitting strategy for the canvas, which affects how the translate @@ -238,7 +311,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {String} [fitStrategy='default'] * @return {String} * @return {dc_graph.diagram} - **/ + */ _diagram.fitStrategy = property('default'); /** @@ -257,7 +330,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {String} [autoZoom=null] * @return {String} * @return {dc_graph.diagram} - **/ + */ _diagram.autoZoom = property(null); _diagram.zoomToFit = function(animate) { // if(!(_nodeLayer && _edgeLayer)) @@ -279,7 +352,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {crossfilter.dimension} [nodeDimension] * @return {crossfilter.dimension} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeDimension = property(); /** @@ -299,7 +372,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {crossfilter.group} [nodeGroup] * @return {crossfilter.group} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeGroup = property(); /** @@ -315,7 +388,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {crossfilter.dimension} [edgeDimension] * @return {crossfilter.dimension} * @return {dc_graph.diagram} - **/ + */ _diagram.edgeDimension = property(); /** @@ -333,7 +406,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {crossfilter.group} [edgeGroup] * @return {crossfilter.group} * @return {dc_graph.diagram} - **/ + */ _diagram.edgeGroup = property(); _diagram.edgesInFront = property(false); @@ -350,10 +423,8 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function} [nodeKey=function(kv) { return kv.key }] * @return {Function} * @return {dc_graph.diagram} - **/ - _diagram.nodeKey = _diagram.nodeKeyAccessor = property(function(kv) { - return kv.key; - }); + */ + _diagram.nodeKey = _diagram.nodeKeyAccessor = property(kv => kv.key); /** * Set or get the function which will be used to retrieve the unique key for each edge. By @@ -365,10 +436,8 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function} [edgeKey=function(kv) { return kv.key }] * @return {Function} * @return {dc_graph.diagram} - **/ - _diagram.edgeKey = _diagram.edgeKeyAccessor = property(function(kv) { - return kv.key; - }); + */ + _diagram.edgeKey = _diagram.edgeKeyAccessor = property(kv => kv.key); /** * Set or get the function which will be used to retrieve the source (origin/tail) key of @@ -382,10 +451,8 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function} [edgeSource=function(kv) { return kv.value.sourcename; }] * @return {Function} * @return {dc_graph.diagram} - **/ - _diagram.edgeSource = _diagram.sourceAccessor = property(function(kv) { - return kv.value.sourcename; - }); + */ + _diagram.edgeSource = _diagram.sourceAccessor = property(kv => kv.value.sourcename); /** * Set or get the function which will be used to retrieve the target (destination/head) key @@ -399,10 +466,8 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function} [edgeTarget=function(kv) { return kv.value.targetname; }] * @return {Function} * @return {dc_graph.diagram} - **/ - _diagram.edgeTarget = _diagram.targetAccessor = property(function(kv) { - return kv.value.targetname; - }); + */ + _diagram.edgeTarget = _diagram.targetAccessor = property(kv => kv.value.targetname); _diagram.portDimension = property(null); _diagram.portGroup = property(null); @@ -412,7 +477,7 @@ dc_graph.diagram = function (parent, chartGroup) { _diagram.portStyleName = property(null); _diagram.portElastic = property(true); - _diagram.portStyle = named_children(); + _diagram.portStyle = namedChildren(); _diagram.portBounds = property(null); // position limits, in radians @@ -432,7 +497,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {crossfilter.dimension} [clusterDimension] * @return {crossfilter.dimension} * @return {dc_graph.diagram} - **/ + */ _diagram.clusterDimension = property(null); /** @@ -449,7 +514,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {crossfilter.group} [clusterGroup] * @return {crossfilter.group} * @return {dc_graph.diagram} - **/ + */ _diagram.clusterGroup = property(null); // cluster accessors @@ -463,8 +528,8 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function} [clusterKey=function(kv) { return kv.key }] * @return {Function} * @return {dc_graph.diagram} - **/ - _diagram.clusterKey = property(dc.pluck('key')); + */ + _diagram.clusterKey = property(pluck('key')); /** * Set or get the function which will be used to retrieve the key of the parent of a cluster, @@ -476,7 +541,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function} [clusterParent=function(kv) { return kv.key }] * @return {Function} * @return {dc_graph.diagram} - **/ + */ _diagram.clusterParent = property(null); /** @@ -491,7 +556,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function} [clusterPadding=function(kv) { return kv.key }] * @return {Function} * @return {dc_graph.diagram} - **/ + */ _diagram.clusterPadding = property(8); // node accessor @@ -505,7 +570,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function} [nodeParentCluster=function(kv) { return kv.key }] * @return {Function} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeParentCluster = property(null); /** @@ -517,7 +582,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|Number} [nodeRadius=25] * @return {Function|Number} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeRadius = _diagram.nodeRadiusAccessor = property(25); /** @@ -530,7 +595,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|Number} [nodeStrokeWidth=1] * @return {Function|Number} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeStrokeWidth = _diagram.nodeStrokeWidthAccessor = property(1); /** @@ -542,7 +607,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|String} [nodeStroke='black'] * @return {Function|String} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeStroke = _diagram.nodeStrokeAccessor = property('black'); _diagram.nodeStrokeDashArray = property(null); @@ -557,7 +622,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|d3.scale} [nodeFillScale] * @return {Function|d3.scale} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeFillScale = property(null); /** @@ -569,7 +634,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|String} [nodeFill='white'] * @return {Function|String} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeFill = _diagram.nodeFillAccessor = property('white'); /** @@ -580,7 +645,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|Number} [nodeOpacity=1] * @return {Function|Number} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeOpacity = property(1); /** @@ -592,10 +657,9 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|Number} [nodePadding=6] * @return {Function|Number} * @return {dc_graph.diagram} - **/ + */ _diagram.nodePadding = property(6); - /** * Set or get the padding, in pixels, for a node's label. If an object, should contain fields * `x` and `y`. If a number, will be applied to both x and y. @@ -605,7 +669,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|Number|Object} [nodeLabelPadding=0] * @return {Function|Number} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeLabelPadding = property(0); /** @@ -616,7 +680,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|Number} [nodeLineHeight=1] * @return {Function|Number} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeLineHeight = property(1); /** @@ -633,10 +697,10 @@ dc_graph.diagram = function (parent, chartGroup) { * return kv.value.label || kv.value.name; * }); * @return {dc_graph.diagram} - **/ - _diagram.nodeLabel = _diagram.nodeLabelAccessor = property(function(kv) { - return kv.value.label || kv.value.name; - }); + */ + _diagram.nodeLabel = _diagram.nodeLabelAccessor = property(kv => + kv.value.label || kv.value.name + ); _diagram.nodeLabelAlignment = property('center'); _diagram.nodeLabelDecoration = property(null); @@ -649,7 +713,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|String} [nodeLabelFill=null] * @return {Function|String} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeLabelFill = _diagram.nodeLabelFillAccessor = property(null); /** @@ -660,7 +724,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|Boolean} [nodeFitLabel=true] * @return {Function|Boolean} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeFitLabel = _diagram.nodeFitLabelAccessor = property(true); /** @@ -683,23 +747,23 @@ dc_graph.diagram = function (parent, chartGroup) { * diagram.nodeShape(function(kv) { * return {shape: kv.value.flag ? 'diamond' : 'parallelogram'}; * }); - **/ - _diagram.nodeShape = property(default_shape); + */ + _diagram.nodeShape = property(defaultShape); // for defining custom (and standard) shapes - _diagram.shape = named_children(); + _diagram.shape = namedChildren(); - _diagram.shape('nothing', dc_graph.no_shape()); - _diagram.shape('ellipse', dc_graph.ellipse_shape()); - _diagram.shape('polygon', dc_graph.polygon_shape()); - _diagram.shape('rounded-rect', dc_graph.rounded_rectangle_shape()); - _diagram.shape('elaborated-rect', dc_graph.elaborated_rectangle_shape()); + _diagram.shape('nothing', noShape()); + _diagram.shape('ellipse', ellipseShape()); + _diagram.shape('polygon', polygonShape()); + _diagram.shape('rounded-rect', roundedRectangleShape()); + _diagram.shape('elaborated-rect', elaboratedRectangleShape()); _diagram.nodeOutlineClip = property(null); _diagram.nodeContent = property('text'); - _diagram.content = named_children(); - _diagram.content('text', dc_graph.text_contents()); + _diagram.content = namedChildren(); + _diagram.content('text', textContents()); // really looks like these should reside in an open namespace - this used only by an extension // but it's no less real than any other computed property @@ -719,10 +783,8 @@ dc_graph.diagram = function (parent, chartGroup) { * return _diagram.nodeKey()(kv); * }); * @return {dc_graph.diagram} - **/ - _diagram.nodeTitle = _diagram.nodeTitleAccessor = property(function(kv) { - return _diagram.nodeKey()(kv); - }); + */ + _diagram.nodeTitle = _diagram.nodeTitleAccessor = property(kv => _diagram.nodeKey()(kv)); /** * By default, nodes are added to the layout in the order that `.nodeGroup().all()` returns @@ -735,7 +797,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function} [nodeOrdering=null] * @return {Function} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeOrdering = property(null); /** @@ -748,10 +810,9 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|Object} [nodeFixed=null] * @return {Function|Object} * @return {dc_graph.diagram} - **/ + */ _diagram.nodeFixed = _diagram.nodeFixedAccessor = property(null); - /** * Set or get the function which will be used to retrieve the stroke color for the edges. * @method edgeStroke @@ -760,7 +821,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|String} [edgeStroke='black'] * @return {Function|String} * @return {dc_graph.diagram} - **/ + */ _diagram.edgeStroke = _diagram.edgeStrokeAccessor = property('black'); /** @@ -771,7 +832,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|Number} [edgeStrokeWidth=1] * @return {Function|Number} * @return {dc_graph.diagram} - **/ + */ _diagram.edgeStrokeWidth = _diagram.edgeStrokeWidthAccessor = property(1); _diagram.edgeStrokeDashArray = property(null); @@ -785,7 +846,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|Number} [edgeOpacity=1] * @return {Function|Number} * @return {dc_graph.diagram} - **/ + */ _diagram.edgeOpacity = _diagram.edgeOpacityAccessor = property(1); /** @@ -802,10 +863,8 @@ dc_graph.diagram = function (parent, chartGroup) { * }); * @return {Function|String} * @return {dc_graph.diagram} - **/ - _diagram.edgeLabel = _diagram.edgeLabelAccessor = property(function(e) { - return _diagram.edgeKey()(e); - }); + */ + _diagram.edgeLabel = _diagram.edgeLabelAccessor = property(e => _diagram.edgeKey()(e)); // vertical spacing when there are multiple lines of edge label _diagram.edgeLabelSpacing = property(12); @@ -819,7 +878,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|String} [edgeArrowhead='vee'] * @return {Function|String} * @return {dc_graph.diagram} - **/ + */ _diagram.edgeArrowhead = _diagram.edgeArrowheadAccessor = property('vee'); /** @@ -832,7 +891,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|String} [edgeArrowtail=null] * @return {Function|String} * @return {dc_graph.diagram} - **/ + */ _diagram.edgeArrowtail = _diagram.edgeArrowtailAccessor = property(null); /** @@ -843,7 +902,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|Number} [edgeArrowSize=1] * @return {Function|Number} * @return {dc_graph.diagram} - **/ + */ _diagram.edgeArrowSize = property(1); /** @@ -861,10 +920,8 @@ dc_graph.diagram = function (parent, chartGroup) { * }); * @return {Function|Boolean} * @return {dc_graph.diagram} - **/ - _diagram.edgeIsLayout = _diagram.edgeIsLayoutAccessor = property(function(kv) { - return !kv.value.notLayout; - }); + */ + _diagram.edgeIsLayout = _diagram.edgeIsLayoutAccessor = property(kv => !kv.value.notLayout); // if false, don't draw or layout the edge. this is not documented because it seems like // the interface could be better and this combined with edgeIsLayout. (currently there is @@ -888,7 +945,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|String} [lengthStrategy='symmetric'] * @return {Function|String} * @return {dc_graph.diagram} - **/ + */ _diagram.lengthStrategy = deprecate_layout_algo_parameter('lengthStrategy'); /** @@ -906,10 +963,8 @@ dc_graph.diagram = function (parent, chartGroup) { * }); * @return {Function|Number} * @return {dc_graph.diagram} - **/ - _diagram.edgeLength = _diagram.edgeDistanceAccessor = property(function(kv) { - return kv.value.distance; - }); + */ + _diagram.edgeLength = _diagram.edgeDistanceAccessor = property(kv => kv.value.distance); /** * This should be equivalent to rankdir and ranksep in the dagre/graphviz nomenclature, but for @@ -925,7 +980,7 @@ dc_graph.diagram = function (parent, chartGroup) { * diagram.flowLayout(null) * // flow in x with min separation 200 * diagram.flowLayout({axis: 'x', minSeparation: 200}) - **/ + */ _diagram.flowLayout = deprecate_layout_algo_parameter('flowLayout'); /** @@ -937,7 +992,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @memberof dc_graph.diagram * @instance * @param {String} [rankdir] - **/ + */ _diagram.rankdir = deprecate_layout_algo_parameter('rankdir'); /** @@ -952,7 +1007,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Number} [baseLength] * @return {Number} * @return {dc_graph.diagram} - **/ + */ _diagram.baseLength = deprecate_layout_algo_parameter('baseLength'); /** @@ -964,7 +1019,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Number} [transitionDuration=500] * @return {Number} * @return {dc_graph.diagram} - **/ + */ _diagram.transitionDuration = property(500); /** @@ -981,7 +1036,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {String} [stageTransitions='none'] * @return {String} * @return {dc_graph.diagram} - **/ + */ _diagram.stageTransitions = property('none'); /** @@ -994,7 +1049,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Number} [deleteDelay=0] * @return {Number} * @return {dc_graph.diagram} - **/ + */ _diagram.deleteDelay = property(0); /** @@ -1005,7 +1060,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {String} [groupConnected=false] * @return {String} * @return {dc_graph.diagram} - **/ + */ _diagram.groupConnected = deprecate_layout_algo_parameter('groupConnected'); /** @@ -1017,7 +1072,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function|Number} [timeLimit=0] * @return {Function|Number} * @return {dc_graph.diagram} - **/ + */ _diagram.timeLimit = property(0); /** @@ -1052,10 +1107,8 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function} [constrain] * @return {Function} * @return {dc_graph.diagram} - **/ - _diagram.constrain = property(function(nodes, edges) { - return []; - }); + */ + _diagram.constrain = property((_nodes, _edges) => []); /** * If there are multiple edges between the same two nodes, start them this many pixels away @@ -1066,7 +1119,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Number} [parallelEdgeOffset=10] * @return {Number} * @return {dc_graph.diagram} - **/ + */ _diagram.parallelEdgeOffset = property(10); /** @@ -1083,7 +1136,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function} [edgeOrdering=null] * @return {Function} * @return {dc_graph.diagram} - **/ + */ _diagram.edgeOrdering = property(null); _diagram.edgeSort = property(null); @@ -1103,7 +1156,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Boolean} [initLayoutOnRedraw=false] * @return {Boolean} * @return {dc_graph.diagram} - **/ + */ _diagram.initLayoutOnRedraw = property(false); /** @@ -1114,16 +1167,16 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Boolean} [layoutUnchanged=false] * @return {Boolean} * @return {dc_graph.diagram} - **/ + */ _diagram.layoutUnchanged = property(false); - _diagram.nodeChangeSelect = property(function() { - if(_diagram.layoutEngine().supportsMoving && _diagram.layoutEngine().supportsMoving()) + _diagram.nodeChangeSelect = property(() => { + if (_diagram.layoutEngine().supportsMoving && _diagram.layoutEngine().supportsMoving()) return topology_node; else return basic_node; }); - _diagram.edgeChangeSelect = property(function() { - if(_diagram.layoutEngine().supportsMoving && _diagram.layoutEngine().supportsMoving()) + _diagram.edgeChangeSelect = property(() => { + if (_diagram.layoutEngine().supportsMoving && _diagram.layoutEngine().supportsMoving()) return topology_edge; else return basic_edge; @@ -1137,7 +1190,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @memberof dc_graph.diagram * @instance * @return {dc_graph.diagram} - **/ + */ _diagram.relayout = function() { _nodes_snapshot = _edges_snapshot = null; return this; @@ -1158,10 +1211,16 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Function} [initialLayout=null] * @return {Function} * @return {dc_graph.diagram} - **/ - _diagram.initialLayout = deprecated_property('initialLayout is deprecated - use layout algorithms instead', null); + */ + _diagram.initialLayout = deprecatedProperty( + 'initialLayout is deprecated - use layout algorithms instead', + null, + ); - _diagram.initialOnly = deprecated_property('initialOnly is deprecated - see the initialLayout deprecation notice in the documentation', false); + _diagram.initialOnly = deprecatedProperty( + 'initialOnly is deprecated - see the initialLayout deprecation notice in the documentation', + false, + ); /** * By default, all nodes are included, and edges are only included if both end-nodes are @@ -1173,7 +1232,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Boolean} [induceNodes=false] * @return {Boolean} * @return {dc_graph.diagram} - **/ + */ _diagram.induceNodes = property(false); /** @@ -1186,7 +1245,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Boolean} [showLayoutSteps=false] * @return {Boolean} * @return {dc_graph.diagram} - **/ + */ _diagram.showLayoutSteps = property(false); /** @@ -1198,49 +1257,53 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Object} [legend=null] * @return {Object} * @return {dc_graph.diagram} - **/ + */ // (pre-deprecated; see below) /** * Specifies another kind of child layer or interface. For example, this can - * be used to display tooltips on nodes using `dc_graph.tip`. + * be used to display tooltips on nodes using `tip`. * The child needs to support a `parent` method, the diagram to modify. * @method child - * @memberof dc_graph.diagram + * @memberof diagram * @instance * @param {String} [id] - the name of the child to modify or add * @param {Object} [object] - the child object to add, or null to remove * @example * // Display tooltips on node hover, via the d3-tip library - * var tip = dc_graph.tip() - * tip.content(function(n, k) { + * import { tip } from 'dc-graph'; + * var myTip = tip() + * tip.content(function(n) { * // you can do an asynchronous call here, e.g. d3.json, if you need - * // to fetch data to show the tooltip - just call k() with the content - * k("This is " + n.orig.value.name + ""); + * // to fetch data to show the tooltip - just return a promise or the content directly + * return "This is " + n.orig.value.name + ""; * }); * diagram.child('tip', tip); * @return {dc_graph.diagram} **/ - _diagram.mode = _diagram.child = named_children(); + _diagram.mode = _diagram.child = namedChildren(); _diagram.mode.reject = function(id, object) { - var rtype = _diagram.renderer().rendererType(); - if(!object) + const rtype = _diagram.renderer().rendererType(); + if (!object) return false; // null is always a valid mode for any renderer - if(!object.supportsRenderer) - onetime_trace('trace', 'could not check if "' + id + '" is compatible with ' + rtype); - else if(!object.supportsRenderer(rtype)) - return 'not installing "' + id + '" because it is not compatible with renderer ' + rtype; + if (!object.supportsRenderer) + onetimeTrace('trace', `could not check if "${id}" is compatible with ${rtype}`); + else if (!object.supportsRenderer(rtype)) + return `not installing "${id}" because it is not compatible with renderer ${rtype}`; return false; }; - _diagram.legend = deprecate_function(".legend() is deprecated; use .child() for more control & multiple legends", function(_) { - if(!arguments.length) - return _diagram.child('node-legend'); - _diagram.child('node-legend', _); - return _diagram; - }); + _diagram.legend = deprecateFunction( + '.legend() is deprecated; use .child() for more control & multiple legends', + function(_) { + if (!arguments.length) + return _diagram.child('node-legend'); + _diagram.child('node-legend', _); + return _diagram; + }, + ); /** * Specify 'cola' (the default) or 'dagre' as the Layout Algorithm and it will replace the @@ -1256,22 +1319,24 @@ dc_graph.diagram = function (parent, chartGroup) { * // use dagre for layout * diagram.layoutAlgorithm('dagre'); * @return {dc_graph.diagram} - **/ + */ _diagram.layoutAlgorithm = function(value, skipWarning) { - if(!arguments.length) + if (!arguments.length) return _diagram.layoutEngine() ? _diagram.layoutEngine().layoutAlgorithm() : 'cola'; - if(!skipWarning) - console.warn('dc.graph.diagram.layoutAlgorithm is deprecated - pass the layout engine object to dc_graph.diagram.layoutEngine instead'); - - var engine; - switch(value) { - case 'cola': - engine = dc_graph.cola_layout(); - break; - case 'dagre': - engine = dc_graph.dagre_layout(); + if (!skipWarning) + console.warn( + 'dc.graph.diagram.layoutAlgorithm is deprecated - pass the layout engine object to dc_graph.diagram.layoutEngine instead', + ); + + let engine; + switch (value) { + case 'cola': + engine = colaLayout(); + break; + case 'dagre': + engine = dagreLayout(); } - engine = dc_graph.webworker_layout(engine); + engine = webworkerLayout(engine); _diagram.layoutEngine(engine); return this; }; @@ -1284,25 +1349,27 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Object} [engine=null] - the layout engine to use * @example * // use cola with no webworker - * diagram.layoutEngine(dc_graph.cola_layout()); + * import { colaLayout } from 'dc-graph'; + * diagram.layoutEngine(colaLayout()); * // use dagre with a webworker - * diagram.layoutEngine(dc_graph.webworker_layout(dc_graph.dagre_layout())); - **/ - _diagram.layoutEngine = property(null).react(function(val) { - if(val && val.parent) + * import { webworkerLayout, dagreLayout } from 'dc-graph'; + * diagram.layoutEngine(webworkerLayout(dagreLayout())); + */ + _diagram.layoutEngine = property(null).react(async val => { + if (val && val.parent) val.parent(_diagram); - if(_diagram.renderer().isRendered()) { + if (_diagram.renderer().isRendered()) { // remove any calculated points, if engine did that - Object.keys(_edges).forEach(function(k) { + Object.keys(_edges).forEach(k => { _edges[k].cola.points = null; }); // initialize engine - initLayout(val); + await initLayout(val); } }); - _diagram.renderer = property(dc_graph.render_svg().parent(_diagram)).react(function(r) { - if(_diagram.renderer()) + _diagram.renderer = property(renderSvg().parent(_diagram)).react(r => { + if (_diagram.renderer()) _diagram.renderer().parent(null); r.parent(_diagram); }); @@ -1312,20 +1379,19 @@ dc_graph.diagram = function (parent, chartGroup) { _diagram.tickSize = deprecate_layout_algo_parameter('tickSize'); - _diagram.uniqueId = function() { - return _diagram.anchorName().replace(/[ .#=\[\]"]/g, '-'); + return _diagram.anchorName().replace(/[ .#=[\]"]/g, '-'); }; _diagram.edgeId = function(e) { - return 'edge-' + _diagram.edgeKey.eval(e).replace(/[^\w-_]/g, '-'); + return `edge-${_diagram.edgeKey.eval(e).replace(/[^\w-_]/g, '-')}`; }; _diagram.arrowId = function(e, kind) { - return 'arrow-' + kind + '-' + _diagram.uniqueId() + '-' + _diagram.edgeId(e); + return `arrow-${kind}-${_diagram.uniqueId()}-${_diagram.edgeId(e)}`; }; _diagram.textpathId = function(e) { - return 'textpath-' + _diagram.uniqueId() + '-' + _diagram.edgeId(e); + return `textpath-${_diagram.uniqueId()}-${_diagram.edgeId(e)}`; }; // this kind of begs a (meta)graph ADT @@ -1348,7 +1414,7 @@ dc_graph.diagram = function (parent, chartGroup) { // again, awful, we need an ADT _diagram.getPort = function(nid, eid, name) { - return _ports[port_name(nid, eid, name)]; + return _ports[portName(nid, eid, name)]; }; _diagram.nodePorts = function() { @@ -1370,26 +1436,25 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {Boolean} [handleDisconnected=true] * @return {Boolean} * @return {dc_graph.diagram} - **/ + */ _diagram.handleDisconnected = deprecate_layout_algo_parameter('handleDisconnected'); - function initLayout(engine) { - if(!_diagram.layoutEngine()) + async function initLayout(engine) { + if (!_diagram.layoutEngine()) _diagram.layoutAlgorithm('cola', true); - (engine || _diagram.layoutEngine()).init({ + await (engine || _diagram.layoutEngine()).init({ width: _diagram.width(), - height: _diagram.height() + height: _diagram.height(), }); } _diagram.forEachChild = function(node, children, idf, f) { - children.enum().forEach(function(key) { - f(children(key), - node.filter(function(n) { return idf(n) === key; })); + children.enum().forEach(key => { + f(children(key), node.filter(n => idf(n) === key)); }); }; _diagram.forEachShape = function(node, f) { - _diagram.forEachChild(node, _diagram.shape, function(n) { return n.dcg_shape.shape; }, f); + _diagram.forEachChild(node, _diagram.shape, n => n.dcg_shape.shape, f); }; _diagram.forEachContent = function(node, f) { _diagram.forEachChild(node, _diagram.content, _diagram.nodeContent.eval, f); @@ -1401,16 +1466,16 @@ dc_graph.diagram = function (parent, chartGroup) { // three stages: delete before layout, and modify & insert split the transitionDuration _diagram.stagedDuration = function() { - return (_diagram.stageTransitions() !== 'none') ? - _diagram.transitionDuration() / 2 : - _diagram.transitionDuration(); + return (_diagram.stageTransitions() !== 'none') + ? _diagram.transitionDuration()/2 + : _diagram.transitionDuration(); }; _diagram.stagedDelay = function(is_enter) { - return _diagram.stageTransitions() === 'none' || - _diagram.stageTransitions() === 'modins' === !is_enter ? - 0 : - _diagram.transitionDuration() / 2; + return _diagram.stageTransitions() === 'none' + || _diagram.stageTransitions() === 'modins' === !is_enter + ? 0 + : _diagram.transitionDuration()/2; }; _diagram.isRunning = function() { @@ -1418,13 +1483,13 @@ dc_graph.diagram = function (parent, chartGroup) { }; function svg_specific(name) { - return trace_function('trace', name + '() is specific to the SVG renderer', function() { + return traceFunction('trace', `${name}() is specific to the SVG renderer`, function() { return _diagram.renderer()[name].apply(this, arguments); }); } function call_on_renderer(name) { - return trace_function('trace', 'calling ' + name + '() on renderer', function() { + return traceFunction('trace', `calling ${name}() on renderer`, function() { return _diagram.renderer()[name].apply(this, arguments); }); } @@ -1441,10 +1506,14 @@ dc_graph.diagram = function (parent, chartGroup) { _diagram.translate = svg_specific('translate'); _diagram.scale = svg_specific('scale'); - function renderer_specific(name) { - return trace_function('trace', name + '() will have renderer-specific arguments', function() { - return _diagram.renderer()[name].apply(this, arguments); - }); + function _renderer_specific(name) { + return traceFunction( + 'trace', + `${name}() will have renderer-specific arguments`, + function() { + return _diagram.renderer()[name].apply(this, arguments); + }, + ); } _diagram.renderNode = svg_specific('renderNode'); _diagram.renderEdge = svg_specific('renderEdge'); @@ -1452,7 +1521,6 @@ dc_graph.diagram = function (parent, chartGroup) { _diagram.redrawEdge = svg_specific('redrawEdge'); _diagram.reposition = call_on_renderer('reposition'); - /** * Standard dc.js * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin} @@ -1473,17 +1541,16 @@ dc_graph.diagram = function (parent, chartGroup) { * @memberof dc_graph.diagram * @instance * @return {dc_graph.diagram} - **/ - var _needsRedraw = false; - _diagram.redraw = function () { + */ + let _needsRedraw = false; + _diagram.redraw = async function() { // since dc.js can receive UI events and trigger redraws whenever it wants, // and cola absolutely will not tolerate being poked while it's doing layout, // we need to guard the startLayout call. - if(_running) { + if (_running) { _needsRedraw = true; return this; - } - else return _diagram.startLayout(); + } else return await _diagram.startLayout(); }; /** @@ -1495,12 +1562,12 @@ dc_graph.diagram = function (parent, chartGroup) { * @memberof dc_graph.diagram * @instance * @return {dc_graph.diagram} - **/ - _diagram.render = function() { - if(_diagram.renderer().isRendered()) - _dispatch.reset(); - if(!_diagram.initLayoutOnRedraw()) - initLayout(); + */ + _diagram.render = async function() { + if (_diagram.renderer().isRendered()) + _dispatch.call('reset'); + if (!_diagram.initLayoutOnRedraw()) + await initLayout(); _nodes = {}; _edges = {}; @@ -1508,14 +1575,18 @@ dc_graph.diagram = function (parent, chartGroup) { _clusters = {}; // start out with 1:1 zoom - _diagram.x(d3.scale.linear() - .domain([0, _diagram.width()]) - .range([0, _diagram.width()])); - _diagram.y(d3.scale.linear() - .domain([0, _diagram.height()]) - .range([0, _diagram.height()])); + _diagram.x( + scaleLinear() + .domain([0, _diagram.width()]) + .range([0, _diagram.width()]), + ); + _diagram.y( + scaleLinear() + .domain([0, _diagram.height()]) + .range([0, _diagram.height()]), + ); _diagram.renderer().initializeDrawing(); - _dispatch.render(); + _dispatch.call('render'); _diagram.redraw(); return this; }; @@ -1531,9 +1602,9 @@ dc_graph.diagram = function (parent, chartGroup) { }; function detect_size_change() { - var oldWidth = _lastWidth, oldHeight = _lastHeight; - var newWidth = _diagram.width(), newHeight = _diagram.height(); - if(oldWidth !== newWidth || oldHeight !== newHeight) + const oldWidth = _lastWidth, oldHeight = _lastHeight; + const newWidth = _diagram.width(), newHeight = _diagram.height(); + if (oldWidth !== newWidth || oldHeight !== newHeight) _diagram.renderer().rezoom(oldWidth, oldHeight, newWidth, newHeight); } @@ -1541,78 +1612,75 @@ dc_graph.diagram = function (parent, chartGroup) { // graph has changed wrt layout. imperfect heuristic: assume that the original // data as well as all cola fields starting with dcg_ are related to topology function dcg_fields(cola) { - var entries = Object.entries(cola) - .filter(function(entry) { return /^dcg_/.test(entry[0]); }); - return entries.reduce(function(p, entry) { + const entries = Object.entries(cola) + .filter(entry => /^dcg_/.test(entry[0])); + return entries.reduce((p, entry) => { p[entry[0]] = entry[1]; return p; }, {}); } function topology_node(n) { - return {orig: get_original(n), cola: dcg_fields(n.cola)}; + return {orig: getOriginal(n), cola: dcg_fields(n.cola)}; } function topology_edge(e) { - return {orig: get_original(e), cola: dcg_fields(e.cola)}; + return {orig: getOriginal(e), cola: dcg_fields(e.cola)}; } function basic_node(n) { - var n0 = get_original(n); + const n0 = getOriginal(n); return { orig: { key: n0.key, value: Object.fromEntries( Object.entries(n0.value) - .filter(function(kv) { return kv[0] !== 'fixedPos'; })) - } + .filter(kv => kv[0] !== 'fixedPos'), + ), + }, }; } function basic_edge(e) { - return {orig: get_original(e)}; + return {orig: getOriginal(e)}; } - _diagram.startLayout = function () { - var nodes = _diagram.nodeGroup().all(); - var edges = _diagram.edgeGroup().all(); - var ports = _diagram.portGroup() ? _diagram.portGroup().all() : []; - var clusters = _diagram.clusterGroup() ? _diagram.clusterGroup().all() : []; - if(_running) { - throw new Error('dc_graph.diagram.redraw already running!'); + _diagram.startLayout = async function() { + let nodes = _diagram.nodeGroup().all(); + let edges = _diagram.edgeGroup().all(); + let ports = _diagram.portGroup() ? _diagram.portGroup().all() : []; + const clusters = _diagram.clusterGroup() ? _diagram.clusterGroup().all() : []; + if (_running) { + throw new Error('diagram.redraw already running!'); } _running = true; - if(_diagram.width_is_automatic() || _diagram.height_is_automatic()) + if (_diagram.width_is_automatic() || _diagram.height_is_automatic()) detect_size_change(); else _diagram.renderer().resize(); - if(_diagram.initLayoutOnRedraw()) - initLayout(); + if (_diagram.initLayoutOnRedraw()) + await initLayout(); _diagram.layoutEngine().stop(); - _dispatch.preDraw(); + _dispatch.call('preDraw'); // ordering shouldn't matter, but we support ordering in case it does - if(_diagram.nodeOrdering()) { - nodes = nodes.slice(0).sort(function(a, b) { - return d3.ascending(_diagram.nodeOrdering()(a), _diagram.nodeOrdering()(b)); - }); + if (_diagram.nodeOrdering()) { + nodes = nodes.slice(0).sort((a, b) => + ascending(_diagram.nodeOrdering()(a), _diagram.nodeOrdering()(b)) + ); } - if(_diagram.edgeOrdering()) { - edges = edges.slice(0).sort(function(a, b) { - return d3.ascending(_diagram.edgeOrdering()(a), _diagram.edgeOrdering()(b)); - }); + if (_diagram.edgeOrdering()) { + edges = edges.slice(0).sort((a, b) => + ascending(_diagram.edgeOrdering()(a), _diagram.edgeOrdering()(b)) + ); } - var wnodes = regenerate_objects(_nodes, nodes, null, function(v) { - return _diagram.nodeKey()(v); - }, function(v1, v) { + let wnodes = regenerateObjects(_nodes, nodes, null, v => _diagram.nodeKey()(v), (v1, v) => { v1.orig = v; v1.cola = v1.cola || {}; v1.cola.dcg_nodeKey = _diagram.nodeKey.eval(v1); v1.cola.dcg_nodeParentCluster = _diagram.nodeParentCluster.eval(v1); _diagram.layoutEngine().populateLayoutNode(v1.cola, v1); }); - var wedges = regenerate_objects(_edges, edges, null, function(e) { - return _diagram.edgeKey()(e); - }, function(e1, e) { + let wedges = regenerateObjects(_edges, edges, null, e => _diagram.edgeKey()(e), (e1, e) => { e1.orig = e; e1.cola = e1.cola || {}; e1.cola.dcg_edgeKey = _diagram.edgeKey.eval(e1); @@ -1629,155 +1697,178 @@ dc_graph.diagram = function (parent, chartGroup) { wedges = wedges.filter(has_source_and_target); // remove self-edges (since we can't draw them - will be option later) - wedges = wedges.filter(function(e) { return e.source !== e.target; }); + wedges = wedges.filter(e => e.source !== e.target); wedges = wedges.filter(_diagram.edgeIsShown.eval); // now we know which ports should exist - var needports = wedges.map(function(e) { - if(_diagram.edgeSourcePortName.eval(e)) - return port_name(_diagram.edgeSource.eval(e), null, _diagram.edgeSourcePortName.eval(e)); - else return port_name(null, _diagram.edgeKey.eval(e), 'source'); + let needports = wedges.map(e => { + if (_diagram.edgeSourcePortName.eval(e)) + return portName( + _diagram.edgeSource.eval(e), + null, + _diagram.edgeSourcePortName.eval(e), + ); + else return portName(null, _diagram.edgeKey.eval(e), 'source'); }); - needports = needports.concat(wedges.map(function(e) { - if(_diagram.edgeTargetPortName.eval(e)) - return port_name(_diagram.edgeTarget.eval(e), null, _diagram.edgeTargetPortName.eval(e)); - else return port_name(null, _diagram.edgeKey.eval(e), 'target'); + needports = needports.concat(wedges.map(e => { + if (_diagram.edgeTargetPortName.eval(e)) + return portName( + _diagram.edgeTarget.eval(e), + null, + _diagram.edgeTargetPortName.eval(e), + ); + else return portName(null, _diagram.edgeKey.eval(e), 'target'); })); // remove any invalid ports so they don't crash in confusing ways later - ports = ports.filter(function(p) { - return _diagram.portNodeKey() && _diagram.portNodeKey()(p) || - _diagram.portEdgeKey() && _diagram.portEdgeKey()(p); - }); - var wports = regenerate_objects(_ports, ports, needports, function(p) { - return port_name(_diagram.portNodeKey() && _diagram.portNodeKey()(p), - _diagram.portEdgeKey() && _diagram.portEdgeKey()(p), - _diagram.portName()(p)); - }, function(p1, p) { - p1.orig = p; - if(p1.named) - p1.edges = []; - }, function(k, p) { - console.assert(k, 'should have screened out invalid ports'); - // it's dumb to parse the id we just created. as usual, i blame the lack of metagraphs - var parse = split_port_name(k); - if(parse.nodeKey) { - p.node = _nodes[parse.nodeKey]; - p.named = true; - } - else { - var e = _edges[parse.edgeKey]; - p.node = e[parse.name]; - p.edges = [e]; - p.named = false; - } - p.name = parse.name; - }); + ports = ports.filter(p => + _diagram.portNodeKey() && _diagram.portNodeKey()(p) + || _diagram.portEdgeKey() && _diagram.portEdgeKey()(p) + ); + let wports = regenerateObjects( + _ports, + ports, + needports, + p => portName( + _diagram.portNodeKey() && _diagram.portNodeKey()(p), + _diagram.portEdgeKey() && _diagram.portEdgeKey()(p), + _diagram.portName()(p), + ), + (p1, p) => { + p1.orig = p; + if (p1.named) + p1.edges = []; + }, + (k, p) => { + console.assert(k, 'should have screened out invalid ports'); + // it's dumb to parse the id we just created. as usual, i blame the lack of metagraphs + const parse = splitPortName(k); + if (parse.nodeKey) { + p.node = _nodes[parse.nodeKey]; + p.named = true; + } else { + const e = _edges[parse.edgeKey]; + p.node = e[parse.name]; + p.edges = [e]; + p.named = false; + } + p.name = parse.name; + }, + ); // remove any ports where the end-node was not found, to avoid crashing elsewhere - wports = wports.filter(function(p) { return p.node; }); + wports = wports.filter(p => p.node); // find all edges for named ports - wedges.forEach(function(e) { - var name = _diagram.edgeSourcePortName.eval(e); - if(name) - _ports[port_name(_diagram.nodeKey.eval(e.source), null, name)].edges.push(e); + wedges.forEach(e => { + let name = _diagram.edgeSourcePortName.eval(e); + if (name) + _ports[portName(_diagram.nodeKey.eval(e.source), null, name)].edges.push(e); name = _diagram.edgeTargetPortName.eval(e); - if(name) - _ports[port_name(_diagram.nodeKey.eval(e.target), null, name)].edges.push(e); + if (name) + _ports[portName(_diagram.nodeKey.eval(e.target), null, name)].edges.push(e); }); // optionally, delete nodes that have no edges - if(_diagram.induceNodes()) { - var keeps = {}; - wedges.forEach(function(e) { + if (_diagram.induceNodes()) { + const keeps = {}; + wedges.forEach(e => { keeps[e.cola.dcg_edgeSource] = true; keeps[e.cola.dcg_edgeTarget] = true; }); - wnodes = wnodes.filter(function(n) { return keeps[n.cola.dcg_nodeKey]; }); - for(var k in _nodes) - if(!keeps[k]) + wnodes = wnodes.filter(n => keeps[n.cola.dcg_nodeKey]); + for (const k in _nodes) + if (!keeps[k]) delete _nodes[k]; } - var needclusters = d3.set(wnodes.map(function(n) { - return _diagram.nodeParentCluster.eval(n); - }).filter(identity)).values(); - - var wclusters = regenerate_objects(_clusters, clusters, needclusters, function(c) { - return _diagram.clusterKey()(c); - }, function(c1, c) { // assign - c1.orig = c; - c1.cola = c1.cola || { - dcg_clusterKey: _diagram.clusterKey.eval(c1), - dcg_clusterParent: _diagram.clusterParent.eval(c1) - }; - }, function(k, c) { // create - }); + const needclusters = set( + wnodes.map(n => _diagram.nodeParentCluster.eval(n)).filter(identity), + ).values(); + + const wclusters = regenerateObjects( + _clusters, + clusters, + needclusters, + c => _diagram.clusterKey()(c), + (c1, c) => { // assign + c1.orig = c; + c1.cola = c1.cola || { + dcg_clusterKey: _diagram.clusterKey.eval(c1), + dcg_clusterParent: _diagram.clusterParent.eval(c1), + }; + }, + (_k, _c) => { // create + }, + ); - wnodes.forEach(function(v, i) { + wnodes.forEach((v, i) => { v.index = i; }); // announce new data - _dispatch.data(_diagram, _nodes, wnodes, _edges, wedges, _ports, wports); + _dispatch.call('data', null, _diagram, _nodes, wnodes, _edges, wedges, _ports, wports); _stats = {nnodes: wnodes.length, nedges: wedges.length}; // fixed nodes may have been affected by .data() so calculate now - wnodes.forEach(function(v) { - if(_diagram.nodeFixed()) + wnodes.forEach(v => { + if (_diagram.nodeFixed()) v.cola.dcg_nodeFixed = _diagram.nodeFixed.eval(v); }); // annotate parallel edges so we can draw them specially - if(_diagram.parallelEdgeOffset()) { - var em = new Array(wnodes.length); - for(var i = 0; i < wnodes.length; ++i) + if (_diagram.parallelEdgeOffset()) { + const em = new Array(wnodes.length); + for (let i = 0; i < wnodes.length; ++i) em[i] = new Array(i); - wedges.forEach(function(e) { + wedges.forEach(e => { e.pos = e.pos || {}; - var min, max, minattr, maxattr; - if(e.source.index < e.target.index) { - min = e.source.index; max = e.target.index; - minattr = 'edgeSourcePortName'; maxattr = 'edgeTargetPortName'; + let min, max, minattr, maxattr; + if (e.source.index < e.target.index) { + min = e.source.index; + max = e.target.index; + minattr = 'edgeSourcePortName'; + maxattr = 'edgeTargetPortName'; } else { - max = e.source.index; min = e.target.index; - maxattr = 'edgeSourcePortName'; minattr = 'edgeTargetPortName'; + max = e.source.index; + min = e.target.index; + maxattr = 'edgeSourcePortName'; + minattr = 'edgeTargetPortName'; } - var minport = _diagram[minattr].eval(e) || 'no port', + const minport = _diagram[minattr].eval(e) || 'no port', maxport = _diagram[maxattr].eval(e) || 'no port'; em[max][min] = em[max][min] || {}; em[max][min][maxport] = em[max][min][maxport] || {}; e.parallel = em[max][min][maxport][minport] = em[max][min][maxport][minport] || { rev: [], - edges: [] + edges: [], }; e.parallel.edges.push(e); e.parallel.rev.push(min !== e.source.index); }); } - var drawState = _diagram.renderer().startRedraw(_dispatch, wnodes, wedges); + const drawState = _diagram.renderer().startRedraw(_dispatch, wnodes, wedges); // really we should have layout chaining like in the good old Dynagraph days // the ordering of this and the previous 4 statements is somewhat questionable - if(_diagram.initialLayout()) + if (_diagram.initialLayout()) _diagram.initialLayout()(_diagram, wnodes, wedges); // no layout if the topology and layout parameters haven't changed - var skip_layout = false; - if(!_diagram.layoutUnchanged()) { - var node_fields = _diagram.nodeChangeSelect()(), + let skip_layout = false; + if (!_diagram.layoutUnchanged()) { + const node_fields = _diagram.nodeChangeSelect()(), edge_fields = _diagram.edgeChangeSelect()(); - var nodes_snapshot = JSON.stringify(wnodes.map(node_fields)); - var edges_snapshot = JSON.stringify(wedges.map(edge_fields)); - if(nodes_snapshot === _nodes_snapshot && edges_snapshot === _edges_snapshot) + const nodes_snapshot = JSON.stringify(wnodes.map(node_fields)); + const edges_snapshot = JSON.stringify(wedges.map(edge_fields)); + if (nodes_snapshot === _nodes_snapshot && edges_snapshot === _edges_snapshot) skip_layout = true; _nodes_snapshot = nodes_snapshot; _edges_snapshot = edges_snapshot; } // edge lengths may be affected by node sizes - wedges.forEach(function(e) { + wedges.forEach(e => { e.cola.dcg_edgeLength = _diagram.edgeLength.eval(e); }); @@ -1786,139 +1877,127 @@ dc_graph.diagram = function (parent, chartGroup) { // i am not satisfied with this constraint generation api... // https://github.com/dc-js/dc.graph.js/issues/10 - var constraints = _diagram.constrain()(_diagram, wnodes, wedges); + let constraints = _diagram.constrain()(_diagram, wnodes, wedges); // warn if there are any loops (before changing names to indices) // it would be better to do this in webcola // (for one thing, this duplicates logic in rectangle.ts) // but by that time it has lost the names of things, // so the output would be difficult to use - var constraints_by_left = constraints.reduce(function(p, c) { - if(c.type) { - switch(c.type) { - case 'alignment': - var left = c.offsets[0].node; - p[left] = p[left] || []; - c.offsets.slice(1).forEach(function(o) { - p[left].push({node: o.node, in_constraint: c}); - }); - break; + const constraints_by_left = constraints.reduce((p, c) => { + if (c.type) { + switch (c.type) { + case 'alignment': { + const left = c.offsets[0].node; + p[left] = p[left] || []; + c.offsets.slice(1).forEach(o => { + p[left].push({node: o.node, in_constraint: c}); + }); + break; + } } - } else if(c.axis) { + } else if (c.axis) { p[c.left] = p[c.left] || []; p[c.left].push({node: c.right, in_constraint: c}); } return p; }, {}); - var touched = {}; + const touched = {}; function find_constraint_loops(con, stack) { - var left = con.node; + const left = con.node; stack = stack || []; - var loop = stack.find(function(con) { return con.node === left; }); + const loop = stack.find(con => con.node === left); stack = stack.concat([con]); - if(loop) + if (loop) console.warn('found a loop in constraints', stack); - if(touched[left]) + if (touched[left]) return; touched[left] = true; - if(!constraints_by_left[left]) + if (!constraints_by_left[left]) return; - constraints_by_left[left].forEach(function(right) { + constraints_by_left[left].forEach(right => { find_constraint_loops(right, stack); }); } - Object.keys(constraints_by_left).forEach(function(left) { - if(!touched[left]) + Object.keys(constraints_by_left).forEach(left => { + if (!touched[left]) find_constraint_loops({node: left, in_constraint: null}); }); // translate references from names to indices (ugly) - var invalid_constraints = []; - constraints.forEach(function(c) { - if(c.type) { - switch(c.type) { - case 'alignment': - c.offsets.forEach(function(o) { - o.node = _nodes[o.node].index; - }); - break; - case 'circle': - c.nodes.forEach(function(n) { - n.node = _nodes[n.node].index; - }); - break; + const invalid_constraints = []; + constraints.forEach(c => { + if (c.type) { + switch (c.type) { + case 'alignment': + c.offsets.forEach(o => { + o.node = _nodes[o.node].index; + }); + break; + case 'circle': + c.nodes.forEach(n => { + n.node = _nodes[n.node].index; + }); + break; } - } else if(c.axis && c.left && c.right) { + } else if (c.axis && c.left && c.right) { c.left = _nodes[c.left].index; c.right = _nodes[c.right].index; - } - else invalid_constraints.push(c); + } else invalid_constraints.push(c); }); - if(invalid_constraints.length) - console.warn(invalid_constraints.length + ' invalid constraints', invalid_constraints); + if (invalid_constraints.length) + console.warn(`${invalid_constraints.length} invalid constraints`, invalid_constraints); // pseudo-cola.js features // 1. non-layout edges are drawn but not told to cola.js - var layout_edges = wedges.filter(_diagram.edgeIsLayout.eval); - var nonlayout_edges = wedges.filter(function(x) { - return !_diagram.edgeIsLayout.eval(x); - }); + let layout_edges = wedges.filter(_diagram.edgeIsLayout.eval); + const _nonlayout_edges = wedges.filter(x => !_diagram.edgeIsLayout.eval(x)); // 2. type=circle constraints - var circle_constraints = constraints.filter(function(c) { - return c.type === 'circle'; - }); - constraints = constraints.filter(function(c) { - return c.type !== 'circle'; - }); - circle_constraints.forEach(function(c) { - var R = (c.distance || _diagram.baseLength()*4) / (2*Math.sin(Math.PI/c.nodes.length)); - var nindices = c.nodes.map(function(x) { return x.node; }); - var namef = function(i) { + const circle_constraints = constraints.filter(c => c.type === 'circle'); + constraints = constraints.filter(c => c.type !== 'circle'); + circle_constraints.forEach(c => { + const R = (c.distance || _diagram.baseLength()*4)/(2*Math.sin(Math.PI/c.nodes.length)); + const nindices = c.nodes.map(x => x.node); + const namef = function(i) { return _diagram.nodeKey.eval(wnodes[i]); }; - var wheel = dc_graph.wheel_edges(namef, nindices, R) - .map(function(e) { - var e1 = {internal: e}; - e1.source = _nodes[e.sourcename]; - e1.target = _nodes[e.targetname]; - return e1; - }); + const wheel = wheelEdges(namef, nindices, R) + .map(e => { + const e1 = {internal: e}; + e1.source = _nodes[e.sourcename]; + e1.target = _nodes[e.targetname]; + return e1; + }); layout_edges = layout_edges.concat(wheel); }); // 3. ordered alignment - var ordered_constraints = constraints.filter(function(c) { - return c.type === 'ordering'; - }); - constraints = constraints.filter(function(c) { - return c.type !== 'ordering'; - }); - ordered_constraints.forEach(function(c) { - var sorted = c.nodes.map(function(n) { return _nodes[n]; }); - if(c.ordering) { - var orderingFn = param(c.ordering); - sorted = sorted.sort(function(a, b) { - return d3.ascending(orderingFn(a), orderingFn(b)); - }); + const ordered_constraints = constraints.filter(c => c.type === 'ordering'); + constraints = constraints.filter(c => c.type !== 'ordering'); + ordered_constraints.forEach(c => { + let sorted = c.nodes.map(n => _nodes[n]); + if (c.ordering) { + const orderingFn = param(c.ordering); + sorted = sorted.sort((a, b) => ascending(orderingFn(a), orderingFn(b))); } - var left; - sorted.forEach(function(n, i) { - if(i===0) + let left; + sorted.forEach((n, i) => { + if (i === 0) left = n; else { constraints.push({ left: left.index, right: (left = n).index, axis: c.axis, - gap: c.gap + gap: c.gap, }); } }); }); - if(skip_layout) { + if (skip_layout) { _running = false; // init_node_ports? _diagram.renderer().draw(drawState, true); @@ -1927,111 +2006,130 @@ dc_graph.diagram = function (parent, chartGroup) { check_zoom(drawState); return this; } - var startTime = Date.now(); + const startTime = Date.now(); function populate_cola(rnodes, redges, rclusters) { - rnodes.forEach(function(rn) { - var n = _nodes[rn.dcg_nodeKey]; - if(!n) { - console.warn('received node "' + rn.dcg_nodeKey + '" that we did not send, ignored'); + rnodes.forEach(rn => { + const n = _nodes[rn.dcg_nodeKey]; + if (!n) { + console.warn(`received node "${rn.dcg_nodeKey}" that we did not send, ignored`); return; } n.cola.x = rn.x; n.cola.y = rn.y; n.cola.z = rn.z; }); - redges.forEach(function(re) { - var e = _edges[re.dcg_edgeKey]; - if(!e) { - console.warn('received edge "' + re.dcg_edgeKey + '" that we did not send, ignored'); + (redges || []).forEach(re => { + const e = _edges[re.dcg_edgeKey]; + if (!e) { + console.warn(`received edge "${re.dcg_edgeKey}" that we did not send, ignored`); return; } - if(re.points) + if (re.points) e.cola.points = re.points; }); - wclusters.forEach(function(c) { + (wclusters || []).forEach(c => { c.cola.bounds = null; }); - if(rclusters) - rclusters.forEach(function(rc) { - var c = _clusters[rc.dcg_clusterKey]; - if(!c) { - console.warn('received cluster "' + rc.dcg_clusterKey + '" that we did not send, ignored'); + if (rclusters) + rclusters.forEach(rc => { + const c = _clusters[rc.dcg_clusterKey]; + if (!c) { + console.warn( + `received cluster "${rc.dcg_clusterKey}" that we did not send, ignored`, + ); return; } - if(rc.bounds) + if (rc.bounds) c.cola.bounds = rc.bounds; }); } _diagram.layoutEngine() - .on('tick.diagram', function(nodes, edges, clusters) { - var elapsed = Date.now() - startTime; - if(!_diagram.initialOnly()) + .on('tick.diagram', (nodes, edges, clusters) => { + const elapsed = Date.now()-startTime; + if (!_diagram.initialOnly()) populate_cola(nodes, edges, clusters); - if(_diagram.showLayoutSteps()) { + if (_diagram.showLayoutSteps()) { init_node_ports(_nodes, wports); - _dispatch.receivedLayout(_diagram, _nodes, wnodes, _edges, wedges, _ports, wports); + _dispatch.call( + 'receivedLayout', + null, + _diagram, + _nodes, + wnodes, + _edges, + wedges, + _ports, + wports, + ); propagate_port_positions(_nodes, wedges, _ports); _diagram.renderer().draw(drawState, true); _diagram.renderer().drawPorts(drawState); // should do this only once _diagram.renderer().fireTSEvent(_dispatch, drawState); } - if(_needsRedraw || _diagram.timeLimit() && elapsed > _diagram.timeLimit()) { + if (_needsRedraw || _diagram.timeLimit() && elapsed > _diagram.timeLimit()) { console.log('cancelled'); _diagram.layoutEngine().stop(); } }) - .on('end.diagram', function(nodes, edges, clusters) { - if(!_diagram.showLayoutSteps()) { - if(!_diagram.initialOnly()) + .on('end.diagram', (nodes, edges, clusters) => { + if (!_diagram.showLayoutSteps()) { + if (!_diagram.initialOnly()) populate_cola(nodes, edges, clusters); init_node_ports(_nodes, wports); - _dispatch.receivedLayout(_diagram, _nodes, wnodes, _edges, wedges, _ports, wports); + _dispatch.call( + 'receivedLayout', + null, + _diagram, + _nodes, + wnodes, + _edges, + wedges, + _ports, + wports, + ); propagate_port_positions(_nodes, wedges, _ports); _diagram.renderer().draw(drawState, true); _diagram.renderer().drawPorts(drawState); _diagram.renderer().fireTSEvent(_dispatch, drawState); - } - else _diagram.layoutDone(true); + } else _diagram.layoutDone(true); check_zoom(drawState); }) - .on('start.diagram', function() { - console.log('algo ' + _diagram.layoutEngine().layoutAlgorithm() + ' started.'); - _dispatch.start(); + .on('start.diagram', () => { + console.log(`algo ${_diagram.layoutEngine().layoutAlgorithm()} started.`); + _dispatch.call('start'); }); - if(_diagram.initialOnly()) + if (_diagram.initialOnly()) _diagram.layoutEngine().dispatch().end(wnodes, wedges); else { - _dispatch.start(); // cola doesn't seem to fire this itself? - var engine = _diagram.layoutEngine(); + _dispatch.call('start'); // cola doesn't seem to fire this itself? + const engine = _diagram.layoutEngine(); engine.data( - { width: _diagram.width(), height: _diagram.height() }, - wnodes.map(function(v) { - var lv = Object.assign({}, v.cola, v.dcg_shape); - if(engine.annotateNode) + {width: _diagram.width(), height: _diagram.height()}, + wnodes.map(v => { + const lv = Object.assign({}, v.dcg_shape, v.cola); + if (engine.annotateNode) engine.annotateNode(lv, v); - else if(engine.extractNodeAttrs) - Object.keys(engine.extractNodeAttrs()).forEach(function(key) { + else if (engine.extractNodeAttrs) + Object.keys(engine.extractNodeAttrs()).forEach(key => { lv[key] = engine.extractNodeAttrs()[key](v.orig); }); return lv; }), - layout_edges.map(function(e) { - var le = e.cola; - if(engine.annotateEdge) + layout_edges.map(e => { + const le = e.cola; + if (engine.annotateEdge) engine.annotateEdge(le, e); - else if(engine.extractEdgeAttrs) - Object.keys(engine.extractEdgeAttrs()).forEach(function(key) { + else if (engine.extractEdgeAttrs) + Object.keys(engine.extractEdgeAttrs()).forEach(key => { le[key] = engine.extractEdgeAttrs()[key](e.orig); }); return le; }), - wclusters.map(function(c) { - return c.cola; - }), - constraints + wclusters.map(c => c.cola), + constraints, ); engine.start(); } @@ -2039,63 +2137,65 @@ dc_graph.diagram = function (parent, chartGroup) { }; function check_zoom(drawState) { - var do_zoom, animate = true; - if(_diagram.width_is_automatic() || _diagram.height_is_automatic()) + let do_zoom, animate = true; + if (_diagram.width_is_automatic() || _diagram.height_is_automatic()) detect_size_change(); - switch(_diagram.autoZoom()) { - case 'always-skipanimonce': - animate = false; - _diagram.autoZoom('always'); - case 'always': - do_zoom = true; - break; - case 'once-noanim': - animate = false; - case 'once': - do_zoom = true; - _diagram.autoZoom(null); - break; - default: - do_zoom = false; + switch (_diagram.autoZoom()) { + case 'always-skipanimonce': + animate = false; + _diagram.autoZoom('always'); + // falls through + case 'always': + do_zoom = true; + break; + case 'once-noanim': + animate = false; + // falls through + case 'once': + do_zoom = true; + _diagram.autoZoom(null); + break; + default: + do_zoom = false; } calc_bounds(drawState); - if(do_zoom) + if (do_zoom) auto_zoom(animate); } function norm(v) { - var len = Math.hypot(v[0], v[1]); + const len = Math.hypot(v[0], v[1]); return [v[0]/len, v[1]/len]; } function edge_vec(n, e) { - var dy = e.target.cola.y - e.source.cola.y, - dx = e.target.cola.x - e.source.cola.x; - if(dy === 0 && dx === 0) + let dy = e.target.cola.y-e.source.cola.y, + dx = e.target.cola.x-e.source.cola.x; + if (dy === 0 && dx === 0) return [1, 0]; - if(e.source !== n) + if (e.source !== n) dy = -dy, dx = -dx; - if(e.parallel && e.parallel.edges.length > 1 && e.source.index > e.target.index) + if (e.parallel && e.parallel.edges.length > 1 && e.source.index > e.target.index) dy = -dy, dx = -dx; return norm([dx, dy]); } function init_node_ports(nodes, wports) { _nodePorts = {}; // assemble port-lists for nodes, again because we don't have a metagraph. - wports.forEach(function(p) { - var nid = _diagram.nodeKey.eval(p.node); - var np = _nodePorts[nid] = _nodePorts[nid] || []; + wports.forEach(p => { + const nid = _diagram.nodeKey.eval(p.node); + const np = _nodePorts[nid] = _nodePorts[nid] || []; np.push(p); }); - for(var nid in _nodePorts) { - var n = nodes[nid], + for (const nid in _nodePorts) { + const n = nodes[nid], nports = _nodePorts[nid]; // initial positions: use average of edge vectors, if any, or existing position - nports.forEach(function(p) { - if(_diagram.portElastic.eval(p) && p.edges.length) { - var vecs = p.edges.map(edge_vec.bind(null, n)); + nports.forEach(p => { + if (_diagram.portElastic.eval(p) && p.edges.length) { + const vecs = p.edges.map(edge_vec.bind(null, n)); p.vec = [ - d3.sum(vecs, function(v) { return v[0]; })/vecs.length, - d3.sum(vecs, function(v) { return v[1]; })/vecs.length + sum(vecs, v => v[0])/vecs.length, + sum(vecs, v => v[1])/vecs.length, ]; } else p.vec = p.vec || undefined; p.pos = null; @@ -2104,144 +2204,169 @@ dc_graph.diagram = function (parent, chartGroup) { } function propagate_port_positions(nodes, wedges, ports) { // make sure we have projected vectors to positions - for(var nid in _nodePorts) { - var n = nodes[nid]; - _nodePorts[nid].forEach(function(p) { - if(!p.pos) - project_port(_diagram, n, p); + for (const nid in _nodePorts) { + const n = nodes[nid]; + _nodePorts[nid].forEach(p => { + if (!p.pos) + projectPort(_diagram, n, p); }); } // propagate port positions to edge endpoints - wedges.forEach(function(e) { - var name = _diagram.edgeSourcePortName.eval(e); - e.sourcePort.pos = name ? ports[port_name(_diagram.nodeKey.eval(e.source), null, name)].pos : - ports[port_name(null, _diagram.edgeKey.eval(e), 'source')].pos; + wedges.forEach(e => { + let name = _diagram.edgeSourcePortName.eval(e); + e.sourcePort.pos = name + ? ports[portName(_diagram.nodeKey.eval(e.source), null, name)].pos + : ports[portName(null, _diagram.edgeKey.eval(e), 'source')].pos; name = _diagram.edgeTargetPortName.eval(e); - e.targetPort.pos = name ? ports[port_name(_diagram.nodeKey.eval(e.target), null, name)].pos : - ports[port_name(null, _diagram.edgeKey.eval(e), 'target')].pos; + e.targetPort.pos = name + ? ports[portName(_diagram.nodeKey.eval(e.target), null, name)].pos + : ports[portName(null, _diagram.edgeKey.eval(e), 'target')].pos; console.assert(e.sourcePort.pos && e.targetPort.pos); }); } _diagram.requestRefresh = function(durationOverride) { - window.requestAnimationFrame(function() { - var transdur; - if(durationOverride !== undefined) { + window.requestAnimationFrame(() => { + let transdur; + if (durationOverride !== undefined) { transdur = _diagram.transitionDuration(); _diagram.transitionDuration(durationOverride); } _diagram.renderer().refresh(); - if(durationOverride !== undefined) + if (durationOverride !== undefined) _diagram.transitionDuration(transdur); }); }; _diagram.layoutDone = function(happens) { - _dispatch.end(happens); + _dispatch.call('end', null, happens); _running = false; - if(_needsRedraw) { + if (_needsRedraw) { _needsRedraw = false; - window.setTimeout(function() { - if(!_diagram.isRunning()) // someone else may already have started + window.setTimeout(() => { + if (!_diagram.isRunning()) // someone else may already have started _diagram.redraw(); }, 0); } }; function enforce_path_direction(path, spos, tpos) { - var points = path.points, first = points[0], last = points[points.length-1]; - switch(_diagram.enforceEdgeDirection()) { - case 'LR': - if(spos.x >= tpos.x) { - var dx = first.x - last.x; - return { - points: [ - first, - {x: first.x + dx, y: first.y - dx/2}, - {x: last.x - dx, y: last.y - dx/2}, - last - ], - bezDegree: 3, - sourcePort: path.sourcePort, - targetPort: path.targetPort - }; - } - break; - case 'TB': - if(spos.y >= tpos.y) { - var dy = first.y - last.y; - return { - points: [ - first, - {x: first.x + dy/2, y: first.y + dy}, - {x: last.x + dy/2, y: last.y - dy}, - last - ], - bezDegree: 3, - sourcePort: path.sourcePort, - targetPort: path.targetPort - }; - } - break; + const points = path.points, first = points[0], last = points[points.length-1]; + switch (_diagram.enforceEdgeDirection()) { + case 'LR': + if (spos.x >= tpos.x) { + const dx = first.x-last.x; + return { + points: [ + first, + {x: first.x+dx, y: first.y-dx/2}, + {x: last.x-dx, y: last.y-dx/2}, + last, + ], + bezDegree: 3, + sourcePort: path.sourcePort, + targetPort: path.targetPort, + }; + } + break; + case 'TB': + if (spos.y >= tpos.y) { + const dy = first.y-last.y; + return { + points: [ + first, + {x: first.x+dy/2, y: first.y+dy}, + {x: last.x+dy/2, y: last.y-dy}, + last, + ], + bezDegree: 3, + sourcePort: path.sourcePort, + targetPort: path.targetPort, + }; + } + break; } return path; } _diagram.calcEdgePath = function(e, age, sx, sy, tx, ty) { - var parallel = e.parallel; - var source = e.source, target = e.target; - if(parallel.edges.length > 1 && e.source.index > e.target.index) { - var t; - t = target; target = source; source = t; - t = tx; tx = sx; sx = t; - t = ty; ty = sy; sy = t; + const parallel = e.parallel; + let source = e.source, target = e.target; + if (parallel.edges.length > 1 && e.source.index > e.target.index) { + let t; + t = target; + target = source; + source = t; + t = tx; + tx = sx; + sx = t; + t = ty; + ty = sy; + sy = t; } - var source_padding = source.dcg_ry + - _diagram.nodeStrokeWidth.eval(source) / 2, - target_padding = target.dcg_ry + - _diagram.nodeStrokeWidth.eval(target) / 2; - for(var p = 0; p < parallel.edges.length; ++p) { + const source_padding = source.dcg_ry + +_diagram.nodeStrokeWidth.eval(source)/2, + target_padding = target.dcg_ry + +_diagram.nodeStrokeWidth.eval(target)/2; + for (let p = 0; p < parallel.edges.length; ++p) { // alternate parallel edges over, then under - var dir = (!!(p%2) === (sx < tx)) ? -1 : 1, + const dir = (!!(p%2) === (sx < tx)) ? -1 : 1, port = Math.floor((p+1)/2), - last = port > 0 ? parallel.edges[p > 2 ? p - 2 : 0].pos[age].path : null; - var path = draw_edge_to_shapes(_diagram, e, sx, sy, tx, ty, - last, dir, _diagram.parallelEdgeOffset(), - source_padding, target_padding - ); - if(parallel.edges.length > 1 && parallel.rev[p]) + last = port > 0 ? parallel.edges[p > 2 ? p-2 : 0].pos[age].path : null; + let path = drawEdgeToShapes( + _diagram, + e, + sx, + sy, + tx, + ty, + last, + dir, + _diagram.parallelEdgeOffset(), + source_padding, + target_padding, + ); + if (parallel.edges.length > 1 && parallel.rev[p]) path.points.reverse(); - if(_diagram.enforceEdgeDirection()) + if (_diagram.enforceEdgeDirection()) path = enforce_path_direction(path, source.cola, target.cola); - var path0 = { + const path0 = { points: path.points, - bezDegree: path.bezDegree + bezDegree: path.bezDegree, }; - var alengths = scaled_arrow_lengths(_diagram, parallel.edges[p]); - path = clip_path_to_arrows(alengths.headLength, alengths.tailLength, path); - var points = path.points, points0 = path0.points; + const alengths = scaledArrowLengths(_diagram, parallel.edges[p]); + path = clipPathToArrows(alengths.headLength, alengths.tailLength, path); + const points = path.points, points0 = path0.points; parallel.edges[p].pos[age] = { - path: path, + path, full: path0, - orienthead: angle_between_points(points[points.length-1], points0[points0.length-1]) + 'rad', - orienttail: angle_between_points(points[0], points0[0]) + 'rad' + orienthead: `${ + angleBetweenPoints(points[points.length-1], points0[points0.length-1]) + }rad`, + orienttail: `${angleBetweenPoints(points[0], points0[0])}rad`, }; } }; function node_bounds(n) { - var bounds = {left: n.cola.x - n.dcg_rx, top: n.cola.y - n.dcg_ry, - right: n.cola.x + n.dcg_rx, bottom: n.cola.y + n.dcg_ry}; - if(_diagram.portStyle.enum().length) { - var ports = _nodePorts[_diagram.nodeKey.eval(n)]; - if(ports) - ports.forEach(function(p) { - var portStyle =_diagram.portStyleName.eval(p); - if(!portStyle || !_diagram.portStyle(portStyle)) + let bounds = { + left: n.cola.x-n.dcg_rx, + top: n.cola.y-n.dcg_ry, + right: n.cola.x+n.dcg_rx, + bottom: n.cola.y+n.dcg_ry, + }; + if (_diagram.portStyle.enum().length) { + const ports = _nodePorts[_diagram.nodeKey.eval(n)]; + if (ports) + ports.forEach(p => { + const portStyle = _diagram.portStyleName.eval(p); + if (!portStyle || !_diagram.portStyle(portStyle)) return; - var pb = _diagram.portStyle(portStyle).portBounds(p); - pb.left += n.cola.x; pb.top += n.cola.y; - pb.right += n.cola.x; pb.bottom += n.cola.y; + const pb = _diagram.portStyle(portStyle).portBounds(p); + pb.left += n.cola.x; + pb.top += n.cola.y; + pb.right += n.cola.x; + pb.bottom += n.cola.y; bounds = union_bounds(bounds, pb); }); } @@ -2253,7 +2378,7 @@ dc_graph.diagram = function (parent, chartGroup) { left: Math.min(b1.left, b2.left), top: Math.min(b1.top, b2.top), right: Math.max(b1.right, b2.right), - bottom: Math.max(b1.bottom, b2.bottom) + bottom: Math.max(b1.bottom, b2.bottom), }; } @@ -2262,97 +2387,102 @@ dc_graph.diagram = function (parent, chartGroup) { left: p.x, top: p.y, right: p.x, - bottom: p.y + bottom: p.y, }; } function edge_bounds(e) { // assumption: edge must have some points - var points = e.pos.new.path.points; + const points = e.pos.new.path.points; return points.map(point_to_bounds).reduce(union_bounds); } _diagram.calculateBounds = function(ndata, edata) { // assumption: there can be no edges without nodes - var bounds = ndata.map(node_bounds).reduce(union_bounds); + const bounds = ndata.map(node_bounds).reduce(union_bounds); return edata.map(edge_bounds).reduce(union_bounds, bounds); }; - var _bounds; + let _bounds; function calc_bounds(drawState) { - if((_diagram.fitStrategy() || _diagram.restrictPan())) { + if ((_diagram.fitStrategy() || _diagram.restrictPan())) { _bounds = _diagram.renderer().calculateBounds(drawState); } } _diagram.animateZoom = function(_) { - if(!arguments.length) + if (!arguments.length) return _animateZoom; _animateZoom = _; return _diagram; }; function auto_zoom(animate) { - if(_diagram.fitStrategy()) { - if(!_bounds) + if (_diagram.fitStrategy()) { + if (!_bounds) return; - var vwidth = _bounds.right - _bounds.left, vheight = _bounds.bottom - _bounds.top, - swidth = _diagram.width() - _diagram.margins().left - _diagram.margins().right, - sheight = _diagram.height() - _diagram.margins().top - _diagram.margins().bottom; - var fitS = _diagram.fitStrategy(), translate = [0,0], scale = 1; - if(['default', 'vertical', 'horizontal'].indexOf(fitS) >= 0) { - var sAR = sheight / swidth, vAR = vheight / vwidth, - vrl = vAR= 0) { + const sAR = sheight/swidth, + vAR = vheight/vwidth, + vrl = vAR < sAR, // view aspect ratio is less (wider) amv = (fitS === 'default') ? !vrl : (fitS === 'vertical'); // align margins vertically - scale = amv ? sheight / vheight : swidth / vwidth; - scale = Math.max(_diagram.zoomExtent()[0], Math.min(_diagram.zoomExtent()[1], scale)); - translate = [_diagram.margins().left - _bounds.left*scale + (swidth - vwidth*scale) / 2, - _diagram.margins().top - _bounds.top*scale + (sheight - vheight*scale) / 2]; - } - else if(typeof fitS === 'string' && fitS.match(/^align_/)) { - var sides = fitS.split('_')[1].toLowerCase().split(''); - if(sides.length > 2) - throw new Error("align_ expecting 0-2 sides, not " + sides.length); - var bounds = margined_bounds(); + scale = amv ? sheight/vheight : swidth/vwidth; + scale = Math.max( + _diagram.zoomExtent()[0], + Math.min(_diagram.zoomExtent()[1], scale), + ); + translate = [ + _diagram.margins().left-_bounds.left*scale+(swidth-vwidth*scale)/2, + _diagram.margins().top-_bounds.top*scale+(sheight-vheight*scale)/2, + ]; + } else if (typeof fitS === 'string' && fitS.match(/^align_/)) { + const sides = fitS.split('_')[1].toLowerCase().split(''); + if (sides.length > 2) + throw new Error(`align_ expecting 0-2 sides, not ${sides.length}`); + const bounds = margined_bounds(); translate = _diagram.renderer().translate(); scale = _diagram.renderer().scale(); - var vertalign = false, horzalign = false; - sides.forEach(function(s) { - switch(s) { - case 'l': - translate[0] = align_left(translate, bounds.left); - horzalign = true; - break; - case 't': - translate[1] = align_top(translate, bounds.top); - vertalign = true; - break; - case 'r': - translate[0] = align_right(translate, bounds.right); - horzalign = true; - break; - case 'b': - translate[1] = align_bottom(translate, bounds.bottom); - vertalign = true; - break; - case 'c': // handled below - break; - default: - throw new Error("align_ expecting l t r b or c, not '" + s + "'"); + let vertalign = false, horzalign = false; + sides.forEach(s => { + switch (s) { + case 'l': + translate[0] = align_left(translate, bounds.left); + horzalign = true; + break; + case 't': + translate[1] = align_top(translate, bounds.top); + vertalign = true; + break; + case 'r': + translate[0] = align_right(translate, bounds.right); + horzalign = true; + break; + case 'b': + translate[1] = align_bottom(translate, bounds.bottom); + vertalign = true; + break; + case 'c': // handled below + break; + default: + throw new Error(`align_ expecting l t r b or c, not '${s}'`); } }); - if(sides.includes('c')) { - if(!horzalign) + if (sides.includes('c')) { + if (!horzalign) translate[0] = center_horizontally(translate, bounds); - if(!vertalign) + if (!vertalign) translate[1] = center_vertically(translate, bounds); } - } - else if(fitS === 'zoom') { + } else if (fitS === 'zoom') { scale = _diagram.renderer().scale(); translate = bring_in_bounds(_diagram.renderer().translate()); - } - else - throw new Error('unknown fitStrategy type ' + typeof fitS); + } else + throw new Error(`unknown fitStrategy type ${typeof fitS}`); _animateZoom = animate; _diagram.renderer().translate(translate).scale(scale).commitTranslateScale(); @@ -2361,21 +2491,27 @@ dc_graph.diagram = function (parent, chartGroup) { } function namespace_event_reducer(msg_fun) { return function(p, ev) { - var namespace = {}; + const namespace = {}; p[ev] = function(ns) { - return namespace[ns] = namespace[ns] || onetime_trace('trace', msg_fun(ns, ev)); + return namespace[ns] = namespace[ns] || onetimeTrace('trace', msg_fun(ns, ev)); }; return p; }; } - var renderer_specific_events = ['drawn', 'transitionsStarted', 'zoomed'] - .reduce(namespace_event_reducer(function(ns, ev) { - return 'subscribing "' + ns + '" to event "' + ev + '" which takes renderer-specific parameters'; - }), {}); - var inconsistent_arguments = ['end'] - .reduce(namespace_event_reducer(function(ns, ev) { - return 'subscribing "' + ns + '" to event "' + ev + '" which may receive inconsistent arguments'; - }), {}); + const renderer_specific_events = ['drawn', 'transitionsStarted', 'zoomed'] + .reduce( + namespace_event_reducer((ns, ev) => + `subscribing "${ns}" to event "${ev}" which takes renderer-specific parameters` + ), + {}, + ); + const inconsistent_arguments = ['end'] + .reduce( + namespace_event_reducer((ns, ev) => + `subscribing "${ns}" to event "${ev}" which may receive inconsistent arguments` + ), + {}, + ); /** * Standard dc.js @@ -2391,13 +2527,13 @@ dc_graph.diagram = function (parent, chartGroup) { * @param {String} [event] - the event to subscribe to * @param {Function} [f] - the event handler * @return {dc_graph.diagram} - **/ + */ _diagram.on = function(event, f) { - if(arguments.length === 1) + if (arguments.length === 1) return _dispatch.on(event); - var evns = event.split('.'), + const evns = event.split('.'), warning = renderer_specific_events[evns[0]] || inconsistent_arguments[evns[0]]; - if(warning) + if (warning) warning(evns[1] || '')(); _dispatch.on(event, f); return this; @@ -2412,7 +2548,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @instance * @return {} * @return {dc_graph.diagram} - **/ + */ _diagram.getStats = function() { return _stats; }; @@ -2453,9 +2589,9 @@ dc_graph.diagram = function (parent, chartGroup) { * @memberof dc_graph.diagram * @instance * @return {dc_graph.diagram} - **/ - _diagram.redrawGroup = function () { - dc.redrawAll(_chartGroup); + */ + _diagram.redrawGroup = function() { + redrawAll(_chartGroup); }; /** @@ -2466,9 +2602,9 @@ dc_graph.diagram = function (parent, chartGroup) { * @memberof dc_graph.diagram * @instance * @return {dc_graph.diagram} - **/ - _diagram.renderGroup = function () { - dc.renderAll(_chartGroup); + */ + _diagram.renderGroup = function() { + renderAll(_chartGroup); }; /** @@ -2478,10 +2614,12 @@ dc_graph.diagram = function (parent, chartGroup) { * [arrows.js](https://github.com/dc-js/dc.graph.js/blob/develop/src/arrows.js) * for examples * @return {dc_graph.diagram} - **/ + */ _diagram.defineArrow = function(name, defn) { - if(typeof defn !== 'function') - throw new Error('sorry, defineArrow no longer takes specific shape parameters, and the parameters have changed too much to convert them. it takes a name and a function returning a definition - please look at arrows.js for new format'); + if (typeof defn !== 'function') + throw new Error( + 'sorry, defineArrow no longer takes specific shape parameters, and the parameters have changed too much to convert them. it takes a name and a function returning a definition - please look at arrows.js for new format', + ); _arrows[name] = defn; return _diagram; }; @@ -2491,109 +2629,120 @@ dc_graph.diagram = function (parent, chartGroup) { return _arrows; }; - Object.keys(dc_graph.builtin_arrows).forEach(function(aname) { - var defn = dc_graph.builtin_arrows[aname]; + Object.keys(builtinArrows).forEach(aname => { + const defn = builtinArrows[aname]; _diagram.defineArrow(aname, defn); }); function margined_bounds() { - var bounds = _bounds || {left: 0, top: 0, right: 0, bottom: 0}; - var scale = _diagram.renderer().scale(); + const bounds = _bounds || {left: 0, top: 0, right: 0, bottom: 0}; + const scale = _diagram.renderer().scale(); return { - left: bounds.left - _diagram.margins().left/scale, - top: bounds.top - _diagram.margins().top/scale, - right: bounds.right + _diagram.margins().right/scale, - bottom: bounds.bottom + _diagram.margins().bottom/scale + left: bounds.left-_diagram.margins().left/scale, + top: bounds.top-_diagram.margins().top/scale, + right: bounds.right+_diagram.margins().right/scale, + bottom: bounds.bottom+_diagram.margins().bottom/scale, }; } // with thanks to comments in https://github.com/d3/d3/issues/1084 function align_left(translate, x) { - return translate[0] - _diagram.x()(x) + _diagram.x().range()[0]; + return translate[0]-_diagram.x()(x)+_diagram.x().range()[0]; } function align_top(translate, y) { - return translate[1] - _diagram.y()(y) + _diagram.y().range()[0]; + return translate[1]-_diagram.y()(y)+_diagram.y().range()[0]; } function align_right(translate, x) { - return translate[0] - _diagram.x()(x) + _diagram.x().range()[1]; + return translate[0]-_diagram.x()(x)+_diagram.x().range()[1]; } function align_bottom(translate, y) { - return translate[1] - _diagram.y()(y) + _diagram.y().range()[1];; + return translate[1]-_diagram.y()(y)+_diagram.y().range()[1]; } function center_horizontally(translate, bounds) { - return (align_left(translate, bounds.left) + align_right(translate, bounds.right))/2; + return (align_left(translate, bounds.left)+align_right(translate, bounds.right))/2; } function center_vertically(translate, bounds) { - return (align_top(translate, bounds.top) + align_bottom(translate, bounds.bottom))/2; + return (align_top(translate, bounds.top)+align_bottom(translate, bounds.bottom))/2; } function bring_in_bounds(translate) { - var xDomain = _diagram.x().domain(), yDomain = _diagram.y().domain(); - var bounds = margined_bounds(); - var less1 = bounds.left < xDomain[0], less2 = bounds.right < xDomain[1], - lessExt = (bounds.right - bounds.left) < (xDomain[1] - xDomain[0]); - var align, nothing = 0; - if(less1 && less2) - if(lessExt) + const xDomain = _diagram.x().domain(), yDomain = _diagram.y().domain(); + const bounds = margined_bounds(); + let less1 = bounds.left < xDomain[0], + less2 = bounds.right < xDomain[1], + lessExt = (bounds.right-bounds.left) < (xDomain[1]-xDomain[0]); + let align, _nothing = 0; + if (less1 && less2) { + if (lessExt) align = 'left'; - else - align = 'right'; - else if(!less1 && !less2) - if(lessExt) + else align = 'right'; - else - align = 'left'; - switch(align) { - case 'left': - translate[0] = align_left(translate, bounds.left); - break; - case 'right': - translate[0] = align_right(translate, bounds.right); - break; - default: - ++nothing; + } else if (!less1 && !less2) { + if (lessExt) + align = 'right'; + else + align = 'left'; + } + switch (align) { + case 'left': + translate[0] = align_left(translate, bounds.left); + break; + case 'right': + translate[0] = align_right(translate, bounds.right); + break; + default: + ++_nothing; } - less1 = bounds.top < yDomain[0]; less2 = bounds.bottom < yDomain[1]; - lessExt = (bounds.bottom - bounds.top) < (yDomain[1] - yDomain[0]); - if(less1 && less2) - if(lessExt) + less1 = bounds.top < yDomain[0]; + less2 = bounds.bottom < yDomain[1]; + lessExt = (bounds.bottom-bounds.top) < (yDomain[1]-yDomain[0]); + if (less1 && less2) { + if (lessExt) align = 'top'; - else - align = 'bottom'; - else if(!less1 && !less2) - if(lessExt) + else align = 'bottom'; - else - align = 'top'; - switch(align) { - case 'top': - translate[1] = align_top(translate, bounds.top); - break; - case 'bottom': - translate[1] = align_bottom(translate, bounds.bottom); - break; - default: - ++nothing; + } else if (!less1 && !less2) { + if (lessExt) + align = 'bottom'; + else + align = 'top'; + } + switch (align) { + case 'top': + translate[1] = align_top(translate, bounds.top); + break; + case 'bottom': + translate[1] = align_bottom(translate, bounds.bottom); + break; + default: + ++_nothing; } return translate; - } _diagram.doZoom = function() { - if(_diagram.width_is_automatic() || _diagram.height_is_automatic()) + if (_diagram.width_is_automatic() || _diagram.height_is_automatic()) detect_size_change(); - var translate, scale = d3.event.scale; - if(_diagram.restrictPan()) - _diagram.renderer().translate(translate = bring_in_bounds(d3.event.translate)); - else translate = d3.event.translate; + + const transform = zoomTransform(_diagram.renderer().svg().node()); + const scale = transform.k; + let translate; + if (_diagram.restrictPan()) + translate = bring_in_bounds([transform.x, transform.y]); + else translate = [transform.x, transform.y]; + + // Manually rescale x and y scales for D3 v5 + const newX = transform.rescaleX(_diagram.x()); + const newY = transform.rescaleY(_diagram.y()); + _diagram.renderer().globalTransform(translate, scale, _animateZoom); - _dispatch.zoomed(translate, scale, _diagram.x().domain(), _diagram.y().domain()); + _dispatch.call('zoomed', null, translate, scale, newX.domain(), newY.domain()); }; _diagram.invertCoord = function(clientCoord) { return [ _diagram.x().invert(clientCoord[0]), - _diagram.y().invert(clientCoord[1]) + _diagram.y().invert(clientCoord[1]), ]; }; @@ -2621,11 +2770,11 @@ dc_graph.diagram = function (parent, chartGroup) { } else { _anchor = parent; } - _diagram.root(d3.select(_anchor)); - _diagram.root().classed(dc_graph.constants.CHART_CLASS, true); - dc.registerChart(_diagram, chartGroup); + _diagram.root(select(_anchor)); + _diagram.root().classed(constants.CHART_CLASS, true); + registerChart(_diagram, chartGroup); } else { - throw new dc.errors.BadArgumentException('parent must be defined'); + throw new BadArgumentException('parent must be defined'); } _chartGroup = chartGroup; return _diagram; @@ -2638,7 +2787,7 @@ dc_graph.diagram = function (parent, chartGroup) { * @instance * @returns {String} */ - _diagram.chartID = function () { + _diagram.chartID = function() { return _diagram.__dcFlag__; }; @@ -2649,16 +2798,16 @@ dc_graph.diagram = function (parent, chartGroup) { * @instance * @return {String} */ - _diagram.anchorName = function () { - var a = _diagram.anchor(); + _diagram.anchorName = function() { + const a = _diagram.anchor(); if (a && a.id) { return a.id; } if (a && a.replace) { return a.replace('#', ''); } - return 'dc-graph' + _diagram.chartID(); + return `dc-graph${_diagram.chartID()}`; }; return _diagram.anchor(parent, chartGroup); -}; +} diff --git a/src/draw_clusters.js b/src/draw_clusters.js index f3f53167..ae5763c0 100644 --- a/src/draw_clusters.js +++ b/src/draw_clusters.js @@ -1,57 +1,43 @@ -dc_graph.draw_clusters = function() { +import { property } from './core.js'; +import { mode } from './mode.js'; +export function drawClusters() { function apply_bounds(rect) { - rect.attr({ - x: function(c) { - return c.cola.bounds.left; - }, - y: function(c) { - return c.cola.bounds.top; - }, - width: function(c) { - return c.cola.bounds.right - c.cola.bounds.left; - }, - height: function(c) { - return c.cola.bounds.bottom - c.cola.bounds.top; - } - }); + rect.attr('x', c => c.cola.bounds.left) + .attr('y', c => c.cola.bounds.top) + .attr('width', c => c.cola.bounds.right-c.cola.bounds.left) + .attr('height', c => c.cola.bounds.bottom-c.cola.bounds.top); } function draw(diagram) { - if(!diagram.clusterGroup()) + if (!diagram.clusterGroup()) return; - var clayer = diagram.g().selectAll('g.cluster-layer').data([0]); + const clayer = diagram.g().selectAll('g.cluster-layer').data([0]); clayer.enter().insert('g', ':first-child') .attr('class', 'cluster-layer'); - var clusters = diagram.clusterGroup().all().map(function(kv) { - return _mode.parent().getWholeCluster(kv.key); - }).filter(function(c) { - return c && c.cola.bounds; - }); - var rects = clayer.selectAll('rect.cluster') - .data(clusters, function(c) { return c.orig.key; }); + const clusters = diagram.clusterGroup().all().map(kv => + _mode.parent().getWholeCluster(kv.key) + ).filter(c => c && c.cola.bounds); + const rects = clayer.selectAll('rect.cluster') + .data(clusters, c => c.orig.key); rects.exit().remove(); rects.enter().append('rect') - .attr({ - class: 'cluster', - opacity: 0, - stroke: _mode.clusterStroke.eval, - 'stroke-width': _mode.clusterStrokeWidth.eval, - fill: function(c) { - return _mode.clusterFill.eval(c) || 'none'; - } - }) + .attr('class', 'cluster') + .attr('opacity', 0) + .attr('stroke', _mode.clusterStroke.eval) + .attr('stroke-width', _mode.clusterStrokeWidth.eval) + .attr('fill', c => _mode.clusterFill.eval(c) || 'none') .call(apply_bounds); rects.transition() .duration(_mode.parent().stagedDuration()) .attr('opacity', _mode.clusterOpacity.eval) .call(apply_bounds); } - function remove(diagram, node, edge, ehover) { + function remove(_diagram, _node, _edge, _ehover) { } - var _mode = dc_graph.mode('draw-clusters', { + const _mode = mode('draw-clusters', { laterDraw: true, - draw: draw, - remove: remove + draw, + remove, }); _mode.clusterOpacity = property(0.25); _mode.clusterStroke = property('black'); @@ -59,8 +45,7 @@ dc_graph.draw_clusters = function() { _mode.clusterFill = property(null); _mode.clusterLabel = property(null); _mode.clusterLabelFill = property('black'); - _mode.clusterLabelAlignment = property(['bottom','right']); + _mode.clusterLabelAlignment = property(['bottom', 'right']); return _mode; -}; - +} diff --git a/src/draw_graphs.js b/src/draw_graphs.js index 79102bf6..e0622911 100644 --- a/src/draw_graphs.js +++ b/src/draw_graphs.js @@ -1,73 +1,96 @@ -dc_graph.draw_graphs = function(options) { - var select_nodes_group = dc_graph.select_things_group(options.select_nodes_group || 'select-nodes-group', 'select-nodes'), - select_edges_group = dc_graph.select_things_group(options.select_edges_group || 'select-edges-group', 'select-edges'), - label_nodes_group = dc_graph.label_things_group('label-nodes-group', 'label-nodes'), - label_edges_group = dc_graph.label_things_group('label-edges-group', 'label-edges'), - fix_nodes_group = dc_graph.fix_nodes_group('fix-nodes-group'); - var _nodeIdTag = options.idTag || 'id', +import { event as d3Event } from 'd3-selection'; +import { property, uuid } from './core.js'; +import { fixNodesGroup } from './fix_nodes.js'; +import { labelThingsGroup } from './label_things.js'; +import { mode } from './mode.js'; +import { selectThingsGroup } from './select_things.js'; +import { eventCoords, promiseIdentity } from './utils.js'; + +export function drawGraphs(options) { + const select_nodes_group = selectThingsGroup( + options.select_nodes_group || 'select-nodes-group', + 'select-nodes', + ), + select_edges_group = selectThingsGroup( + options.select_edges_group || 'select-edges-group', + 'select-edges', + ), + _label_nodes_group = labelThingsGroup('label-nodes-group', 'label-nodes'), + _label_edges_group = labelThingsGroup('label-edges-group', 'label-edges'), + fix_nodes_group = fixNodesGroup('fix-nodes-group'); + const _nodeIdTag = options.idTag || 'id', _edgeIdTag = options.edgeIdTag || _nodeIdTag, _sourceTag = options.sourceTag || 'source', _targetTag = options.targetTag || 'target', _nodeLabelTag = options.labelTag || 'label', _edgeLabelTag = options.edgeLabelTag || _nodeLabelTag; - var _sourceDown = null, _targetMove = null, _targetValid = false, _edgeLayer = null, _hintData = [], _crossout; + let _sourceDown = null, + _targetMove = null, + _targetValid = false, + _edgeLayer = null, + _hintData = [], + _crossout; function update_hint() { - var data = _hintData.filter(function(h) { - return h.source && h.target; - }); - var line = _edgeLayer.selectAll('line.hint-edge').data(data); + const data = _hintData.filter(h => h.source && h.target); + let line = _edgeLayer.selectAll('line.hint-edge').data(data); line.exit().remove(); - line.enter().append('line') + const lineEnter = line.enter().append('line') .attr('class', 'hint-edge') - .style({ - fill: 'none', - stroke: 'black', - 'pointer-events': 'none' - }); + .attr('stroke', _mode.hintStroke()) + .style('fill', 'none') + .style('pointer-events', 'none'); - line.attr({ - x1: function(n) { return n.source.x; }, - y1: function(n) { return n.source.y; }, - x2: function(n) { return n.target.x; }, - y2: function(n) { return n.target.y; } - }); + line = lineEnter.merge(line); + + line.attr('x1', n => n.source.x) + .attr('y1', n => n.source.y) + .attr('x2', n => n.target.x) + .attr('y2', n => n.target.y); } function port_pos(p) { - var style = _mode.parent().portStyle(_mode.parent().portStyleName.eval(p)); - var pos = style.portPosition(p); + const style = _mode.parent().portStyle(_mode.parent().portStyleName.eval(p)); + const pos = style.portPosition(p); pos.x += p.node.cola.x; pos.y += p.node.cola.y; return pos; } function update_crossout() { - var data; - if(_crossout) { - if(_mode.usePorts()) + let data; + if (_crossout) { + if (_mode.usePorts()) data = [port_pos(_crossout)]; else data = [{x: _crossout.node.cola.x, y: _crossout.node.cola.y}]; - } - else data = []; + } else data = []; - var size = _mode.crossSize(), wid = _mode.crossWidth(); - var cross = _edgeLayer.selectAll('polygon.graph-draw-crossout').data(data); + const size = _mode.crossSize(), wid = _mode.crossWidth(); + let cross = _edgeLayer.selectAll('polygon.graph-draw-crossout').data(data); cross.exit().remove(); - cross.enter().append('polygon') + const crossEnter = cross.enter().append('polygon') .attr('class', 'graph-draw-crossout'); + cross = cross.merge(crossEnter); cross - .attr('points', function(d) { - var x = d.x, y = d.y; + .attr('points', d => { + const x = d.x, y = d.y; return [ - [x-size/2, y+size/2], [x-size/2+wid, y+size/2], [x, y+wid/2], - [x+size/2-wid, y+size/2], [x+size/2, y+size/2], [x+wid/2, y], - [x+size/2, y-size/2], [x+size/2-wid, y-size/2], [x, y-wid/2], - [x-size/2+wid, y-size/2], [x-size/2, y-size/2], [x-wid/2, y] + [x-size/2, y+size/2], + [x-size/2+wid, y+size/2], + [x, y+wid/2], + [x+size/2-wid, y+size/2], + [x+size/2, y+size/2], + [x+wid/2, y], + [x+size/2, y-size/2], + [x+size/2-wid, y-size/2], + [x, y-wid/2], + [x-size/2+wid, y-size/2], + [x-size/2, y-size/2], + [x-wid/2, y], ] - .map(function(p) { return p.join(','); }) + .map(p => p.join(',')) .join(' '); }); } @@ -79,75 +102,89 @@ dc_graph.draw_graphs = function(options) { } function create_node(diagram, pos, data) { - if(!_mode.nodeCrossfilter()) + if (!_mode.nodeCrossfilter()) throw new Error('need nodeCrossfilter'); - var node, callback = _mode.addNode() || promise_identity; - if(data) + let node; + const callback = _mode.addNode() || promiseIdentity; + if (data) node = data; else { node = {}; node[_nodeIdTag] = uuid(); node[_nodeLabelTag] = ''; } - if(pos) - fix_nodes_group.new_node(node[_nodeIdTag], node, {x: pos[0], y: pos[1]}); - callback(node).then(function(node2) { - if(!node2) + if (pos) + fix_nodes_group.call('new_node', null, node[_nodeIdTag], node, {x: pos[0], y: pos[1]}); + callback(node).then(node2 => { + if (!node2) return; _mode.nodeCrossfilter().add([node2]); diagram.redrawGroup(); - select_nodes_group.set_changed([node2[_nodeIdTag]]); + select_nodes_group.call('set_changed', null, [node2[_nodeIdTag]]); }); } function create_edge(diagram, source, target) { - if(!_mode.edgeCrossfilter()) + if (!_mode.edgeCrossfilter()) throw new Error('need edgeCrossfilter'); - var edge = {}, callback = _mode.addEdge() || promise_identity; + const edge = {}, callback = _mode.addEdge() || promiseIdentity; edge[_edgeIdTag] = uuid(); edge[_edgeLabelTag] = ''; - if(_mode.conduct().detectReversedEdge && _mode.conduct().detectReversedEdge(edge, source.port, target.port)) { + if ( + _mode.conduct().detectReversedEdge + && _mode.conduct().detectReversedEdge(edge, source.port, target.port) + ) { edge[_sourceTag] = target.node.orig.key; edge[_targetTag] = source.node.orig.key; - var t; - t = source; source = target; target = t; + const t = source; + source = target; + target = t; } else { edge[_sourceTag] = source.node.orig.key; edge[_targetTag] = target.node.orig.key; } - callback(edge, source.port, target.port).then(function(edge2) { - if(!edge2) + callback(edge, source.port, target.port).then(edge2 => { + if (!edge2) return; - fix_nodes_group.new_edge(edge[_edgeIdTag], edge2[_sourceTag], edge2[_targetTag]); + fix_nodes_group.call( + 'new_edge', + null, + edge[_edgeIdTag], + edge2[_sourceTag], + edge2[_targetTag], + ); _mode.edgeCrossfilter().add([edge2]); - select_nodes_group.set_changed([], false); - select_edges_group.set_changed([edge2[_edgeIdTag]], false); + select_nodes_group.call('set_changed', null, [], false); + select_edges_group.call('set_changed', null, [edge2[_edgeIdTag]], false); diagram.redrawGroup(); }); } - function check_invalid_drag(coords) { - var msg; - if(!(d3.event.buttons & 1)) { + function check_invalid_drag(coords, event) { + let msg; + if (!(event.buttons&1)) { // mouse button was released but we missed it _crossout = null; - if(_mode.conduct().cancelDragEdge) + if (_mode.conduct().cancelDragEdge) _mode.conduct().cancelDragEdge(_sourceDown); erase_hint(); update_crossout(); return true; } - if(!_sourceDown.started && Math.hypot(coords[0] - _hintData[0].source.x, coords[1] - _hintData[0].source.y) > _mode.dragSize()) { - if(_mode.conduct().startDragEdge) { - if(_mode.conduct().startDragEdge(_sourceDown)) { + if ( + !_sourceDown.started + && Math.hypot(coords[0]-_hintData[0].source.x, coords[1]-_hintData[0].source.y) + > _mode.dragSize() + ) { + if (_mode.conduct().startDragEdge) { + if (_mode.conduct().startDragEdge(_sourceDown)) { _sourceDown.started = true; } else { - if(_mode.conduct().invalidSourceMessage) { + if (_mode.conduct().invalidSourceMessage) { msg = _mode.conduct().invalidSourceMessage(_sourceDown); - console.log(msg); - if(options.negativeTip) { + if (options.negativeTip) { options.negativeTip - .content(function(_, k) { k(msg); }) + .content(() => msg) .displayTip(_mode.usePorts() ? _sourceDown.port : _sourceDown.node); } } @@ -159,164 +196,174 @@ dc_graph.draw_graphs = function(options) { return false; } - function draw(diagram, node, edge, ehover) { - var select_nodes = diagram.child('select-nodes'); - if(select_nodes) { - if(_mode.clickCreatesNodes()) + function draw(diagram, node, _edge, _ehover) { + const select_nodes = diagram.child('select-nodes'); + if (select_nodes) { + if (_mode.clickCreatesNodes()) select_nodes.clickBackgroundClears(false); } node - .on('mousedown.draw-graphs', function(n) { - d3.event.stopPropagation(); - if(!_mode.dragCreatesEdges()) + .on('mousedown.draw-graphs', n => { + d3Event.stopPropagation(); + if (!_mode.dragCreatesEdges()) return; - if(options.tipsDisable) - options.tipsDisable.forEach(function(tip) { + if (options.tipsDisable) + options.tipsDisable.forEach(tip => { tip .hideTip() .disabled(true); }); - if(_mode.usePorts()) { - var activePort; - if(typeof _mode.usePorts() === 'object' && _mode.usePorts().eventPort) - activePort = _mode.usePorts().eventPort(); + if (_mode.usePorts()) { + let activePort; + if (typeof _mode.usePorts() === 'object' && _mode.usePorts().eventPort) + activePort = _mode.usePorts().eventPort(d3Event); else activePort = diagram.getPort(diagram.nodeKey.eval(n), null, 'out') - || diagram.getPort(diagram.nodeKey.eval(n), null, 'in'); - if(!activePort) + || diagram.getPort(diagram.nodeKey.eval(n), null, 'in'); + if (!activePort) return; _sourceDown = {node: n, port: activePort}; _hintData = [{source: port_pos(activePort)}]; } else { _sourceDown = {node: n}; - _hintData = [{source: {x: _sourceDown.node.cola.x, y: _sourceDown.node.cola.y}}]; + _hintData = [{ + source: {x: _sourceDown.node.cola.x, y: _sourceDown.node.cola.y}, + }]; } }) - .on('mousemove.draw-graphs', function(n) { - var msg; - d3.event.stopPropagation(); - if(_sourceDown) { - var coords = dc_graph.event_coords(diagram); - if(check_invalid_drag(coords)) + .on('mousemove.draw-graphs', n => { + let msg; + d3Event.stopPropagation(); + if (_sourceDown) { + const coords = eventCoords(diagram, d3Event); + if (check_invalid_drag(coords, d3Event)) return; - var oldTarget = _targetMove; - if(n === _sourceDown.node) { - _mode.conduct().invalidTargetMessage && - console.log(_mode.conduct().invalidTargetMessage(_sourceDown, _sourceDown)); + const oldTarget = _targetMove; + if (n === _sourceDown.node) { + _mode.conduct().invalidTargetMessage + && console.log( + _mode.conduct().invalidTargetMessage(_sourceDown, _sourceDown), + ); _targetMove = null; _hintData[0].target = null; - } - else if(_mode.usePorts()) { - var activePort; - if(typeof _mode.usePorts() === 'object' && _mode.usePorts().eventPort) - activePort = _mode.usePorts().eventPort(); + } else if (_mode.usePorts()) { + let activePort; + if (typeof _mode.usePorts() === 'object' && _mode.usePorts().eventPort) + activePort = _mode.usePorts().eventPort(d3Event); else activePort = diagram.getPort(diagram.nodeKey.eval(n), null, 'in') - || diagram.getPort(diagram.nodeKey.eval(n), null, 'out'); - if(activePort) + || diagram.getPort(diagram.nodeKey.eval(n), null, 'out'); + if (activePort) _targetMove = {node: n, port: activePort}; else _targetMove = null; - } else if(!_targetMove || n !== _targetMove.node) { + } else if (!_targetMove || n !== _targetMove.node) { _targetMove = {node: n}; } - if(_mode.conduct().changeDragTarget) { - var change; - if(_mode.usePorts()) { - var oldPort = oldTarget && oldTarget.port, + if (_mode.conduct().changeDragTarget) { + let change; + if (_mode.usePorts()) { + const oldPort = oldTarget && oldTarget.port, newPort = _targetMove && _targetMove.port; change = oldPort !== newPort; } else { - var oldNode = oldTarget && oldTarget.node, + const oldNode = oldTarget && oldTarget.node, newNode = _targetMove && _targetMove.node; - change = oldNode !== newNode; + change = oldNode !== newNode; } - if(change) - if(_mode.conduct().changeDragTarget(_sourceDown, _targetMove)) { + if (change) { + if (_mode.conduct().changeDragTarget(_sourceDown, _targetMove)) { _crossout = null; - if(options.negativeTip) + if (options.negativeTip) options.negativeTip.hideTip(); - msg = _mode.conduct().validTargetMessage && _mode.conduct().validTargetMessage() || - 'matches'; - if(options.positiveTip) { + msg = _mode.conduct().validTargetMessage + && _mode.conduct().validTargetMessage() + || 'matches'; + if (options.positiveTip) { options.positiveTip - .content(function(_, k) { k(msg); }) - .displayTip(_mode.usePorts() ? _targetMove.port : _targetMove.node); + .content(() => msg) + .displayTip( + _mode.usePorts() ? _targetMove.port : _targetMove.node, + ); } _targetValid = true; } else { - _crossout = _mode.usePorts() ? - _targetMove && _targetMove.port : - _targetMove && _targetMove.node; - if(_targetMove && _mode.conduct().invalidTargetMessage) { - if(options.positiveTip) + _crossout = _mode.usePorts() + ? _targetMove && _targetMove.port + : _targetMove && _targetMove.node; + if (_targetMove && _mode.conduct().invalidTargetMessage) { + if (options.positiveTip) options.positiveTip.hideTip(); - msg = _mode.conduct().invalidTargetMessage(_sourceDown, _targetMove); - console.log(msg); - if(options.negativeTip) { + msg = _mode.conduct().invalidTargetMessage( + _sourceDown, + _targetMove, + ); + if (options.negativeTip) { options.negativeTip - .content(function(_, k) { k(msg); }) - .displayTip(_mode.usePorts() ? _targetMove.port : _targetMove.node); + .content(() => msg) + .displayTip( + _mode.usePorts() + ? _targetMove.port + : _targetMove.node, + ); } } _targetValid = false; } + } } else _targetValid = true; - if(_targetMove) { - if(_targetMove.port) - _hintData[0].target = port_pos(activePort); + if (_targetMove) { + if (_targetMove.port) + _hintData[0].target = port_pos(_targetMove.port); else _hintData[0].target = {x: n.cola.x, y: n.cola.y}; - } - else { + } else { _hintData[0].target = {x: coords[0], y: coords[1]}; } update_hint(); update_crossout(); } }) - .on('mouseup.draw-graphs', function(n) { + .on('mouseup.draw-graphs', _n => { _crossout = null; - if(options.negativeTip) + if (options.negativeTip) options.negativeTip.hideTip(true); - if(options.positiveTip) + if (options.positiveTip) options.positiveTip.hideTip(true); - if(options.tipsDisable) - options.tipsDisable.forEach(function(tip) { + if (options.tipsDisable) + options.tipsDisable.forEach(tip => { tip.disabled(false); }); - // allow keyboard mode to hear this one (again, we need better cooperation) - // d3.event.stopPropagation(); - if(_sourceDown && _targetValid) { - var finishPromise; - if(_mode.conduct().finishDragEdge) + if (_sourceDown && _targetValid) { + let finishPromise; + if (_mode.conduct().finishDragEdge) finishPromise = _mode.conduct().finishDragEdge(_sourceDown, _targetMove); else finishPromise = Promise.resolve(true); - var source = _sourceDown, target = _targetMove; - finishPromise.then(function(ok) { - if(ok) + const source = _sourceDown, target = _targetMove; + finishPromise.then(ok => { + if (ok) create_edge(diagram, source, target); }); - } - else if(_sourceDown) { - if(_mode.conduct().cancelDragEdge) + } else if (_sourceDown) { + if (_mode.conduct().cancelDragEdge) _mode.conduct().cancelDragEdge(_sourceDown); } erase_hint(); update_crossout(); }); + diagram.svg() - .on('mousedown.draw-graphs', function() { + .on('mousedown.draw-graphs', () => { _sourceDown = null; }) - .on('mousemove.draw-graphs', function() { - var data = []; - if(_sourceDown) { // drawing edge - var coords = dc_graph.event_coords(diagram); + .on('mousemove.draw-graphs', () => { + const _data = []; + if (_sourceDown) { // drawing edge + const coords = eventCoords(diagram, d3Event); _crossout = null; - if(check_invalid_drag(coords)) + if (check_invalid_drag(coords, d3Event)) return; - if(_mode.conduct().dragCanvas) + if (_mode.conduct().dragCanvas) _mode.conduct().dragCanvas(_sourceDown, coords); - if(_mode.conduct().changeDragTarget && _targetMove) + if (_mode.conduct().changeDragTarget && _targetMove) _mode.conduct().changeDragTarget(_sourceDown, null); _targetMove = null; _hintData[0].target = {x: coords[0], y: coords[1]}; @@ -324,31 +371,36 @@ dc_graph.draw_graphs = function(options) { update_crossout(); } }) - .on('mouseup.draw-graphs', function() { + .on('mouseup.draw-graphs', () => { _crossout = null; - if(options.negativeTip) + if (options.negativeTip) options.negativeTip.hideTip(true); - if(options.positiveTip) + if (options.positiveTip) options.positiveTip.hideTip(true); - if(options.tipsDisable) - options.tipsDisable.forEach(function(tip) { + if (options.tipsDisable) + options.tipsDisable.forEach(tip => { tip.disabled(false); }); - if(_sourceDown) { // drag-edge - if(_mode.conduct().cancelDragEdge) + if (_sourceDown) { // drag-edge + if (_mode.conduct().cancelDragEdge) _mode.conduct().cancelDragEdge(_sourceDown); erase_hint(); } else { // click-node - if(d3.event.target === this && _mode.clickCreatesNodes()) - create_node(diagram, dc_graph.event_coords(diagram)); + if (d3Event.target === d3Event.currentTarget && _mode.clickCreatesNodes()) + create_node(diagram, eventCoords(diagram, d3Event)); } update_crossout(); }); - if(!_edgeLayer) - _edgeLayer = diagram.g().append('g').attr('class', 'draw-graphs'); + const diagramG = diagram.g(); + + const edgeLayerSelection = diagramG.selectAll('g.draw-graphs') + .data([1]); + _edgeLayer = edgeLayerSelection.enter().append('g') + .attr('class', 'draw-graphs') + .merge(edgeLayerSelection); } - function remove(diagram, node, edge, ehover) { + function remove(diagram, node, _edge, _ehover) { node .on('mousedown.draw-graphs', null) .on('mousemove.draw-graphs', null) @@ -359,9 +411,9 @@ dc_graph.draw_graphs = function(options) { .on('mouseup.draw-graphs', null); } - var _mode = dc_graph.mode('highlight-paths', { - draw: draw, - remove: remove + const _mode = mode('highlight-paths', { + draw, + remove, }); // update the data source/destination @@ -378,6 +430,9 @@ dc_graph.draw_graphs = function(options) { _mode.crossSize = property(15); _mode.crossWidth = property(5); + // hint line stroke color + _mode.hintStroke = property('black'); + // really this is a behavior or strategy _mode.conduct = property({}); @@ -392,5 +447,4 @@ dc_graph.draw_graphs = function(options) { }; return _mode; -}; - +} diff --git a/src/dropdown.js b/src/dropdown.js index 1b3e19d5..4e743e3d 100644 --- a/src/dropdown.js +++ b/src/dropdown.js @@ -1,75 +1,77 @@ -dc_graph.dropdown = function() { - dc_graph.dropdown.unique_id = (dc_graph.dropdown.unique_id || 16) + 1; - var _dropdown = { - id: 'id' + dc_graph.dropdown.unique_id, +import { property } from './core.js'; + +export function dropdown() { + dropdown.unique_id = (dropdown.unique_id || 16)+1; + const _dropdown = { + id: `id${dropdown.unique_id}`, parent: property(null), - show: function(key, x, y) { - var dropdown = _dropdown.parent().root() - .selectAll('div.dropdown.' + _dropdown.id).data([0]); - var dropdownEnter = dropdown + show(key, x, y) { + const dropdown = _dropdown.parent().root() + .selectAll(`div.dropdown.${_dropdown.id}`).data([0]); + const dropdownEnter = dropdown .enter().append('div') - .attr('class', 'dropdown ' + _dropdown.id); + .attr('class', `dropdown ${_dropdown.id}`); dropdown .style('visibility', 'visible') - .style('left', x + 'px') - .style('top', y + 'px'); - var capture; - var hides = _dropdown.hideOn().split('|'); - var selects = _dropdown.selectOn().split('|'); - if(hides.includes('leave')) - dropdown.on('mouseleave', function() { + .style('left', `${x}px`) + .style('top', `${y}px`); + let capture; + const hides = _dropdown.hideOn().split('|'); + const selects = _dropdown.selectOn().split('|'); + if (hides.includes('leave')) + dropdown.on('mouseleave', () => { dropdown.style('visibility', 'hidden'); }); - else if(hides.includes('clickout')) { - var diagram = _dropdown.parent(); + else if (hides.includes('clickout')) { + const diagram = _dropdown.parent(); capture = diagram.svg().append('rect') .attr('x', 0) .attr('y', 0) .attr('width', diagram.width()) .attr('height', diagram.height()) .attr('opacity', 0) - .on('click', function() { + .on('click', () => { capture.remove(); dropdown.style('visibility', 'hidden'); }); } - var container = dropdown; - if(_dropdown.scrollHeight()) { - var height = _dropdown.scrollHeight(); - if(typeof height === 'number') - height = height + 'px'; + let container = dropdown; + if (_dropdown.scrollHeight()) { + let height = _dropdown.scrollHeight(); + if (typeof height === 'number') + height = `${height}px`; dropdown .style('max-height', height) .property('scrollTop', 0); dropdownEnter .style('overflow-y', 'auto') - .append('div') + .append('div') .attr('class', 'scroller'); container = dropdown.selectAll('div.scroller'); } - var values = _dropdown.fetchValues()(key, function(values) { - var items = container + const _values = _dropdown.fetchValues()(key, values => { + const items = container .selectAll('div.dropdown-item').data(values); items .enter().append('div') .attr('class', 'dropdown-item'); items.exit().remove(); - var select_event = null; - if(selects.includes('click')) + let select_event = null; + if (selects.includes('click')) select_event = 'click'; - else if(selects.includes('hover')) + else if (selects.includes('hover')) select_event = 'mouseenter'; items - .text(function(item) { return _dropdown.itemText()(item); }); - if(select_event) { + .text(item => _dropdown.itemText()(item)); + if (select_event) { items - .on(select_event + '.select', function(d) { + .on(`${select_event}.select`, d => { _dropdown.itemSelected()(d); }); } - if(hides.includes('clickitem')) { + if (hides.includes('clickitem')) { items - .on('click.hide', function(d) { + .on('click.hide', _d => { capture.remove(); dropdown.style('visibility', 'hidden'); }); @@ -79,10 +81,12 @@ dc_graph.dropdown = function() { hideOn: property('clickout|clickitem'), selectOn: property('click'), height: property(10), - itemText: property(function(x) { return x; }), - itemSelected: property(function() {}), - fetchValues: property(function(key, k) { k([]); }), - scrollHeight: property('12em') + itemText: property(x => x), + itemSelected: property(() => {}), + fetchValues: property((key, k) => { + k([]); + }), + scrollHeight: property('12em'), }; return _dropdown; -}; +} diff --git a/src/dynagraph_layout.js b/src/dynagraph_layout.js index 1422392d..fec030bf 100644 --- a/src/dynagraph_layout.js +++ b/src/dynagraph_layout.js @@ -1,30 +1,36 @@ /** - * `dc_graph.dynagraph_layout` connects to dynagraph-wasm and does dynamic directed graph layout. - * @class dynagraph_layout - * @memberof dc_graph - * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.dynagraph_layout} - **/ -dc_graph.dynagraph_layout = function(id, layout) { - var _layoutId = id || uuid(); - const _Gname = _layoutId; - var _layout; - var _dispatch = d3.dispatch('tick', 'start', 'end'); - var _tick, _done; - var _nodes = {}, _edges = {}; - var _linesOut = [], _incrIn = [], _opened = false, _open_graph; - var _lock = 0; + * Dynagraph-wasm layout adaptor for dc.graph.js + * @module dynagraph_layout + */ +import { dispatch } from 'd3-dispatch'; +import { property, uuid } from './core.js'; +import { regenerateObjects } from './generate_objects.js'; +import { graphvizAttrs } from './graphviz_attrs.js'; +/** + * `dynagraphLayout` connects to dynagraph WebAssembly module and does dynamic directed graph layout. + * @param {String} [id=uuid()] - Unique identifier + * @param {String} [layout] - Layout algorithm name + * @return {Object} dynagraph layout engine + */ +export function dynagraphLayout(id, layout) { + const _layoutId = id || uuid(); + const _Gname = _layoutId; + let _layout = null; + const _dispatch = (globalThis.d3?.dispatch || dispatch)('tick', 'start', 'end'); + let _tick, _done; + const _nodes = {}, _edges = {}; + let _linesOut = [], _incrIn = [], _opened = false, _open_graph; + let _lock = 0; let bb = null; // dg2incr function dg2incr_coord(c) { const [x, y] = c; - return [x, /*(bb && bb[0][1] || 0)*/ - y]; + return [x, /*(bb && bb[0][1] || 0)*/ -y]; } - function dg2incr_graph_attrs() { return [ ['rankdir', _layout.rankdir()], @@ -36,219 +42,254 @@ dc_graph.dynagraph_layout = function(id, layout) { function dg2incr_node_attrs(n) { const attr_pairs = []; - if(n.x !== undefined && n.y !== undefined) + if (n.x !== undefined && n.y !== undefined) attr_pairs.push(['pos', dg2incr_coord([n.x, n.y]).map(String).join(',')]); return attr_pairs; } function dg2incr_node_attrs_changed(n, n2) { const attr_pairs = []; - if(n2.x !== undefined && n2.y !== undefined && (n2.x !== n.x || n2.y !== n.y)) + if (n2.x !== undefined && n2.y !== undefined && (n2.x !== n.x || n2.y !== n.y)) attr_pairs.push(['pos', dg2incr_coord([n2.x, n2.y]).map(String).join(',')]); return attr_pairs; } - function dg2incr_edge_attrs(e) { + function dg2incr_edge_attrs(_e) { return []; } function mq(x) { // maybe quote - if(x === +x) // isNumber + if (x === +x) // isNumber return x; - else if(/^[A-Za-z_][A-Za-z0-9_]*$/.test(x)) + else if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(x)) return x; - else return '"' + x + '"'; + else return `"${x}"`; } function print_incr_attrs(attr_pairs) { - return '[' + attr_pairs.map(([a,b]) => `${mq(a)}=${mq(b)}`).join(', ') + ']'; + return `[${attr_pairs.map(([a, b]) => `${mq(a)}=${mq(b)}`).join(', ')}]`; } // incr2dg function incr2dg_coord(c) { const [x, y] = c; - return [+x, /*(bb && bb[0][1] || 0)*/ - y]; + return [+x, /*(bb && bb[0][1] || 0)*/ -y]; } function incr2dg_bb(bb) { - const [x1,y1,x2,y2] = bb.split(','); - return [incr2dg_coord([x1,y1]), incr2dg_coord([x2,y2])]; + const [x1, y1, x2, y2] = bb.split(','); + return [incr2dg_coord([x1, y1]), incr2dg_coord([x2, y2])]; } function incr2dg_node_attrs(n) { const attrs = {}; - if(n.pos) + if (n.pos) [attrs.x, attrs.y] = incr2dg_coord(n.pos.split(',').map(Number)); return attrs; } function incr2dg_edge_attrs(e) { const attrs = {}; - if(e.pos) + if (e.pos) attrs.points = e.pos.split(' ') .map(coord => coord.split(',').map(Number)) .map(incr2dg_coord) - .map(([x,y]) => ({x,y})); + .map(([x, y]) => ({x, y})); return attrs; } function runCommands(cmds) { - for(const cmd of cmds) { + for (const cmd of cmds) { const {action, kind} = cmd; - switch(`${action}_${kind}`) { + switch (`${action}_${kind}`) { case 'open_graph': { const {attrs} = cmd; - console.log('open graph', attrs); - console.log('open graph bb', bb) - bb = incr2dg_bb(attrs.bb) - console.log('open graph bb', bb) + if (_layout.verbose()) { + console.log('open graph', attrs); + console.log('open graph bb', bb); + } + bb = incr2dg_bb(attrs.bb); + if (_layout.verbose()) { + console.log('open graph bb', bb); + } break; } case 'modify_graph': { const {attrs} = cmd; - console.log('modify graph', attrs); - console.log('modify graph bb', bb) - bb = incr2dg_bb(attrs.bb) - console.log('modify graph bb', bb) + if (_layout.verbose()) { + console.log('modify graph', attrs); + console.log('modify graph bb', bb); + } + bb = incr2dg_bb(attrs.bb); + if (_layout.verbose()) { + console.log('modify graph bb', bb); + } break; } case 'close_graph': { - console.log('close graph'); + if (_layout.verbose()) { + console.log('close graph'); + } break; } case 'insert_node': { const {node, attrs} = cmd; - console.log('insert node', node, attrs); - console.log('insert node2', _nodes[node]) + if (_layout.verbose()) { + console.log('insert node', node, attrs); + console.log('insert node2', _nodes[node]); + } Object.assign(_nodes[node], incr2dg_node_attrs(attrs)); - console.log('insert node3', _nodes[node]) + if (_layout.verbose()) { + console.log('insert node3', _nodes[node]); + } break; } case 'modify_node': { const {node, attrs} = cmd; - console.log('modify node', node, attrs); - console.log('modify node2', _nodes[node]) + if (_layout.verbose()) { + console.log('modify node', node, attrs); + console.log('modify node2', _nodes[node]); + } Object.assign(_nodes[node], incr2dg_node_attrs(attrs)); - console.log('modify node3', _nodes[node]) + if (_layout.verbose()) { + console.log('modify node3', _nodes[node]); + } break; } case 'delete_node': { const {node} = cmd; - console.log('delete node', node); + if (_layout.verbose()) { + console.log('delete node', node); + } break; } case 'insert_edge': { const {edge, source, target, attrs} = cmd; - console.log('insert edge', edge, source, target, attrs); - console.log('insert edge2', _edges[edge]) + if (_layout.verbose()) { + console.log('insert edge', edge, source, target, attrs); + console.log('insert edge2', _edges[edge]); + } Object.assign(_edges[edge], incr2dg_edge_attrs(attrs)); - console.log('insert edge3', _edges[edge]) + if (_layout.verbose()) { + console.log('insert edge3', _edges[edge]); + } break; } case 'modify_edge': { const {edge, attrs} = cmd; - console.log('modify edge', edge, attrs); - console.log('modify edge2', _edges[edge]) + if (_layout.verbose()) { + console.log('modify edge', edge, attrs); + console.log('modify edge2', _edges[edge]); + } Object.assign(_edges[edge], incr2dg_edge_attrs(attrs)); - console.log('modify edge3', _edges[edge]) + if (_layout.verbose()) { + console.log('modify edge3', _edges[edge]); + } break; } case 'delete_edge': { const {edge} = cmd; - console.log('delete edge', edge); + if (_layout.verbose()) { + console.log('delete edge', edge); + } break; } } } } function receiveIncr(text) { - console.log(text); + if (_layout.verbose()) { + console.log(text); + } let cmds = null; try { - const parseIncrface = self.parseIncrface || (self.incrface && self.incrface.parse); - if(!parseIncrface) { - console.log('parseIncrface not available, skipping'); + const parseIncrface = globalThis.parseIncrface || self.parseIncrface + || (self.incrface && self.incrface.parse); + if (!parseIncrface) { + console.log('[DYNAGRAPH] parseIncrface not available, skipping'); return; } cmds = parseIncrface(text); - } catch(xep) { - console.log('incrface parse failed', xep) + } catch (xep) { + console.log('[DYNAGRAPH] incrface parse failed', xep); } - if (!cmds) + if (!cmds) { return; - for(const cmd of cmds) { + } + for (const cmd of cmds) { const {action, kind, graph} = cmd; - if(action === 'message') { - console.warn('dynagraph message', cmd.message); + if (action === 'message') { + console.warn('[DYNAGRAPH] dynagraph message', cmd.message); continue; } - if(graph !== _Gname) { - console.warn('graph name mismatch', _Gname, graph); + if (graph !== _Gname) { + console.warn('[DYNAGRAPH] graph name mismatch', _Gname, 'vs', graph); continue; } - switch(`${action}_${kind}`) { + switch (`${action}_${kind}`) { case 'lock_graph': _lock++; break; case 'unlock_graph': // maybe error on negative lock? - if(--_lock <= 0) { + if (--_lock <= 0) { runCommands(_incrIn); - _incrIn = [] + _incrIn = []; } break; default: - if(_lock > 0) + if (_lock > 0) { _incrIn.push(cmd); - else + } else { runCommands([cmd]); + } } } _done(); } - function init(options) { + function init(_options) { self.receiveIncr = receiveIncr; _opened = false; - _open_graph = `open graph ${mq(_Gname)} ${print_incr_attrs(dg2incr_graph_attrs())}` + _open_graph = `open graph ${mq(_Gname)} ${print_incr_attrs(dg2incr_graph_attrs())}`; } - function data(nodes, edges, clusters) { + function data(nodes, edges, _clusters) { const linesOutDeleteNode = []; - var wnodes = regenerate_objects(_nodes, nodes, null, - function key(v) { - return v.dcg_nodeKey; - }, function assign(v1, v) { + const wnodes = regenerateObjects(_nodes, nodes, null, v => v.dcg_nodeKey, (v1, v) => { v1.dcg_nodeKey = v.dcg_nodeKey; v1.width = v.width; v1.height = v.height; - if(v.dcg_nodeFixed) { + if (v.dcg_nodeFixed) { v1.x = v.dcg_nodeFixed.x; v1.y = v.dcg_nodeFixed.y; } const na = dg2incr_node_attrs_changed(v1, v); - if(na.length) - _linesOut.push(`modify node ${mq(_Gname)} ${mq(v1.dcg_nodeKey)} ${print_incr_attrs(na)}`); - }, function create(k, o) { - _linesOut.push(`insert node ${mq(_Gname)} ${mq(k)} ${print_incr_attrs(dg2incr_node_attrs(o))}`); - }, function destroy(k) { + if (na.length) + _linesOut.push( + `modify node ${mq(_Gname)} ${mq(v1.dcg_nodeKey)} ${print_incr_attrs(na)}`, + ); + }, (k, o) => { + _linesOut.push( + `insert node ${mq(_Gname)} ${mq(k)} ${print_incr_attrs(dg2incr_node_attrs(o))}`, + ); + }, k => { linesOutDeleteNode.push(`delete node ${mq(_Gname)} ${mq(k)}`); }); - var wedges = regenerate_objects(_edges, edges, null, function key(e) { - return e.dcg_edgeKey; - }, function assign(e1, e) { + const wedges = regenerateObjects(_edges, edges, null, e => e.dcg_edgeKey, (e1, e) => { e1.dcg_edgeKey = e.dcg_edgeKey; e1.dcg_edgeSource = e.dcg_edgeSource; e1.dcg_edgeTarget = e.dcg_edgeTarget; - }, function create(k, o, e) { - _linesOut.push(`insert edge ${mq(_Gname)} ${mq(k)} ${mq(e.dcg_edgeSource)} ${mq(e.dcg_edgeTarget)} ${print_incr_attrs(dg2incr_edge_attrs(e))}`); - }, function destroy(k, e) { + }, (k, o, e) => { + _linesOut.push( + `insert edge ${mq(_Gname)} ${mq(k)} ${mq(e.dcg_edgeSource)} ${ + mq(e.dcg_edgeTarget) + } ${print_incr_attrs(dg2incr_edge_attrs(e))}`, + ); + }, (k, _e) => { _linesOut.push(`delete edge ${mq(_Gname)} ${k}`); }); _linesOut.push(...linesOutDeleteNode); function dispatchState(event) { - _dispatch[event]( - wnodes, - wedges - ); + _dispatch.call(event, null, wnodes, wedges); } _tick = function() { dispatchState('tick'); @@ -258,69 +299,83 @@ dc_graph.dynagraph_layout = function(id, layout) { }; } - function start() { - if(_linesOut.length) { + async function start() { + // Ensure dynagraph is initialized for main thread (no-op in worker) + if (globalThis.ensureDynagraphInitialized && typeof importScripts === 'undefined') { + try { + await globalThis.ensureDynagraphInitialized(); + } catch (error) { + console.error('[DYNAGRAPH] Failed to initialize dynagraph:', error); + return; + } + } + + if (_linesOut.length) { const open = _opened ? [] : [_open_graph]; _opened = true; - const actions = _linesOut.length > 1 ? [ - `lock graph ${mq(_Gname)}`, - ... _linesOut, - `unlock graph ${mq(_Gname)}` - ] : _linesOut; + const actions = _linesOut.length > 1 + ? [ + `lock graph ${mq(_Gname)}`, + ..._linesOut, + `unlock graph ${mq(_Gname)}`, + ] + : _linesOut; const input = [...open, ...actions].join('\n'); - console.log('dynagraph input:', input); + if (_layout.verbose()) { + console.log('dynagraph input:', input); + } self.incrface_input = input; _linesOut = []; + } else { + _done(); } - else _done(); } function stop() { } _layout = { - ...dc_graph.graphviz_attrs(), - layoutAlgorithm: function() { + ...graphvizAttrs(), + layoutAlgorithm() { return layout; }, - layoutId: function() { + layoutId() { return _layoutId; }, - supportsWebworker: function() { + supportsWebworker() { return true; }, resolution: property({x: 5, y: 5}), defaultsize: property({width: 50, height: 50}), separation: property({x: 20, y: 20}), - on: function(event, f) { - if(arguments.length === 1) + verbose: property(false), + on(event, f) { + if (arguments.length === 1) return _dispatch.on(event); _dispatch.on(event, f); return this; }, - init: function(options) { - this.optionNames().forEach(function(option) { + init(options) { + this.optionNames().forEach(option => { options[option] = options[option] || this[option](); - }.bind(this)); + }); init(options); return this; }, - data: function(graph, nodes, edges) { + data(graph, nodes, edges) { data(nodes, edges); }, - start: function() { - start(); + async start() { + await start(); }, - stop: function() { + stop() { stop(); }, - optionNames: function() { - return ['resolution', 'defaultsize', 'separation']; + optionNames() { + return ['resolution', 'defaultsize', 'separation', 'verbose']; }, - populateLayoutNode: function(layout, node) {}, - populateLayoutEdge: function() {} + populateLayoutNode(_layout, _node) {}, + populateLayoutEdge() {}, }; return _layout; -}; - -dc_graph.dynagraph_layout.scripts = ['d3.js', 'dynagraph-wasm.js', 'incrface-umd.js']; +} diff --git a/src/edit_text.js b/src/edit_text.js index 9f88ea29..c4fecd21 100644 --- a/src/edit_text.js +++ b/src/edit_text.js @@ -1,42 +1,42 @@ // adapted from // http://stackoverflow.com/questions/9308938/inline-text-editing-in-svg/#26644652 -dc_graph.edit_text = function(parent, options) { - var foreign = parent.append('foreignObject').attr({ - height: '100%', - width: '100%' // don't wrap - }); - var padding = options.padding !== undefined ? options.padding : 2; +import { event as d3Event } from 'd3-selection'; + +export function editText(parent, options) { + const foreign = parent.append('foreignObject') + .attr('height', '100%') + .attr('width', '100%'); // don't wrap + const padding = options.padding !== undefined ? options.padding : 2; function reposition() { - var pos; - switch(options.align) { - case 'left': - pos = [options.box.x-padding, options.box.y-padding]; - break; - default: - case 'center': - pos = [ - options.box.x + (options.box.width - textdiv.node().offsetWidth)/2, - options.box.y + (options.box.height - textdiv.node().offsetHeight)/2 - ]; - break; + let pos; + switch (options.align) { + case 'left': + pos = [options.box.x-padding, options.box.y-padding]; + break; + default: + case 'center': + pos = [ + options.box.x+(options.box.width-textdiv.node().offsetWidth)/2, + options.box.y+(options.box.height-textdiv.node().offsetHeight)/2, + ]; + break; } - foreign.attr('transform', 'translate(' + pos.join(' ') + ')'); + foreign.attr('transform', `translate(${pos.join(' ')})`); } - var textdiv = foreign.append('xhtml:div'); - var text = options.text || "type on me"; - textdiv.text(text).attr({ - contenteditable: true, - width: 'auto', - class: options.class || null - }).style({ - display: 'inline-block', - 'background-color': 'white', - padding: padding + 'px' - }); + const textdiv = foreign.append('xhtml:div'); + const text = options.text || 'type on me'; + textdiv.text(text) + .attr('contenteditable', true) + .attr('width', 'auto') + .attr('class', options.class || null).style({ + display: 'inline-block', + 'background-color': 'white', + padding: `${padding}px`, + }); function stopProp() { - d3.event.stopPropagation(); + d3Event.stopPropagation(); } foreign .on('mousedown.edit-text', stopProp) @@ -57,17 +57,17 @@ dc_graph.edit_text = function(parent, options) { options.finally && options.finally(); } - textdiv.on('keydown.edit-text', function() { + textdiv.on('keydown.edit-text', () => { // prevent keyboard mode from seeing this (especially delete key!) - d3.event.stopPropagation(); - if(d3.event.keyCode===13) { - d3.event.preventDefault(); + d3Event.stopPropagation(); + if (d3Event.keyCode === 13) { + d3Event.preventDefault(); } - }).on('keyup.edit-text', function() { - d3.event.stopPropagation(); - if(d3.event.keyCode===13) { + }).on('keyup.edit-text', () => { + d3Event.stopPropagation(); + if (d3Event.keyCode === 13) { accept(); - } else if(d3.event.keyCode===27) { + } else if (d3Event.keyCode === 27) { cancel(); } reposition(); @@ -75,14 +75,14 @@ dc_graph.edit_text = function(parent, options) { reposition(); textdiv.node().focus(); - var range = document.createRange(); - if(options.selectText) { + const range = document.createRange(); + if (options.selectText) { range.selectNodeContents(textdiv.node()); } else { range.setStart(textdiv.node(), 1); range.setEnd(textdiv.node(), 1); } - var sel = window.getSelection(); + const sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); -}; +} diff --git a/src/engine.js b/src/engine.js index fc708339..c6536700 100644 --- a/src/engine.js +++ b/src/engine.js @@ -1,152 +1,163 @@ -dc_graph.spawn_engine = function(layout, args, worker) { +/** + * Layout engine registry and management + * @module engine + */ + +import { colaLayout } from './cola_layout.js'; +import { d3v4ForceLayout } from './d3v4_force_layout.js'; +import { dagreLayout } from './dagre_layout.js'; +import { dynagraphLayout } from './dynagraph_layout.js'; +import { flexboxLayout } from './flexbox_layout.js'; +import { graphvizLayout } from './graphviz_layout.js'; +import { layeredLayout } from './layered_layout.js'; +import { manualLayout } from './manual_layout.js'; +import { treeLayout } from './tree_layout.js'; +import { webworkerLayout } from './webworker_layout.js'; + +export function spawnEngine(layout, args, worker) { args = args || {}; worker = worker && !!window.Worker; - var engine = dc_graph.engines.instantiate(layout, args, worker); - if(!engine) { - console.warn('layout engine ' + layout + ' not found; using default ' + dc_graph._default_engine); - engine = dc_graph.engines.instantiate(dc_graph._default_engine, args, worker); + let engine = engines.instantiate(layout, args, worker); + if (!engine) { + console.warn(`layout engine ${layout} not found; using default ${_defaultEngine}`); + engine = engines.instantiate(_defaultEngine, args, worker); } return engine; -}; +} -dc_graph._engines = [ +const _engines = [ { name: 'dagre', params: ['rankdir'], - instantiate: function() { - return dc_graph.dagre_layout(); - } - }, - { - name: 'd3force', - instantiate: function() { - return dc_graph.d3_force_layout(); - } + instantiate() { + return dagreLayout(); + }, }, { name: 'd3v4force', - instantiate: function() { - return dc_graph.d3v4_force_layout(); - } + instantiate() { + return d3v4ForceLayout(); + }, }, { name: 'tree', - instantiate: function() { - return dc_graph.tree_layout(); - } + instantiate() { + return treeLayout(); + }, }, { names: ['circo', 'dot', 'neato', 'osage', 'twopi', 'fdp'], - instantiate: function(layout, args) { - return dc_graph.graphviz_layout(null, layout, args.server); - } + instantiate(layout, args) { + return graphvizLayout(null, layout, args.server); + }, }, { name: 'cola', params: ['lengthStrategy'], - instantiate: function() { - return dc_graph.cola_layout(); - } + instantiate() { + return colaLayout(); + }, }, { names: ['dynadag'], workerName: 'dynagraph', - instantiate: function(layout, args) { - return dc_graph.dynagraph_layout(null, layout, args.server); - } + instantiate(layout, args) { + return dynagraphLayout(null, layout, args.server); + }, }, { name: 'manual', - instantiate: function() { - return dc_graph.manual_layout(); - } + instantiate() { + return manualLayout(); + }, }, { name: 'flexbox', - instantiate: function() { - return dc_graph.flexbox_layout(); - } + instantiate() { + return flexboxLayout(); + }, }, { name: 'layered', - instantiate: function() { - return dc_graph.layered_layout(); - } - } + instantiate() { + return layeredLayout(); + }, + }, ]; -dc_graph._default_engine = 'cola'; +const _defaultEngine = 'cola'; -dc_graph.engines = { - entry_pred: function(layoutName) { +export const engines = { + entry_pred(layoutName) { return function(e) { return e.name && e.name === layoutName || e.names && e.names.includes(layoutName); }; }, - get: function(layoutName) { - return dc_graph._engines.find(this.entry_pred(layoutName)); + get(layoutName) { + return _engines.find(this.entry_pred(layoutName)); }, - is_directed: function(layoutName) { + is_directed(layoutName) { // to a first approximation. cola is sometimes directed return ['dagre', 'dot'].includes(layoutName); }, - instantiate: function(layout, args, worker) { - var entry = this.get(layout); - if(!entry) + instantiate(layout, args, worker) { + const entry = this.get(layout); + if (!entry) return null; - var engine = entry.instantiate(layout, args), - params = entry.params || []; - params.forEach(function(p) { - if(args[p]) + let engine = entry.instantiate(layout, args); + const params = entry.params || []; + params.forEach(p => { + if (args[p]) engine[p](args[p]); }); - if(engine.supportsWebworker && engine.supportsWebworker() && worker) - engine = dc_graph.webworker_layout(engine, entry.workerName); + if (engine.supportsWebworker && engine.supportsWebworker() && worker) + engine = webworkerLayout(engine, entry.workerName); return engine; }, - available: function() { - return dc_graph._engines.reduce(function(avail, entry) { - return avail.concat(entry.name ? [entry.name] : entry.names); - }, []); + available() { + return _engines.reduce( + (avail, entry) => avail.concat(entry.name ? [entry.name] : entry.names), + [], + ); }, - unregister: function(layoutName) { + unregister(layoutName) { // meh. this is a bit much. there is such a thing as making the api too "easy". - var i = dc_graph._engines.findIndex(this.entry_pred(layoutName)); - var remove = false; - if(i < 0) + const i = _engines.findIndex(this.entry_pred(layoutName)); + let remove = false; + if (i < 0) return false; - var entry = dc_graph._engines[i]; - if(entry.name === layoutName) + const entry = _engines[i]; + if (entry.name === layoutName) remove = true; else { - var j = entry.names.indexOf(layoutName); - if(j >= 0) + const j = entry.names.indexOf(layoutName); + if (j >= 0) entry.names.splice(j, 1); else console.warn('search for engine failed', layoutName); - if(entry.names.length === 0) + if (entry.names.length === 0) remove = true; } - if(remove) - dc_graph._engines.splice(i, 1); + if (remove) + _engines.splice(i, 1); return true; }, - register: function(entry) { - var that = this; - if(!entry.instantiate) { + register(entry) { + const that = this; + if (!entry.instantiate) { console.error('engine definition needs instantiate: function(layout, args) { ... }'); return this; } - if(entry.name) + if (entry.name) this.unregister(entry.name); - else if(entry.names) - entry.names.forEach(function(layoutName) { + else if (entry.names) + entry.names.forEach(layoutName => { that.unregister(layoutName); }); else { console.error('engine definition needs name or names[]'); return this; } - dc_graph._engines.push(entry); + _engines.push(entry); return this; - } + }, }; diff --git a/src/expand_collapse.js b/src/expand_collapse.js index 79a76741..6f45265f 100644 --- a/src/expand_collapse.js +++ b/src/expand_collapse.js @@ -1,171 +1,197 @@ -dc_graph.expand_collapse = function(options) { - if(typeof options === 'function') { +import { range } from 'd3-array'; +import { event as d3Event } from 'd3-selection'; +import { deprecatedProperty, functorWrap, property } from './core.js'; +import { engines } from './engine.js'; +import { registerHighlightThingsGroup } from './highlight_things_group.js'; +import { keyboard } from './keyboard.js'; +import { mode } from './mode.js'; +import { conditionalProperties, is_a_mac } from './utils.js'; + +export function expandCollapse(options) { + if (typeof options === 'function') { options = { get_degree: arguments[0], expand: arguments[1], collapse: arguments[2], - dirs: arguments[3] + dirs: arguments[3], }; } - var _keyboard, _overNode, _overDir, _overEdge, _expanded = {}, _changing, _ignore = null; - var changing_highlight_group = dc_graph.register_highlight_things_group(options.changing_highlight_group || 'changing-highlight-group'); - var expanded_highlight_group = dc_graph.register_highlight_things_group(options.expanded_highlight_group || 'expanded-highlight-group'); - var collapse_highlight_group = dc_graph.register_highlight_things_group(options.collapse_highlight_group || 'collapse-highlight-group'); - var hide_highlight_group = dc_graph.register_highlight_things_group(options.hide_highlight_group || 'hide-highlight-group'); + let _keyboard, _overNode, _overDir, _overEdge, _changing, _ignore = null; + const _expanded = {}; + const changing_highlight_group = registerHighlightThingsGroup( + options.changing_highlight_group || 'changing-highlight-group', + ); + const expanded_highlight_group = registerHighlightThingsGroup( + options.expanded_highlight_group || 'expanded-highlight-group', + ); + const collapse_highlight_group = registerHighlightThingsGroup( + options.collapse_highlight_group || 'collapse-highlight-group', + ); + const hide_highlight_group = registerHighlightThingsGroup( + options.hide_highlight_group || 'hide-highlight-group', + ); options.dirs = options.dirs || ['both']; - options.dirs.forEach(function(dir) { + options.dirs.forEach(dir => { _expanded[dir] = new Set(); }); options.hideKey = options.hideKey || 'Alt'; options.recurseKey = options.recurseKey || 'Shift'; options.linkKey = options.linkKey || (is_a_mac ? 'Meta' : 'Control'); - if(options.dirs.length > 2) + if (options.dirs.length > 2) throw new Error('there are only two directions to expand in'); - var _gradients_added = {}; + const _gradients_added = {}; function add_gradient_def(color, diagram) { - if(_gradients_added[color]) + if (_gradients_added[color]) return; _gradients_added[color] = true; - diagram.addOrRemoveDef('spike-gradient-' + color, true, 'linearGradient', function(gradient) { - gradient.attr({ - x1: '0%', - y1: '0%', - x2: '100%', - y2: '0%', - spreadMethod: 'pad' - }); + diagram.addOrRemoveDef(`spike-gradient-${color}`, true, 'linearGradient', gradient => { + gradient.attr('x1', '0%') + .attr('y1', '0%') + .attr('x2', '100%') + .attr('y2', '0%') + .attr('spreadMethod', 'pad'); gradient.selectAll('stop').data([[0, color, 1], [100, color, '0']]) - .enter().append('stop').attr({ - offset: function(d) { - return d[0] + '%'; - }, - 'stop-color': function(d) { - return d[1]; - }, - 'stop-opacity': function(d) { - return d[2]; - } - }); + .enter().append('stop') + .attr('offset', d => `${d[0]}%`) + .attr('stop-color', d => d[1]) + .attr('stop-opacity', d => d[2]); }); } function visible_edges(diagram, edge, dir, key) { - var fil; - switch(dir) { - case 'out': - fil = function(e) { - return diagram.edgeSource.eval(e) === key; - }; - break; - case 'in': - fil = function(e) { - return diagram.edgeTarget.eval(e) === key; - }; - break; - case 'both': - fil = function(e) { - return diagram.edgeSource.eval(e) === key || diagram.edgeTarget.eval(e) === key; - }; - break; + let fil; + switch (dir) { + case 'out': + fil = function(e) { + return diagram.edgeSource.eval(e) === key; + }; + break; + case 'in': + fil = function(e) { + return diagram.edgeTarget.eval(e) === key; + }; + break; + case 'both': + fil = function(e) { + return diagram.edgeSource.eval(e) === key || diagram.edgeTarget.eval(e) === key; + }; + break; } return edge.filter(fil).data(); } - const sweep_angle = (N, ofs, span = Math.PI) => - i => ofs + ((N-1)*span/N) * (-.5 + (N > 1 ? i / (N-1) : 0)); // avoid 0/0 + const sweep_angle = (N, ofs, span = Math.PI) => i => + ofs+((N-1)*span/N)*(-.5+(N > 1 ? i/(N-1) : 0)); // avoid 0/0 function spike_directioner(rankdir, dir, N) { - if(dir==='both') + if (dir === 'both') return function(i) { - return Math.PI * (2 * i / N - 0.5); + return Math.PI*(2*i/N-0.5); }; else { - var ofs; - switch(rankdir) { - case 'LR': - ofs = 0; - break; - case 'TB': - ofs = Math.PI/2; - break; - case 'RL': - ofs = Math.PI; - break; - case 'BT': - ofs = -Math.PI/2; - break; + let ofs; + switch (rankdir) { + case 'LR': + ofs = 0; + break; + case 'TB': + ofs = Math.PI/2; + break; + case 'RL': + ofs = Math.PI; + break; + case 'BT': + ofs = -Math.PI/2; + break; } - if(dir === 'in') + if (dir === 'in') ofs += Math.PI; return sweep_angle(N, ofs); } } function produce_spikes_helper(cx, cy, rx, ry, a, spike, span, ret) { - const dx = Math.cos(a) * rx, - dy = Math.sin(a) * ry; + const dx = Math.cos(a)*rx, + dy = Math.sin(a)*ry; const dash = { - a: a * 180 / Math.PI, - x: cx + dx, - y: cy + dy, - edge: spike.pe + a: a*180/Math.PI, + x: cx+dx, + y: cy+dy, + edge: spike.pe, }; ret.push(dash); span *= 0.75; const sweep = sweep_angle(spike.children.length, a, span); - for(const i of d3.range(spike.children.length)) - produce_spikes_helper(cx + 1.5*dx, cy + 1.5*dy, rx, ry, sweep(i), spike.children[i], span, ret); + for (const i of range(spike.children.length)) + produce_spikes_helper( + cx+1.5*dx, + cy+1.5*dy, + rx, + ry, + sweep(i), + spike.children[i], + span, + ret, + ); } function produce_spikes(diagram, n, spikeses) { const ret = []; Object.keys(spikeses).forEach(dir => { - const sweep = spike_directioner(diagram.layoutEngine().rankdir(), dir, spikeses[dir].length); - for(const i of d3.range(spikeses[dir].length)) - produce_spikes_helper(0, 0, n.dcg_rx * 0.9, n.dcg_ry * 0.9, sweep(i), spikeses[dir][i], Math.PI, ret); + const sweep = spike_directioner( + diagram.layoutEngine().rankdir(), + dir, + spikeses[dir].length, + ); + for (const i of range(spikeses[dir].length)) + produce_spikes_helper( + 0, + 0, + n.dcg_rx*0.9, + n.dcg_ry*0.9, + sweep(i), + spikeses[dir][i], + Math.PI, + ret, + ); }); return ret; } function draw_stubs(diagram, node, edge, n, spikeseses) { - var spike = node + const spike = node .selectAll('g.spikes') - .data(function(n2) { - return spikeseses[diagram.nodeKey.eval(n2)] ? - [n2] : []; - }); + .data(n2 => + spikeseses[diagram.nodeKey.eval(n2)] + ? [n2] + : [] + ); spike.exit().remove(); spike - .enter().insert('g', ':first-child') + .enter().insert('g', ':first-child') .classed('spikes', true); - var rect = spike - .selectAll('rect.spike') - .data(function(n) { - var key = diagram.nodeKey.eval(n); + const rect = spike + .selectAll('rect.spike') + .data(n => { + const key = diagram.nodeKey.eval(n); return produce_spikes(diagram, n, spikeseses[key]); }); rect - .enter().append('rect') + .enter().append('rect') .classed('spike', true) - .attr({ - width: 25, - height: 3, - rx: 1, - ry: 1, - x: 0, - y: 0 - }); - rect.attr({ - fill: function(s) { - var color = s.edge ? dc_graph.functor_wrap(diagram.edgeStroke())(s.edge) : 'black'; - add_gradient_def(color, diagram); - return 'url(#spike-gradient-' + color + ')'; - }, - transform: function(d) { - return 'translate(' + d.x + ',' + d.y + ') rotate(' + d.a + ')'; - } - }); + .attr('width', 25) + .attr('height', 3) + .attr('rx', 1) + .attr('ry', 1) + .attr('x', 0) + .attr('y', 0); + rect.attr('fill', s => { + const color = s.edge ? functorWrap(diagram.edgeStroke())(s.edge) : 'black'; + add_gradient_def(color, diagram); + return `url(#spike-gradient-${color})`; + }) + .attr('transform', d => `translate(${d.x},${d.y}) rotate(${d.a})`); rect.exit().remove(); } @@ -174,64 +200,73 @@ dc_graph.expand_collapse = function(options) { } function zonedir(diagram, event, dirs, n) { - if(dirs.length === 1) // we assume it's ['out', 'in'] + if (dirs.length === 1) // we assume it's ['out', 'in'] return dirs[0]; - var bound = diagram.root().node().getBoundingClientRect(); - var invert = diagram.invertCoord([event.clientX - bound.left,event.clientY - bound.top]), + const bound = diagram.root().node().getBoundingClientRect(); + const invert = diagram.invertCoord([event.clientX-bound.left, event.clientY-bound.top]), x = invert[0], y = invert[1]; - switch(diagram.layoutEngine().rankdir()) { - case 'TB': - return y > n.cola.y ? 'out' : 'in'; - case 'BT': - return y < n.cola.y ? 'out' : 'in'; - case 'LR': - return x > n.cola.x ? 'out' : 'in'; - case 'RL': - return x < n.cola.x ? 'out' : 'in'; + switch (diagram.layoutEngine().rankdir()) { + case 'TB': + return y > n.cola.y ? 'out' : 'in'; + case 'BT': + return y < n.cola.y ? 'out' : 'in'; + case 'LR': + return x > n.cola.x ? 'out' : 'in'; + case 'RL': + return x < n.cola.x ? 'out' : 'in'; } - throw new Error('unknown rankdir ' + diagram.layoutEngine().rankdir()); + throw new Error(`unknown rankdir ${diagram.layoutEngine().rankdir()}`); } - function detect_key(key) { - switch(key) { - case 'Alt': - return d3.event.altKey; - case 'Meta': - return d3.event.metaKey; - case 'Shift': - return d3.event.shiftKey; - case 'Control': - return d3.event.ctrlKey; + function detect_key(key, event) { + switch (key) { + case 'Alt': + return event.altKey; + case 'Meta': + return event.metaKey; + case 'Shift': + return event.shiftKey; + case 'Control': + return event.ctrlKey; } return false; } function highlight_hiding_node(diagram, n, edge) { - var nk = diagram.nodeKey.eval(n); - var hide_nodes_set = {}, hide_edges_set = {}; + const nk = diagram.nodeKey.eval(n); + const hide_nodes_set = {}, hide_edges_set = {}; hide_nodes_set[nk] = true; - edge.each(function(e) { - if(diagram.edgeSource.eval(e) === nk || diagram.edgeTarget.eval(e) === nk) + edge.each(e => { + if (diagram.edgeSource.eval(e) === nk || diagram.edgeTarget.eval(e) === nk) hide_edges_set[diagram.edgeKey.eval(e)] = true; }); - hide_highlight_group.highlight(hide_nodes_set, hide_edges_set); + hide_highlight_group.call('highlight', null, hide_nodes_set, hide_edges_set); } function highlight_hiding_edge(diagram, e) { - var hide_edges_set = {}; + const hide_edges_set = {}; hide_edges_set[diagram.edgeKey.eval(e)] = true; - hide_highlight_group.highlight({}, hide_edges_set); + hide_highlight_group.call('highlight', null, {}, hide_edges_set); } function partition_among_visible(tree_edges, visible, parts, nk, pe = null, seen = new Set()) { - if(seen.has(nk)) + if (seen.has(nk)) return []; seen.add(nk); let children = tree_edges[nk].nks .filter(nk => !seen.has(nk)) - .flatMap((nk2, i) => partition_among_visible(tree_edges, visible, parts, nk2, tree_edges[nk].edges[i], seen)) + .flatMap((nk2, i) => + partition_among_visible( + tree_edges, + visible, + parts, + nk2, + tree_edges[nk].edges[i], + seen, + ) + ) .filter(({nk}) => !visible.has(nk)); - if(visible.has(nk)) { + if (visible.has(nk)) { parts[nk] = children; children = []; } @@ -239,115 +274,138 @@ dc_graph.expand_collapse = function(options) { } function highlight_expand_collapse(diagram, n, node, edge, dir, recurse) { - var nk = diagram.nodeKey.eval(n); - let tree_edges = options.get_tree_edges(nk, dir, !recurse); - let visible_nodes = new Set(node.data().map(n => diagram.nodeKey.eval(n)).filter(nk => tree_edges[nk])); + const nk = diagram.nodeKey.eval(n); + const tree_edges = options.get_tree_edges(nk, dir, !recurse); + const visible_nodes = new Set( + node.data().map(n => diagram.nodeKey.eval(n)).filter(nk => tree_edges[nk]), + ); const parts = {}; - if(recurse) + if (recurse) partition_among_visible(tree_edges, visible_nodes, parts, nk); const spikeseses = {}; - if(!_expanded[dir].has(nk)) + if (!_expanded[dir].has(nk)) Object.keys(tree_edges).forEach(nk => { let spikes; - if(recurse) { + if (recurse) { spikes = parts[nk] || []; - } - else { + } else { const edges = tree_edges[nk].edges; const degree = edges.length; const visible_e = visible_edges(diagram, edge, dir, nk); const shown = new Set(visible_e.map(e => diagram.edgeKey.eval(e))); - const invis = edges.filter(function(e) { return !shown.has(diagram.edgeKey()(e)); }); + const invis = edges.filter(e => !shown.has(diagram.edgeKey()(e))); spikes = invis.map(e => ({pe: e, children: []})); - if(degree - visible_e.length !== spikes.length) { - console.log('number of stubs', spikes.length, 'does not equal degree - visible edges', degree - visible_e.length); - debugger; + if (degree-visible_e.length !== spikes.length) { + console.log( + 'number of stubs', + spikes.length, + 'does not equal degree - visible edges', + degree-visible_e.length, + ); + // debugger; } } const spikeses = {}; - if(dir == 'both' && dc_graph.engines.is_directed(diagram.layoutEngine().layoutAlgorithm())) { + if ( + dir == 'both' && engines.is_directed(diagram.layoutEngine().layoutAlgorithm()) + ) { spikeses.in = []; spikeses.out = []; spikes.forEach(spk => { - if(diagram.edgeSource()(spk.pe) === nk) + if (diagram.edgeSource()(spk.pe) === nk) spikeses.out.push(spk); else { console.assert(diagram.edgeTarget()(spk.pe) === nk); spikeses.in.push(spk); } }); - } - else spikeses[dir] = spikes; + } else spikeses[dir] = spikes; spikeseses[nk] = spikeses; }); draw_stubs(diagram, node, edge, n, spikeseses); - var collapse_nodes_set = {}, collapse_edges_set = {}; - if(_expanded[dir].has(nk)) { + let collapse_nodes_set = {}, collapse_edges_set = {}; + if (_expanded[dir].has(nk)) { // collapse - const will_change = Object.keys(tree_edges).flatMap(nk => _expanded[dir].has(nk) ? [nk] : []); + const will_change = Object.keys(tree_edges).flatMap(nk => + _expanded[dir].has(nk) ? [nk] : [] + ); _changing = Object.fromEntries(will_change.map(nk => [nk, {dir, whether: false}])); - if(options.collapsibles) { - var clps = options.collapsibles(will_change, dir); + if (options.collapsibles) { + const clps = options.collapsibles(will_change, dir); collapse_nodes_set = clps.nodes; collapse_edges_set = clps.edges; } - changing_highlight_group.highlight(Object.fromEntries(will_change.map(nk => [nk, true])), {}); + changing_highlight_group.call( + 'highlight', + null, + Object.fromEntries(will_change.map(nk => [nk, true])), + {}, + ); } else { - _changing = Object.fromEntries(Object.keys(tree_edges).map(nk => [nk, {dir, whether: true}])); - changing_highlight_group.highlight(Object.fromEntries(Object.keys(tree_edges).map(nk => [nk, true])), {}); + _changing = Object.fromEntries( + Object.keys(tree_edges).map(nk => [nk, {dir, whether: true}]), + ); + changing_highlight_group.call( + 'highlight', + null, + Object.fromEntries(Object.keys(tree_edges).map(nk => [nk, true])), + {}, + ); } - collapse_highlight_group.highlight(collapse_nodes_set, collapse_edges_set); + collapse_highlight_group.call('highlight', null, collapse_nodes_set, collapse_edges_set); } function draw(diagram, node, edge, ehover) { function over_node(n) { - var dir = zonedir(diagram, d3.event, options.dirs, n); + const dir = zonedir(diagram, d3Event, options.dirs, n); _overNode = n; _overDir = dir; - if(_ignore && _ignore !== n) + if (_ignore && _ignore !== n) _ignore = null; - if(_ignore) + if (_ignore) return; - if(options.hideNode && detect_key(options.hideKey)) + if (options.hideNode && detect_key(options.hideKey, d3Event)) highlight_hiding_node(diagram, n, edge); - else if(_mode.nodeURL.eval(_overNode) && detect_key(options.linkKey)) { + else if (_mode.nodeURL.eval(_overNode) && detect_key(options.linkKey, d3Event)) { diagram.selectAllNodes() - .filter(function(n) { - return n === _overNode; - }).attr('cursor', 'pointer'); + .filter(n => n === _overNode).attr('cursor', 'pointer'); diagram.requestRefresh(0); - } - else - highlight_expand_collapse(diagram, n, node, edge, dir, detect_key(options.recurseKey)); + } else + highlight_expand_collapse( + diagram, + n, + node, + edge, + dir, + detect_key(options.recurseKey, d3Event), + ); } - function leave_node(n) { + function leave_node(_n) { diagram.selectAllNodes() - .filter(function(n) { - return n === _overNode; - }).attr('cursor', null); + .filter(n => n === _overNode).attr('cursor', null); _overNode = null; _ignore = null; clear_stubs(diagram, node, edge); _changing = null; - changing_highlight_group.highlight({}, {}); - collapse_highlight_group.highlight({}, {}); - hide_highlight_group.highlight({}, {}); + changing_highlight_group.call('highlight', null, {}, {}); + collapse_highlight_group.call('highlight', null, {}, {}); + hide_highlight_group.call('highlight', null, {}, {}); } function click_node(n) { - var nk = diagram.nodeKey.eval(n); - if(options.hideNode && detect_key(options.hideKey)) + const nk = diagram.nodeKey.eval(n); + if (options.hideNode && detect_key(options.hideKey, d3Event)) options.hideNode(nk); - else if(detect_key(options.linkKey)) { - if(_mode.nodeURL.eval(n) && _mode.urlOpener) + else if (detect_key(options.linkKey, d3Event)) { + if (_mode.nodeURL.eval(n) && _mode.urlOpener) _mode.urlOpener()(_mode, n, _mode.nodeURL.eval(n)); } else { clear_stubs(diagram, node, edge); _ignore = n; _changing = null; - changing_highlight_group.highlight({}, {}); - var dir = zonedir(diagram, d3.event, options.dirs, n); + changing_highlight_group.call('highlight', null, {}, {}); + const dir = zonedir(diagram, d3Event, options.dirs, n); let tree_nodes = [nk]; - if(detect_key(options.recurseKey) && options.get_tree_edges) + if (detect_key(options.recurseKey, d3Event) && options.get_tree_edges) tree_nodes = Object.keys(options.get_tree_edges(nk, dir)); expand(dir, tree_nodes, !_expanded[dir].has(nk)); } @@ -355,15 +413,15 @@ dc_graph.expand_collapse = function(options) { function enter_edge(e) { _overEdge = e; - if(options.hideEdge && detect_key(options.hideKey)) + if (options.hideEdge && detect_key(options.hideKey, d3Event)) highlight_hiding_edge(diagram, e); } - function leave_edge(e) { + function leave_edge(_e) { _overEdge = null; - hide_highlight_group.highlight({}, {}); + hide_highlight_group.call('highlight', null, {}, {}); } function click_edge(e) { - if(options.hideEdge && detect_key(options.hideKey)) + if (options.hideEdge && detect_key(options.hideKey, d3Event)) options.hideEdge(diagram.edgeKey.eval(e)); } @@ -380,54 +438,63 @@ dc_graph.expand_collapse = function(options) { .on('click.expand-collapse', click_edge); _keyboard - .on('keydown.expand-collapse', function() { - if(d3.event.key === options.hideKey && (_overNode && options.hideNode || _overEdge && options.hideEdge)) { - if(_overNode) + .on('keydown.expand-collapse', () => { + if ( + d3Event.key === options.hideKey + && (_overNode && options.hideNode || _overEdge && options.hideEdge) + ) { + if (_overNode) highlight_hiding_node(diagram, _overNode, edge); - if(_overEdge) + if (_overEdge) highlight_hiding_edge(diagram, _overEdge); clear_stubs(diagram, node, edge); _changing = null; - changing_highlight_group.highlight({}, {}); - collapse_highlight_group.highlight({}, {}); - } - else if(d3.event.key === options.linkKey && _overNode) { - if(_overNode && _mode.nodeURL.eval(_overNode)) { + changing_highlight_group.call('highlight', null, {}, {}); + collapse_highlight_group.call('highlight', null, {}, {}); + } else if (d3Event.key === options.linkKey && _overNode) { + if (_overNode && _mode.nodeURL.eval(_overNode)) { diagram.selectAllNodes() - .filter(function(n) { - return n === _overNode; - }).attr('cursor', 'pointer'); + .filter(n => n === _overNode).attr('cursor', 'pointer'); } - hide_highlight_group.highlight({}, {}); + hide_highlight_group.call('highlight', null, {}, {}); clear_stubs(diagram, node, edge); - collapse_highlight_group.highlight({}, {}); - } - else if(d3.event.key === options.recurseKey && _overNode) { + collapse_highlight_group.call('highlight', null, {}, {}); + } else if (d3Event.key === options.recurseKey && _overNode) { highlight_expand_collapse(diagram, _overNode, node, edge, _overDir, true); } }) - .on('keyup.expand_collapse', function() { - if((d3.event.key === options.hideKey || d3.event.key === options.linkKey || d3.event.key === options.recurseKey) && (_overNode || _overEdge)) { - hide_highlight_group.highlight({}, {}); - if(_overNode) { - highlight_expand_collapse(diagram, _overNode, node, edge, _overDir, detect_key(options.recurseKey)); - if(_mode.nodeURL.eval(_overNode)) { + .on('keyup.expand_collapse', () => { + if ( + (d3Event.key === options.hideKey || d3Event.key === options.linkKey + || d3Event.key === options.recurseKey) && (_overNode || _overEdge) + ) { + hide_highlight_group.call('highlight', null, {}, {}); + if (_overNode) { + highlight_expand_collapse( + diagram, + _overNode, + node, + edge, + _overDir, + detect_key(options.recurseKey, d3Event), + ); + if (_mode.nodeURL.eval(_overNode)) { diagram.selectAllNodes() - .filter(function(n) { - return n === _overNode; - }).attr('cursor', null); + .filter(n => n === _overNode).attr('cursor', null); } } } }); - diagram.cascade(97, true, conditional_properties( - function(n) { - return n === _overNode && n.orig.value.value && n.orig.value.value.URL; - }, - { - nodeLabelDecoration: 'underline' - } - )); + diagram.cascade( + 97, + true, + conditionalProperties( + n => n === _overNode && n.orig.value.value && n.orig.value.value.URL, + { + nodeLabelDecoration: 'underline', + }, + ), + ); } function remove(diagram, node, edge, ehover) { @@ -446,104 +513,112 @@ dc_graph.expand_collapse = function(options) { function expand(dir, nks, whether) { nks.forEach(nk => { - if(dir === 'both' && !_expanded.both) - options.dirs.forEach(function(dir2) { - if(whether) + if (dir === 'both' && !_expanded.both) + options.dirs.forEach(dir2 => { + if (whether) _expanded[dir2].add(nk); else _expanded[dir2].delete(nk); }); - else if(whether) + else if (whether) _expanded[dir].add(nk); else _expanded[dir].delete(nk); }); - var bothmap; - if(_expanded.both) + let bothmap; + if (_expanded.both) bothmap = Object.fromEntries( - Array.from(_expanded.both, nk => [nk, true])); + Array.from(_expanded.both, nk => [nk, true]), + ); else { bothmap = Object.fromEntries( [..._expanded.in, ..._expanded.out] - .map(nk => [nk, true])); + .map(nk => [nk, true]), + ); } - expanded_highlight_group.highlight(bothmap, {}); + expanded_highlight_group.call('highlight', null, bothmap, {}); options.refresh(); } function expandNodes(nks, dir) { - if(!Array.isArray(nks)) { + if (!Array.isArray(nks)) { Object.keys(nks).forEach(dir => { _expanded[dir] = new Set(nks[dir]); }); } else { - var expset = new Set(nks); + const expset = new Set(nks); const dirs = dir == 'both' ? options.dirs : [dir]; dirs.forEach(dir => { _expanded[dir] = new Set(expset); }); } const mm = Object.fromEntries( - Array.prototype.concat.apply([], Object.keys(_expanded).map(dir => Array.from(_expanded[dir]))) - .map(nk => [nk, true])); - expanded_highlight_group.highlight( - mm, - {}); + Array.prototype.concat.apply( + [], + Object.keys(_expanded).map(dir => Array.from(_expanded[dir])), + ) + .map(nk => [nk, true]), + ); + expanded_highlight_group.call('highlight', null, mm, {}); options.refresh(); } function nodeOutlineClip(n) { const dirs = _mode.expandedDirs(n.key); - if(dirs.length == 0) // changing from expanded to not + if (dirs.length == 0) // changing from expanded to not return 'none'; - if(dirs.length == 2 || dirs[0] == 'both') + if (dirs.length == 2 || dirs[0] == 'both') return null; - switch(_mode.parent().layoutEngine().rankdir()) { - case 'TB': - return dirs[0] == 'in' ? 'top' : 'bottom'; - case 'BT': - return dirs[0] == 'in' ? 'bottom' : 'top'; - case 'LR': - return dirs[0] == 'in' ? 'left' : 'right'; - case 'RL': - return dirs[0] == 'in' ? 'right' : 'left'; - default: - throw new Error('unknown rankdir ' + mode.parent().layoutEngine().rankdir()); + switch (_mode.parent().layoutEngine().rankdir()) { + case 'TB': + return dirs[0] == 'in' ? 'top' : 'bottom'; + case 'BT': + return dirs[0] == 'in' ? 'bottom' : 'top'; + case 'LR': + return dirs[0] == 'in' ? 'left' : 'right'; + case 'RL': + return dirs[0] == 'in' ? 'right' : 'left'; + default: + throw new Error(`unknown rankdir ${mode.parent().layoutEngine().rankdir()}`); } } - var _mode = dc_graph.mode('expand-collapse', { - draw: draw, - remove: remove, - parent: function(p) { - if(p) { + const _mode = mode('expand-collapse', { + draw, + remove, + parent(p) { + if (p) { _keyboard = p.child('keyboard'); - if(!_keyboard) - p.child('keyboard', _keyboard = dc_graph.keyboard()); - const highlight_changing = p.child(options.highlight_changing || 'highlight-changing'); + if (!_keyboard) + p.child('keyboard', _keyboard = keyboard()); + const highlight_changing = p.child( + options.highlight_changing || 'highlight-changing', + ); highlight_changing.includeProps()['nodeOutlineClip'] = nodeOutlineClip; - const highlight_expanded = p.child(options.highlight_expanded || 'highlight-expanded'); + const highlight_expanded = p.child( + options.highlight_expanded || 'highlight-expanded', + ); highlight_expanded.includeProps()['nodeOutlineClip'] = nodeOutlineClip; } - } + }, }); _mode.getExpanded = function() { return _expanded; }; _mode.expandedDirs = function(nk) { - if(_expanded.both) + if (_expanded.both) return _expanded.both.has(nk) || _changing && _changing[nk] ? ['both'] : []; else { const dirs = []; let has_in = _expanded.in.has(nk); - if(_changing && _changing[nk] && _changing[nk].dir === 'in') + if (_changing && _changing[nk] && _changing[nk].dir === 'in') has_in = _changing[nk].whether; - if(has_in) + if (has_in) dirs.push('in'); let has_out = _expanded.out.has(nk); - if(_changing && _changing[nk] && _changing[nk].dir === 'out') + if (_changing && _changing[nk] && _changing[nk].dir === 'out') has_out = _changing[nk].whether; - if(has_out) + if (has_out) dirs.push('out'); return dirs; } @@ -551,17 +626,24 @@ dc_graph.expand_collapse = function(options) { _mode.expand = expand; _mode.expandNodes = expandNodes; - _mode.clickableLinks = deprecated_property("warning - clickableLinks doesn't belong in collapse_expand and will be moved", false); - _mode.nodeURL = property(function(n) { - return n.value && n.value.value && n.value.value.URL; - }); + _mode.clickableLinks = deprecatedProperty( + "warning - clickableLinks doesn't belong in collapse_expand and will be moved", + false, + ); + _mode.nodeURL = property(n => n.value && n.value.value && n.value.value.URL); _mode.urlTargetWindow = property('dcgraphlink'); - _mode.urlOpener = property(dc_graph.expand_collapse.default_url_opener); - if(options.expandCollapse) + _mode.urlOpener = property(defaultUrlOpener); + if (options.expandCollapse) options.expandCollapse(_mode); return _mode; -}; +} -dc_graph.expand_collapse.default_url_opener = function(mode, node, url) { +export function defaultUrlOpener(mode, node, _url) { window.open(mode.nodeURL.eval(node), mode.urlTargetWindow()); -}; +} + +// Import strategy functions +import { expandedHidden } from './expanded_hidden.js'; + +// Attach strategies to expandCollapse function for backward compatibility +expandCollapse.expanded_hidden = expandedHidden; diff --git a/src/expanded_hidden.js b/src/expanded_hidden.js index 626a0c80..ad26188a 100644 --- a/src/expanded_hidden.js +++ b/src/expanded_hidden.js @@ -1,164 +1,170 @@ -dc_graph.expand_collapse.expanded_hidden = function(opts) { - var options = Object.assign({ - nodeKey: function(n) { return n.key; }, - edgeKey: function(e) { return e.key; }, - edgeSource: function(e) { return e.value.source; }, - edgeTarget: function(e) { return e.value.target; } +import { redrawAll } from 'dc'; +import { property } from './core.js'; + +export function expandedHidden(opts) { + const options = Object.assign({ + nodeKey(n) { + return n.key; + }, + edgeKey(e) { + return e.key; + }, + edgeSource(e) { + return e.value.source; + }, + edgeTarget(e) { + return e.value.target; + }, }, opts); - var _nodeHidden = {}, _edgeHidden = {}; + const _nodeHidden = {}, _edgeHidden = {}; // independent dimension on keys so that the diagram dimension will observe it - var _nodeDim = options.nodeCrossfilter.dimension(options.nodeKey), + const _nodeDim = options.nodeCrossfilter.dimension(options.nodeKey), _edgeDim = options.edgeCrossfilter && options.edgeCrossfilter.dimension(options.edgeRawKey); function get_shown(expanded) { - return Object.keys(expanded).reduce(function(p, dir) { - return Array.from(expanded[dir]).reduce(function(p, nk) { - p[nk] = true; - let list; - switch(dir) { - case 'in': - list = in_edges(nk).map(e => options.edgeSource(e)); - break; - case 'out': - list = out_edges(nk).map(e => options.edgeTarget(e)); - break; - case 'both': - list = adjacent_nodes(nk); - break; - } - list.forEach(function(nk2) { - if(!_nodeHidden[nk2]) - p[nk2] = true; - }); - return p; - }, p); - }, {}); + return Object.keys(expanded).reduce( + (p, dir) => + Array.from(expanded[dir]).reduce((p, nk) => { + p[nk] = true; + let list; + switch (dir) { + case 'in': + list = in_edges(nk).map(e => options.edgeSource(e)); + break; + case 'out': + list = out_edges(nk).map(e => options.edgeTarget(e)); + break; + case 'both': + list = adjacent_nodes(nk); + break; + } + list.forEach(nk2 => { + if (!_nodeHidden[nk2]) + p[nk2] = true; + }); + return p; + }, p), + {}, + ); } function apply_filter(ec) { - var _shown = get_shown(ec.getExpanded()); - _nodeDim.filterFunction(function(nk) { - return _shown[nk]; - }); - _edgeDim && _edgeDim.filterFunction(function(ek) { - return !_edgeHidden[ek]; - }); + const _shown = get_shown(ec.getExpanded()); + _nodeDim.filterFunction(nk => _shown[nk]); + _edgeDim && _edgeDim.filterFunction(ek => !_edgeHidden[ek]); } function adjacent_edges(nk) { - return options.edgeGroup.all().filter(function(e) { - return options.edgeSource(e) === nk || options.edgeTarget(e) === nk; - }); + return options.edgeGroup.all().filter(e => + options.edgeSource(e) === nk || options.edgeTarget(e) === nk + ); } function out_edges(nk) { - return options.edgeGroup.all().filter(function(e) { - return options.edgeSource(e) === nk; - }); + return options.edgeGroup.all().filter(e => options.edgeSource(e) === nk); } function in_edges(nk) { - return options.edgeGroup.all().filter(function(e) { - return options.edgeTarget(e) === nk; - }); + return options.edgeGroup.all().filter(e => options.edgeTarget(e) === nk); } const other_node = (e, nk) => - options.edgeSource(e) === nk ? options.edgeTarget(e) : options.edgeSource(e); + options.edgeSource(e) === nk ? options.edgeTarget(e) : options.edgeSource(e); function adjacent_nodes(nk) { return adjacent_edges(nk).map(e => other_node(e, nk)); } const dfs_pre_order = (nk, seen, traverse, other, fall, funseen, pe = null, pres = null) => { fall(pe, pres, nk); - if(seen.has(nk)) + if (seen.has(nk)) return; seen.add(nk); const nres = funseen(pe, pres, nk); - for(const e of traverse(nk)) + for (const e of traverse(nk)) dfs_pre_order(other(e, nk), seen, traverse, other, fall, funseen, e, nres); }; - var _strategy = { - get_edges: function(nk, dir) { - switch(dir) { - case 'in': - return in_edges(nk); - case 'out': - return out_edges(nk); - case 'both': - return adjacent_edges(nk); - default: - throw new Error(`unknown dir ${dir}`); + const _strategy = { + get_edges(nk, dir) { + switch (dir) { + case 'in': + return in_edges(nk); + case 'out': + return out_edges(nk); + case 'both': + return adjacent_edges(nk); + default: + throw new Error(`unknown dir ${dir}`); } }, get_tree_edges: (nk, dir, once = false) => { - const traverse = dir === 'in' ? in_edges : - dir === 'out' ? out_edges : - adjacent_edges; - const other = dir === 'in' ? options.edgeSource : - dir === 'out' ? options.edgeTarget : - other_node; - if(once) { + const traverse = dir === 'in' + ? in_edges + : dir === 'out' + ? out_edges + : adjacent_edges; + const other = dir === 'in' + ? options.edgeSource + : dir === 'out' + ? options.edgeTarget + : other_node; + if (once) { const edges = traverse(nk), - nks = edges.map(other); + nks = edges.map(other); return {[nk]: {edges, nks}}; } const nodes = {}, seen = new Set(); dfs_pre_order(nk, seen, traverse, other, (pe, pres, nk) => { - if(pres) { + if (pres) { pres.edges.push(pe); pres.nks.push(nk); } - }, (pe, pres, nk) => { - return nodes[nk] = {edges: [], nks: []}; - }); + }, (pe, pres, nk) => nodes[nk] = {edges: [], nks: []}); return nodes; }, - partition_among_visible: (tree_edges, visible_nodes) => { + partition_among_visible: (_tree_edges, _visible_nodes) => { }, - refresh: function() { + refresh() { apply_filter(_strategy.expandCollapse()); - dc.redrawAll(); + redrawAll(); return this; }, - collapsibles: function(nks, dir) { + collapsibles(nks, dir) { const expanded = _strategy.expandCollapse().getExpanded(); - var whatif = structuredClone(expanded); + const whatif = structuredClone(expanded); nks.forEach( - nk => whatif[dir].delete(nk) + nk => whatif[dir].delete(nk), ); - var shown = get_shown(expanded), would = get_shown(whatif); - var going = Object.keys(shown) - .filter(function(nk2) { return !would[nk2]; }) - .reduce(function(p, v) { + const shown = get_shown(expanded), would = get_shown(whatif); + const going = Object.keys(shown) + .filter(nk2 => !would[nk2]) + .reduce((p, v) => { p[v] = true; return p; }, {}); return { nodes: going, - edges: options.edgeGroup.all().filter(function(e) { - return going[options.edgeSource(e)] || going[options.edgeTarget(e)]; - }).reduce(function(p, e) { + edges: options.edgeGroup.all().filter(e => + going[options.edgeSource(e)] || going[options.edgeTarget(e)] + ).reduce((p, e) => { p[options.edgeKey(e)] = true; return p; - }, {}) + }, {}), }; }, - hideNode: function(nk) { + hideNode(nk) { _nodeHidden[nk] = true; _strategy.expandCollapse().expand('both', [nk], false); }, - hideEdge: function(ek) { - if(!options.edgeCrossfilter) + hideEdge(ek) { + if (!options.edgeCrossfilter) console.warn('expanded_hidden needs edgeCrossfilter to hide edges'); _edgeHidden[ek] = true; apply_filter(_strategy.expandCollapse()); - dc.redrawAll(); + redrawAll(); }, - expandCollapse: property(null).react(function(ec) { - if(ec) + expandCollapse: property(null).react(ec => { + if (ec) apply_filter(ec); - - }) + }), }; - if(options.directional) + if (options.directional) _strategy.dirs = ['out', 'in']; return _strategy; -}; +} diff --git a/src/filter_selection.js b/src/filter_selection.js index 5cbfd741..a8a70c6a 100644 --- a/src/filter_selection.js +++ b/src/filter_selection.js @@ -1,26 +1,29 @@ -dc_graph.filter_selection = function(things_group, things_name) { +import { set } from 'd3-collection'; +import { property } from './core.js'; +import { selectThingsGroup } from './select_things.js'; + +export function filterSelection(things_group, things_name) { things_name = things_name || 'select-nodes'; - var select_nodes_group = dc_graph.select_things_group(things_group || 'select-nodes-group', things_name); + const select_nodes_group = selectThingsGroup(things_group || 'select-nodes-group', things_name); function selection_changed(diagram) { return function(selection) { - if(selection.length) { - var set = d3.set(selection); - _mode.dimensionAccessor()(diagram).filterFunction(function(k) { - return set.has(k); - }); + if (selection.length) { + const selectionSet = set(selection); + _mode.dimensionAccessor()(diagram).filterFunction(k => selectionSet.has(k)); } else _mode.dimensionAccessor()(diagram).filter(null); diagram.redrawGroup(); }; } - var _mode = { - parent: property(null).react(function(p) { - select_nodes_group.on('set_changed.filter-selection-' + things_name, p ? selection_changed(p) : null); - }) + const _mode = { + parent: property(null).react(p => { + select_nodes_group.on( + `set_changed.filter-selection-${things_name}`, + p ? selection_changed(p) : null, + ); + }), }; - _mode.dimensionAccessor = property(function(diagram) { - return diagram.nodeDimension(); - }); + _mode.dimensionAccessor = property(diagram => diagram.nodeDimension()); return _mode; -}; +} diff --git a/src/fix_nodes.js b/src/fix_nodes.js index a09565c7..cf84db7c 100644 --- a/src/fix_nodes.js +++ b/src/fix_nodes.js @@ -1,39 +1,43 @@ -dc_graph.fix_nodes = function(options) { +import { dispatch } from 'd3-dispatch'; +import { property } from './core.js'; +import { undirectedDfs } from './depth_first_traversal.js'; + +export function fixNodes(options) { options = options || {}; - var fix_nodes_group = dc_graph.fix_nodes_group(options.fix_nodes_group || 'fix-nodes-group'); - var _fixedPosTag = options.fixedPosTag || 'fixedPos'; - var _fixes = [], _nodes, _wnodes, _edges, _wedges; + const fix_nodes_group = fixNodesGroup(options.fix_nodes_group || 'fix-nodes-group'); + const _fixedPosTag = options.fixedPosTag || 'fixedPos'; + let _fixes = [], _nodes, _wnodes, _edges, _wedges; - var _execute = { - nodeid: function(n) { + const _execute = { + nodeid(n) { return _mode.parent().nodeKey.eval(n); }, - sourceid: function(e) { + sourceid(e) { return _mode.parent().edgeSource.eval(e); }, - targetid: function(e) { + targetid(e) { return _mode.parent().edgeTarget.eval(e); }, - get_fix: function(n) { + get_fix(n) { return _mode.parent().nodeFixed.eval(n); }, - fix_node: function(n, pos) { + fix_node(n, pos) { n[_fixedPosTag] = pos; }, - unfix_node: function(n) { + unfix_node(n) { n[_fixedPosTag] = null; }, - clear_fixes: function() { + clear_fixes() { _fixes = {}; }, - register_fix: function(id, pos) { + register_fix(id, pos) { _fixes[id] = pos; - } + }, }; function request_fixes(fixes) { _mode.strategy().request_fixes(_execute, fixes); - tell_then_set(find_changes()).then(function() { + tell_then_set(find_changes()).then(() => { _mode.parent().redraw(); }); } @@ -41,63 +45,64 @@ dc_graph.fix_nodes = function(options) { _mode.strategy().new_node(_execute, nid, n, pos); } function new_edge(eid, sourceid, targetid) { - var source = _nodes[sourceid], target = _nodes[targetid]; + const source = _nodes[sourceid], target = _nodes[targetid]; _mode.strategy().new_edge(_execute, eid, source, target); } function find_changes() { - var changes = []; - _wnodes.forEach(function(n) { - var key = _mode.parent().nodeKey.eval(n), - fixPos = _fixes[key], - oldFixed = n.orig.value[_fixedPosTag], - changed = false; - if(oldFixed) { - if(!fixPos || fixPos.x !== oldFixed.x || fixPos.y !== oldFixed.y) + const changes = []; + _wnodes.forEach(n => { + const key = _mode.parent().nodeKey.eval(n), + fixPos = _fixes[key]; + const oldFixed = n.orig.value[_fixedPosTag]; + let changed = false; + if (oldFixed) { + if (!fixPos || fixPos.x !== oldFixed.x || fixPos.y !== oldFixed.y) changed = true; - } - else changed = fixPos; - if(changed) - changes.push({n: n, fixed: fixPos ? {x: fixPos.x, y: fixPos.y} : null}); + } else changed = fixPos; + if (changed) + changes.push({n, fixed: fixPos ? {x: fixPos.x, y: fixPos.y} : null}); }); return changes; } function execute_change(n, fixed) { - if(fixed) + if (fixed) _execute.fix_node(n.orig.value, fixed); else _execute.unfix_node(n.orig.value); } function tell_then_set(changes) { - var callback = _mode.fixNode() || function(n, pos) { return Promise.resolve(pos); }; - var promises = changes.map(function(change) { - var key = _mode.parent().nodeKey.eval(change.n); + const callback = _mode.fixNode() || function(n, pos) { + return Promise.resolve(pos); + }; + const promises = changes.map(change => { + const key = _mode.parent().nodeKey.eval(change.n); return callback(key, change.fixed) - .then(function(fixed) { + .then(fixed => { execute_change(change.n, fixed); }); }); return Promise.all(promises); } function set_changes(changes) { - changes.forEach(function(change) { + changes.forEach(change => { execute_change(change.n, change.fixed); }); } function tell_changes(changes) { - var callback = _mode.fixNode() || function(n, pos) { return Promise.resolve(pos); }; - var promises = changes.map(function(change) { - var key = _mode.parent().nodeKey.eval(change.n); + const callback = _mode.fixNode() || function(n, pos) { + return Promise.resolve(pos); + }; + const promises = changes.map(change => { + const key = _mode.parent().nodeKey.eval(change.n); return callback(key, change.fixed); }); return Promise.all(promises); } function fix_all_nodes(tell) { - if(tell === undefined) - tell = true; - var changes = _wnodes.map(function(n) { - return {n: n, fixed: {x: n.cola.x, y: n.cola.y}}; - }); - if(tell) + if (tell === undefined) + tell = true; + const changes = _wnodes.map(n => ({n, fixed: {x: n.cola.x, y: n.cola.y}})); + if (tell) return tell_then_set(changes); else { set_changes(changes); @@ -109,29 +114,34 @@ dc_graph.fix_nodes = function(options) { _execute.clear_fixes(); } function on_data(diagram, nodes, wnodes, edges, wedges, ports, wports) { + console.assert( + Array.isArray(wnodes), + 'fix_nodes.on_data: wnodes should be an array, got:', + wnodes, + ); _nodes = nodes; _wnodes = wnodes; _edges = edges; _wedges = wedges; - if(_mode.strategy().on_data) { + if (_mode.strategy().on_data) { _mode.strategy().on_data(_execute, nodes, wnodes, edges, wedges, ports, wports); // ghastly - var changes = find_changes(); + const changes = find_changes(); set_changes(changes); // can't wait for backend to acknowledge/approve so just set then blast - if(_mode.reportOverridesAsynchronously()) + if (_mode.reportOverridesAsynchronously()) tell_changes(changes); // dangling promise } } - var _mode = { - parent: property(null).react(function(p) { + const _mode = { + parent: property(null).react(p => { fix_nodes_group .on('request_fixes.fix-nodes', p ? request_fixes : null) .on('new_node.fix_nodes', p ? new_node : null) .on('new_edge.fix_nodes', p ? new_edge : null); - if(p) { + if (p) { p.on('data.fix-nodes', on_data); - } else if(_mode.parent()) + } else if (_mode.parent()) _mode.parent().on('data.fix-nodes', null); }), // callback for setting & fixing node position @@ -140,132 +150,134 @@ dc_graph.fix_nodes = function(options) { // (should probably be automatic though) fixAllNodes: fix_all_nodes, clearFixes: clear_fixes, - strategy: property(dc_graph.fix_nodes.strategy.fix_last()), - reportOverridesAsynchronously: property(true) + strategy: property(fixNodes.strategy.fixLast()), + reportOverridesAsynchronously: property(true), }; return _mode; -}; +} -dc_graph.fix_nodes.strategy = {}; -dc_graph.fix_nodes.strategy.fix_last = function() { +fixNodes.strategy = {}; +fixNodes.strategy.fixLast = function() { return { - request_fixes: function(exec, fixes) { + request_fixes(exec, fixes) { exec.clear_fixes(); - fixes.forEach(function(fix) { + fixes.forEach(fix => { exec.register_fix(fix.id, fix.pos); }); }, - new_node: function(exec, nid, n, pos) { + new_node(exec, nid, n, pos) { exec.fix_node(n, pos); }, - new_edge: function(exec, eid, source, target) { + new_edge(exec, eid, source, target) { exec.unfix_node(source.orig.value); exec.unfix_node(target.orig.value); - } + }, }; }; -dc_graph.fix_nodes.strategy.last_N_per_component = function(maxf) { +fixNodes.strategy.lastNPerComponent = function(maxf) { maxf = maxf || 1; - var _age = 0; - var _allFixes = {}; + let _age = 0; + let _allFixes = {}; return { - clear_all_fixes: function() { + clear_all_fixes() { _allFixes = {}; }, - request_fixes: function(exec, fixes) { + request_fixes(exec, fixes) { ++_age; - fixes.forEach(function(fix) { + fixes.forEach(fix => { _allFixes[fix.id] = {id: fix.id, age: _age, pos: fix.pos}; }); }, - new_node: function(exec, nid, n, pos) { + new_node(exec, nid, n, pos) { ++_age; - _allFixes[nid] = {id: nid, age: _age, pos: pos}; + _allFixes[nid] = {id: nid, age: _age, pos}; exec.fix_node(n, pos); }, - new_edge: function() {}, - on_data: function(exec, nodes, wnodes, edges, wedges, ports, wports) { + new_edge() {}, + on_data(exec, nodes, wnodes, edges, wedges, _ports, _wports) { ++_age; // add any existing fixes as requests - wnodes.forEach(function(n) { - var nid = exec.nodeid(n), pos = exec.get_fix(n); - if(pos && !_allFixes[nid]) - _allFixes[nid] = {id: nid, age: _age, pos: pos}; + console.assert( + Array.isArray(wnodes), + 'fix_nodes strategy.on_data: wnodes should be an array, got:', + wnodes, + ); + wnodes.forEach(n => { + const nid = exec.nodeid(n), pos = exec.get_fix(n); + if (pos && !_allFixes[nid]) + _allFixes[nid] = {id: nid, age: _age, pos}; }); // determine components - var components = []; - var dfs = dc_graph.undirected_dfs({ + const components = []; + const dfs = undirectedDfs({ nodeid: exec.nodeid, sourceid: exec.sourceid, targetid: exec.targetid, - comp: function() { + comp() { components.push([]); }, - node: function(compid, n) { + node(compid, n) { components[compid].push(n); - } + }, }); dfs(wnodes, wedges); // start from scratch exec.clear_fixes(); // keep or produce enough fixed nodes per component - components.forEach(function(comp, i) { - var oldcomps = comp.reduce(function(cc, n) { - if(n.last_component) { - var counts = cc[n.last_component] = cc[n.last_component] || { + components.forEach((comp, i) => { + const oldcomps = comp.reduce((cc, n) => { + if (n.last_component) { + const counts = cc[n.last_component] = cc[n.last_component] || { total: 0, - fixed: 0 + fixed: 0, }; counts.total++; - if(_allFixes[exec.nodeid(n)]) + if (_allFixes[exec.nodeid(n)]) counts.fixed++; } return cc; }, {}); - var fixed_by_size = Object.keys(oldcomps).reduce(function(ff, compid) { - if(oldcomps[compid].fixed) - ff.push({compid: +compid, total: oldcomps[compid].total, fixed: oldcomps[compid].fixed}); + const fixed_by_size = Object.keys(oldcomps).reduce((ff, compid) => { + if (oldcomps[compid].fixed) + ff.push({ + compid: +compid, + total: oldcomps[compid].total, + fixed: oldcomps[compid].fixed, + }); return ff; - }, []).sort(function(coa, cob) { - return cob.total - coa.total; - }); - var largest_fixed = fixed_by_size.length && fixed_by_size[0].compid; - var fixes = comp.filter(function(n) { - return !n.last_component || n.last_component === largest_fixed; - }).map(function(n) { - return _allFixes[exec.nodeid(n)]; - }).filter(function(fix) { - return fix; - }); - if(fixes.length > maxf) { - fixes.sort(function(f1, f2) { - return f2.age - f1.age; - }); + }, []).sort((coa, cob) => cob.total-coa.total); + const largest_fixed = fixed_by_size.length && fixed_by_size[0].compid; + let fixes = comp.filter(n => + !n.last_component || n.last_component === largest_fixed + ).map(n => _allFixes[exec.nodeid(n)]).filter(fix => fix); + if (fixes.length > maxf) { + fixes.sort((f1, f2) => f2.age-f1.age); fixes = fixes.slice(0, maxf); } - fixes.forEach(function(fix) { + fixes.forEach(fix => { exec.register_fix(fix.id, fix.pos); }); - var kept = fixes.reduce(function(m, fix) { + const kept = fixes.reduce((m, fix) => { m[fix.id] = true; return m; }, {}); - comp.forEach(function(n) { - var nid = exec.nodeid(n); - if(!kept[nid]) + comp.forEach(n => { + const nid = exec.nodeid(n); + if (!kept[nid]) _allFixes[nid] = null; n.last_component = i+1; }); }); - } + }, }; }; -dc_graph.fix_nodes_group = function(brushgroup) { - window.chart_registry.create_type('fix-nodes', function() { - return d3.dispatch('request_fixes', 'new_node', 'new_edge'); - }); +export function fixNodesGroup(brushgroup) { + window.chart_registry.create_type( + 'fix-nodes', + () => dispatch('request_fixes', 'new_node', 'new_edge'), + ); return window.chart_registry.create_group('fix-nodes', brushgroup); -}; +} diff --git a/src/flat_group.js b/src/flat_group.js index d5137e3a..e6b457e5 100644 --- a/src/flat_group.js +++ b/src/flat_group.js @@ -1,42 +1,44 @@ /** - * `dc_graph.flat_group` implements a + * `flatGroup` implements a * ["fake crossfilter group"](https://github.com/dc-js/dc.js/wiki/FAQ#fake-groups) * for the case of a group which is 1:1 with the rows of the data array. * * Although `dc_graph` can be used with aggregated or reduced data, typically the nodes and edges * are rows of two data arrays, and each row has a column which contains the unique identifier for * the node or edge. - * - * @namespace flat_group - * @memberof dc_graph - * @type {{}} -**/ + */ + +import crossfilter from 'crossfilter2'; -dc_graph.flat_group = (function() { - var reduce_01 = { - add: function(p, v) { return v; }, - remove: function() { return null; }, - init: function() { return null; } +export const flatGroup = (function() { + const reduce_01 = { + add(p, v) { + return v; + }, + remove() { + return null; + }, + init() { + return null; + }, }; // now we only really want to see the non-null values, so make a fake group function non_null(group) { return { - all: function() { - return group.all().filter(function(kv) { - return kv.value !== null; - }); - } + all() { + return group.all().filter(kv => kv.value !== null); + }, }; } function dim_group(ndx, id_accessor) { - var dimension = ndx.dimension(id_accessor); + const dimension = ndx.dimension(id_accessor); return { crossfilter: ndx, - dimension: dimension, - group: non_null(dimension.group().reduce(reduce_01.add, - reduce_01.remove, - reduce_01.init)) + dimension, + group: non_null( + dimension.group().reduce(reduce_01.add, reduce_01.remove, reduce_01.init), + ), }; } @@ -59,10 +61,10 @@ dc_graph.flat_group = (function() { * @param {Function} id_accessor - accessor function taking a row object and returning its * unique identifier * @return {Object} `{crossfilter, dimension, group}` - **/ - make: function(source, id_accessor) { - var cf; - if(Array.isArray(source)) + */ + make(source, id_accessor) { + let cf; + if (Array.isArray(source)) cf = crossfilter(source); else cf = source; return dim_group(cf, id_accessor); @@ -77,11 +79,10 @@ dc_graph.flat_group = (function() { * @param {Function} id_accessor - accessor function taking a row object and returning its * unique identifier * @return {Object} `{crossfilter, dimension, group}` - **/ - another: deprecate_function('use .make() instead', function(cf, id_accessor) { + */ + another(cf, id_accessor) { + console.warn('flat_group.another() is deprecated, use .make() instead'); return this.make(cf, id_accessor); - }) + }, }; })(); - - diff --git a/src/flexbox_layout.js b/src/flexbox_layout.js index 16c56988..4b748eae 100644 --- a/src/flexbox_layout.js +++ b/src/flexbox_layout.js @@ -29,248 +29,256 @@ * @memberof dc_graph * @param {String} [id=uuid()] - Unique identifier * @return {dc_graph.flexbox_layout} - **/ -dc_graph.flexbox_layout = function(id, options) { - var _layoutId = id || uuid(); + */ +/** + * Flexbox layout for dc.graph.js + * @module flexbox_layout + */ + +import { ascending } from 'd3-array'; +import { dispatch } from 'd3-dispatch'; +import yoga from 'yoga-layout'; +import { property, uuid } from './core.js'; + +export function flexboxLayout(id, options) { + const _layoutId = id || uuid(); options = options || {algo: 'yoga-layout'}; - var _dispatch = d3.dispatch('tick', 'start', 'end'); + const _dispatch = dispatch('tick', 'start', 'end'); - var _graph, _tree, _nodes = {}, _wnodes; + let _graph, _tree, _wnodes; + const _nodes = {}; - function init(options) { + function init(_options) { } // like d3.nest but address can be of arbitrary (and different) length // probably less efficient too function add_node(adhead, adtail, n, tree) { tree.address = adhead.slice(); tree.children = tree.children || {}; - if(!adtail.length) { + if (!adtail.length) { tree.node = n; return; } - var t = tree.children[adtail[0]] = tree.children[adtail[0]] || {}; + const t = tree.children[adtail[0]] = tree.children[adtail[0]] || {}; adhead.push(adtail.shift()); add_node(adhead, adtail, n, t); } function all_keys(tree) { - var key = _engine.addressToKey()(tree.address); - return Array.prototype.concat.apply([key], Object.keys(tree.children || {}).map(function(k) { - return all_keys(tree.children[k]); - })); + const key = _engine.addressToKey()(tree.address); + return Array.prototype.concat.apply( + [key], + Object.keys(tree.children || {}).map(k => all_keys(tree.children[k])), + ); } function data(graph, nodes) { _graph = graph; _tree = {address: [], children: {}}; - nodes.forEach(function(n) { - var ad = _engine.keyToAddress()(n.dcg_nodeKey); + nodes.forEach(n => { + const ad = _engine.keyToAddress()(n.dcg_nodeKey); add_node([], ad, n, _tree); }); - var need = all_keys(_tree); + const _need = all_keys(_tree); _wnodes = nodes; } function ensure_inner_nodes(tree) { - if(!tree.node) - tree.node = {dcg_nodeKey: tree.address.length ? tree.address[tree.address.length-1] : null}; + if (!tree.node) + tree.node = { + dcg_nodeKey: tree.address.length ? tree.address[tree.address.length-1] : null, + }; Object.values(tree.children).forEach(ensure_inner_nodes); } - function getYogaConstants() { - // Return constants only if yogaLayout is available - if (typeof yogaLayout === 'undefined') return null; - - return { + function set_yoga_attr(flexnode, attr, value) { + const fname = `set${attr.charAt(0).toUpperCase()}${attr.slice(1)}`; + if (typeof flexnode[fname] !== 'function') + throw new Error(`Could not set yoga attr "${attr}" (${fname})`); + + // Map string values to yoga constants + const constantMaps = { alignItems: { - stretch: yogaLayout.ALIGN_STRETCH, - 'flex-start': yogaLayout.ALIGN_FLEX_START, - center: yogaLayout.ALIGN_CENTER, - 'flex-end': yogaLayout.ALIGN_FLEX_END, - baseline: yogaLayout.ALIGN_BASELINE + stretch: yoga.ALIGN_STRETCH, + 'flex-start': yoga.ALIGN_FLEX_START, + center: yoga.ALIGN_CENTER, + 'flex-end': yoga.ALIGN_FLEX_END, + baseline: yoga.ALIGN_BASELINE, }, alignSelf: { - stretch: yogaLayout.ALIGN_STRETCH, - 'flex-start': yogaLayout.ALIGN_FLEX_START, - center: yogaLayout.ALIGN_CENTER, - 'flex-end': yogaLayout.ALIGN_FLEX_END, - baseline: yogaLayout.ALIGN_BASELINE + stretch: yoga.ALIGN_STRETCH, + 'flex-start': yoga.ALIGN_FLEX_START, + center: yoga.ALIGN_CENTER, + 'flex-end': yoga.ALIGN_FLEX_END, + baseline: yoga.ALIGN_BASELINE, }, alignContent: { - 'flex-start': yogaLayout.ALIGN_FLEX_START, - 'flex-end': yogaLayout.ALIGN_FLEX_END, - stretch: yogaLayout.ALIGN_STRETCH, - center: yogaLayout.ALIGN_CENTER, - 'space-between': yogaLayout.ALIGN_SPACE_BETWEEN, - 'space-around': yogaLayout.ALIGN_SPACE_AROUND + 'flex-start': yoga.ALIGN_FLEX_START, + 'flex-end': yoga.ALIGN_FLEX_END, + stretch: yoga.ALIGN_STRETCH, + center: yoga.ALIGN_CENTER, + 'space-between': yoga.ALIGN_SPACE_BETWEEN, + 'space-around': yoga.ALIGN_SPACE_AROUND, }, flexDirection: { - column: yogaLayout.FLEX_DIRECTION_COLUMN, - 'column-reverse': yogaLayout.FLEX_DIRECTION_COLUMN_REVERSE, - row: yogaLayout.FLEX_DIRECTION_ROW, - 'row-reverse': yogaLayout.FLEX_DIRECTION_ROW_REVERSE + column: yoga.FLEX_DIRECTION_COLUMN, + 'column-reverse': yoga.FLEX_DIRECTION_COLUMN_REVERSE, + row: yoga.FLEX_DIRECTION_ROW, + 'row-reverse': yoga.FLEX_DIRECTION_ROW_REVERSE, }, justifyContent: { - 'flex-start': yogaLayout.JUSTIFY_FLEX_START, - center: yogaLayout.JUSTIFY_CENTER, - 'flex-end': yogaLayout.JUSTIFY_FLEX_END, - 'space-between': yogaLayout.JUSTIFY_SPACE_BETWEEN, - 'space-around': yogaLayout.JUSTIFY_SPACE_AROUND, - 'space-evenly': yogaLayout.JUSTIFY_SPACE_EVENLY - } + 'flex-start': yoga.JUSTIFY_FLEX_START, + center: yoga.JUSTIFY_CENTER, + 'flex-end': yoga.JUSTIFY_FLEX_END, + 'space-between': yoga.JUSTIFY_SPACE_BETWEEN, + 'space-around': yoga.JUSTIFY_SPACE_AROUND, + 'space-evenly': yoga.JUSTIFY_SPACE_EVENLY, + }, }; - } - function set_yoga_attr(flexnode, attr, value) { - var fname = 'set' + attr.charAt(0).toUpperCase() + attr.slice(1); - if(typeof flexnode[fname] !== 'function') - throw new Error('Could not set yoga attr "' + attr + '" (' + fname + ')'); - var yoga_constants = getYogaConstants(); - if(yoga_constants && yoga_constants[attr]) - value = yoga_constants[attr][value]; - + + if (constantMaps[attr] && constantMaps[attr][value]) + value = constantMaps[attr][value]; + // Handle attributes that need an edge parameter (padding, margin, border, position) - if(attr === 'padding' || attr === 'margin' || attr === 'border' || attr.endsWith('Padding') || attr.endsWith('Margin')) { + if ( + attr === 'padding' || attr === 'margin' || attr === 'border' || attr.endsWith('Padding') + || attr.endsWith('Margin') + ) { // For generic padding/margin, apply to all edges - flexnode[fname](yogaLayout.EDGE_ALL, value); - } else if(attr === 'width') { + flexnode[fname](yoga.EDGE_ALL, value); + } else if (attr === 'width') { flexnode.setWidth(value); - } else if(attr === 'height') { + } else if (attr === 'height') { flexnode.setHeight(value); } else { flexnode[fname](value); } } function get_yoga_attr(flexnode, attr) { - var fname = 'getComputed' + attr.charAt(0).toUpperCase() + attr.slice(1); - if(typeof flexnode[fname] !== 'function') - throw new Error('Could not get yoga attr "' + attr + '" (' + fname + ')'); + const fname = `getComputed${attr.charAt(0).toUpperCase()}${attr.slice(1)}`; + if (typeof flexnode[fname] !== 'function') + throw new Error(`Could not get yoga attr "${attr}" (${fname})`); return flexnode[fname](); } - var internal_attrs = ['sort', 'order', 'dcg_nodeKey', 'dcg_nodeParentCluster', 'shape', 'abstract', 'rx', 'ry', 'x', 'y', 'z', 'nodeOutlineClip'], + const internal_attrs = [ + 'sort', + 'order', + 'dcg_nodeKey', + 'dcg_nodeParentCluster', + 'shape', + 'abstract', + 'rx', + 'ry', + 'x', + 'y', + 'z', + 'nodeOutlineClip', + ], skip_on_parents = ['width', 'height']; function create_flextree(attrs, tree) { - var flexnode; - switch(options.algo) { - case 'css-layout': - flexnode = {name: _engine.addressToKey()(tree.address), style: {}}; - break; - case 'yoga-layout': - if (typeof yogaLayout === 'undefined') { - // Return a placeholder that will be replaced when yoga is ready - flexnode = { _yogaPending: true }; - } else { - flexnode = new yogaLayout.Node(); - } - break; + let flexnode; + switch (options.algo) { + case 'css-layout': + flexnode = {name: _engine.addressToKey()(tree.address), style: {}}; + break; + case 'yoga-layout': + flexnode = new yoga.Node(); + break; } - var attrs2 = Object.assign({}, attrs); - var isParent = Object.keys(tree.children).length; - if(tree.node) + const attrs2 = Object.assign({}, attrs); + const isParent = Object.keys(tree.children).length; + if (tree.node) Object.assign(attrs, tree.node); - for(var attr in attrs) { - if(internal_attrs.includes(attr)) + for (const attr in attrs) { + if (internal_attrs.includes(attr)) continue; - if(isParent && skip_on_parents.includes(attr)) + if (isParent && skip_on_parents.includes(attr)) continue; - var value = attrs[attr]; - if(typeof value === 'function') + let value = attrs[attr]; + if (typeof value === 'function') value = value(tree.node); - switch(options.algo) { - case 'css-layout': - flexnode.style[attr] = value; - break; - case 'yoga-layout': - set_yoga_attr(flexnode, attr, value); - break; + switch (options.algo) { + case 'css-layout': + flexnode.style[attr] = value; + break; + case 'yoga-layout': + set_yoga_attr(flexnode, attr, value); + break; } } - if(isParent) { - var children = Object.values(tree.children) + if (isParent) { + const children = Object.values(tree.children) .sort(attrs.sort) - .map(function(c) { return c.address[c.address.length-1]; }) - .map(function(key) { - return create_flextree(Object.assign({}, attrs2), tree.children[key]); - }); - switch(options.algo) { - case 'css-layout': - flexnode.children = children; - break; - case 'yoga-layout': - children.forEach(function(child, i) { - flexnode.insertChild(child, i); - }); - break; + .map(c => c.address[c.address.length-1]) + .map(key => create_flextree(Object.assign({}, attrs2), tree.children[key])); + switch (options.algo) { + case 'css-layout': + flexnode.children = children; + break; + case 'yoga-layout': + children.forEach((child, i) => { + flexnode.insertChild(child, i); + }); + break; } } tree.flexnode = flexnode; return flexnode; } function apply_layout(offset, tree) { - var left, top, width, height; - switch(options.algo) { - case 'css-layout': - if(_engine.logStuff()) - console.log(tree.node.dcg_nodeKey + ': '+ JSON.stringify(tree.flexnode.layout)); - left = tree.flexnode.layout.left; width = tree.flexnode.layout.width; - top = tree.flexnode.layout.top; height = tree.flexnode.layout.height; - break; - case 'yoga-layout': - left = get_yoga_attr(tree.flexnode, 'left'); width = get_yoga_attr(tree.flexnode, 'width'); - top = get_yoga_attr(tree.flexnode, 'top'); height = get_yoga_attr(tree.flexnode, 'height'); - break; + let left, top, width, height; + switch (options.algo) { + case 'css-layout': + if (_engine.logStuff()) + console.log( + `${tree.node.dcg_nodeKey}: ${JSON.stringify(tree.flexnode.layout)}`, + ); + left = tree.flexnode.layout.left; + width = tree.flexnode.layout.width; + top = tree.flexnode.layout.top; + height = tree.flexnode.layout.height; + break; + case 'yoga-layout': + left = get_yoga_attr(tree.flexnode, 'left'); + width = get_yoga_attr(tree.flexnode, 'width'); + top = get_yoga_attr(tree.flexnode, 'top'); + height = get_yoga_attr(tree.flexnode, 'height'); + break; } - tree.node.x = offset.x + left + width/2; - tree.node.y = offset.y + top + height/2; + tree.node.x = offset.x+left+width/2; + tree.node.y = offset.y+top+height/2; Object.keys(tree.children) - .map(function(key) { return tree.children[key]; }) - .forEach(function(child) { - apply_layout({x: offset.x + left, y: offset.y + top}, child); + .map(key => tree.children[key]) + .forEach(child => { + apply_layout({x: offset.x+left, y: offset.y+top}, child); }); } function dispatchState(wnodes, wedges, event) { - _dispatch[event]( - wnodes, - wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }) - ); + _dispatch.call(event, null, wnodes, wedges.map(e => ({dcg_edgeKey: e.dcg_edgeKey}))); } function start() { - // If yoga layout is requested but yoga isn't ready yet, wait for it - if (options.algo === 'yoga-layout' && typeof yogaLayout === 'undefined') { - if (typeof loadYogaLayout === 'function') { - loadYogaLayout().then(function() { - start(); // Retry when yoga is ready - }); - return; - } else { - console.warn('yoga-layout requested but yogaLayout not available. Falling back to css-layout.'); - options.algo = 'css-layout'; - } - } - - var defaults = { - sort: function(a, b) { - return d3.ascending(a.node.dcg_nodeKey, b.node.dcg_nodeKey); - } + const defaults = { + sort(a, b) { + return ascending(a.node.dcg_nodeKey, b.node.dcg_nodeKey); + }, }; ensure_inner_nodes(_tree); - var flexTree = create_flextree(defaults, _tree); - switch(options.algo) { - case 'css-layout': - flexTree.style.width = _graph.width; - flexTree.style.height = _graph.height; - break; - case 'yoga-layout': - set_yoga_attr(flexTree, 'width', _graph.width); - set_yoga_attr(flexTree, 'height', _graph.height); - break; + const flexTree = create_flextree(defaults, _tree); + switch (options.algo) { + case 'css-layout': + flexTree.style.width = _graph.width; + flexTree.style.height = _graph.height; + break; + case 'yoga-layout': + set_yoga_attr(flexTree, 'width', _graph.width); + set_yoga_attr(flexTree, 'height', _graph.height); + break; } - if(_engine.logStuff()) + if (_engine.logStuff()) console.log(JSON.stringify(flexTree, null, 2)); - switch(options.algo) { - case 'css-layout': - computeLayout(flexTree); - break; - case 'yoga-layout': - flexTree.calculateLayout(); - break; + switch (options.algo) { + case 'css-layout': + computeLayout(flexTree); + break; + case 'yoga-layout': + flexTree.calculateLayout(); + break; } apply_layout({x: 0, y: 0}, _tree); dispatchState(_wnodes, [], 'end'); @@ -282,65 +290,84 @@ dc_graph.flexbox_layout = function(id, options) { // needed for layout and does not pass in the original data. flexbox has a huge number of attributes // and it might be more appropriate for it to look at the original data. // (Especially because it also computes some attributes based on data.) - var supportedAttributes = [ - 'width', 'height', // positive number - 'minWidth', 'minHeight', // positive number - 'maxWidth', 'maxHeight', // positive number - 'left', 'right', 'top', 'bottom', // number - 'margin', 'marginLeft', 'marginRight', 'marginTop', 'marginBottom', // number - 'padding', 'paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom', // positive number - 'borderWidth', 'borderLeftWidth', 'borderRightWidth', 'borderTopWidth', 'borderBottomWidth', // positive number + const supportedAttributes = [ + 'width', + 'height', // positive number + 'minWidth', + 'minHeight', // positive number + 'maxWidth', + 'maxHeight', // positive number + 'left', + 'right', + 'top', + 'bottom', // number + 'margin', + 'marginLeft', + 'marginRight', + 'marginTop', + 'marginBottom', // number + 'padding', + 'paddingLeft', + 'paddingRight', + 'paddingTop', + 'paddingBottom', // positive number + 'borderWidth', + 'borderLeftWidth', + 'borderRightWidth', + 'borderTopWidth', + 'borderBottomWidth', // positive number 'flexDirection', // 'column', 'row' 'justifyContent', // 'flex-start', 'center', 'flex-end', 'space-between', 'space-around' - 'alignItems', 'alignSelf', // 'flex-start', 'center', 'flex-end', 'stretch' + 'alignItems', + 'alignSelf', // 'flex-start', 'center', 'flex-end', 'stretch' 'flex', // positive number 'flexWrap', // 'wrap', 'nowrap' - 'position' // 'relative', 'absolute' + 'position', // 'relative', 'absolute' ]; - var _engine = { - layoutAlgorithm: function() { + const _engine = { + layoutAlgorithm() { return 'cola'; }, - layoutId: function() { + layoutId() { return _layoutId; }, - supportsWebworker: function() { + supportsWebworker() { return true; }, parent: property(null), - on: function(event, f) { - if(arguments.length === 1) + on(event, f) { + if (arguments.length === 1) return _dispatch.on(event); _dispatch.on(event, f); return this; }, - init: function(options) { - this.optionNames().forEach(function(option) { + init(options) { + this.optionNames().forEach(option => { options[option] = options[option] || this[option](); - }.bind(this)); + }); init(options); return this; }, - data: function(graph, nodes) { + data(graph, nodes) { data(graph, nodes); }, - start: function() { + start() { start(); }, - stop: function() { + stop() { stop(); }, - optionNames: function() { + optionNames() { return []; }, - populateLayoutNode: function(n1, n) { - ['sort', 'order'].concat(supportedAttributes).forEach(function(attr) { - if(n.orig.value[attr]) + populateLayoutNode(n1, n) { + ['sort', 'order'].concat(supportedAttributes).forEach(attr => { + if (n.orig.value[attr]) n1[attr] = n.orig.value[attr]; }); }, - populateLayoutEdge: function() {}, + populateLayoutEdge() {}, /** * This function constructs a node key string from an "address". An address is an array of * strings identifying the path from the root to the node. @@ -352,8 +379,8 @@ dc_graph.flexbox_layout = function(id, options) { * @param {Function} [addressToKey = function(ad) { return ad.join(','); }] * @return {Function} * @return {dc_graph.flexbox_layout} - **/ - addressToKey: property(function(ad) { return ad.join(','); }), + */ + addressToKey: property(ad => ad.join(',')), /** * This function constructs an "address" from a node key string. An address is an array of * strings identifying the path from the root to the node. @@ -365,16 +392,16 @@ dc_graph.flexbox_layout = function(id, options) { * @param {Function} [keyToAddress = function(nid) { return nid.split(','); }] * @return {Function} * @return {dc_graph.flexbox_layout} - **/ - keyToAddress: property(function(nid) { return nid.split(','); }), - yogaConstants: function() { - // in case any are missing, they can be added - // please file PRs for any missing constants! - return yoga_constants; + */ + keyToAddress: property(nid => nid.split(',')), + yogaConstants() { + // Direct access to yoga constants + return yoga; }, - logStuff: property(false) + logStuff: property(false), }; return _engine; -}; +} -dc_graph.flexbox_layout.scripts = ['css-layout.js']; +// No external scripts needed - yoga-layout is imported as ES6 module +flexboxLayout.scripts = []; diff --git a/src/footer.js b/src/footer.js deleted file mode 100644 index 81e10440..00000000 --- a/src/footer.js +++ /dev/null @@ -1,21 +0,0 @@ -dc_graph.d3 = d3; -dc_graph.crossfilter = crossfilter; -dc_graph.dc = dc; - -return dc_graph; -} - if (typeof define === 'function' && define.amd) { - define(["d3", "crossfilter", "dc"], _dc_graph); - } else if (typeof module == "object" && module.exports) { - var _d3 = require('d3'); - var _crossfilter = require('crossfilter'); - if (typeof _crossfilter !== "function") { - _crossfilter = _crossfilter.crossfilter; - } - var _dc = require('dc'); - module.exports = _dc_graph(_d3, _crossfilter, _dc); - } else { - this.dc_graph = _dc_graph(d3, crossfilter, dc); - } -} -)(); diff --git a/src/generate.js b/src/generate.js index 9e5c8d05..efa25345 100644 --- a/src/generate.js +++ b/src/generate.js @@ -1,98 +1,107 @@ -dc_graph.node_name = function(i) { +export function nodeName(i) { // a-z, A-Z, aa-Zz, then quit - if(i<26) + if (i < 26) return String.fromCharCode(97+i); - else if(i<52) + else if (i < 52) return String.fromCharCode(65+i-26); - else if(i<52*52) - return dc_graph.node_name(Math.floor(i/52)) + dc_graph.node_name(i%52); + else if (i < 52*52) + return nodeName(Math.floor(i/52))+nodeName(i%52); else throw new Error("no, that's too large"); -}; -dc_graph.node_object = function(i, attrs) { +} +export function nodeObject(i, attrs) { attrs = attrs || {}; return _.extend({ id: i, - name: dc_graph.node_name(i) + name: nodeName(i), }, attrs); -}; +} -dc_graph.edge_object = function(namef, i, j, attrs) { +export function edgeObject(namef, i, j, attrs) { attrs = attrs || {}; return _.extend({ source: i, target: j, sourcename: namef(i), - targetname: namef(j) + targetname: namef(j), }, attrs); -}; +} -dc_graph.generate = function(type, args, env, callback) { - var nodes, edges, i, j; - var nodePrefix = env.nodePrefix || ''; - var namef = function(i) { +export function generate(type, args, env, callback) { + let nodes, edges, i, j; + const nodePrefix = env.nodePrefix || ''; + const namef = function(i) { return nodes[i].name; }; - var N = args[0]; - var linkLength = env.linkLength || 30; - switch(type) { - case 'clique': - case 'cliquestf': - nodes = new Array(N); - edges = []; - for(i = 0; i 0) { - var choice = Math.random(); - var n1, n2; - if(!_nodes.length || choice < options.newComponentProb) { + while (N > 0) { + const choice = Math.random(); + let n1, n2; + if (!_nodes.length || choice < options.newComponentProb) { n1 = new_node(); N--; } else n1 = random_node(); - if(choice < options.newNodeProb) { + if (choice < options.newNodeProb) { n2 = new_node(); N--; } else n2 = random_node(); - if(n1 && n2) { - var edge = {}; + if (n1 && n2) { + const edge = {}; edge[options.edgeKey] = options.edgeKeyGen(_edges.length); const sourceKey = n1[options.nodeKey], targetKey = n2[options.nodeKey]; - if(!options.allowParallelEdges) { - if(edgeInserted[sourceKey] && edgeInserted[sourceKey][targetKey]) + if (!options.allowParallelEdges) { + if (edgeInserted[sourceKey] && edgeInserted[sourceKey][targetKey]) continue; - edgeInserted[sourceKey] = edgeInserted[sourceKey] || {} + edgeInserted[sourceKey] = edgeInserted[sourceKey] || {}; edgeInserted[sourceKey][targetKey] = true; } edge[options.sourceKey] = sourceKey; edge[options.targetKey] = targetKey; edge[options.dashTag] = Math.floor(Math.random()*options.ndashes); - if(options.log) - console.log(n1[options.nodeKey] + ' -> ' + n2[options.nodeKey]); + if (options.log) + console.log(`${n1[options.nodeKey]} -> ${n2[options.nodeKey]}`); _edges.push(edge); } } }, - remove: function(N) { - while(N-- > 0) { - var choice = Math.random(); - if(choice < options.removeEdgeProb) + remove(N) { + while (N-- > 0) { + const choice = Math.random(); + if (choice < options.removeEdgeProb) _edges.splice(Math.floor(Math.random()*_edges.length), 1); else { - var n = _nodes[Math.floor(Math.random()*_nodes.length)]; - var eis = []; - _edges.forEach(function(e, ei) { - if(e[options.sourceKey] === n[options.nodeKey] || - e[options.targetKey] === n[options.nodeKey]) + const n = _nodes[Math.floor(Math.random()*_nodes.length)]; + const eis = []; + _edges.forEach((e, ei) => { + if ( + e[options.sourceKey] === n[options.nodeKey] + || e[options.targetKey] === n[options.nodeKey] + ) eis.push(ei); }); - eis.reverse().forEach(function(ei) { + eis.reverse().forEach(ei => { _edges.splice(ei, 1); }); } } - } + }, }; -}; +} diff --git a/src/generate_objects.js b/src/generate_objects.js index e9cbbf47..60811b64 100644 --- a/src/generate_objects.js +++ b/src/generate_objects.js @@ -1,32 +1,37 @@ +/** + * Object generation and management utilities + * @module generate_objects + */ + // create or re-use objects in a map, delete the ones that were not reused -function regenerate_objects(preserved, list, need, key, assign, create, destroy) { - if(!create) create = function(k, o) { }; - if(!destroy) destroy = function(k) { }; - var keep = {}; +export function regenerateObjects(preserved, list, need, key, assign, create, destroy) { + if (!create) create = function(_k, _o) {}; + if (!destroy) destroy = function(_k) {}; + const keep = {}; function wrap(o) { - var k = key(o); - if(!preserved[k]) + const k = key(o); + if (!preserved[k]) create(k, preserved[k] = {}, o); - var o1 = preserved[k]; + const o1 = preserved[k]; assign(o1, o); keep[k] = true; return o1; } - var wlist = list.map(wrap); - if(need) - need.forEach(function(k) { - if(!preserved[k]) { // hasn't been created, needs to be + const wlist = list.map(wrap); + if (need) + need.forEach(k => { + if (!preserved[k]) { // hasn't been created, needs to be create(k, preserved[k] = {}, null); assign(preserved[k], null); } - if(!keep[k]) { // wasn't in list, should be + if (!keep[k]) { // wasn't in list, should be wlist.push(preserved[k]); keep[k] = true; } }); // delete any objects from last round that are no longer used - for(var k in preserved) - if(!keep[k]) { + for (const k in preserved) + if (!keep[k]) { destroy(k, preserved[k]); delete preserved[k]; } diff --git a/src/graphviz_attrs.js b/src/graphviz_attrs.js index 35419e5d..7d47ae12 100644 --- a/src/graphviz_attrs.js +++ b/src/graphviz_attrs.js @@ -1,14 +1,19 @@ /** - * `dc_graph.graphviz_attrs defines a basic set of attributes which layout engines should + * Graphviz attributes for layout engines + * @module graphviz_attrs + */ + +import { property } from './core.js'; + +/** + * `graphvizAttrs` defines a basic set of attributes which layout engines should * implement - although these are not required, they make it easier for clients and * modes (like expand_collapse) to work with multiple layout engines. * * these attributes are {@link http://www.graphviz.org/doc/info/attrs.html from graphviz} - * @class graphviz_attrs - * @memberof dc_graph * @return {Object} - **/ -dc_graph.graphviz_attrs = function() { + */ +export function graphvizAttrs() { return { /** * Direction to draw ranks. @@ -16,7 +21,7 @@ dc_graph.graphviz_attrs = function() { * @memberof dc_graph.graphviz_attrs * @instance * @param {String} [rankdir='TB'] 'TB', 'LR', 'BT', or 'RL' - **/ + */ rankdir: property('TB'), /** * Spacing in between nodes in the same rank. @@ -24,7 +29,7 @@ dc_graph.graphviz_attrs = function() { * @memberof dc_graph.graphviz_attrs * @instance * @param {String} [nodesep=40] - **/ + */ nodesep: property(40), /** * Spacing in between ranks. @@ -32,10 +37,10 @@ dc_graph.graphviz_attrs = function() { * @memberof dc_graph.graphviz_attrs * @instance * @param {String} [ranksep=40] - **/ - ranksep: property(40) + */ + ranksep: property(40), }; -}; +} // graphlib-dot seems to wrap nodes in an extra {value} // actually this is quite a common problem with generic libs @@ -45,124 +50,113 @@ function nvalue(n) { // apply standard accessors to a diagram in order to style it as graphviz would // this is a work in progress -dc_graph.apply_graphviz_accessors = function(diagram) { +export function applyGraphvizAccessors(diagram) { diagram - .nodeLabel(function(n) { - var label = nvalue(n).label; - if(label === undefined) + .nodeLabel(n => { + let label = nvalue(n).label; + if (label === undefined) label = n.key; return label && label.split(/\n|\\n/); }) - .nodeRadius(function(n) { + .nodeRadius(n => // should do width & height instead, #25 - return nvalue(n).radius || 25; - }) - .nodeShape(function(n) { return nvalue(n).shape; }) - .nodeFill(function(n) { return nvalue(n).fillcolor || 'white'; }) - .nodeOpacity(function(n) { + nvalue(n).radius || 25 + ) + .nodeShape(n => nvalue(n).shape) + .nodeFill(n => nvalue(n).fillcolor || 'white') + .nodeOpacity(n => // not standard gv - return nvalue(n).opacity || 1; - }) - .nodeLabelFill(function(n) { return nvalue(n).fontcolor || 'black'; }) - .nodeTitle(function(n) { - return (nvalue(n).htmltip || nvalue(n).jsontip) ? null : - nvalue(n).tooltip !== undefined ? - nvalue(n).tooltip : - diagram.nodeLabel()(n); - }) - .nodeStrokeWidth(function(n) { + nvalue(n).opacity || 1 + ) + .nodeLabelFill(n => nvalue(n).fontcolor || 'black') + .nodeTitle(n => + (nvalue(n).htmltip || nvalue(n).jsontip) + ? null + : nvalue(n).tooltip !== undefined + ? nvalue(n).tooltip + : diagram.nodeLabel()(n) + ) + .nodeStrokeWidth(n => { // it is debatable whether a point === a pixel but they are close // https://graphicdesign.stackexchange.com/questions/199/point-vs-pixel-what-is-the-difference - var penwidth = nvalue(n).penwidth; + const penwidth = nvalue(n).penwidth; return penwidth !== undefined ? +penwidth : 1; }) - .edgeLabel(function(e) { return e.value.label ? e.value.label.split(/\n|\\n/) : ''; }) - .edgeStroke(function(e) { return e.value.color || 'black'; }) - .edgeOpacity(function(e) { + .edgeLabel(e => e.value.label ? e.value.label.split(/\n|\\n/) : '') + .edgeStroke(e => e.value.color || 'black') + .edgeOpacity(e => // not standard gv - return e.value.opacity || 1; - }) - .edgeArrowSize(function(e) { - return e.value.arrowsize || 1; - }) + e.value.opacity || 1 + ) + .edgeArrowSize(e => e.value.arrowsize || 1) // need directedness to default these correctly, see #106 - .edgeArrowhead(function(e) { - var head = e.value.arrowhead; + .edgeArrowhead(e => { + const head = e.value.arrowhead; return head !== undefined ? head : 'vee'; }) - .edgeArrowtail(function(e) { - var tail = e.value.arrowtail; + .edgeArrowtail(e => { + const tail = e.value.arrowtail; return tail !== undefined ? tail : null; }) - .edgeStrokeDashArray(function(e) { - switch(e.value.style) { - case 'dotted': - return [1,5]; + .edgeStrokeDashArray(e => { + switch (e.value.style) { + case 'dotted': + return [1, 5]; } return null; }); - var draw_clusters = diagram.child('draw-clusters'); - if(draw_clusters) { + const draw_clusters = diagram.child('draw-clusters'); + if (draw_clusters) { draw_clusters - .clusterStroke(function(c) { - return c.value.color || 'black'; - }) - .clusterFill(function(c) { - return c.value.style === 'filled' ? c.value.fillcolor || c.value.color || c.value.bgcolor : null; - }) - .clusterLabel(function(c) { - return c.value.label; - }); + .clusterStroke(c => c.value.color || 'black') + .clusterFill(c => + c.value.style === 'filled' + ? c.value.fillcolor || c.value.color || c.value.bgcolor + : null + ) + .clusterLabel(c => c.value.label); } -}; +} -dc_graph.snapshot_graphviz = function(diagram) { - var xDomain = diagram.x().domain(), yDomain = diagram.y().domain(); +export function snapshotGraphviz(diagram) { + const xDomain = diagram.x().domain(), yDomain = diagram.y().domain(); return { - nodes: diagram.nodeGroup().all().map(function(n) { - return diagram.getWholeNode(n.key); - }) - .filter(function(x) { return x; }) - .map(function(n) { - return { - key: diagram.nodeKey.eval(n), - label: diagram.nodeLabel.eval(n), - fillcolor: diagram.nodeFillScale()(diagram.nodeFill.eval(n)), - penwidth: diagram.nodeStrokeWidth.eval(n), - // not supported as input, see dc.graph.js#25 - // width: n.cola.dcg_rx*2, - // height: n.cola.dcg_ry*2, + nodes: diagram.nodeGroup().all().map(n => diagram.getWholeNode(n.key)) + .filter(x => x) + .map(n => ({ + key: diagram.nodeKey.eval(n), + label: diagram.nodeLabel.eval(n), + fillcolor: diagram.nodeFillScale()(diagram.nodeFill.eval(n)), + penwidth: diagram.nodeStrokeWidth.eval(n), + // not supported as input, see dc.graph.js#25 + // width: n.cola.dcg_rx*2, + // height: n.cola.dcg_ry*2, - // not graphviz attributes - // until we have w/h - radius: diagram.nodeRadius.eval(n), - // does not seem to exist in gv - opacity: diagram.nodeOpacity.eval(n), - // should be pos - x: n.cola.x, - y: n.cola.y - }; - }), - edges: diagram.edgeGroup().all().map(function(e) { - return diagram.getWholeEdge(e.key); - }).map(function(e) { - return { - key: diagram.edgeKey.eval(e), - source: diagram.edgeSource.eval(e), - target: diagram.edgeTarget.eval(e), - color: diagram.edgeStroke.eval(e), - arrowsize: diagram.edgeArrowSize.eval(e), - opacity: diagram.edgeOpacity.eval(e), - // should support dir, see dc.graph.js#106 - arrowhead: diagram.edgeArrowhead.eval(e), - arrowtail: diagram.edgeArrowtail.eval(e) - }; - }), + // not graphviz attributes + // until we have w/h + radius: diagram.nodeRadius.eval(n), + // does not seem to exist in gv + opacity: diagram.nodeOpacity.eval(n), + // should be pos + x: n.cola.x, + y: n.cola.y, + })), + edges: diagram.edgeGroup().all().map(e => diagram.getWholeEdge(e.key)).map(e => ({ + key: diagram.edgeKey.eval(e), + source: diagram.edgeSource.eval(e), + target: diagram.edgeTarget.eval(e), + color: diagram.edgeStroke.eval(e), + arrowsize: diagram.edgeArrowSize.eval(e), + opacity: diagram.edgeOpacity.eval(e), + // should support dir, see dc.graph.js#106 + arrowhead: diagram.edgeArrowhead.eval(e), + arrowtail: diagram.edgeArrowtail.eval(e), + })), bounds: { left: xDomain[0], top: yDomain[0], right: xDomain[1], - bottom: yDomain[1] - } + bottom: yDomain[1], + }, }; -}; +} diff --git a/src/graphviz_layout.js b/src/graphviz_layout.js index 4c1af8ca..5724dc8a 100644 --- a/src/graphviz_layout.js +++ b/src/graphviz_layout.js @@ -1,19 +1,30 @@ /** - * `dc_graph.graphviz_layout` is an adaptor for viz.js (graphviz) layouts in dc.graph.js + * Graphviz layout for dc.graph.js + * @module graphviz_layout + */ + +// External dependencies +import { dispatch } from 'd3-dispatch'; +import { json } from 'd3-fetch'; +import { uuid } from './core.js'; +import { graphvizAttrs } from './graphviz_attrs.js'; + +/** + * `graphvizLayout` is an adaptor for viz.js (graphviz) layouts in dc.graph.js * - * In addition to the below layout attributes, `graphviz_layout` also implements the attributes from - * {@link dc_graph.graphviz_attrs graphviz_attrs} - * @class graphviz_layout - * @memberof dc_graph + * In addition to the below layout attributes, `graphvizLayout` also implements the attributes from + * {@link graphvizAttrs graphviz_attrs} * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.graphviz_layout} - **/ -dc_graph.graphviz_layout = function(id, layout, server) { - var _layoutId = id || uuid(); - var _dispatch = d3.dispatch('tick', 'start', 'end'); - var _dotInput, _dotString; + * @param {String} [layout] - Layout algorithm + * @param {String} [server] - Server URL + * @return {Object} graphviz layout engine + */ +export function graphvizLayout(id, layout, server) { + const _layoutId = id || uuid(); + const _dispatch = dispatch('tick', 'start', 'end'); + let _dotInput, _dotString; - function init(options) { + function init(_options) { } function encode_name(name) { @@ -23,132 +34,137 @@ dc_graph.graphviz_layout = function(id, layout, server) { return name.replace(/^%/, '%'); } function stringize_property(prop, value) { - return [prop, '"' + value + '"'].join('='); + return [prop, `"${value}"`].join('='); } function stringize_properties(props) { - return '[' + props.join(', ') + ']'; + return `[${props.join(', ')}]`; } function data(nodes, edges, clusters) { - if(_dotInput) { + if (_dotInput) { _dotString = _dotInput; return; } - var lines = []; - var directed = layout !== 'neato'; - lines.push((directed ? 'digraph' : 'graph') + ' g {'); - lines.push('graph ' + stringize_properties([ - stringize_property('nodesep', graphviz.nodesep()/72), - stringize_property('ranksep', graphviz.ranksep()/72), - stringize_property('rankdir', graphviz.rankdir()) - ])); - var cluster_nodes = {}; - nodes.forEach(function(n) { - var cl = n.dcg_nodeParentCluster; - if(cl) { + let lines = []; + const directed = layout !== 'neato'; + lines.push(`${directed ? 'digraph' : 'graph'} g {`); + lines.push(`graph ${ + stringize_properties([ + stringize_property('nodesep', graphviz.nodesep()/72), + stringize_property('ranksep', graphviz.ranksep()/72), + stringize_property('rankdir', graphviz.rankdir()), + ]) + }`); + const cluster_nodes = {}; + nodes.forEach(n => { + const cl = n.dcg_nodeParentCluster; + if (cl) { cluster_nodes[cl] = cluster_nodes[cl] || []; cluster_nodes[cl].push(n.dcg_nodeKey); } }); - var cluster_children = {}, tops = []; - clusters.forEach(function(c) { - var p = c.dcg_clusterParent; - if(p) { + const cluster_children = {}, tops = []; + clusters.forEach(c => { + const p = c.dcg_clusterParent; + if (p) { cluster_children[p] = cluster_children[p] || []; cluster_children[p].push(c.dcg_clusterKey); } else tops.push(c.dcg_clusterKey); }); function print_subgraph(i, c) { - var indent = ' '.repeat(i*2); - lines.push(indent + 'subgraph "' + c + '" {'); - if(cluster_children[c]) + const indent = ' '.repeat(i*2); + lines.push(`${indent}subgraph "${c}" {`); + if (cluster_children[c]) cluster_children[c].forEach(print_subgraph.bind(null, i+1)); - if(cluster_nodes[c]) - lines.push(indent + ' ' + cluster_nodes[c].map(function (s) { return JSON.stringify(s) }).join(' ')); - lines.push(indent + '}'); + if (cluster_nodes[c]) + lines.push(`${indent} ${cluster_nodes[c].map(s => JSON.stringify(s)).join(' ')}`); + lines.push(`${indent}}`); } tops.forEach(print_subgraph.bind(null, 1)); - lines = lines.concat(nodes.map(function(v) { - var props = [ + lines = lines.concat(nodes.map(v => { + const props = [ stringize_property('width', v.width/72), stringize_property('height', v.height/72), stringize_property('fixedsize', 'shape'), - stringize_property('shape', v.abstract.shape) + stringize_property('shape', v.abstract.shape), ]; - if(v.dcg_nodeFixed) - props.push(stringize_property('pos', [ - v.dcg_nodeFixed.x, - 1000-v.dcg_nodeFixed.y - ].join(','))); - return ' "' + encode_name(v.dcg_nodeKey) + '" ' + stringize_properties(props); - })); - lines = lines.concat(edges.map(function(e) { - return ' "' + encode_name(e.dcg_edgeSource) + (directed ? '" -> "' : '" -- "') + - encode_name(e.dcg_edgeTarget) + '" ' + stringize_properties([ - stringize_property('id', encode_name(e.dcg_edgeKey)), - stringize_property('arrowhead', 'none'), - stringize_property('arrowtail', 'none') - ]); + if (v.dcg_nodeFixed) + props.push(stringize_property( + 'pos', + [ + v.dcg_nodeFixed.x, + 1000-v.dcg_nodeFixed.y, + ].join(','), + )); + return ` "${encode_name(v.dcg_nodeKey)}" ${stringize_properties(props)}`; })); + lines = lines.concat( + edges.map(e => + ` "${encode_name(e.dcg_edgeSource)}${directed ? '" -> "' : '" -- "'}${ + encode_name(e.dcg_edgeTarget) + }" ${ + stringize_properties([ + stringize_property('id', encode_name(e.dcg_edgeKey)), + stringize_property('arrowhead', 'none'), + stringize_property('arrowtail', 'none'), + ]) + }` + ), + ); lines.push('}'); lines.push(''); _dotString = lines.join('\n'); } function process_response(error, result) { - if(error) { - console.warn("graphviz layout failed: ", error); + if (error) { + console.warn('graphviz layout failed: ', error); return; } - _dispatch.start(); - var bb = result.bb.split(',').map(function(x) { return +x; }); - var nodes = (result.objects || []).filter(function(n) { - return n.pos; // remove non-nodes like clusters - }).map(function(n) { - var pos = n.pos.split(','); - if(isNaN(pos[0]) || isNaN(pos[1])) { + _dispatch.call('start'); + const bb = result.bb.split(',').map(x => +x); + const nodes = (result.objects || []).filter(n => n.pos // remove non-nodes like clusters + ).map(n => { + const pos = n.pos.split(','); + if (isNaN(pos[0]) || isNaN(pos[1])) { console.warn('got a NaN position from graphviz'); pos[0] = pos[1] = 0; } return { dcg_nodeKey: decode_name(n.name), x: +pos[0], - y: bb[3] - pos[1] + y: bb[3]-pos[1], }; }); - var clusters = (result.objects || []).filter(function(n) { - return /^cluster/.test(n.name) && n.bb; - }); - clusters.forEach(function(c) { + const clusters = (result.objects || []).filter(n => /^cluster/.test(n.name) && n.bb); + clusters.forEach(c => { c.dcg_clusterKey = c.name; // gv: llx, lly, urx, ury, up-positive - var cbb = c.bb.split(',').map(function(s) { return +s; }); - c.bounds = {left: cbb[0], top: bb[3] - cbb[3], - right: cbb[2], bottom: bb[3] - cbb[1]}; + const cbb = c.bb.split(',').map(s => +s); + c.bounds = {left: cbb[0], top: bb[3]-cbb[3], right: cbb[2], bottom: bb[3]-cbb[1]}; }); - var edges = (result.edges || []).map(function(e) { - var e2 = { - dcg_edgeKey: decode_name(e.id || 'n' + e._gvid) + const edges = (result.edges || []).map(e => { + const e2 = { + dcg_edgeKey: decode_name(e.id || `n${e._gvid}`), }; - if(e._draw_) { - var directive = e._draw_.find(function(d) { return d.op && d.points; }); - e2.points = directive.points.map(function(p) { return {x: p[0], y: bb[3] - p[1]}; }); + if (e._draw_) { + const directive = e._draw_.find(d => d.op && d.points); + e2.points = directive.points.map(p => ({x: p[0], y: bb[3]-p[1]})); } return e2; }); - _dispatch.end(nodes, edges, clusters); + _dispatch.call('end', null, nodes, edges, clusters); } function start() { - if(server) { - d3.json(server) - .header("Content-type", "application/x-www-form-urlencoded") - .post('layouttool=' + layout + '&' + encodeURIComponent(_dotString), process_response); - } - else { - var result = Viz(_dotString, {format: 'json', engine: layout, totalMemory: 1 << 25}); + if (server) { + json(server) + .header('Content-type', 'application/x-www-form-urlencoded') + .post(`layouttool=${layout}&${encodeURIComponent(_dotString)}`, process_response); + } else { + let result = Viz(_dotString, {format: 'json', engine: layout, totalMemory: 1<<25}); result = JSON.parse(result); process_response(null, result); } @@ -157,48 +173,47 @@ dc_graph.graphviz_layout = function(id, layout, server) { function stop() { } - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); + const graphviz = graphvizAttrs(), graphviz_keys = Object.keys(graphviz); return Object.assign(graphviz, { - layoutAlgorithm: function() { + layoutAlgorithm() { return layout; }, - layoutId: function() { + layoutId() { return _layoutId; }, - supportsWebworker: function() { + supportsWebworker() { return false; }, - on: function(event, f) { - if(arguments.length === 1) + on(event, f) { + if (arguments.length === 1) return _dispatch.on(event); _dispatch.on(event, f); return this; }, - init: function(options) { - this.optionNames().forEach(function(option) { + init(options) { + this.optionNames().forEach(option => { options[option] = options[option] || this[option](); - }.bind(this)); + }); init(options); return this; }, - data: function(graph, nodes, edges, clusters) { + data(graph, nodes, edges, clusters) { data(nodes, edges, clusters); }, - dotInput: function(text) { + dotInput(text) { _dotInput = text; return this; }, - start: function() { + start() { start(); }, - stop: function() { + stop() { stop(); }, - optionNames: function() { + optionNames() { return graphviz_keys; }, - populateLayoutNode: function() {}, - populateLayoutEdge: function() {} + populateLayoutNode() {}, + populateLayoutEdge() {}, }); } - diff --git a/src/grid.js b/src/grid.js index 16669beb..d14dce5d 100644 --- a/src/grid.js +++ b/src/grid.js @@ -1,57 +1,60 @@ -dc_graph.grid = function() { - var _gridLayer = null; - var _translate, _scale, _xDomain, _yDomain; +import { property } from './core.js'; +import { mode } from './mode.js'; - function draw(diagram, node, edge, ehover) { - //infer_and_draw(diagram); +// External dependencies +import { range } from 'd3-array'; + +export function grid() { + let _gridLayer = null; + let _translate, _scale, _xDomain, _yDomain; + + function drawMode(_diagram, _node, _edge, _ehover) { + // infer_and_draw(diagram); } - function remove(diagram, node, edge, ehover) { - if(_gridLayer) + function remove(_diagram, _node, _edge, _ehover) { + if (_gridLayer) _gridLayer.remove(); } function draw(diagram) { _gridLayer = diagram.g().selectAll('g.grid-layer').data([0]); _gridLayer.enter().append('g').attr('class', 'grid-layer'); - var ofs = _mode.wholeOnLines() ? 0 : 0.5; - var vline_data = _scale >= _mode.threshold() ? d3.range(Math.floor(_xDomain[0]), Math.ceil(_xDomain[1]) + 1) : []; - var vlines = _gridLayer.selectAll('line.grid-line.vertical') - .data(vline_data, function(d) { return d - ofs; }); + const ofs = _mode.wholeOnLines() ? 0 : 0.5; + const vline_data = _scale >= _mode.threshold() + ? range(Math.floor(_xDomain[0]), Math.ceil(_xDomain[1])+1) + : []; + let vlines = _gridLayer.selectAll('line.grid-line.vertical') + .data(vline_data, d => d-ofs); vlines.exit().remove(); - vlines.enter().append('line') - .attr({ - class: 'grid-line vertical', - x1: function(d) { return d - ofs; }, - x2: function(d) { return d - ofs; } - }); - vlines.attr({ - 'stroke-width': 1/_scale, - y1: _yDomain[0], - y2: _yDomain[1] - }); - var hline_data = _scale >= _mode.threshold() ? d3.range(Math.floor(_yDomain[0]), Math.ceil(_yDomain[1]) + 1) : []; - var hlines = _gridLayer.selectAll('line.grid-line.horizontal') - .data(hline_data, function(d) { return d - ofs; }); + const vlinesEnter = vlines.enter().append('line') + .attr('class', 'grid-line vertical') + .attr('x1', d => d-ofs) + .attr('x2', d => d-ofs); + vlines = vlines.merge(vlinesEnter); + vlines.attr('stroke-width', 1/_scale) + .attr('y1', _yDomain[0]) + .attr('y2', _yDomain[1]); + const hline_data = _scale >= _mode.threshold() + ? range(Math.floor(_yDomain[0]), Math.ceil(_yDomain[1])+1) + : []; + let hlines = _gridLayer.selectAll('line.grid-line.horizontal') + .data(hline_data, d => d-ofs); hlines.exit().remove(); - hlines.enter().append('line') - .attr({ - class: 'grid-line horizontal', - y1: function(d) { return d - ofs; }, - y2: function(d) { return d - ofs; } - }); - hlines.attr({ - 'stroke-width': 1/_scale, - x1: _xDomain[0], - x2: _xDomain[1] - }); + const hlinesEnter = hlines.enter().append('line') + .attr('class', 'grid-line horizontal') + .attr('y1', d => d-ofs) + .attr('y2', d => d-ofs); + hlines = hlines.merge(hlinesEnter); + hlines.attr('stroke-width', 1/_scale) + .attr('x1', _xDomain[0]) + .attr('x2', _xDomain[1]); } function on_zoom(translate, scale, xDomain, yDomain) { _translate = translate; _scale = scale; - _xDomain = xDomain, - _yDomain = yDomain; + _xDomain = xDomain, _yDomain = yDomain; draw(_mode.parent()); } @@ -63,21 +66,19 @@ dc_graph.grid = function() { draw(diagram); } - var _mode = dc_graph.mode('highlight-paths', { - draw: draw, - remove: remove, - parent: function(p) { - if(p) { + const _mode = mode('highlight-paths', { + draw: drawMode, + remove, + parent(p) { + if (p) { p.on('zoomed.grid', on_zoom); infer_and_draw(p); } - } + }, }); _mode.threshold = property(4); _mode.wholeOnLines = property(true); return _mode; -}; - - +} diff --git a/src/highlight_neighbors.js b/src/highlight_neighbors.js index 99eb0915..02fe1ab5 100644 --- a/src/highlight_neighbors.js +++ b/src/highlight_neighbors.js @@ -1,57 +1,74 @@ -dc_graph.highlight_neighbors = function(includeprops, excludeprops, neighborsgroup, thingsgroup) { - var highlight_neighbors_group = dc_graph.register_highlight_neighbors_group(neighborsgroup || 'highlight-neighbors-group'); - var highlight_things_group = dc_graph.register_highlight_things_group(thingsgroup || 'highlight-things-group'); +import { property } from './core.js'; +import { registerHighlightNeighborsGroup } from './highlight_neighbors_group.js'; +import { highlightThings } from './highlight_things.js'; +import { registerHighlightThingsGroup } from './highlight_things_group.js'; +import { mode } from './mode.js'; + +export function highlightNeighbors(includeprops, excludeprops, neighborsgroup, thingsgroup) { + const highlight_neighbors_group = registerHighlightNeighborsGroup( + neighborsgroup || 'highlight-neighbors-group', + ); + const highlight_things_group = registerHighlightThingsGroup( + thingsgroup || 'highlight-things-group', + ); function highlight_node(nodeid) { - var diagram = _mode.parent(); - var nodeset = {}, edgeset = {}; - if(nodeid) { + const diagram = _mode.parent(); + const nodeset = {}, edgeset = {}; + if (nodeid) { nodeset[nodeid] = true; - _mode.parent().selectAllEdges().each(function(e) { - if(diagram.nodeKey.eval(e.source) === nodeid) { + _mode.parent().selectAllEdges().each(e => { + if (diagram.nodeKey.eval(e.source) === nodeid) { edgeset[diagram.edgeKey.eval(e)] = true; nodeset[diagram.nodeKey.eval(e.target)] = true; } - if(diagram.nodeKey.eval(e.target) === nodeid) { + if (diagram.nodeKey.eval(e.target) === nodeid) { edgeset[diagram.edgeKey.eval(e)] = true; nodeset[diagram.nodeKey.eval(e.source)] = true; } }); - highlight_things_group.highlight(nodeset, edgeset); - } - else highlight_things_group.highlight(null, null); + highlight_things_group.call('highlight', null, nodeset, edgeset); + } else highlight_things_group.call('highlight', null, null, null); } - function draw(diagram, node, edge) { + function draw(diagram, node, _edge) { node - .on('mouseover.highlight-neighbors', function(n) { - highlight_neighbors_group.highlight_node(_mode.parent().nodeKey.eval(n)); + .on('mouseover.highlight-neighbors', n => { + highlight_neighbors_group.call( + 'highlight_node', + null, + _mode.parent().nodeKey.eval(n), + ); }) - .on('mouseout.highlight-neighbors', function(n) { - highlight_neighbors_group.highlight_node(null); + .on('mouseout.highlight-neighbors', _n => { + highlight_neighbors_group.call('highlight_node', null, null); }); } - function remove(diagram, node, edge) { + function remove(diagram, node, _edge) { node .on('mouseover.highlight-neighbors', null) .on('mouseout.highlight-neighbors', null); - highlight_neighbors_group.highlight_node(null); + highlight_neighbors_group.call('highlight_node', null, null); } - var _mode = dc_graph.mode('highlight-neighbors', { - draw: draw, - remove: function(diagram, node, edge) { + const _mode = mode('highlight-neighbors', { + draw, + remove(diagram, node, edge) { remove(diagram, node, edge); }, - parent: function(p) { - highlight_neighbors_group.on('highlight_node.highlight-neighbors', p ? highlight_node : null); - if(p && !p.child('highlight-things')) - p.child('highlight-things', - dc_graph.highlight_things(includeprops, excludeprops) - .durationOverride(_mode.durationOverride())); - } + parent(p) { + highlight_neighbors_group.on( + 'highlight_node.highlight-neighbors', + p ? highlight_node : null, + ); + if (p && !p.child('highlight-things')) + p.child( + 'highlight-things', + highlightThings(includeprops, excludeprops) + .durationOverride(_mode.durationOverride()), + ); + }, }); _mode.durationOverride = property(undefined); return _mode; -}; - +} diff --git a/src/highlight_neighbors_group.js b/src/highlight_neighbors_group.js index 45defb3f..042064cc 100644 --- a/src/highlight_neighbors_group.js +++ b/src/highlight_neighbors_group.js @@ -1,7 +1,8 @@ -dc_graph.register_highlight_neighbors_group = function(neighborsgroup) { - window.chart_registry.create_type('highlight-neighbors', function() { - return d3.dispatch('highlight_node'); - }); +// External dependencies +import { dispatch } from 'd3-dispatch'; + +export function registerHighlightNeighborsGroup(neighborsgroup) { + window.chart_registry.create_type('highlight-neighbors', () => dispatch('highlight_node')); return window.chart_registry.create_group('highlight-neighbors', neighborsgroup); -}; +} diff --git a/src/highlight_paths.js b/src/highlight_paths.js index 91a6dbce..d5c653f6 100644 --- a/src/highlight_paths.js +++ b/src/highlight_paths.js @@ -1,13 +1,20 @@ -dc_graph.highlight_paths = function(pathprops, hoverprops, selectprops, pathsgroup) { - var highlight_paths_group = dc_graph.register_highlight_paths_group(pathsgroup || 'highlight-paths-group'); +import { property } from './core.js'; +import { registerHighlightPathsGroup } from './highlight_paths_group.js'; +import { mode } from './mode.js'; +import { nodeEdgeConditions } from './utils.js'; + +export function highlightPaths(pathprops, hoverprops, selectprops, pathsgroup) { + const highlight_paths_group = registerHighlightPathsGroup( + pathsgroup || 'highlight-paths-group', + ); pathprops = pathprops || {}; hoverprops = hoverprops || {}; selectprops = selectprops || {}; - var node_on_paths = {}, edge_on_paths = {}, selected = null, hoverpaths = null; - var _anchor; + let node_on_paths = {}, edge_on_paths = {}, selected = null, hoverpaths = null; + let _anchor; function refresh() { - if(_mode.doRedraw()) + if (_mode.doRedraw()) _mode.parent().relayout().redraw(); else _mode.parent().refresh(); @@ -16,8 +23,10 @@ dc_graph.highlight_paths = function(pathprops, hoverprops, selectprops, pathsgro function paths_changed(nop, eop) { selected = hoverpaths = null; // it would be difficult to check if no change, but at least check if changing from empty to empty - if(Object.keys(node_on_paths).length === 0 && Object.keys(nop).length === 0 && - Object.keys(edge_on_paths).length === 0 && Object.keys(eop).length === 0) + if ( + Object.keys(node_on_paths).length === 0 && Object.keys(nop).length === 0 + && Object.keys(edge_on_paths).length === 0 && Object.keys(eop).length === 0 + ) return; node_on_paths = nop; edge_on_paths = eop; @@ -25,14 +34,14 @@ dc_graph.highlight_paths = function(pathprops, hoverprops, selectprops, pathsgro } function hover_changed(hp) { - if(hp !== hoverpaths) { + if (hp !== hoverpaths) { hoverpaths = hp; refresh(); } } function select_changed(sp) { - if(sp !== selected) { + if (sp !== selected) { selected = sp; refresh(); } @@ -45,73 +54,88 @@ dc_graph.highlight_paths = function(pathprops, hoverprops, selectprops, pathsgro function contains_path(paths) { return function(path) { - return paths.indexOf(path)>=0; + return paths.indexOf(path) >= 0; }; } // sigh function doesnt_contain_path(paths) { - var cp = contains_path(paths); + const cp = contains_path(paths); return function(path) { return !cp(path); }; } function intersect_paths(pathsA, pathsB) { - if(!pathsA || !pathsB) + if (!pathsA || !pathsB) return false; return pathsA.some(contains_path(pathsB)); } function toggle_paths(pathsA, pathsB) { - if(!pathsA) + if (!pathsA) return pathsB; - else if(!pathsB) + else if (!pathsB) return pathsA; - if(pathsB.every(contains_path(pathsA))) + if (pathsB.every(contains_path(pathsA))) return pathsA.filter(doesnt_contain_path(pathsB)); else return pathsA.concat(pathsB.filter(doesnt_contain_path(pathsA))); } function draw(diagram, node, edge, ehover) { diagram - .cascade(200, true, node_edge_conditions(function(n) { - return !!node_on_paths[diagram.nodeKey.eval(n)]; - }, function(e) { - return !!edge_on_paths[diagram.edgeKey.eval(e)]; - }, pathprops)) - .cascade(300, true, node_edge_conditions(function(n) { - return intersect_paths(node_on_paths[diagram.nodeKey.eval(n)], selected); - }, function(e) { - return intersect_paths(edge_on_paths[diagram.edgeKey.eval(e)], selected); - }, selectprops)) - .cascade(400, true, node_edge_conditions(function(n) { - return intersect_paths(node_on_paths[diagram.nodeKey.eval(n)], hoverpaths); - }, function(e) { - return intersect_paths(edge_on_paths[diagram.edgeKey.eval(e)], hoverpaths); - }, hoverprops)); + .cascade( + 200, + true, + nodeEdgeConditions( + n => !!node_on_paths[diagram.nodeKey.eval(n)], + e => !!edge_on_paths[diagram.edgeKey.eval(e)], + pathprops, + ), + ) + .cascade( + 300, + true, + nodeEdgeConditions( + n => intersect_paths(node_on_paths[diagram.nodeKey.eval(n)], selected), + e => intersect_paths(edge_on_paths[diagram.edgeKey.eval(e)], selected), + selectprops, + ), + ) + .cascade( + 400, + true, + nodeEdgeConditions( + n => intersect_paths(node_on_paths[diagram.nodeKey.eval(n)], hoverpaths), + e => intersect_paths(edge_on_paths[diagram.edgeKey.eval(e)], hoverpaths), + hoverprops, + ), + ); node - .on('mouseover.highlight-paths', function(n) { + .on('mouseover.highlight-paths', n => { highlight_paths_group.hover_changed(node_on_paths[diagram.nodeKey.eval(n)] || null); }) - .on('mouseout.highlight-paths', function(n) { + .on('mouseout.highlight-paths', _n => { highlight_paths_group.hover_changed(null); }) - .on('click.highlight-paths', function(n) { - highlight_paths_group.select_changed(toggle_paths(selected, node_on_paths[diagram.nodeKey.eval(n)])); + .on('click.highlight-paths', n => { + highlight_paths_group.select_changed( + toggle_paths(selected, node_on_paths[diagram.nodeKey.eval(n)]), + ); }); - ehover - .on('mouseover.highlight-paths', function(e) { + .on('mouseover.highlight-paths', e => { highlight_paths_group.hover_changed(edge_on_paths[diagram.edgeKey.eval(e)] || null); }) - .on('mouseout.highlight-paths', function(e) { + .on('mouseout.highlight-paths', _e => { highlight_paths_group.hover_changed(null); }) - .on('click.highlight-paths', function(n) { - highlight_paths_group.select_changed(toggle_paths(selected, edge_on_paths[diagram.nodeKey.eval(n)])); + .on('click.highlight-paths', n => { + highlight_paths_group.select_changed( + toggle_paths(selected, edge_on_paths[diagram.nodeKey.eval(n)]), + ); }); } @@ -131,25 +155,33 @@ dc_graph.highlight_paths = function(pathprops, hoverprops, selectprops, pathsgro .cascade(400, false, hoverprops); } - var _mode = dc_graph.mode('highlight-paths', { - draw: draw, - remove: function(diagram, node, edge, ehover) { + const _mode = mode('highlight-paths', { + draw, + remove(diagram, node, edge, ehover) { remove(diagram, node, edge, ehover); return this; }, - parent: function(p) { - if(p) + parent(p) { + if (p) _anchor = p.anchorName(); // else we should have received anchor earlier - highlight_paths_group.on('paths_changed.highlight-paths-' + _anchor, p ? paths_changed : null); - highlight_paths_group.on('hover_changed.highlight-paths-' + _anchor, p ? hover_changed : null); - highlight_paths_group.on('select_changed.highlight-paths-' + _anchor, p ? select_changed : null); - } + highlight_paths_group.on( + `paths_changed.highlight-paths-${_anchor}`, + p ? paths_changed : null, + ); + highlight_paths_group.on( + `hover_changed.highlight-paths-${_anchor}`, + p ? hover_changed : null, + ); + highlight_paths_group.on( + `select_changed.highlight-paths-${_anchor}`, + p ? select_changed : null, + ); + }, }); // whether to do relayout & redraw (true) or just refresh (false) _mode.doRedraw = property(false); return _mode; -}; - +} diff --git a/src/highlight_paths_group.js b/src/highlight_paths_group.js index d0978bb8..559e7c37 100644 --- a/src/highlight_paths_group.js +++ b/src/highlight_paths_group.js @@ -1,7 +1,11 @@ -dc_graph.register_highlight_paths_group = function(pathsgroup) { - window.chart_registry.create_type('highlight-paths', function() { - return d3.dispatch('paths_changed', 'hover_changed', 'select_changed'); - }); +// External dependencies +import { dispatch } from 'd3-dispatch'; + +export function registerHighlightPathsGroup(pathsgroup) { + window.chart_registry.create_type( + 'highlight-paths', + () => dispatch('paths_changed', 'hover_changed', 'select_changed'), + ); return window.chart_registry.create_group('highlight-paths', pathsgroup); -}; +} diff --git a/src/highlight_radius.js b/src/highlight_radius.js index ec548e2f..382a7e53 100644 --- a/src/highlight_radius.js +++ b/src/highlight_radius.js @@ -1,21 +1,26 @@ -dc_graph.highlight_radius = function(options) { +import { property } from './core.js'; +import { registerHighlightThingsGroup } from './highlight_things_group.js'; +import { selectThingsGroup } from './select_things.js'; + +export function highlightRadius(options) { options = options || {}; - var select_nodes_group = dc_graph.select_things_group(options.select_nodes_group || 'select-nodes-group', 'select-nodes'); - var highlight_things_group = dc_graph.register_highlight_things_group(options.highlight_things_group || 'highlight-things-group'); - var _graph, _selection = []; + const select_nodes_group = selectThingsGroup( + options.select_nodes_group || 'select-nodes-group', + 'select-nodes', + ); + const highlight_things_group = registerHighlightThingsGroup( + options.highlight_things_group || 'highlight-things-group', + ); + let _graph, _selection = []; function recurse(n, r, nodeset, edgeset) { nodeset[n.key()] = true; - if(r) { - n.outs().filter(function(e) { - return !edgeset[e.key()]; - }).forEach(function(e) { + if (r) { + n.outs().filter(e => !edgeset[e.key()]).forEach(e => { edgeset[e.key()] = true; recurse(e.target(), r-1, nodeset, edgeset); }); - n.ins().filter(function(e) { - return !edgeset[e.key()]; - }).forEach(function(e) { + n.ins().filter(e => !edgeset[e.key()]).forEach(e => { edgeset[e.key()] = true; recurse(e.source(), r-1, nodeset, edgeset); }); @@ -24,39 +29,37 @@ dc_graph.highlight_radius = function(options) { function selection_changed(nodes) { _selection = nodes; console.assert(_graph); - var nodeset = {}, edgeset = {}; - nodes.forEach(function(nkey) { + let nodeset = {}, edgeset = {}; + nodes.forEach(nkey => { recurse(_graph.node(nkey), _mode.radius(), nodeset, edgeset); }); - if(!Object.keys(nodeset).length && !Object.keys(edgeset).length) + if (!Object.keys(nodeset).length && !Object.keys(edgeset).length) nodeset = edgeset = null; - highlight_things_group.highlight(nodeset, edgeset); + highlight_things_group.call('highlight', null, nodeset, edgeset); } - function on_data(diagram, nodes, wnodes, edges, wedges, ports, wports) { + function on_data(diagram, nodes, wnodes, edges, wedges, _ports, _wports) { _graph = metagraph.graph(wnodes, wedges, { nodeKey: diagram.nodeKey.eval, edgeKey: diagram.edgeKey.eval, edgeSource: diagram.edgeSource.eval, - edgeTarget: diagram.edgeTarget.eval - }); - var sel2 = _selection.filter(function(nk) { - return !!_graph.node(nk); + edgeTarget: diagram.edgeTarget.eval, }); - if(sel2.length < _selection.length) - window.setTimeout(function() { - select_nodes_group.set_changed(sel2); + const sel2 = _selection.filter(nk => !!_graph.node(nk)); + if (sel2.length < _selection.length) + window.setTimeout(() => { + select_nodes_group.call('set_changed', null, sel2); }, 0); } - var _mode = { - parent: function(p) { - if(p) { + const _mode = { + parent(p) { + if (p) { p.on('data.highlight-radius', on_data); - } else if(_mode.parent()) + } else if (_mode.parent()) _mode.parent().on('data.highlight-radius', null); select_nodes_group.on('set_changed.highlight-radius', selection_changed); - } + }, }; _mode.radius = property(1); return _mode; -}; +} diff --git a/src/highlight_things.js b/src/highlight_things.js index 872fb3a9..e5523395 100644 --- a/src/highlight_things.js +++ b/src/highlight_things.js @@ -1,7 +1,14 @@ -dc_graph.highlight_things = function(includeprops, excludeprops, modename, groupname, cascbase) { - var highlight_things_group = dc_graph.register_highlight_things_group(groupname || 'highlight-things-group'); - var _includeprops = {...includeprops}, _excludeprops = {...excludeprops}; - var _active, _nodeset = {}, _edgeset = {}; +import { property } from './core.js'; +import { registerHighlightThingsGroup } from './highlight_things_group.js'; +import { mode } from './mode.js'; +import { nodeEdgeConditions } from './utils.js'; + +export function highlightThings(includeprops, excludeprops, modename, groupname, cascbase) { + const highlight_things_group = registerHighlightThingsGroup( + groupname || 'highlight-things-group', + ); + const _includeprops = {...includeprops}, _excludeprops = {...excludeprops}; + let _active, _nodeset = {}, _edgeset = {}; cascbase = cascbase || 150; function highlight(nodeset, edgeset) { @@ -11,32 +18,38 @@ dc_graph.highlight_things = function(includeprops, excludeprops, modename, group _mode.parent().requestRefresh(_mode.durationOverride()); } function draw(diagram) { - diagram.cascade(cascbase, true, node_edge_conditions( - function(n) { - return _nodeset[_mode.parent().nodeKey.eval(n)]; - }, function(e) { - return _edgeset[_mode.parent().edgeKey.eval(e)]; - }, _includeprops)); - diagram.cascade(cascbase+10, true, node_edge_conditions( - function(n) { - return _active && !_nodeset[_mode.parent().nodeKey.eval(n)]; - }, function(e) { - return _active && !_edgeset[_mode.parent().edgeKey.eval(e)]; - }, _excludeprops)); + diagram.cascade( + cascbase, + true, + nodeEdgeConditions( + n => _nodeset[_mode.parent().nodeKey.eval(n)], + e => _edgeset[_mode.parent().edgeKey.eval(e)], + _includeprops, + ), + ); + diagram.cascade( + cascbase+10, + true, + nodeEdgeConditions( + n => _active && !_nodeset[_mode.parent().nodeKey.eval(n)], + e => _active && !_edgeset[_mode.parent().edgeKey.eval(e)], + _excludeprops, + ), + ); } function remove(diagram) { diagram.cascade(cascbase, false, _includeprops); - diagram.cascade(cascbase + 10, false, _excludeprops); + diagram.cascade(cascbase+10, false, _excludeprops); } - var _mode = dc_graph.mode(modename, { - draw: draw, - remove: remove, - parent: function(p) { - highlight_things_group.on('highlight.' + modename, p ? highlight : null); - } + const _mode = mode(modename, { + draw, + remove, + parent(p) { + highlight_things_group.on(`highlight.${modename}`, p ? highlight : null); + }, }); _mode.includeProps = () => _includeprops; _mode.excludeProps = () => _excludeprops; _mode.durationOverride = property(undefined); return _mode; -}; +} diff --git a/src/highlight_things_group.js b/src/highlight_things_group.js index 8b50577d..faeed01e 100644 --- a/src/highlight_things_group.js +++ b/src/highlight_things_group.js @@ -1,7 +1,8 @@ -dc_graph.register_highlight_things_group = function(thingsgroup) { - window.chart_registry.create_type('highlight-things', function() { - return d3.dispatch('highlight'); - }); +// External dependencies +import { dispatch } from 'd3-dispatch'; + +export function registerHighlightThingsGroup(thingsgroup) { + window.chart_registry.create_type('highlight-things', () => dispatch('highlight')); return window.chart_registry.create_group('highlight-things', thingsgroup); -}; +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 00000000..7d7b93b7 --- /dev/null +++ b/src/index.js @@ -0,0 +1,157 @@ +/** + * dc.graph.js - Graph visualization library for dc.js + * Main entry point for ES6 module exports + * @module dc-graph + */ + +// Core utilities +export { + constants, + deprecatedProperty, + deprecateFunction, + deprecationWarning, + functorWrap, + getBBoxNoThrow, + identity, + isIe, + isSafari, + namedChildren, + property, + uuid, + version, +} from './core.js'; + +// Main diagram component +export { diagram } from './diagram.js'; + +// Layout engines +export { colaLayout } from './cola_layout.js'; +export { d3v4ForceLayout } from './d3v4_force_layout.js'; +export { dagreLayout } from './dagre_layout.js'; +export { dynagraphLayout } from './dynagraph_layout.js'; +export { flexboxLayout } from './flexbox_layout.js'; +export { graphvizLayout } from './graphviz_layout.js'; +export { layeredLayout } from './layered_layout.js'; +export { manualLayout } from './manual_layout.js'; +export { treeLayout } from './tree_layout.js'; + +// Layout engine management +export { engines, spawnEngine } from './engine.js'; +export { webworkerLayout } from './webworker_layout.js'; + +// Utilities +export { annotateLayers } from './annotate_layers.js'; +export { annotateNodes } from './annotate_nodes.js'; +export { builtinArrows } from './arrows.js'; +export { addPoints, arrowOffsets, arrowParts, multPoint } from './arrows.js'; +export { brush } from './brush.js'; +export { + alignX, + alignY, + constraintPattern, + gapX, + gapY, + orderX, + orderY, +} from './constraint_pattern.js'; +export { convertAdjacencyList, convertNest, convertTree } from './convert.js'; +export { deleteNodes } from './delete_nodes.js'; +export { deleteThings } from './delete_things.js'; +export { depthFirstTraversal } from './depth_first_traversal.js'; +export { drawClusters } from './draw_clusters.js'; +export { drawGraphs } from './draw_graphs.js'; +export { dropdown } from './dropdown.js'; +export { editText } from './edit_text.js'; +export { defaultUrlOpener, expandCollapse } from './expand_collapse.js'; +export { expandedHidden } from './expanded_hidden.js'; +export { filterSelection } from './filter_selection.js'; +export { fixNodes, fixNodesGroup } from './fix_nodes.js'; +export { flatGroup } from './flat_group.js'; +export { edgeObject, generate, nodeName, nodeObject, randomGraph, wheelEdges } from './generate.js'; +export { regenerateObjects } from './generate_objects.js'; +export { applyGraphvizAccessors, graphvizAttrs, snapshotGraphviz } from './graphviz_attrs.js'; +export { grid } from './grid.js'; +export { highlightNeighbors } from './highlight_neighbors.js'; +export { registerHighlightNeighborsGroup } from './highlight_neighbors_group.js'; +export { highlightPaths } from './highlight_paths.js'; +export { registerHighlightPathsGroup } from './highlight_paths_group.js'; +export { highlightRadius } from './highlight_radius.js'; +export { highlightThings } from './highlight_things.js'; +export { registerHighlightThingsGroup } from './highlight_things_group.js'; +export { keyboard } from './keyboard.js'; +export { labelEdges } from './label_edges.js'; +export { labelNodes } from './label_nodes.js'; +export { labelThings, labelThingsGroup } from './label_things.js'; +export { edgeLegend, legend, nodeLegend, symbolLegend } from './legend.js'; +export { lineBreaks } from './line_breaks.js'; +export { + dataUrl, + fileFormats, + loadGraph, + loadGraphText, + matchFileFormat, + matchMimeType, +} from './load_graph.js'; +export { matchOpposites } from './match_opposites.js'; +export { matchPorts } from './match_ports.js'; +export { behavior, mode } from './mode.js'; +export { moveNodes } from './move_nodes.js'; +export { mungeGraph } from './munge_graph.js'; +export { textContents, withIconContents } from './node_contents.js'; +export { pathReader } from './path_reader.js'; +export { pathSelector } from './path_selector.js'; +export { placePorts } from './place_ports.js'; +export { renderSvg } from './render_svg.js'; +export { renderWebgl } from './render_webgl.js'; +export { selectEdges } from './select_edges.js'; +export { selectNodes } from './select_nodes.js'; +export { selectPorts } from './select_ports.js'; +export { selectThings, selectThingsGroup } from './select_things.js'; +export { + availableShapes, + defaultShape, + elaboratedRectangleShape, + ellipseShape, + noShape, + polygonShape, + roundedRectangleShape, + shapePresets, +} from './shape.js'; +export { nodeLabelPadding } from './shape.js'; +export { drawSplinePaths, splinePaths } from './spline_paths.js'; +export { supergraph } from './supergraph.js'; +export { symbolPortStyle } from './symbol_port_style.js'; +export { + selectEdge, + selectNode, + selectNodeAndEdge, + selectPort, + tip, + tipHtmlOrJsonTable, + tipJsonTable, + tipTable, +} from './tip.js'; +export { deparallelize } from './transform.js'; +export { treeConstraints } from './tree_constraints.js'; +export { treePositions } from './tree_positions.js'; +export { troubleshoot } from './troubleshoot.js'; +export { buildTypeGraph } from './type_graph.js'; +export { cascade, eventCoords, scriptPath } from './utils.js'; +export { + ancestorHasClass, + clone, + conditionalProperties, + multiplyProperties, + nodeEdgeConditions, + param, + uniq, +} from './utils.js'; +export { validate } from './validate.js'; +export { wildcardPorts } from './wildcard_ports.js'; + +// Example usage: +// import { diagram, colaLayout, dagreLayout } from 'dc-graph'; +// const myDiagram = diagram('#chart') +// .width(800) +// .height(600) +// .layoutEngine(colaLayout()); diff --git a/src/keyboard.js b/src/keyboard.js index 26ce80e5..f2fea663 100644 --- a/src/keyboard.js +++ b/src/keyboard.js @@ -1,51 +1,58 @@ -dc_graph.keyboard = function() { - var _dispatch = d3.dispatch('keydown', 'keyup', 'modkeyschanged'); - var _unique_id = 'keyboard' + Math.floor(Math.random() * 100000); - var _mod_keys = d3.set(['Shift', 'Control', 'Alt', 'Meta']), - _pressed = d3.set(); +import { mode } from './mode.js'; + +// External dependencies +import { set } from 'd3-collection'; +import { dispatch } from 'd3-dispatch'; +import { event, select } from 'd3-selection'; + +export function keyboard() { + const _dispatch = dispatch('keydown', 'keyup', 'modkeyschanged'); + const _unique_id = `keyboard${Math.floor(Math.random()*100000)}`; + const _mod_keys = set(['Shift', 'Control', 'Alt', 'Meta']); + let _pressed = set(); function pressed() { return _pressed.values().sort(); } function keydown() { - if(_mod_keys.has(d3.event.key)) { - _pressed.add(d3.event.key); - _dispatch.modkeyschanged(pressed()); + if (_mod_keys.has(event.key)) { + _pressed.add(event.key); + _dispatch.call('modkeyschanged', null, pressed()); } - _dispatch.keydown(); + _dispatch.call('keydown', null, event); } function keyup() { - if(_mod_keys.has(d3.event.key)) { - _pressed.remove(d3.event.key); - _dispatch.modkeyschanged(pressed()); + if (_mod_keys.has(event.key)) { + _pressed.remove(event.key); + _dispatch.call('modkeyschanged', null, pressed()); } - _dispatch.keyup(); + _dispatch.call('keyup', null, event); } function clear() { - if(!_pressed.empty()) { - _pressed = d3.set(); - _dispatch.modkeyschanged(pressed()); + if (!_pressed.empty()) { + _pressed = set(); + _dispatch.call('modkeyschanged', null, pressed()); } } - function draw(diagram) { - d3.select(window) - .on('keydown.' + _unique_id, keydown) - .on('keyup.' + _unique_id, keyup) - .on('blur.' + _unique_id, clear); + function draw(_diagram) { + select(window) + .on(`keydown.${_unique_id}`, keydown) + .on(`keyup.${_unique_id}`, keyup) + .on(`blur.${_unique_id}`, clear); } - function remove(diagram) { - d3.select(window) - .on('keydown.' + _unique_id, null) - .on('keyup.' + _unique_id, null) - .on('blur.' + _unique_id, null); + function remove(_diagram) { + select(window) + .on(`keydown.${_unique_id}`, null) + .on(`keyup.${_unique_id}`, null) + .on(`blur.${_unique_id}`, null); } - var _mode = dc_graph.mode('brush', { - draw: draw, - remove: remove + const _mode = mode('brush', { + draw, + remove, }); _mode.on = function(event, f) { - if(arguments.length === 1) + if (arguments.length === 1) return _dispatch.on(event); _dispatch.on(event, f); return this; @@ -54,16 +61,22 @@ dc_graph.keyboard = function() { _mode.modKeysPressed = function() { return pressed(); }; - _mode.modKeysMatch = function(keys) { - if(!keys || keys === []) - return _pressed.empty(); - if(!Array.isArray(keys)) + _mode.modKeysMatch = function(keys, ignoreKeys) { + const pressed = set(_pressed.values()); + if (ignoreKeys) { + if (!Array.isArray(ignoreKeys)) + ignoreKeys = [ignoreKeys]; + ignoreKeys.forEach(_key => pressed.remove(_key)); + } + if (!keys || keys.length === 0) + return pressed.empty(); + if (!Array.isArray(keys)) keys = [keys]; - var p = pressed(); - if(p.length !== keys.length) + const pv = pressed.values(); + if (pv.length !== keys.length) return false; - return keys.slice().sort().every(function(k, i) { return k === p[i]; }); + return keys.slice().sort().every((k, i) => k === pv[i]); }; return _mode; -}; +} diff --git a/src/label_edges.js b/src/label_edges.js index b3701194..caabfec5 100644 --- a/src/label_edges.js +++ b/src/label_edges.js @@ -1,42 +1,45 @@ -dc_graph.label_edges = function(options) { +import { property } from './core.js'; +import { labelThings } from './label_things.js'; + +export function labelEdges(options) { options = options || {}; - var _labelTag = options.labelTag || 'label'; + const _labelTag = options.labelTag || 'label'; options.select_group = options.select_group || 'select-edges-group'; options.select_type = options.select_type || 'select-edges'; options.label_group = options.label_group || 'label-edges-group'; options.label_type = options.label_type || 'label-edges'; - options.default_label = "edge name"; + options.default_label = 'edge name'; options.find_thing = function(key, node, edge) { - return edge.filter(function(e) { - return _mode.parent().edgeKey.eval(e) === key; - }); + return edge.filter(e => _mode.parent().edgeKey.eval(e) === key); }; options.hide_thing_label = function(edge, whether) { - var label = _mode.parent().selectAll('#' + _mode.parent().edgeId(edge.datum()) + '-label textPath'); + const label = _mode.parent().selectAll( + `#${_mode.parent().edgeId(edge.datum())}-label textPath`, + ); label.attr('visibility', whether ? 'hidden' : 'visible'); }; - options.thing_box = function(edge, eventOptions) { - var points = edge.datum().pos.new.path.points, - x = (points[0].x + points[1].x)/2, - y = (points[0].y + points[1].y)/2; - return {x: x, y: y-10, width:0, height: 20}; + options.thing_box = function(edge, _eventOptions) { + const points = edge.datum().pos.new.path.points, + x = (points[0].x+points[1].x)/2, + y = (points[0].y+points[1].y)/2; + return {x, y: y-10, width: 0, height: 20}; }; options.thing_label = function(edge) { return _mode.parent().edgeLabel.eval(edge.datum()); }; options.accept = function(edge, text) { - var callback = _mode.changeEdgeLabel() ? - _mode.changeEdgeLabel()(_mode.parent().edgeKey.eval(edge.datum()), text) : - Promise.resolve(text); - return callback.then(function(text2) { - var e = edge.datum(); + const callback = _mode.changeEdgeLabel() + ? _mode.changeEdgeLabel()(_mode.parent().edgeKey.eval(edge.datum()), text) + : Promise.resolve(text); + return callback.then(text2 => { + const e = edge.datum(); e.orig.value[_labelTag] = text2; _mode.parent().redrawGroup(); }); }; - var _mode = dc_graph.label_things(options); + const _mode = labelThings(options); _mode.changeEdgeLabel = property(null); return _mode; -}; +} diff --git a/src/label_nodes.js b/src/label_nodes.js index 14072c9c..900ae94f 100644 --- a/src/label_nodes.js +++ b/src/label_nodes.js @@ -1,23 +1,24 @@ -dc_graph.label_nodes = function(options) { +import { property } from './core.js'; +import { labelThings } from './label_things.js'; + +export function labelNodes(options) { options = options || {}; - var _labelTag = options.labelTag || 'label'; + const _labelTag = options.labelTag || 'label'; options.select_group = options.select_group || 'select-nodes-group'; options.select_type = options.select_type || 'select-nodes'; options.label_group = options.label_group || 'label-nodes-group'; options.label_type = options.label_type || 'label-nodes'; - options.default_label = "node name"; + options.default_label = 'node name'; - options.find_thing = function(key, node, edge) { - return node.filter(function(n) { - return _mode.parent().nodeKey.eval(n) === key; - }); + options.find_thing = function(key, node, _edge) { + return node.filter(n => _mode.parent().nodeKey.eval(n) === key); }; options.hide_thing_label = function(node, whether) { - var contents = _mode.parent().content(_mode.parent().nodeContent.eval(node.datum())); + const contents = _mode.parent().content(_mode.parent().nodeContent.eval(node.datum())); contents.selectText(node).attr('visibility', whether ? 'hidden' : 'visible'); }; - options.thing_box = function(node, eventOptions) { - var contents = _mode.parent().content(_mode.parent().nodeContent.eval(node.datum())), + options.thing_box = function(node, _eventOptions) { + const contents = _mode.parent().content(_mode.parent().nodeContent.eval(node.datum())), box = contents.textbox(node); box.x += node.datum().cola.x; box.y += node.datum().cola.y; @@ -27,17 +28,17 @@ dc_graph.label_nodes = function(options) { return _mode.parent().nodeLabel.eval(node.datum()); }; options.accept = function(node, text) { - var callback = _mode.changeNodeLabel() ? - _mode.changeNodeLabel()(_mode.parent().nodeKey.eval(node.datum()), text) : - Promise.resolve(text); - return callback.then(function(text2) { - var n = node.datum(); + const callback = _mode.changeNodeLabel() + ? _mode.changeNodeLabel()(_mode.parent().nodeKey.eval(node.datum()), text) + : Promise.resolve(text); + return callback.then(text2 => { + const n = node.datum(); n.orig.value[_labelTag] = text2; _mode.parent().redrawGroup(); }); }; - var _mode = dc_graph.label_things(options); + const _mode = labelThings(options); _mode.changeNodeLabel = property(null); return _mode; -}; +} diff --git a/src/label_things.js b/src/label_things.js index 797ac890..b6cab669 100644 --- a/src/label_things.js +++ b/src/label_things.js @@ -1,11 +1,20 @@ -dc_graph.label_things = function(options) { +import { editText } from './edit_text.js'; +import { keyboard } from './keyboard.js'; +import { mode } from './mode.js'; +import { selectThingsGroup } from './select_things.js'; + +// External dependency loaded as global +import { dispatch } from 'd3-dispatch'; +import { event } from 'd3-selection'; + +export function labelThings(options) { options = options || {}; - var select_things_group = dc_graph.select_things_group(options.select_group, options.select_type), - label_things_group = dc_graph.label_things_group(options.label_group, options.label_type); - var _selected = []; - var _keyboard, _selectThings; + const select_things_group = selectThingsGroup(options.select_group, options.select_type), + label_things_group = labelThingsGroup(options.label_group, options.label_type); + let _selected = []; + let _keyboard, _selectThings; - function selection_changed_listener(diagram) { + function selection_changed_listener(_diagram) { return function(selection) { _selected = selection; }; @@ -13,82 +22,94 @@ dc_graph.label_things = function(options) { function edit_label_listener(diagram) { return function(thing, eventOptions) { - var box = options.thing_box(thing); + const box = options.thing_box(thing); options.hide_thing_label(thing, true); - dc_graph.edit_text( + editText( diagram.g(), { text: eventOptions.text || options.thing_label(thing) || options.default_label, align: options.align, class: options.class, - box: box, + box, selectText: eventOptions.selectText, - accept: function(text) { + accept(text) { return options.accept(thing, text); }, - finally: function() { + finally() { options.hide_thing_label(thing, false); - } - }); + }, + }, + ); }; } function edit_selection(node, edge, eventOptions) { // less than ideal interface. // what if there are other things? can i blame the missing metagraph? - var thing = options.find_thing(_selected[0], node, edge); - if(thing.empty()) { - console.error("couldn't find thing '" + _selected[0] + "'!"); + const thing = options.find_thing(_selected[0], node, edge); + if (thing.empty()) { + console.error(`couldn't find thing '${_selected[0]}'!`); return; } - if(thing.size()>1) { - console.error("found too many things for '" + _selected[0] + "' (" + thing.size() + ")!"); + if (thing.size() > 1) { + console.error(`found too many things for '${_selected[0]}' (${thing.size()})!`); return; } - label_things_group.edit_label(thing, eventOptions); + label_things_group.call('edit_label', null, thing, eventOptions); } function draw(diagram, node, edge) { - _keyboard.on('keyup.' + options.label_type, function() { - if(_selected.length) { + _keyboard.on(`keyup.${options.label_type}`, () => { + if (_selected.length) { // printable characters should start edit - if(d3.event.key.length !== 1) + if (event.key.length !== 1) return; - edit_selection(node, edge, {text: d3.event.key, selectText: false}); + edit_selection(node, edge, {text: event.key, selectText: false}); } }); - if(_selectThings) - _selectThings.thinginess().clickables(diagram, node, edge).on('dblclick.' + options.label_type, function() { - edit_selection(node, edge, {selectText: true}); - }); + if (_selectThings) + _selectThings.thinginess().clickables(diagram, node, edge).on( + `dblclick.${options.label_type}`, + () => { + edit_selection(node, edge, {selectText: true}); + }, + ); } - function remove(diagram, node, edge) { + function remove(_diagram, _node, _edge) { } - var _mode = dc_graph.mode(options.label_type, { - draw: draw, - remove: remove, - parent: function(p) { - select_things_group.on('set_changed.' + options.label_type, p ? selection_changed_listener(p) : null); - label_things_group.on('edit_label.' + options.label_type, p ? edit_label_listener(p) : null); - if(p) { + const _mode = mode(options.label_type, { + draw, + remove, + parent(p) { + select_things_group.on( + `set_changed.${options.label_type}`, + p ? selection_changed_listener(p) : null, + ); + label_things_group.on( + `edit_label.${options.label_type}`, + p ? edit_label_listener(p) : null, + ); + if (p) { _keyboard = p.child('keyboard'); - if(!_keyboard) - p.child('keyboard', _keyboard = dc_graph.keyboard()); + if (!_keyboard) + p.child('keyboard', _keyboard = keyboard()); _selectThings = p.child(options.select_type); } - } + }, }); _mode.editSelection = function(eventOptions) { - edit_selection(_mode.parent().selectAllNodes(), _mode.parent().selectAllEdges(), eventOptions); + edit_selection( + _mode.parent().selectAllNodes(), + _mode.parent().selectAllEdges(), + eventOptions, + ); }; return _mode; -}; +} -dc_graph.label_things_group = function(brushgroup, type) { - window.chart_registry.create_type(type, function() { - return d3.dispatch('edit_label'); - }); +export function labelThingsGroup(brushgroup, type) { + window.chart_registry.create_type(type, () => dispatch('edit_label')); return window.chart_registry.create_group(type, brushgroup); -}; +} diff --git a/src/layered_layout.js b/src/layered_layout.js index 3458400f..5729bb41 100644 --- a/src/layered_layout.js +++ b/src/layered_layout.js @@ -1,51 +1,70 @@ /** - * `dc_graph.layered_layout` produces 3D layered layouts, utilizing another layout + * Layered layout for dc.graph.js + * @module layered_layout + */ + +import { dispatch } from 'd3-dispatch'; +import { property, uuid } from './core.js'; +import { graphvizAttrs } from './graphviz_attrs.js'; +import { supergraph } from './supergraph.js'; + +/** + * `layeredLayout` produces 3D layered layouts, utilizing another layout * that supports fixed nodes and position hints for the layers - * @class layered_layout - * @memberof dc_graph * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.layered_layout} - **/ -dc_graph.layered_layout = function(id) { - var _layoutId = id || uuid(); - var _dispatch = d3.dispatch('tick', 'start', 'end'); - var _supergraph, _subgraphs; - var _layers; - var _options = null; + * @return {Object} layered layout engine + */ +export function layeredLayout(id) { + const _layoutId = id || uuid(); + const _dispatch = dispatch('tick', 'start', 'end'); + let _supergraph, _subgraphs; + let _layers; + let _options = null; function init(options) { _options = options; - } - function data(nodes, edges, constraints) { - _supergraph = dc_graph.supergraph({nodes: nodes, edges: edges}, { - nodeKey: function(n) { return n.dcg_nodeKey; }, - edgeKey: function(n) { return n.dcg_edgeKey; }, - nodeValue: function(n) { return n; }, - edgeValue: function(e) { return e; }, - edgeSource: function(e) { return e.dcg_edgeSource; }, - edgeTarget: function(e) { return e.dcg_edgeTarget; } + function data(nodes, edges, _constraints) { + _supergraph = supergraph({nodes, edges}, { + nodeKey(n) { + return n.dcg_nodeKey; + }, + edgeKey(n) { + return n.dcg_edgeKey; + }, + nodeValue(n) { + return n; + }, + edgeValue(e) { + return e; + }, + edgeSource(e) { + return e.dcg_edgeSource; + }, + edgeTarget(e) { + return e.dcg_edgeTarget; + }, }); // every node belongs natively in one rank - var nranks = _supergraph.nodes().reduce(function(p, n) { - var rank = engine.layerAccessor()(n.value()); + const nranks = _supergraph.nodes().reduce((p, n) => { + const rank = engine.layerAccessor()(n.value()); p[rank] = p[rank] || []; p[rank].push(n); return p; }, {}); - var eranks = Object.keys(nranks).reduce(function(p, r) { + const eranks = Object.keys(nranks).reduce((p, r) => { p[r] = []; return p; }, {}); // nodes are shadowed into any layers to which they are adjacent // edges are induced from the native&shadow nodes in each layer - _supergraph.edges().forEach(function(e) { - var srank = engine.layerAccessor()(e.source().value()), + _supergraph.edges().forEach(e => { + const srank = engine.layerAccessor()(e.source().value()), trank = engine.layerAccessor()(e.target().value()); - if(srank == trank) { + if (srank == trank) { eranks[srank].push(e); return; } @@ -56,156 +75,155 @@ dc_graph.layered_layout = function(id) { }); // produce a subgraph for each layer - _subgraphs = Object.keys(nranks).reduce(function(p, r) { + _subgraphs = Object.keys(nranks).reduce((p, r) => { p[r] = _supergraph.subgraph( - nranks[r].map(function(n) { return n.key(); }), - eranks[r].map(function(e) { return e.key(); })); + nranks[r].map(n => n.key()), + eranks[r].map(e => e.key()), + ); return p; }, {}); // start from the most populous layer - var max = null; - Object.keys(nranks).forEach(function(r) { - if(max === null || - _subgraphs[r].nodes().length > _subgraphs[max].nodes().length) + let max = null; + Object.keys(nranks).forEach(r => { + if ( + max === null + || _subgraphs[r].nodes().length > _subgraphs[max].nodes().length + ) max = +r; }); // travel up and down from there, each time fixing the nodes from the last layer - var ranks = Object.keys(nranks).map(function(r) { return +r; }).sort(); - _layers = ranks.map(function(r) { - return { - rank: r, - z: -r * engine.layerSeparationZ() - }; - }); - var mi = ranks.indexOf(max); - var ups = ranks.slice(mi+1), downs = ranks.slice(0, mi).reverse(); - layout_layer(max, -1).then(function(layout) { + const ranks = Object.keys(nranks).map(r => +r).sort(); + _layers = ranks.map(r => ({ + rank: r, + z: -r*engine.layerSeparationZ(), + })); + const mi = ranks.indexOf(max); + const ups = ranks.slice(mi+1), downs = ranks.slice(0, mi).reverse(); + layout_layer(max, -1).then(layout => { Promise.all([ layout_layers(layout, max, ups), - layout_layers(layout, max, downs) - ]).then(function() { - _dispatch.end( - _supergraph.nodes().map(function(n) { return n.value(); }), - _supergraph.edges().map(function(e) { return e.value(); })); + layout_layers(layout, max, downs), + ]).then(() => { + _dispatch.call( + 'end', + null, + _supergraph.nodes().map(n => n.value()), + _supergraph.edges().map(e => e.value()), + ); }); }); } function layout_layers(layout, last, layers) { - if(layers.length === 0) + if (layers.length === 0) return Promise.resolve(layout); - var curr = layers.shift(); - return layout_layer(curr, last).then(function(layout) { - return layout_layers(layout, curr, layers); - }); + const curr = layers.shift(); + return layout_layer(curr, last).then(layout => layout_layers(layout, curr, layers)); } - function layout_layer(r, last) { - _subgraphs[r].nodes().forEach(function(n) { - if(engine.layerAccessor()(n.value()) !== r && - n.value().x !== undefined && - n.value().y !== undefined) + function layout_layer(r, _last) { + _subgraphs[r].nodes().forEach(n => { + if ( + engine.layerAccessor()(n.value()) !== r + && n.value().x !== undefined + && n.value().y !== undefined + ) n.value().dcg_nodeFixed = { x: n.value().x, - y: n.value().y + y: n.value().y, }; else n.value().dcg_nodeFixed = null; }); - var subengine = engine.engineFactory()(); + const subengine = engine.engineFactory()(); subengine.init(_options); subengine.data( {}, - _subgraphs[r].nodes().map(function(n) { - return n.value(); - }), - _subgraphs[r].edges().map(function(e) { - return e.value(); - })); + _subgraphs[r].nodes().map(n => n.value()), + _subgraphs[r].edges().map(e => e.value()), + ); return promise_layout(r, subengine); } function promise_layout(r, subengine) { // stopgap - engine.start() should return a promise - return new Promise(function(resolve, reject) { - subengine.on('end', function(nodes, edges) { - resolve({nodes: nodes, edges: edges}); + return new Promise((resolve, _reject) => { + subengine.on('end', (nodes, edges) => { + resolve({nodes, edges}); }); subengine.start(); - }).then(function(layout) { + }).then(layout => { // copy positions back into the subgraph (and hence supergraph) - layout.nodes.forEach(function(ln) { - var n = _subgraphs[r].node(ln.dcg_nodeKey); + layout.nodes.forEach(ln => { + const n = _subgraphs[r].node(ln.dcg_nodeKey); // do not copy positions for shadow nodes - if(engine.layerAccessor()(n.value()) !== r) + if (engine.layerAccessor()(n.value()) !== r) return; n.value().x = ln.x; n.value().y = ln.y; - n.value().z = -r * engine.layerSeparationZ(); // lowest rank at top + n.value().z = -r*engine.layerSeparationZ(); // lowest rank at top }); return layout; }); } function start() { - _dispatch.start(); + _dispatch.call('start'); } function stop() { } - var graphviz = dc_graph.graphviz_attrs(), graphviz_keys = Object.keys(graphviz); + const graphviz = graphvizAttrs(), graphviz_keys = Object.keys(graphviz); - var engine = Object.assign(graphviz, { - layoutAlgorithm: function() { + const engine = Object.assign(graphviz, { + layoutAlgorithm() { return 'layered'; }, - layoutId: function() { + layoutId() { return _layoutId; }, - supportsWebworker: function() { + supportsWebworker() { return false; }, parent: property(null), - on: function(event, f) { - if(arguments.length === 1) + on(event, f) { + if (arguments.length === 1) return _dispatch.on(event); _dispatch.on(event, f); return this; }, - init: function(options) { - this.optionNames().forEach(function(option) { + init(options) { + this.optionNames().forEach(option => { options[option] = options[option] || this[option](); - }.bind(this)); + }); init(options); return this; }, - data: function(graph, nodes, edges, constraints) { + data(graph, nodes, edges, constraints) { data(nodes, edges, constraints); }, - start: function() { + start() { start(); }, - stop: function() { + stop() { stop(); }, - optionNames: function() { + optionNames() { return [] .concat(graphviz_keys); }, engineFactory: property(null), layerAccessor: property(null), layerSeparationZ: property(50), - layers: function() { + layers() { return _layers; }, - populateLayoutNode: function() {}, - populateLayoutEdge: function() {}, + populateLayoutNode() {}, + populateLayoutEdge() {}, extractNodeAttrs: property({}), // {attr: function(node)} - extractEdgeAttrs: property({}) + extractEdgeAttrs: property({}), }); return engine; -}; - - +} diff --git a/src/legend.js b/src/legend.js index ad3ebd96..283012cc 100644 --- a/src/legend.js +++ b/src/legend.js @@ -3,56 +3,57 @@ The dc_graph.legend shows labeled examples of nodes & edges, within the frame of a dc_graph.diagram. **/ -dc_graph.legend = function(legend_namespace) { +import { dispatch } from 'd3-dispatch'; +import { select } from 'd3-selection'; +import { deprecateFunction, getBBoxNoThrow, getOriginal, property } from './core.js'; +import { mode } from './mode.js'; +import { renderSvg } from './render_svg.js'; + +export function legend(legend_namespace) { legend_namespace = legend_namespace || 'node-legend'; - var _items, _included = []; - var _dispatch = d3.dispatch('filtered'); - var _totals, _counts; + let _items, _included = []; + const _dispatch = dispatch('filtered'); + let _totals, _counts; - var _svg_renderer; + let _svg_renderer; function apply_filter() { - if(_legend.customFilter()) + if (_legend.customFilter()) _legend.customFilter()(_included); - else if(_legend.dimension()) { - if(_legend.isTagDimension()) { - _legend.dimension().filterFunction(function(ks) { - return !_included.length || ks.filter(function(k) { - return _included.includes(k); - }).length; - }); + else if (_legend.dimension()) { + if (_legend.isTagDimension()) { + _legend.dimension().filterFunction(ks => + !_included.length || ks.filter(k => _included.includes(k)).length + ); } else { - _legend.dimension().filterFunction(function(k) { - return !_included.length || _included.includes(k); - }); + _legend.dimension().filterFunction(k => !_included.length || _included.includes(k)); } _legend.parent().redraw(); } } - var _legend = dc_graph.mode(legend_namespace, { + const _legend = mode(legend_namespace, { renderers: ['svg', 'webgl'], draw: redraw, - remove: function() {}, - parent: function(p) { - if(p) { + remove() {}, + parent(p) { + if (p) { p - .on('render.' + legend_namespace, render) - .on('data.' + legend_namespace, on_data); - } - else { + .on(`render.${legend_namespace}`, render) + .on(`data.${legend_namespace}`, on_data); + } else { _legend.parent() - .on('render.' + legend_namespace, null) - .on('data.' + legend_namespace, null); + .on(`render.${legend_namespace}`, null) + .on(`data.${legend_namespace}`, null); } - } + }, }); /** #### .type([value]) Set or get the handler for the specific type of item to be displayed. Default: dc_graph.legend.node_legend() **/ - _legend.type = property(dc_graph.legend.node_legend()); + _legend.type = property(nodeLegend()); /** #### .x([value]) @@ -97,7 +98,7 @@ dc_graph.legend = function(legend_namespace) { _legend.counter = property(null); _legend.replaceFilter = function(filter) { - if(filter && filter.length === 1) + if (filter && filter.length === 1) _included = filter[0]; else _included = []; @@ -123,47 +124,72 @@ dc_graph.legend = function(legend_namespace) { _legend.exemplars = property({}); function on_data(diagram, nodes, wnodes, edges, wedges, ports, wports) { - if(_legend.counter()) - _counts = _legend.counter()(wnodes.map(get_original), wedges.map(get_original), wports.map(get_original), false); + if (_legend.counter()) + _counts = _legend.counter()( + wnodes.map(getOriginal), + wedges.map(getOriginal), + wports.map(getOriginal), + false, + ); } - _legend.redraw = deprecate_function("dc_graph.legend is an ordinary mode now; redraw will go away soon", redraw); + _legend.redraw = deprecateFunction( + 'dc_graph.legend is an ordinary mode now; redraw will go away soon', + redraw, + ); function redraw() { - var legend = (_svg_renderer || _legend.parent()).svg() - .selectAll('g.dc-graph-legend.' + legend_namespace) - .data([0]); + const legend = (_svg_renderer || _legend.parent()).svg() + .selectAll(`g.dc-graph-legend.${legend_namespace}`) + .data([0]); legend.enter().append('g') - .attr('class', 'dc-graph-legend ' + legend_namespace) - .attr('transform', 'translate(' + _legend.x() + ',' + _legend.y() + ')'); - - var items = !_legend.omitEmpty() || !_counts ? _items : _items.filter(function(i) { - return _included.length && !_included.includes(i.orig.key) || _counts[i.orig.key]; - }); - var item = legend.selectAll(_legend.type().itemSelector()) - .data(items, function(n) { return n.name; }); + .attr('class', `dc-graph-legend ${legend_namespace}`) + .attr('transform', `translate(${_legend.x()},${_legend.y()})`); + + const items = !_legend.omitEmpty() || !_counts + ? _items + : _items.filter(i => + _included.length && !_included.includes(i.orig.key) || _counts[i.orig.key] + ); + const item = legend.selectAll(_legend.type().itemSelector()) + .data(items, n => n.name); item.exit().remove(); - var itemEnter = _legend.type().create(_legend.parent(), item.enter(), _legend.itemWidth(), _legend.itemHeight()); + const itemEnter = _legend.type().create( + _legend.parent(), + item.enter(), + _legend.itemWidth(), + _legend.itemHeight(), + ); itemEnter.append('text') .attr('dy', _legend.dyLabel()) .attr('class', 'legend-label'); item - .attr('transform', function(n, i) { - return 'translate(' + _legend.itemWidth()/2 + ',' + (_legend.itemHeight() + _legend.gap())*(i+0.5) + ')'; - }); + .attr( + 'transform', + (n, i) => + `translate(${_legend.itemWidth()/2},${ + (_legend.itemHeight()+_legend.gap())*(i+0.5) + })`, + ); item.select('text.legend-label') - .attr('transform', 'translate(' + (_legend.itemWidth()/2+_legend.gap()) + ',0)') + .attr('transform', `translate(${_legend.itemWidth()/2+_legend.gap()},0)`) .attr('pointer-events', _legend.dimension() ? 'auto' : 'none') - .text(function(d) { - return d.name + (_legend.counter() && _legend.filterable()(d) && _counts ? (' (' + (_counts[d.orig.key] || 0) + (_counts[d.orig.key] !== _totals[d.orig.key] ? '/' + (_totals[d.orig.key] || 0) : '') + ')') : ''); - }); + .text(d => + d.name+(_legend.counter() && _legend.filterable()(d) && _counts + ? (` (${_counts[d.orig.key] || 0}${ + _counts[d.orig.key] !== _totals[d.orig.key] + ? `/${_totals[d.orig.key] || 0}` + : '' + })`) + : '') + ); _legend.type().draw(_svg_renderer || _legend.parent(), itemEnter, item); - if(_legend.noLabel()) + if (_legend.noLabel()) item.selectAll(_legend.type().labelSelector()).remove(); - if(_legend.dropdown()) { - var caret = item.selectAll('text.dropdown-caret').data(function(x) { return [x]; }); + if (_legend.dropdown()) { + const caret = item.selectAll('text.dropdown-caret').data(x => [x]); caret - .enter().append('text') + .enter().append('text') .attr('dy', '0.3em') .attr('font-size', '75%') .attr('fill', 'blue') @@ -171,101 +197,120 @@ dc_graph.legend = function(legend_namespace) { .style('visibility', 'hidden') .html(' ▼'); caret - .attr('dx', function(d) { - return (_legend.itemWidth()/2+_legend.gap()) + getBBoxNoThrow(d3.select(this.parentNode).select('text.legend-label').node()).width; + .attr('dx', function(_d) { + return (_legend.itemWidth()/2+_legend.gap())+getBBoxNoThrow( + select(this.parentNode).select('text.legend-label').node(), + ).width; }) - .on('mouseenter.' + legend_namespace, function(n) { - var rect = this.getBoundingClientRect(); - var key = _legend.parent().nodeKey.eval(n); + .on(`mouseenter.${legend_namespace}`, function(n) { + const rect = this.getBoundingClientRect(); + const key = _legend.parent().nodeKey.eval(n); _legend.dropdown() .show(key, rect.x, rect.y); }); item - .on('mouseenter.' + legend_namespace, function(d) { - if(_counts && _counts[d.orig.key]) { - d3.select(this).selectAll('.dropdown-caret') + .on(`mouseenter.${legend_namespace}`, function(d) { + if (_counts && _counts[d.orig.key]) { + select(this).selectAll('.dropdown-caret') .style('visibility', 'visible'); } }) - .on('mouseleave.' + legend_namespace, function(d) { - d3.select(this).selectAll('.dropdown-caret') + .on(`mouseleave.${legend_namespace}`, function(_d) { + select(this).selectAll('.dropdown-caret') .style('visibility', 'hidden'); }); } - if(_legend.dimension()) { + if (_legend.dimension()) { item.filter(_legend.filterable()) .attr('cursor', 'pointer') - .on('click.' + legend_namespace, function(d) { - var key = _legend.parent().nodeKey.eval(d); - if(!_included.length && !_legend.isInclusiveDimension()) + .on(`click.${legend_namespace}`, d => { + const key = _legend.parent().nodeKey.eval(d); + if (!_included.length && !_legend.isInclusiveDimension()) _included = _items.map(_legend.parent().nodeKey.eval); - if(_included.includes(key)) - _included = _included.filter(function(x) { return x !== key; }); + if (_included.includes(key)) + _included = _included.filter(x => x !== key); else _included.push(key); apply_filter(); - _dispatch.filtered(_legend, key); - if(_svg_renderer) + _dispatch.call('filtered', null, _legend, key); + if (_svg_renderer) window.setTimeout(redraw, 250); }); } else { item.attr('cursor', 'auto') - .on('click.' + legend_namespace, null); + .on(`click.${legend_namespace}`, null); } item.transition().duration(1000) - .attr('opacity', function(d) { - return (!_legend.filterable()(d) || !_included.length || _included.includes(_legend.parent().nodeKey.eval(d))) ? 1 : 0.25; - }); - }; + .attr( + 'opacity', + d => (!_legend.filterable()(d) || !_included.length + || _included.includes(_legend.parent().nodeKey.eval(d))) + ? 1 + : 0.25, + ); + } _legend.countBaseline = function() { - if(_legend.counter()) + if (_legend.counter()) _totals = _legend.counter()( _legend.parent().nodeGroup().all(), _legend.parent().edgeGroup().all(), _legend.parent().portGroup() && _legend.parent().portGroup().all(), - true); + true, + ); }; - _legend.render = deprecate_function("dc_graph.legend is an ordinary mode now; render will go away soon", render); + _legend.render = deprecateFunction( + 'dc_graph.legend is an ordinary mode now; render will go away soon', + render, + ); function render() { - if(_legend.parent().renderer().rendererType() !== 'svg') { - _svg_renderer = dc_graph.render_svg(); + if (_legend.parent().renderer().rendererType() !== 'svg') { + _svg_renderer = renderSvg(); _svg_renderer.parent(_legend.parent()) - .svg(_legend.parent().root().append('svg') - .style({ - position: 'absolute', - left: 0, top: 0, - width: '100%', height: '100%', - fill: 'wheat', - 'pointer-events': 'none' - })); + .svg( + _legend.parent().root().append('svg') + .style({ + position: 'absolute', + left: 0, + top: 0, + width: '100%', + height: '100%', + fill: 'wheat', + 'pointer-events': 'none', + }), + ); } - - var exemplars = _legend.exemplars(); + const exemplars = _legend.exemplars(); _legend.countBaseline(); - if(exemplars instanceof Array) { - _items = exemplars.map(function(v) { return {name: v.name, orig: {key: v.key, value: v.value}, cola: {}}; }); - } - else { + if (exemplars instanceof Array) { + _items = exemplars.map(v => ({ + name: v.name, + orig: {key: v.key, value: v.value}, + cola: {}, + })); + } else { _items = []; - for(var item in exemplars) + for (const item in exemplars) _items.push({name: item, orig: {key: item, value: exemplars[item]}, cola: {}}); } redraw(); - }; + } - _legend.dropdown = property(null).react(function(v) { - if(!!v !== !!_legend.dropdown() && _legend.parent() && (_svg_renderer || _legend.parent()).svg()) + _legend.dropdown = property(null).react(v => { + if ( + !!v !== !!_legend.dropdown() && _legend.parent() + && (_svg_renderer || _legend.parent()).svg() + ) window.setTimeout(_legend.redraw, 0); }); /* enables filtering */ _legend.dimension = property(null) - .react(function(v) { - if(!v) { + .react(v => { + if (!v) { _included = []; apply_filter(); } @@ -276,105 +321,97 @@ dc_graph.legend = function(legend_namespace) { _legend.customFilter = property(null); return _legend; -}; - +} -dc_graph.legend.node_legend = function() { +export function nodeLegend() { return { - itemSelector: function() { + itemSelector() { return '.node'; }, - labelSelector: function() { + labelSelector() { return '.node-label'; }, - create: function(diagram, selection) { + create(diagram, selection) { return selection.append('g') .attr('class', 'node'); }, - draw: function(renderer, itemEnter, item) { + draw(renderer, itemEnter, item) { renderer .renderNode(itemEnter) .redrawNode(item); - } + }, }; -}; +} -dc_graph.legend.edge_legend = function() { - var _type = { - itemSelector: function() { +export function edgeLegend() { + const _type = { + itemSelector() { return '.edge-container'; }, - labelSelector: function() { + labelSelector() { return '.edge-label'; }, - create: function(diagram, selection, w, h) { - var edgeEnter = selection.append('g') + create(diagram, selection, w, h) { + const edgeEnter = selection.append('g') .attr('class', 'edge-container') .attr('opacity', 0); edgeEnter .append('rect') - .attr({ - x: -w/2, - y: -h/2, - width: w, - height: h, - fill: 'green', - opacity: 0 - }); + .attr('x', -w/2) + .attr('y', -h/2) + .attr('width', w) + .attr('height', h) + .attr('fill', 'green') + .attr('opacity', 0); edgeEnter .selectAll('circle') .data([-1, 1]) - .enter() + .enter() .append('circle') - .attr({ - r: _type.fakeNodeRadius(), - fill: 'none', - stroke: 'black', - "stroke-dasharray": "4,4", - opacity: 0.15, - transform: function(d) { - return 'translate(' + [d * _type.length() / 2, 0].join(',') + ')'; - } - }); - var edgex = _type.length()/2 - _type.fakeNodeRadius(); + .attr('r', _type.fakeNodeRadius()) + .attr('fill', 'none') + .attr('stroke', 'black') + .attr('stroke-dasharray', '4,4') + .attr('opacity', 0.15) + .attr('transform', d => `translate(${[d*_type.length()/2, 0].join(',')})`); + const edgex = _type.length()/2-_type.fakeNodeRadius(); edgeEnter.append('svg:path') - .attr({ - class: 'edge', - id: function(d) { return d.name; }, - d: 'M' + -edgex + ',0 L' + edgex + ',0', - opacity: diagram.edgeOpacity.eval - }); + .attr('class', 'edge') + .attr('id', d => d.name) + .attr('d', `M${-edgex},0 L${edgex},0`) + .attr('opacity', diagram.edgeOpacity.eval); return edgeEnter; }, fakeNodeRadius: property(10), length: property(50), - draw: function(renderer, itemEnter, item) { - renderer.redrawEdge(itemEnter.select('path.edge'), renderer.selectAllEdges('.edge-arrows')); - } + draw(renderer, itemEnter, _item) { + renderer.redrawEdge( + itemEnter.select('path.edge'), + renderer.selectAllEdges('.edge-arrows'), + ); + }, }; return _type; -}; +} -dc_graph.legend.symbol_legend = function(symbolScale) { +export function symbolLegend(symbolScale) { return { - itemSelector: function() { + itemSelector() { return '.symbol'; }, - labelSelector: function() { + labelSelector() { return '.symbol-label'; }, - create: function(diagram, selection, w, h) { - var symbolEnter = selection.append('g') + create(diagram, selection, _w, _h) { + const symbolEnter = selection.append('g') .attr('class', 'symbol'); return symbolEnter; }, - draw: function(renderer, symbolEnter, symbol) { + draw(renderer, symbolEnter, _symbol) { symbolEnter.append('text') - .html(function(d) { - return symbolScale(d.orig.key); - }); + .html(d => symbolScale(d.orig.key)); return symbolEnter; - } + }, }; -}; +} diff --git a/src/line_breaks.js b/src/line_breaks.js index 74727948..7c54bb4d 100644 --- a/src/line_breaks.js +++ b/src/line_breaks.js @@ -1,29 +1,33 @@ -var dont_use_key = deprecation_warning('dc_graph.line_breaks now takes a string - d.key behavior is deprecated and will be removed in a later version'); +import { deprecationWarning } from './core.js'; -dc_graph.line_breaks = function(charexp, max_line_length) { - var regexp = new RegExp(charexp, 'g'); +const dont_use_key = deprecationWarning( + 'line_breaks now takes a string - d.key behavior is deprecated and will be removed in a later version', +); + +export function lineBreaks(charexp, max_line_length) { + const regexp = new RegExp(charexp, 'g'); return function(s) { - if(typeof s === 'object') { // backward compatibility + if (typeof s === 'object') { // backward compatibility dont_use_key(); s = s.key; } - var result; - var line = '', lines = [], part, i = 0; + let result; + let line = '', part, i = 0; + const lines = []; do { result = regexp.exec(s); - if(result) + if (result) part = s.slice(i, regexp.lastIndex); else part = s.slice(i); - if(line.length + part.length > max_line_length && line.length > 0) { + if (line.length+part.length > max_line_length && line.length > 0) { lines.push(line); line = ''; } line += part; i = regexp.lastIndex; - } - while(result !== null); + } while (result !== null); lines.push(line); return lines; }; -}; +} diff --git a/src/load_graph.js b/src/load_graph.js index 9424169a..a3156286 100644 --- a/src/load_graph.js +++ b/src/load_graph.js @@ -1,229 +1,192 @@ -function process_dot(callback, error, text) { - if(error) { - callback(error, null); - return; - } - var nodes, edges, node_cluster = {}, clusters = []; - if(graphlibDot.parse) { // graphlib-dot 1.1.0 (where did i get it from?) - var digraph = graphlibDot.parse(text); - - var nodeNames = digraph.nodes(); - nodes = new Array(nodeNames.length); - nodeNames.forEach(function (name, i) { - var node = nodes[i] = digraph._nodes[nodeNames[i]]; - node.id = i; - node.name = name; - }); +import { set } from 'd3-collection'; +import { csv, dsv, json, text } from 'd3-fetch'; - var edgeNames = digraph.edges(); - edges = []; - edgeNames.forEach(function(e) { - var edge = digraph._edges[e]; - edges.push(Object.assign({}, edge.value, { - source: digraph._nodes[edge.u].id, - target: digraph._nodes[edge.v].id, - sourcename: edge.u, - targetname: edge.v - })); - }); - // TODO: if this version exists in the wild, look at how it does subgraphs/clusters - } else { // graphlib-dot 0.6 - digraph = graphlibDot.read(text); - - nodeNames = digraph.nodes(); - nodes = new Array(nodeNames.length); - nodeNames.forEach(function (name, i) { - var node = nodes[i] = digraph._nodes[nodeNames[i]]; - node.id = i; - node.name = name; - }); +function processDot(text) { + return new Promise((resolve, _reject) => { + let nodes, edges; + const node_cluster = {}, clusters = []; + if (graphlibDot.parse) { // graphlib-dot 1.1.0 (where did i get it from?) + const digraph = graphlibDot.parse(text); - edges = []; - digraph.edges().forEach(function(e) { - edges.push(Object.assign({}, digraph.edge(e.v, e.w), { - source: digraph._nodes[e.v].id, - target: digraph._nodes[e.w].id, - sourcename: e.v, - targetname: e.w - })); - }); + const nodeNames = digraph.nodes(); + nodes = new Array(nodeNames.length); + nodeNames.forEach((name, i) => { + const node = nodes[i] = digraph._nodes[nodeNames[i]]; + node.id = i; + node.name = name; + }); - // iterative bfs for variety (recursion would work just as well) - var cluster_names = {}; - var queue = digraph.children().map(function(c) { return Object.assign({parent: null, key: c}, digraph.node(c)); }); - while(queue.length) { - var item = queue.shift(), - children = digraph.children(item.key); - if(children.length) { - clusters.push(item); - cluster_names[item.key] = true; + const edgeNames = digraph.edges(); + edges = []; + edgeNames.forEach(e => { + const edge = digraph._edges[e]; + edges.push(Object.assign({}, edge.value, { + source: digraph._nodes[edge.u].id, + target: digraph._nodes[edge.v].id, + sourcename: edge.u, + targetname: edge.v, + })); + }); + // TODO: if this version exists in the wild, look at how it does subgraphs/clusters + } else { // graphlib-dot 0.6 + const digraph = graphlibDot.read(text); + + const nodeNames = digraph.nodes(); + nodes = new Array(nodeNames.length); + nodeNames.forEach((name, i) => { + const node = nodes[i] = digraph._nodes[nodeNames[i]]; + node.id = i; + node.name = name; + }); + + edges = []; + digraph.edges().forEach(e => { + edges.push(Object.assign({}, digraph.edge(e.v, e.w), { + source: digraph._nodes[e.v].id, + target: digraph._nodes[e.w].id, + sourcename: e.v, + targetname: e.w, + })); + }); + + // iterative bfs for variety (recursion would work just as well) + const cluster_names = {}; + let queue = digraph.children().map(c => + Object.assign({parent: null, key: c}, digraph.node(c)) + ); + while (queue.length) { + const item = queue.shift(), + children = digraph.children(item.key); + if (children.length) { + clusters.push(item); + cluster_names[item.key] = true; + } else + node_cluster[item.key] = item.parent; + queue = queue.concat(children.map(c => ({parent: item.key, key: c}))); } - else - node_cluster[item.key] = item.parent; - queue = queue.concat(children.map(function(c) { return {parent: item.key, key: c}; })); + // clusters as nodes not currently supported + nodes = nodes.filter(n => !cluster_names[n.name]); } - // clusters as nodes not currently supported - nodes = nodes.filter(function(n) { - return !cluster_names[n.name]; - }); - } - var graph = {nodes: nodes, links: edges, node_cluster: node_cluster, clusters: clusters}; - callback(null, graph); + const graph = {nodes, links: edges, node_cluster, clusters}; + resolve(graph); + }); } -function process_dsv(callback, error, data) { - if(error) { - callback(error, null); - return; - } - var keys = Object.keys(data[0]); - var source = keys[0], target = keys[1]; - var nodes = d3.set(data.map(function(r) { return r[source]; })); - data.forEach(function(r) { - nodes.add(r[target]); - }); - nodes = nodes.values().map(function(k) { return {name: k}; }); - callback(null, { - nodes: nodes, - links: data.map(function(r, i) { - return { +function processDsv(data) { + return new Promise((resolve, _reject) => { + const keys = Object.keys(data[0]); + const source = keys[0], target = keys[1]; + let nodes = set(data.map(r => r[source])); + data.forEach(r => { + nodes.add(r[target]); + }); + nodes = nodes.values().map(k => ({name: k})); + resolve({ + nodes, + links: data.map((r, i) => ({ key: i, sourcename: r[source], - targetname: r[target] - }; - }) + targetname: r[target], + })), + }); }); } -dc_graph.file_formats = [ +export const fileFormats = [ { exts: 'json', mimes: 'application/json', - from_url: d3.json, - from_text: function(text, callback) { - callback(null, JSON.parse(text)); - } + from_url: url => json(url), + from_text: text => Promise.resolve(JSON.parse(text)), }, { exts: ['gv', 'dot'], mimes: 'text/vnd.graphviz', - from_url: function(url, callback) { - d3.text(url, process_dot.bind(null, callback)); - }, - from_text: function(text, callback) { - process_dot(callback, null, text); - } + from_url: url => text(url).then(textData => processDot(textData)), + from_text: text => processDot(text), }, { exts: 'psv', mimes: 'text/psv', - from_url: function(url, callback) { - d3.dsv('|', 'text/plain')(url, process_dsv.bind(null, callback)); - }, - from_text: function(text, callback) { - process_dsv(callback, null, d3.dsv('|').parse(text)); - } + from_url: url => dsv('|', 'text/plain')(url).then(data => processDsv(data)), + from_text: text => processDsv(dsv('|').parse(text)), }, { exts: 'csv', mimes: 'text/csv', - from_url: function(url, callback) { - d3.csv(url, process_dsv.bind(null, callback)); - }, - from_text: function(text, callback) { - process_dsv(callback, null, d3.csv.parse(text)); - } - } + from_url: url => csv(url).then(data => processDsv(data)), + from_text: text => processDsv(csv.parse(text)), + }, ]; -dc_graph.match_file_format = function(filename) { - return dc_graph.file_formats.find(function(format) { - var exts = format.exts; - if(!Array.isArray(exts)) +export function matchFileFormat(filename) { + return fileFormats.find(format => { + let exts = format.exts; + if (!Array.isArray(exts)) exts = [exts]; - return exts.find(function(ext) { - return new RegExp('\.' + ext + '$').test(filename); - }); + return exts.find(ext => new RegExp(`\\.${ext}$`).test(filename)); }); -}; +} -dc_graph.match_mime_type = function(mime) { - return dc_graph.file_formats.find(function(format) { - var mimes = format.mimes; - if(!Array.isArray(mimes)) +export function matchMimeType(mime) { + return fileFormats.find(format => { + let mimes = format.mimes; + if (!Array.isArray(mimes)) mimes = [mimes]; return mimes.includes(mime); }); -}; +} -function unknown_format_error(filename) { - var spl = filename.split('.'); - if(spl.length) - return new Error('do not know how to process graph file extension ' + spl[spl.length-1]); +function unknownFormatError(filename) { + const spl = filename.split('.'); + if (spl.length) + return new Error(`do not know how to process graph file extension ${spl[spl.length-1]}`); else - return new Error('need file extension to process graph file automatically, filename ' + filename); + return new Error( + `need file extension to process graph file automatically, filename ${filename}`, + ); } -function unknown_mime_error(mime) { - return new Error('do not know how to process mime type ' + mime); +function unknownMimeError(mime) { + return new Error(`do not know how to process mime type ${mime}`); } // load a graph from various formats and return the data in consistent {nodes, links} format -dc_graph.load_graph = function() { +export function loadGraph(file1, file2) { // ignore any query parameters for checking extension - function ignore_query(file) { - if(!file) - return null; - return file.replace(/\?.*/, ''); - } - var file1, file2, callback; - file1 = arguments[0]; - if(arguments.length===3) { - file2 = arguments[1]; - callback = arguments[2]; - } - else if(arguments.length===2) { - callback = arguments[1]; - } - else throw new Error('need two or three arguments'); + const ignore_query = file => file ? file.replace(/\?.*/, '') : null; - if(file2) { + if (file2) { // this is not general - really titan-specific - queue() - .defer(d3.json, file1) - .defer(d3.json, file2) - .await(function(error, nodes, edges) { - if(error) - callback(error, null); - else - callback(null, {nodes: nodes.results, edges: edges.results}); - }); - } - else { - var format; - if(/^data:/.test(file1)) { - var parts = file1.slice(5).split(/,(.+)/); - format = dc_graph.match_mime_type(parts[0]); - if(format) - format.from_text(parts[1], callback); - else callback(unknown_mime_error(parts[0])); + return Promise.all([json(file1), json(file2)]) + .then(([nodes, edges]) => ({nodes: nodes.results, edges: edges.results})); + } else { + if (/^data:/.test(file1)) { + const parts = file1.slice(5).split(/,(.+)/); + const format = matchMimeType(parts[0]); + if (format) + return format.from_text(parts[1]); + else + return Promise.reject(unknownMimeError(parts[0])); } else { - var file1noq = ignore_query(file1); - format = dc_graph.match_file_format(file1noq); - if(format) - format.from_url(file1, callback); - else callback(unknown_format_error(file1noq)); + const file1noq = ignore_query(file1); + const format = matchFileFormat(file1noq); + if (format) + return format.from_url(file1); + else + return Promise.reject(unknownFormatError(file1noq)); } } -}; - -dc_graph.load_graph_text = function(text, filename, callback) { - var format = dc_graph.match_file_format(filename); - if(format) - format.from_text(text, callback); - else callback(unknown_format_error(filename)); -}; - -dc_graph.data_url = function(data) { - return 'data:application/json,' + JSON.stringify(data); -}; +} + +export function loadGraphText(text, filename) { + const format = matchFileFormat(filename); + if (format) + return format.from_text(text); + else + return Promise.reject(unknownFormatError(filename)); +} + +export function dataUrl(data) { + return `data:application/json,${JSON.stringify(data)}`; +} diff --git a/src/manual_layout.js b/src/manual_layout.js index 1f634666..b490537d 100644 --- a/src/manual_layout.js +++ b/src/manual_layout.js @@ -1,21 +1,25 @@ -dc_graph.manual_layout = function(id) { - var _layoutId = id || uuid(); - var _dispatch = d3.dispatch('tick', 'start', 'end'); +/** + * Manual layout for dc.graph.js + * @module manual_layout + */ - var _wnodes; +// External dependencies +import { dispatch } from 'd3-dispatch'; +import { property, uuid } from './core.js'; - function init(options) { +export function manualLayout(id) { + const _layoutId = id || uuid(); + const _dispatch = dispatch('tick', 'start', 'end'); + + let _wnodes; + + function init(_options) { } function data(nodes) { _wnodes = nodes; } function dispatchState(wnodes, wedges, event) { - _dispatch[event]( - wnodes, - wedges.map(function(e) { - return {dcg_edgeKey: e.dcg_edgeKey}; - }) - ); + _dispatch.call(event, null, wnodes, wedges.map(e => ({dcg_edgeKey: e.dcg_edgeKey}))); } function start() { dispatchState(_wnodes, [], 'end'); @@ -23,53 +27,54 @@ dc_graph.manual_layout = function(id) { function stop() { } - var _engine = { - layoutAlgorithm: function() { + const _engine = { + layoutAlgorithm() { return 'manual'; }, - layoutId: function() { + layoutId() { return _layoutId; }, - supportsWebworker: function() { + supportsWebworker() { return false; }, parent: property(null), - on: function(event, f) { - if(arguments.length === 1) + on(event, f) { + if (arguments.length === 1) return _dispatch.on(event); _dispatch.on(event, f); return this; }, - init: function(options) { - this.optionNames().forEach(function(option) { + init(options) { + this.optionNames().forEach(option => { options[option] = options[option] || this[option](); - }.bind(this)); + }); init(options); return this; }, - data: function(graph, nodes, edges) { + data(graph, nodes, _edges) { data(nodes); }, - start: function() { + start() { start(); }, - stop: function() { + stop() { stop(); }, - optionNames: function() { + optionNames() { return []; }, - populateLayoutNode: function(n1, n) { - ['x', 'y'].forEach(function(attr) { - if(n.orig.value[attr] !== undefined) + populateLayoutNode(n1, n) { + ['x', 'y'].forEach(attr => { + if (n.orig.value[attr] !== undefined) n1[attr] = n.orig.value[attr]; }); }, - populateLayoutEdge: function() {}, - addressToKey: property(function(ad) { return ad.join(','); }), - keyToAddress: property(function(nid) { return nid.split(','); }) + populateLayoutEdge() {}, + addressToKey: property(ad => ad.join(',')), + keyToAddress: property(nid => nid.split(',')), }; return _engine; -}; +} -dc_graph.manual_layout.scripts = ['css-layout.js']; +// Scripts needed for web worker +manualLayout.scripts = ['css-layout.js']; diff --git a/src/match_opposites.js b/src/match_opposites.js index 26760672..b2b5a448 100644 --- a/src/match_opposites.js +++ b/src/match_opposites.js @@ -1,95 +1,105 @@ -dc_graph.match_opposites = function(diagram, deleteProps, options) { +import { property } from './core.js'; +import { multiplyProperties, propertyInterpolate } from './utils.js'; + +// External dependencies +import { easeCubic } from 'd3-ease'; + +export function matchOpposites(diagram, deleteProps, options) { options = Object.assign({ multiplier: 2, - ease: d3.ease('cubic') + ease: easeCubic, }, options); - var _ports, _wports, _wedges, _validTargets; + let _ports, _wports, _wedges, _validTargets; - diagram.cascade(100, true, multiply_properties(function(e) { - return options.ease(e.deleting || 0); - }, deleteProps, property_interpolate)); - diagram.on('data.match-opposites', function(diagram, nodes, wnodes, edges, wedges, ports, wports) { + diagram.cascade( + 100, + true, + multiplyProperties(e => options.ease(e.deleting || 0), deleteProps, propertyInterpolate), + ); + diagram.on('data.match-opposites', (diagram, nodes, wnodes, edges, wedges, ports, wports) => { _ports = ports; _wports = wports; _wedges = wedges; }); function port_pos(p) { - return { x: p.node.cola.x + p.pos.x, y: p.node.cola.y + p.pos.y }; + return {x: p.node.cola.x+p.pos.x, y: p.node.cola.y+p.pos.y}; } function is_valid(sourcePort, targetPort) { - return (_strategy.allowParallel() || !_wedges.some(function(e) { - return sourcePort.edges.indexOf(e) >= 0 && targetPort.edges.indexOf(e) >= 0; - })) && _strategy.isValid()(sourcePort, targetPort); + return (_strategy.allowParallel() + || !_wedges.some(e => + sourcePort.edges.indexOf(e) >= 0 && targetPort.edges.indexOf(e) >= 0 + )) && _strategy.isValid()(sourcePort, targetPort); } function reset_deletables(source, targets) { - targets.forEach(function(p) { - p.edges.forEach(function(e) { + targets.forEach(p => { + p.edges.forEach(e => { e.deleting = 0; }); }); - if(source) - source.port.edges.forEach(function(e) { + if (source) + source.port.edges.forEach(e => { e.deleting = 0; }); } - var _strategy = { - isValid: property(function(sourcePort, targetPort) { + const _strategy = { + isValid: property((sourcePort, targetPort) => // draw_graphs is already enforcing this, but this makes more sense and i use xor any chance i get - return (diagram.portName.eval(sourcePort) === 'in') ^ (diagram.portName.eval(targetPort) === 'in'); - }), + (diagram.portName.eval(sourcePort) === 'in')^(diagram.portName.eval(targetPort) + === 'in') + ), allowParallel: property(false), - hoverPort: function(port) { + hoverPort(_port) { // could be called by draw_graphs when node is hovered, isn't }, - startDragEdge: function(source) { + startDragEdge(source) { _validTargets = _wports.filter(is_valid.bind(null, source.port)); console.log('valid targets', _validTargets.map(diagram.portNodeKey.eval)); return _validTargets.length !== 0; }, - dragCanvas: function(source, coords) { - var closest = _validTargets.map(function(p) { - var ppos = port_pos(p); + dragCanvas(source, coords) { + const closest = _validTargets.map(p => { + const ppos = port_pos(p); return { - distance: Math.hypot(coords[0] - ppos.x, coords[1] - ppos.y), - port: p + distance: Math.hypot(coords[0]-ppos.x, coords[1]-ppos.y), + port: p, }; - }).sort(function(a, b) { - return a.distance - b.distance; - }); - var cpos = port_pos(closest[0].port), spos = port_pos(source.port); - closest.forEach(function(c) { - c.port.edges.forEach(function(e) { - e.deleting = 1 - options.multiplier * c.distance / Math.hypot(cpos.x - spos.x, cpos.y - spos.y); + }).sort((a, b) => a.distance-b.distance); + const cpos = port_pos(closest[0].port), spos = port_pos(source.port); + closest.forEach(c => { + c.port.edges.forEach(e => { + e.deleting = + 1-options.multiplier*c.distance/Math.hypot(cpos.x-spos.x, cpos.y-spos.y); }); }); - source.port.edges.forEach(function(e) { - e.deleting = 1 - options.multiplier * closest[0].distance / Math.hypot(cpos.x - spos.x, cpos.y - spos.y); + source.port.edges.forEach(e => { + e.deleting = 1-options.multiplier*closest[0].distance/Math.hypot( + cpos.x-spos.x, + cpos.y-spos.y, + ); }); diagram.requestRefresh(0); }, - changeDragTarget: function(source, target) { - var valid = target && is_valid(source.port, target.port); - if(valid) { - target.port.edges.forEach(function(e) { + changeDragTarget(source, target) { + const valid = target && is_valid(source.port, target.port); + if (valid) { + target.port.edges.forEach(e => { e.deleting = 1; }); - source.port.edges.forEach(function(e) { + source.port.edges.forEach(e => { e.deleting = 1; }); - reset_deletables(null, _validTargets.filter(function(p) { - return p !== target.port; - })); + reset_deletables(null, _validTargets.filter(p => p !== target.port)); diagram.requestRefresh(0); } return valid; }, - finishDragEdge: function(source, target) { - if(is_valid(source.port, target.port)) { - reset_deletables(null, _validTargets.filter(function(p) { - return p !== target.port; - })); - if(options.delete_edges) { - var edgeKeys = source.port.edges.map(diagram.edgeKey.eval).concat(target.port.edges.map(diagram.edgeKey.eval)); + finishDragEdge(source, target) { + if (is_valid(source.port, target.port)) { + reset_deletables(null, _validTargets.filter(p => p !== target.port)); + if (options.delete_edges) { + const edgeKeys = source.port.edges.map(diagram.edgeKey.eval).concat( + target.port.edges.map(diagram.edgeKey.eval), + ); return options.delete_edges.deleteSelection(edgeKeys); } return Promise.resolve(true); @@ -97,13 +107,13 @@ dc_graph.match_opposites = function(diagram, deleteProps, options) { reset_deletables(source, _validTargets || []); return Promise.resolve(false); }, - cancelDragEdge: function(source) { + cancelDragEdge(source) { reset_deletables(source, _validTargets || []); return true; }, - detectReversedEdge: function(edge, sourcePort, targetPort) { + detectReversedEdge(edge, sourcePort, _targetPort) { return diagram.portName.eval(sourcePort) === 'in'; - } + }, }; return _strategy; -}; +} diff --git a/src/match_ports.js b/src/match_ports.js index 382e03cc..a61972d6 100644 --- a/src/match_ports.js +++ b/src/match_ports.js @@ -1,60 +1,63 @@ -dc_graph.match_ports = function(diagram, symbolPorts) { - var _ports, _wports, _wedges, _validTargets; - diagram.on('data.match-ports', function(diagram, nodes, wnodes, edges, wedges, ports, wports) { +import { property } from './core.js'; + +export function matchPorts(diagram, symbolPorts) { + let _ports, _wports, _wedges, _validTargets; + diagram.on('data.match-ports', (diagram, nodes, wnodes, edges, wedges, ports, wports) => { _ports = ports; _wports = wports; _wedges = wedges; }); - diagram.on('transitionsStarted.match-ports', function() { + diagram.on('transitionsStarted.match-ports', () => { symbolPorts.enableHover(true); }); function change_state(ports, state) { - return ports.map(function(p) { + return ports.map(p => { p.state = state; return diagram.portNodeKey.eval(p); }); } function reset_ports(source) { - var nids = change_state(_validTargets, 'small'); + const nids = change_state(_validTargets, 'small'); source.port.state = 'small'; nids.push(diagram.portNodeKey.eval(source.port)); symbolPorts.animateNodes(nids); } function has_parallel(sourcePort, targetPort) { - return _wedges.some(function(e) { - return sourcePort.edges.indexOf(e) >= 0 && targetPort.edges.indexOf(e) >= 0; - }); + return _wedges.some(e => + sourcePort.edges.indexOf(e) >= 0 && targetPort.edges.indexOf(e) >= 0 + ); } function is_valid(sourcePort, targetPort) { return (_strategy.allowParallel() || !has_parallel(sourcePort, targetPort)) && _strategy.isValid()(sourcePort, targetPort); } function why_invalid(sourcePort, targetPort) { - return !_strategy.allowParallel() && has_parallel(sourcePort, targetPort) && "can't connect two edges between the same two ports" || - _strategy.whyInvalid()(sourcePort, targetPort); + return !_strategy.allowParallel() && has_parallel(sourcePort, targetPort) + && "can't connect two edges between the same two ports" + || _strategy.whyInvalid()(sourcePort, targetPort); } - var _strategy = { - isValid: property(function(sourcePort, targetPort) { - return targetPort !== sourcePort && targetPort.name === sourcePort.name; - }), - whyInvalid: property(function(sourcePort, targetPort) { - return targetPort === sourcePort && "can't connect port to itself" || - targetPort.name !== sourcePort.name && "must connect ports of the same type"; - }), + const _strategy = { + isValid: property((sourcePort, targetPort) => + targetPort !== sourcePort && targetPort.name === sourcePort.name + ), + whyInvalid: property((sourcePort, targetPort) => + targetPort === sourcePort && "can't connect port to itself" + || targetPort.name !== sourcePort.name && 'must connect ports of the same type' + ), allowParallel: property(false), - hoverPort: function(port) { - if(port) { + hoverPort(port) { + if (port) { _validTargets = _wports.filter(is_valid.bind(null, port)); - if(_validTargets.length) + if (_validTargets.length) return change_state(_validTargets, 'shimmer-medium'); - } else if(_validTargets) + } else if (_validTargets) return change_state(_validTargets, 'small'); return null; }, - startDragEdge: function(source) { + startDragEdge(source) { _validTargets = _wports.filter(is_valid.bind(null, source.port)); - var nids = change_state(_validTargets, 'shimmer'); - if(_validTargets.length) { + const nids = change_state(_validTargets, 'shimmer'); + if (_validTargets.length) { symbolPorts.enableHover(false); source.port.state = 'large'; nids.push(diagram.portNodeKey.eval(source.port)); @@ -63,16 +66,16 @@ dc_graph.match_ports = function(diagram, symbolPorts) { console.log('valid targets', nids); return _validTargets.length !== 0; }, - invalidSourceMessage: function(source) { - return "no valid matches for this port"; + invalidSourceMessage(_source) { + return 'no valid matches for this port'; }, - changeDragTarget: function(source, target) { - var nids, valid = target && is_valid(source.port, target.port), before; - if(valid) { + changeDragTarget(source, target) { + let nids, before; + const valid = target && is_valid(source.port, target.port); + if (valid) { nids = change_state(_validTargets, 'small'); target.port.state = 'large'; // it's one of the valid - } - else { + } else { nids = change_state(_validTargets, 'small'); before = symbolPorts.animateNodes(nids); nids = change_state(_validTargets, 'shimmer'); @@ -80,22 +83,22 @@ dc_graph.match_ports = function(diagram, symbolPorts) { symbolPorts.animateNodes(nids, before); return valid; }, - validTargetMessage: function(source, target) { + validTargetMessage(_source, _target) { return "it's a match!"; }, - invalidTargetMessage: function(source, target) { + invalidTargetMessage(source, target) { return why_invalid(source.port, target.port); }, - finishDragEdge: function(source, target) { + finishDragEdge(source, target) { symbolPorts.enableHover(true); reset_ports(source); return Promise.resolve(is_valid(source.port, target.port)); }, - cancelDragEdge: function(source) { + cancelDragEdge(source) { symbolPorts.enableHover(true); reset_ports(source); return true; - } + }, }; return _strategy; -}; +} diff --git a/src/mode.js b/src/mode.js index a469705d..424d5cb2 100644 --- a/src/mode.js +++ b/src/mode.js @@ -1,14 +1,16 @@ -dc_graph.mode = function(event_namespace, options) { - var _mode = {}; - var _eventName = options.laterDraw ? 'transitionsStarted' : 'drawn'; - var draw = options.draw, remove = options.remove; - var supported_renderers = options.renderers || ['svg']; +import { deprecateFunction, property } from './core.js'; - if(!draw) { +export function mode(event_namespace, options) { + const _mode = {}; + const _eventName = options.laterDraw ? 'transitionsStarted' : 'drawn'; + let draw = options.draw, remove = options.remove; + const supported_renderers = options.renderers || ['svg']; + + if (!draw) { console.warn('behavior.add_behavior has been replaced by mode.draw'); draw = options.add_behavior; } - if(!remove) { + if (!remove) { console.warn('behavior.remove_behavior has been replaced by mode.remove'); remove = options.remove_behavior; } @@ -18,34 +20,32 @@ dc_graph.mode = function(event_namespace, options) { Assigns this mode to a diagram. **/ _mode.parent = property(null) - .react(function(p) { - var diagram; - if(p) { - var first = true; + .react(p => { + let diagram; + if (p) { + let first = true; diagram = p; - p.on(_eventName + '.' + event_namespace, function() { - var args2 = [diagram].concat(Array.prototype.slice.call(arguments)); + p.on(`${_eventName}.${event_namespace}`, function() { + const args2 = [diagram].concat(Array.prototype.slice.call(arguments)); draw.apply(null, args2); - if(first && options.first) { + if (first && options.first) { options.first.apply(null, args2); first = false; - } - else if(options.rest) + } else if (options.rest) options.rest.apply(null, args2); }); - p.on('reset.' + event_namespace, function() { - var rend = diagram.renderer(), + p.on(`reset.${event_namespace}`, () => { + const rend = diagram.renderer(), node = rend.selectAllNodes ? rend.selectAllNodes() : null, edge = rend.selectAllEdges ? rend.selectAllEdges() : null, edgeHover = rend.selectAllEdges ? rend.selectAllEdges('.edge-hover') : null; remove(diagram, node, edge, edgeHover); }); - } - else if(_mode.parent()) { + } else if (_mode.parent()) { diagram = _mode.parent(); - diagram.on(_eventName + '.' + event_namespace, function(node, edge, ehover) { + diagram.on(`${_eventName}.${event_namespace}`, (node, edge, ehover) => { remove(diagram, node, edge, ehover); - diagram.on(_eventName + '.' + event_namespace, null); + diagram.on(`${_eventName}.${event_namespace}`, null); }); } options.parent && options.parent(p); @@ -56,6 +56,6 @@ dc_graph.mode = function(event_namespace, options) { }; return _mode; -}; +} -dc_graph.behavior = deprecate_function('dc_graph.behavior has been renamed dc_graph.mode', dc_graph.mode); +export const behavior = deprecateFunction('behavior has been renamed mode', mode); diff --git a/src/move_nodes.js b/src/move_nodes.js index a051be53..333762c8 100644 --- a/src/move_nodes.js +++ b/src/move_nodes.js @@ -1,105 +1,116 @@ -dc_graph.move_nodes = function(options) { +import { event as d3Event, select } from 'd3-selection'; +import { property } from './core.js'; +import { fixNodesGroup } from './fix_nodes.js'; +import { keyboard } from './keyboard.js'; +import { mode } from './mode.js'; +import { selectThingsGroup } from './select_things.js'; +import { is_a_mac } from './utils.js'; +import { eventCoords } from './utils.js'; + +export function moveNodes(options) { options = options || {}; - var select_nodes_group = dc_graph.select_things_group(options.select_nodes_group || 'select-nodes-group', 'select-nodes'); - var fix_nodes_group = dc_graph.fix_nodes_group(options.fix_nodes_group || 'fix-nodes-group'); - var _selected = [], _startPos = null, _downNode, _moveStarted; - var _brush, _drawGraphs, _selectNodes, _restoreBackgroundClick, _keyboard; - var _maybeSelect = null; + const select_nodes_group = selectThingsGroup( + options.select_nodes_group || 'select-nodes-group', + 'select-nodes', + ); + const fix_nodes_group = fixNodesGroup(options.fix_nodes_group || 'fix-nodes-group'); + let _selected = [], _startPos = null, _downNode, _moveStarted; + let _brush, _drawGraphs, _selectNodes, _restoreBackgroundClick, _keyboard; + let _maybeSelect = null; - function isUnion(event) { + function _isUnion(event) { return event.shiftKey; } - function isToggle(event) { + function _isToggle(event) { return is_a_mac ? event.metaKey : event.ctrlKey; } - function selection_changed(diagram) { + function selection_changed(_diagram) { return function(selection, refresh) { - if(refresh === undefined) + if (refresh === undefined) refresh = true; _selected = selection; }; } function for_each_selected(f, selected) { selected = selected || _selected; - selected.forEach(function(key) { - var n = _mode.parent().getWholeNode(key); + selected.forEach(key => { + const n = _mode.parent().getWholeNode(key); f(n, key); }); } function draw(diagram, node, edge) { node.on('mousedown.move-nodes', function(n) { // Need a more general way for modes to say "I got this" - if(_drawGraphs && _drawGraphs.usePorts() && _drawGraphs.usePorts().eventPort()) + if (_drawGraphs && _drawGraphs.usePorts() && _drawGraphs.usePorts().eventPort(d3Event)) return; - if(!_keyboard.modKeysMatch(_mode.modKeys())) + if (!_keyboard.modKeysMatch(_mode.modKeys())) return; - _startPos = dc_graph.event_coords(diagram); - _downNode = d3.select(this); + _startPos = eventCoords(diagram, d3Event); + _downNode = select(this); // if the node under the mouse is not in the selection, need to // make that node selected - var key = diagram.nodeKey.eval(n); - var selected = _selected; - if(_selected.indexOf(key)<0) { + const key = diagram.nodeKey.eval(n); + let selected = _selected; + if (_selected.indexOf(key) < 0) { selected = [key]; _maybeSelect = key; - } - else _maybeSelect = null; - for_each_selected(function(n) { + } else _maybeSelect = null; + for_each_selected(n => { n.original_position = [n.cola.x, n.cola.y]; }, selected); - if(_brush) + if (_brush) _brush.deactivate(); }); - function mouse_move() { - if(_startPos) { - if(!(d3.event.buttons & 1)) { + function mouse_move(event) { + if (_startPos) { + if (!(event.buttons&1)) { mouse_up(); return; } - if(_maybeSelect) - select_nodes_group.set_changed([_maybeSelect]); - var pos = dc_graph.event_coords(diagram); - var dx = pos[0] - _startPos[0], - dy = pos[1] - _startPos[1]; - if(!_moveStarted && Math.hypot(dx, dy) > _mode.dragSize()) { + if (_maybeSelect) + select_nodes_group.call('set_changed', null, [_maybeSelect]); + const pos = eventCoords(diagram, event); + const dx = pos[0]-_startPos[0], + dy = pos[1]-_startPos[1]; + if (!_moveStarted && Math.hypot(dx, dy) > _mode.dragSize()) { _moveStarted = true; // prevent click event for this node setting selection just to this - if(_downNode) + if (_downNode) _downNode.style('pointer-events', 'none'); } - if(_moveStarted) { - for_each_selected(function(n) { - n.cola.x = n.original_position[0] + dx; - n.cola.y = n.original_position[1] + dy; + if (_moveStarted) { + for_each_selected(n => { + n.cola.x = n.original_position[0]+dx; + n.cola.y = n.original_position[1]+dy; }); - var node2 = node.filter(function(n) { return _selected.includes(n.orig.key); }), - edge2 = edge.filter(function(e) { - return _selected.includes(e.source.orig.key) || - _selected.includes(e.target.orig.key); - }); + const node2 = node.filter(n => _selected.includes(n.orig.key)), + edge2 = edge.filter(e => + _selected.includes(e.source.orig.key) + || _selected.includes(e.target.orig.key) + ); diagram.reposition(node2, edge2); } } } function mouse_up() { - if(_startPos) { - if(_moveStarted) { + if (_startPos) { + if (_moveStarted) { _moveStarted = false; - if(_downNode) { + if (_downNode) { _downNode.style('pointer-events', null); _downNode = null; } - var fixes = []; - for_each_selected(function(n, id) { + const fixes = []; + for_each_selected((n, id) => { fixes.push({ - id: id, - pos: {x: n.cola.x, y: n.cola.y} + id, + pos: {x: n.cola.x, y: n.cola.y}, }); }); - fix_nodes_group.request_fixes(fixes); + fix_nodes_group.call('request_fixes', null, fixes); } - if(_brush) + if (_brush) _brush.activate(); _startPos = null; } @@ -112,27 +123,26 @@ dc_graph.move_nodes = function(options) { .on('mouseup.move-nodes', mouse_up); } - function remove(diagram, node, edge) { + function remove(diagram, node, _edge) { node.on('mousedown.move-nodes', null); node.on('mousemove.move-nodes', null); node.on('mouseup.move-nodes', null); } - var _mode = dc_graph.mode('move-nodes', { - draw: draw, - remove: remove, - parent: function(p) { + const _mode = mode('move-nodes', { + draw, + remove, + parent(p) { select_nodes_group.on('set_changed.move-nodes', p ? selection_changed(p) : null); - if(p) { + if (p) { _brush = p.child('brush'); _drawGraphs = p.child('draw-graphs'); _selectNodes = p.child('select-nodes'); _keyboard = p.child('keyboard'); - if(!_keyboard) - p.child('keyboard', _keyboard = dc_graph.keyboard()); - } - else _brush = _drawGraphs = _selectNodes = null; - } + if (!_keyboard) + p.child('keyboard', _keyboard = keyboard()); + } else _brush = _drawGraphs = _selectNodes = null; + }, }); // minimum distance that is considered a drag, not a click @@ -140,4 +150,4 @@ dc_graph.move_nodes = function(options) { _mode.modKeys = property(null); return _mode; -}; +} diff --git a/src/munge_graph.js b/src/munge_graph.js index 10275786..37a40823 100644 --- a/src/munge_graph.js +++ b/src/munge_graph.js @@ -1,19 +1,22 @@ -function can_get_graph_from_this(data) { +function canGetGraphFromThis(data) { return (data.nodes || data.vertices) && (data.edges || data.links); } // general-purpose reader of various json-based graph formats // (esp but not limited to titan graph database-like formats) // this could be generalized a lot -dc_graph.munge_graph = function(data, nodekeyattr, sourceattr, targetattr) { +export function mungeGraph(data, nodekeyattr, sourceattr, targetattr) { // we want data = {nodes, edges} and the field names for keys; find those in common json formats - var nodes, edges, nka = nodekeyattr || "name", - sa = sourceattr || "sourcename", ta = targetattr || "targetname"; + let nodes, + edges, + nka = nodekeyattr || 'name', + sa = sourceattr || 'sourcename', + ta = targetattr || 'targetname'; - if(!can_get_graph_from_this(data)) { - var wrappers = ['database', 'response']; - var wi = wrappers.findIndex(function(f) { return data[f] && can_get_graph_from_this(data[f]); }); - if(wi<0) + if (!canGetGraphFromThis(data)) { + const wrappers = ['database', 'response']; + const wi = wrappers.findIndex(f => data[f] && canGetGraphFromThis(data[f])); + if (wi < 0) throw new Error("couldn't find the data!"); data = data[wrappers[wi]]; } @@ -21,48 +24,51 @@ dc_graph.munge_graph = function(data, nodekeyattr, sourceattr, targetattr) { nodes = data.nodes || data.vertices; function find_attr(o, attrs) { - return attrs.filter(function(a) { return !!o[a]; }); + return attrs.filter(a => !!o[a]); } - //var edgekeyattr = "id"; - var edge0 = edges[0]; - if(edge0[sa] === undefined) { - var sourceattrs = sourceattr ? [sourceattr] : ['source_ecomp_uid', "node1", "source", "tail"], - targetattrs = targetattr ? [targetattr] : ['target_ecomp_uid', "node2", "target", "head"]; - //var edgekeyattrs = ['id', '_id', 'ecomp_uid']; - var edgewrappers = ['edge']; - if(edge0.node0 && edge0.node1) { // specific conflict here + // var edgekeyattr = "id"; + let edge0 = edges[0]; + if (edge0[sa] === undefined) { + const sourceattrs = sourceattr + ? [sourceattr] + : ['source_ecomp_uid', 'node1', 'source', 'tail'], + targetattrs = targetattr + ? [targetattr] + : ['target_ecomp_uid', 'node2', 'target', 'head']; + // var edgekeyattrs = ['id', '_id', 'ecomp_uid']; + const edgewrappers = ['edge']; + if (edge0.node0 && edge0.node1) { // specific conflict here sa = 'node0'; ta = 'node1'; - } - else { - var candidates = find_attr(edge0, sourceattrs); - if(!candidates.length) { - wi = edgewrappers.findIndex(function(w) { - return edge0[w] && find_attr(edge0[w], sourceattrs).length; - }); - if(wi<0) { - if(sourceattr) - throw new Error('sourceattr ' + sa + " didn't work"); + } else { + let candidates = find_attr(edge0, sourceattrs); + if (!candidates.length) { + const wi = edgewrappers.findIndex(w => + edge0[w] && find_attr(edge0[w], sourceattrs).length + ); + if (wi < 0) { + if (sourceattr) + throw new Error(`sourceattr ${sa} didn't work`); else throw new Error("didn't find any source attr"); } - edges = edges.map(function(e) { return e[edgewrappers[wi]]; }); + edges = edges.map(e => e[edgewrappers[wi]]); edge0 = edges[0]; candidates = find_attr(edge0, sourceattrs); } - if(candidates.length > 1) + if (candidates.length > 1) console.warn('found more than one possible source attr', candidates); sa = candidates[0]; candidates = find_attr(edge0, targetattrs); - if(!candidates.length) { - if(targetattr && !edge0[targetattr]) - throw new Error('targetattr ' + ta + " didn't work"); + if (!candidates.length) { + if (targetattr && !edge0[targetattr]) + throw new Error(`targetattr ${ta} didn't work`); else throw new Error("didn't find any target attr"); } - if(candidates.length > 1) + if (candidates.length > 1) console.warn('found more than one possible target attr', candidates); ta = candidates[0]; @@ -77,35 +83,35 @@ dc_graph.munge_graph = function(data, nodekeyattr, sourceattr, targetattr) { */ } } - var node0 = nodes[0]; - if(node0[nka] === undefined) { - var nodekeyattrs = nodekeyattr ? [nodekeyattr] : ['ecomp_uid', 'id', '_id', 'key']; - var nodewrappers = ['vertex']; - candidates = find_attr(node0, nodekeyattrs); - if(!candidates.length) { - wi = nodewrappers.findIndex(function(w) { - return node0[w] && find_attr(node0[w], nodekeyattrs).length; - }); - if(wi<0) { - if(nodekeyattr) - throw new Error('nodekeyattr ' + nka + " didn't work"); + let node0 = nodes[0]; + if (node0[nka] === undefined) { + const nodekeyattrs = nodekeyattr ? [nodekeyattr] : ['ecomp_uid', 'id', '_id', 'key']; + const nodewrappers = ['vertex']; + let candidates = find_attr(node0, nodekeyattrs); + if (!candidates.length) { + const wi = nodewrappers.findIndex(w => + node0[w] && find_attr(node0[w], nodekeyattrs).length + ); + if (wi < 0) { + if (nodekeyattr) + throw new Error(`nodekeyattr ${nka} didn't work`); else throw new Error("couldn't find the node data"); } - nodes = nodes.map(function(n) { return n[nodewrappers[wi]]; }); + nodes = nodes.map(n => n[nodewrappers[wi]]); node0 = nodes[0]; candidates = find_attr(node0, nodekeyattrs); } - if(candidates.length > 1) + if (candidates.length > 1) console.warn('found more than one possible node key attr', candidates); nka = candidates[0]; } return { - nodes: nodes, - edges: edges, + nodes, + edges, nodekeyattr: nka, sourceattr: sa, - targetattr: ta + targetattr: ta, }; } diff --git a/src/node_contents.js b/src/node_contents.js index 3609df07..56d875f3 100644 --- a/src/node_contents.js +++ b/src/node_contents.js @@ -1,131 +1,140 @@ -dc_graph.text_contents = function() { - var _contents = { +import { select } from 'd3-selection'; +import { getBBoxNoThrow, isIe, isSafari, property } from './core.js'; +import { nodeLabelPadding } from './shape.js'; + +export function textContents() { + const _contents = { parent: property(null), - update: function(container) { - var text = container.selectAll('text.node-label') - .data(function(n) { return [n]; }); - text.enter().append('text') + update(container) { + let text = container.selectAll('text.node-label') + .data(n => [n]); + const textEnter = text.enter().append('text') .attr('class', 'node-label'); - var tspan = text.selectAll('tspan').data(function(n) { - var lines = _contents.parent().nodeLabel.eval(n); - if(!lines) + text = text.merge(textEnter); + let tspan = text.selectAll('tspan').data(n => { + let lines = _contents.parent().nodeLabel.eval(n); + if (!lines) return []; - else if(typeof lines === 'string') + else if (typeof lines === 'string') lines = [lines]; - var lineHeight = _contents.parent().nodeLineHeight(); - var first = 0.5 - ((lines.length - 1) * lineHeight + 1)/2; + const lineHeight = _contents.parent().nodeLineHeight(); + let first = 0.5-((lines.length-1)*lineHeight+1)/2; // IE, Edge, and Safari do not seem to support // dominant-baseline: central although they say they do - if(is_ie() || is_safari()) + if (isIe() || isSafari()) first += 0.3; - return lines.map(function(line, i) { return {node: n, line: line, yofs: (i==0 ? first : lineHeight) + 'em'}; }); + return lines.map((line, i) => ({ + node: n, + line, + yofs: `${i == 0 ? first : lineHeight}em`, + })); }); - tspan.enter().append('tspan'); - tspan.attr({ - 'text-anchor': 'start', - 'text-decoration': function(line) { - return _contents.parent().nodeLabelDecoration.eval(line.node); - }, - x: 0 - }).html(function(s) { return s.line; }); + const tspanEnter = tspan.enter().append('tspan'); + tspan = tspan.merge(tspanEnter); + tspan + .attr('text-anchor', 'start') + .attr( + 'text-decoration', + line => _contents.parent().nodeLabelDecoration.eval(line.node), + ) + .attr('x', 0) + .html(s => s.line); text - .each(function(n) { + .each(n => { n.xofs = 0; }) - .filter(function(n) { - return _contents.parent().nodeLabelAlignment.eval(n) !== 'center'; - }) + .filter(n => _contents.parent().nodeLabelAlignment.eval(n) !== 'center') .each(function(n) { - var bbox = getBBoxNoThrow(this); + const bbox = getBBoxNoThrow(this); n.bbox = {x: bbox.x, y: bbox.y, width: bbox.width, height: bbox.height}; - switch(_contents.parent().nodeLabelAlignment.eval(n)) { - case 'left': n.xofs = -n.bbox.width/2; - break; - case 'right': n.xofs = n.bbox.width/2; - break; + switch (_contents.parent().nodeLabelAlignment.eval(n)) { + case 'left': + n.xofs = -n.bbox.width/2; + break; + case 'right': + n.xofs = n.bbox.width/2; + break; } }) .selectAll('tspan'); - tspan.attr({ - 'text-anchor': function(s) { - switch(_contents.parent().nodeLabelAlignment.eval(s.node)) { - case 'left': return 'start'; - case 'center': return 'middle'; - case 'right': return 'end'; + tspan + .attr('text-anchor', s => { + switch (_contents.parent().nodeLabelAlignment.eval(s.node)) { + case 'left': + return 'start'; + case 'center': + return 'middle'; + case 'right': + return 'end'; } return null; - }, - x: function(s) { - return s.node.xofs; - }, - dy: function(d) { return d.yofs; } - }); + }) + .attr('x', s => s.node.xofs) + .attr('dy', d => d.yofs); tspan.exit().remove(); text .attr('fill', _contents.parent().nodeLabelFill.eval); }, - textbox: function(container) { - var bbox = getBBoxNoThrow(this.selectContent(container).node()); + textbox(container) { + const bbox = getBBoxNoThrow(this.selectContent(container).node()); return {x: bbox.x, y: bbox.y, width: bbox.width, height: bbox.height}; }, - selectContent: function(container) { + selectContent(container) { return container.select('text.node-label'); }, - selectText: function(container) { + selectText(container) { return this.selectContent(container); - } + }, }; return _contents; -}; +} -dc_graph.with_icon_contents = function(contents, width, height) { - var _contents = { - parent: property(null).react(function(parent) { +export function withIconContents(contents, width, height) { + const _contents = { + parent: property(null).react(parent => { contents.parent(parent); }), - padding: function(n) { - var padding = node_label_padding(_contents.parent(), n); + padding(n) { + const padding = nodeLabelPadding(_contents.parent(), n); return { - x: padding.x * 3, - y: padding.y * 3 + x: padding.x*3, + y: padding.y*3, }; }, - update: function(container) { - var g = container.selectAll('g.with-icon') - .data(function(n) { return [n]; }); - var gEnter = g.enter(); + update(container) { + let g = container.selectAll('g.with-icon') + .data(n => [n]); + const gEnter = g.enter(); gEnter.append('g') .attr('class', 'with-icon') - .append('image').attr({ - class: 'icon', - width: width + 'px', - height: height + 'px' - }); + .append('image') + .attr('class', 'icon') + .attr('width', `${width}px`) + .attr('height', `${height}px`); + g = g.merge(gEnter.select('g.with-icon')); g.call(contents.update); contents.selectContent(g) - .attr('transform', 'translate(' + width/2 + ')'); - g.selectAll('image.icon').attr({ - href: _contents.parent().nodeIcon.eval, - x: function(n) { - var totwid = width + contents.textbox(d3.select(this.parentNode)).width; - return -totwid/2 - node_label_padding(_contents.parent(), n).x; - }, - y: -height/2 - }); + .attr('transform', `translate(${width/2})`); + g.selectAll('image.icon') + .attr('href', _contents.parent().nodeIcon.eval) + .attr('x', function(n) { + const totwid = width+contents.textbox(select(this.parentNode)).width; + return -totwid/2-nodeLabelPadding(_contents.parent(), n).x; + }) + .attr('y', -height/2); }, - textbox: function(container) { - var box = contents.textbox(container); + textbox(container) { + const box = contents.textbox(container); box.x += width/2; return box; }, - selectContent: function(container) { + selectContent(container) { return container.select('g.with-icon'); }, - selectText: function(container) { + selectText(container) { return this.selectContent(container).select('text.node-label'); - } + }, }; return _contents; -}; - +} diff --git a/src/path_reader.js b/src/path_reader.js index 070da1b9..cebc9071 100644 --- a/src/path_reader.js +++ b/src/path_reader.js @@ -1,25 +1,30 @@ -dc_graph.path_reader = function(pathsgroup) { - var highlight_paths_group = dc_graph.register_highlight_paths_group(pathsgroup || 'highlight-paths-group'); - var _intervals, _intervalTree, _time; +import { identity, property } from './core.js'; +import { registerHighlightPathsGroup } from './highlight_paths_group.js'; + +export function pathReader(pathsgroup) { + const highlight_paths_group = registerHighlightPathsGroup( + pathsgroup || 'highlight-paths-group', + ); + let _intervals, _intervalTree, _time; function register_path_objs(path, nop, eop) { - reader.elementList.eval(path).forEach(function(element) { - var key, paths; - switch(reader.elementType.eval(element)) { - case 'node': - key = reader.nodeKey.eval(element); - paths = nop[key] = nop[key] || []; - break; - case 'edge': - key = reader.edgeSource.eval(element) + '-' + reader.edgeTarget.eval(element); - paths = eop[key] = eop[key] || []; - break; + reader.elementList.eval(path).forEach(element => { + let key, paths; + switch (reader.elementType.eval(element)) { + case 'node': + key = reader.nodeKey.eval(element); + paths = nop[key] = nop[key] || []; + break; + case 'edge': + key = `${reader.edgeSource.eval(element)}-${reader.edgeTarget.eval(element)}`; + paths = eop[key] = eop[key] || []; + break; } paths.push(path); }); } - var reader = { + const reader = { pathList: property(identity, false), timeRange: property(null, false), pathStrength: property(null, false), @@ -28,33 +33,34 @@ dc_graph.path_reader = function(pathsgroup) { nodeKey: property(null, false), edgeSource: property(null, false), edgeTarget: property(null, false), - clear: function() { + clear() { highlight_paths_group.paths_changed({}, {}, []); }, - data: function(data) { - var nop = {}, eop = {}, allpaths = [], has_ranges; - reader.pathList.eval(data).forEach(function(path) { - if((path._range = reader.timeRange.eval(path))) { // ugh modifying user data - if(has_ranges===false) + data(data) { + const nop = {}, eop = {}, allpaths = []; + let has_ranges; + reader.pathList.eval(data).forEach(path => { + if ((path._range = reader.timeRange.eval(path))) { // ugh modifying user data + if (has_ranges === false) throw new Error("can't have a mix of ranged and non-ranged paths"); has_ranges = true; } else { - if(has_ranges===true) + if (has_ranges === true) throw new Error("can't have a mix of ranged and non-ranged paths"); has_ranges = false; register_path_objs(path, nop, eop); } allpaths.push(path); }); - if(has_ranges) { - _intervals = allpaths.map(function(path) { - var interval = [path._range[0].getTime(), path._range[1].getTime()]; + if (has_ranges) { + _intervals = allpaths.map(path => { + const interval = [path._range[0].getTime(), path._range[1].getTime()]; interval.path = path; return interval; }); // currently must include lysenko-interval-tree separately _intervalTree = lysenkoIntervalTree(_intervals); - if(_time) + if (_time) this.setTime(_time); } else { _intervals = null; @@ -62,22 +68,21 @@ dc_graph.path_reader = function(pathsgroup) { highlight_paths_group.paths_changed(nop, eop, allpaths); } }, - getIntervals: function() { + getIntervals() { return _intervals; }, - setTime: function(t) { - if(t && _intervalTree) { - var paths = [], nop = {}, eop = {}; - _intervalTree.queryPoint(t.getTime(), function(interval) { + setTime(t) { + if (t && _intervalTree) { + const paths = [], nop = {}, eop = {}; + _intervalTree.queryPoint(t.getTime(), interval => { paths.push(interval.path); register_path_objs(interval.path, nop, eop); }); highlight_paths_group.paths_changed(nop, eop, paths); } _time = t; - } + }, }; return reader; -}; - +} diff --git a/src/path_selector.js b/src/path_selector.js index b5faa553..ae155e75 100644 --- a/src/path_selector.js +++ b/src/path_selector.js @@ -1,29 +1,38 @@ -dc_graph.path_selector = function(parent, reader, pathsgroup, chartgroup) { - var highlight_paths_group = dc_graph.register_highlight_paths_group(pathsgroup || 'highlight-paths-group'); - var root = d3.select(parent).append('svg'); - var paths_ = []; - var hovered = null, selected = null; +import { registerChart } from 'dc'; +import { property } from './core.js'; +import { registerHighlightPathsGroup } from './highlight_paths_group.js'; - // unfortunately these functions are copied from dc_graph.highlight_paths +// External dependency loaded as global +import { select } from 'd3-selection'; + +export function pathSelector(parent, reader, pathsgroup, chartgroup) { + const highlight_paths_group = registerHighlightPathsGroup( + pathsgroup || 'highlight-paths-group', + ); + const root = select(parent).append('svg'); + let paths_ = []; + let hovered = null, selected = null; + + // unfortunately these functions are copied from highlightPaths function contains_path(paths) { return function(path) { - return paths ? paths.indexOf(path)>=0 : false; + return paths ? paths.indexOf(path) >= 0 : false; }; } function doesnt_contain_path(paths) { - var cp = contains_path(paths); + const cp = contains_path(paths); return function(path) { return !cp(path); }; } function toggle_paths(pathsA, pathsB) { - if(!pathsA) + if (!pathsA) return pathsB; - else if(!pathsB) + else if (!pathsB) return pathsA; - if(pathsB.every(contains_path(pathsA))) + if (pathsB.every(contains_path(pathsA))) return pathsA.filter(doesnt_contain_path(pathsB)); else return pathsA.concat(pathsB.filter(doesnt_contain_path(pathsA))); } @@ -33,126 +42,129 @@ dc_graph.path_selector = function(parent, reader, pathsgroup, chartgroup) { // in fact, you can't even reliably overlap attributes without that (so we don't) function draw_paths(diagram, paths) { - if(paths.length === 0) return; - var xpadding = 30; - var space = 30; - var radius = 8; + if (paths.length === 0) return; + const xpadding = 30; + const space = 30; + const radius = 8; // set the height of SVG accordingly root.attr('height', 20*(paths.length+1)) - .attr('width', xpadding+(space+2*radius)*(paths.length/2+1)+20); + .attr('width', xpadding+(space+2*radius)*(paths.length/2+1)+20); root.selectAll('.path-selector').remove(); - var pathlist = root.selectAll('g.path-selector').data(paths); + const pathlist = root.selectAll('g.path-selector').data(paths); pathlist.enter() - .append('g') - .attr('class', 'path-selector') - .attr("transform", function(path, i) { return "translate(0, " + i*20 + ")"; }) - .each(function(path_data, i) { - var nodes = path_data.element_list.filter(function(d) { return d.element_type === 'node'; }); - // line - var line = d3.select(this).append('line'); - line.attr('x1', xpadding+space) - .attr('y1', radius+1) - .attr('x2', xpadding+space*nodes.length) - .attr('y2', radius+1) - .attr('opacity', 0.4) - .attr('stroke-width', 5) - .attr('stroke', '#bdbdbd'); + .append('g') + .attr('class', 'path-selector') + .attr('transform', (path, i) => `translate(0, ${i*20})`) + .each(function(path_data, i) { + const nodes = path_data.element_list.filter(d => d.element_type === 'node'); + // line + const line = select(this).append('line'); + line.attr('x1', xpadding+space) + .attr('y1', radius+1) + .attr('x2', xpadding+space*nodes.length) + .attr('y2', radius+1) + .attr('opacity', 0.4) + .attr('stroke-width', 5) + .attr('stroke', '#bdbdbd'); - // dots - var path = d3.select(this).selectAll('circle').data(nodes); - path.enter() - .append('circle') - .attr('cx', function(d, i) { return xpadding+space*(i+1); }) - .attr('cy', radius+1) - .attr('r', radius) - .attr('opacity', 0.4) - .attr('fill', function(d) { - // TODO path_selector shouldn't know the data structure of orignal node objects - var regeneratedNode = {key:d.property_map.ecomp_uid, value:d.property_map}; - return diagram.nodeStroke()(regeneratedNode); - }); + // dots + const path = select(this).selectAll('circle').data(nodes); + path.enter() + .append('circle') + .attr('cx', (d, i) => xpadding+space*(i+1)) + .attr('cy', radius+1) + .attr('r', radius) + .attr('opacity', 0.4) + .attr('fill', d => { + // TODO path_selector shouldn't know the data structure of orignal node objects + const regeneratedNode = { + key: d.property_map.ecomp_uid, + value: d.property_map, + }; + return diagram.nodeStroke()(regeneratedNode); + }); - // label - var text = d3.select(this).append('text'); - text.text('Path '+i) - .attr('class', 'path_label') - .attr('x', 0) - .attr('y', radius*1.7) - .on('mouseover.path-selector', function() { - highlight_paths_group.hover_changed([path_data]); - }) - .on('mouseout.path-selector', function() { - highlight_paths_group.hover_changed(null); - }) - .on('click.path-selector', function() { - highlight_paths_group.select_changed(toggle_paths(selected, [path_data])); - }); - }); + // label + const text = select(this).append('text'); + text.text(`Path ${i}`) + .attr('class', 'path_label') + .attr('x', 0) + .attr('y', radius*1.7) + .on('mouseover.path-selector', () => { + highlight_paths_group.hover_changed([path_data]); + }) + .on('mouseout.path-selector', () => { + highlight_paths_group.hover_changed(null); + }) + .on('click.path-selector', () => { + highlight_paths_group.select_changed(toggle_paths(selected, [path_data])); + }); + }); pathlist.exit().transition(1000).attr('opacity', 0).remove(); } function draw_hovered() { - var is_hovered = contains_path(hovered); - root.selectAll('g.path-selector') - .each(function(d, i) { - var textColor = is_hovered(d) ? '#e41a1c' : 'black'; - var lineColor = is_hovered(d) ? 'black' : '#bdbdbd'; - var opacity = is_hovered(d) ? '1' : '0.4'; - d3.select(this).select('.path_label').attr('fill', textColor); - d3.select(this).selectAll('line') - .attr('stroke', lineColor) - .attr('opacity', opacity); - d3.select(this).selectAll('circle').attr('opacity', opacity); - }); + const is_hovered = contains_path(hovered); + root.selectAll('g.path-selector') + .each(function(d, _i) { + const textColor = is_hovered(d) ? '#e41a1c' : 'black'; + const lineColor = is_hovered(d) ? 'black' : '#bdbdbd'; + const opacity = is_hovered(d) ? '1' : '0.4'; + select(this).select('.path_label').attr('fill', textColor); + select(this).selectAll('line') + .attr('stroke', lineColor) + .attr('opacity', opacity); + select(this).selectAll('circle').attr('opacity', opacity); + }); } function draw_selected() { - var is_selected = contains_path(selected); + const is_selected = contains_path(selected); root.selectAll('g.path-selector') - .each(function(d, i) { - var textWeight = is_selected(d) ? 'bold' : 'normal'; - var lineColor = is_selected(d) ? 'black' : '#bdbdbd'; - var opacity = is_selected(d) ? '1' : '0.4'; - d3.select(this).select('.path_label') - .attr('font-weight', textWeight); - d3.select(this).selectAll('line') - .attr('stroke', lineColor) - .attr('opacity', opacity); - d3.select(this).selectAll('circle').attr('opacity', opacity); - }); + .each(function(d, _i) { + const textWeight = is_selected(d) ? 'bold' : 'normal'; + const lineColor = is_selected(d) ? 'black' : '#bdbdbd'; + const opacity = is_selected(d) ? '1' : '0.4'; + select(this).select('.path_label') + .attr('font-weight', textWeight); + select(this).selectAll('line') + .attr('stroke', lineColor) + .attr('opacity', opacity); + select(this).selectAll('circle').attr('opacity', opacity); + }); } highlight_paths_group - .on('paths_changed.path-selector', function(nop, eop, paths) { + .on('paths_changed.path-selector', (nop, eop, paths) => { hovered = selected = null; paths_ = paths; selector.redraw(); }) - .on('hover_changed.path-selector', function(hpaths) { + .on('hover_changed.path-selector', hpaths => { hovered = hpaths; draw_hovered(); }) - .on('select_changed.path-selector', function(spaths) { + .on('select_changed.path-selector', spaths => { selected = spaths; draw_selected(); }); - var selector = { + const selector = { default_text: property('Nothing here'), zero_text: property('No paths'), error_text: property(null), queried: property(false), - redraw: function() { - draw_paths(diagram, paths_); + redraw() { + draw_paths(selector, paths_); draw_hovered(); draw_selected(); }, - render: function() { + render() { this.redraw(); return this; - } + }, }; - dc.registerChart(selector, chartgroup); + registerChart(selector, chartgroup); return selector; -}; +} diff --git a/src/place_ports.js b/src/place_ports.js index 418cfd5d..f6685b62 100644 --- a/src/place_ports.js +++ b/src/place_ports.js @@ -1,49 +1,50 @@ -function port_name(nodeId, edgeId, portName) { - if(!(nodeId || edgeId)) +import { min } from 'd3-array'; +import { property } from './core.js'; + +export function portName(nodeId, edgeId, portName) { + if (!(nodeId || edgeId)) return null; // must have one key or the other - if(nodeId) nodeId = nodeId.replace(/\//g, '%2F'); - if(edgeId) edgeId = edgeId.replace(/\//g, '%2F'); - return (nodeId ? 'node/' + nodeId : 'edge/' + edgeId) + '/' + portName; -}; -function split_port_name(portname) { - var parts = portname.split('/'); + if (nodeId) nodeId = nodeId.replace(/\//g, '%2F'); + if (edgeId) edgeId = edgeId.replace(/\//g, '%2F'); + return `${nodeId ? `node/${nodeId}` : `edge/${edgeId}`}/${portName}`; +} +export function splitPortName(portname) { + let parts = portname.split('/'); console.assert(parts.length === 3); - parts = parts.map(function(p) { - return p.replace(/%2F/g, '/'); - }); - if(parts[0] === 'node') + parts = parts.map(p => p.replace(/%2F/g, '/')); + if (parts[0] === 'node') return { nodeKey: parts[1], - name: parts[2] + name: parts[2], }; else return { - edgeKey: parts[1], - name: parts[2] - }; + edgeKey: parts[1], + name: parts[2], + }; } -function project_port(diagram, n, p) { - if(!p.vec) { +export function projectPort(diagram, n, p) { + if (!p.vec) { console.assert(!p.edges.length); - throw new Error("port has not been placed, maybe install place_ports? " + p.name); + throw new Error(`port has not been placed, maybe install place_ports? ${p.name}`); } p.pos = diagram.shape(n.dcg_shape.shape).intersect_vec(n, p.vec[0]*1000, p.vec[1]*1000); } -dc_graph.place_ports = function() { - function received_layout(diagram, nodes, wnodes, edges, wedges, ports, wports) { - var node_ports = diagram.nodePorts(); +export function placePorts() { + function received_layout(diagram, nodes, _wnodes, _edges, _wedges, _ports, _wports) { + const node_ports = diagram.nodePorts(); function is_ccw(u, v) { - return u[0]*v[1] - u[1]*v[0] > 0; + return u[0]*v[1]-u[1]*v[0] > 0; } function in_bounds(v, bounds) { // assume bounds are ccw return is_ccw(bounds[0], v) && is_ccw(v, bounds[1]); } function clip(v, bounds) { - if(is_ccw(v, bounds[0])) + if (is_ccw(v, bounds[0])) return bounds[0]; - else if(is_ccw(bounds[1], v)) + else if (is_ccw(bounds[1], v)) return bounds[1]; else return v; } @@ -54,71 +55,71 @@ dc_graph.place_ports = function() { return Math.atan2(v[1], v[0]); } function distance(p, p2) { - return Math.hypot(p2.pos.x - p.pos.x, p2.pos.y - p.pos.y); + return Math.hypot(p2.pos.x-p.pos.x, p2.pos.y-p.pos.y); } function misses(p, p2) { - var dist = distance(p, p2); - var misses = dist > _mode.minDistance(); + const dist = distance(p, p2); + const misses = dist > _mode.minDistance(); return misses; } function rand_within(a, b) { - return a + Math.random()*(b-a); + return a+Math.random()*(b-a); } // calculate port positions - for(var nid in node_ports) { - var n = nodes[nid], + for (const nid in node_ports) { + const n = nodes[nid], nports = node_ports[nid]; // make sure that we have vector and angle bounds for any ports with specification - nports.forEach(function(p) { - var bounds = p.orig && diagram.portBounds.eval(p) || [0, 2*Math.PI]; - if(Array.isArray(bounds[0])) { + nports.forEach(p => { + const bounds = p.orig && diagram.portBounds.eval(p) || [0, 2*Math.PI]; + if (Array.isArray(bounds[0])) { p.vbounds = bounds; p.abounds = bounds.map(v_to_a); - } - else { + } else { p.vbounds = bounds.map(a_to_v); p.abounds = bounds; } - if(p.abounds[0] > p.abounds[1]) + if (p.abounds[0] > p.abounds[1]) p.abounds[1] += 2*Math.PI; console.assert(p.orig || p.vec, 'unplaced unspecified port'); }); // determine which ports satisfy bounds or are unplaced - var inside = [], outside = [], unplaced = []; - nports.forEach(function(p) { - if(!p.vec) + let inside = [], unplaced = []; + const outside = []; + nports.forEach(p => { + if (!p.vec) unplaced.push(p); - else if(p.vbounds && !in_bounds(p.vec, p.vbounds)) + else if (p.vbounds && !in_bounds(p.vec, p.vbounds)) outside.push(p); else inside.push(p); }); // shunt outside ports into their bounds - outside.forEach(function(p) { + outside.forEach(p => { p.vec = clip(p.vec, p.vbounds); inside.push(p); }); // for all unplaced ports that share a bounds, evenly distribute them within those bounds. // assume that bounds are disjoint. - var boundses = {}, boundports = {}; - unplaced.forEach(function(p) { - var boundskey = p.abounds.map(function(x) { return x.toFixed(3); }).join(','); + const boundses = {}, boundports = {}; + unplaced.forEach(p => { + const boundskey = p.abounds.map(x => x.toFixed(3)).join(','); boundses[boundskey] = p.abounds; boundports[boundskey] = boundports[boundskey] || []; boundports[boundskey].push(p); }); - for(var b in boundports) { - var bounds = boundses[b], bports = boundports[b]; - if(bports.length === 1) - bports[0].vec = a_to_v((bounds[0] + bounds[1])/2); + for (const b in boundports) { + const bounds = boundses[b], bports = boundports[b]; + if (bports.length === 1) + bports[0].vec = a_to_v((bounds[0]+bounds[1])/2); else { - var slice = (bounds[1] - bounds[0]) / (boundports[b].length - 1); - boundports[b].forEach(function(p, i) { - p.vec = a_to_v(bounds[0] + i*slice); + const slice = (bounds[1]-bounds[0])/(boundports[b].length-1); + boundports[b].forEach((p, i) => { + p.vec = a_to_v(bounds[0]+i*slice); }); } } @@ -126,47 +127,46 @@ dc_graph.place_ports = function() { unplaced = []; // determine positions of all satisfied - inside.forEach(function(p) { - project_port(diagram, n, p); + inside.forEach(p => { + projectPort(diagram, n, p); }); // detect any existing collisions, unplace the one without edges or second one - for(var i = 0; i < inside.length; ++i) { - var x = inside[i]; - if(unplaced.includes(x)) + for (let i = 0; i < inside.length; ++i) { + const x = inside[i]; + if (unplaced.includes(x)) continue; - for(var j = i+1; j < inside.length; ++j) { - var y = inside[j]; - if(unplaced.includes(y)) + for (let j = i+1; j < inside.length; ++j) { + const y = inside[j]; + if (unplaced.includes(y)) continue; - if(!misses(x, y)) { - if(!x.edges.length) { + if (!misses(x, y)) { + if (!x.edges.length) { unplaced.push(x); continue; - } - else + } else unplaced.push(y); } } } - inside = inside.filter(function(p) { return !unplaced.includes(p); }); + inside = inside.filter(p => !unplaced.includes(p)); // place any remaining by trying random spots within the range until it misses all or we give up - var patience = _mode.patience(), maxdist = 0, maxvec; - while(unplaced.length) { - var p = unplaced[0]; + let patience = _mode.patience(), maxdist = 0, maxvec; + while (unplaced.length) { + const p = unplaced[0]; p.vec = a_to_v(rand_within(p.abounds[0], p.abounds[1])); - project_port(diagram, n, p); - var mindist = d3.min(inside, function(p2) { return distance(p, p2); }); - if(mindist > maxdist) { + projectPort(diagram, n, p); + const mindist = min(inside, p2 => distance(p, p2)); + if (mindist > maxdist) { maxdist = mindist; maxvec = p.vec; } - if(!patience-- || mindist > _mode.minDistance()) { - if(patience<0) { + if (!patience-- || mindist > _mode.minDistance()) { + if (patience < 0) { console.warn('ran out of patience placing a port'); p.vec = maxvec; - project_port(diagram, n, p); + projectPort(diagram, n, p); } inside.push(p); unplaced.shift(); @@ -175,19 +175,19 @@ dc_graph.place_ports = function() { } } } - }; - var _mode = { - parent: property(null).react(function(p) { - if(p) { + } + const _mode = { + parent: property(null).react(p => { + if (p) { p.on('receivedLayout.place-ports', received_layout); - } else if(_mode.parent()) + } else if (_mode.parent()) _mode.parent().on('receivedLayout.place-ports', null); }), // minimum distance between ports minDistance: property(20), // number of random places to try when resolving collision - patience: property(20) + patience: property(20), }; return _mode; -}; +} diff --git a/src/render_svg.js b/src/render_svg.js index e4c72ebb..8d6fe0a5 100644 --- a/src/render_svg.js +++ b/src/render_svg.js @@ -1,8 +1,23 @@ -dc_graph.render_svg = function() { - var _svg = null, _defs = null, _g = null, _nodeLayer = null, _edgeLayer = null; - var _animating = false; // do not refresh during animations - var _zoom; - var _renderer = {}; +import { select, selectAll } from 'd3-selection'; +import { zoom, zoomIdentity, zoomTransform } from 'd3-zoom'; +import { edgeArrow, placeArrowsOnSpline, unsurprisingOrient } from './arrows.js'; +import { identity, property } from './core.js'; +import { keyboard as keyboardMode } from './keyboard.js'; +import { + asBezier3, + fitShape, + inferShape, + isOneSegment, + shapeChanged, + splitBezierN, +} from './shape.js'; +import { compose, generatePath } from './utils.js'; + +export function renderSvg() { + let _svg = null, _defs = null, _g = null, _nodeLayer = null, _edgeLayer = null; + let _animating = false; // do not refresh during animations + let _zoom; + const _renderer = {}; _renderer.rendererType = function() { return 'svg'; @@ -11,43 +26,50 @@ dc_graph.render_svg = function() { _renderer.parent = property(null); _renderer.renderNode = _renderer._enterNode = function(nodeEnter) { - if(_renderer.parent().nodeTitle()) + if (_renderer.parent().nodeTitle()) nodeEnter.append('title'); - nodeEnter.each(infer_shape(_renderer.parent())); - _renderer.parent().forEachShape(nodeEnter, function(shape, node) { + nodeEnter.each(inferShape(_renderer.parent())); + _renderer.parent().forEachShape(nodeEnter, (shape, node) => { node.call(shape.create); }); return _renderer; }; _renderer.redrawNode = _renderer._updateNode = function(node) { - var changedShape = node.filter(shape_changed(_renderer.parent())); + const changedShape = node.filter(shapeChanged(_renderer.parent())); changedShape.selectAll('.node-outline,.node-fill').remove(); - changedShape.each(infer_shape(_renderer.parent())); - _renderer.parent().forEachShape(changedShape, function(shape, node) { + changedShape.each(inferShape(_renderer.parent())); + _renderer.parent().forEachShape(changedShape, (shape, node) => { node.call(shape.create); }); node.select('title') .text(_renderer.parent().nodeTitle.eval); - _renderer.parent().forEachContent(node, function(contentType, node) { + _renderer.parent().forEachContent(node, (contentType, node) => { node.call(contentType.update); - _renderer.parent().forEachShape(contentType.selectContent(node), function(shape, content) { + _renderer.parent().forEachShape(contentType.selectContent(node), (shape, content) => { content - .call(fit_shape(shape, _renderer.parent())); + .call(fitShape(shape, _renderer.parent())); }); }); - _renderer.parent().forEachShape(node, function(shape, node) { + // Ensure nodes without content also get their dimensions calculated + const nodesWithoutContent = node.filter(n => !_renderer.parent().nodeContent.eval(n)); + _renderer.parent().forEachShape(nodesWithoutContent, (shape, node) => { + node.call(fitShape(shape, _renderer.parent())); + }); + _renderer.parent().forEachShape(node, (shape, node) => { node.call(shape.update); }); node.select('.node-fill') - .attr({ - fill: compose(_renderer.parent().nodeFillScale() || identity, _renderer.parent().nodeFill.eval) - }); + .attr( + 'fill', + compose( + _renderer.parent().nodeFillScale() || identity, + _renderer.parent().nodeFill.eval, + ), + ); node.select('.node-outline') - .attr({ - stroke: _renderer.parent().nodeStroke.eval, - 'stroke-width': _renderer.parent().nodeStrokeWidth.eval, - 'stroke-dasharray': _renderer.parent().nodeStrokeDashArray.eval - }); + .attr('stroke', _renderer.parent().nodeStroke.eval) + .attr('stroke-width', _renderer.parent().nodeStrokeWidth.eval) + .attr('stroke-dasharray', _renderer.parent().nodeStrokeDashArray.eval); return _renderer; }; _renderer.redrawEdge = _renderer._updateEdge = function(edge, edgeArrows) { @@ -56,98 +78,127 @@ dc_graph.render_svg = function() { .attr('stroke-width', _renderer.parent().edgeStrokeWidth.eval) .attr('stroke-dasharray', _renderer.parent().edgeStrokeDashArray.eval); edgeArrows - .attr('marker-end', function(e) { - var name = _renderer.parent().edgeArrowhead.eval(e), - id = edgeArrow(_renderer.parent(), _renderer.parent().arrows(), e, 'head', name); - return id ? 'url(#' + id + ')' : null; + .attr('marker-end', e => { + const name = _renderer.parent().edgeArrowhead.eval(e), + id = edgeArrow( + _renderer.parent(), + _renderer.parent().arrows(), + e, + 'head', + name, + ); + return id ? `url(#${id})` : null; }) - .attr('marker-start', function(e) { - var name = _renderer.parent().edgeArrowtail.eval(e), - arrow_id = edgeArrow(_renderer.parent(), _renderer.parent().arrows(), e, 'tail', name); - return name ? 'url(#' + arrow_id + ')' : null; + .attr('marker-start', e => { + const name = _renderer.parent().edgeArrowtail.eval(e), + arrow_id = edgeArrow( + _renderer.parent(), + _renderer.parent().arrows(), + e, + 'tail', + name, + ); + return name ? `url(#${arrow_id})` : null; }) - .each(function(e) { - var fillEdgeStroke = _renderer.parent().edgeStroke.eval(e); - _renderer.selectAll('#' + _renderer.parent().arrowId(e, 'head')) + .each(e => { + const _fillEdgeStroke = _renderer.parent().edgeStroke.eval(e); + _renderer.selectAll(`#${_renderer.parent().arrowId(e, 'head')}`) .attr('fill', _renderer.parent().edgeStroke.eval(e)); - _renderer.selectAll('#' + _renderer.parent().arrowId(e, 'tail')) + _renderer.selectAll(`#${_renderer.parent().arrowId(e, 'tail')}`) .attr('fill', _renderer.parent().edgeStroke.eval(e)); }); }; _renderer.selectAllNodes = function(selector) { selector = selector || '.node'; - return _nodeLayer && _nodeLayer.selectAll(selector).filter(function(n) { - return !n.deleted; - }) || d3.selectAll('.foo-this-does-not-exist'); + return _nodeLayer && _nodeLayer.selectAll(selector).filter(n => !n.deleted) + || selectAll('.foo-this-does-not-exist'); }; _renderer.selectAllEdges = function(selector) { selector = selector || '.edge'; - return _edgeLayer && _edgeLayer.selectAll(selector).filter(function(e) { - return !e.deleted; - }) || d3.selectAll('.foo-this-does-not-exist'); + return _edgeLayer && _edgeLayer.selectAll(selector).filter(e => !e.deleted) + || selectAll('.foo-this-does-not-exist'); }; _renderer.selectAllDefs = function(selector) { - return _defs && _defs.selectAll(selector).filter(function(def) { - return !def.deleted; - }) || d3.selectAll('.foo-this-does-not-exist'); + return _defs && _defs.selectAll(selector).filter(def => !def.deleted) + || selectAll('.foo-this-does-not-exist'); }; _renderer.resize = function(w, h) { - if(_svg) { - _svg.attr('width', w || (_renderer.parent().width_is_automatic() ? '100%' : _renderer.parent().width())) - .attr('height', h || (_renderer.parent().height_is_automatic() ? '100%' : _renderer.parent().height())); + if (_svg) { + _svg.attr( + 'width', + w + || (_renderer.parent().width_is_automatic() + ? '100%' + : _renderer.parent().width()), + ) + .attr( + 'height', + h || (_renderer.parent().height_is_automatic() + ? '100%' + : _renderer.parent().height()), + ); } return _renderer; }; _renderer.rezoom = function(oldWidth, oldHeight, newWidth, newHeight) { - var scale = _zoom.scale(), translate = _zoom.translate(); - _zoom.scale(1).translate([0,0]); - var xDomain = _renderer.parent().x().domain(), yDomain = _renderer.parent().y().domain(); + const currentTransform = zoomTransform(_svg.node()); + const scale = currentTransform.k, translate = [currentTransform.x, currentTransform.y]; + _svg.call(_zoom.transform, zoomIdentity); + const xDomain = _renderer.parent().x().domain(), yDomain = _renderer.parent().y().domain(); _renderer.parent().x() - .domain([xDomain[0], xDomain[0] + (xDomain[1] - xDomain[0])*newWidth/oldWidth]) + .domain([xDomain[0], xDomain[0]+(xDomain[1]-xDomain[0])*newWidth/oldWidth]) .range([0, newWidth]); _renderer.parent().y() - .domain([yDomain[0], yDomain[0] + (yDomain[1] - yDomain[0])*newHeight/oldHeight]) + .domain([yDomain[0], yDomain[0]+(yDomain[1]-yDomain[0])*newHeight/oldHeight]) .range([0, newHeight]); - _zoom - .x(_renderer.parent().x()).y(_renderer.parent().y()) - .translate(translate).scale(scale); + // D3 v5: apply the transform directly instead of using .x()/.y() methods + _svg.call(_zoom.transform, zoomIdentity.translate(translate[0], translate[1]).scale(scale)); }; _renderer.globalTransform = function(pos, scale, animate) { // _translate = pos; // _scale = scale; - var obj = _g; - if(animate) + let obj = _g; + if (animate) obj = _g.transition().duration(_renderer.parent().zoomDuration()); - obj.attr('transform', 'translate(' + pos + ')' + ' scale(' + scale + ')'); + obj.attr('transform', `translate(${pos})`+` scale(${scale})`); }; _renderer.translate = function(_) { - if(!arguments.length) - return _zoom.translate(); - _zoom.translate(_); + if (!arguments.length) { + const transform = zoomTransform(_svg.node()); + return [transform.x, transform.y]; + } + const currentTransform = zoomTransform(_svg.node()); + _svg.call(_zoom.transform, zoomIdentity.translate(_[0], _[1]).scale(currentTransform.k)); return this; }; _renderer.scale = function(_) { - if(!arguments.length) - return _zoom ? _zoom.scale() : 1; - _zoom.scale(_); + if (!arguments.length) { + if (!_zoom) return 1; + const transform = zoomTransform(_svg.node()); + return transform.k; + } + const currentTransform = zoomTransform(_svg.node()); + _svg.call( + _zoom.transform, + zoomIdentity.translate(currentTransform.x, currentTransform.y).scale(_), + ); return this; }; - // argh _renderer.commitTranslateScale = function() { - _zoom.event(_svg); + return this; }; _renderer.zoom = function(_) { - if(!arguments.length) + if (!arguments.length) return _zoom; _zoom = _; // is this a good idea? return _renderer; @@ -155,129 +206,159 @@ dc_graph.render_svg = function() { _renderer.startRedraw = function(dispatch, wnodes, wedges) { // create edge SVG elements - var edge = _edgeLayer.selectAll('.edge') - .data(wedges, _renderer.parent().edgeKey.eval); - var edgeEnter = edge.enter().append('svg:path') - .attr({ - class: 'edge', - id: _renderer.parent().edgeId, - opacity: 0 - }) - .each(function(e) { - e.deleted = false; - }); - edge.exit().each(function(e) { + let edge = _edgeLayer.selectAll('.edge') + .data(wedges, _renderer.parent().edgeKey.eval); + + const edgeExit = edge.exit(); + edgeExit.each(e => { e.deleted = true; - }).transition() - .duration(_renderer.parent().stagedDuration()) - .delay(_renderer.parent().deleteDelay()) - .attr('opacity', 0) - .remove(); - - var edgeArrows = _edgeLayer.selectAll('.edge-arrows') - .data(wedges, _renderer.parent().edgeKey.eval); - var edgeArrowsEnter = edgeArrows.enter().append('svg:path') - .attr({ - class: 'edge-arrows', - id: function(d) { - return _renderer.parent().edgeId(d) + '-arrows'; - }, - fill: 'none', - opacity: 0 + }); + const duration = _renderer.parent().stagedDuration(); + if (duration === 0) { + edgeExit.remove(); + } else { + edgeExit.transition() + .duration(duration) + .delay(_renderer.parent().deleteDelay()) + .attr('opacity', 0) + .on('end', function() { + console.log('render_svg: transition end, removing edge element'); + select(this).remove(); }); - edgeArrows.exit().transition() + } + + // Handle enter selection + const edgeEnter = edge.enter().append('svg:path') + .attr('class', 'edge') + .attr('id', _renderer.parent().edgeId) + .attr('opacity', 0) + .each(e => { + e.deleted = false; + }); + + edge = edge.merge(edgeEnter); + + let edgeArrows = _edgeLayer.selectAll('.edge-arrows') + .data(wedges, _renderer.parent().edgeKey.eval); + const edgeArrowsEnter = edgeArrows.enter().append('svg:path') + .attr('class', 'edge-arrows') + .attr('id', d => `${_renderer.parent().edgeId(d)}-arrows`) + .attr('fill', 'none') + .attr('opacity', 0); + const edgeArrowsExit = edgeArrows.exit(); + edgeArrowsExit.transition() .duration(_renderer.parent().stagedDuration()) .delay(_renderer.parent().deleteDelay()) .attr('opacity', 0) - .remove() - .each('end.delarrow', function(e) { + .on('end', function(e) { edgeArrow(_renderer.parent(), _renderer.parent().arrows(), e, 'head', null); edgeArrow(_renderer.parent(), _renderer.parent().arrows(), e, 'tail', null); + select(this).remove(); }); + if (_renderer.parent().stagedDuration() === 0) { + edgeArrowsExit.remove(); + } + edgeArrows = edgeArrows.merge(edgeArrowsEnter); - if(_renderer.parent().edgeSort()) { - edge.sort(function(a, b) { - var as = _renderer.parent().edgeSort.eval(a), bs = _renderer.parent().edgeSort.eval(b); + if (_renderer.parent().edgeSort()) { + edge.sort((a, b) => { + const as = _renderer.parent().edgeSort.eval(a), + bs = _renderer.parent().edgeSort.eval(b); return as < bs ? -1 : bs < as ? 1 : 0; }); } // another wider copy of the edge just for hover events - var edgeHover = _edgeLayer.selectAll('.edge-hover') - .data(wedges, _renderer.parent().edgeKey.eval); - var edgeHoverEnter = edgeHover.enter().append('svg:path') + let edgeHover = _edgeLayer.selectAll('.edge-hover') + .data(wedges, _renderer.parent().edgeKey.eval); + const edgeHoverEnter = edgeHover.enter().append('svg:path') .attr('class', 'edge-hover') .attr('opacity', 0) .attr('fill', 'none') .attr('stroke', 'green') .attr('stroke-width', 10) - .on('mouseover.diagram', function(e) { - _renderer.select('#' + _renderer.parent().edgeId(e) + '-label') + .on('mouseover.diagram', e => { + _renderer.select(`#${_renderer.parent().edgeId(e)}-label`) .attr('visibility', 'visible'); }) - .on('mouseout.diagram', function(e) { - _renderer.select('#' + _renderer.parent().edgeId(e) + '-label') + .on('mouseout.diagram', e => { + _renderer.select(`#${_renderer.parent().edgeId(e)}-label`) .attr('visibility', 'hidden'); }); edgeHover.exit().remove(); + edgeHover = edgeHover.merge(edgeHoverEnter); - var edgeLabels = _edgeLayer.selectAll('g.edge-label-wrapper') + let edgeLabels = _edgeLayer.selectAll('g.edge-label-wrapper') .data(wedges, _renderer.parent().edgeKey.eval); - var edgeLabelsEnter = edgeLabels.enter() + const edgeLabelsEnter = edgeLabels.enter() .append('g') - .attr('class', 'edge-label-wrapper') - .attr('visibility', 'hidden') - .attr('id', function(e) { - return _renderer.parent().edgeId(e) + '-label'; - }); - var textPaths = _defs.selectAll('path.edge-label-path') - .data(wedges, _renderer.parent().textpathId); - var textPathsEnter = textPaths.enter() - .append('svg:path').attr({ - class: 'edge-label-path', - id: _renderer.parent().textpathId - }); - edgeLabels.exit().transition() + .attr('class', 'edge-label-wrapper') + .attr('visibility', 'hidden') + .attr('id', e => `${_renderer.parent().edgeId(e)}-label`); + const edgeLabelsExit = edgeLabels.exit(); + edgeLabelsExit.transition() .duration(_renderer.parent().stagedDuration()) .delay(_renderer.parent().deleteDelay()) - .attr('opacity', 0).remove(); + .attr('opacity', 0) + .on('end', function() { + select(this).remove(); + }); + if (_renderer.parent().stagedDuration() === 0) { + edgeLabelsExit.remove(); + } + edgeLabels = edgeLabels.merge(edgeLabelsEnter); + + let textPaths = _defs.selectAll('path.edge-label-path') + .data(wedges, _renderer.parent().textpathId); + const textPathsEnter = textPaths.enter() + .append('svg:path') + .attr('class', 'edge-label-path') + .attr('id', _renderer.parent().textpathId); + textPaths.exit().remove(); + textPaths = textPaths.merge(textPathsEnter); // create node SVG elements - var node = _nodeLayer.selectAll('.node') - .data(wnodes, _renderer.parent().nodeKey.eval); - var nodeEnter = node.enter().append('g') - .attr('class', 'node') - .attr('opacity', '0') // don't show until has layout - .each(function(n) { + let node = _nodeLayer.selectAll('.node') + .data(wnodes, _renderer.parent().nodeKey.eval); + const nodeEnter = node.enter().append('g') + .attr('class', 'node') + .attr('opacity', '0') // don't show until has layout + .each(n => { n.deleted = false; }); - // .call(_d3cola.drag); - - _renderer.renderNode(nodeEnter); - - node.exit().each(function(n) { + const nodeExit = node.exit().each(n => { n.deleted = true; - }).transition() + }); + nodeExit.transition() .duration(_renderer.parent().stagedDuration()) .delay(_renderer.parent().deleteDelay()) .attr('opacity', 0) - .remove(); - - dispatch.drawn(node, edge, edgeHover); - - var drawState = { - node: node, - nodeEnter: nodeEnter, - edge: edge, - edgeEnter: edgeEnter, - edgeHover: edgeHover, - edgeHoverEnter: edgeHoverEnter, - edgeLabels: edgeLabels, - edgeLabelsEnter: edgeLabelsEnter, - edgeArrows: edgeArrows, - edgeArrowsEnter: edgeArrowsEnter, - textPaths: textPaths, - textPathsEnter: textPathsEnter + .on('end', function() { + select(this).remove(); + }); + if (_renderer.parent().stagedDuration() === 0) { + nodeExit.remove(); + } + node = node.merge(nodeEnter); + // .call(_d3cola.drag); + + _renderer.renderNode(nodeEnter); + + dispatch.call('drawn', null, node, edge, edgeHover); + + const drawState = { + node, + nodeEnter, + edge, + edgeEnter, + edgeHover, + edgeHoverEnter, + edgeLabels, + edgeLabelsEnter, + edgeArrows, + edgeArrowsEnter, + textPaths, + textPathsEnter, }; _refresh(drawState); @@ -292,279 +373,350 @@ dc_graph.render_svg = function() { } _renderer.refresh = function(node, edge, edgeHover, edgeLabels, textPaths) { - if(_animating) + if (_animating) return this; // but what about changed attributes? node = node || _renderer.selectAllNodes(); edge = edge || _renderer.selectAllEdges(); - var edgeArrows = _renderer.selectAllEdges('.edge-arrows'); - _refresh({node: node, edge: edge, edgeArrows: edgeArrows}); + const edgeArrows = _renderer.selectAllEdges('.edge-arrows'); + _refresh({node, edge, edgeArrows}); edgeHover = edgeHover || _renderer.selectAllEdges('.edge-hover'); edgeLabels = edgeLabels || _renderer.selectAllEdges('.edge-label-wrapper'); textPaths = textPaths || _renderer.selectAllDefs('path.edge-label-path'); - var nullSel = d3.select(null); // no enters - draw(node, nullSel, edge, nullSel, edgeHover, nullSel, edgeLabels, nullSel, edgeArrows, nullSel, textPaths, nullSel, false); + const nullSel = select(null); // no enters + draw( + node, + nullSel, + edge, + nullSel, + edgeHover, + nullSel, + edgeLabels, + nullSel, + edgeArrows, + nullSel, + textPaths, + nullSel, + false, + ); return this; }; _renderer.reposition = function(node, edge) { node - .attr('transform', function (n) { - return 'translate(' + n.cola.x + ',' + n.cola.y + ')'; - }); + .attr('transform', n => `translate(${n.cola.x},${n.cola.y})`); // reset edge ports - edge.each(function(e) { + edge.each(e => { e.pos.new = null; e.pos.old = null; e.cola.points = null; - _renderer.parent().calcEdgePath(e, 'new', e.source.cola.x, e.source.cola.y, e.target.cola.x, e.target.cola.y); - if(_renderer.parent().edgeArrowhead.eval(e)) - _renderer.select('#' + _renderer.parent().arrowId(e, 'head')) - .attr('orient', function() { - return e.pos.new.orienthead; - }); - if(_renderer.parent().edgeArrowtail.eval(e)) - _renderer.select('#' + _renderer.parent().arrowId(e, 'tail')) - .attr('orient', function() { - return e.pos.new.orienttail; - }); - _renderer.select('#' + _renderer.parent().edgeId(e) + '-arrows') + _renderer.parent().calcEdgePath( + e, + 'new', + e.source.cola.x, + e.source.cola.y, + e.target.cola.x, + e.target.cola.y, + ); + if (_renderer.parent().edgeArrowhead.eval(e)) + _renderer.select(`#${_renderer.parent().arrowId(e, 'head')}`) + .attr('orient', () => e.pos.new.orienthead); + if (_renderer.parent().edgeArrowtail.eval(e)) + _renderer.select(`#${_renderer.parent().arrowId(e, 'tail')}`) + .attr('orient', () => e.pos.new.orienttail); + _renderer.select(`#${_renderer.parent().edgeId(e)}-arrows`) .attr('d', generate_edge_path('new', true)); - }) .attr('d', generate_edge_path('new')); return this; }; function generate_edge_path(age, full) { - var field = full ? 'full' : 'path'; + const field = full ? 'full' : 'path'; return function(e) { - var path = e.pos[age][field]; - return generate_path(path.points, path.bezDegree); + const path = e.pos?.[age]?.[field]; + if (!path) return ''; + return generatePath(path.points, path.bezDegree); }; - }; + } function generate_edge_label_path(age) { return function(e) { - var path = e.pos[age].path; - var points = path.points[path.points.length-1].x < path.points[0].x ? - path.points.slice(0).reverse() : path.points; - return generate_path(points, path.bezDegree); + const path = e.pos?.[age]?.path; + if (!path) return ''; + const points = path.points[path.points.length-1].x < path.points[0].x + ? path.points.slice(0).reverse() + : path.points; + return generatePath(points, path.bezDegree); }; - }; + } function with_rad(f) { return function() { - return f.apply(this, arguments) + 'rad'; + return `${f.apply(this, arguments)}rad`; }; } function unsurprising_orient_rad(oldorient, neworient) { - return with_rad(unsurprising_orient)(oldorient, neworient); - } + return with_rad(unsurprisingOrient)(oldorient, neworient); + } function has_source_and_target(e) { return !!e.source && !!e.target; } _renderer.draw = function(drawState, animatePositions) { - draw(drawState.node, drawState.nodeEnter, - drawState.edge, drawState.edgeEnter, - drawState.edgeHover, drawState.edgeHoverEnter, - drawState.edgeLabels, drawState.edgeLabelsEnter, - drawState.edgeArrows, drawState.edgeArrowsEnter, - drawState.textPaths, drawState.textPathsEnter, - animatePositions); + draw( + drawState.node, + drawState.nodeEnter, + drawState.edge, + drawState.edgeEnter, + drawState.edgeHover, + drawState.edgeHoverEnter, + drawState.edgeLabels, + drawState.edgeLabelsEnter, + drawState.edgeArrows, + drawState.edgeArrowsEnter, + drawState.textPaths, + drawState.textPathsEnter, + animatePositions, + ); }; - function draw(node, nodeEnter, edge, edgeEnter, edgeHover, edgeHoverEnter, - edgeLabels, edgeLabelsEnter, edgeArrows, edgeArrowsEnter, - textPaths, textPathsEnter, animatePositions) { + function draw( + node, + nodeEnter, + edge, + edgeEnter, + edgeHover, + edgeHoverEnter, + edgeLabels, + edgeLabelsEnter, + edgeArrows, + edgeArrowsEnter, + textPaths, + textPathsEnter, + animatePositions, + ) { console.assert(edge.data().every(has_source_and_target)); - var nodeEntered = {}; + const nodeEntered = {}; nodeEnter - .each(function(n) { + .each(n => { nodeEntered[_renderer.parent().nodeKey.eval(n)] = true; }) - .attr('transform', function (n) { + .attr('transform', n => // start new nodes at their final position - return 'translate(' + n.cola.x + ',' + n.cola.y + ')'; - }); - var ntrans = node - .transition() - .duration(_renderer.parent().stagedDuration()) - .delay(function(n) { - return _renderer.parent().stagedDelay(nodeEntered[_renderer.parent().nodeKey.eval(n)]); - }) - .attr('opacity', _renderer.parent().nodeOpacity.eval); - if(animatePositions) + `translate(${n.cola.x},${n.cola.y})`); + const ntrans = node + .transition() + .duration(_renderer.parent().stagedDuration()) + .delay(n => + _renderer.parent().stagedDelay(nodeEntered[_renderer.parent().nodeKey.eval(n)]) + ) + .attr('opacity', _renderer.parent().nodeOpacity.eval); + if (animatePositions) ntrans - .attr('transform', function (n) { - return 'translate(' + n.cola.x + ',' + n.cola.y + ')'; - }) - .each('end.record', function(n) { + .attr('transform', n => `translate(${n.cola.x},${n.cola.y})`) + .on('end.record', n => { n.prevX = n.cola.x; n.prevY = n.cola.y; }); // recalculate edge positions - edge.each(function(e) { + edge.each(e => { e.pos.new = null; }); - edge.each(function(e) { - if(e.cola.points) { - e.pos.new = place_arrows_on_spline(_renderer.parent(), e, e.cola.points); - } - else { - if(!e.pos.old) - _renderer.parent().calcEdgePath(e, 'old', e.source.prevX || e.source.cola.x, e.source.prevY || e.source.cola.y, - e.target.prevX || e.target.cola.x, e.target.prevY || e.target.cola.y); - if(!e.pos.new) - _renderer.parent().calcEdgePath(e, 'new', e.source.cola.x, e.source.cola.y, e.target.cola.x, e.target.cola.y); + edge.each(e => { + if (e.cola.points) { + e.pos.new = placeArrowsOnSpline(_renderer.parent(), e, e.cola.points); + } else { + if (!e.pos.old) + _renderer.parent().calcEdgePath( + e, + 'old', + e.source.prevX || e.source.cola.x, + e.source.prevY || e.source.cola.y, + e.target.prevX || e.target.cola.x, + e.target.prevY || e.target.cola.y, + ); + if (!e.pos.new) + _renderer.parent().calcEdgePath( + e, + 'new', + e.source.cola.x, + e.source.cola.y, + e.target.cola.x, + e.target.cola.y, + ); } - if(e.pos.old) { - if(e.pos.old.path.bezDegree !== e.pos.new.path.bezDegree || - e.pos.old.path.points.length !== e.pos.new.path.points.length) { - //console.log('old', e.pos.old.path.points.length, 'new', e.pos.new.path.points.length); - if(is_one_segment(e.pos.old.path)) { - e.pos.new.path.points = as_bezier3(e.pos.new.path); - e.pos.old.path.points = split_bezier_n(as_bezier3(e.pos.old.path), - (e.pos.new.path.points.length-1)/3); + if (e.pos.old) { + if ( + e.pos.old.path.bezDegree !== e.pos.new.path.bezDegree + || e.pos.old.path.points.length !== e.pos.new.path.points.length + ) { + // console.log('old', e.pos.old.path.points.length, 'new', e.pos.new.path.points.length); + if (isOneSegment(e.pos.old.path)) { + e.pos.new.path.points = asBezier3(e.pos.new.path); + e.pos.old.path.points = splitBezierN( + asBezier3(e.pos.old.path), + (e.pos.new.path.points.length-1)/3, + ); e.pos.old.path.bezDegree = e.pos.new.bezDegree = 3; - } - else if(is_one_segment(e.pos.new.path)) { - e.pos.old.path.points = as_bezier3(e.pos.old.path); - e.pos.new.path.points = split_bezier_n(as_bezier3(e.pos.new.path), - (e.pos.old.path.points.length-1)/3); + } else if (isOneSegment(e.pos.new.path)) { + e.pos.old.path.points = asBezier3(e.pos.old.path); + e.pos.new.path.points = splitBezierN( + asBezier3(e.pos.new.path), + (e.pos.old.path.points.length-1)/3, + ); e.pos.old.path.bezDegree = e.pos.new.bezDegree = 3; - } - else console.warn("don't know how to interpolate two multi-segments"); + } else console.warn("don't know how to interpolate two multi-segments"); } - } - else + } else e.pos.old = e.pos.new; }); - var edgeEntered = {}; + const edgeEntered = {}; edgeEnter - .each(function(e) { + .each(e => { edgeEntered[_renderer.parent().edgeKey.eval(e)] = true; }) - .attr('d', generate_edge_path(_renderer.parent().stageTransitions() === 'modins' ? 'new' : 'old')); + .attr( + 'd', + generate_edge_path( + _renderer.parent().stageTransitions() === 'modins' ? 'new' : 'old', + ), + ); edgeArrowsEnter - .each(function(e) { + .each(e => { // if staging transitions, just fade new edges in at new position // else start new edges at old positions of nodes, if any, else new positions - var age = _renderer.parent().stageTransitions() === 'modins' ? 'new' : 'old'; - if(_renderer.parent().edgeArrowhead.eval(e)) - _renderer.select('#' + _renderer.parent().arrowId(e, 'head')) - .attr('orient', function() { - return e.pos[age].orienthead; - }); - if(_renderer.parent().edgeArrowtail.eval(e)) - _renderer.select('#' + _renderer.parent().arrowId(e, 'tail')) - .attr('orient', function() { - return e.pos[age].orienttail; - }); + const age = _renderer.parent().stageTransitions() === 'modins' ? 'new' : 'old'; + if (_renderer.parent().edgeArrowhead.eval(e)) + _renderer.select(`#${_renderer.parent().arrowId(e, 'head')}`) + .attr('orient', () => e.pos[age].orienthead); + if (_renderer.parent().edgeArrowtail.eval(e)) + _renderer.select(`#${_renderer.parent().arrowId(e, 'tail')}`) + .attr('orient', () => e.pos[age].orienttail); }) - .attr('d', generate_edge_path(_renderer.parent().stageTransitions() === 'modins' ? 'new' : 'old', true)); + .attr( + 'd', + generate_edge_path( + _renderer.parent().stageTransitions() === 'modins' ? 'new' : 'old', + true, + ), + ); edgeArrows - .each(function(e) { - if(_renderer.parent().edgeArrowhead.eval(e)) - _renderer.select('#' + _renderer.parent().arrowId(e, 'head')) - .attr('orient', unsurprising_orient_rad(e.pos.old.orienthead, e.pos.new.orienthead)) - .transition().duration(_renderer.parent().stagedDuration()) - .delay(_renderer.parent().stagedDelay(false)) - .attr('orient', function() { - return e.pos.new.orienthead; - }); - if(_renderer.parent().edgeArrowtail.eval(e)) - _renderer.select('#' + _renderer.parent().arrowId(e, 'tail')) - .attr('orient', unsurprising_orient_rad(e.pos.old.orienttail, e.pos.new.orienttail)) - .transition().duration(_renderer.parent().stagedDuration()) - .delay(_renderer.parent().stagedDelay(false)) - .attr('orient', function() { - return e.pos.new.orienttail; - }); + .each(e => { + if (_renderer.parent().edgeArrowhead.eval(e)) + _renderer.select(`#${_renderer.parent().arrowId(e, 'head')}`) + .attr( + 'orient', + unsurprising_orient_rad(e.pos.old.orienthead, e.pos.new.orienthead), + ) + .transition().duration(_renderer.parent().stagedDuration()) + .delay(_renderer.parent().stagedDelay(false)) + .attr('orient', () => e.pos.new.orienthead); + if (_renderer.parent().edgeArrowtail.eval(e)) + _renderer.select(`#${_renderer.parent().arrowId(e, 'tail')}`) + .attr( + 'orient', + unsurprising_orient_rad(e.pos.old.orienttail, e.pos.new.orienttail), + ) + .transition().duration(_renderer.parent().stagedDuration()) + .delay(_renderer.parent().stagedDelay(false)) + .attr('orient', () => e.pos.new.orienttail); }); - var etrans = edge - .transition() - .duration(_renderer.parent().stagedDuration()) - .delay(function(e) { - return _renderer.parent().stagedDelay(edgeEntered[_renderer.parent().edgeKey.eval(e)]); - }) - .attr('opacity', _renderer.parent().edgeOpacity.eval); - var arrowtrans = edgeArrows - .transition() - .duration(_renderer.parent().stagedDuration()) - .delay(function(e) { - return _renderer.parent().stagedDelay(edgeEntered[_renderer.parent().edgeKey.eval(e)]); - }) - .attr('opacity', _renderer.parent().edgeOpacity.eval); + let etrans = edge + .transition() + .duration(_renderer.parent().stagedDuration()) + .delay(e => + _renderer.parent().stagedDelay(edgeEntered[_renderer.parent().edgeKey.eval(e)]) + ) + .attr('opacity', _renderer.parent().edgeOpacity.eval); + const arrowtrans = edgeArrows + .transition() + .duration(_renderer.parent().stagedDuration()) + .delay(e => + _renderer.parent().stagedDelay(edgeEntered[_renderer.parent().edgeKey.eval(e)]) + ) + .attr('opacity', _renderer.parent().edgeOpacity.eval); (animatePositions ? etrans : edge) - .attr('d', function(e) { - var when = _renderer.parent().stageTransitions() === 'insmod' && - edgeEntered[_renderer.parent().edgeKey.eval(e)] ? 'old' : 'new'; + .attr('d', e => { + const when = _renderer.parent().stageTransitions() === 'insmod' + && edgeEntered[_renderer.parent().edgeKey.eval(e)] + ? 'old' + : 'new'; return generate_edge_path(when)(e); }); (animatePositions ? arrowtrans : edgeArrows) - .attr('d', function(e) { - var when = _renderer.parent().stageTransitions() === 'insmod' && - edgeEntered[_renderer.parent().edgeKey.eval(e)] ? 'old' : 'new'; + .attr('d', e => { + const when = _renderer.parent().stageTransitions() === 'insmod' + && edgeEntered[_renderer.parent().edgeKey.eval(e)] + ? 'old' + : 'new'; return generate_edge_path(when, true)(e); }); - var elabels = edgeLabels - .selectAll('text').data(function(e) { - var labels = _renderer.parent().edgeLabel.eval(e); - if(!labels) + const elabels = edgeLabels + .selectAll('text').data(e => { + const labels = _renderer.parent().edgeLabel.eval(e); + if (!labels) return []; - else if(typeof labels === 'string') + else if (typeof labels === 'string') return [labels]; else return labels; }); elabels.enter() - .append('text') - .attr({ - 'class': 'edge-label', - 'text-anchor': 'middle', - dy: function(_, i) { - return i * _renderer.parent().edgeLabelSpacing.eval(this.parentNode) -2; - } + .append('text') + .attr('class', 'edge-label') + .attr('text-anchor', 'middle') + .attr('dy', function(_, i) { + return i*_renderer.parent().edgeLabelSpacing.eval(this.parentNode)-2; }) - .append('textPath') + .append('textPath') .attr('startOffset', '50%'); elabels - .select('textPath') - .html(function(t) { return t; }) + .select('textPath') + .html(t => t) .attr('opacity', function() { - return _renderer.parent().edgeOpacity.eval(d3.select(this.parentNode.parentNode).datum()); + return _renderer.parent().edgeOpacity.eval( + select(this.parentNode.parentNode).datum(), + ); }) - .attr('xlink:href', function(e) { - var id = _renderer.parent().textpathId(d3.select(this.parentNode.parentNode).datum()); + .attr('xlink:href', function(_e) { + const id = _renderer.parent().textpathId( + select(this.parentNode.parentNode).datum(), + ); // angular on firefox needs absolute paths for fragments - return window.location.href.split('#')[0] + '#' + id; + return `${window.location.href.split('#')[0]}#${id}`; }); textPathsEnter - .attr('d', generate_edge_label_path(_renderer.parent().stageTransitions() === 'modins' ? 'new' : 'old')); - var textTrans = textPaths.transition() + .attr( + 'd', + generate_edge_label_path( + _renderer.parent().stageTransitions() === 'modins' ? 'new' : 'old', + ), + ); + let textTrans = textPaths.transition() .duration(_renderer.parent().stagedDuration()) - .delay(function(e) { - return _renderer.parent().stagedDelay(edgeEntered[_renderer.parent().edgeKey.eval(e)]); - }); - if(animatePositions) + .delay(e => + _renderer.parent().stagedDelay(edgeEntered[_renderer.parent().edgeKey.eval(e)]) + ); + if (animatePositions) textTrans - .attr('d', function(e) { - var when = _renderer.parent().stageTransitions() === 'insmod' && - edgeEntered[_renderer.parent().edgeKey.eval(e)] ? 'old' : 'new'; - return generate_edge_label_path(when)(e); - }); - if(_renderer.parent().stageTransitions() === 'insmod' && animatePositions) { + .attr('d', e => { + const when = _renderer.parent().stageTransitions() === 'insmod' + && edgeEntered[_renderer.parent().edgeKey.eval(e)] + ? 'old' + : 'new'; + return generate_edge_label_path(when)(e); + }); + if (_renderer.parent().stageTransitions() === 'insmod' && animatePositions) { // inserted edges transition twice in insmod mode - if(_renderer.parent().stagedDuration() >= 50) { + if (_renderer.parent().stagedDuration() >= 50) { etrans = etrans.transition() .duration(_renderer.parent().stagedDuration()) .attr('d', generate_edge_path('new')); @@ -591,17 +743,16 @@ dc_graph.render_svg = function() { // signal layout done when all transitions complete // because otherwise client might start another layout and lock the processor _animating = true; - if(!_renderer.parent().showLayoutSteps()) - endall([ntrans, etrans, textTrans], - function() { - _animating = false; - _renderer.parent().layoutDone(true); - }); - - if(animatePositions) + if (!_renderer.parent().showLayoutSteps()) + endall([ntrans, etrans, textTrans], () => { + _animating = false; + _renderer.parent().layoutDone(true); + }); + + if (animatePositions) edgeHover.attr('d', generate_edge_path('new')); - edge.each(function(e) { + edge.each(e => { e.pos.old = e.pos.new; }); } @@ -609,13 +760,17 @@ dc_graph.render_svg = function() { // wait on multiple transitions, adapted from // http://stackoverflow.com/questions/10692100/invoke-a-callback-at-the-end-of-a-transition function endall(transitions, callback) { - if (transitions.every(function(transition) { return transition.size() === 0; })) + if (transitions.every(transition => transition.size() === 0)) callback(); - var n = 0; - transitions.forEach(function(transition) { + let n = 0; + transitions.forEach(transition => { transition - .each(function() { ++n; }) - .each('end.all', function() { if (!--n) callback(); }); + .each(() => { + ++n; + }) + .on('end.all', () => { + if (!--n) callback(); + }); }); } @@ -623,23 +778,24 @@ dc_graph.render_svg = function() { return !!_svg; }; - _renderer.initializeDrawing = function () { + _renderer.initializeDrawing = function() { _renderer.resetSvg(); - _g = _svg.append('g') + _g = _svg.selectAll('g.draw') + .data([1]) + .enter().append('g') .attr('class', 'draw'); - var layers = ['edge-layer', 'node-layer']; - if(_renderer.parent().edgesInFront()) + const layers = ['edge-layer', 'node-layer']; + if (_renderer.parent().edgesInFront()) layers.reverse(); _g.selectAll('g').data(layers) - .enter().append('g') - .attr('class', function(l) { return l; }); + .enter().append('g') + .attr('class', l => l); _edgeLayer = _g.selectAll('g.edge-layer'); _nodeLayer = _g.selectAll('g.node-layer'); return this; }; - /** * Standard dc.js * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin} @@ -656,8 +812,8 @@ dc_graph.render_svg = function() { * @param {String} [selector] * @return {d3.selection} * @return {dc_graph.diagram} - **/ - _renderer.select = function (s) { + */ + _renderer.select = function(s) { return _renderer.parent().root().select(s); }; @@ -679,38 +835,44 @@ dc_graph.render_svg = function() { * @param {String} [selector] * @return {d3.selection} * @return {dc_graph.diagram} - **/ - _renderer.selectAll = function (s) { + */ + _renderer.selectAll = function(s) { return _renderer.parent().root() ? _renderer.parent().root().selectAll(s) : null; }; _renderer.selectNodePortsOfStyle = function(node, style) { - return node.selectAll('g.port').filter(function(p) { - return _renderer.parent().portStyleName.eval(p) === style; - }); + return node.selectAll('g.port').filter(p => + _renderer.parent().portStyleName.eval(p) === style + ); }; _renderer.drawPorts = function(drawState) { - var nodePorts = _renderer.parent().nodePorts(); - if(!nodePorts) + const nodePorts = _renderer.parent().nodePorts(); + if (!nodePorts) return; - _renderer.parent().portStyle.enum().forEach(function(style) { - var nodePorts2 = {}; - for(var nid in nodePorts) - nodePorts2[nid] = nodePorts[nid].filter(function(p) { - return _renderer.parent().portStyleName.eval(p) === style; - }); - var port = _renderer.selectNodePortsOfStyle(drawState.node, style); + _renderer.parent().portStyle.enum().forEach(style => { + const nodePorts2 = {}; + for (const nid in nodePorts) + nodePorts2[nid] = nodePorts[nid].filter(p => + _renderer.parent().portStyleName.eval(p) === style + ); + const port = _renderer.selectNodePortsOfStyle(drawState.node, style); _renderer.parent().portStyle(style).drawPorts(port, nodePorts2, drawState.node); }); }; _renderer.fireTSEvent = function(dispatch, drawState) { - dispatch.transitionsStarted(drawState.node, drawState.edge, drawState.edgeHover); + dispatch.call( + 'transitionsStarted', + null, + drawState.node, + drawState.edge, + drawState.edgeHover, + ); }; _renderer.calculateBounds = function(drawState) { - if(!drawState.node.size()) + if (!drawState.node.size()) return null; return _renderer.parent().calculateBounds(drawState.node.data(), drawState.edge.data()); }; @@ -726,8 +888,8 @@ dc_graph.render_svg = function() { * @param {d3.selection} [selection] * @return {d3.selection} * @return {dc_graph.diagram} - **/ - _renderer.svg = function (_) { + */ + _renderer.svg = function(_) { if (!arguments.length) { return _svg; } @@ -748,7 +910,7 @@ dc_graph.render_svg = function() { * @return {dc_graph.diagram} **/ - _renderer.g = function (_) { + _renderer.g = function(_) { if (!arguments.length) { return _g; } @@ -756,7 +918,6 @@ dc_graph.render_svg = function() { return _renderer; }; - /** * Standard dc.js * {@link https://github.com/dc-js/dc.js/blob/develop/web/docs/api-latest.md#dc.baseMixin baseMixin} @@ -766,109 +927,100 @@ dc_graph.render_svg = function() { * @memberof dc_graph.diagram * @instance * @return {dc_graph.diagram} - **/ - _renderer.resetSvg = function () { + */ + _renderer.resetSvg = function() { // we might be re-initialized in a div, in which case // we already have an element to delete - var svg = _svg || _renderer.select('svg'); + const svg = _svg || _renderer.select('svg'); svg.remove(); _svg = null; - //_renderer.parent().x(null).y(null); + // _renderer.parent().x(null).y(null); return generateSvg(); }; _renderer.addOrRemoveDef = function(id, whether, tag, onEnter) { - var data = whether ? [0] : []; - var sel = _defs.selectAll('#' + id).data(data); + const data = whether ? [0] : []; + const sel = _defs.selectAll(`#${id}`).data(data); - var selEnter = sel + const selEnter = sel .enter().append(tag) - .attr('id', id); - if(selEnter.size() && onEnter) + .attr('id', id); + if (selEnter.size() && onEnter) selEnter.call(onEnter); sel.exit().remove(); - return sel; + return sel.merge(selEnter); }; - function enableZoom() { - _svg.call(_zoom); - _svg.on('dblclick.zoom', null); - } - function disableZoom() { - _svg.on('.zoom', null); - } - function generateSvg() { - _svg = _renderer.parent().root().append('svg'); + const root = _renderer.parent().root(); + _svg = root.selectAll('svg') + .data([1]) + .enter().append('svg'); _renderer.resize(); - _defs = _svg.append('svg:defs'); + _defs = _svg.selectAll('defs') + .data([1]) + .enter().append('svg:defs'); // for lack of a better place - _renderer.addOrRemoveDef('node-clip-top', true, 'clipPath', function(clipPath) { + _renderer.addOrRemoveDef('node-clip-top', true, 'clipPath', clipPath => { clipPath.selectAll('rect').data([0]) - .enter().append('rect').attr({ - x: -1000, - y: -1000, - width: 2000, - height: 1000 - }); + .enter().append('rect') + .attr('x', -1000) + .attr('y', -1000) + .attr('width', 2000) + .attr('height', 1000); }); - _renderer.addOrRemoveDef('node-clip-bottom', true, 'clipPath', function(clipPath) { + _renderer.addOrRemoveDef('node-clip-bottom', true, 'clipPath', clipPath => { clipPath.selectAll('rect').data([0]) - .enter().append('rect').attr({ - x: -1000, - y: 0, - width: 2000, - height: 1000 - }); + .enter().append('rect') + .attr('x', -1000) + .attr('y', 0) + .attr('width', 2000) + .attr('height', 1000); }); - _renderer.addOrRemoveDef('node-clip-left', true, 'clipPath', function(clipPath) { + _renderer.addOrRemoveDef('node-clip-left', true, 'clipPath', clipPath => { clipPath.selectAll('rect').data([0]) - .enter().append('rect').attr({ - x: -1000, - y: -1000, - width: 1000, - height: 2000 - }); + .enter().append('rect') + .attr('x', -1000) + .attr('y', -1000) + .attr('width', 1000) + .attr('height', 2000); }); - _renderer.addOrRemoveDef('node-clip-right', true, 'clipPath', function(clipPath) { + _renderer.addOrRemoveDef('node-clip-right', true, 'clipPath', clipPath => { clipPath.selectAll('rect').data([0]) - .enter().append('rect').attr({ - x: 0, - y: -1000, - width: 1000, - height: 2000 - }); + .enter().append('rect') + .attr('x', 0) + .attr('y', -1000) + .attr('width', 1000) + .attr('height', 2000); }); - _renderer.addOrRemoveDef('node-clip-none', true, 'clipPath', function(clipPath) { + _renderer.addOrRemoveDef('node-clip-none', true, 'clipPath', clipPath => { clipPath.selectAll('rect').data([0]) - .enter().append('rect').attr({ - x: 0, - y: 0, - width: 0, - height: 0 - }); + .enter().append('rect') + .attr('x', 0) + .attr('y', 0) + .attr('width', 0) + .attr('height', 0); }); - _zoom = d3.behavior.zoom() + _zoom = zoom() .on('zoom.diagram', _renderer.parent().doZoom) - .x(_renderer.parent().x()).y(_renderer.parent().y()) .scaleExtent(_renderer.parent().zoomExtent()); - if(_renderer.parent().mouseZoomable()) { - var mod, mods; - var brush = _renderer.parent().child('brush'); - var keyboard = _renderer.parent().child('keyboard'); - if(!keyboard) - _renderer.parent().child('keyboard', keyboard = dc_graph.keyboard()); - var modkeyschanged = function() { - if(keyboard.modKeysMatch(_renderer.parent().modKeyZoom())) - enableZoom(); - else - disableZoom(); - }; - keyboard.on('modkeyschanged.zoom', modkeyschanged); - modkeyschanged(); + + if (_renderer.parent().mouseZoomable()) { + const _brush = _renderer.parent().child('brush'); + let keyboard = _renderer.parent().child('keyboard'); + if (!keyboard) + _renderer.parent().child('keyboard', keyboard = keyboardMode()); + + _zoom.filter(() => keyboard.modKeysMatch(_renderer.parent().modKeyZoom())); + + _svg.call(_zoom); + _svg.on('dblclick.zoom', null); + } else { + _zoom.filter(() => false); + _svg.call(_zoom); } return _svg; @@ -879,5 +1031,4 @@ dc_graph.render_svg = function() { }; return _renderer; -}; - +} diff --git a/src/render_webgl.js b/src/render_webgl.js index 36d5eae1..e6224227 100644 --- a/src/render_webgl.js +++ b/src/render_webgl.js @@ -1,12 +1,17 @@ -dc_graph.render_webgl = function() { - //var _svg = null, _defs = null, _g = null, _nodeLayer = null, _edgeLayer = null; - var _camera, _scene, _webgl_renderer; - var _directionalLight, _ambientLight; - var _controls; - var _sphereGeometry; - var _nodes = {}, _edges = {}; - var _animating = false; // do not refresh during animations - var _renderer = {}; +import { extent } from 'd3-array'; +import { property } from './core.js'; +import { regenerateObjects } from './generate_objects.js'; +import { inferShape } from './shape.js'; + +export function renderWebgl() { + // var _svg = null, _defs = null, _g = null, _nodeLayer = null, _edgeLayer = null; + let _camera, _scene, _webgl_renderer; + let _directionalLight, _ambientLight; + let _controls; + let _sphereGeometry; + const _nodes = {}, _edges = {}; + let _animating = false; // do not refresh during animations + const _renderer = {}; _renderer.rendererType = function() { return 'webgl'; @@ -18,26 +23,26 @@ dc_graph.render_webgl = function() { return !!_camera; }; - _renderer.resize = function(w, h) { + _renderer.resize = function(_w, _h) { return _renderer; }; - _renderer.rezoom = function(oldWidth, oldHeight, newWidth, newHeight) { + _renderer.rezoom = function(_oldWidth, _oldHeight, _newWidth, _newHeight) { return _renderer; }; - _renderer.globalTransform = function(pos, scale, animate) { + _renderer.globalTransform = function(_pos, _scale, _animate) { return _renderer; }; _renderer.translate = function(_) { - if(!arguments.length) - return [0,0]; + if (!arguments.length) + return [0, 0]; return _renderer; }; _renderer.scale = function(_) { - if(!arguments.length) + if (!arguments.length) return 1; return _renderer; }; @@ -46,11 +51,11 @@ dc_graph.render_webgl = function() { _renderer.commitTranslateScale = function() { }; - _renderer.initializeDrawing = function () { - if(_scene) // just treat it as a redraw + _renderer.initializeDrawing = function() { + if (_scene) // just treat it as a redraw return _renderer; - _camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000); + _camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 10000); _camera.up = new THREE.Vector3(0, 0, 1); _scene = new THREE.Scene(); @@ -64,9 +69,9 @@ dc_graph.render_webgl = function() { _ambientLight = new THREE.AmbientLight(0xaaaaaa); _scene.add(_ambientLight); - _webgl_renderer = new THREE.WebGLRenderer({ antialias: true }); + _webgl_renderer = new THREE.WebGLRenderer({antialias: true}); _webgl_renderer.setPixelRatio(window.devicePixelRatio); - var boundRect = _renderer.parent().root().node().getBoundingClientRect(); + const boundRect = _renderer.parent().root().node().getBoundingClientRect(); _webgl_renderer.setSize(boundRect.width, boundRect.height); _renderer.parent().root().node().appendChild(_webgl_renderer.domElement); @@ -77,108 +82,135 @@ dc_graph.render_webgl = function() { }; _renderer.startRedraw = function(dispatch, wnodes, wedges) { - wnodes.forEach(infer_shape(_renderer.parent())); - var rnodes = regenerate_objects(_nodes, wnodes, null, function(n) { - return _renderer.parent().nodeKey.eval(n); - }, function(rn, n) { - rn.wnode = n; - }, null, function(wnode, rnode) { - _scene.remove(rnode.mesh); - //rnode.mesh.dispose(); - rnode.material.dispose(); - }); - var redges = regenerate_objects(_edges, wedges, null, function(e) { - return _renderer.parent().edgeKey.eval(e); - }, function(re, e) { - re.wedge = e; - }, null, function(wedge, redge) { - _scene.remove(redge.mesh); - //redge.mesh.dispose(); - redge.geometry.dispose(); - redge.material.dispose(); - }); + wnodes.forEach(inferShape(_renderer.parent())); + const rnodes = regenerateObjects( + _nodes, + wnodes, + null, + n => _renderer.parent().nodeKey.eval(n), + (rn, n) => { + rn.wnode = n; + }, + null, + (wnode, rnode) => { + _scene.remove(rnode.mesh); + // rnode.mesh.dispose(); + rnode.material.dispose(); + }, + ); + const redges = regenerateObjects( + _edges, + wedges, + null, + e => _renderer.parent().edgeKey.eval(e), + (re, e) => { + re.wedge = e; + }, + null, + (wedge, redge) => { + _scene.remove(redge.mesh); + // redge.mesh.dispose(); + redge.geometry.dispose(); + redge.material.dispose(); + }, + ); animate(); - return {wnodes: wnodes, wedges: wedges, rnodes: rnodes, redges: redges}; + return {wnodes, wedges, rnodes, redges}; }; function color_to_int(color) { // it better be 6 byte hex RGB - if(color.length !== 7 || color[0] !== '#') { - console.warn("don't know how to use color " + color); + if (color.length !== 7 || color[0] !== '#') { + console.warn(`don't know how to use color ${color}`); color = '#888888'; } return parseInt(color.slice(1), 16); } _renderer.color_to_int = color_to_int; - _renderer.draw = function(drawState, animatePositions) { - drawState.wedges.forEach(function(e) { - if(!e.pos.old) - _renderer.parent().calcEdgePath(e, 'old', e.source.prevX || e.source.cola.x, e.source.prevY || e.source.cola.y, - e.target.prevX || e.target.cola.x, e.target.prevY || e.target.cola.y); - if(!e.pos.new) - _renderer.parent().calcEdgePath(e, 'new', e.source.cola.x, e.source.cola.y, e.target.cola.x, e.target.cola.y); + _renderer.draw = function(drawState, _animatePositions) { + drawState.wedges.forEach(e => { + if (!e.pos.old) + _renderer.parent().calcEdgePath( + e, + 'old', + e.source.prevX || e.source.cola.x, + e.source.prevY || e.source.cola.y, + e.target.prevX || e.target.cola.x, + e.target.prevY || e.target.cola.y, + ); + if (!e.pos.new) + _renderer.parent().calcEdgePath( + e, + 'new', + e.source.cola.x, + e.source.cola.y, + e.target.cola.x, + e.target.cola.y, + ); }); - var MULT = _renderer.multiplier(); - drawState.rnodes.forEach(function(rn) { - var color = _renderer.parent().nodeFill.eval(rn.wnode); - var add = false; - if(!rn.mesh) { + const MULT = _renderer.multiplier(); + drawState.rnodes.forEach(rn => { + let color = _renderer.parent().nodeFill.eval(rn.wnode); + let add = false; + if (!rn.mesh) { add = true; - if(_renderer.parent().nodeFillScale()) + if (_renderer.parent().nodeFillScale()) color = _renderer.parent().nodeFillScale()(color); - var cint = color_to_int(color); + const cint = color_to_int(color); rn.material = new THREE.MeshLambertMaterial({color: cint}); rn.mesh = new THREE.Mesh(_sphereGeometry, rn.material); rn.mesh.name = _renderer.parent().nodeKey.eval(rn.wnode); } - rn.mesh.position.x = rn.wnode.cola.x * MULT; - rn.mesh.position.y = -rn.wnode.cola.y * MULT; - rn.mesh.position.z = rn.wnode.cola.z * MULT || 0; - if(add) + rn.mesh.position.x = rn.wnode.cola.x*MULT; + rn.mesh.position.y = -rn.wnode.cola.y*MULT; + rn.mesh.position.z = rn.wnode.cola.z*MULT || 0; + if (add) _scene.add(rn.mesh); }); - var xext = d3.extent(drawState.wnodes, function(n) { return n.cola.x * MULT; }), - yext = d3.extent(drawState.wnodes, function(n) { return -n.cola.y * MULT; }), - zext = d3.extent(drawState.wnodes, function(n) { return n.cola.z * MULT || 0; }); - var cx = (xext[0] + xext[1])/2, - cy = (yext[0] + yext[1])/2, - cz = (zext[0] + zext[1])/2; + const xext = extent(drawState.wnodes, n => n.cola.x*MULT), + yext = extent(drawState.wnodes, n => -n.cola.y*MULT), + zext = extent(drawState.wnodes, n => n.cola.z*MULT || 0); + const cx = (xext[0]+xext[1])/2, + cy = (yext[0]+yext[1])/2, + cz = (zext[0]+zext[1])/2; drawState.center = [cx, cy, cz]; drawState.extents = [xext, yext, zext]; _controls.target.set(cx, cy, cz); _controls.update(); - var vertices = []; - drawState.redges.forEach(function(re) { - if(!re.wedge.source || !re.wedge.target) + const _vertices = []; + drawState.redges.forEach(re => { + if (!re.wedge.source || !re.wedge.target) return; - var a = re.wedge.source.cola, b = re.wedge.target.cola; - var add = false; - var width = _renderer.parent().edgeStrokeWidth.eval(re.wedge); - if(!re.mesh) { + const a = re.wedge.source.cola, b = re.wedge.target.cola; + let add = false; + const width = _renderer.parent().edgeStrokeWidth.eval(re.wedge); + if (!re.mesh) { add = true; - var color = _renderer.parent().edgeStroke.eval(re.wedge); - var cint = color_to_int(color); - re.material = new THREE.MeshLambertMaterial({ color: cint }); + const color = _renderer.parent().edgeStroke.eval(re.wedge); + const cint = color_to_int(color); + re.material = new THREE.MeshLambertMaterial({color: cint}); re.curve = new THREE.LineCurve3( new THREE.Vector3(a.x*MULT, -a.y*MULT, a.z*MULT || 0), - new THREE.Vector3(b.x*MULT, -b.y*MULT, b.z*MULT || 0)); + new THREE.Vector3(b.x*MULT, -b.y*MULT, b.z*MULT || 0), + ); re.geometry = new THREE.TubeBufferGeometry(re.curve, 20, width/2, 8, false); re.mesh = new THREE.Mesh(re.geometry, re.material); re.mesh.name = _renderer.parent().edgeKey.eval(re.wedge); } else { re.curve = new THREE.LineCurve3( new THREE.Vector3(a.x*MULT, -a.y*MULT, a.z*MULT || 0), - new THREE.Vector3(b.x*MULT, -b.y*MULT, b.z*MULT || 0)); + new THREE.Vector3(b.x*MULT, -b.y*MULT, b.z*MULT || 0), + ); re.geometry.dispose(); re.geometry = new THREE.TubeBufferGeometry(re.curve, 20, width/2, 8, false); re.mesh.geometry = re.geometry; } - if(add) + if (add) _scene.add(re.mesh); }); _animating = false; @@ -196,42 +228,42 @@ dc_graph.render_webgl = function() { } _renderer.drawPorts = function(drawState) { - var nodePorts = _renderer.parent().nodePorts(); - if(!nodePorts) + const nodePorts = _renderer.parent().nodePorts(); + if (!nodePorts) return; - _renderer.parent().portStyle.enum().forEach(function(style) { - var nodePorts2 = {}; - for(var nid in nodePorts) - nodePorts2[nid] = nodePorts[nid].filter(function(p) { - return _renderer.parent().portStyleName.eval(p) === style; - }); + _renderer.parent().portStyle.enum().forEach(style => { + const nodePorts2 = {}; + for (const nid in nodePorts) + nodePorts2[nid] = nodePorts[nid].filter(p => + _renderer.parent().portStyleName.eval(p) === style + ); // not implemented - var port = _renderer.selectNodePortsOfStyle(drawState.node, style); - //_renderer.parent().portStyle(style).drawPorts(port, nodePorts2, drawState.node); + const _port = _renderer.selectNodePortsOfStyle(drawState.node, style); + // _renderer.parent().portStyle(style).drawPorts(port, nodePorts2, drawState.node); }); }; _renderer.fireTSEvent = function(dispatch, drawState) { - dispatch.transitionsStarted(_scene, drawState); + dispatch.call('transitionsStarted', null, _scene, drawState); }; _renderer.calculateBounds = function(drawState) { - if(!drawState.wnodes.length) + if (!drawState.wnodes.length) return null; return _renderer.parent().calculateBounds(drawState.wnodes, drawState.wedges); }; - _renderer.refresh = function(node, edge, edgeHover, edgeLabels, textPaths) { - if(_animating) + _renderer.refresh = function(_node, _edge, _edgeHover, _edgeLabels, _textPaths) { + if (_animating) return _renderer; // but what about changed attributes? return _renderer; }; - _renderer.reposition = function(node, edge) { + _renderer.reposition = function(_node, _edge) { return _renderer; }; - function has_source_and_target(e) { + function _has_source_and_target(e) { return !!e.source && !!e.target; } @@ -242,5 +274,4 @@ dc_graph.render_webgl = function() { _renderer.multiplier = property(3); return _renderer; -}; - +} diff --git a/src/select_edges.js b/src/select_edges.js index 362fec85..ca783de2 100644 --- a/src/select_edges.js +++ b/src/select_edges.js @@ -1,37 +1,43 @@ -dc_graph.select_edges = function(props, options) { +import { selectThings, selectThingsGroup } from './select_things.js'; +import { nodeEdgeConditions } from './utils.js'; + +export function selectEdges(props, options) { options = options || {}; - var select_edges_group = dc_graph.select_things_group(options.select_edges_group || 'select-edges-group', 'select-edges'); - var thinginess = { - intersectRect: function(ext) { - return this.clickables().data().filter(function(e) { + const select_edges_group = selectThingsGroup( + options.select_edges_group || 'select-edges-group', + 'select-edges', + ); + const thinginess = { + intersectRect(ext) { + return this.clickables().data().filter(e => { // this nonsense because another select_things may have invalidated the edge positions (!!) - var sp = { - x: e.source.cola.x + e.sourcePort.pos.x, - y: e.source.cola.y + e.sourcePort.pos.y - }, + const sp = { + x: e.source.cola.x+e.sourcePort.pos.x, + y: e.source.cola.y+e.sourcePort.pos.y, + }, tp = { - x: e.target.cola.x + e.targetPort.pos.x, - y: e.target.cola.y + e.targetPort.pos.y + x: e.target.cola.x+e.targetPort.pos.x, + y: e.target.cola.y+e.targetPort.pos.y, }; - return [sp, tp].some(function(p) { - return ext[0][0] < p.x && p.x < ext[1][0] && - ext[0][1] < p.y && p.y < ext[1][1]; - }); + return [sp, tp].some(p => + ext[0][0] < p.x && p.x < ext[1][0] + && ext[0][1] < p.y && p.y < ext[1][1] + ); }).map(this.key); }, - clickables: function() { + clickables() { return _mode.parent().selectAllEdges('.edge-hover'); }, - key: function(e) { + key(e) { return _mode.parent().edgeKey.eval(e); }, - applyStyles: function(pred) { - _mode.parent().cascade(50, true, node_edge_conditions(null, pred, props)); + applyStyles(pred) { + _mode.parent().cascade(50, true, nodeEdgeConditions(null, pred, props)); }, - removeStyles: function() { + removeStyles() { _mode.parent().cascade(50, false, props); - } + }, }; - var _mode = dc_graph.select_things(select_edges_group, 'select-edges', thinginess); + const _mode = selectThings(select_edges_group, 'select-edges', thinginess); return _mode; -}; +} diff --git a/src/select_nodes.js b/src/select_nodes.js index b9920249..37397ec2 100644 --- a/src/select_nodes.js +++ b/src/select_nodes.js @@ -1,30 +1,36 @@ -dc_graph.select_nodes = function(props, options) { +import { selectThings, selectThingsGroup } from './select_things.js'; +import { ancestorHasClass, nodeEdgeConditions } from './utils.js'; + +export function selectNodes(props, options) { options = options || {}; - var select_nodes_group = dc_graph.select_things_group(options.select_nodes_group || 'select-nodes-group', 'select-nodes'); + const select_nodes_group = selectThingsGroup( + options.select_nodes_group || 'select-nodes-group', + 'select-nodes', + ); - var thinginess = { - intersectRect: function(ext) { - return _mode.parent().selectAllNodes().data().filter(function(n) { - return n && ext[0][0] < n.cola.x && n.cola.x < ext[1][0] && - ext[0][1] < n.cola.y && n.cola.y < ext[1][1]; - }).map(this.key); + const thinginess = { + intersectRect(ext) { + return _mode.parent().selectAllNodes().data().filter(n => + n && ext[0][0] < n.cola.x && n.cola.x < ext[1][0] + && ext[0][1] < n.cola.y && n.cola.y < ext[1][1] + ).map(this.key); }, - clickables: function(diagram, node, edge) { + clickables(diagram, node, _edge) { return node; }, - excludeClick: function(element) { - return ancestor_has_class(element, 'port'); + excludeClick(element) { + return ancestorHasClass(element, 'port'); }, - key: function(n) { + key(n) { return _mode.parent().nodeKey.eval(n); }, - applyStyles: function(pred) { - _mode.parent().cascade(50, true, node_edge_conditions(pred, null, props)); + applyStyles(pred) { + _mode.parent().cascade(50, true, nodeEdgeConditions(pred, null, props)); }, - removeStyles: function() { + removeStyles() { _mode.parent().cascade(50, false, props); - } + }, }; - var _mode = dc_graph.select_things(select_nodes_group, 'select-nodes', thinginess); + const _mode = selectThings(select_nodes_group, 'select-nodes', thinginess); return _mode; -}; +} diff --git a/src/select_ports.js b/src/select_ports.js index 3147132b..3a0f67a7 100644 --- a/src/select_ports.js +++ b/src/select_ports.js @@ -1,29 +1,39 @@ -dc_graph.select_ports = function(props, options) { +import { selectThings, selectThingsGroup } from './select_things.js'; +import { conditionalProperties } from './utils.js'; + +export function selectPorts(props, options) { options = options || {}; - var port_style = options.portStyle || 'symbols'; - var select_ports_group = dc_graph.select_things_group(options.select_ports_group || 'select-ports-group', 'select-ports'); - var thinginess = { + const port_style = options.portStyle || 'symbols'; + const select_ports_group = selectThingsGroup( + options.select_ports_group || 'select-ports-group', + 'select-ports', + ); + const thinginess = { laterDraw: true, intersectRect: null, // multiple selection not supported for now - clickables: function() { + clickables() { return _mode.parent().selectAllNodes('g.port'); }, - key: function(p) { + key(p) { // this scheme also won't work with multiselect - return p.named ? - {node: _mode.parent().nodeKey.eval(p.node), name: p.name} : - {edge: _mode.parent().edgeKey.eval(p.edges[0]), name: p.name}; + return p.named + ? {node: _mode.parent().nodeKey.eval(p.node), name: p.name} + : {edge: _mode.parent().edgeKey.eval(p.edges[0]), name: p.name}; }, - applyStyles: function(pred) { - _mode.parent().portStyle(port_style).cascade(50, true, conditional_properties(pred, props)); + applyStyles(pred) { + _mode.parent().portStyle(port_style).cascade( + 50, + true, + conditionalProperties(pred, props), + ); }, - removeStyles: function() { + removeStyles() { _mode.parent().portStyle(port_style).cascade(50, false, props); }, - keysEqual: function(k1, k2) { + keysEqual(k1, k2) { return k1.name === k2.name && (k1.node ? k1.node === k2.node : k1.edge === k2.edge); - } + }, }; - var _mode = dc_graph.select_things(select_ports_group, 'select-ports', thinginess); + const _mode = selectThings(select_ports_group, 'select-ports', thinginess); return _mode; -}; +} diff --git a/src/select_things.js b/src/select_things.js index e7ed10c3..14ab5ced 100644 --- a/src/select_things.js +++ b/src/select_things.js @@ -1,15 +1,23 @@ -dc_graph.select_things = function(things_group, things_name, thinginess) { - var _selected = [], _oldSelected; - var _mousedownThing = null; - var _keyboard; +import { dispatch } from 'd3-dispatch'; +import { event } from 'd3-selection'; +import { brush } from './brush.js'; +import { property } from './core.js'; +import { keyboard } from './keyboard.js'; +import { mode } from './mode.js'; +import { is_a_mac } from './utils.js'; - var contains_predicate = thinginess.keysEqual ? - function(k1) { - return function(k2) { - return thinginess.keysEqual(k1, k2); - }; - } : - function(k1) { +export function selectThings(things_group, things_name, thinginess) { + let _selected = [], _oldSelected; + let _mousedownThing = null; + let _keyboard; + + const contains_predicate = thinginess.keysEqual + ? function(k1) { + return function(k2) { + return thinginess.keysEqual(k1, k2); + }; + } + : function(k1) { return function(k2) { return k1 === k2; }; @@ -27,140 +35,147 @@ dc_graph.select_things = function(things_group, things_name, thinginess) { return contains(array, key) ? array : array.concat([key]); } function toggle_array(array, key) { - return contains(array, key) ? array.filter(function(x) { return x != key; }) : array.concat([key]); + return contains(array, key) ? array.filter(x => x != key) : array.concat([key]); } function selection_changed(diagram) { return function(selection, refresh) { - if(refresh === undefined) + if (refresh === undefined) refresh = true; _selected = selection; - if(refresh) + if (refresh) diagram.requestRefresh(); }; } - var _have_bce = false; + let _have_bce = false; function background_click_event(diagram, v) { // we seem to have nodes-background interrupting edges-background by reinstalling uselessly - if(_have_bce === v) + if (_have_bce === v) return; - diagram.svg().on('click.' + things_name, v ? function(t) { - if(d3.event.target === this) - things_group.set_changed([]); - } : null); + diagram.svg().on( + `click.${things_name}`, + v + ? function(_t) { + if (event.target === this) + things_group.call('set_changed', null, []); + } + : null, + ); _have_bce = v; } function modkeyschanged() { - if(_mode.multipleSelect()) { - var brush_mode = _mode.parent().child('brush'); - if(_keyboard.modKeysMatch(_mode.modKeys())) + if (_mode.multipleSelect()) { + const brush_mode = _mode.parent().child('brush'); + if (_keyboard.modKeysMatch(_mode.modKeys(), is_a_mac ? 'Meta' : 'Control')) brush_mode.activate(); else brush_mode.deactivate(); } } function brushstart() { - if(isUnion(d3.event.sourceEvent) || isToggle(d3.event.sourceEvent)) + if (isUnion(event.sourceEvent) || isToggle(event.sourceEvent)) _oldSelected = _selected.slice(); else { _oldSelected = []; - things_group.set_changed([]); + things_group.call('set_changed', null, []); } } function brushmove(ext) { - if(!thinginess.intersectRect) + if (!thinginess.intersectRect) return; - var rectSelect = thinginess.intersectRect(ext); - var newSelected; - if(isUnion(d3.event.sourceEvent)) + const rectSelect = ext ? thinginess.intersectRect(ext) : []; + let newSelected; + if (isUnion(event.sourceEvent)) newSelected = rectSelect.reduce(add_array, _oldSelected); - else if(isToggle(d3.event.sourceEvent)) + else if (isToggle(event.sourceEvent)) newSelected = rectSelect.reduce(toggle_array, _oldSelected); else newSelected = rectSelect; - things_group.set_changed(newSelected); + things_group.call('set_changed', null, newSelected); } function draw(diagram, node, edge) { - var condition = _mode.noneIsAll() ? function(t) { - return !_selected.length || contains(_selected, thinginess.key(t)); - } : function(t) { - return contains(_selected, thinginess.key(t)); - }; + const condition = _mode.noneIsAll() + ? function(t) { + return !_selected.length || contains(_selected, thinginess.key(t)); + } + : function(t) { + return contains(_selected, thinginess.key(t)); + }; thinginess.applyStyles(condition); - thinginess.clickables(diagram, node, edge).on('mousedown.' + things_name, function(t) { + thinginess.clickables(diagram, node, edge).on(`mousedown.${things_name}`, t => { _mousedownThing = t; }); - thinginess.clickables(diagram, node, edge).on('mouseup.' + things_name, function(t) { - if(thinginess.excludeClick && thinginess.excludeClick(d3.event.target)) + thinginess.clickables(diagram, node, edge).on(`mouseup.${things_name}`, t => { + if (thinginess.excludeClick && thinginess.excludeClick(event.target)) return; // it's only a click if the same target was mousedown & mouseup // but we can't use click event because things may have been reordered - if(_mousedownThing !== t) + if (_mousedownThing !== t) return; - var key = thinginess.key(t), newSelected; - if(_mode.multipleSelect()) { - if(isUnion(d3.event)) + const key = thinginess.key(t); + let newSelected; + if (_mode.multipleSelect()) { + if (isUnion(event)) newSelected = add_array(_selected, key); - else if(isToggle(d3.event)) + else if (isToggle(event)) newSelected = toggle_array(_selected, key); } - if(!newSelected) + if (!newSelected) newSelected = [key]; - things_group.set_changed(newSelected); + things_group.call('set_changed', null, newSelected); }); - if(_mode.multipleSelect()) { - if(_keyboard.modKeysMatch(_mode.modKeys())) + if (_mode.multipleSelect()) { + if (_keyboard.modKeysMatch(_mode.modKeys())) diagram.child('brush').activate(); - } - else + } else background_click_event(diagram, _mode.clickBackgroundClears()); - if(_mode.autoCropSelection()) { + if (_mode.autoCropSelection()) { // drop any selected which no longer exist in the diagram - var present = thinginess.clickables(diagram, node, edge).data().map(thinginess.key); - var now_selected = _selected.filter(function(k) { return contains(present, k); }); - if(_selected.length !== now_selected.length) - things_group.set_changed(now_selected, false); + const present = thinginess.clickables(diagram, node, edge).data().map(thinginess.key); + const now_selected = _selected.filter(k => contains(present, k)); + if (_selected.length !== now_selected.length) + things_group.call('set_changed', null, now_selected, false); } } function remove(diagram, node, edge) { - thinginess.clickables(diagram, node, edge).on('click.' + things_name, null); - diagram.svg().on('click.' + things_name, null); + thinginess.clickables(diagram, node, edge).on(`click.${things_name}`, null); + diagram.svg().on(`click.${things_name}`, null); thinginess.removeStyles(); } - var _mode = dc_graph.mode(things_name, { - draw: draw, - remove: remove, - parent: function(p) { - things_group.on('set_changed.' + things_name, p ? selection_changed(p) : null); - if(p && _mode.multipleSelect()) { - var brush_mode = p.child('brush'); - if(!brush_mode) { - brush_mode = dc_graph.brush(); + const _mode = mode(things_name, { + draw, + remove, + parent(p) { + things_group.on(`set_changed.${things_name}`, p ? selection_changed(p) : null); + if (p && _mode.multipleSelect()) { + let brush_mode = p.child('brush'); + if (!brush_mode) { + brush_mode = brush(); p.child('brush', brush_mode); } brush_mode - .on('brushstart.' + things_name, brushstart) - .on('brushmove.' + things_name, brushmove); + .on(`brushstart.${things_name}`, brushstart) + .on(`brushmove.${things_name}`, brushmove); } _keyboard = p.child('keyboard'); - if(!_keyboard) - p.child('keyboard', _keyboard = dc_graph.keyboard()); - _keyboard.on('modkeyschanged.' + things_name, modkeyschanged); + if (!_keyboard) + p.child('keyboard', _keyboard = keyboard()); + _keyboard.on(`modkeyschanged.${things_name}`, modkeyschanged); }, - laterDraw: thinginess.laterDraw || false + laterDraw: thinginess.laterDraw || false, }); _mode.multipleSelect = property(true); _mode.modKeys = property(null); - _mode.clickBackgroundClears = property(true, false).react(function(v) { - if(!_mode.multipleSelect() && _mode.parent()) + _mode.clickBackgroundClears = property(true, false).react(v => { + if (!_mode.multipleSelect() && _mode.parent()) background_click_event(_mode.parent(), v); }); _mode.noneIsAll = property(false); @@ -173,12 +188,10 @@ dc_graph.select_things = function(things_group, things_name, thinginess) { return thinginess; }; return _mode; -}; +} -dc_graph.select_things_group = function(brushgroup, type) { - window.chart_registry.create_type(type, function() { - return d3.dispatch('set_changed'); - }); +export function selectThingsGroup(brushgroup, type) { + window.chart_registry.create_type(type, () => dispatch('set_changed')); return window.chart_registry.create_group(type, brushgroup); -}; +} diff --git a/src/shape.js b/src/shape.js index 64201da8..62385f50 100644 --- a/src/shape.js +++ b/src/shape.js @@ -1,59 +1,70 @@ -function point_on_ellipse(A, B, dx, dy) { - var tansq = Math.tan(Math.atan2(dy, dx)); +import { extent } from 'd3-array'; +import { getBBoxNoThrow, property } from './core.js'; +import { generatePath } from './utils.js'; + +function pointOnEllipse(A, B, dx, dy) { + let tansq = Math.tan(Math.atan2(dy, dx)); tansq = tansq*tansq; // why is this not just dy*dy/dx*dx ? ? - var ret = {x: A*B/Math.sqrt(B*B + A*A*tansq), y: A*B/Math.sqrt(A*A + B*B/tansq)}; - if(dx<0) + const ret = {x: A*B/Math.sqrt(B*B+A*A*tansq), y: A*B/Math.sqrt(A*A+B*B/tansq)}; + if (dx < 0) ret.x = -ret.x; - if(dy<0) + if (dy < 0) ret.y = -ret.y; return ret; } -var eps = 0.0000001; +const eps = 0.0000001; function between(a, b, c) { return a-eps <= b && b <= c+eps; } // Adapted from http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect/1968345#1968345 -function segment_intersection(x1,y1,x2,y2, x3,y3,x4,y4) { - var x=((x1*y2-y1*x2)*(x3-x4)-(x1-x2)*(x3*y4-y3*x4)) / - ((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)); - var y=((x1*y2-y1*x2)*(y3-y4)-(y1-y2)*(x3*y4-y3*x4)) / - ((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)); - if (isNaN(x)||isNaN(y)) { +function segmentIntersection(x1, y1, x2, y2, x3, y3, x4, y4) { + const x = ((x1*y2-y1*x2)*(x3-x4)-(x1-x2)*(x3*y4-y3*x4)) + /((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)); + const y = ((x1*y2-y1*x2)*(y3-y4)-(y1-y2)*(x3*y4-y3*x4)) + /((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)); + if (isNaN(x) || isNaN(y)) { return false; } else { - if (x1>=x2) { - if (!between(x2, x, x1)) {return false;} + if (x1 >= x2) { + if (!between(x2, x, x1)) { return false; } } else { - if (!between(x1, x, x2)) {return false;} + if (!between(x1, x, x2)) { return false; } } - if (y1>=y2) { - if (!between(y2, y, y1)) {return false;} + if (y1 >= y2) { + if (!between(y2, y, y1)) { return false; } } else { - if (!between(y1, y, y2)) {return false;} + if (!between(y1, y, y2)) { return false; } } - if (x3>=x4) { - if (!between(x4, x, x3)) {return false;} + if (x3 >= x4) { + if (!between(x4, x, x3)) { return false; } } else { - if (!between(x3, x, x4)) {return false;} + if (!between(x3, x, x4)) { return false; } } - if (y3>=y4) { - if (!between(y4, y, y3)) {return false;} + if (y3 >= y4) { + if (!between(y4, y, y3)) { return false; } } else { - if (!between(y3, y, y4)) {return false;} + if (!between(y3, y, y4)) { return false; } } } - return {x: x, y: y}; + return {x, y}; } - -function point_on_polygon(points, x0, y0, x1, y1) { - for(var i = 0; i < points.length; ++i) { - var next = i===points.length-1 ? 0 : i+1; - var isect = segment_intersection(points[i].x, points[i].y, points[next].x, points[next].y, - x0, y0, x1, y1); - if(isect) +function pointOnPolygon(points, x0, y0, x1, y1) { + for (let i = 0; i < points.length; ++i) { + const next = i === points.length-1 ? 0 : i+1; + const isect = segmentIntersection( + points[i].x, + points[i].y, + points[next].x, + points[next].y, + x0, + y0, + x1, + y1, + ); + if (isect) return isect; } return null; @@ -61,179 +72,179 @@ function point_on_polygon(points, x0, y0, x1, y1) { // as many as we can get from // http://www.graphviz.org/doc/info/shapes.html -dc_graph.shape_presets = { +export const shapePresets = { egg: { // not really: an ovoid should be two half-ellipses stuck together // https://en.wikipedia.org/wiki/Oval generator: 'polygon', - preset: function() { + preset() { return {sides: 100, distortion: -0.25}; - } + }, }, triangle: { generator: 'polygon', - preset: function() { + preset() { return {sides: 3}; - } + }, }, rectangle: { generator: 'polygon', - preset: function() { + preset() { return {sides: 4}; - } + }, }, diamond: { generator: 'polygon', - preset: function() { + preset() { return {sides: 4, rotation: 45}; - } + }, }, trapezium: { generator: 'polygon', - preset: function() { + preset() { return {sides: 4, distortion: -0.5}; - } + }, }, parallelogram: { generator: 'polygon', - preset: function() { + preset() { return {sides: 4, skew: 0.5}; - } + }, }, pentagon: { generator: 'polygon', - preset: function() { + preset() { return {sides: 5}; - } + }, }, hexagon: { generator: 'polygon', - preset: function() { + preset() { return {sides: 6}; - } + }, }, septagon: { generator: 'polygon', - preset: function() { + preset() { return {sides: 7}; - } + }, }, octagon: { generator: 'polygon', - preset: function() { + preset() { return {sides: 8}; - } + }, }, invtriangle: { generator: 'polygon', - preset: function() { + preset() { return {sides: 3, rotation: 180}; - } + }, }, invtrapezium: { generator: 'polygon', - preset: function() { + preset() { return {sides: 4, distortion: 0.5}; - } + }, }, square: { generator: 'polygon', - preset: function() { + preset() { return { sides: 4, - regular: true + regular: true, }; - } + }, }, plain: { generator: 'rounded-rect', - preset: function() { + preset() { return { - noshape: true + noshape: true, }; - } + }, }, house: { generator: 'elaborated-rect', - preset: function() { + preset() { return { - get_points: function(rx, ry) { + get_points(rx, ry) { return [ {x: rx, y: ry*2/3}, {x: rx, y: -ry/2}, {x: 0, y: -ry}, {x: -rx, y: -ry/2}, - {x: -rx, y: ry*2/3} + {x: -rx, y: ry*2/3}, ]; }, - minrx: 30 + minrx: 30, }; - } + }, }, invhouse: { generator: 'elaborated-rect', - preset: function() { + preset() { return { - get_points: function(rx, ry) { + get_points(rx, ry) { return [ {x: rx, y: ry/2}, {x: rx, y: -ry*2/3}, {x: -rx, y: -ry*2/3}, {x: -rx, y: ry/2}, - {x: 0, y: ry} + {x: 0, y: ry}, ]; }, - minrx: 30 + minrx: 30, }; - } + }, }, rarrow: { generator: 'elaborated-rect', - preset: function() { + preset() { return { - get_points: function(rx, ry) { + get_points(rx, ry) { return [ {x: rx, y: ry}, {x: rx, y: ry*1.5}, - {x: rx + ry*1.5, y: 0}, + {x: rx+ry*1.5, y: 0}, {x: rx, y: -ry*1.5}, {x: rx, y: -ry}, {x: -rx, y: -ry}, - {x: -rx, y: ry} + {x: -rx, y: ry}, ]; }, - minrx: 30 + minrx: 30, }; - } + }, }, larrow: { generator: 'elaborated-rect', - preset: function() { + preset() { return { - get_points: function(rx, ry) { + get_points(rx, ry) { return [ {x: -rx, y: ry}, {x: -rx, y: ry*1.5}, - {x: -rx - ry*1.5, y: 0}, + {x: -rx-ry*1.5, y: 0}, {x: -rx, y: -ry*1.5}, {x: -rx, y: -ry}, {x: rx, y: -ry}, - {x: rx, y: ry} + {x: rx, y: ry}, ]; }, - minrx: 30 + minrx: 30, }; - } + }, }, rpromoter: { generator: 'elaborated-rect', - preset: function() { + preset() { return { - get_points: function(rx, ry) { + get_points(rx, ry) { return [ {x: rx, y: ry}, {x: rx, y: ry*1.5}, - {x: rx + ry*1.5, y: 0}, + {x: rx+ry*1.5, y: 0}, {x: rx, y: -ry*1.5}, {x: rx, y: -ry}, {x: -rx, y: -ry}, @@ -242,158 +253,163 @@ dc_graph.shape_presets = { {x: 0, y: ry}, ]; }, - minrx: 30 + minrx: 30, }; - } + }, }, lpromoter: { generator: 'elaborated-rect', - preset: function() { + preset() { return { - get_points: function(rx, ry) { + get_points(rx, ry) { return [ {x: -rx, y: ry}, {x: -rx, y: ry*1.5}, - {x: -rx - ry*1.5, y: 0}, + {x: -rx-ry*1.5, y: 0}, {x: -rx, y: -ry*1.5}, {x: -rx, y: -ry}, {x: rx, y: -ry}, {x: rx, y: ry*1.5}, {x: 0, y: ry*1.5}, - {x: 0, y: ry} + {x: 0, y: ry}, ]; }, - minrx: 30 + minrx: 30, }; - } + }, }, cds: { generator: 'elaborated-rect', - preset: function() { + preset() { return { - get_points: function(rx, ry) { + get_points(rx, ry) { return [ {x: rx, y: ry}, - {x: rx + ry, y: 0}, + {x: rx+ry, y: 0}, {x: rx, y: -ry}, {x: -rx, y: -ry}, - {x: -rx, y: ry} + {x: -rx, y: ry}, ]; }, - minrx: 30 + minrx: 30, }; - } + }, }, }; -dc_graph.shape_presets.box = dc_graph.shape_presets.rect = dc_graph.shape_presets.rectangle; +shapePresets.box = shapePresets.rect = shapePresets.rectangle; -dc_graph.available_shapes = function() { - var shapes = Object.keys(dc_graph.shape_presets); +export function availableShapes() { + const shapes = Object.keys(shapePresets); return shapes.slice(0, shapes.length-1); // not including polygon -}; +} -var default_shape = {shape: 'ellipse'}; +export const defaultShape = {shape: 'ellipse'}; -function normalize_shape_def(diagram, n) { - var def = diagram.nodeShape.eval(n); - if(!def) - def = {...default_shape}; - else if(typeof def === 'string') +function normalizeShapeDef(diagram, n) { + let def = diagram.nodeShape.eval(n); + if (!def) + def = {...defaultShape}; + else if (typeof def === 'string') def = {shape: def}; def.nodeOutlineClip = diagram.nodeOutlineClip.eval(n); return def; } -function elaborate_shape(diagram, def) { - var shape = def.shape, def2 = Object.assign({}, def); +function elaborateShape(diagram, def) { + let shape = def.shape; + const def2 = Object.assign({}, def); delete def2.shape; - if(shape === 'random') { - var available = dc_graph.available_shapes(); // could include diagram.shape !== ellipse, polygon + if (shape === 'random') { + const available = availableShapes(); // could include diagram.shape !== ellipse, polygon shape = available[Math.floor(Math.random()*available.length)]; - } - else if(diagram.shape.enum().indexOf(shape) !== -1) - return diagram.shape(shape).elaborate({shape: shape}, def2); - if(!dc_graph.shape_presets[shape]) { + } else if (diagram.shape.enum().indexOf(shape) !== -1) + return diagram.shape(shape).elaborate({shape}, def2); + if (!shapePresets[shape]) { console.warn('unknown shape ', shape); - return default_shape; + return defaultShape; } - var preset = dc_graph.shape_presets[shape].preset(def2); - preset.shape = dc_graph.shape_presets[shape].generator; + const preset = shapePresets[shape].preset(def2); + preset.shape = shapePresets[shape].generator; return diagram.shape(preset.shape).elaborate(preset, def2); } -function infer_shape(diagram) { +export function inferShape(diagram) { return function(n) { - var def = normalize_shape_def(diagram, n); - n.dcg_shape = elaborate_shape(diagram, def); + const def = normalizeShapeDef(diagram, n); + n.dcg_shape = elaborateShape(diagram, def); n.dcg_shape.abstract = def; }; } -function shape_changed(diagram) { +export function shapeChanged(diagram) { return function(n) { - var def = normalize_shape_def(diagram, n); - var old = n.dcg_shape.abstract; - if(def.shape !== old.shape) + const def = normalizeShapeDef(diagram, n); + const old = n.dcg_shape.abstract; + if (def.shape !== old.shape) return true; - else if(def.nodeOutlineClip !== old.nodeOutlineClip) + else if (def.nodeOutlineClip !== old.nodeOutlineClip) return true; - else if(def.shape === 'polygon') { - return def.shape.sides !== old.sides || def.shape.skew !== old.skew || - def.shape.distortion !== old.distortion || def.shape.rotation !== old.rotation; - } - else return false; + else if (def.shape === 'polygon') { + return def.shape.sides !== old.sides || def.shape.skew !== old.skew + || def.shape.distortion !== old.distortion || def.shape.rotation !== old.rotation; + } else return false; }; } -function node_label_padding(diagram, n) { - var nlp = diagram.nodeLabelPadding.eval(n); - if(typeof nlp === 'number' || typeof nlp === 'string') +export function nodeLabelPadding(diagram, n) { + const nlp = diagram.nodeLabelPadding.eval(n); + if (typeof nlp === 'number' || typeof nlp === 'string') return {x: +nlp, y: +nlp}; else return nlp; } -function fit_shape(shape, diagram) { +export function fitShape(shape, diagram) { return function(content) { content.each(function(n) { - var bbox = null; - if((!shape.useTextSize || shape.useTextSize(n.dcg_shape)) && diagram.nodeFitLabel.eval(n)) { + let bbox = null; + if ( + (!shape.useTextSize || shape.useTextSize(n.dcg_shape)) + && diagram.nodeFitLabel.eval(n) + ) { bbox = getBBoxNoThrow(this); bbox = {x: bbox.x, y: bbox.y, width: bbox.width, height: bbox.height}; - var padding; - var content = diagram.nodeContent.eval(n); - if(content && diagram.content(content).padding) + let padding; + const content = diagram.nodeContent.eval(n); + if (content && diagram.content(content).padding) padding = diagram.content(content).padding(n); else { - var padding2 = node_label_padding(diagram, n); + const padding2 = nodeLabelPadding(diagram, n); padding = { x: padding2.x*2, - y: padding2.y*2 + y: padding2.y*2, }; } bbox.width += padding.x; bbox.height += padding.y; n.bbox = bbox; } - var r = 0, radii; - if(!shape.useRadius || shape.useRadius(n.dcg_shape)) - r = diagram.nodeRadius.eval(n); - if(bbox && bbox.width && bbox.height || shape.useTextSize && !shape.useTextSize(n.dcg_shape)) + let r = 0, radii; + if (!shape.useRadius || shape.useRadius(n.dcg_shape)) + r = Math.max(0, diagram.nodeRadius.eval(n) || 0); + if ( + bbox && bbox.width && bbox.height + || shape.useTextSize && !shape.useTextSize(n.dcg_shape) + ) radii = shape.calc_radii(n, r, bbox); else radii = {rx: r, ry: r}; - n.dcg_rx = radii.rx; - n.dcg_ry = radii.ry; + n.dcg_rx = Math.max(0, radii.rx || 0); + n.dcg_ry = Math.max(0, radii.ry || 0); - var w = radii.rx*2, h = radii.ry*2; + let w = radii.rx*2, h = radii.ry*2; // fixme: this is only consistent if regular || !squeeze // but we'd need to calculate polygon first in order to find out // (not a bad idea, just no time right now) // if(w theta.y); + if (def.regular) + rx = ry = Math.max(rx, ry); + else if (rx < ry && !def.squeeze) + rx = ry; + else + ry = ry/Math.min(-yext[0], yext[1]); + n.dcg_points = angles.map(theta => { + let x = rx*theta.x; + const y = ry*theta.y; + x *= 1+distortion*((ry-y)/ry-1); + x -= skew*y/2; + return {x, y}; + }); + return generatePath(n.dcg_points, 1, true); } -function binary_search(f, a, b) { - var patience = 100; - if(f(a).val >= 0) - throw new Error("f(a) must be less than 0"); - if(f(b).val <= 0) - throw new Error("f(b) must be greater than 0"); - while(true) { - if(!--patience) - throw new Error("patience ran out"); - var c = (a+b)/2, - f_c = f(c), fv = f_c.val; - if(Math.abs(fv) < 0.5) +function binarySearch(f, a, b) { + let patience = 100; + if (f(a).val >= 0) + throw new Error('f(a) must be less than 0'); + if (f(b).val <= 0) + throw new Error('f(b) must be greater than 0'); + while (true) { + if (!--patience) + throw new Error('patience ran out'); + const c = (a+b)/2, + f_c = f(c), + fv = f_c.val; + if (Math.abs(fv) < 0.5) return f_c; - if(fv > 0) + if (fv > 0) b = c; else a = c; } } -function draw_edge_to_shapes(diagram, e, sx, sy, tx, ty, - neighbor, dir, offset, source_padding, target_padding) { - var deltaX, deltaY, - sp, tp, points, bezDegree, - headAng, retPath; - if(!neighbor) { +export function drawEdgeToShapes( + diagram, + e, + sx, + sy, + tx, + ty, + neighbor, + dir, + offset, + source_padding, + target_padding, +) { + let _deltaX, _deltaY, sp, tp, points, bezDegree, _headAng, _retPath; + if (!neighbor) { sp = e.sourcePort.pos; tp = e.targetPort.pos; - if(!sp) sp = {x: 0, y: 0}; - if(!tp) tp = {x: 0, y: 0}; + if (!sp) sp = {x: 0, y: 0}; + if (!tp) tp = {x: 0, y: 0}; points = [{ - x: sx + sp.x, - y: sy + sp.y + x: sx+sp.x, + y: sy+sp.y, }, { - x: tx + tp.x, - y: ty + tp.y + x: tx+tp.x, + y: ty+tp.y, }]; bezDegree = 1; - } - else { - var p_on_s = function(node, ang) { - return diagram.shape(node.dcg_shape.shape).intersect_vec(node, Math.cos(ang)*1000, Math.sin(ang)*1000); + } else { + const p_on_s = function(node, ang) { + return diagram.shape(node.dcg_shape.shape).intersect_vec( + node, + Math.cos(ang)*1000, + Math.sin(ang)*1000, + ); }; - var compare_dist = function(node, port0, goal) { + const compare_dist = function(node, port0, goal) { return function(ang) { - var port = p_on_s(node, ang); - if(!port) + const port = p_on_s(node, ang); + if (!port) return { port: {x: 0, y: 0}, val: 0, - ang: ang + ang, }; else return { - port: port, - val: Math.hypot(port.x - port0.x, port.y - port0.y) - goal, - ang: ang + port, + val: Math.hypot(port.x-port0.x, port.y-port0.y)-goal, + ang, }; }; }; - var srcang = Math.atan2(neighbor.sourcePort.y, neighbor.sourcePort.x), + const srcang = Math.atan2(neighbor.sourcePort.y, neighbor.sourcePort.x), tarang = Math.atan2(neighbor.targetPort.y, neighbor.targetPort.x); - var bss, bst; + let bss, bst; // don't like this but throwing is unacceptable try { - bss = binary_search(compare_dist(e.source, neighbor.sourcePort, offset), - srcang, srcang + 2 * dir * offset / source_padding); - } - catch(x) { + bss = binarySearch( + compare_dist(e.source, neighbor.sourcePort, offset), + srcang, + srcang+2*dir*offset/source_padding, + ); + } catch (_x) { bss = {ang: srcang, port: neighbor.sourcePort}; } try { - bst = binary_search(compare_dist(e.target, neighbor.targetPort, offset), - tarang, tarang - 2 * dir * offset / source_padding); - } - catch(x) { + bst = binarySearch( + compare_dist(e.target, neighbor.targetPort, offset), + tarang, + tarang-2*dir*offset/source_padding, + ); + } catch (_x) { bst = {ang: tarang, port: neighbor.targetPort}; } sp = bss.port; tp = bst.port; - var sdist = Math.hypot(sp.x, sp.y), + const sdist = Math.hypot(sp.x, sp.y), tdist = Math.hypot(tp.x, tp.y), c1dist = sdist+source_padding/2, c2dist = tdist+target_padding/2; - var c1X = sx + c1dist * Math.cos(bss.ang), - c1Y = sy + c1dist * Math.sin(bss.ang), - c2X = tx + c2dist * Math.cos(bst.ang), - c2Y = ty + c2dist * Math.sin(bst.ang); + const c1X = sx+c1dist*Math.cos(bss.ang), + c1Y = sy+c1dist*Math.sin(bss.ang), + c2X = tx+c2dist*Math.cos(bst.ang), + c2Y = ty+c2dist*Math.sin(bst.ang); points = [ - {x: sx + sp.x, y: sy + sp.y}, + {x: sx+sp.x, y: sy+sp.y}, {x: c1X, y: c1Y}, {x: c2X, y: c2Y}, - {x: tx + tp.x, y: ty + tp.y} + {x: tx+tp.x, y: ty+tp.y}, ]; bezDegree = 3; } return { sourcePort: sp, targetPort: tp, - points: points, - bezDegree: bezDegree + points, + bezDegree, }; } -function is_one_segment(path) { - return path.bezDegree === 1 && path.points.length === 2 || - path.bezDegree === 3 && path.points.length === 4; +export function isOneSegment(path) { + return path.bezDegree === 1 && path.points.length === 2 + || path.bezDegree === 3 && path.points.length === 4; } -function as_bezier3(path) { - var p = path.points; - if(path.bezDegree === 3) return p; - else if(path.bezDegree === 1) +export function asBezier3(path) { + const p = path.points; + if (path.bezDegree === 3) return p; + else if (path.bezDegree === 1) return [ { x: p[0].x, - y: p[0].y + y: p[0].y, }, { - x: p[0].x + (p[1].x - p[0].x)/3, - y: p[0].y + (p[1].y - p[0].y)/3 + x: p[0].x+(p[1].x-p[0].x)/3, + y: p[0].y+(p[1].y-p[0].y)/3, }, { - x: p[0].x + 2*(p[1].x - p[0].x)/3, - y: p[0].y + 2*(p[1].y - p[0].y)/3 + x: p[0].x+2*(p[1].x-p[0].x)/3, + y: p[0].y+2*(p[1].y-p[0].y)/3, }, { x: p[1].x, - y: p[1].y - } + y: p[1].y, + }, ]; - else throw new Error('unknown bezDegree ' + path.bezDegree); + else throw new Error(`unknown bezDegree ${path.bezDegree}`); } // from https://www.jasondavies.com/animated-bezier/ -function interpolate(d, p) { - var r = []; - for (var i=1; i 1) { - var parts = split_bezier(p, 1/n); +export function splitBezierN(p, n) { + const ret = []; + while (n > 1) { + const parts = splitBezier(p, 1/n); ret.push(parts[0][0], parts[0][1], parts[0][2]); p = parts[1]; --n; @@ -650,10 +670,10 @@ function split_bezier_n(p, n) { // binary search for a point along a bezier that is a certain distance from one of the end points // return the bezier cut at that point. -function chop_bezier(points, end, dist) { - var EPS = 0.1, dist2 = dist*dist; - var ref, dir, segment; - if(end === 'head') { +export function chopBezier(points, end, dist) { + const EPS = 0.1, dist2 = dist*dist; + let ref, dir, segment; + if (end === 'head') { ref = points[points.length-1]; segment = points.slice(points.length-4); dir = -1; @@ -662,57 +682,62 @@ function chop_bezier(points, end, dist) { segment = points.slice(0, 4); dir = 1; } - var parts, d2, t = 0.5, dt = 0.5, dx, dy; + let parts, d2, t = 0.5, dt = 0.5, dx, dy; do { - parts = split_bezier(segment, t); - dx = ref.x - parts[1][0].x; - dy = ref.y - parts[1][0].y; - d2 = dx*dx + dy*dy; + parts = splitBezier(segment, t); + dx = ref.x-parts[1][0].x; + dy = ref.y-parts[1][0].y; + d2 = dx*dx+dy*dy; dt /= 2; - if(d2 > dist2) + if (d2 > dist2) t -= dt*dir; else t += dt*dir; - //console.log('dist', dist, 'dir', dir, 'd', d, 't', t, 'dt', dt); - } - while(dt > 0.0000001 && Math.abs(d2 - dist2) > EPS); + // console.log('dist', dist, 'dir', dir, 'd', d, 't', t, 'dt', dt); + } while (dt > 0.0000001 && Math.abs(d2-dist2) > EPS); points = points.slice(); - if(end === 'head') + if (end === 'head') return points.slice(0, points.length-4).concat(parts[0]); else return parts[1].concat(points.slice(4)); } -function angle_between_points(p0, p1) { - return Math.atan2(p1.y - p0.y, p1.x - p0.x); +export function angleBetweenPoints(p0, p1) { + return Math.atan2(p1.y-p0.y, p1.x-p0.x); } -dc_graph.no_shape = function() { - var _shape = { +export function noShape() { + const _shape = { parent: property(null), - elaborate: function(preset, def) { + elaborate(preset, def) { return Object.assign(preset, def); }, - useTextSize: function() { return false; }, - useRadius: function() { return false; }, - usePaddingAndStroke: function() { return false; }, - intersect_vec: function(n, deltaX, deltaY) { + useTextSize() { + return false; + }, + useRadius() { + return false; + }, + usePaddingAndStroke() { + return false; + }, + intersect_vec(_n, _deltaX, _deltaY) { return {x: 0, y: 0}; }, - calc_radii: function(n, ry, bbox) { + calc_radii(_n, _ry, _bbox) { return {rx: 0, ry: 0}; }, - create: function(nodeEnter) { + create(_nodeEnter) { }, - replace: function(nodeChanged) { + replace(_nodeChanged) { + }, + update(_node) { }, - update: function(node) { - } }; return _shape; -}; +} -function create_maybe_clipped(diagram, nodeEnter, element) { +function createMaybeClipped(diagram, nodeEnter, element) { const clipped = nodeEnter.filter(n => diagram.nodeOutlineClip.eval(n)); const unclipped = nodeEnter.filter(n => !diagram.nodeOutlineClip.eval(n)); clipped.insert(element, ':first-child') @@ -725,158 +750,144 @@ function create_maybe_clipped(diagram, nodeEnter, element) { .attr('class', 'node-outline node-fill'); } -dc_graph.ellipse_shape = function() { - var _shape = { +export function ellipseShape() { + const _shape = { parent: property(null), - elaborate: function(preset, def) { + elaborate(preset, def) { return Object.assign(preset, def); }, - intersect_vec: function(n, deltaX, deltaY) { - return point_on_ellipse(n.dcg_rx, n.dcg_ry, deltaX, deltaY); + intersect_vec(n, deltaX, deltaY) { + return pointOnEllipse(n.dcg_rx, n.dcg_ry, deltaX, deltaY); }, - calc_radii: function(n, ry, bbox) { + calc_radii(n, ry, bbox) { // make sure we can fit height in r - ry = Math.max(ry, bbox.height/2 + 5); - var rx = bbox.width/2; + ry = Math.max(ry, bbox.height/2+5); + let rx = bbox.width/2; // solve (x/A)^2 + (y/B)^2) = 1 for A, with B=r, to fit text in ellipse // http://stackoverflow.com/a/433438/676195 - var y_over_B = bbox.height/2/ry; - rx = rx/Math.sqrt(1 - y_over_B*y_over_B); + const y_over_B = bbox.height/2/ry; + rx = rx/Math.sqrt(1-y_over_B*y_over_B); rx = Math.max(rx, ry); - return {rx: rx, ry: ry}; + return {rx, ry}; }, - create: function(nodeEnter) { - create_maybe_clipped(_shape.parent(), nodeEnter, 'ellipse'); + create(nodeEnter) { + createMaybeClipped(_shape.parent(), nodeEnter, 'ellipse'); }, - update: function(node) { + update(node) { node.selectAll('ellipse.node-fill,ellipse.node-outline') - .attr(ellipse_attrs(_shape.parent())); - } + .attr('rx', n => n.dcg_rx) + .attr('ry', n => n.dcg_ry); + }, }; return _shape; -}; +} -dc_graph.polygon_shape = function() { - var _shape = { +export function polygonShape() { + const _shape = { parent: property(null), - elaborate: function(preset, def) { + elaborate(preset, def) { return Object.assign(preset, def); }, - intersect_vec: function(n, deltaX, deltaY) { - return point_on_polygon(n.dcg_points, 0, 0, deltaX, deltaY); + intersect_vec(n, deltaX, deltaY) { + return pointOnPolygon(n.dcg_points, 0, 0, deltaX, deltaY); }, - calc_radii: function(n, ry, bbox) { + calc_radii(n, ry, bbox) { // make sure we can fit height in r - ry = Math.max(ry, bbox.height/2 + 5); - var rx = bbox.width/2; + ry = Math.max(ry, bbox.height/2+5); + let rx = bbox.width/2; // this is cribbed from graphviz but there is much i don't understand // and any errors are mine // https://github.com/ellson/graphviz/blob/6acd566eab716c899ef3c4ddc87eceb9b428b627/lib/common/shapes.c#L1996 - rx = rx*Math.sqrt(2)/Math.cos(Math.PI/(n.dcg_shape.sides||4)); + rx = rx*Math.sqrt(2)/Math.cos(Math.PI/(n.dcg_shape.sides || 4)); - return {rx: rx, ry: ry}; + return {rx, ry}; }, - create: function(nodeEnter) { - create_maybe_clipped(_shape.parent(), nodeEnter, 'path'); + create(nodeEnter) { + createMaybeClipped(_shape.parent(), nodeEnter, 'path'); }, - update: function(node) { + update(node) { node.selectAll('path.node-fill,path.node-outline') - .attr(polygon_attrs(_shape.parent())); - } + .attr('d', polygonPath); + }, }; return _shape; -}; +} -dc_graph.rounded_rectangle_shape = function() { - var _shape = { +export function roundedRectangleShape() { + const _shape = { parent: property(null), - elaborate: function(preset, def) { + elaborate(preset, def) { preset = Object.assign({rx: 10, ry: 10}, preset); return Object.assign(preset, def); }, - intersect_vec: function(n, deltaX, deltaY) { - var points = [ - {x: n.dcg_rx, y: n.dcg_ry}, - {x: n.dcg_rx, y: -n.dcg_ry}, + intersect_vec(n, deltaX, deltaY) { + const points = [ + {x: n.dcg_rx, y: n.dcg_ry}, + {x: n.dcg_rx, y: -n.dcg_ry}, {x: -n.dcg_rx, y: -n.dcg_ry}, - {x: -n.dcg_rx, y: n.dcg_ry} + {x: -n.dcg_rx, y: n.dcg_ry}, ]; - return point_on_polygon(points, 0, 0, deltaX, deltaY); // not rounded + return pointOnPolygon(points, 0, 0, deltaX, deltaY); // not rounded }, - useRadius: function(shape) { + useRadius(shape) { return !shape.noshape; }, - calc_radii: function(n, ry, bbox) { - var fity = bbox.height/2; + calc_radii(n, ry, bbox) { + let fity = bbox.height/2; // fixme: fudge to make sure text is not too tall for node - if(!n.dcg_shape.noshape) + if (!n.dcg_shape.noshape) fity += 5; return { - rx: bbox.width / 2, - ry: Math.max(ry, fity) + rx: bbox.width/2, + ry: Math.max(ry, fity), }; }, - create: function(nodeEnter) { - create_maybe_clipped(_shape.parent(), nodeEnter.filter(function(n) { - return !n.dcg_shape.noshape; - }), 'rect'); + create(nodeEnter) { + createMaybeClipped( + _shape.parent(), + nodeEnter.filter(n => !n.dcg_shape.noshape), + 'rect', + ); }, - update: function(node) { + update(node) { node.selectAll('rect.node-fill,rect.node-outline') - .attr({ - x: function(n) { - return -n.dcg_rx; - }, - y: function(n) { - return -n.dcg_ry; - }, - width: function(n) { - return 2*n.dcg_rx; - }, - height: function(n) { - return 2*n.dcg_ry; - }, - rx: function(n) { - return n.dcg_shape.rx + 'px'; - }, - ry: function(n) { - return n.dcg_shape.ry + 'px'; - } - }); - } + .attr('x', n => -n.dcg_rx) + .attr('y', n => -n.dcg_ry) + .attr('width', n => 2*n.dcg_rx) + .attr('height', n => 2*n.dcg_ry) + .attr('rx', n => `${n.dcg_shape.rx}px`) + .attr('ry', n => `${n.dcg_shape.ry}px`); + }, }; return _shape; -}; +} // this is not all that accurate - idea is that arrows, houses, etc, are rectangles // in terms of sizing, but elaborated drawing & clipping. refine until done. -dc_graph.elaborated_rectangle_shape = function() { - var _shape = dc_graph.rounded_rectangle_shape(); +export function elaboratedRectangleShape() { + const _shape = roundedRectangleShape(); _shape.intersect_vec = function(n, deltaX, deltaY) { - var points = n.dcg_shape.get_points(n.dcg_rx, n.dcg_ry); - return point_on_polygon(points, 0, 0, deltaX, deltaY); + const points = n.dcg_shape.get_points(n.dcg_rx, n.dcg_ry); + return pointOnPolygon(points, 0, 0, deltaX, deltaY); }; delete _shape.useRadius; - var orig_radii = _shape.calc_radii; + const orig_radii = _shape.calc_radii; _shape.calc_radii = function(n, ry, bbox) { - var ret = orig_radii(n, ry, bbox); + const ret = orig_radii(n, ry, bbox); return { rx: Math.max(ret.rx, n.dcg_shape.minrx), - ry: ret.ry + ry: ret.ry, }; }; _shape.create = function(nodeEnter) { - create_maybe_clipped(_shape.parent(), nodeEnter, 'path'); + createMaybeClipped(_shape.parent(), nodeEnter, 'path'); }; _shape.update = function(node) { node.selectAll('path.node-fill,path.node-outline') - .attr('d', function(n) { - return generate_path(n.dcg_shape.get_points(n.dcg_rx, n.dcg_ry), 1, true); - }); + .attr('d', n => generatePath(n.dcg_shape.get_points(n.dcg_rx, n.dcg_ry), 1, true)); }; return _shape; -}; - +} diff --git a/src/spline_paths.js b/src/spline_paths.js index e5d73b0a..75a9e9f1 100644 --- a/src/spline_paths.js +++ b/src/spline_paths.js @@ -1,42 +1,50 @@ -dc_graph.spline_paths = function(pathreader, pathprops, hoverprops, selectprops, pathsgroup) { - var highlight_paths_group = dc_graph.register_highlight_paths_group(pathsgroup || 'highlight-paths-group'); +import { event } from 'd3-selection'; +import { deprecateFunction, property } from './core.js'; +import { registerHighlightPathsGroup } from './highlight_paths_group.js'; +import { mode } from './mode.js'; +import { uniq } from './utils.js'; + +export function splinePaths(pathreader, pathprops, hoverprops, selectprops, pathsgroup) { + const highlight_paths_group = registerHighlightPathsGroup( + pathsgroup || 'highlight-paths-group', + ); pathprops = pathprops || {}; hoverprops = hoverprops || {}; - var _paths = null, _hoverpaths = null, _selected = null; - var _anchor; - var _layer = null; - var _savedPositions = null; + let _paths = null, _hoverpaths = null, _selected = null; + let _anchor; + let _layer = null; + let _savedPositions = null; function paths_changed(nop, eop, paths) { _paths = paths; - var engine = _mode.parent().layoutEngine(), + const engine = _mode.parent().layoutEngine(), localPaths = paths.filter(pathIsPresent); - if(localPaths.length) { - var nidpaths = localPaths.map(function(lpath) { - var strength = pathreader.pathStrength.eval(lpath); - if(typeof strength !== 'number') + if (localPaths.length) { + const nidpaths = localPaths.map(lpath => { + let strength = pathreader.pathStrength.eval(lpath); + if (typeof strength !== 'number') strength = 1; - if(_selected && _selected.indexOf(lpath) !== -1) + if (_selected && _selected.indexOf(lpath) !== -1) strength *= _mode.selectedStrength(); return { nodes: path_keys(lpath), - strength: strength + strength, }; }); engine.paths(nidpaths); } else { engine.paths(null); - if(_savedPositions) + if (_savedPositions) engine.restorePositions(_savedPositions); } - if(_selected) - _selected = _selected.filter(function(p) { return localPaths.indexOf(p) !== -1; }); + if (_selected) + _selected = _selected.filter(p => localPaths.indexOf(p) !== -1); _mode.parent().redraw(); } function select_changed(sp) { - if(sp !== _selected) { + if (sp !== _selected) { _selected = sp; paths_changed(null, null, _paths); } @@ -44,104 +52,106 @@ dc_graph.spline_paths = function(pathreader, pathprops, hoverprops, selectprops, function path_keys(path, unique) { unique = unique !== false; - var keys = pathreader.elementList.eval(path).filter(function(elem) { - return pathreader.elementType.eval(elem) === 'node'; - }).map(function(elem) { - return pathreader.nodeKey.eval(elem); - }); + const keys = pathreader.elementList.eval(path).filter(elem => + pathreader.elementType.eval(elem) === 'node' + ).map(elem => pathreader.nodeKey.eval(elem)); return unique ? uniq(keys) : keys; } // check if entire path is present in this view function pathIsPresent(path) { - return pathreader.elementList.eval(path).every(function(element) { - return pathreader.elementType.eval(element) !== 'node' || - _mode.parent().getWholeNode(pathreader.nodeKey.eval(element)); - }); + return pathreader.elementList.eval(path).every(element => + pathreader.elementType.eval(element) !== 'node' + || _mode.parent().getWholeNode(pathreader.nodeKey.eval(element)) + ); } // get the positions of nodes on path function getNodePositions(path, old) { - return path_keys(path, false).map(function(key) { - var node = _mode.parent().getWholeNode(key); - return {x: old && node.prevX !== undefined ? node.prevX : node.cola.x, - y: old && node.prevY !== undefined ? node.prevY : node.cola.y}; + return path_keys(path, false).map(key => { + const node = _mode.parent().getWholeNode(key); + return { + x: old && node.prevX !== undefined ? node.prevX : node.cola.x, + y: old && node.prevY !== undefined ? node.prevY : node.cola.y, + }; }); - }; + } // insert fake nodes to avoid sharp turns - function insertDummyNodes(path_coord) { + function _insertDummyNodes(path_coord) { function _distance(node1, node2) { - return Math.sqrt(Math.pow((node1.x-node2.x),2) + Math.pow((node1.y-node2.y),2)); + return Math.sqrt((node1.x-node2.x) ** 2+(node1.y-node2.y) ** 2); } - var new_path_coord = []; + const new_path_coord = []; - for(var i = 0; i < path_coord.length; i ++) { + for (let i = 0; i < path_coord.length; i++) { if (i-1 >= 0 && i+1 < path_coord.length) { - if (path_coord[i-1].x === path_coord[i+1].x && - path_coord[i-1].y === path_coord[i+1].y ) { + if ( + path_coord[i-1].x === path_coord[i+1].x + && path_coord[i-1].y === path_coord[i+1].y + ) { // insert node when the previous and next nodes are the same - var x1 = path_coord[i-1].x, y1 = path_coord[i-1].y; - var x2 = path_coord[i].x, y2 = path_coord[i].y; - var dx = x1 - x2, dy = y1 - y2; + const x1 = path_coord[i-1].x, y1 = path_coord[i-1].y; + const x2 = path_coord[i].x, y2 = path_coord[i].y; + const dx = x1-x2, dy = y1-y2; - var v1 = dy / Math.sqrt(dx*dx + dy*dy); - var v2 = - dx / Math.sqrt(dx*dx + dy*dy); + const v1 = dy/Math.sqrt(dx*dx+dy*dy); + const v2 = -dx/Math.sqrt(dx*dx+dy*dy); - var insert_p1 = {'x': null, 'y': null}; - var insert_p2 = {'x': null, 'y': null}; + const insert_p1 = {'x': null, 'y': null}; + const insert_p2 = {'x': null, 'y': null}; - var offset = 10; + const offset = 10; - insert_p1.x = (x1+x2)/2.0 + offset*v1; - insert_p1.y = (y1+y2)/2.0 + offset*v2; + insert_p1.x = (x1+x2)/2.0+offset*v1; + insert_p1.y = (y1+y2)/2.0+offset*v2; - insert_p2.x = (x1+x2)/2.0 - offset*v1; - insert_p2.y = (y1+y2)/2.0 - offset*v2; + insert_p2.x = (x1+x2)/2.0-offset*v1; + insert_p2.y = (y1+y2)/2.0-offset*v2; new_path_coord.push(insert_p1); new_path_coord.push(path_coord[i]); new_path_coord.push(insert_p2); - } else if (_distance(path_coord[i-1], path_coord[i+1]) < pathprops.nearNodesDistance){ + } else if ( + _distance(path_coord[i-1], path_coord[i+1]) < pathprops.nearNodesDistance + ) { // insert node when the previous and next nodes are very close // first node - var x1 = path_coord[i-1].x, y1 = path_coord[i-1].y; - var x2 = path_coord[i].x, y2 = path_coord[i].y; - var dx = x1 - x2, dy = y1 - y2; + let x1 = path_coord[i-1].x, y1 = path_coord[i-1].y; + let x2 = path_coord[i].x, y2 = path_coord[i].y; + let dx = x1-x2, dy = y1-y2; - var v1 = dy / Math.sqrt(dx*dx + dy*dy); - var v2 = - dx / Math.sqrt(dx*dx + dy*dy); + let v1 = dy/Math.sqrt(dx*dx+dy*dy); + let v2 = -dx/Math.sqrt(dx*dx+dy*dy); - var insert_p1 = {'x': null, 'y': null}; + const insert_p1 = {'x': null, 'y': null}; - var offset = 10; + const offset = 10; - insert_p1.x = (x1+x2)/2.0 + offset*v1; - insert_p1.y = (y1+y2)/2.0 + offset*v2; + insert_p1.x = (x1+x2)/2.0+offset*v1; + insert_p1.y = (y1+y2)/2.0+offset*v2; // second node x1 = path_coord[i].x; y1 = path_coord[i].y; x2 = path_coord[i+1].x; y2 = path_coord[i+1].y; - dx = x1 - x2; - dy = y1 - y2; + dx = x1-x2; + dy = y1-y2; - v1 = dy / Math.sqrt(dx*dx + dy*dy); - v2 = - dx / Math.sqrt(dx*dx + dy*dy); + v1 = dy/Math.sqrt(dx*dx+dy*dy); + v2 = -dx/Math.sqrt(dx*dx+dy*dy); - var insert_p2 = {'x': null, 'y': null}; + const insert_p2 = {'x': null, 'y': null}; - insert_p2.x = (x1+x2)/2.0 + offset*v1; - insert_p2.y = (y1+y2)/2.0 + offset*v2; + insert_p2.x = (x1+x2)/2.0+offset*v1; + insert_p2.y = (y1+y2)/2.0+offset*v2; new_path_coord.push(insert_p1); new_path_coord.push(path_coord[i]); new_path_coord.push(insert_p2); - - } - else { + } else { new_path_coord.push(path_coord[i]); } } else { @@ -152,331 +162,343 @@ dc_graph.spline_paths = function(pathreader, pathprops, hoverprops, selectprops, } // helper functions - var vecDot = function(v0, v1) { return v0.x*v1.x+v0.y*v1.y; }; - var vecMag = function(v) { return Math.sqrt(v.x*v.x + v.y*v.y); }; - var l2Dist = function(p1, p2) { + const vecDot = function(v0, v1) { + return v0.x*v1.x+v0.y*v1.y; + }; + const vecMag = function(v) { + return Math.sqrt(v.x*v.x+v.y*v.y); + }; + const l2Dist = function(p1, p2) { return Math.sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); }; function drawCardinalSpline(points, lineTension, avoidSharpTurn, angleThreshold) { - var c = lineTension || 0; - avoidSharpTurn = avoidSharpTurn !== false; - angleThreshold = angleThreshold || 0.02; - - // get the path without self loops - var path_list = [points[0]]; - for(var i = 1; i < points.length; i ++) { - if(l2Dist(points[i], path_list[path_list.length-1]) > 1e-6) { - path_list.push(points[i]); + const c = lineTension || 0; + avoidSharpTurn = avoidSharpTurn !== false; + angleThreshold = angleThreshold || 0.02; + + // get the path without self loops + const path_list = [points[0]]; + for (let i = 1; i < points.length; i++) { + if (l2Dist(points[i], path_list[path_list.length-1]) > 1e-6) { + path_list.push(points[i]); + } } - } - - // repeat first and last node - points = [path_list[0]]; - points = points.concat(path_list); - points.push(path_list[path_list.length-1]); - - // a segment is a list of three points: [c0, c1, p1], - // representing the coordinates in "C x0,y0,x1,y1,x,y" in svg:path - var segments = []; // control points - for(var i = 1; i < points.length-2; i ++) { - // generate svg:path - var m_0_x = (1-c)*(points[i+1].x - points[i-1].x)/2; - var m_0_y = (1-c)*(points[i+1].y - points[i-1].y)/2; - - var m_1_x = (1-c)*(points[i+2].x - points[i].x)/2; - var m_1_y = (1-c)*(points[i+2].y - points[i].y)/2; - - var p0 = points[i]; - var p1 = points[i+1]; - var c0 = p0; - if(i !== 1) { - c0 = {x: p0.x+(m_0_x/3), y:p0.y+(m_0_y/3)}; + + // repeat first and last node + points = [path_list[0]]; + points = points.concat(path_list); + points.push(path_list[path_list.length-1]); + + // a segment is a list of three points: [c0, c1, p1], + // representing the coordinates in "C x0,y0,x1,y1,x,y" in svg:path + const segments = []; // control points + for (let i = 1; i < points.length-2; i++) { + // generate svg:path + const m_0_x = (1-c)*(points[i+1].x-points[i-1].x)/2; + const m_0_y = (1-c)*(points[i+1].y-points[i-1].y)/2; + + const m_1_x = (1-c)*(points[i+2].x-points[i].x)/2; + const m_1_y = (1-c)*(points[i+2].y-points[i].y)/2; + + const p0 = points[i]; + const p1 = points[i+1]; + let c0 = p0; + if (i !== 1) { + c0 = {x: p0.x+(m_0_x/3), y: p0.y+(m_0_y/3)}; + } + let c1 = p1; + if (i !== points.length-3) { + c1 = {x: p1.x-(m_1_x/3), y: p1.y-(m_1_y/3)}; + } + + // detect special case by calculating the angle + if (avoidSharpTurn) { + const v0 = {x: points[i-1].x-points[i].x, y: points[i-1].y-points[i].y}; + const v1 = {x: points[i+1].x-points[i].x, y: points[i+1].y-points[i].y}; + let acosValue = vecDot(v0, v1)/(vecMag(v0)*vecMag(v1)); + acosValue = Math.max(-1, Math.min(1, acosValue)); + const angle = Math.acos(acosValue); + + if (angle <= angleThreshold) { + const m_x = (1-c)*(points[i].x-points[i-1].x)/2; + const m_y = (1-c)*(points[i].y-points[i-1].y)/2; + const k = 2; + + const cp1 = {x: p0.x+k*(-m_y/3), y: p0.y+k*(m_x/3)}; + const cp2 = {x: p0.x-k*(-m_y/3), y: p0.y-k*(m_x/3)}; + // CP_1CP_2 + const vCP = {x: cp1.x-cp2.x, y: cp1.y-cp2.y}; // vector cp1->cp2 + const vPN = {x: points[i-2].x-points[i+2].x, y: points[i-2].y-points[i+2].y}; // vector Previous->Next + if (vecDot(vCP, vPN) > 0) { + c0 = cp1; + segments[segments.length-1][1] = cp2; + } else { + c0 = cp2; + segments[segments.length-1][1] = cp1; + } + } + } + + segments.push([c0, c1, p1]); } - var c1 = p1; - if(i !== points.length-3) { - c1 = {x: p1.x-(m_1_x/3), y:p1.y-(m_1_y/3)}; + + let path_d = `M${points[0].x},${points[0].y}`; + for (let i = 0; i < segments.length; i++) { + const s = segments[i]; + path_d += `C${s[0].x},${s[0].y}`; + path_d += `,${s[1].x},${s[1].y}`; + path_d += `,${s[2].x},${s[2].y}`; } + return path_d; + } - // detect special case by calculating the angle - if(avoidSharpTurn) { - var v0 = {x:points[i-1].x - points[i].x, y:points[i-1].y - points[i].y}; - var v1 = {x:points[i+1].x - points[i].x, y:points[i+1].y - points[i].y}; - var acosValue = vecDot(v0,v1) / (vecMag(v0)*vecMag(v1)); - acosValue = Math.max(-1, Math.min(1, acosValue)); - var angle = Math.acos( acosValue ); - - if(angle <= angleThreshold ){ - var m_x = (1-c)*(points[i].x - points[i-1].x)/2; - var m_y = (1-c)*(points[i].y - points[i-1].y)/2; - var k = 2; - - var cp1 = {x: p0.x+k*(-m_y/3), y:p0.y+k*(m_x/3)}; - var cp2 = {x: p0.x-k*(-m_y/3), y:p0.y-k*(m_x/3)}; - // CP_1CP_2 - var vCP = {x: cp1.x-cp2.x, y:cp1.y-cp2.y}; // vector cp1->cp2 - var vPN = {x: points[i-2].x - points[i+2].x, y:points[i-2].y-points[i+2].y}; // vector Previous->Next - if(vecDot(vCP, vPN) > 0) { - c0 = cp1; - segments[segments.length-1][1] = cp2; + function drawDedicatedLoops(points, _lineTension, _avoidSharpTurn, _angleThreshold) { + // get loops as segments + let p1 = 0, p2 = 1; + const seg_list = []; // (start, end) + while (p1 < points.length-1 && p2 < points.length) { + if (l2Dist(points[p1], points[p2]) < 1e-6) { + const repeated = points[p2]; + while (p2 < points.length && l2Dist(points[p2], repeated) < 1e-6) p2++; + seg_list.push({'start': Math.max(0, p1-1), 'end': Math.min(points.length-1, p2)}); + p1 = p2; + p2 = p1+1; } else { - c0 = cp2; - segments[segments.length-1][1] = cp1; + p1++; + p2++; } - } } - segments.push([c0,c1,p1]); - } - - var path_d = "M"+points[0].x+","+points[0].y; - for(var i = 0; i < segments.length; i ++) { - var s = segments[i]; - path_d += "C"+s[0].x+","+s[0].y; - path_d += ","+s[1].x+","+s[1].y; - path_d += ","+s[2].x+","+s[2].y; - } - return path_d; - } + let loopCurves = ''; + for (let i = 0; i < seg_list.length; i++) { + const segment = seg_list[i]; + const loopCount = segment.end-segment.start-2; + const anchorPoint = points[segment.start+1]; + + // the vector from previous node to next node + let vec_pre_next = { + x: points[segment.end].x-points[segment.start].x, + y: points[segment.end].y-points[segment.start].y, + }; + + // when previous node and next node are the same node, we need to handle + // them differently. + // e.g. for a loop segment A->B->B->A, we use the perpendicular vector perp_AB + // instead of vector AA(which is vec_pre_next in this case). + if (vecMag(vec_pre_next) == 0) { + vec_pre_next = { + x: -(points[segment.end].y-anchorPoint.y), + y: points[segment.end].x-anchorPoint.x, + }; + } - function drawDedicatedLoops(points, lineTension, avoidSharpTurn, angleThreshold) { - // get loops as segments - var p1 = 0, p2 = 1; - var seg_list = []; // (start, end) - while(p1 < points.length-1 && p2 < points.length) { - if(l2Dist(points[p1], points[p2]) < 1e-6) { - var repeated = points[p2]; - while(p2 < points.length && l2Dist(points[p2], repeated) < 1e-6) p2++; - seg_list.push({'start': Math.max(0, p1-1), 'end': Math.min(points.length-1, p2)}); - p1 = p2; - p2 = p1+1; - } else { - p1++; - p2++; - } - } - - var loopCurves = ""; - for(var i = 0; i < seg_list.length; i ++) { - var segment = seg_list[i]; - var loopCount = segment.end - segment.start - 2; - var anchorPoint = points[segment.start+1]; - - // the vector from previous node to next node - var vec_pre_next = { - x: points[segment.end].x-points[segment.start].x, - y: points[segment.end].y-points[segment.start].y - }; - - // when previous node and next node are the same node, we need to handle - // them differently. - // e.g. for a loop segment A->B->B->A, we use the perpendicular vector perp_AB - // instead of vector AA(which is vec_pre_next in this case). - if(vecMag(vec_pre_next) == 0) { - vec_pre_next = { - x: -(points[segment.end].y-anchorPoint.y), - y: points[segment.end].x-anchorPoint.x - }; - } + // unit length vector + const vec_pre_next_unit = { + x: vec_pre_next.x/vecMag(vec_pre_next), + y: vec_pre_next.y/vecMag(vec_pre_next), + }; + const vec_pre_next_perp = { + x: -vec_pre_next.y/vecMag(vec_pre_next), + y: vec_pre_next.x/vecMag(vec_pre_next), + }; + + let insertP; + for (let j = 0; j < loopCount; j++) { + // change the control points every time this loop appears + const cp_k = 15+2*j; + + // calculate c1 and c4, their tangent match the tangent at anchorPoint + const c1 = { + x: anchorPoint.x+cp_k*vec_pre_next_unit.x, + y: anchorPoint.y+cp_k*vec_pre_next_unit.y, + }; - // unit length vector - var vec_pre_next_unit = { - x: vec_pre_next.x / vecMag(vec_pre_next), - y: vec_pre_next.y / vecMag(vec_pre_next) - }; - var vec_pre_next_perp = { - x: -vec_pre_next.y / vecMag(vec_pre_next), - y: vec_pre_next.x / vecMag(vec_pre_next) - }; - - var insertP; - for(var j = 0; j < loopCount; j ++) { - var c1,c2,c3,c4; - - // change the control points every time this loop appears - var cp_k = 15+2*j; - - // calculate c1 and c4, their tangent match the tangent at anchorPoint - c1 = { - x: anchorPoint.x + cp_k*vec_pre_next_unit.x, - y: anchorPoint.y + cp_k*vec_pre_next_unit.y - }; - - c4 = { - x: anchorPoint.x - cp_k*vec_pre_next_unit.x, - y: anchorPoint.y - cp_k*vec_pre_next_unit.y - }; - - // change the location of inserted virtual point every time this loop appears - var control_k = 25+5*j; - var insertP1 = { - x: anchorPoint.x+vec_pre_next_perp.x*control_k, - y: anchorPoint.y+vec_pre_next_perp.y*control_k - }; - var insertP2 = { - x: anchorPoint.x-vec_pre_next_perp.x*control_k, - y: anchorPoint.y-vec_pre_next_perp.y*control_k - }; - var vec_i_to_next = { - x: points[segment.end].x - anchorPoint.x, - y: points[segment.end].y - anchorPoint.y - }; - var vec_i_to_insert = { - x: insertP1.x - anchorPoint.x, - y: insertP1.y - anchorPoint.y - }; - insertP = insertP1; - if(vecDot(vec_i_to_insert, vec_i_to_next) > 0) { - insertP = insertP2; - } - - // calculate c2 and c3 based on insertP - c2 = { - x: insertP.x + cp_k*vec_pre_next_unit.x, - y: insertP.y + cp_k*vec_pre_next_unit.y - }; - - c3 = { - x: insertP.x - cp_k*vec_pre_next_unit.x, - y: insertP.y - cp_k*vec_pre_next_unit.y - }; - - var curve = "M"+anchorPoint.x+","+anchorPoint.y; - curve += "C"+c1.x+","+c1.y+","+c2.x+","+c2.y+","+insertP.x+","+insertP.y; - curve += "C"+c3.x+","+c3.y+","+c4.x+","+c4.y+","+anchorPoint.x+","+anchorPoint.y; - - loopCurves += curve; + const c4 = { + x: anchorPoint.x-cp_k*vec_pre_next_unit.x, + y: anchorPoint.y-cp_k*vec_pre_next_unit.y, + }; + + // change the location of inserted virtual point every time this loop appears + const control_k = 25+5*j; + const insertP1 = { + x: anchorPoint.x+vec_pre_next_perp.x*control_k, + y: anchorPoint.y+vec_pre_next_perp.y*control_k, + }; + const insertP2 = { + x: anchorPoint.x-vec_pre_next_perp.x*control_k, + y: anchorPoint.y-vec_pre_next_perp.y*control_k, + }; + const vec_i_to_next = { + x: points[segment.end].x-anchorPoint.x, + y: points[segment.end].y-anchorPoint.y, + }; + const vec_i_to_insert = { + x: insertP1.x-anchorPoint.x, + y: insertP1.y-anchorPoint.y, + }; + insertP = insertP1; + if (vecDot(vec_i_to_insert, vec_i_to_next) > 0) { + insertP = insertP2; + } + + // calculate c2 and c3 based on insertP + const c2 = { + x: insertP.x+cp_k*vec_pre_next_unit.x, + y: insertP.y+cp_k*vec_pre_next_unit.y, + }; + + const c3 = { + x: insertP.x-cp_k*vec_pre_next_unit.x, + y: insertP.y-cp_k*vec_pre_next_unit.y, + }; + + let curve = `M${anchorPoint.x},${anchorPoint.y}`; + curve += `C${c1.x},${c1.y},${c2.x},${c2.y},${insertP.x},${insertP.y}`; + curve += `C${c3.x},${c3.y},${c4.x},${c4.y},${anchorPoint.x},${anchorPoint.y}`; + + loopCurves += curve; + } } - } - return loopCurves; + return loopCurves; } // convert original path data into function genPath(originalPoints, old, lineTension, avoidSharpTurn, angleThreshold) { - // get coordinates - var path_coord = getNodePositions(originalPoints, old); - if(path_coord.length < 2) return ""; + // get coordinates + const path_coord = getNodePositions(originalPoints, old); + if (path_coord.length < 2) return ''; - var result = ""; - // process the points and treat them differently: - // 1. sub-path without self loop - result += drawCardinalSpline(path_coord, lineTension, avoidSharpTurn, angleThreshold); + let result = ''; + // process the points and treat them differently: + // 1. sub-path without self loop + result += drawCardinalSpline(path_coord, lineTension, avoidSharpTurn, angleThreshold); - // 2. a list of loop segments - result += drawDedicatedLoops(path_coord, lineTension, avoidSharpTurn, angleThreshold); + // 2. a list of loop segments + result += drawDedicatedLoops(path_coord, lineTension, avoidSharpTurn, angleThreshold); - return result; + return result; } // draw the spline for paths function drawSpline(paths) { - if(paths === null) { + if (paths === null) { _savedPositions = _mode.parent().layoutEngine().savePositions(); return; } paths = paths.filter(pathIsPresent); - var hoverpaths = _hoverpaths || [], + const hoverpaths = _hoverpaths || [], selected = _selected || []; // edge spline - var edge = _layer.selectAll(".spline-edge").data(paths, function(path) { return path_keys(path).join(','); }); + let edge = _layer.selectAll('.spline-edge').data(paths, path => path_keys(path).join(',')); edge.exit().remove(); - var edgeEnter = edge.enter().append("svg:path") + const edgeEnter = edge.enter().append('svg:path') .attr('class', 'spline-edge') - .attr('id', function(d, i) { return "spline-path-"+i; }) + .attr('id', (d, i) => `spline-path-${i}`) .attr('stroke-width', pathprops.edgeStrokeWidth || 1) .attr('fill', 'none') - .attr('d', function(d) { return genPath(d, true, pathprops.lineTension, _mode.avoidSharpTurns()); }); + .attr('d', d => genPath(d, true, pathprops.lineTension, _mode.avoidSharpTurns())); + edge = edge.merge(edgeEnter); edge - .attr('stroke', function(p) { - return selected.indexOf(p) !== -1 && selectprops.edgeStroke || - hoverpaths.indexOf(p) !== -1 && hoverprops.edgeStroke || - pathprops.edgeStroke || 'black'; - }) - .attr('opacity', function(p) { - return selected.indexOf(p) !== -1 && selectprops.edgeOpacity || - hoverpaths.indexOf(p) !== -1 && hoverprops.edgeOpacity || - pathprops.edgeOpacity || 1; - }); + .attr('stroke', p => + selected.indexOf(p) !== -1 && selectprops.edgeStroke + || hoverpaths.indexOf(p) !== -1 && hoverprops.edgeStroke + || pathprops.edgeStroke || 'black') + .attr('opacity', p => + selected.indexOf(p) !== -1 && selectprops.edgeOpacity + || hoverpaths.indexOf(p) !== -1 && hoverprops.edgeOpacity + || pathprops.edgeOpacity || 1); function path_order(p) { - return hoverpaths.indexOf(p) !== -1 ? 2 : - selected.indexOf(p) !== -1 ? 1 : - 0; + return hoverpaths.indexOf(p) !== -1 + ? 2 + : selected.indexOf(p) !== -1 + ? 1 + : 0; } - edge.sort(function(a, b) { - return path_order(a) - path_order(b); - }); + edge.sort((a, b) => path_order(a)-path_order(b)); _layer.selectAll('.spline-edge-hover') - .each(function() {this.parentNode.appendChild(this);}); + .each(function() { + this.parentNode.appendChild(this); + }); edge.transition().duration(_mode.parent().transitionDuration()) - .attr('d', function(d) { return genPath(d, false, pathprops.lineTension, _mode.avoidSharpTurns()); }); + .attr('d', d => genPath(d, false, pathprops.lineTension, _mode.avoidSharpTurns())); // another wider copy of the edge just for hover events - var edgeHover = _layer.selectAll('.spline-edge-hover') - .data(paths, function(path) { return path_keys(path).join(','); }); + let edgeHover = _layer.selectAll('.spline-edge-hover') + .data(paths, path => path_keys(path).join(',')); edgeHover.exit().remove(); - var edgeHoverEnter = edgeHover.enter().append('svg:path') + const edgeHoverEnter = edgeHover.enter().append('svg:path') .attr('class', 'spline-edge-hover') - .attr('d', function(d) { return genPath(d, true, pathprops.lineTension, _mode.avoidSharpTurns()); }) + .attr('d', d => genPath(d, true, pathprops.lineTension, _mode.avoidSharpTurns())) .attr('opacity', 0) .attr('stroke', 'green') - .attr('stroke-width', (pathprops.edgeStrokeWidth || 1) + 4) + .attr('stroke-width', (pathprops.edgeStrokeWidth || 1)+4) .attr('fill', 'none') - .on('mouseover.spline-paths', function(d) { + .on('mouseover.spline-paths', d => { highlight_paths_group.hover_changed([d]); - }) - .on('mouseout.spline-paths', function(d) { + }) + .on('mouseout.spline-paths', _d => { highlight_paths_group.hover_changed(null); - }) - .on('click.spline-paths', function(d) { - var selected = _selected && _selected.slice(0) || [], - i = selected.indexOf(d); - if(i !== -1) + }) + .on('click.spline-paths', d => { + let selected = _selected && _selected.slice(0) || []; + const i = selected.indexOf(d); + if (i !== -1) selected.splice(i, 1); - else if(d3.event.shiftKey) + else if (event.shiftKey) selected.push(d); else selected = [d]; highlight_paths_group.select_changed(selected); - }); + }); + edgeHover = edgeHover.merge(edgeHoverEnter); edgeHover.transition().duration(_mode.parent().transitionDuration()) - .attr('d', function(d) { return genPath(d, false, pathprops.lineTension, _mode.avoidSharpTurns()); }); - }; + .attr('d', d => genPath(d, false, pathprops.lineTension, _mode.avoidSharpTurns())); + } - function draw(diagram, node, edge, ehover) { + function draw(_diagram, _node, _edge, _ehover) { _layer = _mode.parent().select('g.draw').selectAll('g.spline-layer').data([0]); _layer.enter().append('g').attr('class', 'spline-layer'); drawSpline(_paths); } - function remove(diagram, node, edge, ehover) { + function remove(_diagram, _node, _edge, _ehover) { } - var _mode = dc_graph.mode('draw-spline-paths', { + const _mode = mode('draw-spline-paths', { laterDraw: true, - draw: draw, - remove: function(diagram, node, edge, ehover) { + draw, + remove(diagram, node, edge, ehover) { remove(diagram, node, edge, ehover); return this; }, - parent: function(p) { - if(p) + parent(p) { + if (p) _anchor = p.anchorName(); highlight_paths_group - .on('paths_changed.draw-spline-paths-' + _anchor, p ? paths_changed : null) - .on('select_changed.draw-spline-paths-' + _anchor, p ? select_changed : null) - .on('hover_changed.draw-spline-paths-' + _anchor, p ? function(hpaths) { - _hoverpaths = hpaths; - drawSpline(_paths); - } : null); - } + .on(`paths_changed.draw-spline-paths-${_anchor}`, p ? paths_changed : null) + .on(`select_changed.draw-spline-paths-${_anchor}`, p ? select_changed : null) + .on( + `hover_changed.draw-spline-paths-${_anchor}`, + p + ? hpaths => { + _hoverpaths = hpaths; + drawSpline(_paths); + } + : null, + ); + }, }); _mode.selectedStrength = property(1); _mode.avoidSharpTurns = property(true); return _mode; -}; +} -dc_graph.draw_spline_paths = deprecate_function("draw_spline_paths has been renamed spline_paths, please update", dc_graph.spline_paths); +export const drawSplinePaths = deprecateFunction( + 'draw_spline_paths has been renamed spline_paths, please update', + splinePaths, +); diff --git a/src/supergraph.js b/src/supergraph.js index db0f0dbf..eb296728 100644 --- a/src/supergraph.js +++ b/src/supergraph.js @@ -1,26 +1,26 @@ -dc_graph.supergraph = function(data, options) { - if(!dc_graph.supergraph.pattern) { - var mg = metagraph; - var graph_and_subgraph = { +export function supergraph(data, options) { + if (!supergraph.pattern) { + const mg = metagraph; + const graph_and_subgraph = { nodes: { graph: mg.graph_pattern(options), sg: mg.subgraph_pattern(options), - subgraph: mg.graph_pattern(options) + subgraph: mg.graph_pattern(options), }, edges: { to_sg: { source: 'graph', target: 'sg', - input: 'parent' + input: 'parent', }, from_sg: { source: 'subgraph', target: 'sg', - input: 'child' - } - } + input: 'child', + }, + }, }; - dc_graph.supergraph.pattern = mg.compose(mg.graph_detect(graph_and_subgraph)); + supergraph.pattern = mg.compose(mg.graph_detect(graph_and_subgraph)); } - return dc_graph.supergraph.pattern.node('graph.Graph').value().create(data); -}; + return supergraph.pattern.node('graph.Graph').value().create(data); +} diff --git a/src/symbol_port_style.js b/src/symbol_port_style.js index 813b0282..0f4d359b 100644 --- a/src/symbol_port_style.js +++ b/src/symbol_port_style.js @@ -1,21 +1,45 @@ -dc_graph.symbol_port_style = function() { - var _style = {}; - var _nodePorts, _node; - var _drawConduct; +import { range, shuffle } from 'd3-array'; +import { set } from 'd3-collection'; +import { easeBounce, easeSin } from 'd3-ease'; +import { scaleOrdinal } from 'd3-scale'; +import { event as d3Event, select } from 'd3-selection'; +import { symbol, symbols } from 'd3-shape'; +import { getBBoxNoThrow, identity, property } from './core.js'; +import { cascade } from './utils.js'; + +export function symbolPortStyle() { + const _style = {}; + let _nodePorts, _node; + let _drawConduct; _style.symbolScale = property(null); - _style.colorScale = property(d3.scale.ordinal().range( - // colorbrewer light qualitative scale - d3.shuffle(['#8dd3c7','#ffffb3','#bebada','#fb8072','#80b1d3','#fdb462', - '#b3de69','#fccde5','#d9d9d9','#bc80bd','#ccebc5','#ffed6f']))); + _style.colorScale = property( + scaleOrdinal().range( + // colorbrewer light qualitative scale + shuffle([ + '#8dd3c7', + '#ffffb3', + '#bebada', + '#fb8072', + '#80b1d3', + '#fdb462', + '#b3de69', + '#fccde5', + '#d9d9d9', + '#bc80bd', + '#ccebc5', + '#ffed6f', + ]), + ), + ); function name_or_edge(p) { return p.named ? p.name : _style.parent().edgeKey.eval(p.edges[0]); } _style.symbol = _style.portSymbol = property(name_or_edge, false); // non standard properties taking "outer datum" _style.color = _style.portColor = property(name_or_edge, false); - _style.outline = property(dc_graph.symbol_port_style.outline.circle()); - _style.content = property(dc_graph.symbol_port_style.content.d3symbol()); + _style.outline = property(symbolPortStyle.outline.circle()); + _style.content = property(symbolPortStyle.content.d3symbol()); _style.smallRadius = _style.portRadius = property(7); _style.mediumRadius = _style.portHoverNodeRadius = property(10); _style.largeRadius = _style.portHoverPortRadius = property(14); @@ -25,73 +49,70 @@ dc_graph.symbol_port_style = function() { _style.outlineStroke = _style.portBackgroundStroke = property(null); _style.outlineStrokeWidth = _style.portBackgroundStrokeWidth = property(null); _style.padding = _style.portPadding = property(2); - _style.label = _style.portLabel = _style.portText = property(function(p) { - return p.name; - }); + _style.label = _style.portLabel = _style.portText = property(p => p.name); _style.portLabelPadding = property({x: 5, y: 5}); _style.cascade = cascade(_style); _style.portPosition = function(p) { - var l = Math.hypot(p.pos.x, p.pos.y), - u = {x: p.pos.x / l, y: p.pos.y / l}, + const l = Math.hypot(p.pos.x, p.pos.y), + u = {x: p.pos.x/l, y: p.pos.y/l}, disp = _style.displacement.eval(p); - return {x: p.pos.x + disp * u.x, y: p.pos.y + disp * u.y}; + return {x: p.pos.x+disp*u.x, y: p.pos.y+disp*u.y}; }; _style.portBounds = function(p) { - var R = _style.largeRadius.eval(p), + const R = _style.largeRadius.eval(p), pos = _style.portPosition(p); return { - left: pos.x - R/2, - top: pos.y - R/2, - right: pos.x + R/2, - bottom: pos.y + R/2 + left: pos.x-R/2, + top: pos.y-R/2, + right: pos.x+R/2, + bottom: pos.y+R/2, }; }; function symbol_fill(p) { - var symcolor = _style.color.eval(p); - return symcolor ? - (_style.colorScale() ? _style.colorScale()(symcolor) : symcolor) : - 'none'; + const symcolor = _style.color.eval(p); + return symcolor + ? (_style.colorScale() ? _style.colorScale()(symcolor) : symcolor) + : 'none'; } function port_transform(p) { - var pos = _style.portPosition(p); - return 'translate(' + pos.x + ',' + pos.y + ')'; + const pos = _style.portPosition(p); + return `translate(${pos.x},${pos.y})`; } function port_symbol(p) { - if(!_style.symbolScale()) - _style.symbolScale(d3.scale.ordinal().range(d3.shuffle(_style.content().enum()))); - var symname = _style.symbol.eval(p); + if (!_style.symbolScale()) + _style.symbolScale(scaleOrdinal().range(shuffle(_style.content().enum()))); + const symname = _style.symbol.eval(p); return symname && (_style.symbolScale() ? _style.symbolScale()(symname) : symname); } function is_left(p) { return p.vec[0] < 0; } function hover_radius(p) { - switch(p.state) { - case 'large': - return _style.largeRadius.eval(p); - case 'medium': - return _style.mediumRadius.eval(p); - case 'small': - default: - return _style.smallRadius.eval(p); + switch (p.state) { + case 'large': + return _style.largeRadius.eval(p); + case 'medium': + return _style.mediumRadius.eval(p); + case 'small': + default: + return _style.smallRadius.eval(p); } } function shimmer_radius(p) { - return /-medium$/.test(p.state) ? - _style.mediumRadius.eval(p) : - _style.largeRadius.eval(p); + return /-medium$/.test(p.state) + ? _style.mediumRadius.eval(p) + : _style.largeRadius.eval(p); } // fall back to node aesthetics if not defined for port function outline_fill(p) { - var scale, fill; - if(_style.outlineFill.eval(p)) { + let scale, fill; + if (_style.outlineFill.eval(p)) { scale = _style.outlineFillScale() || identity; fill = _style.outlineFill.eval(p); - } - else { + } else { scale = _style.parent().nodeFillScale() || identity; fill = _style.parent().nodeFill.eval(p.node); } @@ -101,372 +122,338 @@ dc_graph.symbol_port_style = function() { return _style.outlineStroke.eval(p) || _style.parent().nodeStroke.eval(p.node); } function outline_stroke_width(p) { - var sw = _style.outlineStrokeWidth.eval(p); + const sw = _style.outlineStrokeWidth.eval(p); return typeof sw === 'number' ? sw : _style.parent().nodeStrokeWidth.eval(p.node); } _style.animateNodes = function(nids, before) { - var setn = d3.set(nids); - var node = _node - .filter(function(n) { - return setn.has(_style.parent().nodeKey.eval(n)); - }); - var symbol = _style.parent().selectNodePortsOfStyle(node, _style.parent().portStyle.nameOf(this)); - var shimmer = symbol.filter(function(p) { return /^shimmer/.test(p.state); }), - nonshimmer = symbol.filter(function(p) { return !/^shimmer/.test(p.state); }); - if(shimmer.size()) { - if(before) - before.each('end', repeat); + const setn = set(nids); + const node = _node + .filter(n => setn.has(_style.parent().nodeKey.eval(n))); + const symbol = _style.parent().selectNodePortsOfStyle( + node, + _style.parent().portStyle.nameOf(this), + ); + const shimmer = symbol.filter(p => /^shimmer/.test(p.state)), + nonshimmer = symbol.filter(p => !/^shimmer/.test(p.state)); + if (shimmer.size()) { + if (before) + before.on('end', repeat); else repeat(); } function repeat() { - var shimin = shimmer.transition() - .duration(1000) - .ease("bounce"); + const shimin = shimmer.transition() + .duration(1000) + .ease(easeBounce); shimin.selectAll('.port-outline') - .call(_style.outline().draw(function(p) { - return shimmer_radius(p) + _style.portPadding.eval(p); - })); + .call(_style.outline().draw(p => shimmer_radius(p)+_style.portPadding.eval(p))); shimin.selectAll('.port-symbol') .call(_style.content().draw(port_symbol, shimmer_radius)); - var shimout = shimin.transition() - .duration(1000) - .ease('sin'); + const shimout = shimin.transition() + .duration(1000) + .ease(easeSin); shimout.selectAll('.port-outline') - .call(_style.outline().draw(function(p) { - return _style.smallRadius.eval(p) + _style.portPadding.eval(p); - })); + .call( + _style.outline().draw(p => + _style.smallRadius.eval(p)+_style.portPadding.eval(p) + ), + ); shimout.selectAll('.port-symbol') .call(_style.content().draw(port_symbol, _style.smallRadius.eval)); - shimout.each("end", repeat); + shimout.on('end', repeat); } - var trans = nonshimmer.transition() - .duration(250); + const trans = nonshimmer.transition() + .duration(250); trans.selectAll('.port-outline') - .call(_style.outline().draw(function(p) { - return hover_radius(p) + _style.portPadding.eval(p); - })); + .call(_style.outline().draw(p => hover_radius(p)+_style.portPadding.eval(p))); trans.selectAll('.port-symbol') .call(_style.content().draw(port_symbol, hover_radius)); - function text_showing(p) { - return p.state === 'large' || p.state === 'medium'; - } + const text_showing = p => p.state === 'large' || p.state === 'medium'; trans.selectAll('text.port-label') - .attr({ - opacity: function(p) { - return text_showing(p) ? 1 : 0; - }, - 'pointer-events': function(p) { - return text_showing(p) ? 'auto' : 'none'; - } - }); + .attr('opacity', p => text_showing(p) ? 1 : 0) + .attr('pointer-events', p => text_showing(p) ? 'auto' : 'none'); trans.selectAll('rect.port-label-background') - .attr('opacity', function(p) { - return text_showing(p) ? 1 : 0; - }); + .attr('opacity', p => text_showing(p) ? 1 : 0); // bring all nodes which have labels showing to the front - _node.filter(function(n) { - var ports = _nodePorts[_style.parent().nodeKey.eval(n)]; + _node.filter(n => { + const ports = _nodePorts[_style.parent().nodeKey.eval(n)]; return ports && ports.some(text_showing); }).each(function() { this.parentNode.appendChild(this); }); // bring all active ports to the front - symbol.filter(function(p) { - return p.state !== 'small'; - }).each(function() { + symbol.filter(p => p.state !== 'small').each(function() { this.parentNode.appendChild(this); }); return trans; }; - _style.eventPort = function() { - var parent = d3.select(d3.event.target.parentNode); - if(d3.event.target.parentNode.tagName === 'g' && parent.classed('port')) + _style.eventPort = function(event) { + // In D3 v5, use the global event if no event passed + const evt = event || d3Event; + if (!evt || !evt.target) return null; + const parent = select(evt.target.parentNode); + if (evt.target.parentNode.tagName === 'g' && parent.classed('port')) return parent.datum(); return null; }; _style.drawPorts = function(ports, nodePorts, node) { - _nodePorts = nodePorts; _node = node; - var port = ports.data(function(n) { - return nodePorts[_style.parent().nodeKey.eval(n)] || []; - }, name_or_edge); + _nodePorts = nodePorts; + _node = node; + let port = ports.data(n => nodePorts[_style.parent().nodeKey.eval(n)] || [], name_or_edge); port.exit().remove(); - var portEnter = port.enter().append('g') - .attr({ - class: 'port', - transform: port_transform - }); + const portEnter = port.enter().append('g') + .attr('class', 'port') + .attr('transform', port_transform); + port = port.merge(portEnter); port.transition('port-position') .duration(_style.parent().stagedDuration()) .delay(_style.parent().stagedDelay(false)) // need to account for enters as well - .attr({ - transform: port_transform - }); + .attr('transform', port_transform); - var outline = port.selectAll('.port-outline').data(function(p) { - return outline_fill(p) !== 'none' ? [p] : []; - }); + let outline = port.selectAll('.port-outline').data(p => + outline_fill(p) !== 'none' ? [p] : [] + ); outline.exit().remove(); - var outlineEnter = outline.enter().append(_style.outline().tag()) - .attr({ - class: 'port-outline', - fill: outline_fill, - 'stroke-width': outline_stroke_width, - stroke: outline_stroke - }); - if(_style.outline().init) + const outlineEnter = outline.enter().append(_style.outline().tag()) + .attr('class', 'port-outline') + .attr('fill', outline_fill) + .attr('stroke-width', outline_stroke_width) + .attr('stroke', outline_stroke); + outline = outline.merge(outlineEnter); + if (_style.outline().init) outlineEnter.call(_style.outline().init); outlineEnter - .call(_style.outline().draw(function(p) { - return _style.smallRadius.eval(p) + _style.portPadding.eval(p); - })); + .call( + _style.outline().draw(p => _style.smallRadius.eval(p)+_style.portPadding.eval(p)), + ); // only position and size are animated (?) - anyway these are not on the node // and they are typically used to indicate selection which should be fast outline - .attr({ - fill: outline_fill, - 'stroke-width': outline_stroke_width, - stroke: outline_stroke - }); + .attr('fill', outline_fill) + .attr('stroke-width', outline_stroke_width) + .attr('stroke', outline_stroke); outline.transition() .duration(_style.parent().stagedDuration()) .delay(_style.parent().stagedDelay(false)) // need to account for enters as well - .call(_style.outline().draw(function(p) { - return _style.smallRadius.eval(p) + _style.portPadding.eval(p); - })); + .call( + _style.outline().draw(p => _style.smallRadius.eval(p)+_style.portPadding.eval(p)), + ); - var symbolEnter = portEnter.append(_style.content().tag()) + const _symbolEnter = portEnter.append(_style.content().tag()) .attr('class', 'port-symbol') .call(_style.content().draw(port_symbol, _style.smallRadius.eval)); - var symbol = port.select('.port-symbol'); + const symbol = port.select('.port-symbol'); symbol.attr('fill', symbol_fill); symbol.transition() .duration(_style.parent().stagedDuration()) .delay(_style.parent().stagedDelay(false)) // need to account for enters as well .call(_style.content().draw(port_symbol, _style.smallRadius.eval)); - var label = port.selectAll('text.port-label').data(function(p) { - return _style.portLabel.eval(p) ? [p] : []; - }); + const label = port.selectAll('text.port-label').data(p => + _style.portLabel.eval(p) ? [p] : [] + ); label.exit().remove(); - var labelEnter = label.enter(); + const labelEnter = label.enter(); labelEnter.append('rect') - .attr({ - class: 'port-label-background', - 'pointer-events': 'none' - }); + .attr('class', 'port-label-background') + .attr('pointer-events', 'none'); labelEnter.append('text') - .attr({ - class: 'port-label', - 'dominant-baseline': 'middle', - 'pointer-events': 'none', - cursor: 'default', - opacity: 0 - }); + .attr('class', 'port-label') + .attr('dominant-baseline', 'middle') + .attr('pointer-events', 'none') + .attr('cursor', 'default') + .attr('opacity', 0); label - .each(function(p) { - p.offset = (is_left(p) ? -1 : 1) * (_style.largeRadius.eval(p) + _style.portPadding.eval(p)); - }) - .attr({ - 'text-anchor': function(p) { - return is_left(p) ? 'end' : 'start'; - }, - transform: function(p) { - return 'translate(' + p.offset + ',0)'; - } + .each(p => { + p.offset = + (is_left(p) ? -1 : 1)*(_style.largeRadius.eval(p)+_style.portPadding.eval(p)); }) + .attr('text-anchor', p => is_left(p) ? 'end' : 'start') + .attr('transform', p => `translate(${p.offset},0)`) .text(_style.portLabel.eval) .each(function(p) { p.bbox = getBBoxNoThrow(this); }); port.selectAll('rect.port-label-background') - .attr({ - x: function(p) { - return (p.offset < 0 ? p.offset - p.bbox.width : p.offset) - _style.portLabelPadding.eval(p).x; - }, - y: function(p) { - return -p.bbox.height/2 - _style.portLabelPadding.eval(p).y; - }, - width: function(p) { - return p.bbox.width + 2*_style.portLabelPadding.eval(p).x; - }, - height: function(p) { - return p.bbox.height + 2*_style.portLabelPadding.eval(p).y; - }, - fill: 'white', - opacity: 0 - }); + .attr( + 'x', + p => (p.offset < 0 ? p.offset-p.bbox.width : p.offset)-_style.portLabelPadding.eval( + p, + ).x, + ) + .attr('y', p => -p.bbox.height/2-_style.portLabelPadding.eval(p).y) + .attr('width', p => p.bbox.width+2*_style.portLabelPadding.eval(p).x) + .attr('height', p => p.bbox.height+2*_style.portLabelPadding.eval(p).y) + .attr('fill', 'white') + .attr('opacity', 0); return _style; }; _style.enableHover = function(whether) { - if(!_drawConduct) { - if(_style.parent()) { - var draw = _style.parent().child('draw-graphs'); - if(draw) + if (!_drawConduct) { + if (_style.parent()) { + const draw = _style.parent().child('draw-graphs'); + if (draw) _drawConduct = draw.conduct(); } } - var namespace = 'grow-ports-' + _style.parent().portStyle.nameOf(this); - if(whether) { - _node.on('mouseover.' + namespace, function(n) { - var nid = _style.parent().nodeKey.eval(n); - var activePort = _style.eventPort(); - if(_nodePorts[nid]) - _nodePorts[nid].forEach(function(p) { + const namespace = `grow-ports-${_style.parent().portStyle.nameOf(this)}`; + if (whether) { + _node.on(`mouseover.${namespace}`, d => { + // In D3 v5, use global event and data is first parameter + const nid = _style.parent().nodeKey.eval(d); + const activePort = _style.eventPort(); + if (_nodePorts[nid]) + _nodePorts[nid].forEach(p => { p.state = p === activePort ? 'large' : activePort ? 'small' : 'medium'; }); - var nids = _drawConduct && _drawConduct.hoverPort(activePort) || []; + const nids = _drawConduct && _drawConduct.hoverPort(activePort) || []; nids.push(nid); _style.animateNodes(nids); }); - _node.on('mouseout.' + namespace, function(n) { - var nid = _style.parent().nodeKey.eval(n); - if(_nodePorts[nid]) - _nodePorts[nid].forEach(function(p) { + _node.on(`mouseout.${namespace}`, n => { + const nid = _style.parent().nodeKey.eval(n); + if (_nodePorts[nid]) + _nodePorts[nid].forEach(p => { p.state = 'small'; }); - var nids = _drawConduct && _drawConduct.hoverPort(null) || []; + const nids = _drawConduct && _drawConduct.hoverPort(null) || []; nids.push(nid); _style.animateNodes(nids); }); } else { - _node.on('mouseover.' + namespace, null); - _node.on('mouseout.' + namespace, null); + _node.on(`mouseover.${namespace}`, null); + _node.on(`mouseout.${namespace}`, null); } return _style; }; _style.parent = property(null); return _style; -}; +} -dc_graph.symbol_port_style.outline = {}; -dc_graph.symbol_port_style.outline.circle = function() { +symbolPortStyle.outline = {}; +symbolPortStyle.outline.circle = function() { return { - tag: function() { + tag() { return 'circle'; }, - draw: function(rf) { + draw(rf) { return function(outlines) { - outlines.attr('r', function(p) { return rf(p); }); + outlines.attr('r', p => rf(p)); }; - } + }, }; }; -dc_graph.symbol_port_style.outline.square = function() { +symbolPortStyle.outline.square = function() { return { - tag: function() { + tag() { return 'rect'; }, - init: function(outlines) { + init(_outlines) { // crispEdges can make outline off-center from symbols // outlines.attr('shape-rendering', 'crispEdges'); }, - draw: function(rf) { + draw(rf) { return function(outlines) { - outlines.attr({ - x: function(p) { return -rf(p); }, - y: function(p) { return -rf(p); }, - width: function(p) { return 2*rf(p); }, - height: function(p) { return 2*rf(p); } - }); + outlines.attr('x', p => -rf(p)) + .attr('y', p => -rf(p)) + .attr('width', p => 2*rf(p)) + .attr('height', p => 2*rf(p)); }; - } + }, }; }; -dc_graph.symbol_port_style.outline.arrow = function() { +symbolPortStyle.outline.arrow = function() { // offset needed for body in order to keep centroid at 0,0 - var left_portion = 3/4 - Math.PI/8; - var _outline = { - tag: function() { + const left_portion = 3/4-Math.PI/8; + const _outline = { + tag() { return 'path'; }, - init: function(outlines) { - //outlines.attr('shape-rendering', 'crispEdges'); + init(_outlines) { + // outlines.attr('shape-rendering', 'crispEdges'); }, - draw: function(rf) { + draw(rf) { return function(outlines) { - outlines.attr('d', function(p) { - var r = rf(p); - if(!_outline.outie() || _outline.outie()(p.orig)) - return 'M' + -left_portion*r + ',' + -r + ' h' + r + - ' l' + r + ',' + r + ' l' + -r + ',' + r + - ' h' + -r + - ' a' + r + ',' + r + ' 0 1,1 0,' + -2*r; + outlines.attr('d', p => { + const r = rf(p); + if (!_outline.outie() || _outline.outie()(p.orig)) + return `M${ + -left_portion*r + },${-r} h${r} l${r},${r} l${-r},${r} h${-r} a${r},${r} 0 1,1 0,${-2*r}`; else - return 'M' + -(2-left_portion)*r + ',' + -r + ' h' + 2*r + - ' a' + r + ',' + r + ' 0 1,1 0,' + 2*r + - ' h' + -2*r + - ' l' + r + ',' + -r + ' l' + -r + ',' + -r; + return `M${-(2-left_portion)*r},${-r} h${2*r} a${r},${r} 0 1,1 0,${2*r} h${ + -2*r + } l${r},${-r} l${-r},${-r}`; }); }; }, - outie: property(null) + outie: property(null), }; return _outline; }; -dc_graph.symbol_port_style.content = {}; -dc_graph.symbol_port_style.content.d3symbol = function() { - var _symbol = { - tag: function() { +symbolPortStyle.content = {}; +symbolPortStyle.content.d3symbol = function() { + const _symbol = { + tag() { return 'path'; }, - enum: function() { - return d3.svg.symbolTypes; + enum() { + return symbols; }, - draw: function(symf, rf) { + draw(symf, rf) { return function(symbols) { - symbols.attr('d', function(p) { - var sym = symf(p), r = rf(p); - return sym ? d3.svg.symbol() - .type(sym) - .size(r*r) - () : ''; + symbols.attr('d', p => { + const sym = symf(p), r = rf(p); + return sym + ? symbol() + .type(sym) + .size(r*r)() + : ''; }); - symbols.attr('transform', function(p) { - switch(symf(p)) { - case 'triangle-up': - return 'translate(0, -1)'; - case 'triangle-down': - return 'translate(0, 1)'; - default: return null; + symbols.attr('transform', p => { + switch (symf(p)) { + case 'triangle-up': + return 'translate(0, -1)'; + case 'triangle-down': + return 'translate(0, 1)'; + default: + return null; } }); }; - } + }, }; return _symbol; }; -dc_graph.symbol_port_style.content.letter = function() { - var _symbol = { - tag: function() { +symbolPortStyle.content.letter = function() { + const _symbol = { + tag() { return 'text'; }, - enum: function() { - return d3.range(65, 91).map(String.fromCharCode); + enum() { + return range(65, 91).map(String.fromCharCode); }, - draw: function(symf, rf) { + draw(symf, rf) { return function(symbols) { symbols.text(symf) - .attr({ - 'dominant-baseline': 'middle', - 'text-anchor': 'middle' - }); + .attr('dominant-baseline', 'middle') + .attr('text-anchor', 'middle'); symbols.each(function(p) { - if(!p.symbol_size) + if (!p.symbol_size) p.symbol_size = getBBoxNoThrow(this); }); - symbols.attr('transform', function(p) { - return 'scale(' + (2*rf(p)/p.symbol_size.height) + - ') translate(' + [0,2].join(',') + ')'; - }); + symbols.attr( + 'transform', + p => `scale(${2*rf(p)/p.symbol_size.height}) translate(${[0, 2].join(',')})`, + ); }; - } + }, }; return _symbol; }; diff --git a/src/tip.js b/src/tip.js index 48b05040..02215e54 100644 --- a/src/tip.js +++ b/src/tip.js @@ -1,206 +1,220 @@ /** - * Asynchronous [d3.tip](https://github.com/Caged/d3-tip) support for dc.graph.js + * Tippy.js tooltip support for dc.graph.js * - * Add tooltips to the nodes and edges of a graph using an asynchronous callback to get - * the html to show. - * - * Optional - requires separately loading the d3.tip script and CSS (which are included in - * dc.graph.js in `web/js/d3-tip/index.js` and `web/css/d3-tip/example-styles.css`) + * Modern replacement for d3.tip using tippy.js for better performance and features. * * @class tip * @memberof dc_graph * @return {Object} - **/ -dc_graph.tip = function(options) { + */ +import { dispatch } from 'd3-dispatch'; +import { select } from 'd3-selection'; +import tippy from 'tippy.js'; +import { functorWrap, property } from './core.js'; +import { mode } from './mode.js'; +import { ancestorHasClass } from './utils.js'; + +export function tip(options) { options = options || {}; - var _namespace = options.namespace || 'tip'; - var _d3tip = null; - var _showTimeout, _hideTimeout; - var _dispatch = d3.dispatch('tipped'); - - function init(parent) { - if(!_d3tip) { - _d3tip = d3.tip() - .attr('class', options.class || 'd3-tip') - .html(function(d) { return "" + d + ""; }) - .direction(_mode.direction()); - if(_mode.offset()) - _d3tip.offset(_mode.offset()); - parent.svg().call(_d3tip); - } - } - function fetch_and_show_content(d) { - if(_mode.disabled() || _mode.selection().exclude && _mode.selection().exclude(d3.event.target)) { - hide_tip.call(this); - return; + const _namespace = options.namespace || 'tip'; + const _instances = new Map(); // element -> tippy instance + const _dispatch = dispatch('tipped'); + + // Map d3.tip directions to tippy placements + const directionMap = { + 'n': 'top', + 'ne': 'top-end', + 'e': 'right', + 'se': 'bottom-end', + 's': 'bottom', + 'sw': 'bottom-start', + 'w': 'left', + 'nw': 'top-start', + }; + + function createTippyInstance(element, datum) { + if (_instances.has(element)) { + return _instances.get(element); } - var target = this, - next = function() { - _mode.content()(d, function(content) { - _d3tip.show.call(target, content, target); - d3.select('div.d3-tip') - .selectAll('a.tip-link') - .on('click.' + _namespace, function() { - d3.event.preventDefault(); - if(_mode.linkCallback()) - _mode.linkCallback()(this.id); - }); - _dispatch.tipped(d); + + const instance = tippy(element, { + content: '', + placement: directionMap[_mode.direction()] || 'top', + interactive: _mode.clickable(), + appendTo: () => document.body, + allowHTML: true, + theme: 'light-border', + animation: 'scale-subtle', + maxWidth: 350, + arrow: true, + trigger: 'manual', // We'll handle showing/hiding manually + onHidden() {}, + }); + + let showTimeout; + let hideTimeout; + + // Handle mouse enter - check content before showing + element.addEventListener('mouseenter', event => { + // Stop propagation to prevent parent tips from showing + event.stopPropagation(); + + if ( + _mode.disabled() + || (_mode.selection().exclude && _mode.selection().exclude(element)) + ) { + return; + } + + // Clear any pending hide timeout + clearTimeout(hideTimeout); + + // Set up show timeout + clearTimeout(showTimeout); + showTimeout = setTimeout(async () => { + // Hide all other instances first + _instances.forEach(otherInstance => { + if (otherInstance !== instance) { + otherInstance.hide(); + } }); - }; - if(_hideTimeout) - window.clearTimeout(_hideTimeout); - if(_mode.delay()) { - window.clearTimeout(_showTimeout); - _showTimeout = window.setTimeout(next, _mode.delay()); - } - else next(); - } - function check_hide_tip() { - if(d3.event.relatedTarget && - (!_mode.selection().exclude || !_mode.selection().exclude(d3.event.target)) && - (this && this.contains(d3.event.relatedTarget) || // do not hide when mouse is still over a child - _mode.clickable() && d3.event.relatedTarget.classList.contains('d3-tip'))) - return false; - return true; - } + const d = element._dcgraph_datum || datum; + try { + const content = await _mode.content()(d); + // Only show tooltip if content is not empty + if (content && content.trim() !== '') { + instance.setContent(content); + instance.show(); + _dispatch.call('tipped', null, d); + } + } catch (error) { + console.warn('Tooltip content error:', error); + } + }, _mode.showDelay()); + }); - function preempt_tip() { - if(_showTimeout) { - window.clearTimeout(_showTimeout); - _showTimeout = null; - } - } + // Handle mouse leave - hide after delay + element.addEventListener('mouseleave', () => { + clearTimeout(showTimeout); + clearTimeout(hideTimeout); + hideTimeout = setTimeout(() => { + instance.hide(); + }, _mode.hideDelay()); + }); - function hide_tip() { - if(!check_hide_tip.apply(this)) - return; - preempt_tip(); - _d3tip.hide(); + _instances.set(element, instance); + element._dcgraph_datum = datum; + return instance; } - function hide_tip_delay() { - if(!check_hide_tip.apply(this)) - return; - preempt_tip(); - if(_mode.hideDelay()) - _hideTimeout = window.setTimeout(function () { - _d3tip.hide(); - }, _mode.hideDelay()); - else - _d3tip.hide(); + function destroyTippyInstance(element) { + const instance = _instances.get(element); + if (instance) { + instance.destroy(); + _instances.delete(element); + delete element._dcgraph_datum; + } } function draw(diagram, node, edge, ehover) { - init(diagram); - _mode.programmatic() || _mode.selection().select(diagram, node, edge, ehover) - .on('mouseover.' + _namespace, fetch_and_show_content) - .on('mouseout.' + _namespace, hide_tip_delay); - if(_mode.clickable()) { - d3.select('div.d3-tip') - .on('mouseover.' + _namespace, function() { - if(_hideTimeout) - window.clearTimeout(_hideTimeout); - }) - .on('mouseout.' + _namespace, hide_tip_delay); - } + const selection = _mode.selection().select(diagram, node, edge, ehover); + selection.each(function(d) { + createTippyInstance(this, d); + }); } + function remove(diagram, node, edge, ehover) { - _mode.programmatic() || _mode.selection().select(diagram, node, edge, ehover) - .on('mouseover.' + _namespace, null) - .on('mouseout.' + _namespace, null); + const selection = _mode.selection().select(diagram, node, edge, ehover); + + selection.each(function() { + destroyTippyInstance(this); + }); } - var _mode = dc_graph.mode(_namespace, { - draw: draw, - remove: remove, - laterDraw: true + const _mode = mode(_namespace, { + draw, + remove, + laterDraw: true, }); + /** * Specify the direction for tooltips. Currently supports the - * [cardinal and intercardinal directions](https://en.wikipedia.org/wiki/Points_of_the_compass) supported by - * [d3.tip.direction](https://github.com/Caged/d3-tip/blob/master/docs/positioning-tooltips.md#tipdirection): - * `'n'`, `'ne'`, `'e'`, etc. + * cardinal and intercardinal directions: 'n', 'ne', 'e', etc. * @name direction * @memberof dc_graph.tip * @instance * @param {String} [direction='n'] * @return {String} * @return {dc_graph.tip} - **/ + */ _mode.direction = property('n'); /** - * Specifies the function to generate content for the tooltip. This function has the - * signature `function(d, k)`, where `d` is the datum of the thing being hovered over, - * and `k` is a continuation. The function should fetch the content, asynchronously if - * needed, and then pass html forward to `k`. + * Specifies the async function to generate content for the tooltip. This function has the + * signature `async function(d)`, where `d` is the datum of the thing being hovered over. + * The function should return a promise that resolves to the HTML content string. * @name content * @memberof dc_graph.tip * @instance - * @param {Function} [content] + * @param {Function} [content] - Async function that returns Promise * @return {Function} - * @example - * // Default mode: assume it's a node, show node title - * var tip = dc_graph.tip().content(function(n, k) { - * k(_mode.parent() ? _mode.parent().nodeTitle.eval(n) : ''); - * }); - **/ - _mode.content = property(function(n, k) { - k(_mode.parent() ? _mode.parent().nodeTitle.eval(n) : ''); - }); + */ + _mode.content = property(async n => _mode.parent() ? _mode.parent().nodeTitle.eval(n) : ''); - _mode.on = function(event, f) { - return _dispatch.on(event, f); - }; + _mode.on = (event, f) => _dispatch.on(event, f); _mode.disabled = property(false); _mode.programmatic = property(false); - _mode.displayTip = function(filter, n, cb) { - if(typeof filter !== 'function') { - var d = filter; - filter = function(d2) { return d2 === d; }; + _mode.displayTip = (filter, n, cb) => { + if (typeof filter !== 'function') { + const d = filter; + filter = d2 => d2 === d; } - var found = _mode.selection().select(_mode.parent(), _mode.parent().selectAllNodes(), _mode.parent().selectAllEdges(), null) - .filter(filter); - if(found.size() > 0) { - var action = fetch_and_show_content; - // we need to flatten e.g. for ports, which will have nested selections - // .nodes() does this better in D3v4 - var flattened = found.reduce(function(p, v) { - return p.concat(v); - }, []); - var which = (n || 0) % flattened.length; - action.call(flattened[which], d3.select(flattened[which]).datum()); - d = d3.select(flattened[which]).datum(); - if(cb) - cb(d); - if(_mode.programmatic()) - found.on('mouseout.' + _namespace, hide_tip_delay); + + const found = _mode.selection().select( + _mode.parent(), + _mode.parent().selectAllNodes(), + _mode.parent().selectAllEdges(), + null, + ); + const elements = []; + + found.each(function(d) { + if (filter(d)) { + elements.push(this); + } + }); + + if (elements.length > 0) { + const which = (n || 0)%elements.length; + const element = elements[which]; + const instance = _instances.get(element); + if (instance) { + instance.show(); + if (cb) cb(element._dcgraph_datum); + } } return _mode; }; - _mode.hideTip = function(delay) { - if(_d3tip) { - if(delay) - hide_tip_delay(); - else - hide_tip(); - } + _mode.hideTip = _delay => { + _instances.forEach(instance => { + instance.hide(); + }); return _mode; }; - _mode.selection = property(dc_graph.tip.select_node_and_edge()); + + _mode.selection = property(selectNodeAndEdge()); _mode.showDelay = _mode.delay = property(0); - _mode.hideDelay = property(200); - _mode.offset = property(null); + _mode.hideDelay = property(50); + _mode.offset = property(null); // Not used with tippy, but kept for API compatibility _mode.clickable = property(false); _mode.linkCallback = property(null); return _mode; -}; +} /** * Generates a handler which can be passed to `tip.content` to produce a table of the @@ -214,113 +228,102 @@ dc_graph.tip = function(options) { * // show all the attributes and values in the node and edge objects * var tip = dc_graph.tip(); * tip.content(dc_graph.tip.table()); - **/ -dc_graph.tip.table = function() { - var gen = function(d, k) { + */ +export function tipTable() { + const gen = async function(d) { d = gen.fetch()(d); - if(!d) - return; // don't display tooltip if no content - var data, keys; - if(Array.isArray(d)) + if (!d) { + return ''; // return empty string to prevent tooltip from showing + } + let data, keys; + if (Array.isArray(d)) data = d; - else if(typeof d === 'number' || typeof d === 'string') + else if (typeof d === 'number' || typeof d === 'string') data = [d]; else { // object - data = keys = Object.keys(d).filter(d3.functor(gen.filter())) - .filter(function(k) { - return d[k] !== undefined; - }); + data = keys = Object.keys(d).filter(functorWrap(gen.filter())) + .filter(k => d[k] !== undefined); } - var table = d3.select(document.createElement('table')); - var rows = table.selectAll('tr').data(data); - var rowsEnter = rows.enter().append('tr'); - rowsEnter.append('td').text(function(item) { - if(keys && typeof item === 'string') + const table = select(document.createElement('table')); + const rows = table.selectAll('tr').data(data); + const rowsEnter = rows.enter().append('tr'); + rowsEnter.append('td').text(item => { + if (keys && typeof item === 'string') return item; return JSON.stringify(item); }); - if(keys) - rowsEnter.append('td').text(function(item) { - return JSON.stringify(d[item]); - }); - k(table.node().outerHTML); // optimizing for clarity over speed (?) + if (keys) + rowsEnter.append('td').text(item => JSON.stringify(d[item])); + return table.node().outerHTML; // optimizing for clarity over speed (?) }; gen.filter = property(true); - gen.fetch = property(function(d) { - return d.orig.value; - }); + gen.fetch = property(d => d.orig.value); return gen; -}; +} -dc_graph.tip.json_table = function() { - var table = dc_graph.tip.table().fetch(function(d) { - var jsontip = table.json()(d); - if(!jsontip) return null; +export function tipJsonTable() { + const table = tipTable().fetch(d => { + const jsontip = table.json()(d); + if (!jsontip) return null; try { return JSON.parse(jsontip); - } catch(xep) { + } catch (_xep) { return [jsontip]; } }); - table.json = property(function(d) { - return (d.orig.value.value || d.orig.value).jsontip; - }); + table.json = property(d => (d.orig.value.value || d.orig.value).jsontip); return table; -}; - -dc_graph.tip.html_or_json_table = function() { - var json_table = dc_graph.tip.json_table(); - var gen = function(d, k) { - var html = gen.html()(d); - if(html) - k(html); - else - json_table(d, k); +} + +export function tipHtmlOrJsonTable() { + const json_table = tipJsonTable(); + const gen = async function(d) { + const html = gen.html()(d); + if (html) { + return html; + } else { + return await json_table(d); + } }; gen.json = json_table.json; - gen.html = property(function(d) { - return (d.orig.value.value || d.orig.value).htmltip; - }); + gen.html = property(d => (d.orig.value.value || d.orig.value).htmltip); return gen; -}; +} -dc_graph.tip.select_node_and_edge = function() { +export function selectNodeAndEdge() { return { - select: function(diagram, node, edge, ehover) { - // hack to merge selections, not supported d3v3 - var selection = diagram.selectAll('.foo-this-does-not-exist'); - selection[0] = node[0].concat(ehover ? ehover[0] : []); - return selection; + select(diagram, node, edge, ehover) { + return ehover ? node.merge(ehover) : node; + }, + exclude(element) { + return ancestorHasClass(element, 'port'); }, - exclude: function(element) { - return ancestor_has_class(element, 'port'); - } }; -}; +} -dc_graph.tip.select_node = function() { +export function selectNode() { return { - select: function(diagram, node, edge, ehover) { + select(diagram, node, _edge, _ehover) { return node; }, - exclude: function(element) { - return ancestor_has_class(element, 'port'); - } + exclude(element) { + return ancestorHasClass(element, 'port'); + }, }; -}; +} -dc_graph.tip.select_edge = function() { +export function selectEdge() { return { - select: function(diagram, node, edge, ehover) { + select(diagram, node, edge, _ehover) { return edge; - } + }, }; -}; +} -dc_graph.tip.select_port = function() { +export function selectPort() { return { - select: function(diagram, node, edge, ehover) { + select(diagram, node, _edge, _ehover) { return node.selectAll('g.port'); - } + }, }; -}; +} diff --git a/src/transform.js b/src/transform.js index 0b956286..37380667 100644 --- a/src/transform.js +++ b/src/transform.js @@ -1,38 +1,38 @@ // collapse edges between same source and target -dc_graph.deparallelize = function(group, sourceTag, targetTag, options) { +export function deparallelize(group, sourceTag, targetTag, options) { options = options || {}; - var both = options.both || false, + const both = options.both || false, reduce = options.reduce || null; return { - all: function() { - var ST = {}; - group.all().forEach(function(kv) { - var source = kv.value[sourceTag], + all() { + const ST = {}; + group.all().forEach(kv => { + const source = kv.value[sourceTag], target = kv.value[targetTag]; - var dir = both ? true : source < target; - var min = dir ? source : target, max = dir ? target : source; + const dir = both ? true : source < target; + const min = dir ? source : target, max = dir ? target : source; ST[min] = ST[min] || {}; - var entry; - if(ST[min][max]) { + let entry; + if (ST[min][max]) { entry = ST[min][max]; - if(reduce) + if (reduce) entry.original = reduce(entry.original, kv); } else ST[min][max] = entry = {in: 0, out: 0, original: Object.assign({}, kv)}; - if(dir) + if (dir) ++entry.in; else ++entry.out; }); - var ret = []; - Object.keys(ST).forEach(function(source) { - Object.keys(ST[source]).forEach(function(target) { - var entry = ST[source][target]; + const ret = []; + Object.keys(ST).forEach(source => { + Object.keys(ST[source]).forEach(target => { + const entry = ST[source][target]; entry[sourceTag] = source; entry[targetTag] = target; ret.push({key: entry.original.key, value: entry}); }); }); return ret; - } + }, }; -}; +} diff --git a/src/tree_constraints.js b/src/tree_constraints.js index de2551f4..803f0d9e 100644 --- a/src/tree_constraints.js +++ b/src/tree_constraints.js @@ -1,32 +1,36 @@ // this naive tree-drawer is paraphrased from memory from dot -dc_graph.tree_constraints = function(rootf, treef, xgap, ygap) { - console.warn('dc_graph.tree_constraints is deprecated - it never worked right and may not be a good idea'); +import { depthFirstTraversal } from './depth_first_traversal.js'; + +export function treeConstraints(rootf, treef, xgap, _ygap) { + console.warn( + 'treeConstraints is deprecated - it never worked right and may not be a good idea', + ); return function(diagram, nodes, edges) { - var constraints = []; - var x = 0; - var dfs = dc_graph.depth_first_traversal({ + const constraints = []; + let x = 0; + const dfs = depthFirstTraversal({ root: rootf, tree: treef, - place: function(n, r, row) { - if(row.length) { - var last = row[row.length-1]; + place(n, r, row) { + if (row.length) { + const last = row[row.length-1]; constraints.push({ left: diagram.nodeKey.eval(last), right: diagram.nodeKey.eval(n), axis: 'x', gap: x-last.foo_x, - equality: true + equality: true, }); } n.foo_x = x; // n.cola.x = x; // n.cola.y = r*ygap; }, - sib: function() { + sib() { x += xgap; - } + }, }); dfs(diagram, nodes, edges); return constraints; }; -}; +} diff --git a/src/tree_layout.js b/src/tree_layout.js index 92413e2d..55be25d7 100644 --- a/src/tree_layout.js +++ b/src/tree_layout.js @@ -1,94 +1,110 @@ /** - * `dc_graph.tree_layout` is a very simple and not very bright tree layout. It can draw any DAG, but + * Tree layout for dc.graph.js + * @module tree_layout + */ + +// External dependencies +import { dispatch } from 'd3-dispatch'; +import { property, uuid } from './core.js'; +import { depthFirstTraversal } from './depth_first_traversal.js'; + +/** + * `treeLayout` is a very simple and not very bright tree layout. It can draw any DAG, but * tries to position the nodes as a tree. - * @class tree_layout - * @memberof dc_graph * @param {String} [id=uuid()] - Unique identifier - * @return {dc_graph.tree_layout} - **/ -dc_graph.tree_layout = function(id) { - var _layoutId = id || uuid(); - var _dispatch = d3.dispatch('tick', 'start', 'end'); - var _dfs; + * @return {Object} tree layout engine + */ +export function treeLayout(id) { + const _layoutId = id || uuid(); + const _dispatch = dispatch('tick', 'start', 'end'); + let _dfs; function init(options) { - var x; - var nodeWidth = d3.functor(options.nodeWidth); + let x; + const nodeWidth = typeof options.nodeWidth === 'function' ? options.nodeWidth : function() { + return options.nodeWidth; + }; function best_dist(left, right) { - return (nodeWidth(left) + nodeWidth(right)) / 2; + return (nodeWidth(left)+nodeWidth(right))/2; } - _dfs = dc_graph.depth_first_traversal({ - nodeid: function(n) { + _dfs = depthFirstTraversal({ + nodeid(n) { return n.dcg_nodeKey; }, - sourceid: function(n) { + sourceid(n) { return n.dcg_edgeSource; }, - targetid: function(n) { + targetid(n) { return n.dcg_edgeTarget; }, - init: function() { + init() { x = options.offsetX; }, - row: function(n) { + row(n) { return n.dcg_rank; }, - place: function(n, r, row) { - if(row.length) { - var left = row[row.length-1]; - var g = (nodeWidth(left) + nodeWidth(n)) / 2; - x = Math.max(x, left.left_x + g); + place(n, r, row) { + if (row.length) { + const left = row[row.length-1]; + const g = (nodeWidth(left)+nodeWidth(n))/2; + x = Math.max(x, left.left_x+g); } n.left_x = x; n.hit_ins = 1; - n.y = r*options.gapY + options.offsetY; + n.y = r*options.gapY+options.offsetY; }, - sib: function(isroot, left, right) { - var g = best_dist(left, right); - if(isroot) g = g*1.5; + sib(isroot, left, right) { + let g = best_dist(left, right); + if (isroot) g = g*1.5; x += g; }, - pop: function(n) { - n.x = (n.left_x + x)/2; + pop(n) { + n.x = (n.left_x+x)/2; }, - skip: function(n, indegree) { + skip(n, indegree) { // rolling average of in-neighbor x positions - n.x = (n.hit_ins*n.x + x)/++n.hit_ins; - if(n.hit_ins === indegree) + n.x = (n.hit_ins*n.x+x)/++n.hit_ins; + if (n.hit_ins === indegree) delete n.hit_ins; }, - finish: function(rows) { + finish(rows) { // this is disgusting. patch up any places where nodes overlap by scanning // right far enough to find the space, then fill from left to right at the // minimum gap - rows.forEach(function(row) { - var sort = row.sort(function(a, b) { return a.x - b.x; }); - var badi = null, badl = null, want; - for(var i=0; i { + const sort = row.sort((a, b) => a.x-b.x); + let badi = null, badl = null, want; + for (let i = 0; i < sort.length-1; ++i) { + const left = sort[i], right = sort[i+1]; + if (!badi) { + if (right.x-left.x < best_dist(left, right)) { badi = i; badl = left.x; want = best_dist(left, right); } // else still not bad } else { want += best_dist(left, right); - if(i < sort.length - 2 && right.x < badl + want) + if (i < sort.length-2 && right.x < badl+want) continue; // still bad else { - if(badi>0) + if (badi > 0) --badi; // might want to use more left - var l, limit; - if(i < sort.length - 2) { // found space before right - var extra = right.x - (badl + want); - l = sort[badi].x + extra/2; + let l, limit; + if (i < sort.length-2) { // found space before right + const extra = right.x-(badl+want); + l = sort[badi].x+extra/2; limit = i+1; } else { - l = Math.max(sort[badi].x, badl - best_dist(sort[badi], sort[badi+1]) - (want - right.x + badl)/2); + l = Math.max( + sort[badi].x, + badl-best_dist( + sort[badi], + sort[badi+1], + )-(want-right.x+badl)/2, + ); limit = sort.length; } - for(var j = badi+1; j { options[option] = options[option] || this[option](); - }.bind(this)); + }); init(options); return this; }, - data: function(graph, nodes, edges) { + data(graph, nodes, edges) { data(nodes, edges); }, - start: function() { + start() { start(); }, - stop: function() { + stop() { stop(); }, - optionNames: function() { + optionNames() { return ['nodeWidth', 'offsetX', 'offsetY', 'rowFunction', 'gapY']; }, - populateLayoutNode: function(layout, node) { - if(this.rowFunction()) + populateLayoutNode(layout, node) { + if (this.rowFunction()) layout.dcg_rank = this.rowFunction.eval(node); }, - populateLayoutEdge: function() {}, - nodeWidth: property(function(n) { return n.width; }), + populateLayoutEdge() {}, + nodeWidth: property(n => n.width), offsetX: property(30), offsetY: property(30), rowFunction: property(null), - gapY: property(100) + gapY: property(100), }; return layout; -}; +} -dc_graph.tree_layout.scripts = []; +// Scripts needed for web worker +treeLayout.scripts = []; diff --git a/src/tree_positions.js b/src/tree_positions.js index b72df0c7..4155b7fe 100644 --- a/src/tree_positions.js +++ b/src/tree_positions.js @@ -1,86 +1,94 @@ // this naive tree-drawer is paraphrased from memory from dot -dc_graph.tree_positions = function(rootf, rowf, treef, ofsx, ofsy, nwidth, ygap) { - console.warn('dc_graph.tree_positions is deprecated; use the layout engine tree_layout instead'); - if(rootf || treef) { - console.warn('dc_graph.tree_positions: rootf and treef are ignored'); +import { depthFirstTraversal } from './depth_first_traversal.js'; + +export function treePositions(rootf, rowf, treef, ofsx, ofsy, nwidth, ygap) { + console.warn('treePositions is deprecated; use the layout engine tree_layout instead'); + if (rootf || treef) { + console.warn('treePositions: rootf and treef are ignored'); } - var x; - nwidth = d3.functor(nwidth); + let x; + nwidth = typeof nwidth === 'function' ? nwidth : () => nwidth; function best_dist(left, right) { - return (nwidth(left) + nwidth(right)) / 2; + return (nwidth(left)+nwidth(right))/2; } - var dfs = dc_graph.depth_first_traversal({ - nodeid: function(n) { + const dfs = depthFirstTraversal({ + nodeid(n) { return n.cola.dcg_nodeKey; }, - sourceid: function(n) { + sourceid(n) { return n.cola.dcg_edgeSource; }, - targetid: function(n) { + targetid(n) { return n.cola.dcg_edgeTarget; }, - init: function() { + init() { x = ofsx; }, - row: function(n) { + row(n) { return rowf(n.orig); }, - place: function(n, r, row) { - if(row.length) { - var left = row[row.length-1]; - var g = (nwidth(left) + nwidth(n)) / 2; - x = Math.max(x, left.left_x + g); + place(n, r, row) { + if (row.length) { + const left = row[row.length-1]; + const g = (nwidth(left)+nwidth(n))/2; + x = Math.max(x, left.left_x+g); } n.left_x = x; n.hit_ins = 1; - n.cola.y = r*ygap + ofsy; + n.cola.y = r*ygap+ofsy; }, - sib: function(isroot, left, right) { - var g = best_dist(left, right); - if(isroot) g = g*1.5; + sib(isroot, left, right) { + let g = best_dist(left, right); + if (isroot) g = g*1.5; x += g; }, - pop: function(n) { - n.cola.x = (n.left_x + x)/2; + pop(n) { + n.cola.x = (n.left_x+x)/2; }, - skip: function(n, indegree) { + skip(n, indegree) { // rolling average of in-neighbor x positions - n.cola.x = (n.hit_ins*n.cola.x + x)/++n.hit_ins; - if(n.hit_ins === indegree) + n.cola.x = (n.hit_ins*n.cola.x+x)/++n.hit_ins; + if (n.hit_ins === indegree) delete n.hit_ins; }, - finish: function(rows) { + finish(rows) { // this is disgusting. patch up any places where nodes overlap by scanning // right far enough to find the space, then fill from left to right at the // minimum gap - rows.forEach(function(row) { - var sort = row.sort(function(a, b) { return a.cola.x - b.cola.x; }); - var badi = null, badl = null, want; - for(var i=0; i { + const sort = row.sort((a, b) => a.cola.x-b.cola.x); + let badi = null, badl = null, want; + for (let i = 0; i < sort.length-1; ++i) { + const left = sort[i], right = sort[i+1]; + if (!badi) { + if (right.cola.x-left.cola.x < best_dist(left, right)) { badi = i; badl = left.cola.x; want = best_dist(left, right); } // else still not bad } else { want += best_dist(left, right); - if(i < sort.length - 2 && right.cola.x < badl + want) + if (i < sort.length-2 && right.cola.x < badl+want) continue; // still bad else { - if(badi>0) + if (badi > 0) --badi; // might want to use more left - var l, limit; - if(i < sort.length - 2) { // found space before right - var extra = right.cola.x - (badl + want); - l = sort[badi].cola.x + extra/2; + let l, limit; + if (i < sort.length-2) { // found space before right + const extra = right.cola.x-(badl+want); + l = sort[badi].cola.x+extra/2; limit = i+1; } else { - l = Math.max(sort[badi].cola.x, badl - best_dist(sort[badi], sort[badi+1]) - (want - right.cola.x + badl)/2); + l = Math.max( + sort[badi].cola.x, + badl-best_dist( + sort[badi], + sort[badi+1], + )-(want-right.cola.x+badl)/2, + ); limit = sort.length; } - for(var j = badi+1; j ({ + x: n.cola.x, + y: n.cola.y, + })); + let crosshairs = _debugLayer.selectAll('path.nodecenter').data(centers); crosshairs.exit().remove(); - crosshairs.enter().append('path').attr('class', 'nodecenter'); - crosshairs.attr({ - d: function(c) { - return 'M' + (c.x - _mode.xhairWidth()/2) + ',' + c.y + ' h' + _mode.xhairWidth() + - ' M' + c.x + ',' + (c.y - _mode.xhairHeight()/2) + ' v' + _mode.xhairHeight(); - }, - opacity: _mode.xhairOpacity() !== null ? _mode.xhairOpacity() : _mode.opacity(), - stroke: _mode.xhairColor(), - 'stroke-width': 1/_scale - }); + const crosshairsEnter = crosshairs.enter().append('path').attr('class', 'nodecenter'); + crosshairs = crosshairs.merge(crosshairsEnter); + crosshairs.attr( + 'd', + c => `M${c.x-_mode.xhairWidth()/2},${c.y} h${_mode.xhairWidth()} M${c.x},${ + c.y-_mode.xhairHeight()/2 + } v${_mode.xhairHeight()}`, + ) + .attr('opacity', _mode.xhairOpacity() !== null ? _mode.xhairOpacity() : _mode.opacity()) + .attr('stroke', _mode.xhairColor()) + .attr('stroke-width', 1/_scale); function cola_point(n) { return {x: n.cola.x, y: n.cola.y}; } - var colabounds = node.data().map(function(n) { - return boundary(cola_point(n), n.cola.width, n.cola.height); - }); - var colaboundary = _debugLayer.selectAll('path.colaboundary').data(colabounds); + const colabounds = node.data().map(n => + boundary(cola_point(n), n.cola.width, n.cola.height) + ); + const colaboundary = _debugLayer.selectAll('path.colaboundary').data(colabounds); draw_corners(colaboundary, 'colaboundary', _mode.boundsColor()); - var textbounds = node.data().map(function(n) { - if(!n.bbox || (!n.bbox.width && !n.bbox.height)) + const textbounds = node.data().map(n => { + if (!n.bbox || (!n.bbox.width && !n.bbox.height)) return null; return boundary(cola_point(n), n.bbox.width, n.bbox.height); - }).filter(function(n) { return !!n; }); - var textboundary = _debugLayer.selectAll('path.textboundary').data(textbounds); + }).filter(n => !!n); + const textboundary = _debugLayer.selectAll('path.textboundary').data(textbounds); draw_corners(textboundary, 'textboundary', _mode.boundsColor()); - var radiibounds = node.data().map(function(n) { - if(typeof n.dcg_rx !== 'number') + const radiibounds = node.data().map(n => { + if (typeof n.dcg_rx !== 'number') return null; return boundary(cola_point(n), n.dcg_rx*2, n.dcg_ry*2); - }).filter(function(n) { return !!n; }); - var radiiboundary = _debugLayer.selectAll('path.radiiboundary').data(radiibounds); + }).filter(n => !!n); + const radiiboundary = _debugLayer.selectAll('path.radiiboundary').data(radiibounds); draw_corners(radiiboundary, 'radiiboundary', _mode.boundsColor()); - diagram.addOrRemoveDef('debug-orient-marker-head', - true, - 'svg:marker', - orient_marker.bind(null, _mode.arrowHeadColor())); - diagram.addOrRemoveDef('debug-orient-marker-tail', - true, - 'svg:marker', - orient_marker.bind(null, _mode.arrowTailColor())); - var heads = _mode.arrowLength() ? edge.data().map(function(e) { - return {pos: e.pos.new.path.points[e.pos.new.path.points.length-1], orient: e.pos.new.orienthead}; - }) : []; - var headOrients = _debugLayer.selectAll('line.heads').data(heads); - draw_arrow_orient(headOrients, 'heads', _mode.arrowHeadColor(), '#debug-orient-marker-head'); + diagram.addOrRemoveDef( + 'debug-orient-marker-head', + true, + 'svg:marker', + orient_marker.bind(null, _mode.arrowHeadColor()), + ); + diagram.addOrRemoveDef( + 'debug-orient-marker-tail', + true, + 'svg:marker', + orient_marker.bind(null, _mode.arrowTailColor()), + ); + const heads = _mode.arrowLength() + ? edge.data().map(e => ({ + pos: e.pos.new.path.points[e.pos.new.path.points.length-1], + orient: e.pos.new.orienthead, + })) + : []; + const headOrients = _debugLayer.selectAll('line.heads').data(heads); + draw_arrow_orient( + headOrients, + 'heads', + _mode.arrowHeadColor(), + '#debug-orient-marker-head', + ); - var tails = _mode.arrowLength() ? edge.data().map(function(e) { - return {pos: e.pos.new.path.points[0], orient: e.pos.new.orienttail}; - }) : []; - var tailOrients = _debugLayer.selectAll('line.tails').data(tails); - draw_arrow_orient(tailOrients, 'tails', _mode.arrowTailColor(), '#debug-orient-marker-tail'); + const tails = _mode.arrowLength() + ? edge.data().map(e => ({pos: e.pos.new.path.points[0], orient: e.pos.new.orienttail})) + : []; + const tailOrients = _debugLayer.selectAll('line.tails').data(tails); + draw_arrow_orient( + tailOrients, + 'tails', + _mode.arrowTailColor(), + '#debug-orient-marker-tail', + ); - var headpts = Array.prototype.concat.apply([], edge.data().map(function(e) { - var arrowSize = diagram.edgeArrowSize.eval(e); - return edge_arrow_points( - diagram.arrows(), - diagram.edgeArrowhead.eval(e), - arrowSize, - diagram.edgeStrokeWidth.eval(e) / arrowSize, - unrad(e.pos.new.orienthead), - e.pos.new.full.points[e.pos.new.full.points.length-1], - diagram.nodeStrokeWidth.eval(e.target) - ); - })); - var hp = _debugLayer.selectAll('path.head-point').data(headpts); + const headpts = Array.prototype.concat.apply( + [], + edge.data().map(e => { + const arrowSize = diagram.edgeArrowSize.eval(e); + return edge_arrow_points( + diagram.arrows(), + diagram.edgeArrowhead.eval(e), + arrowSize, + diagram.edgeStrokeWidth.eval(e)/arrowSize, + unrad(e.pos.new.orienthead), + e.pos.new.full.points[e.pos.new.full.points.length-1], + diagram.nodeStrokeWidth.eval(e.target), + ); + }), + ); + const hp = _debugLayer.selectAll('path.head-point').data(headpts); draw_x(hp, 'head-point', _mode.arrowHeadColor()); - var tailpts = Array.prototype.concat.apply([], edge.data().map(function(e) { - var arrowSize = diagram.edgeArrowSize.eval(e); - return edge_arrow_points( - diagram.arrows(), - diagram.edgeArrowtail.eval(e), - arrowSize, - diagram.edgeStrokeWidth.eval(e) / arrowSize, - unrad(e.pos.new.orienttail), - e.pos.new.full.points[0], - diagram.nodeStrokeWidth.eval(e.source) - ); - })); - var tp = _debugLayer.selectAll('path.tail-point').data(tailpts); + const tailpts = Array.prototype.concat.apply( + [], + edge.data().map(e => { + const arrowSize = diagram.edgeArrowSize.eval(e); + return edge_arrow_points( + diagram.arrows(), + diagram.edgeArrowtail.eval(e), + arrowSize, + diagram.edgeStrokeWidth.eval(e)/arrowSize, + unrad(e.pos.new.orienttail), + e.pos.new.full.points[0], + diagram.nodeStrokeWidth.eval(e.source), + ); + }), + ); + const tp = _debugLayer.selectAll('path.tail-point').data(tailpts); draw_x(tp, 'tail-point', _mode.arrowTailColor()); - var domain = _debugLayer.selectAll('rect.domain').data([0]); - domain.enter().append('rect'); - var xd = _mode.parent().x().domain(), yd = _mode.parent().y().domain(); - domain.attr({ - class: 'domain', - fill: 'none', - opacity: _mode.domainOpacity(), - stroke: _mode.domainColor(), - 'stroke-width': _mode.domainStrokeWidth()/_scale, - x: xd[0], - y: yd[0], - width: xd[1] - xd[0], - height: yd[1] - yd[0] - }); + let domain = _debugLayer.selectAll('rect.domain').data([0]); + const domainEnter = domain.enter().append('rect'); + domain = domain.merge(domainEnter); + const xd = _mode.parent().x().domain(), yd = _mode.parent().y().domain(); + domain.attr('class', 'domain') + .attr('fill', 'none') + .attr('opacity', _mode.domainOpacity()) + .attr('stroke', _mode.domainColor()) + .attr('stroke-width', _mode.domainStrokeWidth()/_scale) + .attr('x', xd[0]) + .attr('y', yd[0]) + .attr('width', xd[1]-xd[0]) + .attr('height', yd[1]-yd[0]); } function on_zoom(translate, scale, xDomain, yDomain) { _translate = translate; @@ -126,14 +158,14 @@ dc_graph.troubleshoot = function() { function boundary(point, wid, hei) { return { - left: point.x - wid/2, - top: point.y - hei/2, - right: point.x + wid/2, - bottom: point.y + hei/2 + left: point.x-wid/2, + top: point.y-hei/2, + right: point.x+wid/2, + bottom: point.y+hei/2, }; - }; + } function bound_tick(x, y, dx, dy) { - return 'M' + x + ',' + (y + dy) + ' v' + -dy + ' h' + dx; + return `M${x},${y+dy} v${-dy} h${dx}`; } function corners(bounds) { return [ @@ -146,111 +178,110 @@ dc_graph.troubleshoot = function() { function draw_corners(binding, classname, color) { binding.exit().remove(); binding.enter().append('path').attr('class', classname); - binding.attr({ - d: corners, - opacity: _mode.boundsOpacity() !== null ? _mode.boundsOpacity() : _mode.opacity(), - stroke: color, - 'stroke-width': 1/_scale, - fill: 'none' - }); + binding.attr('d', corners) + .attr( + 'opacity', + _mode.boundsOpacity() !== null ? _mode.boundsOpacity() : _mode.opacity(), + ) + .attr('stroke', color) + .attr('stroke-width', 1/_scale) + .attr('fill', 'none'); + } + function unrad(orient) { + return +orient.replace('rad', ''); } - function unrad(orient) { - return +orient.replace('rad',''); - } function draw_arrow_orient(binding, classname, color, markerUrl) { binding.exit().remove(); binding.enter().append('line').attr('class', classname); - binding.attr({ - x1: function(d) { return d.pos.x; }, - y1: function(d) { return d.pos.y; }, - x2: function(d) { return d.pos.x - Math.cos(unrad(d.orient))*_mode.arrowLength(); }, - y2: function(d) { return d.pos.y - Math.sin(unrad(d.orient))*_mode.arrowLength(); }, - stroke: color, - 'stroke-width': _mode.arrowStrokeWidth()/_scale, - opacity: _mode.arrowOpacity() !== null ? _mode.arrowOpacity() : _mode.opacity(), - 'marker-end': 'url(' + markerUrl + ')' - }); + binding.attr('x1', d => d.pos.x) + .attr('y1', d => d.pos.y) + .attr('x2', d => d.pos.x-Math.cos(unrad(d.orient))*_mode.arrowLength()) + .attr('y2', d => d.pos.y-Math.sin(unrad(d.orient))*_mode.arrowLength()) + .attr('stroke', color) + .attr('stroke-width', _mode.arrowStrokeWidth()/_scale) + .attr('opacity', _mode.arrowOpacity() !== null ? _mode.arrowOpacity() : _mode.opacity()) + .attr('marker-end', `url(${markerUrl})`); } function orient_marker(color, markerEnter) { markerEnter - .attr({ - viewBox: '0 -3 3 6', - refX: 3, - refY: 0, - orient: 'auto' - }); + .attr('viewBox', '0 -3 3 6') + .attr('refX', 3) + .attr('refY', 0) + .attr('orient', 'auto'); markerEnter.append('path') .attr('stroke', color) .attr('fill', 'none') .attr('d', 'M0,3 L3,0 L0,-3'); } function edge_arrow_points(arrows, defn, arrowSize, stemWidth, orient, endp, strokeWidth) { - var parts = arrow_parts(arrows, defn), - offsets = arrow_offsets(parts, stemWidth), + const parts = arrowParts(arrows, defn), + offsets = arrowOffsets(parts, stemWidth), xunit = [Math.cos(orient), Math.sin(orient)]; endp = [endp.x, endp.y]; - if(!parts.length) - return [[endp[0] - xunit[0]*strokeWidth/2, - endp[1] - xunit[1]*strokeWidth/2]]; - var globofs = add_points( - [-strokeWidth/arrowSize/2,0], - mult_point(front_ref(parts[0].frontRef), -1)); - var pts = offsets.map(function(ofs, i) { - return mult_point([ + if (!parts.length) + return [[endp[0]-xunit[0]*strokeWidth/2, endp[1]-xunit[1]*strokeWidth/2]]; + const globofs = addPoints( + [-strokeWidth/arrowSize/2, 0], + multPoint(front_ref(parts[0].frontRef), -1), + ); + const pts = offsets.map((ofs, i) => + multPoint( + [ + globofs, + front_ref(parts[i].frontRef), + ofs.offset, + ].reduce(add_points), + arrowSize, + ) + ); + pts.push(multPoint( + [ globofs, - front_ref(parts[i].frontRef), - ofs.offset - ].reduce(add_points), arrowSize); - }); - pts.push(mult_point([ - globofs, - back_ref(parts[parts.length-1].backRef), - offsets[parts.length-1].offset - ].reduce(add_points), arrowSize)); - return pts.map(function(p) { - return add_points( + back_ref(parts[parts.length-1].backRef), + offsets[parts.length-1].offset, + ].reduce(add_points), + arrowSize, + )); + return pts.map(p => + addPoints( endp, - [p[0]*xunit[0] - p[1]*xunit[1], p[0]*xunit[1] + p[1]*xunit[0]] - ); - }); + [p[0]*xunit[0]-p[1]*xunit[1], p[0]*xunit[1]+p[1]*xunit[0]], + ) + ); } - function draw_x(binding, classname, color) { - var xw = _mode.xWidth()/2, xh = _mode.xHeight()/2; + const xw = _mode.xWidth()/2, xh = _mode.xHeight()/2; binding.exit().remove(); binding.enter().append('path').attr('class', classname); - binding.attr({ - d: function(pos) { - return [[[-xw,-xh],[xw,xh]], [[xw,-xh], [-xw,xh]]].map(function(seg) { - return 'M' + seg.map(function(p) { - return (pos[0] + p[0]) + ',' + (pos[1] + p[1]); - }).join(' L'); - }).join(' '); - }, - 'stroke-width': 2/_scale, - stroke: color, - opacity: _mode.xOpacity() - }); + binding.attr( + 'd', + pos => + [[[-xw, -xh], [xw, xh]], [[xw, -xh], [-xw, xh]]].map(seg => + `M${seg.map(p => `${pos[0]+p[0]},${pos[1]+p[1]}`).join(' L')}` + ).join(' '), + ) + .attr('stroke-width', 2/_scale) + .attr('stroke', color) + .attr('opacity', _mode.xOpacity()); } - function remove(diagram, node, edge, ehover) { - if(_debugLayer) + function remove(_diagram, _node, _edge, _ehover) { + if (_debugLayer) _debugLayer.remove(); } - var _mode = dc_graph.mode('highlight-paths', { + const _mode = mode('highlight-paths', { laterDraw: true, - draw: draw, - remove: remove, - parent: function(p) { - if(p) { + draw, + remove, + parent(p) { + if (p) { _translate = p.translate(); _scale = p.scale(); p.on('zoomed.troubleshoot', on_zoom); - } - else if(_mode.parent()) + } else if (_mode.parent()) _mode.parent().on('zoomed.troubleshoot', null); - } + }, }); _mode.opacity = property(0.75); @@ -279,5 +310,4 @@ dc_graph.troubleshoot = function() { _mode.domainStrokeWidth = property(4); return _mode; -}; - +} diff --git a/src/type_graph.js b/src/type_graph.js index d0ff4f83..057cb88f 100644 --- a/src/type_graph.js +++ b/src/type_graph.js @@ -1,27 +1,28 @@ -dc_graph.build_type_graph = function(nodes, edges, nkey, ntype, esource, etarget) { - var nmap = {}, tnodes = {}, tedges = {}; - nodes.forEach(function(n) { +export function buildTypeGraph(nodes, edges, nkey, ntype, esource, etarget) { + const nmap = {}, tnodes = {}, tedges = {}; + nodes.forEach(n => { nmap[nkey(n)] = n; - var t = ntype(n); - if(!tnodes[t]) + const t = ntype(n); + if (!tnodes[t]) tnodes[t] = {type: t}; }); - edges.forEach(function(e) { - var source = esource(e), target = etarget(e), sn, tn; - if(!(sn = nmap[source])) - throw new Error('source key ' + source + ' not found!'); - if(!(tn = nmap[target])) - throw new Error('target key ' + target + ' not found!'); - var etype = ntype(sn) + '/' + ntype(tn); - if(!tedges[etype]) + edges.forEach(e => { + const source = esource(e), target = etarget(e); + let sn, tn; + if (!(sn = nmap[source])) + throw new Error(`source key ${source} not found!`); + if (!(tn = nmap[target])) + throw new Error(`target key ${target} not found!`); + const etype = `${ntype(sn)}/${ntype(tn)}`; + if (!tedges[etype]) tedges[etype] = { type: etype, source: ntype(sn), - target: ntype(tn) + target: ntype(tn), }; }); return { - nodes: Object.keys(tnodes).map(function(k) { return tnodes[k]; }), - edges: Object.keys(tedges).map(function(k) { return tedges[k]; }) + nodes: Object.keys(tnodes).map(k => tnodes[k]), + edges: Object.keys(tedges).map(k => tedges[k]), }; } diff --git a/src/utils.js b/src/utils.js index f8340472..6be90b16 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,55 +1,62 @@ -function property_if(pred, curr) { +import { interpolate } from 'd3-interpolate'; +import { select } from 'd3-selection'; +import { getOriginal } from './core.js'; + +export function propertyIf(pred, curr) { return function(o, last) { return pred(o) ? curr(o) : last(); }; } -function property_interpolate(value, curr) { +export function propertyInterpolate(value, curr) { return function(o, last) { - return d3.interpolate(last(o), curr(o))(value(o)); + return interpolate(last(o), curr(o))(value(o)); }; } -function multiply_properties(pred, props, blend) { - var props2 = {}; - for(var p in props) +export function multiplyProperties(pred, props, blend) { + const props2 = {}; + for (const p in props) props2[p] = blend(pred, param(props[p])); return props2; } -function conditional_properties(pred, props) { - return multiply_properties(pred, props, property_if); +export function conditionalProperties(pred, props) { + return multiplyProperties(pred, props, propertyIf); } -function node_edge_conditions(npred, epred, props) { - var nprops = {}, eprops = {}, badprops = []; - for(var p in props) { - if(/^node/.test(p)) +export function nodeEdgeConditions(npred, epred, props) { + const nprops = {}, eprops = {}, badprops = []; + for (const p in props) { + if (/^node/.test(p)) nprops[p] = props[p]; - else if(/^edge/.test(p)) + else if (/^edge/.test(p)) eprops[p] = props[p]; else badprops.push(p); } - if(badprops.length) - console.error('only know how to deal with properties that start with "node" or "edge"', badprops); - var props2 = npred ? conditional_properties(npred, nprops) : {}; - if(epred) - Object.assign(props2, conditional_properties(epred, eprops)); + if (badprops.length) + console.error( + 'only know how to deal with properties that start with "node" or "edge"', + badprops, + ); + const props2 = npred ? conditionalProperties(npred, nprops) : {}; + if (epred) + Object.assign(props2, conditionalProperties(epred, eprops)); return props2; } -function cascade(parent) { +export function cascade(parent) { return function(level, add, props) { - for(var p in props) { - if(!parent[p]) - throw new Error('unknown attribute ' + p); + for (const p in props) { + if (!parent[p]) + throw new Error(`unknown attribute ${p}`); parent[p].cascade(level, add ? props[p] : null); } return parent; }; } -function compose(f, g) { +export function compose(f, g) { return function() { return f(g.apply(null, arguments)); }; @@ -57,29 +64,30 @@ function compose(f, g) { // version of d3.functor that optionally wraps the function with another // one, if the parameter is a function -dc_graph.functor_wrap = function (v, wrap) { - if(typeof v === "function") { - return wrap ? function(x) { - return v(wrap(x)); - } : v; - } - else return function() { - return v; - }; -}; +export function functorWrap(v, wrap) { + if (typeof v === 'function') { + return wrap + ? function(x) { + return v(wrap(x)); + } + : v; + } else return function() { + return v; + }; +} // we want to allow either values or functions to be passed to specify parameters. // if a function, the function needs a preprocessor to extract the original key/value // pair from the wrapper object we put it in. -function param(v) { - return dc_graph.functor_wrap(v, get_original); +export function param(v) { + return functorWrap(v, getOriginal); } // http://jsperf.com/cloning-an-object/101 -function clone(obj) { - var target = {}; - for(var i in obj) { - if(obj.hasOwnProperty(i)) { +export function clone(obj) { + const target = {}; + for (const i in obj) { + if (obj.hasOwnProperty(i)) { target[i] = obj[i]; } } @@ -87,46 +95,49 @@ function clone(obj) { } // because i don't think we need to bind edge point data (yet!) -var bez_cmds = { - 1: 'L', 2: 'Q', 3: 'C' +const bez_cmds = { + 1: 'L', + 2: 'Q', + 3: 'C', }; -function generate_path(pts, bezDegree, close) { - var cats = ['M', pts[0].x, ',', pts[0].y], remain = bezDegree; - var hasNaN = false; - for(var i = 1; i < pts.length; ++i) { - if(isNaN(pts[i].x) || isNaN(pts[i].y)) - hasNaN = true; - cats.push(remain===bezDegree ? bez_cmds[bezDegree] : ' ', pts[i].x, ',', pts[i].y); - if(--remain===0) +export function generatePath(pts, bezDegree, close) { + const cats = ['M', pts[0].x, ',', pts[0].y]; + let remain = bezDegree; + let _hasNaN = false; + for (let i = 1; i < pts.length; ++i) { + if (isNaN(pts[i].x) || isNaN(pts[i].y)) + _hasNaN = true; + cats.push(remain === bezDegree ? bez_cmds[bezDegree] : ' ', pts[i].x, ',', pts[i].y); + if (--remain === 0) remain = bezDegree; } - if(remain!=bezDegree) + if (remain != bezDegree) console.log("warning: pts.length didn't match bezian degree", pts, bezDegree); - if(close) + if (close) cats.push('Z'); return cats.join(''); } // for IE (do we care really?) Math.hypot = Math.hypot || function() { - var y = 0; - var length = arguments.length; + let y = 0; + const length = arguments.length; - for (var i = 0; i < length; i++) { - if (arguments[i] === Infinity || arguments[i] === -Infinity) { - return Infinity; + for (let i = 0; i < length; i++) { + if (arguments[i] === Infinity || arguments[i] === -Infinity) { + return Infinity; + } + y += arguments[i]*arguments[i]; } - y += arguments[i] * arguments[i]; - } - return Math.sqrt(y); + return Math.sqrt(y); }; // outputs the array with adjacent identical lines collapsed to one -function uniq(a) { - var ret = []; - a.forEach(function(x, i) { - if(i === 0 || x !== a[i-1]) +export function uniq(a) { + const ret = []; + a.forEach((x, i) => { + if (i === 0 || x !== a[i-1]) ret.push(x); }); return ret; @@ -134,88 +145,108 @@ function uniq(a) { // https://tc39.github.io/ecma262/#sec-array.prototype.find if (!Array.prototype.find) { - Object.defineProperty(Array.prototype, 'find', { - value: function(predicate) { - // 1. Let O be ? ToObject(this value). - if (this == null) { - throw new TypeError('"this" is null or not defined'); - } - - var o = Object(this); - - // 2. Let len be ? ToLength(? Get(O, "length")). - var len = o.length >>> 0; - - // 3. If IsCallable(predicate) is false, throw a TypeError exception. - if (typeof predicate !== 'function') { - throw new TypeError('predicate must be a function'); - } - - // 4. If thisArg was supplied, let T be thisArg; else let T be undefined. - var thisArg = arguments[1]; - - // 5. Let k be 0. - var k = 0; - - // 6. Repeat, while k < len - while (k < len) { - // a. Let Pk be ! ToString(k). - // b. Let kValue be ? Get(O, Pk). - // c. Let testResult be ToBoolean(? Call(predicate, T, << kValue, k, O >>)). - // d. If testResult is true, return kValue. - var kValue = o[k]; - if (predicate.call(thisArg, kValue, k, o)) { - return kValue; - } - // e. Increase k by 1. - k++; - } + Object.defineProperty(Array.prototype, 'find', { + value(predicate) { + // 1. Let O be ? ToObject(this value). + if (this == null) { + throw new TypeError('"this" is null or not defined'); + } - // 7. Return undefined. - return undefined; - } - }); + const o = Object(this); + + // 2. Let len be ? ToLength(? Get(O, "length")). + const len = o.length>>>0; + + // 3. If IsCallable(predicate) is false, throw a TypeError exception. + if (typeof predicate !== 'function') { + throw new TypeError('predicate must be a function'); + } + + // 4. If thisArg was supplied, let T be thisArg; else let T be undefined. + const thisArg = arguments[1]; + + // 5. Let k be 0. + let k = 0; + + // 6. Repeat, while k < len + while (k < len) { + // a. Let Pk be ! ToString(k). + // b. Let kValue be ? Get(O, Pk). + // c. Let testResult be ToBoolean(? Call(predicate, T, << kValue, k, O >>)). + // d. If testResult is true, return kValue. + const kValue = o[k]; + if (predicate.call(thisArg, kValue, k, o)) { + return kValue; + } + // e. Increase k by 1. + k++; + } + + // 7. Return undefined. + return undefined; + }, + }); } -var script_path = function() { - var _path; +export const scriptPath = function() { + let _path; return function() { - if(_path === undefined) { - // adapted from http://stackoverflow.com/a/18283141/676195 + if (_path === undefined) { _path = null; // only try once - var filename = 'dc.graph.js'; - var scripts = document.getElementsByTagName('script'); + + // For ES6 modules, try to use import.meta.url if available + try { + if (import.meta && import.meta.url) { + const url = new URL(import.meta.url); + _path = url.pathname.replace(/[^/]*$/, ''); + return _path; + } + } catch (_e) { + // fallback to script tag detection + } + + // Fallback: look for script tags + const scripts = document.getElementsByTagName('script'); if (scripts && scripts.length > 0) { - for (var i in scripts) { - if (scripts[i].src && scripts[i].src.match(new RegExp(filename+'$'))) { - _path = scripts[i].src.replace(new RegExp('(.*)'+filename+'$'), '$1'); + // Try dc-graph.js (ES6 module version) + for (const i in scripts) { + if (scripts[i].src && scripts[i].src.match(/dc-graph\.js$/)) { + _path = scripts[i].src.replace(/(.*)dc-graph\.js$/, '$1'); break; } } + // Try dc.graph.js (legacy version) + if (!_path) { + for (const i in scripts) { + if (scripts[i].src && scripts[i].src.match(/dc\.graph\.js$/)) { + _path = scripts[i].src.replace(/(.*)dc\.graph\.js$/, '$1'); + break; + } + } + } } } return _path; }; }(); -dc_graph.event_coords = function(diagram) { - var bound = diagram.root().node().getBoundingClientRect(); - return diagram.invertCoord([d3.event.clientX - bound.left, - d3.event.clientY - bound.top]); -}; +export function eventCoords(diagram, event) { + const bound = diagram.root().node().getBoundingClientRect(); + return diagram.invertCoord([event.clientX-bound.left, event.clientY-bound.top]); +} -function promise_identity(x) { +export function promiseIdentity(x) { return Promise.resolve(x); } // http://stackoverflow.com/questions/7044944/jquery-javascript-to-detect-os-without-a-plugin -var is_a_mac = navigator.platform.toUpperCase().indexOf('MAC')!==-1; +export const is_a_mac = navigator.platform.toUpperCase().indexOf('MAC') !== -1; // https://stackoverflow.com/questions/16863917/check-if-class-exists-somewhere-in-parent-vanilla-js -function ancestor_has_class(element, classname) { - if(d3.select(element).classed(classname)) +export function ancestorHasClass(element, classname) { + if (select(element).classed(classname)) return true; - return element.parentElement && ancestor_has_class(element.parentElement, classname); + return element.parentElement && ancestorHasClass(element.parentElement, classname); } if (typeof SVGElement.prototype.contains == 'undefined') { diff --git a/src/validate.js b/src/validate.js index b06fee6d..a82adef0 100644 --- a/src/validate.js +++ b/src/validate.js @@ -1,37 +1,42 @@ - dc_graph.validate = function(title) { +import { set } from 'd3-collection'; +import { functorWrap, property } from './core.js'; + +export function validate(title) { function falsy(objects, accessor, what, who) { - var f = objects.filter(function(o) { - return !accessor(o); - }); - return f.length ? - [what + ' is empty for ' + f.length + ' of ' + objects.length + ' ' + who, f] : - null; + const f = objects.filter(o => !accessor(o)); + return f.length + ? [`${what} is empty for ${f.length} of ${objects.length} ${who}`, f] + : null; } function build_index(objects, accessor) { - return objects.reduce(function(m, o) { + return objects.reduce((m, o) => { m[accessor(o)] = o; return m; }, {}); } function not_found(index, objects, accessor, what, where, who) { - var nf = objects.filter(function(o) { - return !index[accessor(o)]; - }).map(function(o) { - return {key: accessor(o), value: o}; - }); - return nf.length ? - [what + ' was not found in ' + where, Object.keys(index), 'for ' + nf.length + ' of ' + objects.length + ' ' + who, nf] : - null; + const nf = objects.filter(o => !index[accessor(o)]).map(o => ({ + key: accessor(o), + value: o, + })); + return nf.length + ? [ + `${what} was not found in ${where}`, + Object.keys(index), + `for ${nf.length} of ${objects.length} ${who}`, + nf, + ] + : null; } function validate() { - var diagram = _mode.parent(); - var nodes = diagram.nodeGroup().all(), + const diagram = _mode.parent(); + const nodes = diagram.nodeGroup().all(), edges = diagram.edgeGroup().all(), ports = diagram.portGroup() ? diagram.portGroup().all() : []; - var errors = []; + const errors = []; function check(error) { - if(error) + if (error) errors.push(error); } @@ -39,67 +44,98 @@ check(falsy(edges, diagram.edgeSource(), 'edgeSource', 'edges')); check(falsy(edges, diagram.edgeTarget(), 'edgeTarget', 'edges')); - var contentTypes = d3.set(diagram.content.enum()); - var ct = dc_graph.functor_wrap(diagram.nodeContent()); - var noContentNodes = nodes.filter(function(kv) { - return !contentTypes.has(ct(kv)); - }); - if(noContentNodes.length) - errors.push(['there are ' + noContentNodes.length + ' nodes with nodeContent not matching any content', noContentNodes]); + const contentTypes = set(diagram.content.enum()); + const ct = functorWrap(diagram.nodeContent()); + const noContentNodes = nodes.filter(kv => !contentTypes.has(ct(kv))); + if (noContentNodes.length) + errors.push([ + `there are ${noContentNodes.length} nodes with nodeContent not matching any content`, + noContentNodes, + ]); - var nindex = build_index(nodes, diagram.nodeKey()), + const nindex = build_index(nodes, diagram.nodeKey()), eindex = build_index(edges, diagram.edgeKey()); check(not_found(nindex, edges, diagram.edgeSource(), 'edgeSource', 'nodes', 'edges')); check(not_found(nindex, edges, diagram.edgeTarget(), 'edgeTarget', 'nodes', 'edges')); - check(falsy(ports, function(p) { - return diagram.portNodeKey() && diagram.portNodeKey()(p) || - diagram.portEdgeKey() && diagram.portEdgeKey()(p); - }, 'portNodeKey||portEdgeKey', 'ports')); + check(falsy( + ports, + p => diagram.portNodeKey() && diagram.portNodeKey()(p) + || diagram.portEdgeKey() && diagram.portEdgeKey()(p), + 'portNodeKey||portEdgeKey', + 'ports', + )); - var named_ports = !diagram.portNodeKey() && [] || ports.filter(function(p) { - return diagram.portNodeKey()(p); - }); - var anonymous_ports = !diagram.portEdgeKey() && [] || ports.filter(function(p) { - return diagram.portEdgeKey()(p); - }); - check(not_found(nindex, named_ports, diagram.portNodeKey(), 'portNodeKey', 'nodes', 'ports')); - check(not_found(eindex, anonymous_ports, diagram.portEdgeKey(), 'portEdgeKey', 'edges', 'ports')); + const named_ports = !diagram.portNodeKey() && [] + || ports.filter(p => diagram.portNodeKey()(p)); + const anonymous_ports = !diagram.portEdgeKey() && [] + || ports.filter(p => diagram.portEdgeKey()(p)); + check( + not_found(nindex, named_ports, diagram.portNodeKey(), 'portNodeKey', 'nodes', 'ports'), + ); + check( + not_found( + eindex, + anonymous_ports, + diagram.portEdgeKey(), + 'portEdgeKey', + 'edges', + 'ports', + ), + ); - if(diagram.portName()) { - var pindex = build_index(named_ports, function(p) { - return diagram.portNodeKey()(p) + ' - ' + diagram.portName()(p); - }); - if(diagram.edgeSourcePortName()) - check(not_found(pindex, edges, function(e) { - return diagram.edgeSource()(e) + ' - ' + d3.functor(diagram.edgeSourcePortName())(e); - }, 'edgeSourcePortName', 'ports', 'edges')); - if(diagram.edgeTargetPortName()) - check(not_found(pindex, edges, function(e) { - return diagram.edgeTarget()(e) + ' - ' + d3.functor(diagram.edgeTargetPortName())(e); - }, 'edgeTargetPortName', 'ports', 'edges')); + if (diagram.portName()) { + const pindex = build_index( + named_ports, + p => `${diagram.portNodeKey()(p)} - ${diagram.portName()(p)}`, + ); + if (diagram.edgeSourcePortName()) + check( + not_found( + pindex, + edges, + e => `${diagram.edgeSource()(e)} - ${ + functorWrap(diagram.edgeSourcePortName())(e) + }`, + 'edgeSourcePortName', + 'ports', + 'edges', + ), + ); + if (diagram.edgeTargetPortName()) + check( + not_found( + pindex, + edges, + e => `${diagram.edgeTarget()(e)} - ${ + functorWrap(diagram.edgeTargetPortName())(e) + }`, + 'edgeTargetPortName', + 'ports', + 'edges', + ), + ); } function count_text() { - return nodes.length + ' nodes, ' + edges.length + ' edges, ' + ports.length + ' ports'; + return `${nodes.length} nodes, ${edges.length} edges, ${ports.length} ports`; } - if(errors.length) { - console.warn('validation of ' + title + ' failed with ' + count_text() + ':'); - errors.forEach(function(err) { + if (errors.length) { + console.warn(`validation of ${title} failed with ${count_text()}:`); + errors.forEach(err => { console.warn.apply(console, err); }); - } - else - console.log('validation of ' + title + ' succeeded with ' + count_text() + '.'); + } else + console.log(`validation of ${title} succeeded with ${count_text()}.`); } - var _mode = { - parent: property(null).react(function(p) { - if(p) + const _mode = { + parent: property(null).react(p => { + if (p) p.on('data.validate', validate); else _mode.parent().on('data.validate', null); - }) + }), }; return _mode; -}; +} diff --git a/src/webworker_layout.js b/src/webworker_layout.js index d65c43df..69a65bbc 100644 --- a/src/webworker_layout.js +++ b/src/webworker_layout.js @@ -1,81 +1,140 @@ -var _workers = {}; -var NUMBER_RESULTS = 3; -function create_worker(workerName) { - if(!_workers[workerName]) { - var worker = _workers[workerName] = { - worker: new Worker(script_path() + 'dc.graph.' + workerName + '.worker.js'), - layouts: {} +/** + * Web worker layout wrapper + * @module webworker_layout + */ + +import { dispatch } from 'd3-dispatch'; +import { scriptPath } from './utils.js'; + +const _workers = {}; +const NUMBER_RESULTS = 3; +function createWorker(workerName) { + if (!_workers[workerName]) { + const worker = _workers[workerName] = { + worker: new Worker(`${scriptPath()}dc.graph.${workerName}.worker.js`, {type: 'module'}), + layouts: {}, }; worker.worker.onmessage = function(e) { - var layoutId = e.data.layoutId; - if(!worker.layouts[layoutId]) - throw new Error('layoutId "' + layoutId + '" unknown!'); - var engine = worker.layouts[layoutId].getEngine(); - if(e.data.args.length > NUMBER_RESULTS && engine.processExtraWorkerResults) + const layoutId = e.data.layoutId; + if (!worker.layouts[layoutId]) + throw new Error(`layoutId "${layoutId}" unknown!`); + const engine = worker.layouts[layoutId].getEngine(); + const _layoutName = engine.layoutAlgorithm?.() || 'unknown'; + if (e.data.args.length > NUMBER_RESULTS && engine.processExtraWorkerResults) engine.processExtraWorkerResults.apply(engine, e.data.args.slice(NUMBER_RESULTS)); - worker.layouts[layoutId].dispatch()[e.data.response].apply(null, e.data.args); + const dispatch = worker.layouts[layoutId].dispatch(); + dispatch.call(e.data.response, null, ...e.data.args); }; worker.worker.onerror = function(e) { - console.error('Worker error:', e); + console.error(`[WORKER] Worker error for layout ${workerName}:`, e); }; } return _workers[workerName]; } -dc_graph.webworker_layout = function(layoutEngine, workerName) { - var _tick, _done, _dispatch = d3.dispatch('init', 'start', 'tick', 'end'); - var _worker = create_worker(workerName || layoutEngine.layoutAlgorithm()); - var engine = {}; +export function webworkerLayout(layoutEngine, workerName) { + const _dispatch = dispatch('init', 'start', 'tick', 'end'); + let _tick, _done; + const _worker = createWorker(workerName || layoutEngine.layoutAlgorithm()); + const engine = {}; _worker.layouts[layoutEngine.layoutId()] = engine; engine.parent = function(parent) { - if(layoutEngine.parent) + if (layoutEngine.parent) layoutEngine.parent(parent); }; - engine.init = function(options) { + // Helper function to clone options while filtering out functions + function serializeOptions(obj) { + if (obj === null || typeof obj !== 'object') return obj; + if (typeof obj === 'function') { + console.warn( + '[WORKER] Filtering out function from options:', + `${obj.toString().slice(0, 100)}...`, + ); + return null; // Remove functions + } + if (Array.isArray(obj)) return obj.map(serializeOptions); + + const result = {}; + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + const value = serializeOptions(obj[key]); + if (value !== null) { // Only include non-null values + result[key] = value; + } + } + } + return result; + } + + engine.init = async function(options) { options = layoutEngine.optionNames().reduce( - function(options, option) { - options[option] = layoutEngine[option](); + (options, option) => { + const value = layoutEngine[option](); + // Serialize each option value as we collect it + options[option] = serializeOptions(value); return options; - }, options); - if(layoutEngine.propagateOptions) + }, + options, + ); + if (layoutEngine.propagateOptions) layoutEngine.propagateOptions(options); - _worker.worker.postMessage({ - command: 'init', - args: { - layoutId: layoutEngine.layoutId(), - options: options - } + + return new Promise((resolve, reject) => { + // Set up one-time listener for init completion + const originalOnMessage = _worker.worker.onmessage; + const initTimeout = setTimeout(() => { + _worker.worker.onmessage = originalOnMessage; + reject(new Error('Worker init timeout')); + }, 10000); // 10 second timeout + + _worker.worker.onmessage = function(e) { + if (e.data.response === 'init' && e.data.layoutId === layoutEngine.layoutId()) { + clearTimeout(initTimeout); + _worker.worker.onmessage = originalOnMessage; + resolve(); + } else { + // Pass other messages to original handler + originalOnMessage.call(this, e); + } + }; + + _worker.worker.postMessage({ + command: 'init', + args: { + layoutId: layoutEngine.layoutId(), + options: serializeOptions(options), + }, + }); }); - return this; }; engine.data = function(graph, nodes, edges, clusters, constraints) { _worker.worker.postMessage({ command: 'data', args: { layoutId: layoutEngine.layoutId(), - graph: graph, - nodes: nodes, - edges: edges, - clusters: clusters, - constraints: constraints - } + graph, + nodes, + edges, + clusters, + constraints, + }, }); }; engine.start = function() { _worker.worker.postMessage({ command: 'start', args: { - layoutId: layoutEngine.layoutId() - } + layoutId: layoutEngine.layoutId(), + }, }); }; engine.stop = function() { _worker.worker.postMessage({ command: 'stop', args: { - layoutId: layoutEngine.layoutId() - } + layoutId: layoutEngine.layoutId(), + }, }); return this; }; @@ -84,17 +143,24 @@ dc_graph.webworker_layout = function(layoutEngine, workerName) { return layoutEngine; }; // somewhat sketchy - do we want this object to be transparent or not? - var passthroughs = ['layoutAlgorithm', 'populateLayoutNode', 'populateLayoutEdge', - 'rankdir', 'ranksep']; - passthroughs.concat(layoutEngine.optionNames(), - layoutEngine.passThru ? layoutEngine.passThru() : []).forEach(function(name) { + const passthroughs = [ + 'layoutAlgorithm', + 'populateLayoutNode', + 'populateLayoutEdge', + 'rankdir', + 'ranksep', + ]; + passthroughs.concat( + layoutEngine.optionNames(), + layoutEngine.passThru ? layoutEngine.passThru() : [], + ).forEach(name => { engine[name] = function() { - var ret = layoutEngine[name].apply(layoutEngine, arguments); + const ret = layoutEngine[name].apply(layoutEngine, arguments); return arguments.length ? this : ret; }; }); engine.on = function(event, f) { - if(arguments.length === 1) + if (arguments.length === 1) return _dispatch.on(event); _dispatch.on(event, f); return this; @@ -103,4 +169,4 @@ dc_graph.webworker_layout = function(layoutEngine, workerName) { return _dispatch; }; return engine; -}; +} diff --git a/src/webworker_message.js b/src/webworker_message.js index b7fe26ee..cdb2330f 100644 --- a/src/webworker_message.js +++ b/src/webworker_message.js @@ -1,10 +1,10 @@ -var _layouts; +let _layouts; function postResponse(event, layoutId) { return function() { - var message = { + const message = { response: event, - layoutId: layoutId + layoutId, }; message.args = Array.prototype.slice.call(arguments); postMessage(message); @@ -12,51 +12,56 @@ function postResponse(event, layoutId) { } onmessage = function(e) { - var args = e.data.args; - switch(e.data.command) { - case 'init': - // find a function under dc_graph that has `scripts` - var layout_name; - for(var name in dc_graph) { - if(typeof dc_graph[name] === 'function' && dc_graph[name].scripts) - layout_name = name; - } - if(!_layouts) { - _layouts = {}; - importScripts.apply(null, dc_graph[layout_name].scripts); - if(dc_graph[layout_name].optional_scripts) { - try { - importScripts.apply(null, dc_graph[layout_name].optional_scripts); - } - catch(xep) { - console.log(xep); + const args = e.data.args; + switch (e.data.command) { + case 'init': { + // find a function under dc_graph that has `scripts` + let layout_name; + for (const name in dc_graph) { + if (typeof dc_graph[name] === 'function' && dc_graph[name].scripts) + layout_name = name; + } + if (!_layouts) { + _layouts = {}; + importScripts.apply(null, dc_graph[layout_name].scripts); + if (dc_graph[layout_name].optional_scripts) { + try { + importScripts.apply(null, dc_graph[layout_name].optional_scripts); + } catch (xep) { + console.log(xep); + } } } - } - _layouts[args.layoutId] = dc_graph[layout_name]() - .on('tick', postResponse('tick', args.layoutId)) - .on('start', postResponse('start', args.layoutId)) - .on('end', postResponse('end', args.layoutId)) - .init(args.options); - break; - case 'data': - if(_layouts) - _layouts[args.layoutId].data(args.graph, args.nodes, args.edges, args.clusters, args.constraints); - break; - case 'start': - // if(args.initialOnly) { - // if(args.showLayoutSteps) - // _tick(); - // _done(); - // } - // else - _layouts[args.layoutId].start(); - break; - case 'stop': - if(_layouts) - _layouts[args.layoutId].stop(); - break; + _layouts[args.layoutId] = dc_graph[layout_name]() + .on('tick', postResponse('tick', args.layoutId)) + .on('start', postResponse('start', args.layoutId)) + .on('end', postResponse('end', args.layoutId)) + .init(args.options); + break; + } + case 'data': + if (_layouts) + _layouts[args.layoutId].data( + args.graph, + args.nodes, + args.edges, + args.clusters, + args.constraints, + ); + break; + case 'start': + // if(args.initialOnly) { + // if(args.showLayoutSteps) + // _tick(); + // _done(); + // } + // else + _layouts[args.layoutId].start(); + break; + case 'stop': + if (_layouts) + _layouts[args.layoutId].stop(); + break; } }; - diff --git a/src/wildcard_ports.js b/src/wildcard_ports.js index 7b7f2e16..6c04d8fc 100644 --- a/src/wildcard_ports.js +++ b/src/wildcard_ports.js @@ -1,91 +1,96 @@ -dc_graph.wildcard_ports = function(options) { - var diagram = options.diagram, - get_type = options.get_type || function(p) { return p.orig.value.type; }, - set_type = options.set_type || function(p, src) { p.orig.value.type = src.orig.value.type; }, - get_name = options.get_name || function(p) { return p.orig.value.name; }, - is_wild = options.is_wild || function(p) { return p.orig.value.wild; }, +export function wildcardPorts(options) { + const diagram = options.diagram, + get_type = options.get_type || function(p) { + return p.orig.value.type; + }, + set_type = options.set_type || function(p, src) { + p.orig.value.type = src.orig.value.type; + }, + get_name = options.get_name || function(p) { + return p.orig.value.name; + }, + is_wild = options.is_wild || function(p) { + return p.orig.value.wild; + }, update_ports = options.update_ports || function() {}, - get_linked = options.get_linked || function() { return []; }; + get_linked = options.get_linked || function() { + return []; + }; function linked_ports(n, port) { - if(!diagram) + if (!diagram) return []; - var nid = diagram.nodeKey.eval(n); - var name = get_name(port); - var links = get_linked(n) || []; - var found = links.find(function(set) { - return set.includes(name); - }); - if(!found) return []; - return found.filter(function(link) { return link !== name; }).map(function(link) { - return diagram.getPort(nid, null, link); - }); + const nid = diagram.nodeKey.eval(n); + const name = get_name(port); + const links = get_linked(n) || []; + const found = links.find(set => set.includes(name)); + if (!found) return []; + return found.filter(link => link !== name).map(link => diagram.getPort(nid, null, link)); } function no_edges(ports) { - return ports.every(function(lp) { - return lp.edges.length === 0; - }); + return ports.every(lp => lp.edges.length === 0); } return { - isValid: function(p1, p2) { - return get_type(p1) === null ^ get_type(p2) === null || - get_type(p1) !== null && get_type(p1) === get_type(p2); + isValid(p1, p2) { + return get_type(p1) === null^get_type(p2) === null + || get_type(p1) !== null && get_type(p1) === get_type(p2); }, - whyInvalid: function(p1, p2) { - return get_type(p1) === null && get_type(p2) === null && "can't connect wildcard to wildcard" || - get_type(p1) !== get_type(p2) && "the types of ports must match"; + whyInvalid(p1, p2) { + return get_type(p1) === null && get_type(p2) === null + && "can't connect wildcard to wildcard" + || get_type(p1) !== get_type(p2) && 'the types of ports must match'; }, - copyLinked: function(n, port) { - linked_ports(n, port).forEach(function(lp) { + copyLinked(n, port) { + linked_ports(n, port).forEach(lp => { set_type(lp, port); }); }, - copyType: function(e, sport, tport) { - if(get_type(sport) === null) { + copyType(e, sport, tport) { + if (get_type(sport) === null) { set_type(sport, tport); this.copyLinked(sport.node, sport); update_ports(); - } else if(get_type(tport) === null) { + } else if (get_type(tport) === null) { set_type(tport, sport); this.copyLinked(tport.node, tport); update_ports(); } return Promise.resolve(e); }, - resetTypes: function(edges) { + resetTypes(edges) { // backward compatibility: this used to take diagram as // first arg, which was wrong - var dia = diagram; - if(arguments.length === 2) { + let dia = diagram; + if (arguments.length === 2) { dia = arguments[0]; edges = arguments[1]; } - edges.forEach(function(eid) { - var e = dia.getWholeEdge(eid), + edges.forEach(eid => { + const e = dia.getWholeEdge(eid), spname = dia.edgeSourcePortName.eval(e), tpname = dia.edgeTargetPortName.eval(e); - var update = false; - var p = dia.getPort(dia.nodeKey.eval(e.source), null, spname); - var linked = linked_ports(e.source, p); - if(is_wild(p) && p.edges.length === 1 && no_edges(linked)) { + let update = false; + let p = dia.getPort(dia.nodeKey.eval(e.source), null, spname); + let linked = linked_ports(e.source, p); + if (is_wild(p) && p.edges.length === 1 && no_edges(linked)) { set_type(p, null); - linked.forEach(function(lp) { + linked.forEach(lp => { set_type(lp, null); update = true; }); } p = dia.getPort(dia.nodeKey.eval(e.target), null, tpname); linked = linked_ports(e.target, p); - if(is_wild(p) && p.edges.length === 1 && no_edges(linked)) { + if (is_wild(p) && p.edges.length === 1 && no_edges(linked)) { set_type(p, null); - linked.forEach(function(lp) { + linked.forEach(lp => { set_type(lp, null); update = true; }); } - if(update) + if (update) update_ports(); }); return Promise.resolve(edges); - } + }, }; -}; +} diff --git a/src/workers/cola-worker.js b/src/workers/cola-worker.js new file mode 100644 index 00000000..7e7a5f98 --- /dev/null +++ b/src/workers/cola-worker.js @@ -0,0 +1,4 @@ +import { colaLayout } from '../cola_layout.js'; +import { createWorkerHandler } from './worker_common.js'; + +onmessage = createWorkerHandler(colaLayout); diff --git a/src/workers/d3v4-force-worker.js b/src/workers/d3v4-force-worker.js new file mode 100644 index 00000000..11382e61 --- /dev/null +++ b/src/workers/d3v4-force-worker.js @@ -0,0 +1,10 @@ +import * as d3Dispatch from 'https://cdn.jsdelivr.net/npm/d3-dispatch@1.0.6/+esm'; + +globalThis.d3 = { + dispatch: d3Dispatch.dispatch, +}; + +import { d3v4ForceLayout } from '../d3v4_force_layout.js'; +import { createWorkerHandler } from './worker_common.js'; + +onmessage = createWorkerHandler(d3v4ForceLayout); diff --git a/src/workers/dagre-worker.js b/src/workers/dagre-worker.js new file mode 100644 index 00000000..57b51bdb --- /dev/null +++ b/src/workers/dagre-worker.js @@ -0,0 +1,10 @@ +import * as d3Dispatch from 'https://cdn.jsdelivr.net/npm/d3-dispatch@1.0.6/+esm'; + +globalThis.d3 = { + dispatch: d3Dispatch.dispatch, +}; + +import { dagreLayout } from '../dagre_layout.js'; +import { createWorkerHandler } from './worker_common.js'; + +onmessage = createWorkerHandler(dagreLayout); diff --git a/src/workers/dynagraph-worker.js b/src/workers/dynagraph-worker.js new file mode 100644 index 00000000..9d8875b9 --- /dev/null +++ b/src/workers/dynagraph-worker.js @@ -0,0 +1,34 @@ +// Dynagraph layout web worker entry point +import { dynagraphLayout } from '../dynagraph_layout.js'; +import { createWorkerHandler } from './worker_common.js'; + +// Initialize WASM once when worker loads +let wasmInitialized = false; + +async function initializeWASM() { + if (!wasmInitialized) { + try { + await globalThis.createDynagraphModule(); + wasmInitialized = true; + } catch (error) { + console.error('[DYNAGRAPH WORKER] Failed to initialize WASM module:', error); + throw error; + } + } +} + +// Create layout factory that ensures WASM is initialized +function dynagraphLayoutWithWASM(id, layout) { + const baseLayout = dynagraphLayout(id, layout); + const originalInit = baseLayout.init; + + // Override init to ensure WASM is initialized first + baseLayout.init = async function(options) { + await initializeWASM(); + return originalInit.call(this, options); + }; + + return baseLayout; +} + +onmessage = createWorkerHandler(dynagraphLayoutWithWASM); diff --git a/src/workers/worker_common.js b/src/workers/worker_common.js new file mode 100644 index 00000000..afa25872 --- /dev/null +++ b/src/workers/worker_common.js @@ -0,0 +1,65 @@ +// Shared worker message handling code +const _layouts = {}; + +function postResponse(event, layoutId) { + return function() { + const message = { + response: event, + layoutId, + }; + message.args = Array.prototype.slice.call(arguments); + postMessage(message); + }; +} + +export function createWorkerHandler(layoutFactory) { + return async function(e) { + const args = e.data.args; + const layoutId = args.layoutId; + + switch (e.data.command) { + case 'init': { + const layout = layoutFactory() + .on('tick', postResponse('tick', layoutId)) + .on('start', postResponse('start', layoutId)) + .on('end', postResponse('end', layoutId)); + + const initResult = layout.init(args.options); + + // Handle both sync and async init methods + if (initResult && typeof initResult.then === 'function') { + await initResult; + _layouts[layoutId] = layout; + } else { + _layouts[layoutId] = initResult || layout; + } + + // Send init completion response + postMessage({ + response: 'init', + layoutId, + args: [], + }); + break; + } + case 'data': + if (_layouts[layoutId]) + _layouts[layoutId].data( + args.graph, + args.nodes, + args.edges, + args.clusters, + args.constraints, + ); + break; + case 'start': + if (_layouts[layoutId]) + await _layouts[layoutId].start(); + break; + case 'stop': + if (_layouts[layoutId]) + _layouts[layoutId].stop(); + break; + } + }; +} diff --git a/sync-url-options.js b/sync-url-options.js index c4a25232..18d730b1 100644 --- a/sync-url-options.js +++ b/sync-url-options.js @@ -3,11 +3,14 @@ // Copyright 2016-2017 AT&T Intellectual Property // License: Apache v2 -var sync_url_options = (function() { - if(!querystring) - throw new Error('need querystring library'); - function read_query(type, val) { - switch(type) { +import { select } from 'd3-selection'; +import querystring from './querystring.js'; + +if (!querystring) + throw new Error('need querystring library'); + +function read_query(type, val) { + switch (type) { case 'boolean': return val === 'true'; case 'number': @@ -16,89 +19,98 @@ var sync_url_options = (function() { return val; case 'array': return val.split(querystring.listsep()); - default: throw new Error('unsupported query type ' + type); - } + default: + throw new Error('unsupported query type '+type); } +} - function write_query(type, val) { - switch(type) { +function write_query(type, val) { + switch (type) { case 'array': return val.join(querystring.listsep()); case 'boolean': case 'number': case 'string': - return '' + val; - default: throw new Error('unsupported query type ' + type); - } + return ''+val; + default: + throw new Error('unsupported query type '+type); } +} - function query_type(val) { - return Array.isArray(val) ? 'array' : val === null ? 'string' : typeof val; - } +function query_type(val) { + return Array.isArray(val) ? 'array' : val === null ? 'string' : typeof val; +} - // we could probably depend on _, but _.pick is the only thing we need atm - function pick(object, fields) { - return fields.reduce(function(reduced, key) { - if(key in object) - reduced[key] = object[key]; - return reduced; - }, {}); - } +// we could probably depend on _, but _.pick is the only thing we need atm +function pick(object, fields) { + return fields.reduce(function(reduced, key) { + if (key in object) + reduced[key] = object[key]; + return reduced; + }, {}); +} - function option_synchronizer(options, domain, args) { - var qs = querystring.parse(); - var settings = {}; - var _output = function(m) { - querystring.update(m); - }; +function option_synchronizer(options, domain, args) { + var qs = querystring.parse(); + var settings = {}; + var _output = function(m) { + querystring.update(m); + }; - function interesting_params(qs) { - var interesting = Object.keys(options) - .filter(function(k) { - return qs[options[k].query] !== write_query(query_type(options[k].default), options[k].default); - }).map(function(k) { - return options[k].query || k; - }); - return pick(qs, interesting); - } + function interesting_params(qs) { + var interesting = Object.keys(options) + .filter(function(k) { + return qs[options[k].query] + !== write_query(query_type(options[k].default), options[k].default); + }).map(function(k) { + return options[k].query || k; + }); + return pick(qs, interesting); + } - function update_interesting(qs) { - _output(interesting_params(qs)); - } + function update_interesting(qs) { + _output(interesting_params(qs)); + } - function do_option(key, opt, callback) { - settings[key] = opt.default; - var query = opt.query = opt.query || key; - var type = query_type(opt.default); - if(query in qs) - settings[key] = read_query(type, qs[query]); + function do_option(key, opt, callback) { + settings[key] = opt.default; + var query = opt.query = opt.query || key; + var type = query_type(opt.default); + if (query in qs) + settings[key] = read_query(type, qs[query]); - function update_setting(opt, val) { - settings[key] = val; - if(opt.query) { - qs[opt.query] = write_query(type, val); - update_interesting(qs); - } - } - if(opt.values) { // generate options + var selection = select(opt.selector); + var opts = selection.selectAll('option').data(opt.values); + opts.enter().append('option') + .attr('value', function(x) { + return x; + }) + .attr('selected', function(x) { + return x === settings[key]; + }) + .text(function(x) { + return x; + }); + selection + .property('value', settings[key]); + } + if (opt.selector) { + switch (type) { case 'boolean': - if(!opt.set) + if (!opt.set) opt.set = function(val) { $(opt.selector) .prop('checked', val); }; - if(!opt.subscribe) + if (!opt.subscribe) opt.subscribe = function(k) { $(opt.selector) .change(function() { @@ -109,12 +121,12 @@ var sync_url_options = (function() { break; case 'number': case 'string': - if(!opt.set) + if (!opt.set) opt.set = function(val) { $(opt.selector) .val(val); }; - if(!opt.subscribe) + if (!opt.subscribe) opt.subscribe = function(k) { $(opt.selector) .change(function() { @@ -123,64 +135,63 @@ var sync_url_options = (function() { }); }; break; - default: throw new Error('unsupported selector type ' + type); - } + default: + throw new Error('unsupported selector type '+type); } - if(opt.set) - opt.set(settings[key]); - opt.update = function(val, manual) { - update_setting(opt, val); - callback && callback(val, manual); - }; - if(opt.subscribe) - opt.subscribe(opt.update); - } - - for(var key in options) { - var callback = function(opt, val, manual) { - args[0] = val; - if(opt.exert && (manual || !opt.dont_exert_after_subscribe)) - opt.exert.apply(opt, args); - if(domain && domain.on_exert) - domain.on_exert(opt); - }; - if(typeof options[key] !== 'object' || options[key] === null) - options[key] = { - default: options[key] - }; - do_option(key, options[key], callback.bind(null, options[key])); } + if (opt.set) + opt.set(settings[key]); + opt.update = function(val, manual) { + update_setting(opt, val); + callback && callback(val, manual); + }; + if (opt.subscribe) + opt.subscribe(opt.update); + } - return { - vals: settings, - exert: function() { - for(var key in options) - if(options[key].exert) { - args[0] = settings[key]; - options[key].exert.apply(options[key], args); - } - }, - output: function(_) { - if(!arguments.length) - return _output; - _output = _; - return this; - }, - update: function(k, v, do_ui) { - if(do_ui) - options[k].set(v); - options[k].update(v, true); - }, - what_if_url: function(overrides) { - var qs2 = Object.assign({}, qs, overrides); - return querystring.get_url(interesting_params(qs2)); - } + for (var key in options) { + var callback = function(opt, val, manual) { + args[0] = val; + if (opt.exert && (manual || !opt.dont_exert_after_subscribe)) + opt.exert.apply(opt, args); + if (domain && domain.on_exert) + domain.on_exert(opt); }; + if (typeof options[key] !== 'object' || options[key] === null) + options[key] = { + default: options[key], + }; + do_option(key, options[key], callback.bind(null, options[key])); } - return function(options, domain /* ... arguments for exert ... */) { - var args = Array.prototype.slice.call(arguments, 2); - args.unshift(0); - return option_synchronizer(options, domain, args); - }; -})(); + return { + vals: settings, + exert: function() { + for (var key in options) + if (options[key].exert) { + args[0] = settings[key]; + options[key].exert.apply(options[key], args); + } + }, + output: function(_) { + if (!arguments.length) + return _output; + _output = _; + return this; + }, + update: function(k, v, do_ui) { + if (do_ui) + options[k].set(v); + options[k].update(v, true); + }, + what_if_url: function(overrides) { + var qs2 = Object.assign({}, qs, overrides); + return querystring.get_url(interesting_params(qs2)); + }, + }; +} +export default function sync_url_options(options, domain /* ... arguments for exert ... */) { + var args = Array.prototype.slice.call(arguments, 2); + args.unshift(0); + return option_synchronizer(options, domain, args); +} diff --git a/timeline.js b/timeline.js index b30e00fb..de203bd7 100644 --- a/timeline.js +++ b/timeline.js @@ -20,32 +20,32 @@ function timeline(parent) { var _timewid = 65, _timefmt = d3.time.format('%-m/%-d %H:%M:%S'); _chart.x = function(scale) { - if(!arguments.length) + if (!arguments.length) return _x; _x = scale; return _chart; }; _chart.y = function(scale) { - if(!arguments.length) + if (!arguments.length) return _y; _y = scale; return _chart; }; _chart.events = function(events) { - if(!arguments.length) + if (!arguments.length) return _events; _events = events.map(function(e) { var value; - if(e.value.adds !== undefined) { + if (e.value.adds !== undefined) { value = [ {key: 'adds', height: e.value.adds, fill: 'green'}, - {key: 'dels', height: e.value.dels, fill: 'red'} + {key: 'dels', height: e.value.dels, fill: 'red'}, ]; } else { value = [ - {key: 'place', height: NaN, fill: 'grey'} + {key: 'place', height: NaN, fill: 'grey'}, ]; } return {key: e.key, value: value}; @@ -55,14 +55,14 @@ function timeline(parent) { // a region {x1, x2, color, opacity} to highlight _chart.region = function(region) { - if(!arguments.length) + if (!arguments.length) return _region; _region = region; return _chart; }; _chart.current = function(t) { - if(!arguments.length) + if (!arguments.length) return _current; _current = t; return _chart; @@ -73,68 +73,84 @@ function timeline(parent) { } function y(height) { - return isNaN(height) ? 3 : _y(0) - _y(height); + return isNaN(height) ? 3 : _y(0)-_y(height); } _chart.minHeight = function(h) { - if(!arguments.length) + if (!arguments.length) return _minHeight; _minHeight = h; return _chart; }; _chart.tickOpacity = function(o) { - if(!arguments.length) + if (!arguments.length) return _tickOpacity; _tickOpacity = o; return _chart; }; _chart.tickWidth = function(o) { - if(!arguments.length) + if (!arguments.length) return _tickWidth; _tickWidth = o; return _chart; }; function height(tick) { - switch(tick.key) { - case 'place': return 3; - case 'marker': return baseline(); - default: return y(tick.height); + switch (tick.key) { + case 'place': + return 3; + case 'marker': + return baseline(); + default: + return y(tick.height); } } function y0(tick) { - switch(tick.key) { - case 'place': return baseline()-1; - case 'adds': return baseline()-y(tick.height); - case 'dels': return baseline(); - default: throw new Error('unknown tick type ' + tick.key); + switch (tick.key) { + case 'place': + return baseline()-1; + case 'adds': + return baseline()-y(tick.height); + case 'dels': + return baseline(); + default: + throw new Error('unknown tick type '+tick.key); } } _chart.redraw = function() { var bl = baseline(); - if(!_x) _x = d3.time.scale(); - if(!_y) _y = d3.scale.linear(); - _x.domain(d3.extent(_events, function(e) { return e.key; })) + if (!_x) _x = d3.time.scale(); + if (!_y) _y = d3.scale.linear(); + _x.domain(d3.extent(_events, function(e) { + return e.key; + })) .range([_timewid, _width-_tickWidth]); - var max = Math.max(_minHeight, d3.max(_events, function(e) { - return e.value[0].key === 'adds' ? Math.max(e.value[0].height, e.value[1].height) : 0; - })); + var max = Math.max( + _minHeight, + d3.max(_events, function(e) { + return e.value[0].key === 'adds' + ? Math.max(e.value[0].height, e.value[1].height) + : 0; + }), + ); _y.domain([max, -max]).range([0, _height]); var axis = _g.selectAll('rect.timeline').data([0]); axis.enter().append('rect').attr('class', 'timeline'); axis.attr({ - width: _width-_timewid, height: 1, - x: _timewid, y: bl, - fill: '#ccc' + width: _width-_timewid, + height: 1, + x: _timewid, + y: bl, + fill: '#ccc', }); var region = _g.selectAll('rect.region') - .data(_region ? [_region] : []); + .data(_region ? [_region] : []); region.enter().append('rect') .attr('class', 'region'); region.attr({ @@ -143,56 +159,67 @@ function timeline(parent) { }, y: 0, width: function(d) { - return _x(d.x2) - _x(d.x1) + _tickWidth; + return _x(d.x2)-_x(d.x1)+_tickWidth; }, height: _height, fill: _region && _region.color || 'blue', - opacity: _region && _region.opacity || 0.5 + opacity: _region && _region.opacity || 0.5, }); region.exit().remove(); var ticks = _g.selectAll('g.timetick') - .data(_events, function(e) { return e.key; }); + .data(_events, function(e) { + return e.key; + }); ticks.enter().append('g').attr('class', 'timetick'); ticks.attr('transform', function(d) { - return 'translate(' + Math.floor(_x(d.key)) + ',0)'; + return 'translate('+Math.floor(_x(d.key))+',0)'; }); ticks.exit().remove(); var tick = ticks.selectAll('rect') - .data(function(d) { return d.value; }, function(t) { return t.key; }); + .data(function(d) { + return d.value; + }, function(t) { + return t.key; + }); tick.enter().append('rect'); tick.attr({ width: _tickWidth, height: height, - x: 0, y: y0, - fill: function(t) { return t.fill; }, - opacity: _tickOpacity + x: 0, + y: y0, + fill: function(t) { + return t.fill; + }, + opacity: _tickOpacity, }); tick.exit().remove(); - if(_current) { + if (_current) { var text = _g.selectAll('text.currtime') - .data([0]); + .data([0]); text.enter().append('text').attr('class', 'currtime'); text.text(_timefmt(_current)).attr({ 'font-family': 'sans-serif', 'font-size': '10px', x: 0, - y: bl + y: bl, }); var head = _g.selectAll('g.playhead') - .data([0]); + .data([0]); head.enter().append('g').attr('class', 'playhead'); var playbox = head.selectAll('rect') - .data([0]); + .data([0]); playbox.enter().append('rect'); playbox.attr({ - width: 4, height: _height, - x: Math.floor(_x(_current))-1, y: 0, + width: 4, + height: _height, + x: Math.floor(_x(_current))-1, + y: 0, fill: 'none', stroke: 'darkblue', 'stroke-width': 1, - opacity: 0.5 + opacity: 0.5, }); } return _chart; @@ -204,7 +231,7 @@ function timeline(parent) { .append('g'); _svg.on('click', function() { - if(_x) + if (_x) _dispatch.jump(_x.invert(d3.mouse(this)[0])); }); _chart.redraw(); @@ -217,14 +244,14 @@ function timeline(parent) { }; _chart.width = function(w) { - if(!arguments.length) + if (!arguments.length) return _width; _width = w; return _chart; }; _chart.height = function(h) { - if(!arguments.length) + if (!arguments.length) return _height; _height = h; return _chart; @@ -245,8 +272,7 @@ function timeline(parent) { function generateSvg() { _svg = _root.append('svg') - .attr({width: _chart.width(), - height: _chart.height()}); + .attr({width: _chart.width(), height: _chart.height()}); } _root = d3.select(parent); diff --git a/web/arrow-designer.html b/web/arrow-designer.html index 351dced2..387c7777 100644 --- a/web/arrow-designer.html +++ b/web/arrow-designer.html @@ -9,22 +9,32 @@ - - - - - - + - - -
- +
      @@ -45,6 +55,6 @@
- + diff --git a/web/brushing-filtering.html b/web/brushing-filtering.html index a0aeb52b..09d5a55b 100644 --- a/web/brushing-filtering.html +++ b/web/brushing-filtering.html @@ -3,6 +3,38 @@ Brushing and filtering + + + + + + + @@ -10,34 +42,26 @@ - - - - + - - + - - + - - - - +
- +
@@ -58,5 +82,5 @@
- + diff --git a/web/catalog/A.json b/web/catalog/A.json index 8ce69fed..17600f02 100644 --- a/web/catalog/A.json +++ b/web/catalog/A.json @@ -8,4 +8,3 @@ "requirements": [], "capabilities": ["cap1", "cap2", "cap3"] } - diff --git a/web/collapse-equivalent-subgraphs.html b/web/collapse-equivalent-subgraphs.html deleted file mode 100644 index 60553edb..00000000 --- a/web/collapse-equivalent-subgraphs.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - Collapse equivalent subgraphs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
-
-     - - -
-
-
- - -
-
-
-
- - - - diff --git a/web/compare-layouts.html b/web/compare-layouts.html index 99e7bf96..5f5ebe32 100644 --- a/web/compare-layouts.html +++ b/web/compare-layouts.html @@ -5,35 +5,47 @@ - - - - - - + - + + + - - + - - - - - + + + " ).appendTo( body ); - } - - // We need to make sure to grab the zIndex before setting the - // opacity, because setting the opacity to anything lower than 1 - // causes the zIndex to change from "auto" to 0. - if ( o.zIndex ) { // zIndex option - if ( this.helper.css( "zIndex" ) ) { - this._storedZIndex = this.helper.css( "zIndex" ); - } - this.helper.css( "zIndex", o.zIndex ); - } - - if ( o.opacity ) { // opacity option - if ( this.helper.css( "opacity" ) ) { - this._storedOpacity = this.helper.css( "opacity" ); - } - this.helper.css( "opacity", o.opacity ); - } - - //Prepare scrolling - if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && - this.scrollParent[ 0 ].tagName !== "HTML" ) { - this.overflowOffset = this.scrollParent.offset(); - } - - //Call callbacks - this._trigger( "start", event, this._uiHash() ); - - //Recache the helper size - if ( !this._preserveHelperProportions ) { - this._cacheHelperProportions(); - } - - //Post "activate" events to possible containers - if ( !noActivation ) { - for ( i = this.containers.length - 1; i >= 0; i-- ) { - this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); - } - } - - //Prepare possible droppables - if ( $.ui.ddmanager ) { - $.ui.ddmanager.current = this; - } - - if ( $.ui.ddmanager && !o.dropBehaviour ) { - $.ui.ddmanager.prepareOffsets( this, event ); - } - - this.dragging = true; - - this._addClass( this.helper, "ui-sortable-helper" ); - - //Move the helper, if needed - if ( !this.helper.parent().is( this.appendTo ) ) { - this.helper.detach().appendTo( this.appendTo ); - - //Update position - this.offset.parent = this._getParentOffset(); - } - - //Generate the original position - this.position = this.originalPosition = this._generatePosition( event ); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - this.lastPositionAbs = this.positionAbs = this._convertPositionTo( "absolute" ); - - this._mouseDrag( event ); - - return true; - - }, - - _scroll: function( event ) { - var o = this.options, - scrolled = false; - - if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && - this.scrollParent[ 0 ].tagName !== "HTML" ) { - - if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) - - event.pageY < o.scrollSensitivity ) { - this.scrollParent[ 0 ].scrollTop = - scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed; - } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) { - this.scrollParent[ 0 ].scrollTop = - scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed; - } - - if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) - - event.pageX < o.scrollSensitivity ) { - this.scrollParent[ 0 ].scrollLeft = scrolled = - this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed; - } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) { - this.scrollParent[ 0 ].scrollLeft = scrolled = - this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed; - } - - } else { - - if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) { - scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed ); - } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) < - o.scrollSensitivity ) { - scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed ); - } - - if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) { - scrolled = this.document.scrollLeft( - this.document.scrollLeft() - o.scrollSpeed - ); - } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) < - o.scrollSensitivity ) { - scrolled = this.document.scrollLeft( - this.document.scrollLeft() + o.scrollSpeed - ); - } - - } - - return scrolled; - }, - - _mouseDrag: function( event ) { - var i, item, itemElement, intersection, - o = this.options; - - //Compute the helpers position - this.position = this._generatePosition( event ); - this.positionAbs = this._convertPositionTo( "absolute" ); - - //Set the helper position - if ( !this.options.axis || this.options.axis !== "y" ) { - this.helper[ 0 ].style.left = this.position.left + "px"; - } - if ( !this.options.axis || this.options.axis !== "x" ) { - this.helper[ 0 ].style.top = this.position.top + "px"; - } - - //Do scrolling - if ( o.scroll ) { - if ( this._scroll( event ) !== false ) { - - //Update item positions used in position checks - this._refreshItemPositions( true ); - - if ( $.ui.ddmanager && !o.dropBehaviour ) { - $.ui.ddmanager.prepareOffsets( this, event ); - } - } - } - - this.dragDirection = { - vertical: this._getDragVerticalDirection(), - horizontal: this._getDragHorizontalDirection() - }; - - //Rearrange - for ( i = this.items.length - 1; i >= 0; i-- ) { - - //Cache variables and intersection, continue if no intersection - item = this.items[ i ]; - itemElement = item.item[ 0 ]; - intersection = this._intersectsWithPointer( item ); - if ( !intersection ) { - continue; - } - - // Only put the placeholder inside the current Container, skip all - // items from other containers. This works because when moving - // an item from one container to another the - // currentContainer is switched before the placeholder is moved. - // - // Without this, moving items in "sub-sortables" can cause - // the placeholder to jitter between the outer and inner container. - if ( item.instance !== this.currentContainer ) { - continue; - } - - // Cannot intersect with itself - // no useless actions that have been done before - // no action if the item moved is the parent of the item checked - if ( itemElement !== this.currentItem[ 0 ] && - this.placeholder[ intersection === 1 ? - "next" : "prev" ]()[ 0 ] !== itemElement && - !$.contains( this.placeholder[ 0 ], itemElement ) && - ( this.options.type === "semi-dynamic" ? - !$.contains( this.element[ 0 ], itemElement ) : - true - ) - ) { - - this.direction = intersection === 1 ? "down" : "up"; - - if ( this.options.tolerance === "pointer" || - this._intersectsWithSides( item ) ) { - this._rearrange( event, item ); - } else { - break; - } - - this._trigger( "change", event, this._uiHash() ); - break; - } - } - - //Post events to containers - this._contactContainers( event ); - - //Interconnect with droppables - if ( $.ui.ddmanager ) { - $.ui.ddmanager.drag( this, event ); - } - - //Call callbacks - this._trigger( "sort", event, this._uiHash() ); - - this.lastPositionAbs = this.positionAbs; - return false; - - }, - - _mouseStop: function( event, noPropagation ) { - - if ( !event ) { - return; - } - - //If we are using droppables, inform the manager about the drop - if ( $.ui.ddmanager && !this.options.dropBehaviour ) { - $.ui.ddmanager.drop( this, event ); - } - - if ( this.options.revert ) { - var that = this, - cur = this.placeholder.offset(), - axis = this.options.axis, - animation = {}; - - if ( !axis || axis === "x" ) { - animation.left = cur.left - this.offset.parent.left - this.margins.left + - ( this.offsetParent[ 0 ] === this.document[ 0 ].body ? - 0 : - this.offsetParent[ 0 ].scrollLeft - ); - } - if ( !axis || axis === "y" ) { - animation.top = cur.top - this.offset.parent.top - this.margins.top + - ( this.offsetParent[ 0 ] === this.document[ 0 ].body ? - 0 : - this.offsetParent[ 0 ].scrollTop - ); - } - this.reverting = true; - $( this.helper ).animate( - animation, - parseInt( this.options.revert, 10 ) || 500, - function() { - that._clear( event ); - } - ); - } else { - this._clear( event, noPropagation ); - } - - return false; - - }, - - cancel: function() { - - if ( this.dragging ) { - - this._mouseUp( new $.Event( "mouseup", { target: null } ) ); - - if ( this.options.helper === "original" ) { - this.currentItem.css( this._storedCSS ); - this._removeClass( this.currentItem, "ui-sortable-helper" ); - } else { - this.currentItem.show(); - } - - //Post deactivating events to containers - for ( var i = this.containers.length - 1; i >= 0; i-- ) { - this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) ); - if ( this.containers[ i ].containerCache.over ) { - this.containers[ i ]._trigger( "out", null, this._uiHash( this ) ); - this.containers[ i ].containerCache.over = 0; - } - } - - } - - if ( this.placeholder ) { - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, - // it unbinds ALL events from the original node! - if ( this.placeholder[ 0 ].parentNode ) { - this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] ); - } - if ( this.options.helper !== "original" && this.helper && - this.helper[ 0 ].parentNode ) { - this.helper.remove(); - } - - $.extend( this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - } ); - - if ( this.domPosition.prev ) { - $( this.domPosition.prev ).after( this.currentItem ); - } else { - $( this.domPosition.parent ).prepend( this.currentItem ); - } - } - - return this; - - }, - - serialize: function( o ) { - - var items = this._getItemsAsjQuery( o && o.connected ), - str = []; - o = o || {}; - - $( items ).each( function() { - var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" ) - .match( o.expression || ( /(.+)[\-=_](.+)/ ) ); - if ( res ) { - str.push( - ( o.key || res[ 1 ] + "[]" ) + - "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) ); - } - } ); - - if ( !str.length && o.key ) { - str.push( o.key + "=" ); - } - - return str.join( "&" ); - - }, - - toArray: function( o ) { - - var items = this._getItemsAsjQuery( o && o.connected ), - ret = []; - - o = o || {}; - - items.each( function() { - ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" ); - } ); - return ret; - - }, - - /* Be careful with the following core functions */ - _intersectsWith: function( item ) { - - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height, - l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height, - dyClick = this.offset.click.top, - dxClick = this.offset.click.left, - isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && - ( y1 + dyClick ) < b ), - isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && - ( x1 + dxClick ) < r ), - isOverElement = isOverElementHeight && isOverElementWidth; - - if ( this.options.tolerance === "pointer" || - this.options.forcePointerForContainers || - ( this.options.tolerance !== "pointer" && - this.helperProportions[ this.floating ? "width" : "height" ] > - item[ this.floating ? "width" : "height" ] ) - ) { - return isOverElement; - } else { - - return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half - x2 - ( this.helperProportions.width / 2 ) < r && // Left Half - t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half - y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half - - } - }, - - _intersectsWithPointer: function( item ) { - var verticalDirection, horizontalDirection, - isOverElementHeight = ( this.options.axis === "x" ) || - this._isOverAxis( - this.positionAbs.top + this.offset.click.top, item.top, item.height ), - isOverElementWidth = ( this.options.axis === "y" ) || - this._isOverAxis( - this.positionAbs.left + this.offset.click.left, item.left, item.width ), - isOverElement = isOverElementHeight && isOverElementWidth; - - if ( !isOverElement ) { - return false; - } - - verticalDirection = this.dragDirection.vertical; - horizontalDirection = this.dragDirection.horizontal; - - return this.floating ? - ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 ) : - ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) ); - - }, - - _intersectsWithSides: function( item ) { - - var isOverBottomHalf = this._isOverAxis( this.positionAbs.top + - this.offset.click.top, item.top + ( item.height / 2 ), item.height ), - isOverRightHalf = this._isOverAxis( this.positionAbs.left + - this.offset.click.left, item.left + ( item.width / 2 ), item.width ), - verticalDirection = this.dragDirection.vertical, - horizontalDirection = this.dragDirection.horizontal; - - if ( this.floating && horizontalDirection ) { - return ( ( horizontalDirection === "right" && isOverRightHalf ) || - ( horizontalDirection === "left" && !isOverRightHalf ) ); - } else { - return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) || - ( verticalDirection === "up" && !isOverBottomHalf ) ); - } - - }, - - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta !== 0 && ( delta > 0 ? "down" : "up" ); - }, - - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta !== 0 && ( delta > 0 ? "right" : "left" ); - }, - - refresh: function( event ) { - this._refreshItems( event ); - this._setHandleClassName(); - this.refreshPositions(); - return this; - }, - - _connectWith: function() { - var options = this.options; - return options.connectWith.constructor === String ? - [ options.connectWith ] : - options.connectWith; - }, - - _getItemsAsjQuery: function( connected ) { - - var i, j, cur, inst, - items = [], - queries = [], - connectWith = this._connectWith(); - - if ( connectWith && connected ) { - for ( i = connectWith.length - 1; i >= 0; i-- ) { - cur = $( connectWith[ i ], this.document[ 0 ] ); - for ( j = cur.length - 1; j >= 0; j-- ) { - inst = $.data( cur[ j ], this.widgetFullName ); - if ( inst && inst !== this && !inst.options.disabled ) { - queries.push( [ typeof inst.options.items === "function" ? - inst.options.items.call( inst.element ) : - $( inst.options.items, inst.element ) - .not( ".ui-sortable-helper" ) - .not( ".ui-sortable-placeholder" ), inst ] ); - } - } - } - } - - queries.push( [ typeof this.options.items === "function" ? - this.options.items - .call( this.element, null, { options: this.options, item: this.currentItem } ) : - $( this.options.items, this.element ) - .not( ".ui-sortable-helper" ) - .not( ".ui-sortable-placeholder" ), this ] ); - - function addItems() { - items.push( this ); - } - for ( i = queries.length - 1; i >= 0; i-- ) { - queries[ i ][ 0 ].each( addItems ); - } - - return $( items ); - - }, - - _removeCurrentsFromItems: function() { - - var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" ); - - this.items = $.grep( this.items, function( item ) { - for ( var j = 0; j < list.length; j++ ) { - if ( list[ j ] === item.item[ 0 ] ) { - return false; - } - } - return true; - } ); - - }, - - _refreshItems: function( event ) { - - this.items = []; - this.containers = [ this ]; - - var i, j, cur, inst, targetData, _queries, item, queriesLength, - items = this.items, - queries = [ [ typeof this.options.items === "function" ? - this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) : - $( this.options.items, this.element ), this ] ], - connectWith = this._connectWith(); - - //Shouldn't be run the first time through due to massive slow-down - if ( connectWith && this.ready ) { - for ( i = connectWith.length - 1; i >= 0; i-- ) { - cur = $( connectWith[ i ], this.document[ 0 ] ); - for ( j = cur.length - 1; j >= 0; j-- ) { - inst = $.data( cur[ j ], this.widgetFullName ); - if ( inst && inst !== this && !inst.options.disabled ) { - queries.push( [ typeof inst.options.items === "function" ? - inst.options.items - .call( inst.element[ 0 ], event, { item: this.currentItem } ) : - $( inst.options.items, inst.element ), inst ] ); - this.containers.push( inst ); - } - } - } - } - - for ( i = queries.length - 1; i >= 0; i-- ) { - targetData = queries[ i ][ 1 ]; - _queries = queries[ i ][ 0 ]; - - for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) { - item = $( _queries[ j ] ); - - // Data for target checking (mouse manager) - item.data( this.widgetName + "-item", targetData ); - - items.push( { - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - } ); - } - } - - }, - - _refreshItemPositions: function( fast ) { - var i, item, t, p; - - for ( i = this.items.length - 1; i >= 0; i-- ) { - item = this.items[ i ]; - - //We ignore calculating positions of all connected containers when we're not over them - if ( this.currentContainer && item.instance !== this.currentContainer && - item.item[ 0 ] !== this.currentItem[ 0 ] ) { - continue; - } - - t = this.options.toleranceElement ? - $( this.options.toleranceElement, item.item ) : - item.item; - - if ( !fast ) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } - - p = t.offset(); - item.left = p.left; - item.top = p.top; - } - }, - - refreshPositions: function( fast ) { - - // Determine whether items are being displayed horizontally - this.floating = this.items.length ? - this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) : - false; - - // This has to be redone because due to the item being moved out/into the offsetParent, - // the offsetParent's position will change - if ( this.offsetParent && this.helper ) { - this.offset.parent = this._getParentOffset(); - } - - this._refreshItemPositions( fast ); - - var i, p; - - if ( this.options.custom && this.options.custom.refreshContainers ) { - this.options.custom.refreshContainers.call( this ); - } else { - for ( i = this.containers.length - 1; i >= 0; i-- ) { - p = this.containers[ i ].element.offset(); - this.containers[ i ].containerCache.left = p.left; - this.containers[ i ].containerCache.top = p.top; - this.containers[ i ].containerCache.width = - this.containers[ i ].element.outerWidth(); - this.containers[ i ].containerCache.height = - this.containers[ i ].element.outerHeight(); - } - } - - return this; - }, - - _createPlaceholder: function( that ) { - that = that || this; - var className, nodeName, - o = that.options; - - if ( !o.placeholder || o.placeholder.constructor === String ) { - className = o.placeholder; - nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(); - o.placeholder = { - element: function() { - - var element = $( "<" + nodeName + ">", that.document[ 0 ] ); - - that._addClass( element, "ui-sortable-placeholder", - className || that.currentItem[ 0 ].className ) - ._removeClass( element, "ui-sortable-helper" ); - - if ( nodeName === "tbody" ) { - that._createTrPlaceholder( - that.currentItem.find( "tr" ).eq( 0 ), - $( "", that.document[ 0 ] ).appendTo( element ) - ); - } else if ( nodeName === "tr" ) { - that._createTrPlaceholder( that.currentItem, element ); - } else if ( nodeName === "img" ) { - element.attr( "src", that.currentItem.attr( "src" ) ); - } - - if ( !className ) { - element.css( "visibility", "hidden" ); - } - - return element; - }, - update: function( container, p ) { - - // 1. If a className is set as 'placeholder option, we don't force sizes - - // the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a - // class name is specified - if ( className && !o.forcePlaceholderSize ) { - return; - } - - // If the element doesn't have a actual height or width by itself (without - // styles coming from a stylesheet), it receives the inline height and width - // from the dragged item. Or, if it's a tbody or tr, it's going to have a height - // anyway since we're populating them with s above, but they're unlikely to - // be the correct height on their own if the row heights are dynamic, so we'll - // always assign the height of the dragged item given forcePlaceholderSize - // is true. - if ( !p.height() || ( o.forcePlaceholderSize && - ( nodeName === "tbody" || nodeName === "tr" ) ) ) { - p.height( - that.currentItem.innerHeight() - - parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) - - parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) ); - } - if ( !p.width() ) { - p.width( - that.currentItem.innerWidth() - - parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) - - parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) ); - } - } - }; - } - - //Create the placeholder - that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) ); - - //Append it after the actual current item - that.currentItem.after( that.placeholder ); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update( that, that.placeholder ); - - }, - - _createTrPlaceholder: function( sourceTr, targetTr ) { - var that = this; - - sourceTr.children().each( function() { - $( " ", that.document[ 0 ] ) - .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) - .appendTo( targetTr ); - } ); - }, - - _contactContainers: function( event ) { - var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, - floating, axis, - innermostContainer = null, - innermostIndex = null; - - // Get innermost container that intersects with item - for ( i = this.containers.length - 1; i >= 0; i-- ) { - - // Never consider a container that's located within the item itself - if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) { - continue; - } - - if ( this._intersectsWith( this.containers[ i ].containerCache ) ) { - - // If we've already found a container and it's more "inner" than this, then continue - if ( innermostContainer && - $.contains( - this.containers[ i ].element[ 0 ], - innermostContainer.element[ 0 ] ) ) { - continue; - } - - innermostContainer = this.containers[ i ]; - innermostIndex = i; - - } else { - - // container doesn't intersect. trigger "out" event if necessary - if ( this.containers[ i ].containerCache.over ) { - this.containers[ i ]._trigger( "out", event, this._uiHash( this ) ); - this.containers[ i ].containerCache.over = 0; - } - } - - } - - // If no intersecting containers found, return - if ( !innermostContainer ) { - return; - } - - // Move the item into the container if it's not there already - if ( this.containers.length === 1 ) { - if ( !this.containers[ innermostIndex ].containerCache.over ) { - this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) ); - this.containers[ innermostIndex ].containerCache.over = 1; - } - } else { - - // When entering a new container, we will find the item with the least distance and - // append our item near it - dist = 10000; - itemWithLeastDistance = null; - floating = innermostContainer.floating || this._isFloating( this.currentItem ); - posProperty = floating ? "left" : "top"; - sizeProperty = floating ? "width" : "height"; - axis = floating ? "pageX" : "pageY"; - - for ( j = this.items.length - 1; j >= 0; j-- ) { - if ( !$.contains( - this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] ) - ) { - continue; - } - if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) { - continue; - } - - cur = this.items[ j ].item.offset()[ posProperty ]; - nearBottom = false; - if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) { - nearBottom = true; - } - - if ( Math.abs( event[ axis ] - cur ) < dist ) { - dist = Math.abs( event[ axis ] - cur ); - itemWithLeastDistance = this.items[ j ]; - this.direction = nearBottom ? "up" : "down"; - } - } - - //Check if dropOnEmpty is enabled - if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) { - return; - } - - if ( this.currentContainer === this.containers[ innermostIndex ] ) { - if ( !this.currentContainer.containerCache.over ) { - this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() ); - this.currentContainer.containerCache.over = 1; - } - return; - } - - if ( itemWithLeastDistance ) { - this._rearrange( event, itemWithLeastDistance, null, true ); - } else { - this._rearrange( event, null, this.containers[ innermostIndex ].element, true ); - } - this._trigger( "change", event, this._uiHash() ); - this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) ); - this.currentContainer = this.containers[ innermostIndex ]; - - //Update the placeholder - this.options.placeholder.update( this.currentContainer, this.placeholder ); - - //Update scrollParent - this.scrollParent = this.placeholder.scrollParent(); - - //Update overflowOffset - if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && - this.scrollParent[ 0 ].tagName !== "HTML" ) { - this.overflowOffset = this.scrollParent.offset(); - } - - this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) ); - this.containers[ innermostIndex ].containerCache.over = 1; - } - - }, - - _createHelper: function( event ) { - - var o = this.options, - helper = typeof o.helper === "function" ? - $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) : - ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem ); - - //Add the helper to the DOM if that didn't happen already - if ( !helper.parents( "body" ).length ) { - this.appendTo[ 0 ].appendChild( helper[ 0 ] ); - } - - if ( helper[ 0 ] === this.currentItem[ 0 ] ) { - this._storedCSS = { - width: this.currentItem[ 0 ].style.width, - height: this.currentItem[ 0 ].style.height, - position: this.currentItem.css( "position" ), - top: this.currentItem.css( "top" ), - left: this.currentItem.css( "left" ) - }; - } - - if ( !helper[ 0 ].style.width || o.forceHelperSize ) { - helper.width( this.currentItem.width() ); - } - if ( !helper[ 0 ].style.height || o.forceHelperSize ) { - helper.height( this.currentItem.height() ); - } - - return helper; - - }, - - _adjustOffsetFromHelper: function( obj ) { - if ( typeof obj === "string" ) { - obj = obj.split( " " ); - } - if ( Array.isArray( obj ) ) { - obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 }; - } - if ( "left" in obj ) { - this.offset.click.left = obj.left + this.margins.left; - } - if ( "right" in obj ) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ( "top" in obj ) { - this.offset.click.top = obj.top + this.margins.top; - } - if ( "bottom" in obj ) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the - // following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the - // next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't - // the document, which means that the scroll is included in the initial calculation of the - // offset of the parent, and never recalculated upon drag - if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] && - $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - // This needs to be actually done for all browsers, since pageX/pageY includes this - // information with an ugly IE fix - if ( this.offsetParent[ 0 ] === this.document[ 0 ].body || - ( this.offsetParent[ 0 ].tagName && - this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) { - po = { top: 0, left: 0 }; - } - - return { - top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ), - left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 ) - }; - - }, - - _getRelativeOffset: function() { - - if ( this.cssPosition === "relative" ) { - var p = this.currentItem.position(); - return { - top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) + - this.scrollParent.scrollTop(), - left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) + - this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ), - top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 ) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var ce, co, over, - o = this.options; - if ( o.containment === "parent" ) { - o.containment = this.helper[ 0 ].parentNode; - } - if ( o.containment === "document" || o.containment === "window" ) { - this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - o.containment === "document" ? - this.document.width() : - this.window.width() - this.helperProportions.width - this.margins.left, - ( o.containment === "document" ? - ( this.document.height() || document.body.parentNode.scrollHeight ) : - this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight - ) - this.helperProportions.height - this.margins.top - ]; - } - - if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) { - ce = $( o.containment )[ 0 ]; - co = $( o.containment ).offset(); - over = ( $( ce ).css( "overflow" ) !== "hidden" ); - - this.containment = [ - co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) + - ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left, - co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) + - ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top, - co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - - ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) - - ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) - - this.helperProportions.width - this.margins.left, - co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - - ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) - - ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) - - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function( d, pos ) { - - if ( !pos ) { - pos = this.position; - } - var mod = d === "absolute" ? 1 : -1, - scroll = this.cssPosition === "absolute" && - !( this.scrollParent[ 0 ] !== this.document[ 0 ] && - $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? - this.offsetParent : - this.scrollParent, - scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName ); - - return { - top: ( - - // The absolute mouse position - pos.top + - - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.relative.top * mod + - - // The offsetParent's offset without borders (offset + border) - this.offset.parent.top * mod - - ( ( this.cssPosition === "fixed" ? - -this.scrollParent.scrollTop() : - ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod ) - ), - left: ( - - // The absolute mouse position - pos.left + - - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.relative.left * mod + - - // The offsetParent's offset without borders (offset + border) - this.offset.parent.left * mod - - ( ( this.cssPosition === "fixed" ? - -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : - scroll.scrollLeft() ) * mod ) - ) - }; - - }, - - _generatePosition: function( event ) { - - var top, left, - o = this.options, - pageX = event.pageX, - pageY = event.pageY, - scroll = this.cssPosition === "absolute" && - !( this.scrollParent[ 0 ] !== this.document[ 0 ] && - $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? - this.offsetParent : - this.scrollParent, - scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName ); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] && - this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) { - this.offset.relative = this._getRelativeOffset(); - } - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options - - if ( this.containment ) { - if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) { - pageX = this.containment[ 0 ] + this.offset.click.left; - } - if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) { - pageY = this.containment[ 1 ] + this.offset.click.top; - } - if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) { - pageX = this.containment[ 2 ] + this.offset.click.left; - } - if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) { - pageY = this.containment[ 3 ] + this.offset.click.top; - } - } - - if ( o.grid ) { - top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) / - o.grid[ 1 ] ) * o.grid[ 1 ]; - pageY = this.containment ? - ( ( top - this.offset.click.top >= this.containment[ 1 ] && - top - this.offset.click.top <= this.containment[ 3 ] ) ? - top : - ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ? - top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : - top; - - left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) / - o.grid[ 0 ] ) * o.grid[ 0 ]; - pageX = this.containment ? - ( ( left - this.offset.click.left >= this.containment[ 0 ] && - left - this.offset.click.left <= this.containment[ 2 ] ) ? - left : - ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ? - left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : - left; - } - - } - - return { - top: ( - - // The absolute mouse position - pageY - - - // Click offset (relative to the element) - this.offset.click.top - - - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.relative.top - - - // The offsetParent's offset without borders (offset + border) - this.offset.parent.top + - ( ( this.cssPosition === "fixed" ? - -this.scrollParent.scrollTop() : - ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) ) - ), - left: ( - - // The absolute mouse position - pageX - - - // Click offset (relative to the element) - this.offset.click.left - - - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.relative.left - - - // The offsetParent's offset without borders (offset + border) - this.offset.parent.left + - ( ( this.cssPosition === "fixed" ? - -this.scrollParent.scrollLeft() : - scrollIsRootNode ? 0 : scroll.scrollLeft() ) ) - ) - }; - - }, - - _rearrange: function( event, i, a, hardRefresh ) { - - if ( a ) { - a[ 0 ].appendChild( this.placeholder[ 0 ] ); - } else { - i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ], - ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) ); - } - - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, - // if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var counter = this.counter; - - this._delay( function() { - if ( counter === this.counter ) { - - //Precompute after each DOM insertion, NOT on mousemove - this.refreshPositions( !hardRefresh ); - } - } ); - - }, - - _clear: function( event, noPropagation ) { - - this.reverting = false; - - // We delay all events that have to be triggered to after the point where the placeholder - // has been removed and everything else normalized again - var i, - delayedTriggers = []; - - // We first have to update the dom position of the actual currentItem - // Note: don't do it if the current item is already removed (by a user), or it gets - // reappended (see #4088) - if ( !this._noFinalSort && this.currentItem.parent().length ) { - this.placeholder.before( this.currentItem ); - } - this._noFinalSort = null; - - if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) { - for ( i in this._storedCSS ) { - if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) { - this._storedCSS[ i ] = ""; - } - } - this.currentItem.css( this._storedCSS ); - this._removeClass( this.currentItem, "ui-sortable-helper" ); - } else { - this.currentItem.show(); - } - - if ( this.fromOutside && !noPropagation ) { - delayedTriggers.push( function( event ) { - this._trigger( "receive", event, this._uiHash( this.fromOutside ) ); - } ); - } - if ( ( this.fromOutside || - this.domPosition.prev !== - this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] || - this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) { - - // Trigger update callback if the DOM position has changed - delayedTriggers.push( function( event ) { - this._trigger( "update", event, this._uiHash() ); - } ); - } - - // Check if the items Container has Changed and trigger appropriate - // events. - if ( this !== this.currentContainer ) { - if ( !noPropagation ) { - delayedTriggers.push( function( event ) { - this._trigger( "remove", event, this._uiHash() ); - } ); - delayedTriggers.push( ( function( c ) { - return function( event ) { - c._trigger( "receive", event, this._uiHash( this ) ); - }; - } ).call( this, this.currentContainer ) ); - delayedTriggers.push( ( function( c ) { - return function( event ) { - c._trigger( "update", event, this._uiHash( this ) ); - }; - } ).call( this, this.currentContainer ) ); - } - } - - //Post events to containers - function delayEvent( type, instance, container ) { - return function( event ) { - container._trigger( type, event, instance._uiHash( instance ) ); - }; - } - for ( i = this.containers.length - 1; i >= 0; i-- ) { - if ( !noPropagation ) { - delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) ); - } - if ( this.containers[ i ].containerCache.over ) { - delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) ); - this.containers[ i ].containerCache.over = 0; - } - } - - //Do what was originally in plugins - if ( this.storedCursor ) { - this.document.find( "body" ).css( "cursor", this.storedCursor ); - this.storedStylesheet.remove(); - } - if ( this._storedOpacity ) { - this.helper.css( "opacity", this._storedOpacity ); - } - if ( this._storedZIndex ) { - this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex ); - } - - this.dragging = false; - - if ( !noPropagation ) { - this._trigger( "beforeStop", event, this._uiHash() ); - } - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, - // it unbinds ALL events from the original node! - this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] ); - - if ( !this.cancelHelperRemoval ) { - if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) { - this.helper.remove(); - } - this.helper = null; - } - - if ( !noPropagation ) { - for ( i = 0; i < delayedTriggers.length; i++ ) { - - // Trigger all delayed events - delayedTriggers[ i ].call( this, event ); - } - this._trigger( "stop", event, this._uiHash() ); - } - - this.fromOutside = false; - return !this.cancelHelperRemoval; - - }, - - _trigger: function() { - if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) { - this.cancel(); - } - }, - - _uiHash: function( _inst ) { - var inst = _inst || this; - return { - helper: inst.helper, - placeholder: inst.placeholder || $( [] ), - position: inst.position, - originalPosition: inst.originalPosition, - offset: inst.positionAbs, - item: inst.currentItem, - sender: _inst ? _inst.element : null - }; - } - -} ); - - -/*! + // >>label: Sortable + // >>group: Interactions + // >>description: Enables items in a list to be sorted using the mouse. + // >>docs: https://api.jqueryui.com/sortable/ + // >>demos: https://jqueryui.com/sortable/ + // >>css.structure: ../../themes/base/sortable.css + + var widgetsSortable = $.widget('ui.sortable', $.ui.mouse, { + version: '1.13.3', + widgetEventPrefix: 'sort', + ready: false, + options: { + appendTo: 'parent', + axis: false, + connectWith: false, + containment: false, + cursor: 'auto', + cursorAt: false, + dropOnEmpty: true, + forcePlaceholderSize: false, + forceHelperSize: false, + grid: false, + handle: false, + helper: 'original', + items: '> *', + opacity: false, + placeholder: false, + revert: false, + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + scope: 'default', + tolerance: 'intersect', + zIndex: 1000, + + // Callbacks + activate: null, + beforeStop: null, + change: null, + deactivate: null, + out: null, + over: null, + receive: null, + remove: null, + sort: null, + start: null, + stop: null, + update: null, + }, + + _isOverAxis: function(x, reference, size) { + return (x >= reference) && (x < (reference+size)); + }, + + _isFloating: function(item) { + return (/left|right/).test(item.css('float')) + || (/inline|table-cell/).test(item.css('display')); + }, + + _create: function() { + this.containerCache = {}; + this._addClass('ui-sortable'); + + // Get the items + this.refresh(); + + // Let's determine the parent's offset + this.offset = this.element.offset(); + + // Initialize mouse events for interaction + this._mouseInit(); + + this._setHandleClassName(); + + // We're ready to go + this.ready = true; + }, + + _setOption: function(key, value) { + this._super(key, value); + + if (key === 'handle') { + this._setHandleClassName(); + } + }, + + _setHandleClassName: function() { + var that = this; + this._removeClass(this.element.find('.ui-sortable-handle'), 'ui-sortable-handle'); + $.each(this.items, function() { + that._addClass( + this.instance.options.handle + ? this.item.find(this.instance.options.handle) + : this.item, + 'ui-sortable-handle', + ); + }); + }, + + _destroy: function() { + this._mouseDestroy(); + + for (var i = this.items.length-1; i >= 0; i--) { + this.items[i].item.removeData(this.widgetName+'-item'); + } + + return this; + }, + + _mouseCapture: function(event, overrideHandle) { + var currentItem = null, + validHandle = false, + that = this; + + if (this.reverting) { + return false; + } + + if (this.options.disabled || this.options.type === 'static') { + return false; + } + + // We have to refresh the items data once first + this._refreshItems(event); + + // Find out if the clicked node (or one of its parents) is a actual item in this.items + $(event.target).parents().each(function() { + if ($.data(this, that.widgetName+'-item') === that) { + currentItem = $(this); + return false; + } + }); + if ($.data(event.target, that.widgetName+'-item') === that) { + currentItem = $(event.target); + } + + if (!currentItem) { + return false; + } + if (this.options.handle && !overrideHandle) { + $(this.options.handle, currentItem).find('*').addBack().each(function() { + if (this === event.target) { + validHandle = true; + } + }); + if (!validHandle) { + return false; + } + } + + this.currentItem = currentItem; + this._removeCurrentsFromItems(); + return true; + }, + + _mouseStart: function(event, overrideHandle, noActivation) { + var i, body, o = this.options; + + this.currentContainer = this; + + // We only need to call refreshPositions, because the refreshItems call has been moved to + // mouseCapture + this.refreshPositions(); + + // Prepare the dragged items parent + this.appendTo = $( + o.appendTo !== 'parent' + ? o.appendTo + : this.currentItem.parent(), + ); + + // Create and append the visible helper + this.helper = this._createHelper(event); + + // Cache the helper size + this._cacheHelperProportions(); + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + // Cache the margins of the original element + this._cacheMargins(); + + // The element's absolute position on the page minus margins + this.offset = this.currentItem.offset(); + this.offset = { + top: this.offset.top-this.margins.top, + left: this.offset.left-this.margins.left, + }; + + $.extend(this.offset, { + click: { // Where the click happened, relative to the element + left: event.pageX-this.offset.left, + top: event.pageY-this.offset.top, + }, + + // This is a relative to absolute position minus the actual position calculation - + // only used for relative positioned helper + relative: this._getRelativeOffset(), + }); + + // After we get the helper offset, but before we get the parent offset we can + // change the helper's position to absolute + // TODO: Still need to figure out a way to make relative sorting possible + this.helper.css('position', 'absolute'); + this.cssPosition = this.helper.css('position'); + + // Adjust the mouse offset relative to the helper if "cursorAt" is supplied + if (o.cursorAt) { + this._adjustOffsetFromHelper(o.cursorAt); + } + + // Cache the former DOM position + this.domPosition = { + prev: this.currentItem.prev()[0], + parent: this.currentItem.parent()[0], + }; + + // If the helper is not the original, hide the original so it's not playing any role during + // the drag, won't cause anything bad this way + if (this.helper[0] !== this.currentItem[0]) { + this.currentItem.hide(); + } + + // Create the placeholder + this._createPlaceholder(); + + // Get the next scrolling parent + this.scrollParent = this.placeholder.scrollParent(); + + $.extend(this.offset, { + parent: this._getParentOffset(), + }); + + // Set a containment if given in the options + if (o.containment) { + this._setContainment(); + } + + if (o.cursor && o.cursor !== 'auto') { // cursor option + body = this.document.find('body'); + + // Support: IE + this.storedCursor = body.css('cursor'); + body.css('cursor', o.cursor); + + this.storedStylesheet = $('') + .appendTo(body); + } + + // We need to make sure to grab the zIndex before setting the + // opacity, because setting the opacity to anything lower than 1 + // causes the zIndex to change from "auto" to 0. + if (o.zIndex) { // zIndex option + if (this.helper.css('zIndex')) { + this._storedZIndex = this.helper.css('zIndex'); + } + this.helper.css('zIndex', o.zIndex); + } + + if (o.opacity) { // opacity option + if (this.helper.css('opacity')) { + this._storedOpacity = this.helper.css('opacity'); + } + this.helper.css('opacity', o.opacity); + } + + // Prepare scrolling + if ( + this.scrollParent[0] !== this.document[0] + && this.scrollParent[0].tagName !== 'HTML' + ) { + this.overflowOffset = this.scrollParent.offset(); + } + + // Call callbacks + this._trigger('start', event, this._uiHash()); + + // Recache the helper size + if (!this._preserveHelperProportions) { + this._cacheHelperProportions(); + } + + // Post "activate" events to possible containers + if (!noActivation) { + for (i = this.containers.length-1; i >= 0; i--) { + this.containers[i]._trigger('activate', event, this._uiHash(this)); + } + } + + // Prepare possible droppables + if ($.ui.ddmanager) { + $.ui.ddmanager.current = this; + } + + if ($.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + + this.dragging = true; + + this._addClass(this.helper, 'ui-sortable-helper'); + + // Move the helper, if needed + if (!this.helper.parent().is(this.appendTo)) { + this.helper.detach().appendTo(this.appendTo); + + // Update position + this.offset.parent = this._getParentOffset(); + } + + // Generate the original position + this.position = this.originalPosition = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + this.lastPositionAbs = this.positionAbs = this._convertPositionTo('absolute'); + + this._mouseDrag(event); + + return true; + }, + + _scroll: function(event) { + var o = this.options, + scrolled = false; + + if ( + this.scrollParent[0] !== this.document[0] + && this.scrollParent[0].tagName !== 'HTML' + ) { + if ( + (this.overflowOffset.top+this.scrollParent[0].offsetHeight) + -event.pageY < o.scrollSensitivity + ) { + this.scrollParent[0].scrollTop = + scrolled = + this.scrollParent[0].scrollTop+o.scrollSpeed; + } else if (event.pageY-this.overflowOffset.top < o.scrollSensitivity) { + this.scrollParent[0].scrollTop = + scrolled = + this.scrollParent[0].scrollTop-o.scrollSpeed; + } + + if ( + (this.overflowOffset.left+this.scrollParent[0].offsetWidth) + -event.pageX < o.scrollSensitivity + ) { + this.scrollParent[0].scrollLeft = + scrolled = + this.scrollParent[0].scrollLeft+o.scrollSpeed; + } else if (event.pageX-this.overflowOffset.left < o.scrollSensitivity) { + this.scrollParent[0].scrollLeft = + scrolled = + this.scrollParent[0].scrollLeft-o.scrollSpeed; + } + } else { + if (event.pageY-this.document.scrollTop() < o.scrollSensitivity) { + scrolled = this.document.scrollTop(this.document.scrollTop()-o.scrollSpeed); + } else if ( + this.window.height()-(event.pageY-this.document.scrollTop()) + < o.scrollSensitivity + ) { + scrolled = this.document.scrollTop(this.document.scrollTop()+o.scrollSpeed); + } + + if (event.pageX-this.document.scrollLeft() < o.scrollSensitivity) { + scrolled = this.document.scrollLeft( + this.document.scrollLeft()-o.scrollSpeed, + ); + } else if ( + this.window.width()-(event.pageX-this.document.scrollLeft()) + < o.scrollSensitivity + ) { + scrolled = this.document.scrollLeft( + this.document.scrollLeft()+o.scrollSpeed, + ); + } + } + + return scrolled; + }, + + _mouseDrag: function(event) { + var i, item, itemElement, intersection, o = this.options; + + // Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo('absolute'); + + // Set the helper position + if (!this.options.axis || this.options.axis !== 'y') { + this.helper[0].style.left = this.position.left+'px'; + } + if (!this.options.axis || this.options.axis !== 'x') { + this.helper[0].style.top = this.position.top+'px'; + } + + // Do scrolling + if (o.scroll) { + if (this._scroll(event) !== false) { + // Update item positions used in position checks + this._refreshItemPositions(true); + + if ($.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + } + } + + this.dragDirection = { + vertical: this._getDragVerticalDirection(), + horizontal: this._getDragHorizontalDirection(), + }; + + // Rearrange + for (i = this.items.length-1; i >= 0; i--) { + // Cache variables and intersection, continue if no intersection + item = this.items[i]; + itemElement = item.item[0]; + intersection = this._intersectsWithPointer(item); + if (!intersection) { + continue; + } + + // Only put the placeholder inside the current Container, skip all + // items from other containers. This works because when moving + // an item from one container to another the + // currentContainer is switched before the placeholder is moved. + // + // Without this, moving items in "sub-sortables" can cause + // the placeholder to jitter between the outer and inner container. + if (item.instance !== this.currentContainer) { + continue; + } + + // Cannot intersect with itself + // no useless actions that have been done before + // no action if the item moved is the parent of the item checked + if ( + itemElement !== this.currentItem[0] + && this.placeholder[ + intersection === 1 + ? 'next' + : 'prev' + ]()[0] !== itemElement + && !$.contains(this.placeholder[0], itemElement) + && (this.options.type === 'semi-dynamic' + ? !$.contains(this.element[0], itemElement) + : true) + ) { + this.direction = intersection === 1 ? 'down' : 'up'; + + if ( + this.options.tolerance === 'pointer' + || this._intersectsWithSides(item) + ) { + this._rearrange(event, item); + } else { + break; + } + + this._trigger('change', event, this._uiHash()); + break; + } + } + + // Post events to containers + this._contactContainers(event); + + // Interconnect with droppables + if ($.ui.ddmanager) { + $.ui.ddmanager.drag(this, event); + } + + // Call callbacks + this._trigger('sort', event, this._uiHash()); + + this.lastPositionAbs = this.positionAbs; + return false; + }, + + _mouseStop: function(event, noPropagation) { + if (!event) { + return; + } + + // If we are using droppables, inform the manager about the drop + if ($.ui.ddmanager && !this.options.dropBehaviour) { + $.ui.ddmanager.drop(this, event); + } + + if (this.options.revert) { + var that = this, + cur = this.placeholder.offset(), + axis = this.options.axis, + animation = {}; + + if (!axis || axis === 'x') { + animation.left = cur.left-this.offset.parent.left-this.margins.left + +(this.offsetParent[0] === this.document[0].body + ? 0 + : this.offsetParent[0].scrollLeft); + } + if (!axis || axis === 'y') { + animation.top = cur.top-this.offset.parent.top-this.margins.top + +(this.offsetParent[0] === this.document[0].body + ? 0 + : this.offsetParent[0].scrollTop); + } + this.reverting = true; + $(this.helper).animate( + animation, + parseInt(this.options.revert, 10) || 500, + function() { + that._clear(event); + }, + ); + } else { + this._clear(event, noPropagation); + } + + return false; + }, + + cancel: function() { + if (this.dragging) { + this._mouseUp(new $.Event('mouseup', {target: null})); + + if (this.options.helper === 'original') { + this.currentItem.css(this._storedCSS); + this._removeClass(this.currentItem, 'ui-sortable-helper'); + } else { + this.currentItem.show(); + } + + // Post deactivating events to containers + for (var i = this.containers.length-1; i >= 0; i--) { + this.containers[i]._trigger('deactivate', null, this._uiHash(this)); + if (this.containers[i].containerCache.over) { + this.containers[i]._trigger('out', null, this._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + } + + if (this.placeholder) { + // $(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, + // it unbinds ALL events from the original node! + if (this.placeholder[0].parentNode) { + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + } + if ( + this.options.helper !== 'original' && this.helper + && this.helper[0].parentNode + ) { + this.helper.remove(); + } + + $.extend(this, { + helper: null, + dragging: false, + reverting: false, + _noFinalSort: null, + }); + + if (this.domPosition.prev) { + $(this.domPosition.prev).after(this.currentItem); + } else { + $(this.domPosition.parent).prepend(this.currentItem); + } + } + + return this; + }, + + serialize: function(o) { + var items = this._getItemsAsjQuery(o && o.connected), + str = []; + o = o || {}; + + $(items).each(function() { + var res = ($(o.item || this).attr(o.attribute || 'id') || '') + .match(o.expression || (/(.+)[\-=_](.+)/)); + if (res) { + str.push( + (o.key || res[1]+'[]') + +'='+(o.key && o.expression ? res[1] : res[2]), + ); + } + }); + + if (!str.length && o.key) { + str.push(o.key+'='); + } + + return str.join('&'); + }, + + toArray: function(o) { + var items = this._getItemsAsjQuery(o && o.connected), + ret = []; + + o = o || {}; + + items.each(function() { + ret.push($(o.item || this).attr(o.attribute || 'id') || ''); + }); + return ret; + }, + + /* Be careful with the following core functions */ + _intersectsWith: function(item) { + var x1 = this.positionAbs.left, + x2 = x1+this.helperProportions.width, + y1 = this.positionAbs.top, + y2 = y1+this.helperProportions.height, + l = item.left, + r = l+item.width, + t = item.top, + b = t+item.height, + dyClick = this.offset.click.top, + dxClick = this.offset.click.left, + isOverElementHeight = (this.options.axis === 'x') || ((y1+dyClick) > t + && (y1+dyClick) < b), + isOverElementWidth = (this.options.axis === 'y') || ((x1+dxClick) > l + && (x1+dxClick) < r), + isOverElement = isOverElementHeight && isOverElementWidth; + + if ( + this.options.tolerance === 'pointer' + || this.options.forcePointerForContainers + || (this.options.tolerance !== 'pointer' + && this.helperProportions[this.floating ? 'width' : 'height'] + > item[this.floating ? 'width' : 'height']) + ) { + return isOverElement; + } else { + return (l < x1+(this.helperProportions.width/2) // Right Half + && x2-(this.helperProportions.width/2) < r // Left Half + && t < y1+(this.helperProportions.height/2) // Bottom Half + && y2-(this.helperProportions.height/2) < b); // Top Half + } + }, + + _intersectsWithPointer: function(item) { + var verticalDirection, + horizontalDirection, + isOverElementHeight = (this.options.axis === 'x') + || this._isOverAxis( + this.positionAbs.top+this.offset.click.top, + item.top, + item.height, + ), + isOverElementWidth = (this.options.axis === 'y') + || this._isOverAxis( + this.positionAbs.left+this.offset.click.left, + item.left, + item.width, + ), + isOverElement = isOverElementHeight && isOverElementWidth; + + if (!isOverElement) { + return false; + } + + verticalDirection = this.dragDirection.vertical; + horizontalDirection = this.dragDirection.horizontal; + + return this.floating + ? ((horizontalDirection === 'right' || verticalDirection === 'down') ? 2 : 1) + : (verticalDirection && (verticalDirection === 'down' ? 2 : 1)); + }, + + _intersectsWithSides: function(item) { + var isOverBottomHalf = this._isOverAxis( + this.positionAbs.top + +this.offset.click.top, + item.top+(item.height/2), + item.height, + ), + isOverRightHalf = this._isOverAxis( + this.positionAbs.left + +this.offset.click.left, + item.left+(item.width/2), + item.width, + ), + verticalDirection = this.dragDirection.vertical, + horizontalDirection = this.dragDirection.horizontal; + + if (this.floating && horizontalDirection) { + return ((horizontalDirection === 'right' && isOverRightHalf) + || (horizontalDirection === 'left' && !isOverRightHalf)); + } else { + return verticalDirection && ((verticalDirection === 'down' && isOverBottomHalf) + || (verticalDirection === 'up' && !isOverBottomHalf)); + } + }, + + _getDragVerticalDirection: function() { + var delta = this.positionAbs.top-this.lastPositionAbs.top; + return delta !== 0 && (delta > 0 ? 'down' : 'up'); + }, + + _getDragHorizontalDirection: function() { + var delta = this.positionAbs.left-this.lastPositionAbs.left; + return delta !== 0 && (delta > 0 ? 'right' : 'left'); + }, + + refresh: function(event) { + this._refreshItems(event); + this._setHandleClassName(); + this.refreshPositions(); + return this; + }, + + _connectWith: function() { + var options = this.options; + return options.connectWith.constructor === String + ? [options.connectWith] + : options.connectWith; + }, + + _getItemsAsjQuery: function(connected) { + var i, j, cur, inst, items = [], queries = [], connectWith = this._connectWith(); + + if (connectWith && connected) { + for (i = connectWith.length-1; i >= 0; i--) { + cur = $(connectWith[i], this.document[0]); + for (j = cur.length-1; j >= 0; j--) { + inst = $.data(cur[j], this.widgetFullName); + if (inst && inst !== this && !inst.options.disabled) { + queries.push([ + typeof inst.options.items === 'function' + ? inst.options.items.call(inst.element) + : $(inst.options.items, inst.element) + .not('.ui-sortable-helper') + .not('.ui-sortable-placeholder'), + inst, + ]); + } + } + } + } + + queries.push([ + typeof this.options.items === 'function' + ? this.options.items + .call(this.element, null, {options: this.options, item: this.currentItem}) + : $(this.options.items, this.element) + .not('.ui-sortable-helper') + .not('.ui-sortable-placeholder'), + this, + ]); + + function addItems() { + items.push(this); + } + for (i = queries.length-1; i >= 0; i--) { + queries[i][0].each(addItems); + } + + return $(items); + }, + + _removeCurrentsFromItems: function() { + var list = this.currentItem.find(':data('+this.widgetName+'-item)'); + + this.items = $.grep(this.items, function(item) { + for (var j = 0; j < list.length; j++) { + if (list[j] === item.item[0]) { + return false; + } + } + return true; + }); + }, + + _refreshItems: function(event) { + this.items = []; + this.containers = [this]; + + var i, + j, + cur, + inst, + targetData, + _queries, + item, + queriesLength, + items = this.items, + queries = [[ + typeof this.options.items === 'function' + ? this.options.items.call(this.element[0], event, {item: this.currentItem}) + : $(this.options.items, this.element), + this, + ]], + connectWith = this._connectWith(); + + // Shouldn't be run the first time through due to massive slow-down + if (connectWith && this.ready) { + for (i = connectWith.length-1; i >= 0; i--) { + cur = $(connectWith[i], this.document[0]); + for (j = cur.length-1; j >= 0; j--) { + inst = $.data(cur[j], this.widgetFullName); + if (inst && inst !== this && !inst.options.disabled) { + queries.push([ + typeof inst.options.items === 'function' + ? inst.options.items + .call(inst.element[0], event, {item: this.currentItem}) + : $(inst.options.items, inst.element), + inst, + ]); + this.containers.push(inst); + } + } + } + } + + for (i = queries.length-1; i >= 0; i--) { + targetData = queries[i][1]; + _queries = queries[i][0]; + + for (j = 0, queriesLength = _queries.length; j < queriesLength; j++) { + item = $(_queries[j]); + + // Data for target checking (mouse manager) + item.data(this.widgetName+'-item', targetData); + + items.push({ + item: item, + instance: targetData, + width: 0, + height: 0, + left: 0, + top: 0, + }); + } + } + }, + + _refreshItemPositions: function(fast) { + var i, item, t, p; + + for (i = this.items.length-1; i >= 0; i--) { + item = this.items[i]; + + // We ignore calculating positions of all connected containers when we're not over them + if ( + this.currentContainer && item.instance !== this.currentContainer + && item.item[0] !== this.currentItem[0] + ) { + continue; + } + + t = this.options.toleranceElement + ? $(this.options.toleranceElement, item.item) + : item.item; + + if (!fast) { + item.width = t.outerWidth(); + item.height = t.outerHeight(); + } + + p = t.offset(); + item.left = p.left; + item.top = p.top; + } + }, + + refreshPositions: function(fast) { + // Determine whether items are being displayed horizontally + this.floating = this.items.length + ? this.options.axis === 'x' || this._isFloating(this.items[0].item) + : false; + + // This has to be redone because due to the item being moved out/into the offsetParent, + // the offsetParent's position will change + if (this.offsetParent && this.helper) { + this.offset.parent = this._getParentOffset(); + } + + this._refreshItemPositions(fast); + + var i, p; + + if (this.options.custom && this.options.custom.refreshContainers) { + this.options.custom.refreshContainers.call(this); + } else { + for (i = this.containers.length-1; i >= 0; i--) { + p = this.containers[i].element.offset(); + this.containers[i].containerCache.left = p.left; + this.containers[i].containerCache.top = p.top; + this.containers[i].containerCache.width = this.containers[i].element + .outerWidth(); + this.containers[i].containerCache.height = this.containers[i].element + .outerHeight(); + } + } + + return this; + }, + + _createPlaceholder: function(that) { + that = that || this; + var className, nodeName, o = that.options; + + if (!o.placeholder || o.placeholder.constructor === String) { + className = o.placeholder; + nodeName = that.currentItem[0].nodeName.toLowerCase(); + o.placeholder = { + element: function() { + var element = $('<'+nodeName+'>', that.document[0]); + + that._addClass( + element, + 'ui-sortable-placeholder', + className || that.currentItem[0].className, + ) + ._removeClass(element, 'ui-sortable-helper'); + + if (nodeName === 'tbody') { + that._createTrPlaceholder( + that.currentItem.find('tr').eq(0), + $('', that.document[0]).appendTo(element), + ); + } else if (nodeName === 'tr') { + that._createTrPlaceholder(that.currentItem, element); + } else if (nodeName === 'img') { + element.attr('src', that.currentItem.attr('src')); + } + + if (!className) { + element.css('visibility', 'hidden'); + } + + return element; + }, + update: function(container, p) { + // 1. If a className is set as 'placeholder option, we don't force sizes - + // the class is responsible for that + // 2. The option 'forcePlaceholderSize can be enabled to force it even if a + // class name is specified + if (className && !o.forcePlaceholderSize) { + return; + } + + // If the element doesn't have a actual height or width by itself (without + // styles coming from a stylesheet), it receives the inline height and width + // from the dragged item. Or, if it's a tbody or tr, it's going to have a height + // anyway since we're populating them with s above, but they're unlikely to + // be the correct height on their own if the row heights are dynamic, so we'll + // always assign the height of the dragged item given forcePlaceholderSize + // is true. + if ( + !p.height() || (o.forcePlaceholderSize + && (nodeName === 'tbody' || nodeName === 'tr')) + ) { + p.height( + that.currentItem.innerHeight() + -parseInt(that.currentItem.css('paddingTop') || 0, 10) + -parseInt(that.currentItem.css('paddingBottom') || 0, 10), + ); + } + if (!p.width()) { + p.width( + that.currentItem.innerWidth() + -parseInt(that.currentItem.css('paddingLeft') || 0, 10) + -parseInt(that.currentItem.css('paddingRight') || 0, 10), + ); + } + }, + }; + } + + // Create the placeholder + that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); + + // Append it after the actual current item + that.currentItem.after(that.placeholder); + + // Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) + o.placeholder.update(that, that.placeholder); + }, + + _createTrPlaceholder: function(sourceTr, targetTr) { + var that = this; + + sourceTr.children().each(function() { + $(' ', that.document[0]) + .attr('colspan', $(this).attr('colspan') || 1) + .appendTo(targetTr); + }); + }, + + _contactContainers: function(event) { + var i, + j, + dist, + itemWithLeastDistance, + posProperty, + sizeProperty, + cur, + nearBottom, + floating, + axis, + innermostContainer = null, + innermostIndex = null; + + // Get innermost container that intersects with item + for (i = this.containers.length-1; i >= 0; i--) { + // Never consider a container that's located within the item itself + if ($.contains(this.currentItem[0], this.containers[i].element[0])) { + continue; + } + + if (this._intersectsWith(this.containers[i].containerCache)) { + // If we've already found a container and it's more "inner" than this, then continue + if ( + innermostContainer + && $.contains( + this.containers[i].element[0], + innermostContainer.element[0], + ) + ) { + continue; + } + + innermostContainer = this.containers[i]; + innermostIndex = i; + } else { + // container doesn't intersect. trigger "out" event if necessary + if (this.containers[i].containerCache.over) { + this.containers[i]._trigger('out', event, this._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + } + + // If no intersecting containers found, return + if (!innermostContainer) { + return; + } + + // Move the item into the container if it's not there already + if (this.containers.length === 1) { + if (!this.containers[innermostIndex].containerCache.over) { + this.containers[innermostIndex]._trigger('over', event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; + } + } else { + // When entering a new container, we will find the item with the least distance and + // append our item near it + dist = 10000; + itemWithLeastDistance = null; + floating = innermostContainer.floating || this._isFloating(this.currentItem); + posProperty = floating ? 'left' : 'top'; + sizeProperty = floating ? 'width' : 'height'; + axis = floating ? 'pageX' : 'pageY'; + + for (j = this.items.length-1; j >= 0; j--) { + if ( + !$.contains( + this.containers[innermostIndex].element[0], + this.items[j].item[0], + ) + ) { + continue; + } + if (this.items[j].item[0] === this.currentItem[0]) { + continue; + } + + cur = this.items[j].item.offset()[posProperty]; + nearBottom = false; + if (event[axis]-cur > this.items[j][sizeProperty]/2) { + nearBottom = true; + } + + if (Math.abs(event[axis]-cur) < dist) { + dist = Math.abs(event[axis]-cur); + itemWithLeastDistance = this.items[j]; + this.direction = nearBottom ? 'up' : 'down'; + } + } + + // Check if dropOnEmpty is enabled + if (!itemWithLeastDistance && !this.options.dropOnEmpty) { + return; + } + + if (this.currentContainer === this.containers[innermostIndex]) { + if (!this.currentContainer.containerCache.over) { + this.containers[innermostIndex]._trigger('over', event, this._uiHash()); + this.currentContainer.containerCache.over = 1; + } + return; + } + + if (itemWithLeastDistance) { + this._rearrange(event, itemWithLeastDistance, null, true); + } else { + this._rearrange(event, null, this.containers[innermostIndex].element, true); + } + this._trigger('change', event, this._uiHash()); + this.containers[innermostIndex]._trigger('change', event, this._uiHash(this)); + this.currentContainer = this.containers[innermostIndex]; + + // Update the placeholder + this.options.placeholder.update(this.currentContainer, this.placeholder); + + // Update scrollParent + this.scrollParent = this.placeholder.scrollParent(); + + // Update overflowOffset + if ( + this.scrollParent[0] !== this.document[0] + && this.scrollParent[0].tagName !== 'HTML' + ) { + this.overflowOffset = this.scrollParent.offset(); + } + + this.containers[innermostIndex]._trigger('over', event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; + } + }, + + _createHelper: function(event) { + var o = this.options, + helper = typeof o.helper === 'function' + ? $(o.helper.apply(this.element[0], [event, this.currentItem])) + : (o.helper === 'clone' ? this.currentItem.clone() : this.currentItem); + + // Add the helper to the DOM if that didn't happen already + if (!helper.parents('body').length) { + this.appendTo[0].appendChild(helper[0]); + } + + if (helper[0] === this.currentItem[0]) { + this._storedCSS = { + width: this.currentItem[0].style.width, + height: this.currentItem[0].style.height, + position: this.currentItem.css('position'), + top: this.currentItem.css('top'), + left: this.currentItem.css('left'), + }; + } + + if (!helper[0].style.width || o.forceHelperSize) { + helper.width(this.currentItem.width()); + } + if (!helper[0].style.height || o.forceHelperSize) { + helper.height(this.currentItem.height()); + } + + return helper; + }, + + _adjustOffsetFromHelper: function(obj) { + if (typeof obj === 'string') { + obj = obj.split(' '); + } + if (Array.isArray(obj)) { + obj = {left: +obj[0], top: +obj[1] || 0}; + } + if ('left' in obj) { + this.offset.click.left = obj.left+this.margins.left; + } + if ('right' in obj) { + this.offset.click.left = this.helperProportions.width-obj.right+this.margins.left; + } + if ('top' in obj) { + this.offset.click.top = obj.top+this.margins.top; + } + if ('bottom' in obj) { + this.offset.click.top = this.helperProportions.height-obj.bottom+this.margins.top; + } + }, + + _getParentOffset: function() { + // Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the + // following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the + // next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't + // the document, which means that the scroll is included in the initial calculation of the + // offset of the parent, and never recalculated upon drag + if ( + this.cssPosition === 'absolute' && this.scrollParent[0] !== this.document[0] + && $.contains(this.scrollParent[0], this.offsetParent[0]) + ) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + // This needs to be actually done for all browsers, since pageX/pageY includes this + // information with an ugly IE fix + if ( + this.offsetParent[0] === this.document[0].body + || (this.offsetParent[0].tagName + && this.offsetParent[0].tagName.toLowerCase() === 'html' && $.ui.ie) + ) { + po = {top: 0, left: 0}; + } + + return { + top: po.top+(parseInt(this.offsetParent.css('borderTopWidth'), 10) || 0), + left: po.left+(parseInt(this.offsetParent.css('borderLeftWidth'), 10) || 0), + }; + }, + + _getRelativeOffset: function() { + if (this.cssPosition === 'relative') { + var p = this.currentItem.position(); + return { + top: p.top-(parseInt(this.helper.css('top'), 10) || 0) + +this.scrollParent.scrollTop(), + left: p.left-(parseInt(this.helper.css('left'), 10) || 0) + +this.scrollParent.scrollLeft(), + }; + } else { + return {top: 0, left: 0}; + } + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.currentItem.css('marginLeft'), 10) || 0), + top: (parseInt(this.currentItem.css('marginTop'), 10) || 0), + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight(), + }; + }, + + _setContainment: function() { + var ce, co, over, o = this.options; + if (o.containment === 'parent') { + o.containment = this.helper[0].parentNode; + } + if (o.containment === 'document' || o.containment === 'window') { + this.containment = [ + 0-this.offset.relative.left-this.offset.parent.left, + 0-this.offset.relative.top-this.offset.parent.top, + o.containment === 'document' + ? this.document.width() + : this.window.width()-this.helperProportions.width-this.margins.left, + (o.containment === 'document' + ? (this.document.height() || document.body.parentNode.scrollHeight) + : this.window.height() + || this.document[0].body.parentNode.scrollHeight) + -this.helperProportions + .height + -this.margins.top, + ]; + } + + if (!(/^(document|window|parent)$/).test(o.containment)) { + ce = $(o.containment)[0]; + co = $(o.containment).offset(); + over = $(ce).css('overflow') !== 'hidden'; + + this.containment = [ + co.left+(parseInt($(ce).css('borderLeftWidth'), 10) || 0) + +(parseInt($(ce).css('paddingLeft'), 10) || 0)-this.margins.left, + co.top+(parseInt($(ce).css('borderTopWidth'), 10) || 0) + +(parseInt($(ce).css('paddingTop'), 10) || 0)-this.margins.top, + co.left+(over ? Math.max(ce.scrollWidth, ce.offsetWidth) : ce.offsetWidth) + -(parseInt($(ce).css('borderLeftWidth'), 10) || 0) + -(parseInt($(ce).css('paddingRight'), 10) || 0) + -this.helperProportions.width-this.margins.left, + co.top+(over ? Math.max(ce.scrollHeight, ce.offsetHeight) : ce.offsetHeight) + -(parseInt($(ce).css('borderTopWidth'), 10) || 0) + -(parseInt($(ce).css('paddingBottom'), 10) || 0) + -this.helperProportions.height-this.margins.top, + ]; + } + }, + + _convertPositionTo: function(d, pos) { + if (!pos) { + pos = this.position; + } + var mod = d === 'absolute' ? 1 : -1, + scroll = this.cssPosition === 'absolute' + && !(this.scrollParent[0] !== this.document[0] + && $.contains(this.scrollParent[0], this.offsetParent[0])) + ? this.offsetParent + : this.scrollParent, + scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + return { + top: ( + // The absolute mouse position + pos.top + // Only for relative positioned nodes: Relative offset from element to offset parent + +this.offset.relative.top*mod + // The offsetParent's offset without borders (offset + border) + +this.offset.parent.top*mod + -((this.cssPosition === 'fixed' + ? -this.scrollParent.scrollTop() + : (scrollIsRootNode ? 0 : scroll.scrollTop()))*mod) + ), + left: ( + // The absolute mouse position + pos.left + // Only for relative positioned nodes: Relative offset from element to offset parent + +this.offset.relative.left*mod + // The offsetParent's offset without borders (offset + border) + +this.offset.parent.left*mod + -((this.cssPosition === 'fixed' + ? -this.scrollParent.scrollLeft() + : scrollIsRootNode + ? 0 + : scroll.scrollLeft())*mod) + ), + }; + }, + + _generatePosition: function(event) { + var top, + left, + o = this.options, + pageX = event.pageX, + pageY = event.pageY, + scroll = this.cssPosition === 'absolute' + && !(this.scrollParent[0] !== this.document[0] + && $.contains(this.scrollParent[0], this.offsetParent[0])) + ? this.offsetParent + : this.scrollParent, + scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + // This is another very weird special case that only happens for relative elements: + // 1. If the css position is relative + // 2. and the scroll parent is the document or similar to the offset parent + // we have to refresh the relative offset during the scroll so there are no jumps + if ( + this.cssPosition === 'relative' && !(this.scrollParent[0] !== this.document[0] + && this.scrollParent[0] !== this.offsetParent[0]) + ) { + this.offset.relative = this._getRelativeOffset(); + } + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + if (this.originalPosition) { // If we are not dragging yet, we won't check for options + if (this.containment) { + if (event.pageX-this.offset.click.left < this.containment[0]) { + pageX = this.containment[0]+this.offset.click.left; + } + if (event.pageY-this.offset.click.top < this.containment[1]) { + pageY = this.containment[1]+this.offset.click.top; + } + if (event.pageX-this.offset.click.left > this.containment[2]) { + pageX = this.containment[2]+this.offset.click.left; + } + if (event.pageY-this.offset.click.top > this.containment[3]) { + pageY = this.containment[3]+this.offset.click.top; + } + } + + if (o.grid) { + top = this.originalPageY+Math.round( + (pageY-this.originalPageY) + /o.grid[1], + )*o.grid[1]; + pageY = this.containment + ? ((top-this.offset.click.top >= this.containment[1] + && top-this.offset.click.top <= this.containment[3]) + ? top + : ((top-this.offset.click.top >= this.containment[1]) + ? top-o.grid[1] + : top+o.grid[1])) + : top; + + left = this.originalPageX+Math.round( + (pageX-this.originalPageX) + /o.grid[0], + )*o.grid[0]; + pageX = this.containment + ? ((left-this.offset.click.left >= this.containment[0] + && left-this.offset.click.left <= this.containment[2]) + ? left + : ((left-this.offset.click.left >= this.containment[0]) + ? left-o.grid[0] + : left+o.grid[0])) + : left; + } + } + + return { + top: ( + // The absolute mouse position + pageY + // Click offset (relative to the element) + -this.offset.click.top + // Only for relative positioned nodes: Relative offset from element to offset parent + -this.offset.relative.top + // The offsetParent's offset without borders (offset + border) + -this.offset.parent.top + +(this.cssPosition === 'fixed' + ? -this.scrollParent.scrollTop() + : (scrollIsRootNode ? 0 : scroll.scrollTop())) + ), + left: ( + // The absolute mouse position + pageX + // Click offset (relative to the element) + -this.offset.click.left + // Only for relative positioned nodes: Relative offset from element to offset parent + -this.offset.relative.left + // The offsetParent's offset without borders (offset + border) + -this.offset.parent.left + +(this.cssPosition === 'fixed' + ? -this.scrollParent.scrollLeft() + : scrollIsRootNode + ? 0 + : scroll.scrollLeft()) + ), + }; + }, + + _rearrange: function(event, i, a, hardRefresh) { + if (a) { + a[0].appendChild(this.placeholder[0]); + } else { + i.item[0].parentNode.insertBefore( + this.placeholder[0], + this.direction === 'down' ? i.item[0] : i.item[0].nextSibling, + ); + } + + // Various things done here to improve the performance: + // 1. we create a setTimeout, that calls refreshPositions + // 2. on the instance, we have a counter variable, that get's higher after every append + // 3. on the local scope, we copy the counter variable, and check in the timeout, + // if it's still the same + // 4. this lets only the last addition to the timeout stack through + this.counter = this.counter ? ++this.counter : 1; + var counter = this.counter; + + this._delay(function() { + if (counter === this.counter) { + // Precompute after each DOM insertion, NOT on mousemove + this.refreshPositions(!hardRefresh); + } + }); + }, + + _clear: function(event, noPropagation) { + this.reverting = false; + + // We delay all events that have to be triggered to after the point where the placeholder + // has been removed and everything else normalized again + var i, + delayedTriggers = []; + + // We first have to update the dom position of the actual currentItem + // Note: don't do it if the current item is already removed (by a user), or it gets + // reappended (see #4088) + if (!this._noFinalSort && this.currentItem.parent().length) { + this.placeholder.before(this.currentItem); + } + this._noFinalSort = null; + + if (this.helper[0] === this.currentItem[0]) { + for (i in this._storedCSS) { + if (this._storedCSS[i] === 'auto' || this._storedCSS[i] === 'static') { + this._storedCSS[i] = ''; + } + } + this.currentItem.css(this._storedCSS); + this._removeClass(this.currentItem, 'ui-sortable-helper'); + } else { + this.currentItem.show(); + } + + if (this.fromOutside && !noPropagation) { + delayedTriggers.push(function(event) { + this._trigger('receive', event, this._uiHash(this.fromOutside)); + }); + } + if ( + (this.fromOutside + || this.domPosition.prev + !== this.currentItem.prev().not('.ui-sortable-helper')[0] + || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation + ) { + // Trigger update callback if the DOM position has changed + delayedTriggers.push(function(event) { + this._trigger('update', event, this._uiHash()); + }); + } + + // Check if the items Container has Changed and trigger appropriate + // events. + if (this !== this.currentContainer) { + if (!noPropagation) { + delayedTriggers.push(function(event) { + this._trigger('remove', event, this._uiHash()); + }); + delayedTriggers.push((function(c) { + return function(event) { + c._trigger('receive', event, this._uiHash(this)); + }; + }).call(this, this.currentContainer)); + delayedTriggers.push((function(c) { + return function(event) { + c._trigger('update', event, this._uiHash(this)); + }; + }).call(this, this.currentContainer)); + } + } + + // Post events to containers + function delayEvent(type, instance, container) { + return function(event) { + container._trigger(type, event, instance._uiHash(instance)); + }; + } + for (i = this.containers.length-1; i >= 0; i--) { + if (!noPropagation) { + delayedTriggers.push(delayEvent('deactivate', this, this.containers[i])); + } + if (this.containers[i].containerCache.over) { + delayedTriggers.push(delayEvent('out', this, this.containers[i])); + this.containers[i].containerCache.over = 0; + } + } + + // Do what was originally in plugins + if (this.storedCursor) { + this.document.find('body').css('cursor', this.storedCursor); + this.storedStylesheet.remove(); + } + if (this._storedOpacity) { + this.helper.css('opacity', this._storedOpacity); + } + if (this._storedZIndex) { + this.helper.css('zIndex', this._storedZIndex === 'auto' ? '' : this._storedZIndex); + } + + this.dragging = false; + + if (!noPropagation) { + this._trigger('beforeStop', event, this._uiHash()); + } + + // $(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, + // it unbinds ALL events from the original node! + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + + if (!this.cancelHelperRemoval) { + if (this.helper[0] !== this.currentItem[0]) { + this.helper.remove(); + } + this.helper = null; + } + + if (!noPropagation) { + for (i = 0; i < delayedTriggers.length; i++) { + // Trigger all delayed events + delayedTriggers[i].call(this, event); + } + this._trigger('stop', event, this._uiHash()); + } + + this.fromOutside = false; + return !this.cancelHelperRemoval; + }, + + _trigger: function() { + if ($.Widget.prototype._trigger.apply(this, arguments) === false) { + this.cancel(); + } + }, + + _uiHash: function(_inst) { + var inst = _inst || this; + return { + helper: inst.helper, + placeholder: inst.placeholder || $([]), + position: inst.position, + originalPosition: inst.originalPosition, + offset: inst.positionAbs, + item: inst.currentItem, + sender: _inst ? _inst.element : null, + }; + }, + }); + + /*! * jQuery UI Spinner 1.13.3 * https://jqueryui.com * @@ -17103,559 +17483,566 @@ var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, { * https://jquery.org/license */ -//>>label: Spinner -//>>group: Widgets -//>>description: Displays buttons to easily input numbers via the keyboard or mouse. -//>>docs: https://api.jqueryui.com/spinner/ -//>>demos: https://jqueryui.com/spinner/ -//>>css.structure: ../../themes/base/core.css -//>>css.structure: ../../themes/base/spinner.css -//>>css.theme: ../../themes/base/theme.css - - -function spinnerModifier( fn ) { - return function() { - var previous = this.element.val(); - fn.apply( this, arguments ); - this._refresh(); - if ( previous !== this.element.val() ) { - this._trigger( "change" ); - } - }; -} - -$.widget( "ui.spinner", { - version: "1.13.3", - defaultElement: "", - widgetEventPrefix: "spin", - options: { - classes: { - "ui-spinner": "ui-corner-all", - "ui-spinner-down": "ui-corner-br", - "ui-spinner-up": "ui-corner-tr" - }, - culture: null, - icons: { - down: "ui-icon-triangle-1-s", - up: "ui-icon-triangle-1-n" - }, - incremental: true, - max: null, - min: null, - numberFormat: null, - page: 10, - step: 1, - - change: null, - spin: null, - start: null, - stop: null - }, - - _create: function() { - - // handle string values that need to be parsed - this._setOption( "max", this.options.max ); - this._setOption( "min", this.options.min ); - this._setOption( "step", this.options.step ); - - // Only format if there is a value, prevents the field from being marked - // as invalid in Firefox, see #9573. - if ( this.value() !== "" ) { - - // Format the value, but don't constrain. - this._value( this.element.val(), true ); - } - - this._draw(); - this._on( this._events ); - this._refresh(); - - // Turning off autocomplete prevents the browser from remembering the - // value when navigating through history, so we re-enable autocomplete - // if the page is unloaded before the widget is destroyed. #7790 - this._on( this.window, { - beforeunload: function() { - this.element.removeAttr( "autocomplete" ); - } - } ); - }, - - _getCreateOptions: function() { - var options = this._super(); - var element = this.element; - - $.each( [ "min", "max", "step" ], function( i, option ) { - var value = element.attr( option ); - if ( value != null && value.length ) { - options[ option ] = value; - } - } ); - - return options; - }, - - _events: { - keydown: function( event ) { - if ( this._start( event ) && this._keydown( event ) ) { - event.preventDefault(); - } - }, - keyup: "_stop", - focus: function() { - this.previous = this.element.val(); - }, - blur: function( event ) { - if ( this.cancelBlur ) { - delete this.cancelBlur; - return; - } - - this._stop(); - this._refresh(); - if ( this.previous !== this.element.val() ) { - this._trigger( "change", event ); - } - }, - mousewheel: function( event, delta ) { - var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ); - var isActive = this.element[ 0 ] === activeElement; - - if ( !isActive || !delta ) { - return; - } - - if ( !this.spinning && !this._start( event ) ) { - return false; - } - - this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event ); - clearTimeout( this.mousewheelTimer ); - this.mousewheelTimer = this._delay( function() { - if ( this.spinning ) { - this._stop( event ); - } - }, 100 ); - event.preventDefault(); - }, - "mousedown .ui-spinner-button": function( event ) { - var previous; - - // We never want the buttons to have focus; whenever the user is - // interacting with the spinner, the focus should be on the input. - // If the input is focused then this.previous is properly set from - // when the input first received focus. If the input is not focused - // then we need to set this.previous based on the value before spinning. - previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ? - this.previous : this.element.val(); - function checkFocus() { - var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ); - if ( !isActive ) { - this.element.trigger( "focus" ); - this.previous = previous; - - // support: IE - // IE sets focus asynchronously, so we need to check if focus - // moved off of the input because the user clicked on the button. - this._delay( function() { - this.previous = previous; - } ); - } - } - - // Ensure focus is on (or stays on) the text field - event.preventDefault(); - checkFocus.call( this ); - - // Support: IE - // IE doesn't prevent moving focus even with event.preventDefault() - // so we set a flag to know when we should ignore the blur event - // and check (again) if focus moved off of the input. - this.cancelBlur = true; - this._delay( function() { - delete this.cancelBlur; - checkFocus.call( this ); - } ); - - if ( this._start( event ) === false ) { - return; - } - - this._repeat( null, $( event.currentTarget ) - .hasClass( "ui-spinner-up" ) ? 1 : -1, event ); - }, - "mouseup .ui-spinner-button": "_stop", - "mouseenter .ui-spinner-button": function( event ) { - - // button will add ui-state-active if mouse was down while mouseleave and kept down - if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { - return; - } - - if ( this._start( event ) === false ) { - return false; - } - this._repeat( null, $( event.currentTarget ) - .hasClass( "ui-spinner-up" ) ? 1 : -1, event ); - }, - - // TODO: do we really want to consider this a stop? - // shouldn't we just stop the repeater and wait until mouseup before - // we trigger the stop event? - "mouseleave .ui-spinner-button": "_stop" - }, - - // Support mobile enhanced option and make backcompat more sane - _enhance: function() { - this.uiSpinner = this.element - .attr( "autocomplete", "off" ) - .wrap( "" ) - .parent() - - // Add buttons - .append( - "" - ); - }, - - _draw: function() { - this._enhance(); - - this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" ); - this._addClass( "ui-spinner-input" ); - - this.element.attr( "role", "spinbutton" ); - - // Button bindings - this.buttons = this.uiSpinner.children( "a" ) - .attr( "tabIndex", -1 ) - .attr( "aria-hidden", true ) - .button( { - classes: { - "ui-button": "" - } - } ); - - // TODO: Right now button does not support classes this is already updated in button PR - this._removeClass( this.buttons, "ui-corner-all" ); - - this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" ); - this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" ); - this.buttons.first().button( { - "icon": this.options.icons.up, - "showLabel": false - } ); - this.buttons.last().button( { - "icon": this.options.icons.down, - "showLabel": false - } ); - - // IE 6 doesn't understand height: 50% for the buttons - // unless the wrapper has an explicit height - if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) && - this.uiSpinner.height() > 0 ) { - this.uiSpinner.height( this.uiSpinner.height() ); - } - }, - - _keydown: function( event ) { - var options = this.options, - keyCode = $.ui.keyCode; - - switch ( event.keyCode ) { - case keyCode.UP: - this._repeat( null, 1, event ); - return true; - case keyCode.DOWN: - this._repeat( null, -1, event ); - return true; - case keyCode.PAGE_UP: - this._repeat( null, options.page, event ); - return true; - case keyCode.PAGE_DOWN: - this._repeat( null, -options.page, event ); - return true; - } - - return false; - }, - - _start: function( event ) { - if ( !this.spinning && this._trigger( "start", event ) === false ) { - return false; - } - - if ( !this.counter ) { - this.counter = 1; - } - this.spinning = true; - return true; - }, - - _repeat: function( i, steps, event ) { - i = i || 500; - - clearTimeout( this.timer ); - this.timer = this._delay( function() { - this._repeat( 40, steps, event ); - }, i ); - - this._spin( steps * this.options.step, event ); - }, - - _spin: function( step, event ) { - var value = this.value() || 0; - - if ( !this.counter ) { - this.counter = 1; - } - - value = this._adjustValue( value + step * this._increment( this.counter ) ); - - if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) { - this._value( value ); - this.counter++; - } - }, - - _increment: function( i ) { - var incremental = this.options.incremental; - - if ( incremental ) { - return typeof incremental === "function" ? - incremental( i ) : - Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 ); - } - - return 1; - }, - - _precision: function() { - var precision = this._precisionOf( this.options.step ); - if ( this.options.min !== null ) { - precision = Math.max( precision, this._precisionOf( this.options.min ) ); - } - return precision; - }, - - _precisionOf: function( num ) { - var str = num.toString(), - decimal = str.indexOf( "." ); - return decimal === -1 ? 0 : str.length - decimal - 1; - }, - - _adjustValue: function( value ) { - var base, aboveMin, - options = this.options; - - // Make sure we're at a valid step - // - find out where we are relative to the base (min or 0) - base = options.min !== null ? options.min : 0; - aboveMin = value - base; - - // - round to the nearest step - aboveMin = Math.round( aboveMin / options.step ) * options.step; - - // - rounding is based on 0, so adjust back to our base - value = base + aboveMin; - - // Fix precision from bad JS floating point math - value = parseFloat( value.toFixed( this._precision() ) ); - - // Clamp the value - if ( options.max !== null && value > options.max ) { - return options.max; - } - if ( options.min !== null && value < options.min ) { - return options.min; - } - - return value; - }, - - _stop: function( event ) { - if ( !this.spinning ) { - return; - } - - clearTimeout( this.timer ); - clearTimeout( this.mousewheelTimer ); - this.counter = 0; - this.spinning = false; - this._trigger( "stop", event ); - }, - - _setOption: function( key, value ) { - var prevValue, first, last; - - if ( key === "culture" || key === "numberFormat" ) { - prevValue = this._parse( this.element.val() ); - this.options[ key ] = value; - this.element.val( this._format( prevValue ) ); - return; - } - - if ( key === "max" || key === "min" || key === "step" ) { - if ( typeof value === "string" ) { - value = this._parse( value ); - } - } - if ( key === "icons" ) { - first = this.buttons.first().find( ".ui-icon" ); - this._removeClass( first, null, this.options.icons.up ); - this._addClass( first, null, value.up ); - last = this.buttons.last().find( ".ui-icon" ); - this._removeClass( last, null, this.options.icons.down ); - this._addClass( last, null, value.down ); - } - - this._super( key, value ); - }, - - _setOptionDisabled: function( value ) { - this._super( value ); - - this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value ); - this.element.prop( "disabled", !!value ); - this.buttons.button( value ? "disable" : "enable" ); - }, - - _setOptions: spinnerModifier( function( options ) { - this._super( options ); - } ), - - _parse: function( val ) { - if ( typeof val === "string" && val !== "" ) { - val = window.Globalize && this.options.numberFormat ? - Globalize.parseFloat( val, 10, this.options.culture ) : +val; - } - return val === "" || isNaN( val ) ? null : val; - }, - - _format: function( value ) { - if ( value === "" ) { - return ""; - } - return window.Globalize && this.options.numberFormat ? - Globalize.format( value, this.options.numberFormat, this.options.culture ) : - value; - }, - - _refresh: function() { - this.element.attr( { - "aria-valuemin": this.options.min, - "aria-valuemax": this.options.max, - - // TODO: what should we do with values that can't be parsed? - "aria-valuenow": this._parse( this.element.val() ) - } ); - }, - - isValid: function() { - var value = this.value(); - - // Null is invalid - if ( value === null ) { - return false; - } - - // If value gets adjusted, it's invalid - return value === this._adjustValue( value ); - }, - - // Update the value without triggering change - _value: function( value, allowAny ) { - var parsed; - if ( value !== "" ) { - parsed = this._parse( value ); - if ( parsed !== null ) { - if ( !allowAny ) { - parsed = this._adjustValue( parsed ); - } - value = this._format( parsed ); - } - } - this.element.val( value ); - this._refresh(); - }, - - _destroy: function() { - this.element - .prop( "disabled", false ) - .removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" ); - - this.uiSpinner.replaceWith( this.element ); - }, - - stepUp: spinnerModifier( function( steps ) { - this._stepUp( steps ); - } ), - _stepUp: function( steps ) { - if ( this._start() ) { - this._spin( ( steps || 1 ) * this.options.step ); - this._stop(); - } - }, - - stepDown: spinnerModifier( function( steps ) { - this._stepDown( steps ); - } ), - _stepDown: function( steps ) { - if ( this._start() ) { - this._spin( ( steps || 1 ) * -this.options.step ); - this._stop(); - } - }, - - pageUp: spinnerModifier( function( pages ) { - this._stepUp( ( pages || 1 ) * this.options.page ); - } ), - - pageDown: spinnerModifier( function( pages ) { - this._stepDown( ( pages || 1 ) * this.options.page ); - } ), - - value: function( newVal ) { - if ( !arguments.length ) { - return this._parse( this.element.val() ); - } - spinnerModifier( this._value ).call( this, newVal ); - }, - - widget: function() { - return this.uiSpinner; - } -} ); - -// DEPRECATED -// TODO: switch return back to widget declaration at top of file when this is removed -if ( $.uiBackCompat !== false ) { - - // Backcompat for spinner html extension points - $.widget( "ui.spinner", $.ui.spinner, { - _enhance: function() { - this.uiSpinner = this.element - .attr( "autocomplete", "off" ) - .wrap( this._uiSpinnerHtml() ) - .parent() - - // Add buttons - .append( this._buttonHtml() ); - }, - _uiSpinnerHtml: function() { - return ""; - }, - - _buttonHtml: function() { - return ""; - } - } ); -} - -var widgetsSpinner = $.ui.spinner; - - -/*! + // >>label: Spinner + // >>group: Widgets + // >>description: Displays buttons to easily input numbers via the keyboard or mouse. + // >>docs: https://api.jqueryui.com/spinner/ + // >>demos: https://jqueryui.com/spinner/ + // >>css.structure: ../../themes/base/core.css + // >>css.structure: ../../themes/base/spinner.css + // >>css.theme: ../../themes/base/theme.css + + function spinnerModifier(fn) { + return function() { + var previous = this.element.val(); + fn.apply(this, arguments); + this._refresh(); + if (previous !== this.element.val()) { + this._trigger('change'); + } + }; + } + + $.widget('ui.spinner', { + version: '1.13.3', + defaultElement: '', + widgetEventPrefix: 'spin', + options: { + classes: { + 'ui-spinner': 'ui-corner-all', + 'ui-spinner-down': 'ui-corner-br', + 'ui-spinner-up': 'ui-corner-tr', + }, + culture: null, + icons: { + down: 'ui-icon-triangle-1-s', + up: 'ui-icon-triangle-1-n', + }, + incremental: true, + max: null, + min: null, + numberFormat: null, + page: 10, + step: 1, + + change: null, + spin: null, + start: null, + stop: null, + }, + + _create: function() { + // handle string values that need to be parsed + this._setOption('max', this.options.max); + this._setOption('min', this.options.min); + this._setOption('step', this.options.step); + + // Only format if there is a value, prevents the field from being marked + // as invalid in Firefox, see #9573. + if (this.value() !== '') { + // Format the value, but don't constrain. + this._value(this.element.val(), true); + } + + this._draw(); + this._on(this._events); + this._refresh(); + + // Turning off autocomplete prevents the browser from remembering the + // value when navigating through history, so we re-enable autocomplete + // if the page is unloaded before the widget is destroyed. #7790 + this._on(this.window, { + beforeunload: function() { + this.element.removeAttr('autocomplete'); + }, + }); + }, + + _getCreateOptions: function() { + var options = this._super(); + var element = this.element; + + $.each(['min', 'max', 'step'], function(i, option) { + var value = element.attr(option); + if (value != null && value.length) { + options[option] = value; + } + }); + + return options; + }, + + _events: { + keydown: function(event) { + if (this._start(event) && this._keydown(event)) { + event.preventDefault(); + } + }, + keyup: '_stop', + focus: function() { + this.previous = this.element.val(); + }, + blur: function(event) { + if (this.cancelBlur) { + delete this.cancelBlur; + return; + } + + this._stop(); + this._refresh(); + if (this.previous !== this.element.val()) { + this._trigger('change', event); + } + }, + mousewheel: function(event, delta) { + var activeElement = $.ui.safeActiveElement(this.document[0]); + var isActive = this.element[0] === activeElement; + + if (!isActive || !delta) { + return; + } + + if (!this.spinning && !this._start(event)) { + return false; + } + + this._spin((delta > 0 ? 1 : -1)*this.options.step, event); + clearTimeout(this.mousewheelTimer); + this.mousewheelTimer = this._delay(function() { + if (this.spinning) { + this._stop(event); + } + }, 100); + event.preventDefault(); + }, + 'mousedown .ui-spinner-button': function(event) { + var previous; + + // We never want the buttons to have focus; whenever the user is + // interacting with the spinner, the focus should be on the input. + // If the input is focused then this.previous is properly set from + // when the input first received focus. If the input is not focused + // then we need to set this.previous based on the value before spinning. + previous = this.element[0] === $.ui.safeActiveElement(this.document[0]) + ? this.previous + : this.element.val(); + function checkFocus() { + var isActive = this.element[0] === $.ui.safeActiveElement(this.document[0]); + if (!isActive) { + this.element.trigger('focus'); + this.previous = previous; + + // support: IE + // IE sets focus asynchronously, so we need to check if focus + // moved off of the input because the user clicked on the button. + this._delay(function() { + this.previous = previous; + }); + } + } + + // Ensure focus is on (or stays on) the text field + event.preventDefault(); + checkFocus.call(this); + + // Support: IE + // IE doesn't prevent moving focus even with event.preventDefault() + // so we set a flag to know when we should ignore the blur event + // and check (again) if focus moved off of the input. + this.cancelBlur = true; + this._delay(function() { + delete this.cancelBlur; + checkFocus.call(this); + }); + + if (this._start(event) === false) { + return; + } + + this._repeat( + null, + $(event.currentTarget) + .hasClass('ui-spinner-up') + ? 1 + : -1, + event, + ); + }, + 'mouseup .ui-spinner-button': '_stop', + 'mouseenter .ui-spinner-button': function(event) { + // button will add ui-state-active if mouse was down while mouseleave and kept down + if (!$(event.currentTarget).hasClass('ui-state-active')) { + return; + } + + if (this._start(event) === false) { + return false; + } + this._repeat( + null, + $(event.currentTarget) + .hasClass('ui-spinner-up') + ? 1 + : -1, + event, + ); + }, + + // TODO: do we really want to consider this a stop? + // shouldn't we just stop the repeater and wait until mouseup before + // we trigger the stop event? + 'mouseleave .ui-spinner-button': '_stop', + }, + + // Support mobile enhanced option and make backcompat more sane + _enhance: function() { + this.uiSpinner = this.element + .attr('autocomplete', 'off') + .wrap('') + .parent() + // Add buttons + .append( + '', + ); + }, + + _draw: function() { + this._enhance(); + + this._addClass(this.uiSpinner, 'ui-spinner', 'ui-widget ui-widget-content'); + this._addClass('ui-spinner-input'); + + this.element.attr('role', 'spinbutton'); + + // Button bindings + this.buttons = this.uiSpinner.children('a') + .attr('tabIndex', -1) + .attr('aria-hidden', true) + .button({ + classes: { + 'ui-button': '', + }, + }); + + // TODO: Right now button does not support classes this is already updated in button PR + this._removeClass(this.buttons, 'ui-corner-all'); + + this._addClass(this.buttons.first(), 'ui-spinner-button ui-spinner-up'); + this._addClass(this.buttons.last(), 'ui-spinner-button ui-spinner-down'); + this.buttons.first().button({ + 'icon': this.options.icons.up, + 'showLabel': false, + }); + this.buttons.last().button({ + 'icon': this.options.icons.down, + 'showLabel': false, + }); + + // IE 6 doesn't understand height: 50% for the buttons + // unless the wrapper has an explicit height + if ( + this.buttons.height() > Math.ceil(this.uiSpinner.height()*0.5) + && this.uiSpinner.height() > 0 + ) { + this.uiSpinner.height(this.uiSpinner.height()); + } + }, + + _keydown: function(event) { + var options = this.options, + keyCode = $.ui.keyCode; + + switch (event.keyCode) { + case keyCode.UP: + this._repeat(null, 1, event); + return true; + case keyCode.DOWN: + this._repeat(null, -1, event); + return true; + case keyCode.PAGE_UP: + this._repeat(null, options.page, event); + return true; + case keyCode.PAGE_DOWN: + this._repeat(null, -options.page, event); + return true; + } + + return false; + }, + + _start: function(event) { + if (!this.spinning && this._trigger('start', event) === false) { + return false; + } + + if (!this.counter) { + this.counter = 1; + } + this.spinning = true; + return true; + }, + + _repeat: function(i, steps, event) { + i = i || 500; + + clearTimeout(this.timer); + this.timer = this._delay(function() { + this._repeat(40, steps, event); + }, i); + + this._spin(steps*this.options.step, event); + }, + + _spin: function(step, event) { + var value = this.value() || 0; + + if (!this.counter) { + this.counter = 1; + } + + value = this._adjustValue(value+step*this._increment(this.counter)); + + if (!this.spinning || this._trigger('spin', event, {value: value}) !== false) { + this._value(value); + this.counter++; + } + }, + + _increment: function(i) { + var incremental = this.options.incremental; + + if (incremental) { + return typeof incremental === 'function' + ? incremental(i) + : Math.floor(i*i*i/50000-i*i/500+17*i/200+1); + } + + return 1; + }, + + _precision: function() { + var precision = this._precisionOf(this.options.step); + if (this.options.min !== null) { + precision = Math.max(precision, this._precisionOf(this.options.min)); + } + return precision; + }, + + _precisionOf: function(num) { + var str = num.toString(), + decimal = str.indexOf('.'); + return decimal === -1 ? 0 : str.length-decimal-1; + }, + + _adjustValue: function(value) { + var base, aboveMin, options = this.options; + + // Make sure we're at a valid step + // - find out where we are relative to the base (min or 0) + base = options.min !== null ? options.min : 0; + aboveMin = value-base; + + // - round to the nearest step + aboveMin = Math.round(aboveMin/options.step)*options.step; + + // - rounding is based on 0, so adjust back to our base + value = base+aboveMin; + + // Fix precision from bad JS floating point math + value = parseFloat(value.toFixed(this._precision())); + + // Clamp the value + if (options.max !== null && value > options.max) { + return options.max; + } + if (options.min !== null && value < options.min) { + return options.min; + } + + return value; + }, + + _stop: function(event) { + if (!this.spinning) { + return; + } + + clearTimeout(this.timer); + clearTimeout(this.mousewheelTimer); + this.counter = 0; + this.spinning = false; + this._trigger('stop', event); + }, + + _setOption: function(key, value) { + var prevValue, first, last; + + if (key === 'culture' || key === 'numberFormat') { + prevValue = this._parse(this.element.val()); + this.options[key] = value; + this.element.val(this._format(prevValue)); + return; + } + + if (key === 'max' || key === 'min' || key === 'step') { + if (typeof value === 'string') { + value = this._parse(value); + } + } + if (key === 'icons') { + first = this.buttons.first().find('.ui-icon'); + this._removeClass(first, null, this.options.icons.up); + this._addClass(first, null, value.up); + last = this.buttons.last().find('.ui-icon'); + this._removeClass(last, null, this.options.icons.down); + this._addClass(last, null, value.down); + } + + this._super(key, value); + }, + + _setOptionDisabled: function(value) { + this._super(value); + + this._toggleClass(this.uiSpinner, null, 'ui-state-disabled', !!value); + this.element.prop('disabled', !!value); + this.buttons.button(value ? 'disable' : 'enable'); + }, + + _setOptions: spinnerModifier(function(options) { + this._super(options); + }), + + _parse: function(val) { + if (typeof val === 'string' && val !== '') { + val = window.Globalize && this.options.numberFormat + ? Globalize.parseFloat(val, 10, this.options.culture) + : +val; + } + return val === '' || isNaN(val) ? null : val; + }, + + _format: function(value) { + if (value === '') { + return ''; + } + return window.Globalize && this.options.numberFormat + ? Globalize.format(value, this.options.numberFormat, this.options.culture) + : value; + }, + + _refresh: function() { + this.element.attr({ + 'aria-valuemin': this.options.min, + 'aria-valuemax': this.options.max, + + // TODO: what should we do with values that can't be parsed? + 'aria-valuenow': this._parse(this.element.val()), + }); + }, + + isValid: function() { + var value = this.value(); + + // Null is invalid + if (value === null) { + return false; + } + + // If value gets adjusted, it's invalid + return value === this._adjustValue(value); + }, + + // Update the value without triggering change + _value: function(value, allowAny) { + var parsed; + if (value !== '') { + parsed = this._parse(value); + if (parsed !== null) { + if (!allowAny) { + parsed = this._adjustValue(parsed); + } + value = this._format(parsed); + } + } + this.element.val(value); + this._refresh(); + }, + + _destroy: function() { + this.element + .prop('disabled', false) + .removeAttr('autocomplete role aria-valuemin aria-valuemax aria-valuenow'); + + this.uiSpinner.replaceWith(this.element); + }, + + stepUp: spinnerModifier(function(steps) { + this._stepUp(steps); + }), + _stepUp: function(steps) { + if (this._start()) { + this._spin((steps || 1)*this.options.step); + this._stop(); + } + }, + + stepDown: spinnerModifier(function(steps) { + this._stepDown(steps); + }), + _stepDown: function(steps) { + if (this._start()) { + this._spin((steps || 1)*-this.options.step); + this._stop(); + } + }, + + pageUp: spinnerModifier(function(pages) { + this._stepUp((pages || 1)*this.options.page); + }), + + pageDown: spinnerModifier(function(pages) { + this._stepDown((pages || 1)*this.options.page); + }), + + value: function(newVal) { + if (!arguments.length) { + return this._parse(this.element.val()); + } + spinnerModifier(this._value).call(this, newVal); + }, + + widget: function() { + return this.uiSpinner; + }, + }); + + // DEPRECATED + // TODO: switch return back to widget declaration at top of file when this is removed + if ($.uiBackCompat !== false) { + // Backcompat for spinner html extension points + $.widget('ui.spinner', $.ui.spinner, { + _enhance: function() { + this.uiSpinner = this.element + .attr('autocomplete', 'off') + .wrap(this._uiSpinnerHtml()) + .parent() + // Add buttons + .append(this._buttonHtml()); + }, + _uiSpinnerHtml: function() { + return ''; + }, + + _buttonHtml: function() { + return ''; + }, + }); + } + + var widgetsSpinner = $.ui.spinner; + + /*! * jQuery UI Tabs 1.13.3 * https://jqueryui.com * @@ -17664,902 +18051,909 @@ var widgetsSpinner = $.ui.spinner; * https://jquery.org/license */ -//>>label: Tabs -//>>group: Widgets -//>>description: Transforms a set of container elements into a tab structure. -//>>docs: https://api.jqueryui.com/tabs/ -//>>demos: https://jqueryui.com/tabs/ -//>>css.structure: ../../themes/base/core.css -//>>css.structure: ../../themes/base/tabs.css -//>>css.theme: ../../themes/base/theme.css - - -$.widget( "ui.tabs", { - version: "1.13.3", - delay: 300, - options: { - active: null, - classes: { - "ui-tabs": "ui-corner-all", - "ui-tabs-nav": "ui-corner-all", - "ui-tabs-panel": "ui-corner-bottom", - "ui-tabs-tab": "ui-corner-top" - }, - collapsible: false, - event: "click", - heightStyle: "content", - hide: null, - show: null, - - // Callbacks - activate: null, - beforeActivate: null, - beforeLoad: null, - load: null - }, - - _isLocal: ( function() { - var rhash = /#.*$/; - - return function( anchor ) { - var anchorUrl, locationUrl; - - anchorUrl = anchor.href.replace( rhash, "" ); - locationUrl = location.href.replace( rhash, "" ); - - // Decoding may throw an error if the URL isn't UTF-8 (#9518) - try { - anchorUrl = decodeURIComponent( anchorUrl ); - } catch ( error ) {} - try { - locationUrl = decodeURIComponent( locationUrl ); - } catch ( error ) {} - - return anchor.hash.length > 1 && anchorUrl === locationUrl; - }; - } )(), - - _create: function() { - var that = this, - options = this.options; - - this.running = false; - - this._addClass( "ui-tabs", "ui-widget ui-widget-content" ); - this._toggleClass( "ui-tabs-collapsible", null, options.collapsible ); - - this._processTabs(); - options.active = this._initialActive(); - - // Take disabling tabs via class attribute from HTML - // into account and update option properly. - if ( Array.isArray( options.disabled ) ) { - options.disabled = $.uniqueSort( options.disabled.concat( - $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { - return that.tabs.index( li ); - } ) - ) ).sort(); - } - - // Check for length avoids error when initializing empty list - if ( this.options.active !== false && this.anchors.length ) { - this.active = this._findActive( options.active ); - } else { - this.active = $(); - } - - this._refresh(); - - if ( this.active.length ) { - this.load( options.active ); - } - }, - - _initialActive: function() { - var active = this.options.active, - collapsible = this.options.collapsible, - locationHash = location.hash.substring( 1 ); - - if ( active === null ) { - - // check the fragment identifier in the URL - if ( locationHash ) { - this.tabs.each( function( i, tab ) { - if ( $( tab ).attr( "aria-controls" ) === locationHash ) { - active = i; - return false; - } - } ); - } - - // Check for a tab marked active via a class - if ( active === null ) { - active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); - } - - // No active tab, set to false - if ( active === null || active === -1 ) { - active = this.tabs.length ? 0 : false; - } - } - - // Handle numbers: negative, out of range - if ( active !== false ) { - active = this.tabs.index( this.tabs.eq( active ) ); - if ( active === -1 ) { - active = collapsible ? false : 0; - } - } - - // Don't allow collapsible: false and active: false - if ( !collapsible && active === false && this.anchors.length ) { - active = 0; - } - - return active; - }, - - _getCreateEventData: function() { - return { - tab: this.active, - panel: !this.active.length ? $() : this._getPanelForTab( this.active ) - }; - }, - - _tabKeydown: function( event ) { - var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ), - selectedIndex = this.tabs.index( focusedTab ), - goingForward = true; - - if ( this._handlePageNav( event ) ) { - return; - } - - switch ( event.keyCode ) { - case $.ui.keyCode.RIGHT: - case $.ui.keyCode.DOWN: - selectedIndex++; - break; - case $.ui.keyCode.UP: - case $.ui.keyCode.LEFT: - goingForward = false; - selectedIndex--; - break; - case $.ui.keyCode.END: - selectedIndex = this.anchors.length - 1; - break; - case $.ui.keyCode.HOME: - selectedIndex = 0; - break; - case $.ui.keyCode.SPACE: - - // Activate only, no collapsing - event.preventDefault(); - clearTimeout( this.activating ); - this._activate( selectedIndex ); - return; - case $.ui.keyCode.ENTER: - - // Toggle (cancel delayed activation, allow collapsing) - event.preventDefault(); - clearTimeout( this.activating ); - - // Determine if we should collapse or activate - this._activate( selectedIndex === this.options.active ? false : selectedIndex ); - return; - default: - return; - } - - // Focus the appropriate tab, based on which key was pressed - event.preventDefault(); - clearTimeout( this.activating ); - selectedIndex = this._focusNextTab( selectedIndex, goingForward ); - - // Navigating with control/command key will prevent automatic activation - if ( !event.ctrlKey && !event.metaKey ) { - - // Update aria-selected immediately so that AT think the tab is already selected. - // Otherwise AT may confuse the user by stating that they need to activate the tab, - // but the tab will already be activated by the time the announcement finishes. - focusedTab.attr( "aria-selected", "false" ); - this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); - - this.activating = this._delay( function() { - this.option( "active", selectedIndex ); - }, this.delay ); - } - }, - - _panelKeydown: function( event ) { - if ( this._handlePageNav( event ) ) { - return; - } - - // Ctrl+up moves focus to the current tab - if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { - event.preventDefault(); - this.active.trigger( "focus" ); - } - }, - - // Alt+page up/down moves focus to the previous/next tab (and activates) - _handlePageNav: function( event ) { - if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { - this._activate( this._focusNextTab( this.options.active - 1, false ) ); - return true; - } - if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { - this._activate( this._focusNextTab( this.options.active + 1, true ) ); - return true; - } - }, - - _findNextTab: function( index, goingForward ) { - var lastTabIndex = this.tabs.length - 1; - - function constrain() { - if ( index > lastTabIndex ) { - index = 0; - } - if ( index < 0 ) { - index = lastTabIndex; - } - return index; - } - - while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { - index = goingForward ? index + 1 : index - 1; - } - - return index; - }, - - _focusNextTab: function( index, goingForward ) { - index = this._findNextTab( index, goingForward ); - this.tabs.eq( index ).trigger( "focus" ); - return index; - }, - - _setOption: function( key, value ) { - if ( key === "active" ) { - - // _activate() will handle invalid values and update this.options - this._activate( value ); - return; - } - - this._super( key, value ); - - if ( key === "collapsible" ) { - this._toggleClass( "ui-tabs-collapsible", null, value ); - - // Setting collapsible: false while collapsed; open first panel - if ( !value && this.options.active === false ) { - this._activate( 0 ); - } - } - - if ( key === "event" ) { - this._setupEvents( value ); - } - - if ( key === "heightStyle" ) { - this._setupHeightStyle( value ); - } - }, - - _sanitizeSelector: function( hash ) { - return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : ""; - }, - - refresh: function() { - var options = this.options, - lis = this.tablist.children( ":has(a[href])" ); - - // Get disabled tabs from class attribute from HTML - // this will get converted to a boolean if needed in _refresh() - options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { - return lis.index( tab ); - } ); - - this._processTabs(); - - // Was collapsed or no tabs - if ( options.active === false || !this.anchors.length ) { - options.active = false; - this.active = $(); - - // was active, but active tab is gone - } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { - - // all remaining tabs are disabled - if ( this.tabs.length === options.disabled.length ) { - options.active = false; - this.active = $(); - - // activate previous tab - } else { - this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); - } - - // was active, active tab still exists - } else { - - // make sure active index is correct - options.active = this.tabs.index( this.active ); - } - - this._refresh(); - }, - - _refresh: function() { - this._setOptionDisabled( this.options.disabled ); - this._setupEvents( this.options.event ); - this._setupHeightStyle( this.options.heightStyle ); - - this.tabs.not( this.active ).attr( { - "aria-selected": "false", - "aria-expanded": "false", - tabIndex: -1 - } ); - this.panels.not( this._getPanelForTab( this.active ) ) - .hide() - .attr( { - "aria-hidden": "true" - } ); - - // Make sure one tab is in the tab order - if ( !this.active.length ) { - this.tabs.eq( 0 ).attr( "tabIndex", 0 ); - } else { - this.active - .attr( { - "aria-selected": "true", - "aria-expanded": "true", - tabIndex: 0 - } ); - this._addClass( this.active, "ui-tabs-active", "ui-state-active" ); - this._getPanelForTab( this.active ) - .show() - .attr( { - "aria-hidden": "false" - } ); - } - }, - - _processTabs: function() { - var that = this, - prevTabs = this.tabs, - prevAnchors = this.anchors, - prevPanels = this.panels; - - this.tablist = this._getList().attr( "role", "tablist" ); - this._addClass( this.tablist, "ui-tabs-nav", - "ui-helper-reset ui-helper-clearfix ui-widget-header" ); - - // Prevent users from focusing disabled tabs via click - this.tablist - .on( "mousedown" + this.eventNamespace, "> li", function( event ) { - if ( $( this ).is( ".ui-state-disabled" ) ) { - event.preventDefault(); - } - } ) - - // Support: IE <9 - // Preventing the default action in mousedown doesn't prevent IE - // from focusing the element, so if the anchor gets focused, blur. - // We don't have to worry about focusing the previously focused - // element since clicking on a non-focusable element should focus - // the body anyway. - .on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() { - if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) { - this.blur(); - } - } ); - - this.tabs = this.tablist.find( "> li:has(a[href])" ) - .attr( { - role: "tab", - tabIndex: -1 - } ); - this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" ); - - this.anchors = this.tabs.map( function() { - return $( "a", this )[ 0 ]; - } ) - .attr( { - tabIndex: -1 - } ); - this._addClass( this.anchors, "ui-tabs-anchor" ); - - this.panels = $(); - - this.anchors.each( function( i, anchor ) { - var selector, panel, panelId, - anchorId = $( anchor ).uniqueId().attr( "id" ), - tab = $( anchor ).closest( "li" ), - originalAriaControls = tab.attr( "aria-controls" ); - - // Inline tab - if ( that._isLocal( anchor ) ) { - selector = anchor.hash; - panelId = selector.substring( 1 ); - panel = that.element.find( that._sanitizeSelector( selector ) ); - - // remote tab - } else { - - // If the tab doesn't already have aria-controls, - // generate an id by using a throw-away element - panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id; - selector = "#" + panelId; - panel = that.element.find( selector ); - if ( !panel.length ) { - panel = that._createPanel( panelId ); - panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); - } - panel.attr( "aria-live", "polite" ); - } - - if ( panel.length ) { - that.panels = that.panels.add( panel ); - } - if ( originalAriaControls ) { - tab.data( "ui-tabs-aria-controls", originalAriaControls ); - } - tab.attr( { - "aria-controls": panelId, - "aria-labelledby": anchorId - } ); - panel.attr( "aria-labelledby", anchorId ); - } ); - - this.panels.attr( "role", "tabpanel" ); - this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" ); - - // Avoid memory leaks (#10056) - if ( prevTabs ) { - this._off( prevTabs.not( this.tabs ) ); - this._off( prevAnchors.not( this.anchors ) ); - this._off( prevPanels.not( this.panels ) ); - } - }, - - // Allow overriding how to find the list for rare usage scenarios (#7715) - _getList: function() { - return this.tablist || this.element.find( "ol, ul" ).eq( 0 ); - }, - - _createPanel: function( id ) { - return $( "
" ) - .attr( "id", id ) - .data( "ui-tabs-destroy", true ); - }, - - _setOptionDisabled: function( disabled ) { - var currentItem, li, i; - - if ( Array.isArray( disabled ) ) { - if ( !disabled.length ) { - disabled = false; - } else if ( disabled.length === this.anchors.length ) { - disabled = true; - } - } - - // Disable tabs - for ( i = 0; ( li = this.tabs[ i ] ); i++ ) { - currentItem = $( li ); - if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { - currentItem.attr( "aria-disabled", "true" ); - this._addClass( currentItem, null, "ui-state-disabled" ); - } else { - currentItem.removeAttr( "aria-disabled" ); - this._removeClass( currentItem, null, "ui-state-disabled" ); - } - } - - this.options.disabled = disabled; - - this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, - disabled === true ); - }, - - _setupEvents: function( event ) { - var events = {}; - if ( event ) { - $.each( event.split( " " ), function( index, eventName ) { - events[ eventName ] = "_eventHandler"; - } ); - } - - this._off( this.anchors.add( this.tabs ).add( this.panels ) ); - - // Always prevent the default action, even when disabled - this._on( true, this.anchors, { - click: function( event ) { - event.preventDefault(); - } - } ); - this._on( this.anchors, events ); - this._on( this.tabs, { keydown: "_tabKeydown" } ); - this._on( this.panels, { keydown: "_panelKeydown" } ); - - this._focusable( this.tabs ); - this._hoverable( this.tabs ); - }, - - _setupHeightStyle: function( heightStyle ) { - var maxHeight, - parent = this.element.parent(); - - if ( heightStyle === "fill" ) { - maxHeight = parent.height(); - maxHeight -= this.element.outerHeight() - this.element.height(); - - this.element.siblings( ":visible" ).each( function() { - var elem = $( this ), - position = elem.css( "position" ); - - if ( position === "absolute" || position === "fixed" ) { - return; - } - maxHeight -= elem.outerHeight( true ); - } ); - - this.element.children().not( this.panels ).each( function() { - maxHeight -= $( this ).outerHeight( true ); - } ); - - this.panels.each( function() { - $( this ).height( Math.max( 0, maxHeight - - $( this ).innerHeight() + $( this ).height() ) ); - } ) - .css( "overflow", "auto" ); - } else if ( heightStyle === "auto" ) { - maxHeight = 0; - this.panels.each( function() { - maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); - } ).height( maxHeight ); - } - }, - - _eventHandler: function( event ) { - var options = this.options, - active = this.active, - anchor = $( event.currentTarget ), - tab = anchor.closest( "li" ), - clickedIsActive = tab[ 0 ] === active[ 0 ], - collapsing = clickedIsActive && options.collapsible, - toShow = collapsing ? $() : this._getPanelForTab( tab ), - toHide = !active.length ? $() : this._getPanelForTab( active ), - eventData = { - oldTab: active, - oldPanel: toHide, - newTab: collapsing ? $() : tab, - newPanel: toShow - }; - - event.preventDefault(); - - if ( tab.hasClass( "ui-state-disabled" ) || - - // tab is already loading - tab.hasClass( "ui-tabs-loading" ) || - - // can't switch durning an animation - this.running || - - // click on active header, but not collapsible - ( clickedIsActive && !options.collapsible ) || - - // allow canceling activation - ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { - return; - } - - options.active = collapsing ? false : this.tabs.index( tab ); - - this.active = clickedIsActive ? $() : tab; - if ( this.xhr ) { - this.xhr.abort(); - } - - if ( !toHide.length && !toShow.length ) { - $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); - } - - if ( toShow.length ) { - this.load( this.tabs.index( tab ), event ); - } - this._toggle( event, eventData ); - }, - - // Handles show/hide for selecting tabs - _toggle: function( event, eventData ) { - var that = this, - toShow = eventData.newPanel, - toHide = eventData.oldPanel; - - this.running = true; - - function complete() { - that.running = false; - that._trigger( "activate", event, eventData ); - } - - function show() { - that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" ); - - if ( toShow.length && that.options.show ) { - that._show( toShow, that.options.show, complete ); - } else { - toShow.show(); - complete(); - } - } - - // Start out by hiding, then showing, then completing - if ( toHide.length && this.options.hide ) { - this._hide( toHide, this.options.hide, function() { - that._removeClass( eventData.oldTab.closest( "li" ), - "ui-tabs-active", "ui-state-active" ); - show(); - } ); - } else { - this._removeClass( eventData.oldTab.closest( "li" ), - "ui-tabs-active", "ui-state-active" ); - toHide.hide(); - show(); - } - - toHide.attr( "aria-hidden", "true" ); - eventData.oldTab.attr( { - "aria-selected": "false", - "aria-expanded": "false" - } ); - - // If we're switching tabs, remove the old tab from the tab order. - // If we're opening from collapsed state, remove the previous tab from the tab order. - // If we're collapsing, then keep the collapsing tab in the tab order. - if ( toShow.length && toHide.length ) { - eventData.oldTab.attr( "tabIndex", -1 ); - } else if ( toShow.length ) { - this.tabs.filter( function() { - return $( this ).attr( "tabIndex" ) === 0; - } ) - .attr( "tabIndex", -1 ); - } - - toShow.attr( "aria-hidden", "false" ); - eventData.newTab.attr( { - "aria-selected": "true", - "aria-expanded": "true", - tabIndex: 0 - } ); - }, - - _activate: function( index ) { - var anchor, - active = this._findActive( index ); - - // Trying to activate the already active panel - if ( active[ 0 ] === this.active[ 0 ] ) { - return; - } - - // Trying to collapse, simulate a click on the current active header - if ( !active.length ) { - active = this.active; - } - - anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; - this._eventHandler( { - target: anchor, - currentTarget: anchor, - preventDefault: $.noop - } ); - }, - - _findActive: function( index ) { - return index === false ? $() : this.tabs.eq( index ); - }, - - _getIndex: function( index ) { - - // meta-function to give users option to provide a href string instead of a numerical index. - if ( typeof index === "string" ) { - index = this.anchors.index( this.anchors.filter( "[href$='" + - $.escapeSelector( index ) + "']" ) ); - } - - return index; - }, - - _destroy: function() { - if ( this.xhr ) { - this.xhr.abort(); - } - - this.tablist - .removeAttr( "role" ) - .off( this.eventNamespace ); - - this.anchors - .removeAttr( "role tabIndex" ) - .removeUniqueId(); - - this.tabs.add( this.panels ).each( function() { - if ( $.data( this, "ui-tabs-destroy" ) ) { - $( this ).remove(); - } else { - $( this ).removeAttr( "role tabIndex " + - "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" ); - } - } ); - - this.tabs.each( function() { - var li = $( this ), - prev = li.data( "ui-tabs-aria-controls" ); - if ( prev ) { - li - .attr( "aria-controls", prev ) - .removeData( "ui-tabs-aria-controls" ); - } else { - li.removeAttr( "aria-controls" ); - } - } ); - - this.panels.show(); - - if ( this.options.heightStyle !== "content" ) { - this.panels.css( "height", "" ); - } - }, - - enable: function( index ) { - var disabled = this.options.disabled; - if ( disabled === false ) { - return; - } - - if ( index === undefined ) { - disabled = false; - } else { - index = this._getIndex( index ); - if ( Array.isArray( disabled ) ) { - disabled = $.map( disabled, function( num ) { - return num !== index ? num : null; - } ); - } else { - disabled = $.map( this.tabs, function( li, num ) { - return num !== index ? num : null; - } ); - } - } - this._setOptionDisabled( disabled ); - }, - - disable: function( index ) { - var disabled = this.options.disabled; - if ( disabled === true ) { - return; - } - - if ( index === undefined ) { - disabled = true; - } else { - index = this._getIndex( index ); - if ( $.inArray( index, disabled ) !== -1 ) { - return; - } - if ( Array.isArray( disabled ) ) { - disabled = $.merge( [ index ], disabled ).sort(); - } else { - disabled = [ index ]; - } - } - this._setOptionDisabled( disabled ); - }, - - load: function( index, event ) { - index = this._getIndex( index ); - var that = this, - tab = this.tabs.eq( index ), - anchor = tab.find( ".ui-tabs-anchor" ), - panel = this._getPanelForTab( tab ), - eventData = { - tab: tab, - panel: panel - }, - complete = function( jqXHR, status ) { - if ( status === "abort" ) { - that.panels.stop( false, true ); - } - - that._removeClass( tab, "ui-tabs-loading" ); - panel.removeAttr( "aria-busy" ); - - if ( jqXHR === that.xhr ) { - delete that.xhr; - } - }; - - // Not remote - if ( this._isLocal( anchor[ 0 ] ) ) { - return; - } - - this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); - - // Support: jQuery <1.8 - // jQuery <1.8 returns false if the request is canceled in beforeSend, - // but as of 1.8, $.ajax() always returns a jqXHR object. - if ( this.xhr && this.xhr.statusText !== "canceled" ) { - this._addClass( tab, "ui-tabs-loading" ); - panel.attr( "aria-busy", "true" ); - - this.xhr - .done( function( response, status, jqXHR ) { - - // support: jQuery <1.8 - // https://bugs.jquery.com/ticket/11778 - setTimeout( function() { - panel.html( response ); - that._trigger( "load", event, eventData ); - - complete( jqXHR, status ); - }, 1 ); - } ) - .fail( function( jqXHR, status ) { - - // support: jQuery <1.8 - // https://bugs.jquery.com/ticket/11778 - setTimeout( function() { - complete( jqXHR, status ); - }, 1 ); - } ); - } - }, - - _ajaxSettings: function( anchor, event, eventData ) { - var that = this; - return { - - // Support: IE <11 only - // Strip any hash that exists to prevent errors with the Ajax request - url: anchor.attr( "href" ).replace( /#.*$/, "" ), - beforeSend: function( jqXHR, settings ) { - return that._trigger( "beforeLoad", event, - $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) ); - } - }; - }, - - _getPanelForTab: function( tab ) { - var id = $( tab ).attr( "aria-controls" ); - return this.element.find( this._sanitizeSelector( "#" + id ) ); - } -} ); - -// DEPRECATED -// TODO: Switch return back to widget declaration at top of file when this is removed -if ( $.uiBackCompat !== false ) { - - // Backcompat for ui-tab class (now ui-tabs-tab) - $.widget( "ui.tabs", $.ui.tabs, { - _processTabs: function() { - this._superApply( arguments ); - this._addClass( this.tabs, "ui-tab" ); - } - } ); -} - -var widgetsTabs = $.ui.tabs; - - -/*! + // >>label: Tabs + // >>group: Widgets + // >>description: Transforms a set of container elements into a tab structure. + // >>docs: https://api.jqueryui.com/tabs/ + // >>demos: https://jqueryui.com/tabs/ + // >>css.structure: ../../themes/base/core.css + // >>css.structure: ../../themes/base/tabs.css + // >>css.theme: ../../themes/base/theme.css + + $.widget('ui.tabs', { + version: '1.13.3', + delay: 300, + options: { + active: null, + classes: { + 'ui-tabs': 'ui-corner-all', + 'ui-tabs-nav': 'ui-corner-all', + 'ui-tabs-panel': 'ui-corner-bottom', + 'ui-tabs-tab': 'ui-corner-top', + }, + collapsible: false, + event: 'click', + heightStyle: 'content', + hide: null, + show: null, + + // Callbacks + activate: null, + beforeActivate: null, + beforeLoad: null, + load: null, + }, + + _isLocal: (function() { + var rhash = /#.*$/; + + return function(anchor) { + var anchorUrl, locationUrl; + + anchorUrl = anchor.href.replace(rhash, ''); + locationUrl = location.href.replace(rhash, ''); + + // Decoding may throw an error if the URL isn't UTF-8 (#9518) + try { + anchorUrl = decodeURIComponent(anchorUrl); + } catch (error) {} + try { + locationUrl = decodeURIComponent(locationUrl); + } catch (error) {} + + return anchor.hash.length > 1 && anchorUrl === locationUrl; + }; + })(), + + _create: function() { + var that = this, + options = this.options; + + this.running = false; + + this._addClass('ui-tabs', 'ui-widget ui-widget-content'); + this._toggleClass('ui-tabs-collapsible', null, options.collapsible); + + this._processTabs(); + options.active = this._initialActive(); + + // Take disabling tabs via class attribute from HTML + // into account and update option properly. + if (Array.isArray(options.disabled)) { + options.disabled = $.uniqueSort(options.disabled.concat( + $.map(this.tabs.filter('.ui-state-disabled'), function(li) { + return that.tabs.index(li); + }), + )).sort(); + } + + // Check for length avoids error when initializing empty list + if (this.options.active !== false && this.anchors.length) { + this.active = this._findActive(options.active); + } else { + this.active = $(); + } + + this._refresh(); + + if (this.active.length) { + this.load(options.active); + } + }, + + _initialActive: function() { + var active = this.options.active, + collapsible = this.options.collapsible, + locationHash = location.hash.substring(1); + + if (active === null) { + // check the fragment identifier in the URL + if (locationHash) { + this.tabs.each(function(i, tab) { + if ($(tab).attr('aria-controls') === locationHash) { + active = i; + return false; + } + }); + } + + // Check for a tab marked active via a class + if (active === null) { + active = this.tabs.index(this.tabs.filter('.ui-tabs-active')); + } + + // No active tab, set to false + if (active === null || active === -1) { + active = this.tabs.length ? 0 : false; + } + } + + // Handle numbers: negative, out of range + if (active !== false) { + active = this.tabs.index(this.tabs.eq(active)); + if (active === -1) { + active = collapsible ? false : 0; + } + } + + // Don't allow collapsible: false and active: false + if (!collapsible && active === false && this.anchors.length) { + active = 0; + } + + return active; + }, + + _getCreateEventData: function() { + return { + tab: this.active, + panel: !this.active.length ? $() : this._getPanelForTab(this.active), + }; + }, + + _tabKeydown: function(event) { + var focusedTab = $($.ui.safeActiveElement(this.document[0])).closest('li'), + selectedIndex = this.tabs.index(focusedTab), + goingForward = true; + + if (this._handlePageNav(event)) { + return; + } + + switch (event.keyCode) { + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + selectedIndex++; + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.LEFT: + goingForward = false; + selectedIndex--; + break; + case $.ui.keyCode.END: + selectedIndex = this.anchors.length-1; + break; + case $.ui.keyCode.HOME: + selectedIndex = 0; + break; + case $.ui.keyCode.SPACE: + // Activate only, no collapsing + event.preventDefault(); + clearTimeout(this.activating); + this._activate(selectedIndex); + return; + case $.ui.keyCode.ENTER: + // Toggle (cancel delayed activation, allow collapsing) + event.preventDefault(); + clearTimeout(this.activating); + + // Determine if we should collapse or activate + this._activate(selectedIndex === this.options.active ? false : selectedIndex); + return; + default: + return; + } + + // Focus the appropriate tab, based on which key was pressed + event.preventDefault(); + clearTimeout(this.activating); + selectedIndex = this._focusNextTab(selectedIndex, goingForward); + + // Navigating with control/command key will prevent automatic activation + if (!event.ctrlKey && !event.metaKey) { + // Update aria-selected immediately so that AT think the tab is already selected. + // Otherwise AT may confuse the user by stating that they need to activate the tab, + // but the tab will already be activated by the time the announcement finishes. + focusedTab.attr('aria-selected', 'false'); + this.tabs.eq(selectedIndex).attr('aria-selected', 'true'); + + this.activating = this._delay(function() { + this.option('active', selectedIndex); + }, this.delay); + } + }, + + _panelKeydown: function(event) { + if (this._handlePageNav(event)) { + return; + } + + // Ctrl+up moves focus to the current tab + if (event.ctrlKey && event.keyCode === $.ui.keyCode.UP) { + event.preventDefault(); + this.active.trigger('focus'); + } + }, + + // Alt+page up/down moves focus to the previous/next tab (and activates) + _handlePageNav: function(event) { + if (event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP) { + this._activate(this._focusNextTab(this.options.active-1, false)); + return true; + } + if (event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN) { + this._activate(this._focusNextTab(this.options.active+1, true)); + return true; + } + }, + + _findNextTab: function(index, goingForward) { + var lastTabIndex = this.tabs.length-1; + + function constrain() { + if (index > lastTabIndex) { + index = 0; + } + if (index < 0) { + index = lastTabIndex; + } + return index; + } + + while ($.inArray(constrain(), this.options.disabled) !== -1) { + index = goingForward ? index+1 : index-1; + } + + return index; + }, + + _focusNextTab: function(index, goingForward) { + index = this._findNextTab(index, goingForward); + this.tabs.eq(index).trigger('focus'); + return index; + }, + + _setOption: function(key, value) { + if (key === 'active') { + // _activate() will handle invalid values and update this.options + this._activate(value); + return; + } + + this._super(key, value); + + if (key === 'collapsible') { + this._toggleClass('ui-tabs-collapsible', null, value); + + // Setting collapsible: false while collapsed; open first panel + if (!value && this.options.active === false) { + this._activate(0); + } + } + + if (key === 'event') { + this._setupEvents(value); + } + + if (key === 'heightStyle') { + this._setupHeightStyle(value); + } + }, + + _sanitizeSelector: function(hash) { + return hash ? hash.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, '\\$&') : ''; + }, + + refresh: function() { + var options = this.options, + lis = this.tablist.children(':has(a[href])'); + + // Get disabled tabs from class attribute from HTML + // this will get converted to a boolean if needed in _refresh() + options.disabled = $.map(lis.filter('.ui-state-disabled'), function(tab) { + return lis.index(tab); + }); + + this._processTabs(); + + // Was collapsed or no tabs + if (options.active === false || !this.anchors.length) { + options.active = false; + this.active = $(); + + // was active, but active tab is gone + } else if (this.active.length && !$.contains(this.tablist[0], this.active[0])) { + // all remaining tabs are disabled + if (this.tabs.length === options.disabled.length) { + options.active = false; + this.active = $(); + + // activate previous tab + } else { + this._activate(this._findNextTab(Math.max(0, options.active-1), false)); + } + + // was active, active tab still exists + } else { + // make sure active index is correct + options.active = this.tabs.index(this.active); + } + + this._refresh(); + }, + + _refresh: function() { + this._setOptionDisabled(this.options.disabled); + this._setupEvents(this.options.event); + this._setupHeightStyle(this.options.heightStyle); + + this.tabs.not(this.active).attr({ + 'aria-selected': 'false', + 'aria-expanded': 'false', + tabIndex: -1, + }); + this.panels.not(this._getPanelForTab(this.active)) + .hide() + .attr({ + 'aria-hidden': 'true', + }); + + // Make sure one tab is in the tab order + if (!this.active.length) { + this.tabs.eq(0).attr('tabIndex', 0); + } else { + this.active + .attr({ + 'aria-selected': 'true', + 'aria-expanded': 'true', + tabIndex: 0, + }); + this._addClass(this.active, 'ui-tabs-active', 'ui-state-active'); + this._getPanelForTab(this.active) + .show() + .attr({ + 'aria-hidden': 'false', + }); + } + }, + + _processTabs: function() { + var that = this, + prevTabs = this.tabs, + prevAnchors = this.anchors, + prevPanels = this.panels; + + this.tablist = this._getList().attr('role', 'tablist'); + this._addClass( + this.tablist, + 'ui-tabs-nav', + 'ui-helper-reset ui-helper-clearfix ui-widget-header', + ); + + // Prevent users from focusing disabled tabs via click + this.tablist + .on('mousedown'+this.eventNamespace, '> li', function(event) { + if ($(this).is('.ui-state-disabled')) { + event.preventDefault(); + } + }) + // Support: IE <9 + // Preventing the default action in mousedown doesn't prevent IE + // from focusing the element, so if the anchor gets focused, blur. + // We don't have to worry about focusing the previously focused + // element since clicking on a non-focusable element should focus + // the body anyway. + .on('focus'+this.eventNamespace, '.ui-tabs-anchor', function() { + if ($(this).closest('li').is('.ui-state-disabled')) { + this.blur(); + } + }); + + this.tabs = this.tablist.find('> li:has(a[href])') + .attr({ + role: 'tab', + tabIndex: -1, + }); + this._addClass(this.tabs, 'ui-tabs-tab', 'ui-state-default'); + + this.anchors = this.tabs.map(function() { + return $('a', this)[0]; + }) + .attr({ + tabIndex: -1, + }); + this._addClass(this.anchors, 'ui-tabs-anchor'); + + this.panels = $(); + + this.anchors.each(function(i, anchor) { + var selector, + panel, + panelId, + anchorId = $(anchor).uniqueId().attr('id'), + tab = $(anchor).closest('li'), + originalAriaControls = tab.attr('aria-controls'); + + // Inline tab + if (that._isLocal(anchor)) { + selector = anchor.hash; + panelId = selector.substring(1); + panel = that.element.find(that._sanitizeSelector(selector)); + + // remote tab + } else { + // If the tab doesn't already have aria-controls, + // generate an id by using a throw-away element + panelId = tab.attr('aria-controls') || $({}).uniqueId()[0].id; + selector = '#'+panelId; + panel = that.element.find(selector); + if (!panel.length) { + panel = that._createPanel(panelId); + panel.insertAfter(that.panels[i-1] || that.tablist); + } + panel.attr('aria-live', 'polite'); + } + + if (panel.length) { + that.panels = that.panels.add(panel); + } + if (originalAriaControls) { + tab.data('ui-tabs-aria-controls', originalAriaControls); + } + tab.attr({ + 'aria-controls': panelId, + 'aria-labelledby': anchorId, + }); + panel.attr('aria-labelledby', anchorId); + }); + + this.panels.attr('role', 'tabpanel'); + this._addClass(this.panels, 'ui-tabs-panel', 'ui-widget-content'); + + // Avoid memory leaks (#10056) + if (prevTabs) { + this._off(prevTabs.not(this.tabs)); + this._off(prevAnchors.not(this.anchors)); + this._off(prevPanels.not(this.panels)); + } + }, + + // Allow overriding how to find the list for rare usage scenarios (#7715) + _getList: function() { + return this.tablist || this.element.find('ol, ul').eq(0); + }, + + _createPanel: function(id) { + return $('
') + .attr('id', id) + .data('ui-tabs-destroy', true); + }, + + _setOptionDisabled: function(disabled) { + var currentItem, li, i; + + if (Array.isArray(disabled)) { + if (!disabled.length) { + disabled = false; + } else if (disabled.length === this.anchors.length) { + disabled = true; + } + } + + // Disable tabs + for (i = 0; (li = this.tabs[i]); i++) { + currentItem = $(li); + if (disabled === true || $.inArray(i, disabled) !== -1) { + currentItem.attr('aria-disabled', 'true'); + this._addClass(currentItem, null, 'ui-state-disabled'); + } else { + currentItem.removeAttr('aria-disabled'); + this._removeClass(currentItem, null, 'ui-state-disabled'); + } + } + + this.options.disabled = disabled; + + this._toggleClass( + this.widget(), + this.widgetFullName+'-disabled', + null, + disabled === true, + ); + }, + + _setupEvents: function(event) { + var events = {}; + if (event) { + $.each(event.split(' '), function(index, eventName) { + events[eventName] = '_eventHandler'; + }); + } + + this._off(this.anchors.add(this.tabs).add(this.panels)); + + // Always prevent the default action, even when disabled + this._on(true, this.anchors, { + click: function(event) { + event.preventDefault(); + }, + }); + this._on(this.anchors, events); + this._on(this.tabs, {keydown: '_tabKeydown'}); + this._on(this.panels, {keydown: '_panelKeydown'}); + + this._focusable(this.tabs); + this._hoverable(this.tabs); + }, + + _setupHeightStyle: function(heightStyle) { + var maxHeight, + parent = this.element.parent(); + + if (heightStyle === 'fill') { + maxHeight = parent.height(); + maxHeight -= this.element.outerHeight()-this.element.height(); + + this.element.siblings(':visible').each(function() { + var elem = $(this), + position = elem.css('position'); + + if (position === 'absolute' || position === 'fixed') { + return; + } + maxHeight -= elem.outerHeight(true); + }); + + this.element.children().not(this.panels).each(function() { + maxHeight -= $(this).outerHeight(true); + }); + + this.panels.each(function() { + $(this).height(Math.max( + 0, + maxHeight + -$(this).innerHeight()+$(this).height(), + )); + }) + .css('overflow', 'auto'); + } else if (heightStyle === 'auto') { + maxHeight = 0; + this.panels.each(function() { + maxHeight = Math.max(maxHeight, $(this).height('').height()); + }).height(maxHeight); + } + }, + + _eventHandler: function(event) { + var options = this.options, + active = this.active, + anchor = $(event.currentTarget), + tab = anchor.closest('li'), + clickedIsActive = tab[0] === active[0], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : this._getPanelForTab(tab), + toHide = !active.length ? $() : this._getPanelForTab(active), + eventData = { + oldTab: active, + oldPanel: toHide, + newTab: collapsing ? $() : tab, + newPanel: toShow, + }; + + event.preventDefault(); + + if ( + tab.hasClass('ui-state-disabled') + // tab is already loading + || tab.hasClass('ui-tabs-loading') + // can't switch durning an animation + || this.running + // click on active header, but not collapsible + || (clickedIsActive && !options.collapsible) + // allow canceling activation + || (this._trigger('beforeActivate', event, eventData) === false) + ) { + return; + } + + options.active = collapsing ? false : this.tabs.index(tab); + + this.active = clickedIsActive ? $() : tab; + if (this.xhr) { + this.xhr.abort(); + } + + if (!toHide.length && !toShow.length) { + $.error('jQuery UI Tabs: Mismatching fragment identifier.'); + } + + if (toShow.length) { + this.load(this.tabs.index(tab), event); + } + this._toggle(event, eventData); + }, + + // Handles show/hide for selecting tabs + _toggle: function(event, eventData) { + var that = this, + toShow = eventData.newPanel, + toHide = eventData.oldPanel; + + this.running = true; + + function complete() { + that.running = false; + that._trigger('activate', event, eventData); + } + + function show() { + that._addClass(eventData.newTab.closest('li'), 'ui-tabs-active', 'ui-state-active'); + + if (toShow.length && that.options.show) { + that._show(toShow, that.options.show, complete); + } else { + toShow.show(); + complete(); + } + } + + // Start out by hiding, then showing, then completing + if (toHide.length && this.options.hide) { + this._hide(toHide, this.options.hide, function() { + that._removeClass( + eventData.oldTab.closest('li'), + 'ui-tabs-active', + 'ui-state-active', + ); + show(); + }); + } else { + this._removeClass( + eventData.oldTab.closest('li'), + 'ui-tabs-active', + 'ui-state-active', + ); + toHide.hide(); + show(); + } + + toHide.attr('aria-hidden', 'true'); + eventData.oldTab.attr({ + 'aria-selected': 'false', + 'aria-expanded': 'false', + }); + + // If we're switching tabs, remove the old tab from the tab order. + // If we're opening from collapsed state, remove the previous tab from the tab order. + // If we're collapsing, then keep the collapsing tab in the tab order. + if (toShow.length && toHide.length) { + eventData.oldTab.attr('tabIndex', -1); + } else if (toShow.length) { + this.tabs.filter(function() { + return $(this).attr('tabIndex') === 0; + }) + .attr('tabIndex', -1); + } + + toShow.attr('aria-hidden', 'false'); + eventData.newTab.attr({ + 'aria-selected': 'true', + 'aria-expanded': 'true', + tabIndex: 0, + }); + }, + + _activate: function(index) { + var anchor, + active = this._findActive(index); + + // Trying to activate the already active panel + if (active[0] === this.active[0]) { + return; + } + + // Trying to collapse, simulate a click on the current active header + if (!active.length) { + active = this.active; + } + + anchor = active.find('.ui-tabs-anchor')[0]; + this._eventHandler({ + target: anchor, + currentTarget: anchor, + preventDefault: $.noop, + }); + }, + + _findActive: function(index) { + return index === false ? $() : this.tabs.eq(index); + }, + + _getIndex: function(index) { + // meta-function to give users option to provide a href string instead of a numerical index. + if (typeof index === 'string') { + index = this.anchors.index(this.anchors.filter( + "[href$='" + +$.escapeSelector(index)+"']", + )); + } + + return index; + }, + + _destroy: function() { + if (this.xhr) { + this.xhr.abort(); + } + + this.tablist + .removeAttr('role') + .off(this.eventNamespace); + + this.anchors + .removeAttr('role tabIndex') + .removeUniqueId(); + + this.tabs.add(this.panels).each(function() { + if ($.data(this, 'ui-tabs-destroy')) { + $(this).remove(); + } else { + $(this).removeAttr( + 'role tabIndex ' + +'aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded', + ); + } + }); + + this.tabs.each(function() { + var li = $(this), + prev = li.data('ui-tabs-aria-controls'); + if (prev) { + li + .attr('aria-controls', prev) + .removeData('ui-tabs-aria-controls'); + } else { + li.removeAttr('aria-controls'); + } + }); + + this.panels.show(); + + if (this.options.heightStyle !== 'content') { + this.panels.css('height', ''); + } + }, + + enable: function(index) { + var disabled = this.options.disabled; + if (disabled === false) { + return; + } + + if (index === undefined) { + disabled = false; + } else { + index = this._getIndex(index); + if (Array.isArray(disabled)) { + disabled = $.map(disabled, function(num) { + return num !== index ? num : null; + }); + } else { + disabled = $.map(this.tabs, function(li, num) { + return num !== index ? num : null; + }); + } + } + this._setOptionDisabled(disabled); + }, + + disable: function(index) { + var disabled = this.options.disabled; + if (disabled === true) { + return; + } + + if (index === undefined) { + disabled = true; + } else { + index = this._getIndex(index); + if ($.inArray(index, disabled) !== -1) { + return; + } + if (Array.isArray(disabled)) { + disabled = $.merge([index], disabled).sort(); + } else { + disabled = [index]; + } + } + this._setOptionDisabled(disabled); + }, + + load: function(index, event) { + index = this._getIndex(index); + var that = this, + tab = this.tabs.eq(index), + anchor = tab.find('.ui-tabs-anchor'), + panel = this._getPanelForTab(tab), + eventData = { + tab: tab, + panel: panel, + }, + complete = function(jqXHR, status) { + if (status === 'abort') { + that.panels.stop(false, true); + } + + that._removeClass(tab, 'ui-tabs-loading'); + panel.removeAttr('aria-busy'); + + if (jqXHR === that.xhr) { + delete that.xhr; + } + }; + + // Not remote + if (this._isLocal(anchor[0])) { + return; + } + + this.xhr = $.ajax(this._ajaxSettings(anchor, event, eventData)); + + // Support: jQuery <1.8 + // jQuery <1.8 returns false if the request is canceled in beforeSend, + // but as of 1.8, $.ajax() always returns a jqXHR object. + if (this.xhr && this.xhr.statusText !== 'canceled') { + this._addClass(tab, 'ui-tabs-loading'); + panel.attr('aria-busy', 'true'); + + this.xhr + .done(function(response, status, jqXHR) { + // support: jQuery <1.8 + // https://bugs.jquery.com/ticket/11778 + setTimeout(function() { + panel.html(response); + that._trigger('load', event, eventData); + + complete(jqXHR, status); + }, 1); + }) + .fail(function(jqXHR, status) { + // support: jQuery <1.8 + // https://bugs.jquery.com/ticket/11778 + setTimeout(function() { + complete(jqXHR, status); + }, 1); + }); + } + }, + + _ajaxSettings: function(anchor, event, eventData) { + var that = this; + return { + // Support: IE <11 only + // Strip any hash that exists to prevent errors with the Ajax request + url: anchor.attr('href').replace(/#.*$/, ''), + beforeSend: function(jqXHR, settings) { + return that._trigger( + 'beforeLoad', + event, + $.extend({jqXHR: jqXHR, ajaxSettings: settings}, eventData), + ); + }, + }; + }, + + _getPanelForTab: function(tab) { + var id = $(tab).attr('aria-controls'); + return this.element.find(this._sanitizeSelector('#'+id)); + }, + }); + + // DEPRECATED + // TODO: Switch return back to widget declaration at top of file when this is removed + if ($.uiBackCompat !== false) { + // Backcompat for ui-tab class (now ui-tabs-tab) + $.widget('ui.tabs', $.ui.tabs, { + _processTabs: function() { + this._superApply(arguments); + this._addClass(this.tabs, 'ui-tab'); + }, + }); + } + + var widgetsTabs = $.ui.tabs; + + /*! * jQuery UI Tooltip 1.13.3 * https://jqueryui.com * @@ -18568,503 +18962,494 @@ var widgetsTabs = $.ui.tabs; * https://jquery.org/license */ -//>>label: Tooltip -//>>group: Widgets -//>>description: Shows additional information for any element on hover or focus. -//>>docs: https://api.jqueryui.com/tooltip/ -//>>demos: https://jqueryui.com/tooltip/ -//>>css.structure: ../../themes/base/core.css -//>>css.structure: ../../themes/base/tooltip.css -//>>css.theme: ../../themes/base/theme.css - - -$.widget( "ui.tooltip", { - version: "1.13.3", - options: { - classes: { - "ui-tooltip": "ui-corner-all ui-widget-shadow" - }, - content: function() { - var title = $( this ).attr( "title" ); - - // Escape title, since we're going from an attribute to raw HTML - return $( "" ).text( title ).html(); - }, - hide: true, - - // Disabled elements have inconsistent behavior across browsers (#8661) - items: "[title]:not([disabled])", - position: { - my: "left top+15", - at: "left bottom", - collision: "flipfit flip" - }, - show: true, - track: false, - - // Callbacks - close: null, - open: null - }, - - _addDescribedBy: function( elem, id ) { - var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ); - describedby.push( id ); - elem - .data( "ui-tooltip-id", id ) - .attr( "aria-describedby", String.prototype.trim.call( describedby.join( " " ) ) ); - }, - - _removeDescribedBy: function( elem ) { - var id = elem.data( "ui-tooltip-id" ), - describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ), - index = $.inArray( id, describedby ); - - if ( index !== -1 ) { - describedby.splice( index, 1 ); - } - - elem.removeData( "ui-tooltip-id" ); - describedby = String.prototype.trim.call( describedby.join( " " ) ); - if ( describedby ) { - elem.attr( "aria-describedby", describedby ); - } else { - elem.removeAttr( "aria-describedby" ); - } - }, - - _create: function() { - this._on( { - mouseover: "open", - focusin: "open" - } ); - - // IDs of generated tooltips, needed for destroy - this.tooltips = {}; - - // IDs of parent tooltips where we removed the title attribute - this.parents = {}; - - // Append the aria-live region so tooltips announce correctly - this.liveRegion = $( "
" ) - .attr( { - role: "log", - "aria-live": "assertive", - "aria-relevant": "additions" - } ) - .appendTo( this.document[ 0 ].body ); - this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" ); - - this.disabledTitles = $( [] ); - }, - - _setOption: function( key, value ) { - var that = this; - - this._super( key, value ); - - if ( key === "content" ) { - $.each( this.tooltips, function( id, tooltipData ) { - that._updateContent( tooltipData.element ); - } ); - } - }, - - _setOptionDisabled: function( value ) { - this[ value ? "_disable" : "_enable" ](); - }, - - _disable: function() { - var that = this; - - // Close open tooltips - $.each( this.tooltips, function( id, tooltipData ) { - var event = $.Event( "blur" ); - event.target = event.currentTarget = tooltipData.element[ 0 ]; - that.close( event, true ); - } ); - - // Remove title attributes to prevent native tooltips - this.disabledTitles = this.disabledTitles.add( - this.element.find( this.options.items ).addBack() - .filter( function() { - var element = $( this ); - if ( element.is( "[title]" ) ) { - return element - .data( "ui-tooltip-title", element.attr( "title" ) ) - .removeAttr( "title" ); - } - } ) - ); - }, - - _enable: function() { - - // restore title attributes - this.disabledTitles.each( function() { - var element = $( this ); - if ( element.data( "ui-tooltip-title" ) ) { - element.attr( "title", element.data( "ui-tooltip-title" ) ); - } - } ); - this.disabledTitles = $( [] ); - }, - - open: function( event ) { - var that = this, - target = $( event ? event.target : this.element ) - - // we need closest here due to mouseover bubbling, - // but always pointing at the same event target - .closest( this.options.items ); - - // No element to show a tooltip for or the tooltip is already open - if ( !target.length || target.data( "ui-tooltip-id" ) ) { - return; - } - - if ( target.attr( "title" ) ) { - target.data( "ui-tooltip-title", target.attr( "title" ) ); - } - - target.data( "ui-tooltip-open", true ); - - // Kill parent tooltips, custom or native, for hover - if ( event && event.type === "mouseover" ) { - target.parents().each( function() { - var parent = $( this ), - blurEvent; - if ( parent.data( "ui-tooltip-open" ) ) { - blurEvent = $.Event( "blur" ); - blurEvent.target = blurEvent.currentTarget = this; - that.close( blurEvent, true ); - } - if ( parent.attr( "title" ) ) { - parent.uniqueId(); - that.parents[ this.id ] = { - element: this, - title: parent.attr( "title" ) - }; - parent.attr( "title", "" ); - } - } ); - } - - this._registerCloseHandlers( event, target ); - this._updateContent( target, event ); - }, - - _updateContent: function( target, event ) { - var content, - contentOption = this.options.content, - that = this, - eventType = event ? event.type : null; - - if ( typeof contentOption === "string" || contentOption.nodeType || - contentOption.jquery ) { - return this._open( event, target, contentOption ); - } - - content = contentOption.call( target[ 0 ], function( response ) { - - // IE may instantly serve a cached response for ajax requests - // delay this call to _open so the other call to _open runs first - that._delay( function() { - - // Ignore async response if tooltip was closed already - if ( !target.data( "ui-tooltip-open" ) ) { - return; - } - - // JQuery creates a special event for focusin when it doesn't - // exist natively. To improve performance, the native event - // object is reused and the type is changed. Therefore, we can't - // rely on the type being correct after the event finished - // bubbling, so we set it back to the previous value. (#8740) - if ( event ) { - event.type = eventType; - } - this._open( event, target, response ); - } ); - } ); - if ( content ) { - this._open( event, target, content ); - } - }, - - _open: function( event, target, content ) { - var tooltipData, tooltip, delayedShow, a11yContent, - positionOption = $.extend( {}, this.options.position ); - - if ( !content ) { - return; - } - - // Content can be updated multiple times. If the tooltip already - // exists, then just update the content and bail. - tooltipData = this._find( target ); - if ( tooltipData ) { - tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content ); - return; - } - - // If we have a title, clear it to prevent the native tooltip - // we have to check first to avoid defining a title if none exists - // (we don't want to cause an element to start matching [title]) - // - // We use removeAttr only for key events, to allow IE to export the correct - // accessible attributes. For mouse events, set to empty string to avoid - // native tooltip showing up (happens only when removing inside mouseover). - if ( target.is( "[title]" ) ) { - if ( event && event.type === "mouseover" ) { - target.attr( "title", "" ); - } else { - target.removeAttr( "title" ); - } - } - - tooltipData = this._tooltip( target ); - tooltip = tooltipData.tooltip; - this._addDescribedBy( target, tooltip.attr( "id" ) ); - tooltip.find( ".ui-tooltip-content" ).html( content ); - - // Support: Voiceover on OS X, JAWS on IE <= 9 - // JAWS announces deletions even when aria-relevant="additions" - // Voiceover will sometimes re-read the entire log region's contents from the beginning - this.liveRegion.children().hide(); - a11yContent = $( "
" ).html( tooltip.find( ".ui-tooltip-content" ).html() ); - a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" ); - a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" ); - a11yContent.appendTo( this.liveRegion ); - - function position( event ) { - positionOption.of = event; - if ( tooltip.is( ":hidden" ) ) { - return; - } - tooltip.position( positionOption ); - } - if ( this.options.track && event && /^mouse/.test( event.type ) ) { - this._on( this.document, { - mousemove: position - } ); - - // trigger once to override element-relative positioning - position( event ); - } else { - tooltip.position( $.extend( { - of: target - }, this.options.position ) ); - } - - tooltip.hide(); - - this._show( tooltip, this.options.show ); - - // Handle tracking tooltips that are shown with a delay (#8644). As soon - // as the tooltip is visible, position the tooltip using the most recent - // event. - // Adds the check to add the timers only when both delay and track options are set (#14682) - if ( this.options.track && this.options.show && this.options.show.delay ) { - delayedShow = this.delayedShow = setInterval( function() { - if ( tooltip.is( ":visible" ) ) { - position( positionOption.of ); - clearInterval( delayedShow ); - } - }, 13 ); - } - - this._trigger( "open", event, { tooltip: tooltip } ); - }, - - _registerCloseHandlers: function( event, target ) { - var events = { - keyup: function( event ) { - if ( event.keyCode === $.ui.keyCode.ESCAPE ) { - var fakeEvent = $.Event( event ); - fakeEvent.currentTarget = target[ 0 ]; - this.close( fakeEvent, true ); - } - } - }; - - // Only bind remove handler for delegated targets. Non-delegated - // tooltips will handle this in destroy. - if ( target[ 0 ] !== this.element[ 0 ] ) { - events.remove = function() { - var targetElement = this._find( target ); - if ( targetElement ) { - this._removeTooltip( targetElement.tooltip ); - } - }; - } - - if ( !event || event.type === "mouseover" ) { - events.mouseleave = "close"; - } - if ( !event || event.type === "focusin" ) { - events.focusout = "close"; - } - this._on( true, target, events ); - }, - - close: function( event ) { - var tooltip, - that = this, - target = $( event ? event.currentTarget : this.element ), - tooltipData = this._find( target ); - - // The tooltip may already be closed - if ( !tooltipData ) { - - // We set ui-tooltip-open immediately upon open (in open()), but only set the - // additional data once there's actually content to show (in _open()). So even if the - // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in - // the period between open() and _open(). - target.removeData( "ui-tooltip-open" ); - return; - } - - tooltip = tooltipData.tooltip; - - // Disabling closes the tooltip, so we need to track when we're closing - // to avoid an infinite loop in case the tooltip becomes disabled on close - if ( tooltipData.closing ) { - return; - } - - // Clear the interval for delayed tracking tooltips - clearInterval( this.delayedShow ); - - // Only set title if we had one before (see comment in _open()) - // If the title attribute has changed since open(), don't restore - if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) { - target.attr( "title", target.data( "ui-tooltip-title" ) ); - } - - this._removeDescribedBy( target ); - - tooltipData.hiding = true; - tooltip.stop( true ); - this._hide( tooltip, this.options.hide, function() { - that._removeTooltip( $( this ) ); - } ); - - target.removeData( "ui-tooltip-open" ); - this._off( target, "mouseleave focusout keyup" ); - - // Remove 'remove' binding only on delegated targets - if ( target[ 0 ] !== this.element[ 0 ] ) { - this._off( target, "remove" ); - } - this._off( this.document, "mousemove" ); - - if ( event && event.type === "mouseleave" ) { - $.each( this.parents, function( id, parent ) { - $( parent.element ).attr( "title", parent.title ); - delete that.parents[ id ]; - } ); - } - - tooltipData.closing = true; - this._trigger( "close", event, { tooltip: tooltip } ); - if ( !tooltipData.hiding ) { - tooltipData.closing = false; - } - }, - - _tooltip: function( element ) { - var tooltip = $( "
" ).attr( "role", "tooltip" ), - content = $( "
" ).appendTo( tooltip ), - id = tooltip.uniqueId().attr( "id" ); - - this._addClass( content, "ui-tooltip-content" ); - this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" ); - - tooltip.appendTo( this._appendTo( element ) ); - - return this.tooltips[ id ] = { - element: element, - tooltip: tooltip - }; - }, - - _find: function( target ) { - var id = target.data( "ui-tooltip-id" ); - return id ? this.tooltips[ id ] : null; - }, - - _removeTooltip: function( tooltip ) { - - // Clear the interval for delayed tracking tooltips - clearInterval( this.delayedShow ); - - tooltip.remove(); - delete this.tooltips[ tooltip.attr( "id" ) ]; - }, - - _appendTo: function( target ) { - var element = target.closest( ".ui-front, dialog" ); - - if ( !element.length ) { - element = this.document[ 0 ].body; - } - - return element; - }, - - _destroy: function() { - var that = this; - - // Close open tooltips - $.each( this.tooltips, function( id, tooltipData ) { - - // Delegate to close method to handle common cleanup - var event = $.Event( "blur" ), - element = tooltipData.element; - event.target = event.currentTarget = element[ 0 ]; - that.close( event, true ); - - // Remove immediately; destroying an open tooltip doesn't use the - // hide animation - $( "#" + id ).remove(); - - // Restore the title - if ( element.data( "ui-tooltip-title" ) ) { - - // If the title attribute has changed since open(), don't restore - if ( !element.attr( "title" ) ) { - element.attr( "title", element.data( "ui-tooltip-title" ) ); - } - element.removeData( "ui-tooltip-title" ); - } - } ); - this.liveRegion.remove(); - } -} ); - -// DEPRECATED -// TODO: Switch return back to widget declaration at top of file when this is removed -if ( $.uiBackCompat !== false ) { - - // Backcompat for tooltipClass option - $.widget( "ui.tooltip", $.ui.tooltip, { - options: { - tooltipClass: null - }, - _tooltip: function() { - var tooltipData = this._superApply( arguments ); - if ( this.options.tooltipClass ) { - tooltipData.tooltip.addClass( this.options.tooltipClass ); - } - return tooltipData; - } - } ); -} - -var widgetsTooltip = $.ui.tooltip; - - - - -} ); \ No newline at end of file + // >>label: Tooltip + // >>group: Widgets + // >>description: Shows additional information for any element on hover or focus. + // >>docs: https://api.jqueryui.com/tooltip/ + // >>demos: https://jqueryui.com/tooltip/ + // >>css.structure: ../../themes/base/core.css + // >>css.structure: ../../themes/base/tooltip.css + // >>css.theme: ../../themes/base/theme.css + + $.widget('ui.tooltip', { + version: '1.13.3', + options: { + classes: { + 'ui-tooltip': 'ui-corner-all ui-widget-shadow', + }, + content: function() { + var title = $(this).attr('title'); + + // Escape title, since we're going from an attribute to raw HTML + return $('').text(title).html(); + }, + hide: true, + + // Disabled elements have inconsistent behavior across browsers (#8661) + items: '[title]:not([disabled])', + position: { + my: 'left top+15', + at: 'left bottom', + collision: 'flipfit flip', + }, + show: true, + track: false, + + // Callbacks + close: null, + open: null, + }, + + _addDescribedBy: function(elem, id) { + var describedby = (elem.attr('aria-describedby') || '').split(/\s+/); + describedby.push(id); + elem + .data('ui-tooltip-id', id) + .attr('aria-describedby', String.prototype.trim.call(describedby.join(' '))); + }, + + _removeDescribedBy: function(elem) { + var id = elem.data('ui-tooltip-id'), + describedby = (elem.attr('aria-describedby') || '').split(/\s+/), + index = $.inArray(id, describedby); + + if (index !== -1) { + describedby.splice(index, 1); + } + + elem.removeData('ui-tooltip-id'); + describedby = String.prototype.trim.call(describedby.join(' ')); + if (describedby) { + elem.attr('aria-describedby', describedby); + } else { + elem.removeAttr('aria-describedby'); + } + }, + + _create: function() { + this._on({ + mouseover: 'open', + focusin: 'open', + }); + + // IDs of generated tooltips, needed for destroy + this.tooltips = {}; + + // IDs of parent tooltips where we removed the title attribute + this.parents = {}; + + // Append the aria-live region so tooltips announce correctly + this.liveRegion = $('
') + .attr({ + role: 'log', + 'aria-live': 'assertive', + 'aria-relevant': 'additions', + }) + .appendTo(this.document[0].body); + this._addClass(this.liveRegion, null, 'ui-helper-hidden-accessible'); + + this.disabledTitles = $([]); + }, + + _setOption: function(key, value) { + var that = this; + + this._super(key, value); + + if (key === 'content') { + $.each(this.tooltips, function(id, tooltipData) { + that._updateContent(tooltipData.element); + }); + } + }, + + _setOptionDisabled: function(value) { + this[value ? '_disable' : '_enable'](); + }, + + _disable: function() { + var that = this; + + // Close open tooltips + $.each(this.tooltips, function(id, tooltipData) { + var event = $.Event('blur'); + event.target = event.currentTarget = tooltipData.element[0]; + that.close(event, true); + }); + + // Remove title attributes to prevent native tooltips + this.disabledTitles = this.disabledTitles.add( + this.element.find(this.options.items).addBack() + .filter(function() { + var element = $(this); + if (element.is('[title]')) { + return element + .data('ui-tooltip-title', element.attr('title')) + .removeAttr('title'); + } + }), + ); + }, + + _enable: function() { + // restore title attributes + this.disabledTitles.each(function() { + var element = $(this); + if (element.data('ui-tooltip-title')) { + element.attr('title', element.data('ui-tooltip-title')); + } + }); + this.disabledTitles = $([]); + }, + + open: function(event) { + var that = this, + target = $(event ? event.target : this.element) + // we need closest here due to mouseover bubbling, + // but always pointing at the same event target + .closest(this.options.items); + + // No element to show a tooltip for or the tooltip is already open + if (!target.length || target.data('ui-tooltip-id')) { + return; + } + + if (target.attr('title')) { + target.data('ui-tooltip-title', target.attr('title')); + } + + target.data('ui-tooltip-open', true); + + // Kill parent tooltips, custom or native, for hover + if (event && event.type === 'mouseover') { + target.parents().each(function() { + var parent = $(this), + blurEvent; + if (parent.data('ui-tooltip-open')) { + blurEvent = $.Event('blur'); + blurEvent.target = blurEvent.currentTarget = this; + that.close(blurEvent, true); + } + if (parent.attr('title')) { + parent.uniqueId(); + that.parents[this.id] = { + element: this, + title: parent.attr('title'), + }; + parent.attr('title', ''); + } + }); + } + + this._registerCloseHandlers(event, target); + this._updateContent(target, event); + }, + + _updateContent: function(target, event) { + var content, + contentOption = this.options.content, + that = this, + eventType = event ? event.type : null; + + if ( + typeof contentOption === 'string' || contentOption.nodeType + || contentOption.jquery + ) { + return this._open(event, target, contentOption); + } + + content = contentOption.call(target[0], function(response) { + // IE may instantly serve a cached response for ajax requests + // delay this call to _open so the other call to _open runs first + that._delay(function() { + // Ignore async response if tooltip was closed already + if (!target.data('ui-tooltip-open')) { + return; + } + + // JQuery creates a special event for focusin when it doesn't + // exist natively. To improve performance, the native event + // object is reused and the type is changed. Therefore, we can't + // rely on the type being correct after the event finished + // bubbling, so we set it back to the previous value. (#8740) + if (event) { + event.type = eventType; + } + this._open(event, target, response); + }); + }); + if (content) { + this._open(event, target, content); + } + }, + + _open: function(event, target, content) { + var tooltipData, + tooltip, + delayedShow, + a11yContent, + positionOption = $.extend({}, this.options.position); + + if (!content) { + return; + } + + // Content can be updated multiple times. If the tooltip already + // exists, then just update the content and bail. + tooltipData = this._find(target); + if (tooltipData) { + tooltipData.tooltip.find('.ui-tooltip-content').html(content); + return; + } + + // If we have a title, clear it to prevent the native tooltip + // we have to check first to avoid defining a title if none exists + // (we don't want to cause an element to start matching [title]) + // + // We use removeAttr only for key events, to allow IE to export the correct + // accessible attributes. For mouse events, set to empty string to avoid + // native tooltip showing up (happens only when removing inside mouseover). + if (target.is('[title]')) { + if (event && event.type === 'mouseover') { + target.attr('title', ''); + } else { + target.removeAttr('title'); + } + } + + tooltipData = this._tooltip(target); + tooltip = tooltipData.tooltip; + this._addDescribedBy(target, tooltip.attr('id')); + tooltip.find('.ui-tooltip-content').html(content); + + // Support: Voiceover on OS X, JAWS on IE <= 9 + // JAWS announces deletions even when aria-relevant="additions" + // Voiceover will sometimes re-read the entire log region's contents from the beginning + this.liveRegion.children().hide(); + a11yContent = $('
').html(tooltip.find('.ui-tooltip-content').html()); + a11yContent.removeAttr('name').find('[name]').removeAttr('name'); + a11yContent.removeAttr('id').find('[id]').removeAttr('id'); + a11yContent.appendTo(this.liveRegion); + + function position(event) { + positionOption.of = event; + if (tooltip.is(':hidden')) { + return; + } + tooltip.position(positionOption); + } + if (this.options.track && event && /^mouse/.test(event.type)) { + this._on(this.document, { + mousemove: position, + }); + + // trigger once to override element-relative positioning + position(event); + } else { + tooltip.position($.extend({ + of: target, + }, this.options.position)); + } + + tooltip.hide(); + + this._show(tooltip, this.options.show); + + // Handle tracking tooltips that are shown with a delay (#8644). As soon + // as the tooltip is visible, position the tooltip using the most recent + // event. + // Adds the check to add the timers only when both delay and track options are set (#14682) + if (this.options.track && this.options.show && this.options.show.delay) { + delayedShow = this.delayedShow = setInterval(function() { + if (tooltip.is(':visible')) { + position(positionOption.of); + clearInterval(delayedShow); + } + }, 13); + } + + this._trigger('open', event, {tooltip: tooltip}); + }, + + _registerCloseHandlers: function(event, target) { + var events = { + keyup: function(event) { + if (event.keyCode === $.ui.keyCode.ESCAPE) { + var fakeEvent = $.Event(event); + fakeEvent.currentTarget = target[0]; + this.close(fakeEvent, true); + } + }, + }; + + // Only bind remove handler for delegated targets. Non-delegated + // tooltips will handle this in destroy. + if (target[0] !== this.element[0]) { + events.remove = function() { + var targetElement = this._find(target); + if (targetElement) { + this._removeTooltip(targetElement.tooltip); + } + }; + } + + if (!event || event.type === 'mouseover') { + events.mouseleave = 'close'; + } + if (!event || event.type === 'focusin') { + events.focusout = 'close'; + } + this._on(true, target, events); + }, + + close: function(event) { + var tooltip, + that = this, + target = $(event ? event.currentTarget : this.element), + tooltipData = this._find(target); + + // The tooltip may already be closed + if (!tooltipData) { + // We set ui-tooltip-open immediately upon open (in open()), but only set the + // additional data once there's actually content to show (in _open()). So even if the + // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in + // the period between open() and _open(). + target.removeData('ui-tooltip-open'); + return; + } + + tooltip = tooltipData.tooltip; + + // Disabling closes the tooltip, so we need to track when we're closing + // to avoid an infinite loop in case the tooltip becomes disabled on close + if (tooltipData.closing) { + return; + } + + // Clear the interval for delayed tracking tooltips + clearInterval(this.delayedShow); + + // Only set title if we had one before (see comment in _open()) + // If the title attribute has changed since open(), don't restore + if (target.data('ui-tooltip-title') && !target.attr('title')) { + target.attr('title', target.data('ui-tooltip-title')); + } + + this._removeDescribedBy(target); + + tooltipData.hiding = true; + tooltip.stop(true); + this._hide(tooltip, this.options.hide, function() { + that._removeTooltip($(this)); + }); + + target.removeData('ui-tooltip-open'); + this._off(target, 'mouseleave focusout keyup'); + + // Remove 'remove' binding only on delegated targets + if (target[0] !== this.element[0]) { + this._off(target, 'remove'); + } + this._off(this.document, 'mousemove'); + + if (event && event.type === 'mouseleave') { + $.each(this.parents, function(id, parent) { + $(parent.element).attr('title', parent.title); + delete that.parents[id]; + }); + } + + tooltipData.closing = true; + this._trigger('close', event, {tooltip: tooltip}); + if (!tooltipData.hiding) { + tooltipData.closing = false; + } + }, + + _tooltip: function(element) { + var tooltip = $('
').attr('role', 'tooltip'), + content = $('
').appendTo(tooltip), + id = tooltip.uniqueId().attr('id'); + + this._addClass(content, 'ui-tooltip-content'); + this._addClass(tooltip, 'ui-tooltip', 'ui-widget ui-widget-content'); + + tooltip.appendTo(this._appendTo(element)); + + return this.tooltips[id] = { + element: element, + tooltip: tooltip, + }; + }, + + _find: function(target) { + var id = target.data('ui-tooltip-id'); + return id ? this.tooltips[id] : null; + }, + + _removeTooltip: function(tooltip) { + // Clear the interval for delayed tracking tooltips + clearInterval(this.delayedShow); + + tooltip.remove(); + delete this.tooltips[tooltip.attr('id')]; + }, + + _appendTo: function(target) { + var element = target.closest('.ui-front, dialog'); + + if (!element.length) { + element = this.document[0].body; + } + + return element; + }, + + _destroy: function() { + var that = this; + + // Close open tooltips + $.each(this.tooltips, function(id, tooltipData) { + // Delegate to close method to handle common cleanup + var event = $.Event('blur'), + element = tooltipData.element; + event.target = event.currentTarget = element[0]; + that.close(event, true); + + // Remove immediately; destroying an open tooltip doesn't use the + // hide animation + $('#'+id).remove(); + + // Restore the title + if (element.data('ui-tooltip-title')) { + // If the title attribute has changed since open(), don't restore + if (!element.attr('title')) { + element.attr('title', element.data('ui-tooltip-title')); + } + element.removeData('ui-tooltip-title'); + } + }); + this.liveRegion.remove(); + }, + }); + + // DEPRECATED + // TODO: Switch return back to widget declaration at top of file when this is removed + if ($.uiBackCompat !== false) { + // Backcompat for tooltipClass option + $.widget('ui.tooltip', $.ui.tooltip, { + options: { + tooltipClass: null, + }, + _tooltip: function() { + var tooltipData = this._superApply(arguments); + if (this.options.tooltipClass) { + tooltipData.tooltip.addClass(this.options.tooltipClass); + } + return tooltipData; + }, + }); + } + + var widgetsTooltip = $.ui.tooltip; +}); diff --git a/web/js/jquery.js b/web/js/jquery.js index b86de89a..d7256269 100644 --- a/web/js/jquery.js +++ b/web/js/jquery.js @@ -11,517 +11,504 @@ * * Date: 2022-12-20T21:28Z */ -( function( global, factory ) { - - "use strict"; - - if ( typeof module === "object" && typeof module.exports === "object" ) { - - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket trac-14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 -// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode -// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common -// enough that all such attempts are guarded in a try block. -"use strict"; - -var arr = []; - -var getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var flat = arr.flat ? function( array ) { - return arr.flat.call( array ); -} : function( array ) { - return arr.concat.apply( [], array ); -}; - - -var push = arr.push; - -var indexOf = arr.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var fnToString = hasOwn.toString; - -var ObjectFunctionString = fnToString.call( Object ); - -var support = {}; - -var isFunction = function isFunction( obj ) { - - // Support: Chrome <=57, Firefox <=52 - // In some browsers, typeof returns "function" for HTML elements - // (i.e., `typeof document.createElement( "object" ) === "function"`). - // We don't want to classify *any* DOM node as a function. - // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 - // Plus for old WebKit, typeof returns "function" for HTML collections - // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) - return typeof obj === "function" && typeof obj.nodeType !== "number" && - typeof obj.item !== "function"; - }; - - -var isWindow = function isWindow( obj ) { - return obj != null && obj === obj.window; - }; - - -var document = window.document; - - - - var preservedScriptAttributes = { - type: true, - src: true, - nonce: true, - noModule: true - }; - - function DOMEval( code, node, doc ) { - doc = doc || document; - - var i, val, - script = doc.createElement( "script" ); - - script.text = code; - if ( node ) { - for ( i in preservedScriptAttributes ) { - - // Support: Firefox 64+, Edge 18+ - // Some browsers don't support the "nonce" property on scripts. - // On the other hand, just using `getAttribute` is not enough as - // the `nonce` attribute is reset to an empty string whenever it - // becomes browsing-context connected. - // See https://github.com/whatwg/html/issues/2369 - // See https://html.spec.whatwg.org/#nonce-attributes - // The `node.getAttribute` check was added for the sake of - // `jQuery.globalEval` so that it can fake a nonce-containing node - // via an object. - val = node[ i ] || node.getAttribute && node.getAttribute( i ); - if ( val ) { - script.setAttribute( i, val ); - } - } - } - doc.head.appendChild( script ).parentNode.removeChild( script ); - } - - -function toType( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; -} -/* global Symbol */ -// Defining this global in .eslintrc.json would create a danger of using the global -// unguarded in another place, it seems safer to define global only for this module - - - -var - version = "3.6.3", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - - // Return all the elements in a clean array - if ( num == null ) { - return slice.call( this ); - } - - // Return just the one element from the set - return num < 0 ? this[ num + this.length ] : this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - even: function() { - return this.pushStack( jQuery.grep( this, function( _elem, i ) { - return ( i + 1 ) % 2; - } ) ); - }, - - odd: function() { - return this.pushStack( jQuery.grep( this, function( _elem, i ) { - return i % 2; - } ) ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: arr.sort, - splice: arr.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // Skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !isFunction( target ) ) { - target = {}; - } - - // Extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - copy = options[ name ]; - - // Prevent Object.prototype pollution - // Prevent never-ending loop - if ( name === "__proto__" || target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = Array.isArray( copy ) ) ) ) { - src = target[ name ]; - - // Ensure proper type for the source value - if ( copyIsArray && !Array.isArray( src ) ) { - clone = []; - } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { - clone = {}; - } else { - clone = src; - } - copyIsArray = false; - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - isPlainObject: function( obj ) { - var proto, Ctor; - - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if ( !obj || toString.call( obj ) !== "[object Object]" ) { - return false; - } - - proto = getProto( obj ); - - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if ( !proto ) { - return true; - } - - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; - return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; - }, - - isEmptyObject: function( obj ) { - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - // Evaluates a script in a provided context; falls back to the global one - // if not specified. - globalEval: function( code, options, doc ) { - DOMEval( code, { nonce: options && options.nonce }, doc ); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : indexOf.call( arr, elem, i ); - }, - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - for ( ; j < len; j++ ) { - first[ i++ ] = second[ j ]; - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return flat( ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; -} - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), - function( _i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); - } ); - -function isArrayLike( obj ) { - - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = toType( obj ); - - if ( isFunction( obj ) || isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! +(function(global, factory) { + 'use strict'; + + if (typeof module === 'object' && typeof module.exports === 'object') { + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket trac-14549 for more info. + module.exports = global.document + ? factory(global, true) + : function(w) { + if (!w.document) { + throw new Error('jQuery requires a window with a document'); + } + return factory(w); + }; + } else { + factory(global); + } + + // Pass this if window is not defined yet +})(typeof window !== 'undefined' ? window : this, function(window, noGlobal) { + // Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 + // throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode + // arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common + // enough that all such attempts are guarded in a try block. + 'use strict'; + + var arr = []; + + var getProto = Object.getPrototypeOf; + + var slice = arr.slice; + + var flat = arr.flat + ? function(array) { + return arr.flat.call(array); + } + : function(array) { + return arr.concat.apply([], array); + }; + + var push = arr.push; + + var indexOf = arr.indexOf; + + var class2type = {}; + + var toString = class2type.toString; + + var hasOwn = class2type.hasOwnProperty; + + var fnToString = hasOwn.toString; + + var ObjectFunctionString = fnToString.call(Object); + + var support = {}; + + var isFunction = function isFunction(obj) { + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === 'function' && typeof obj.nodeType !== 'number' + && typeof obj.item !== 'function'; + }; + + var isWindow = function isWindow(obj) { + return obj != null && obj === obj.window; + }; + + var document = window.document; + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true, + }; + + function DOMEval(code, node, doc) { + doc = doc || document; + + var i, val, script = doc.createElement('script'); + + script.text = code; + if (node) { + for (i in preservedScriptAttributes) { + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[i] || node.getAttribute && node.getAttribute(i); + if (val) { + script.setAttribute(i, val); + } + } + } + doc.head.appendChild(script).parentNode.removeChild(script); + } + + function toType(obj) { + if (obj == null) { + return obj+''; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === 'object' || typeof obj === 'function' + ? class2type[toString.call(obj)] || 'object' + : typeof obj; + } + /* global Symbol */ + // Defining this global in .eslintrc.json would create a danger of using the global + // unguarded in another place, it seems safer to define global only for this module + + var version = '3.6.3', + // Define a local copy of jQuery + jQuery = function(selector, context) { + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init(selector, context); + }; + + jQuery.fn = jQuery.prototype = { + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call(this); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function(num) { + // Return all the elements in a clean array + if (num == null) { + return slice.call(this); + } + + // Return just the one element from the set + return num < 0 ? this[num+this.length] : this[num]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function(elems) { + // Build a new jQuery matched element set + var ret = jQuery.merge(this.constructor(), elems); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function(callback) { + return jQuery.each(this, callback); + }, + + map: function(callback) { + return this.pushStack(jQuery.map(this, function(elem, i) { + return callback.call(elem, i, elem); + })); + }, + + slice: function() { + return this.pushStack(slice.apply(this, arguments)); + }, + + first: function() { + return this.eq(0); + }, + + last: function() { + return this.eq(-1); + }, + + even: function() { + return this.pushStack(jQuery.grep(this, function(_elem, i) { + return (i+1)%2; + })); + }, + + odd: function() { + return this.pushStack(jQuery.grep(this, function(_elem, i) { + return i%2; + })); + }, + + eq: function(i) { + var len = this.length, + j = +i+(i < 0 ? len : 0); + return this.pushStack(j >= 0 && j < len ? [this[j]] : []); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice, + }; + + jQuery.extend = jQuery.fn.extend = function() { + var options, + name, + src, + copy, + copyIsArray, + clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if (typeof target === 'boolean') { + deep = target; + + // Skip the boolean and the target + target = arguments[i] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if (typeof target !== 'object' && !isFunction(target)) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if (i === length) { + target = this; + i--; + } + + for (; i < length; i++) { + // Only deal with non-null/undefined values + if ((options = arguments[i]) != null) { + // Extend the base object + for (name in options) { + copy = options[name]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if (name === '__proto__' || target === copy) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( + deep && copy && (jQuery.isPlainObject(copy) + || (copyIsArray = Array.isArray(copy))) + ) { + src = target[name]; + + // Ensure proper type for the source value + if (copyIsArray && !Array.isArray(src)) { + clone = []; + } else if (!copyIsArray && !jQuery.isPlainObject(src)) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[name] = jQuery.extend(deep, clone, copy); + + // Don't bring in undefined values + } else if (copy !== undefined) { + target[name] = copy; + } + } + } + } + + // Return the modified object + return target; + }; + + jQuery.extend({ + // Unique for each copy of jQuery on the page + expando: 'jQuery'+(version+Math.random()).replace(/\D/g, ''), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function(msg) { + throw new Error(msg); + }, + + noop: function() {}, + + isPlainObject: function(obj) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if (!obj || toString.call(obj) !== '[object Object]') { + return false; + } + + proto = getProto(obj); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if (!proto) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call(proto, 'constructor') && proto.constructor; + return typeof Ctor === 'function' && fnToString.call(Ctor) === ObjectFunctionString; + }, + + isEmptyObject: function(obj) { + var name; + + for (name in obj) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function(code, options, doc) { + DOMEval(code, {nonce: options && options.nonce}, doc); + }, + + each: function(obj, callback) { + var length, i = 0; + + if (isArrayLike(obj)) { + length = obj.length; + for (; i < length; i++) { + if (callback.call(obj[i], i, obj[i]) === false) { + break; + } + } + } else { + for (i in obj) { + if (callback.call(obj[i], i, obj[i]) === false) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function(arr, results) { + var ret = results || []; + + if (arr != null) { + if (isArrayLike(Object(arr))) { + jQuery.merge( + ret, + typeof arr === 'string' + ? [arr] + : arr, + ); + } else { + push.call(ret, arr); + } + } + + return ret; + }, + + inArray: function(elem, arr, i) { + return arr == null ? -1 : indexOf.call(arr, elem, i); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function(first, second) { + var len = +second.length, + j = 0, + i = first.length; + + for (; j < len; j++) { + first[i++] = second[j]; + } + + first.length = i; + + return first; + }, + + grep: function(elems, callback, invert) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for (; i < length; i++) { + callbackInverse = !callback(elems[i], i); + if (callbackInverse !== callbackExpect) { + matches.push(elems[i]); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function(elems, callback, arg) { + var length, value, i = 0, ret = []; + + // Go through the array, translating each of the items to their new values + if (isArrayLike(elems)) { + length = elems.length; + for (; i < length; i++) { + value = callback(elems[i], i, arg); + + if (value != null) { + ret.push(value); + } + } + + // Go through every key on the object, + } else { + for (i in elems) { + value = callback(elems[i], i, arg); + + if (value != null) { + ret.push(value); + } + } + } + + // Flatten any nested arrays + return flat(ret); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support, + }); + + if (typeof Symbol === 'function') { + jQuery.fn[Symbol.iterator] = arr[Symbol.iterator]; + } + + // Populate the class2type map + jQuery.each( + 'Boolean Number String Function Array Date RegExp Object Error Symbol'.split(' '), + function(_i, name) { + class2type['[object '+name+']'] = name.toLowerCase(); + }, + ); + + function isArrayLike(obj) { + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && 'length' in obj && obj.length, + type = toType(obj); + + if (isFunction(obj) || isWindow(obj)) { + return false; + } + + return type === 'array' || length === 0 + || typeof length === 'number' && length > 0 && (length-1) in obj; + } + var Sizzle = + /*! * Sizzle CSS Selector Engine v2.3.9 * https://sizzlejs.com/ * @@ -531,1331 +518,1305 @@ var Sizzle = * * Date: 2022-12-19 */ -( function( window ) { -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - nonnativeSelectorCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // Instance methods - hasOwn = ( {} ).hasOwnProperty, - arr = [], - pop = arr.pop, - pushNative = arr.push, - push = arr.push, - slice = arr.slice, - - // Use a stripped-down indexOf as it's faster than native - // https://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[ i ] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + - "ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - - // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram - identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + - "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - - // "Attribute values must be CSS identifiers [capture 5] - // or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + - whitespace + "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + - whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + - "*" ), - rdescend = new RegExp( whitespace + "|>" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + identifier + ")" ), - "CLASS": new RegExp( "^\\.(" + identifier + ")" ), - "TAG": new RegExp( "^(" + identifier + "|[*])" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + - whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + - whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + - "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + - "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rhtml = /HTML$/i, - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - - // CSS escapes - // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), - funescape = function( escape, nonHex ) { - var high = "0x" + escape.slice( 1 ) - 0x10000; - - return nonHex ? - - // Strip the backslash prefix from a non-hex escape sequence - nonHex : - - // Replace a hexadecimal escape sequence with the encoded Unicode code point - // Support: IE <=11+ - // For values outside the Basic Multilingual Plane (BMP), manually construct a - // surrogate pair - high < 0 ? - String.fromCharCode( high + 0x10000 ) : - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // CSS string/identifier serialization - // https://drafts.csswg.org/cssom/#common-serializing-idioms - rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, - fcssescape = function( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + - ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; - } - - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; - }, - - // Used for iframes - // See setDocument() - // Removing the function wrapper causes a "Permission Denied" - // error in IE - unloadHandler = function() { - setDocument(); - }, - - inDisabledFieldset = addCombinator( - function( elem ) { - return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; - }, - { dir: "parentNode", next: "legend" } - ); - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - ( arr = slice.call( preferredDoc.childNodes ) ), - preferredDoc.childNodes - ); - - // Support: Android<4.0 - // Detect silently failing push.apply - // eslint-disable-next-line no-unused-expressions - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - pushNative.apply( target, slice.call( els ) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - - // Can't trust NodeList.length - while ( ( target[ j++ ] = els[ i++ ] ) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var m, i, elem, nid, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - setDocument( context ); - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { - - // ID selector - if ( ( m = match[ 1 ] ) ) { - - // Document context - if ( nodeType === 9 ) { - if ( ( elem = context.getElementById( m ) ) ) { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( newContext && ( elem = newContext.getElementById( m ) ) && - contains( context, elem ) && - elem.id === m ) { - - results.push( elem ); - return results; - } - } - - // Type selector - } else if ( match[ 2 ] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && - context.getElementsByClassName ) { - - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( support.qsa && - !nonnativeSelectorCache[ selector + " " ] && - ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && - - // Support: IE 8 only - // Exclude object elements - ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { - - newSelector = selector; - newContext = context; - - // qSA considers elements outside a scoping root when evaluating child or - // descendant combinators, which is not what we want. - // In such cases, we work around the behavior by prefixing every selector in the - // list with an ID selector referencing the scope context. - // The technique has to be used as well when a leading combinator is used - // as such selectors are not recognized by querySelectorAll. - // Thanks to Andrew Dupont for this technique. - if ( nodeType === 1 && - ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - - // We can use :scope instead of the ID hack if the browser - // supports it & if we're not changing the context. - if ( newContext !== context || !support.scope ) { - - // Capture the context ID, setting it first if necessary - if ( ( nid = context.getAttribute( "id" ) ) ) { - nid = nid.replace( rcssescape, fcssescape ); - } else { - context.setAttribute( "id", ( nid = expando ) ); - } - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - while ( i-- ) { - groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + - toSelector( groups[ i ] ); - } - newSelector = groups.join( "," ); - } - - try { - - // `qSA` may not throw for unrecognized parts using forgiving parsing: - // https://drafts.csswg.org/selectors/#forgiving-selector - // like the `:has()` pseudo-class: - // https://drafts.csswg.org/selectors/#relational - // `CSS.supports` is still expected to return `false` then: - // https://drafts.csswg.org/css-conditional-4/#typedef-supports-selector-fn - // https://drafts.csswg.org/css-conditional-4/#dfn-support-selector - if ( support.cssSupportsSelector && - - // eslint-disable-next-line no-undef - !CSS.supports( "selector(:is(" + newSelector + "))" ) ) { - - // Support: IE 11+ - // Throw to get to the same code path as an error directly in qSA. - // Note: once we only support browser supporting - // `CSS.supports('selector(...)')`, we can most likely drop - // the `try-catch`. IE doesn't implement the API. - throw new Error(); - } - - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - nonnativeSelectorCache( selector, true ); - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return ( cache[ key + " " ] = value ); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ -function assert( fn ) { - var el = document.createElement( "fieldset" ); - - try { - return !!fn( el ); - } catch ( e ) { - return false; - } finally { - - // Remove from its parent by default - if ( el.parentNode ) { - el.parentNode.removeChild( el ); - } - - // release memory in IE - el = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split( "|" ), - i = arr.length; - - while ( i-- ) { - Expr.attrHandle[ arr[ i ] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - a.sourceIndex - b.sourceIndex; - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( ( cur = cur.nextSibling ) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return ( name === "input" || name === "button" ) && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ -function createDisabledPseudo( disabled ) { - - // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function( elem ) { - - // Only certain elements can match :enabled or :disabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled - if ( "form" in elem ) { - - // Check for inherited disabledness on relevant non-disabled elements: - // * listed form-associated elements in a disabled fieldset - // https://html.spec.whatwg.org/multipage/forms.html#category-listed - // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled - // * option elements in a disabled optgroup - // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled - // All such elements have a "form" property. - if ( elem.parentNode && elem.disabled === false ) { - - // Option elements defer to a parent optgroup if present - if ( "label" in elem ) { - if ( "label" in elem.parentNode ) { - return elem.parentNode.disabled === disabled; - } else { - return elem.disabled === disabled; - } - } - - // Support: IE 6 - 11 - // Use the isDisabled shortcut property to check for disabled fieldset ancestors - return elem.isDisabled === disabled || - - // Where there is no isDisabled, check manually - /* jshint -W018 */ - elem.isDisabled !== !disabled && - inDisabledFieldset( elem ) === disabled; - } - - return elem.disabled === disabled; - - // Try to winnow out elements that can't be disabled before trusting the disabled property. - // Some victims get caught in our net (label, legend, menu, track), but it shouldn't - // even exist on them, let alone have a boolean value. - } else if ( "label" in elem ) { - return elem.disabled === disabled; - } - - // Remaining elements are neither :enabled nor :disabled - return false; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction( function( argument ) { - argument = +argument; - return markFunction( function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ ( j = matchIndexes[ i ] ) ] ) { - seed[ j ] = !( matches[ j ] = seed[ j ] ); - } - } - } ); - } ); -} - -/** - * Checks a node for validity as a Sizzle context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - var namespace = elem && elem.namespaceURI, - docElem = elem && ( elem.ownerDocument || elem ).documentElement; - - // Support: IE <=8 - // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes - // https://bugs.jquery.com/ticket/4833 - return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, subWindow, - doc = node ? node.ownerDocument || node : preferredDoc; - - // Return early if doc is invalid or already selected - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Update global variables - document = doc; - docElem = document.documentElement; - documentIsHTML = !isXML( document ); - - // Support: IE 9 - 11+, Edge 12 - 18+ - // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( preferredDoc != document && - ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { - - // Support: IE 11, Edge - if ( subWindow.addEventListener ) { - subWindow.addEventListener( "unload", unloadHandler, false ); - - // Support: IE 9 - 10 only - } else if ( subWindow.attachEvent ) { - subWindow.attachEvent( "onunload", unloadHandler ); - } - } - - // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, - // Safari 4 - 5 only, Opera <=11.6 - 12.x only - // IE/Edge & older browsers don't support the :scope pseudo-class. - // Support: Safari 6.0 only - // Safari 6.0 supports :scope but it's an alias of :root there. - support.scope = assert( function( el ) { - docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); - return typeof el.querySelectorAll !== "undefined" && - !el.querySelectorAll( ":scope fieldset div" ).length; - } ); - - // Support: Chrome 105+, Firefox 104+, Safari 15.4+ - // Make sure forgiving mode is not used in `CSS.supports( "selector(...)" )`. - // - // `:is()` uses a forgiving selector list as an argument and is widely - // implemented, so it's a good one to test against. - support.cssSupportsSelector = assert( function() { - /* eslint-disable no-undef */ - - return CSS.supports( "selector(*)" ) && - - // Support: Firefox 78-81 only - // In old Firefox, `:is()` didn't use forgiving parsing. In that case, - // fail this test as there's no selector to test against that. - // `CSS.supports` uses unforgiving parsing - document.querySelectorAll( ":is(:jqfake)" ) && - - // `*` is needed as Safari & newer Chrome implemented something in between - // for `:has()` - it throws in `qSA` if it only contains an unsupported - // argument but multiple ones, one of which is supported, are fine. - // We want to play safe in case `:is()` gets the same treatment. - !CSS.supports( "selector(:is(*,:jqfake))" ); - - /* eslint-enable */ - } ); - - /* Attributes + (function(window) { + var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + // Instance-specific data + expando = 'sizzle'+1*new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function(a, b) { + if (a === b) { + hasDuplicate = true; + } + return 0; + }, + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function(list, elem) { + var i = 0, + len = list.length; + for (; i < len; i++) { + if (list[i] === elem) { + return i; + } + } + return -1; + }, + booleans = + 'checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|' + +'ismap|loop|multiple|open|readonly|required|scoped', + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = '[\\x20\\t\\r\\n\\f]', + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = '(?:\\\\[\\da-fA-F]{1,6}'+whitespace + +'?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+', + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = '\\['+whitespace+'*('+identifier+')(?:'+whitespace + // Operator (capture 2) + +'*([*^$|!~]?=)'+whitespace + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + +'*(?:\'((?:\\\\.|[^\\\\\'])*)\'|"((?:\\\\.|[^\\\\"])*)"|('+identifier+'))|)' + +whitespace+'*\\]', + pseudos = ':('+identifier+')(?:\\((' + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + +'(\'((?:\\\\.|[^\\\\\'])*)\'|"((?:\\\\.|[^\\\\"])*)")|' + // 2. simple (capture 6) + +'((?:\\\\.|[^\\\\()[\\]]|'+attributes+')*)|' + // 3. anything else (capture 2) + +'.*' + +')\\)|)', + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp(whitespace+'+', 'g'), + rtrim = new RegExp( + '^'+whitespace+'+|((?:^|[^\\\\])(?:\\\\.)*)' + +whitespace+'+$', + 'g', + ), + rcomma = new RegExp('^'+whitespace+'*,'+whitespace+'*'), + rcombinators = new RegExp( + '^'+whitespace+'*([>+~]|'+whitespace+')'+whitespace + +'*', + ), + rdescend = new RegExp(whitespace+'|>'), + rpseudo = new RegExp(pseudos), + ridentifier = new RegExp('^'+identifier+'$'), + matchExpr = { + 'ID': new RegExp('^#('+identifier+')'), + 'CLASS': new RegExp('^\\.('+identifier+')'), + 'TAG': new RegExp('^('+identifier+'|[*])'), + 'ATTR': new RegExp('^'+attributes), + 'PSEUDO': new RegExp('^'+pseudos), + 'CHILD': new RegExp( + '^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(' + +whitespace+'*(even|odd|(([+-]|)(\\d*)n|)'+whitespace+'*(?:([+-]|)' + +whitespace+'*(\\d+)|))'+whitespace+'*\\)|)', + 'i', + ), + 'bool': new RegExp('^(?:'+booleans+')$', 'i'), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + 'needsContext': new RegExp( + '^'+whitespace + +'*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\('+whitespace + +'*((?:-\\d)?\\d*)'+whitespace+'*\\)|)(?=[^-]|$)', + 'i', + ), + }, + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + rnative = /^[^{]+\{\s*\[native \w/, + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + rsibling = /[+~]/, + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( + '\\\\[\\da-fA-F]{1,6}'+whitespace+'?|\\\\([^\\r\\n\\f])', + 'g', + ), + funescape = function(escape, nonHex) { + var high = '0x'+escape.slice(1)-0x10000; + + return nonHex + // Strip the backslash prefix from a non-hex escape sequence + ? nonHex + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + : high < 0 + ? String.fromCharCode(high+0x10000) + : String.fromCharCode(high>>10|0xD800, high&0x3FF|0xDC00); + }, + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function(ch, asCodePoint) { + if (asCodePoint) { + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if (ch === '\0') { + return '\uFFFD'; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice(0, -1)+'\\' + +ch.charCodeAt(ch.length-1).toString(16)+' '; + } + + // Other potentially-special ASCII characters get backslash-escaped + return '\\'+ch; + }, + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + inDisabledFieldset = addCombinator( + function(elem) { + return elem.disabled === true && elem.nodeName.toLowerCase() === 'fieldset'; + }, + {dir: 'parentNode', next: 'legend'}, + ); + + // Optimize for push.apply( _, NodeList ) + try { + push.apply( + arr = slice.call(preferredDoc.childNodes), + preferredDoc.childNodes, + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[preferredDoc.childNodes.length].nodeType; + } catch (e) { + push = { + apply: arr.length + // Leverage slice if possible + ? function(target, els) { + pushNative.apply(target, slice.call(els)); + } + // Support: IE<9 + // Otherwise append directly + : function(target, els) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ((target[j++] = els[i++])) {} + target.length = j-1; + }, + }; + } + + function Sizzle(selector, context, results, seed) { + var m, + i, + elem, + nid, + match, + groups, + newSelector, + newContext = context && context.ownerDocument, + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( + typeof selector !== 'string' || !selector + || nodeType !== 1 && nodeType !== 9 && nodeType !== 11 + ) { + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if (!seed) { + setDocument(context); + context = context || document; + + if (documentIsHTML) { + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if (nodeType !== 11 && (match = rquickExpr.exec(selector))) { + // ID selector + if ((m = match[1])) { + // Document context + if (nodeType === 9) { + if ((elem = context.getElementById(m))) { + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if (elem.id === m) { + results.push(elem); + return results; + } + } else { + return results; + } + + // Element context + } else { + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( + newContext && (elem = newContext.getElementById(m)) + && contains(context, elem) + && elem.id === m + ) { + results.push(elem); + return results; + } + } + + // Type selector + } else if (match[2]) { + push.apply(results, context.getElementsByTagName(selector)); + return results; + + // Class selector + } else if ( + (m = match[3]) && support.getElementsByClassName + && context.getElementsByClassName + ) { + push.apply(results, context.getElementsByClassName(m)); + return results; + } + } + + // Take advantage of querySelectorAll + if ( + support.qsa + && !nonnativeSelectorCache[selector+' '] + && (!rbuggyQSA || !rbuggyQSA.test(selector)) + // Support: IE 8 only + // Exclude object elements + && (nodeType !== 1 || context.nodeName.toLowerCase() !== 'object') + ) { + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( + nodeType === 1 + && (rdescend.test(selector) || rcombinators.test(selector)) + ) { + // Expand context for sibling selectors + newContext = + rsibling.test(selector) && testContext(context.parentNode) + || context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if (newContext !== context || !support.scope) { + // Capture the context ID, setting it first if necessary + if ((nid = context.getAttribute('id'))) { + nid = nid.replace(rcssescape, fcssescape); + } else { + context.setAttribute('id', nid = expando); + } + } + + // Prefix every selector in the list + groups = tokenize(selector); + i = groups.length; + while (i--) { + groups[i] = (nid ? '#'+nid : ':scope')+' ' + +toSelector(groups[i]); + } + newSelector = groups.join(','); + } + + try { + // `qSA` may not throw for unrecognized parts using forgiving parsing: + // https://drafts.csswg.org/selectors/#forgiving-selector + // like the `:has()` pseudo-class: + // https://drafts.csswg.org/selectors/#relational + // `CSS.supports` is still expected to return `false` then: + // https://drafts.csswg.org/css-conditional-4/#typedef-supports-selector-fn + // https://drafts.csswg.org/css-conditional-4/#dfn-support-selector + if ( + support.cssSupportsSelector + // eslint-disable-next-line no-undef + && !CSS.supports('selector(:is('+newSelector+'))') + ) { + // Support: IE 11+ + // Throw to get to the same code path as an error directly in qSA. + // Note: once we only support browser supporting + // `CSS.supports('selector(...)')`, we can most likely drop + // the `try-catch`. IE doesn't implement the API. + throw new Error(); + } + + push.apply(results, newContext.querySelectorAll(newSelector)); + return results; + } catch (qsaError) { + nonnativeSelectorCache(selector, true); + } finally { + if (nid === expando) { + context.removeAttribute('id'); + } + } + } + } + } + + // All others + return select(selector.replace(rtrim, '$1'), context, results, seed); + } + + /** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ + function createCache() { + var keys = []; + + function cache(key, value) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if (keys.push(key+' ') > Expr.cacheLength) { + // Only keep the most recent entries + delete cache[keys.shift()]; + } + return (cache[key+' '] = value); + } + return cache; + } + + /** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ + function markFunction(fn) { + fn[expando] = true; + return fn; + } + + /** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ + function assert(fn) { + var el = document.createElement('fieldset'); + + try { + return !!fn(el); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if (el.parentNode) { + el.parentNode.removeChild(el); + } + + // release memory in IE + el = null; + } + } + + /** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ + function addHandle(attrs, handler) { + var arr = attrs.split('|'), + i = arr.length; + + while (i--) { + Expr.attrHandle[arr[i]] = handler; + } + } + + /** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ + function siblingCheck(a, b) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 + && a.sourceIndex-b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if (diff) { + return diff; + } + + // Check if b follows a + if (cur) { + while ((cur = cur.nextSibling)) { + if (cur === b) { + return -1; + } + } + } + + return a ? 1 : -1; + } + + /** + * Returns a function to use in pseudos for input types + * @param {String} type + */ + function createInputPseudo(type) { + return function(elem) { + var name = elem.nodeName.toLowerCase(); + return name === 'input' && elem.type === type; + }; + } + + /** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ + function createButtonPseudo(type) { + return function(elem) { + var name = elem.nodeName.toLowerCase(); + return (name === 'input' || name === 'button') && elem.type === type; + }; + } + + /** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ + function createDisabledPseudo(disabled) { + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function(elem) { + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ('form' in elem) { + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if (elem.parentNode && elem.disabled === false) { + // Option elements defer to a parent optgroup if present + if ('label' in elem) { + if ('label' in elem.parentNode) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled + // Where there is no isDisabled, check manually + /* jshint -W018 */ + || elem.isDisabled !== !disabled + && inDisabledFieldset(elem) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ('label' in elem) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; + } + + /** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ + function createPositionalPseudo(fn) { + return markFunction(function(argument) { + argument = +argument; + return markFunction(function(seed, matches) { + var j, + matchIndexes = fn([], seed.length, argument), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while (i--) { + if (seed[j = matchIndexes[i]]) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); + } + + /** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ + function testContext(context) { + return context && typeof context.getElementsByTagName !== 'undefined' && context; + } + + // Expose support vars for convenience + support = Sizzle.support = {}; + + /** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ + isXML = Sizzle.isXML = function(elem) { + var namespace = elem && elem.namespaceURI, + docElem = elem && (elem.ownerDocument || elem).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test(namespace || docElem && docElem.nodeName || 'HTML'); + }; + + /** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ + setDocument = Sizzle.setDocument = function(node) { + var hasCompare, subWindow, doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if (doc == document || doc.nodeType !== 9 || !doc.documentElement) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML(document); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( + preferredDoc != document + && (subWindow = document.defaultView) && subWindow.top !== subWindow + ) { + // Support: IE 11, Edge + if (subWindow.addEventListener) { + subWindow.addEventListener('unload', unloadHandler, false); + + // Support: IE 9 - 10 only + } else if (subWindow.attachEvent) { + subWindow.attachEvent('onunload', unloadHandler); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert(function(el) { + docElem.appendChild(el).appendChild(document.createElement('div')); + return typeof el.querySelectorAll !== 'undefined' + && !el.querySelectorAll(':scope fieldset div').length; + }); + + // Support: Chrome 105+, Firefox 104+, Safari 15.4+ + // Make sure forgiving mode is not used in `CSS.supports( "selector(...)" )`. + // + // `:is()` uses a forgiving selector list as an argument and is widely + // implemented, so it's a good one to test against. + support.cssSupportsSelector = assert(function() { + /* eslint-disable no-undef */ + + return CSS.supports('selector(*)') + // Support: Firefox 78-81 only + // In old Firefox, `:is()` didn't use forgiving parsing. In that case, + // fail this test as there's no selector to test against that. + // `CSS.supports` uses unforgiving parsing + && document.querySelectorAll(':is(:jqfake)') + // `*` is needed as Safari & newer Chrome implemented something in between + // for `:has()` - it throws in `qSA` if it only contains an unsupported + // argument but multiple ones, one of which is supported, are fine. + // We want to play safe in case `:is()` gets the same treatment. + && !CSS.supports('selector(:is(*,:jqfake))'); + + /* eslint-enable */ + }); + + /* Attributes ---------------------------------------------------------------------- */ - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties - // (excepting IE8 booleans) - support.attributes = assert( function( el ) { - el.className = "i"; - return !el.getAttribute( "className" ); - } ); + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function(el) { + el.className = 'i'; + return !el.getAttribute('className'); + }); - /* getElement(s)By* + /* getElement(s)By* ---------------------------------------------------------------------- */ - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert( function( el ) { - el.appendChild( document.createComment( "" ) ); - return !el.getElementsByTagName( "*" ).length; - } ); - - // Support: IE<9 - support.getElementsByClassName = rnative.test( document.getElementsByClassName ); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert( function( el ) { - docElem.appendChild( el ).id = expando; - return !document.getElementsByName || !document.getElementsByName( expando ).length; - } ); - - // ID filter and find - if ( support.getById ) { - Expr.filter[ "ID" ] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute( "id" ) === attrId; - }; - }; - Expr.find[ "ID" ] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var elem = context.getElementById( id ); - return elem ? [ elem ] : []; - } - }; - } else { - Expr.filter[ "ID" ] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode( "id" ); - return node && node.value === attrId; - }; - }; - - // Support: IE 6 - 7 only - // getElementById is not reliable as a find shortcut - Expr.find[ "ID" ] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var node, i, elems, - elem = context.getElementById( id ); - - if ( elem ) { - - // Verify the id attribute - node = elem.getAttributeNode( "id" ); - if ( node && node.value === id ) { - return [ elem ]; - } - - // Fall back on getElementsByName - elems = context.getElementsByName( id ); - i = 0; - while ( ( elem = elems[ i++ ] ) ) { - node = elem.getAttributeNode( "id" ); - if ( node && node.value === id ) { - return [ elem ]; - } - } - } - - return []; - } - }; - } - - // Tag - Expr.find[ "TAG" ] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else if ( support.qsa ) { - return context.querySelectorAll( tag ); - } - } : - - function( tag, context ) { - var elem, - tmp = [], - i = 0, - - // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( ( elem = results[ i++ ] ) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function(el) { + el.appendChild(document.createComment('')); + return !el.getElementsByTagName('*').length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test(document.getElementsByClassName); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function(el) { + docElem.appendChild(el).id = expando; + return !document.getElementsByName + || !document.getElementsByName(expando).length; + }); + + // ID filter and find + if (support.getById) { + Expr.filter['ID'] = function(id) { + var attrId = id.replace(runescape, funescape); + return function(elem) { + return elem.getAttribute('id') === attrId; + }; + }; + Expr.find['ID'] = function(id, context) { + if (typeof context.getElementById !== 'undefined' && documentIsHTML) { + var elem = context.getElementById(id); + return elem ? [elem] : []; + } + }; + } else { + Expr.filter['ID'] = function(id) { + var attrId = id.replace(runescape, funescape); + return function(elem) { + var node = typeof elem.getAttributeNode !== 'undefined' + && elem.getAttributeNode('id'); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find['ID'] = function(id, context) { + if (typeof context.getElementById !== 'undefined' && documentIsHTML) { + var node, i, elems, elem = context.getElementById(id); + + if (elem) { + // Verify the id attribute + node = elem.getAttributeNode('id'); + if (node && node.value === id) { + return [elem]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName(id); + i = 0; + while ((elem = elems[i++])) { + node = elem.getAttributeNode('id'); + if (node && node.value === id) { + return [elem]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find['TAG'] = support.getElementsByTagName + ? function(tag, context) { + if (typeof context.getElementsByTagName !== 'undefined') { + return context.getElementsByTagName(tag); + + // DocumentFragment nodes don't have gEBTN + } else if (support.qsa) { + return context.querySelectorAll(tag); + } + } + : function(tag, context) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName(tag); + + // Filter out possible comments + if (tag === '*') { + while ((elem = results[i++])) { + if (elem.nodeType === 1) { + tmp.push(elem); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find['CLASS'] = support.getElementsByClassName + && function(className, context) { + if ( + typeof context.getElementsByClassName !== 'undefined' && documentIsHTML + ) { + return context.getElementsByClassName(className); + } + }; + + /* QSA/matchesSelector ---------------------------------------------------------------------- */ - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See https://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert( function( el ) { - - var input; - - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // https://bugs.jquery.com/ticket/12359 - docElem.appendChild( el ).innerHTML = "" + - ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !el.querySelectorAll( "[selected]" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ - if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push( "~=" ); - } - - // Support: IE 11+, Edge 15 - 18+ - // IE 11/Edge don't find elements on a `[name='']` query in some cases. - // Adding a temporary attribute to the document before the selection works - // around the issue. - // Interestingly, IE 10 & older don't seem to have the issue. - input = document.createElement( "input" ); - input.setAttribute( "name", "" ); - el.appendChild( input ); - if ( !el.querySelectorAll( "[name='']" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + - whitespace + "*(?:''|\"\")" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !el.querySelectorAll( ":checked" ).length ) { - rbuggyQSA.push( ":checked" ); - } - - // Support: Safari 8+, iOS 8+ - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push( ".#.+[+~]" ); - } - - // Support: Firefox <=3.6 - 5 only - // Old Firefox doesn't throw on a badly-escaped identifier. - el.querySelectorAll( "\\\f" ); - rbuggyQSA.push( "[\\r\\n\\f]" ); - } ); - - assert( function( el ) { - el.innerHTML = "" + - ""; - - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement( "input" ); - input.setAttribute( "type", "hidden" ); - el.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( el.querySelectorAll( "[name=d]" ).length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: IE9-11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - docElem.appendChild( el ).disabled = true; - if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: Opera 10 - 11 only - // Opera 10-11 does not throw on post-comma invalid pseudos - el.querySelectorAll( "*,:x" ); - rbuggyQSA.push( ",.*:" ); - } ); - } - - if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector ) ) ) ) { - - assert( function( el ) { - - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( el, "*" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( el, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - } ); - } - - if ( !support.cssSupportsSelector ) { - - // Support: Chrome 105+, Safari 15.4+ - // `:has()` uses a forgiving selector list as an argument so our regular - // `try-catch` mechanism fails to catch `:has()` with arguments not supported - // natively like `:has(:contains("Foo"))`. Where supported & spec-compliant, - // we now use `CSS.supports("selector(:is(SELECTOR_TO_BE_TESTED))")`, but - // outside that we mark `:has` as buggy. - rbuggyQSA.push( ":has" ); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); - - /* Contains + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ((support.qsa = rnative.test(document.querySelectorAll))) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function(el) { + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild(el).innerHTML = "" + +""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if (el.querySelectorAll("[msallowcapture^='']").length) { + rbuggyQSA.push('[*^$]='+whitespace+'*(?:\'\'|"")'); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if (!el.querySelectorAll('[selected]').length) { + rbuggyQSA.push('\\['+whitespace+'*(?:value|'+booleans+')'); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if (!el.querySelectorAll('[id~='+expando+'-]').length) { + rbuggyQSA.push('~='); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement('input'); + input.setAttribute('name', ''); + el.appendChild(input); + if (!el.querySelectorAll("[name='']").length) { + rbuggyQSA.push( + '\\['+whitespace+'*name'+whitespace+'*=' + +whitespace+'*(?:\'\'|"")', + ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if (!el.querySelectorAll(':checked').length) { + rbuggyQSA.push(':checked'); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if (!el.querySelectorAll('a#'+expando+'+*').length) { + rbuggyQSA.push('.#.+[+~]'); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll('\\\f'); + rbuggyQSA.push('[\\r\\n\\f]'); + }); + + assert(function(el) { + el.innerHTML = "" + +""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement('input'); + input.setAttribute('type', 'hidden'); + el.appendChild(input).setAttribute('name', 'D'); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if (el.querySelectorAll('[name=d]').length) { + rbuggyQSA.push('name'+whitespace+'*[*^$|!~]?='); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if (el.querySelectorAll(':enabled').length !== 2) { + rbuggyQSA.push(':enabled', ':disabled'); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild(el).disabled = true; + if (el.querySelectorAll(':disabled').length !== 2) { + rbuggyQSA.push(':enabled', ':disabled'); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll('*,:x'); + rbuggyQSA.push(',.*:'); + }); + } + + if ( + (support.matchesSelector = rnative.test( + matches = docElem.matches + || docElem.webkitMatchesSelector + || docElem.mozMatchesSelector + || docElem.oMatchesSelector + || docElem.msMatchesSelector, + )) + ) { + assert(function(el) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call(el, '*'); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call(el, "[s!='']:x"); + rbuggyMatches.push('!=', pseudos); + }); + } + + if (!support.cssSupportsSelector) { + // Support: Chrome 105+, Safari 15.4+ + // `:has()` uses a forgiving selector list as an argument so our regular + // `try-catch` mechanism fails to catch `:has()` with arguments not supported + // natively like `:has(:contains("Foo"))`. Where supported & spec-compliant, + // we now use `CSS.supports("selector(:is(SELECTOR_TO_BE_TESTED))")`, but + // outside that we mark `:has` as buggy. + rbuggyQSA.push(':has'); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join('|')); + rbuggyMatches = rbuggyMatches.length && new RegExp(rbuggyMatches.join('|')); + + /* Contains ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully self-exclusive - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - - // Support: IE <9 only - // IE doesn't have `contains` on `document` so we need to check for - // `documentElement` presence. - // We need to fall back to `a` when `documentElement` is missing - // as `ownerDocument` of elements within `