From 8b64f975a4ecd291c835db50f5f74fcff0e4313b Mon Sep 17 00:00:00 2001 From: Stefan Hanauska Date: Thu, 29 Aug 2024 22:04:43 +0200 Subject: [PATCH 1/6] MBS-9327: Fix backlink cache task --- classes/cachemanager.php | 3 +++ classes/task/fill_backlink_cache.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/classes/cachemanager.php b/classes/cachemanager.php index a2e8d80..78fe7a7 100644 --- a/classes/cachemanager.php +++ b/classes/cachemanager.php @@ -79,6 +79,9 @@ public static function build_backlink_cache(int $courseid = 0) { $coursepageurl = course_get_format($module->course)->get_view_url($module->sectionnum); $coursepageurl->set_anchor('module-' . $module->id); foreach ($placestore->places as $place) { + if (!isset($place->linkedActivity)) { + continue; + } $url = !empty($module->showdescription) ? $coursepageurl->out() : new \moodle_url('/mod/learningmap/view.php', ['id' => $module->id]); diff --git a/classes/task/fill_backlink_cache.php b/classes/task/fill_backlink_cache.php index a5e05cf..3274bbb 100644 --- a/classes/task/fill_backlink_cache.php +++ b/classes/task/fill_backlink_cache.php @@ -49,7 +49,7 @@ public function execute() { $fillstate = $cache->get('fillstate'); // If the cache is filled within the last 24 hours, do nothing. - if (!empty($fillstate) && $fillstate < time() - 60 * 60 * 24) { + if (!empty($fillstate) && $fillstate > time() - 60 * 60 * 24) { mtrace('Backlink cache is already filled within the last 24 hours. Exiting.'); return; } From 4f513d96336f38f825ddf2c0353dba1ec9d5e8f4 Mon Sep 17 00:00:00 2001 From: Stefan Hanauska Date: Mon, 28 Oct 2024 00:49:11 +0100 Subject: [PATCH 2/6] Prepare course format --- classes/helper.php | 41 +++++++++++++++++++++++++++++++++++++++++ lib.php | 7 +++---- mod_form.php | 12 +++++++++--- 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 classes/helper.php diff --git a/classes/helper.php b/classes/helper.php new file mode 100644 index 0000000..466a809 --- /dev/null +++ b/classes/helper.php @@ -0,0 +1,41 @@ +. + +namespace mod_learningmap; + +/** + * Class helper + * + * @package mod_learningmap + * @copyright 2024 ISB Bayern + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class helper { + /** + * Returns whether the map should be shown on the course page. If course format is format_learningmap + * the setting in the database is ignored. + * + * @param cm_info $cm + * @return bool + */ + public static function show_map_on_course_page($cm): bool { + global $DB; + $showmaponcoursepage = $DB->get_field('learningmap', 'showmaponcoursepage', ['id' => $cm->instance]); + [$course, ] = get_course_and_cm_from_cmid($cm->id); + $courseformat = $course->format; + return !empty($showmaponcoursepage) && $courseformat != 'learningmap'; + } +} diff --git a/lib.php b/lib.php index 6c1c97b..e1ee10c 100644 --- a/lib.php +++ b/lib.php @@ -24,6 +24,7 @@ */ use mod_learningmap\cachemanager; +use mod_learningmap\helper; /** * Array with all features the plugin supports for advanced settings. Might be moved @@ -213,10 +214,8 @@ function learningmap_get_coursemodule_info($cm): cached_cm_info { * @return void */ function learningmap_cm_info_dynamic(cm_info $cm): void { - global $DB; - $showmaponcoursepage = $DB->get_field('learningmap', 'showmaponcoursepage', ['id' => $cm->instance]); // Decides whether to display the link. - if (!empty($showmaponcoursepage)) { + if (helper::show_map_on_course_page($cm)) { $cm->set_no_view_link(true); } } @@ -241,7 +240,7 @@ function learningmap_cm_info_view(cm_info $cm): void { } // Only show map on course page if showmaponcoursepage is set. - if (!empty($learningmap->showmaponcoursepage)) { + if (helper::show_map_on_course_page($cm)) { if (!empty($cm->groupmode)) { $groupdropdown = groups_print_activity_menu( $cm, diff --git a/mod_form.php b/mod_form.php index 245e1e2..88bf742 100644 --- a/mod_form.php +++ b/mod_form.php @@ -106,9 +106,15 @@ public function definition(): void { ) ); - $mform->addElement('advcheckbox', 'showmaponcoursepage', get_string('showmaponcoursepage', 'learningmap')); - $mform->setType('showmaponcoursepage', PARAM_INT); - $mform->addHelpButton('showmaponcoursepage', 'showmaponcoursepage', 'learningmap'); + // If using learningmap course format, the map is never shown on the course page. + if ($this->_course->format == 'learningmap') { + $mform->addElement('hidden', 'showmaponcoursepage', 0); + } else { + $mform->addElement('advcheckbox', 'showmaponcoursepage', get_string('showmaponcoursepage', 'learningmap')); + $mform->addHelpButton('showmaponcoursepage', 'showmaponcoursepage', 'learningmap'); + } + + $mform->setType('showmaponcoursepage', PARAM_INT); $backlinkallowed = get_config('mod_learningmap', 'backlinkallowed'); From 621829ea410f40a9ae285f3d17fd0225bb18be34 Mon Sep 17 00:00:00 2001 From: Stefan Hanauska Date: Mon, 28 Oct 2024 16:14:44 +0100 Subject: [PATCH 3/6] Changes for format_learningmap --- amd/build/initmainlearningmap.min.js | 11 +++ amd/build/initmainlearningmap.min.js.map | 1 + amd/build/mainlearningmap.min.js | 12 +++ amd/build/mainlearningmap.min.js.map | 1 + amd/src/initmainlearningmap.js | 34 +++++++ amd/src/mainlearningmap.js | 98 +++++++++++++++++++ classes/output/courseformat/activitybadge.php | 41 ++++++++ view.php | 4 +- 8 files changed, 200 insertions(+), 2 deletions(-) create mode 100644 amd/build/initmainlearningmap.min.js create mode 100644 amd/build/initmainlearningmap.min.js.map create mode 100644 amd/build/mainlearningmap.min.js create mode 100644 amd/build/mainlearningmap.min.js.map create mode 100644 amd/src/initmainlearningmap.js create mode 100644 amd/src/mainlearningmap.js create mode 100644 classes/output/courseformat/activitybadge.php diff --git a/amd/build/initmainlearningmap.min.js b/amd/build/initmainlearningmap.min.js new file mode 100644 index 0000000..cf79e98 --- /dev/null +++ b/amd/build/initmainlearningmap.min.js @@ -0,0 +1,11 @@ +define("mod_learningmap/initmainlearningmap",["exports","mod_learningmap/mainlearningmap","core_courseformat/courseeditor"],(function(_exports,_mainlearningmap,_courseeditor){var obj; +/** + * Load module for highlighting the main learningmap. + * + * @module mod_learningmap/initmainlearningmap + * @copyright 2024 ISB Bayern + * @author Stefan Hanauska + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_mainlearningmap=(obj=_mainlearningmap)&&obj.__esModule?obj:{default:obj};_exports.init=function(cmid){let isfirstlearningmap=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return new _mainlearningmap.default({element:document.querySelector('.activity[data-id="'+cmid+'"]'),reactive:(0,_courseeditor.getCurrentCourseEditor)(),cmid:cmid,isfirstlearningmap:isfirstlearningmap})}})); + +//# sourceMappingURL=initmainlearningmap.min.js.map \ No newline at end of file diff --git a/amd/build/initmainlearningmap.min.js.map b/amd/build/initmainlearningmap.min.js.map new file mode 100644 index 0000000..d627ba4 --- /dev/null +++ b/amd/build/initmainlearningmap.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"initmainlearningmap.min.js","sources":["../src/initmainlearningmap.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Load module for highlighting the main learningmap.\n *\n * @module mod_learningmap/initmainlearningmap\n * @copyright 2024 ISB Bayern\n * @author Stefan Hanauska \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport MainLearningmap from 'mod_learningmap/mainlearningmap';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\n\nexport const init = (cmid, isfirstlearningmap = false) => {\n return new MainLearningmap({\n element: document.querySelector('.activity[data-id=\"' + cmid + '\"]'),\n reactive: getCurrentCourseEditor(),\n cmid: cmid,\n isfirstlearningmap: isfirstlearningmap,\n });\n};\n"],"names":["cmid","isfirstlearningmap","MainLearningmap","element","document","querySelector","reactive"],"mappings":";;;;;;;;0KA0BoB,SAACA,UAAMC,kFAChB,IAAIC,yBAAgB,CACvBC,QAASC,SAASC,cAAc,sBAAwBL,KAAO,MAC/DM,UAAU,0CACVN,KAAMA,KACNC,mBAAoBA"} \ No newline at end of file diff --git a/amd/build/mainlearningmap.min.js b/amd/build/mainlearningmap.min.js new file mode 100644 index 0000000..5bad8bd --- /dev/null +++ b/amd/build/mainlearningmap.min.js @@ -0,0 +1,12 @@ +define("mod_learningmap/mainlearningmap",["exports","core/reactive","core_course/actions","core/templates"],(function(_exports,_reactive,_actions,_templates){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0; +/** + * Highlight main learningmap for format_learningmap. + * + * @module mod_learningmap/mainlearningmap + * @copyright 2024 ISB Bayern + * @author Stefan Hanauska + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class _default extends _reactive.BaseComponent{create(descriptor){this.element=descriptor.element,this.reactive=descriptor.reactive,this.cmid=descriptor.cmid,this.isfirstlearningmap=descriptor.isfirstlearningmap}getWatchers(){return[{watch:"cm:deleted",handler:this._updateLearningmap},{watch:"section:updated",handler:this._updateLearningmap},{watch:"cm:added",handler:this._updateLearningmap},{watch:"cm[".concat(this.cmid,"]:deleted"),handler:this.destroy}]}async destroy(){void 0===this._getFirstLearningmap()&&await(0,_templates.render)("format_learningmap/notification",{}).then((html=>(document.querySelector(".format_learningmap-notification").innerHTML=html,!0)))}async _updateLearningmap(){this._isFirstLearningmap()&&!this.isfirstlearningmap?(this.isfirstlearningmap=!0,this.getElement().classList.add("format_learningmap-firstlearningmap"),(0,_actions.refreshModule)(this.element,this.cmid),document.querySelector(".format_learningmap-notification").innerHTML=""):this.isfirstlearningmap&&(this.isfirstlearningmap=!1,this.getElement().classList.remove("format_learningmap-firstlearningmap"),(0,_actions.refreshModule)(this.element,this.cmid))}_isFirstLearningmap(){return this._getFirstLearningmap()==this.cmid}_getFirstLearningmap(){let state=this.reactive.stateManager.state;return this._getCmlist().find((cmid=>"learningmap"==state.cm.get(cmid).module))}_getCmlist(){let state=this.reactive.stateManager.state,cmlist=[];return state.course.sectionlist.forEach((sectionid=>{state.section.get(sectionid).cmlist.forEach((cmid=>{cmlist.push(cmid)}))})),cmlist}}return _exports.default=_default,_exports.default})); + +//# sourceMappingURL=mainlearningmap.min.js.map \ No newline at end of file diff --git a/amd/build/mainlearningmap.min.js.map b/amd/build/mainlearningmap.min.js.map new file mode 100644 index 0000000..48b391a --- /dev/null +++ b/amd/build/mainlearningmap.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"mainlearningmap.min.js","sources":["../src/mainlearningmap.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Highlight main learningmap for format_learningmap.\n *\n * @module mod_learningmap/mainlearningmap\n * @copyright 2024 ISB Bayern\n * @author Stefan Hanauska \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport {BaseComponent} from 'core/reactive';\nimport {refreshModule} from 'core_course/actions';\nimport {render as renderTemplate} from 'core/templates';\n\n/**\n * The live updater component.\n */\nexport default class extends BaseComponent {\n create(descriptor) {\n this.element = descriptor.element;\n this.reactive = descriptor.reactive;\n this.cmid = descriptor.cmid;\n this.isfirstlearningmap = descriptor.isfirstlearningmap;\n }\n\n getWatchers() {\n const watchers = [\n {watch: `cm:deleted`, handler: this._updateLearningmap},\n {watch: `section:updated`, handler: this._updateLearningmap},\n {watch: `cm:added`, handler: this._updateLearningmap},\n {watch: `cm[${this.cmid}]:deleted`, handler: this.destroy},\n ];\n return watchers;\n }\n\n async destroy() {\n if (this._getFirstLearningmap() === undefined) {\n await renderTemplate('format_learningmap/notification', {}).then((html) => {\n document.querySelector('.format_learningmap-notification').innerHTML = html;\n return true;\n });\n }\n }\n\n async _updateLearningmap() {\n if (this._isFirstLearningmap() && !this.isfirstlearningmap) {\n this.isfirstlearningmap = true;\n this.getElement().classList.add('format_learningmap-firstlearningmap');\n refreshModule(this.element, this.cmid);\n document.querySelector('.format_learningmap-notification').innerHTML = '';\n } else {\n if (this.isfirstlearningmap) {\n this.isfirstlearningmap = false;\n this.getElement().classList.remove('format_learningmap-firstlearningmap');\n refreshModule(this.element, this.cmid);\n }\n }\n }\n\n _isFirstLearningmap() {\n let firstLearningmap = this._getFirstLearningmap();\n return firstLearningmap == this.cmid;\n }\n\n _getFirstLearningmap() {\n let state = this.reactive.stateManager.state;\n let cmlist = this._getCmlist();\n return cmlist.find((cmid) => {\n let cm = state.cm.get(cmid);\n return (cm.module == 'learningmap');\n });\n }\n\n _getCmlist() {\n let state = this.reactive.stateManager.state;\n let cmlist = [];\n state.course.sectionlist.forEach((sectionid) => {\n let section = state.section.get(sectionid);\n section.cmlist.forEach((cmid) => {\n cmlist.push(cmid);\n });\n });\n return cmlist;\n }\n}\n"],"names":["BaseComponent","create","descriptor","element","reactive","cmid","isfirstlearningmap","getWatchers","watch","handler","this","_updateLearningmap","destroy","undefined","_getFirstLearningmap","then","html","document","querySelector","innerHTML","_isFirstLearningmap","getElement","classList","add","remove","state","stateManager","_getCmlist","find","cm","get","module","cmlist","course","sectionlist","forEach","sectionid","section","push"],"mappings":";;;;;;;;;uBA8B6BA,wBACzBC,OAAOC,iBACEC,QAAUD,WAAWC,aACrBC,SAAWF,WAAWE,cACtBC,KAAOH,WAAWG,UAClBC,mBAAqBJ,WAAWI,mBAGzCC,oBACqB,CACb,CAACC,mBAAqBC,QAASC,KAAKC,oBACpC,CAACH,wBAA0BC,QAASC,KAAKC,oBACzC,CAACH,iBAAmBC,QAASC,KAAKC,oBAClC,CAACH,mBAAaE,KAAKL,kBAAiBI,QAASC,KAAKE,+BAMlBC,IAAhCH,KAAKI,8BACC,qBAAe,kCAAmC,IAAIC,MAAMC,OAC9DC,SAASC,cAAc,oCAAoCC,UAAYH,MAChE,gCAMXN,KAAKU,wBAA0BV,KAAKJ,yBAC/BA,oBAAqB,OACrBe,aAAaC,UAAUC,IAAI,kEAClBb,KAAKP,QAASO,KAAKL,MACjCY,SAASC,cAAc,oCAAoCC,UAAY,IAEnET,KAAKJ,0BACAA,oBAAqB,OACrBe,aAAaC,UAAUE,OAAO,kEACrBd,KAAKP,QAASO,KAAKL,OAK7Ce,6BAC2BV,KAAKI,wBACDJ,KAAKL,KAGpCS,2BACQW,MAAQf,KAAKN,SAASsB,aAAaD,aAC1Bf,KAAKiB,aACJC,MAAMvB,MAEK,eADZoB,MAAMI,GAAGC,IAAIzB,MACX0B,SAInBJ,iBACQF,MAAQf,KAAKN,SAASsB,aAAaD,MACnCO,OAAS,UACbP,MAAMQ,OAAOC,YAAYC,SAASC,YAChBX,MAAMY,QAAQP,IAAIM,WACxBJ,OAAOG,SAAS9B,OACpB2B,OAAOM,KAAKjC,YAGb2B"} \ No newline at end of file diff --git a/amd/src/initmainlearningmap.js b/amd/src/initmainlearningmap.js new file mode 100644 index 0000000..51a5bd3 --- /dev/null +++ b/amd/src/initmainlearningmap.js @@ -0,0 +1,34 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * Load module for highlighting the main learningmap. + * + * @module mod_learningmap/initmainlearningmap + * @copyright 2024 ISB Bayern + * @author Stefan Hanauska + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +import MainLearningmap from 'mod_learningmap/mainlearningmap'; +import {getCurrentCourseEditor} from 'core_courseformat/courseeditor'; + +export const init = (cmid, isfirstlearningmap = false) => { + return new MainLearningmap({ + element: document.querySelector('.activity[data-id="' + cmid + '"]'), + reactive: getCurrentCourseEditor(), + cmid: cmid, + isfirstlearningmap: isfirstlearningmap, + }); +}; diff --git a/amd/src/mainlearningmap.js b/amd/src/mainlearningmap.js new file mode 100644 index 0000000..754b3d8 --- /dev/null +++ b/amd/src/mainlearningmap.js @@ -0,0 +1,98 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * Highlight main learningmap for format_learningmap. + * + * @module mod_learningmap/mainlearningmap + * @copyright 2024 ISB Bayern + * @author Stefan Hanauska + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +import {BaseComponent} from 'core/reactive'; +import {refreshModule} from 'core_course/actions'; +import {render as renderTemplate} from 'core/templates'; + +/** + * The live updater component. + */ +export default class extends BaseComponent { + create(descriptor) { + this.element = descriptor.element; + this.reactive = descriptor.reactive; + this.cmid = descriptor.cmid; + this.isfirstlearningmap = descriptor.isfirstlearningmap; + } + + getWatchers() { + const watchers = [ + {watch: `cm:deleted`, handler: this._updateLearningmap}, + {watch: `section:updated`, handler: this._updateLearningmap}, + {watch: `cm:added`, handler: this._updateLearningmap}, + {watch: `cm[${this.cmid}]:deleted`, handler: this.destroy}, + ]; + return watchers; + } + + async destroy() { + if (this._getFirstLearningmap() === undefined) { + await renderTemplate('format_learningmap/notification', {}).then((html) => { + document.querySelector('.format_learningmap-notification').innerHTML = html; + return true; + }); + } + } + + async _updateLearningmap() { + if (this._isFirstLearningmap() && !this.isfirstlearningmap) { + this.isfirstlearningmap = true; + this.getElement().classList.add('format_learningmap-firstlearningmap'); + refreshModule(this.element, this.cmid); + document.querySelector('.format_learningmap-notification').innerHTML = ''; + } else { + if (this.isfirstlearningmap) { + this.isfirstlearningmap = false; + this.getElement().classList.remove('format_learningmap-firstlearningmap'); + refreshModule(this.element, this.cmid); + } + } + } + + _isFirstLearningmap() { + let firstLearningmap = this._getFirstLearningmap(); + return firstLearningmap == this.cmid; + } + + _getFirstLearningmap() { + let state = this.reactive.stateManager.state; + let cmlist = this._getCmlist(); + return cmlist.find((cmid) => { + let cm = state.cm.get(cmid); + return (cm.module == 'learningmap'); + }); + } + + _getCmlist() { + let state = this.reactive.stateManager.state; + let cmlist = []; + state.course.sectionlist.forEach((sectionid) => { + let section = state.section.get(sectionid); + section.cmlist.forEach((cmid) => { + cmlist.push(cmid); + }); + }); + return cmlist; + } +} diff --git a/classes/output/courseformat/activitybadge.php b/classes/output/courseformat/activitybadge.php new file mode 100644 index 0000000..e996393 --- /dev/null +++ b/classes/output/courseformat/activitybadge.php @@ -0,0 +1,41 @@ +. + +namespace mod_learningmap\output\courseformat; + +/** + * Class activitybadge + * + * @package mod_learningmap + * @copyright 2024 ISB Bayern + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class activitybadge extends \core_courseformat\output\activitybadge { + + protected function update_content(): void { + $course = $this->cminfo->get_course(); + if ($course->format == 'learningmap') { + $courseformat = course_get_format($course); + if($courseformat->main_learningmap_exists()) { + $mainlearningmap = $courseformat->get_main_learningmap(); + if ($this->cminfo->id == $mainlearningmap->id) { + $this->content = get_string('mainlearningmap', 'format_learningmap'); + $this->style = 'badge-primary'; + } + } + } + } +} diff --git a/view.php b/view.php index 3777e74..2e31fa7 100644 --- a/view.php +++ b/view.php @@ -29,13 +29,13 @@ $id = required_param('id', PARAM_INT); [$course, $cm] = get_course_and_cm_from_cmid($id, 'learningmap'); +$PAGE->set_url(new moodle_url('/mod/learningmap/view.php', ['id' => $id])); + require_course_login($course, true, $cm); $context = context_module::instance($cm->id); require_capability('mod/learningmap:view', $context); - $map = $DB->get_record('learningmap', ['id' => $cm->instance], '*', MUST_EXIST); -$PAGE->set_url(new moodle_url('/mod/learningmap/view.php', ['id' => $id])); $PAGE->set_title(get_string('pluginname', 'mod_learningmap') . ' ' . $map->name); $PAGE->set_heading($map->name); From aa0f3cd33eba45aca3c536f5c40d81d35b4d6c84 Mon Sep 17 00:00:00 2001 From: Stefan Hanauska Date: Mon, 28 Oct 2024 16:49:14 +0100 Subject: [PATCH 4/6] Coding standard --- classes/output/courseformat/activitybadge.php | 6 ++++-- mod_form.php | 2 +- tests/generator/lib.php | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/classes/output/courseformat/activitybadge.php b/classes/output/courseformat/activitybadge.php index e996393..e42f7ac 100644 --- a/classes/output/courseformat/activitybadge.php +++ b/classes/output/courseformat/activitybadge.php @@ -24,12 +24,14 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class activitybadge extends \core_courseformat\output\activitybadge { - + /** + * Updates the content of the activity badge. + */ protected function update_content(): void { $course = $this->cminfo->get_course(); if ($course->format == 'learningmap') { $courseformat = course_get_format($course); - if($courseformat->main_learningmap_exists()) { + if ($courseformat->main_learningmap_exists()) { $mainlearningmap = $courseformat->get_main_learningmap(); if ($this->cminfo->id == $mainlearningmap->id) { $this->content = get_string('mainlearningmap', 'format_learningmap'); diff --git a/mod_form.php b/mod_form.php index 88bf742..289379f 100644 --- a/mod_form.php +++ b/mod_form.php @@ -114,7 +114,7 @@ public function definition(): void { $mform->addHelpButton('showmaponcoursepage', 'showmaponcoursepage', 'learningmap'); } - $mform->setType('showmaponcoursepage', PARAM_INT); + $mform->setType('showmaponcoursepage', PARAM_INT); $backlinkallowed = get_config('mod_learningmap', 'backlinkallowed'); diff --git a/tests/generator/lib.php b/tests/generator/lib.php index e385446..386e6d4 100644 --- a/tests/generator/lib.php +++ b/tests/generator/lib.php @@ -31,7 +31,7 @@ class mod_learningmap_generator extends testing_module_generator { * @param array|null $options * @return stdClass learningmap instance */ - public function create_instance($record = null, array $options = null): stdClass { + public function create_instance($record = null, array|null $options = null): stdClass { global $CFG; $record = (array)$record + [ From 53000e503627b7171b0f6dc78a0b7917f305b9fa Mon Sep 17 00:00:00 2001 From: Stefan Hanauska Date: Sun, 3 Nov 2024 06:53:36 +0100 Subject: [PATCH 5/6] Change form --- mod_form.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod_form.php b/mod_form.php index 289379f..35c73cb 100644 --- a/mod_form.php +++ b/mod_form.php @@ -152,7 +152,7 @@ public function definition(): void { $this->standard_coursemodule_elements(); - $this->add_action_buttons(true, false, null); + $this->add_action_buttons(true, null, null); $mform->addHelpButton('groupmode', 'groupmode', 'learningmap'); } From ae060436ea40a9069b6eb7f03626afcf221b5cb1 Mon Sep 17 00:00:00 2001 From: Stefan Hanauska Date: Sun, 3 Nov 2024 13:11:39 +0100 Subject: [PATCH 6/6] WIP --- amd/build/circle.min.js | 12 + amd/build/circle.min.js.map | 1 + amd/build/emoji.min.js | 11 + amd/build/emoji.min.js.map | 1 + amd/build/learningmap.min.js | 2 +- amd/build/learningmap.min.js.map | 2 +- amd/build/placestore.min.js | 2 +- amd/build/placestore.min.js.map | 2 +- amd/build/shapes.min.js | 11 + amd/build/shapes.min.js.map | 1 + amd/build/square.min.js | 12 + amd/build/square.min.js.map | 1 + amd/build/svg.min.js | 36 + amd/build/svg.min.js.map | 1 + amd/src/circle.js | 37 + amd/src/emoji.js | 41 + amd/src/learningmap.js | 226 +- amd/src/placestore.js | 21 +- amd/src/shapes.js | 33 + amd/src/square.js | 37 + amd/src/svg.js | 6945 ++++++++++++++++++++++++++++++ classes/mapworker.php | 4 +- classes/svgmap.php | 14 +- thirdpartylibs.xml | 9 + 24 files changed, 7324 insertions(+), 138 deletions(-) create mode 100644 amd/build/circle.min.js create mode 100644 amd/build/circle.min.js.map create mode 100644 amd/build/emoji.min.js create mode 100644 amd/build/emoji.min.js.map create mode 100644 amd/build/shapes.min.js create mode 100644 amd/build/shapes.min.js.map create mode 100644 amd/build/square.min.js create mode 100644 amd/build/square.min.js.map create mode 100644 amd/build/svg.min.js create mode 100644 amd/build/svg.min.js.map create mode 100644 amd/src/circle.js create mode 100644 amd/src/emoji.js create mode 100644 amd/src/shapes.js create mode 100644 amd/src/square.js create mode 100644 amd/src/svg.js create mode 100644 thirdpartylibs.xml diff --git a/amd/build/circle.min.js b/amd/build/circle.min.js new file mode 100644 index 0000000..6c9f86d --- /dev/null +++ b/amd/build/circle.min.js @@ -0,0 +1,12 @@ +define("mod_learningmap/circle",["exports"],(function(_exports){return Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default= +/** + * A circle shape. + * + * @module mod_learningmap/circle + * @copyright 2024 ISB Bayern + * @author Stefan Hanauska + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +function(mapsvg,x,y,r,classes,id){return mapsvg.circle(2*r).cx(x).cy(y).attr({class:classes}).id(id)},_exports.default})); + +//# sourceMappingURL=circle.min.js.map \ No newline at end of file diff --git a/amd/build/circle.min.js.map b/amd/build/circle.min.js.map new file mode 100644 index 0000000..86f4cb0 --- /dev/null +++ b/amd/build/circle.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"circle.min.js","sources":["../src/circle.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * A circle shape.\n *\n * @module mod_learningmap/circle\n * @copyright 2024 ISB Bayern\n * @author Stefan Hanauska \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Returns a circle tag with the given dimensions.\n * @param {*} mapsvg\n * @param {*} x x coordinate of the center\n * @param {*} y y coordinate of the center\n * @param {*} r radius\n * @param {*} classes classes to add\n * @param {*} id id of the circle\n * @returns {any}\n */\nexport default function circle(mapsvg, x, y, r, classes, id) {\n return mapsvg.circle(r * 2).cx(x).cy(y).attr({'class': classes}).id(id);\n}"],"names":["mapsvg","x","y","r","classes","id","circle","cx","cy","attr"],"mappings":";;;;;;;;;SAkC+BA,OAAQC,EAAGC,EAAGC,EAAGC,QAASC,WAC9CL,OAAOM,OAAW,EAAJH,GAAOI,GAAGN,GAAGO,GAAGN,GAAGO,KAAK,OAAUL,UAAUC,GAAGA"} \ No newline at end of file diff --git a/amd/build/emoji.min.js b/amd/build/emoji.min.js new file mode 100644 index 0000000..fbec0f1 --- /dev/null +++ b/amd/build/emoji.min.js @@ -0,0 +1,11 @@ +define("mod_learningmap/emoji",["exports"],(function(_exports){return Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default= +/** + * TODO describe module emoji + * + * @module mod_learningmap/emoji + * @copyright 2024 ISB Bayern + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +function(mapsvg,x,y,r,classes,id,content){let newelement=mapsvg.nested();return newelement.center(x,y).attr({class:classes}).id(id).width(2*r+10).height(2*r+10),newelement.circle(2*r,r,r),newelement.text().plain(null!=content?content:"😀"),newelement},_exports.default})); + +//# sourceMappingURL=emoji.min.js.map \ No newline at end of file diff --git a/amd/build/emoji.min.js.map b/amd/build/emoji.min.js.map new file mode 100644 index 0000000..225fdab --- /dev/null +++ b/amd/build/emoji.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"emoji.min.js","sources":["../src/emoji.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * TODO describe module emoji\n *\n * @module mod_learningmap/emoji\n * @copyright 2024 ISB Bayern\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Returns an text tag containing an emoji with the given dimensions.\n * @param {*} mapsvg\n * @param {*} x\n * @param {*} y\n * @param {*} r\n * @param {*} classes\n * @param {*} id\n * @param {*} content\n * @returns\n */\nexport default function emoji(mapsvg, x, y, r, classes, id, content) {\n let newelement = mapsvg.nested();\n newelement.center(x, y).attr({'class': classes}).id(id).width(r * 2 + 10).height(r * 2 + 10);\n newelement.circle(r * 2, r, r);\n newelement.text().plain(content ?? '😀');\n return newelement;\n}"],"names":["mapsvg","x","y","r","classes","id","content","newelement","nested","center","attr","width","height","circle","text","plain"],"mappings":";;;;;;;;SAkC8BA,OAAQC,EAAGC,EAAGC,EAAGC,QAASC,GAAIC,aACpDC,WAAaP,OAAOQ,gBACxBD,WAAWE,OAAOR,EAAGC,GAAGQ,KAAK,OAAUN,UAAUC,GAAGA,IAAIM,MAAU,EAAJR,EAAQ,IAAIS,OAAW,EAAJT,EAAQ,IACzFI,WAAWM,OAAW,EAAJV,EAAOA,EAAGA,GAC5BI,WAAWO,OAAOC,MAAMT,MAAAA,QAAAA,QAAW,MAC5BC"} \ No newline at end of file diff --git a/amd/build/learningmap.min.js b/amd/build/learningmap.min.js index 55057a0..078676c 100644 --- a/amd/build/learningmap.min.js +++ b/amd/build/learningmap.min.js @@ -1,3 +1,3 @@ -define("mod_learningmap/learningmap",["exports","core/notification","core/templates","mod_learningmap/placestore"],(function(_exports,_notification,_templates,_placestore){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_templates=_interopRequireDefault(_templates),_placestore=_interopRequireDefault(_placestore);const targetPoints_firstPoint=1,targetPoints_secondPoint=2,targetPoints_bezierPoint=3,pathTypes_line=1,pathTypes_quadraticbezier=2;_exports.init=()=>{var offset,dragel,pathsToUpdateFirstPoint,pathsToUpdateSecondPoint;_templates.default.prefetchTemplates(["mod_learningmap/cssskeleton"]);var selectedElement=null,firstPlace=null,secondPlace=null,lastTarget=null,elementForActivitySelector=null,touchstart=!1,touchend=!1,touchmove=0;let mapdiv=document.getElementById("learningmap-editor-map"),code=document.getElementById("id_svgcode"),activitySetting=document.getElementById("learningmap-activity-setting"),activitySelector=document.getElementById("learningmap-activity-selector"),activityStarting=document.getElementById("learningmap-activity-starting"),activityTarget=document.getElementById("learningmap-activity-target"),activityHiddenWarning=document.getElementById("learningmap-activity-hidden-warning"),advancedSettingsIcon=document.getElementById("learningmap-advanced-settings-icon"),treeView=document.querySelector(".fp-viewbar .fp-vb-tree");treeView&&treeView.setAttribute("style","display: none;");let iconView=document.querySelector(".fp-viewbar .fp-vb-icons");iconView&&setTimeout((()=>{iconView.dispatchEvent(new Event("click"))}),1e3),activitySelector&&(activitySelector.addEventListener("change",(function(){if(_placestore.default.setActivityId(elementForActivitySelector,activitySelector.value),activitySelector.value){let text=document.getElementById("text"+elementForActivitySelector);text&&(text.textContent=activitySelector.querySelector('option[value="'+activitySelector.value+'"]').textContent);let title=document.getElementById("title"+elementForActivitySelector);title&&(title.textContent=activitySelector.querySelector('option[value="'+activitySelector.value+'"]').textContent),document.getElementById(elementForActivitySelector).classList.remove("learningmap-emptyplace")}else document.getElementById(elementForActivitySelector).classList.add("learningmap-emptyplace");updateActivities(),updateCode()})),activityStarting.addEventListener("change",(function(){activityStarting.checked?_placestore.default.addStartingPlace(elementForActivitySelector):_placestore.default.removeStartingPlace(elementForActivitySelector),updateCode()})),activityTarget.addEventListener("change",(function(){activityTarget.checked?(_placestore.default.addTargetPlace(elementForActivitySelector),document.getElementById(elementForActivitySelector).classList.add("learningmap-targetplace")):(_placestore.default.removeTargetPlace(elementForActivitySelector),document.getElementById(elementForActivitySelector).classList.remove("learningmap-targetplace")),updateCode()})));let placestoreInput=document.getElementsByName("placestore")[0];if(placestoreInput&&_placestore.default.loadJSON(placestoreInput.value),updateActivities(),advancedSettingsIcon){let advancedSettings=document.getElementById("learningmap-advanced-settings");advancedSettingsIcon.addEventListener("click",(function(){null===advancedSettings.getAttribute("hidden")?hideAdvancedSettings():(advancedSettings.removeAttribute("hidden"),hideContextMenu())}));let advancedSettingsClose=document.getElementById("learningmap-advanced-settings-close");advancedSettingsClose&&advancedSettingsClose.addEventListener("click",(function(){advancedSettings.setAttribute("hidden","")})),advancedSettingsLogic("hidepaths",_placestore.default.getHidePaths,_placestore.default.setHidePaths),advancedSettingsLogic("usecheckmark",_placestore.default.getUseCheckmark,_placestore.default.setUseCheckmark),advancedSettingsLogic("hover",_placestore.default.getHover,_placestore.default.setHover),advancedSettingsLogic("pulse",_placestore.default.getPulse,_placestore.default.setPulse),advancedSettingsLogic("showall",_placestore.default.getShowall,_placestore.default.setShowall),advancedSettingsLogic("hidestroke",_placestore.default.getHideStroke,_placestore.default.setHideStroke),advancedSettingsLogic("showtext",_placestore.default.getShowText,_placestore.default.setShowText,(function(){let options=Array.from(activitySelector.getElementsByTagName("option")),places=_placestore.default.getPlaces();for(const place of places)if(null===document.getElementById("text"+place.id)){let content="";for(const option of options)if(option.value==place.linkedActivity){content=option.textContent;break}let placeNode=document.getElementById(place.id),textNode=text("text"+place.id,content,placeNode.cx.baseVal.value,placeNode.cy.baseVal.value);placeNode.parentNode.appendChild(textNode)}})),advancedSettingsLogic("slicemode",_placestore.default.getSliceMode,_placestore.default.setSliceMode),advancedSettingsLogic("showwaygone",_placestore.default.getShowWayGone,_placestore.default.setShowWayGone)}colorChooserLogic("stroke","text"),colorChooserLogic("place"),colorChooserLogic("visited"),code&&mapdiv&&(mapdiv.innerHTML=code.value),refreshBackgroundImage(),function(){let background=document.getElementById("learningmap-background-image");background&&background.addEventListener("load",(function(){background.removeAttribute("height");let height=parseInt(background.getBBox().height),width=background.getBBox().width;_placestore.default.setBackgroundDimensions(width,height),svg.setAttribute("viewBox","0 0 "+_placestore.default.width+" "+_placestore.default.height),background.setAttribute("width",width),background.setAttribute("height",height),updateCode()}))}(),updateCode();let svg=document.getElementById("learningmap-svgmap-"+_placestore.default.getMapid());function showContextMenu(e){if(unselectAll(),hideAdvancedSettings(),activitySetting&&null!==document.getElementById(e.target.id))if(e.touches&&(e=e.touches[0]),e.target.classList.contains("learningmap-place")){e.target.classList.add("learningmap-selected-activity-selector");let activityId=_placestore.default.getActivityId(e.target.id),scalingFactor=mapdiv.clientWidth/800;activitySetting.style.setProperty("--pos-x",e.target.cx.baseVal.value*scalingFactor+"px"),activitySetting.style.setProperty("--pos-y",e.target.cy.baseVal.value*scalingFactor+"px"),activitySetting.style.setProperty("--map-width",mapdiv.clientWidth+"px"),activitySetting.style.setProperty("--map-height",mapdiv.clientHeight+"px"),activitySetting.style.display="block",document.getElementById("learningmap-activity-selector").value=activityId,document.getElementById("learningmap-activity-starting").checked=_placestore.default.isStartingPlace(e.target.id),document.getElementById("learningmap-activity-target").checked=_placestore.default.isTargetPlace(e.target.id),elementForActivitySelector=e.target.id,updateActivities()}else hideContextMenu(),hideAdvancedSettings()}function hideContextMenu(){let e=document.getElementById(elementForActivitySelector);e&&e.classList.remove("learningmap-selected-activity-selector"),activitySetting.style.display="none"}!function(el){dragel=el,el&&(el.addEventListener("mousedown",startDrag),el.addEventListener("mousemove",drag),el.addEventListener("mouseup",endDrag),el.addEventListener("mouseleave",endDrag),el.addEventListener("touchstart",(function(evt){evt.cancelable&&evt.preventDefault();evt.target.classList.contains("learningmap-draggable")||"text"==evt.target.nodeName||"path"==evt.target.nodeName?(touchstart?(dblclickHandler(evt),touchstart=!1):(touchstart=!0,touchmove=0,touchend=!1,setTimeout((evt=>{touchmove<3&&!touchend&&(evt.touches&&(evt=evt.touches[0]),showContextMenu(evt))}),2e3,evt),setTimeout((()=>{touchstart=!1}),300)),startDrag(evt)):touchstart?(dblclickHandler(evt),touchstart=!1):(touchstart=!0,touchend=!1,touchmove=0,setTimeout((()=>{touchstart=!1}),300))})),el.addEventListener("touchmove",drag),el.addEventListener("touchend",endTouch),el.addEventListener("touchleave",endTouch),el.addEventListener("touchcancel",endTouch));function startDrag(evt){if(evt.cancelable&&evt.preventDefault(),pathsToUpdateFirstPoint=[],pathsToUpdateSecondPoint=[],evt.target.classList.contains("learningmap-draggable"))selectedElement=evt.target,(offset=getMousePosition(evt)).x-=parseInt(selectedElement.getAttributeNS(null,"cx")),offset.y-=parseInt(selectedElement.getAttributeNS(null,"cy")),pathsToUpdateFirstPoint=_placestore.default.getPathsWithFid(selectedElement.id),pathsToUpdateSecondPoint=_placestore.default.getPathsWithSid(selectedElement.id);else if("text"==evt.target.nodeName){let place=(selectedElement=evt.target).parentNode.querySelector(".learningmap-place");(offset=getMousePosition(evt)).x-=parseInt(selectedElement.getAttributeNS(null,"dx"))+place.cx.baseVal.value,offset.y-=parseInt(selectedElement.getAttributeNS(null,"dy"))+place.cy.baseVal.value}else if("path"==evt.target.nodeName){selectedElement=evt.target,offset=getMousePosition(evt);let pathPoint=transformCoordinates(evt.layerX,evt.layerY);offset.x+=pathPoint.x,offset.y+=pathPoint.y}}function drag(evt){if(evt.cancelable&&evt.preventDefault(),touchmove++,selectedElement){var coord=getMousePosition(evt);let cx=coord.x-offset.x,cy=coord.y-offset.y;if("text"==selectedElement.nodeName){let place=selectedElement.parentNode.querySelector(".learningmap-place"),dx=coord.x-offset.x-place.cx.baseVal.value,dy=coord.y-offset.y-place.cy.baseVal.value;selectedElement.setAttributeNS(null,"dx",dx),selectedElement.setAttributeNS(null,"dy",dy)}if("path"==selectedElement.nodeName&&selectedElement.setAttribute("d",updatePathDeclaration(selectedElement.getAttribute("d"),coord.x,coord.y,targetPoints_bezierPoint)),"circle"==selectedElement.nodeName){selectedElement.setAttributeNS(null,"cx",cx),selectedElement.setAttributeNS(null,"cy",cy);let textNode=document.getElementById("text"+selectedElement.id);null!==textNode&&(textNode.setAttributeNS(null,"x",cx),textNode.setAttributeNS(null,"y",cy)),pathsToUpdateFirstPoint.forEach((function(path){let pathNode=document.getElementById(path.id);null!==pathNode&&("path"==pathNode.nodeName?pathNode.setAttribute("d",updatePathDeclaration(pathNode.getAttribute("d"),cx,cy,targetPoints_firstPoint)):(pathNode.setAttribute("x1",cx),pathNode.setAttribute("y1",cy)))})),pathsToUpdateSecondPoint.forEach((function(path){let pathNode=document.getElementById(path.id);null!==pathNode&&("path"==pathNode.nodeName?pathNode.setAttribute("d",updatePathDeclaration(pathNode.getAttribute("d"),cx,cy,targetPoints_secondPoint)):(pathNode.setAttribute("x2",cx),pathNode.setAttribute("y2",cy)))}))}}}function endDrag(evt){evt.cancelable&&evt.preventDefault(),selectedElement=null,unselectAll(),updateCode()}function endTouch(evt){selectedElement=null,touchend=!0,touchmove<3&&touchstart?clickHandler(evt):endDrag(evt),evt.cancelable&&evt.preventDefault()}function updatePathDeclaration(oldDefinition,targetX,targetY){let targetP=arguments.length>3&&void 0!==arguments[3]?arguments[3]:targetPoints_firstPoint,parts=oldDefinition.split(" "),fromX=0,fromY=0,toX=0,toY=0,bezierX=0,bezierY=0,pathType=pathTypes_line;for(let i=0;i2&&void 0!==arguments[2]?arguments[2]:null,text=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,link=document.createElementNS("http://www.w3.org/2000/svg","a");link.setAttribute("id",id),link.setAttribute("xlink:href",""),link.appendChild(child),null!==title&&link.appendChild(title);null!==text&&link.appendChild(text);return link}(function(x,y,r,classes,id){let circle=document.createElementNS("http://www.w3.org/2000/svg","circle");return circle.setAttribute("class",classes),circle.setAttribute("id",id),circle.setAttribute("cx",x),circle.setAttribute("cy",y),circle.setAttribute("r",r),circle}(cx,cy,10,"learningmap-place learningmap-draggable learningmap-emptyplace",placeId),linkId,function(id){let title=document.createElementNS("http://www.w3.org/2000/svg","title");return title.setAttribute("id",id),title}("title"+placeId),text("text"+placeId,"",cx,cy))),_placestore.default.addPlace(placeId,linkId)}(event):event.target.classList.contains("learningmap-place")?lastTarget==event.target.id?(lastTarget=null,clickHandler(event)):function(event){let place=document.getElementById(event.target.id),parent=place.parentNode;id=event.target.id,_placestore.default.getTouchingPaths(id).forEach((function(e){removePath(e.id)})),_placestore.default.removePlace(event.target.id),parent.removeChild(place),parent.parentNode.removeChild(parent),updateCode();var id}(event):event.target.classList.contains("learningmap-path")&&removePath(event.target.id),updateCode()}function text(id,content,x,y){let text=document.createElementNS("http://www.w3.org/2000/svg","text");return text.setAttribute("id",id),text.setAttribute("x",x),text.setAttribute("y",y),text.setAttribute("dx",15),text.setAttribute("dy",15),text.textContent=content,text}function clickHandler(event){if(event.preventDefault(),hideContextMenu(),hideAdvancedSettings(),event.target.classList.contains("learningmap-place")&&null===selectedElement)if(null===firstPlace)firstPlace=event.target.id,document.getElementById(firstPlace).classList.add("learningmap-selected");else{secondPlace=event.target.id;let fid=parseInt(firstPlace.replace("p","")),sid=parseInt(secondPlace.replace("p",""));if(sid==fid)return;if(sid0){let background=document.getElementById("learningmap-background-image"),backgroundurl=previewimage[0].getAttribute("src").split("?")[0];previewimage[0].getAttribute("src").split("?")[1].includes("&oid=")&&(backgroundurl+="?oid="+previewimage[0].getAttribute("src").split("&oid=")[1]),background.setAttribute("xlink:href",backgroundurl)}}function updateCSS(){_templates.default.renderForPromise("mod_learningmap/cssskeleton",_placestore.default.getPlacestore()).then((_ref=>{let{html:html,js:js}=_ref;return _templates.default.replaceNode("#learningmap-svgstyle",html,js),updateCode(),!0})).catch((ex=>(0,_notification.exception)(ex)))}function updateActivities(){let activities=_placestore.default.getAllActivities(),options=Array.from(activitySelector.getElementsByTagName("option"));activityHiddenWarning.setAttribute("hidden",""),options.forEach((function(n){activities.includes(n.value)?(n.classList.add("learningmap-used-activity"),n.selected&&1==n.getAttribute("data-activity-hidden")&&activityHiddenWarning.removeAttribute("hidden")):n.classList.remove("learningmap-used-activity")}))}function colorChooserLogic(name){let secondValue=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",colorChooser=document.getElementById("learningmap-color-"+name);colorChooser&&(colorChooser.addEventListener("change",(function(){_placestore.default.setColor(name,colorChooser.value),""!=secondValue&&_placestore.default.setColor(secondValue,colorChooser.value),updateCSS()})),colorChooser.value=_placestore.default.getColor(name))}function advancedSettingsLogic(name,getCall,setCall){let callback=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,settingItem=document.getElementById("learningmap-advanced-setting-"+name);settingItem&&(settingItem.checked=getCall.call(_placestore.default),settingItem.addEventListener("change",(function(){setCall.call(_placestore.default,settingItem.checked),null!==callback&&callback(),updateCSS()})))}function hideAdvancedSettings(){document.getElementById("learningmap-advanced-settings").setAttribute("hidden","")}}})); +define("mod_learningmap/learningmap",["exports","core/notification","core/templates","mod_learningmap/placestore","mod_learningmap/svg","./shapes"],(function(_exports,_notification,_templates,_placestore,_svg,_shapes){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_templates=_interopRequireDefault(_templates),_placestore=_interopRequireDefault(_placestore),_svg=_interopRequireDefault(_svg),_shapes=_interopRequireDefault(_shapes);const targetPoints_firstPoint=1,targetPoints_secondPoint=2,targetPoints_bezierPoint=3,pathTypes_line=1,pathTypes_quadraticbezier=2;_exports.init=()=>{var offset,dragel,pathsToUpdateFirstPoint,pathsToUpdateSecondPoint;_templates.default.prefetchTemplates(["mod_learningmap/cssskeleton"]);var selectedElement=null,firstPlace=null,secondPlace=null,lastTarget=null,elementForActivitySelector=null,touchstart=!1,touchend=!1,touchmove=0;let mapdiv=document.getElementById("learningmap-editor-map"),code=document.getElementById("id_svgcode"),activitySetting=document.getElementById("learningmap-activity-setting"),activitySelector=document.getElementById("learningmap-activity-selector"),activityStarting=document.getElementById("learningmap-activity-starting"),activityTarget=document.getElementById("learningmap-activity-target"),activityHiddenWarning=document.getElementById("learningmap-activity-hidden-warning"),advancedSettingsIcon=document.getElementById("learningmap-advanced-settings-icon"),treeView=document.querySelector(".fp-viewbar .fp-vb-tree");treeView&&treeView.setAttribute("style","display: none;");let iconView=document.querySelector(".fp-viewbar .fp-vb-icons");iconView&&setTimeout((()=>{iconView.dispatchEvent(new Event("click"))}),1e3),activitySelector&&(activitySelector.addEventListener("change",(function(){if(_placestore.default.setActivityId(elementForActivitySelector,activitySelector.value),activitySelector.value){let text=document.getElementById("text"+elementForActivitySelector);text&&(text.textContent=activitySelector.querySelector('option[value="'+activitySelector.value+'"]').textContent);let title=document.getElementById("title"+elementForActivitySelector);title&&(title.textContent=activitySelector.querySelector('option[value="'+activitySelector.value+'"]').textContent),document.getElementById(elementForActivitySelector).classList.remove("learningmap-emptyplace")}else document.getElementById(elementForActivitySelector).classList.add("learningmap-emptyplace");updateActivities(),updateCode()})),activityStarting.addEventListener("change",(function(){activityStarting.checked?_placestore.default.addStartingPlace(elementForActivitySelector):_placestore.default.removeStartingPlace(elementForActivitySelector),updateCode()})),activityTarget.addEventListener("change",(function(){activityTarget.checked?(_placestore.default.addTargetPlace(elementForActivitySelector),document.getElementById(elementForActivitySelector).classList.add("learningmap-targetplace")):(_placestore.default.removeTargetPlace(elementForActivitySelector),document.getElementById(elementForActivitySelector).classList.remove("learningmap-targetplace")),updateCode()})));let placestoreInput=document.getElementsByName("placestore")[0];if(placestoreInput&&_placestore.default.loadJSON(placestoreInput.value),updateActivities(),advancedSettingsIcon){let advancedSettings=document.getElementById("learningmap-advanced-settings");advancedSettingsIcon.addEventListener("click",(function(){null===advancedSettings.getAttribute("hidden")?hideAdvancedSettings():(advancedSettings.removeAttribute("hidden"),hideContextMenu())}));let advancedSettingsClose=document.getElementById("learningmap-advanced-settings-close");advancedSettingsClose&&advancedSettingsClose.addEventListener("click",(function(){advancedSettings.setAttribute("hidden","")})),advancedSettingsLogic("hidepaths",_placestore.default.getHidePaths,_placestore.default.setHidePaths),advancedSettingsLogic("usecheckmark",_placestore.default.getUseCheckmark,_placestore.default.setUseCheckmark),advancedSettingsLogic("hover",_placestore.default.getHover,_placestore.default.setHover),advancedSettingsLogic("pulse",_placestore.default.getPulse,_placestore.default.setPulse),advancedSettingsLogic("showall",_placestore.default.getShowall,_placestore.default.setShowall),advancedSettingsLogic("hidestroke",_placestore.default.getHideStroke,_placestore.default.setHideStroke),advancedSettingsLogic("showtext",_placestore.default.getShowText,_placestore.default.setShowText,(function(){let options=Array.from(activitySelector.getElementsByTagName("option")),places=_placestore.default.getPlaces();for(const place of places)if(null===document.getElementById("text"+place.id)){let content="";for(const option of options)if(option.value==place.linkedActivity){content=option.textContent;break}let placeNode=mapsvg.findOne("#"+place.id);text("text"+place.id,content,placeNode.cx(),placeNode.cy()).addTo(placeNode.parent())}})),advancedSettingsLogic("slicemode",_placestore.default.getSliceMode,_placestore.default.setSliceMode),advancedSettingsLogic("showwaygone",_placestore.default.getShowWayGone,_placestore.default.setShowWayGone)}colorChooserLogic("stroke","text"),colorChooserLogic("place"),colorChooserLogic("visited"),code&&mapdiv&&(mapdiv.innerHTML=code.value),refreshBackgroundImage(),function(){let background=document.getElementById("learningmap-background-image");background&&background.addEventListener("load",(function(){background.removeAttribute("height");let height=parseInt(background.getBBox().height),width=background.getBBox().width;_placestore.default.setBackgroundDimensions(width,height),svgel.setAttribute("viewBox","0 0 "+_placestore.default.width+" "+_placestore.default.height),background.setAttribute("width",width),background.setAttribute("height",height),updateCode()}))}(),updateCode();let svgel=document.getElementById("learningmap-svgmap-"+_placestore.default.getMapid());!function(el){dragel=el,el&&(el.addEventListener("mousedown",startDrag),el.addEventListener("mousemove",drag),el.addEventListener("mouseup",endDrag),el.addEventListener("mouseleave",endDrag),el.addEventListener("touchstart",(function(evt){evt.cancelable&&evt.preventDefault();evt.target.classList.contains("learningmap-draggable")||"text"==evt.target.nodeName||"path"==evt.target.nodeName?(touchstart?(dblclickHandler(evt),touchstart=!1):(touchstart=!0,touchmove=0,touchend=!1,setTimeout((evt=>{touchmove<3&&!touchend&&(evt.touches&&(evt=evt.touches[0]),showContextMenu(evt))}),2e3,evt),setTimeout((()=>{touchstart=!1}),300)),startDrag(evt)):touchstart?(dblclickHandler(evt),touchstart=!1):(touchstart=!0,touchend=!1,touchmove=0,setTimeout((()=>{touchstart=!1}),300))})),el.addEventListener("touchmove",drag),el.addEventListener("touchend",endTouch),el.addEventListener("touchleave",endTouch),el.addEventListener("touchcancel",endTouch));function startDrag(evt){if(evt.cancelable&&evt.preventDefault(),pathsToUpdateFirstPoint=[],pathsToUpdateSecondPoint=[],evt.target.classList.contains("learningmap-draggable")){let svgel=getSVGShape(selectedElement=evt.target);(offset=getMousePosition(evt)).x-=svgel.cx(),offset.y-=svgel.cy(),pathsToUpdateFirstPoint=_placestore.default.getPathsWithFid(evt.target.id),pathsToUpdateSecondPoint=_placestore.default.getPathsWithSid(evt.target.id)}else if("text"==evt.target.nodeName){let svgel=getSVGShape(selectedElement=evt.target),place=svgel.parent().findOne(".learningmap-place");(offset=getMousePosition(evt)).x-=svgel.attr("dx")+place.cx(),offset.y-=svgel.attr("dy")+place.cy()}else if("path"==evt.target.nodeName){selectedElement=evt.target,offset=getMousePosition(evt);let pathPoint=transformCoordinates(evt.layerX,evt.layerY);offset.x+=pathPoint.x,offset.y+=pathPoint.y}}function drag(evt){if(evt.cancelable&&evt.preventDefault(),touchmove++,selectedElement){var coord=getMousePosition(evt);let cx=coord.x-offset.x,cy=coord.y-offset.y;console.log(selectedElement);let closest=selectedElement.closest(".learningmap-place");if(console.log(closest),closest&&(selectedElement=closest),selectedElement.classList.contains("learningmap-place")){let placeel=mapsvg.findOne("#"+selectedElement.id);placeel.center(cx,cy);let textNode=mapsvg.findOne("#text"+selectedElement.id);null!==textNode&&textNode.amove(cx,cy),pathsToUpdateFirstPoint.forEach((function(path){let pathElement=getSVGShape(path);null!==pathElement&&("path"==pathElement.type?pathElement.attr({d:updatePathDeclaration(pathElement.attr("d"),cx,cy,targetPoints_firstPoint)}):pathElement.attr({x1:cx,y1:cy}))})),pathsToUpdateSecondPoint.forEach((function(path){let pathElement=getSVGShape(path);null!==pathElement&&("path"==pathElement.type?pathElement.attr({d:updatePathDeclaration(pathElement.attr("d"),cx,cy,targetPoints_secondPoint)}):pathElement.attr({x2:cx,y2:cy}))})),_placestore.default.setBbox(selectedElement.id,placeel.parent().bbox())}else if("text"==selectedElement.nodeName){let textel=getSVGShape(selectedElement),place=textel.parent().findOne(".learningmap-place"),dx=cx-place.cx(),dy=cy-place.cy();textel.attr({dx:dx,dy:dy}),_placestore.default.setBbox(place.node.id,textel.parent().bbox())}else"path"==selectedElement.nodeName&&selectedElement.setAttribute("d",updatePathDeclaration(selectedElement.getAttribute("d"),coord.x,coord.y,targetPoints_bezierPoint))}}function endDrag(evt){evt.cancelable&&evt.preventDefault(),selectedElement=null,unselectAll(),updateCode()}function endTouch(evt){selectedElement=null,touchend=!0,touchmove<3&&touchstart?clickHandler(evt):endDrag(evt),evt.cancelable&&evt.preventDefault()}function updatePathDeclaration(oldDefinition,targetX,targetY){let targetP=arguments.length>3&&void 0!==arguments[3]?arguments[3]:targetPoints_firstPoint,parts=oldDefinition.split(" "),fromX=0,fromY=0,toX=0,toY=0,bezierX=0,bezierY=0,pathType=pathTypes_line;for(let i=0;i2&&void 0!==arguments[2]?arguments[2]:null,text=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;return mapsvg.link("").id(id).add(child).add(title).add(text)}(_shapes.default.emoji(mapsvg,cx,cy,10,"learningmap-place learningmap-draggable learningmap-emptyplace",placeId),linkId,(id="title"+placeId,mapsvg.element("title").id(id)),text("text"+placeId,"",cx,cy));var id;svglink.addTo(placesgroup),_placestore.default.addPlace(placeId,linkId,null,svglink.bbox())}(event):event.target.classList.contains("learningmap-place")?lastTarget==event.target.id?(lastTarget=null,clickHandler(event)):function(event){let place=getSVGShape(event.target.id);id=event.target.id,_placestore.default.getTouchingPaths(id).forEach((function(e){removePath(e.id)})),_placestore.default.removePlace(event.target.id),place.parent().remove(),updateCode();var id}(event):event.target.classList.contains("learningmap-path")&&removePath(event.target.id),updateCode()}function text(id,content,x,y){return mapsvg.text().attr({dx:15,dy:15}).plain(content).move(x,y).id(id)}function clickHandler(event){if(event.preventDefault(),hideContextMenu(),hideAdvancedSettings(),event.target.classList.contains("learningmap-place")&&null===selectedElement)if(null===firstPlace)firstPlace=event.target.id,document.getElementById(firstPlace).classList.add("learningmap-selected");else{secondPlace=event.target.id;let fid=parseInt(firstPlace.replace("p","")),sid=parseInt(secondPlace.replace("p",""));if(sid==fid)return;if(sid0){let background=document.getElementById("learningmap-background-image"),backgroundurl=previewimage[0].getAttribute("src").split("?")[0];previewimage[0].getAttribute("src").split("?")[1].includes("&oid=")&&(backgroundurl+="?oid="+previewimage[0].getAttribute("src").split("&oid=")[1]),background.setAttribute("xlink:href",backgroundurl)}}function updateCSS(){_templates.default.renderForPromise("mod_learningmap/cssskeleton",_placestore.default.getPlacestore()).then((_ref=>{let{html:html,js:js}=_ref;return _templates.default.replaceNode("#learningmap-svgstyle",html,js),updateCode(),!0})).catch((ex=>(0,_notification.exception)(ex)))}function updateActivities(){let activities=_placestore.default.getAllActivities(),options=Array.from(activitySelector.getElementsByTagName("option"));activityHiddenWarning.setAttribute("hidden",""),options.forEach((function(n){activities.includes(n.value)?(n.classList.add("learningmap-used-activity"),n.selected&&1==n.getAttribute("data-activity-hidden")&&activityHiddenWarning.removeAttribute("hidden")):n.classList.remove("learningmap-used-activity")}))}function colorChooserLogic(name){let secondValue=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",colorChooser=document.getElementById("learningmap-color-"+name);colorChooser&&(colorChooser.addEventListener("change",(function(){_placestore.default.setColor(name,colorChooser.value),""!=secondValue&&_placestore.default.setColor(secondValue,colorChooser.value),updateCSS()})),colorChooser.value=_placestore.default.getColor(name))}function advancedSettingsLogic(name,getCall,setCall){let callback=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,settingItem=document.getElementById("learningmap-advanced-setting-"+name);settingItem&&(settingItem.checked=getCall.call(_placestore.default),settingItem.addEventListener("change",(function(){setCall.call(_placestore.default,settingItem.checked),null!==callback&&callback(),updateCSS()})))}function hideAdvancedSettings(){document.getElementById("learningmap-advanced-settings").setAttribute("hidden","")}}})); //# sourceMappingURL=learningmap.min.js.map \ No newline at end of file diff --git a/amd/build/learningmap.min.js.map b/amd/build/learningmap.min.js.map index c79bdf7..c416499 100644 --- a/amd/build/learningmap.min.js.map +++ b/amd/build/learningmap.min.js.map @@ -1 +1 @@ -{"version":3,"file":"learningmap.min.js","sources":["../src/learningmap.js"],"sourcesContent":["import {exception as displayException} from 'core/notification';\nimport Templates from 'core/templates';\nimport placestore from 'mod_learningmap/placestore';\n\nconst circleRadius = 10;\n\n// Constants for updatePathDeclaration.\nconst targetPoints = {\n firstPoint: 1,\n secondPoint: 2,\n bezierPoint: 3,\n};\n\nconst pathTypes = {\n line: 1,\n quadraticbezier: 2,\n};\n\nexport const init = () => {\n // Load the needed template on startup for better execution speed.\n Templates.prefetchTemplates(['mod_learningmap/cssskeleton']);\n\n // Variable for storing the mouse offset\n var offset;\n\n // Variable for draggable element\n var dragel;\n\n // Variables for storing the paths that need update of the first or\n // the second coordinates.\n var pathsToUpdateFirstPoint, pathsToUpdateSecondPoint;\n\n // Variables for handling the currently selected elements\n var selectedElement = null,\n firstPlace = null,\n secondPlace = null,\n lastTarget = null;\n\n // Variable for storing the selected element for the activity selector\n var elementForActivitySelector = null;\n\n // Variables for simulating double click on touch devices, set when the\n // corresponding events are handled\n var touchstart = false;\n var touchend = false;\n // Counter for touchmove events\n var touchmove = 0;\n\n // DOM nodes for the editor\n let mapdiv = document.getElementById('learningmap-editor-map');\n let code = document.getElementById('id_svgcode');\n\n // DOM nodes for the activity selector\n let activitySetting = document.getElementById('learningmap-activity-setting');\n let activitySelector = document.getElementById('learningmap-activity-selector');\n let activityStarting = document.getElementById('learningmap-activity-starting');\n let activityTarget = document.getElementById('learningmap-activity-target');\n let activityHiddenWarning = document.getElementById('learningmap-activity-hidden-warning');\n let advancedSettingsIcon = document.getElementById('learningmap-advanced-settings-icon');\n\n // Hide tree view as there is no preview file we can attach to\n let treeView = document.querySelector('.fp-viewbar .fp-vb-tree');\n if (treeView) {\n treeView.setAttribute('style', 'display: none;');\n }\n\n // Trigger click event on icon view to ensure that tree view is not active.\n let iconView = document.querySelector('.fp-viewbar .fp-vb-icons');\n if (iconView) {\n // Handle possible delay in form loading.\n setTimeout(() => {\n iconView.dispatchEvent(new Event('click'));\n }, 1000);\n }\n\n // Attach listeners to the activity selector\n if (activitySelector) {\n // Show places that are not linked to an activity\n activitySelector.addEventListener('change', function() {\n placestore.setActivityId(elementForActivitySelector, activitySelector.value);\n if (activitySelector.value) {\n let text = document.getElementById('text' + elementForActivitySelector);\n if (text) {\n text.textContent = activitySelector.querySelector('option[value=\"' + activitySelector.value + '\"]').textContent;\n }\n let title = document.getElementById('title' + elementForActivitySelector);\n if (title) {\n title.textContent =\n activitySelector.querySelector('option[value=\"' + activitySelector.value + '\"]').textContent;\n }\n document.getElementById(elementForActivitySelector).classList.remove('learningmap-emptyplace');\n } else {\n document.getElementById(elementForActivitySelector).classList.add('learningmap-emptyplace');\n }\n updateActivities();\n updateCode();\n });\n // Add / remove a place to the starting places array\n activityStarting.addEventListener('change', function() {\n if (activityStarting.checked) {\n placestore.addStartingPlace(elementForActivitySelector);\n } else {\n placestore.removeStartingPlace(elementForActivitySelector);\n }\n updateCode();\n });\n // Add / remove a place to the target places array\n activityTarget.addEventListener('change', function() {\n if (activityTarget.checked) {\n placestore.addTargetPlace(elementForActivitySelector);\n document.getElementById(elementForActivitySelector).classList.add('learningmap-targetplace');\n } else {\n placestore.removeTargetPlace(elementForActivitySelector);\n document.getElementById(elementForActivitySelector).classList.remove('learningmap-targetplace');\n }\n updateCode();\n });\n }\n\n // Load placestore values from the hidden input field\n let placestoreInput = document.getElementsByName('placestore')[0];\n if (placestoreInput) {\n placestore.loadJSON(placestoreInput.value);\n }\n\n // Mark all activities in the placestore as \"used\".\n updateActivities();\n\n // Attach listeners to the advanced settings div\n if (advancedSettingsIcon) {\n let advancedSettings = document.getElementById('learningmap-advanced-settings');\n advancedSettingsIcon.addEventListener('click', function() {\n if (advancedSettings.getAttribute('hidden') === null) {\n hideAdvancedSettings();\n } else {\n advancedSettings.removeAttribute('hidden');\n hideContextMenu();\n }\n });\n let advancedSettingsClose = document.getElementById('learningmap-advanced-settings-close');\n if (advancedSettingsClose) {\n advancedSettingsClose.addEventListener('click', function() {\n advancedSettings.setAttribute('hidden', '');\n });\n }\n\n advancedSettingsLogic('hidepaths', placestore.getHidePaths, placestore.setHidePaths);\n advancedSettingsLogic('usecheckmark', placestore.getUseCheckmark, placestore.setUseCheckmark);\n advancedSettingsLogic('hover', placestore.getHover, placestore.setHover);\n advancedSettingsLogic('pulse', placestore.getPulse, placestore.setPulse);\n advancedSettingsLogic('showall', placestore.getShowall, placestore.setShowall);\n advancedSettingsLogic('hidestroke', placestore.getHideStroke, placestore.setHideStroke);\n advancedSettingsLogic('showtext', placestore.getShowText, placestore.setShowText, fixPlaceLabels);\n advancedSettingsLogic('slicemode', placestore.getSliceMode, placestore.setSliceMode);\n advancedSettingsLogic('showwaygone', placestore.getShowWayGone, placestore.setShowWayGone);\n }\n\n // Attach listener to the color choosers\n colorChooserLogic('stroke', 'text');\n colorChooserLogic('place');\n colorChooserLogic('visited');\n\n // Get SVG code from the (hidden) textarea field\n if (code && mapdiv) {\n mapdiv.innerHTML = code.value;\n }\n // Reload background image to get the correct width and height values\n refreshBackgroundImage();\n registerBackgroundListener();\n updateCode();\n\n // Enable dragging of places\n let svg = document.getElementById('learningmap-svgmap-' + placestore.getMapid());\n makeDraggable(svg);\n\n // Refresh stylesheet values from placestore\n updateCSS();\n\n // Add listeners for clicking and context menu\n if (mapdiv) {\n mapdiv.addEventListener('dblclick', dblclickHandler);\n mapdiv.addEventListener('click', clickHandler);\n\n mapdiv.addEventListener('contextmenu', function(e) {\n e.preventDefault();\n showContextMenu(e);\n }, false);\n }\n /**\n * Shows the context menu at the current mouse position\n * @param {*} e\n */\n function showContextMenu(e) {\n unselectAll();\n hideAdvancedSettings();\n // Check for the existence of the target (could have vanished since the event started).\n if (activitySetting && document.getElementById(e.target.id) !== null) {\n if (e.touches) {\n e = e.touches[0];\n }\n if (e.target.classList.contains('learningmap-place')) {\n e.target.classList.add('learningmap-selected-activity-selector');\n let activityId = placestore.getActivityId(e.target.id);\n let scalingFactor = mapdiv.clientWidth / 800;\n activitySetting.style.setProperty('--pos-x', e.target.cx.baseVal.value * scalingFactor + 'px');\n activitySetting.style.setProperty('--pos-y', e.target.cy.baseVal.value * scalingFactor + 'px');\n activitySetting.style.setProperty('--map-width', mapdiv.clientWidth + 'px');\n activitySetting.style.setProperty('--map-height', mapdiv.clientHeight + 'px');\n activitySetting.style.display = 'block';\n document.getElementById('learningmap-activity-selector').value = activityId;\n document.getElementById('learningmap-activity-starting').checked = placestore.isStartingPlace(e.target.id);\n document.getElementById('learningmap-activity-target').checked = placestore.isTargetPlace(e.target.id);\n elementForActivitySelector = e.target.id;\n updateActivities();\n } else {\n hideContextMenu();\n hideAdvancedSettings();\n }\n }\n }\n\n /**\n * Hides the context menu\n */\n function hideContextMenu() {\n let e = document.getElementById(elementForActivitySelector);\n if (e) {\n e.classList.remove('learningmap-selected-activity-selector');\n }\n activitySetting.style.display = 'none';\n }\n\n let backgroundfileNode = document.getElementById('id_backgroundfile_fieldset');\n if (backgroundfileNode) {\n let observer = new MutationObserver(refreshBackgroundImage);\n observer.observe(backgroundfileNode, {attributes: true, childList: true, subtree: true});\n }\n\n /**\n * Helper function for getting the right coordinates from the mouse\n * @param {*} evt\n * @returns {object}\n */\n function getMousePosition(evt) {\n if (evt.touches) {\n evt = evt.touches[0];\n }\n return transformCoordinates(evt.clientX, evt.clientY);\n }\n\n /**\n * Transforms client coordinates to SVG coordinates\n * @param {number} x x coordinate to transform\n * @param {number} y y coordinate to transform\n * @returns {object} Object containing transformed x and y coordinate\n */\n function transformCoordinates(x, y) {\n var CTM = dragel.getScreenCTM();\n return {\n x: (x - CTM.e) / CTM.a,\n y: (y - CTM.f) / CTM.d\n };\n }\n\n /**\n * Enables dragging on an DOM node\n * @param {*} el\n */\n function makeDraggable(el) {\n dragel = el;\n if (el) {\n el.addEventListener('mousedown', startDrag);\n el.addEventListener('mousemove', drag);\n el.addEventListener('mouseup', endDrag);\n el.addEventListener('mouseleave', endDrag);\n el.addEventListener('touchstart', startTouch);\n el.addEventListener('touchmove', drag);\n el.addEventListener('touchend', endTouch);\n el.addEventListener('touchleave', endTouch);\n el.addEventListener('touchcancel', endTouch);\n }\n\n /**\n * Function called whenn dragging starts.\n * @param {*} evt\n */\n function startDrag(evt) {\n if (evt.cancelable) {\n evt.preventDefault();\n }\n pathsToUpdateFirstPoint = [];\n pathsToUpdateSecondPoint = [];\n if (evt.target.classList.contains('learningmap-draggable')) {\n selectedElement = evt.target;\n offset = getMousePosition(evt);\n offset.x -= parseInt(selectedElement.getAttributeNS(null, \"cx\"));\n offset.y -= parseInt(selectedElement.getAttributeNS(null, \"cy\"));\n // Get paths that need to be updated.\n pathsToUpdateFirstPoint = placestore.getPathsWithFid(selectedElement.id);\n pathsToUpdateSecondPoint = placestore.getPathsWithSid(selectedElement.id);\n } else if (evt.target.nodeName == 'text') {\n selectedElement = evt.target;\n let place = selectedElement.parentNode.querySelector('.learningmap-place');\n offset = getMousePosition(evt);\n offset.x -= parseInt(selectedElement.getAttributeNS(null, \"dx\")) + place.cx.baseVal.value;\n offset.y -= parseInt(selectedElement.getAttributeNS(null, \"dy\")) + place.cy.baseVal.value;\n } else if (evt.target.nodeName == 'path') {\n selectedElement = evt.target;\n offset = getMousePosition(evt);\n let pathPoint = transformCoordinates(evt.layerX, evt.layerY);\n offset.x += pathPoint.x;\n offset.y += pathPoint.y;\n }\n }\n\n /**\n * Function called during dragging. Continuously updates circles center coordinates and the\n * coordinates of the touching paths.\n * @param {*} evt\n */\n function drag(evt) {\n if (evt.cancelable) {\n evt.preventDefault();\n }\n // Count touchmove events\n touchmove++;\n if (selectedElement) {\n var coord = getMousePosition(evt);\n let cx = coord.x - offset.x;\n let cy = coord.y - offset.y;\n if (selectedElement.nodeName == 'text') {\n let place = selectedElement.parentNode.querySelector('.learningmap-place');\n // Calculate the delta from the current mouse position to the corresponding place.\n // coord: current mouse position\n // offset: delta from the mouse position to the coordinates of the text node\n let dx = coord.x - offset.x - place.cx.baseVal.value;\n let dy = coord.y - offset.y - place.cy.baseVal.value;\n selectedElement.setAttributeNS(null, \"dx\", dx);\n selectedElement.setAttributeNS(null, \"dy\", dy);\n }\n if (selectedElement.nodeName == 'path') {\n selectedElement.setAttribute(\n 'd',\n updatePathDeclaration(selectedElement.getAttribute('d'), coord.x, coord.y, targetPoints.bezierPoint)\n );\n }\n if (selectedElement.nodeName == 'circle') {\n selectedElement.setAttributeNS(null, \"cx\", cx);\n selectedElement.setAttributeNS(null, \"cy\", cy);\n let textNode = document.getElementById('text' + selectedElement.id);\n if (textNode !== null) {\n textNode.setAttributeNS(null, 'x', cx);\n textNode.setAttributeNS(null, 'y', cy);\n }\n pathsToUpdateFirstPoint.forEach(function(path) {\n let pathNode = document.getElementById(path.id);\n if (pathNode !== null) {\n if (pathNode.nodeName == 'path') {\n pathNode.setAttribute(\n 'd',\n updatePathDeclaration(pathNode.getAttribute('d'), cx, cy, targetPoints.firstPoint)\n );\n } else {\n pathNode.setAttribute('x1', cx);\n pathNode.setAttribute('y1', cy);\n }\n }\n });\n\n pathsToUpdateSecondPoint.forEach(function(path) {\n let pathNode = document.getElementById(path.id);\n if (pathNode !== null) {\n if (pathNode.nodeName == 'path') {\n pathNode.setAttribute(\n 'd',\n updatePathDeclaration(pathNode.getAttribute('d'), cx, cy, targetPoints.secondPoint)\n );\n } else {\n pathNode.setAttribute('x2', cx);\n pathNode.setAttribute('y2', cy);\n }\n }\n });\n }\n }\n }\n\n /**\n * Function called when dragging ends.\n * @param {*} evt\n */\n function endDrag(evt) {\n if (evt.cancelable) {\n evt.preventDefault();\n }\n selectedElement = null;\n unselectAll();\n updateCode();\n }\n\n /**\n * Function called when touchstart event occurs.\n * @param {*} evt\n */\n function startTouch(evt) {\n if (evt.cancelable) {\n evt.preventDefault();\n }\n if (\n evt.target.classList.contains('learningmap-draggable') ||\n evt.target.nodeName == 'text' ||\n evt.target.nodeName == 'path'\n ) {\n if (!touchstart) {\n touchstart = true;\n touchmove = 0;\n touchend = false;\n setTimeout(\n (evt) => {\n if (touchmove < 3 && !touchend) {\n if (evt.touches) {\n evt = evt.touches[0];\n }\n showContextMenu(evt);\n }\n },\n 2000,\n evt\n );\n setTimeout(\n () => {\n touchstart = false;\n },\n 300);\n } else {\n dblclickHandler(evt);\n touchstart = false;\n }\n startDrag(evt);\n } else {\n if (!touchstart) {\n touchstart = true;\n touchend = false;\n touchmove = 0;\n setTimeout(\n () => {\n touchstart = false;\n },\n 300);\n } else {\n dblclickHandler(evt);\n touchstart = false;\n }\n }\n }\n\n /**\n * Function called when touchend, touchleave or touchcancel event occurs.\n * @param {*} evt\n */\n function endTouch(evt) {\n selectedElement = null;\n touchend = true;\n // If there was only a small move (<3 move events), this also counts as a click.\n if (touchmove < 3 && touchstart) {\n clickHandler(evt);\n } else {\n endDrag(evt);\n }\n if (evt.cancelable) {\n evt.preventDefault();\n }\n }\n\n /**\n * Updates the path declaration of lines and quadratic bezier curves setting one of the points.\n * @param {string} oldDefinition SVG path definition string\n * @param {number} targetX x coordinate of the point to set\n * @param {number} targetY y coordinate of the point to set\n * @param {number} targetP Which point to change (you can use the targetPoints constants here)\n * @returns {string} Updated SVG path definition\n */\n function updatePathDeclaration(oldDefinition, targetX, targetY, targetP = targetPoints.firstPoint) {\n let parts = oldDefinition.split(' ');\n let fromX = 0;\n let fromY = 0;\n let toX = 0;\n let toY = 0;\n let bezierX = 0;\n let bezierY = 0;\n let pathType = pathTypes.line;\n\n // The d attribute of an SVG path in a learning map can have two different formats (in this version):\n // \"M x1 y1 L x2 y2\" Line from x1, y1 to x2, y2\n // \"M x1 y2 Q x3 y3 x2 y2\" Quadratic bezier curve inside the triangle defined by x1, y1, x2, y2 and x3, y3.\n for (let i = 0; i < parts.length; i++) {\n // Every path contains the first point in that way.\n if (parts[i] == 'M') {\n fromX = parseInt(parts[i + 1]);\n fromY = parseInt(parts[i + 2]);\n i += 2;\n }\n // This path is a direct line, so there are only two points in total.\n if (parts[i] == 'L') {\n toX = parseInt(parts[i + 1]);\n toY = parseInt(parts[i + 2]);\n i += 2;\n }\n // This path is a bezier curve, there are three points in total.\n if (parts[i] == 'Q') {\n bezierX = parseInt(parts[i + 1]);\n bezierY = parseInt(parts[i + 2]);\n toX = parseInt(parts[i + 3]);\n toY = parseInt(parts[i + 4]);\n i += 4;\n pathType = pathTypes.quadraticbezier;\n }\n }\n\n switch (targetP) {\n case targetPoints.firstPoint:\n fromX = targetX;\n fromY = targetY;\n break;\n case targetPoints.secondPoint:\n toX = targetX;\n toY = targetY;\n break;\n case targetPoints.bezierPoint:\n // Calculate the third triangle point for the bezier curve.\n bezierX = targetX * 2 - (fromX + toX) * 0.5;\n bezierY = targetY * 2 - (fromY + toY) * 0.5;\n pathType = pathTypes.quadraticbezier;\n break;\n }\n\n if (pathType == pathTypes.quadraticbezier) {\n return 'M ' + fromX + ' ' + fromY + ' Q ' + bezierX + ' ' + bezierY + ', ' + toX + ' ' + toY;\n } else {\n return 'M ' + fromX + ' ' + fromY + ' L ' + toX + ' ' + toY;\n }\n }\n }\n\n /**\n * Updates the form fields for the SVG code and the placestore from the editor.\n */\n function updateCode() {\n if (code && mapdiv) {\n code.innerHTML = mapdiv.innerHTML;\n }\n if (placestoreInput) {\n document.getElementsByName('placestore')[0].value = JSON.stringify(placestore.getPlacestore());\n }\n }\n\n /**\n * Handles double clicks on the map\n * @param {*} event\n */\n function dblclickHandler(event) {\n hideContextMenu();\n hideAdvancedSettings();\n unselectAll();\n if (event.target.classList.contains('learningmap-mapcontainer') ||\n event.target.classList.contains('learningmap-background-image')) {\n addPlace(event);\n } else if (event.target.classList.contains('learningmap-place')) {\n if (lastTarget == event.target.id) {\n lastTarget = null;\n clickHandler(event);\n } else {\n removePlace(event);\n }\n } else if (event.target.classList.contains('learningmap-path')) {\n removePath(event.target.id);\n }\n updateCode();\n }\n\n /**\n * Returns an empty title tag with the given id.\n * @param {*} id id for the title\n * @returns {any}\n */\n function title(id) {\n let title = document.createElementNS('http://www.w3.org/2000/svg', 'title');\n title.setAttribute('id', id);\n return title;\n }\n\n /**\n * Returns an text tag with the given id.\n * @param {*} id id for the text\n * @param {*} content content of the tag\n * @param {*} x x coordinate of the text\n * @param {*} y y coordinate of the text\n * @returns {any}\n */\n function text(id, content, x, y) {\n let text = document.createElementNS('http://www.w3.org/2000/svg', 'text');\n text.setAttribute('id', id);\n text.setAttribute('x', x);\n text.setAttribute('y', y);\n // Default value for delta: Circle radius * 1.5 (as a padding)\n text.setAttribute('dx', circleRadius * 1.5);\n text.setAttribute('dy', circleRadius * 1.5);\n text.textContent = content;\n return text;\n }\n\n /**\n * Returns a circle tag with the given dimensions.\n * @param {*} x x coordinate of the center\n * @param {*} y y coordinate of the center\n * @param {*} r radius\n * @param {*} classes classes to add\n * @param {*} id id of the circle\n * @returns {any}\n */\n function circle(x, y, r, classes, id) {\n let circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');\n circle.setAttribute('class', classes);\n circle.setAttribute('id', id);\n circle.setAttribute('cx', x);\n circle.setAttribute('cy', y);\n circle.setAttribute('r', r);\n return circle;\n }\n\n /**\n * Returns a path between two points.\n * @param {*} x1 x coordinate of the first point\n * @param {*} y1 y coordinate of the first point\n * @param {*} x2 x coordinate of the second point\n * @param {*} y2 y coordinate of the second point\n * @param {*} classes CSS classes to set\n * @param {*} id id of the path\n * @returns {any}\n */\n function path(x1, y1, x2, y2, classes, id) {\n let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n path.setAttribute('class', classes);\n path.setAttribute('id', id);\n path.setAttribute('d', 'M ' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2);\n return path;\n }\n\n /**\n * Returns a link around a given child element. This function also adds a title element next\n * to the child for accessibility.\n * @param {*} child child item to set the link on\n * @param {*} id id of the link\n * @param {*} title title of the link\n * @param {*} text text to describe the link\n * @returns {any}\n */\n function link(child, id, title = null, text = null) {\n let link = document.createElementNS('http://www.w3.org/2000/svg', 'a');\n link.setAttribute('id', id);\n link.setAttribute('xlink:href', '');\n link.appendChild(child);\n if (title !== null) {\n link.appendChild(title);\n }\n if (text !== null) {\n link.appendChild(text);\n }\n return link;\n }\n\n /**\n * Adds a place on the SVG map. This function also prepares the code for linking activities\n * and adding titles (for accessibility).\n * @param {*} event event causing the command\n */\n function addPlace(event) {\n let placesgroup = document.getElementById('placesGroup');\n let placeId = 'p' + placestore.getId();\n let linkId = 'a' + placestore.getId();\n var CTM = event.target.getScreenCTM();\n if (event.touches) {\n event = event.touches[0];\n }\n let cx = (event.clientX - CTM.e) / CTM.a;\n let cy = (event.clientY - CTM.f) / CTM.d;\n placesgroup.appendChild(\n link(\n circle(cx, cy, circleRadius, 'learningmap-place learningmap-draggable learningmap-emptyplace', placeId),\n linkId,\n title('title' + placeId),\n text('text' + placeId, '', cx, cy)\n )\n );\n placestore.addPlace(placeId, linkId);\n }\n\n /**\n * Handles single clicks on the background image.\n * @param {*} event click event\n * @returns {void}\n */\n function clickHandler(event) {\n event.preventDefault();\n hideContextMenu();\n hideAdvancedSettings();\n if (event.target.classList.contains('learningmap-place') && selectedElement === null) {\n if (firstPlace === null) {\n firstPlace = event.target.id;\n document.getElementById(firstPlace).classList.add('learningmap-selected');\n } else {\n secondPlace = event.target.id;\n let fid = parseInt(firstPlace.replace('p', ''));\n let sid = parseInt(secondPlace.replace('p', ''));\n if (sid == fid) {\n return;\n }\n if (sid < fid) {\n let z = sid;\n sid = fid;\n fid = z;\n }\n addPath(fid, sid);\n let first = document.getElementById(firstPlace);\n if (first) {\n first.classList.remove('learningmap-selected');\n }\n firstPlace = null;\n lastTarget = secondPlace;\n secondPlace = null;\n }\n } else {\n unselectAll();\n firstPlace = null;\n }\n }\n /**\n * Removes the classes 'learningmap-selected' and 'learningmap-selectet-activity-selector'\n * from all nodes\n */\n function unselectAll() {\n Array.from(document.getElementsByClassName('learningmap-selected')).forEach(function(e) {\n e.classList.remove('learningmap-selected');\n });\n Array.from(document.getElementsByClassName('learningmap-selected-activity-selector')).forEach(function(e) {\n e.classList.remove('learningmap-selected-activity-selector');\n });\n }\n\n /**\n * Adds a path between two places.\n * @param {number} fid id of the first place (meant to be the smaller one)\n * @param {number} sid id of the second place (meant to be the bigger one)\n */\n function addPath(fid, sid) {\n let pid = 'p' + fid + '_' + sid;\n if (document.getElementById(pid) === null) {\n let pathsgroup = document.getElementById('pathsGroup');\n let first = document.getElementById('p' + fid);\n let second = document.getElementById('p' + sid);\n if (pathsgroup && first && second) {\n pathsgroup.appendChild(\n path(\n first.cx.baseVal.value,\n first.cy.baseVal.value,\n second.cx.baseVal.value,\n second.cy.baseVal.value,\n 'learningmap-path',\n pid\n )\n );\n placestore.addPath(pid, 'p' + fid, 'p' + sid);\n }\n }\n }\n\n /**\n * Removes a place from the SVG and the placestore. This function also removes all\n * touching paths and entries in statringplaces / targetplaces linking to the removed\n * place.\n * @param {any} event event causing the remove order\n */\n function removePlace(event) {\n let place = document.getElementById(event.target.id);\n let parent = place.parentNode;\n removePathsTouchingPlace(event.target.id);\n placestore.removePlace(event.target.id);\n parent.removeChild(place);\n parent.parentNode.removeChild(parent);\n\n updateCode();\n }\n\n /**\n * Removes all paths touching a certain place\n * @param {number} id id of the place\n */\n function removePathsTouchingPlace(id) {\n placestore.getTouchingPaths(id).forEach(\n function(e) {\n removePath(e.id);\n }\n );\n }\n\n /**\n * Removes a path from the SVG and from the placestore\n * @param {number} id id of the path\n */\n function removePath(id) {\n let path = document.getElementById(id);\n if (path !== null) {\n path.parentNode.removeChild(path);\n placestore.removePath(id);\n }\n }\n\n /**\n * Sets the background image of the SVG to the current image in filemanager.\n */\n function refreshBackgroundImage() {\n let previewimage = document.getElementsByClassName('realpreview');\n if (previewimage.length > 0) {\n let background = document.getElementById('learningmap-background-image');\n let backgroundurl = previewimage[0].getAttribute('src').split('?')[0];\n // If the uploaded file reuses the filename of a previously uploaded image, they differ\n // only in the oid. So one has to append the oid to the url.\n if (previewimage[0].getAttribute('src').split('?')[1].includes('&oid=')) {\n backgroundurl += '?oid=' + previewimage[0].getAttribute('src').split('&oid=')[1];\n }\n background.setAttribute('xlink:href', backgroundurl);\n }\n }\n\n /**\n * Adds an eventListener to the background image for watching file changes and updating\n * height and width of the image.\n */\n function registerBackgroundListener() {\n let background = document.getElementById('learningmap-background-image');\n if (background) {\n background.addEventListener('load', function() {\n background.removeAttribute('height');\n let height = parseInt(background.getBBox().height);\n let width = background.getBBox().width;\n placestore.setBackgroundDimensions(width, height);\n svg.setAttribute('viewBox', '0 0 ' + placestore.width + ' ' + placestore.height);\n background.setAttribute('width', width);\n background.setAttribute('height', height);\n updateCode();\n });\n }\n }\n\n /**\n * Updates CSS code inside the SVG (called, when one of the colors is changed).\n * Calls updateCode() when completed.\n */\n function updateCSS() {\n Templates.renderForPromise('mod_learningmap/cssskeleton', placestore.getPlacestore())\n .then(({html, js}) => {\n Templates.replaceNode('#learningmap-svgstyle', html, js);\n updateCode();\n return true;\n })\n .catch(ex => displayException(ex));\n }\n\n /**\n * Updates the activity selector to highlight the activities already used\n * and to show the alert for hidden activities.\n */\n function updateActivities() {\n let activities = placestore.getAllActivities();\n let options = Array.from(activitySelector.getElementsByTagName('option'));\n activityHiddenWarning.setAttribute('hidden', '');\n options.forEach(function(n) {\n if (activities.includes(n.value)) {\n n.classList.add('learningmap-used-activity');\n if (n.selected) {\n if (n.getAttribute('data-activity-hidden') == true) {\n activityHiddenWarning.removeAttribute('hidden');\n }\n }\n } else {\n n.classList.remove('learningmap-used-activity');\n }\n });\n }\n\n /**\n * Adds the event listener to the color chooser buttons.\n * @param {*} name name of the color\n * @param {*} secondValue name of a second placestore value that has to be changed along\n */\n function colorChooserLogic(name, secondValue = '') {\n let colorChooser = document.getElementById('learningmap-color-' + name);\n if (colorChooser) {\n colorChooser.addEventListener('change', function() {\n placestore.setColor(name, colorChooser.value);\n if (secondValue != '') {\n placestore.setColor(secondValue, colorChooser.value);\n }\n updateCSS();\n });\n colorChooser.value = placestore.getColor(name);\n }\n }\n\n /**\n * Adds the event listener to advanced settings menu items\n * @param {*} name Name of the item\n * @param {*} getCall Method of placestore to call to read value\n * @param {*} setCall Method of placestore to call to save value\n * @param {*} callback Additional callback after value is saved\n */\n function advancedSettingsLogic(name, getCall, setCall, callback = null) {\n let settingItem = document.getElementById('learningmap-advanced-setting-' + name);\n if (settingItem) {\n settingItem.checked = getCall.call(placestore);\n settingItem.addEventListener('change', function() {\n setCall.call(placestore, settingItem.checked);\n if (callback !== null) {\n callback();\n }\n updateCSS();\n });\n }\n }\n\n /**\n * Adds missing text nodes\n */\n function fixPlaceLabels() {\n let options = Array.from(activitySelector.getElementsByTagName('option'));\n let places = placestore.getPlaces();\n for (const place of places) {\n if (document.getElementById('text' + place.id) === null) {\n let content = '';\n for (const option of options) {\n if (option.value == place.linkedActivity) {\n content = option.textContent;\n break;\n }\n }\n let placeNode = document.getElementById(place.id);\n let textNode = text('text' + place.id, content, placeNode.cx.baseVal.value, placeNode.cy.baseVal.value);\n placeNode.parentNode.appendChild(textNode);\n }\n }\n }\n\n /**\n * Hides the advanced settings menu.\n */\n function hideAdvancedSettings() {\n let advancedSettings = document.getElementById('learningmap-advanced-settings');\n advancedSettings.setAttribute('hidden', '');\n }\n};\n"],"names":["targetPoints","pathTypes","offset","dragel","pathsToUpdateFirstPoint","pathsToUpdateSecondPoint","prefetchTemplates","selectedElement","firstPlace","secondPlace","lastTarget","elementForActivitySelector","touchstart","touchend","touchmove","mapdiv","document","getElementById","code","activitySetting","activitySelector","activityStarting","activityTarget","activityHiddenWarning","advancedSettingsIcon","treeView","querySelector","setAttribute","iconView","setTimeout","dispatchEvent","Event","addEventListener","setActivityId","value","text","textContent","title","classList","remove","add","updateActivities","updateCode","checked","addStartingPlace","removeStartingPlace","addTargetPlace","removeTargetPlace","placestoreInput","getElementsByName","loadJSON","advancedSettings","getAttribute","hideAdvancedSettings","removeAttribute","hideContextMenu","advancedSettingsClose","advancedSettingsLogic","placestore","getHidePaths","setHidePaths","getUseCheckmark","setUseCheckmark","getHover","setHover","getPulse","setPulse","getShowall","setShowall","getHideStroke","setHideStroke","getShowText","setShowText","options","Array","from","getElementsByTagName","places","getPlaces","place","id","content","option","linkedActivity","placeNode","textNode","cx","baseVal","cy","parentNode","appendChild","getSliceMode","setSliceMode","getShowWayGone","setShowWayGone","colorChooserLogic","innerHTML","refreshBackgroundImage","background","height","parseInt","getBBox","width","setBackgroundDimensions","svg","registerBackgroundListener","getMapid","showContextMenu","e","unselectAll","target","touches","contains","activityId","getActivityId","scalingFactor","clientWidth","style","setProperty","clientHeight","display","isStartingPlace","isTargetPlace","el","startDrag","drag","endDrag","evt","cancelable","preventDefault","nodeName","dblclickHandler","endTouch","getMousePosition","x","getAttributeNS","y","getPathsWithFid","getPathsWithSid","pathPoint","transformCoordinates","layerX","layerY","coord","dx","dy","setAttributeNS","updatePathDeclaration","forEach","path","pathNode","clickHandler","oldDefinition","targetX","targetY","targetP","parts","split","fromX","fromY","toX","toY","bezierX","bezierY","pathType","i","length","makeDraggable","updateCSS","backgroundfileNode","MutationObserver","observe","attributes","childList","subtree","clientX","clientY","CTM","getScreenCTM","a","f","d","JSON","stringify","getPlacestore","event","placesgroup","placeId","getId","linkId","child","link","createElementNS","r","classes","circle","addPlace","parent","getTouchingPaths","removePath","removePlace","removeChild","circleRadius","fid","replace","sid","z","pid","pathsgroup","first","second","x1","y1","x2","y2","addPath","getElementsByClassName","previewimage","backgroundurl","includes","renderForPromise","then","_ref","html","js","replaceNode","catch","ex","activities","getAllActivities","n","selected","name","secondValue","colorChooser","setColor","getColor","getCall","setCall","callback","settingItem","call"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"learningmap.min.js","sources":["../src/learningmap.js"],"sourcesContent":["import {exception as displayException} from 'core/notification';\nimport Templates from 'core/templates';\nimport placestore from 'mod_learningmap/placestore';\nimport svgjs from 'mod_learningmap/svg';\nimport shapes from './shapes';\n\nconst circleRadius = 10;\n\n// Constants for updatePathDeclaration.\nconst targetPoints = {\n firstPoint: 1,\n secondPoint: 2,\n bezierPoint: 3,\n};\n\nconst pathTypes = {\n line: 1,\n quadraticbezier: 2,\n};\n\nexport const init = () => {\n // Load the needed template on startup for better execution speed.\n Templates.prefetchTemplates(['mod_learningmap/cssskeleton']);\n\n // Variable for storing the mouse offset\n var offset;\n\n // Variable for draggable element\n var dragel;\n\n // Variables for storing the paths that need update of the first or\n // the second coordinates.\n var pathsToUpdateFirstPoint, pathsToUpdateSecondPoint;\n\n // Variables for handling the currently selected elements\n var selectedElement = null,\n firstPlace = null,\n secondPlace = null,\n lastTarget = null;\n\n // Variable for storing the selected element for the activity selector\n var elementForActivitySelector = null;\n\n // Variables for simulating double click on touch devices, set when the\n // corresponding events are handled\n var touchstart = false;\n var touchend = false;\n // Counter for touchmove events\n var touchmove = 0;\n\n // DOM nodes for the editor\n let mapdiv = document.getElementById('learningmap-editor-map');\n let code = document.getElementById('id_svgcode');\n\n // DOM nodes for the activity selector\n let activitySetting = document.getElementById('learningmap-activity-setting');\n let activitySelector = document.getElementById('learningmap-activity-selector');\n let activityStarting = document.getElementById('learningmap-activity-starting');\n let activityTarget = document.getElementById('learningmap-activity-target');\n let activityHiddenWarning = document.getElementById('learningmap-activity-hidden-warning');\n let advancedSettingsIcon = document.getElementById('learningmap-advanced-settings-icon');\n\n // Hide tree view as there is no preview file we can attach to\n let treeView = document.querySelector('.fp-viewbar .fp-vb-tree');\n if (treeView) {\n treeView.setAttribute('style', 'display: none;');\n }\n\n // Trigger click event on icon view to ensure that tree view is not active.\n let iconView = document.querySelector('.fp-viewbar .fp-vb-icons');\n if (iconView) {\n // Handle possible delay in form loading.\n setTimeout(() => {\n iconView.dispatchEvent(new Event('click'));\n }, 1000);\n }\n\n // Attach listeners to the activity selector\n if (activitySelector) {\n // Show places that are not linked to an activity\n activitySelector.addEventListener('change', function() {\n placestore.setActivityId(elementForActivitySelector, activitySelector.value);\n if (activitySelector.value) {\n let text = document.getElementById('text' + elementForActivitySelector);\n if (text) {\n text.textContent = activitySelector.querySelector('option[value=\"' + activitySelector.value + '\"]').textContent;\n }\n let title = document.getElementById('title' + elementForActivitySelector);\n if (title) {\n title.textContent =\n activitySelector.querySelector('option[value=\"' + activitySelector.value + '\"]').textContent;\n }\n document.getElementById(elementForActivitySelector).classList.remove('learningmap-emptyplace');\n } else {\n document.getElementById(elementForActivitySelector).classList.add('learningmap-emptyplace');\n }\n updateActivities();\n updateCode();\n });\n // Add / remove a place to the starting places array\n activityStarting.addEventListener('change', function() {\n if (activityStarting.checked) {\n placestore.addStartingPlace(elementForActivitySelector);\n } else {\n placestore.removeStartingPlace(elementForActivitySelector);\n }\n updateCode();\n });\n // Add / remove a place to the target places array\n activityTarget.addEventListener('change', function() {\n if (activityTarget.checked) {\n placestore.addTargetPlace(elementForActivitySelector);\n document.getElementById(elementForActivitySelector).classList.add('learningmap-targetplace');\n } else {\n placestore.removeTargetPlace(elementForActivitySelector);\n document.getElementById(elementForActivitySelector).classList.remove('learningmap-targetplace');\n }\n updateCode();\n });\n }\n\n // Load placestore values from the hidden input field\n let placestoreInput = document.getElementsByName('placestore')[0];\n if (placestoreInput) {\n placestore.loadJSON(placestoreInput.value);\n }\n\n // Mark all activities in the placestore as \"used\".\n updateActivities();\n\n // Attach listeners to the advanced settings div\n if (advancedSettingsIcon) {\n let advancedSettings = document.getElementById('learningmap-advanced-settings');\n advancedSettingsIcon.addEventListener('click', function() {\n if (advancedSettings.getAttribute('hidden') === null) {\n hideAdvancedSettings();\n } else {\n advancedSettings.removeAttribute('hidden');\n hideContextMenu();\n }\n });\n let advancedSettingsClose = document.getElementById('learningmap-advanced-settings-close');\n if (advancedSettingsClose) {\n advancedSettingsClose.addEventListener('click', function() {\n advancedSettings.setAttribute('hidden', '');\n });\n }\n\n advancedSettingsLogic('hidepaths', placestore.getHidePaths, placestore.setHidePaths);\n advancedSettingsLogic('usecheckmark', placestore.getUseCheckmark, placestore.setUseCheckmark);\n advancedSettingsLogic('hover', placestore.getHover, placestore.setHover);\n advancedSettingsLogic('pulse', placestore.getPulse, placestore.setPulse);\n advancedSettingsLogic('showall', placestore.getShowall, placestore.setShowall);\n advancedSettingsLogic('hidestroke', placestore.getHideStroke, placestore.setHideStroke);\n advancedSettingsLogic('showtext', placestore.getShowText, placestore.setShowText, fixPlaceLabels);\n advancedSettingsLogic('slicemode', placestore.getSliceMode, placestore.setSliceMode);\n advancedSettingsLogic('showwaygone', placestore.getShowWayGone, placestore.setShowWayGone);\n }\n\n // Attach listener to the color choosers\n colorChooserLogic('stroke', 'text');\n colorChooserLogic('place');\n colorChooserLogic('visited');\n\n // Get SVG code from the (hidden) textarea field\n if (code && mapdiv) {\n mapdiv.innerHTML = code.value;\n }\n // Reload background image to get the correct width and height values\n refreshBackgroundImage();\n registerBackgroundListener();\n updateCode();\n\n // Enable dragging of places\n let svgel = document.getElementById('learningmap-svgmap-' + placestore.getMapid());\n makeDraggable(svgel);\n var mapsvg = svgjs().SVG('#learningmap-svgmap-' + placestore.getMapid());\n\n // Refresh stylesheet values from placestore\n updateCSS();\n\n // Add listeners for clicking and context menu\n if (mapdiv) {\n mapdiv.addEventListener('dblclick', dblclickHandler);\n mapdiv.addEventListener('click', clickHandler);\n\n mapdiv.addEventListener('contextmenu', function(e) {\n e.preventDefault();\n showContextMenu(e);\n }, false);\n }\n /**\n * Shows the context menu at the current mouse position\n * @param {*} e\n */\n function showContextMenu(e) {\n unselectAll();\n hideAdvancedSettings();\n // Check for the existence of the target (could have vanished since the event started).\n if (activitySetting && document.getElementById(e.target.id) !== null) {\n if (e.touches) {\n e = e.touches[0];\n }\n if (e.target.classList.contains('learningmap-place')) {\n let element = getSVGShape(e.target.id);\n e.target.classList.add('learningmap-selected-activity-selector');\n let activityId = placestore.getActivityId(e.target.id);\n let scalingFactor = mapdiv.clientWidth / 800;\n activitySetting.style.setProperty('--pos-x', element.cx() * scalingFactor + 'px');\n activitySetting.style.setProperty('--pos-y', element.cy() * scalingFactor + 'px');\n activitySetting.style.setProperty('--map-width', mapdiv.clientWidth + 'px');\n activitySetting.style.setProperty('--map-height', mapdiv.clientHeight + 'px');\n activitySetting.style.display = 'block';\n document.getElementById('learningmap-activity-selector').value = activityId;\n document.getElementById('learningmap-activity-starting').checked = placestore.isStartingPlace(e.target.id);\n document.getElementById('learningmap-activity-target').checked = placestore.isTargetPlace(e.target.id);\n elementForActivitySelector = e.target.id;\n updateActivities();\n } else {\n hideContextMenu();\n hideAdvancedSettings();\n }\n }\n }\n\n /**\n * Hides the context menu\n */\n function hideContextMenu() {\n let e = document.getElementById(elementForActivitySelector);\n if (e) {\n e.classList.remove('learningmap-selected-activity-selector');\n }\n activitySetting.style.display = 'none';\n }\n\n let backgroundfileNode = document.getElementById('id_backgroundfile_fieldset');\n if (backgroundfileNode) {\n let observer = new MutationObserver(refreshBackgroundImage);\n observer.observe(backgroundfileNode, {attributes: true, childList: true, subtree: true});\n }\n\n /**\n * Helper function for getting the right coordinates from the mouse\n * @param {*} evt\n * @returns {object}\n */\n function getMousePosition(evt) {\n if (evt.touches) {\n evt = evt.touches[0];\n }\n return transformCoordinates(evt.clientX, evt.clientY);\n }\n\n /**\n * Transforms client coordinates to SVG coordinates\n * @param {number} x x coordinate to transform\n * @param {number} y y coordinate to transform\n * @returns {object} Object containing transformed x and y coordinate\n */\n function transformCoordinates(x, y) {\n var CTM = dragel.getScreenCTM();\n return {\n x: (x - CTM.e) / CTM.a,\n y: (y - CTM.f) / CTM.d\n };\n }\n\n /**\n * Returns the SVG shape with the given id or representing the\n * given object.\n * @param {*} element\n * @returns\n */\n function getSVGShape(element) {\n if (typeof element === 'object') {\n return mapsvg.findOne('#' + element.id);\n } else {\n return mapsvg.findOne('#' + element);\n }\n }\n\n /**\n * Enables dragging on an DOM node\n * @param {*} el\n */\n function makeDraggable(el) {\n dragel = el;\n if (el) {\n el.addEventListener('mousedown', startDrag);\n el.addEventListener('mousemove', drag);\n el.addEventListener('mouseup', endDrag);\n el.addEventListener('mouseleave', endDrag);\n el.addEventListener('touchstart', startTouch);\n el.addEventListener('touchmove', drag);\n el.addEventListener('touchend', endTouch);\n el.addEventListener('touchleave', endTouch);\n el.addEventListener('touchcancel', endTouch);\n }\n\n /**\n * Function called whenn dragging starts.\n * @param {*} evt\n */\n function startDrag(evt) {\n if (evt.cancelable) {\n evt.preventDefault();\n }\n pathsToUpdateFirstPoint = [];\n pathsToUpdateSecondPoint = [];\n if (evt.target.classList.contains('learningmap-draggable')) {\n selectedElement = evt.target;\n let svgel = getSVGShape(selectedElement);\n offset = getMousePosition(evt);\n offset.x -= svgel.cx();\n offset.y -= svgel.cy();\n // Get paths that need to be updated.\n pathsToUpdateFirstPoint = placestore.getPathsWithFid(evt.target.id);\n pathsToUpdateSecondPoint = placestore.getPathsWithSid(evt.target.id);\n } else if (evt.target.nodeName == 'text') {\n selectedElement = evt.target;\n let svgel = getSVGShape(selectedElement);\n let place = svgel.parent().findOne('.learningmap-place');\n offset = getMousePosition(evt);\n offset.x -= svgel.attr('dx') + place.cx();\n offset.y -= svgel.attr('dy') + place.cy();\n } else if (evt.target.nodeName == 'path') {\n selectedElement = evt.target;\n offset = getMousePosition(evt);\n let pathPoint = transformCoordinates(evt.layerX, evt.layerY);\n offset.x += pathPoint.x;\n offset.y += pathPoint.y;\n }\n }\n\n /**\n * Function called during dragging. Continuously updates places center coordinates and the\n * coordinates of the touching paths.\n * @param {*} evt\n */\n function drag(evt) {\n if (evt.cancelable) {\n evt.preventDefault();\n }\n // Count touchmove events\n touchmove++;\n if (selectedElement) {\n var coord = getMousePosition(evt);\n let cx = coord.x - offset.x;\n let cy = coord.y - offset.y;\n console.log(selectedElement);\n let closest = selectedElement.closest('.learningmap-place');\n console.log(closest);\n if (closest) {\n selectedElement = closest;\n }\n if (selectedElement.classList.contains('learningmap-place')) {\n let placeel = mapsvg.findOne('#' + selectedElement.id);\n placeel.center(cx, cy);\n let textNode = mapsvg.findOne('#text' + selectedElement.id);\n if (textNode !== null) {\n textNode.amove(cx, cy);\n }\n pathsToUpdateFirstPoint.forEach(function(path) {\n let pathElement = getSVGShape(path);\n if (pathElement !== null) {\n if (pathElement.type == 'path') {\n pathElement.attr(\n {'d': updatePathDeclaration(pathElement.attr('d'), cx, cy, targetPoints.firstPoint)}\n );\n } else {\n pathElement.attr({'x1': cx, 'y1': cy});\n }\n }\n });\n\n pathsToUpdateSecondPoint.forEach(function(path) {\n let pathElement = getSVGShape(path);\n if (pathElement !== null) {\n if (pathElement.type == 'path') {\n pathElement.attr(\n {'d': updatePathDeclaration(pathElement.attr('d'), cx, cy, targetPoints.secondPoint)}\n );\n } else {\n pathElement.attr({'x2': cx, 'y2': cy});\n }\n }\n });\n placestore.setBbox(selectedElement.id, placeel.parent().bbox());\n } else if (selectedElement.nodeName == 'text') {\n let textel = getSVGShape(selectedElement);\n let place = textel.parent().findOne('.learningmap-place');\n // Calculate the delta from the current mouse position to the corresponding place.\n // coord: current mouse position\n // offset: delta from the mouse position to the coordinates of the text node\n let dx = cx - place.cx();\n let dy = cy - place.cy();\n // We cannot use the dx() and dy() functions of the text node, because they are not\n // setting the attributes dx and dy.\n textel.attr({dx: dx, dy: dy});\n placestore.setBbox(place.node.id, textel.parent().bbox());\n } else if (selectedElement.nodeName == 'path') {\n selectedElement.setAttribute(\n 'd',\n updatePathDeclaration(selectedElement.getAttribute('d'), coord.x, coord.y, targetPoints.bezierPoint)\n );\n }\n }\n }\n\n /**\n * Function called when dragging ends.\n * @param {*} evt\n */\n function endDrag(evt) {\n if (evt.cancelable) {\n evt.preventDefault();\n }\n selectedElement = null;\n unselectAll();\n updateCode();\n }\n\n /**\n * Function called when touchstart event occurs.\n * @param {*} evt\n */\n function startTouch(evt) {\n if (evt.cancelable) {\n evt.preventDefault();\n }\n if (\n evt.target.classList.contains('learningmap-draggable') ||\n evt.target.nodeName == 'text' ||\n evt.target.nodeName == 'path'\n ) {\n if (!touchstart) {\n touchstart = true;\n touchmove = 0;\n touchend = false;\n setTimeout(\n (evt) => {\n if (touchmove < 3 && !touchend) {\n if (evt.touches) {\n evt = evt.touches[0];\n }\n showContextMenu(evt);\n }\n },\n 2000,\n evt\n );\n setTimeout(\n () => {\n touchstart = false;\n },\n 300);\n } else {\n dblclickHandler(evt);\n touchstart = false;\n }\n startDrag(evt);\n } else {\n if (!touchstart) {\n touchstart = true;\n touchend = false;\n touchmove = 0;\n setTimeout(\n () => {\n touchstart = false;\n },\n 300);\n } else {\n dblclickHandler(evt);\n touchstart = false;\n }\n }\n }\n\n /**\n * Function called when touchend, touchleave or touchcancel event occurs.\n * @param {*} evt\n */\n function endTouch(evt) {\n selectedElement = null;\n touchend = true;\n // If there was only a small move (<3 move events), this also counts as a click.\n if (touchmove < 3 && touchstart) {\n clickHandler(evt);\n } else {\n endDrag(evt);\n }\n if (evt.cancelable) {\n evt.preventDefault();\n }\n }\n\n /**\n * Updates the path declaration of lines and quadratic bezier curves setting one of the points.\n * @param {string} oldDefinition SVG path definition string\n * @param {number} targetX x coordinate of the point to set\n * @param {number} targetY y coordinate of the point to set\n * @param {number} targetP Which point to change (you can use the targetPoints constants here)\n * @returns {string} Updated SVG path definition\n */\n function updatePathDeclaration(oldDefinition, targetX, targetY, targetP = targetPoints.firstPoint) {\n let parts = oldDefinition.split(' ');\n let fromX = 0;\n let fromY = 0;\n let toX = 0;\n let toY = 0;\n let bezierX = 0;\n let bezierY = 0;\n let pathType = pathTypes.line;\n\n // The d attribute of an SVG path in a learning map can have two different formats (in this version):\n // \"M x1 y1 L x2 y2\" Line from x1, y1 to x2, y2\n // \"M x1 y2 Q x3 y3 x2 y2\" Quadratic bezier curve inside the triangle defined by x1, y1, x2, y2 and x3, y3.\n for (let i = 0; i < parts.length; i++) {\n // Every path contains the first point in that way.\n if (parts[i] == 'M') {\n fromX = parseInt(parts[i + 1]);\n fromY = parseInt(parts[i + 2]);\n i += 2;\n }\n // This path is a direct line, so there are only two points in total.\n if (parts[i] == 'L') {\n toX = parseInt(parts[i + 1]);\n toY = parseInt(parts[i + 2]);\n i += 2;\n }\n // This path is a bezier curve, there are three points in total.\n if (parts[i] == 'Q') {\n bezierX = parseInt(parts[i + 1]);\n bezierY = parseInt(parts[i + 2]);\n toX = parseInt(parts[i + 3]);\n toY = parseInt(parts[i + 4]);\n i += 4;\n pathType = pathTypes.quadraticbezier;\n }\n }\n\n switch (targetP) {\n case targetPoints.firstPoint:\n fromX = targetX;\n fromY = targetY;\n break;\n case targetPoints.secondPoint:\n toX = targetX;\n toY = targetY;\n break;\n case targetPoints.bezierPoint:\n // Calculate the third triangle point for the bezier curve.\n bezierX = targetX * 2 - (fromX + toX) * 0.5;\n bezierY = targetY * 2 - (fromY + toY) * 0.5;\n pathType = pathTypes.quadraticbezier;\n break;\n }\n\n if (pathType == pathTypes.quadraticbezier) {\n return 'M ' + fromX + ' ' + fromY + ' Q ' + bezierX + ' ' + bezierY + ', ' + toX + ' ' + toY;\n } else {\n return 'M ' + fromX + ' ' + fromY + ' L ' + toX + ' ' + toY;\n }\n }\n }\n\n /**\n * Updates the form fields for the SVG code and the placestore from the editor.\n */\n function updateCode() {\n if (code && mapdiv) {\n code.innerHTML = mapdiv.innerHTML;\n }\n if (placestoreInput) {\n document.getElementsByName('placestore')[0].value = JSON.stringify(placestore.getPlacestore());\n }\n }\n\n /**\n * Handles double clicks on the map\n * @param {*} event\n */\n function dblclickHandler(event) {\n hideContextMenu();\n hideAdvancedSettings();\n unselectAll();\n if (event.target.classList.contains('learningmap-mapcontainer') ||\n event.target.classList.contains('learningmap-background-image')) {\n addPlace(event);\n } else if (event.target.classList.contains('learningmap-place')) {\n if (lastTarget == event.target.id) {\n lastTarget = null;\n clickHandler(event);\n } else {\n removePlace(event);\n }\n } else if (event.target.classList.contains('learningmap-path')) {\n removePath(event.target.id);\n }\n updateCode();\n }\n\n /**\n * Returns an empty title tag with the given id.\n * @param {*} id id for the title\n * @returns {any}\n */\n function title(id) {\n return mapsvg.element('title').id(id);\n }\n\n /**\n * Returns an text tag with the given id.\n * @param {*} id id for the text\n * @param {*} content content of the tag\n * @param {*} x x coordinate of the text\n * @param {*} y y coordinate of the text\n * @returns {any}\n */\n function text(id, content, x, y) {\n return mapsvg.text().attr({dx: circleRadius * 1.5, dy: circleRadius * 1.5}).plain(content).move(x, y).id(id);\n }\n\n /**\n * Returns a path between two points.\n * @param {*} x1 x coordinate of the first point\n * @param {*} y1 y coordinate of the first point\n * @param {*} x2 x coordinate of the second point\n * @param {*} y2 y coordinate of the second point\n * @param {*} classes CSS classes to set\n * @param {*} id id of the path\n * @returns {any}\n */\n function path(x1, y1, x2, y2, classes, id) {\n return mapsvg.path('M ' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2).attr({'class': classes}).id(id);\n }\n\n /**\n * Returns a link around a given child element. This function also adds a title element next\n * to the child for accessibility.\n * @param {*} child child item to set the link on\n * @param {*} id id of the link\n * @param {*} title title of the link\n * @param {*} text text to describe the link\n * @returns {any}\n */\n function link(child, id, title = null, text = null) {\n return mapsvg.link('').id(id).add(child).add(title).add(text);\n }\n\n /**\n * Adds a place on the SVG map. This function also prepares the code for linking activities\n * and adding titles (for accessibility).\n * @param {*} event event causing the command\n */\n function addPlace(event) {\n let placesgroup = mapsvg.findOne('#placesGroup');\n let placeId = 'p' + placestore.getId();\n let linkId = 'a' + placestore.getId();\n var CTM = event.target.getScreenCTM();\n if (event.touches) {\n event = event.touches[0];\n }\n let cx = (event.clientX - CTM.e) / CTM.a;\n let cy = (event.clientY - CTM.f) / CTM.d;\n let svglink = link(\n shapes.emoji(mapsvg, cx, cy, circleRadius, 'learningmap-place learningmap-draggable learningmap-emptyplace', placeId),\n linkId,\n title('title' + placeId),\n text('text' + placeId, '', cx, cy)\n );\n svglink.addTo(placesgroup);\n placestore.addPlace(placeId, linkId, null, svglink.bbox());\n }\n\n /**\n * Handles single clicks on the background image.\n * @param {*} event click event\n * @returns {void}\n */\n function clickHandler(event) {\n event.preventDefault();\n hideContextMenu();\n hideAdvancedSettings();\n if (event.target.classList.contains('learningmap-place') && selectedElement === null) {\n if (firstPlace === null) {\n firstPlace = event.target.id;\n document.getElementById(firstPlace).classList.add('learningmap-selected');\n } else {\n secondPlace = event.target.id;\n let fid = parseInt(firstPlace.replace('p', ''));\n let sid = parseInt(secondPlace.replace('p', ''));\n if (sid == fid) {\n return;\n }\n if (sid < fid) {\n let z = sid;\n sid = fid;\n fid = z;\n }\n addPath(fid, sid);\n let first = document.getElementById(firstPlace);\n if (first) {\n first.classList.remove('learningmap-selected');\n }\n firstPlace = null;\n lastTarget = secondPlace;\n secondPlace = null;\n }\n } else {\n unselectAll();\n firstPlace = null;\n }\n }\n /**\n * Removes the classes 'learningmap-selected' and 'learningmap-selectet-activity-selector'\n * from all nodes\n */\n function unselectAll() {\n Array.from(document.getElementsByClassName('learningmap-selected')).forEach(function(e) {\n e.classList.remove('learningmap-selected');\n });\n Array.from(document.getElementsByClassName('learningmap-selected-activity-selector')).forEach(function(e) {\n e.classList.remove('learningmap-selected-activity-selector');\n });\n }\n\n /**\n * Adds a path between two places.\n * @param {number} fid id of the first place (meant to be the smaller one)\n * @param {number} sid id of the second place (meant to be the bigger one)\n */\n function addPath(fid, sid) {\n let pid = 'p' + fid + '_' + sid;\n if (document.getElementById(pid) === null) {\n let pathsgroup = mapsvg.findOne('#pathsGroup');\n let first = mapsvg.findOne('#p' + fid);\n let second = mapsvg.findOne('#p' + sid);\n if (pathsgroup && first && second) {\n let svgpath = path(\n first.cx(),\n first.cy(),\n second.cx(),\n second.cy(),\n 'learningmap-path',\n pid\n );\n svgpath.addTo(pathsgroup);\n placestore.addPath(pid, 'p' + fid, 'p' + sid);\n }\n }\n }\n\n /**\n * Removes a place from the SVG and the placestore. This function also removes all\n * touching paths and entries in statringplaces / targetplaces linking to the removed\n * place.\n * @param {any} event event causing the remove order\n */\n function removePlace(event) {\n let place = getSVGShape(event.target.id);\n removePathsTouchingPlace(event.target.id);\n placestore.removePlace(event.target.id);\n place.parent().remove();\n\n updateCode();\n }\n\n /**\n * Removes all paths touching a certain place\n * @param {number} id id of the place\n */\n function removePathsTouchingPlace(id) {\n placestore.getTouchingPaths(id).forEach(\n function(e) {\n removePath(e.id);\n }\n );\n }\n\n /**\n * Removes a path from the SVG and from the placestore\n * @param {number} id id of the path\n */\n function removePath(id) {\n let path = getSVGShape(id);\n if (path !== null) {\n path.remove();\n placestore.removePath(id);\n }\n }\n\n /**\n * Sets the background image of the SVG to the current image in filemanager.\n */\n function refreshBackgroundImage() {\n let previewimage = document.getElementsByClassName('realpreview');\n if (previewimage.length > 0) {\n let background = document.getElementById('learningmap-background-image');\n let backgroundurl = previewimage[0].getAttribute('src').split('?')[0];\n // If the uploaded file reuses the filename of a previously uploaded image, they differ\n // only in the oid. So one has to append the oid to the url.\n if (previewimage[0].getAttribute('src').split('?')[1].includes('&oid=')) {\n backgroundurl += '?oid=' + previewimage[0].getAttribute('src').split('&oid=')[1];\n }\n background.setAttribute('xlink:href', backgroundurl);\n }\n }\n\n /**\n * Adds an eventListener to the background image for watching file changes and updating\n * height and width of the image.\n */\n function registerBackgroundListener() {\n let background = document.getElementById('learningmap-background-image');\n if (background) {\n background.addEventListener('load', function() {\n background.removeAttribute('height');\n let height = parseInt(background.getBBox().height);\n let width = background.getBBox().width;\n placestore.setBackgroundDimensions(width, height);\n svgel.setAttribute('viewBox', '0 0 ' + placestore.width + ' ' + placestore.height);\n background.setAttribute('width', width);\n background.setAttribute('height', height);\n updateCode();\n });\n }\n }\n\n /**\n * Updates CSS code inside the SVG (called, when one of the colors is changed).\n * Calls updateCode() when completed.\n */\n function updateCSS() {\n Templates.renderForPromise('mod_learningmap/cssskeleton', placestore.getPlacestore())\n .then(({html, js}) => {\n Templates.replaceNode('#learningmap-svgstyle', html, js);\n updateCode();\n return true;\n })\n .catch(ex => displayException(ex));\n }\n\n /**\n * Updates the activity selector to highlight the activities already used\n * and to show the alert for hidden activities.\n */\n function updateActivities() {\n let activities = placestore.getAllActivities();\n let options = Array.from(activitySelector.getElementsByTagName('option'));\n activityHiddenWarning.setAttribute('hidden', '');\n options.forEach(function(n) {\n if (activities.includes(n.value)) {\n n.classList.add('learningmap-used-activity');\n if (n.selected) {\n if (n.getAttribute('data-activity-hidden') == true) {\n activityHiddenWarning.removeAttribute('hidden');\n }\n }\n } else {\n n.classList.remove('learningmap-used-activity');\n }\n });\n }\n\n /**\n * Adds the event listener to the color chooser buttons.\n * @param {*} name name of the color\n * @param {*} secondValue name of a second placestore value that has to be changed along\n */\n function colorChooserLogic(name, secondValue = '') {\n let colorChooser = document.getElementById('learningmap-color-' + name);\n if (colorChooser) {\n colorChooser.addEventListener('change', function() {\n placestore.setColor(name, colorChooser.value);\n if (secondValue != '') {\n placestore.setColor(secondValue, colorChooser.value);\n }\n updateCSS();\n });\n colorChooser.value = placestore.getColor(name);\n }\n }\n\n /**\n * Adds the event listener to advanced settings menu items\n * @param {*} name Name of the item\n * @param {*} getCall Method of placestore to call to read value\n * @param {*} setCall Method of placestore to call to save value\n * @param {*} callback Additional callback after value is saved\n */\n function advancedSettingsLogic(name, getCall, setCall, callback = null) {\n let settingItem = document.getElementById('learningmap-advanced-setting-' + name);\n if (settingItem) {\n settingItem.checked = getCall.call(placestore);\n settingItem.addEventListener('change', function() {\n setCall.call(placestore, settingItem.checked);\n if (callback !== null) {\n callback();\n }\n updateCSS();\n });\n }\n }\n\n /**\n * Adds missing text nodes\n */\n function fixPlaceLabels() {\n let options = Array.from(activitySelector.getElementsByTagName('option'));\n let places = placestore.getPlaces();\n for (const place of places) {\n if (document.getElementById('text' + place.id) === null) {\n let content = '';\n for (const option of options) {\n if (option.value == place.linkedActivity) {\n content = option.textContent;\n break;\n }\n }\n let placeNode = mapsvg.findOne('#' + place.id);\n let textNode = text('text' + place.id, content, placeNode.cx(), placeNode.cy());\n textNode.addTo(placeNode.parent());\n }\n }\n }\n\n /**\n * Hides the advanced settings menu.\n */\n function hideAdvancedSettings() {\n let advancedSettings = document.getElementById('learningmap-advanced-settings');\n advancedSettings.setAttribute('hidden', '');\n }\n};\n"],"names":["targetPoints","pathTypes","offset","dragel","pathsToUpdateFirstPoint","pathsToUpdateSecondPoint","prefetchTemplates","selectedElement","firstPlace","secondPlace","lastTarget","elementForActivitySelector","touchstart","touchend","touchmove","mapdiv","document","getElementById","code","activitySetting","activitySelector","activityStarting","activityTarget","activityHiddenWarning","advancedSettingsIcon","treeView","querySelector","setAttribute","iconView","setTimeout","dispatchEvent","Event","addEventListener","setActivityId","value","text","textContent","title","classList","remove","add","updateActivities","updateCode","checked","addStartingPlace","removeStartingPlace","addTargetPlace","removeTargetPlace","placestoreInput","getElementsByName","loadJSON","advancedSettings","getAttribute","hideAdvancedSettings","removeAttribute","hideContextMenu","advancedSettingsClose","advancedSettingsLogic","placestore","getHidePaths","setHidePaths","getUseCheckmark","setUseCheckmark","getHover","setHover","getPulse","setPulse","getShowall","setShowall","getHideStroke","setHideStroke","getShowText","setShowText","options","Array","from","getElementsByTagName","places","getPlaces","place","id","content","option","linkedActivity","placeNode","mapsvg","findOne","cx","cy","addTo","parent","getSliceMode","setSliceMode","getShowWayGone","setShowWayGone","colorChooserLogic","innerHTML","refreshBackgroundImage","background","height","parseInt","getBBox","width","setBackgroundDimensions","svgel","registerBackgroundListener","getMapid","el","startDrag","drag","endDrag","evt","cancelable","preventDefault","target","contains","nodeName","dblclickHandler","touches","showContextMenu","endTouch","getSVGShape","getMousePosition","x","y","getPathsWithFid","getPathsWithSid","attr","pathPoint","transformCoordinates","layerX","layerY","coord","console","log","closest","placeel","center","textNode","amove","forEach","path","pathElement","type","updatePathDeclaration","setBbox","bbox","textel","dx","dy","node","unselectAll","clickHandler","oldDefinition","targetX","targetY","targetP","parts","split","fromX","fromY","toX","toY","bezierX","bezierY","pathType","i","length","makeDraggable","SVG","e","element","activityId","getActivityId","scalingFactor","clientWidth","style","setProperty","clientHeight","display","isStartingPlace","isTargetPlace","updateCSS","backgroundfileNode","MutationObserver","observe","attributes","childList","subtree","clientX","clientY","CTM","getScreenCTM","a","f","d","JSON","stringify","getPlacestore","event","placesgroup","placeId","getId","linkId","svglink","child","link","shapes","emoji","addPlace","getTouchingPaths","removePath","removePlace","circleRadius","plain","move","fid","replace","sid","z","pid","pathsgroup","first","second","x1","y1","x2","y2","classes","addPath","getElementsByClassName","previewimage","backgroundurl","includes","renderForPromise","then","_ref","html","js","replaceNode","catch","ex","activities","getAllActivities","n","selected","name","secondValue","colorChooser","setColor","getColor","getCall","setCall","callback","settingItem","call"],"mappings":"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"} \ No newline at end of file diff --git a/amd/build/placestore.min.js b/amd/build/placestore.min.js index 1da359a..60ccff3 100644 --- a/amd/build/placestore.min.js +++ b/amd/build/placestore.min.js @@ -1,3 +1,3 @@ -define("mod_learningmap/placestore",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;let placestore={version:2024072201,id:0,places:[],paths:[],startingplaces:[],targetplaces:[],placecolor:"#c01c28",strokecolor:"#ffffff",strokeopacity:1,textcolor:"#ffffff",visitedcolor:"#26a269",height:100,width:800,hidepaths:!1,mapid:"",usecheckmark:!1,editmode:!0,pulse:!1,hover:!1,showall:!1,showtext:!1,slicemode:!1,showwaygone:!1,loadJSON:function(json){try{let fromjson=JSON.parse(json);null===fromjson.textcolor&&(fromjson.textcolor=fromjson.strokecolor),Object.assign(this,fromjson)}catch{}this.version=2024072201},buildJSON:function(){return JSON.stringify(this.getPlacestore())},addPlace:function(id,linkId){let linkedActivity=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;this.places.push({id:id,linkId:linkId,linkedActivity:linkedActivity,placecolor:null,visitedcolor:null}),1==this.places.length&&this.addStartingPlace(id),this.id++},removePlace:function(id){this.removeStartingPlace(id),this.removeTargetPlace(id),this.places=this.places.filter((function(p){return p.id!=id}))},addStartingPlace:function(id){this.startingplaces.push(id)},removeStartingPlace:function(id){this.startingplaces=this.startingplaces.filter((function(e){return e!=id}))},isStartingPlace:function(id){return this.startingplaces.includes(id)},addTargetPlace:function(id){this.targetplaces.push(id)},removeTargetPlace:function(id){this.targetplaces=this.targetplaces.filter((function(e){return e!=id}))},isTargetPlace:function(id){return this.targetplaces.includes(id)},addPath:function(pid,fid,sid){this.paths.push({id:pid,fid:fid,sid:sid,strokecolor:null,strokedasharray:null,hidepath:null})},removePath:function(id){this.paths=this.paths.filter((function(p){return p.id!=id}))},getTouchingPaths:function(id){return this.paths.filter((function(p){return p.fid==id||p.sid==id}))},getActivityId:function(id){let place=this.places.filter((function(e){return id==e.id}));return place.length>0?place[0].linkedActivity:null},setActivityId:function(id,linkedActivity){let place=this.places.filter((function(e){return id==e.id}));place.length>0&&(place[0].linkedActivity=linkedActivity)},setColor:function(type,color){switch(type){case"stroke":this.strokecolor=color;break;case"place":this.placecolor=color;break;case"visited":this.visitedcolor=color;break;case"text":this.textcolor=color}},getColor:function(type){switch(type){case"stroke":return this.strokecolor;case"place":return this.placecolor;case"visited":return this.visitedcolor;case"text":return this.textcolor}return null},getId:function(){return this.id},setBackgroundDimensions:function(width,height){this.width=width,this.height=height},getPathsWithFid:function(id){return this.paths.filter((function(p){return p.fid==id}))},getPathsWithSid:function(id){return this.paths.filter((function(p){return p.sid==id}))},getPlacestore:function(){return{id:this.id,places:this.places,paths:this.paths,startingplaces:this.startingplaces,targetplaces:this.targetplaces,placecolor:this.placecolor,strokecolor:this.strokecolor,strokeopacity:this.strokeopacity,textcolor:this.textcolor,visitedcolor:this.visitedcolor,height:this.height,width:this.width,hidepaths:this.hidepaths,mapid:this.mapid,usecheckmark:this.usecheckmark,editmode:this.editmode,version:this.version,pulse:this.pulse,hover:this.hover,showall:this.showall,showtext:this.showtext,slicemode:this.slicemode,showwaygone:this.showwaygone}},setHidePaths:function(value){this.hidepaths=value},getHidePaths:function(){return this.hidepaths},setPulse:function(value){this.pulse=value},getPulse:function(){return this.pulse},setHover:function(value){this.hover=value},getHover:function(){return this.hover},setShowall:function(value){this.showall=value},getShowall:function(){return this.showall},getMapid:function(){return this.mapid},getUseCheckmark:function(){return this.usecheckmark},setUseCheckmark:function(value){this.usecheckmark=value},getAllActivities:function(){let activities=[];return this.places.forEach((function(p){p.linkedActivity&&activities.push(p.linkedActivity)})),activities},setStrokeOpacity:function(value){this.strokeopacity=value},getStrokeOpacity:function(){return this.strokeopacity},setHideStroke:function(value){this.strokeopacity=value?0:1},getHideStroke:function(){return this.strokeopacity<1},getShowText:function(){return this.showtext},setShowText:function(value){this.showtext=value},getPlaces:function(){return this.places},getSliceMode:function(){return this.slicemode},setSliceMode:function(value){this.slicemode=value},getShowWayGone:function(){return this.showwaygone},setShowWayGone:function(value){this.showwaygone=value}};var _default=placestore;return _exports.default=_default,_exports.default})); +define("mod_learningmap/placestore",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;let placestore={version:2024072201,id:0,places:[],paths:[],startingplaces:[],targetplaces:[],placecolor:"#c01c28",strokecolor:"#ffffff",strokeopacity:1,textcolor:"#ffffff",visitedcolor:"#26a269",height:100,width:800,hidepaths:!1,mapid:"",usecheckmark:!1,editmode:!0,pulse:!1,hover:!1,showall:!1,showtext:!1,slicemode:!1,showwaygone:!1,loadJSON:function(json){try{let fromjson=JSON.parse(json);null===fromjson.textcolor&&(fromjson.textcolor=fromjson.strokecolor),Object.assign(this,fromjson)}catch{}this.version=2024072201},buildJSON:function(){return JSON.stringify(this.getPlacestore())},addPlace:function(id,linkId){let linkedActivity=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,bbox=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};this.places.push({id:id,linkId:linkId,linkedActivity:linkedActivity,placecolor:null,visitedcolor:null,bbox:bbox||{}}),1==this.places.length&&this.addStartingPlace(id),this.id++},removePlace:function(id){this.removeStartingPlace(id),this.removeTargetPlace(id),this.places=this.places.filter((function(p){return p.id!=id}))},addStartingPlace:function(id){this.startingplaces.push(id)},removeStartingPlace:function(id){this.startingplaces=this.startingplaces.filter((function(e){return e!=id}))},isStartingPlace:function(id){return this.startingplaces.includes(id)},addTargetPlace:function(id){this.targetplaces.push(id)},removeTargetPlace:function(id){this.targetplaces=this.targetplaces.filter((function(e){return e!=id}))},isTargetPlace:function(id){return this.targetplaces.includes(id)},addPath:function(pid,fid,sid){this.paths.push({id:pid,fid:fid,sid:sid,strokecolor:null,strokedasharray:null,hidepath:null})},removePath:function(id){this.paths=this.paths.filter((function(p){return p.id!=id}))},getTouchingPaths:function(id){return this.paths.filter((function(p){return p.fid==id||p.sid==id}))},getActivityId:function(id){let place=this.places.filter((function(e){return id==e.id}));return place.length>0?place[0].linkedActivity:null},setActivityId:function(id,linkedActivity){let place=this.places.filter((function(e){return id==e.id}));place.length>0&&(place[0].linkedActivity=linkedActivity)},setColor:function(type,color){switch(type){case"stroke":this.strokecolor=color;break;case"place":this.placecolor=color;break;case"visited":this.visitedcolor=color;break;case"text":this.textcolor=color}},getColor:function(type){switch(type){case"stroke":return this.strokecolor;case"place":return this.placecolor;case"visited":return this.visitedcolor;case"text":return this.textcolor}return null},getId:function(){return this.id},setBackgroundDimensions:function(width,height){this.width=width,this.height=height},getPathsWithFid:function(id){return this.paths.filter((function(p){return p.fid==id}))},getPathsWithSid:function(id){return this.paths.filter((function(p){return p.sid==id}))},getPlacestore:function(){return{id:this.id,places:this.places,paths:this.paths,startingplaces:this.startingplaces,targetplaces:this.targetplaces,placecolor:this.placecolor,strokecolor:this.strokecolor,strokeopacity:this.strokeopacity,textcolor:this.textcolor,visitedcolor:this.visitedcolor,height:this.height,width:this.width,hidepaths:this.hidepaths,mapid:this.mapid,usecheckmark:this.usecheckmark,editmode:this.editmode,version:this.version,pulse:this.pulse,hover:this.hover,showall:this.showall,showtext:this.showtext,slicemode:this.slicemode,showwaygone:this.showwaygone}},setHidePaths:function(value){this.hidepaths=value},getHidePaths:function(){return this.hidepaths},setPulse:function(value){this.pulse=value},getPulse:function(){return this.pulse},setHover:function(value){this.hover=value},getHover:function(){return this.hover},setShowall:function(value){this.showall=value},getShowall:function(){return this.showall},getMapid:function(){return this.mapid},getUseCheckmark:function(){return this.usecheckmark},setUseCheckmark:function(value){this.usecheckmark=value},getAllActivities:function(){let activities=[];return this.places.forEach((function(p){p.linkedActivity&&activities.push(p.linkedActivity)})),activities},setStrokeOpacity:function(value){this.strokeopacity=value},getStrokeOpacity:function(){return this.strokeopacity},setHideStroke:function(value){this.strokeopacity=value?0:1},getHideStroke:function(){return this.strokeopacity<1},getShowText:function(){return this.showtext},setShowText:function(value){this.showtext=value},getPlaces:function(){return this.places},getSliceMode:function(){return this.slicemode},setSliceMode:function(value){this.slicemode=value},getShowWayGone:function(){return this.showwaygone},setShowWayGone:function(value){this.showwaygone=value},setBbox:function(id,bbox){let place=this.places.filter((function(e){return id==e.id}));place.length>0&&(place[0].bbox=bbox)}};var _default=placestore;return _exports.default=_default,_exports.default})); //# sourceMappingURL=placestore.min.js.map \ No newline at end of file diff --git a/amd/build/placestore.min.js.map b/amd/build/placestore.min.js.map index 5ddc577..ec5cf24 100644 --- a/amd/build/placestore.min.js.map +++ b/amd/build/placestore.min.js.map @@ -1 +1 @@ -{"version":3,"file":"placestore.min.js","sources":["../src/placestore.js"],"sourcesContent":["let placestore = {\n version: 2024072201,\n id: 0,\n places: [],\n paths: [],\n startingplaces: [],\n targetplaces: [],\n placecolor: '#c01c28',\n strokecolor: '#ffffff',\n strokeopacity: 1,\n textcolor: '#ffffff',\n visitedcolor: '#26a269',\n height: 100,\n width: 800,\n hidepaths: false,\n mapid: '',\n usecheckmark: false,\n editmode: true,\n pulse: false,\n hover: false,\n showall: false,\n showtext: false,\n slicemode: false,\n showwaygone: false,\n /**\n * Loads attributes from JSON into placestore\n * @param {*} json\n */\n loadJSON: function(json) {\n try {\n let fromjson = JSON.parse(json);\n if (fromjson.textcolor === null) {\n fromjson.textcolor = fromjson.strokecolor;\n }\n Object.assign(this, fromjson);\n // eslint-disable-next-line no-empty\n } catch { }\n // Update version (only relevant if learning map is saved)\n this.version = 2024072201;\n },\n /**\n * Returns placestore as a JSON string ()\n * @returns {string}\n */\n buildJSON: function() {\n return JSON.stringify(this.getPlacestore());\n },\n /**\n * Adds a place. If it is the only place, it is set as starting place\n * @param {*} id id of the place\n * @param {*} linkId id of the corresponding link\n * @param {*} linkedActivity course module id of linked activity\n */\n addPlace: function(id, linkId, linkedActivity = null) {\n this.places.push({\n id: id,\n linkId: linkId,\n linkedActivity: linkedActivity,\n placecolor: null,\n visitedcolor: null\n });\n if (this.places.length == 1) {\n this.addStartingPlace(id);\n }\n this.id++;\n },\n /**\n * Removes a place\n * @param {*} id id of the place\n */\n removePlace: function(id) {\n this.removeStartingPlace(id);\n this.removeTargetPlace(id);\n this.places = this.places.filter(\n function(p) {\n return p.id != id;\n }\n );\n },\n /**\n * Adds a place to the array of starting places\n * @param {*} id id of the place\n */\n addStartingPlace: function(id) {\n this.startingplaces.push(id);\n },\n /**\n * Removes a place from the array of starting places\n * @param {*} id id of the place\n */\n removeStartingPlace: function(id) {\n this.startingplaces = this.startingplaces.filter(\n function(e) {\n return e != id;\n }\n );\n },\n /**\n * Returns whether a place is in the array of starting places\n * @param {*} id id of the place\n * @returns {boolean}\n */\n isStartingPlace: function(id) {\n return this.startingplaces.includes(id);\n },\n /**\n * Adds a place to the array of target places\n * @param {*} id id of the place\n */\n addTargetPlace: function(id) {\n this.targetplaces.push(id);\n },\n /**\n * Removes a place from the array of target places\n * @param {*} id id of the place\n */\n removeTargetPlace: function(id) {\n this.targetplaces = this.targetplaces.filter(\n function(e) {\n return e != id;\n }\n );\n },\n /**\n * Returns whether a place is in the array of target places\n * @param {number} id id of the place\n * @returns {boolean}\n */\n isTargetPlace: function(id) {\n return this.targetplaces.includes(id);\n },\n /**\n * Adds a path between two places\n * @param {*} pid id of the path\n * @param {*} fid id of the first place\n * @param {*} sid id of the second place\n */\n addPath: function(pid, fid, sid) {\n this.paths.push({\n id: pid,\n fid: fid,\n sid: sid,\n strokecolor: null,\n strokedasharray: null,\n hidepath: null\n });\n },\n /**\n * Removes a path\n * @param {*} id id of the place\n */\n removePath: function(id) {\n this.paths = this.paths.filter(\n function(p) {\n return p.id != id;\n }\n );\n },\n /**\n * Returns an array of paths touching a place\n * @param {*} id id of the place\n * @returns {array}\n */\n getTouchingPaths: function(id) {\n return this.paths.filter(\n function(p) {\n return p.fid == id || p.sid == id;\n }\n );\n },\n /**\n * Returns the course module id linked to a place\n * @param {*} id id of the place\n * @returns {number} id of the linked course module\n */\n getActivityId: function(id) {\n let place = this.places.filter(\n function(e) {\n return id == e.id;\n }\n );\n if (place.length > 0) {\n return place[0].linkedActivity;\n } else {\n return null;\n }\n },\n /**\n * Sets the id of the linked course module\n * @param {*} id id of the place\n * @param {*} linkedActivity course module id\n */\n setActivityId: function(id, linkedActivity) {\n let place = this.places.filter(\n function(e) {\n return id == e.id;\n }\n );\n if (place.length > 0) {\n place[0].linkedActivity = linkedActivity;\n }\n },\n /**\n * Sets the color of 'stroke', 'place' or 'visited'\n * @param {*} type type of the color\n * @param {*} color color in hex format\n */\n setColor: function(type, color) {\n switch (type) {\n case 'stroke':\n this.strokecolor = color;\n break;\n case 'place':\n this.placecolor = color;\n break;\n case 'visited':\n this.visitedcolor = color;\n break;\n case 'text':\n this.textcolor = color;\n break;\n }\n },\n /**\n * Gets the color of 'stroke', 'place' or 'visited'\n * @param {*} type type of the color\n * @returns {string} color in hex format\n */\n getColor: function(type) {\n switch (type) {\n case 'stroke':\n return this.strokecolor;\n case 'place':\n return this.placecolor;\n case 'visited':\n return this.visitedcolor;\n case 'text':\n return this.textcolor;\n }\n return null;\n },\n /**\n * Returns the current id\n * @returns {number}\n */\n getId: function() {\n return this.id;\n },\n /**\n * Sets the dimensions of the background image\n * @param {*} width\n * @param {*} height\n */\n setBackgroundDimensions: function(width, height) {\n this.width = width;\n this.height = height;\n },\n /**\n * Returns all paths starting at a place\n * @param {*} id id of the place\n * @returns {array}\n */\n getPathsWithFid: function(id) {\n return this.paths.filter(function(p) {\n return p.fid == id;\n });\n },\n /**\n * Returns all paths ending at a place\n * @param {*} id id of the place\n * @returns {array}\n */\n getPathsWithSid: function(id) {\n return this.paths.filter(function(p) {\n return p.sid == id;\n });\n },\n /**\n * Returns the attributes of placestore\n * @returns {object}\n */\n getPlacestore: function() {\n return {\n id: this.id,\n places: this.places,\n paths: this.paths,\n startingplaces: this.startingplaces,\n targetplaces: this.targetplaces,\n placecolor: this.placecolor,\n strokecolor: this.strokecolor,\n strokeopacity: this.strokeopacity,\n textcolor: this.textcolor,\n visitedcolor: this.visitedcolor,\n height: this.height,\n width: this.width,\n hidepaths: this.hidepaths,\n mapid: this.mapid,\n usecheckmark: this.usecheckmark,\n editmode: this.editmode,\n version: this.version,\n pulse: this.pulse,\n hover: this.hover,\n showall: this.showall,\n showtext: this.showtext,\n slicemode: this.slicemode,\n showwaygone: this.showwaygone,\n };\n },\n /**\n * Sets hidepaths attribute\n * @param {boolean} value\n */\n setHidePaths: function(value) {\n this.hidepaths = value;\n },\n /**\n * Returns the value of hidepaths attribute\n * @returns {boolean}\n */\n getHidePaths: function() {\n return this.hidepaths;\n },\n /**\n * Sets pulse attribute\n * @param {boolean} value\n */\n setPulse: function(value) {\n this.pulse = value;\n },\n /**\n * Returns the value of pulse attribute\n * @returns {boolean}\n */\n getPulse: function() {\n return this.pulse;\n },\n /**\n * Sets hover attribute\n * @param {boolean} value\n */\n setHover: function(value) {\n this.hover = value;\n },\n /**\n * Returns the value of hover attribute\n * @returns {boolean}\n */\n getHover: function() {\n return this.hover;\n },\n /**\n * Sets showall attribute\n * @param {boolean} value\n */\n setShowall: function(value) {\n this.showall = value;\n },\n /**\n * Returns the value of showall attribute\n * @returns {boolean}\n */\n getShowall: function() {\n return this.showall;\n },\n /**\n * Returns the mapid\n * @returns {string}\n */\n getMapid: function() {\n return this.mapid;\n },\n /**\n * Returns the value of usecheckmark attribute\n * @returns {boolean}\n */\n getUseCheckmark: function() {\n return this.usecheckmark;\n },\n /**\n * Sets the value of usecheckmark attribute\n * @param {boolean} value\n */\n setUseCheckmark: function(value) {\n this.usecheckmark = value;\n },\n /**\n * Returns an array with all activity ids\n * @returns {array}\n */\n getAllActivities: function() {\n let activities = [];\n this.places.forEach(function(p) {\n if (p.linkedActivity) {\n activities.push(p.linkedActivity);\n }\n });\n return activities;\n },\n /**\n * Sets stroke opacity\n * @param {number} value\n */\n setStrokeOpacity: function(value) {\n this.strokeopacity = value;\n },\n /**\n * Returns the current stroke opacity\n * @returns {number}\n */\n getStrokeOpacity: function() {\n return this.strokeopacity;\n },\n /**\n * Sets stroke opacity to 0\n * @param {number} value\n */\n setHideStroke: function(value) {\n this.strokeopacity = (value ? 0 : 1);\n },\n /**\n * Returns the current stroke opacity\n * @returns {number}\n */\n getHideStroke: function() {\n return this.strokeopacity < 1;\n },\n /**\n * Returns the value of showtext attribute\n * @returns {boolean}\n */\n getShowText: function() {\n return this.showtext;\n },\n /**\n * Sets the value of showtext attribute\n * @param {boolean} value\n */\n setShowText: function(value) {\n this.showtext = value;\n },\n /**\n * Returns an array with all place identifiers\n * @returns {array}\n */\n getPlaces: function() {\n return this.places;\n },\n /**\n * Returns if slicemode is enabled\n * @returns {boolean}\n */\n getSliceMode: function() {\n return this.slicemode;\n },\n /**\n * Sets state of slicemode\n * @param {boolean} value\n */\n setSliceMode: function(value) {\n this.slicemode = value;\n },\n /**\n * Returns if showwaygone is enabled\n * @returns {boolean}\n */\n getShowWayGone: function() {\n return this.showwaygone;\n },\n /**\n * Sets state of showwaygone\n * @param {boolean} value\n */\n setShowWayGone: function(value) {\n this.showwaygone = value;\n },\n};\n\nexport default placestore;\n"],"names":["placestore","version","id","places","paths","startingplaces","targetplaces","placecolor","strokecolor","strokeopacity","textcolor","visitedcolor","height","width","hidepaths","mapid","usecheckmark","editmode","pulse","hover","showall","showtext","slicemode","showwaygone","loadJSON","json","fromjson","JSON","parse","Object","assign","this","buildJSON","stringify","getPlacestore","addPlace","linkId","linkedActivity","push","length","addStartingPlace","removePlace","removeStartingPlace","removeTargetPlace","filter","p","e","isStartingPlace","includes","addTargetPlace","isTargetPlace","addPath","pid","fid","sid","strokedasharray","hidepath","removePath","getTouchingPaths","getActivityId","place","setActivityId","setColor","type","color","getColor","getId","setBackgroundDimensions","getPathsWithFid","getPathsWithSid","setHidePaths","value","getHidePaths","setPulse","getPulse","setHover","getHover","setShowall","getShowall","getMapid","getUseCheckmark","setUseCheckmark","getAllActivities","activities","forEach","setStrokeOpacity","getStrokeOpacity","setHideStroke","getHideStroke","getShowText","setShowText","getPlaces","getSliceMode","setSliceMode","getShowWayGone","setShowWayGone"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"placestore.min.js","sources":["../src/placestore.js"],"sourcesContent":["let placestore = {\n version: 2024072201,\n id: 0,\n places: [],\n paths: [],\n startingplaces: [],\n targetplaces: [],\n placecolor: '#c01c28',\n strokecolor: '#ffffff',\n strokeopacity: 1,\n textcolor: '#ffffff',\n visitedcolor: '#26a269',\n height: 100,\n width: 800,\n hidepaths: false,\n mapid: '',\n usecheckmark: false,\n editmode: true,\n pulse: false,\n hover: false,\n showall: false,\n showtext: false,\n slicemode: false,\n showwaygone: false,\n /**\n * Loads attributes from JSON into placestore\n * @param {*} json\n */\n loadJSON: function(json) {\n try {\n let fromjson = JSON.parse(json);\n if (fromjson.textcolor === null) {\n fromjson.textcolor = fromjson.strokecolor;\n }\n Object.assign(this, fromjson);\n // eslint-disable-next-line no-empty\n } catch { }\n // Update version (only relevant if learning map is saved)\n this.version = 2024072201;\n },\n /**\n * Returns placestore as a JSON string ()\n * @returns {string}\n */\n buildJSON: function() {\n return JSON.stringify(this.getPlacestore());\n },\n /**\n * Adds a place. If it is the only place, it is set as starting place\n * @param {*} id id of the place\n * @param {*} linkId id of the corresponding link\n * @param {*} linkedActivity course module id of linked activity\n * @param {*} bbox bounding box of the place (including text)\n */\n addPlace: function(id, linkId, linkedActivity = null, bbox = {}) {\n this.places.push({\n id: id,\n linkId: linkId,\n linkedActivity: linkedActivity,\n placecolor: null,\n visitedcolor: null,\n bbox: bbox || {},\n });\n if (this.places.length == 1) {\n this.addStartingPlace(id);\n }\n this.id++;\n },\n /**\n * Removes a place\n * @param {*} id id of the place\n */\n removePlace: function(id) {\n this.removeStartingPlace(id);\n this.removeTargetPlace(id);\n this.places = this.places.filter(\n function(p) {\n return p.id != id;\n }\n );\n },\n /**\n * Adds a place to the array of starting places\n * @param {*} id id of the place\n */\n addStartingPlace: function(id) {\n this.startingplaces.push(id);\n },\n /**\n * Removes a place from the array of starting places\n * @param {*} id id of the place\n */\n removeStartingPlace: function(id) {\n this.startingplaces = this.startingplaces.filter(\n function(e) {\n return e != id;\n }\n );\n },\n /**\n * Returns whether a place is in the array of starting places\n * @param {*} id id of the place\n * @returns {boolean}\n */\n isStartingPlace: function(id) {\n return this.startingplaces.includes(id);\n },\n /**\n * Adds a place to the array of target places\n * @param {*} id id of the place\n */\n addTargetPlace: function(id) {\n this.targetplaces.push(id);\n },\n /**\n * Removes a place from the array of target places\n * @param {*} id id of the place\n */\n removeTargetPlace: function(id) {\n this.targetplaces = this.targetplaces.filter(\n function(e) {\n return e != id;\n }\n );\n },\n /**\n * Returns whether a place is in the array of target places\n * @param {number} id id of the place\n * @returns {boolean}\n */\n isTargetPlace: function(id) {\n return this.targetplaces.includes(id);\n },\n /**\n * Adds a path between two places\n * @param {*} pid id of the path\n * @param {*} fid id of the first place\n * @param {*} sid id of the second place\n */\n addPath: function(pid, fid, sid) {\n this.paths.push({\n id: pid,\n fid: fid,\n sid: sid,\n strokecolor: null,\n strokedasharray: null,\n hidepath: null\n });\n },\n /**\n * Removes a path\n * @param {*} id id of the place\n */\n removePath: function(id) {\n this.paths = this.paths.filter(\n function(p) {\n return p.id != id;\n }\n );\n },\n /**\n * Returns an array of paths touching a place\n * @param {*} id id of the place\n * @returns {array}\n */\n getTouchingPaths: function(id) {\n return this.paths.filter(\n function(p) {\n return p.fid == id || p.sid == id;\n }\n );\n },\n /**\n * Returns the course module id linked to a place\n * @param {*} id id of the place\n * @returns {number} id of the linked course module\n */\n getActivityId: function(id) {\n let place = this.places.filter(\n function(e) {\n return id == e.id;\n }\n );\n if (place.length > 0) {\n return place[0].linkedActivity;\n } else {\n return null;\n }\n },\n /**\n * Sets the id of the linked course module\n * @param {*} id id of the place\n * @param {*} linkedActivity course module id\n */\n setActivityId: function(id, linkedActivity) {\n let place = this.places.filter(\n function(e) {\n return id == e.id;\n }\n );\n if (place.length > 0) {\n place[0].linkedActivity = linkedActivity;\n }\n },\n /**\n * Sets the color of 'stroke', 'place' or 'visited'\n * @param {*} type type of the color\n * @param {*} color color in hex format\n */\n setColor: function(type, color) {\n switch (type) {\n case 'stroke':\n this.strokecolor = color;\n break;\n case 'place':\n this.placecolor = color;\n break;\n case 'visited':\n this.visitedcolor = color;\n break;\n case 'text':\n this.textcolor = color;\n break;\n }\n },\n /**\n * Gets the color of 'stroke', 'place' or 'visited'\n * @param {*} type type of the color\n * @returns {string} color in hex format\n */\n getColor: function(type) {\n switch (type) {\n case 'stroke':\n return this.strokecolor;\n case 'place':\n return this.placecolor;\n case 'visited':\n return this.visitedcolor;\n case 'text':\n return this.textcolor;\n }\n return null;\n },\n /**\n * Returns the current id\n * @returns {number}\n */\n getId: function() {\n return this.id;\n },\n /**\n * Sets the dimensions of the background image\n * @param {*} width\n * @param {*} height\n */\n setBackgroundDimensions: function(width, height) {\n this.width = width;\n this.height = height;\n },\n /**\n * Returns all paths starting at a place\n * @param {*} id id of the place\n * @returns {array}\n */\n getPathsWithFid: function(id) {\n return this.paths.filter(function(p) {\n return p.fid == id;\n });\n },\n /**\n * Returns all paths ending at a place\n * @param {*} id id of the place\n * @returns {array}\n */\n getPathsWithSid: function(id) {\n return this.paths.filter(function(p) {\n return p.sid == id;\n });\n },\n /**\n * Returns the attributes of placestore\n * @returns {object}\n */\n getPlacestore: function() {\n return {\n id: this.id,\n places: this.places,\n paths: this.paths,\n startingplaces: this.startingplaces,\n targetplaces: this.targetplaces,\n placecolor: this.placecolor,\n strokecolor: this.strokecolor,\n strokeopacity: this.strokeopacity,\n textcolor: this.textcolor,\n visitedcolor: this.visitedcolor,\n height: this.height,\n width: this.width,\n hidepaths: this.hidepaths,\n mapid: this.mapid,\n usecheckmark: this.usecheckmark,\n editmode: this.editmode,\n version: this.version,\n pulse: this.pulse,\n hover: this.hover,\n showall: this.showall,\n showtext: this.showtext,\n slicemode: this.slicemode,\n showwaygone: this.showwaygone,\n };\n },\n /**\n * Sets hidepaths attribute\n * @param {boolean} value\n */\n setHidePaths: function(value) {\n this.hidepaths = value;\n },\n /**\n * Returns the value of hidepaths attribute\n * @returns {boolean}\n */\n getHidePaths: function() {\n return this.hidepaths;\n },\n /**\n * Sets pulse attribute\n * @param {boolean} value\n */\n setPulse: function(value) {\n this.pulse = value;\n },\n /**\n * Returns the value of pulse attribute\n * @returns {boolean}\n */\n getPulse: function() {\n return this.pulse;\n },\n /**\n * Sets hover attribute\n * @param {boolean} value\n */\n setHover: function(value) {\n this.hover = value;\n },\n /**\n * Returns the value of hover attribute\n * @returns {boolean}\n */\n getHover: function() {\n return this.hover;\n },\n /**\n * Sets showall attribute\n * @param {boolean} value\n */\n setShowall: function(value) {\n this.showall = value;\n },\n /**\n * Returns the value of showall attribute\n * @returns {boolean}\n */\n getShowall: function() {\n return this.showall;\n },\n /**\n * Returns the mapid\n * @returns {string}\n */\n getMapid: function() {\n return this.mapid;\n },\n /**\n * Returns the value of usecheckmark attribute\n * @returns {boolean}\n */\n getUseCheckmark: function() {\n return this.usecheckmark;\n },\n /**\n * Sets the value of usecheckmark attribute\n * @param {boolean} value\n */\n setUseCheckmark: function(value) {\n this.usecheckmark = value;\n },\n /**\n * Returns an array with all activity ids\n * @returns {array}\n */\n getAllActivities: function() {\n let activities = [];\n this.places.forEach(function(p) {\n if (p.linkedActivity) {\n activities.push(p.linkedActivity);\n }\n });\n return activities;\n },\n /**\n * Sets stroke opacity\n * @param {number} value\n */\n setStrokeOpacity: function(value) {\n this.strokeopacity = value;\n },\n /**\n * Returns the current stroke opacity\n * @returns {number}\n */\n getStrokeOpacity: function() {\n return this.strokeopacity;\n },\n /**\n * Sets stroke opacity to 0\n * @param {number} value\n */\n setHideStroke: function(value) {\n this.strokeopacity = (value ? 0 : 1);\n },\n /**\n * Returns the current stroke opacity\n * @returns {number}\n */\n getHideStroke: function() {\n return this.strokeopacity < 1;\n },\n /**\n * Returns the value of showtext attribute\n * @returns {boolean}\n */\n getShowText: function() {\n return this.showtext;\n },\n /**\n * Sets the value of showtext attribute\n * @param {boolean} value\n */\n setShowText: function(value) {\n this.showtext = value;\n },\n /**\n * Returns an array with all place identifiers\n * @returns {array}\n */\n getPlaces: function() {\n return this.places;\n },\n /**\n * Returns if slicemode is enabled\n * @returns {boolean}\n */\n getSliceMode: function() {\n return this.slicemode;\n },\n /**\n * Sets state of slicemode\n * @param {boolean} value\n */\n setSliceMode: function(value) {\n this.slicemode = value;\n },\n /**\n * Returns if showwaygone is enabled\n * @returns {boolean}\n */\n getShowWayGone: function() {\n return this.showwaygone;\n },\n /**\n * Sets state of showwaygone\n * @param {boolean} value\n */\n setShowWayGone: function(value) {\n this.showwaygone = value;\n },\n /**\n * Sets the bbox of the place\n * @param {*} id id of the place\n * @param {*} bbox bounding box of the place (including text)\n */\n setBbox: function(id, bbox) {\n let place = this.places.filter(\n function(e) {\n return id == e.id;\n }\n );\n if (place.length > 0) {\n place[0].bbox = bbox;\n }\n },\n};\n\nexport default placestore;\n"],"names":["placestore","version","id","places","paths","startingplaces","targetplaces","placecolor","strokecolor","strokeopacity","textcolor","visitedcolor","height","width","hidepaths","mapid","usecheckmark","editmode","pulse","hover","showall","showtext","slicemode","showwaygone","loadJSON","json","fromjson","JSON","parse","Object","assign","this","buildJSON","stringify","getPlacestore","addPlace","linkId","linkedActivity","bbox","push","length","addStartingPlace","removePlace","removeStartingPlace","removeTargetPlace","filter","p","e","isStartingPlace","includes","addTargetPlace","isTargetPlace","addPath","pid","fid","sid","strokedasharray","hidepath","removePath","getTouchingPaths","getActivityId","place","setActivityId","setColor","type","color","getColor","getId","setBackgroundDimensions","getPathsWithFid","getPathsWithSid","setHidePaths","value","getHidePaths","setPulse","getPulse","setHover","getHover","setShowall","getShowall","getMapid","getUseCheckmark","setUseCheckmark","getAllActivities","activities","forEach","setStrokeOpacity","getStrokeOpacity","setHideStroke","getHideStroke","getShowText","setShowText","getPlaces","getSliceMode","setSliceMode","getShowWayGone","setShowWayGone","setBbox"],"mappings":"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"} \ No newline at end of file diff --git a/amd/build/shapes.min.js b/amd/build/shapes.min.js new file mode 100644 index 0000000..627cfb1 --- /dev/null +++ b/amd/build/shapes.min.js @@ -0,0 +1,11 @@ +define("mod_learningmap/shapes",["exports","./circle","./square","./emoji"],(function(_exports,_circle,_square,_emoji){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} +/** + * Shapes for learningmap places. + * + * @module mod_learningmap/shapes + * @copyright 2024 ISB Bayern + * @author Stefan Hanauska + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_circle=_interopRequireDefault(_circle),_square=_interopRequireDefault(_square),_emoji=_interopRequireDefault(_emoji);var _default={circle:_circle.default,square:_square.default,emoji:_emoji.default};return _exports.default=_default,_exports.default})); + +//# sourceMappingURL=shapes.min.js.map \ No newline at end of file diff --git a/amd/build/shapes.min.js.map b/amd/build/shapes.min.js.map new file mode 100644 index 0000000..337c155 --- /dev/null +++ b/amd/build/shapes.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"shapes.min.js","sources":["../src/shapes.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Shapes for learningmap places.\n *\n * @module mod_learningmap/shapes\n * @copyright 2024 ISB Bayern\n * @author Stefan Hanauska \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport circle from './circle';\nimport square from './square';\nimport emoji from './emoji';\n\nexport default {\n circle: circle,\n square: square,\n emoji: emoji,\n};"],"names":["circle","square","emoji"],"mappings":";;;;;;;;wNA4Be,CACXA,OAAQA,gBACRC,OAAQA,gBACRC,MAAOA"} \ No newline at end of file diff --git a/amd/build/square.min.js b/amd/build/square.min.js new file mode 100644 index 0000000..a59c89d --- /dev/null +++ b/amd/build/square.min.js @@ -0,0 +1,12 @@ +define("mod_learningmap/square",["exports"],(function(_exports){return Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default= +/** + * A square shape. + * + * @module mod_learningmap/square + * @copyright 2024 ISB Bayern + * @author Stefan Hanauska + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +function(mapsvg,x,y,r,classes,id){return mapsvg.rect(2*r,2*r).cx(x).cy(y).attr({class:classes}).id(id)},_exports.default})); + +//# sourceMappingURL=square.min.js.map \ No newline at end of file diff --git a/amd/build/square.min.js.map b/amd/build/square.min.js.map new file mode 100644 index 0000000..a3bd47d --- /dev/null +++ b/amd/build/square.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"square.min.js","sources":["../src/square.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * A square shape.\n *\n * @module mod_learningmap/square\n * @copyright 2024 ISB Bayern\n * @author Stefan Hanauska \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Returns a rectangle with the given dimensions\n * @param {*} mapsvg\n * @param {*} x\n * @param {*} y\n * @param {*} r\n * @param {*} classes\n * @param {*} id\n * @returns\n */\nexport default function(mapsvg, x, y, r, classes, id) {\n return mapsvg.rect(r * 2, r * 2).cx(x).cy(y).attr({'class': classes}).id(id);\n}"],"names":["mapsvg","x","y","r","classes","id","rect","cx","cy","attr"],"mappings":";;;;;;;;;SAkCwBA,OAAQC,EAAGC,EAAGC,EAAGC,QAASC,WACvCL,OAAOM,KAAS,EAAJH,EAAW,EAAJA,GAAOI,GAAGN,GAAGO,GAAGN,GAAGO,KAAK,OAAUL,UAAUC,GAAGA"} \ No newline at end of file diff --git a/amd/build/svg.min.js b/amd/build/svg.min.js new file mode 100644 index 0000000..f2dcb42 --- /dev/null +++ b/amd/build/svg.min.js @@ -0,0 +1,36 @@ +define("mod_learningmap/svg",["exports"],(function(_exports){return Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default= +/* + * @svgdotjs/svg.js - A lightweight library for manipulating and animating SVG. + * @version 3.2.4 + * https://svgjs.dev/ + * + * @copyright Wout Fierens + * @license MIT + * Copyright (c) 2012-2018 Wout Fierens + * https://svgdotjs.github.io/ + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * BUILT: Thu Jun 27 2024 12:00:16 GMT+0200 (Central European Summer Time) + */ +function(){const methods$1={},names=[];function registerMethods(name,m){if(Array.isArray(name))for(const _name of name)registerMethods(_name,m);else if("object"!=typeof name)addMethodNames(Object.getOwnPropertyNames(m)),methods$1[name]=Object.assign(methods$1[name]||{},m);else for(const _name in name)registerMethods(_name,name[_name])}function getMethodsFor(name){return methods$1[name]||{}}function addMethodNames(_names){names.push(..._names)}function map(array,block){let i;const il=array.length,result=[];for(i=0;idescriptiveElements.has(element.nodeName),writeDataToDom=function(element,data){let defaults=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const cloned={...data};for(const key in cloned)cloned[key].valueOf()===defaults[key]&&delete cloned[key];Object.keys(cloned).length?element.node.setAttribute("data-svgjs",JSON.stringify(cloned)):(element.node.removeAttribute("data-svgjs"),element.node.removeAttribute("svgjs:data"))};var utils={__proto__:null,capitalize:capitalize,degrees:function(r){return 180*r/Math.PI%360},filter:filter,getOrigin:getOrigin,isDescriptive:isDescriptive,map:map,proportionalSize:proportionalSize,radians:radians,unCamelCase:unCamelCase,writeDataToDom:writeDataToDom};const svg="http://www.w3.org/2000/svg",html="http://www.w3.org/1999/xhtml",xmlns="http://www.w3.org/2000/xmlns/",xlink="http://www.w3.org/1999/xlink";var namespaces={__proto__:null,html:html,svg:svg,xlink:xlink,xmlns:xmlns};const globals={window:"undefined"==typeof window?null:window,document:"undefined"==typeof document?null:document};function registerWindow(){let win=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,doc=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;globals.window=win,globals.document=doc}const save={};function saveWindow(){save.window=globals.window,save.document=globals.document}function restoreWindow(){globals.window=save.window,globals.document=save.document}function getWindow(){return globals.window}class Base{}const elements={},root="___SYMBOL___ROOT___";function create(name){let ns=arguments.length>1&&void 0!==arguments[1]?arguments[1]:svg;return globals.document.createElementNS(ns,name)}function makeInstance(element){let isHTML=arguments.length>1&&void 0!==arguments[1]&&arguments[1];if(element instanceof Base)return element;if("object"==typeof element)return adopter(element);if(null==element)return new elements[root];if("string"==typeof element&&"<"!==element.charAt(0))return adopter(globals.document.querySelector(element));const wrapper=isHTML?globals.document.createElement("div"):create("svg");return wrapper.innerHTML=element,element=adopter(wrapper.firstChild),wrapper.removeChild(wrapper.firstChild),element}function nodeOrNew(name,node){return node&&(node instanceof globals.window.Node||node.ownerDocument&&node instanceof node.ownerDocument.defaultView.Node)?node:create(name)}function adopt(node){if(!node)return null;if(node.instance instanceof Base)return node.instance;if("#document-fragment"===node.nodeName)return new elements.Fragment(node);let className=capitalize(node.nodeName||"Dom");return"LinearGradient"===className||"RadialGradient"===className?className="Gradient":elements[className]||(className="Dom"),new elements[className](node)}let adopter=adopt;function register(element){let name=arguments.length>1&&void 0!==arguments[1]?arguments[1]:element.name,asRoot=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return elements[name]=element,asRoot&&(elements[root]=element),addMethodNames(Object.getOwnPropertyNames(element.prototype)),element}function getClass(name){return elements[name]}let did=1e3;function eid(name){return"Svgjs"+capitalize(name)+did++}function assignNewId(node){for(let i=node.children.length-1;i>=0;i--)assignNewId(node.children[i]);return node.id?(node.id=eid(node.nodeName),node):node}function extend(modules,methods){let key,i;for(i=(modules=Array.isArray(modules)?modules:[modules]).length-1;i>=0;i--)for(key in methods)modules[i].prototype[key]=methods[key]}function wrapWithAttrCheck(fn){return function(){for(var _len=arguments.length,args=new Array(_len),_key=0;_key<_len;_key++)args[_key]=arguments[_key];const o=args[args.length-1];return!o||o.constructor!==Object||o instanceof Array?fn.apply(this,args):fn.apply(this,args.slice(0,-1)).attr(o)}}registerMethods("Dom",{siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},prev:function(){return this.siblings()[this.position()-1]},forward:function(){const i=this.position();return this.parent().add(this.remove(),i+1),this},backward:function(){const i=this.position();return this.parent().add(this.remove(),i?i-1:0),this},front:function(){return this.parent().add(this.remove()),this},back:function(){return this.parent().add(this.remove(),0),this},before:function(element){(element=makeInstance(element)).remove();const i=this.position();return this.parent().add(element,i),this},after:function(element){(element=makeInstance(element)).remove();const i=this.position();return this.parent().add(element,i+1),this},insertBefore:function(element){return(element=makeInstance(element)).before(this),this},insertAfter:function(element){return(element=makeInstance(element)).after(this),this}});const numberAndUnit=/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,hex=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb=/rgb\((\d+),(\d+),(\d+)\)/,reference=/(#[a-z_][a-z0-9\-_]*)/i,transforms=/\)\s*,?\s*/,whitespace=/\s/g,isHex=/^#[a-f0-9]{3}$|^#[a-f0-9]{6}$/i,isRgb=/^rgb\(/,isBlank=/^(\s+)?$/,isNumber=/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,isImage=/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,delimiter=/[\s,]+/,isPathLetter=/[MLHVCSQTAZ]/i;var regex={__proto__:null,delimiter:delimiter,hex:hex,isBlank:isBlank,isHex:isHex,isImage:isImage,isNumber:isNumber,isPathLetter:isPathLetter,isRgb:isRgb,numberAndUnit:numberAndUnit,reference:reference,rgb:rgb,transforms:transforms,whitespace:whitespace};function componentHex(component){const integer=Math.round(component),hex=Math.max(0,Math.min(255,integer)).toString(16);return 1===hex.length?"0"+hex:hex}function is(object,space){for(let i=space.length;i--;)if(null==object[space[i]])return!1;return!0}function hueToRgb(p,q,t){return t<0&&(t+=1),t>1&&(t-=1),t<1/6?p+6*(q-p)*t:t<.5?q:t<2/3?p+(q-p)*(2/3-t)*6:p}registerMethods("Dom",{classes:function(){const attr=this.attr("class");return null==attr?[]:attr.trim().split(delimiter)},hasClass:function(name){return-1!==this.classes().indexOf(name)},addClass:function(name){if(!this.hasClass(name)){const array=this.classes();array.push(name),this.attr("class",array.join(" "))}return this},removeClass:function(name){return this.hasClass(name)&&this.attr("class",this.classes().filter((function(c){return c!==name})).join(" ")),this},toggleClass:function(name){return this.hasClass(name)?this.removeClass(name):this.addClass(name)}}),registerMethods("Dom",{css:function(style,val){const ret={};if(0===arguments.length)return this.node.style.cssText.split(/\s*;\s*/).filter((function(el){return!!el.length})).forEach((function(el){const t=el.split(/\s*:\s*/);ret[t[0]]=t[1]})),ret;if(arguments.length<2){if(Array.isArray(style)){for(const name of style){const cased=name;ret[name]=this.node.style.getPropertyValue(cased)}return ret}if("string"==typeof style)return this.node.style.getPropertyValue(style);if("object"==typeof style)for(const name in style)this.node.style.setProperty(name,null==style[name]||isBlank.test(style[name])?"":style[name])}return 2===arguments.length&&this.node.style.setProperty(style,null==val||isBlank.test(val)?"":val),this},show:function(){return this.css("display","")},hide:function(){return this.css("display","none")},visible:function(){return"none"!==this.css("display")}}),registerMethods("Dom",{data:function(a,v,r){if(null==a)return this.data(map(filter(this.node.attributes,(el=>0===el.nodeName.indexOf("data-"))),(el=>el.nodeName.slice(5))));if(a instanceof Array){const data={};for(const key of a)data[key]=this.data(key);return data}if("object"==typeof a)for(v in a)this.data(v,a[v]);else if(arguments.length<2)try{return JSON.parse(this.attr("data-"+a))}catch(e){return this.attr("data-"+a)}else this.attr("data-"+a,null===v?null:!0===r||"string"==typeof v||"number"==typeof v?v:JSON.stringify(v));return this}}),registerMethods("Dom",{remember:function(k,v){if("object"==typeof arguments[0])for(const key in k)this.remember(key,k[key]);else{if(1===arguments.length)return this.memory()[k];this.memory()[k]=v}return this},forget:function(){if(0===arguments.length)this._memory={};else for(let i=arguments.length-1;i>=0;i--)delete this.memory()[arguments[i]];return this},memory:function(){return this._memory=this._memory||{}}});class Color{constructor(){this.init(...arguments)}static isColor(color){return color&&(color instanceof Color||this.isRgb(color)||this.test(color))}static isRgb(color){return color&&"number"==typeof color.r&&"number"==typeof color.g&&"number"==typeof color.b}static random(){let mode=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"vibrant",t=arguments.length>1?arguments[1]:void 0;const{random:random,round:round,sin:sin,PI:pi}=Math;if("vibrant"===mode){const l=24*random()+57,c=38*random()+45,h=360*random();return new Color(l,c,h,"lch")}if("sine"===mode){t=null==t?random():t;const r=round(80*sin(2*pi*t/.5+.01)+150),g=round(50*sin(2*pi*t/.5+4.6)+200),b=round(100*sin(2*pi*t/.5+2.3)+150);return new Color(r,g,b)}if("pastel"===mode){const l=8*random()+86,c=17*random()+9,h=360*random();return new Color(l,c,h,"lch")}if("dark"===mode){const l=10+10*random(),c=50*random()+86,h=360*random();return new Color(l,c,h,"lch")}if("rgb"===mode){const r=255*random(),g=255*random(),b=255*random();return new Color(r,g,b)}if("lab"===mode){const l=100*random(),a=256*random()-128,b=256*random()-128;return new Color(l,a,b,"lab")}if("grey"===mode){const grey=255*random();return new Color(grey,grey,grey)}throw new Error("Unsupported random color mode")}static test(color){return"string"==typeof color&&(isHex.test(color)||isRgb.test(color))}cmyk(){const{_a:_a,_b:_b,_c:_c}=this.rgb(),[r,g,b]=[_a,_b,_c].map((v=>v/255)),k=Math.min(1-r,1-g,1-b);if(1===k)return new Color(0,0,0,1,"cmyk");return new Color((1-r-k)/(1-k),(1-g-k)/(1-k),(1-b-k)/(1-k),k,"cmyk")}hsl(){const{_a:_a,_b:_b,_c:_c}=this.rgb(),[r,g,b]=[_a,_b,_c].map((v=>v/255)),max=Math.max(r,g,b),min=Math.min(r,g,b),l=(max+min)/2,isGrey=max===min,delta=max-min;return new Color(360*(isGrey?0:max===r?((g-b)/delta+(g.5?delta/(2-max-min):delta/(max+min)),100*l,"hsl")}init(){let a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,b=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,c=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,d=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,space=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"rgb";if(a=a||0,this.space)for(const component in this.space)delete this[this.space[component]];if("number"==typeof a)space="string"==typeof d?d:space,d="string"==typeof d?0:d,Object.assign(this,{_a:a,_b:b,_c:c,_d:d,space:space});else if(a instanceof Array)this.space=b||("string"==typeof a[3]?a[3]:a[4])||"rgb",Object.assign(this,{_a:a[0],_b:a[1],_c:a[2],_d:a[3]||0});else if(a instanceof Object){const values=function(a,b){const params=is(a,"rgb")?{_a:a.r,_b:a.g,_c:a.b,_d:0,space:"rgb"}:is(a,"xyz")?{_a:a.x,_b:a.y,_c:a.z,_d:0,space:"xyz"}:is(a,"hsl")?{_a:a.h,_b:a.s,_c:a.l,_d:0,space:"hsl"}:is(a,"lab")?{_a:a.l,_b:a.a,_c:a.b,_d:0,space:"lab"}:is(a,"lch")?{_a:a.l,_b:a.c,_c:a.h,_d:0,space:"lch"}:is(a,"cmyk")?{_a:a.c,_b:a.m,_c:a.y,_d:a.k,space:"cmyk"}:{_a:0,_b:0,_c:0,space:"rgb"};return params.space=b||params.space,params}(a,b);Object.assign(this,values)}else if("string"==typeof a)if(isRgb.test(a)){const noWhitespace=a.replace(whitespace,""),[_a,_b,_c]=rgb.exec(noWhitespace).slice(1,4).map((v=>parseInt(v)));Object.assign(this,{_a:_a,_b:_b,_c:_c,_d:0,space:"rgb"})}else{if(!isHex.test(a))throw Error("Unsupported string format, can't construct Color");{const hexParse=v=>parseInt(v,16),[,_a,_b,_c]=hex.exec(function(hex){return 4===hex.length?["#",hex.substring(1,2),hex.substring(1,2),hex.substring(2,3),hex.substring(2,3),hex.substring(3,4),hex.substring(3,4)].join(""):hex}(a)).map(hexParse);Object.assign(this,{_a:_a,_b:_b,_c:_c,_d:0,space:"rgb"})}}const{_a:_a,_b:_b,_c:_c,_d:_d}=this,components="rgb"===this.space?{r:_a,g:_b,b:_c}:"xyz"===this.space?{x:_a,y:_b,z:_c}:"hsl"===this.space?{h:_a,s:_b,l:_c}:"lab"===this.space?{l:_a,a:_b,b:_c}:"lch"===this.space?{l:_a,c:_b,h:_c}:"cmyk"===this.space?{c:_a,m:_b,y:_c,k:_d}:{};Object.assign(this,components)}lab(){const{x:x,y:y,z:z}=this.xyz();return new Color(116*y-16,500*(x-y),200*(y-z),"lab")}lch(){const{l:l,a:a,b:b}=this.lab(),c=Math.sqrt(a**2+b**2);let h=180*Math.atan2(b,a)/Math.PI;h<0&&(h*=-1,h=360-h);return new Color(l,c,h,"lch")}rgb(){if("rgb"===this.space)return this;if("lab"===(space=this.space)||"xyz"===space||"lch"===space){let{x:x,y:y,z:z}=this;if("lab"===this.space||"lch"===this.space){let{l:l,a:a,b:b}=this;if("lch"===this.space){const{c:c,h:h}=this,dToR=Math.PI/180;a=c*Math.cos(dToR*h),b=c*Math.sin(dToR*h)}const yL=(l+16)/116,xL=a/500+yL,zL=yL-b/200,ct=16/116,mx=.008856,nm=7.787;x=.95047*(xL**3>mx?xL**3:(xL-ct)/nm),y=1*(yL**3>mx?yL**3:(yL-ct)/nm),z=1.08883*(zL**3>mx?zL**3:(zL-ct)/nm)}const rU=3.2406*x+-1.5372*y+-.4986*z,gU=-.9689*x+1.8758*y+.0415*z,bU=.0557*x+-.204*y+1.057*z,pow=Math.pow,bd=.0031308,r=rU>bd?1.055*pow(rU,1/2.4)-.055:12.92*rU,g=gU>bd?1.055*pow(gU,1/2.4)-.055:12.92*gU,b=bU>bd?1.055*pow(bU,1/2.4)-.055:12.92*bU;return new Color(255*r,255*g,255*b)}if("hsl"===this.space){let{h:h,s:s,l:l}=this;if(h/=360,s/=100,l/=100,0===s){l*=255;return new Color(l,l,l)}const q=l<.5?l*(1+s):l+s-l*s,p=2*l-q,r=255*hueToRgb(p,q,h+1/3),g=255*hueToRgb(p,q,h),b=255*hueToRgb(p,q,h-1/3);return new Color(r,g,b)}if("cmyk"===this.space){const{c:c,m:m,y:y,k:k}=this,r=255*(1-Math.min(1,c*(1-k)+k)),g=255*(1-Math.min(1,m*(1-k)+k)),b=255*(1-Math.min(1,y*(1-k)+k));return new Color(r,g,b)}return this;var space}toArray(){const{_a:_a,_b:_b,_c:_c,_d:_d,space:space}=this;return[_a,_b,_c,_d,space]}toHex(){const[r,g,b]=this._clamped().map(componentHex);return"#".concat(r).concat(g).concat(b)}toRgb(){const[rV,gV,bV]=this._clamped();return"rgb(".concat(rV,",").concat(gV,",").concat(bV,")")}toString(){return this.toHex()}xyz(){const{_a:r255,_b:g255,_c:b255}=this.rgb(),[r,g,b]=[r255,g255,b255].map((v=>v/255)),rL=r>.04045?Math.pow((r+.055)/1.055,2.4):r/12.92,gL=g>.04045?Math.pow((g+.055)/1.055,2.4):g/12.92,bL=b>.04045?Math.pow((b+.055)/1.055,2.4):b/12.92,xU=(.4124*rL+.3576*gL+.1805*bL)/.95047,yU=(.2126*rL+.7152*gL+.0722*bL)/1,zU=(.0193*rL+.1192*gL+.9505*bL)/1.08883,x=xU>.008856?Math.pow(xU,1/3):7.787*xU+16/116,y=yU>.008856?Math.pow(yU,1/3):7.787*yU+16/116,z=zU>.008856?Math.pow(zU,1/3):7.787*zU+16/116;return new Color(x,y,z,"xyz")}_clamped(){const{_a:_a,_b:_b,_c:_c}=this.rgb(),{max:max,min:min,round:round}=Math;return[_a,_b,_c].map((v=>max(0,min(round(v),255))))}}class Point{constructor(){this.init(...arguments)}clone(){return new Point(this)}init(x,y){const base_x=0,base_y=0,source=Array.isArray(x)?{x:x[0],y:x[1]}:"object"==typeof x?{x:x.x,y:x.y}:{x:x,y:y};return this.x=null==source.x?base_x:source.x,this.y=null==source.y?base_y:source.y,this}toArray(){return[this.x,this.y]}transform(m){return this.clone().transformO(m)}transformO(m){Matrix.isMatrixLike(m)||(m=new Matrix(m));const{x:x,y:y}=this;return this.x=m.a*x+m.c*y+m.e,this.y=m.b*x+m.d*y+m.f,this}}function closeEnough(a,b,threshold){return Math.abs(b-a)<1e-6}class Matrix{constructor(){this.init(...arguments)}static formatTransforms(o){const flipBoth="both"===o.flip||!0===o.flip,flipX=o.flip&&(flipBoth||"x"===o.flip)?-1:1,flipY=o.flip&&(flipBoth||"y"===o.flip)?-1:1,skewX=o.skew&&o.skew.length?o.skew[0]:isFinite(o.skew)?o.skew:isFinite(o.skewX)?o.skewX:0,skewY=o.skew&&o.skew.length?o.skew[1]:isFinite(o.skew)?o.skew:isFinite(o.skewY)?o.skewY:0,scaleX=o.scale&&o.scale.length?o.scale[0]*flipX:isFinite(o.scale)?o.scale*flipX:isFinite(o.scaleX)?o.scaleX*flipX:flipX,scaleY=o.scale&&o.scale.length?o.scale[1]*flipY:isFinite(o.scale)?o.scale*flipY:isFinite(o.scaleY)?o.scaleY*flipY:flipY,shear=o.shear||0,theta=o.rotate||o.theta||0,origin=new Point(o.origin||o.around||o.ox||o.originX,o.oy||o.originY),ox=origin.x,oy=origin.y,position=new Point(o.position||o.px||o.positionX||NaN,o.py||o.positionY||NaN),px=position.x,py=position.y,translate=new Point(o.translate||o.tx||o.translateX,o.ty||o.translateY),tx=translate.x,ty=translate.y,relative=new Point(o.relative||o.rx||o.relativeX,o.ry||o.relativeY);return{scaleX:scaleX,scaleY:scaleY,skewX:skewX,skewY:skewY,shear:shear,theta:theta,rx:relative.x,ry:relative.y,tx:tx,ty:ty,ox:ox,oy:oy,px:px,py:py}}static fromArray(a){return{a:a[0],b:a[1],c:a[2],d:a[3],e:a[4],f:a[5]}}static isMatrixLike(o){return null!=o.a||null!=o.b||null!=o.c||null!=o.d||null!=o.e||null!=o.f}static matrixMultiply(l,r,o){const a=l.a*r.a+l.c*r.b,b=l.b*r.a+l.d*r.b,c=l.a*r.c+l.c*r.d,d=l.b*r.c+l.d*r.d,e=l.e+l.a*r.e+l.c*r.f,f=l.f+l.b*r.e+l.d*r.f;return o.a=a,o.b=b,o.c=c,o.d=d,o.e=e,o.f=f,o}around(cx,cy,matrix){return this.clone().aroundO(cx,cy,matrix)}aroundO(cx,cy,matrix){const dx=cx||0,dy=cy||0;return this.translateO(-dx,-dy).lmultiplyO(matrix).translateO(dx,dy)}clone(){return new Matrix(this)}decompose(){let cx=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,cy=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;const a=this.a,b=this.b,c=this.c,d=this.d,e=this.e,f=this.f,determinant=a*d-b*c,ccw=determinant>0?1:-1,sx=ccw*Math.sqrt(a*a+b*b),thetaRad=Math.atan2(ccw*b,ccw*a),theta=180/Math.PI*thetaRad,ct=Math.cos(thetaRad),st=Math.sin(thetaRad),lam=(a*c+b*d)/determinant,sy=c*sx/(lam*a-b)||d*sx/(lam*b+a);return{scaleX:sx,scaleY:sy,shear:lam,rotate:theta,translateX:e-cx+cx*ct*sx+cy*(lam*ct*sx-st*sy),translateY:f-cy+cx*st*sx+cy*(lam*st*sx+ct*sy),originX:cx,originY:cy,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f}}equals(other){if(other===this)return!0;const comp=new Matrix(other);return closeEnough(this.a,comp.a)&&closeEnough(this.b,comp.b)&&closeEnough(this.c,comp.c)&&closeEnough(this.d,comp.d)&&closeEnough(this.e,comp.e)&&closeEnough(this.f,comp.f)}flip(axis,around){return this.clone().flipO(axis,around)}flipO(axis,around){return"x"===axis?this.scaleO(-1,1,around,0):"y"===axis?this.scaleO(1,-1,0,around):this.scaleO(-1,-1,axis,around||axis)}init(source){const base=Matrix.fromArray([1,0,0,1,0,0]);return source=source instanceof Element?source.matrixify():"string"==typeof source?Matrix.fromArray(source.split(delimiter).map(parseFloat)):Array.isArray(source)?Matrix.fromArray(source):"object"==typeof source&&Matrix.isMatrixLike(source)?source:"object"==typeof source?(new Matrix).transform(source):6===arguments.length?Matrix.fromArray([].slice.call(arguments)):base,this.a=null!=source.a?source.a:base.a,this.b=null!=source.b?source.b:base.b,this.c=null!=source.c?source.c:base.c,this.d=null!=source.d?source.d:base.d,this.e=null!=source.e?source.e:base.e,this.f=null!=source.f?source.f:base.f,this}inverse(){return this.clone().inverseO()}inverseO(){const a=this.a,b=this.b,c=this.c,d=this.d,e=this.e,f=this.f,det=a*d-b*c;if(!det)throw new Error("Cannot invert "+this);const na=d/det,nb=-b/det,nc=-c/det,nd=a/det,ne=-(na*e+nc*f),nf=-(nb*e+nd*f);return this.a=na,this.b=nb,this.c=nc,this.d=nd,this.e=ne,this.f=nf,this}lmultiply(matrix){return this.clone().lmultiplyO(matrix)}lmultiplyO(matrix){const l=matrix instanceof Matrix?matrix:new Matrix(matrix);return Matrix.matrixMultiply(l,this,this)}multiply(matrix){return this.clone().multiplyO(matrix)}multiplyO(matrix){const r=matrix instanceof Matrix?matrix:new Matrix(matrix);return Matrix.matrixMultiply(this,r,this)}rotate(r,cx,cy){return this.clone().rotateO(r,cx,cy)}rotateO(r){let cx=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,cy=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;r=radians(r);const cos=Math.cos(r),sin=Math.sin(r),{a:a,b:b,c:c,d:d,e:e,f:f}=this;return this.a=a*cos-b*sin,this.b=b*cos+a*sin,this.c=c*cos-d*sin,this.d=d*cos+c*sin,this.e=e*cos-f*sin+cy*sin-cx*cos+cx,this.f=f*cos+e*sin-cx*sin-cy*cos+cy,this}scale(){return this.clone().scaleO(...arguments)}scaleO(x){let y=arguments.length>1&&void 0!==arguments[1]?arguments[1]:x,cx=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,cy=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;3===arguments.length&&(cy=cx,cx=y,y=x);const{a:a,b:b,c:c,d:d,e:e,f:f}=this;return this.a=a*x,this.b=b*y,this.c=c*x,this.d=d*y,this.e=e*x-cx*x+cx,this.f=f*y-cy*y+cy,this}shear(a,cx,cy){return this.clone().shearO(a,cx,cy)}shearO(lx){let cy=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;const{a:a,b:b,c:c,d:d,e:e,f:f}=this;return this.a=a+b*lx,this.c=c+d*lx,this.e=e+f*lx-cy*lx,this}skew(){return this.clone().skewO(...arguments)}skewO(x){let y=arguments.length>1&&void 0!==arguments[1]?arguments[1]:x,cx=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,cy=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;3===arguments.length&&(cy=cx,cx=y,y=x),x=radians(x),y=radians(y);const lx=Math.tan(x),ly=Math.tan(y),{a:a,b:b,c:c,d:d,e:e,f:f}=this;return this.a=a+b*lx,this.b=b+a*ly,this.c=c+d*lx,this.d=d+c*ly,this.e=e+f*lx-cy*lx,this.f=f+e*ly-cx*ly,this}skewX(x,cx,cy){return this.skew(x,0,cx,cy)}skewY(y,cx,cy){return this.skew(0,y,cx,cy)}toArray(){return[this.a,this.b,this.c,this.d,this.e,this.f]}toString(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}transform(o){if(Matrix.isMatrixLike(o)){return new Matrix(o).multiplyO(this)}const t=Matrix.formatTransforms(o),{x:ox,y:oy}=new Point(t.ox,t.oy).transform(this),transformer=(new Matrix).translateO(t.rx,t.ry).lmultiplyO(this).translateO(-ox,-oy).scaleO(t.scaleX,t.scaleY).skewO(t.skewX,t.skewY).shearO(t.shear).rotateO(t.theta).translateO(ox,oy);if(isFinite(t.px)||isFinite(t.py)){const origin=new Point(ox,oy).transform(transformer),dx=isFinite(t.px)?t.px-origin.x:0,dy=isFinite(t.py)?t.py-origin.y:0;transformer.translateO(dx,dy)}return transformer.translateO(t.tx,t.ty),transformer}translate(x,y){return this.clone().translateO(x,y)}translateO(x,y){return this.e+=x||0,this.f+=y||0,this}valueOf(){return{a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f}}}function parser(){if(!parser.nodes){const svg=makeInstance().size(2,0);svg.node.style.cssText=["opacity: 0","position: absolute","left: -100%","top: -100%","overflow: hidden"].join(";"),svg.attr("focusable","false"),svg.attr("aria-hidden","true");const path=svg.path().node;parser.nodes={svg:svg,path:path}}if(!parser.nodes.svg.node.parentNode){const b=globals.document.body||globals.document.documentElement;parser.nodes.svg.addTo(b)}return parser.nodes}function isNulledBox(box){return!(box.width||box.height||box.x||box.y)}register(Matrix,"Matrix");class Box{constructor(){this.init(...arguments)}addOffset(){return this.x+=globals.window.pageXOffset,this.y+=globals.window.pageYOffset,new Box(this)}init(source){return source="string"==typeof source?source.split(delimiter).map(parseFloat):Array.isArray(source)?source:"object"==typeof source?[null!=source.left?source.left:source.x,null!=source.top?source.top:source.y,source.width,source.height]:4===arguments.length?[].slice.call(arguments):[0,0,0,0],this.x=source[0]||0,this.y=source[1]||0,this.width=this.w=source[2]||0,this.height=this.h=source[3]||0,this.x2=this.x+this.w,this.y2=this.y+this.h,this.cx=this.x+this.w/2,this.cy=this.y+this.h/2,this}isNulled(){return isNulledBox(this)}merge(box){const x=Math.min(this.x,box.x),y=Math.min(this.y,box.y),width=Math.max(this.x+this.width,box.x+box.width)-x,height=Math.max(this.y+this.height,box.y+box.height)-y;return new Box(x,y,width,height)}toArray(){return[this.x,this.y,this.width,this.height]}toString(){return this.x+" "+this.y+" "+this.width+" "+this.height}transform(m){m instanceof Matrix||(m=new Matrix(m));let xMin=1/0,xMax=-1/0,yMin=1/0,yMax=-1/0;return[new Point(this.x,this.y),new Point(this.x2,this.y),new Point(this.x,this.y2),new Point(this.x2,this.y2)].forEach((function(p){p=p.transform(m),xMin=Math.min(xMin,p.x),xMax=Math.max(xMax,p.x),yMin=Math.min(yMin,p.y),yMax=Math.max(yMax,p.y)})),new Box(xMin,yMin,xMax-xMin,yMax-yMin)}}function getBox(el,getBBoxFn,retry){let box;try{if(box=getBBoxFn(el.node),isNulledBox(box)&&((node=el.node)!==globals.document&&!(globals.document.documentElement.contains||function(node){for(;node.parentNode;)node=node.parentNode;return node===globals.document}).call(globals.document.documentElement,node)))throw new Error("Element not in the dom")}catch(e){box=retry(el)}var node;return box}registerMethods({viewbox:{viewbox(x,y,width,height){return null==x?new Box(this.attr("viewBox")):this.attr("viewBox",new Box(x,y,width,height))},zoom(level,point){let{width:width,height:height}=this.attr(["width","height"]);if((width||height)&&"string"!=typeof width&&"string"!=typeof height||(width=this.node.clientWidth,height=this.node.clientHeight),!width||!height)throw new Error("Impossible to get absolute width and height. Please provide an absolute width and height attribute on the zooming element");const v=this.viewbox(),zoomX=width/v.width,zoomY=height/v.height,zoom=Math.min(zoomX,zoomY);if(null==level)return zoom;let zoomAmount=zoom/level;zoomAmount===1/0&&(zoomAmount=Number.MAX_SAFE_INTEGER/100),point=point||new Point(width/2/zoomX+v.x,height/2/zoomY+v.y);const box=new Box(v).transform(new Matrix({scale:zoomAmount,origin:point}));return this.viewbox(box)}}}),register(Box,"Box");class List extends Array{constructor(){let arr=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];for(var _len2=arguments.length,args=new Array(_len2>1?_len2-1:0),_key2=1;_key2<_len2;_key2++)args[_key2-1]=arguments[_key2];if(super(arr,...args),"number"==typeof arr)return this;this.length=0,this.push(...arr)}}extend([List],{each(fnOrMethodName){for(var _len3=arguments.length,args=new Array(_len3>1?_len3-1:0),_key3=1;_key3<_len3;_key3++)args[_key3-1]=arguments[_key3];return"function"==typeof fnOrMethodName?this.map(((el,i,arr)=>fnOrMethodName.call(el,el,i,arr))):this.map((el=>el[fnOrMethodName](...args)))},toArray(){return Array.prototype.concat.apply([],this)}});const reserved=["toArray","constructor","each"];function baseFind(query,parent){return new List(map((parent||globals.document).querySelectorAll(query),(function(node){return adopt(node)})))}List.extend=function(methods){methods=methods.reduce(((obj,name)=>(reserved.includes(name)||"_"===name[0]||(name in Array.prototype&&(obj["$"+name]=Array.prototype[name]),obj[name]=function(){for(var _len4=arguments.length,attrs=new Array(_len4),_key4=0;_key4<_len4;_key4++)attrs[_key4]=arguments[_key4];return this.each(name,...attrs)}),obj)),{}),extend([List],methods)};let listenerId=0;const windowEvents={};function getEvents(instance){let n=instance.getEventHolder();return n===globals.window&&(n=windowEvents),n.events||(n.events={}),n.events}function getEventTarget(instance){return instance.getEventTarget()}function clearEvents(instance){let n=instance.getEventHolder();n===globals.window&&(n=windowEvents),n.events&&(n.events={})}function on(node,events,listener,binding,options){const l=listener.bind(binding||node),instance=makeInstance(node),bag=getEvents(instance),n=getEventTarget(instance);events=Array.isArray(events)?events:events.split(delimiter),listener._svgjsListenerId||(listener._svgjsListenerId=++listenerId),events.forEach((function(event){const ev=event.split(".")[0],ns=event.split(".")[1]||"*";bag[ev]=bag[ev]||{},bag[ev][ns]=bag[ev][ns]||{},bag[ev][ns][listener._svgjsListenerId]=l,n.addEventListener(ev,l,options||!1)}))}function off(node,events,listener,options){const instance=makeInstance(node),bag=getEvents(instance),n=getEventTarget(instance);("function"!=typeof listener||(listener=listener._svgjsListenerId))&&(events=Array.isArray(events)?events:(events||"").split(delimiter)).forEach((function(event){const ev=event&&event.split(".")[0],ns=event&&event.split(".")[1];let namespace,l;if(listener)bag[ev]&&bag[ev][ns||"*"]&&(n.removeEventListener(ev,bag[ev][ns||"*"][listener],options||!1),delete bag[ev][ns||"*"][listener]);else if(ev&&ns){if(bag[ev]&&bag[ev][ns]){for(l in bag[ev][ns])off(n,[ev,ns].join("."),l);delete bag[ev][ns]}}else if(ns)for(event in bag)for(namespace in bag[event])ns===namespace&&off(n,[event,ns].join("."));else if(ev){if(bag[ev]){for(namespace in bag[ev])off(n,[ev,namespace].join("."));delete bag[ev]}}else{for(event in bag)off(n,event);clearEvents(instance)}}))}function dispatch(node,event,data,options){const n=getEventTarget(node);return event instanceof globals.window.Event||(event=new globals.window.CustomEvent(event,{detail:data,cancelable:!0,...options})),n.dispatchEvent(event),event}class EventTarget extends Base{addEventListener(){}dispatch(event,data,options){return dispatch(this,event,data,options)}dispatchEvent(event){const bag=this.getEventHolder().events;if(!bag)return!0;const events=bag[event.type];for(const i in events)for(const j in events[i])events[i][j](event);return!event.defaultPrevented}fire(event,data,options){return this.dispatch(event,data,options),this}getEventHolder(){return this}getEventTarget(){return this}off(event,listener,options){return off(this,event,listener,options),this}on(event,listener,binding,options){return on(this,event,listener,binding,options),this}removeEventListener(){}}function noop(){}register(EventTarget,"EventTarget");const timeline={duration:400,ease:">",delay:0},attrs={"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,"stroke-linejoin":"miter","stroke-linecap":"butt",fill:"#000000",stroke:"#000000",opacity:1,x:0,y:0,cx:0,cy:0,width:0,height:0,r:0,rx:0,ry:0,offset:0,"stop-opacity":1,"stop-color":"#000000","text-anchor":"start"};var defaults={__proto__:null,attrs:attrs,noop:noop,timeline:timeline};class SVGArray extends Array{constructor(){super(...arguments),this.init(...arguments)}clone(){return new this.constructor(this)}init(arr){return"number"==typeof arr||(this.length=0,this.push(...this.parse(arr))),this}parse(){let array=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return array instanceof Array?array:array.trim().split(delimiter).map(parseFloat)}toArray(){return Array.prototype.concat.apply([],this)}toSet(){return new Set(this)}toString(){return this.join(" ")}valueOf(){const ret=[];return ret.push(...this),ret}}class SVGNumber{constructor(){this.init(...arguments)}convert(unit){return new SVGNumber(this.value,unit)}divide(number){return number=new SVGNumber(number),new SVGNumber(this/number,this.unit||number.unit)}init(value,unit){return unit=Array.isArray(value)?value[1]:unit,value=Array.isArray(value)?value[0]:value,this.value=0,this.unit=unit||"","number"==typeof value?this.value=isNaN(value)?0:isFinite(value)?value:value<0?-34e37:34e37:"string"==typeof value?(unit=value.match(numberAndUnit))&&(this.value=parseFloat(unit[1]),"%"===unit[5]?this.value/=100:"s"===unit[5]&&(this.value*=1e3),this.unit=unit[5]):value instanceof SVGNumber&&(this.value=value.valueOf(),this.unit=value.unit),this}minus(number){return number=new SVGNumber(number),new SVGNumber(this-number,this.unit||number.unit)}plus(number){return number=new SVGNumber(number),new SVGNumber(this+number,this.unit||number.unit)}times(number){return number=new SVGNumber(number),new SVGNumber(this*number,this.unit||number.unit)}toArray(){return[this.value,this.unit]}toJSON(){return this.toString()}toString(){return("%"===this.unit?~~(1e8*this.value)/1e6:"s"===this.unit?this.value/1e3:this.value)+this.unit}valueOf(){return this.value}}const colorAttributes=new Set(["fill","stroke","color","bgcolor","stop-color","flood-color","lighting-color"]),hooks=[];class Dom extends EventTarget{constructor(node,attrs){super(),this.node=node,this.type=node.nodeName,attrs&&node!==attrs&&this.attr(attrs)}add(element,i){return(element=makeInstance(element)).removeNamespace&&this.node instanceof globals.window.SVGElement&&element.removeNamespace(),null==i?this.node.appendChild(element.node):element.node!==this.node.childNodes[i]&&this.node.insertBefore(element.node,this.node.childNodes[i]),this}addTo(parent,i){return makeInstance(parent).put(this,i)}children(){return new List(map(this.node.children,(function(node){return adopt(node)})))}clear(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this}clone(){let deep=!(arguments.length>0&&void 0!==arguments[0])||arguments[0],assignNewIds=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];this.writeDataToDom();let nodeClone=this.node.cloneNode(deep);return assignNewIds&&(nodeClone=assignNewId(nodeClone)),new this.constructor(nodeClone)}each(block,deep){const children=this.children();let i,il;for(i=0,il=children.length;i=0}html(htmlOrFn,outerHTML){return this.xml(htmlOrFn,outerHTML,html)}id(id){return void 0!==id||this.node.id||(this.node.id=eid(this.type)),this.attr("id",id)}index(element){return[].slice.call(this.node.childNodes).indexOf(element.node)}last(){return adopt(this.node.lastChild)}matches(selector){const el=this.node,matcher=el.matches||el.matchesSelector||el.msMatchesSelector||el.mozMatchesSelector||el.webkitMatchesSelector||el.oMatchesSelector||null;return matcher&&matcher.call(el,selector)}parent(type){let parent=this;if(!parent.node.parentNode)return null;if(parent=adopt(parent.node.parentNode),!type)return parent;do{if("string"==typeof type?parent.matches(type):parent instanceof type)return parent}while(parent=adopt(parent.node.parentNode));return parent}put(element,i){return element=makeInstance(element),this.add(element,i),element}putIn(parent,i){return makeInstance(parent).add(this,i)}remove(){return this.parent()&&this.parent().removeElement(this),this}removeElement(element){return this.node.removeChild(element.node),this}replace(element){return element=makeInstance(element),this.node.parentNode&&this.node.parentNode.replaceChild(element.node,this.node),element}round(){let map=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;const factor=10**(arguments.length>0&&void 0!==arguments[0]?arguments[0]:2),attrs=this.attr(map);for(const i in attrs)"number"==typeof attrs[i]&&(attrs[i]=Math.round(attrs[i]*factor)/factor);return this.attr(attrs),this}svg(svgOrFn,outerSVG){return this.xml(svgOrFn,outerSVG,svg)}toString(){return this.id()}words(text){return this.node.textContent=text,this}wrap(node){const parent=this.parent();if(!parent)return this.addTo(node);const position=parent.index(this);return parent.put(node,position).put(this)}writeDataToDom(){return this.each((function(){this.writeDataToDom()})),this}xml(xmlOrFn,outerXML,ns){if("boolean"==typeof xmlOrFn&&(ns=outerXML,outerXML=xmlOrFn,xmlOrFn=null),null==xmlOrFn||"function"==typeof xmlOrFn){outerXML=null==outerXML||outerXML,this.writeDataToDom();let current=this;if(null!=xmlOrFn){if(current=adopt(current.node.cloneNode(!0)),outerXML){const result=xmlOrFn(current);if(current=result||current,!1===result)return""}current.each((function(){const result=xmlOrFn(this),_this=result||this;!1===result?this.remove():result&&this!==_this&&this.replace(_this)}),!0)}return outerXML?current.node.outerHTML:current.node.innerHTML}outerXML=null!=outerXML&&outerXML;const well=create("wrapper",ns),fragment=globals.document.createDocumentFragment();well.innerHTML=xmlOrFn;for(let len=well.children.length;len--;)fragment.appendChild(well.firstElementChild);const parent=this.parent();return outerXML?this.replace(fragment)&&parent:this.add(fragment)}}extend(Dom,{attr:function(attr,val,ns){if(null==attr){attr={},val=this.node.attributes;for(const node of val)attr[node.nodeName]=isNumber.test(node.nodeValue)?parseFloat(node.nodeValue):node.nodeValue;return attr}if(attr instanceof Array)return attr.reduce(((last,curr)=>(last[curr]=this.attr(curr),last)),{});if("object"==typeof attr&&attr.constructor===Object)for(val in attr)this.attr(val,attr[val]);else if(null===val)this.node.removeAttribute(attr);else{if(null==val)return null==(val=this.node.getAttribute(attr))?attrs[attr]:isNumber.test(val)?parseFloat(val):val;"number"==typeof(val=hooks.reduce(((_val,hook)=>hook(attr,_val,this)),val))?val=new SVGNumber(val):colorAttributes.has(attr)&&Color.isColor(val)?val=new Color(val):val.constructor===Array&&(val=new SVGArray(val)),"leading"===attr?this.leading&&this.leading(val):"string"==typeof ns?this.node.setAttributeNS(ns,attr,val.toString()):this.node.setAttribute(attr,val.toString()),!this.rebuild||"font-size"!==attr&&"x"!==attr||this.rebuild()}return this},find:function(query){return baseFind(query,this.node)},findOne:function(query){return adopt(this.node.querySelector(query))}}),register(Dom,"Dom");class Element extends Dom{constructor(node,attrs){var _ref,_JSON$parse;(super(node,attrs),this.dom={},this.node.instance=this,node.hasAttribute("data-svgjs")||node.hasAttribute("svgjs:data"))&&this.setData(null!==(_ref=null!==(_JSON$parse=JSON.parse(node.getAttribute("data-svgjs")))&&void 0!==_JSON$parse?_JSON$parse:JSON.parse(node.getAttribute("svgjs:data")))&&void 0!==_ref?_ref:{})}center(x,y){return this.cx(x).cy(y)}cx(x){return null==x?this.x()+this.width()/2:this.x(x-this.width()/2)}cy(y){return null==y?this.y()+this.height()/2:this.y(y-this.height()/2)}defs(){const root=this.root();return root&&root.defs()}dmove(x,y){return this.dx(x).dy(y)}dx(){let x=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;return this.x(new SVGNumber(x).plus(this.x()))}dy(){let y=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;return this.y(new SVGNumber(y).plus(this.y()))}getEventHolder(){return this}height(height){return this.attr("height",height)}move(x,y){return this.x(x).y(y)}parents(){let until=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.root();const isSelector="string"==typeof until;isSelector||(until=makeInstance(until));const parents=new List;let parent=this;for(;(parent=parent.parent())&&parent.node!==globals.document&&"#document-fragment"!==parent.nodeName&&(parents.push(parent),isSelector||parent.node!==until.node)&&(!isSelector||!parent.matches(until));)if(parent.node===this.root().node)return null;return parents}reference(attr){if(!(attr=this.attr(attr)))return null;const m=(attr+"").match(reference);return m?makeInstance(m[1]):null}root(){const p=this.parent(getClass(root));return p&&p.root()}setData(o){return this.dom=o,this}size(width,height){const p=proportionalSize(this,width,height);return this.width(new SVGNumber(p.width)).height(new SVGNumber(p.height))}width(width){return this.attr("width",width)}writeDataToDom(){return writeDataToDom(this,this.dom),super.writeDataToDom()}x(x){return this.attr("x",x)}y(y){return this.attr("y",y)}}extend(Element,{bbox:function(){const box=getBox(this,(node=>node.getBBox()),(el=>{try{const clone=el.clone().addTo(parser().svg).show(),box=clone.node.getBBox();return clone.remove(),box}catch(e){throw new Error('Getting bbox of element "'.concat(el.node.nodeName,'" is not possible: ').concat(e.toString()))}}));return new Box(box)},rbox:function(el){const box=getBox(this,(node=>node.getBoundingClientRect()),(el=>{throw new Error('Getting rbox of element "'.concat(el.node.nodeName,'" is not possible'))})),rbox=new Box(box);return el?rbox.transform(el.screenCTM().inverseO()):rbox.addOffset()},inside:function(x,y){const box=this.bbox();return x>box.x&&y>box.y&&x=0;i--)null!=o[sugar[m][i]]&&this.attr(sugar.prefix(m,sugar[m][i]),o[sugar[m][i]]);return this},registerMethods(["Element","Runner"],extension)})),registerMethods(["Element","Runner"],{matrix:function(mat,b,c,d,e,f){return null==mat?new Matrix(this):this.attr("transform",new Matrix(mat,b,c,d,e,f))},rotate:function(angle,cx,cy){return this.transform({rotate:angle,ox:cx,oy:cy},!0)},skew:function(x,y,cx,cy){return 1===arguments.length||3===arguments.length?this.transform({skew:x,ox:y,oy:cx},!0):this.transform({skew:[x,y],ox:cx,oy:cy},!0)},shear:function(lam,cx,cy){return this.transform({shear:lam,ox:cx,oy:cy},!0)},scale:function(x,y,cx,cy){return 1===arguments.length||3===arguments.length?this.transform({scale:x,ox:y,oy:cx},!0):this.transform({scale:[x,y],ox:cx,oy:cy},!0)},translate:function(x,y){return this.transform({translate:[x,y]},!0)},relative:function(x,y){return this.transform({relative:[x,y]},!0)},flip:function(){let direction=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"both",origin=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"center";return-1==="xybothtrue".indexOf(direction)&&(origin=direction,direction="both"),this.transform({flip:direction,origin:origin},!0)},opacity:function(value){return this.attr("opacity",value)}}),registerMethods("radius",{radius:function(x){let y=arguments.length>1&&void 0!==arguments[1]?arguments[1]:x;const type=(this._element||this).type;return"radialGradient"===type?this.attr("r",new SVGNumber(x)):this.rx(x).ry(y)}}),registerMethods("Path",{length:function(){return this.node.getTotalLength()},pointAt:function(length){return new Point(this.node.getPointAtLength(length))}}),registerMethods(["Element","Runner"],{font:function(a,v){if("object"==typeof a){for(v in a)this.font(v,a[v]);return this}return"leading"===a?this.leading(v):"anchor"===a?this.attr("text-anchor",v):"size"===a||"family"===a||"weight"===a||"stretch"===a||"variant"===a||"style"===a?this.attr("font-"+a,v):this.attr(a,v)}});registerMethods("Element",["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","mouseenter","mouseleave","touchstart","touchmove","touchleave","touchend","touchcancel","contextmenu","wheel","pointerdown","pointermove","pointerup","pointerleave","pointercancel"].reduce((function(last,event){return last[event]=function(f){return null===f?this.off(event):this.on(event,f),this},last}),{})),registerMethods("Element",{untransform:function(){return this.attr("transform",null)},matrixify:function(){const matrix=(this.attr("transform")||"").split(transforms).slice(0,-1).map((function(str){const kv=str.trim().split("(");return[kv[0],kv[1].split(delimiter).map((function(str){return parseFloat(str)}))]})).reverse().reduce((function(matrix,transform){return"matrix"===transform[0]?matrix.lmultiply(Matrix.fromArray(transform[1])):matrix[transform[0]].apply(matrix,transform[1])}),new Matrix);return matrix},toParent:function(parent,i){if(this===parent)return this;if(isDescriptive(this.node))return this.addTo(parent,i);const ctm=this.screenCTM(),pCtm=parent.screenCTM().inverse();return this.addTo(parent,i).untransform().transform(pCtm.multiply(ctm)),this},toRoot:function(i){return this.toParent(this.root(),i)},transform:function(o,relative){if(null==o||"string"==typeof o){const decomposed=new Matrix(this).decompose();return null==o?decomposed:decomposed[o]}Matrix.isMatrixLike(o)||(o={...o,origin:getOrigin(o,this)});const result=new Matrix(!0===relative?this:relative||!1).transform(o);return this.attr("transform",result)}});class Container extends Element{flatten(){return this.each((function(){if(this instanceof Container)return this.flatten().ungroup()})),this}ungroup(){let parent=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.parent(),index=arguments.length>1&&void 0!==arguments[1]?arguments[1]:parent.index(this);return index=-1===index?parent.children().length:index,this.each((function(i,children){return children[children.length-i-1].toParent(parent,index)})),this.remove()}}register(Container,"Container");class Defs extends Container{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("defs",node),attrs)}flatten(){return this}ungroup(){return this}}register(Defs,"Defs");class Shape extends Element{}function rx(rx){return this.attr("rx",rx)}function ry(ry){return this.attr("ry",ry)}function x$3(x){return null==x?this.cx()-this.rx():this.cx(x+this.rx())}function y$3(y){return null==y?this.cy()-this.ry():this.cy(y+this.ry())}function cx$1(x){return this.attr("cx",x)}function cy$1(y){return this.attr("cy",y)}function width$2(width){return null==width?2*this.rx():this.rx(new SVGNumber(width).divide(2))}function height$2(height){return null==height?2*this.ry():this.ry(new SVGNumber(height).divide(2))}register(Shape,"Shape");var circled={__proto__:null,cx:cx$1,cy:cy$1,height:height$2,rx:rx,ry:ry,width:width$2,x:x$3,y:y$3};class Ellipse extends Shape{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("ellipse",node),attrs)}size(width,height){const p=proportionalSize(this,width,height);return this.rx(new SVGNumber(p.width).divide(2)).ry(new SVGNumber(p.height).divide(2))}}extend(Ellipse,circled),registerMethods("Container",{ellipse:wrapWithAttrCheck((function(){let width=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,height=arguments.length>1&&void 0!==arguments[1]?arguments[1]:width;return this.put(new Ellipse).size(width,height).move(0,0)}))}),register(Ellipse,"Ellipse");class Fragment extends Dom{constructor(){super(arguments.length>0&&void 0!==arguments[0]?arguments[0]:globals.document.createDocumentFragment())}xml(xmlOrFn,outerXML,ns){if("boolean"==typeof xmlOrFn&&(ns=outerXML,outerXML=xmlOrFn,xmlOrFn=null),null==xmlOrFn||"function"==typeof xmlOrFn){const wrapper=new Dom(create("wrapper",ns));return wrapper.add(this.node.cloneNode(!0)),wrapper.xml(!1,ns)}return super.xml(xmlOrFn,!1,ns)}}function from(x,y){return"radialGradient"===(this._element||this).type?this.attr({fx:new SVGNumber(x),fy:new SVGNumber(y)}):this.attr({x1:new SVGNumber(x),y1:new SVGNumber(y)})}function to(x,y){return"radialGradient"===(this._element||this).type?this.attr({cx:new SVGNumber(x),cy:new SVGNumber(y)}):this.attr({x2:new SVGNumber(x),y2:new SVGNumber(y)})}register(Fragment,"Fragment");var gradiented={__proto__:null,from:from,to:to};class Gradient extends Container{constructor(type,attrs){super(nodeOrNew(type+"Gradient","string"==typeof type?null:type),attrs)}attr(a,b,c){return"transform"===a&&(a="gradientTransform"),super.attr(a,b,c)}bbox(){return new Box}targets(){return baseFind("svg [fill*="+this.id()+"]")}toString(){return this.url()}update(block){return this.clear(),"function"==typeof block&&block.call(this,this),this}url(){return"url(#"+this.id()+")"}}extend(Gradient,gradiented),registerMethods({Container:{gradient(){return this.defs().gradient(...arguments)}},Defs:{gradient:wrapWithAttrCheck((function(type,block){return this.put(new Gradient(type)).update(block)}))}}),register(Gradient,"Gradient");class Pattern extends Container{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("pattern",node),attrs)}attr(a,b,c){return"transform"===a&&(a="patternTransform"),super.attr(a,b,c)}bbox(){return new Box}targets(){return baseFind("svg [fill*="+this.id()+"]")}toString(){return this.url()}update(block){return this.clear(),"function"==typeof block&&block.call(this,this),this}url(){return"url(#"+this.id()+")"}}registerMethods({Container:{pattern(){return this.defs().pattern(...arguments)}},Defs:{pattern:wrapWithAttrCheck((function(width,height,block){return this.put(new Pattern).update(block).attr({x:0,y:0,width:width,height:height,patternUnits:"userSpaceOnUse"})}))}}),register(Pattern,"Pattern");class Image extends Shape{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("image",node),attrs)}load(url,callback){if(!url)return this;const img=new globals.window.Image;return on(img,"load",(function(e){const p=this.parent(Pattern);0===this.width()&&0===this.height()&&this.size(img.width,img.height),p instanceof Pattern&&0===p.width()&&0===p.height()&&p.size(this.width(),this.height()),"function"==typeof callback&&callback.call(this,e)}),this),on(img,"load error",(function(){off(img)})),this.attr("href",img.src=url,xlink)}}fn=function(attr,val,_this){return"fill"!==attr&&"stroke"!==attr||isImage.test(val)&&(val=_this.root().defs().image(val)),val instanceof Image&&(val=_this.root().defs().pattern(0,0,(pattern=>{pattern.add(val)}))),val},hooks.push(fn),registerMethods({Container:{image:wrapWithAttrCheck((function(source,callback){return this.put(new Image).size(0,0).load(source,callback)}))}}),register(Image,"Image");var fn;class PointArray extends SVGArray{bbox(){let maxX=-1/0,maxY=-1/0,minX=1/0,minY=1/0;return this.forEach((function(el){maxX=Math.max(el[0],maxX),maxY=Math.max(el[1],maxY),minX=Math.min(el[0],minX),minY=Math.min(el[1],minY)})),new Box(minX,minY,maxX-minX,maxY-minY)}move(x,y){const box=this.bbox();if(x-=box.x,y-=box.y,!isNaN(x)&&!isNaN(y))for(let i=this.length-1;i>=0;i--)this[i]=[this[i][0]+x,this[i][1]+y];return this}parse(){let array=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[0,0];const points=[];array=array instanceof Array?Array.prototype.concat.apply([],array):array.trim().split(delimiter).map(parseFloat),array.length%2!=0&&array.pop();for(let i=0,len=array.length;i=0;i--)box.width&&(this[i][0]=(this[i][0]-box.x)*width/box.width+box.x),box.height&&(this[i][1]=(this[i][1]-box.y)*height/box.height+box.y);return this}toLine(){return{x1:this[0][0],y1:this[0][1],x2:this[1][0],y2:this[1][1]}}toString(){const array=[];for(let i=0,il=this.length;i1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("line",node),attrs)}array(){return new PointArray([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])}move(x,y){return this.attr(this.array().move(x,y).toLine())}plot(x1,y1,x2,y2){return null==x1?this.array():(x1=void 0!==y1?{x1:x1,y1:y1,x2:x2,y2:y2}:new PointArray(x1).toLine(),this.attr(x1))}size(width,height){const p=proportionalSize(this,width,height);return this.attr(this.array().size(p.width,p.height).toLine())}}extend(Line,pointed),registerMethods({Container:{line:wrapWithAttrCheck((function(){for(var _len5=arguments.length,args=new Array(_len5),_key5=0;_key5<_len5;_key5++)args[_key5]=arguments[_key5];return Line.prototype.plot.apply(this.put(new Line),null!=args[0]?args:[0,0,0,0])}))}}),register(Line,"Line");class Marker extends Container{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("marker",node),attrs)}height(height){return this.attr("markerHeight",height)}orient(orient){return this.attr("orient",orient)}ref(x,y){return this.attr("refX",x).attr("refY",y)}toString(){return"url(#"+this.id()+")"}update(block){return this.clear(),"function"==typeof block&&block.call(this,this),this}width(width){return this.attr("markerWidth",width)}}function makeSetterGetter(k,f){return function(v){return null==v?this[k]:(this[k]=v,f&&f.call(this),this)}}registerMethods({Container:{marker(){return this.defs().marker(...arguments)}},Defs:{marker:wrapWithAttrCheck((function(width,height,block){return this.put(new Marker).size(width,height).ref(width/2,height/2).viewbox(0,0,width,height).attr("orient","auto").update(block)}))},marker:{marker(marker,width,height,block){let attr=["marker"];return"all"!==marker&&attr.push(marker),attr=attr.join("-"),marker=arguments[1]instanceof Marker?arguments[1]:this.defs().marker(width,height,block),this.attr(attr,marker)}}}),register(Marker,"Marker");const easing={"-":function(pos){return pos},"<>":function(pos){return-Math.cos(pos*Math.PI)/2+.5},">":function(pos){return Math.sin(pos*Math.PI/2)},"<":function(pos){return 1-Math.cos(pos*Math.PI/2)},bezier:function(x1,y1,x2,y2){return function(t){return t<0?x1>0?y1/x1*t:x2>0?y2/x2*t:0:t>1?x2<1?(1-y2)/(1-x2)*t+(y2-x2)/(1-x2):x1<1?(1-y1)/(1-x1)*t+(y1-x1)/(1-x1):1:3*t*(1-t)**2*y1+3*t**2*(1-t)*y2+t**3}},steps:function(steps){let stepPosition=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"end";stepPosition=stepPosition.split("-").reverse()[0];let jumps=steps;return"none"===stepPosition?--jumps:"both"===stepPosition&&++jumps,function(t){let beforeFlag=arguments.length>1&&void 0!==arguments[1]&&arguments[1],step=Math.floor(t*steps);const jumping=t*step%1==0;return"start"!==stepPosition&&"both"!==stepPosition||++step,beforeFlag&&jumping&&--step,t>=0&&step<0&&(step=0),t<=1&&step>jumps&&(step=jumps),step/jumps}}};class Stepper{done(){return!1}}class Ease extends Stepper{constructor(){let fn=arguments.length>0&&void 0!==arguments[0]?arguments[0]:timeline.ease;super(),this.ease=easing[fn]||fn}step(from,to,pos){return"number"!=typeof from?pos<1?from:to:from+(to-from)*this.ease(pos)}}class Controller extends Stepper{constructor(fn){super(),this.stepper=fn}done(c){return c.done}step(current,target,dt,c){return this.stepper(current,target,dt,c)}}function recalculate(){const duration=(this._duration||500)/1e3,overshoot=this._overshoot||0,pi=Math.PI,os=Math.log(overshoot/100+1e-10),zeta=-os/Math.sqrt(pi*pi+os*os),wn=3.9/(zeta*duration);this.d=2*zeta*wn,this.k=wn*wn}class Spring extends Controller{constructor(){let duration=arguments.length>0&&void 0!==arguments[0]?arguments[0]:500,overshoot=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;super(),this.duration(duration).overshoot(overshoot)}step(current,target,dt,c){if("string"==typeof current)return current;if(c.done=dt===1/0,dt===1/0)return target;if(0===dt)return current;dt>100&&(dt=16),dt/=1e3;const velocity=c.velocity||0,acceleration=-this.d*velocity-this.k*(current-target),newPosition=current+velocity*dt+acceleration*dt*dt/2;return c.velocity=velocity+acceleration*dt,c.done=Math.abs(target-newPosition)+Math.abs(velocity)<.002,c.done?target:newPosition}}extend(Spring,{duration:makeSetterGetter("_duration",recalculate),overshoot:makeSetterGetter("_overshoot",recalculate)});class PID extends Controller{constructor(){let p=arguments.length>0&&void 0!==arguments[0]?arguments[0]:.1,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:.01,d=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,windup=arguments.length>3&&void 0!==arguments[3]?arguments[3]:1e3;super(),this.p(p).i(i).d(d).windup(windup)}step(current,target,dt,c){if("string"==typeof current)return current;if(c.done=dt===1/0,dt===1/0)return target;if(0===dt)return current;const p=target-current;let i=(c.integral||0)+p*dt;const d=(p-(c.error||0))/dt,windup=this._windup;return!1!==windup&&(i=Math.max(-windup,Math.min(i,windup))),c.error=p,c.integral=i,c.done=Math.abs(p)<.001,c.done?target:current+(this.P*p+this.I*i+this.D*d)}}extend(PID,{windup:makeSetterGetter("_windup"),p:makeSetterGetter("P"),i:makeSetterGetter("I"),d:makeSetterGetter("D")});const segmentParameters={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7,Z:0},pathHandlers={M:function(c,p,p0){return p.x=p0.x=c[0],p.y=p0.y=c[1],["M",p.x,p.y]},L:function(c,p){return p.x=c[0],p.y=c[1],["L",c[0],c[1]]},H:function(c,p){return p.x=c[0],["H",c[0]]},V:function(c,p){return p.y=c[0],["V",c[0]]},C:function(c,p){return p.x=c[4],p.y=c[5],["C",c[0],c[1],c[2],c[3],c[4],c[5]]},S:function(c,p){return p.x=c[2],p.y=c[3],["S",c[0],c[1],c[2],c[3]]},Q:function(c,p){return p.x=c[2],p.y=c[3],["Q",c[0],c[1],c[2],c[3]]},T:function(c,p){return p.x=c[0],p.y=c[1],["T",c[0],c[1]]},Z:function(c,p,p0){return p.x=p0.x,p.y=p0.y,["Z"]},A:function(c,p){return p.x=c[5],p.y=c[6],["A",c[0],c[1],c[2],c[3],c[4],c[5],c[6]]}},mlhvqtcsaz="mlhvqtcsaz".split("");for(let i=0,il=mlhvqtcsaz.length;i=0;i--)l=this[i][0],"M"===l||"L"===l||"T"===l?(this[i][1]+=x,this[i][2]+=y):"H"===l?this[i][1]+=x:"V"===l?this[i][1]+=y:"C"===l||"S"===l||"Q"===l?(this[i][1]+=x,this[i][2]+=y,this[i][3]+=x,this[i][4]+=y,"C"===l&&(this[i][5]+=x,this[i][6]+=y)):"A"===l&&(this[i][6]+=x,this[i][7]+=y);return this}parse(){let d=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"M0 0";return Array.isArray(d)&&(d=Array.prototype.concat.apply([],d).toString()),function(d){let index=0,token="";const parser={segment:[],inNumber:!1,number:"",lastToken:"",inSegment:!1,segments:[],pointSeen:!1,hasExponent:!1,absolute:!(arguments.length>1&&void 0!==arguments[1])||arguments[1],p0:new Point,p:new Point};for(;parser.lastToken=token,token=d.charAt(index++);)if(parser.inSegment||!startNewSegment(parser,token))if("."!==token)if(isNaN(parseInt(token)))if(pathDelimiters.has(token))parser.inNumber&&finalizeNumber(parser,!1);else if("-"!==token&&"+"!==token)if("E"!==token.toUpperCase()){if(isPathLetter.test(token)){if(parser.inNumber)finalizeNumber(parser,!1);else{if(!segmentComplete(parser))throw new Error("parser Error");finalizeSegment(parser)}--index}}else parser.number+=token,parser.hasExponent=!0;else{if(parser.inNumber&&!isExponential(parser)){finalizeNumber(parser,!1),--index;continue}parser.number+=token,parser.inNumber=!0}else{if("0"===parser.number||isArcFlag(parser)){parser.inNumber=!0,parser.number=token,finalizeNumber(parser,!0);continue}parser.inNumber=!0,parser.number+=token}else{if(parser.pointSeen||parser.hasExponent){finalizeNumber(parser,!1),--index;continue}parser.inNumber=!0,parser.pointSeen=!0,parser.number+=token}return parser.inNumber&&finalizeNumber(parser,!1),parser.inSegment&&segmentComplete(parser)&&finalizeSegment(parser),parser.segments}(d)}size(width,height){const box=this.bbox();let i,l;for(box.width=0===box.width?1:box.width,box.height=0===box.height?1:box.height,i=this.length-1;i>=0;i--)l=this[i][0],"M"===l||"L"===l||"T"===l?(this[i][1]=(this[i][1]-box.x)*width/box.width+box.x,this[i][2]=(this[i][2]-box.y)*height/box.height+box.y):"H"===l?this[i][1]=(this[i][1]-box.x)*width/box.width+box.x:"V"===l?this[i][1]=(this[i][1]-box.y)*height/box.height+box.y:"C"===l||"S"===l||"Q"===l?(this[i][1]=(this[i][1]-box.x)*width/box.width+box.x,this[i][2]=(this[i][2]-box.y)*height/box.height+box.y,this[i][3]=(this[i][3]-box.x)*width/box.width+box.x,this[i][4]=(this[i][4]-box.y)*height/box.height+box.y,"C"===l&&(this[i][5]=(this[i][5]-box.x)*width/box.width+box.x,this[i][6]=(this[i][6]-box.y)*height/box.height+box.y)):"A"===l&&(this[i][1]=this[i][1]*width/box.width,this[i][2]=this[i][2]*height/box.height,this[i][6]=(this[i][6]-box.x)*width/box.width+box.x,this[i][7]=(this[i][7]-box.y)*height/box.height+box.y);return this}toString(){return function(a){let s="";for(let i=0,il=a.length;i{const type=typeof value;return"number"===type?SVGNumber:"string"===type?Color.isColor(value)?Color:delimiter.test(value)?isPathLetter.test(value)?PathArray:SVGArray:numberAndUnit.test(value)?SVGNumber:NonMorphable:morphableTypes.indexOf(value.constructor)>-1?value.constructor:Array.isArray(value)?SVGArray:"object"===type?ObjectBag:NonMorphable};class Morphable{constructor(stepper){this._stepper=stepper||new Ease("-"),this._from=null,this._to=null,this._type=null,this._context=null,this._morphObj=null}at(pos){return this._morphObj.morph(this._from,this._to,pos,this._stepper,this._context)}done(){return this._context.map(this._stepper.done).reduce((function(last,curr){return last&&curr}),!0)}from(val){return null==val?this._from:(this._from=this._set(val),this)}stepper(stepper){return null==stepper?this._stepper:(this._stepper=stepper,this)}to(val){return null==val?this._to:(this._to=this._set(val),this)}type(type){return null==type?this._type:(this._type=type,this)}_set(value){this._type||this.type(getClassForType(value));let result=new this._type(value);return this._type===Color&&(result=this._to?result[this._to[4]]():this._from?result[this._from[4]]():result),this._type===ObjectBag&&(result=this._to?result.align(this._to):this._from?result.align(this._from):result),result=result.toConsumable(),this._morphObj=this._morphObj||new this._type,this._context=this._context||Array.apply(null,Array(result.length)).map(Object).map((function(o){return o.done=!0,o})),result}}class NonMorphable{constructor(){this.init(...arguments)}init(val){return val=Array.isArray(val)?val[0]:val,this.value=val,this}toArray(){return[this.value]}valueOf(){return this.value}}class TransformBag{constructor(){this.init(...arguments)}init(obj){return Array.isArray(obj)&&(obj={scaleX:obj[0],scaleY:obj[1],shear:obj[2],rotate:obj[3],translateX:obj[4],translateY:obj[5],originX:obj[6],originY:obj[7]}),Object.assign(this,TransformBag.defaults,obj),this}toArray(){const v=this;return[v.scaleX,v.scaleY,v.shear,v.rotate,v.translateX,v.translateY,v.originX,v.originY]}}TransformBag.defaults={scaleX:1,scaleY:1,shear:0,rotate:0,translateX:0,translateY:0,originX:0,originY:0};const sortByKey=(a,b)=>a[0]b[0]?1:0;class ObjectBag{constructor(){this.init(...arguments)}align(other){const values=this.values;for(let i=0,il=values.length;ilast.concat(curr)),[]),this}toArray(){return this.values}valueOf(){const obj={},arr=this.values;for(;arr.length;){const key=arr.shift(),Type=arr.shift(),num=arr.shift(),values=arr.splice(0,num);obj[key]=new Type(values)}return obj}}const morphableTypes=[NonMorphable,TransformBag,ObjectBag];function registerMorphableType(){let type=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];morphableTypes.push(...[].concat(type))}function makeMorphable(){extend(morphableTypes,{to(val){return(new Morphable).type(this.constructor).from(this.toArray()).to(val)},fromArray(arr){return this.init(arr),this},toConsumable(){return this.toArray()},morph(from,to,pos,stepper,context){return this.fromArray(from.map((function(i,index){return stepper.step(i,to[index],pos,context[index],context)})))}})}class Path extends Shape{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("path",node),attrs)}array(){return this._array||(this._array=new PathArray(this.attr("d")))}clear(){return delete this._array,this}height(height){return null==height?this.bbox().height:this.size(this.bbox().width,height)}move(x,y){return this.attr("d",this.array().move(x,y))}plot(d){return null==d?this.array():this.clear().attr("d","string"==typeof d?d:this._array=new PathArray(d))}size(width,height){const p=proportionalSize(this,width,height);return this.attr("d",this.array().size(p.width,p.height))}width(width){return null==width?this.bbox().width:this.size(width,this.bbox().height)}x(x){return null==x?this.bbox().x:this.move(x,this.bbox().y)}y(y){return null==y?this.bbox().y:this.move(this.bbox().x,y)}}Path.prototype.MorphArray=PathArray,registerMethods({Container:{path:wrapWithAttrCheck((function(d){return this.put(new Path).plot(d||new PathArray)}))}}),register(Path,"Path");var poly={__proto__:null,array:function(){return this._array||(this._array=new PointArray(this.attr("points")))},clear:function(){return delete this._array,this},move:function(x,y){return this.attr("points",this.array().move(x,y))},plot:function(p){return null==p?this.array():this.clear().attr("points","string"==typeof p?p:this._array=new PointArray(p))},size:function(width,height){const p=proportionalSize(this,width,height);return this.attr("points",this.array().size(p.width,p.height))}};class Polygon extends Shape{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("polygon",node),attrs)}}registerMethods({Container:{polygon:wrapWithAttrCheck((function(p){return this.put(new Polygon).plot(p||new PointArray)}))}}),extend(Polygon,pointed),extend(Polygon,poly),register(Polygon,"Polygon");class Polyline extends Shape{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("polyline",node),attrs)}}registerMethods({Container:{polyline:wrapWithAttrCheck((function(p){return this.put(new Polyline).plot(p||new PointArray)}))}}),extend(Polyline,pointed),extend(Polyline,poly),register(Polyline,"Polyline");class Rect extends Shape{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("rect",node),attrs)}}extend(Rect,{rx:rx,ry:ry}),registerMethods({Container:{rect:wrapWithAttrCheck((function(width,height){return this.put(new Rect).size(width,height)}))}}),register(Rect,"Rect");class Queue{constructor(){this._first=null,this._last=null}first(){return this._first&&this._first.value}last(){return this._last&&this._last.value}push(value){const item=void 0!==value.next?value:{value:value,next:null,prev:null};return this._last?(item.prev=this._last,this._last.next=item,this._last=item):(this._last=item,this._first=item),item}remove(item){item.prev&&(item.prev.next=item.next),item.next&&(item.next.prev=item.prev),item===this._last&&(this._last=item.prev),item===this._first&&(this._first=item.next),item.prev=null,item.next=null}shift(){const remove=this._first;return remove?(this._first=remove.next,this._first&&(this._first.prev=null),this._last=this._first?this._last:null,remove.value):null}}const Animator={nextDraw:null,frames:new Queue,timeouts:new Queue,immediates:new Queue,timer:()=>globals.window.performance||globals.window.Date,transforms:[],frame(fn){const node=Animator.frames.push({run:fn});return null===Animator.nextDraw&&(Animator.nextDraw=globals.window.requestAnimationFrame(Animator._draw)),node},timeout(fn,delay){delay=delay||0;const time=Animator.timer().now()+delay,node=Animator.timeouts.push({run:fn,time:time});return null===Animator.nextDraw&&(Animator.nextDraw=globals.window.requestAnimationFrame(Animator._draw)),node},immediate(fn){const node=Animator.immediates.push(fn);return null===Animator.nextDraw&&(Animator.nextDraw=globals.window.requestAnimationFrame(Animator._draw)),node},cancelFrame(node){null!=node&&Animator.frames.remove(node)},clearTimeout(node){null!=node&&Animator.timeouts.remove(node)},cancelImmediate(node){null!=node&&Animator.immediates.remove(node)},_draw(now){let nextTimeout=null;const lastTimeout=Animator.timeouts.last();for(;(nextTimeout=Animator.timeouts.shift())&&(now>=nextTimeout.time?nextTimeout.run():Animator.timeouts.push(nextTimeout),nextTimeout!==lastTimeout););let nextFrame=null;const lastFrame=Animator.frames.last();for(;nextFrame!==lastFrame&&(nextFrame=Animator.frames.shift());)nextFrame.run(now);let nextImmediate=null;for(;nextImmediate=Animator.immediates.shift();)nextImmediate();Animator.nextDraw=Animator.timeouts.first()||Animator.frames.first()?globals.window.requestAnimationFrame(Animator._draw):null}},makeSchedule=function(runnerInfo){const start=runnerInfo.start,duration=runnerInfo.runner.duration();return{start:start,duration:duration,end:start+duration,runner:runnerInfo.runner}},defaultSource=function(){const w=globals.window;return(w.performance||w.Date).now()};class Timeline extends EventTarget{constructor(){let timeSource=arguments.length>0&&void 0!==arguments[0]?arguments[0]:defaultSource;super(),this._timeSource=timeSource,this.terminate()}active(){return!!this._nextFrame}finish(){return this.time(this.getEndTimeOfTimeline()+1),this.pause()}getEndTime(){const lastRunnerInfo=this.getLastRunnerInfo(),lastDuration=lastRunnerInfo?lastRunnerInfo.runner.duration():0;return(lastRunnerInfo?lastRunnerInfo.start:this._time)+lastDuration}getEndTimeOfTimeline(){const endTimes=this._runners.map((i=>i.start+i.runner.duration()));return Math.max(0,...endTimes)}getLastRunnerInfo(){return this.getRunnerInfoById(this._lastRunnerId)}getRunnerInfoById(id){return this._runners[this._runnerIds.indexOf(id)]||null}pause(){return this._paused=!0,this._continue()}persist(dtOrForever){return null==dtOrForever?this._persist:(this._persist=dtOrForever,this)}play(){return this._paused=!1,this.updateTime()._continue()}reverse(yes){const currentSpeed=this.speed();if(null==yes)return this.speed(-currentSpeed);const positive=Math.abs(currentSpeed);return this.speed(yes?-positive:positive)}schedule(runner,delay,when){if(null==runner)return this._runners.map(makeSchedule);let absoluteStartTime=0;const endTime=this.getEndTime();if(delay=delay||0,null==when||"last"===when||"after"===when)absoluteStartTime=endTime;else if("absolute"===when||"start"===when)absoluteStartTime=delay,delay=0;else if("now"===when)absoluteStartTime=this._time;else if("relative"===when){const runnerInfo=this.getRunnerInfoById(runner.id);runnerInfo&&(absoluteStartTime=runnerInfo.start+delay,delay=0)}else{if("with-last"!==when)throw new Error('Invalid value for the "when" parameter');{const lastRunnerInfo=this.getLastRunnerInfo();absoluteStartTime=lastRunnerInfo?lastRunnerInfo.start:this._time}}runner.unschedule(),runner.timeline(this);const persist=runner.persist(),runnerInfo={persist:null===persist?this._persist:persist,start:absoluteStartTime+delay,runner:runner};return this._lastRunnerId=runner.id,this._runners.push(runnerInfo),this._runners.sort(((a,b)=>a.start-b.start)),this._runnerIds=this._runners.map((info=>info.runner.id)),this.updateTime()._continue(),this}seek(dt){return this.time(this._time+dt)}source(fn){return null==fn?this._timeSource:(this._timeSource=fn,this)}speed(speed){return null==speed?this._speed:(this._speed=speed,this)}stop(){return this.time(0),this.pause()}time(time){return null==time?this._time:(this._time=time,this._continue(!0))}unschedule(runner){const index=this._runnerIds.indexOf(runner.id);return index<0||(this._runners.splice(index,1),this._runnerIds.splice(index,1),runner.timeline(null)),this}updateTime(){return this.active()||(this._lastSourceTime=this._timeSource()),this}_continue(){let immediateStep=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return Animator.cancelFrame(this._nextFrame),this._nextFrame=null,immediateStep?this._stepImmediate():(this._paused||(this._nextFrame=Animator.frame(this._step)),this)}_stepFn(){let immediateStep=arguments.length>0&&void 0!==arguments[0]&&arguments[0];const time=this._timeSource();let dtSource=time-this._lastSourceTime;immediateStep&&(dtSource=0);const dtTime=this._speed*dtSource+(this._time-this._lastStepTime);this._lastSourceTime=time,immediateStep||(this._time+=dtTime,this._time=this._time<0?0:this._time),this._lastStepTime=this._time,this.fire("time",this._time);for(let k=this._runners.length;k--;){const runnerInfo=this._runners[k],runner=runnerInfo.runner;this._time-runnerInfo.start<=0&&runner.reset()}let runnersLeft=!1;for(let i=0,len=this._runners.length;i0?this._continue():(this.pause(),this.fire("finished")),this}terminate(){this._startTime=0,this._speed=1,this._persist=0,this._nextFrame=null,this._paused=!0,this._runners=[],this._runnerIds=[],this._lastRunnerId=-1,this._time=0,this._lastSourceTime=0,this._lastStepTime=0,this._step=this._stepFn.bind(this,!1),this._stepImmediate=this._stepFn.bind(this,!0)}}registerMethods({Element:{timeline:function(timeline){return null==timeline?(this._timeline=this._timeline||new Timeline,this._timeline):(this._timeline=timeline,this)}}});class Runner extends EventTarget{constructor(options){super(),this.id=Runner.id++,options="function"==typeof(options=null==options?timeline.duration:options)?new Controller(options):options,this._element=null,this._timeline=null,this.done=!1,this._queue=[],this._duration="number"==typeof options&&options,this._isDeclarative=options instanceof Controller,this._stepper=this._isDeclarative?options:new Ease,this._history={},this.enabled=!0,this._time=0,this._lastTime=0,this._reseted=!0,this.transforms=new Matrix,this.transformId=1,this._haveReversed=!1,this._reverse=!1,this._loopsDone=0,this._swing=!1,this._wait=0,this._times=1,this._frameId=null,this._persist=!!this._isDeclarative||null}static sanitise(duration,delay,when){var _duration,_delay;let times=1,swing=!1,wait=0;var _duration$delay,_duration$when,_duration$times,_duration$wait,_duration$duration;(duration=null!==(_duration=duration)&&void 0!==_duration?_duration:timeline.duration,delay=null!==(_delay=delay)&&void 0!==_delay?_delay:timeline.delay,when=when||"last","object"!=typeof duration||duration instanceof Stepper)||(delay=null!==(_duration$delay=duration.delay)&&void 0!==_duration$delay?_duration$delay:delay,when=null!==(_duration$when=duration.when)&&void 0!==_duration$when?_duration$when:when,swing=duration.swing||swing,times=null!==(_duration$times=duration.times)&&void 0!==_duration$times?_duration$times:times,wait=null!==(_duration$wait=duration.wait)&&void 0!==_duration$wait?_duration$wait:wait,duration=null!==(_duration$duration=duration.duration)&&void 0!==_duration$duration?_duration$duration:timeline.duration);return{duration:duration,delay:delay,swing:swing,times:times,wait:wait,when:when}}active(enabled){return null==enabled?this.enabled:(this.enabled=enabled,this)}addTransform(transform){return this.transforms.lmultiplyO(transform),this}after(fn){return this.on("finished",fn)}animate(duration,delay,when){const o=Runner.sanitise(duration,delay,when),runner=new Runner(o.duration);return this._timeline&&runner.timeline(this._timeline),this._element&&runner.element(this._element),runner.loop(o).schedule(o.delay,o.when)}clearTransform(){return this.transforms=new Matrix,this}clearTransformsFromQueue(){this.done&&this._timeline&&this._timeline._runnerIds.includes(this.id)||(this._queue=this._queue.filter((item=>!item.isTransform)))}delay(delay){return this.animate(0,delay)}duration(){return this._times*(this._wait+this._duration)-this._wait}during(fn){return this.queue(null,fn)}ease(fn){return this._stepper=new Ease(fn),this}element(element){return null==element?this._element:(this._element=element,element._prepareRunner(),this)}finish(){return this.step(1/0)}loop(times,swing,wait){return"object"==typeof times&&(swing=times.swing,wait=times.wait,times=times.times),this._times=times||1/0,this._swing=swing||!1,this._wait=wait||0,!0===this._times&&(this._times=1/0),this}loops(p){const loopDuration=this._duration+this._wait;if(null==p){const loopsDone=Math.floor(this._time/loopDuration),position=(this._time-loopsDone*loopDuration)/this._duration;return Math.min(loopsDone+position,this._times)}const partial=p%1,time=loopDuration*Math.floor(p)+this._duration*partial;return this.time(time)}persist(dtOrForever){return null==dtOrForever?this._persist:(this._persist=dtOrForever,this)}position(p){const x=this._time,d=this._duration,w=this._wait,t=this._times,s=this._swing,r=this._reverse;let position;if(null==p){const f=function(x){const swinging=s*Math.floor(x%(2*(w+d))/(w+d)),backwards=swinging&&!r||!swinging&&r,uncliped=Math.pow(-1,backwards)*(x%(w+d))/d+backwards;return Math.max(Math.min(uncliped,1),0)},endTime=t*(w+d)-w;return position=x<=0?Math.round(f(1e-5)):x=0;this._lastPosition=position;const duration=this.duration(),justStarted=this._lastTime<=0&&this._time>0,justFinished=this._lastTime=duration;this._lastTime=this._time,justStarted&&this.fire("start",this);const declarative=this._isDeclarative;this.done=!declarative&&!justFinished&&this._time>=duration,this._reseted=!1;let converged=!1;return(running||declarative)&&(this._initialise(running),this.transforms=new Matrix,converged=this._run(declarative?dt:position),this.fire("step",this)),this.done=this.done||converged&&declarative,justFinished&&this.fire("finished",this),this}time(time){if(null==time)return this._time;const dt=time-this._time;return this.step(dt),this}timeline(timeline){return void 0===timeline?this._timeline:(this._timeline=timeline,this)}unschedule(){const timeline=this.timeline();return timeline&&timeline.unschedule(this),this}_initialise(running){if(running||this._isDeclarative)for(let i=0,len=this._queue.length;i0&&void 0!==arguments[0]?arguments[0]:new Matrix,id=arguments.length>1&&void 0!==arguments[1]?arguments[1]:-1,done=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];this.transforms=transforms,this.id=id,this.done=done}clearTransformsFromQueue(){}}extend([Runner,FakeRunner],{mergeWith(runner){return new FakeRunner(runner.transforms.lmultiply(this.transforms),runner.id)}});const lmultiply=(last,curr)=>last.lmultiplyO(curr),getRunnerTransform=runner=>runner.transforms;function mergeTransforms(){const netTransform=this._transformationRunners.runners.map(getRunnerTransform).reduce(lmultiply,new Matrix);this.transform(netTransform),this._transformationRunners.merge(),1===this._transformationRunners.length()&&(this._frameId=null)}class RunnerArray{constructor(){this.runners=[],this.ids=[]}add(runner){if(this.runners.includes(runner))return;const id=runner.id+1;return this.runners.push(runner),this.ids.push(id),this}clearBefore(id){const deleteCnt=this.ids.indexOf(id+1)||1;return this.ids.splice(0,deleteCnt,0),this.runners.splice(0,deleteCnt,new FakeRunner).forEach((r=>r.clearTransformsFromQueue())),this}edit(id,newRunner){const index=this.ids.indexOf(id+1);return this.ids.splice(index,1,id+1),this.runners.splice(index,1,newRunner),this}getByID(id){return this.runners[this.ids.indexOf(id+1)]}length(){return this.ids.length}merge(){let lastRunner=null;for(let i=0;irunner.id<=current.id)).map(getRunnerTransform).reduce(lmultiply,new Matrix)},_addRunner(runner){this._transformationRunners.add(runner),Animator.cancelImmediate(this._frameId),this._frameId=Animator.immediate(mergeTransforms.bind(this))},_prepareRunner(){null==this._frameId&&(this._transformationRunners=(new RunnerArray).add(new FakeRunner(new Matrix(this))))}}});extend(Runner,{attr(a,v){return this.styleAttr("attr",a,v)},css(s,v){return this.styleAttr("css",s,v)},styleAttr(type,nameOrAttrs,val){if("string"==typeof nameOrAttrs)return this.styleAttr(type,{[nameOrAttrs]:val});let attrs=nameOrAttrs;if(this._tryRetarget(type,attrs))return this;let morpher=new Morphable(this._stepper).to(attrs),keys=Object.keys(attrs);return this.queue((function(){morpher=morpher.from(this.element()[type](keys))}),(function(pos){return this.element()[type](morpher.at(pos).valueOf()),morpher.done()}),(function(newToAttrs){const newKeys=Object.keys(newToAttrs),differences=(b=keys,newKeys.filter((x=>!b.includes(x))));var b;if(differences.length){const addedFromAttrs=this.element()[type](differences),oldFromAttrs=new ObjectBag(morpher.from()).valueOf();Object.assign(oldFromAttrs,addedFromAttrs),morpher.from(oldFromAttrs)}const oldToAttrs=new ObjectBag(morpher.to()).valueOf();Object.assign(oldToAttrs,newToAttrs),morpher.to(oldToAttrs),keys=newKeys,attrs=newToAttrs})),this._rememberMorpher(type,morpher),this},zoom(level,point){if(this._tryRetarget("zoom",level,point))return this;let morpher=new Morphable(this._stepper).to(new SVGNumber(level));return this.queue((function(){morpher=morpher.from(this.element().zoom())}),(function(pos){return this.element().zoom(morpher.at(pos),point),morpher.done()}),(function(newLevel,newPoint){point=newPoint,morpher.to(newLevel)})),this._rememberMorpher("zoom",morpher),this},transform(transforms,relative,affine){if(relative=transforms.relative||relative,this._isDeclarative&&!relative&&this._tryRetarget("transform",transforms))return this;const isMatrix=Matrix.isMatrixLike(transforms);affine=null!=transforms.affine?transforms.affine:null!=affine?affine:!isMatrix;const morpher=new Morphable(this._stepper).type(affine?TransformBag:Matrix);let origin,element,current,currentAngle,startTransform;return this.queue((function(){element=element||this.element(),origin=origin||getOrigin(transforms,element),startTransform=new Matrix(relative?void 0:element),element._addRunner(this),relative||element._clearTransformRunnersBefore(this)}),(function(pos){relative||this.clearTransform();const{x:x,y:y}=new Point(origin).transform(element._currentTransform(this));let target=new Matrix({...transforms,origin:[x,y]}),start=this._isDeclarative&¤t?current:startTransform;if(affine){target=target.decompose(x,y),start=start.decompose(x,y);const rTarget=target.rotate,rCurrent=start.rotate,possibilities=[rTarget-360,rTarget,rTarget+360],distances=possibilities.map((a=>Math.abs(a-rCurrent))),shortest=Math.min(...distances),index=distances.indexOf(shortest);target.rotate=possibilities[index]}relative&&(isMatrix||(target.rotate=transforms.rotate||0),this._isDeclarative&¤tAngle&&(start.rotate=currentAngle)),morpher.from(start),morpher.to(target);const affineParameters=morpher.at(pos);return currentAngle=affineParameters.rotate,current=new Matrix(affineParameters),this.addTransform(current),element._addRunner(this),morpher.done()}),(function(newTransforms){(newTransforms.origin||"center").toString()!==(transforms.origin||"center").toString()&&(origin=getOrigin(newTransforms,element)),transforms={...newTransforms,origin:origin}}),!0),this._isDeclarative&&this._rememberMorpher("transform",morpher),this},x(x){return this._queueNumber("x",x)},y(y){return this._queueNumber("y",y)},ax(x){return this._queueNumber("ax",x)},ay(y){return this._queueNumber("ay",y)},dx(){let x=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;return this._queueNumberDelta("x",x)},dy(){let y=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;return this._queueNumberDelta("y",y)},dmove(x,y){return this.dx(x).dy(y)},_queueNumberDelta(method,to){if(to=new SVGNumber(to),this._tryRetarget(method,to))return this;const morpher=new Morphable(this._stepper).to(to);let from=null;return this.queue((function(){from=this.element()[method](),morpher.from(from),morpher.to(from+to)}),(function(pos){return this.element()[method](morpher.at(pos)),morpher.done()}),(function(newTo){morpher.to(from+new SVGNumber(newTo))})),this._rememberMorpher(method,morpher),this},_queueObject(method,to){if(this._tryRetarget(method,to))return this;const morpher=new Morphable(this._stepper).to(to);return this.queue((function(){morpher.from(this.element()[method]())}),(function(pos){return this.element()[method](morpher.at(pos)),morpher.done()})),this._rememberMorpher(method,morpher),this},_queueNumber(method,value){return this._queueObject(method,new SVGNumber(value))},cx(x){return this._queueNumber("cx",x)},cy(y){return this._queueNumber("cy",y)},move(x,y){return this.x(x).y(y)},amove(x,y){return this.ax(x).ay(y)},center(x,y){return this.cx(x).cy(y)},size(width,height){let box;return width&&height||(box=this._element.bbox()),width||(width=box.width/box.height*height),height||(height=box.height/box.width*width),this.width(width).height(height)},width(width){return this._queueNumber("width",width)},height(height){return this._queueNumber("height",height)},plot(a,b,c,d){if(4===arguments.length)return this.plot([a,b,c,d]);if(this._tryRetarget("plot",a))return this;const morpher=new Morphable(this._stepper).type(this._element.MorphArray).to(a);return this.queue((function(){morpher.from(this._element.array())}),(function(pos){return this._element.plot(morpher.at(pos)),morpher.done()})),this._rememberMorpher("plot",morpher),this},leading(value){return this._queueNumber("leading",value)},viewbox(x,y,width,height){return this._queueObject("viewbox",new Box(x,y,width,height))},update(o){return"object"!=typeof o?this.update({offset:arguments[0],color:arguments[1],opacity:arguments[2]}):(null!=o.opacity&&this.attr("stop-opacity",o.opacity),null!=o.color&&this.attr("stop-color",o.color),null!=o.offset&&this.attr("offset",o.offset),this)}}),extend(Runner,{rx:rx,ry:ry,from:from,to:to}),register(Runner,"Runner");class Svg extends Container{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("svg",node),attrs),this.namespace()}defs(){return this.isRoot()?adopt(this.node.querySelector("defs"))||this.put(new Defs):this.root().defs()}isRoot(){return!this.node.parentNode||!(this.node.parentNode instanceof globals.window.SVGElement)&&"#document-fragment"!==this.node.parentNode.nodeName}namespace(){return this.isRoot()?this.attr({xmlns:svg,version:"1.1"}).attr("xmlns:xlink",xlink,xmlns):this.root().namespace()}removeNamespace(){return this.attr({xmlns:null,version:null}).attr("xmlns:xlink",null,xmlns).attr("xmlns:svgjs",null,xmlns)}root(){return this.isRoot()?this:super.root()}}registerMethods({Container:{nested:wrapWithAttrCheck((function(){return this.put(new Svg)}))}}),register(Svg,"Svg",!0);class Symbol extends Container{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("symbol",node),attrs)}}registerMethods({Container:{symbol:wrapWithAttrCheck((function(){return this.put(new Symbol)}))}}),register(Symbol,"Symbol");var textable={__proto__:null,amove:function(x,y){return this.ax(x).ay(y)},ax:function(x){return this.attr("x",x)},ay:function(y){return this.attr("y",y)},build:function(build){return this._build=!!build,this},center:function(x,y){let box=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.bbox();return this.cx(x,box).cy(y,box)},cx:function(x){let box=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.bbox();return null==x?box.cx:this.attr("x",this.attr("x")+x-box.cx)},cy:function(y){let box=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.bbox();return null==y?box.cy:this.attr("y",this.attr("y")+y-box.cy)},length:function(){return this.node.getComputedTextLength()},move:function(x,y){let box=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.bbox();return this.x(x,box).y(y,box)},plain:function(text){return!1===this._build&&this.clear(),this.node.appendChild(globals.document.createTextNode(text)),this},x:function(x){let box=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.bbox();return null==x?box.x:this.attr("x",this.attr("x")+x-box.x)},y:function(y){let box=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.bbox();return null==y?box.y:this.attr("y",this.attr("y")+y-box.y)}};class Text extends Shape{constructor(node){var _this$dom$leading;let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("text",node),attrs),this.dom.leading=null!==(_this$dom$leading=this.dom.leading)&&void 0!==_this$dom$leading?_this$dom$leading:new SVGNumber(1.3),this._rebuild=!0,this._build=!1}leading(value){return null==value?this.dom.leading:(this.dom.leading=new SVGNumber(value),this.rebuild())}rebuild(rebuild){if("boolean"==typeof rebuild&&(this._rebuild=rebuild),this._rebuild){const self=this;let blankLineOffset=0;const leading=this.dom.leading;this.each((function(i){if(isDescriptive(this.node))return;const fontSize=globals.window.getComputedStyle(this.node).getPropertyValue("font-size"),dy=leading*new SVGNumber(fontSize);this.dom.newLined&&(this.attr("x",self.attr("x")),"\n"===this.text()?blankLineOffset+=dy:(this.attr("dy",i?dy+blankLineOffset:0),blankLineOffset=0))})),this.fire("rebuild")}return this}setData(o){return this.dom=o,this.dom.leading=new SVGNumber(o.leading||1.3),this}writeDataToDom(){return writeDataToDom(this,this.dom,{leading:1.3}),this}text(text){if(void 0===text){const children=this.node.childNodes;let firstLine=0;text="";for(let i=0,len=children.length;i0&&void 0!==arguments[0]?arguments[0]:"";return this.put(new Text).text(text)})),plain:wrapWithAttrCheck((function(){let text=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return this.put(new Text).plain(text)}))}}),register(Text,"Text");class Tspan extends Shape{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("tspan",node),attrs),this._build=!1}dx(dx){return this.attr("dx",dx)}dy(dy){return this.attr("dy",dy)}newLine(){this.dom.newLined=!0;const text=this.parent();if(!(text instanceof Text))return this;const i=text.index(this),fontSize=globals.window.getComputedStyle(this.node).getPropertyValue("font-size"),dy=text.dom.leading*new SVGNumber(fontSize);return this.dy(i?dy:0).attr("x",text.x())}text(text){return null==text?this.node.textContent+(this.dom.newLined?"\n":""):("function"==typeof text?(this.clear().build(!0),text.call(this,this),this.build(!1)):this.plain(text),this)}}extend(Tspan,textable),registerMethods({Tspan:{tspan:wrapWithAttrCheck((function(){let text=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";const tspan=new Tspan;return this._build||this.clear(),this.put(tspan).text(text)}))},Text:{newLine:function(){let text=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return this.tspan(text).newLine()}}}),register(Tspan,"Tspan");class Circle extends Shape{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("circle",node),attrs)}radius(r){return this.attr("r",r)}rx(rx){return this.attr("r",rx)}ry(ry){return this.rx(ry)}size(size){return this.radius(new SVGNumber(size).divide(2))}}extend(Circle,{x:x$3,y:y$3,cx:cx$1,cy:cy$1,width:width$2,height:height$2}),registerMethods({Container:{circle:wrapWithAttrCheck((function(){let size=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;return this.put(new Circle).size(size).move(0,0)}))}}),register(Circle,"Circle");class ClipPath extends Container{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("clipPath",node),attrs)}remove(){return this.targets().forEach((function(el){el.unclip()})),super.remove()}targets(){return baseFind("svg [clip-path*="+this.id()+"]")}}registerMethods({Container:{clip:wrapWithAttrCheck((function(){return this.defs().put(new ClipPath)}))},Element:{clipper(){return this.reference("clip-path")},clipWith(element){const clipper=element instanceof ClipPath?element:this.parent().clip().add(element);return this.attr("clip-path","url(#"+clipper.id()+")")},unclip(){return this.attr("clip-path",null)}}}),register(ClipPath,"ClipPath");class ForeignObject extends Element{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("foreignObject",node),attrs)}}registerMethods({Container:{foreignObject:wrapWithAttrCheck((function(width,height){return this.put(new ForeignObject).size(width,height)}))}}),register(ForeignObject,"ForeignObject");var containerGeometry={__proto__:null,dmove:function(dx,dy){return this.children().forEach((child=>{let bbox;try{bbox=child.node instanceof getWindow().SVGSVGElement?new Box(child.attr(["x","y","width","height"])):child.bbox()}catch(e){return}const m=new Matrix(child),matrix=m.translate(dx,dy).transform(m.inverse()),p=new Point(bbox.x,bbox.y).transform(matrix);child.move(p.x,p.y)})),this},dx:function(dx){return this.dmove(dx,0)},dy:function(dy){return this.dmove(0,dy)},height:function(height){let box=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.bbox();return null==height?box.height:this.size(box.width,height,box)},move:function(){let x=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,y=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,box=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.bbox();const dx=x-box.x,dy=y-box.y;return this.dmove(dx,dy)},size:function(width,height){let box=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.bbox();const p=proportionalSize(this,width,height,box),scaleX=p.width/box.width,scaleY=p.height/box.height;return this.children().forEach((child=>{const o=new Point(box).transform(new Matrix(child).inverse());child.scale(scaleX,scaleY,o.x,o.y)})),this},width:function(width){let box=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.bbox();return null==width?box.width:this.size(width,box.height,box)},x:function(x){let box=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.bbox();return null==x?box.x:this.move(x,box.y,box)},y:function(y){let box=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.bbox();return null==y?box.y:this.move(box.x,y,box)}};class G extends Container{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("g",node),attrs)}}extend(G,containerGeometry),registerMethods({Container:{group:wrapWithAttrCheck((function(){return this.put(new G)}))}}),register(G,"G");class A extends Container{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("a",node),attrs)}target(target){return this.attr("target",target)}to(url){return this.attr("href",url,xlink)}}extend(A,containerGeometry),registerMethods({Container:{link:wrapWithAttrCheck((function(url){return this.put(new A).to(url)}))},Element:{unlink(){const link=this.linker();if(!link)return this;const parent=link.parent();if(!parent)return this.remove();const index=parent.index(link);return parent.add(this,index),link.remove(),this},linkTo(url){let link=this.linker();return link||(link=new A,this.wrap(link)),"function"==typeof url?url.call(link,link):link.to(url),this},linker(){const link=this.parent();return link&&"a"===link.node.nodeName.toLowerCase()?link:null}}}),register(A,"A");class Mask extends Container{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("mask",node),attrs)}remove(){return this.targets().forEach((function(el){el.unmask()})),super.remove()}targets(){return baseFind("svg [mask*="+this.id()+"]")}}registerMethods({Container:{mask:wrapWithAttrCheck((function(){return this.defs().put(new Mask)}))},Element:{masker(){return this.reference("mask")},maskWith(element){const masker=element instanceof Mask?element:this.parent().mask().add(element);return this.attr("mask","url(#"+masker.id()+")")},unmask(){return this.attr("mask",null)}}}),register(Mask,"Mask");class Stop extends Element{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("stop",node),attrs)}update(o){return("number"==typeof o||o instanceof SVGNumber)&&(o={offset:arguments[0],color:arguments[1],opacity:arguments[2]}),null!=o.opacity&&this.attr("stop-opacity",o.opacity),null!=o.color&&this.attr("stop-color",o.color),null!=o.offset&&this.attr("offset",new SVGNumber(o.offset)),this}}registerMethods({Gradient:{stop:function(offset,color,opacity){return this.put(new Stop).update(offset,color,opacity)}}}),register(Stop,"Stop");class Style extends Element{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("style",node),attrs)}addText(){let w=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return this.node.textContent+=w,this}font(name,src){let params=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return this.rule("@font-face",{fontFamily:name,src:src,...params})}rule(selector,obj){return this.addText(function(selector,rule){if(!selector)return"";if(!rule)return selector;let ret=selector+"{";for(const i in rule)ret+=unCamelCase(i)+":"+rule[i]+";";return ret+="}",ret}(selector,obj))}}registerMethods("Dom",{style(selector,obj){return this.put(new Style).rule(selector,obj)},fontface(name,src,params){return this.put(new Style).font(name,src,params)}}),register(Style,"Style");class TextPath extends Text{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("textPath",node),attrs)}array(){const track=this.track();return track?track.array():null}plot(d){const track=this.track();let pathArray=null;return track&&(pathArray=track.plot(d)),null==d?pathArray:this}track(){return this.reference("href")}}registerMethods({Container:{textPath:wrapWithAttrCheck((function(text,path){return text instanceof Text||(text=this.text(text)),text.path(path)}))},Text:{path:wrapWithAttrCheck((function(track){let importNodes=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];const textPath=new TextPath;let node;if(track instanceof Path||(track=this.defs().path(track)),textPath.attr("href","#"+track,xlink),importNodes)for(;node=this.node.firstChild;)textPath.node.appendChild(node);return this.put(textPath)})),textPath(){return this.findOne("textPath")}},Path:{text:wrapWithAttrCheck((function(text){return text instanceof Text||(text=(new Text).addTo(this.parent()).text(text)),text.path(this)})),targets(){return baseFind("svg textPath").filter((node=>(node.attr("href")||"").includes(this.id())))}}}),TextPath.prototype.MorphArray=PathArray,register(TextPath,"TextPath");class Use extends Shape{constructor(node){let attrs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:node;super(nodeOrNew("use",node),attrs)}use(element,file){return this.attr("href",(file||"")+"#"+element,xlink)}}registerMethods({Container:{use:wrapWithAttrCheck((function(element,file){return this.put(new Use).use(element,file)}))}}),register(Use,"Use");const SVG$1=makeInstance;extend([Svg,Symbol,Image,Pattern,Marker],getMethodsFor("viewbox")),extend([Line,Polyline,Polygon,Path],getMethodsFor("marker")),extend(Text,getMethodsFor("Text")),extend(Path,getMethodsFor("Path")),extend(Defs,getMethodsFor("Defs")),extend([Text,Tspan],getMethodsFor("Tspan")),extend([Rect,Ellipse,Gradient,Runner],getMethodsFor("radius")),extend(EventTarget,getMethodsFor("EventTarget")),extend(Dom,getMethodsFor("Dom")),extend(Element,getMethodsFor("Element")),extend(Shape,getMethodsFor("Shape")),extend([Container,Fragment],getMethodsFor("Container")),extend(Gradient,getMethodsFor("Gradient")),extend(Runner,getMethodsFor("Runner")),List.extend([...new Set(names)]),registerMorphableType([SVGNumber,Color,Box,Matrix,SVGArray,PointArray,PathArray,Point]),makeMorphable();var svgMembers={__proto__:null,A:A,Animator:Animator,Array:SVGArray,Box:Box,Circle:Circle,ClipPath:ClipPath,Color:Color,Container:Container,Controller:Controller,Defs:Defs,Dom:Dom,Ease:Ease,Element:Element,Ellipse:Ellipse,EventTarget:EventTarget,ForeignObject:ForeignObject,Fragment:Fragment,G:G,Gradient:Gradient,Image:Image,Line:Line,List:List,Marker:Marker,Mask:Mask,Matrix:Matrix,Morphable:Morphable,NonMorphable:NonMorphable,Number:SVGNumber,ObjectBag:ObjectBag,PID:PID,Path:Path,PathArray:PathArray,Pattern:Pattern,Point:Point,PointArray:PointArray,Polygon:Polygon,Polyline:Polyline,Queue:Queue,Rect:Rect,Runner:Runner,SVG:SVG$1,Shape:Shape,Spring:Spring,Stop:Stop,Style:Style,Svg:Svg,Symbol:Symbol,Text:Text,TextPath:TextPath,Timeline:Timeline,TransformBag:TransformBag,Tspan:Tspan,Use:Use,adopt:adopt,assignNewId:assignNewId,clearEvents:clearEvents,create:create,defaults:defaults,dispatch:dispatch,easing:easing,eid:eid,extend:extend,find:baseFind,getClass:getClass,getEventTarget:getEventTarget,getEvents:getEvents,getWindow:getWindow,makeInstance:makeInstance,makeMorphable:makeMorphable,mockAdopt:function(){adopter=arguments.length>0&&void 0!==arguments[0]?arguments[0]:adopt},namespaces:namespaces,nodeOrNew:nodeOrNew,off:off,on:on,parser:parser,regex:regex,register:register,registerMorphableType:registerMorphableType,registerWindow:registerWindow,restoreWindow:restoreWindow,root:root,saveWindow:saveWindow,utils:utils,windowEvents:windowEvents,withWindow:function(win,fn){saveWindow(),registerWindow(win,win.document),fn(win,win.document),restoreWindow()},wrapWithAttrCheck:wrapWithAttrCheck};function SVG(element,isHTML){return makeInstance(element,isHTML)}return Object.assign(SVG,svgMembers),SVG},_exports.default})); + +//# sourceMappingURL=svg.min.js.map \ No newline at end of file diff --git a/amd/build/svg.min.js.map b/amd/build/svg.min.js.map new file mode 100644 index 0000000..d8410f4 --- /dev/null +++ b/amd/build/svg.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"svg.min.js","sources":["../src/svg.js"],"sourcesContent":["/*\n* @svgdotjs/svg.js - A lightweight library for manipulating and animating SVG.\n* @version 3.2.4\n* https://svgjs.dev/\n*\n* @copyright Wout Fierens \n* @license MIT\n* Copyright (c) 2012-2018 Wout Fierens\n* https://svgdotjs.github.io/\n*\n* Permission is hereby granted, free of charge, to any person obtaining\n* a copy of this software and associated documentation files (the\n* \"Software\"), to deal in the Software without restriction, including\n* without limitation the rights to use, copy, modify, merge, publish,\n* distribute, sublicense, and/or sell copies of the Software, and to\n* permit persons to whom the Software is furnished to do so, subject to\n* the following conditions:\n*\n* The above copyright notice and this permission notice shall be\n* included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*\n*\n* BUILT: Thu Jun 27 2024 12:00:16 GMT+0200 (Central European Summer Time)\n*/\nexport default function () {\n 'use strict';\n\n const methods$1 = {};\n const names = [];\n function registerMethods(name, m) {\n if (Array.isArray(name)) {\n for (const _name of name) {\n registerMethods(_name, m);\n }\n return;\n }\n if (typeof name === 'object') {\n for (const _name in name) {\n registerMethods(_name, name[_name]);\n }\n return;\n }\n addMethodNames(Object.getOwnPropertyNames(m));\n methods$1[name] = Object.assign(methods$1[name] || {}, m);\n }\n function getMethodsFor(name) {\n return methods$1[name] || {};\n }\n function getMethodNames() {\n return [...new Set(names)];\n }\n function addMethodNames(_names) {\n names.push(..._names);\n }\n\n // Map function\n function map(array, block) {\n let i;\n const il = array.length;\n const result = [];\n for (i = 0; i < il; i++) {\n result.push(block(array[i]));\n }\n return result;\n }\n\n // Filter function\n function filter(array, block) {\n let i;\n const il = array.length;\n const result = [];\n for (i = 0; i < il; i++) {\n if (block(array[i])) {\n result.push(array[i]);\n }\n }\n return result;\n }\n\n // Degrees to radians\n function radians(d) {\n return d % 360 * Math.PI / 180;\n }\n\n // Radians to degrees\n function degrees(r) {\n return r * 180 / Math.PI % 360;\n }\n\n // Convert camel cased string to dash separated\n function unCamelCase(s) {\n return s.replace(/([A-Z])/g, function (m, g) {\n return '-' + g.toLowerCase();\n });\n }\n\n // Capitalize first letter of a string\n function capitalize(s) {\n return s.charAt(0).toUpperCase() + s.slice(1);\n }\n\n // Calculate proportional width and height values when necessary\n function proportionalSize(element, width, height, box) {\n if (width == null || height == null) {\n box = box || element.bbox();\n if (width == null) {\n width = box.width / box.height * height;\n } else if (height == null) {\n height = box.height / box.width * width;\n }\n }\n return {\n width: width,\n height: height\n };\n }\n\n /**\n * This function adds support for string origins.\n * It searches for an origin in o.origin o.ox and o.originX.\n * This way, origin: {x: 'center', y: 50} can be passed as well as ox: 'center', oy: 50\n **/\n function getOrigin(o, element) {\n const origin = o.origin;\n // First check if origin is in ox or originX\n let ox = o.ox != null ? o.ox : o.originX != null ? o.originX : 'center';\n let oy = o.oy != null ? o.oy : o.originY != null ? o.originY : 'center';\n\n // Then check if origin was used and overwrite in that case\n if (origin != null) {\n [ox, oy] = Array.isArray(origin) ? origin : typeof origin === 'object' ? [origin.x, origin.y] : [origin, origin];\n }\n\n // Make sure to only call bbox when actually needed\n const condX = typeof ox === 'string';\n const condY = typeof oy === 'string';\n if (condX || condY) {\n const {\n height,\n width,\n x,\n y\n } = element.bbox();\n\n // And only overwrite if string was passed for this specific axis\n if (condX) {\n ox = ox.includes('left') ? x : ox.includes('right') ? x + width : x + width / 2;\n }\n if (condY) {\n oy = oy.includes('top') ? y : oy.includes('bottom') ? y + height : y + height / 2;\n }\n }\n\n // Return the origin as it is if it wasn't a string\n return [ox, oy];\n }\n const descriptiveElements = new Set(['desc', 'metadata', 'title']);\n const isDescriptive = element => descriptiveElements.has(element.nodeName);\n const writeDataToDom = (element, data, defaults = {}) => {\n const cloned = {\n ...data\n };\n for (const key in cloned) {\n if (cloned[key].valueOf() === defaults[key]) {\n delete cloned[key];\n }\n }\n if (Object.keys(cloned).length) {\n element.node.setAttribute('data-svgjs', JSON.stringify(cloned)); // see #428\n } else {\n element.node.removeAttribute('data-svgjs');\n element.node.removeAttribute('svgjs:data');\n }\n };\n\n var utils = {\n __proto__: null,\n capitalize: capitalize,\n degrees: degrees,\n filter: filter,\n getOrigin: getOrigin,\n isDescriptive: isDescriptive,\n map: map,\n proportionalSize: proportionalSize,\n radians: radians,\n unCamelCase: unCamelCase,\n writeDataToDom: writeDataToDom\n };\n\n // Default namespaces\n const svg = 'http://www.w3.org/2000/svg';\n const html = 'http://www.w3.org/1999/xhtml';\n const xmlns = 'http://www.w3.org/2000/xmlns/';\n const xlink = 'http://www.w3.org/1999/xlink';\n\n var namespaces = {\n __proto__: null,\n html: html,\n svg: svg,\n xlink: xlink,\n xmlns: xmlns\n };\n\n const globals = {\n window: typeof window === 'undefined' ? null : window,\n document: typeof document === 'undefined' ? null : document\n };\n function registerWindow(win = null, doc = null) {\n globals.window = win;\n globals.document = doc;\n }\n const save = {};\n function saveWindow() {\n save.window = globals.window;\n save.document = globals.document;\n }\n function restoreWindow() {\n globals.window = save.window;\n globals.document = save.document;\n }\n function withWindow(win, fn) {\n saveWindow();\n registerWindow(win, win.document);\n fn(win, win.document);\n restoreWindow();\n }\n function getWindow() {\n return globals.window;\n }\n\n class Base {\n // constructor (node/*, {extensions = []} */) {\n // // this.tags = []\n // //\n // // for (let extension of extensions) {\n // // extension.setup.call(this, node)\n // // this.tags.push(extension.name)\n // // }\n // }\n }\n\n const elements = {};\n const root = '___SYMBOL___ROOT___';\n\n // Method for element creation\n function create(name, ns = svg) {\n // create element\n return globals.document.createElementNS(ns, name);\n }\n function makeInstance(element, isHTML = false) {\n if (element instanceof Base) return element;\n if (typeof element === 'object') {\n return adopter(element);\n }\n if (element == null) {\n return new elements[root]();\n }\n if (typeof element === 'string' && element.charAt(0) !== '<') {\n return adopter(globals.document.querySelector(element));\n }\n\n // Make sure, that HTML elements are created with the correct namespace\n const wrapper = isHTML ? globals.document.createElement('div') : create('svg');\n wrapper.innerHTML = element;\n\n // We can use firstChild here because we know,\n // that the first char is < and thus an element\n element = adopter(wrapper.firstChild);\n\n // make sure, that element doesn't have its wrapper attached\n wrapper.removeChild(wrapper.firstChild);\n return element;\n }\n function nodeOrNew(name, node) {\n return node && (node instanceof globals.window.Node || node.ownerDocument && node instanceof node.ownerDocument.defaultView.Node) ? node : create(name);\n }\n\n // Adopt existing svg elements\n function adopt(node) {\n // check for presence of node\n if (!node) return null;\n\n // make sure a node isn't already adopted\n if (node.instance instanceof Base) return node.instance;\n if (node.nodeName === '#document-fragment') {\n return new elements.Fragment(node);\n }\n\n // initialize variables\n let className = capitalize(node.nodeName || 'Dom');\n\n // Make sure that gradients are adopted correctly\n if (className === 'LinearGradient' || className === 'RadialGradient') {\n className = 'Gradient';\n\n // Fallback to Dom if element is not known\n } else if (!elements[className]) {\n className = 'Dom';\n }\n return new elements[className](node);\n }\n let adopter = adopt;\n function mockAdopt(mock = adopt) {\n adopter = mock;\n }\n function register(element, name = element.name, asRoot = false) {\n elements[name] = element;\n if (asRoot) elements[root] = element;\n addMethodNames(Object.getOwnPropertyNames(element.prototype));\n return element;\n }\n function getClass(name) {\n return elements[name];\n }\n\n // Element id sequence\n let did = 1000;\n\n // Get next named element id\n function eid(name) {\n return 'Svgjs' + capitalize(name) + did++;\n }\n\n // Deep new id assignment\n function assignNewId(node) {\n // do the same for SVG child nodes as well\n for (let i = node.children.length - 1; i >= 0; i--) {\n assignNewId(node.children[i]);\n }\n if (node.id) {\n node.id = eid(node.nodeName);\n return node;\n }\n return node;\n }\n\n // Method for extending objects\n function extend(modules, methods) {\n let key, i;\n modules = Array.isArray(modules) ? modules : [modules];\n for (i = modules.length - 1; i >= 0; i--) {\n for (key in methods) {\n modules[i].prototype[key] = methods[key];\n }\n }\n }\n function wrapWithAttrCheck(fn) {\n return function (...args) {\n const o = args[args.length - 1];\n if (o && o.constructor === Object && !(o instanceof Array)) {\n return fn.apply(this, args.slice(0, -1)).attr(o);\n } else {\n return fn.apply(this, args);\n }\n };\n }\n\n // Get all siblings, including myself\n function siblings() {\n return this.parent().children();\n }\n\n // Get the current position siblings\n function position() {\n return this.parent().index(this);\n }\n\n // Get the next element (will return null if there is none)\n function next() {\n return this.siblings()[this.position() + 1];\n }\n\n // Get the next element (will return null if there is none)\n function prev() {\n return this.siblings()[this.position() - 1];\n }\n\n // Send given element one step forward\n function forward() {\n const i = this.position();\n const p = this.parent();\n\n // move node one step forward\n p.add(this.remove(), i + 1);\n return this;\n }\n\n // Send given element one step backward\n function backward() {\n const i = this.position();\n const p = this.parent();\n p.add(this.remove(), i ? i - 1 : 0);\n return this;\n }\n\n // Send given element all the way to the front\n function front() {\n const p = this.parent();\n\n // Move node forward\n p.add(this.remove());\n return this;\n }\n\n // Send given element all the way to the back\n function back() {\n const p = this.parent();\n\n // Move node back\n p.add(this.remove(), 0);\n return this;\n }\n\n // Inserts a given element before the targeted element\n function before(element) {\n element = makeInstance(element);\n element.remove();\n const i = this.position();\n this.parent().add(element, i);\n return this;\n }\n\n // Inserts a given element after the targeted element\n function after(element) {\n element = makeInstance(element);\n element.remove();\n const i = this.position();\n this.parent().add(element, i + 1);\n return this;\n }\n function insertBefore(element) {\n element = makeInstance(element);\n element.before(this);\n return this;\n }\n function insertAfter(element) {\n element = makeInstance(element);\n element.after(this);\n return this;\n }\n registerMethods('Dom', {\n siblings,\n position,\n next,\n prev,\n forward,\n backward,\n front,\n back,\n before,\n after,\n insertBefore,\n insertAfter\n });\n\n // Parse unit value\n const numberAndUnit = /^([+-]?(\\d+(\\.\\d*)?|\\.\\d+)(e[+-]?\\d+)?)([a-z%]*)$/i;\n\n // Parse hex value\n const hex = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i;\n\n // Parse rgb value\n const rgb = /rgb\\((\\d+),(\\d+),(\\d+)\\)/;\n\n // Parse reference id\n const reference = /(#[a-z_][a-z0-9\\-_]*)/i;\n\n // splits a transformation chain\n const transforms = /\\)\\s*,?\\s*/;\n\n // Whitespace\n const whitespace = /\\s/g;\n\n // Test hex value\n const isHex = /^#[a-f0-9]{3}$|^#[a-f0-9]{6}$/i;\n\n // Test rgb value\n const isRgb = /^rgb\\(/;\n\n // Test for blank string\n const isBlank = /^(\\s+)?$/;\n\n // Test for numeric string\n const isNumber = /^[+-]?(\\d+(\\.\\d*)?|\\.\\d+)(e[+-]?\\d+)?$/i;\n\n // Test for image url\n const isImage = /\\.(jpg|jpeg|png|gif|svg)(\\?[^=]+.*)?/i;\n\n // split at whitespace and comma\n const delimiter = /[\\s,]+/;\n\n // Test for path letter\n const isPathLetter = /[MLHVCSQTAZ]/i;\n\n var regex = {\n __proto__: null,\n delimiter: delimiter,\n hex: hex,\n isBlank: isBlank,\n isHex: isHex,\n isImage: isImage,\n isNumber: isNumber,\n isPathLetter: isPathLetter,\n isRgb: isRgb,\n numberAndUnit: numberAndUnit,\n reference: reference,\n rgb: rgb,\n transforms: transforms,\n whitespace: whitespace\n };\n\n // Return array of classes on the node\n function classes() {\n const attr = this.attr('class');\n return attr == null ? [] : attr.trim().split(delimiter);\n }\n\n // Return true if class exists on the node, false otherwise\n function hasClass(name) {\n return this.classes().indexOf(name) !== -1;\n }\n\n // Add class to the node\n function addClass(name) {\n if (!this.hasClass(name)) {\n const array = this.classes();\n array.push(name);\n this.attr('class', array.join(' '));\n }\n return this;\n }\n\n // Remove class from the node\n function removeClass(name) {\n if (this.hasClass(name)) {\n this.attr('class', this.classes().filter(function (c) {\n return c !== name;\n }).join(' '));\n }\n return this;\n }\n\n // Toggle the presence of a class on the node\n function toggleClass(name) {\n return this.hasClass(name) ? this.removeClass(name) : this.addClass(name);\n }\n registerMethods('Dom', {\n classes,\n hasClass,\n addClass,\n removeClass,\n toggleClass\n });\n\n // Dynamic style generator\n function css(style, val) {\n const ret = {};\n if (arguments.length === 0) {\n // get full style as object\n this.node.style.cssText.split(/\\s*;\\s*/).filter(function (el) {\n return !!el.length;\n }).forEach(function (el) {\n const t = el.split(/\\s*:\\s*/);\n ret[t[0]] = t[1];\n });\n return ret;\n }\n if (arguments.length < 2) {\n // get style properties as array\n if (Array.isArray(style)) {\n for (const name of style) {\n const cased = name;\n ret[name] = this.node.style.getPropertyValue(cased);\n }\n return ret;\n }\n\n // get style for property\n if (typeof style === 'string') {\n return this.node.style.getPropertyValue(style);\n }\n\n // set styles in object\n if (typeof style === 'object') {\n for (const name in style) {\n // set empty string if null/undefined/'' was given\n this.node.style.setProperty(name, style[name] == null || isBlank.test(style[name]) ? '' : style[name]);\n }\n }\n }\n\n // set style for property\n if (arguments.length === 2) {\n this.node.style.setProperty(style, val == null || isBlank.test(val) ? '' : val);\n }\n return this;\n }\n\n // Show element\n function show() {\n return this.css('display', '');\n }\n\n // Hide element\n function hide() {\n return this.css('display', 'none');\n }\n\n // Is element visible?\n function visible() {\n return this.css('display') !== 'none';\n }\n registerMethods('Dom', {\n css,\n show,\n hide,\n visible\n });\n\n // Store data values on svg nodes\n function data(a, v, r) {\n if (a == null) {\n // get an object of attributes\n return this.data(map(filter(this.node.attributes, el => el.nodeName.indexOf('data-') === 0), el => el.nodeName.slice(5)));\n } else if (a instanceof Array) {\n const data = {};\n for (const key of a) {\n data[key] = this.data(key);\n }\n return data;\n } else if (typeof a === 'object') {\n for (v in a) {\n this.data(v, a[v]);\n }\n } else if (arguments.length < 2) {\n try {\n return JSON.parse(this.attr('data-' + a));\n } catch (e) {\n return this.attr('data-' + a);\n }\n } else {\n this.attr('data-' + a, v === null ? null : r === true || typeof v === 'string' || typeof v === 'number' ? v : JSON.stringify(v));\n }\n return this;\n }\n registerMethods('Dom', {\n data\n });\n\n // Remember arbitrary data\n function remember(k, v) {\n // remember every item in an object individually\n if (typeof arguments[0] === 'object') {\n for (const key in k) {\n this.remember(key, k[key]);\n }\n } else if (arguments.length === 1) {\n // retrieve memory\n return this.memory()[k];\n } else {\n // store memory\n this.memory()[k] = v;\n }\n return this;\n }\n\n // Erase a given memory\n function forget() {\n if (arguments.length === 0) {\n this._memory = {};\n } else {\n for (let i = arguments.length - 1; i >= 0; i--) {\n delete this.memory()[arguments[i]];\n }\n }\n return this;\n }\n\n // This triggers creation of a new hidden class which is not performant\n // However, this function is not rarely used so it will not happen frequently\n // Return local memory object\n function memory() {\n return this._memory = this._memory || {};\n }\n registerMethods('Dom', {\n remember,\n forget,\n memory\n });\n\n function sixDigitHex(hex) {\n return hex.length === 4 ? ['#', hex.substring(1, 2), hex.substring(1, 2), hex.substring(2, 3), hex.substring(2, 3), hex.substring(3, 4), hex.substring(3, 4)].join('') : hex;\n }\n function componentHex(component) {\n const integer = Math.round(component);\n const bounded = Math.max(0, Math.min(255, integer));\n const hex = bounded.toString(16);\n return hex.length === 1 ? '0' + hex : hex;\n }\n function is(object, space) {\n for (let i = space.length; i--;) {\n if (object[space[i]] == null) {\n return false;\n }\n }\n return true;\n }\n function getParameters(a, b) {\n const params = is(a, 'rgb') ? {\n _a: a.r,\n _b: a.g,\n _c: a.b,\n _d: 0,\n space: 'rgb'\n } : is(a, 'xyz') ? {\n _a: a.x,\n _b: a.y,\n _c: a.z,\n _d: 0,\n space: 'xyz'\n } : is(a, 'hsl') ? {\n _a: a.h,\n _b: a.s,\n _c: a.l,\n _d: 0,\n space: 'hsl'\n } : is(a, 'lab') ? {\n _a: a.l,\n _b: a.a,\n _c: a.b,\n _d: 0,\n space: 'lab'\n } : is(a, 'lch') ? {\n _a: a.l,\n _b: a.c,\n _c: a.h,\n _d: 0,\n space: 'lch'\n } : is(a, 'cmyk') ? {\n _a: a.c,\n _b: a.m,\n _c: a.y,\n _d: a.k,\n space: 'cmyk'\n } : {\n _a: 0,\n _b: 0,\n _c: 0,\n space: 'rgb'\n };\n params.space = b || params.space;\n return params;\n }\n function cieSpace(space) {\n if (space === 'lab' || space === 'xyz' || space === 'lch') {\n return true;\n } else {\n return false;\n }\n }\n function hueToRgb(p, q, t) {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n }\n class Color {\n constructor(...inputs) {\n this.init(...inputs);\n }\n\n // Test if given value is a color\n static isColor(color) {\n return color && (color instanceof Color || this.isRgb(color) || this.test(color));\n }\n\n // Test if given value is an rgb object\n static isRgb(color) {\n return color && typeof color.r === 'number' && typeof color.g === 'number' && typeof color.b === 'number';\n }\n\n /*\n Generating random colors\n */\n static random(mode = 'vibrant', t) {\n // Get the math modules\n const {\n random,\n round,\n sin,\n PI: pi\n } = Math;\n\n // Run the correct generator\n if (mode === 'vibrant') {\n const l = (81 - 57) * random() + 57;\n const c = (83 - 45) * random() + 45;\n const h = 360 * random();\n const color = new Color(l, c, h, 'lch');\n return color;\n } else if (mode === 'sine') {\n t = t == null ? random() : t;\n const r = round(80 * sin(2 * pi * t / 0.5 + 0.01) + 150);\n const g = round(50 * sin(2 * pi * t / 0.5 + 4.6) + 200);\n const b = round(100 * sin(2 * pi * t / 0.5 + 2.3) + 150);\n const color = new Color(r, g, b);\n return color;\n } else if (mode === 'pastel') {\n const l = (94 - 86) * random() + 86;\n const c = (26 - 9) * random() + 9;\n const h = 360 * random();\n const color = new Color(l, c, h, 'lch');\n return color;\n } else if (mode === 'dark') {\n const l = 10 + 10 * random();\n const c = (125 - 75) * random() + 86;\n const h = 360 * random();\n const color = new Color(l, c, h, 'lch');\n return color;\n } else if (mode === 'rgb') {\n const r = 255 * random();\n const g = 255 * random();\n const b = 255 * random();\n const color = new Color(r, g, b);\n return color;\n } else if (mode === 'lab') {\n const l = 100 * random();\n const a = 256 * random() - 128;\n const b = 256 * random() - 128;\n const color = new Color(l, a, b, 'lab');\n return color;\n } else if (mode === 'grey') {\n const grey = 255 * random();\n const color = new Color(grey, grey, grey);\n return color;\n } else {\n throw new Error('Unsupported random color mode');\n }\n }\n\n // Test if given value is a color string\n static test(color) {\n return typeof color === 'string' && (isHex.test(color) || isRgb.test(color));\n }\n cmyk() {\n // Get the rgb values for the current color\n const {\n _a,\n _b,\n _c\n } = this.rgb();\n const [r, g, b] = [_a, _b, _c].map(v => v / 255);\n\n // Get the cmyk values in an unbounded format\n const k = Math.min(1 - r, 1 - g, 1 - b);\n if (k === 1) {\n // Catch the black case\n return new Color(0, 0, 0, 1, 'cmyk');\n }\n const c = (1 - r - k) / (1 - k);\n const m = (1 - g - k) / (1 - k);\n const y = (1 - b - k) / (1 - k);\n\n // Construct the new color\n const color = new Color(c, m, y, k, 'cmyk');\n return color;\n }\n hsl() {\n // Get the rgb values\n const {\n _a,\n _b,\n _c\n } = this.rgb();\n const [r, g, b] = [_a, _b, _c].map(v => v / 255);\n\n // Find the maximum and minimum values to get the lightness\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const l = (max + min) / 2;\n\n // If the r, g, v values are identical then we are grey\n const isGrey = max === min;\n\n // Calculate the hue and saturation\n const delta = max - min;\n const s = isGrey ? 0 : l > 0.5 ? delta / (2 - max - min) : delta / (max + min);\n const h = isGrey ? 0 : max === r ? ((g - b) / delta + (g < b ? 6 : 0)) / 6 : max === g ? ((b - r) / delta + 2) / 6 : max === b ? ((r - g) / delta + 4) / 6 : 0;\n\n // Construct and return the new color\n const color = new Color(360 * h, 100 * s, 100 * l, 'hsl');\n return color;\n }\n init(a = 0, b = 0, c = 0, d = 0, space = 'rgb') {\n // This catches the case when a falsy value is passed like ''\n a = !a ? 0 : a;\n\n // Reset all values in case the init function is rerun with new color space\n if (this.space) {\n for (const component in this.space) {\n delete this[this.space[component]];\n }\n }\n if (typeof a === 'number') {\n // Allow for the case that we don't need d...\n space = typeof d === 'string' ? d : space;\n d = typeof d === 'string' ? 0 : d;\n\n // Assign the values straight to the color\n Object.assign(this, {\n _a: a,\n _b: b,\n _c: c,\n _d: d,\n space\n });\n // If the user gave us an array, make the color from it\n } else if (a instanceof Array) {\n this.space = b || (typeof a[3] === 'string' ? a[3] : a[4]) || 'rgb';\n Object.assign(this, {\n _a: a[0],\n _b: a[1],\n _c: a[2],\n _d: a[3] || 0\n });\n } else if (a instanceof Object) {\n // Set the object up and assign its values directly\n const values = getParameters(a, b);\n Object.assign(this, values);\n } else if (typeof a === 'string') {\n if (isRgb.test(a)) {\n const noWhitespace = a.replace(whitespace, '');\n const [_a, _b, _c] = rgb.exec(noWhitespace).slice(1, 4).map(v => parseInt(v));\n Object.assign(this, {\n _a,\n _b,\n _c,\n _d: 0,\n space: 'rgb'\n });\n } else if (isHex.test(a)) {\n const hexParse = v => parseInt(v, 16);\n const [, _a, _b, _c] = hex.exec(sixDigitHex(a)).map(hexParse);\n Object.assign(this, {\n _a,\n _b,\n _c,\n _d: 0,\n space: 'rgb'\n });\n } else throw Error(\"Unsupported string format, can't construct Color\");\n }\n\n // Now add the components as a convenience\n const {\n _a,\n _b,\n _c,\n _d\n } = this;\n const components = this.space === 'rgb' ? {\n r: _a,\n g: _b,\n b: _c\n } : this.space === 'xyz' ? {\n x: _a,\n y: _b,\n z: _c\n } : this.space === 'hsl' ? {\n h: _a,\n s: _b,\n l: _c\n } : this.space === 'lab' ? {\n l: _a,\n a: _b,\n b: _c\n } : this.space === 'lch' ? {\n l: _a,\n c: _b,\n h: _c\n } : this.space === 'cmyk' ? {\n c: _a,\n m: _b,\n y: _c,\n k: _d\n } : {};\n Object.assign(this, components);\n }\n lab() {\n // Get the xyz color\n const {\n x,\n y,\n z\n } = this.xyz();\n\n // Get the lab components\n const l = 116 * y - 16;\n const a = 500 * (x - y);\n const b = 200 * (y - z);\n\n // Construct and return a new color\n const color = new Color(l, a, b, 'lab');\n return color;\n }\n lch() {\n // Get the lab color directly\n const {\n l,\n a,\n b\n } = this.lab();\n\n // Get the chromaticity and the hue using polar coordinates\n const c = Math.sqrt(a ** 2 + b ** 2);\n let h = 180 * Math.atan2(b, a) / Math.PI;\n if (h < 0) {\n h *= -1;\n h = 360 - h;\n }\n\n // Make a new color and return it\n const color = new Color(l, c, h, 'lch');\n return color;\n }\n /*\n Conversion Methods\n */\n\n rgb() {\n if (this.space === 'rgb') {\n return this;\n } else if (cieSpace(this.space)) {\n // Convert to the xyz color space\n let {\n x,\n y,\n z\n } = this;\n if (this.space === 'lab' || this.space === 'lch') {\n // Get the values in the lab space\n let {\n l,\n a,\n b\n } = this;\n if (this.space === 'lch') {\n const {\n c,\n h\n } = this;\n const dToR = Math.PI / 180;\n a = c * Math.cos(dToR * h);\n b = c * Math.sin(dToR * h);\n }\n\n // Undo the nonlinear function\n const yL = (l + 16) / 116;\n const xL = a / 500 + yL;\n const zL = yL - b / 200;\n\n // Get the xyz values\n const ct = 16 / 116;\n const mx = 0.008856;\n const nm = 7.787;\n x = 0.95047 * (xL ** 3 > mx ? xL ** 3 : (xL - ct) / nm);\n y = 1.0 * (yL ** 3 > mx ? yL ** 3 : (yL - ct) / nm);\n z = 1.08883 * (zL ** 3 > mx ? zL ** 3 : (zL - ct) / nm);\n }\n\n // Convert xyz to unbounded rgb values\n const rU = x * 3.2406 + y * -1.5372 + z * -0.4986;\n const gU = x * -0.9689 + y * 1.8758 + z * 0.0415;\n const bU = x * 0.0557 + y * -0.204 + z * 1.057;\n\n // Convert the values to true rgb values\n const pow = Math.pow;\n const bd = 0.0031308;\n const r = rU > bd ? 1.055 * pow(rU, 1 / 2.4) - 0.055 : 12.92 * rU;\n const g = gU > bd ? 1.055 * pow(gU, 1 / 2.4) - 0.055 : 12.92 * gU;\n const b = bU > bd ? 1.055 * pow(bU, 1 / 2.4) - 0.055 : 12.92 * bU;\n\n // Make and return the color\n const color = new Color(255 * r, 255 * g, 255 * b);\n return color;\n } else if (this.space === 'hsl') {\n // https://bgrins.github.io/TinyColor/docs/tinycolor.html\n // Get the current hsl values\n let {\n h,\n s,\n l\n } = this;\n h /= 360;\n s /= 100;\n l /= 100;\n\n // If we are grey, then just make the color directly\n if (s === 0) {\n l *= 255;\n const color = new Color(l, l, l);\n return color;\n }\n\n // TODO I have no idea what this does :D If you figure it out, tell me!\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n\n // Get the rgb values\n const r = 255 * hueToRgb(p, q, h + 1 / 3);\n const g = 255 * hueToRgb(p, q, h);\n const b = 255 * hueToRgb(p, q, h - 1 / 3);\n\n // Make a new color\n const color = new Color(r, g, b);\n return color;\n } else if (this.space === 'cmyk') {\n // https://gist.github.com/felipesabino/5066336\n // Get the normalised cmyk values\n const {\n c,\n m,\n y,\n k\n } = this;\n\n // Get the rgb values\n const r = 255 * (1 - Math.min(1, c * (1 - k) + k));\n const g = 255 * (1 - Math.min(1, m * (1 - k) + k));\n const b = 255 * (1 - Math.min(1, y * (1 - k) + k));\n\n // Form the color and return it\n const color = new Color(r, g, b);\n return color;\n } else {\n return this;\n }\n }\n toArray() {\n const {\n _a,\n _b,\n _c,\n _d,\n space\n } = this;\n return [_a, _b, _c, _d, space];\n }\n toHex() {\n const [r, g, b] = this._clamped().map(componentHex);\n return `#${r}${g}${b}`;\n }\n toRgb() {\n const [rV, gV, bV] = this._clamped();\n const string = `rgb(${rV},${gV},${bV})`;\n return string;\n }\n toString() {\n return this.toHex();\n }\n xyz() {\n // Normalise the red, green and blue values\n const {\n _a: r255,\n _b: g255,\n _c: b255\n } = this.rgb();\n const [r, g, b] = [r255, g255, b255].map(v => v / 255);\n\n // Convert to the lab rgb space\n const rL = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;\n const gL = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;\n const bL = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;\n\n // Convert to the xyz color space without bounding the values\n const xU = (rL * 0.4124 + gL * 0.3576 + bL * 0.1805) / 0.95047;\n const yU = (rL * 0.2126 + gL * 0.7152 + bL * 0.0722) / 1.0;\n const zU = (rL * 0.0193 + gL * 0.1192 + bL * 0.9505) / 1.08883;\n\n // Get the proper xyz values by applying the bounding\n const x = xU > 0.008856 ? Math.pow(xU, 1 / 3) : 7.787 * xU + 16 / 116;\n const y = yU > 0.008856 ? Math.pow(yU, 1 / 3) : 7.787 * yU + 16 / 116;\n const z = zU > 0.008856 ? Math.pow(zU, 1 / 3) : 7.787 * zU + 16 / 116;\n\n // Make and return the color\n const color = new Color(x, y, z, 'xyz');\n return color;\n }\n\n /*\n Input and Output methods\n */\n\n _clamped() {\n const {\n _a,\n _b,\n _c\n } = this.rgb();\n const {\n max,\n min,\n round\n } = Math;\n const format = v => max(0, min(round(v), 255));\n return [_a, _b, _c].map(format);\n }\n\n /*\n Constructing colors\n */\n }\n\n class Point {\n // Initialize\n constructor(...args) {\n this.init(...args);\n }\n\n // Clone point\n clone() {\n return new Point(this);\n }\n init(x, y) {\n const base = {\n x: 0,\n y: 0\n };\n\n // ensure source as object\n const source = Array.isArray(x) ? {\n x: x[0],\n y: x[1]\n } : typeof x === 'object' ? {\n x: x.x,\n y: x.y\n } : {\n x: x,\n y: y\n };\n\n // merge source\n this.x = source.x == null ? base.x : source.x;\n this.y = source.y == null ? base.y : source.y;\n return this;\n }\n toArray() {\n return [this.x, this.y];\n }\n transform(m) {\n return this.clone().transformO(m);\n }\n\n // Transform point with matrix\n transformO(m) {\n if (!Matrix.isMatrixLike(m)) {\n m = new Matrix(m);\n }\n const {\n x,\n y\n } = this;\n\n // Perform the matrix multiplication\n this.x = m.a * x + m.c * y + m.e;\n this.y = m.b * x + m.d * y + m.f;\n return this;\n }\n }\n function point(x, y) {\n return new Point(x, y).transformO(this.screenCTM().inverseO());\n }\n\n function closeEnough(a, b, threshold) {\n return Math.abs(b - a) < (1e-6);\n }\n class Matrix {\n constructor(...args) {\n this.init(...args);\n }\n static formatTransforms(o) {\n // Get all of the parameters required to form the matrix\n const flipBoth = o.flip === 'both' || o.flip === true;\n const flipX = o.flip && (flipBoth || o.flip === 'x') ? -1 : 1;\n const flipY = o.flip && (flipBoth || o.flip === 'y') ? -1 : 1;\n const skewX = o.skew && o.skew.length ? o.skew[0] : isFinite(o.skew) ? o.skew : isFinite(o.skewX) ? o.skewX : 0;\n const skewY = o.skew && o.skew.length ? o.skew[1] : isFinite(o.skew) ? o.skew : isFinite(o.skewY) ? o.skewY : 0;\n const scaleX = o.scale && o.scale.length ? o.scale[0] * flipX : isFinite(o.scale) ? o.scale * flipX : isFinite(o.scaleX) ? o.scaleX * flipX : flipX;\n const scaleY = o.scale && o.scale.length ? o.scale[1] * flipY : isFinite(o.scale) ? o.scale * flipY : isFinite(o.scaleY) ? o.scaleY * flipY : flipY;\n const shear = o.shear || 0;\n const theta = o.rotate || o.theta || 0;\n const origin = new Point(o.origin || o.around || o.ox || o.originX, o.oy || o.originY);\n const ox = origin.x;\n const oy = origin.y;\n // We need Point to be invalid if nothing was passed because we cannot default to 0 here. That is why NaN\n const position = new Point(o.position || o.px || o.positionX || NaN, o.py || o.positionY || NaN);\n const px = position.x;\n const py = position.y;\n const translate = new Point(o.translate || o.tx || o.translateX, o.ty || o.translateY);\n const tx = translate.x;\n const ty = translate.y;\n const relative = new Point(o.relative || o.rx || o.relativeX, o.ry || o.relativeY);\n const rx = relative.x;\n const ry = relative.y;\n\n // Populate all of the values\n return {\n scaleX,\n scaleY,\n skewX,\n skewY,\n shear,\n theta,\n rx,\n ry,\n tx,\n ty,\n ox,\n oy,\n px,\n py\n };\n }\n static fromArray(a) {\n return {\n a: a[0],\n b: a[1],\n c: a[2],\n d: a[3],\n e: a[4],\n f: a[5]\n };\n }\n static isMatrixLike(o) {\n return o.a != null || o.b != null || o.c != null || o.d != null || o.e != null || o.f != null;\n }\n\n // left matrix, right matrix, target matrix which is overwritten\n static matrixMultiply(l, r, o) {\n // Work out the product directly\n const a = l.a * r.a + l.c * r.b;\n const b = l.b * r.a + l.d * r.b;\n const c = l.a * r.c + l.c * r.d;\n const d = l.b * r.c + l.d * r.d;\n const e = l.e + l.a * r.e + l.c * r.f;\n const f = l.f + l.b * r.e + l.d * r.f;\n\n // make sure to use local variables because l/r and o could be the same\n o.a = a;\n o.b = b;\n o.c = c;\n o.d = d;\n o.e = e;\n o.f = f;\n return o;\n }\n around(cx, cy, matrix) {\n return this.clone().aroundO(cx, cy, matrix);\n }\n\n // Transform around a center point\n aroundO(cx, cy, matrix) {\n const dx = cx || 0;\n const dy = cy || 0;\n return this.translateO(-dx, -dy).lmultiplyO(matrix).translateO(dx, dy);\n }\n\n // Clones this matrix\n clone() {\n return new Matrix(this);\n }\n\n // Decomposes this matrix into its affine parameters\n decompose(cx = 0, cy = 0) {\n // Get the parameters from the matrix\n const a = this.a;\n const b = this.b;\n const c = this.c;\n const d = this.d;\n const e = this.e;\n const f = this.f;\n\n // Figure out if the winding direction is clockwise or counterclockwise\n const determinant = a * d - b * c;\n const ccw = determinant > 0 ? 1 : -1;\n\n // Since we only shear in x, we can use the x basis to get the x scale\n // and the rotation of the resulting matrix\n const sx = ccw * Math.sqrt(a * a + b * b);\n const thetaRad = Math.atan2(ccw * b, ccw * a);\n const theta = 180 / Math.PI * thetaRad;\n const ct = Math.cos(thetaRad);\n const st = Math.sin(thetaRad);\n\n // We can then solve the y basis vector simultaneously to get the other\n // two affine parameters directly from these parameters\n const lam = (a * c + b * d) / determinant;\n const sy = c * sx / (lam * a - b) || d * sx / (lam * b + a);\n\n // Use the translations\n const tx = e - cx + cx * ct * sx + cy * (lam * ct * sx - st * sy);\n const ty = f - cy + cx * st * sx + cy * (lam * st * sx + ct * sy);\n\n // Construct the decomposition and return it\n return {\n // Return the affine parameters\n scaleX: sx,\n scaleY: sy,\n shear: lam,\n rotate: theta,\n translateX: tx,\n translateY: ty,\n originX: cx,\n originY: cy,\n // Return the matrix parameters\n a: this.a,\n b: this.b,\n c: this.c,\n d: this.d,\n e: this.e,\n f: this.f\n };\n }\n\n // Check if two matrices are equal\n equals(other) {\n if (other === this) return true;\n const comp = new Matrix(other);\n return closeEnough(this.a, comp.a) && closeEnough(this.b, comp.b) && closeEnough(this.c, comp.c) && closeEnough(this.d, comp.d) && closeEnough(this.e, comp.e) && closeEnough(this.f, comp.f);\n }\n\n // Flip matrix on x or y, at a given offset\n flip(axis, around) {\n return this.clone().flipO(axis, around);\n }\n flipO(axis, around) {\n return axis === 'x' ? this.scaleO(-1, 1, around, 0) : axis === 'y' ? this.scaleO(1, -1, 0, around) : this.scaleO(-1, -1, axis, around || axis); // Define an x, y flip point\n }\n\n // Initialize\n init(source) {\n const base = Matrix.fromArray([1, 0, 0, 1, 0, 0]);\n\n // ensure source as object\n source = source instanceof Element ? source.matrixify() : typeof source === 'string' ? Matrix.fromArray(source.split(delimiter).map(parseFloat)) : Array.isArray(source) ? Matrix.fromArray(source) : typeof source === 'object' && Matrix.isMatrixLike(source) ? source : typeof source === 'object' ? new Matrix().transform(source) : arguments.length === 6 ? Matrix.fromArray([].slice.call(arguments)) : base;\n\n // Merge the source matrix with the base matrix\n this.a = source.a != null ? source.a : base.a;\n this.b = source.b != null ? source.b : base.b;\n this.c = source.c != null ? source.c : base.c;\n this.d = source.d != null ? source.d : base.d;\n this.e = source.e != null ? source.e : base.e;\n this.f = source.f != null ? source.f : base.f;\n return this;\n }\n inverse() {\n return this.clone().inverseO();\n }\n\n // Inverses matrix\n inverseO() {\n // Get the current parameters out of the matrix\n const a = this.a;\n const b = this.b;\n const c = this.c;\n const d = this.d;\n const e = this.e;\n const f = this.f;\n\n // Invert the 2x2 matrix in the top left\n const det = a * d - b * c;\n if (!det) throw new Error('Cannot invert ' + this);\n\n // Calculate the top 2x2 matrix\n const na = d / det;\n const nb = -b / det;\n const nc = -c / det;\n const nd = a / det;\n\n // Apply the inverted matrix to the top right\n const ne = -(na * e + nc * f);\n const nf = -(nb * e + nd * f);\n\n // Construct the inverted matrix\n this.a = na;\n this.b = nb;\n this.c = nc;\n this.d = nd;\n this.e = ne;\n this.f = nf;\n return this;\n }\n lmultiply(matrix) {\n return this.clone().lmultiplyO(matrix);\n }\n lmultiplyO(matrix) {\n const r = this;\n const l = matrix instanceof Matrix ? matrix : new Matrix(matrix);\n return Matrix.matrixMultiply(l, r, this);\n }\n\n // Left multiplies by the given matrix\n multiply(matrix) {\n return this.clone().multiplyO(matrix);\n }\n multiplyO(matrix) {\n // Get the matrices\n const l = this;\n const r = matrix instanceof Matrix ? matrix : new Matrix(matrix);\n return Matrix.matrixMultiply(l, r, this);\n }\n\n // Rotate matrix\n rotate(r, cx, cy) {\n return this.clone().rotateO(r, cx, cy);\n }\n rotateO(r, cx = 0, cy = 0) {\n // Convert degrees to radians\n r = radians(r);\n const cos = Math.cos(r);\n const sin = Math.sin(r);\n const {\n a,\n b,\n c,\n d,\n e,\n f\n } = this;\n this.a = a * cos - b * sin;\n this.b = b * cos + a * sin;\n this.c = c * cos - d * sin;\n this.d = d * cos + c * sin;\n this.e = e * cos - f * sin + cy * sin - cx * cos + cx;\n this.f = f * cos + e * sin - cx * sin - cy * cos + cy;\n return this;\n }\n\n // Scale matrix\n scale() {\n return this.clone().scaleO(...arguments);\n }\n scaleO(x, y = x, cx = 0, cy = 0) {\n // Support uniform scaling\n if (arguments.length === 3) {\n cy = cx;\n cx = y;\n y = x;\n }\n const {\n a,\n b,\n c,\n d,\n e,\n f\n } = this;\n this.a = a * x;\n this.b = b * y;\n this.c = c * x;\n this.d = d * y;\n this.e = e * x - cx * x + cx;\n this.f = f * y - cy * y + cy;\n return this;\n }\n\n // Shear matrix\n shear(a, cx, cy) {\n return this.clone().shearO(a, cx, cy);\n }\n\n // eslint-disable-next-line no-unused-vars\n shearO(lx, cx = 0, cy = 0) {\n const {\n a,\n b,\n c,\n d,\n e,\n f\n } = this;\n this.a = a + b * lx;\n this.c = c + d * lx;\n this.e = e + f * lx - cy * lx;\n return this;\n }\n\n // Skew Matrix\n skew() {\n return this.clone().skewO(...arguments);\n }\n skewO(x, y = x, cx = 0, cy = 0) {\n // support uniformal skew\n if (arguments.length === 3) {\n cy = cx;\n cx = y;\n y = x;\n }\n\n // Convert degrees to radians\n x = radians(x);\n y = radians(y);\n const lx = Math.tan(x);\n const ly = Math.tan(y);\n const {\n a,\n b,\n c,\n d,\n e,\n f\n } = this;\n this.a = a + b * lx;\n this.b = b + a * ly;\n this.c = c + d * lx;\n this.d = d + c * ly;\n this.e = e + f * lx - cy * lx;\n this.f = f + e * ly - cx * ly;\n return this;\n }\n\n // SkewX\n skewX(x, cx, cy) {\n return this.skew(x, 0, cx, cy);\n }\n\n // SkewY\n skewY(y, cx, cy) {\n return this.skew(0, y, cx, cy);\n }\n toArray() {\n return [this.a, this.b, this.c, this.d, this.e, this.f];\n }\n\n // Convert matrix to string\n toString() {\n return 'matrix(' + this.a + ',' + this.b + ',' + this.c + ',' + this.d + ',' + this.e + ',' + this.f + ')';\n }\n\n // Transform a matrix into another matrix by manipulating the space\n transform(o) {\n // Check if o is a matrix and then left multiply it directly\n if (Matrix.isMatrixLike(o)) {\n const matrix = new Matrix(o);\n return matrix.multiplyO(this);\n }\n\n // Get the proposed transformations and the current transformations\n const t = Matrix.formatTransforms(o);\n const current = this;\n const {\n x: ox,\n y: oy\n } = new Point(t.ox, t.oy).transform(current);\n\n // Construct the resulting matrix\n const transformer = new Matrix().translateO(t.rx, t.ry).lmultiplyO(current).translateO(-ox, -oy).scaleO(t.scaleX, t.scaleY).skewO(t.skewX, t.skewY).shearO(t.shear).rotateO(t.theta).translateO(ox, oy);\n\n // If we want the origin at a particular place, we force it there\n if (isFinite(t.px) || isFinite(t.py)) {\n const origin = new Point(ox, oy).transform(transformer);\n // TODO: Replace t.px with isFinite(t.px)\n // Doesn't work because t.px is also 0 if it wasn't passed\n const dx = isFinite(t.px) ? t.px - origin.x : 0;\n const dy = isFinite(t.py) ? t.py - origin.y : 0;\n transformer.translateO(dx, dy);\n }\n\n // Translate now after positioning\n transformer.translateO(t.tx, t.ty);\n return transformer;\n }\n\n // Translate matrix\n translate(x, y) {\n return this.clone().translateO(x, y);\n }\n translateO(x, y) {\n this.e += x || 0;\n this.f += y || 0;\n return this;\n }\n valueOf() {\n return {\n a: this.a,\n b: this.b,\n c: this.c,\n d: this.d,\n e: this.e,\n f: this.f\n };\n }\n }\n function ctm() {\n return new Matrix(this.node.getCTM());\n }\n function screenCTM() {\n try {\n /* https://bugzilla.mozilla.org/show_bug.cgi?id=1344537\n This is needed because FF does not return the transformation matrix\n for the inner coordinate system when getScreenCTM() is called on nested svgs.\n However all other Browsers do that */\n if (typeof this.isRoot === 'function' && !this.isRoot()) {\n const rect = this.rect(1, 1);\n const m = rect.node.getScreenCTM();\n rect.remove();\n return new Matrix(m);\n }\n return new Matrix(this.node.getScreenCTM());\n } catch (e) {\n console.warn(`Cannot get CTM from SVG node ${this.node.nodeName}. Is the element rendered?`);\n return new Matrix();\n }\n }\n register(Matrix, 'Matrix');\n\n function parser() {\n // Reuse cached element if possible\n if (!parser.nodes) {\n const svg = makeInstance().size(2, 0);\n svg.node.style.cssText = ['opacity: 0', 'position: absolute', 'left: -100%', 'top: -100%', 'overflow: hidden'].join(';');\n svg.attr('focusable', 'false');\n svg.attr('aria-hidden', 'true');\n const path = svg.path().node;\n parser.nodes = {\n svg,\n path\n };\n }\n if (!parser.nodes.svg.node.parentNode) {\n const b = globals.document.body || globals.document.documentElement;\n parser.nodes.svg.addTo(b);\n }\n return parser.nodes;\n }\n\n function isNulledBox(box) {\n return !box.width && !box.height && !box.x && !box.y;\n }\n function domContains(node) {\n return node === globals.document || (globals.document.documentElement.contains || function (node) {\n // This is IE - it does not support contains() for top-level SVGs\n while (node.parentNode) {\n node = node.parentNode;\n }\n return node === globals.document;\n }).call(globals.document.documentElement, node);\n }\n class Box {\n constructor(...args) {\n this.init(...args);\n }\n addOffset() {\n // offset by window scroll position, because getBoundingClientRect changes when window is scrolled\n this.x += globals.window.pageXOffset;\n this.y += globals.window.pageYOffset;\n return new Box(this);\n }\n init(source) {\n const base = [0, 0, 0, 0];\n source = typeof source === 'string' ? source.split(delimiter).map(parseFloat) : Array.isArray(source) ? source : typeof source === 'object' ? [source.left != null ? source.left : source.x, source.top != null ? source.top : source.y, source.width, source.height] : arguments.length === 4 ? [].slice.call(arguments) : base;\n this.x = source[0] || 0;\n this.y = source[1] || 0;\n this.width = this.w = source[2] || 0;\n this.height = this.h = source[3] || 0;\n\n // Add more bounding box properties\n this.x2 = this.x + this.w;\n this.y2 = this.y + this.h;\n this.cx = this.x + this.w / 2;\n this.cy = this.y + this.h / 2;\n return this;\n }\n isNulled() {\n return isNulledBox(this);\n }\n\n // Merge rect box with another, return a new instance\n merge(box) {\n const x = Math.min(this.x, box.x);\n const y = Math.min(this.y, box.y);\n const width = Math.max(this.x + this.width, box.x + box.width) - x;\n const height = Math.max(this.y + this.height, box.y + box.height) - y;\n return new Box(x, y, width, height);\n }\n toArray() {\n return [this.x, this.y, this.width, this.height];\n }\n toString() {\n return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height;\n }\n transform(m) {\n if (!(m instanceof Matrix)) {\n m = new Matrix(m);\n }\n let xMin = Infinity;\n let xMax = -Infinity;\n let yMin = Infinity;\n let yMax = -Infinity;\n const pts = [new Point(this.x, this.y), new Point(this.x2, this.y), new Point(this.x, this.y2), new Point(this.x2, this.y2)];\n pts.forEach(function (p) {\n p = p.transform(m);\n xMin = Math.min(xMin, p.x);\n xMax = Math.max(xMax, p.x);\n yMin = Math.min(yMin, p.y);\n yMax = Math.max(yMax, p.y);\n });\n return new Box(xMin, yMin, xMax - xMin, yMax - yMin);\n }\n }\n function getBox(el, getBBoxFn, retry) {\n let box;\n try {\n // Try to get the box with the provided function\n box = getBBoxFn(el.node);\n\n // If the box is worthless and not even in the dom, retry\n // by throwing an error here...\n if (isNulledBox(box) && !domContains(el.node)) {\n throw new Error('Element not in the dom');\n }\n } catch (e) {\n // ... and calling the retry handler here\n box = retry(el);\n }\n return box;\n }\n function bbox() {\n // Function to get bbox is getBBox()\n const getBBox = node => node.getBBox();\n\n // Take all measures so that a stupid browser renders the element\n // so we can get the bbox from it when we try again\n const retry = el => {\n try {\n const clone = el.clone().addTo(parser().svg).show();\n const box = clone.node.getBBox();\n clone.remove();\n return box;\n } catch (e) {\n // We give up...\n throw new Error(`Getting bbox of element \"${el.node.nodeName}\" is not possible: ${e.toString()}`);\n }\n };\n const box = getBox(this, getBBox, retry);\n const bbox = new Box(box);\n return bbox;\n }\n function rbox(el) {\n const getRBox = node => node.getBoundingClientRect();\n const retry = el => {\n // There is no point in trying tricks here because if we insert the element into the dom ourselves\n // it obviously will be at the wrong position\n throw new Error(`Getting rbox of element \"${el.node.nodeName}\" is not possible`);\n };\n const box = getBox(this, getRBox, retry);\n const rbox = new Box(box);\n\n // If an element was passed, we want the bbox in the coordinate system of that element\n if (el) {\n return rbox.transform(el.screenCTM().inverseO());\n }\n\n // Else we want it in absolute screen coordinates\n // Therefore we need to add the scrollOffset\n return rbox.addOffset();\n }\n\n // Checks whether the given point is inside the bounding box\n function inside(x, y) {\n const box = this.bbox();\n return x > box.x && y > box.y && x < box.x + box.width && y < box.y + box.height;\n }\n registerMethods({\n viewbox: {\n viewbox(x, y, width, height) {\n // act as getter\n if (x == null) return new Box(this.attr('viewBox'));\n\n // act as setter\n return this.attr('viewBox', new Box(x, y, width, height));\n },\n zoom(level, point) {\n // Its best to rely on the attributes here and here is why:\n // clientXYZ: Doesn't work on non-root svgs because they dont have a CSSBox (silly!)\n // getBoundingClientRect: Doesn't work because Chrome just ignores width and height of nested svgs completely\n // that means, their clientRect is always as big as the content.\n // Furthermore this size is incorrect if the element is further transformed by its parents\n // computedStyle: Only returns meaningful values if css was used with px. We dont go this route here!\n // getBBox: returns the bounding box of its content - that doesn't help!\n let {\n width,\n height\n } = this.attr(['width', 'height']);\n\n // Width and height is a string when a number with a unit is present which we can't use\n // So we try clientXYZ\n if (!width && !height || typeof width === 'string' || typeof height === 'string') {\n width = this.node.clientWidth;\n height = this.node.clientHeight;\n }\n\n // Giving up...\n if (!width || !height) {\n throw new Error('Impossible to get absolute width and height. Please provide an absolute width and height attribute on the zooming element');\n }\n const v = this.viewbox();\n const zoomX = width / v.width;\n const zoomY = height / v.height;\n const zoom = Math.min(zoomX, zoomY);\n if (level == null) {\n return zoom;\n }\n let zoomAmount = zoom / level;\n\n // Set the zoomAmount to the highest value which is safe to process and recover from\n // The * 100 is a bit of wiggle room for the matrix transformation\n if (zoomAmount === Infinity) zoomAmount = Number.MAX_SAFE_INTEGER / 100;\n point = point || new Point(width / 2 / zoomX + v.x, height / 2 / zoomY + v.y);\n const box = new Box(v).transform(new Matrix({\n scale: zoomAmount,\n origin: point\n }));\n return this.viewbox(box);\n }\n }\n });\n register(Box, 'Box');\n\n // import { subClassArray } from './ArrayPolyfill.js'\n\n class List extends Array {\n constructor(arr = [], ...args) {\n super(arr, ...args);\n if (typeof arr === 'number') return this;\n this.length = 0;\n this.push(...arr);\n }\n }\n extend([List], {\n each(fnOrMethodName, ...args) {\n if (typeof fnOrMethodName === 'function') {\n return this.map((el, i, arr) => {\n return fnOrMethodName.call(el, el, i, arr);\n });\n } else {\n return this.map(el => {\n return el[fnOrMethodName](...args);\n });\n }\n },\n toArray() {\n return Array.prototype.concat.apply([], this);\n }\n });\n const reserved = ['toArray', 'constructor', 'each'];\n List.extend = function (methods) {\n methods = methods.reduce((obj, name) => {\n // Don't overwrite own methods\n if (reserved.includes(name)) return obj;\n\n // Don't add private methods\n if (name[0] === '_') return obj;\n\n // Allow access to original Array methods through a prefix\n if (name in Array.prototype) {\n obj['$' + name] = Array.prototype[name];\n }\n\n // Relay every call to each()\n obj[name] = function (...attrs) {\n return this.each(name, ...attrs);\n };\n return obj;\n }, {});\n extend([List], methods);\n };\n\n function baseFind(query, parent) {\n return new List(map((parent || globals.document).querySelectorAll(query), function (node) {\n return adopt(node);\n }));\n }\n\n // Scoped find method\n function find(query) {\n return baseFind(query, this.node);\n }\n function findOne(query) {\n return adopt(this.node.querySelector(query));\n }\n\n let listenerId = 0;\n const windowEvents = {};\n function getEvents(instance) {\n let n = instance.getEventHolder();\n\n // We dont want to save events in global space\n if (n === globals.window) n = windowEvents;\n if (!n.events) n.events = {};\n return n.events;\n }\n function getEventTarget(instance) {\n return instance.getEventTarget();\n }\n function clearEvents(instance) {\n let n = instance.getEventHolder();\n if (n === globals.window) n = windowEvents;\n if (n.events) n.events = {};\n }\n\n // Add event binder in the SVG namespace\n function on(node, events, listener, binding, options) {\n const l = listener.bind(binding || node);\n const instance = makeInstance(node);\n const bag = getEvents(instance);\n const n = getEventTarget(instance);\n\n // events can be an array of events or a string of events\n events = Array.isArray(events) ? events : events.split(delimiter);\n\n // add id to listener\n if (!listener._svgjsListenerId) {\n listener._svgjsListenerId = ++listenerId;\n }\n events.forEach(function (event) {\n const ev = event.split('.')[0];\n const ns = event.split('.')[1] || '*';\n\n // ensure valid object\n bag[ev] = bag[ev] || {};\n bag[ev][ns] = bag[ev][ns] || {};\n\n // reference listener\n bag[ev][ns][listener._svgjsListenerId] = l;\n\n // add listener\n n.addEventListener(ev, l, options || false);\n });\n }\n\n // Add event unbinder in the SVG namespace\n function off(node, events, listener, options) {\n const instance = makeInstance(node);\n const bag = getEvents(instance);\n const n = getEventTarget(instance);\n\n // listener can be a function or a number\n if (typeof listener === 'function') {\n listener = listener._svgjsListenerId;\n if (!listener) return;\n }\n\n // events can be an array of events or a string or undefined\n events = Array.isArray(events) ? events : (events || '').split(delimiter);\n events.forEach(function (event) {\n const ev = event && event.split('.')[0];\n const ns = event && event.split('.')[1];\n let namespace, l;\n if (listener) {\n // remove listener reference\n if (bag[ev] && bag[ev][ns || '*']) {\n // removeListener\n n.removeEventListener(ev, bag[ev][ns || '*'][listener], options || false);\n delete bag[ev][ns || '*'][listener];\n }\n } else if (ev && ns) {\n // remove all listeners for a namespaced event\n if (bag[ev] && bag[ev][ns]) {\n for (l in bag[ev][ns]) {\n off(n, [ev, ns].join('.'), l);\n }\n delete bag[ev][ns];\n }\n } else if (ns) {\n // remove all listeners for a specific namespace\n for (event in bag) {\n for (namespace in bag[event]) {\n if (ns === namespace) {\n off(n, [event, ns].join('.'));\n }\n }\n }\n } else if (ev) {\n // remove all listeners for the event\n if (bag[ev]) {\n for (namespace in bag[ev]) {\n off(n, [ev, namespace].join('.'));\n }\n delete bag[ev];\n }\n } else {\n // remove all listeners on a given node\n for (event in bag) {\n off(n, event);\n }\n clearEvents(instance);\n }\n });\n }\n function dispatch(node, event, data, options) {\n const n = getEventTarget(node);\n\n // Dispatch event\n if (event instanceof globals.window.Event) {\n n.dispatchEvent(event);\n } else {\n event = new globals.window.CustomEvent(event, {\n detail: data,\n cancelable: true,\n ...options\n });\n n.dispatchEvent(event);\n }\n return event;\n }\n\n class EventTarget extends Base {\n addEventListener() {}\n dispatch(event, data, options) {\n return dispatch(this, event, data, options);\n }\n dispatchEvent(event) {\n const bag = this.getEventHolder().events;\n if (!bag) return true;\n const events = bag[event.type];\n for (const i in events) {\n for (const j in events[i]) {\n events[i][j](event);\n }\n }\n return !event.defaultPrevented;\n }\n\n // Fire given event\n fire(event, data, options) {\n this.dispatch(event, data, options);\n return this;\n }\n getEventHolder() {\n return this;\n }\n getEventTarget() {\n return this;\n }\n\n // Unbind event from listener\n off(event, listener, options) {\n off(this, event, listener, options);\n return this;\n }\n\n // Bind given event to listener\n on(event, listener, binding, options) {\n on(this, event, listener, binding, options);\n return this;\n }\n removeEventListener() {}\n }\n register(EventTarget, 'EventTarget');\n\n function noop() {}\n\n // Default animation values\n const timeline = {\n duration: 400,\n ease: '>',\n delay: 0\n };\n\n // Default attribute values\n const attrs = {\n // fill and stroke\n 'fill-opacity': 1,\n 'stroke-opacity': 1,\n 'stroke-width': 0,\n 'stroke-linejoin': 'miter',\n 'stroke-linecap': 'butt',\n fill: '#000000',\n stroke: '#000000',\n opacity: 1,\n // position\n x: 0,\n y: 0,\n cx: 0,\n cy: 0,\n // size\n width: 0,\n height: 0,\n // radius\n r: 0,\n rx: 0,\n ry: 0,\n // gradient\n offset: 0,\n 'stop-opacity': 1,\n 'stop-color': '#000000',\n // text\n 'text-anchor': 'start'\n };\n\n var defaults = {\n __proto__: null,\n attrs: attrs,\n noop: noop,\n timeline: timeline\n };\n\n class SVGArray extends Array {\n constructor(...args) {\n super(...args);\n this.init(...args);\n }\n clone() {\n return new this.constructor(this);\n }\n init(arr) {\n // This catches the case, that native map tries to create an array with new Array(1)\n if (typeof arr === 'number') return this;\n this.length = 0;\n this.push(...this.parse(arr));\n return this;\n }\n\n // Parse whitespace separated string\n parse(array = []) {\n // If already is an array, no need to parse it\n if (array instanceof Array) return array;\n return array.trim().split(delimiter).map(parseFloat);\n }\n toArray() {\n return Array.prototype.concat.apply([], this);\n }\n toSet() {\n return new Set(this);\n }\n toString() {\n return this.join(' ');\n }\n\n // Flattens the array if needed\n valueOf() {\n const ret = [];\n ret.push(...this);\n return ret;\n }\n }\n\n // Module for unit conversions\n class SVGNumber {\n // Initialize\n constructor(...args) {\n this.init(...args);\n }\n convert(unit) {\n return new SVGNumber(this.value, unit);\n }\n\n // Divide number\n divide(number) {\n number = new SVGNumber(number);\n return new SVGNumber(this / number, this.unit || number.unit);\n }\n init(value, unit) {\n unit = Array.isArray(value) ? value[1] : unit;\n value = Array.isArray(value) ? value[0] : value;\n\n // initialize defaults\n this.value = 0;\n this.unit = unit || '';\n\n // parse value\n if (typeof value === 'number') {\n // ensure a valid numeric value\n this.value = isNaN(value) ? 0 : !isFinite(value) ? value < 0 ? -3.4e38 : +3.4e38 : value;\n } else if (typeof value === 'string') {\n unit = value.match(numberAndUnit);\n if (unit) {\n // make value numeric\n this.value = parseFloat(unit[1]);\n\n // normalize\n if (unit[5] === '%') {\n this.value /= 100;\n } else if (unit[5] === 's') {\n this.value *= 1000;\n }\n\n // store unit\n this.unit = unit[5];\n }\n } else {\n if (value instanceof SVGNumber) {\n this.value = value.valueOf();\n this.unit = value.unit;\n }\n }\n return this;\n }\n\n // Subtract number\n minus(number) {\n number = new SVGNumber(number);\n return new SVGNumber(this - number, this.unit || number.unit);\n }\n\n // Add number\n plus(number) {\n number = new SVGNumber(number);\n return new SVGNumber(this + number, this.unit || number.unit);\n }\n\n // Multiply number\n times(number) {\n number = new SVGNumber(number);\n return new SVGNumber(this * number, this.unit || number.unit);\n }\n toArray() {\n return [this.value, this.unit];\n }\n toJSON() {\n return this.toString();\n }\n toString() {\n return (this.unit === '%' ? ~~(this.value * 1e8) / 1e6 : this.unit === 's' ? this.value / 1e3 : this.value) + this.unit;\n }\n valueOf() {\n return this.value;\n }\n }\n\n const colorAttributes = new Set(['fill', 'stroke', 'color', 'bgcolor', 'stop-color', 'flood-color', 'lighting-color']);\n const hooks = [];\n function registerAttrHook(fn) {\n hooks.push(fn);\n }\n\n // Set svg element attribute\n function attr(attr, val, ns) {\n // act as full getter\n if (attr == null) {\n // get an object of attributes\n attr = {};\n val = this.node.attributes;\n for (const node of val) {\n attr[node.nodeName] = isNumber.test(node.nodeValue) ? parseFloat(node.nodeValue) : node.nodeValue;\n }\n return attr;\n } else if (attr instanceof Array) {\n // loop through array and get all values\n return attr.reduce((last, curr) => {\n last[curr] = this.attr(curr);\n return last;\n }, {});\n } else if (typeof attr === 'object' && attr.constructor === Object) {\n // apply every attribute individually if an object is passed\n for (val in attr) this.attr(val, attr[val]);\n } else if (val === null) {\n // remove value\n this.node.removeAttribute(attr);\n } else if (val == null) {\n // act as a getter if the first and only argument is not an object\n val = this.node.getAttribute(attr);\n return val == null ? attrs[attr] : isNumber.test(val) ? parseFloat(val) : val;\n } else {\n // Loop through hooks and execute them to convert value\n val = hooks.reduce((_val, hook) => {\n return hook(attr, _val, this);\n }, val);\n\n // ensure correct numeric values (also accepts NaN and Infinity)\n if (typeof val === 'number') {\n val = new SVGNumber(val);\n } else if (colorAttributes.has(attr) && Color.isColor(val)) {\n // ensure full hex color\n val = new Color(val);\n } else if (val.constructor === Array) {\n // Check for plain arrays and parse array values\n val = new SVGArray(val);\n }\n\n // if the passed attribute is leading...\n if (attr === 'leading') {\n // ... call the leading method instead\n if (this.leading) {\n this.leading(val);\n }\n } else {\n // set given attribute on node\n typeof ns === 'string' ? this.node.setAttributeNS(ns, attr, val.toString()) : this.node.setAttribute(attr, val.toString());\n }\n\n // rebuild if required\n if (this.rebuild && (attr === 'font-size' || attr === 'x')) {\n this.rebuild();\n }\n }\n return this;\n }\n\n class Dom extends EventTarget {\n constructor(node, attrs) {\n super();\n this.node = node;\n this.type = node.nodeName;\n if (attrs && node !== attrs) {\n this.attr(attrs);\n }\n }\n\n // Add given element at a position\n add(element, i) {\n element = makeInstance(element);\n\n // If non-root svg nodes are added we have to remove their namespaces\n if (element.removeNamespace && this.node instanceof globals.window.SVGElement) {\n element.removeNamespace();\n }\n if (i == null) {\n this.node.appendChild(element.node);\n } else if (element.node !== this.node.childNodes[i]) {\n this.node.insertBefore(element.node, this.node.childNodes[i]);\n }\n return this;\n }\n\n // Add element to given container and return self\n addTo(parent, i) {\n return makeInstance(parent).put(this, i);\n }\n\n // Returns all child elements\n children() {\n return new List(map(this.node.children, function (node) {\n return adopt(node);\n }));\n }\n\n // Remove all elements in this container\n clear() {\n // remove children\n while (this.node.hasChildNodes()) {\n this.node.removeChild(this.node.lastChild);\n }\n return this;\n }\n\n // Clone element\n clone(deep = true, assignNewIds = true) {\n // write dom data to the dom so the clone can pickup the data\n this.writeDataToDom();\n\n // clone element\n let nodeClone = this.node.cloneNode(deep);\n if (assignNewIds) {\n // assign new id\n nodeClone = assignNewId(nodeClone);\n }\n return new this.constructor(nodeClone);\n }\n\n // Iterates over all children and invokes a given block\n each(block, deep) {\n const children = this.children();\n let i, il;\n for (i = 0, il = children.length; i < il; i++) {\n block.apply(children[i], [i, children]);\n if (deep) {\n children[i].each(block, deep);\n }\n }\n return this;\n }\n element(nodeName, attrs) {\n return this.put(new Dom(create(nodeName), attrs));\n }\n\n // Get first child\n first() {\n return adopt(this.node.firstChild);\n }\n\n // Get a element at the given index\n get(i) {\n return adopt(this.node.childNodes[i]);\n }\n getEventHolder() {\n return this.node;\n }\n getEventTarget() {\n return this.node;\n }\n\n // Checks if the given element is a child\n has(element) {\n return this.index(element) >= 0;\n }\n html(htmlOrFn, outerHTML) {\n return this.xml(htmlOrFn, outerHTML, html);\n }\n\n // Get / set id\n id(id) {\n // generate new id if no id set\n if (typeof id === 'undefined' && !this.node.id) {\n this.node.id = eid(this.type);\n }\n\n // don't set directly with this.node.id to make `null` work correctly\n return this.attr('id', id);\n }\n\n // Gets index of given element\n index(element) {\n return [].slice.call(this.node.childNodes).indexOf(element.node);\n }\n\n // Get the last child\n last() {\n return adopt(this.node.lastChild);\n }\n\n // matches the element vs a css selector\n matches(selector) {\n const el = this.node;\n const matcher = el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector || null;\n return matcher && matcher.call(el, selector);\n }\n\n // Returns the parent element instance\n parent(type) {\n let parent = this;\n\n // check for parent\n if (!parent.node.parentNode) return null;\n\n // get parent element\n parent = adopt(parent.node.parentNode);\n if (!type) return parent;\n\n // loop through ancestors if type is given\n do {\n if (typeof type === 'string' ? parent.matches(type) : parent instanceof type) return parent;\n } while (parent = adopt(parent.node.parentNode));\n return parent;\n }\n\n // Basically does the same as `add()` but returns the added element instead\n put(element, i) {\n element = makeInstance(element);\n this.add(element, i);\n return element;\n }\n\n // Add element to given container and return container\n putIn(parent, i) {\n return makeInstance(parent).add(this, i);\n }\n\n // Remove element\n remove() {\n if (this.parent()) {\n this.parent().removeElement(this);\n }\n return this;\n }\n\n // Remove a given child\n removeElement(element) {\n this.node.removeChild(element.node);\n return this;\n }\n\n // Replace this with element\n replace(element) {\n element = makeInstance(element);\n if (this.node.parentNode) {\n this.node.parentNode.replaceChild(element.node, this.node);\n }\n return element;\n }\n round(precision = 2, map = null) {\n const factor = 10 ** precision;\n const attrs = this.attr(map);\n for (const i in attrs) {\n if (typeof attrs[i] === 'number') {\n attrs[i] = Math.round(attrs[i] * factor) / factor;\n }\n }\n this.attr(attrs);\n return this;\n }\n\n // Import / Export raw svg\n svg(svgOrFn, outerSVG) {\n return this.xml(svgOrFn, outerSVG, svg);\n }\n\n // Return id on string conversion\n toString() {\n return this.id();\n }\n words(text) {\n // This is faster than removing all children and adding a new one\n this.node.textContent = text;\n return this;\n }\n wrap(node) {\n const parent = this.parent();\n if (!parent) {\n return this.addTo(node);\n }\n const position = parent.index(this);\n return parent.put(node, position).put(this);\n }\n\n // write svgjs data to the dom\n writeDataToDom() {\n // dump variables recursively\n this.each(function () {\n this.writeDataToDom();\n });\n return this;\n }\n\n // Import / Export raw svg\n xml(xmlOrFn, outerXML, ns) {\n if (typeof xmlOrFn === 'boolean') {\n ns = outerXML;\n outerXML = xmlOrFn;\n xmlOrFn = null;\n }\n\n // act as getter if no svg string is given\n if (xmlOrFn == null || typeof xmlOrFn === 'function') {\n // The default for exports is, that the outerNode is included\n outerXML = outerXML == null ? true : outerXML;\n\n // write svgjs data to the dom\n this.writeDataToDom();\n let current = this;\n\n // An export modifier was passed\n if (xmlOrFn != null) {\n current = adopt(current.node.cloneNode(true));\n\n // If the user wants outerHTML we need to process this node, too\n if (outerXML) {\n const result = xmlOrFn(current);\n current = result || current;\n\n // The user does not want this node? Well, then he gets nothing\n if (result === false) return '';\n }\n\n // Deep loop through all children and apply modifier\n current.each(function () {\n const result = xmlOrFn(this);\n const _this = result || this;\n\n // If modifier returns false, discard node\n if (result === false) {\n this.remove();\n\n // If modifier returns new node, use it\n } else if (result && this !== _this) {\n this.replace(_this);\n }\n }, true);\n }\n\n // Return outer or inner content\n return outerXML ? current.node.outerHTML : current.node.innerHTML;\n }\n\n // Act as setter if we got a string\n\n // The default for import is, that the current node is not replaced\n outerXML = outerXML == null ? false : outerXML;\n\n // Create temporary holder\n const well = create('wrapper', ns);\n const fragment = globals.document.createDocumentFragment();\n\n // Dump raw svg\n well.innerHTML = xmlOrFn;\n\n // Transplant nodes into the fragment\n for (let len = well.children.length; len--;) {\n fragment.appendChild(well.firstElementChild);\n }\n const parent = this.parent();\n\n // Add the whole fragment at once\n return outerXML ? this.replace(fragment) && parent : this.add(fragment);\n }\n }\n extend(Dom, {\n attr,\n find,\n findOne\n });\n register(Dom, 'Dom');\n\n class Element extends Dom {\n constructor(node, attrs) {\n super(node, attrs);\n\n // initialize data object\n this.dom = {};\n\n // create circular reference\n this.node.instance = this;\n if (node.hasAttribute('data-svgjs') || node.hasAttribute('svgjs:data')) {\n // pull svgjs data from the dom (getAttributeNS doesn't work in html5)\n this.setData(JSON.parse(node.getAttribute('data-svgjs')) ?? JSON.parse(node.getAttribute('svgjs:data')) ?? {});\n }\n }\n\n // Move element by its center\n center(x, y) {\n return this.cx(x).cy(y);\n }\n\n // Move by center over x-axis\n cx(x) {\n return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2);\n }\n\n // Move by center over y-axis\n cy(y) {\n return y == null ? this.y() + this.height() / 2 : this.y(y - this.height() / 2);\n }\n\n // Get defs\n defs() {\n const root = this.root();\n return root && root.defs();\n }\n\n // Relative move over x and y axes\n dmove(x, y) {\n return this.dx(x).dy(y);\n }\n\n // Relative move over x axis\n dx(x = 0) {\n return this.x(new SVGNumber(x).plus(this.x()));\n }\n\n // Relative move over y axis\n dy(y = 0) {\n return this.y(new SVGNumber(y).plus(this.y()));\n }\n getEventHolder() {\n return this;\n }\n\n // Set height of element\n height(height) {\n return this.attr('height', height);\n }\n\n // Move element to given x and y values\n move(x, y) {\n return this.x(x).y(y);\n }\n\n // return array of all ancestors of given type up to the root svg\n parents(until = this.root()) {\n const isSelector = typeof until === 'string';\n if (!isSelector) {\n until = makeInstance(until);\n }\n const parents = new List();\n let parent = this;\n while ((parent = parent.parent()) && parent.node !== globals.document && parent.nodeName !== '#document-fragment') {\n parents.push(parent);\n if (!isSelector && parent.node === until.node) {\n break;\n }\n if (isSelector && parent.matches(until)) {\n break;\n }\n if (parent.node === this.root().node) {\n // We worked our way to the root and didn't match `until`\n return null;\n }\n }\n return parents;\n }\n\n // Get referenced element form attribute value\n reference(attr) {\n attr = this.attr(attr);\n if (!attr) return null;\n const m = (attr + '').match(reference);\n return m ? makeInstance(m[1]) : null;\n }\n\n // Get parent document\n root() {\n const p = this.parent(getClass(root));\n return p && p.root();\n }\n\n // set given data to the elements data property\n setData(o) {\n this.dom = o;\n return this;\n }\n\n // Set element size to given width and height\n size(width, height) {\n const p = proportionalSize(this, width, height);\n return this.width(new SVGNumber(p.width)).height(new SVGNumber(p.height));\n }\n\n // Set width of element\n width(width) {\n return this.attr('width', width);\n }\n\n // write svgjs data to the dom\n writeDataToDom() {\n writeDataToDom(this, this.dom);\n return super.writeDataToDom();\n }\n\n // Move over x-axis\n x(x) {\n return this.attr('x', x);\n }\n\n // Move over y-axis\n y(y) {\n return this.attr('y', y);\n }\n }\n extend(Element, {\n bbox,\n rbox,\n inside,\n point,\n ctm,\n screenCTM\n });\n register(Element, 'Element');\n\n // Define list of available attributes for stroke and fill\n const sugar = {\n stroke: ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'],\n fill: ['color', 'opacity', 'rule'],\n prefix: function (t, a) {\n return a === 'color' ? t : t + '-' + a;\n }\n }\n\n // Add sugar for fill and stroke\n ;\n ['fill', 'stroke'].forEach(function (m) {\n const extension = {};\n let i;\n extension[m] = function (o) {\n if (typeof o === 'undefined') {\n return this.attr(m);\n }\n if (typeof o === 'string' || o instanceof Color || Color.isRgb(o) || o instanceof Element) {\n this.attr(m, o);\n } else {\n // set all attributes from sugar.fill and sugar.stroke list\n for (i = sugar[m].length - 1; i >= 0; i--) {\n if (o[sugar[m][i]] != null) {\n this.attr(sugar.prefix(m, sugar[m][i]), o[sugar[m][i]]);\n }\n }\n }\n return this;\n };\n registerMethods(['Element', 'Runner'], extension);\n });\n registerMethods(['Element', 'Runner'], {\n // Let the user set the matrix directly\n matrix: function (mat, b, c, d, e, f) {\n // Act as a getter\n if (mat == null) {\n return new Matrix(this);\n }\n\n // Act as a setter, the user can pass a matrix or a set of numbers\n return this.attr('transform', new Matrix(mat, b, c, d, e, f));\n },\n // Map rotation to transform\n rotate: function (angle, cx, cy) {\n return this.transform({\n rotate: angle,\n ox: cx,\n oy: cy\n }, true);\n },\n // Map skew to transform\n skew: function (x, y, cx, cy) {\n return arguments.length === 1 || arguments.length === 3 ? this.transform({\n skew: x,\n ox: y,\n oy: cx\n }, true) : this.transform({\n skew: [x, y],\n ox: cx,\n oy: cy\n }, true);\n },\n shear: function (lam, cx, cy) {\n return this.transform({\n shear: lam,\n ox: cx,\n oy: cy\n }, true);\n },\n // Map scale to transform\n scale: function (x, y, cx, cy) {\n return arguments.length === 1 || arguments.length === 3 ? this.transform({\n scale: x,\n ox: y,\n oy: cx\n }, true) : this.transform({\n scale: [x, y],\n ox: cx,\n oy: cy\n }, true);\n },\n // Map translate to transform\n translate: function (x, y) {\n return this.transform({\n translate: [x, y]\n }, true);\n },\n // Map relative translations to transform\n relative: function (x, y) {\n return this.transform({\n relative: [x, y]\n }, true);\n },\n // Map flip to transform\n flip: function (direction = 'both', origin = 'center') {\n if ('xybothtrue'.indexOf(direction) === -1) {\n origin = direction;\n direction = 'both';\n }\n return this.transform({\n flip: direction,\n origin: origin\n }, true);\n },\n // Opacity\n opacity: function (value) {\n return this.attr('opacity', value);\n }\n });\n registerMethods('radius', {\n // Add x and y radius\n radius: function (x, y = x) {\n const type = (this._element || this).type;\n return type === 'radialGradient' ? this.attr('r', new SVGNumber(x)) : this.rx(x).ry(y);\n }\n });\n registerMethods('Path', {\n // Get path length\n length: function () {\n return this.node.getTotalLength();\n },\n // Get point at length\n pointAt: function (length) {\n return new Point(this.node.getPointAtLength(length));\n }\n });\n registerMethods(['Element', 'Runner'], {\n // Set font\n font: function (a, v) {\n if (typeof a === 'object') {\n for (v in a) this.font(v, a[v]);\n return this;\n }\n return a === 'leading' ? this.leading(v) : a === 'anchor' ? this.attr('text-anchor', v) : a === 'size' || a === 'family' || a === 'weight' || a === 'stretch' || a === 'variant' || a === 'style' ? this.attr('font-' + a, v) : this.attr(a, v);\n }\n });\n\n // Add events to elements\n const methods = ['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout', 'mousemove', 'mouseenter', 'mouseleave', 'touchstart', 'touchmove', 'touchleave', 'touchend', 'touchcancel', 'contextmenu', 'wheel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel'].reduce(function (last, event) {\n // add event to Element\n const fn = function (f) {\n if (f === null) {\n this.off(event);\n } else {\n this.on(event, f);\n }\n return this;\n };\n last[event] = fn;\n return last;\n }, {});\n registerMethods('Element', methods);\n\n // Reset all transformations\n function untransform() {\n return this.attr('transform', null);\n }\n\n // merge the whole transformation chain into one matrix and returns it\n function matrixify() {\n const matrix = (this.attr('transform') || ''\n // split transformations\n ).split(transforms).slice(0, -1).map(function (str) {\n // generate key => value pairs\n const kv = str.trim().split('(');\n return [kv[0], kv[1].split(delimiter).map(function (str) {\n return parseFloat(str);\n })];\n }).reverse()\n // merge every transformation into one matrix\n .reduce(function (matrix, transform) {\n if (transform[0] === 'matrix') {\n return matrix.lmultiply(Matrix.fromArray(transform[1]));\n }\n return matrix[transform[0]].apply(matrix, transform[1]);\n }, new Matrix());\n return matrix;\n }\n\n // add an element to another parent without changing the visual representation on the screen\n function toParent(parent, i) {\n if (this === parent) return this;\n if (isDescriptive(this.node)) return this.addTo(parent, i);\n const ctm = this.screenCTM();\n const pCtm = parent.screenCTM().inverse();\n this.addTo(parent, i).untransform().transform(pCtm.multiply(ctm));\n return this;\n }\n\n // same as above with parent equals root-svg\n function toRoot(i) {\n return this.toParent(this.root(), i);\n }\n\n // Add transformations\n function transform(o, relative) {\n // Act as a getter if no object was passed\n if (o == null || typeof o === 'string') {\n const decomposed = new Matrix(this).decompose();\n return o == null ? decomposed : decomposed[o];\n }\n if (!Matrix.isMatrixLike(o)) {\n // Set the origin according to the defined transform\n o = {\n ...o,\n origin: getOrigin(o, this)\n };\n }\n\n // The user can pass a boolean, an Element or an Matrix or nothing\n const cleanRelative = relative === true ? this : relative || false;\n const result = new Matrix(cleanRelative).transform(o);\n return this.attr('transform', result);\n }\n registerMethods('Element', {\n untransform,\n matrixify,\n toParent,\n toRoot,\n transform\n });\n\n class Container extends Element {\n flatten() {\n this.each(function () {\n if (this instanceof Container) {\n return this.flatten().ungroup();\n }\n });\n return this;\n }\n ungroup(parent = this.parent(), index = parent.index(this)) {\n // when parent != this, we want append all elements to the end\n index = index === -1 ? parent.children().length : index;\n this.each(function (i, children) {\n // reverse each\n return children[children.length - i - 1].toParent(parent, index);\n });\n return this.remove();\n }\n }\n register(Container, 'Container');\n\n class Defs extends Container {\n constructor(node, attrs = node) {\n super(nodeOrNew('defs', node), attrs);\n }\n flatten() {\n return this;\n }\n ungroup() {\n return this;\n }\n }\n register(Defs, 'Defs');\n\n class Shape extends Element {}\n register(Shape, 'Shape');\n\n // Radius x value\n function rx(rx) {\n return this.attr('rx', rx);\n }\n\n // Radius y value\n function ry(ry) {\n return this.attr('ry', ry);\n }\n\n // Move over x-axis\n function x$3(x) {\n return x == null ? this.cx() - this.rx() : this.cx(x + this.rx());\n }\n\n // Move over y-axis\n function y$3(y) {\n return y == null ? this.cy() - this.ry() : this.cy(y + this.ry());\n }\n\n // Move by center over x-axis\n function cx$1(x) {\n return this.attr('cx', x);\n }\n\n // Move by center over y-axis\n function cy$1(y) {\n return this.attr('cy', y);\n }\n\n // Set width of element\n function width$2(width) {\n return width == null ? this.rx() * 2 : this.rx(new SVGNumber(width).divide(2));\n }\n\n // Set height of element\n function height$2(height) {\n return height == null ? this.ry() * 2 : this.ry(new SVGNumber(height).divide(2));\n }\n\n var circled = {\n __proto__: null,\n cx: cx$1,\n cy: cy$1,\n height: height$2,\n rx: rx,\n ry: ry,\n width: width$2,\n x: x$3,\n y: y$3\n };\n\n class Ellipse extends Shape {\n constructor(node, attrs = node) {\n super(nodeOrNew('ellipse', node), attrs);\n }\n size(width, height) {\n const p = proportionalSize(this, width, height);\n return this.rx(new SVGNumber(p.width).divide(2)).ry(new SVGNumber(p.height).divide(2));\n }\n }\n extend(Ellipse, circled);\n registerMethods('Container', {\n // Create an ellipse\n ellipse: wrapWithAttrCheck(function (width = 0, height = width) {\n return this.put(new Ellipse()).size(width, height).move(0, 0);\n })\n });\n register(Ellipse, 'Ellipse');\n\n class Fragment extends Dom {\n constructor(node = globals.document.createDocumentFragment()) {\n super(node);\n }\n\n // Import / Export raw xml\n xml(xmlOrFn, outerXML, ns) {\n if (typeof xmlOrFn === 'boolean') {\n ns = outerXML;\n outerXML = xmlOrFn;\n xmlOrFn = null;\n }\n\n // because this is a fragment we have to put all elements into a wrapper first\n // before we can get the innerXML from it\n if (xmlOrFn == null || typeof xmlOrFn === 'function') {\n const wrapper = new Dom(create('wrapper', ns));\n wrapper.add(this.node.cloneNode(true));\n return wrapper.xml(false, ns);\n }\n\n // Act as setter if we got a string\n return super.xml(xmlOrFn, false, ns);\n }\n }\n register(Fragment, 'Fragment');\n\n function from(x, y) {\n return (this._element || this).type === 'radialGradient' ? this.attr({\n fx: new SVGNumber(x),\n fy: new SVGNumber(y)\n }) : this.attr({\n x1: new SVGNumber(x),\n y1: new SVGNumber(y)\n });\n }\n function to(x, y) {\n return (this._element || this).type === 'radialGradient' ? this.attr({\n cx: new SVGNumber(x),\n cy: new SVGNumber(y)\n }) : this.attr({\n x2: new SVGNumber(x),\n y2: new SVGNumber(y)\n });\n }\n\n var gradiented = {\n __proto__: null,\n from: from,\n to: to\n };\n\n class Gradient extends Container {\n constructor(type, attrs) {\n super(nodeOrNew(type + 'Gradient', typeof type === 'string' ? null : type), attrs);\n }\n\n // custom attr to handle transform\n attr(a, b, c) {\n if (a === 'transform') a = 'gradientTransform';\n return super.attr(a, b, c);\n }\n bbox() {\n return new Box();\n }\n targets() {\n return baseFind('svg [fill*=' + this.id() + ']');\n }\n\n // Alias string conversion to fill\n toString() {\n return this.url();\n }\n\n // Update gradient\n update(block) {\n // remove all stops\n this.clear();\n\n // invoke passed block\n if (typeof block === 'function') {\n block.call(this, this);\n }\n return this;\n }\n\n // Return the fill id\n url() {\n return 'url(#' + this.id() + ')';\n }\n }\n extend(Gradient, gradiented);\n registerMethods({\n Container: {\n // Create gradient element in defs\n gradient(...args) {\n return this.defs().gradient(...args);\n }\n },\n // define gradient\n Defs: {\n gradient: wrapWithAttrCheck(function (type, block) {\n return this.put(new Gradient(type)).update(block);\n })\n }\n });\n register(Gradient, 'Gradient');\n\n class Pattern extends Container {\n // Initialize node\n constructor(node, attrs = node) {\n super(nodeOrNew('pattern', node), attrs);\n }\n\n // custom attr to handle transform\n attr(a, b, c) {\n if (a === 'transform') a = 'patternTransform';\n return super.attr(a, b, c);\n }\n bbox() {\n return new Box();\n }\n targets() {\n return baseFind('svg [fill*=' + this.id() + ']');\n }\n\n // Alias string conversion to fill\n toString() {\n return this.url();\n }\n\n // Update pattern by rebuilding\n update(block) {\n // remove content\n this.clear();\n\n // invoke passed block\n if (typeof block === 'function') {\n block.call(this, this);\n }\n return this;\n }\n\n // Return the fill id\n url() {\n return 'url(#' + this.id() + ')';\n }\n }\n registerMethods({\n Container: {\n // Create pattern element in defs\n pattern(...args) {\n return this.defs().pattern(...args);\n }\n },\n Defs: {\n pattern: wrapWithAttrCheck(function (width, height, block) {\n return this.put(new Pattern()).update(block).attr({\n x: 0,\n y: 0,\n width: width,\n height: height,\n patternUnits: 'userSpaceOnUse'\n });\n })\n }\n });\n register(Pattern, 'Pattern');\n\n class Image extends Shape {\n constructor(node, attrs = node) {\n super(nodeOrNew('image', node), attrs);\n }\n\n // (re)load image\n load(url, callback) {\n if (!url) return this;\n const img = new globals.window.Image();\n on(img, 'load', function (e) {\n const p = this.parent(Pattern);\n\n // ensure image size\n if (this.width() === 0 && this.height() === 0) {\n this.size(img.width, img.height);\n }\n if (p instanceof Pattern) {\n // ensure pattern size if not set\n if (p.width() === 0 && p.height() === 0) {\n p.size(this.width(), this.height());\n }\n }\n if (typeof callback === 'function') {\n callback.call(this, e);\n }\n }, this);\n on(img, 'load error', function () {\n // dont forget to unbind memory leaking events\n off(img);\n });\n return this.attr('href', img.src = url, xlink);\n }\n }\n registerAttrHook(function (attr, val, _this) {\n // convert image fill and stroke to patterns\n if (attr === 'fill' || attr === 'stroke') {\n if (isImage.test(val)) {\n val = _this.root().defs().image(val);\n }\n }\n if (val instanceof Image) {\n val = _this.root().defs().pattern(0, 0, pattern => {\n pattern.add(val);\n });\n }\n return val;\n });\n registerMethods({\n Container: {\n // create image element, load image and set its size\n image: wrapWithAttrCheck(function (source, callback) {\n return this.put(new Image()).size(0, 0).load(source, callback);\n })\n }\n });\n register(Image, 'Image');\n\n class PointArray extends SVGArray {\n // Get bounding box of points\n bbox() {\n let maxX = -Infinity;\n let maxY = -Infinity;\n let minX = Infinity;\n let minY = Infinity;\n this.forEach(function (el) {\n maxX = Math.max(el[0], maxX);\n maxY = Math.max(el[1], maxY);\n minX = Math.min(el[0], minX);\n minY = Math.min(el[1], minY);\n });\n return new Box(minX, minY, maxX - minX, maxY - minY);\n }\n\n // Move point string\n move(x, y) {\n const box = this.bbox();\n\n // get relative offset\n x -= box.x;\n y -= box.y;\n\n // move every point\n if (!isNaN(x) && !isNaN(y)) {\n for (let i = this.length - 1; i >= 0; i--) {\n this[i] = [this[i][0] + x, this[i][1] + y];\n }\n }\n return this;\n }\n\n // Parse point string and flat array\n parse(array = [0, 0]) {\n const points = [];\n\n // if it is an array, we flatten it and therefore clone it to 1 depths\n if (array instanceof Array) {\n array = Array.prototype.concat.apply([], array);\n } else {\n // Else, it is considered as a string\n // parse points\n array = array.trim().split(delimiter).map(parseFloat);\n }\n\n // validate points - https://svgwg.org/svg2-draft/shapes.html#DataTypePoints\n // Odd number of coordinates is an error. In such cases, drop the last odd coordinate.\n if (array.length % 2 !== 0) array.pop();\n\n // wrap points in two-tuples\n for (let i = 0, len = array.length; i < len; i = i + 2) {\n points.push([array[i], array[i + 1]]);\n }\n return points;\n }\n\n // Resize poly string\n size(width, height) {\n let i;\n const box = this.bbox();\n\n // recalculate position of all points according to new size\n for (i = this.length - 1; i >= 0; i--) {\n if (box.width) this[i][0] = (this[i][0] - box.x) * width / box.width + box.x;\n if (box.height) this[i][1] = (this[i][1] - box.y) * height / box.height + box.y;\n }\n return this;\n }\n\n // Convert array to line object\n toLine() {\n return {\n x1: this[0][0],\n y1: this[0][1],\n x2: this[1][0],\n y2: this[1][1]\n };\n }\n\n // Convert array to string\n toString() {\n const array = [];\n // convert to a poly point string\n for (let i = 0, il = this.length; i < il; i++) {\n array.push(this[i].join(','));\n }\n return array.join(' ');\n }\n transform(m) {\n return this.clone().transformO(m);\n }\n\n // transform points with matrix (similar to Point.transform)\n transformO(m) {\n if (!Matrix.isMatrixLike(m)) {\n m = new Matrix(m);\n }\n for (let i = this.length; i--;) {\n // Perform the matrix multiplication\n const [x, y] = this[i];\n this[i][0] = m.a * x + m.c * y + m.e;\n this[i][1] = m.b * x + m.d * y + m.f;\n }\n return this;\n }\n }\n\n const MorphArray = PointArray;\n\n // Move by left top corner over x-axis\n function x$2(x) {\n return x == null ? this.bbox().x : this.move(x, this.bbox().y);\n }\n\n // Move by left top corner over y-axis\n function y$2(y) {\n return y == null ? this.bbox().y : this.move(this.bbox().x, y);\n }\n\n // Set width of element\n function width$1(width) {\n const b = this.bbox();\n return width == null ? b.width : this.size(width, b.height);\n }\n\n // Set height of element\n function height$1(height) {\n const b = this.bbox();\n return height == null ? b.height : this.size(b.width, height);\n }\n\n var pointed = {\n __proto__: null,\n MorphArray: MorphArray,\n height: height$1,\n width: width$1,\n x: x$2,\n y: y$2\n };\n\n class Line extends Shape {\n // Initialize node\n constructor(node, attrs = node) {\n super(nodeOrNew('line', node), attrs);\n }\n\n // Get array\n array() {\n return new PointArray([[this.attr('x1'), this.attr('y1')], [this.attr('x2'), this.attr('y2')]]);\n }\n\n // Move by left top corner\n move(x, y) {\n return this.attr(this.array().move(x, y).toLine());\n }\n\n // Overwrite native plot() method\n plot(x1, y1, x2, y2) {\n if (x1 == null) {\n return this.array();\n } else if (typeof y1 !== 'undefined') {\n x1 = {\n x1,\n y1,\n x2,\n y2\n };\n } else {\n x1 = new PointArray(x1).toLine();\n }\n return this.attr(x1);\n }\n\n // Set element size to given width and height\n size(width, height) {\n const p = proportionalSize(this, width, height);\n return this.attr(this.array().size(p.width, p.height).toLine());\n }\n }\n extend(Line, pointed);\n registerMethods({\n Container: {\n // Create a line element\n line: wrapWithAttrCheck(function (...args) {\n // make sure plot is called as a setter\n // x1 is not necessarily a number, it can also be an array, a string and a PointArray\n return Line.prototype.plot.apply(this.put(new Line()), args[0] != null ? args : [0, 0, 0, 0]);\n })\n }\n });\n register(Line, 'Line');\n\n class Marker extends Container {\n // Initialize node\n constructor(node, attrs = node) {\n super(nodeOrNew('marker', node), attrs);\n }\n\n // Set height of element\n height(height) {\n return this.attr('markerHeight', height);\n }\n orient(orient) {\n return this.attr('orient', orient);\n }\n\n // Set marker refX and refY\n ref(x, y) {\n return this.attr('refX', x).attr('refY', y);\n }\n\n // Return the fill id\n toString() {\n return 'url(#' + this.id() + ')';\n }\n\n // Update marker\n update(block) {\n // remove all content\n this.clear();\n\n // invoke passed block\n if (typeof block === 'function') {\n block.call(this, this);\n }\n return this;\n }\n\n // Set width of element\n width(width) {\n return this.attr('markerWidth', width);\n }\n }\n registerMethods({\n Container: {\n marker(...args) {\n // Create marker element in defs\n return this.defs().marker(...args);\n }\n },\n Defs: {\n // Create marker\n marker: wrapWithAttrCheck(function (width, height, block) {\n // Set default viewbox to match the width and height, set ref to cx and cy and set orient to auto\n return this.put(new Marker()).size(width, height).ref(width / 2, height / 2).viewbox(0, 0, width, height).attr('orient', 'auto').update(block);\n })\n },\n marker: {\n // Create and attach markers\n marker(marker, width, height, block) {\n let attr = ['marker'];\n\n // Build attribute name\n if (marker !== 'all') attr.push(marker);\n attr = attr.join('-');\n\n // Set marker attribute\n marker = arguments[1] instanceof Marker ? arguments[1] : this.defs().marker(width, height, block);\n return this.attr(attr, marker);\n }\n }\n });\n register(Marker, 'Marker');\n\n /***\n Base Class\n ==========\n The base stepper class that will be\n ***/\n\n function makeSetterGetter(k, f) {\n return function (v) {\n if (v == null) return this[k];\n this[k] = v;\n if (f) f.call(this);\n return this;\n };\n }\n const easing = {\n '-': function (pos) {\n return pos;\n },\n '<>': function (pos) {\n return -Math.cos(pos * Math.PI) / 2 + 0.5;\n },\n '>': function (pos) {\n return Math.sin(pos * Math.PI / 2);\n },\n '<': function (pos) {\n return -Math.cos(pos * Math.PI / 2) + 1;\n },\n bezier: function (x1, y1, x2, y2) {\n // see https://www.w3.org/TR/css-easing-1/#cubic-bezier-algo\n return function (t) {\n if (t < 0) {\n if (x1 > 0) {\n return y1 / x1 * t;\n } else if (x2 > 0) {\n return y2 / x2 * t;\n } else {\n return 0;\n }\n } else if (t > 1) {\n if (x2 < 1) {\n return (1 - y2) / (1 - x2) * t + (y2 - x2) / (1 - x2);\n } else if (x1 < 1) {\n return (1 - y1) / (1 - x1) * t + (y1 - x1) / (1 - x1);\n } else {\n return 1;\n }\n } else {\n return 3 * t * (1 - t) ** 2 * y1 + 3 * t ** 2 * (1 - t) * y2 + t ** 3;\n }\n };\n },\n // see https://www.w3.org/TR/css-easing-1/#step-timing-function-algo\n steps: function (steps, stepPosition = 'end') {\n // deal with \"jump-\" prefix\n stepPosition = stepPosition.split('-').reverse()[0];\n let jumps = steps;\n if (stepPosition === 'none') {\n --jumps;\n } else if (stepPosition === 'both') {\n ++jumps;\n }\n\n // The beforeFlag is essentially useless\n return (t, beforeFlag = false) => {\n // Step is called currentStep in referenced url\n let step = Math.floor(t * steps);\n const jumping = t * step % 1 === 0;\n if (stepPosition === 'start' || stepPosition === 'both') {\n ++step;\n }\n if (beforeFlag && jumping) {\n --step;\n }\n if (t >= 0 && step < 0) {\n step = 0;\n }\n if (t <= 1 && step > jumps) {\n step = jumps;\n }\n return step / jumps;\n };\n }\n };\n class Stepper {\n done() {\n return false;\n }\n }\n\n /***\n Easing Functions\n ================\n ***/\n\n class Ease extends Stepper {\n constructor(fn = timeline.ease) {\n super();\n this.ease = easing[fn] || fn;\n }\n step(from, to, pos) {\n if (typeof from !== 'number') {\n return pos < 1 ? from : to;\n }\n return from + (to - from) * this.ease(pos);\n }\n }\n\n /***\n Controller Types\n ================\n ***/\n\n class Controller extends Stepper {\n constructor(fn) {\n super();\n this.stepper = fn;\n }\n done(c) {\n return c.done;\n }\n step(current, target, dt, c) {\n return this.stepper(current, target, dt, c);\n }\n }\n function recalculate() {\n // Apply the default parameters\n const duration = (this._duration || 500) / 1000;\n const overshoot = this._overshoot || 0;\n\n // Calculate the PID natural response\n const eps = 1e-10;\n const pi = Math.PI;\n const os = Math.log(overshoot / 100 + eps);\n const zeta = -os / Math.sqrt(pi * pi + os * os);\n const wn = 3.9 / (zeta * duration);\n\n // Calculate the Spring values\n this.d = 2 * zeta * wn;\n this.k = wn * wn;\n }\n class Spring extends Controller {\n constructor(duration = 500, overshoot = 0) {\n super();\n this.duration(duration).overshoot(overshoot);\n }\n step(current, target, dt, c) {\n if (typeof current === 'string') return current;\n c.done = dt === Infinity;\n if (dt === Infinity) return target;\n if (dt === 0) return current;\n if (dt > 100) dt = 16;\n dt /= 1000;\n\n // Get the previous velocity\n const velocity = c.velocity || 0;\n\n // Apply the control to get the new position and store it\n const acceleration = -this.d * velocity - this.k * (current - target);\n const newPosition = current + velocity * dt + acceleration * dt * dt / 2;\n\n // Store the velocity\n c.velocity = velocity + acceleration * dt;\n\n // Figure out if we have converged, and if so, pass the value\n c.done = Math.abs(target - newPosition) + Math.abs(velocity) < 0.002;\n return c.done ? target : newPosition;\n }\n }\n extend(Spring, {\n duration: makeSetterGetter('_duration', recalculate),\n overshoot: makeSetterGetter('_overshoot', recalculate)\n });\n class PID extends Controller {\n constructor(p = 0.1, i = 0.01, d = 0, windup = 1000) {\n super();\n this.p(p).i(i).d(d).windup(windup);\n }\n step(current, target, dt, c) {\n if (typeof current === 'string') return current;\n c.done = dt === Infinity;\n if (dt === Infinity) return target;\n if (dt === 0) return current;\n const p = target - current;\n let i = (c.integral || 0) + p * dt;\n const d = (p - (c.error || 0)) / dt;\n const windup = this._windup;\n\n // antiwindup\n if (windup !== false) {\n i = Math.max(-windup, Math.min(i, windup));\n }\n c.error = p;\n c.integral = i;\n c.done = Math.abs(p) < 0.001;\n return c.done ? target : current + (this.P * p + this.I * i + this.D * d);\n }\n }\n extend(PID, {\n windup: makeSetterGetter('_windup'),\n p: makeSetterGetter('P'),\n i: makeSetterGetter('I'),\n d: makeSetterGetter('D')\n });\n\n const segmentParameters = {\n M: 2,\n L: 2,\n H: 1,\n V: 1,\n C: 6,\n S: 4,\n Q: 4,\n T: 2,\n A: 7,\n Z: 0\n };\n const pathHandlers = {\n M: function (c, p, p0) {\n p.x = p0.x = c[0];\n p.y = p0.y = c[1];\n return ['M', p.x, p.y];\n },\n L: function (c, p) {\n p.x = c[0];\n p.y = c[1];\n return ['L', c[0], c[1]];\n },\n H: function (c, p) {\n p.x = c[0];\n return ['H', c[0]];\n },\n V: function (c, p) {\n p.y = c[0];\n return ['V', c[0]];\n },\n C: function (c, p) {\n p.x = c[4];\n p.y = c[5];\n return ['C', c[0], c[1], c[2], c[3], c[4], c[5]];\n },\n S: function (c, p) {\n p.x = c[2];\n p.y = c[3];\n return ['S', c[0], c[1], c[2], c[3]];\n },\n Q: function (c, p) {\n p.x = c[2];\n p.y = c[3];\n return ['Q', c[0], c[1], c[2], c[3]];\n },\n T: function (c, p) {\n p.x = c[0];\n p.y = c[1];\n return ['T', c[0], c[1]];\n },\n Z: function (c, p, p0) {\n p.x = p0.x;\n p.y = p0.y;\n return ['Z'];\n },\n A: function (c, p) {\n p.x = c[5];\n p.y = c[6];\n return ['A', c[0], c[1], c[2], c[3], c[4], c[5], c[6]];\n }\n };\n const mlhvqtcsaz = 'mlhvqtcsaz'.split('');\n for (let i = 0, il = mlhvqtcsaz.length; i < il; ++i) {\n pathHandlers[mlhvqtcsaz[i]] = function (i) {\n return function (c, p, p0) {\n if (i === 'H') c[0] = c[0] + p.x;else if (i === 'V') c[0] = c[0] + p.y;else if (i === 'A') {\n c[5] = c[5] + p.x;\n c[6] = c[6] + p.y;\n } else {\n for (let j = 0, jl = c.length; j < jl; ++j) {\n c[j] = c[j] + (j % 2 ? p.y : p.x);\n }\n }\n return pathHandlers[i](c, p, p0);\n };\n }(mlhvqtcsaz[i].toUpperCase());\n }\n function makeAbsolut(parser) {\n const command = parser.segment[0];\n return pathHandlers[command](parser.segment.slice(1), parser.p, parser.p0);\n }\n function segmentComplete(parser) {\n return parser.segment.length && parser.segment.length - 1 === segmentParameters[parser.segment[0].toUpperCase()];\n }\n function startNewSegment(parser, token) {\n parser.inNumber && finalizeNumber(parser, false);\n const pathLetter = isPathLetter.test(token);\n if (pathLetter) {\n parser.segment = [token];\n } else {\n const lastCommand = parser.lastCommand;\n const small = lastCommand.toLowerCase();\n const isSmall = lastCommand === small;\n parser.segment = [small === 'm' ? isSmall ? 'l' : 'L' : lastCommand];\n }\n parser.inSegment = true;\n parser.lastCommand = parser.segment[0];\n return pathLetter;\n }\n function finalizeNumber(parser, inNumber) {\n if (!parser.inNumber) throw new Error('Parser Error');\n parser.number && parser.segment.push(parseFloat(parser.number));\n parser.inNumber = inNumber;\n parser.number = '';\n parser.pointSeen = false;\n parser.hasExponent = false;\n if (segmentComplete(parser)) {\n finalizeSegment(parser);\n }\n }\n function finalizeSegment(parser) {\n parser.inSegment = false;\n if (parser.absolute) {\n parser.segment = makeAbsolut(parser);\n }\n parser.segments.push(parser.segment);\n }\n function isArcFlag(parser) {\n if (!parser.segment.length) return false;\n const isArc = parser.segment[0].toUpperCase() === 'A';\n const length = parser.segment.length;\n return isArc && (length === 4 || length === 5);\n }\n function isExponential(parser) {\n return parser.lastToken.toUpperCase() === 'E';\n }\n const pathDelimiters = new Set([' ', ',', '\\t', '\\n', '\\r', '\\f']);\n function pathParser(d, toAbsolute = true) {\n let index = 0;\n let token = '';\n const parser = {\n segment: [],\n inNumber: false,\n number: '',\n lastToken: '',\n inSegment: false,\n segments: [],\n pointSeen: false,\n hasExponent: false,\n absolute: toAbsolute,\n p0: new Point(),\n p: new Point()\n };\n while (parser.lastToken = token, token = d.charAt(index++)) {\n if (!parser.inSegment) {\n if (startNewSegment(parser, token)) {\n continue;\n }\n }\n if (token === '.') {\n if (parser.pointSeen || parser.hasExponent) {\n finalizeNumber(parser, false);\n --index;\n continue;\n }\n parser.inNumber = true;\n parser.pointSeen = true;\n parser.number += token;\n continue;\n }\n if (!isNaN(parseInt(token))) {\n if (parser.number === '0' || isArcFlag(parser)) {\n parser.inNumber = true;\n parser.number = token;\n finalizeNumber(parser, true);\n continue;\n }\n parser.inNumber = true;\n parser.number += token;\n continue;\n }\n if (pathDelimiters.has(token)) {\n if (parser.inNumber) {\n finalizeNumber(parser, false);\n }\n continue;\n }\n if (token === '-' || token === '+') {\n if (parser.inNumber && !isExponential(parser)) {\n finalizeNumber(parser, false);\n --index;\n continue;\n }\n parser.number += token;\n parser.inNumber = true;\n continue;\n }\n if (token.toUpperCase() === 'E') {\n parser.number += token;\n parser.hasExponent = true;\n continue;\n }\n if (isPathLetter.test(token)) {\n if (parser.inNumber) {\n finalizeNumber(parser, false);\n } else if (!segmentComplete(parser)) {\n throw new Error('parser Error');\n } else {\n finalizeSegment(parser);\n }\n --index;\n }\n }\n if (parser.inNumber) {\n finalizeNumber(parser, false);\n }\n if (parser.inSegment && segmentComplete(parser)) {\n finalizeSegment(parser);\n }\n return parser.segments;\n }\n\n function arrayToString(a) {\n let s = '';\n for (let i = 0, il = a.length; i < il; i++) {\n s += a[i][0];\n if (a[i][1] != null) {\n s += a[i][1];\n if (a[i][2] != null) {\n s += ' ';\n s += a[i][2];\n if (a[i][3] != null) {\n s += ' ';\n s += a[i][3];\n s += ' ';\n s += a[i][4];\n if (a[i][5] != null) {\n s += ' ';\n s += a[i][5];\n s += ' ';\n s += a[i][6];\n if (a[i][7] != null) {\n s += ' ';\n s += a[i][7];\n }\n }\n }\n }\n }\n }\n return s + ' ';\n }\n class PathArray extends SVGArray {\n // Get bounding box of path\n bbox() {\n parser().path.setAttribute('d', this.toString());\n return new Box(parser.nodes.path.getBBox());\n }\n\n // Move path string\n move(x, y) {\n // get bounding box of current situation\n const box = this.bbox();\n\n // get relative offset\n x -= box.x;\n y -= box.y;\n if (!isNaN(x) && !isNaN(y)) {\n // move every point\n for (let l, i = this.length - 1; i >= 0; i--) {\n l = this[i][0];\n if (l === 'M' || l === 'L' || l === 'T') {\n this[i][1] += x;\n this[i][2] += y;\n } else if (l === 'H') {\n this[i][1] += x;\n } else if (l === 'V') {\n this[i][1] += y;\n } else if (l === 'C' || l === 'S' || l === 'Q') {\n this[i][1] += x;\n this[i][2] += y;\n this[i][3] += x;\n this[i][4] += y;\n if (l === 'C') {\n this[i][5] += x;\n this[i][6] += y;\n }\n } else if (l === 'A') {\n this[i][6] += x;\n this[i][7] += y;\n }\n }\n }\n return this;\n }\n\n // Absolutize and parse path to array\n parse(d = 'M0 0') {\n if (Array.isArray(d)) {\n d = Array.prototype.concat.apply([], d).toString();\n }\n return pathParser(d);\n }\n\n // Resize path string\n size(width, height) {\n // get bounding box of current situation\n const box = this.bbox();\n let i, l;\n\n // If the box width or height is 0 then we ignore\n // transformations on the respective axis\n box.width = box.width === 0 ? 1 : box.width;\n box.height = box.height === 0 ? 1 : box.height;\n\n // recalculate position of all points according to new size\n for (i = this.length - 1; i >= 0; i--) {\n l = this[i][0];\n if (l === 'M' || l === 'L' || l === 'T') {\n this[i][1] = (this[i][1] - box.x) * width / box.width + box.x;\n this[i][2] = (this[i][2] - box.y) * height / box.height + box.y;\n } else if (l === 'H') {\n this[i][1] = (this[i][1] - box.x) * width / box.width + box.x;\n } else if (l === 'V') {\n this[i][1] = (this[i][1] - box.y) * height / box.height + box.y;\n } else if (l === 'C' || l === 'S' || l === 'Q') {\n this[i][1] = (this[i][1] - box.x) * width / box.width + box.x;\n this[i][2] = (this[i][2] - box.y) * height / box.height + box.y;\n this[i][3] = (this[i][3] - box.x) * width / box.width + box.x;\n this[i][4] = (this[i][4] - box.y) * height / box.height + box.y;\n if (l === 'C') {\n this[i][5] = (this[i][5] - box.x) * width / box.width + box.x;\n this[i][6] = (this[i][6] - box.y) * height / box.height + box.y;\n }\n } else if (l === 'A') {\n // resize radii\n this[i][1] = this[i][1] * width / box.width;\n this[i][2] = this[i][2] * height / box.height;\n\n // move position values\n this[i][6] = (this[i][6] - box.x) * width / box.width + box.x;\n this[i][7] = (this[i][7] - box.y) * height / box.height + box.y;\n }\n }\n return this;\n }\n\n // Convert array to string\n toString() {\n return arrayToString(this);\n }\n }\n\n const getClassForType = value => {\n const type = typeof value;\n if (type === 'number') {\n return SVGNumber;\n } else if (type === 'string') {\n if (Color.isColor(value)) {\n return Color;\n } else if (delimiter.test(value)) {\n return isPathLetter.test(value) ? PathArray : SVGArray;\n } else if (numberAndUnit.test(value)) {\n return SVGNumber;\n } else {\n return NonMorphable;\n }\n } else if (morphableTypes.indexOf(value.constructor) > -1) {\n return value.constructor;\n } else if (Array.isArray(value)) {\n return SVGArray;\n } else if (type === 'object') {\n return ObjectBag;\n } else {\n return NonMorphable;\n }\n };\n class Morphable {\n constructor(stepper) {\n this._stepper = stepper || new Ease('-');\n this._from = null;\n this._to = null;\n this._type = null;\n this._context = null;\n this._morphObj = null;\n }\n at(pos) {\n return this._morphObj.morph(this._from, this._to, pos, this._stepper, this._context);\n }\n done() {\n const complete = this._context.map(this._stepper.done).reduce(function (last, curr) {\n return last && curr;\n }, true);\n return complete;\n }\n from(val) {\n if (val == null) {\n return this._from;\n }\n this._from = this._set(val);\n return this;\n }\n stepper(stepper) {\n if (stepper == null) return this._stepper;\n this._stepper = stepper;\n return this;\n }\n to(val) {\n if (val == null) {\n return this._to;\n }\n this._to = this._set(val);\n return this;\n }\n type(type) {\n // getter\n if (type == null) {\n return this._type;\n }\n\n // setter\n this._type = type;\n return this;\n }\n _set(value) {\n if (!this._type) {\n this.type(getClassForType(value));\n }\n let result = new this._type(value);\n if (this._type === Color) {\n result = this._to ? result[this._to[4]]() : this._from ? result[this._from[4]]() : result;\n }\n if (this._type === ObjectBag) {\n result = this._to ? result.align(this._to) : this._from ? result.align(this._from) : result;\n }\n result = result.toConsumable();\n this._morphObj = this._morphObj || new this._type();\n this._context = this._context || Array.apply(null, Array(result.length)).map(Object).map(function (o) {\n o.done = true;\n return o;\n });\n return result;\n }\n }\n class NonMorphable {\n constructor(...args) {\n this.init(...args);\n }\n init(val) {\n val = Array.isArray(val) ? val[0] : val;\n this.value = val;\n return this;\n }\n toArray() {\n return [this.value];\n }\n valueOf() {\n return this.value;\n }\n }\n class TransformBag {\n constructor(...args) {\n this.init(...args);\n }\n init(obj) {\n if (Array.isArray(obj)) {\n obj = {\n scaleX: obj[0],\n scaleY: obj[1],\n shear: obj[2],\n rotate: obj[3],\n translateX: obj[4],\n translateY: obj[5],\n originX: obj[6],\n originY: obj[7]\n };\n }\n Object.assign(this, TransformBag.defaults, obj);\n return this;\n }\n toArray() {\n const v = this;\n return [v.scaleX, v.scaleY, v.shear, v.rotate, v.translateX, v.translateY, v.originX, v.originY];\n }\n }\n TransformBag.defaults = {\n scaleX: 1,\n scaleY: 1,\n shear: 0,\n rotate: 0,\n translateX: 0,\n translateY: 0,\n originX: 0,\n originY: 0\n };\n const sortByKey = (a, b) => {\n return a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0;\n };\n class ObjectBag {\n constructor(...args) {\n this.init(...args);\n }\n align(other) {\n const values = this.values;\n for (let i = 0, il = values.length; i < il; ++i) {\n // If the type is the same we only need to check if the color is in the correct format\n if (values[i + 1] === other[i + 1]) {\n if (values[i + 1] === Color && other[i + 7] !== values[i + 7]) {\n const space = other[i + 7];\n const color = new Color(this.values.splice(i + 3, 5))[space]().toArray();\n this.values.splice(i + 3, 0, ...color);\n }\n i += values[i + 2] + 2;\n continue;\n }\n if (!other[i + 1]) {\n return this;\n }\n\n // The types differ, so we overwrite the new type with the old one\n // And initialize it with the types default (e.g. black for color or 0 for number)\n const defaultObject = new other[i + 1]().toArray();\n\n // Than we fix the values array\n const toDelete = values[i + 2] + 3;\n values.splice(i, toDelete, other[i], other[i + 1], other[i + 2], ...defaultObject);\n i += values[i + 2] + 2;\n }\n return this;\n }\n init(objOrArr) {\n this.values = [];\n if (Array.isArray(objOrArr)) {\n this.values = objOrArr.slice();\n return;\n }\n objOrArr = objOrArr || {};\n const entries = [];\n for (const i in objOrArr) {\n const Type = getClassForType(objOrArr[i]);\n const val = new Type(objOrArr[i]).toArray();\n entries.push([i, Type, val.length, ...val]);\n }\n entries.sort(sortByKey);\n this.values = entries.reduce((last, curr) => last.concat(curr), []);\n return this;\n }\n toArray() {\n return this.values;\n }\n valueOf() {\n const obj = {};\n const arr = this.values;\n\n // for (var i = 0, len = arr.length; i < len; i += 2) {\n while (arr.length) {\n const key = arr.shift();\n const Type = arr.shift();\n const num = arr.shift();\n const values = arr.splice(0, num);\n obj[key] = new Type(values); // .valueOf()\n }\n return obj;\n }\n }\n const morphableTypes = [NonMorphable, TransformBag, ObjectBag];\n function registerMorphableType(type = []) {\n morphableTypes.push(...[].concat(type));\n }\n function makeMorphable() {\n extend(morphableTypes, {\n to(val) {\n return new Morphable().type(this.constructor).from(this.toArray()) // this.valueOf())\n .to(val);\n },\n fromArray(arr) {\n this.init(arr);\n return this;\n },\n toConsumable() {\n return this.toArray();\n },\n morph(from, to, pos, stepper, context) {\n const mapper = function (i, index) {\n return stepper.step(i, to[index], pos, context[index], context);\n };\n return this.fromArray(from.map(mapper));\n }\n });\n }\n\n class Path extends Shape {\n // Initialize node\n constructor(node, attrs = node) {\n super(nodeOrNew('path', node), attrs);\n }\n\n // Get array\n array() {\n return this._array || (this._array = new PathArray(this.attr('d')));\n }\n\n // Clear array cache\n clear() {\n delete this._array;\n return this;\n }\n\n // Set height of element\n height(height) {\n return height == null ? this.bbox().height : this.size(this.bbox().width, height);\n }\n\n // Move by left top corner\n move(x, y) {\n return this.attr('d', this.array().move(x, y));\n }\n\n // Plot new path\n plot(d) {\n return d == null ? this.array() : this.clear().attr('d', typeof d === 'string' ? d : this._array = new PathArray(d));\n }\n\n // Set element size to given width and height\n size(width, height) {\n const p = proportionalSize(this, width, height);\n return this.attr('d', this.array().size(p.width, p.height));\n }\n\n // Set width of element\n width(width) {\n return width == null ? this.bbox().width : this.size(width, this.bbox().height);\n }\n\n // Move by left top corner over x-axis\n x(x) {\n return x == null ? this.bbox().x : this.move(x, this.bbox().y);\n }\n\n // Move by left top corner over y-axis\n y(y) {\n return y == null ? this.bbox().y : this.move(this.bbox().x, y);\n }\n }\n\n // Define morphable array\n Path.prototype.MorphArray = PathArray;\n\n // Add parent method\n registerMethods({\n Container: {\n // Create a wrapped path element\n path: wrapWithAttrCheck(function (d) {\n // make sure plot is called as a setter\n return this.put(new Path()).plot(d || new PathArray());\n })\n }\n });\n register(Path, 'Path');\n\n // Get array\n function array() {\n return this._array || (this._array = new PointArray(this.attr('points')));\n }\n\n // Clear array cache\n function clear() {\n delete this._array;\n return this;\n }\n\n // Move by left top corner\n function move$2(x, y) {\n return this.attr('points', this.array().move(x, y));\n }\n\n // Plot new path\n function plot(p) {\n return p == null ? this.array() : this.clear().attr('points', typeof p === 'string' ? p : this._array = new PointArray(p));\n }\n\n // Set element size to given width and height\n function size$1(width, height) {\n const p = proportionalSize(this, width, height);\n return this.attr('points', this.array().size(p.width, p.height));\n }\n\n var poly = {\n __proto__: null,\n array: array,\n clear: clear,\n move: move$2,\n plot: plot,\n size: size$1\n };\n\n class Polygon extends Shape {\n // Initialize node\n constructor(node, attrs = node) {\n super(nodeOrNew('polygon', node), attrs);\n }\n }\n registerMethods({\n Container: {\n // Create a wrapped polygon element\n polygon: wrapWithAttrCheck(function (p) {\n // make sure plot is called as a setter\n return this.put(new Polygon()).plot(p || new PointArray());\n })\n }\n });\n extend(Polygon, pointed);\n extend(Polygon, poly);\n register(Polygon, 'Polygon');\n\n class Polyline extends Shape {\n // Initialize node\n constructor(node, attrs = node) {\n super(nodeOrNew('polyline', node), attrs);\n }\n }\n registerMethods({\n Container: {\n // Create a wrapped polygon element\n polyline: wrapWithAttrCheck(function (p) {\n // make sure plot is called as a setter\n return this.put(new Polyline()).plot(p || new PointArray());\n })\n }\n });\n extend(Polyline, pointed);\n extend(Polyline, poly);\n register(Polyline, 'Polyline');\n\n class Rect extends Shape {\n // Initialize node\n constructor(node, attrs = node) {\n super(nodeOrNew('rect', node), attrs);\n }\n }\n extend(Rect, {\n rx,\n ry\n });\n registerMethods({\n Container: {\n // Create a rect element\n rect: wrapWithAttrCheck(function (width, height) {\n return this.put(new Rect()).size(width, height);\n })\n }\n });\n register(Rect, 'Rect');\n\n class Queue {\n constructor() {\n this._first = null;\n this._last = null;\n }\n\n // Shows us the first item in the list\n first() {\n return this._first && this._first.value;\n }\n\n // Shows us the last item in the list\n last() {\n return this._last && this._last.value;\n }\n push(value) {\n // An item stores an id and the provided value\n const item = typeof value.next !== 'undefined' ? value : {\n value: value,\n next: null,\n prev: null\n };\n\n // Deal with the queue being empty or populated\n if (this._last) {\n item.prev = this._last;\n this._last.next = item;\n this._last = item;\n } else {\n this._last = item;\n this._first = item;\n }\n\n // Return the current item\n return item;\n }\n\n // Removes the item that was returned from the push\n remove(item) {\n // Relink the previous item\n if (item.prev) item.prev.next = item.next;\n if (item.next) item.next.prev = item.prev;\n if (item === this._last) this._last = item.prev;\n if (item === this._first) this._first = item.next;\n\n // Invalidate item\n item.prev = null;\n item.next = null;\n }\n shift() {\n // Check if we have a value\n const remove = this._first;\n if (!remove) return null;\n\n // If we do, remove it and relink things\n this._first = remove.next;\n if (this._first) this._first.prev = null;\n this._last = this._first ? this._last : null;\n return remove.value;\n }\n }\n\n const Animator = {\n nextDraw: null,\n frames: new Queue(),\n timeouts: new Queue(),\n immediates: new Queue(),\n timer: () => globals.window.performance || globals.window.Date,\n transforms: [],\n frame(fn) {\n // Store the node\n const node = Animator.frames.push({\n run: fn\n });\n\n // Request an animation frame if we don't have one\n if (Animator.nextDraw === null) {\n Animator.nextDraw = globals.window.requestAnimationFrame(Animator._draw);\n }\n\n // Return the node so we can remove it easily\n return node;\n },\n timeout(fn, delay) {\n delay = delay || 0;\n\n // Work out when the event should fire\n const time = Animator.timer().now() + delay;\n\n // Add the timeout to the end of the queue\n const node = Animator.timeouts.push({\n run: fn,\n time: time\n });\n\n // Request another animation frame if we need one\n if (Animator.nextDraw === null) {\n Animator.nextDraw = globals.window.requestAnimationFrame(Animator._draw);\n }\n return node;\n },\n immediate(fn) {\n // Add the immediate fn to the end of the queue\n const node = Animator.immediates.push(fn);\n // Request another animation frame if we need one\n if (Animator.nextDraw === null) {\n Animator.nextDraw = globals.window.requestAnimationFrame(Animator._draw);\n }\n return node;\n },\n cancelFrame(node) {\n node != null && Animator.frames.remove(node);\n },\n clearTimeout(node) {\n node != null && Animator.timeouts.remove(node);\n },\n cancelImmediate(node) {\n node != null && Animator.immediates.remove(node);\n },\n _draw(now) {\n // Run all the timeouts we can run, if they are not ready yet, add them\n // to the end of the queue immediately! (bad timeouts!!! [sarcasm])\n let nextTimeout = null;\n const lastTimeout = Animator.timeouts.last();\n while (nextTimeout = Animator.timeouts.shift()) {\n // Run the timeout if its time, or push it to the end\n if (now >= nextTimeout.time) {\n nextTimeout.run();\n } else {\n Animator.timeouts.push(nextTimeout);\n }\n\n // If we hit the last item, we should stop shifting out more items\n if (nextTimeout === lastTimeout) break;\n }\n\n // Run all of the animation frames\n let nextFrame = null;\n const lastFrame = Animator.frames.last();\n while (nextFrame !== lastFrame && (nextFrame = Animator.frames.shift())) {\n nextFrame.run(now);\n }\n let nextImmediate = null;\n while (nextImmediate = Animator.immediates.shift()) {\n nextImmediate();\n }\n\n // If we have remaining timeouts or frames, draw until we don't anymore\n Animator.nextDraw = Animator.timeouts.first() || Animator.frames.first() ? globals.window.requestAnimationFrame(Animator._draw) : null;\n }\n };\n\n const makeSchedule = function (runnerInfo) {\n const start = runnerInfo.start;\n const duration = runnerInfo.runner.duration();\n const end = start + duration;\n return {\n start: start,\n duration: duration,\n end: end,\n runner: runnerInfo.runner\n };\n };\n const defaultSource = function () {\n const w = globals.window;\n return (w.performance || w.Date).now();\n };\n class Timeline extends EventTarget {\n // Construct a new timeline on the given element\n constructor(timeSource = defaultSource) {\n super();\n this._timeSource = timeSource;\n\n // terminate resets all variables to their initial state\n this.terminate();\n }\n active() {\n return !!this._nextFrame;\n }\n finish() {\n // Go to end and pause\n this.time(this.getEndTimeOfTimeline() + 1);\n return this.pause();\n }\n\n // Calculates the end of the timeline\n getEndTime() {\n const lastRunnerInfo = this.getLastRunnerInfo();\n const lastDuration = lastRunnerInfo ? lastRunnerInfo.runner.duration() : 0;\n const lastStartTime = lastRunnerInfo ? lastRunnerInfo.start : this._time;\n return lastStartTime + lastDuration;\n }\n getEndTimeOfTimeline() {\n const endTimes = this._runners.map(i => i.start + i.runner.duration());\n return Math.max(0, ...endTimes);\n }\n getLastRunnerInfo() {\n return this.getRunnerInfoById(this._lastRunnerId);\n }\n getRunnerInfoById(id) {\n return this._runners[this._runnerIds.indexOf(id)] || null;\n }\n pause() {\n this._paused = true;\n return this._continue();\n }\n persist(dtOrForever) {\n if (dtOrForever == null) return this._persist;\n this._persist = dtOrForever;\n return this;\n }\n play() {\n // Now make sure we are not paused and continue the animation\n this._paused = false;\n return this.updateTime()._continue();\n }\n reverse(yes) {\n const currentSpeed = this.speed();\n if (yes == null) return this.speed(-currentSpeed);\n const positive = Math.abs(currentSpeed);\n return this.speed(yes ? -positive : positive);\n }\n\n // schedules a runner on the timeline\n schedule(runner, delay, when) {\n if (runner == null) {\n return this._runners.map(makeSchedule);\n }\n\n // The start time for the next animation can either be given explicitly,\n // derived from the current timeline time or it can be relative to the\n // last start time to chain animations directly\n\n let absoluteStartTime = 0;\n const endTime = this.getEndTime();\n delay = delay || 0;\n\n // Work out when to start the animation\n if (when == null || when === 'last' || when === 'after') {\n // Take the last time and increment\n absoluteStartTime = endTime;\n } else if (when === 'absolute' || when === 'start') {\n absoluteStartTime = delay;\n delay = 0;\n } else if (when === 'now') {\n absoluteStartTime = this._time;\n } else if (when === 'relative') {\n const runnerInfo = this.getRunnerInfoById(runner.id);\n if (runnerInfo) {\n absoluteStartTime = runnerInfo.start + delay;\n delay = 0;\n }\n } else if (when === 'with-last') {\n const lastRunnerInfo = this.getLastRunnerInfo();\n const lastStartTime = lastRunnerInfo ? lastRunnerInfo.start : this._time;\n absoluteStartTime = lastStartTime;\n } else {\n throw new Error('Invalid value for the \"when\" parameter');\n }\n\n // Manage runner\n runner.unschedule();\n runner.timeline(this);\n const persist = runner.persist();\n const runnerInfo = {\n persist: persist === null ? this._persist : persist,\n start: absoluteStartTime + delay,\n runner\n };\n this._lastRunnerId = runner.id;\n this._runners.push(runnerInfo);\n this._runners.sort((a, b) => a.start - b.start);\n this._runnerIds = this._runners.map(info => info.runner.id);\n this.updateTime()._continue();\n return this;\n }\n seek(dt) {\n return this.time(this._time + dt);\n }\n source(fn) {\n if (fn == null) return this._timeSource;\n this._timeSource = fn;\n return this;\n }\n speed(speed) {\n if (speed == null) return this._speed;\n this._speed = speed;\n return this;\n }\n stop() {\n // Go to start and pause\n this.time(0);\n return this.pause();\n }\n time(time) {\n if (time == null) return this._time;\n this._time = time;\n return this._continue(true);\n }\n\n // Remove the runner from this timeline\n unschedule(runner) {\n const index = this._runnerIds.indexOf(runner.id);\n if (index < 0) return this;\n this._runners.splice(index, 1);\n this._runnerIds.splice(index, 1);\n runner.timeline(null);\n return this;\n }\n\n // Makes sure, that after pausing the time doesn't jump\n updateTime() {\n if (!this.active()) {\n this._lastSourceTime = this._timeSource();\n }\n return this;\n }\n\n // Checks if we are running and continues the animation\n _continue(immediateStep = false) {\n Animator.cancelFrame(this._nextFrame);\n this._nextFrame = null;\n if (immediateStep) return this._stepImmediate();\n if (this._paused) return this;\n this._nextFrame = Animator.frame(this._step);\n return this;\n }\n _stepFn(immediateStep = false) {\n // Get the time delta from the last time and update the time\n const time = this._timeSource();\n let dtSource = time - this._lastSourceTime;\n if (immediateStep) dtSource = 0;\n const dtTime = this._speed * dtSource + (this._time - this._lastStepTime);\n this._lastSourceTime = time;\n\n // Only update the time if we use the timeSource.\n // Otherwise use the current time\n if (!immediateStep) {\n // Update the time\n this._time += dtTime;\n this._time = this._time < 0 ? 0 : this._time;\n }\n this._lastStepTime = this._time;\n this.fire('time', this._time);\n\n // This is for the case that the timeline was seeked so that the time\n // is now before the startTime of the runner. That is why we need to set\n // the runner to position 0\n\n // FIXME:\n // However, resetting in insertion order leads to bugs. Considering the case,\n // where 2 runners change the same attribute but in different times,\n // resetting both of them will lead to the case where the later defined\n // runner always wins the reset even if the other runner started earlier\n // and therefore should win the attribute battle\n // this can be solved by resetting them backwards\n for (let k = this._runners.length; k--;) {\n // Get and run the current runner and ignore it if its inactive\n const runnerInfo = this._runners[k];\n const runner = runnerInfo.runner;\n\n // Make sure that we give the actual difference\n // between runner start time and now\n const dtToStart = this._time - runnerInfo.start;\n\n // Dont run runner if not started yet\n // and try to reset it\n if (dtToStart <= 0) {\n runner.reset();\n }\n }\n\n // Run all of the runners directly\n let runnersLeft = false;\n for (let i = 0, len = this._runners.length; i < len; i++) {\n // Get and run the current runner and ignore it if its inactive\n const runnerInfo = this._runners[i];\n const runner = runnerInfo.runner;\n let dt = dtTime;\n\n // Make sure that we give the actual difference\n // between runner start time and now\n const dtToStart = this._time - runnerInfo.start;\n\n // Dont run runner if not started yet\n if (dtToStart <= 0) {\n runnersLeft = true;\n continue;\n } else if (dtToStart < dt) {\n // Adjust dt to make sure that animation is on point\n dt = dtToStart;\n }\n if (!runner.active()) continue;\n\n // If this runner is still going, signal that we need another animation\n // frame, otherwise, remove the completed runner\n const finished = runner.step(dt).done;\n if (!finished) {\n runnersLeft = true;\n // continue\n } else if (runnerInfo.persist !== true) {\n // runner is finished. And runner might get removed\n const endTime = runner.duration() - runner.time() + this._time;\n if (endTime + runnerInfo.persist < this._time) {\n // Delete runner and correct index\n runner.unschedule();\n --i;\n --len;\n }\n }\n }\n\n // Basically: we continue when there are runners right from us in time\n // when -->, and when runners are left from us when <--\n if (runnersLeft && !(this._speed < 0 && this._time === 0) || this._runnerIds.length && this._speed < 0 && this._time > 0) {\n this._continue();\n } else {\n this.pause();\n this.fire('finished');\n }\n return this;\n }\n terminate() {\n // cleanup memory\n\n // Store the timing variables\n this._startTime = 0;\n this._speed = 1.0;\n\n // Determines how long a runner is hold in memory. Can be a dt or true/false\n this._persist = 0;\n\n // Keep track of the running animations and their starting parameters\n this._nextFrame = null;\n this._paused = true;\n this._runners = [];\n this._runnerIds = [];\n this._lastRunnerId = -1;\n this._time = 0;\n this._lastSourceTime = 0;\n this._lastStepTime = 0;\n\n // Make sure that step is always called in class context\n this._step = this._stepFn.bind(this, false);\n this._stepImmediate = this._stepFn.bind(this, true);\n }\n }\n registerMethods({\n Element: {\n timeline: function (timeline) {\n if (timeline == null) {\n this._timeline = this._timeline || new Timeline();\n return this._timeline;\n } else {\n this._timeline = timeline;\n return this;\n }\n }\n }\n });\n\n class Runner extends EventTarget {\n constructor(options) {\n super();\n\n // Store a unique id on the runner, so that we can identify it later\n this.id = Runner.id++;\n\n // Ensure a default value\n options = options == null ? timeline.duration : options;\n\n // Ensure that we get a controller\n options = typeof options === 'function' ? new Controller(options) : options;\n\n // Declare all of the variables\n this._element = null;\n this._timeline = null;\n this.done = false;\n this._queue = [];\n\n // Work out the stepper and the duration\n this._duration = typeof options === 'number' && options;\n this._isDeclarative = options instanceof Controller;\n this._stepper = this._isDeclarative ? options : new Ease();\n\n // We copy the current values from the timeline because they can change\n this._history = {};\n\n // Store the state of the runner\n this.enabled = true;\n this._time = 0;\n this._lastTime = 0;\n\n // At creation, the runner is in reset state\n this._reseted = true;\n\n // Save transforms applied to this runner\n this.transforms = new Matrix();\n this.transformId = 1;\n\n // Looping variables\n this._haveReversed = false;\n this._reverse = false;\n this._loopsDone = 0;\n this._swing = false;\n this._wait = 0;\n this._times = 1;\n this._frameId = null;\n\n // Stores how long a runner is stored after being done\n this._persist = this._isDeclarative ? true : null;\n }\n static sanitise(duration, delay, when) {\n // Initialise the default parameters\n let times = 1;\n let swing = false;\n let wait = 0;\n duration = duration ?? timeline.duration;\n delay = delay ?? timeline.delay;\n when = when || 'last';\n\n // If we have an object, unpack the values\n if (typeof duration === 'object' && !(duration instanceof Stepper)) {\n delay = duration.delay ?? delay;\n when = duration.when ?? when;\n swing = duration.swing || swing;\n times = duration.times ?? times;\n wait = duration.wait ?? wait;\n duration = duration.duration ?? timeline.duration;\n }\n return {\n duration: duration,\n delay: delay,\n swing: swing,\n times: times,\n wait: wait,\n when: when\n };\n }\n active(enabled) {\n if (enabled == null) return this.enabled;\n this.enabled = enabled;\n return this;\n }\n\n /*\n Private Methods\n ===============\n Methods that shouldn't be used externally\n */\n addTransform(transform) {\n this.transforms.lmultiplyO(transform);\n return this;\n }\n after(fn) {\n return this.on('finished', fn);\n }\n animate(duration, delay, when) {\n const o = Runner.sanitise(duration, delay, when);\n const runner = new Runner(o.duration);\n if (this._timeline) runner.timeline(this._timeline);\n if (this._element) runner.element(this._element);\n return runner.loop(o).schedule(o.delay, o.when);\n }\n clearTransform() {\n this.transforms = new Matrix();\n return this;\n }\n\n // TODO: Keep track of all transformations so that deletion is faster\n clearTransformsFromQueue() {\n if (!this.done || !this._timeline || !this._timeline._runnerIds.includes(this.id)) {\n this._queue = this._queue.filter(item => {\n return !item.isTransform;\n });\n }\n }\n delay(delay) {\n return this.animate(0, delay);\n }\n duration() {\n return this._times * (this._wait + this._duration) - this._wait;\n }\n during(fn) {\n return this.queue(null, fn);\n }\n ease(fn) {\n this._stepper = new Ease(fn);\n return this;\n }\n /*\n Runner Definitions\n ==================\n These methods help us define the runtime behaviour of the Runner or they\n help us make new runners from the current runner\n */\n\n element(element) {\n if (element == null) return this._element;\n this._element = element;\n element._prepareRunner();\n return this;\n }\n finish() {\n return this.step(Infinity);\n }\n loop(times, swing, wait) {\n // Deal with the user passing in an object\n if (typeof times === 'object') {\n swing = times.swing;\n wait = times.wait;\n times = times.times;\n }\n\n // Sanitise the values and store them\n this._times = times || Infinity;\n this._swing = swing || false;\n this._wait = wait || 0;\n\n // Allow true to be passed\n if (this._times === true) {\n this._times = Infinity;\n }\n return this;\n }\n loops(p) {\n const loopDuration = this._duration + this._wait;\n if (p == null) {\n const loopsDone = Math.floor(this._time / loopDuration);\n const relativeTime = this._time - loopsDone * loopDuration;\n const position = relativeTime / this._duration;\n return Math.min(loopsDone + position, this._times);\n }\n const whole = Math.floor(p);\n const partial = p % 1;\n const time = loopDuration * whole + this._duration * partial;\n return this.time(time);\n }\n persist(dtOrForever) {\n if (dtOrForever == null) return this._persist;\n this._persist = dtOrForever;\n return this;\n }\n position(p) {\n // Get all of the variables we need\n const x = this._time;\n const d = this._duration;\n const w = this._wait;\n const t = this._times;\n const s = this._swing;\n const r = this._reverse;\n let position;\n if (p == null) {\n /*\n This function converts a time to a position in the range [0, 1]\n The full explanation can be found in this desmos demonstration\n https://www.desmos.com/calculator/u4fbavgche\n The logic is slightly simplified here because we can use booleans\n */\n\n // Figure out the value without thinking about the start or end time\n const f = function (x) {\n const swinging = s * Math.floor(x % (2 * (w + d)) / (w + d));\n const backwards = swinging && !r || !swinging && r;\n const uncliped = Math.pow(-1, backwards) * (x % (w + d)) / d + backwards;\n const clipped = Math.max(Math.min(uncliped, 1), 0);\n return clipped;\n };\n\n // Figure out the value by incorporating the start time\n const endTime = t * (w + d) - w;\n position = x <= 0 ? Math.round(f(1e-5)) : x < endTime ? f(x) : Math.round(f(endTime - 1e-5));\n return position;\n }\n\n // Work out the loops done and add the position to the loops done\n const loopsDone = Math.floor(this.loops());\n const swingForward = s && loopsDone % 2 === 0;\n const forwards = swingForward && !r || r && swingForward;\n position = loopsDone + (forwards ? p : 1 - p);\n return this.loops(position);\n }\n progress(p) {\n if (p == null) {\n return Math.min(1, this._time / this.duration());\n }\n return this.time(p * this.duration());\n }\n\n /*\n Basic Functionality\n ===================\n These methods allow us to attach basic functions to the runner directly\n */\n queue(initFn, runFn, retargetFn, isTransform) {\n this._queue.push({\n initialiser: initFn || noop,\n runner: runFn || noop,\n retarget: retargetFn,\n isTransform: isTransform,\n initialised: false,\n finished: false\n });\n const timeline = this.timeline();\n timeline && this.timeline()._continue();\n return this;\n }\n reset() {\n if (this._reseted) return this;\n this.time(0);\n this._reseted = true;\n return this;\n }\n reverse(reverse) {\n this._reverse = reverse == null ? !this._reverse : reverse;\n return this;\n }\n schedule(timeline, delay, when) {\n // The user doesn't need to pass a timeline if we already have one\n if (!(timeline instanceof Timeline)) {\n when = delay;\n delay = timeline;\n timeline = this.timeline();\n }\n\n // If there is no timeline, yell at the user...\n if (!timeline) {\n throw Error('Runner cannot be scheduled without timeline');\n }\n\n // Schedule the runner on the timeline provided\n timeline.schedule(this, delay, when);\n return this;\n }\n step(dt) {\n // If we are inactive, this stepper just gets skipped\n if (!this.enabled) return this;\n\n // Update the time and get the new position\n dt = dt == null ? 16 : dt;\n this._time += dt;\n const position = this.position();\n\n // Figure out if we need to run the stepper in this frame\n const running = this._lastPosition !== position && this._time >= 0;\n this._lastPosition = position;\n\n // Figure out if we just started\n const duration = this.duration();\n const justStarted = this._lastTime <= 0 && this._time > 0;\n const justFinished = this._lastTime < duration && this._time >= duration;\n this._lastTime = this._time;\n if (justStarted) {\n this.fire('start', this);\n }\n\n // Work out if the runner is finished set the done flag here so animations\n // know, that they are running in the last step (this is good for\n // transformations which can be merged)\n const declarative = this._isDeclarative;\n this.done = !declarative && !justFinished && this._time >= duration;\n\n // Runner is running. So its not in reset state anymore\n this._reseted = false;\n let converged = false;\n // Call initialise and the run function\n if (running || declarative) {\n this._initialise(running);\n\n // clear the transforms on this runner so they dont get added again and again\n this.transforms = new Matrix();\n converged = this._run(declarative ? dt : position);\n this.fire('step', this);\n }\n // correct the done flag here\n // declarative animations itself know when they converged\n this.done = this.done || converged && declarative;\n if (justFinished) {\n this.fire('finished', this);\n }\n return this;\n }\n\n /*\n Runner animation methods\n ========================\n Control how the animation plays\n */\n time(time) {\n if (time == null) {\n return this._time;\n }\n const dt = time - this._time;\n this.step(dt);\n return this;\n }\n timeline(timeline) {\n // check explicitly for undefined so we can set the timeline to null\n if (typeof timeline === 'undefined') return this._timeline;\n this._timeline = timeline;\n return this;\n }\n unschedule() {\n const timeline = this.timeline();\n timeline && timeline.unschedule(this);\n return this;\n }\n\n // Run each initialise function in the runner if required\n _initialise(running) {\n // If we aren't running, we shouldn't initialise when not declarative\n if (!running && !this._isDeclarative) return;\n\n // Loop through all of the initialisers\n for (let i = 0, len = this._queue.length; i < len; ++i) {\n // Get the current initialiser\n const current = this._queue[i];\n\n // Determine whether we need to initialise\n const needsIt = this._isDeclarative || !current.initialised && running;\n running = !current.finished;\n\n // Call the initialiser if we need to\n if (needsIt && running) {\n current.initialiser.call(this);\n current.initialised = true;\n }\n }\n }\n\n // Save a morpher to the morpher list so that we can retarget it later\n _rememberMorpher(method, morpher) {\n this._history[method] = {\n morpher: morpher,\n caller: this._queue[this._queue.length - 1]\n };\n\n // We have to resume the timeline in case a controller\n // is already done without being ever run\n // This can happen when e.g. this is done:\n // anim = el.animate(new SVG.Spring)\n // and later\n // anim.move(...)\n if (this._isDeclarative) {\n const timeline = this.timeline();\n timeline && timeline.play();\n }\n }\n\n // Try to set the target for a morpher if the morpher exists, otherwise\n // Run each run function for the position or dt given\n _run(positionOrDt) {\n // Run all of the _queue directly\n let allfinished = true;\n for (let i = 0, len = this._queue.length; i < len; ++i) {\n // Get the current function to run\n const current = this._queue[i];\n\n // Run the function if its not finished, we keep track of the finished\n // flag for the sake of declarative _queue\n const converged = current.runner.call(this, positionOrDt);\n current.finished = current.finished || converged === true;\n allfinished = allfinished && current.finished;\n }\n\n // We report when all of the constructors are finished\n return allfinished;\n }\n\n // do nothing and return false\n _tryRetarget(method, target, extra) {\n if (this._history[method]) {\n // if the last method wasn't even initialised, throw it away\n if (!this._history[method].caller.initialised) {\n const index = this._queue.indexOf(this._history[method].caller);\n this._queue.splice(index, 1);\n return false;\n }\n\n // for the case of transformations, we use the special retarget function\n // which has access to the outer scope\n if (this._history[method].caller.retarget) {\n this._history[method].caller.retarget.call(this, target, extra);\n // for everything else a simple morpher change is sufficient\n } else {\n this._history[method].morpher.to(target);\n }\n this._history[method].caller.finished = false;\n const timeline = this.timeline();\n timeline && timeline.play();\n return true;\n }\n return false;\n }\n }\n Runner.id = 0;\n class FakeRunner {\n constructor(transforms = new Matrix(), id = -1, done = true) {\n this.transforms = transforms;\n this.id = id;\n this.done = done;\n }\n clearTransformsFromQueue() {}\n }\n extend([Runner, FakeRunner], {\n mergeWith(runner) {\n return new FakeRunner(runner.transforms.lmultiply(this.transforms), runner.id);\n }\n });\n\n // FakeRunner.emptyRunner = new FakeRunner()\n\n const lmultiply = (last, curr) => last.lmultiplyO(curr);\n const getRunnerTransform = runner => runner.transforms;\n function mergeTransforms() {\n // Find the matrix to apply to the element and apply it\n const runners = this._transformationRunners.runners;\n const netTransform = runners.map(getRunnerTransform).reduce(lmultiply, new Matrix());\n this.transform(netTransform);\n this._transformationRunners.merge();\n if (this._transformationRunners.length() === 1) {\n this._frameId = null;\n }\n }\n class RunnerArray {\n constructor() {\n this.runners = [];\n this.ids = [];\n }\n add(runner) {\n if (this.runners.includes(runner)) return;\n const id = runner.id + 1;\n this.runners.push(runner);\n this.ids.push(id);\n return this;\n }\n clearBefore(id) {\n const deleteCnt = this.ids.indexOf(id + 1) || 1;\n this.ids.splice(0, deleteCnt, 0);\n this.runners.splice(0, deleteCnt, new FakeRunner()).forEach(r => r.clearTransformsFromQueue());\n return this;\n }\n edit(id, newRunner) {\n const index = this.ids.indexOf(id + 1);\n this.ids.splice(index, 1, id + 1);\n this.runners.splice(index, 1, newRunner);\n return this;\n }\n getByID(id) {\n return this.runners[this.ids.indexOf(id + 1)];\n }\n length() {\n return this.ids.length;\n }\n merge() {\n let lastRunner = null;\n for (let i = 0; i < this.runners.length; ++i) {\n const runner = this.runners[i];\n const condition = lastRunner && runner.done && lastRunner.done && (\n // don't merge runner when persisted on timeline\n !runner._timeline || !runner._timeline._runnerIds.includes(runner.id)) && (!lastRunner._timeline || !lastRunner._timeline._runnerIds.includes(lastRunner.id));\n if (condition) {\n // the +1 happens in the function\n this.remove(runner.id);\n const newRunner = runner.mergeWith(lastRunner);\n this.edit(lastRunner.id, newRunner);\n lastRunner = newRunner;\n --i;\n } else {\n lastRunner = runner;\n }\n }\n return this;\n }\n remove(id) {\n const index = this.ids.indexOf(id + 1);\n this.ids.splice(index, 1);\n this.runners.splice(index, 1);\n return this;\n }\n }\n registerMethods({\n Element: {\n animate(duration, delay, when) {\n const o = Runner.sanitise(duration, delay, when);\n const timeline = this.timeline();\n return new Runner(o.duration).loop(o).element(this).timeline(timeline.play()).schedule(o.delay, o.when);\n },\n delay(by, when) {\n return this.animate(0, by, when);\n },\n // this function searches for all runners on the element and deletes the ones\n // which run before the current one. This is because absolute transformations\n // overwrite anything anyway so there is no need to waste time computing\n // other runners\n _clearTransformRunnersBefore(currentRunner) {\n this._transformationRunners.clearBefore(currentRunner.id);\n },\n _currentTransform(current) {\n return this._transformationRunners.runners\n // we need the equal sign here to make sure, that also transformations\n // on the same runner which execute before the current transformation are\n // taken into account\n .filter(runner => runner.id <= current.id).map(getRunnerTransform).reduce(lmultiply, new Matrix());\n },\n _addRunner(runner) {\n this._transformationRunners.add(runner);\n\n // Make sure that the runner merge is executed at the very end of\n // all Animator functions. That is why we use immediate here to execute\n // the merge right after all frames are run\n Animator.cancelImmediate(this._frameId);\n this._frameId = Animator.immediate(mergeTransforms.bind(this));\n },\n _prepareRunner() {\n if (this._frameId == null) {\n this._transformationRunners = new RunnerArray().add(new FakeRunner(new Matrix(this)));\n }\n }\n }\n });\n\n // Will output the elements from array A that are not in the array B\n const difference = (a, b) => a.filter(x => !b.includes(x));\n extend(Runner, {\n attr(a, v) {\n return this.styleAttr('attr', a, v);\n },\n // Add animatable styles\n css(s, v) {\n return this.styleAttr('css', s, v);\n },\n styleAttr(type, nameOrAttrs, val) {\n if (typeof nameOrAttrs === 'string') {\n return this.styleAttr(type, {\n [nameOrAttrs]: val\n });\n }\n let attrs = nameOrAttrs;\n if (this._tryRetarget(type, attrs)) return this;\n let morpher = new Morphable(this._stepper).to(attrs);\n let keys = Object.keys(attrs);\n this.queue(function () {\n morpher = morpher.from(this.element()[type](keys));\n }, function (pos) {\n this.element()[type](morpher.at(pos).valueOf());\n return morpher.done();\n }, function (newToAttrs) {\n // Check if any new keys were added\n const newKeys = Object.keys(newToAttrs);\n const differences = difference(newKeys, keys);\n\n // If their are new keys, initialize them and add them to morpher\n if (differences.length) {\n // Get the values\n const addedFromAttrs = this.element()[type](differences);\n\n // Get the already initialized values\n const oldFromAttrs = new ObjectBag(morpher.from()).valueOf();\n\n // Merge old and new\n Object.assign(oldFromAttrs, addedFromAttrs);\n morpher.from(oldFromAttrs);\n }\n\n // Get the object from the morpher\n const oldToAttrs = new ObjectBag(morpher.to()).valueOf();\n\n // Merge in new attributes\n Object.assign(oldToAttrs, newToAttrs);\n\n // Change morpher target\n morpher.to(oldToAttrs);\n\n // Make sure that we save the work we did so we don't need it to do again\n keys = newKeys;\n attrs = newToAttrs;\n });\n this._rememberMorpher(type, morpher);\n return this;\n },\n zoom(level, point) {\n if (this._tryRetarget('zoom', level, point)) return this;\n let morpher = new Morphable(this._stepper).to(new SVGNumber(level));\n this.queue(function () {\n morpher = morpher.from(this.element().zoom());\n }, function (pos) {\n this.element().zoom(morpher.at(pos), point);\n return morpher.done();\n }, function (newLevel, newPoint) {\n point = newPoint;\n morpher.to(newLevel);\n });\n this._rememberMorpher('zoom', morpher);\n return this;\n },\n /**\n ** absolute transformations\n **/\n\n //\n // M v -----|-----(D M v = F v)------|-----> T v\n //\n // 1. define the final state (T) and decompose it (once)\n // t = [tx, ty, the, lam, sy, sx]\n // 2. on every frame: pull the current state of all previous transforms\n // (M - m can change)\n // and then write this as m = [tx0, ty0, the0, lam0, sy0, sx0]\n // 3. Find the interpolated matrix F(pos) = m + pos * (t - m)\n // - Note F(0) = M\n // - Note F(1) = T\n // 4. Now you get the delta matrix as a result: D = F * inv(M)\n\n transform(transforms, relative, affine) {\n // If we have a declarative function, we should retarget it if possible\n relative = transforms.relative || relative;\n if (this._isDeclarative && !relative && this._tryRetarget('transform', transforms)) {\n return this;\n }\n\n // Parse the parameters\n const isMatrix = Matrix.isMatrixLike(transforms);\n affine = transforms.affine != null ? transforms.affine : affine != null ? affine : !isMatrix;\n\n // Create a morpher and set its type\n const morpher = new Morphable(this._stepper).type(affine ? TransformBag : Matrix);\n let origin;\n let element;\n let current;\n let currentAngle;\n let startTransform;\n function setup() {\n // make sure element and origin is defined\n element = element || this.element();\n origin = origin || getOrigin(transforms, element);\n startTransform = new Matrix(relative ? undefined : element);\n\n // add the runner to the element so it can merge transformations\n element._addRunner(this);\n\n // Deactivate all transforms that have run so far if we are absolute\n if (!relative) {\n element._clearTransformRunnersBefore(this);\n }\n }\n function run(pos) {\n // clear all other transforms before this in case something is saved\n // on this runner. We are absolute. We dont need these!\n if (!relative) this.clearTransform();\n const {\n x,\n y\n } = new Point(origin).transform(element._currentTransform(this));\n let target = new Matrix({\n ...transforms,\n origin: [x, y]\n });\n let start = this._isDeclarative && current ? current : startTransform;\n if (affine) {\n target = target.decompose(x, y);\n start = start.decompose(x, y);\n\n // Get the current and target angle as it was set\n const rTarget = target.rotate;\n const rCurrent = start.rotate;\n\n // Figure out the shortest path to rotate directly\n const possibilities = [rTarget - 360, rTarget, rTarget + 360];\n const distances = possibilities.map(a => Math.abs(a - rCurrent));\n const shortest = Math.min(...distances);\n const index = distances.indexOf(shortest);\n target.rotate = possibilities[index];\n }\n if (relative) {\n // we have to be careful here not to overwrite the rotation\n // with the rotate method of Matrix\n if (!isMatrix) {\n target.rotate = transforms.rotate || 0;\n }\n if (this._isDeclarative && currentAngle) {\n start.rotate = currentAngle;\n }\n }\n morpher.from(start);\n morpher.to(target);\n const affineParameters = morpher.at(pos);\n currentAngle = affineParameters.rotate;\n current = new Matrix(affineParameters);\n this.addTransform(current);\n element._addRunner(this);\n return morpher.done();\n }\n function retarget(newTransforms) {\n // only get a new origin if it changed since the last call\n if ((newTransforms.origin || 'center').toString() !== (transforms.origin || 'center').toString()) {\n origin = getOrigin(newTransforms, element);\n }\n\n // overwrite the old transformations with the new ones\n transforms = {\n ...newTransforms,\n origin\n };\n }\n this.queue(setup, run, retarget, true);\n this._isDeclarative && this._rememberMorpher('transform', morpher);\n return this;\n },\n // Animatable x-axis\n x(x) {\n return this._queueNumber('x', x);\n },\n // Animatable y-axis\n y(y) {\n return this._queueNumber('y', y);\n },\n ax(x) {\n return this._queueNumber('ax', x);\n },\n ay(y) {\n return this._queueNumber('ay', y);\n },\n dx(x = 0) {\n return this._queueNumberDelta('x', x);\n },\n dy(y = 0) {\n return this._queueNumberDelta('y', y);\n },\n dmove(x, y) {\n return this.dx(x).dy(y);\n },\n _queueNumberDelta(method, to) {\n to = new SVGNumber(to);\n\n // Try to change the target if we have this method already registered\n if (this._tryRetarget(method, to)) return this;\n\n // Make a morpher and queue the animation\n const morpher = new Morphable(this._stepper).to(to);\n let from = null;\n this.queue(function () {\n from = this.element()[method]();\n morpher.from(from);\n morpher.to(from + to);\n }, function (pos) {\n this.element()[method](morpher.at(pos));\n return morpher.done();\n }, function (newTo) {\n morpher.to(from + new SVGNumber(newTo));\n });\n\n // Register the morpher so that if it is changed again, we can retarget it\n this._rememberMorpher(method, morpher);\n return this;\n },\n _queueObject(method, to) {\n // Try to change the target if we have this method already registered\n if (this._tryRetarget(method, to)) return this;\n\n // Make a morpher and queue the animation\n const morpher = new Morphable(this._stepper).to(to);\n this.queue(function () {\n morpher.from(this.element()[method]());\n }, function (pos) {\n this.element()[method](morpher.at(pos));\n return morpher.done();\n });\n\n // Register the morpher so that if it is changed again, we can retarget it\n this._rememberMorpher(method, morpher);\n return this;\n },\n _queueNumber(method, value) {\n return this._queueObject(method, new SVGNumber(value));\n },\n // Animatable center x-axis\n cx(x) {\n return this._queueNumber('cx', x);\n },\n // Animatable center y-axis\n cy(y) {\n return this._queueNumber('cy', y);\n },\n // Add animatable move\n move(x, y) {\n return this.x(x).y(y);\n },\n amove(x, y) {\n return this.ax(x).ay(y);\n },\n // Add animatable center\n center(x, y) {\n return this.cx(x).cy(y);\n },\n // Add animatable size\n size(width, height) {\n // animate bbox based size for all other elements\n let box;\n if (!width || !height) {\n box = this._element.bbox();\n }\n if (!width) {\n width = box.width / box.height * height;\n }\n if (!height) {\n height = box.height / box.width * width;\n }\n return this.width(width).height(height);\n },\n // Add animatable width\n width(width) {\n return this._queueNumber('width', width);\n },\n // Add animatable height\n height(height) {\n return this._queueNumber('height', height);\n },\n // Add animatable plot\n plot(a, b, c, d) {\n // Lines can be plotted with 4 arguments\n if (arguments.length === 4) {\n return this.plot([a, b, c, d]);\n }\n if (this._tryRetarget('plot', a)) return this;\n const morpher = new Morphable(this._stepper).type(this._element.MorphArray).to(a);\n this.queue(function () {\n morpher.from(this._element.array());\n }, function (pos) {\n this._element.plot(morpher.at(pos));\n return morpher.done();\n });\n this._rememberMorpher('plot', morpher);\n return this;\n },\n // Add leading method\n leading(value) {\n return this._queueNumber('leading', value);\n },\n // Add animatable viewbox\n viewbox(x, y, width, height) {\n return this._queueObject('viewbox', new Box(x, y, width, height));\n },\n update(o) {\n if (typeof o !== 'object') {\n return this.update({\n offset: arguments[0],\n color: arguments[1],\n opacity: arguments[2]\n });\n }\n if (o.opacity != null) this.attr('stop-opacity', o.opacity);\n if (o.color != null) this.attr('stop-color', o.color);\n if (o.offset != null) this.attr('offset', o.offset);\n return this;\n }\n });\n extend(Runner, {\n rx,\n ry,\n from,\n to\n });\n register(Runner, 'Runner');\n\n class Svg extends Container {\n constructor(node, attrs = node) {\n super(nodeOrNew('svg', node), attrs);\n this.namespace();\n }\n\n // Creates and returns defs element\n defs() {\n if (!this.isRoot()) return this.root().defs();\n return adopt(this.node.querySelector('defs')) || this.put(new Defs());\n }\n isRoot() {\n return !this.node.parentNode || !(this.node.parentNode instanceof globals.window.SVGElement) && this.node.parentNode.nodeName !== '#document-fragment';\n }\n\n // Add namespaces\n namespace() {\n if (!this.isRoot()) return this.root().namespace();\n return this.attr({\n xmlns: svg,\n version: '1.1'\n }).attr('xmlns:xlink', xlink, xmlns);\n }\n removeNamespace() {\n return this.attr({\n xmlns: null,\n version: null\n }).attr('xmlns:xlink', null, xmlns).attr('xmlns:svgjs', null, xmlns);\n }\n\n // Check if this is a root svg\n // If not, call root() from this element\n root() {\n if (this.isRoot()) return this;\n return super.root();\n }\n }\n registerMethods({\n Container: {\n // Create nested svg document\n nested: wrapWithAttrCheck(function () {\n return this.put(new Svg());\n })\n }\n });\n register(Svg, 'Svg', true);\n\n class Symbol extends Container {\n // Initialize node\n constructor(node, attrs = node) {\n super(nodeOrNew('symbol', node), attrs);\n }\n }\n registerMethods({\n Container: {\n symbol: wrapWithAttrCheck(function () {\n return this.put(new Symbol());\n })\n }\n });\n register(Symbol, 'Symbol');\n\n // Create plain text node\n function plain(text) {\n // clear if build mode is disabled\n if (this._build === false) {\n this.clear();\n }\n\n // create text node\n this.node.appendChild(globals.document.createTextNode(text));\n return this;\n }\n\n // Get length of text element\n function length() {\n return this.node.getComputedTextLength();\n }\n\n // Move over x-axis\n // Text is moved by its bounding box\n // text-anchor does NOT matter\n function x$1(x, box = this.bbox()) {\n if (x == null) {\n return box.x;\n }\n return this.attr('x', this.attr('x') + x - box.x);\n }\n\n // Move over y-axis\n function y$1(y, box = this.bbox()) {\n if (y == null) {\n return box.y;\n }\n return this.attr('y', this.attr('y') + y - box.y);\n }\n function move$1(x, y, box = this.bbox()) {\n return this.x(x, box).y(y, box);\n }\n\n // Move center over x-axis\n function cx(x, box = this.bbox()) {\n if (x == null) {\n return box.cx;\n }\n return this.attr('x', this.attr('x') + x - box.cx);\n }\n\n // Move center over y-axis\n function cy(y, box = this.bbox()) {\n if (y == null) {\n return box.cy;\n }\n return this.attr('y', this.attr('y') + y - box.cy);\n }\n function center(x, y, box = this.bbox()) {\n return this.cx(x, box).cy(y, box);\n }\n function ax(x) {\n return this.attr('x', x);\n }\n function ay(y) {\n return this.attr('y', y);\n }\n function amove(x, y) {\n return this.ax(x).ay(y);\n }\n\n // Enable / disable build mode\n function build(build) {\n this._build = !!build;\n return this;\n }\n\n var textable = {\n __proto__: null,\n amove: amove,\n ax: ax,\n ay: ay,\n build: build,\n center: center,\n cx: cx,\n cy: cy,\n length: length,\n move: move$1,\n plain: plain,\n x: x$1,\n y: y$1\n };\n\n class Text extends Shape {\n // Initialize node\n constructor(node, attrs = node) {\n super(nodeOrNew('text', node), attrs);\n this.dom.leading = this.dom.leading ?? new SVGNumber(1.3); // store leading value for rebuilding\n this._rebuild = true; // enable automatic updating of dy values\n this._build = false; // disable build mode for adding multiple lines\n }\n\n // Set / get leading\n leading(value) {\n // act as getter\n if (value == null) {\n return this.dom.leading;\n }\n\n // act as setter\n this.dom.leading = new SVGNumber(value);\n return this.rebuild();\n }\n\n // Rebuild appearance type\n rebuild(rebuild) {\n // store new rebuild flag if given\n if (typeof rebuild === 'boolean') {\n this._rebuild = rebuild;\n }\n\n // define position of all lines\n if (this._rebuild) {\n const self = this;\n let blankLineOffset = 0;\n const leading = this.dom.leading;\n this.each(function (i) {\n if (isDescriptive(this.node)) return;\n const fontSize = globals.window.getComputedStyle(this.node).getPropertyValue('font-size');\n const dy = leading * new SVGNumber(fontSize);\n if (this.dom.newLined) {\n this.attr('x', self.attr('x'));\n if (this.text() === '\\n') {\n blankLineOffset += dy;\n } else {\n this.attr('dy', i ? dy + blankLineOffset : 0);\n blankLineOffset = 0;\n }\n }\n });\n this.fire('rebuild');\n }\n return this;\n }\n\n // overwrite method from parent to set data properly\n setData(o) {\n this.dom = o;\n this.dom.leading = new SVGNumber(o.leading || 1.3);\n return this;\n }\n writeDataToDom() {\n writeDataToDom(this, this.dom, {\n leading: 1.3\n });\n return this;\n }\n\n // Set the text content\n text(text) {\n // act as getter\n if (text === undefined) {\n const children = this.node.childNodes;\n let firstLine = 0;\n text = '';\n for (let i = 0, len = children.length; i < len; ++i) {\n // skip textPaths - they are no lines\n if (children[i].nodeName === 'textPath' || isDescriptive(children[i])) {\n if (i === 0) firstLine = i + 1;\n continue;\n }\n\n // add newline if its not the first child and newLined is set to true\n if (i !== firstLine && children[i].nodeType !== 3 && adopt(children[i]).dom.newLined === true) {\n text += '\\n';\n }\n\n // add content of this node\n text += children[i].textContent;\n }\n return text;\n }\n\n // remove existing content\n this.clear().build(true);\n if (typeof text === 'function') {\n // call block\n text.call(this, this);\n } else {\n // store text and make sure text is not blank\n text = (text + '').split('\\n');\n\n // build new lines\n for (let j = 0, jl = text.length; j < jl; j++) {\n this.newLine(text[j]);\n }\n }\n\n // disable build mode and rebuild lines\n return this.build(false).rebuild();\n }\n }\n extend(Text, textable);\n registerMethods({\n Container: {\n // Create text element\n text: wrapWithAttrCheck(function (text = '') {\n return this.put(new Text()).text(text);\n }),\n // Create plain text element\n plain: wrapWithAttrCheck(function (text = '') {\n return this.put(new Text()).plain(text);\n })\n }\n });\n register(Text, 'Text');\n\n class Tspan extends Shape {\n // Initialize node\n constructor(node, attrs = node) {\n super(nodeOrNew('tspan', node), attrs);\n this._build = false; // disable build mode for adding multiple lines\n }\n\n // Shortcut dx\n dx(dx) {\n return this.attr('dx', dx);\n }\n\n // Shortcut dy\n dy(dy) {\n return this.attr('dy', dy);\n }\n\n // Create new line\n newLine() {\n // mark new line\n this.dom.newLined = true;\n\n // fetch parent\n const text = this.parent();\n\n // early return in case we are not in a text element\n if (!(text instanceof Text)) {\n return this;\n }\n const i = text.index(this);\n const fontSize = globals.window.getComputedStyle(this.node).getPropertyValue('font-size');\n const dy = text.dom.leading * new SVGNumber(fontSize);\n\n // apply new position\n return this.dy(i ? dy : 0).attr('x', text.x());\n }\n\n // Set text content\n text(text) {\n if (text == null) return this.node.textContent + (this.dom.newLined ? '\\n' : '');\n if (typeof text === 'function') {\n this.clear().build(true);\n text.call(this, this);\n this.build(false);\n } else {\n this.plain(text);\n }\n return this;\n }\n }\n extend(Tspan, textable);\n registerMethods({\n Tspan: {\n tspan: wrapWithAttrCheck(function (text = '') {\n const tspan = new Tspan();\n\n // clear if build mode is disabled\n if (!this._build) {\n this.clear();\n }\n\n // add new tspan\n return this.put(tspan).text(text);\n })\n },\n Text: {\n newLine: function (text = '') {\n return this.tspan(text).newLine();\n }\n }\n });\n register(Tspan, 'Tspan');\n\n class Circle extends Shape {\n constructor(node, attrs = node) {\n super(nodeOrNew('circle', node), attrs);\n }\n radius(r) {\n return this.attr('r', r);\n }\n\n // Radius x value\n rx(rx) {\n return this.attr('r', rx);\n }\n\n // Alias radius x value\n ry(ry) {\n return this.rx(ry);\n }\n size(size) {\n return this.radius(new SVGNumber(size).divide(2));\n }\n }\n extend(Circle, {\n x: x$3,\n y: y$3,\n cx: cx$1,\n cy: cy$1,\n width: width$2,\n height: height$2\n });\n registerMethods({\n Container: {\n // Create circle element\n circle: wrapWithAttrCheck(function (size = 0) {\n return this.put(new Circle()).size(size).move(0, 0);\n })\n }\n });\n register(Circle, 'Circle');\n\n class ClipPath extends Container {\n constructor(node, attrs = node) {\n super(nodeOrNew('clipPath', node), attrs);\n }\n\n // Unclip all clipped elements and remove itself\n remove() {\n // unclip all targets\n this.targets().forEach(function (el) {\n el.unclip();\n });\n\n // remove clipPath from parent\n return super.remove();\n }\n targets() {\n return baseFind('svg [clip-path*=' + this.id() + ']');\n }\n }\n registerMethods({\n Container: {\n // Create clipping element\n clip: wrapWithAttrCheck(function () {\n return this.defs().put(new ClipPath());\n })\n },\n Element: {\n // Distribute clipPath to svg element\n clipper() {\n return this.reference('clip-path');\n },\n clipWith(element) {\n // use given clip or create a new one\n const clipper = element instanceof ClipPath ? element : this.parent().clip().add(element);\n\n // apply mask\n return this.attr('clip-path', 'url(#' + clipper.id() + ')');\n },\n // Unclip element\n unclip() {\n return this.attr('clip-path', null);\n }\n }\n });\n register(ClipPath, 'ClipPath');\n\n class ForeignObject extends Element {\n constructor(node, attrs = node) {\n super(nodeOrNew('foreignObject', node), attrs);\n }\n }\n registerMethods({\n Container: {\n foreignObject: wrapWithAttrCheck(function (width, height) {\n return this.put(new ForeignObject()).size(width, height);\n })\n }\n });\n register(ForeignObject, 'ForeignObject');\n\n function dmove(dx, dy) {\n this.children().forEach(child => {\n let bbox;\n\n // We have to wrap this for elements that dont have a bbox\n // e.g. title and other descriptive elements\n try {\n // Get the childs bbox\n // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1905039\n // Because bbox for nested svgs returns the contents bbox in the coordinate space of the svg itself (weird!), we cant use bbox for svgs\n // Therefore we have to use getBoundingClientRect. But THAT is broken (as explained in the bug).\n // Funnily enough the broken behavior would work for us but that breaks it in chrome\n // So we have to replicate the broken behavior of FF by just reading the attributes of the svg itself\n bbox = child.node instanceof getWindow().SVGSVGElement ? new Box(child.attr(['x', 'y', 'width', 'height'])) : child.bbox();\n } catch (e) {\n return;\n }\n\n // Get childs matrix\n const m = new Matrix(child);\n // Translate childs matrix by amount and\n // transform it back into parents space\n const matrix = m.translate(dx, dy).transform(m.inverse());\n // Calculate new x and y from old box\n const p = new Point(bbox.x, bbox.y).transform(matrix);\n // Move element\n child.move(p.x, p.y);\n });\n return this;\n }\n function dx(dx) {\n return this.dmove(dx, 0);\n }\n function dy(dy) {\n return this.dmove(0, dy);\n }\n function height(height, box = this.bbox()) {\n if (height == null) return box.height;\n return this.size(box.width, height, box);\n }\n function move(x = 0, y = 0, box = this.bbox()) {\n const dx = x - box.x;\n const dy = y - box.y;\n return this.dmove(dx, dy);\n }\n function size(width, height, box = this.bbox()) {\n const p = proportionalSize(this, width, height, box);\n const scaleX = p.width / box.width;\n const scaleY = p.height / box.height;\n this.children().forEach(child => {\n const o = new Point(box).transform(new Matrix(child).inverse());\n child.scale(scaleX, scaleY, o.x, o.y);\n });\n return this;\n }\n function width(width, box = this.bbox()) {\n if (width == null) return box.width;\n return this.size(width, box.height, box);\n }\n function x(x, box = this.bbox()) {\n if (x == null) return box.x;\n return this.move(x, box.y, box);\n }\n function y(y, box = this.bbox()) {\n if (y == null) return box.y;\n return this.move(box.x, y, box);\n }\n\n var containerGeometry = {\n __proto__: null,\n dmove: dmove,\n dx: dx,\n dy: dy,\n height: height,\n move: move,\n size: size,\n width: width,\n x: x,\n y: y\n };\n\n class G extends Container {\n constructor(node, attrs = node) {\n super(nodeOrNew('g', node), attrs);\n }\n }\n extend(G, containerGeometry);\n registerMethods({\n Container: {\n // Create a group element\n group: wrapWithAttrCheck(function () {\n return this.put(new G());\n })\n }\n });\n register(G, 'G');\n\n class A extends Container {\n constructor(node, attrs = node) {\n super(nodeOrNew('a', node), attrs);\n }\n\n // Link target attribute\n target(target) {\n return this.attr('target', target);\n }\n\n // Link url\n to(url) {\n return this.attr('href', url, xlink);\n }\n }\n extend(A, containerGeometry);\n registerMethods({\n Container: {\n // Create a hyperlink element\n link: wrapWithAttrCheck(function (url) {\n return this.put(new A()).to(url);\n })\n },\n Element: {\n unlink() {\n const link = this.linker();\n if (!link) return this;\n const parent = link.parent();\n if (!parent) {\n return this.remove();\n }\n const index = parent.index(link);\n parent.add(this, index);\n link.remove();\n return this;\n },\n linkTo(url) {\n // reuse old link if possible\n let link = this.linker();\n if (!link) {\n link = new A();\n this.wrap(link);\n }\n if (typeof url === 'function') {\n url.call(link, link);\n } else {\n link.to(url);\n }\n return this;\n },\n linker() {\n const link = this.parent();\n if (link && link.node.nodeName.toLowerCase() === 'a') {\n return link;\n }\n return null;\n }\n }\n });\n register(A, 'A');\n\n class Mask extends Container {\n // Initialize node\n constructor(node, attrs = node) {\n super(nodeOrNew('mask', node), attrs);\n }\n\n // Unmask all masked elements and remove itself\n remove() {\n // unmask all targets\n this.targets().forEach(function (el) {\n el.unmask();\n });\n\n // remove mask from parent\n return super.remove();\n }\n targets() {\n return baseFind('svg [mask*=' + this.id() + ']');\n }\n }\n registerMethods({\n Container: {\n mask: wrapWithAttrCheck(function () {\n return this.defs().put(new Mask());\n })\n },\n Element: {\n // Distribute mask to svg element\n masker() {\n return this.reference('mask');\n },\n maskWith(element) {\n // use given mask or create a new one\n const masker = element instanceof Mask ? element : this.parent().mask().add(element);\n\n // apply mask\n return this.attr('mask', 'url(#' + masker.id() + ')');\n },\n // Unmask element\n unmask() {\n return this.attr('mask', null);\n }\n }\n });\n register(Mask, 'Mask');\n\n class Stop extends Element {\n constructor(node, attrs = node) {\n super(nodeOrNew('stop', node), attrs);\n }\n\n // add color stops\n update(o) {\n if (typeof o === 'number' || o instanceof SVGNumber) {\n o = {\n offset: arguments[0],\n color: arguments[1],\n opacity: arguments[2]\n };\n }\n\n // set attributes\n if (o.opacity != null) this.attr('stop-opacity', o.opacity);\n if (o.color != null) this.attr('stop-color', o.color);\n if (o.offset != null) this.attr('offset', new SVGNumber(o.offset));\n return this;\n }\n }\n registerMethods({\n Gradient: {\n // Add a color stop\n stop: function (offset, color, opacity) {\n return this.put(new Stop()).update(offset, color, opacity);\n }\n }\n });\n register(Stop, 'Stop');\n\n function cssRule(selector, rule) {\n if (!selector) return '';\n if (!rule) return selector;\n let ret = selector + '{';\n for (const i in rule) {\n ret += unCamelCase(i) + ':' + rule[i] + ';';\n }\n ret += '}';\n return ret;\n }\n class Style extends Element {\n constructor(node, attrs = node) {\n super(nodeOrNew('style', node), attrs);\n }\n addText(w = '') {\n this.node.textContent += w;\n return this;\n }\n font(name, src, params = {}) {\n return this.rule('@font-face', {\n fontFamily: name,\n src: src,\n ...params\n });\n }\n rule(selector, obj) {\n return this.addText(cssRule(selector, obj));\n }\n }\n registerMethods('Dom', {\n style(selector, obj) {\n return this.put(new Style()).rule(selector, obj);\n },\n fontface(name, src, params) {\n return this.put(new Style()).font(name, src, params);\n }\n });\n register(Style, 'Style');\n\n class TextPath extends Text {\n // Initialize node\n constructor(node, attrs = node) {\n super(nodeOrNew('textPath', node), attrs);\n }\n\n // return the array of the path track element\n array() {\n const track = this.track();\n return track ? track.array() : null;\n }\n\n // Plot path if any\n plot(d) {\n const track = this.track();\n let pathArray = null;\n if (track) {\n pathArray = track.plot(d);\n }\n return d == null ? pathArray : this;\n }\n\n // Get the path element\n track() {\n return this.reference('href');\n }\n }\n registerMethods({\n Container: {\n textPath: wrapWithAttrCheck(function (text, path) {\n // Convert text to instance if needed\n if (!(text instanceof Text)) {\n text = this.text(text);\n }\n return text.path(path);\n })\n },\n Text: {\n // Create path for text to run on\n path: wrapWithAttrCheck(function (track, importNodes = true) {\n const textPath = new TextPath();\n\n // if track is a path, reuse it\n if (!(track instanceof Path)) {\n // create path element\n track = this.defs().path(track);\n }\n\n // link textPath to path and add content\n textPath.attr('href', '#' + track, xlink);\n\n // Transplant all nodes from text to textPath\n let node;\n if (importNodes) {\n while (node = this.node.firstChild) {\n textPath.node.appendChild(node);\n }\n }\n\n // add textPath element as child node and return textPath\n return this.put(textPath);\n }),\n // Get the textPath children\n textPath() {\n return this.findOne('textPath');\n }\n },\n Path: {\n // creates a textPath from this path\n text: wrapWithAttrCheck(function (text) {\n // Convert text to instance if needed\n if (!(text instanceof Text)) {\n text = new Text().addTo(this.parent()).text(text);\n }\n\n // Create textPath from text and path and return\n return text.path(this);\n }),\n targets() {\n return baseFind('svg textPath').filter(node => {\n return (node.attr('href') || '').includes(this.id());\n });\n\n // Does not work in IE11. Use when IE support is dropped\n // return baseFind('svg textPath[*|href*=' + this.id() + ']')\n }\n }\n });\n TextPath.prototype.MorphArray = PathArray;\n register(TextPath, 'TextPath');\n\n class Use extends Shape {\n constructor(node, attrs = node) {\n super(nodeOrNew('use', node), attrs);\n }\n\n // Use element as a reference\n use(element, file) {\n // Set lined element\n return this.attr('href', (file || '') + '#' + element, xlink);\n }\n }\n registerMethods({\n Container: {\n // Create a use element\n use: wrapWithAttrCheck(function (element, file) {\n return this.put(new Use()).use(element, file);\n })\n }\n });\n register(Use, 'Use');\n\n /* Optional Modules */\n const SVG$1 = makeInstance;\n extend([Svg, Symbol, Image, Pattern, Marker], getMethodsFor('viewbox'));\n extend([Line, Polyline, Polygon, Path], getMethodsFor('marker'));\n extend(Text, getMethodsFor('Text'));\n extend(Path, getMethodsFor('Path'));\n extend(Defs, getMethodsFor('Defs'));\n extend([Text, Tspan], getMethodsFor('Tspan'));\n extend([Rect, Ellipse, Gradient, Runner], getMethodsFor('radius'));\n extend(EventTarget, getMethodsFor('EventTarget'));\n extend(Dom, getMethodsFor('Dom'));\n extend(Element, getMethodsFor('Element'));\n extend(Shape, getMethodsFor('Shape'));\n extend([Container, Fragment], getMethodsFor('Container'));\n extend(Gradient, getMethodsFor('Gradient'));\n extend(Runner, getMethodsFor('Runner'));\n List.extend(getMethodNames());\n registerMorphableType([SVGNumber, Color, Box, Matrix, SVGArray, PointArray, PathArray, Point]);\n makeMorphable();\n\n var svgMembers = {\n __proto__: null,\n A: A,\n Animator: Animator,\n Array: SVGArray,\n Box: Box,\n Circle: Circle,\n ClipPath: ClipPath,\n Color: Color,\n Container: Container,\n Controller: Controller,\n Defs: Defs,\n Dom: Dom,\n Ease: Ease,\n Element: Element,\n Ellipse: Ellipse,\n EventTarget: EventTarget,\n ForeignObject: ForeignObject,\n Fragment: Fragment,\n G: G,\n Gradient: Gradient,\n Image: Image,\n Line: Line,\n List: List,\n Marker: Marker,\n Mask: Mask,\n Matrix: Matrix,\n Morphable: Morphable,\n NonMorphable: NonMorphable,\n Number: SVGNumber,\n ObjectBag: ObjectBag,\n PID: PID,\n Path: Path,\n PathArray: PathArray,\n Pattern: Pattern,\n Point: Point,\n PointArray: PointArray,\n Polygon: Polygon,\n Polyline: Polyline,\n Queue: Queue,\n Rect: Rect,\n Runner: Runner,\n SVG: SVG$1,\n Shape: Shape,\n Spring: Spring,\n Stop: Stop,\n Style: Style,\n Svg: Svg,\n Symbol: Symbol,\n Text: Text,\n TextPath: TextPath,\n Timeline: Timeline,\n TransformBag: TransformBag,\n Tspan: Tspan,\n Use: Use,\n adopt: adopt,\n assignNewId: assignNewId,\n clearEvents: clearEvents,\n create: create,\n defaults: defaults,\n dispatch: dispatch,\n easing: easing,\n eid: eid,\n extend: extend,\n find: baseFind,\n getClass: getClass,\n getEventTarget: getEventTarget,\n getEvents: getEvents,\n getWindow: getWindow,\n makeInstance: makeInstance,\n makeMorphable: makeMorphable,\n mockAdopt: mockAdopt,\n namespaces: namespaces,\n nodeOrNew: nodeOrNew,\n off: off,\n on: on,\n parser: parser,\n regex: regex,\n register: register,\n registerMorphableType: registerMorphableType,\n registerWindow: registerWindow,\n restoreWindow: restoreWindow,\n root: root,\n saveWindow: saveWindow,\n utils: utils,\n windowEvents: windowEvents,\n withWindow: withWindow,\n wrapWithAttrCheck: wrapWithAttrCheck\n };\n\n // The main wrapping element\n function SVG(element, isHTML) {\n return makeInstance(element, isHTML);\n }\n Object.assign(SVG, svgMembers);\n\n return SVG;\n\n};\n"],"names":["methods$1","names","registerMethods","name","m","Array","isArray","_name","addMethodNames","Object","getOwnPropertyNames","assign","getMethodsFor","_names","push","map","array","block","i","il","length","result","filter","radians","d","Math","PI","unCamelCase","s","replace","g","toLowerCase","capitalize","charAt","toUpperCase","slice","proportionalSize","element","width","height","box","bbox","getOrigin","o","origin","ox","originX","oy","originY","x","y","condX","condY","includes","descriptiveElements","Set","isDescriptive","has","nodeName","writeDataToDom","data","defaults","cloned","key","valueOf","keys","node","setAttribute","JSON","stringify","removeAttribute","utils","__proto__","degrees","r","svg","html","xmlns","xlink","namespaces","globals","window","document","registerWindow","win","doc","save","saveWindow","restoreWindow","getWindow","Base","elements","root","create","ns","createElementNS","makeInstance","isHTML","adopter","querySelector","wrapper","createElement","innerHTML","firstChild","removeChild","nodeOrNew","Node","ownerDocument","defaultView","adopt","instance","Fragment","className","register","asRoot","prototype","getClass","did","eid","assignNewId","children","id","extend","modules","methods","wrapWithAttrCheck","fn","args","constructor","apply","this","attr","siblings","parent","position","index","next","prev","forward","add","remove","backward","front","back","before","after","insertBefore","insertAfter","numberAndUnit","hex","rgb","reference","transforms","whitespace","isHex","isRgb","isBlank","isNumber","isImage","delimiter","isPathLetter","regex","componentHex","component","integer","round","max","min","toString","is","object","space","hueToRgb","p","q","t","classes","trim","split","hasClass","indexOf","addClass","join","removeClass","c","toggleClass","css","style","val","ret","arguments","cssText","el","forEach","cased","getPropertyValue","setProperty","test","show","hide","visible","a","v","attributes","parse","e","remember","k","memory","forget","_memory","Color","init","color","b","mode","random","sin","pi","l","h","grey","Error","cmyk","_a","_b","_c","hsl","isGrey","delta","_d","values","params","z","getParameters","noWhitespace","exec","parseInt","hexParse","substring","sixDigitHex","components","lab","xyz","lch","sqrt","atan2","dToR","cos","yL","xL","zL","ct","mx","nm","rU","gU","bU","pow","bd","toArray","toHex","_clamped","toRgb","rV","gV","bV","r255","g255","b255","rL","gL","bL","xU","yU","zU","Point","clone","base","source","transform","transformO","Matrix","isMatrixLike","f","closeEnough","threshold","abs","flipBoth","flip","flipX","flipY","skewX","skew","isFinite","skewY","scaleX","scale","scaleY","shear","theta","rotate","around","px","positionX","NaN","py","positionY","translate","tx","translateX","ty","translateY","relative","rx","relativeX","ry","relativeY","cx","cy","matrix","aroundO","dx","dy","translateO","lmultiplyO","decompose","determinant","ccw","sx","thetaRad","st","lam","sy","equals","other","comp","axis","flipO","scaleO","fromArray","Element","matrixify","parseFloat","call","inverse","inverseO","det","na","nb","nc","nd","ne","nf","lmultiply","matrixMultiply","multiply","multiplyO","rotateO","shearO","lx","skewO","tan","ly","formatTransforms","transformer","parser","nodes","size","path","parentNode","body","documentElement","addTo","isNulledBox","Box","addOffset","pageXOffset","pageYOffset","left","top","w","x2","y2","isNulled","merge","xMin","Infinity","xMax","yMin","yMax","getBox","getBBoxFn","retry","contains","viewbox","zoom","level","point","clientWidth","clientHeight","zoomX","zoomY","zoomAmount","Number","MAX_SAFE_INTEGER","List","arr","each","fnOrMethodName","concat","reserved","baseFind","query","querySelectorAll","reduce","obj","attrs","listenerId","windowEvents","getEvents","n","getEventHolder","events","getEventTarget","clearEvents","on","listener","binding","options","bind","bag","_svgjsListenerId","event","ev","addEventListener","off","namespace","removeEventListener","dispatch","Event","CustomEvent","detail","cancelable","dispatchEvent","EventTarget","type","j","defaultPrevented","fire","noop","timeline","duration","ease","delay","fill","stroke","opacity","offset","SVGArray","toSet","SVGNumber","convert","unit","value","divide","number","isNaN","match","minus","plus","times","toJSON","colorAttributes","hooks","Dom","removeNamespace","SVGElement","appendChild","childNodes","put","clear","hasChildNodes","lastChild","deep","assignNewIds","nodeClone","cloneNode","first","get","htmlOrFn","outerHTML","xml","last","matches","selector","matcher","matchesSelector","msMatchesSelector","mozMatchesSelector","webkitMatchesSelector","oMatchesSelector","putIn","removeElement","replaceChild","factor","svgOrFn","outerSVG","words","text","textContent","wrap","xmlOrFn","outerXML","current","_this","well","fragment","createDocumentFragment","len","firstElementChild","nodeValue","curr","getAttribute","_val","hook","isColor","leading","setAttributeNS","rebuild","find","findOne","dom","hasAttribute","setData","center","defs","dmove","move","parents","until","isSelector","super","getBBox","rbox","getBoundingClientRect","screenCTM","inside","ctm","getCTM","isRoot","rect","getScreenCTM","console","warn","sugar","prefix","extension","mat","angle","direction","radius","_element","getTotalLength","pointAt","getPointAtLength","font","untransform","str","kv","reverse","toParent","pCtm","toRoot","decomposed","Container","flatten","ungroup","Defs","Shape","x$3","y$3","cx$1","cy$1","width$2","height$2","circled","Ellipse","ellipse","from","fx","fy","x1","y1","to","gradiented","Gradient","targets","url","update","gradient","Pattern","pattern","patternUnits","Image","load","callback","img","src","image","PointArray","maxX","maxY","minX","minY","points","pop","toLine","pointed","MorphArray","Line","plot","line","Marker","orient","ref","makeSetterGetter","marker","easing","pos","bezier","steps","stepPosition","jumps","beforeFlag","step","floor","jumping","Stepper","done","Ease","Controller","stepper","target","dt","recalculate","_duration","overshoot","_overshoot","os","log","zeta","wn","Spring","velocity","acceleration","newPosition","PID","windup","integral","error","_windup","P","I","D","segmentParameters","M","L","H","V","C","S","Q","T","A","Z","pathHandlers","p0","mlhvqtcsaz","jl","segmentComplete","segment","startNewSegment","token","inNumber","finalizeNumber","pathLetter","lastCommand","small","isSmall","inSegment","pointSeen","hasExponent","finalizeSegment","absolute","command","makeAbsolut","segments","isArcFlag","isArc","isExponential","lastToken","pathDelimiters","PathArray","pathParser","arrayToString","getClassForType","NonMorphable","morphableTypes","ObjectBag","Morphable","_stepper","_from","_to","_type","_context","_morphObj","at","morph","_set","align","toConsumable","TransformBag","sortByKey","splice","defaultObject","toDelete","objOrArr","entries","Type","sort","shift","num","registerMorphableType","makeMorphable","context","Path","_array","poly","Polygon","polygon","Polyline","polyline","Rect","Queue","_first","_last","item","Animator","nextDraw","frames","timeouts","immediates","timer","performance","Date","frame","run","requestAnimationFrame","_draw","timeout","time","now","immediate","cancelFrame","clearTimeout","cancelImmediate","nextTimeout","lastTimeout","nextFrame","lastFrame","nextImmediate","makeSchedule","runnerInfo","start","runner","end","defaultSource","Timeline","timeSource","_timeSource","terminate","active","_nextFrame","finish","getEndTimeOfTimeline","pause","getEndTime","lastRunnerInfo","getLastRunnerInfo","lastDuration","_time","endTimes","_runners","getRunnerInfoById","_lastRunnerId","_runnerIds","_paused","_continue","persist","dtOrForever","_persist","play","updateTime","yes","currentSpeed","speed","positive","schedule","when","absoluteStartTime","endTime","unschedule","info","seek","_speed","stop","_lastSourceTime","immediateStep","_stepImmediate","_step","_stepFn","dtSource","dtTime","_lastStepTime","reset","runnersLeft","dtToStart","_startTime","_timeline","Runner","_queue","_isDeclarative","_history","enabled","_lastTime","_reseted","transformId","_haveReversed","_reverse","_loopsDone","_swing","_wait","_times","_frameId","swing","wait","addTransform","animate","sanitise","loop","clearTransform","clearTransformsFromQueue","isTransform","during","queue","_prepareRunner","loops","loopDuration","loopsDone","partial","swinging","backwards","uncliped","swingForward","progress","initFn","runFn","retargetFn","initialiser","retarget","initialised","finished","running","_lastPosition","justStarted","justFinished","declarative","converged","_initialise","_run","needsIt","_rememberMorpher","method","morpher","caller","positionOrDt","allfinished","_tryRetarget","extra","FakeRunner","mergeWith","getRunnerTransform","mergeTransforms","netTransform","_transformationRunners","runners","RunnerArray","ids","clearBefore","deleteCnt","edit","newRunner","getByID","lastRunner","by","_clearTransformRunnersBefore","currentRunner","_currentTransform","_addRunner","styleAttr","nameOrAttrs","newToAttrs","newKeys","differences","addedFromAttrs","oldFromAttrs","oldToAttrs","newLevel","newPoint","affine","isMatrix","currentAngle","startTransform","undefined","rTarget","rCurrent","possibilities","distances","shortest","affineParameters","newTransforms","_queueNumber","ax","ay","_queueNumberDelta","newTo","_queueObject","amove","Svg","version","nested","Symbol","symbol","textable","build","_build","getComputedTextLength","plain","createTextNode","Text","_rebuild","self","blankLineOffset","fontSize","getComputedStyle","newLined","firstLine","nodeType","newLine","Tspan","tspan","Circle","circle","ClipPath","unclip","clip","clipper","clipWith","ForeignObject","foreignObject","containerGeometry","child","SVGSVGElement","G","group","link","unlink","linker","linkTo","Mask","unmask","mask","masker","maskWith","Stop","Style","addText","rule","fontFamily","cssRule","fontface","TextPath","track","pathArray","textPath","importNodes","Use","use","file","SVG$1","svgMembers","SVG","mockAdopt","withWindow"],"mappings":"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"} \ No newline at end of file diff --git a/amd/src/circle.js b/amd/src/circle.js new file mode 100644 index 0000000..97f03e8 --- /dev/null +++ b/amd/src/circle.js @@ -0,0 +1,37 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * A circle shape. + * + * @module mod_learningmap/circle + * @copyright 2024 ISB Bayern + * @author Stefan Hanauska + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** + * Returns a circle tag with the given dimensions. + * @param {*} mapsvg + * @param {*} x x coordinate of the center + * @param {*} y y coordinate of the center + * @param {*} r radius + * @param {*} classes classes to add + * @param {*} id id of the circle + * @returns {any} + */ +export default function circle(mapsvg, x, y, r, classes, id) { + return mapsvg.circle(r * 2).cx(x).cy(y).attr({'class': classes}).id(id); +} \ No newline at end of file diff --git a/amd/src/emoji.js b/amd/src/emoji.js new file mode 100644 index 0000000..180caac --- /dev/null +++ b/amd/src/emoji.js @@ -0,0 +1,41 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * TODO describe module emoji + * + * @module mod_learningmap/emoji + * @copyright 2024 ISB Bayern + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** + * Returns an text tag containing an emoji with the given dimensions. + * @param {*} mapsvg + * @param {*} x + * @param {*} y + * @param {*} r + * @param {*} classes + * @param {*} id + * @param {*} content + * @returns + */ +export default function emoji(mapsvg, x, y, r, classes, id, content) { + let newelement = mapsvg.nested(); + newelement.center(x, y).attr({'class': classes}).id(id).width(r * 2 + 10).height(r * 2 + 10); + newelement.circle(r * 2, r, r); + newelement.text().plain(content ?? '😀'); + return newelement; +} \ No newline at end of file diff --git a/amd/src/learningmap.js b/amd/src/learningmap.js index 9343c49..8ef273c 100644 --- a/amd/src/learningmap.js +++ b/amd/src/learningmap.js @@ -1,6 +1,8 @@ import {exception as displayException} from 'core/notification'; import Templates from 'core/templates'; import placestore from 'mod_learningmap/placestore'; +import svgjs from 'mod_learningmap/svg'; +import shapes from './shapes'; const circleRadius = 10; @@ -170,8 +172,9 @@ export const init = () => { updateCode(); // Enable dragging of places - let svg = document.getElementById('learningmap-svgmap-' + placestore.getMapid()); - makeDraggable(svg); + let svgel = document.getElementById('learningmap-svgmap-' + placestore.getMapid()); + makeDraggable(svgel); + var mapsvg = svgjs().SVG('#learningmap-svgmap-' + placestore.getMapid()); // Refresh stylesheet values from placestore updateCSS(); @@ -199,11 +202,12 @@ export const init = () => { e = e.touches[0]; } if (e.target.classList.contains('learningmap-place')) { + let element = getSVGShape(e.target.id); e.target.classList.add('learningmap-selected-activity-selector'); let activityId = placestore.getActivityId(e.target.id); let scalingFactor = mapdiv.clientWidth / 800; - activitySetting.style.setProperty('--pos-x', e.target.cx.baseVal.value * scalingFactor + 'px'); - activitySetting.style.setProperty('--pos-y', e.target.cy.baseVal.value * scalingFactor + 'px'); + activitySetting.style.setProperty('--pos-x', element.cx() * scalingFactor + 'px'); + activitySetting.style.setProperty('--pos-y', element.cy() * scalingFactor + 'px'); activitySetting.style.setProperty('--map-width', mapdiv.clientWidth + 'px'); activitySetting.style.setProperty('--map-height', mapdiv.clientHeight + 'px'); activitySetting.style.display = 'block'; @@ -262,6 +266,20 @@ export const init = () => { }; } + /** + * Returns the SVG shape with the given id or representing the + * given object. + * @param {*} element + * @returns + */ + function getSVGShape(element) { + if (typeof element === 'object') { + return mapsvg.findOne('#' + element.id); + } else { + return mapsvg.findOne('#' + element); + } + } + /** * Enables dragging on an DOM node * @param {*} el @@ -292,18 +310,20 @@ export const init = () => { pathsToUpdateSecondPoint = []; if (evt.target.classList.contains('learningmap-draggable')) { selectedElement = evt.target; + let svgel = getSVGShape(selectedElement); offset = getMousePosition(evt); - offset.x -= parseInt(selectedElement.getAttributeNS(null, "cx")); - offset.y -= parseInt(selectedElement.getAttributeNS(null, "cy")); + offset.x -= svgel.cx(); + offset.y -= svgel.cy(); // Get paths that need to be updated. - pathsToUpdateFirstPoint = placestore.getPathsWithFid(selectedElement.id); - pathsToUpdateSecondPoint = placestore.getPathsWithSid(selectedElement.id); + pathsToUpdateFirstPoint = placestore.getPathsWithFid(evt.target.id); + pathsToUpdateSecondPoint = placestore.getPathsWithSid(evt.target.id); } else if (evt.target.nodeName == 'text') { selectedElement = evt.target; - let place = selectedElement.parentNode.querySelector('.learningmap-place'); + let svgel = getSVGShape(selectedElement); + let place = svgel.parent().findOne('.learningmap-place'); offset = getMousePosition(evt); - offset.x -= parseInt(selectedElement.getAttributeNS(null, "dx")) + place.cx.baseVal.value; - offset.y -= parseInt(selectedElement.getAttributeNS(null, "dy")) + place.cy.baseVal.value; + offset.x -= svgel.attr('dx') + place.cx(); + offset.y -= svgel.attr('dy') + place.cy(); } else if (evt.target.nodeName == 'path') { selectedElement = evt.target; offset = getMousePosition(evt); @@ -314,7 +334,7 @@ export const init = () => { } /** - * Function called during dragging. Continuously updates circles center coordinates and the + * Function called during dragging. Continuously updates places center coordinates and the * coordinates of the touching paths. * @param {*} evt */ @@ -328,59 +348,56 @@ export const init = () => { var coord = getMousePosition(evt); let cx = coord.x - offset.x; let cy = coord.y - offset.y; - if (selectedElement.nodeName == 'text') { - let place = selectedElement.parentNode.querySelector('.learningmap-place'); - // Calculate the delta from the current mouse position to the corresponding place. - // coord: current mouse position - // offset: delta from the mouse position to the coordinates of the text node - let dx = coord.x - offset.x - place.cx.baseVal.value; - let dy = coord.y - offset.y - place.cy.baseVal.value; - selectedElement.setAttributeNS(null, "dx", dx); - selectedElement.setAttributeNS(null, "dy", dy); - } - if (selectedElement.nodeName == 'path') { - selectedElement.setAttribute( - 'd', - updatePathDeclaration(selectedElement.getAttribute('d'), coord.x, coord.y, targetPoints.bezierPoint) - ); - } - if (selectedElement.nodeName == 'circle') { - selectedElement.setAttributeNS(null, "cx", cx); - selectedElement.setAttributeNS(null, "cy", cy); - let textNode = document.getElementById('text' + selectedElement.id); + if (selectedElement.classList.contains('learningmap-place')) { + let placeel = mapsvg.findOne('#' + selectedElement.id); + placeel.center(cx, cy); + let textNode = mapsvg.findOne('#text' + selectedElement.id); if (textNode !== null) { - textNode.setAttributeNS(null, 'x', cx); - textNode.setAttributeNS(null, 'y', cy); + textNode.amove(cx, cy); } pathsToUpdateFirstPoint.forEach(function(path) { - let pathNode = document.getElementById(path.id); - if (pathNode !== null) { - if (pathNode.nodeName == 'path') { - pathNode.setAttribute( - 'd', - updatePathDeclaration(pathNode.getAttribute('d'), cx, cy, targetPoints.firstPoint) + let pathElement = getSVGShape(path); + if (pathElement !== null) { + if (pathElement.type == 'path') { + pathElement.attr( + {'d': updatePathDeclaration(pathElement.attr('d'), cx, cy, targetPoints.firstPoint)} ); } else { - pathNode.setAttribute('x1', cx); - pathNode.setAttribute('y1', cy); + pathElement.attr({'x1': cx, 'y1': cy}); } } }); pathsToUpdateSecondPoint.forEach(function(path) { - let pathNode = document.getElementById(path.id); - if (pathNode !== null) { - if (pathNode.nodeName == 'path') { - pathNode.setAttribute( - 'd', - updatePathDeclaration(pathNode.getAttribute('d'), cx, cy, targetPoints.secondPoint) + let pathElement = getSVGShape(path); + if (pathElement !== null) { + if (pathElement.type == 'path') { + pathElement.attr( + {'d': updatePathDeclaration(pathElement.attr('d'), cx, cy, targetPoints.secondPoint)} ); } else { - pathNode.setAttribute('x2', cx); - pathNode.setAttribute('y2', cy); + pathElement.attr({'x2': cx, 'y2': cy}); } } }); + placestore.setBbox(selectedElement.id, placeel.parent().bbox()); + } else if (selectedElement.nodeName == 'text') { + let textel = getSVGShape(selectedElement); + let place = textel.parent().findOne('.learningmap-place'); + // Calculate the delta from the current mouse position to the corresponding place. + // coord: current mouse position + // offset: delta from the mouse position to the coordinates of the text node + let dx = cx - place.cx(); + let dy = cy - place.cy(); + // We cannot use the dx() and dy() functions of the text node, because they are not + // setting the attributes dx and dy. + textel.attr({dx: dx, dy: dy}); + placestore.setBbox(place.node.id, textel.parent().bbox()); + } else if (selectedElement.nodeName == 'path') { + selectedElement.setAttribute( + 'd', + updatePathDeclaration(selectedElement.getAttribute('d'), coord.x, coord.y, targetPoints.bezierPoint) + ); } } } @@ -584,9 +601,7 @@ export const init = () => { * @returns {any} */ function title(id) { - let title = document.createElementNS('http://www.w3.org/2000/svg', 'title'); - title.setAttribute('id', id); - return title; + return mapsvg.element('title').id(id); } /** @@ -598,34 +613,7 @@ export const init = () => { * @returns {any} */ function text(id, content, x, y) { - let text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); - text.setAttribute('id', id); - text.setAttribute('x', x); - text.setAttribute('y', y); - // Default value for delta: Circle radius * 1.5 (as a padding) - text.setAttribute('dx', circleRadius * 1.5); - text.setAttribute('dy', circleRadius * 1.5); - text.textContent = content; - return text; - } - - /** - * Returns a circle tag with the given dimensions. - * @param {*} x x coordinate of the center - * @param {*} y y coordinate of the center - * @param {*} r radius - * @param {*} classes classes to add - * @param {*} id id of the circle - * @returns {any} - */ - function circle(x, y, r, classes, id) { - let circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); - circle.setAttribute('class', classes); - circle.setAttribute('id', id); - circle.setAttribute('cx', x); - circle.setAttribute('cy', y); - circle.setAttribute('r', r); - return circle; + return mapsvg.text().attr({dx: circleRadius * 1.5, dy: circleRadius * 1.5}).plain(content).move(x, y).id(id); } /** @@ -639,11 +627,7 @@ export const init = () => { * @returns {any} */ function path(x1, y1, x2, y2, classes, id) { - let path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); - path.setAttribute('class', classes); - path.setAttribute('id', id); - path.setAttribute('d', 'M ' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2); - return path; + return mapsvg.path('M ' + x1 + ' ' + y1 + ' L ' + x2 + ' ' + y2).attr({'class': classes}).id(id); } /** @@ -656,17 +640,7 @@ export const init = () => { * @returns {any} */ function link(child, id, title = null, text = null) { - let link = document.createElementNS('http://www.w3.org/2000/svg', 'a'); - link.setAttribute('id', id); - link.setAttribute('xlink:href', ''); - link.appendChild(child); - if (title !== null) { - link.appendChild(title); - } - if (text !== null) { - link.appendChild(text); - } - return link; + return mapsvg.link('').id(id).add(child).add(title).add(text); } /** @@ -675,7 +649,7 @@ export const init = () => { * @param {*} event event causing the command */ function addPlace(event) { - let placesgroup = document.getElementById('placesGroup'); + let placesgroup = mapsvg.findOne('#placesGroup'); let placeId = 'p' + placestore.getId(); let linkId = 'a' + placestore.getId(); var CTM = event.target.getScreenCTM(); @@ -684,15 +658,14 @@ export const init = () => { } let cx = (event.clientX - CTM.e) / CTM.a; let cy = (event.clientY - CTM.f) / CTM.d; - placesgroup.appendChild( - link( - circle(cx, cy, circleRadius, 'learningmap-place learningmap-draggable learningmap-emptyplace', placeId), - linkId, - title('title' + placeId), - text('text' + placeId, '', cx, cy) - ) + let svglink = link( + shapes.emoji(mapsvg, cx, cy, circleRadius, 'learningmap-place learningmap-draggable learningmap-emptyplace', placeId), + linkId, + title('title' + placeId), + text('text' + placeId, '', cx, cy) ); - placestore.addPlace(placeId, linkId); + svglink.addTo(placesgroup); + placestore.addPlace(placeId, linkId, null, svglink.bbox()); } /** @@ -755,20 +728,19 @@ export const init = () => { function addPath(fid, sid) { let pid = 'p' + fid + '_' + sid; if (document.getElementById(pid) === null) { - let pathsgroup = document.getElementById('pathsGroup'); - let first = document.getElementById('p' + fid); - let second = document.getElementById('p' + sid); + let pathsgroup = mapsvg.findOne('#pathsGroup'); + let first = mapsvg.findOne('#p' + fid); + let second = mapsvg.findOne('#p' + sid); if (pathsgroup && first && second) { - pathsgroup.appendChild( - path( - first.cx.baseVal.value, - first.cy.baseVal.value, - second.cx.baseVal.value, - second.cy.baseVal.value, - 'learningmap-path', - pid - ) + let svgpath = path( + first.cx(), + first.cy(), + second.cx(), + second.cy(), + 'learningmap-path', + pid ); + svgpath.addTo(pathsgroup); placestore.addPath(pid, 'p' + fid, 'p' + sid); } } @@ -781,12 +753,10 @@ export const init = () => { * @param {any} event event causing the remove order */ function removePlace(event) { - let place = document.getElementById(event.target.id); - let parent = place.parentNode; + let place = getSVGShape(event.target.id); removePathsTouchingPlace(event.target.id); placestore.removePlace(event.target.id); - parent.removeChild(place); - parent.parentNode.removeChild(parent); + place.parent().remove(); updateCode(); } @@ -808,9 +778,9 @@ export const init = () => { * @param {number} id id of the path */ function removePath(id) { - let path = document.getElementById(id); + let path = getSVGShape(id); if (path !== null) { - path.parentNode.removeChild(path); + path.remove(); placestore.removePath(id); } } @@ -844,7 +814,7 @@ export const init = () => { let height = parseInt(background.getBBox().height); let width = background.getBBox().width; placestore.setBackgroundDimensions(width, height); - svg.setAttribute('viewBox', '0 0 ' + placestore.width + ' ' + placestore.height); + svgel.setAttribute('viewBox', '0 0 ' + placestore.width + ' ' + placestore.height); background.setAttribute('width', width); background.setAttribute('height', height); updateCode(); @@ -943,9 +913,9 @@ export const init = () => { break; } } - let placeNode = document.getElementById(place.id); - let textNode = text('text' + place.id, content, placeNode.cx.baseVal.value, placeNode.cy.baseVal.value); - placeNode.parentNode.appendChild(textNode); + let placeNode = mapsvg.findOne('#' + place.id); + let textNode = text('text' + place.id, content, placeNode.cx(), placeNode.cy()); + textNode.addTo(placeNode.parent()); } } } diff --git a/amd/src/placestore.js b/amd/src/placestore.js index d825464..e82b24e 100644 --- a/amd/src/placestore.js +++ b/amd/src/placestore.js @@ -50,14 +50,16 @@ let placestore = { * @param {*} id id of the place * @param {*} linkId id of the corresponding link * @param {*} linkedActivity course module id of linked activity + * @param {*} bbox bounding box of the place (including text) */ - addPlace: function(id, linkId, linkedActivity = null) { + addPlace: function(id, linkId, linkedActivity = null, bbox = {}) { this.places.push({ id: id, linkId: linkId, linkedActivity: linkedActivity, placecolor: null, - visitedcolor: null + visitedcolor: null, + bbox: bbox || {}, }); if (this.places.length == 1) { this.addStartingPlace(id); @@ -473,6 +475,21 @@ let placestore = { setShowWayGone: function(value) { this.showwaygone = value; }, + /** + * Sets the bbox of the place + * @param {*} id id of the place + * @param {*} bbox bounding box of the place (including text) + */ + setBbox: function(id, bbox) { + let place = this.places.filter( + function(e) { + return id == e.id; + } + ); + if (place.length > 0) { + place[0].bbox = bbox; + } + }, }; export default placestore; diff --git a/amd/src/shapes.js b/amd/src/shapes.js new file mode 100644 index 0000000..ef0d39c --- /dev/null +++ b/amd/src/shapes.js @@ -0,0 +1,33 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * Shapes for learningmap places. + * + * @module mod_learningmap/shapes + * @copyright 2024 ISB Bayern + * @author Stefan Hanauska + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import circle from './circle'; +import square from './square'; +import emoji from './emoji'; + +export default { + circle: circle, + square: square, + emoji: emoji, +}; \ No newline at end of file diff --git a/amd/src/square.js b/amd/src/square.js new file mode 100644 index 0000000..7de4842 --- /dev/null +++ b/amd/src/square.js @@ -0,0 +1,37 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * A square shape. + * + * @module mod_learningmap/square + * @copyright 2024 ISB Bayern + * @author Stefan Hanauska + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** + * Returns a rectangle with the given dimensions + * @param {*} mapsvg + * @param {*} x + * @param {*} y + * @param {*} r + * @param {*} classes + * @param {*} id + * @returns + */ +export default function(mapsvg, x, y, r, classes, id) { + return mapsvg.rect(r * 2, r * 2).cx(x).cy(y).attr({'class': classes}).id(id); +} \ No newline at end of file diff --git a/amd/src/svg.js b/amd/src/svg.js new file mode 100644 index 0000000..02de33b --- /dev/null +++ b/amd/src/svg.js @@ -0,0 +1,6945 @@ +/* +* @svgdotjs/svg.js - A lightweight library for manipulating and animating SVG. +* @version 3.2.4 +* https://svgjs.dev/ +* +* @copyright Wout Fierens +* @license MIT +* Copyright (c) 2012-2018 Wout Fierens +* https://svgdotjs.github.io/ +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* +* BUILT: Thu Jun 27 2024 12:00:16 GMT+0200 (Central European Summer Time) +*/ +export default function () { + 'use strict'; + + const methods$1 = {}; + const names = []; + function registerMethods(name, m) { + if (Array.isArray(name)) { + for (const _name of name) { + registerMethods(_name, m); + } + return; + } + if (typeof name === 'object') { + for (const _name in name) { + registerMethods(_name, name[_name]); + } + return; + } + addMethodNames(Object.getOwnPropertyNames(m)); + methods$1[name] = Object.assign(methods$1[name] || {}, m); + } + function getMethodsFor(name) { + return methods$1[name] || {}; + } + function getMethodNames() { + return [...new Set(names)]; + } + function addMethodNames(_names) { + names.push(..._names); + } + + // Map function + function map(array, block) { + let i; + const il = array.length; + const result = []; + for (i = 0; i < il; i++) { + result.push(block(array[i])); + } + return result; + } + + // Filter function + function filter(array, block) { + let i; + const il = array.length; + const result = []; + for (i = 0; i < il; i++) { + if (block(array[i])) { + result.push(array[i]); + } + } + return result; + } + + // Degrees to radians + function radians(d) { + return d % 360 * Math.PI / 180; + } + + // Radians to degrees + function degrees(r) { + return r * 180 / Math.PI % 360; + } + + // Convert camel cased string to dash separated + function unCamelCase(s) { + return s.replace(/([A-Z])/g, function (m, g) { + return '-' + g.toLowerCase(); + }); + } + + // Capitalize first letter of a string + function capitalize(s) { + return s.charAt(0).toUpperCase() + s.slice(1); + } + + // Calculate proportional width and height values when necessary + function proportionalSize(element, width, height, box) { + if (width == null || height == null) { + box = box || element.bbox(); + if (width == null) { + width = box.width / box.height * height; + } else if (height == null) { + height = box.height / box.width * width; + } + } + return { + width: width, + height: height + }; + } + + /** + * This function adds support for string origins. + * It searches for an origin in o.origin o.ox and o.originX. + * This way, origin: {x: 'center', y: 50} can be passed as well as ox: 'center', oy: 50 + **/ + function getOrigin(o, element) { + const origin = o.origin; + // First check if origin is in ox or originX + let ox = o.ox != null ? o.ox : o.originX != null ? o.originX : 'center'; + let oy = o.oy != null ? o.oy : o.originY != null ? o.originY : 'center'; + + // Then check if origin was used and overwrite in that case + if (origin != null) { + [ox, oy] = Array.isArray(origin) ? origin : typeof origin === 'object' ? [origin.x, origin.y] : [origin, origin]; + } + + // Make sure to only call bbox when actually needed + const condX = typeof ox === 'string'; + const condY = typeof oy === 'string'; + if (condX || condY) { + const { + height, + width, + x, + y + } = element.bbox(); + + // And only overwrite if string was passed for this specific axis + if (condX) { + ox = ox.includes('left') ? x : ox.includes('right') ? x + width : x + width / 2; + } + if (condY) { + oy = oy.includes('top') ? y : oy.includes('bottom') ? y + height : y + height / 2; + } + } + + // Return the origin as it is if it wasn't a string + return [ox, oy]; + } + const descriptiveElements = new Set(['desc', 'metadata', 'title']); + const isDescriptive = element => descriptiveElements.has(element.nodeName); + const writeDataToDom = (element, data, defaults = {}) => { + const cloned = { + ...data + }; + for (const key in cloned) { + if (cloned[key].valueOf() === defaults[key]) { + delete cloned[key]; + } + } + if (Object.keys(cloned).length) { + element.node.setAttribute('data-svgjs', JSON.stringify(cloned)); // see #428 + } else { + element.node.removeAttribute('data-svgjs'); + element.node.removeAttribute('svgjs:data'); + } + }; + + var utils = { + __proto__: null, + capitalize: capitalize, + degrees: degrees, + filter: filter, + getOrigin: getOrigin, + isDescriptive: isDescriptive, + map: map, + proportionalSize: proportionalSize, + radians: radians, + unCamelCase: unCamelCase, + writeDataToDom: writeDataToDom + }; + + // Default namespaces + const svg = 'http://www.w3.org/2000/svg'; + const html = 'http://www.w3.org/1999/xhtml'; + const xmlns = 'http://www.w3.org/2000/xmlns/'; + const xlink = 'http://www.w3.org/1999/xlink'; + + var namespaces = { + __proto__: null, + html: html, + svg: svg, + xlink: xlink, + xmlns: xmlns + }; + + const globals = { + window: typeof window === 'undefined' ? null : window, + document: typeof document === 'undefined' ? null : document + }; + function registerWindow(win = null, doc = null) { + globals.window = win; + globals.document = doc; + } + const save = {}; + function saveWindow() { + save.window = globals.window; + save.document = globals.document; + } + function restoreWindow() { + globals.window = save.window; + globals.document = save.document; + } + function withWindow(win, fn) { + saveWindow(); + registerWindow(win, win.document); + fn(win, win.document); + restoreWindow(); + } + function getWindow() { + return globals.window; + } + + class Base { + // constructor (node/*, {extensions = []} */) { + // // this.tags = [] + // // + // // for (let extension of extensions) { + // // extension.setup.call(this, node) + // // this.tags.push(extension.name) + // // } + // } + } + + const elements = {}; + const root = '___SYMBOL___ROOT___'; + + // Method for element creation + function create(name, ns = svg) { + // create element + return globals.document.createElementNS(ns, name); + } + function makeInstance(element, isHTML = false) { + if (element instanceof Base) return element; + if (typeof element === 'object') { + return adopter(element); + } + if (element == null) { + return new elements[root](); + } + if (typeof element === 'string' && element.charAt(0) !== '<') { + return adopter(globals.document.querySelector(element)); + } + + // Make sure, that HTML elements are created with the correct namespace + const wrapper = isHTML ? globals.document.createElement('div') : create('svg'); + wrapper.innerHTML = element; + + // We can use firstChild here because we know, + // that the first char is < and thus an element + element = adopter(wrapper.firstChild); + + // make sure, that element doesn't have its wrapper attached + wrapper.removeChild(wrapper.firstChild); + return element; + } + function nodeOrNew(name, node) { + return node && (node instanceof globals.window.Node || node.ownerDocument && node instanceof node.ownerDocument.defaultView.Node) ? node : create(name); + } + + // Adopt existing svg elements + function adopt(node) { + // check for presence of node + if (!node) return null; + + // make sure a node isn't already adopted + if (node.instance instanceof Base) return node.instance; + if (node.nodeName === '#document-fragment') { + return new elements.Fragment(node); + } + + // initialize variables + let className = capitalize(node.nodeName || 'Dom'); + + // Make sure that gradients are adopted correctly + if (className === 'LinearGradient' || className === 'RadialGradient') { + className = 'Gradient'; + + // Fallback to Dom if element is not known + } else if (!elements[className]) { + className = 'Dom'; + } + return new elements[className](node); + } + let adopter = adopt; + function mockAdopt(mock = adopt) { + adopter = mock; + } + function register(element, name = element.name, asRoot = false) { + elements[name] = element; + if (asRoot) elements[root] = element; + addMethodNames(Object.getOwnPropertyNames(element.prototype)); + return element; + } + function getClass(name) { + return elements[name]; + } + + // Element id sequence + let did = 1000; + + // Get next named element id + function eid(name) { + return 'Svgjs' + capitalize(name) + did++; + } + + // Deep new id assignment + function assignNewId(node) { + // do the same for SVG child nodes as well + for (let i = node.children.length - 1; i >= 0; i--) { + assignNewId(node.children[i]); + } + if (node.id) { + node.id = eid(node.nodeName); + return node; + } + return node; + } + + // Method for extending objects + function extend(modules, methods) { + let key, i; + modules = Array.isArray(modules) ? modules : [modules]; + for (i = modules.length - 1; i >= 0; i--) { + for (key in methods) { + modules[i].prototype[key] = methods[key]; + } + } + } + function wrapWithAttrCheck(fn) { + return function (...args) { + const o = args[args.length - 1]; + if (o && o.constructor === Object && !(o instanceof Array)) { + return fn.apply(this, args.slice(0, -1)).attr(o); + } else { + return fn.apply(this, args); + } + }; + } + + // Get all siblings, including myself + function siblings() { + return this.parent().children(); + } + + // Get the current position siblings + function position() { + return this.parent().index(this); + } + + // Get the next element (will return null if there is none) + function next() { + return this.siblings()[this.position() + 1]; + } + + // Get the next element (will return null if there is none) + function prev() { + return this.siblings()[this.position() - 1]; + } + + // Send given element one step forward + function forward() { + const i = this.position(); + const p = this.parent(); + + // move node one step forward + p.add(this.remove(), i + 1); + return this; + } + + // Send given element one step backward + function backward() { + const i = this.position(); + const p = this.parent(); + p.add(this.remove(), i ? i - 1 : 0); + return this; + } + + // Send given element all the way to the front + function front() { + const p = this.parent(); + + // Move node forward + p.add(this.remove()); + return this; + } + + // Send given element all the way to the back + function back() { + const p = this.parent(); + + // Move node back + p.add(this.remove(), 0); + return this; + } + + // Inserts a given element before the targeted element + function before(element) { + element = makeInstance(element); + element.remove(); + const i = this.position(); + this.parent().add(element, i); + return this; + } + + // Inserts a given element after the targeted element + function after(element) { + element = makeInstance(element); + element.remove(); + const i = this.position(); + this.parent().add(element, i + 1); + return this; + } + function insertBefore(element) { + element = makeInstance(element); + element.before(this); + return this; + } + function insertAfter(element) { + element = makeInstance(element); + element.after(this); + return this; + } + registerMethods('Dom', { + siblings, + position, + next, + prev, + forward, + backward, + front, + back, + before, + after, + insertBefore, + insertAfter + }); + + // Parse unit value + const numberAndUnit = /^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i; + + // Parse hex value + const hex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i; + + // Parse rgb value + const rgb = /rgb\((\d+),(\d+),(\d+)\)/; + + // Parse reference id + const reference = /(#[a-z_][a-z0-9\-_]*)/i; + + // splits a transformation chain + const transforms = /\)\s*,?\s*/; + + // Whitespace + const whitespace = /\s/g; + + // Test hex value + const isHex = /^#[a-f0-9]{3}$|^#[a-f0-9]{6}$/i; + + // Test rgb value + const isRgb = /^rgb\(/; + + // Test for blank string + const isBlank = /^(\s+)?$/; + + // Test for numeric string + const isNumber = /^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i; + + // Test for image url + const isImage = /\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i; + + // split at whitespace and comma + const delimiter = /[\s,]+/; + + // Test for path letter + const isPathLetter = /[MLHVCSQTAZ]/i; + + var regex = { + __proto__: null, + delimiter: delimiter, + hex: hex, + isBlank: isBlank, + isHex: isHex, + isImage: isImage, + isNumber: isNumber, + isPathLetter: isPathLetter, + isRgb: isRgb, + numberAndUnit: numberAndUnit, + reference: reference, + rgb: rgb, + transforms: transforms, + whitespace: whitespace + }; + + // Return array of classes on the node + function classes() { + const attr = this.attr('class'); + return attr == null ? [] : attr.trim().split(delimiter); + } + + // Return true if class exists on the node, false otherwise + function hasClass(name) { + return this.classes().indexOf(name) !== -1; + } + + // Add class to the node + function addClass(name) { + if (!this.hasClass(name)) { + const array = this.classes(); + array.push(name); + this.attr('class', array.join(' ')); + } + return this; + } + + // Remove class from the node + function removeClass(name) { + if (this.hasClass(name)) { + this.attr('class', this.classes().filter(function (c) { + return c !== name; + }).join(' ')); + } + return this; + } + + // Toggle the presence of a class on the node + function toggleClass(name) { + return this.hasClass(name) ? this.removeClass(name) : this.addClass(name); + } + registerMethods('Dom', { + classes, + hasClass, + addClass, + removeClass, + toggleClass + }); + + // Dynamic style generator + function css(style, val) { + const ret = {}; + if (arguments.length === 0) { + // get full style as object + this.node.style.cssText.split(/\s*;\s*/).filter(function (el) { + return !!el.length; + }).forEach(function (el) { + const t = el.split(/\s*:\s*/); + ret[t[0]] = t[1]; + }); + return ret; + } + if (arguments.length < 2) { + // get style properties as array + if (Array.isArray(style)) { + for (const name of style) { + const cased = name; + ret[name] = this.node.style.getPropertyValue(cased); + } + return ret; + } + + // get style for property + if (typeof style === 'string') { + return this.node.style.getPropertyValue(style); + } + + // set styles in object + if (typeof style === 'object') { + for (const name in style) { + // set empty string if null/undefined/'' was given + this.node.style.setProperty(name, style[name] == null || isBlank.test(style[name]) ? '' : style[name]); + } + } + } + + // set style for property + if (arguments.length === 2) { + this.node.style.setProperty(style, val == null || isBlank.test(val) ? '' : val); + } + return this; + } + + // Show element + function show() { + return this.css('display', ''); + } + + // Hide element + function hide() { + return this.css('display', 'none'); + } + + // Is element visible? + function visible() { + return this.css('display') !== 'none'; + } + registerMethods('Dom', { + css, + show, + hide, + visible + }); + + // Store data values on svg nodes + function data(a, v, r) { + if (a == null) { + // get an object of attributes + return this.data(map(filter(this.node.attributes, el => el.nodeName.indexOf('data-') === 0), el => el.nodeName.slice(5))); + } else if (a instanceof Array) { + const data = {}; + for (const key of a) { + data[key] = this.data(key); + } + return data; + } else if (typeof a === 'object') { + for (v in a) { + this.data(v, a[v]); + } + } else if (arguments.length < 2) { + try { + return JSON.parse(this.attr('data-' + a)); + } catch (e) { + return this.attr('data-' + a); + } + } else { + this.attr('data-' + a, v === null ? null : r === true || typeof v === 'string' || typeof v === 'number' ? v : JSON.stringify(v)); + } + return this; + } + registerMethods('Dom', { + data + }); + + // Remember arbitrary data + function remember(k, v) { + // remember every item in an object individually + if (typeof arguments[0] === 'object') { + for (const key in k) { + this.remember(key, k[key]); + } + } else if (arguments.length === 1) { + // retrieve memory + return this.memory()[k]; + } else { + // store memory + this.memory()[k] = v; + } + return this; + } + + // Erase a given memory + function forget() { + if (arguments.length === 0) { + this._memory = {}; + } else { + for (let i = arguments.length - 1; i >= 0; i--) { + delete this.memory()[arguments[i]]; + } + } + return this; + } + + // This triggers creation of a new hidden class which is not performant + // However, this function is not rarely used so it will not happen frequently + // Return local memory object + function memory() { + return this._memory = this._memory || {}; + } + registerMethods('Dom', { + remember, + forget, + memory + }); + + function sixDigitHex(hex) { + return hex.length === 4 ? ['#', hex.substring(1, 2), hex.substring(1, 2), hex.substring(2, 3), hex.substring(2, 3), hex.substring(3, 4), hex.substring(3, 4)].join('') : hex; + } + function componentHex(component) { + const integer = Math.round(component); + const bounded = Math.max(0, Math.min(255, integer)); + const hex = bounded.toString(16); + return hex.length === 1 ? '0' + hex : hex; + } + function is(object, space) { + for (let i = space.length; i--;) { + if (object[space[i]] == null) { + return false; + } + } + return true; + } + function getParameters(a, b) { + const params = is(a, 'rgb') ? { + _a: a.r, + _b: a.g, + _c: a.b, + _d: 0, + space: 'rgb' + } : is(a, 'xyz') ? { + _a: a.x, + _b: a.y, + _c: a.z, + _d: 0, + space: 'xyz' + } : is(a, 'hsl') ? { + _a: a.h, + _b: a.s, + _c: a.l, + _d: 0, + space: 'hsl' + } : is(a, 'lab') ? { + _a: a.l, + _b: a.a, + _c: a.b, + _d: 0, + space: 'lab' + } : is(a, 'lch') ? { + _a: a.l, + _b: a.c, + _c: a.h, + _d: 0, + space: 'lch' + } : is(a, 'cmyk') ? { + _a: a.c, + _b: a.m, + _c: a.y, + _d: a.k, + space: 'cmyk' + } : { + _a: 0, + _b: 0, + _c: 0, + space: 'rgb' + }; + params.space = b || params.space; + return params; + } + function cieSpace(space) { + if (space === 'lab' || space === 'xyz' || space === 'lch') { + return true; + } else { + return false; + } + } + function hueToRgb(p, q, t) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + } + class Color { + constructor(...inputs) { + this.init(...inputs); + } + + // Test if given value is a color + static isColor(color) { + return color && (color instanceof Color || this.isRgb(color) || this.test(color)); + } + + // Test if given value is an rgb object + static isRgb(color) { + return color && typeof color.r === 'number' && typeof color.g === 'number' && typeof color.b === 'number'; + } + + /* + Generating random colors + */ + static random(mode = 'vibrant', t) { + // Get the math modules + const { + random, + round, + sin, + PI: pi + } = Math; + + // Run the correct generator + if (mode === 'vibrant') { + const l = (81 - 57) * random() + 57; + const c = (83 - 45) * random() + 45; + const h = 360 * random(); + const color = new Color(l, c, h, 'lch'); + return color; + } else if (mode === 'sine') { + t = t == null ? random() : t; + const r = round(80 * sin(2 * pi * t / 0.5 + 0.01) + 150); + const g = round(50 * sin(2 * pi * t / 0.5 + 4.6) + 200); + const b = round(100 * sin(2 * pi * t / 0.5 + 2.3) + 150); + const color = new Color(r, g, b); + return color; + } else if (mode === 'pastel') { + const l = (94 - 86) * random() + 86; + const c = (26 - 9) * random() + 9; + const h = 360 * random(); + const color = new Color(l, c, h, 'lch'); + return color; + } else if (mode === 'dark') { + const l = 10 + 10 * random(); + const c = (125 - 75) * random() + 86; + const h = 360 * random(); + const color = new Color(l, c, h, 'lch'); + return color; + } else if (mode === 'rgb') { + const r = 255 * random(); + const g = 255 * random(); + const b = 255 * random(); + const color = new Color(r, g, b); + return color; + } else if (mode === 'lab') { + const l = 100 * random(); + const a = 256 * random() - 128; + const b = 256 * random() - 128; + const color = new Color(l, a, b, 'lab'); + return color; + } else if (mode === 'grey') { + const grey = 255 * random(); + const color = new Color(grey, grey, grey); + return color; + } else { + throw new Error('Unsupported random color mode'); + } + } + + // Test if given value is a color string + static test(color) { + return typeof color === 'string' && (isHex.test(color) || isRgb.test(color)); + } + cmyk() { + // Get the rgb values for the current color + const { + _a, + _b, + _c + } = this.rgb(); + const [r, g, b] = [_a, _b, _c].map(v => v / 255); + + // Get the cmyk values in an unbounded format + const k = Math.min(1 - r, 1 - g, 1 - b); + if (k === 1) { + // Catch the black case + return new Color(0, 0, 0, 1, 'cmyk'); + } + const c = (1 - r - k) / (1 - k); + const m = (1 - g - k) / (1 - k); + const y = (1 - b - k) / (1 - k); + + // Construct the new color + const color = new Color(c, m, y, k, 'cmyk'); + return color; + } + hsl() { + // Get the rgb values + const { + _a, + _b, + _c + } = this.rgb(); + const [r, g, b] = [_a, _b, _c].map(v => v / 255); + + // Find the maximum and minimum values to get the lightness + const max = Math.max(r, g, b); + const min = Math.min(r, g, b); + const l = (max + min) / 2; + + // If the r, g, v values are identical then we are grey + const isGrey = max === min; + + // Calculate the hue and saturation + const delta = max - min; + const s = isGrey ? 0 : l > 0.5 ? delta / (2 - max - min) : delta / (max + min); + const h = isGrey ? 0 : max === r ? ((g - b) / delta + (g < b ? 6 : 0)) / 6 : max === g ? ((b - r) / delta + 2) / 6 : max === b ? ((r - g) / delta + 4) / 6 : 0; + + // Construct and return the new color + const color = new Color(360 * h, 100 * s, 100 * l, 'hsl'); + return color; + } + init(a = 0, b = 0, c = 0, d = 0, space = 'rgb') { + // This catches the case when a falsy value is passed like '' + a = !a ? 0 : a; + + // Reset all values in case the init function is rerun with new color space + if (this.space) { + for (const component in this.space) { + delete this[this.space[component]]; + } + } + if (typeof a === 'number') { + // Allow for the case that we don't need d... + space = typeof d === 'string' ? d : space; + d = typeof d === 'string' ? 0 : d; + + // Assign the values straight to the color + Object.assign(this, { + _a: a, + _b: b, + _c: c, + _d: d, + space + }); + // If the user gave us an array, make the color from it + } else if (a instanceof Array) { + this.space = b || (typeof a[3] === 'string' ? a[3] : a[4]) || 'rgb'; + Object.assign(this, { + _a: a[0], + _b: a[1], + _c: a[2], + _d: a[3] || 0 + }); + } else if (a instanceof Object) { + // Set the object up and assign its values directly + const values = getParameters(a, b); + Object.assign(this, values); + } else if (typeof a === 'string') { + if (isRgb.test(a)) { + const noWhitespace = a.replace(whitespace, ''); + const [_a, _b, _c] = rgb.exec(noWhitespace).slice(1, 4).map(v => parseInt(v)); + Object.assign(this, { + _a, + _b, + _c, + _d: 0, + space: 'rgb' + }); + } else if (isHex.test(a)) { + const hexParse = v => parseInt(v, 16); + const [, _a, _b, _c] = hex.exec(sixDigitHex(a)).map(hexParse); + Object.assign(this, { + _a, + _b, + _c, + _d: 0, + space: 'rgb' + }); + } else throw Error("Unsupported string format, can't construct Color"); + } + + // Now add the components as a convenience + const { + _a, + _b, + _c, + _d + } = this; + const components = this.space === 'rgb' ? { + r: _a, + g: _b, + b: _c + } : this.space === 'xyz' ? { + x: _a, + y: _b, + z: _c + } : this.space === 'hsl' ? { + h: _a, + s: _b, + l: _c + } : this.space === 'lab' ? { + l: _a, + a: _b, + b: _c + } : this.space === 'lch' ? { + l: _a, + c: _b, + h: _c + } : this.space === 'cmyk' ? { + c: _a, + m: _b, + y: _c, + k: _d + } : {}; + Object.assign(this, components); + } + lab() { + // Get the xyz color + const { + x, + y, + z + } = this.xyz(); + + // Get the lab components + const l = 116 * y - 16; + const a = 500 * (x - y); + const b = 200 * (y - z); + + // Construct and return a new color + const color = new Color(l, a, b, 'lab'); + return color; + } + lch() { + // Get the lab color directly + const { + l, + a, + b + } = this.lab(); + + // Get the chromaticity and the hue using polar coordinates + const c = Math.sqrt(a ** 2 + b ** 2); + let h = 180 * Math.atan2(b, a) / Math.PI; + if (h < 0) { + h *= -1; + h = 360 - h; + } + + // Make a new color and return it + const color = new Color(l, c, h, 'lch'); + return color; + } + /* + Conversion Methods + */ + + rgb() { + if (this.space === 'rgb') { + return this; + } else if (cieSpace(this.space)) { + // Convert to the xyz color space + let { + x, + y, + z + } = this; + if (this.space === 'lab' || this.space === 'lch') { + // Get the values in the lab space + let { + l, + a, + b + } = this; + if (this.space === 'lch') { + const { + c, + h + } = this; + const dToR = Math.PI / 180; + a = c * Math.cos(dToR * h); + b = c * Math.sin(dToR * h); + } + + // Undo the nonlinear function + const yL = (l + 16) / 116; + const xL = a / 500 + yL; + const zL = yL - b / 200; + + // Get the xyz values + const ct = 16 / 116; + const mx = 0.008856; + const nm = 7.787; + x = 0.95047 * (xL ** 3 > mx ? xL ** 3 : (xL - ct) / nm); + y = 1.0 * (yL ** 3 > mx ? yL ** 3 : (yL - ct) / nm); + z = 1.08883 * (zL ** 3 > mx ? zL ** 3 : (zL - ct) / nm); + } + + // Convert xyz to unbounded rgb values + const rU = x * 3.2406 + y * -1.5372 + z * -0.4986; + const gU = x * -0.9689 + y * 1.8758 + z * 0.0415; + const bU = x * 0.0557 + y * -0.204 + z * 1.057; + + // Convert the values to true rgb values + const pow = Math.pow; + const bd = 0.0031308; + const r = rU > bd ? 1.055 * pow(rU, 1 / 2.4) - 0.055 : 12.92 * rU; + const g = gU > bd ? 1.055 * pow(gU, 1 / 2.4) - 0.055 : 12.92 * gU; + const b = bU > bd ? 1.055 * pow(bU, 1 / 2.4) - 0.055 : 12.92 * bU; + + // Make and return the color + const color = new Color(255 * r, 255 * g, 255 * b); + return color; + } else if (this.space === 'hsl') { + // https://bgrins.github.io/TinyColor/docs/tinycolor.html + // Get the current hsl values + let { + h, + s, + l + } = this; + h /= 360; + s /= 100; + l /= 100; + + // If we are grey, then just make the color directly + if (s === 0) { + l *= 255; + const color = new Color(l, l, l); + return color; + } + + // TODO I have no idea what this does :D If you figure it out, tell me! + const q = l < 0.5 ? l * (1 + s) : l + s - l * s; + const p = 2 * l - q; + + // Get the rgb values + const r = 255 * hueToRgb(p, q, h + 1 / 3); + const g = 255 * hueToRgb(p, q, h); + const b = 255 * hueToRgb(p, q, h - 1 / 3); + + // Make a new color + const color = new Color(r, g, b); + return color; + } else if (this.space === 'cmyk') { + // https://gist.github.com/felipesabino/5066336 + // Get the normalised cmyk values + const { + c, + m, + y, + k + } = this; + + // Get the rgb values + const r = 255 * (1 - Math.min(1, c * (1 - k) + k)); + const g = 255 * (1 - Math.min(1, m * (1 - k) + k)); + const b = 255 * (1 - Math.min(1, y * (1 - k) + k)); + + // Form the color and return it + const color = new Color(r, g, b); + return color; + } else { + return this; + } + } + toArray() { + const { + _a, + _b, + _c, + _d, + space + } = this; + return [_a, _b, _c, _d, space]; + } + toHex() { + const [r, g, b] = this._clamped().map(componentHex); + return `#${r}${g}${b}`; + } + toRgb() { + const [rV, gV, bV] = this._clamped(); + const string = `rgb(${rV},${gV},${bV})`; + return string; + } + toString() { + return this.toHex(); + } + xyz() { + // Normalise the red, green and blue values + const { + _a: r255, + _b: g255, + _c: b255 + } = this.rgb(); + const [r, g, b] = [r255, g255, b255].map(v => v / 255); + + // Convert to the lab rgb space + const rL = r > 0.04045 ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92; + const gL = g > 0.04045 ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92; + const bL = b > 0.04045 ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92; + + // Convert to the xyz color space without bounding the values + const xU = (rL * 0.4124 + gL * 0.3576 + bL * 0.1805) / 0.95047; + const yU = (rL * 0.2126 + gL * 0.7152 + bL * 0.0722) / 1.0; + const zU = (rL * 0.0193 + gL * 0.1192 + bL * 0.9505) / 1.08883; + + // Get the proper xyz values by applying the bounding + const x = xU > 0.008856 ? Math.pow(xU, 1 / 3) : 7.787 * xU + 16 / 116; + const y = yU > 0.008856 ? Math.pow(yU, 1 / 3) : 7.787 * yU + 16 / 116; + const z = zU > 0.008856 ? Math.pow(zU, 1 / 3) : 7.787 * zU + 16 / 116; + + // Make and return the color + const color = new Color(x, y, z, 'xyz'); + return color; + } + + /* + Input and Output methods + */ + + _clamped() { + const { + _a, + _b, + _c + } = this.rgb(); + const { + max, + min, + round + } = Math; + const format = v => max(0, min(round(v), 255)); + return [_a, _b, _c].map(format); + } + + /* + Constructing colors + */ + } + + class Point { + // Initialize + constructor(...args) { + this.init(...args); + } + + // Clone point + clone() { + return new Point(this); + } + init(x, y) { + const base = { + x: 0, + y: 0 + }; + + // ensure source as object + const source = Array.isArray(x) ? { + x: x[0], + y: x[1] + } : typeof x === 'object' ? { + x: x.x, + y: x.y + } : { + x: x, + y: y + }; + + // merge source + this.x = source.x == null ? base.x : source.x; + this.y = source.y == null ? base.y : source.y; + return this; + } + toArray() { + return [this.x, this.y]; + } + transform(m) { + return this.clone().transformO(m); + } + + // Transform point with matrix + transformO(m) { + if (!Matrix.isMatrixLike(m)) { + m = new Matrix(m); + } + const { + x, + y + } = this; + + // Perform the matrix multiplication + this.x = m.a * x + m.c * y + m.e; + this.y = m.b * x + m.d * y + m.f; + return this; + } + } + function point(x, y) { + return new Point(x, y).transformO(this.screenCTM().inverseO()); + } + + function closeEnough(a, b, threshold) { + return Math.abs(b - a) < (1e-6); + } + class Matrix { + constructor(...args) { + this.init(...args); + } + static formatTransforms(o) { + // Get all of the parameters required to form the matrix + const flipBoth = o.flip === 'both' || o.flip === true; + const flipX = o.flip && (flipBoth || o.flip === 'x') ? -1 : 1; + const flipY = o.flip && (flipBoth || o.flip === 'y') ? -1 : 1; + const skewX = o.skew && o.skew.length ? o.skew[0] : isFinite(o.skew) ? o.skew : isFinite(o.skewX) ? o.skewX : 0; + const skewY = o.skew && o.skew.length ? o.skew[1] : isFinite(o.skew) ? o.skew : isFinite(o.skewY) ? o.skewY : 0; + const scaleX = o.scale && o.scale.length ? o.scale[0] * flipX : isFinite(o.scale) ? o.scale * flipX : isFinite(o.scaleX) ? o.scaleX * flipX : flipX; + const scaleY = o.scale && o.scale.length ? o.scale[1] * flipY : isFinite(o.scale) ? o.scale * flipY : isFinite(o.scaleY) ? o.scaleY * flipY : flipY; + const shear = o.shear || 0; + const theta = o.rotate || o.theta || 0; + const origin = new Point(o.origin || o.around || o.ox || o.originX, o.oy || o.originY); + const ox = origin.x; + const oy = origin.y; + // We need Point to be invalid if nothing was passed because we cannot default to 0 here. That is why NaN + const position = new Point(o.position || o.px || o.positionX || NaN, o.py || o.positionY || NaN); + const px = position.x; + const py = position.y; + const translate = new Point(o.translate || o.tx || o.translateX, o.ty || o.translateY); + const tx = translate.x; + const ty = translate.y; + const relative = new Point(o.relative || o.rx || o.relativeX, o.ry || o.relativeY); + const rx = relative.x; + const ry = relative.y; + + // Populate all of the values + return { + scaleX, + scaleY, + skewX, + skewY, + shear, + theta, + rx, + ry, + tx, + ty, + ox, + oy, + px, + py + }; + } + static fromArray(a) { + return { + a: a[0], + b: a[1], + c: a[2], + d: a[3], + e: a[4], + f: a[5] + }; + } + static isMatrixLike(o) { + return o.a != null || o.b != null || o.c != null || o.d != null || o.e != null || o.f != null; + } + + // left matrix, right matrix, target matrix which is overwritten + static matrixMultiply(l, r, o) { + // Work out the product directly + const a = l.a * r.a + l.c * r.b; + const b = l.b * r.a + l.d * r.b; + const c = l.a * r.c + l.c * r.d; + const d = l.b * r.c + l.d * r.d; + const e = l.e + l.a * r.e + l.c * r.f; + const f = l.f + l.b * r.e + l.d * r.f; + + // make sure to use local variables because l/r and o could be the same + o.a = a; + o.b = b; + o.c = c; + o.d = d; + o.e = e; + o.f = f; + return o; + } + around(cx, cy, matrix) { + return this.clone().aroundO(cx, cy, matrix); + } + + // Transform around a center point + aroundO(cx, cy, matrix) { + const dx = cx || 0; + const dy = cy || 0; + return this.translateO(-dx, -dy).lmultiplyO(matrix).translateO(dx, dy); + } + + // Clones this matrix + clone() { + return new Matrix(this); + } + + // Decomposes this matrix into its affine parameters + decompose(cx = 0, cy = 0) { + // Get the parameters from the matrix + const a = this.a; + const b = this.b; + const c = this.c; + const d = this.d; + const e = this.e; + const f = this.f; + + // Figure out if the winding direction is clockwise or counterclockwise + const determinant = a * d - b * c; + const ccw = determinant > 0 ? 1 : -1; + + // Since we only shear in x, we can use the x basis to get the x scale + // and the rotation of the resulting matrix + const sx = ccw * Math.sqrt(a * a + b * b); + const thetaRad = Math.atan2(ccw * b, ccw * a); + const theta = 180 / Math.PI * thetaRad; + const ct = Math.cos(thetaRad); + const st = Math.sin(thetaRad); + + // We can then solve the y basis vector simultaneously to get the other + // two affine parameters directly from these parameters + const lam = (a * c + b * d) / determinant; + const sy = c * sx / (lam * a - b) || d * sx / (lam * b + a); + + // Use the translations + const tx = e - cx + cx * ct * sx + cy * (lam * ct * sx - st * sy); + const ty = f - cy + cx * st * sx + cy * (lam * st * sx + ct * sy); + + // Construct the decomposition and return it + return { + // Return the affine parameters + scaleX: sx, + scaleY: sy, + shear: lam, + rotate: theta, + translateX: tx, + translateY: ty, + originX: cx, + originY: cy, + // Return the matrix parameters + a: this.a, + b: this.b, + c: this.c, + d: this.d, + e: this.e, + f: this.f + }; + } + + // Check if two matrices are equal + equals(other) { + if (other === this) return true; + const comp = new Matrix(other); + return closeEnough(this.a, comp.a) && closeEnough(this.b, comp.b) && closeEnough(this.c, comp.c) && closeEnough(this.d, comp.d) && closeEnough(this.e, comp.e) && closeEnough(this.f, comp.f); + } + + // Flip matrix on x or y, at a given offset + flip(axis, around) { + return this.clone().flipO(axis, around); + } + flipO(axis, around) { + return axis === 'x' ? this.scaleO(-1, 1, around, 0) : axis === 'y' ? this.scaleO(1, -1, 0, around) : this.scaleO(-1, -1, axis, around || axis); // Define an x, y flip point + } + + // Initialize + init(source) { + const base = Matrix.fromArray([1, 0, 0, 1, 0, 0]); + + // ensure source as object + source = source instanceof Element ? source.matrixify() : typeof source === 'string' ? Matrix.fromArray(source.split(delimiter).map(parseFloat)) : Array.isArray(source) ? Matrix.fromArray(source) : typeof source === 'object' && Matrix.isMatrixLike(source) ? source : typeof source === 'object' ? new Matrix().transform(source) : arguments.length === 6 ? Matrix.fromArray([].slice.call(arguments)) : base; + + // Merge the source matrix with the base matrix + this.a = source.a != null ? source.a : base.a; + this.b = source.b != null ? source.b : base.b; + this.c = source.c != null ? source.c : base.c; + this.d = source.d != null ? source.d : base.d; + this.e = source.e != null ? source.e : base.e; + this.f = source.f != null ? source.f : base.f; + return this; + } + inverse() { + return this.clone().inverseO(); + } + + // Inverses matrix + inverseO() { + // Get the current parameters out of the matrix + const a = this.a; + const b = this.b; + const c = this.c; + const d = this.d; + const e = this.e; + const f = this.f; + + // Invert the 2x2 matrix in the top left + const det = a * d - b * c; + if (!det) throw new Error('Cannot invert ' + this); + + // Calculate the top 2x2 matrix + const na = d / det; + const nb = -b / det; + const nc = -c / det; + const nd = a / det; + + // Apply the inverted matrix to the top right + const ne = -(na * e + nc * f); + const nf = -(nb * e + nd * f); + + // Construct the inverted matrix + this.a = na; + this.b = nb; + this.c = nc; + this.d = nd; + this.e = ne; + this.f = nf; + return this; + } + lmultiply(matrix) { + return this.clone().lmultiplyO(matrix); + } + lmultiplyO(matrix) { + const r = this; + const l = matrix instanceof Matrix ? matrix : new Matrix(matrix); + return Matrix.matrixMultiply(l, r, this); + } + + // Left multiplies by the given matrix + multiply(matrix) { + return this.clone().multiplyO(matrix); + } + multiplyO(matrix) { + // Get the matrices + const l = this; + const r = matrix instanceof Matrix ? matrix : new Matrix(matrix); + return Matrix.matrixMultiply(l, r, this); + } + + // Rotate matrix + rotate(r, cx, cy) { + return this.clone().rotateO(r, cx, cy); + } + rotateO(r, cx = 0, cy = 0) { + // Convert degrees to radians + r = radians(r); + const cos = Math.cos(r); + const sin = Math.sin(r); + const { + a, + b, + c, + d, + e, + f + } = this; + this.a = a * cos - b * sin; + this.b = b * cos + a * sin; + this.c = c * cos - d * sin; + this.d = d * cos + c * sin; + this.e = e * cos - f * sin + cy * sin - cx * cos + cx; + this.f = f * cos + e * sin - cx * sin - cy * cos + cy; + return this; + } + + // Scale matrix + scale() { + return this.clone().scaleO(...arguments); + } + scaleO(x, y = x, cx = 0, cy = 0) { + // Support uniform scaling + if (arguments.length === 3) { + cy = cx; + cx = y; + y = x; + } + const { + a, + b, + c, + d, + e, + f + } = this; + this.a = a * x; + this.b = b * y; + this.c = c * x; + this.d = d * y; + this.e = e * x - cx * x + cx; + this.f = f * y - cy * y + cy; + return this; + } + + // Shear matrix + shear(a, cx, cy) { + return this.clone().shearO(a, cx, cy); + } + + // eslint-disable-next-line no-unused-vars + shearO(lx, cx = 0, cy = 0) { + const { + a, + b, + c, + d, + e, + f + } = this; + this.a = a + b * lx; + this.c = c + d * lx; + this.e = e + f * lx - cy * lx; + return this; + } + + // Skew Matrix + skew() { + return this.clone().skewO(...arguments); + } + skewO(x, y = x, cx = 0, cy = 0) { + // support uniformal skew + if (arguments.length === 3) { + cy = cx; + cx = y; + y = x; + } + + // Convert degrees to radians + x = radians(x); + y = radians(y); + const lx = Math.tan(x); + const ly = Math.tan(y); + const { + a, + b, + c, + d, + e, + f + } = this; + this.a = a + b * lx; + this.b = b + a * ly; + this.c = c + d * lx; + this.d = d + c * ly; + this.e = e + f * lx - cy * lx; + this.f = f + e * ly - cx * ly; + return this; + } + + // SkewX + skewX(x, cx, cy) { + return this.skew(x, 0, cx, cy); + } + + // SkewY + skewY(y, cx, cy) { + return this.skew(0, y, cx, cy); + } + toArray() { + return [this.a, this.b, this.c, this.d, this.e, this.f]; + } + + // Convert matrix to string + toString() { + return 'matrix(' + this.a + ',' + this.b + ',' + this.c + ',' + this.d + ',' + this.e + ',' + this.f + ')'; + } + + // Transform a matrix into another matrix by manipulating the space + transform(o) { + // Check if o is a matrix and then left multiply it directly + if (Matrix.isMatrixLike(o)) { + const matrix = new Matrix(o); + return matrix.multiplyO(this); + } + + // Get the proposed transformations and the current transformations + const t = Matrix.formatTransforms(o); + const current = this; + const { + x: ox, + y: oy + } = new Point(t.ox, t.oy).transform(current); + + // Construct the resulting matrix + const transformer = new Matrix().translateO(t.rx, t.ry).lmultiplyO(current).translateO(-ox, -oy).scaleO(t.scaleX, t.scaleY).skewO(t.skewX, t.skewY).shearO(t.shear).rotateO(t.theta).translateO(ox, oy); + + // If we want the origin at a particular place, we force it there + if (isFinite(t.px) || isFinite(t.py)) { + const origin = new Point(ox, oy).transform(transformer); + // TODO: Replace t.px with isFinite(t.px) + // Doesn't work because t.px is also 0 if it wasn't passed + const dx = isFinite(t.px) ? t.px - origin.x : 0; + const dy = isFinite(t.py) ? t.py - origin.y : 0; + transformer.translateO(dx, dy); + } + + // Translate now after positioning + transformer.translateO(t.tx, t.ty); + return transformer; + } + + // Translate matrix + translate(x, y) { + return this.clone().translateO(x, y); + } + translateO(x, y) { + this.e += x || 0; + this.f += y || 0; + return this; + } + valueOf() { + return { + a: this.a, + b: this.b, + c: this.c, + d: this.d, + e: this.e, + f: this.f + }; + } + } + function ctm() { + return new Matrix(this.node.getCTM()); + } + function screenCTM() { + try { + /* https://bugzilla.mozilla.org/show_bug.cgi?id=1344537 + This is needed because FF does not return the transformation matrix + for the inner coordinate system when getScreenCTM() is called on nested svgs. + However all other Browsers do that */ + if (typeof this.isRoot === 'function' && !this.isRoot()) { + const rect = this.rect(1, 1); + const m = rect.node.getScreenCTM(); + rect.remove(); + return new Matrix(m); + } + return new Matrix(this.node.getScreenCTM()); + } catch (e) { + console.warn(`Cannot get CTM from SVG node ${this.node.nodeName}. Is the element rendered?`); + return new Matrix(); + } + } + register(Matrix, 'Matrix'); + + function parser() { + // Reuse cached element if possible + if (!parser.nodes) { + const svg = makeInstance().size(2, 0); + svg.node.style.cssText = ['opacity: 0', 'position: absolute', 'left: -100%', 'top: -100%', 'overflow: hidden'].join(';'); + svg.attr('focusable', 'false'); + svg.attr('aria-hidden', 'true'); + const path = svg.path().node; + parser.nodes = { + svg, + path + }; + } + if (!parser.nodes.svg.node.parentNode) { + const b = globals.document.body || globals.document.documentElement; + parser.nodes.svg.addTo(b); + } + return parser.nodes; + } + + function isNulledBox(box) { + return !box.width && !box.height && !box.x && !box.y; + } + function domContains(node) { + return node === globals.document || (globals.document.documentElement.contains || function (node) { + // This is IE - it does not support contains() for top-level SVGs + while (node.parentNode) { + node = node.parentNode; + } + return node === globals.document; + }).call(globals.document.documentElement, node); + } + class Box { + constructor(...args) { + this.init(...args); + } + addOffset() { + // offset by window scroll position, because getBoundingClientRect changes when window is scrolled + this.x += globals.window.pageXOffset; + this.y += globals.window.pageYOffset; + return new Box(this); + } + init(source) { + const base = [0, 0, 0, 0]; + source = typeof source === 'string' ? source.split(delimiter).map(parseFloat) : Array.isArray(source) ? source : typeof source === 'object' ? [source.left != null ? source.left : source.x, source.top != null ? source.top : source.y, source.width, source.height] : arguments.length === 4 ? [].slice.call(arguments) : base; + this.x = source[0] || 0; + this.y = source[1] || 0; + this.width = this.w = source[2] || 0; + this.height = this.h = source[3] || 0; + + // Add more bounding box properties + this.x2 = this.x + this.w; + this.y2 = this.y + this.h; + this.cx = this.x + this.w / 2; + this.cy = this.y + this.h / 2; + return this; + } + isNulled() { + return isNulledBox(this); + } + + // Merge rect box with another, return a new instance + merge(box) { + const x = Math.min(this.x, box.x); + const y = Math.min(this.y, box.y); + const width = Math.max(this.x + this.width, box.x + box.width) - x; + const height = Math.max(this.y + this.height, box.y + box.height) - y; + return new Box(x, y, width, height); + } + toArray() { + return [this.x, this.y, this.width, this.height]; + } + toString() { + return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height; + } + transform(m) { + if (!(m instanceof Matrix)) { + m = new Matrix(m); + } + let xMin = Infinity; + let xMax = -Infinity; + let yMin = Infinity; + let yMax = -Infinity; + const pts = [new Point(this.x, this.y), new Point(this.x2, this.y), new Point(this.x, this.y2), new Point(this.x2, this.y2)]; + pts.forEach(function (p) { + p = p.transform(m); + xMin = Math.min(xMin, p.x); + xMax = Math.max(xMax, p.x); + yMin = Math.min(yMin, p.y); + yMax = Math.max(yMax, p.y); + }); + return new Box(xMin, yMin, xMax - xMin, yMax - yMin); + } + } + function getBox(el, getBBoxFn, retry) { + let box; + try { + // Try to get the box with the provided function + box = getBBoxFn(el.node); + + // If the box is worthless and not even in the dom, retry + // by throwing an error here... + if (isNulledBox(box) && !domContains(el.node)) { + throw new Error('Element not in the dom'); + } + } catch (e) { + // ... and calling the retry handler here + box = retry(el); + } + return box; + } + function bbox() { + // Function to get bbox is getBBox() + const getBBox = node => node.getBBox(); + + // Take all measures so that a stupid browser renders the element + // so we can get the bbox from it when we try again + const retry = el => { + try { + const clone = el.clone().addTo(parser().svg).show(); + const box = clone.node.getBBox(); + clone.remove(); + return box; + } catch (e) { + // We give up... + throw new Error(`Getting bbox of element "${el.node.nodeName}" is not possible: ${e.toString()}`); + } + }; + const box = getBox(this, getBBox, retry); + const bbox = new Box(box); + return bbox; + } + function rbox(el) { + const getRBox = node => node.getBoundingClientRect(); + const retry = el => { + // There is no point in trying tricks here because if we insert the element into the dom ourselves + // it obviously will be at the wrong position + throw new Error(`Getting rbox of element "${el.node.nodeName}" is not possible`); + }; + const box = getBox(this, getRBox, retry); + const rbox = new Box(box); + + // If an element was passed, we want the bbox in the coordinate system of that element + if (el) { + return rbox.transform(el.screenCTM().inverseO()); + } + + // Else we want it in absolute screen coordinates + // Therefore we need to add the scrollOffset + return rbox.addOffset(); + } + + // Checks whether the given point is inside the bounding box + function inside(x, y) { + const box = this.bbox(); + return x > box.x && y > box.y && x < box.x + box.width && y < box.y + box.height; + } + registerMethods({ + viewbox: { + viewbox(x, y, width, height) { + // act as getter + if (x == null) return new Box(this.attr('viewBox')); + + // act as setter + return this.attr('viewBox', new Box(x, y, width, height)); + }, + zoom(level, point) { + // Its best to rely on the attributes here and here is why: + // clientXYZ: Doesn't work on non-root svgs because they dont have a CSSBox (silly!) + // getBoundingClientRect: Doesn't work because Chrome just ignores width and height of nested svgs completely + // that means, their clientRect is always as big as the content. + // Furthermore this size is incorrect if the element is further transformed by its parents + // computedStyle: Only returns meaningful values if css was used with px. We dont go this route here! + // getBBox: returns the bounding box of its content - that doesn't help! + let { + width, + height + } = this.attr(['width', 'height']); + + // Width and height is a string when a number with a unit is present which we can't use + // So we try clientXYZ + if (!width && !height || typeof width === 'string' || typeof height === 'string') { + width = this.node.clientWidth; + height = this.node.clientHeight; + } + + // Giving up... + if (!width || !height) { + throw new Error('Impossible to get absolute width and height. Please provide an absolute width and height attribute on the zooming element'); + } + const v = this.viewbox(); + const zoomX = width / v.width; + const zoomY = height / v.height; + const zoom = Math.min(zoomX, zoomY); + if (level == null) { + return zoom; + } + let zoomAmount = zoom / level; + + // Set the zoomAmount to the highest value which is safe to process and recover from + // The * 100 is a bit of wiggle room for the matrix transformation + if (zoomAmount === Infinity) zoomAmount = Number.MAX_SAFE_INTEGER / 100; + point = point || new Point(width / 2 / zoomX + v.x, height / 2 / zoomY + v.y); + const box = new Box(v).transform(new Matrix({ + scale: zoomAmount, + origin: point + })); + return this.viewbox(box); + } + } + }); + register(Box, 'Box'); + + // import { subClassArray } from './ArrayPolyfill.js' + + class List extends Array { + constructor(arr = [], ...args) { + super(arr, ...args); + if (typeof arr === 'number') return this; + this.length = 0; + this.push(...arr); + } + } + extend([List], { + each(fnOrMethodName, ...args) { + if (typeof fnOrMethodName === 'function') { + return this.map((el, i, arr) => { + return fnOrMethodName.call(el, el, i, arr); + }); + } else { + return this.map(el => { + return el[fnOrMethodName](...args); + }); + } + }, + toArray() { + return Array.prototype.concat.apply([], this); + } + }); + const reserved = ['toArray', 'constructor', 'each']; + List.extend = function (methods) { + methods = methods.reduce((obj, name) => { + // Don't overwrite own methods + if (reserved.includes(name)) return obj; + + // Don't add private methods + if (name[0] === '_') return obj; + + // Allow access to original Array methods through a prefix + if (name in Array.prototype) { + obj['$' + name] = Array.prototype[name]; + } + + // Relay every call to each() + obj[name] = function (...attrs) { + return this.each(name, ...attrs); + }; + return obj; + }, {}); + extend([List], methods); + }; + + function baseFind(query, parent) { + return new List(map((parent || globals.document).querySelectorAll(query), function (node) { + return adopt(node); + })); + } + + // Scoped find method + function find(query) { + return baseFind(query, this.node); + } + function findOne(query) { + return adopt(this.node.querySelector(query)); + } + + let listenerId = 0; + const windowEvents = {}; + function getEvents(instance) { + let n = instance.getEventHolder(); + + // We dont want to save events in global space + if (n === globals.window) n = windowEvents; + if (!n.events) n.events = {}; + return n.events; + } + function getEventTarget(instance) { + return instance.getEventTarget(); + } + function clearEvents(instance) { + let n = instance.getEventHolder(); + if (n === globals.window) n = windowEvents; + if (n.events) n.events = {}; + } + + // Add event binder in the SVG namespace + function on(node, events, listener, binding, options) { + const l = listener.bind(binding || node); + const instance = makeInstance(node); + const bag = getEvents(instance); + const n = getEventTarget(instance); + + // events can be an array of events or a string of events + events = Array.isArray(events) ? events : events.split(delimiter); + + // add id to listener + if (!listener._svgjsListenerId) { + listener._svgjsListenerId = ++listenerId; + } + events.forEach(function (event) { + const ev = event.split('.')[0]; + const ns = event.split('.')[1] || '*'; + + // ensure valid object + bag[ev] = bag[ev] || {}; + bag[ev][ns] = bag[ev][ns] || {}; + + // reference listener + bag[ev][ns][listener._svgjsListenerId] = l; + + // add listener + n.addEventListener(ev, l, options || false); + }); + } + + // Add event unbinder in the SVG namespace + function off(node, events, listener, options) { + const instance = makeInstance(node); + const bag = getEvents(instance); + const n = getEventTarget(instance); + + // listener can be a function or a number + if (typeof listener === 'function') { + listener = listener._svgjsListenerId; + if (!listener) return; + } + + // events can be an array of events or a string or undefined + events = Array.isArray(events) ? events : (events || '').split(delimiter); + events.forEach(function (event) { + const ev = event && event.split('.')[0]; + const ns = event && event.split('.')[1]; + let namespace, l; + if (listener) { + // remove listener reference + if (bag[ev] && bag[ev][ns || '*']) { + // removeListener + n.removeEventListener(ev, bag[ev][ns || '*'][listener], options || false); + delete bag[ev][ns || '*'][listener]; + } + } else if (ev && ns) { + // remove all listeners for a namespaced event + if (bag[ev] && bag[ev][ns]) { + for (l in bag[ev][ns]) { + off(n, [ev, ns].join('.'), l); + } + delete bag[ev][ns]; + } + } else if (ns) { + // remove all listeners for a specific namespace + for (event in bag) { + for (namespace in bag[event]) { + if (ns === namespace) { + off(n, [event, ns].join('.')); + } + } + } + } else if (ev) { + // remove all listeners for the event + if (bag[ev]) { + for (namespace in bag[ev]) { + off(n, [ev, namespace].join('.')); + } + delete bag[ev]; + } + } else { + // remove all listeners on a given node + for (event in bag) { + off(n, event); + } + clearEvents(instance); + } + }); + } + function dispatch(node, event, data, options) { + const n = getEventTarget(node); + + // Dispatch event + if (event instanceof globals.window.Event) { + n.dispatchEvent(event); + } else { + event = new globals.window.CustomEvent(event, { + detail: data, + cancelable: true, + ...options + }); + n.dispatchEvent(event); + } + return event; + } + + class EventTarget extends Base { + addEventListener() {} + dispatch(event, data, options) { + return dispatch(this, event, data, options); + } + dispatchEvent(event) { + const bag = this.getEventHolder().events; + if (!bag) return true; + const events = bag[event.type]; + for (const i in events) { + for (const j in events[i]) { + events[i][j](event); + } + } + return !event.defaultPrevented; + } + + // Fire given event + fire(event, data, options) { + this.dispatch(event, data, options); + return this; + } + getEventHolder() { + return this; + } + getEventTarget() { + return this; + } + + // Unbind event from listener + off(event, listener, options) { + off(this, event, listener, options); + return this; + } + + // Bind given event to listener + on(event, listener, binding, options) { + on(this, event, listener, binding, options); + return this; + } + removeEventListener() {} + } + register(EventTarget, 'EventTarget'); + + function noop() {} + + // Default animation values + const timeline = { + duration: 400, + ease: '>', + delay: 0 + }; + + // Default attribute values + const attrs = { + // fill and stroke + 'fill-opacity': 1, + 'stroke-opacity': 1, + 'stroke-width': 0, + 'stroke-linejoin': 'miter', + 'stroke-linecap': 'butt', + fill: '#000000', + stroke: '#000000', + opacity: 1, + // position + x: 0, + y: 0, + cx: 0, + cy: 0, + // size + width: 0, + height: 0, + // radius + r: 0, + rx: 0, + ry: 0, + // gradient + offset: 0, + 'stop-opacity': 1, + 'stop-color': '#000000', + // text + 'text-anchor': 'start' + }; + + var defaults = { + __proto__: null, + attrs: attrs, + noop: noop, + timeline: timeline + }; + + class SVGArray extends Array { + constructor(...args) { + super(...args); + this.init(...args); + } + clone() { + return new this.constructor(this); + } + init(arr) { + // This catches the case, that native map tries to create an array with new Array(1) + if (typeof arr === 'number') return this; + this.length = 0; + this.push(...this.parse(arr)); + return this; + } + + // Parse whitespace separated string + parse(array = []) { + // If already is an array, no need to parse it + if (array instanceof Array) return array; + return array.trim().split(delimiter).map(parseFloat); + } + toArray() { + return Array.prototype.concat.apply([], this); + } + toSet() { + return new Set(this); + } + toString() { + return this.join(' '); + } + + // Flattens the array if needed + valueOf() { + const ret = []; + ret.push(...this); + return ret; + } + } + + // Module for unit conversions + class SVGNumber { + // Initialize + constructor(...args) { + this.init(...args); + } + convert(unit) { + return new SVGNumber(this.value, unit); + } + + // Divide number + divide(number) { + number = new SVGNumber(number); + return new SVGNumber(this / number, this.unit || number.unit); + } + init(value, unit) { + unit = Array.isArray(value) ? value[1] : unit; + value = Array.isArray(value) ? value[0] : value; + + // initialize defaults + this.value = 0; + this.unit = unit || ''; + + // parse value + if (typeof value === 'number') { + // ensure a valid numeric value + this.value = isNaN(value) ? 0 : !isFinite(value) ? value < 0 ? -3.4e38 : +3.4e38 : value; + } else if (typeof value === 'string') { + unit = value.match(numberAndUnit); + if (unit) { + // make value numeric + this.value = parseFloat(unit[1]); + + // normalize + if (unit[5] === '%') { + this.value /= 100; + } else if (unit[5] === 's') { + this.value *= 1000; + } + + // store unit + this.unit = unit[5]; + } + } else { + if (value instanceof SVGNumber) { + this.value = value.valueOf(); + this.unit = value.unit; + } + } + return this; + } + + // Subtract number + minus(number) { + number = new SVGNumber(number); + return new SVGNumber(this - number, this.unit || number.unit); + } + + // Add number + plus(number) { + number = new SVGNumber(number); + return new SVGNumber(this + number, this.unit || number.unit); + } + + // Multiply number + times(number) { + number = new SVGNumber(number); + return new SVGNumber(this * number, this.unit || number.unit); + } + toArray() { + return [this.value, this.unit]; + } + toJSON() { + return this.toString(); + } + toString() { + return (this.unit === '%' ? ~~(this.value * 1e8) / 1e6 : this.unit === 's' ? this.value / 1e3 : this.value) + this.unit; + } + valueOf() { + return this.value; + } + } + + const colorAttributes = new Set(['fill', 'stroke', 'color', 'bgcolor', 'stop-color', 'flood-color', 'lighting-color']); + const hooks = []; + function registerAttrHook(fn) { + hooks.push(fn); + } + + // Set svg element attribute + function attr(attr, val, ns) { + // act as full getter + if (attr == null) { + // get an object of attributes + attr = {}; + val = this.node.attributes; + for (const node of val) { + attr[node.nodeName] = isNumber.test(node.nodeValue) ? parseFloat(node.nodeValue) : node.nodeValue; + } + return attr; + } else if (attr instanceof Array) { + // loop through array and get all values + return attr.reduce((last, curr) => { + last[curr] = this.attr(curr); + return last; + }, {}); + } else if (typeof attr === 'object' && attr.constructor === Object) { + // apply every attribute individually if an object is passed + for (val in attr) this.attr(val, attr[val]); + } else if (val === null) { + // remove value + this.node.removeAttribute(attr); + } else if (val == null) { + // act as a getter if the first and only argument is not an object + val = this.node.getAttribute(attr); + return val == null ? attrs[attr] : isNumber.test(val) ? parseFloat(val) : val; + } else { + // Loop through hooks and execute them to convert value + val = hooks.reduce((_val, hook) => { + return hook(attr, _val, this); + }, val); + + // ensure correct numeric values (also accepts NaN and Infinity) + if (typeof val === 'number') { + val = new SVGNumber(val); + } else if (colorAttributes.has(attr) && Color.isColor(val)) { + // ensure full hex color + val = new Color(val); + } else if (val.constructor === Array) { + // Check for plain arrays and parse array values + val = new SVGArray(val); + } + + // if the passed attribute is leading... + if (attr === 'leading') { + // ... call the leading method instead + if (this.leading) { + this.leading(val); + } + } else { + // set given attribute on node + typeof ns === 'string' ? this.node.setAttributeNS(ns, attr, val.toString()) : this.node.setAttribute(attr, val.toString()); + } + + // rebuild if required + if (this.rebuild && (attr === 'font-size' || attr === 'x')) { + this.rebuild(); + } + } + return this; + } + + class Dom extends EventTarget { + constructor(node, attrs) { + super(); + this.node = node; + this.type = node.nodeName; + if (attrs && node !== attrs) { + this.attr(attrs); + } + } + + // Add given element at a position + add(element, i) { + element = makeInstance(element); + + // If non-root svg nodes are added we have to remove their namespaces + if (element.removeNamespace && this.node instanceof globals.window.SVGElement) { + element.removeNamespace(); + } + if (i == null) { + this.node.appendChild(element.node); + } else if (element.node !== this.node.childNodes[i]) { + this.node.insertBefore(element.node, this.node.childNodes[i]); + } + return this; + } + + // Add element to given container and return self + addTo(parent, i) { + return makeInstance(parent).put(this, i); + } + + // Returns all child elements + children() { + return new List(map(this.node.children, function (node) { + return adopt(node); + })); + } + + // Remove all elements in this container + clear() { + // remove children + while (this.node.hasChildNodes()) { + this.node.removeChild(this.node.lastChild); + } + return this; + } + + // Clone element + clone(deep = true, assignNewIds = true) { + // write dom data to the dom so the clone can pickup the data + this.writeDataToDom(); + + // clone element + let nodeClone = this.node.cloneNode(deep); + if (assignNewIds) { + // assign new id + nodeClone = assignNewId(nodeClone); + } + return new this.constructor(nodeClone); + } + + // Iterates over all children and invokes a given block + each(block, deep) { + const children = this.children(); + let i, il; + for (i = 0, il = children.length; i < il; i++) { + block.apply(children[i], [i, children]); + if (deep) { + children[i].each(block, deep); + } + } + return this; + } + element(nodeName, attrs) { + return this.put(new Dom(create(nodeName), attrs)); + } + + // Get first child + first() { + return adopt(this.node.firstChild); + } + + // Get a element at the given index + get(i) { + return adopt(this.node.childNodes[i]); + } + getEventHolder() { + return this.node; + } + getEventTarget() { + return this.node; + } + + // Checks if the given element is a child + has(element) { + return this.index(element) >= 0; + } + html(htmlOrFn, outerHTML) { + return this.xml(htmlOrFn, outerHTML, html); + } + + // Get / set id + id(id) { + // generate new id if no id set + if (typeof id === 'undefined' && !this.node.id) { + this.node.id = eid(this.type); + } + + // don't set directly with this.node.id to make `null` work correctly + return this.attr('id', id); + } + + // Gets index of given element + index(element) { + return [].slice.call(this.node.childNodes).indexOf(element.node); + } + + // Get the last child + last() { + return adopt(this.node.lastChild); + } + + // matches the element vs a css selector + matches(selector) { + const el = this.node; + const matcher = el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector || null; + return matcher && matcher.call(el, selector); + } + + // Returns the parent element instance + parent(type) { + let parent = this; + + // check for parent + if (!parent.node.parentNode) return null; + + // get parent element + parent = adopt(parent.node.parentNode); + if (!type) return parent; + + // loop through ancestors if type is given + do { + if (typeof type === 'string' ? parent.matches(type) : parent instanceof type) return parent; + } while (parent = adopt(parent.node.parentNode)); + return parent; + } + + // Basically does the same as `add()` but returns the added element instead + put(element, i) { + element = makeInstance(element); + this.add(element, i); + return element; + } + + // Add element to given container and return container + putIn(parent, i) { + return makeInstance(parent).add(this, i); + } + + // Remove element + remove() { + if (this.parent()) { + this.parent().removeElement(this); + } + return this; + } + + // Remove a given child + removeElement(element) { + this.node.removeChild(element.node); + return this; + } + + // Replace this with element + replace(element) { + element = makeInstance(element); + if (this.node.parentNode) { + this.node.parentNode.replaceChild(element.node, this.node); + } + return element; + } + round(precision = 2, map = null) { + const factor = 10 ** precision; + const attrs = this.attr(map); + for (const i in attrs) { + if (typeof attrs[i] === 'number') { + attrs[i] = Math.round(attrs[i] * factor) / factor; + } + } + this.attr(attrs); + return this; + } + + // Import / Export raw svg + svg(svgOrFn, outerSVG) { + return this.xml(svgOrFn, outerSVG, svg); + } + + // Return id on string conversion + toString() { + return this.id(); + } + words(text) { + // This is faster than removing all children and adding a new one + this.node.textContent = text; + return this; + } + wrap(node) { + const parent = this.parent(); + if (!parent) { + return this.addTo(node); + } + const position = parent.index(this); + return parent.put(node, position).put(this); + } + + // write svgjs data to the dom + writeDataToDom() { + // dump variables recursively + this.each(function () { + this.writeDataToDom(); + }); + return this; + } + + // Import / Export raw svg + xml(xmlOrFn, outerXML, ns) { + if (typeof xmlOrFn === 'boolean') { + ns = outerXML; + outerXML = xmlOrFn; + xmlOrFn = null; + } + + // act as getter if no svg string is given + if (xmlOrFn == null || typeof xmlOrFn === 'function') { + // The default for exports is, that the outerNode is included + outerXML = outerXML == null ? true : outerXML; + + // write svgjs data to the dom + this.writeDataToDom(); + let current = this; + + // An export modifier was passed + if (xmlOrFn != null) { + current = adopt(current.node.cloneNode(true)); + + // If the user wants outerHTML we need to process this node, too + if (outerXML) { + const result = xmlOrFn(current); + current = result || current; + + // The user does not want this node? Well, then he gets nothing + if (result === false) return ''; + } + + // Deep loop through all children and apply modifier + current.each(function () { + const result = xmlOrFn(this); + const _this = result || this; + + // If modifier returns false, discard node + if (result === false) { + this.remove(); + + // If modifier returns new node, use it + } else if (result && this !== _this) { + this.replace(_this); + } + }, true); + } + + // Return outer or inner content + return outerXML ? current.node.outerHTML : current.node.innerHTML; + } + + // Act as setter if we got a string + + // The default for import is, that the current node is not replaced + outerXML = outerXML == null ? false : outerXML; + + // Create temporary holder + const well = create('wrapper', ns); + const fragment = globals.document.createDocumentFragment(); + + // Dump raw svg + well.innerHTML = xmlOrFn; + + // Transplant nodes into the fragment + for (let len = well.children.length; len--;) { + fragment.appendChild(well.firstElementChild); + } + const parent = this.parent(); + + // Add the whole fragment at once + return outerXML ? this.replace(fragment) && parent : this.add(fragment); + } + } + extend(Dom, { + attr, + find, + findOne + }); + register(Dom, 'Dom'); + + class Element extends Dom { + constructor(node, attrs) { + super(node, attrs); + + // initialize data object + this.dom = {}; + + // create circular reference + this.node.instance = this; + if (node.hasAttribute('data-svgjs') || node.hasAttribute('svgjs:data')) { + // pull svgjs data from the dom (getAttributeNS doesn't work in html5) + this.setData(JSON.parse(node.getAttribute('data-svgjs')) ?? JSON.parse(node.getAttribute('svgjs:data')) ?? {}); + } + } + + // Move element by its center + center(x, y) { + return this.cx(x).cy(y); + } + + // Move by center over x-axis + cx(x) { + return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2); + } + + // Move by center over y-axis + cy(y) { + return y == null ? this.y() + this.height() / 2 : this.y(y - this.height() / 2); + } + + // Get defs + defs() { + const root = this.root(); + return root && root.defs(); + } + + // Relative move over x and y axes + dmove(x, y) { + return this.dx(x).dy(y); + } + + // Relative move over x axis + dx(x = 0) { + return this.x(new SVGNumber(x).plus(this.x())); + } + + // Relative move over y axis + dy(y = 0) { + return this.y(new SVGNumber(y).plus(this.y())); + } + getEventHolder() { + return this; + } + + // Set height of element + height(height) { + return this.attr('height', height); + } + + // Move element to given x and y values + move(x, y) { + return this.x(x).y(y); + } + + // return array of all ancestors of given type up to the root svg + parents(until = this.root()) { + const isSelector = typeof until === 'string'; + if (!isSelector) { + until = makeInstance(until); + } + const parents = new List(); + let parent = this; + while ((parent = parent.parent()) && parent.node !== globals.document && parent.nodeName !== '#document-fragment') { + parents.push(parent); + if (!isSelector && parent.node === until.node) { + break; + } + if (isSelector && parent.matches(until)) { + break; + } + if (parent.node === this.root().node) { + // We worked our way to the root and didn't match `until` + return null; + } + } + return parents; + } + + // Get referenced element form attribute value + reference(attr) { + attr = this.attr(attr); + if (!attr) return null; + const m = (attr + '').match(reference); + return m ? makeInstance(m[1]) : null; + } + + // Get parent document + root() { + const p = this.parent(getClass(root)); + return p && p.root(); + } + + // set given data to the elements data property + setData(o) { + this.dom = o; + return this; + } + + // Set element size to given width and height + size(width, height) { + const p = proportionalSize(this, width, height); + return this.width(new SVGNumber(p.width)).height(new SVGNumber(p.height)); + } + + // Set width of element + width(width) { + return this.attr('width', width); + } + + // write svgjs data to the dom + writeDataToDom() { + writeDataToDom(this, this.dom); + return super.writeDataToDom(); + } + + // Move over x-axis + x(x) { + return this.attr('x', x); + } + + // Move over y-axis + y(y) { + return this.attr('y', y); + } + } + extend(Element, { + bbox, + rbox, + inside, + point, + ctm, + screenCTM + }); + register(Element, 'Element'); + + // Define list of available attributes for stroke and fill + const sugar = { + stroke: ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'], + fill: ['color', 'opacity', 'rule'], + prefix: function (t, a) { + return a === 'color' ? t : t + '-' + a; + } + } + + // Add sugar for fill and stroke + ; + ['fill', 'stroke'].forEach(function (m) { + const extension = {}; + let i; + extension[m] = function (o) { + if (typeof o === 'undefined') { + return this.attr(m); + } + if (typeof o === 'string' || o instanceof Color || Color.isRgb(o) || o instanceof Element) { + this.attr(m, o); + } else { + // set all attributes from sugar.fill and sugar.stroke list + for (i = sugar[m].length - 1; i >= 0; i--) { + if (o[sugar[m][i]] != null) { + this.attr(sugar.prefix(m, sugar[m][i]), o[sugar[m][i]]); + } + } + } + return this; + }; + registerMethods(['Element', 'Runner'], extension); + }); + registerMethods(['Element', 'Runner'], { + // Let the user set the matrix directly + matrix: function (mat, b, c, d, e, f) { + // Act as a getter + if (mat == null) { + return new Matrix(this); + } + + // Act as a setter, the user can pass a matrix or a set of numbers + return this.attr('transform', new Matrix(mat, b, c, d, e, f)); + }, + // Map rotation to transform + rotate: function (angle, cx, cy) { + return this.transform({ + rotate: angle, + ox: cx, + oy: cy + }, true); + }, + // Map skew to transform + skew: function (x, y, cx, cy) { + return arguments.length === 1 || arguments.length === 3 ? this.transform({ + skew: x, + ox: y, + oy: cx + }, true) : this.transform({ + skew: [x, y], + ox: cx, + oy: cy + }, true); + }, + shear: function (lam, cx, cy) { + return this.transform({ + shear: lam, + ox: cx, + oy: cy + }, true); + }, + // Map scale to transform + scale: function (x, y, cx, cy) { + return arguments.length === 1 || arguments.length === 3 ? this.transform({ + scale: x, + ox: y, + oy: cx + }, true) : this.transform({ + scale: [x, y], + ox: cx, + oy: cy + }, true); + }, + // Map translate to transform + translate: function (x, y) { + return this.transform({ + translate: [x, y] + }, true); + }, + // Map relative translations to transform + relative: function (x, y) { + return this.transform({ + relative: [x, y] + }, true); + }, + // Map flip to transform + flip: function (direction = 'both', origin = 'center') { + if ('xybothtrue'.indexOf(direction) === -1) { + origin = direction; + direction = 'both'; + } + return this.transform({ + flip: direction, + origin: origin + }, true); + }, + // Opacity + opacity: function (value) { + return this.attr('opacity', value); + } + }); + registerMethods('radius', { + // Add x and y radius + radius: function (x, y = x) { + const type = (this._element || this).type; + return type === 'radialGradient' ? this.attr('r', new SVGNumber(x)) : this.rx(x).ry(y); + } + }); + registerMethods('Path', { + // Get path length + length: function () { + return this.node.getTotalLength(); + }, + // Get point at length + pointAt: function (length) { + return new Point(this.node.getPointAtLength(length)); + } + }); + registerMethods(['Element', 'Runner'], { + // Set font + font: function (a, v) { + if (typeof a === 'object') { + for (v in a) this.font(v, a[v]); + return this; + } + return a === 'leading' ? this.leading(v) : a === 'anchor' ? this.attr('text-anchor', v) : a === 'size' || a === 'family' || a === 'weight' || a === 'stretch' || a === 'variant' || a === 'style' ? this.attr('font-' + a, v) : this.attr(a, v); + } + }); + + // Add events to elements + const methods = ['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout', 'mousemove', 'mouseenter', 'mouseleave', 'touchstart', 'touchmove', 'touchleave', 'touchend', 'touchcancel', 'contextmenu', 'wheel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel'].reduce(function (last, event) { + // add event to Element + const fn = function (f) { + if (f === null) { + this.off(event); + } else { + this.on(event, f); + } + return this; + }; + last[event] = fn; + return last; + }, {}); + registerMethods('Element', methods); + + // Reset all transformations + function untransform() { + return this.attr('transform', null); + } + + // merge the whole transformation chain into one matrix and returns it + function matrixify() { + const matrix = (this.attr('transform') || '' + // split transformations + ).split(transforms).slice(0, -1).map(function (str) { + // generate key => value pairs + const kv = str.trim().split('('); + return [kv[0], kv[1].split(delimiter).map(function (str) { + return parseFloat(str); + })]; + }).reverse() + // merge every transformation into one matrix + .reduce(function (matrix, transform) { + if (transform[0] === 'matrix') { + return matrix.lmultiply(Matrix.fromArray(transform[1])); + } + return matrix[transform[0]].apply(matrix, transform[1]); + }, new Matrix()); + return matrix; + } + + // add an element to another parent without changing the visual representation on the screen + function toParent(parent, i) { + if (this === parent) return this; + if (isDescriptive(this.node)) return this.addTo(parent, i); + const ctm = this.screenCTM(); + const pCtm = parent.screenCTM().inverse(); + this.addTo(parent, i).untransform().transform(pCtm.multiply(ctm)); + return this; + } + + // same as above with parent equals root-svg + function toRoot(i) { + return this.toParent(this.root(), i); + } + + // Add transformations + function transform(o, relative) { + // Act as a getter if no object was passed + if (o == null || typeof o === 'string') { + const decomposed = new Matrix(this).decompose(); + return o == null ? decomposed : decomposed[o]; + } + if (!Matrix.isMatrixLike(o)) { + // Set the origin according to the defined transform + o = { + ...o, + origin: getOrigin(o, this) + }; + } + + // The user can pass a boolean, an Element or an Matrix or nothing + const cleanRelative = relative === true ? this : relative || false; + const result = new Matrix(cleanRelative).transform(o); + return this.attr('transform', result); + } + registerMethods('Element', { + untransform, + matrixify, + toParent, + toRoot, + transform + }); + + class Container extends Element { + flatten() { + this.each(function () { + if (this instanceof Container) { + return this.flatten().ungroup(); + } + }); + return this; + } + ungroup(parent = this.parent(), index = parent.index(this)) { + // when parent != this, we want append all elements to the end + index = index === -1 ? parent.children().length : index; + this.each(function (i, children) { + // reverse each + return children[children.length - i - 1].toParent(parent, index); + }); + return this.remove(); + } + } + register(Container, 'Container'); + + class Defs extends Container { + constructor(node, attrs = node) { + super(nodeOrNew('defs', node), attrs); + } + flatten() { + return this; + } + ungroup() { + return this; + } + } + register(Defs, 'Defs'); + + class Shape extends Element {} + register(Shape, 'Shape'); + + // Radius x value + function rx(rx) { + return this.attr('rx', rx); + } + + // Radius y value + function ry(ry) { + return this.attr('ry', ry); + } + + // Move over x-axis + function x$3(x) { + return x == null ? this.cx() - this.rx() : this.cx(x + this.rx()); + } + + // Move over y-axis + function y$3(y) { + return y == null ? this.cy() - this.ry() : this.cy(y + this.ry()); + } + + // Move by center over x-axis + function cx$1(x) { + return this.attr('cx', x); + } + + // Move by center over y-axis + function cy$1(y) { + return this.attr('cy', y); + } + + // Set width of element + function width$2(width) { + return width == null ? this.rx() * 2 : this.rx(new SVGNumber(width).divide(2)); + } + + // Set height of element + function height$2(height) { + return height == null ? this.ry() * 2 : this.ry(new SVGNumber(height).divide(2)); + } + + var circled = { + __proto__: null, + cx: cx$1, + cy: cy$1, + height: height$2, + rx: rx, + ry: ry, + width: width$2, + x: x$3, + y: y$3 + }; + + class Ellipse extends Shape { + constructor(node, attrs = node) { + super(nodeOrNew('ellipse', node), attrs); + } + size(width, height) { + const p = proportionalSize(this, width, height); + return this.rx(new SVGNumber(p.width).divide(2)).ry(new SVGNumber(p.height).divide(2)); + } + } + extend(Ellipse, circled); + registerMethods('Container', { + // Create an ellipse + ellipse: wrapWithAttrCheck(function (width = 0, height = width) { + return this.put(new Ellipse()).size(width, height).move(0, 0); + }) + }); + register(Ellipse, 'Ellipse'); + + class Fragment extends Dom { + constructor(node = globals.document.createDocumentFragment()) { + super(node); + } + + // Import / Export raw xml + xml(xmlOrFn, outerXML, ns) { + if (typeof xmlOrFn === 'boolean') { + ns = outerXML; + outerXML = xmlOrFn; + xmlOrFn = null; + } + + // because this is a fragment we have to put all elements into a wrapper first + // before we can get the innerXML from it + if (xmlOrFn == null || typeof xmlOrFn === 'function') { + const wrapper = new Dom(create('wrapper', ns)); + wrapper.add(this.node.cloneNode(true)); + return wrapper.xml(false, ns); + } + + // Act as setter if we got a string + return super.xml(xmlOrFn, false, ns); + } + } + register(Fragment, 'Fragment'); + + function from(x, y) { + return (this._element || this).type === 'radialGradient' ? this.attr({ + fx: new SVGNumber(x), + fy: new SVGNumber(y) + }) : this.attr({ + x1: new SVGNumber(x), + y1: new SVGNumber(y) + }); + } + function to(x, y) { + return (this._element || this).type === 'radialGradient' ? this.attr({ + cx: new SVGNumber(x), + cy: new SVGNumber(y) + }) : this.attr({ + x2: new SVGNumber(x), + y2: new SVGNumber(y) + }); + } + + var gradiented = { + __proto__: null, + from: from, + to: to + }; + + class Gradient extends Container { + constructor(type, attrs) { + super(nodeOrNew(type + 'Gradient', typeof type === 'string' ? null : type), attrs); + } + + // custom attr to handle transform + attr(a, b, c) { + if (a === 'transform') a = 'gradientTransform'; + return super.attr(a, b, c); + } + bbox() { + return new Box(); + } + targets() { + return baseFind('svg [fill*=' + this.id() + ']'); + } + + // Alias string conversion to fill + toString() { + return this.url(); + } + + // Update gradient + update(block) { + // remove all stops + this.clear(); + + // invoke passed block + if (typeof block === 'function') { + block.call(this, this); + } + return this; + } + + // Return the fill id + url() { + return 'url(#' + this.id() + ')'; + } + } + extend(Gradient, gradiented); + registerMethods({ + Container: { + // Create gradient element in defs + gradient(...args) { + return this.defs().gradient(...args); + } + }, + // define gradient + Defs: { + gradient: wrapWithAttrCheck(function (type, block) { + return this.put(new Gradient(type)).update(block); + }) + } + }); + register(Gradient, 'Gradient'); + + class Pattern extends Container { + // Initialize node + constructor(node, attrs = node) { + super(nodeOrNew('pattern', node), attrs); + } + + // custom attr to handle transform + attr(a, b, c) { + if (a === 'transform') a = 'patternTransform'; + return super.attr(a, b, c); + } + bbox() { + return new Box(); + } + targets() { + return baseFind('svg [fill*=' + this.id() + ']'); + } + + // Alias string conversion to fill + toString() { + return this.url(); + } + + // Update pattern by rebuilding + update(block) { + // remove content + this.clear(); + + // invoke passed block + if (typeof block === 'function') { + block.call(this, this); + } + return this; + } + + // Return the fill id + url() { + return 'url(#' + this.id() + ')'; + } + } + registerMethods({ + Container: { + // Create pattern element in defs + pattern(...args) { + return this.defs().pattern(...args); + } + }, + Defs: { + pattern: wrapWithAttrCheck(function (width, height, block) { + return this.put(new Pattern()).update(block).attr({ + x: 0, + y: 0, + width: width, + height: height, + patternUnits: 'userSpaceOnUse' + }); + }) + } + }); + register(Pattern, 'Pattern'); + + class Image extends Shape { + constructor(node, attrs = node) { + super(nodeOrNew('image', node), attrs); + } + + // (re)load image + load(url, callback) { + if (!url) return this; + const img = new globals.window.Image(); + on(img, 'load', function (e) { + const p = this.parent(Pattern); + + // ensure image size + if (this.width() === 0 && this.height() === 0) { + this.size(img.width, img.height); + } + if (p instanceof Pattern) { + // ensure pattern size if not set + if (p.width() === 0 && p.height() === 0) { + p.size(this.width(), this.height()); + } + } + if (typeof callback === 'function') { + callback.call(this, e); + } + }, this); + on(img, 'load error', function () { + // dont forget to unbind memory leaking events + off(img); + }); + return this.attr('href', img.src = url, xlink); + } + } + registerAttrHook(function (attr, val, _this) { + // convert image fill and stroke to patterns + if (attr === 'fill' || attr === 'stroke') { + if (isImage.test(val)) { + val = _this.root().defs().image(val); + } + } + if (val instanceof Image) { + val = _this.root().defs().pattern(0, 0, pattern => { + pattern.add(val); + }); + } + return val; + }); + registerMethods({ + Container: { + // create image element, load image and set its size + image: wrapWithAttrCheck(function (source, callback) { + return this.put(new Image()).size(0, 0).load(source, callback); + }) + } + }); + register(Image, 'Image'); + + class PointArray extends SVGArray { + // Get bounding box of points + bbox() { + let maxX = -Infinity; + let maxY = -Infinity; + let minX = Infinity; + let minY = Infinity; + this.forEach(function (el) { + maxX = Math.max(el[0], maxX); + maxY = Math.max(el[1], maxY); + minX = Math.min(el[0], minX); + minY = Math.min(el[1], minY); + }); + return new Box(minX, minY, maxX - minX, maxY - minY); + } + + // Move point string + move(x, y) { + const box = this.bbox(); + + // get relative offset + x -= box.x; + y -= box.y; + + // move every point + if (!isNaN(x) && !isNaN(y)) { + for (let i = this.length - 1; i >= 0; i--) { + this[i] = [this[i][0] + x, this[i][1] + y]; + } + } + return this; + } + + // Parse point string and flat array + parse(array = [0, 0]) { + const points = []; + + // if it is an array, we flatten it and therefore clone it to 1 depths + if (array instanceof Array) { + array = Array.prototype.concat.apply([], array); + } else { + // Else, it is considered as a string + // parse points + array = array.trim().split(delimiter).map(parseFloat); + } + + // validate points - https://svgwg.org/svg2-draft/shapes.html#DataTypePoints + // Odd number of coordinates is an error. In such cases, drop the last odd coordinate. + if (array.length % 2 !== 0) array.pop(); + + // wrap points in two-tuples + for (let i = 0, len = array.length; i < len; i = i + 2) { + points.push([array[i], array[i + 1]]); + } + return points; + } + + // Resize poly string + size(width, height) { + let i; + const box = this.bbox(); + + // recalculate position of all points according to new size + for (i = this.length - 1; i >= 0; i--) { + if (box.width) this[i][0] = (this[i][0] - box.x) * width / box.width + box.x; + if (box.height) this[i][1] = (this[i][1] - box.y) * height / box.height + box.y; + } + return this; + } + + // Convert array to line object + toLine() { + return { + x1: this[0][0], + y1: this[0][1], + x2: this[1][0], + y2: this[1][1] + }; + } + + // Convert array to string + toString() { + const array = []; + // convert to a poly point string + for (let i = 0, il = this.length; i < il; i++) { + array.push(this[i].join(',')); + } + return array.join(' '); + } + transform(m) { + return this.clone().transformO(m); + } + + // transform points with matrix (similar to Point.transform) + transformO(m) { + if (!Matrix.isMatrixLike(m)) { + m = new Matrix(m); + } + for (let i = this.length; i--;) { + // Perform the matrix multiplication + const [x, y] = this[i]; + this[i][0] = m.a * x + m.c * y + m.e; + this[i][1] = m.b * x + m.d * y + m.f; + } + return this; + } + } + + const MorphArray = PointArray; + + // Move by left top corner over x-axis + function x$2(x) { + return x == null ? this.bbox().x : this.move(x, this.bbox().y); + } + + // Move by left top corner over y-axis + function y$2(y) { + return y == null ? this.bbox().y : this.move(this.bbox().x, y); + } + + // Set width of element + function width$1(width) { + const b = this.bbox(); + return width == null ? b.width : this.size(width, b.height); + } + + // Set height of element + function height$1(height) { + const b = this.bbox(); + return height == null ? b.height : this.size(b.width, height); + } + + var pointed = { + __proto__: null, + MorphArray: MorphArray, + height: height$1, + width: width$1, + x: x$2, + y: y$2 + }; + + class Line extends Shape { + // Initialize node + constructor(node, attrs = node) { + super(nodeOrNew('line', node), attrs); + } + + // Get array + array() { + return new PointArray([[this.attr('x1'), this.attr('y1')], [this.attr('x2'), this.attr('y2')]]); + } + + // Move by left top corner + move(x, y) { + return this.attr(this.array().move(x, y).toLine()); + } + + // Overwrite native plot() method + plot(x1, y1, x2, y2) { + if (x1 == null) { + return this.array(); + } else if (typeof y1 !== 'undefined') { + x1 = { + x1, + y1, + x2, + y2 + }; + } else { + x1 = new PointArray(x1).toLine(); + } + return this.attr(x1); + } + + // Set element size to given width and height + size(width, height) { + const p = proportionalSize(this, width, height); + return this.attr(this.array().size(p.width, p.height).toLine()); + } + } + extend(Line, pointed); + registerMethods({ + Container: { + // Create a line element + line: wrapWithAttrCheck(function (...args) { + // make sure plot is called as a setter + // x1 is not necessarily a number, it can also be an array, a string and a PointArray + return Line.prototype.plot.apply(this.put(new Line()), args[0] != null ? args : [0, 0, 0, 0]); + }) + } + }); + register(Line, 'Line'); + + class Marker extends Container { + // Initialize node + constructor(node, attrs = node) { + super(nodeOrNew('marker', node), attrs); + } + + // Set height of element + height(height) { + return this.attr('markerHeight', height); + } + orient(orient) { + return this.attr('orient', orient); + } + + // Set marker refX and refY + ref(x, y) { + return this.attr('refX', x).attr('refY', y); + } + + // Return the fill id + toString() { + return 'url(#' + this.id() + ')'; + } + + // Update marker + update(block) { + // remove all content + this.clear(); + + // invoke passed block + if (typeof block === 'function') { + block.call(this, this); + } + return this; + } + + // Set width of element + width(width) { + return this.attr('markerWidth', width); + } + } + registerMethods({ + Container: { + marker(...args) { + // Create marker element in defs + return this.defs().marker(...args); + } + }, + Defs: { + // Create marker + marker: wrapWithAttrCheck(function (width, height, block) { + // Set default viewbox to match the width and height, set ref to cx and cy and set orient to auto + return this.put(new Marker()).size(width, height).ref(width / 2, height / 2).viewbox(0, 0, width, height).attr('orient', 'auto').update(block); + }) + }, + marker: { + // Create and attach markers + marker(marker, width, height, block) { + let attr = ['marker']; + + // Build attribute name + if (marker !== 'all') attr.push(marker); + attr = attr.join('-'); + + // Set marker attribute + marker = arguments[1] instanceof Marker ? arguments[1] : this.defs().marker(width, height, block); + return this.attr(attr, marker); + } + } + }); + register(Marker, 'Marker'); + + /*** + Base Class + ========== + The base stepper class that will be + ***/ + + function makeSetterGetter(k, f) { + return function (v) { + if (v == null) return this[k]; + this[k] = v; + if (f) f.call(this); + return this; + }; + } + const easing = { + '-': function (pos) { + return pos; + }, + '<>': function (pos) { + return -Math.cos(pos * Math.PI) / 2 + 0.5; + }, + '>': function (pos) { + return Math.sin(pos * Math.PI / 2); + }, + '<': function (pos) { + return -Math.cos(pos * Math.PI / 2) + 1; + }, + bezier: function (x1, y1, x2, y2) { + // see https://www.w3.org/TR/css-easing-1/#cubic-bezier-algo + return function (t) { + if (t < 0) { + if (x1 > 0) { + return y1 / x1 * t; + } else if (x2 > 0) { + return y2 / x2 * t; + } else { + return 0; + } + } else if (t > 1) { + if (x2 < 1) { + return (1 - y2) / (1 - x2) * t + (y2 - x2) / (1 - x2); + } else if (x1 < 1) { + return (1 - y1) / (1 - x1) * t + (y1 - x1) / (1 - x1); + } else { + return 1; + } + } else { + return 3 * t * (1 - t) ** 2 * y1 + 3 * t ** 2 * (1 - t) * y2 + t ** 3; + } + }; + }, + // see https://www.w3.org/TR/css-easing-1/#step-timing-function-algo + steps: function (steps, stepPosition = 'end') { + // deal with "jump-" prefix + stepPosition = stepPosition.split('-').reverse()[0]; + let jumps = steps; + if (stepPosition === 'none') { + --jumps; + } else if (stepPosition === 'both') { + ++jumps; + } + + // The beforeFlag is essentially useless + return (t, beforeFlag = false) => { + // Step is called currentStep in referenced url + let step = Math.floor(t * steps); + const jumping = t * step % 1 === 0; + if (stepPosition === 'start' || stepPosition === 'both') { + ++step; + } + if (beforeFlag && jumping) { + --step; + } + if (t >= 0 && step < 0) { + step = 0; + } + if (t <= 1 && step > jumps) { + step = jumps; + } + return step / jumps; + }; + } + }; + class Stepper { + done() { + return false; + } + } + + /*** + Easing Functions + ================ + ***/ + + class Ease extends Stepper { + constructor(fn = timeline.ease) { + super(); + this.ease = easing[fn] || fn; + } + step(from, to, pos) { + if (typeof from !== 'number') { + return pos < 1 ? from : to; + } + return from + (to - from) * this.ease(pos); + } + } + + /*** + Controller Types + ================ + ***/ + + class Controller extends Stepper { + constructor(fn) { + super(); + this.stepper = fn; + } + done(c) { + return c.done; + } + step(current, target, dt, c) { + return this.stepper(current, target, dt, c); + } + } + function recalculate() { + // Apply the default parameters + const duration = (this._duration || 500) / 1000; + const overshoot = this._overshoot || 0; + + // Calculate the PID natural response + const eps = 1e-10; + const pi = Math.PI; + const os = Math.log(overshoot / 100 + eps); + const zeta = -os / Math.sqrt(pi * pi + os * os); + const wn = 3.9 / (zeta * duration); + + // Calculate the Spring values + this.d = 2 * zeta * wn; + this.k = wn * wn; + } + class Spring extends Controller { + constructor(duration = 500, overshoot = 0) { + super(); + this.duration(duration).overshoot(overshoot); + } + step(current, target, dt, c) { + if (typeof current === 'string') return current; + c.done = dt === Infinity; + if (dt === Infinity) return target; + if (dt === 0) return current; + if (dt > 100) dt = 16; + dt /= 1000; + + // Get the previous velocity + const velocity = c.velocity || 0; + + // Apply the control to get the new position and store it + const acceleration = -this.d * velocity - this.k * (current - target); + const newPosition = current + velocity * dt + acceleration * dt * dt / 2; + + // Store the velocity + c.velocity = velocity + acceleration * dt; + + // Figure out if we have converged, and if so, pass the value + c.done = Math.abs(target - newPosition) + Math.abs(velocity) < 0.002; + return c.done ? target : newPosition; + } + } + extend(Spring, { + duration: makeSetterGetter('_duration', recalculate), + overshoot: makeSetterGetter('_overshoot', recalculate) + }); + class PID extends Controller { + constructor(p = 0.1, i = 0.01, d = 0, windup = 1000) { + super(); + this.p(p).i(i).d(d).windup(windup); + } + step(current, target, dt, c) { + if (typeof current === 'string') return current; + c.done = dt === Infinity; + if (dt === Infinity) return target; + if (dt === 0) return current; + const p = target - current; + let i = (c.integral || 0) + p * dt; + const d = (p - (c.error || 0)) / dt; + const windup = this._windup; + + // antiwindup + if (windup !== false) { + i = Math.max(-windup, Math.min(i, windup)); + } + c.error = p; + c.integral = i; + c.done = Math.abs(p) < 0.001; + return c.done ? target : current + (this.P * p + this.I * i + this.D * d); + } + } + extend(PID, { + windup: makeSetterGetter('_windup'), + p: makeSetterGetter('P'), + i: makeSetterGetter('I'), + d: makeSetterGetter('D') + }); + + const segmentParameters = { + M: 2, + L: 2, + H: 1, + V: 1, + C: 6, + S: 4, + Q: 4, + T: 2, + A: 7, + Z: 0 + }; + const pathHandlers = { + M: function (c, p, p0) { + p.x = p0.x = c[0]; + p.y = p0.y = c[1]; + return ['M', p.x, p.y]; + }, + L: function (c, p) { + p.x = c[0]; + p.y = c[1]; + return ['L', c[0], c[1]]; + }, + H: function (c, p) { + p.x = c[0]; + return ['H', c[0]]; + }, + V: function (c, p) { + p.y = c[0]; + return ['V', c[0]]; + }, + C: function (c, p) { + p.x = c[4]; + p.y = c[5]; + return ['C', c[0], c[1], c[2], c[3], c[4], c[5]]; + }, + S: function (c, p) { + p.x = c[2]; + p.y = c[3]; + return ['S', c[0], c[1], c[2], c[3]]; + }, + Q: function (c, p) { + p.x = c[2]; + p.y = c[3]; + return ['Q', c[0], c[1], c[2], c[3]]; + }, + T: function (c, p) { + p.x = c[0]; + p.y = c[1]; + return ['T', c[0], c[1]]; + }, + Z: function (c, p, p0) { + p.x = p0.x; + p.y = p0.y; + return ['Z']; + }, + A: function (c, p) { + p.x = c[5]; + p.y = c[6]; + return ['A', c[0], c[1], c[2], c[3], c[4], c[5], c[6]]; + } + }; + const mlhvqtcsaz = 'mlhvqtcsaz'.split(''); + for (let i = 0, il = mlhvqtcsaz.length; i < il; ++i) { + pathHandlers[mlhvqtcsaz[i]] = function (i) { + return function (c, p, p0) { + if (i === 'H') c[0] = c[0] + p.x;else if (i === 'V') c[0] = c[0] + p.y;else if (i === 'A') { + c[5] = c[5] + p.x; + c[6] = c[6] + p.y; + } else { + for (let j = 0, jl = c.length; j < jl; ++j) { + c[j] = c[j] + (j % 2 ? p.y : p.x); + } + } + return pathHandlers[i](c, p, p0); + }; + }(mlhvqtcsaz[i].toUpperCase()); + } + function makeAbsolut(parser) { + const command = parser.segment[0]; + return pathHandlers[command](parser.segment.slice(1), parser.p, parser.p0); + } + function segmentComplete(parser) { + return parser.segment.length && parser.segment.length - 1 === segmentParameters[parser.segment[0].toUpperCase()]; + } + function startNewSegment(parser, token) { + parser.inNumber && finalizeNumber(parser, false); + const pathLetter = isPathLetter.test(token); + if (pathLetter) { + parser.segment = [token]; + } else { + const lastCommand = parser.lastCommand; + const small = lastCommand.toLowerCase(); + const isSmall = lastCommand === small; + parser.segment = [small === 'm' ? isSmall ? 'l' : 'L' : lastCommand]; + } + parser.inSegment = true; + parser.lastCommand = parser.segment[0]; + return pathLetter; + } + function finalizeNumber(parser, inNumber) { + if (!parser.inNumber) throw new Error('Parser Error'); + parser.number && parser.segment.push(parseFloat(parser.number)); + parser.inNumber = inNumber; + parser.number = ''; + parser.pointSeen = false; + parser.hasExponent = false; + if (segmentComplete(parser)) { + finalizeSegment(parser); + } + } + function finalizeSegment(parser) { + parser.inSegment = false; + if (parser.absolute) { + parser.segment = makeAbsolut(parser); + } + parser.segments.push(parser.segment); + } + function isArcFlag(parser) { + if (!parser.segment.length) return false; + const isArc = parser.segment[0].toUpperCase() === 'A'; + const length = parser.segment.length; + return isArc && (length === 4 || length === 5); + } + function isExponential(parser) { + return parser.lastToken.toUpperCase() === 'E'; + } + const pathDelimiters = new Set([' ', ',', '\t', '\n', '\r', '\f']); + function pathParser(d, toAbsolute = true) { + let index = 0; + let token = ''; + const parser = { + segment: [], + inNumber: false, + number: '', + lastToken: '', + inSegment: false, + segments: [], + pointSeen: false, + hasExponent: false, + absolute: toAbsolute, + p0: new Point(), + p: new Point() + }; + while (parser.lastToken = token, token = d.charAt(index++)) { + if (!parser.inSegment) { + if (startNewSegment(parser, token)) { + continue; + } + } + if (token === '.') { + if (parser.pointSeen || parser.hasExponent) { + finalizeNumber(parser, false); + --index; + continue; + } + parser.inNumber = true; + parser.pointSeen = true; + parser.number += token; + continue; + } + if (!isNaN(parseInt(token))) { + if (parser.number === '0' || isArcFlag(parser)) { + parser.inNumber = true; + parser.number = token; + finalizeNumber(parser, true); + continue; + } + parser.inNumber = true; + parser.number += token; + continue; + } + if (pathDelimiters.has(token)) { + if (parser.inNumber) { + finalizeNumber(parser, false); + } + continue; + } + if (token === '-' || token === '+') { + if (parser.inNumber && !isExponential(parser)) { + finalizeNumber(parser, false); + --index; + continue; + } + parser.number += token; + parser.inNumber = true; + continue; + } + if (token.toUpperCase() === 'E') { + parser.number += token; + parser.hasExponent = true; + continue; + } + if (isPathLetter.test(token)) { + if (parser.inNumber) { + finalizeNumber(parser, false); + } else if (!segmentComplete(parser)) { + throw new Error('parser Error'); + } else { + finalizeSegment(parser); + } + --index; + } + } + if (parser.inNumber) { + finalizeNumber(parser, false); + } + if (parser.inSegment && segmentComplete(parser)) { + finalizeSegment(parser); + } + return parser.segments; + } + + function arrayToString(a) { + let s = ''; + for (let i = 0, il = a.length; i < il; i++) { + s += a[i][0]; + if (a[i][1] != null) { + s += a[i][1]; + if (a[i][2] != null) { + s += ' '; + s += a[i][2]; + if (a[i][3] != null) { + s += ' '; + s += a[i][3]; + s += ' '; + s += a[i][4]; + if (a[i][5] != null) { + s += ' '; + s += a[i][5]; + s += ' '; + s += a[i][6]; + if (a[i][7] != null) { + s += ' '; + s += a[i][7]; + } + } + } + } + } + } + return s + ' '; + } + class PathArray extends SVGArray { + // Get bounding box of path + bbox() { + parser().path.setAttribute('d', this.toString()); + return new Box(parser.nodes.path.getBBox()); + } + + // Move path string + move(x, y) { + // get bounding box of current situation + const box = this.bbox(); + + // get relative offset + x -= box.x; + y -= box.y; + if (!isNaN(x) && !isNaN(y)) { + // move every point + for (let l, i = this.length - 1; i >= 0; i--) { + l = this[i][0]; + if (l === 'M' || l === 'L' || l === 'T') { + this[i][1] += x; + this[i][2] += y; + } else if (l === 'H') { + this[i][1] += x; + } else if (l === 'V') { + this[i][1] += y; + } else if (l === 'C' || l === 'S' || l === 'Q') { + this[i][1] += x; + this[i][2] += y; + this[i][3] += x; + this[i][4] += y; + if (l === 'C') { + this[i][5] += x; + this[i][6] += y; + } + } else if (l === 'A') { + this[i][6] += x; + this[i][7] += y; + } + } + } + return this; + } + + // Absolutize and parse path to array + parse(d = 'M0 0') { + if (Array.isArray(d)) { + d = Array.prototype.concat.apply([], d).toString(); + } + return pathParser(d); + } + + // Resize path string + size(width, height) { + // get bounding box of current situation + const box = this.bbox(); + let i, l; + + // If the box width or height is 0 then we ignore + // transformations on the respective axis + box.width = box.width === 0 ? 1 : box.width; + box.height = box.height === 0 ? 1 : box.height; + + // recalculate position of all points according to new size + for (i = this.length - 1; i >= 0; i--) { + l = this[i][0]; + if (l === 'M' || l === 'L' || l === 'T') { + this[i][1] = (this[i][1] - box.x) * width / box.width + box.x; + this[i][2] = (this[i][2] - box.y) * height / box.height + box.y; + } else if (l === 'H') { + this[i][1] = (this[i][1] - box.x) * width / box.width + box.x; + } else if (l === 'V') { + this[i][1] = (this[i][1] - box.y) * height / box.height + box.y; + } else if (l === 'C' || l === 'S' || l === 'Q') { + this[i][1] = (this[i][1] - box.x) * width / box.width + box.x; + this[i][2] = (this[i][2] - box.y) * height / box.height + box.y; + this[i][3] = (this[i][3] - box.x) * width / box.width + box.x; + this[i][4] = (this[i][4] - box.y) * height / box.height + box.y; + if (l === 'C') { + this[i][5] = (this[i][5] - box.x) * width / box.width + box.x; + this[i][6] = (this[i][6] - box.y) * height / box.height + box.y; + } + } else if (l === 'A') { + // resize radii + this[i][1] = this[i][1] * width / box.width; + this[i][2] = this[i][2] * height / box.height; + + // move position values + this[i][6] = (this[i][6] - box.x) * width / box.width + box.x; + this[i][7] = (this[i][7] - box.y) * height / box.height + box.y; + } + } + return this; + } + + // Convert array to string + toString() { + return arrayToString(this); + } + } + + const getClassForType = value => { + const type = typeof value; + if (type === 'number') { + return SVGNumber; + } else if (type === 'string') { + if (Color.isColor(value)) { + return Color; + } else if (delimiter.test(value)) { + return isPathLetter.test(value) ? PathArray : SVGArray; + } else if (numberAndUnit.test(value)) { + return SVGNumber; + } else { + return NonMorphable; + } + } else if (morphableTypes.indexOf(value.constructor) > -1) { + return value.constructor; + } else if (Array.isArray(value)) { + return SVGArray; + } else if (type === 'object') { + return ObjectBag; + } else { + return NonMorphable; + } + }; + class Morphable { + constructor(stepper) { + this._stepper = stepper || new Ease('-'); + this._from = null; + this._to = null; + this._type = null; + this._context = null; + this._morphObj = null; + } + at(pos) { + return this._morphObj.morph(this._from, this._to, pos, this._stepper, this._context); + } + done() { + const complete = this._context.map(this._stepper.done).reduce(function (last, curr) { + return last && curr; + }, true); + return complete; + } + from(val) { + if (val == null) { + return this._from; + } + this._from = this._set(val); + return this; + } + stepper(stepper) { + if (stepper == null) return this._stepper; + this._stepper = stepper; + return this; + } + to(val) { + if (val == null) { + return this._to; + } + this._to = this._set(val); + return this; + } + type(type) { + // getter + if (type == null) { + return this._type; + } + + // setter + this._type = type; + return this; + } + _set(value) { + if (!this._type) { + this.type(getClassForType(value)); + } + let result = new this._type(value); + if (this._type === Color) { + result = this._to ? result[this._to[4]]() : this._from ? result[this._from[4]]() : result; + } + if (this._type === ObjectBag) { + result = this._to ? result.align(this._to) : this._from ? result.align(this._from) : result; + } + result = result.toConsumable(); + this._morphObj = this._morphObj || new this._type(); + this._context = this._context || Array.apply(null, Array(result.length)).map(Object).map(function (o) { + o.done = true; + return o; + }); + return result; + } + } + class NonMorphable { + constructor(...args) { + this.init(...args); + } + init(val) { + val = Array.isArray(val) ? val[0] : val; + this.value = val; + return this; + } + toArray() { + return [this.value]; + } + valueOf() { + return this.value; + } + } + class TransformBag { + constructor(...args) { + this.init(...args); + } + init(obj) { + if (Array.isArray(obj)) { + obj = { + scaleX: obj[0], + scaleY: obj[1], + shear: obj[2], + rotate: obj[3], + translateX: obj[4], + translateY: obj[5], + originX: obj[6], + originY: obj[7] + }; + } + Object.assign(this, TransformBag.defaults, obj); + return this; + } + toArray() { + const v = this; + return [v.scaleX, v.scaleY, v.shear, v.rotate, v.translateX, v.translateY, v.originX, v.originY]; + } + } + TransformBag.defaults = { + scaleX: 1, + scaleY: 1, + shear: 0, + rotate: 0, + translateX: 0, + translateY: 0, + originX: 0, + originY: 0 + }; + const sortByKey = (a, b) => { + return a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0; + }; + class ObjectBag { + constructor(...args) { + this.init(...args); + } + align(other) { + const values = this.values; + for (let i = 0, il = values.length; i < il; ++i) { + // If the type is the same we only need to check if the color is in the correct format + if (values[i + 1] === other[i + 1]) { + if (values[i + 1] === Color && other[i + 7] !== values[i + 7]) { + const space = other[i + 7]; + const color = new Color(this.values.splice(i + 3, 5))[space]().toArray(); + this.values.splice(i + 3, 0, ...color); + } + i += values[i + 2] + 2; + continue; + } + if (!other[i + 1]) { + return this; + } + + // The types differ, so we overwrite the new type with the old one + // And initialize it with the types default (e.g. black for color or 0 for number) + const defaultObject = new other[i + 1]().toArray(); + + // Than we fix the values array + const toDelete = values[i + 2] + 3; + values.splice(i, toDelete, other[i], other[i + 1], other[i + 2], ...defaultObject); + i += values[i + 2] + 2; + } + return this; + } + init(objOrArr) { + this.values = []; + if (Array.isArray(objOrArr)) { + this.values = objOrArr.slice(); + return; + } + objOrArr = objOrArr || {}; + const entries = []; + for (const i in objOrArr) { + const Type = getClassForType(objOrArr[i]); + const val = new Type(objOrArr[i]).toArray(); + entries.push([i, Type, val.length, ...val]); + } + entries.sort(sortByKey); + this.values = entries.reduce((last, curr) => last.concat(curr), []); + return this; + } + toArray() { + return this.values; + } + valueOf() { + const obj = {}; + const arr = this.values; + + // for (var i = 0, len = arr.length; i < len; i += 2) { + while (arr.length) { + const key = arr.shift(); + const Type = arr.shift(); + const num = arr.shift(); + const values = arr.splice(0, num); + obj[key] = new Type(values); // .valueOf() + } + return obj; + } + } + const morphableTypes = [NonMorphable, TransformBag, ObjectBag]; + function registerMorphableType(type = []) { + morphableTypes.push(...[].concat(type)); + } + function makeMorphable() { + extend(morphableTypes, { + to(val) { + return new Morphable().type(this.constructor).from(this.toArray()) // this.valueOf()) + .to(val); + }, + fromArray(arr) { + this.init(arr); + return this; + }, + toConsumable() { + return this.toArray(); + }, + morph(from, to, pos, stepper, context) { + const mapper = function (i, index) { + return stepper.step(i, to[index], pos, context[index], context); + }; + return this.fromArray(from.map(mapper)); + } + }); + } + + class Path extends Shape { + // Initialize node + constructor(node, attrs = node) { + super(nodeOrNew('path', node), attrs); + } + + // Get array + array() { + return this._array || (this._array = new PathArray(this.attr('d'))); + } + + // Clear array cache + clear() { + delete this._array; + return this; + } + + // Set height of element + height(height) { + return height == null ? this.bbox().height : this.size(this.bbox().width, height); + } + + // Move by left top corner + move(x, y) { + return this.attr('d', this.array().move(x, y)); + } + + // Plot new path + plot(d) { + return d == null ? this.array() : this.clear().attr('d', typeof d === 'string' ? d : this._array = new PathArray(d)); + } + + // Set element size to given width and height + size(width, height) { + const p = proportionalSize(this, width, height); + return this.attr('d', this.array().size(p.width, p.height)); + } + + // Set width of element + width(width) { + return width == null ? this.bbox().width : this.size(width, this.bbox().height); + } + + // Move by left top corner over x-axis + x(x) { + return x == null ? this.bbox().x : this.move(x, this.bbox().y); + } + + // Move by left top corner over y-axis + y(y) { + return y == null ? this.bbox().y : this.move(this.bbox().x, y); + } + } + + // Define morphable array + Path.prototype.MorphArray = PathArray; + + // Add parent method + registerMethods({ + Container: { + // Create a wrapped path element + path: wrapWithAttrCheck(function (d) { + // make sure plot is called as a setter + return this.put(new Path()).plot(d || new PathArray()); + }) + } + }); + register(Path, 'Path'); + + // Get array + function array() { + return this._array || (this._array = new PointArray(this.attr('points'))); + } + + // Clear array cache + function clear() { + delete this._array; + return this; + } + + // Move by left top corner + function move$2(x, y) { + return this.attr('points', this.array().move(x, y)); + } + + // Plot new path + function plot(p) { + return p == null ? this.array() : this.clear().attr('points', typeof p === 'string' ? p : this._array = new PointArray(p)); + } + + // Set element size to given width and height + function size$1(width, height) { + const p = proportionalSize(this, width, height); + return this.attr('points', this.array().size(p.width, p.height)); + } + + var poly = { + __proto__: null, + array: array, + clear: clear, + move: move$2, + plot: plot, + size: size$1 + }; + + class Polygon extends Shape { + // Initialize node + constructor(node, attrs = node) { + super(nodeOrNew('polygon', node), attrs); + } + } + registerMethods({ + Container: { + // Create a wrapped polygon element + polygon: wrapWithAttrCheck(function (p) { + // make sure plot is called as a setter + return this.put(new Polygon()).plot(p || new PointArray()); + }) + } + }); + extend(Polygon, pointed); + extend(Polygon, poly); + register(Polygon, 'Polygon'); + + class Polyline extends Shape { + // Initialize node + constructor(node, attrs = node) { + super(nodeOrNew('polyline', node), attrs); + } + } + registerMethods({ + Container: { + // Create a wrapped polygon element + polyline: wrapWithAttrCheck(function (p) { + // make sure plot is called as a setter + return this.put(new Polyline()).plot(p || new PointArray()); + }) + } + }); + extend(Polyline, pointed); + extend(Polyline, poly); + register(Polyline, 'Polyline'); + + class Rect extends Shape { + // Initialize node + constructor(node, attrs = node) { + super(nodeOrNew('rect', node), attrs); + } + } + extend(Rect, { + rx, + ry + }); + registerMethods({ + Container: { + // Create a rect element + rect: wrapWithAttrCheck(function (width, height) { + return this.put(new Rect()).size(width, height); + }) + } + }); + register(Rect, 'Rect'); + + class Queue { + constructor() { + this._first = null; + this._last = null; + } + + // Shows us the first item in the list + first() { + return this._first && this._first.value; + } + + // Shows us the last item in the list + last() { + return this._last && this._last.value; + } + push(value) { + // An item stores an id and the provided value + const item = typeof value.next !== 'undefined' ? value : { + value: value, + next: null, + prev: null + }; + + // Deal with the queue being empty or populated + if (this._last) { + item.prev = this._last; + this._last.next = item; + this._last = item; + } else { + this._last = item; + this._first = item; + } + + // Return the current item + return item; + } + + // Removes the item that was returned from the push + remove(item) { + // Relink the previous item + if (item.prev) item.prev.next = item.next; + if (item.next) item.next.prev = item.prev; + if (item === this._last) this._last = item.prev; + if (item === this._first) this._first = item.next; + + // Invalidate item + item.prev = null; + item.next = null; + } + shift() { + // Check if we have a value + const remove = this._first; + if (!remove) return null; + + // If we do, remove it and relink things + this._first = remove.next; + if (this._first) this._first.prev = null; + this._last = this._first ? this._last : null; + return remove.value; + } + } + + const Animator = { + nextDraw: null, + frames: new Queue(), + timeouts: new Queue(), + immediates: new Queue(), + timer: () => globals.window.performance || globals.window.Date, + transforms: [], + frame(fn) { + // Store the node + const node = Animator.frames.push({ + run: fn + }); + + // Request an animation frame if we don't have one + if (Animator.nextDraw === null) { + Animator.nextDraw = globals.window.requestAnimationFrame(Animator._draw); + } + + // Return the node so we can remove it easily + return node; + }, + timeout(fn, delay) { + delay = delay || 0; + + // Work out when the event should fire + const time = Animator.timer().now() + delay; + + // Add the timeout to the end of the queue + const node = Animator.timeouts.push({ + run: fn, + time: time + }); + + // Request another animation frame if we need one + if (Animator.nextDraw === null) { + Animator.nextDraw = globals.window.requestAnimationFrame(Animator._draw); + } + return node; + }, + immediate(fn) { + // Add the immediate fn to the end of the queue + const node = Animator.immediates.push(fn); + // Request another animation frame if we need one + if (Animator.nextDraw === null) { + Animator.nextDraw = globals.window.requestAnimationFrame(Animator._draw); + } + return node; + }, + cancelFrame(node) { + node != null && Animator.frames.remove(node); + }, + clearTimeout(node) { + node != null && Animator.timeouts.remove(node); + }, + cancelImmediate(node) { + node != null && Animator.immediates.remove(node); + }, + _draw(now) { + // Run all the timeouts we can run, if they are not ready yet, add them + // to the end of the queue immediately! (bad timeouts!!! [sarcasm]) + let nextTimeout = null; + const lastTimeout = Animator.timeouts.last(); + while (nextTimeout = Animator.timeouts.shift()) { + // Run the timeout if its time, or push it to the end + if (now >= nextTimeout.time) { + nextTimeout.run(); + } else { + Animator.timeouts.push(nextTimeout); + } + + // If we hit the last item, we should stop shifting out more items + if (nextTimeout === lastTimeout) break; + } + + // Run all of the animation frames + let nextFrame = null; + const lastFrame = Animator.frames.last(); + while (nextFrame !== lastFrame && (nextFrame = Animator.frames.shift())) { + nextFrame.run(now); + } + let nextImmediate = null; + while (nextImmediate = Animator.immediates.shift()) { + nextImmediate(); + } + + // If we have remaining timeouts or frames, draw until we don't anymore + Animator.nextDraw = Animator.timeouts.first() || Animator.frames.first() ? globals.window.requestAnimationFrame(Animator._draw) : null; + } + }; + + const makeSchedule = function (runnerInfo) { + const start = runnerInfo.start; + const duration = runnerInfo.runner.duration(); + const end = start + duration; + return { + start: start, + duration: duration, + end: end, + runner: runnerInfo.runner + }; + }; + const defaultSource = function () { + const w = globals.window; + return (w.performance || w.Date).now(); + }; + class Timeline extends EventTarget { + // Construct a new timeline on the given element + constructor(timeSource = defaultSource) { + super(); + this._timeSource = timeSource; + + // terminate resets all variables to their initial state + this.terminate(); + } + active() { + return !!this._nextFrame; + } + finish() { + // Go to end and pause + this.time(this.getEndTimeOfTimeline() + 1); + return this.pause(); + } + + // Calculates the end of the timeline + getEndTime() { + const lastRunnerInfo = this.getLastRunnerInfo(); + const lastDuration = lastRunnerInfo ? lastRunnerInfo.runner.duration() : 0; + const lastStartTime = lastRunnerInfo ? lastRunnerInfo.start : this._time; + return lastStartTime + lastDuration; + } + getEndTimeOfTimeline() { + const endTimes = this._runners.map(i => i.start + i.runner.duration()); + return Math.max(0, ...endTimes); + } + getLastRunnerInfo() { + return this.getRunnerInfoById(this._lastRunnerId); + } + getRunnerInfoById(id) { + return this._runners[this._runnerIds.indexOf(id)] || null; + } + pause() { + this._paused = true; + return this._continue(); + } + persist(dtOrForever) { + if (dtOrForever == null) return this._persist; + this._persist = dtOrForever; + return this; + } + play() { + // Now make sure we are not paused and continue the animation + this._paused = false; + return this.updateTime()._continue(); + } + reverse(yes) { + const currentSpeed = this.speed(); + if (yes == null) return this.speed(-currentSpeed); + const positive = Math.abs(currentSpeed); + return this.speed(yes ? -positive : positive); + } + + // schedules a runner on the timeline + schedule(runner, delay, when) { + if (runner == null) { + return this._runners.map(makeSchedule); + } + + // The start time for the next animation can either be given explicitly, + // derived from the current timeline time or it can be relative to the + // last start time to chain animations directly + + let absoluteStartTime = 0; + const endTime = this.getEndTime(); + delay = delay || 0; + + // Work out when to start the animation + if (when == null || when === 'last' || when === 'after') { + // Take the last time and increment + absoluteStartTime = endTime; + } else if (when === 'absolute' || when === 'start') { + absoluteStartTime = delay; + delay = 0; + } else if (when === 'now') { + absoluteStartTime = this._time; + } else if (when === 'relative') { + const runnerInfo = this.getRunnerInfoById(runner.id); + if (runnerInfo) { + absoluteStartTime = runnerInfo.start + delay; + delay = 0; + } + } else if (when === 'with-last') { + const lastRunnerInfo = this.getLastRunnerInfo(); + const lastStartTime = lastRunnerInfo ? lastRunnerInfo.start : this._time; + absoluteStartTime = lastStartTime; + } else { + throw new Error('Invalid value for the "when" parameter'); + } + + // Manage runner + runner.unschedule(); + runner.timeline(this); + const persist = runner.persist(); + const runnerInfo = { + persist: persist === null ? this._persist : persist, + start: absoluteStartTime + delay, + runner + }; + this._lastRunnerId = runner.id; + this._runners.push(runnerInfo); + this._runners.sort((a, b) => a.start - b.start); + this._runnerIds = this._runners.map(info => info.runner.id); + this.updateTime()._continue(); + return this; + } + seek(dt) { + return this.time(this._time + dt); + } + source(fn) { + if (fn == null) return this._timeSource; + this._timeSource = fn; + return this; + } + speed(speed) { + if (speed == null) return this._speed; + this._speed = speed; + return this; + } + stop() { + // Go to start and pause + this.time(0); + return this.pause(); + } + time(time) { + if (time == null) return this._time; + this._time = time; + return this._continue(true); + } + + // Remove the runner from this timeline + unschedule(runner) { + const index = this._runnerIds.indexOf(runner.id); + if (index < 0) return this; + this._runners.splice(index, 1); + this._runnerIds.splice(index, 1); + runner.timeline(null); + return this; + } + + // Makes sure, that after pausing the time doesn't jump + updateTime() { + if (!this.active()) { + this._lastSourceTime = this._timeSource(); + } + return this; + } + + // Checks if we are running and continues the animation + _continue(immediateStep = false) { + Animator.cancelFrame(this._nextFrame); + this._nextFrame = null; + if (immediateStep) return this._stepImmediate(); + if (this._paused) return this; + this._nextFrame = Animator.frame(this._step); + return this; + } + _stepFn(immediateStep = false) { + // Get the time delta from the last time and update the time + const time = this._timeSource(); + let dtSource = time - this._lastSourceTime; + if (immediateStep) dtSource = 0; + const dtTime = this._speed * dtSource + (this._time - this._lastStepTime); + this._lastSourceTime = time; + + // Only update the time if we use the timeSource. + // Otherwise use the current time + if (!immediateStep) { + // Update the time + this._time += dtTime; + this._time = this._time < 0 ? 0 : this._time; + } + this._lastStepTime = this._time; + this.fire('time', this._time); + + // This is for the case that the timeline was seeked so that the time + // is now before the startTime of the runner. That is why we need to set + // the runner to position 0 + + // FIXME: + // However, resetting in insertion order leads to bugs. Considering the case, + // where 2 runners change the same attribute but in different times, + // resetting both of them will lead to the case where the later defined + // runner always wins the reset even if the other runner started earlier + // and therefore should win the attribute battle + // this can be solved by resetting them backwards + for (let k = this._runners.length; k--;) { + // Get and run the current runner and ignore it if its inactive + const runnerInfo = this._runners[k]; + const runner = runnerInfo.runner; + + // Make sure that we give the actual difference + // between runner start time and now + const dtToStart = this._time - runnerInfo.start; + + // Dont run runner if not started yet + // and try to reset it + if (dtToStart <= 0) { + runner.reset(); + } + } + + // Run all of the runners directly + let runnersLeft = false; + for (let i = 0, len = this._runners.length; i < len; i++) { + // Get and run the current runner and ignore it if its inactive + const runnerInfo = this._runners[i]; + const runner = runnerInfo.runner; + let dt = dtTime; + + // Make sure that we give the actual difference + // between runner start time and now + const dtToStart = this._time - runnerInfo.start; + + // Dont run runner if not started yet + if (dtToStart <= 0) { + runnersLeft = true; + continue; + } else if (dtToStart < dt) { + // Adjust dt to make sure that animation is on point + dt = dtToStart; + } + if (!runner.active()) continue; + + // If this runner is still going, signal that we need another animation + // frame, otherwise, remove the completed runner + const finished = runner.step(dt).done; + if (!finished) { + runnersLeft = true; + // continue + } else if (runnerInfo.persist !== true) { + // runner is finished. And runner might get removed + const endTime = runner.duration() - runner.time() + this._time; + if (endTime + runnerInfo.persist < this._time) { + // Delete runner and correct index + runner.unschedule(); + --i; + --len; + } + } + } + + // Basically: we continue when there are runners right from us in time + // when -->, and when runners are left from us when <-- + if (runnersLeft && !(this._speed < 0 && this._time === 0) || this._runnerIds.length && this._speed < 0 && this._time > 0) { + this._continue(); + } else { + this.pause(); + this.fire('finished'); + } + return this; + } + terminate() { + // cleanup memory + + // Store the timing variables + this._startTime = 0; + this._speed = 1.0; + + // Determines how long a runner is hold in memory. Can be a dt or true/false + this._persist = 0; + + // Keep track of the running animations and their starting parameters + this._nextFrame = null; + this._paused = true; + this._runners = []; + this._runnerIds = []; + this._lastRunnerId = -1; + this._time = 0; + this._lastSourceTime = 0; + this._lastStepTime = 0; + + // Make sure that step is always called in class context + this._step = this._stepFn.bind(this, false); + this._stepImmediate = this._stepFn.bind(this, true); + } + } + registerMethods({ + Element: { + timeline: function (timeline) { + if (timeline == null) { + this._timeline = this._timeline || new Timeline(); + return this._timeline; + } else { + this._timeline = timeline; + return this; + } + } + } + }); + + class Runner extends EventTarget { + constructor(options) { + super(); + + // Store a unique id on the runner, so that we can identify it later + this.id = Runner.id++; + + // Ensure a default value + options = options == null ? timeline.duration : options; + + // Ensure that we get a controller + options = typeof options === 'function' ? new Controller(options) : options; + + // Declare all of the variables + this._element = null; + this._timeline = null; + this.done = false; + this._queue = []; + + // Work out the stepper and the duration + this._duration = typeof options === 'number' && options; + this._isDeclarative = options instanceof Controller; + this._stepper = this._isDeclarative ? options : new Ease(); + + // We copy the current values from the timeline because they can change + this._history = {}; + + // Store the state of the runner + this.enabled = true; + this._time = 0; + this._lastTime = 0; + + // At creation, the runner is in reset state + this._reseted = true; + + // Save transforms applied to this runner + this.transforms = new Matrix(); + this.transformId = 1; + + // Looping variables + this._haveReversed = false; + this._reverse = false; + this._loopsDone = 0; + this._swing = false; + this._wait = 0; + this._times = 1; + this._frameId = null; + + // Stores how long a runner is stored after being done + this._persist = this._isDeclarative ? true : null; + } + static sanitise(duration, delay, when) { + // Initialise the default parameters + let times = 1; + let swing = false; + let wait = 0; + duration = duration ?? timeline.duration; + delay = delay ?? timeline.delay; + when = when || 'last'; + + // If we have an object, unpack the values + if (typeof duration === 'object' && !(duration instanceof Stepper)) { + delay = duration.delay ?? delay; + when = duration.when ?? when; + swing = duration.swing || swing; + times = duration.times ?? times; + wait = duration.wait ?? wait; + duration = duration.duration ?? timeline.duration; + } + return { + duration: duration, + delay: delay, + swing: swing, + times: times, + wait: wait, + when: when + }; + } + active(enabled) { + if (enabled == null) return this.enabled; + this.enabled = enabled; + return this; + } + + /* + Private Methods + =============== + Methods that shouldn't be used externally + */ + addTransform(transform) { + this.transforms.lmultiplyO(transform); + return this; + } + after(fn) { + return this.on('finished', fn); + } + animate(duration, delay, when) { + const o = Runner.sanitise(duration, delay, when); + const runner = new Runner(o.duration); + if (this._timeline) runner.timeline(this._timeline); + if (this._element) runner.element(this._element); + return runner.loop(o).schedule(o.delay, o.when); + } + clearTransform() { + this.transforms = new Matrix(); + return this; + } + + // TODO: Keep track of all transformations so that deletion is faster + clearTransformsFromQueue() { + if (!this.done || !this._timeline || !this._timeline._runnerIds.includes(this.id)) { + this._queue = this._queue.filter(item => { + return !item.isTransform; + }); + } + } + delay(delay) { + return this.animate(0, delay); + } + duration() { + return this._times * (this._wait + this._duration) - this._wait; + } + during(fn) { + return this.queue(null, fn); + } + ease(fn) { + this._stepper = new Ease(fn); + return this; + } + /* + Runner Definitions + ================== + These methods help us define the runtime behaviour of the Runner or they + help us make new runners from the current runner + */ + + element(element) { + if (element == null) return this._element; + this._element = element; + element._prepareRunner(); + return this; + } + finish() { + return this.step(Infinity); + } + loop(times, swing, wait) { + // Deal with the user passing in an object + if (typeof times === 'object') { + swing = times.swing; + wait = times.wait; + times = times.times; + } + + // Sanitise the values and store them + this._times = times || Infinity; + this._swing = swing || false; + this._wait = wait || 0; + + // Allow true to be passed + if (this._times === true) { + this._times = Infinity; + } + return this; + } + loops(p) { + const loopDuration = this._duration + this._wait; + if (p == null) { + const loopsDone = Math.floor(this._time / loopDuration); + const relativeTime = this._time - loopsDone * loopDuration; + const position = relativeTime / this._duration; + return Math.min(loopsDone + position, this._times); + } + const whole = Math.floor(p); + const partial = p % 1; + const time = loopDuration * whole + this._duration * partial; + return this.time(time); + } + persist(dtOrForever) { + if (dtOrForever == null) return this._persist; + this._persist = dtOrForever; + return this; + } + position(p) { + // Get all of the variables we need + const x = this._time; + const d = this._duration; + const w = this._wait; + const t = this._times; + const s = this._swing; + const r = this._reverse; + let position; + if (p == null) { + /* + This function converts a time to a position in the range [0, 1] + The full explanation can be found in this desmos demonstration + https://www.desmos.com/calculator/u4fbavgche + The logic is slightly simplified here because we can use booleans + */ + + // Figure out the value without thinking about the start or end time + const f = function (x) { + const swinging = s * Math.floor(x % (2 * (w + d)) / (w + d)); + const backwards = swinging && !r || !swinging && r; + const uncliped = Math.pow(-1, backwards) * (x % (w + d)) / d + backwards; + const clipped = Math.max(Math.min(uncliped, 1), 0); + return clipped; + }; + + // Figure out the value by incorporating the start time + const endTime = t * (w + d) - w; + position = x <= 0 ? Math.round(f(1e-5)) : x < endTime ? f(x) : Math.round(f(endTime - 1e-5)); + return position; + } + + // Work out the loops done and add the position to the loops done + const loopsDone = Math.floor(this.loops()); + const swingForward = s && loopsDone % 2 === 0; + const forwards = swingForward && !r || r && swingForward; + position = loopsDone + (forwards ? p : 1 - p); + return this.loops(position); + } + progress(p) { + if (p == null) { + return Math.min(1, this._time / this.duration()); + } + return this.time(p * this.duration()); + } + + /* + Basic Functionality + =================== + These methods allow us to attach basic functions to the runner directly + */ + queue(initFn, runFn, retargetFn, isTransform) { + this._queue.push({ + initialiser: initFn || noop, + runner: runFn || noop, + retarget: retargetFn, + isTransform: isTransform, + initialised: false, + finished: false + }); + const timeline = this.timeline(); + timeline && this.timeline()._continue(); + return this; + } + reset() { + if (this._reseted) return this; + this.time(0); + this._reseted = true; + return this; + } + reverse(reverse) { + this._reverse = reverse == null ? !this._reverse : reverse; + return this; + } + schedule(timeline, delay, when) { + // The user doesn't need to pass a timeline if we already have one + if (!(timeline instanceof Timeline)) { + when = delay; + delay = timeline; + timeline = this.timeline(); + } + + // If there is no timeline, yell at the user... + if (!timeline) { + throw Error('Runner cannot be scheduled without timeline'); + } + + // Schedule the runner on the timeline provided + timeline.schedule(this, delay, when); + return this; + } + step(dt) { + // If we are inactive, this stepper just gets skipped + if (!this.enabled) return this; + + // Update the time and get the new position + dt = dt == null ? 16 : dt; + this._time += dt; + const position = this.position(); + + // Figure out if we need to run the stepper in this frame + const running = this._lastPosition !== position && this._time >= 0; + this._lastPosition = position; + + // Figure out if we just started + const duration = this.duration(); + const justStarted = this._lastTime <= 0 && this._time > 0; + const justFinished = this._lastTime < duration && this._time >= duration; + this._lastTime = this._time; + if (justStarted) { + this.fire('start', this); + } + + // Work out if the runner is finished set the done flag here so animations + // know, that they are running in the last step (this is good for + // transformations which can be merged) + const declarative = this._isDeclarative; + this.done = !declarative && !justFinished && this._time >= duration; + + // Runner is running. So its not in reset state anymore + this._reseted = false; + let converged = false; + // Call initialise and the run function + if (running || declarative) { + this._initialise(running); + + // clear the transforms on this runner so they dont get added again and again + this.transforms = new Matrix(); + converged = this._run(declarative ? dt : position); + this.fire('step', this); + } + // correct the done flag here + // declarative animations itself know when they converged + this.done = this.done || converged && declarative; + if (justFinished) { + this.fire('finished', this); + } + return this; + } + + /* + Runner animation methods + ======================== + Control how the animation plays + */ + time(time) { + if (time == null) { + return this._time; + } + const dt = time - this._time; + this.step(dt); + return this; + } + timeline(timeline) { + // check explicitly for undefined so we can set the timeline to null + if (typeof timeline === 'undefined') return this._timeline; + this._timeline = timeline; + return this; + } + unschedule() { + const timeline = this.timeline(); + timeline && timeline.unschedule(this); + return this; + } + + // Run each initialise function in the runner if required + _initialise(running) { + // If we aren't running, we shouldn't initialise when not declarative + if (!running && !this._isDeclarative) return; + + // Loop through all of the initialisers + for (let i = 0, len = this._queue.length; i < len; ++i) { + // Get the current initialiser + const current = this._queue[i]; + + // Determine whether we need to initialise + const needsIt = this._isDeclarative || !current.initialised && running; + running = !current.finished; + + // Call the initialiser if we need to + if (needsIt && running) { + current.initialiser.call(this); + current.initialised = true; + } + } + } + + // Save a morpher to the morpher list so that we can retarget it later + _rememberMorpher(method, morpher) { + this._history[method] = { + morpher: morpher, + caller: this._queue[this._queue.length - 1] + }; + + // We have to resume the timeline in case a controller + // is already done without being ever run + // This can happen when e.g. this is done: + // anim = el.animate(new SVG.Spring) + // and later + // anim.move(...) + if (this._isDeclarative) { + const timeline = this.timeline(); + timeline && timeline.play(); + } + } + + // Try to set the target for a morpher if the morpher exists, otherwise + // Run each run function for the position or dt given + _run(positionOrDt) { + // Run all of the _queue directly + let allfinished = true; + for (let i = 0, len = this._queue.length; i < len; ++i) { + // Get the current function to run + const current = this._queue[i]; + + // Run the function if its not finished, we keep track of the finished + // flag for the sake of declarative _queue + const converged = current.runner.call(this, positionOrDt); + current.finished = current.finished || converged === true; + allfinished = allfinished && current.finished; + } + + // We report when all of the constructors are finished + return allfinished; + } + + // do nothing and return false + _tryRetarget(method, target, extra) { + if (this._history[method]) { + // if the last method wasn't even initialised, throw it away + if (!this._history[method].caller.initialised) { + const index = this._queue.indexOf(this._history[method].caller); + this._queue.splice(index, 1); + return false; + } + + // for the case of transformations, we use the special retarget function + // which has access to the outer scope + if (this._history[method].caller.retarget) { + this._history[method].caller.retarget.call(this, target, extra); + // for everything else a simple morpher change is sufficient + } else { + this._history[method].morpher.to(target); + } + this._history[method].caller.finished = false; + const timeline = this.timeline(); + timeline && timeline.play(); + return true; + } + return false; + } + } + Runner.id = 0; + class FakeRunner { + constructor(transforms = new Matrix(), id = -1, done = true) { + this.transforms = transforms; + this.id = id; + this.done = done; + } + clearTransformsFromQueue() {} + } + extend([Runner, FakeRunner], { + mergeWith(runner) { + return new FakeRunner(runner.transforms.lmultiply(this.transforms), runner.id); + } + }); + + // FakeRunner.emptyRunner = new FakeRunner() + + const lmultiply = (last, curr) => last.lmultiplyO(curr); + const getRunnerTransform = runner => runner.transforms; + function mergeTransforms() { + // Find the matrix to apply to the element and apply it + const runners = this._transformationRunners.runners; + const netTransform = runners.map(getRunnerTransform).reduce(lmultiply, new Matrix()); + this.transform(netTransform); + this._transformationRunners.merge(); + if (this._transformationRunners.length() === 1) { + this._frameId = null; + } + } + class RunnerArray { + constructor() { + this.runners = []; + this.ids = []; + } + add(runner) { + if (this.runners.includes(runner)) return; + const id = runner.id + 1; + this.runners.push(runner); + this.ids.push(id); + return this; + } + clearBefore(id) { + const deleteCnt = this.ids.indexOf(id + 1) || 1; + this.ids.splice(0, deleteCnt, 0); + this.runners.splice(0, deleteCnt, new FakeRunner()).forEach(r => r.clearTransformsFromQueue()); + return this; + } + edit(id, newRunner) { + const index = this.ids.indexOf(id + 1); + this.ids.splice(index, 1, id + 1); + this.runners.splice(index, 1, newRunner); + return this; + } + getByID(id) { + return this.runners[this.ids.indexOf(id + 1)]; + } + length() { + return this.ids.length; + } + merge() { + let lastRunner = null; + for (let i = 0; i < this.runners.length; ++i) { + const runner = this.runners[i]; + const condition = lastRunner && runner.done && lastRunner.done && ( + // don't merge runner when persisted on timeline + !runner._timeline || !runner._timeline._runnerIds.includes(runner.id)) && (!lastRunner._timeline || !lastRunner._timeline._runnerIds.includes(lastRunner.id)); + if (condition) { + // the +1 happens in the function + this.remove(runner.id); + const newRunner = runner.mergeWith(lastRunner); + this.edit(lastRunner.id, newRunner); + lastRunner = newRunner; + --i; + } else { + lastRunner = runner; + } + } + return this; + } + remove(id) { + const index = this.ids.indexOf(id + 1); + this.ids.splice(index, 1); + this.runners.splice(index, 1); + return this; + } + } + registerMethods({ + Element: { + animate(duration, delay, when) { + const o = Runner.sanitise(duration, delay, when); + const timeline = this.timeline(); + return new Runner(o.duration).loop(o).element(this).timeline(timeline.play()).schedule(o.delay, o.when); + }, + delay(by, when) { + return this.animate(0, by, when); + }, + // this function searches for all runners on the element and deletes the ones + // which run before the current one. This is because absolute transformations + // overwrite anything anyway so there is no need to waste time computing + // other runners + _clearTransformRunnersBefore(currentRunner) { + this._transformationRunners.clearBefore(currentRunner.id); + }, + _currentTransform(current) { + return this._transformationRunners.runners + // we need the equal sign here to make sure, that also transformations + // on the same runner which execute before the current transformation are + // taken into account + .filter(runner => runner.id <= current.id).map(getRunnerTransform).reduce(lmultiply, new Matrix()); + }, + _addRunner(runner) { + this._transformationRunners.add(runner); + + // Make sure that the runner merge is executed at the very end of + // all Animator functions. That is why we use immediate here to execute + // the merge right after all frames are run + Animator.cancelImmediate(this._frameId); + this._frameId = Animator.immediate(mergeTransforms.bind(this)); + }, + _prepareRunner() { + if (this._frameId == null) { + this._transformationRunners = new RunnerArray().add(new FakeRunner(new Matrix(this))); + } + } + } + }); + + // Will output the elements from array A that are not in the array B + const difference = (a, b) => a.filter(x => !b.includes(x)); + extend(Runner, { + attr(a, v) { + return this.styleAttr('attr', a, v); + }, + // Add animatable styles + css(s, v) { + return this.styleAttr('css', s, v); + }, + styleAttr(type, nameOrAttrs, val) { + if (typeof nameOrAttrs === 'string') { + return this.styleAttr(type, { + [nameOrAttrs]: val + }); + } + let attrs = nameOrAttrs; + if (this._tryRetarget(type, attrs)) return this; + let morpher = new Morphable(this._stepper).to(attrs); + let keys = Object.keys(attrs); + this.queue(function () { + morpher = morpher.from(this.element()[type](keys)); + }, function (pos) { + this.element()[type](morpher.at(pos).valueOf()); + return morpher.done(); + }, function (newToAttrs) { + // Check if any new keys were added + const newKeys = Object.keys(newToAttrs); + const differences = difference(newKeys, keys); + + // If their are new keys, initialize them and add them to morpher + if (differences.length) { + // Get the values + const addedFromAttrs = this.element()[type](differences); + + // Get the already initialized values + const oldFromAttrs = new ObjectBag(morpher.from()).valueOf(); + + // Merge old and new + Object.assign(oldFromAttrs, addedFromAttrs); + morpher.from(oldFromAttrs); + } + + // Get the object from the morpher + const oldToAttrs = new ObjectBag(morpher.to()).valueOf(); + + // Merge in new attributes + Object.assign(oldToAttrs, newToAttrs); + + // Change morpher target + morpher.to(oldToAttrs); + + // Make sure that we save the work we did so we don't need it to do again + keys = newKeys; + attrs = newToAttrs; + }); + this._rememberMorpher(type, morpher); + return this; + }, + zoom(level, point) { + if (this._tryRetarget('zoom', level, point)) return this; + let morpher = new Morphable(this._stepper).to(new SVGNumber(level)); + this.queue(function () { + morpher = morpher.from(this.element().zoom()); + }, function (pos) { + this.element().zoom(morpher.at(pos), point); + return morpher.done(); + }, function (newLevel, newPoint) { + point = newPoint; + morpher.to(newLevel); + }); + this._rememberMorpher('zoom', morpher); + return this; + }, + /** + ** absolute transformations + **/ + + // + // M v -----|-----(D M v = F v)------|-----> T v + // + // 1. define the final state (T) and decompose it (once) + // t = [tx, ty, the, lam, sy, sx] + // 2. on every frame: pull the current state of all previous transforms + // (M - m can change) + // and then write this as m = [tx0, ty0, the0, lam0, sy0, sx0] + // 3. Find the interpolated matrix F(pos) = m + pos * (t - m) + // - Note F(0) = M + // - Note F(1) = T + // 4. Now you get the delta matrix as a result: D = F * inv(M) + + transform(transforms, relative, affine) { + // If we have a declarative function, we should retarget it if possible + relative = transforms.relative || relative; + if (this._isDeclarative && !relative && this._tryRetarget('transform', transforms)) { + return this; + } + + // Parse the parameters + const isMatrix = Matrix.isMatrixLike(transforms); + affine = transforms.affine != null ? transforms.affine : affine != null ? affine : !isMatrix; + + // Create a morpher and set its type + const morpher = new Morphable(this._stepper).type(affine ? TransformBag : Matrix); + let origin; + let element; + let current; + let currentAngle; + let startTransform; + function setup() { + // make sure element and origin is defined + element = element || this.element(); + origin = origin || getOrigin(transforms, element); + startTransform = new Matrix(relative ? undefined : element); + + // add the runner to the element so it can merge transformations + element._addRunner(this); + + // Deactivate all transforms that have run so far if we are absolute + if (!relative) { + element._clearTransformRunnersBefore(this); + } + } + function run(pos) { + // clear all other transforms before this in case something is saved + // on this runner. We are absolute. We dont need these! + if (!relative) this.clearTransform(); + const { + x, + y + } = new Point(origin).transform(element._currentTransform(this)); + let target = new Matrix({ + ...transforms, + origin: [x, y] + }); + let start = this._isDeclarative && current ? current : startTransform; + if (affine) { + target = target.decompose(x, y); + start = start.decompose(x, y); + + // Get the current and target angle as it was set + const rTarget = target.rotate; + const rCurrent = start.rotate; + + // Figure out the shortest path to rotate directly + const possibilities = [rTarget - 360, rTarget, rTarget + 360]; + const distances = possibilities.map(a => Math.abs(a - rCurrent)); + const shortest = Math.min(...distances); + const index = distances.indexOf(shortest); + target.rotate = possibilities[index]; + } + if (relative) { + // we have to be careful here not to overwrite the rotation + // with the rotate method of Matrix + if (!isMatrix) { + target.rotate = transforms.rotate || 0; + } + if (this._isDeclarative && currentAngle) { + start.rotate = currentAngle; + } + } + morpher.from(start); + morpher.to(target); + const affineParameters = morpher.at(pos); + currentAngle = affineParameters.rotate; + current = new Matrix(affineParameters); + this.addTransform(current); + element._addRunner(this); + return morpher.done(); + } + function retarget(newTransforms) { + // only get a new origin if it changed since the last call + if ((newTransforms.origin || 'center').toString() !== (transforms.origin || 'center').toString()) { + origin = getOrigin(newTransforms, element); + } + + // overwrite the old transformations with the new ones + transforms = { + ...newTransforms, + origin + }; + } + this.queue(setup, run, retarget, true); + this._isDeclarative && this._rememberMorpher('transform', morpher); + return this; + }, + // Animatable x-axis + x(x) { + return this._queueNumber('x', x); + }, + // Animatable y-axis + y(y) { + return this._queueNumber('y', y); + }, + ax(x) { + return this._queueNumber('ax', x); + }, + ay(y) { + return this._queueNumber('ay', y); + }, + dx(x = 0) { + return this._queueNumberDelta('x', x); + }, + dy(y = 0) { + return this._queueNumberDelta('y', y); + }, + dmove(x, y) { + return this.dx(x).dy(y); + }, + _queueNumberDelta(method, to) { + to = new SVGNumber(to); + + // Try to change the target if we have this method already registered + if (this._tryRetarget(method, to)) return this; + + // Make a morpher and queue the animation + const morpher = new Morphable(this._stepper).to(to); + let from = null; + this.queue(function () { + from = this.element()[method](); + morpher.from(from); + morpher.to(from + to); + }, function (pos) { + this.element()[method](morpher.at(pos)); + return morpher.done(); + }, function (newTo) { + morpher.to(from + new SVGNumber(newTo)); + }); + + // Register the morpher so that if it is changed again, we can retarget it + this._rememberMorpher(method, morpher); + return this; + }, + _queueObject(method, to) { + // Try to change the target if we have this method already registered + if (this._tryRetarget(method, to)) return this; + + // Make a morpher and queue the animation + const morpher = new Morphable(this._stepper).to(to); + this.queue(function () { + morpher.from(this.element()[method]()); + }, function (pos) { + this.element()[method](morpher.at(pos)); + return morpher.done(); + }); + + // Register the morpher so that if it is changed again, we can retarget it + this._rememberMorpher(method, morpher); + return this; + }, + _queueNumber(method, value) { + return this._queueObject(method, new SVGNumber(value)); + }, + // Animatable center x-axis + cx(x) { + return this._queueNumber('cx', x); + }, + // Animatable center y-axis + cy(y) { + return this._queueNumber('cy', y); + }, + // Add animatable move + move(x, y) { + return this.x(x).y(y); + }, + amove(x, y) { + return this.ax(x).ay(y); + }, + // Add animatable center + center(x, y) { + return this.cx(x).cy(y); + }, + // Add animatable size + size(width, height) { + // animate bbox based size for all other elements + let box; + if (!width || !height) { + box = this._element.bbox(); + } + if (!width) { + width = box.width / box.height * height; + } + if (!height) { + height = box.height / box.width * width; + } + return this.width(width).height(height); + }, + // Add animatable width + width(width) { + return this._queueNumber('width', width); + }, + // Add animatable height + height(height) { + return this._queueNumber('height', height); + }, + // Add animatable plot + plot(a, b, c, d) { + // Lines can be plotted with 4 arguments + if (arguments.length === 4) { + return this.plot([a, b, c, d]); + } + if (this._tryRetarget('plot', a)) return this; + const morpher = new Morphable(this._stepper).type(this._element.MorphArray).to(a); + this.queue(function () { + morpher.from(this._element.array()); + }, function (pos) { + this._element.plot(morpher.at(pos)); + return morpher.done(); + }); + this._rememberMorpher('plot', morpher); + return this; + }, + // Add leading method + leading(value) { + return this._queueNumber('leading', value); + }, + // Add animatable viewbox + viewbox(x, y, width, height) { + return this._queueObject('viewbox', new Box(x, y, width, height)); + }, + update(o) { + if (typeof o !== 'object') { + return this.update({ + offset: arguments[0], + color: arguments[1], + opacity: arguments[2] + }); + } + if (o.opacity != null) this.attr('stop-opacity', o.opacity); + if (o.color != null) this.attr('stop-color', o.color); + if (o.offset != null) this.attr('offset', o.offset); + return this; + } + }); + extend(Runner, { + rx, + ry, + from, + to + }); + register(Runner, 'Runner'); + + class Svg extends Container { + constructor(node, attrs = node) { + super(nodeOrNew('svg', node), attrs); + this.namespace(); + } + + // Creates and returns defs element + defs() { + if (!this.isRoot()) return this.root().defs(); + return adopt(this.node.querySelector('defs')) || this.put(new Defs()); + } + isRoot() { + return !this.node.parentNode || !(this.node.parentNode instanceof globals.window.SVGElement) && this.node.parentNode.nodeName !== '#document-fragment'; + } + + // Add namespaces + namespace() { + if (!this.isRoot()) return this.root().namespace(); + return this.attr({ + xmlns: svg, + version: '1.1' + }).attr('xmlns:xlink', xlink, xmlns); + } + removeNamespace() { + return this.attr({ + xmlns: null, + version: null + }).attr('xmlns:xlink', null, xmlns).attr('xmlns:svgjs', null, xmlns); + } + + // Check if this is a root svg + // If not, call root() from this element + root() { + if (this.isRoot()) return this; + return super.root(); + } + } + registerMethods({ + Container: { + // Create nested svg document + nested: wrapWithAttrCheck(function () { + return this.put(new Svg()); + }) + } + }); + register(Svg, 'Svg', true); + + class Symbol extends Container { + // Initialize node + constructor(node, attrs = node) { + super(nodeOrNew('symbol', node), attrs); + } + } + registerMethods({ + Container: { + symbol: wrapWithAttrCheck(function () { + return this.put(new Symbol()); + }) + } + }); + register(Symbol, 'Symbol'); + + // Create plain text node + function plain(text) { + // clear if build mode is disabled + if (this._build === false) { + this.clear(); + } + + // create text node + this.node.appendChild(globals.document.createTextNode(text)); + return this; + } + + // Get length of text element + function length() { + return this.node.getComputedTextLength(); + } + + // Move over x-axis + // Text is moved by its bounding box + // text-anchor does NOT matter + function x$1(x, box = this.bbox()) { + if (x == null) { + return box.x; + } + return this.attr('x', this.attr('x') + x - box.x); + } + + // Move over y-axis + function y$1(y, box = this.bbox()) { + if (y == null) { + return box.y; + } + return this.attr('y', this.attr('y') + y - box.y); + } + function move$1(x, y, box = this.bbox()) { + return this.x(x, box).y(y, box); + } + + // Move center over x-axis + function cx(x, box = this.bbox()) { + if (x == null) { + return box.cx; + } + return this.attr('x', this.attr('x') + x - box.cx); + } + + // Move center over y-axis + function cy(y, box = this.bbox()) { + if (y == null) { + return box.cy; + } + return this.attr('y', this.attr('y') + y - box.cy); + } + function center(x, y, box = this.bbox()) { + return this.cx(x, box).cy(y, box); + } + function ax(x) { + return this.attr('x', x); + } + function ay(y) { + return this.attr('y', y); + } + function amove(x, y) { + return this.ax(x).ay(y); + } + + // Enable / disable build mode + function build(build) { + this._build = !!build; + return this; + } + + var textable = { + __proto__: null, + amove: amove, + ax: ax, + ay: ay, + build: build, + center: center, + cx: cx, + cy: cy, + length: length, + move: move$1, + plain: plain, + x: x$1, + y: y$1 + }; + + class Text extends Shape { + // Initialize node + constructor(node, attrs = node) { + super(nodeOrNew('text', node), attrs); + this.dom.leading = this.dom.leading ?? new SVGNumber(1.3); // store leading value for rebuilding + this._rebuild = true; // enable automatic updating of dy values + this._build = false; // disable build mode for adding multiple lines + } + + // Set / get leading + leading(value) { + // act as getter + if (value == null) { + return this.dom.leading; + } + + // act as setter + this.dom.leading = new SVGNumber(value); + return this.rebuild(); + } + + // Rebuild appearance type + rebuild(rebuild) { + // store new rebuild flag if given + if (typeof rebuild === 'boolean') { + this._rebuild = rebuild; + } + + // define position of all lines + if (this._rebuild) { + const self = this; + let blankLineOffset = 0; + const leading = this.dom.leading; + this.each(function (i) { + if (isDescriptive(this.node)) return; + const fontSize = globals.window.getComputedStyle(this.node).getPropertyValue('font-size'); + const dy = leading * new SVGNumber(fontSize); + if (this.dom.newLined) { + this.attr('x', self.attr('x')); + if (this.text() === '\n') { + blankLineOffset += dy; + } else { + this.attr('dy', i ? dy + blankLineOffset : 0); + blankLineOffset = 0; + } + } + }); + this.fire('rebuild'); + } + return this; + } + + // overwrite method from parent to set data properly + setData(o) { + this.dom = o; + this.dom.leading = new SVGNumber(o.leading || 1.3); + return this; + } + writeDataToDom() { + writeDataToDom(this, this.dom, { + leading: 1.3 + }); + return this; + } + + // Set the text content + text(text) { + // act as getter + if (text === undefined) { + const children = this.node.childNodes; + let firstLine = 0; + text = ''; + for (let i = 0, len = children.length; i < len; ++i) { + // skip textPaths - they are no lines + if (children[i].nodeName === 'textPath' || isDescriptive(children[i])) { + if (i === 0) firstLine = i + 1; + continue; + } + + // add newline if its not the first child and newLined is set to true + if (i !== firstLine && children[i].nodeType !== 3 && adopt(children[i]).dom.newLined === true) { + text += '\n'; + } + + // add content of this node + text += children[i].textContent; + } + return text; + } + + // remove existing content + this.clear().build(true); + if (typeof text === 'function') { + // call block + text.call(this, this); + } else { + // store text and make sure text is not blank + text = (text + '').split('\n'); + + // build new lines + for (let j = 0, jl = text.length; j < jl; j++) { + this.newLine(text[j]); + } + } + + // disable build mode and rebuild lines + return this.build(false).rebuild(); + } + } + extend(Text, textable); + registerMethods({ + Container: { + // Create text element + text: wrapWithAttrCheck(function (text = '') { + return this.put(new Text()).text(text); + }), + // Create plain text element + plain: wrapWithAttrCheck(function (text = '') { + return this.put(new Text()).plain(text); + }) + } + }); + register(Text, 'Text'); + + class Tspan extends Shape { + // Initialize node + constructor(node, attrs = node) { + super(nodeOrNew('tspan', node), attrs); + this._build = false; // disable build mode for adding multiple lines + } + + // Shortcut dx + dx(dx) { + return this.attr('dx', dx); + } + + // Shortcut dy + dy(dy) { + return this.attr('dy', dy); + } + + // Create new line + newLine() { + // mark new line + this.dom.newLined = true; + + // fetch parent + const text = this.parent(); + + // early return in case we are not in a text element + if (!(text instanceof Text)) { + return this; + } + const i = text.index(this); + const fontSize = globals.window.getComputedStyle(this.node).getPropertyValue('font-size'); + const dy = text.dom.leading * new SVGNumber(fontSize); + + // apply new position + return this.dy(i ? dy : 0).attr('x', text.x()); + } + + // Set text content + text(text) { + if (text == null) return this.node.textContent + (this.dom.newLined ? '\n' : ''); + if (typeof text === 'function') { + this.clear().build(true); + text.call(this, this); + this.build(false); + } else { + this.plain(text); + } + return this; + } + } + extend(Tspan, textable); + registerMethods({ + Tspan: { + tspan: wrapWithAttrCheck(function (text = '') { + const tspan = new Tspan(); + + // clear if build mode is disabled + if (!this._build) { + this.clear(); + } + + // add new tspan + return this.put(tspan).text(text); + }) + }, + Text: { + newLine: function (text = '') { + return this.tspan(text).newLine(); + } + } + }); + register(Tspan, 'Tspan'); + + class Circle extends Shape { + constructor(node, attrs = node) { + super(nodeOrNew('circle', node), attrs); + } + radius(r) { + return this.attr('r', r); + } + + // Radius x value + rx(rx) { + return this.attr('r', rx); + } + + // Alias radius x value + ry(ry) { + return this.rx(ry); + } + size(size) { + return this.radius(new SVGNumber(size).divide(2)); + } + } + extend(Circle, { + x: x$3, + y: y$3, + cx: cx$1, + cy: cy$1, + width: width$2, + height: height$2 + }); + registerMethods({ + Container: { + // Create circle element + circle: wrapWithAttrCheck(function (size = 0) { + return this.put(new Circle()).size(size).move(0, 0); + }) + } + }); + register(Circle, 'Circle'); + + class ClipPath extends Container { + constructor(node, attrs = node) { + super(nodeOrNew('clipPath', node), attrs); + } + + // Unclip all clipped elements and remove itself + remove() { + // unclip all targets + this.targets().forEach(function (el) { + el.unclip(); + }); + + // remove clipPath from parent + return super.remove(); + } + targets() { + return baseFind('svg [clip-path*=' + this.id() + ']'); + } + } + registerMethods({ + Container: { + // Create clipping element + clip: wrapWithAttrCheck(function () { + return this.defs().put(new ClipPath()); + }) + }, + Element: { + // Distribute clipPath to svg element + clipper() { + return this.reference('clip-path'); + }, + clipWith(element) { + // use given clip or create a new one + const clipper = element instanceof ClipPath ? element : this.parent().clip().add(element); + + // apply mask + return this.attr('clip-path', 'url(#' + clipper.id() + ')'); + }, + // Unclip element + unclip() { + return this.attr('clip-path', null); + } + } + }); + register(ClipPath, 'ClipPath'); + + class ForeignObject extends Element { + constructor(node, attrs = node) { + super(nodeOrNew('foreignObject', node), attrs); + } + } + registerMethods({ + Container: { + foreignObject: wrapWithAttrCheck(function (width, height) { + return this.put(new ForeignObject()).size(width, height); + }) + } + }); + register(ForeignObject, 'ForeignObject'); + + function dmove(dx, dy) { + this.children().forEach(child => { + let bbox; + + // We have to wrap this for elements that dont have a bbox + // e.g. title and other descriptive elements + try { + // Get the childs bbox + // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1905039 + // Because bbox for nested svgs returns the contents bbox in the coordinate space of the svg itself (weird!), we cant use bbox for svgs + // Therefore we have to use getBoundingClientRect. But THAT is broken (as explained in the bug). + // Funnily enough the broken behavior would work for us but that breaks it in chrome + // So we have to replicate the broken behavior of FF by just reading the attributes of the svg itself + bbox = child.node instanceof getWindow().SVGSVGElement ? new Box(child.attr(['x', 'y', 'width', 'height'])) : child.bbox(); + } catch (e) { + return; + } + + // Get childs matrix + const m = new Matrix(child); + // Translate childs matrix by amount and + // transform it back into parents space + const matrix = m.translate(dx, dy).transform(m.inverse()); + // Calculate new x and y from old box + const p = new Point(bbox.x, bbox.y).transform(matrix); + // Move element + child.move(p.x, p.y); + }); + return this; + } + function dx(dx) { + return this.dmove(dx, 0); + } + function dy(dy) { + return this.dmove(0, dy); + } + function height(height, box = this.bbox()) { + if (height == null) return box.height; + return this.size(box.width, height, box); + } + function move(x = 0, y = 0, box = this.bbox()) { + const dx = x - box.x; + const dy = y - box.y; + return this.dmove(dx, dy); + } + function size(width, height, box = this.bbox()) { + const p = proportionalSize(this, width, height, box); + const scaleX = p.width / box.width; + const scaleY = p.height / box.height; + this.children().forEach(child => { + const o = new Point(box).transform(new Matrix(child).inverse()); + child.scale(scaleX, scaleY, o.x, o.y); + }); + return this; + } + function width(width, box = this.bbox()) { + if (width == null) return box.width; + return this.size(width, box.height, box); + } + function x(x, box = this.bbox()) { + if (x == null) return box.x; + return this.move(x, box.y, box); + } + function y(y, box = this.bbox()) { + if (y == null) return box.y; + return this.move(box.x, y, box); + } + + var containerGeometry = { + __proto__: null, + dmove: dmove, + dx: dx, + dy: dy, + height: height, + move: move, + size: size, + width: width, + x: x, + y: y + }; + + class G extends Container { + constructor(node, attrs = node) { + super(nodeOrNew('g', node), attrs); + } + } + extend(G, containerGeometry); + registerMethods({ + Container: { + // Create a group element + group: wrapWithAttrCheck(function () { + return this.put(new G()); + }) + } + }); + register(G, 'G'); + + class A extends Container { + constructor(node, attrs = node) { + super(nodeOrNew('a', node), attrs); + } + + // Link target attribute + target(target) { + return this.attr('target', target); + } + + // Link url + to(url) { + return this.attr('href', url, xlink); + } + } + extend(A, containerGeometry); + registerMethods({ + Container: { + // Create a hyperlink element + link: wrapWithAttrCheck(function (url) { + return this.put(new A()).to(url); + }) + }, + Element: { + unlink() { + const link = this.linker(); + if (!link) return this; + const parent = link.parent(); + if (!parent) { + return this.remove(); + } + const index = parent.index(link); + parent.add(this, index); + link.remove(); + return this; + }, + linkTo(url) { + // reuse old link if possible + let link = this.linker(); + if (!link) { + link = new A(); + this.wrap(link); + } + if (typeof url === 'function') { + url.call(link, link); + } else { + link.to(url); + } + return this; + }, + linker() { + const link = this.parent(); + if (link && link.node.nodeName.toLowerCase() === 'a') { + return link; + } + return null; + } + } + }); + register(A, 'A'); + + class Mask extends Container { + // Initialize node + constructor(node, attrs = node) { + super(nodeOrNew('mask', node), attrs); + } + + // Unmask all masked elements and remove itself + remove() { + // unmask all targets + this.targets().forEach(function (el) { + el.unmask(); + }); + + // remove mask from parent + return super.remove(); + } + targets() { + return baseFind('svg [mask*=' + this.id() + ']'); + } + } + registerMethods({ + Container: { + mask: wrapWithAttrCheck(function () { + return this.defs().put(new Mask()); + }) + }, + Element: { + // Distribute mask to svg element + masker() { + return this.reference('mask'); + }, + maskWith(element) { + // use given mask or create a new one + const masker = element instanceof Mask ? element : this.parent().mask().add(element); + + // apply mask + return this.attr('mask', 'url(#' + masker.id() + ')'); + }, + // Unmask element + unmask() { + return this.attr('mask', null); + } + } + }); + register(Mask, 'Mask'); + + class Stop extends Element { + constructor(node, attrs = node) { + super(nodeOrNew('stop', node), attrs); + } + + // add color stops + update(o) { + if (typeof o === 'number' || o instanceof SVGNumber) { + o = { + offset: arguments[0], + color: arguments[1], + opacity: arguments[2] + }; + } + + // set attributes + if (o.opacity != null) this.attr('stop-opacity', o.opacity); + if (o.color != null) this.attr('stop-color', o.color); + if (o.offset != null) this.attr('offset', new SVGNumber(o.offset)); + return this; + } + } + registerMethods({ + Gradient: { + // Add a color stop + stop: function (offset, color, opacity) { + return this.put(new Stop()).update(offset, color, opacity); + } + } + }); + register(Stop, 'Stop'); + + function cssRule(selector, rule) { + if (!selector) return ''; + if (!rule) return selector; + let ret = selector + '{'; + for (const i in rule) { + ret += unCamelCase(i) + ':' + rule[i] + ';'; + } + ret += '}'; + return ret; + } + class Style extends Element { + constructor(node, attrs = node) { + super(nodeOrNew('style', node), attrs); + } + addText(w = '') { + this.node.textContent += w; + return this; + } + font(name, src, params = {}) { + return this.rule('@font-face', { + fontFamily: name, + src: src, + ...params + }); + } + rule(selector, obj) { + return this.addText(cssRule(selector, obj)); + } + } + registerMethods('Dom', { + style(selector, obj) { + return this.put(new Style()).rule(selector, obj); + }, + fontface(name, src, params) { + return this.put(new Style()).font(name, src, params); + } + }); + register(Style, 'Style'); + + class TextPath extends Text { + // Initialize node + constructor(node, attrs = node) { + super(nodeOrNew('textPath', node), attrs); + } + + // return the array of the path track element + array() { + const track = this.track(); + return track ? track.array() : null; + } + + // Plot path if any + plot(d) { + const track = this.track(); + let pathArray = null; + if (track) { + pathArray = track.plot(d); + } + return d == null ? pathArray : this; + } + + // Get the path element + track() { + return this.reference('href'); + } + } + registerMethods({ + Container: { + textPath: wrapWithAttrCheck(function (text, path) { + // Convert text to instance if needed + if (!(text instanceof Text)) { + text = this.text(text); + } + return text.path(path); + }) + }, + Text: { + // Create path for text to run on + path: wrapWithAttrCheck(function (track, importNodes = true) { + const textPath = new TextPath(); + + // if track is a path, reuse it + if (!(track instanceof Path)) { + // create path element + track = this.defs().path(track); + } + + // link textPath to path and add content + textPath.attr('href', '#' + track, xlink); + + // Transplant all nodes from text to textPath + let node; + if (importNodes) { + while (node = this.node.firstChild) { + textPath.node.appendChild(node); + } + } + + // add textPath element as child node and return textPath + return this.put(textPath); + }), + // Get the textPath children + textPath() { + return this.findOne('textPath'); + } + }, + Path: { + // creates a textPath from this path + text: wrapWithAttrCheck(function (text) { + // Convert text to instance if needed + if (!(text instanceof Text)) { + text = new Text().addTo(this.parent()).text(text); + } + + // Create textPath from text and path and return + return text.path(this); + }), + targets() { + return baseFind('svg textPath').filter(node => { + return (node.attr('href') || '').includes(this.id()); + }); + + // Does not work in IE11. Use when IE support is dropped + // return baseFind('svg textPath[*|href*=' + this.id() + ']') + } + } + }); + TextPath.prototype.MorphArray = PathArray; + register(TextPath, 'TextPath'); + + class Use extends Shape { + constructor(node, attrs = node) { + super(nodeOrNew('use', node), attrs); + } + + // Use element as a reference + use(element, file) { + // Set lined element + return this.attr('href', (file || '') + '#' + element, xlink); + } + } + registerMethods({ + Container: { + // Create a use element + use: wrapWithAttrCheck(function (element, file) { + return this.put(new Use()).use(element, file); + }) + } + }); + register(Use, 'Use'); + + /* Optional Modules */ + const SVG$1 = makeInstance; + extend([Svg, Symbol, Image, Pattern, Marker], getMethodsFor('viewbox')); + extend([Line, Polyline, Polygon, Path], getMethodsFor('marker')); + extend(Text, getMethodsFor('Text')); + extend(Path, getMethodsFor('Path')); + extend(Defs, getMethodsFor('Defs')); + extend([Text, Tspan], getMethodsFor('Tspan')); + extend([Rect, Ellipse, Gradient, Runner], getMethodsFor('radius')); + extend(EventTarget, getMethodsFor('EventTarget')); + extend(Dom, getMethodsFor('Dom')); + extend(Element, getMethodsFor('Element')); + extend(Shape, getMethodsFor('Shape')); + extend([Container, Fragment], getMethodsFor('Container')); + extend(Gradient, getMethodsFor('Gradient')); + extend(Runner, getMethodsFor('Runner')); + List.extend(getMethodNames()); + registerMorphableType([SVGNumber, Color, Box, Matrix, SVGArray, PointArray, PathArray, Point]); + makeMorphable(); + + var svgMembers = { + __proto__: null, + A: A, + Animator: Animator, + Array: SVGArray, + Box: Box, + Circle: Circle, + ClipPath: ClipPath, + Color: Color, + Container: Container, + Controller: Controller, + Defs: Defs, + Dom: Dom, + Ease: Ease, + Element: Element, + Ellipse: Ellipse, + EventTarget: EventTarget, + ForeignObject: ForeignObject, + Fragment: Fragment, + G: G, + Gradient: Gradient, + Image: Image, + Line: Line, + List: List, + Marker: Marker, + Mask: Mask, + Matrix: Matrix, + Morphable: Morphable, + NonMorphable: NonMorphable, + Number: SVGNumber, + ObjectBag: ObjectBag, + PID: PID, + Path: Path, + PathArray: PathArray, + Pattern: Pattern, + Point: Point, + PointArray: PointArray, + Polygon: Polygon, + Polyline: Polyline, + Queue: Queue, + Rect: Rect, + Runner: Runner, + SVG: SVG$1, + Shape: Shape, + Spring: Spring, + Stop: Stop, + Style: Style, + Svg: Svg, + Symbol: Symbol, + Text: Text, + TextPath: TextPath, + Timeline: Timeline, + TransformBag: TransformBag, + Tspan: Tspan, + Use: Use, + adopt: adopt, + assignNewId: assignNewId, + clearEvents: clearEvents, + create: create, + defaults: defaults, + dispatch: dispatch, + easing: easing, + eid: eid, + extend: extend, + find: baseFind, + getClass: getClass, + getEventTarget: getEventTarget, + getEvents: getEvents, + getWindow: getWindow, + makeInstance: makeInstance, + makeMorphable: makeMorphable, + mockAdopt: mockAdopt, + namespaces: namespaces, + nodeOrNew: nodeOrNew, + off: off, + on: on, + parser: parser, + regex: regex, + register: register, + registerMorphableType: registerMorphableType, + registerWindow: registerWindow, + restoreWindow: restoreWindow, + root: root, + saveWindow: saveWindow, + utils: utils, + windowEvents: windowEvents, + withWindow: withWindow, + wrapWithAttrCheck: wrapWithAttrCheck + }; + + // The main wrapping element + function SVG(element, isHTML) { + return makeInstance(element, isHTML); + } + Object.assign(SVG, svgMembers); + + return SVG; + +}; diff --git a/classes/mapworker.php b/classes/mapworker.php index 2ee8f49..2d42c3f 100644 --- a/classes/mapworker.php +++ b/classes/mapworker.php @@ -16,8 +16,6 @@ namespace mod_learningmap; -use DOMElement; - /** * Class for handling the content of the learningmap * @@ -222,7 +220,7 @@ public function process_map_objects(): void { // Make all completed places visible and set color for visited places. foreach ($completedplaces as $place) { $this->svgmap->set_visited($place); - // If the option "usecheckmark" is selected, add the checkmark to the circle. + // If the option "usecheckmark" is selected, add the checkmark to the place. if ($this->placestore['usecheckmark']) { $this->svgmap->add_checkmark($place); } diff --git a/classes/svgmap.php b/classes/svgmap.php index eac5a5b..8527705 100644 --- a/classes/svgmap.php +++ b/classes/svgmap.php @@ -155,6 +155,18 @@ public function get_attribute(string $id, string $attribute): ?string { return $element === null ? null : $element->getAttribute($attribute); } + /** + * Check if an element is a place + * + * @param string $id The id of the DOM element + * @return bool + */ + public function is_place(string $id): bool { + $element = $this->dom->getElementById($id); + $classes = explode(' ', $element->getAttribute('class')); + return $element !== null && in_array('learningmap-place', $classes); + } + /** * Remove a place or path. If removing a place also the link and the connected paths are removed. * @@ -164,7 +176,7 @@ public function get_attribute(string $id, string $attribute): ?string { public function remove_place_or_path(string $id): void { $placeorpath = $this->dom->getElementById($id); if ($placeorpath) { - if ($placeorpath->nodeName == 'circle') { + if (self::is_place($id)) { // Also remove connected paths for places. foreach ($this->placestore['paths'] as $path) { if ($path['sid'] == $id || $path['fid'] == $id) { diff --git a/thirdpartylibs.xml b/thirdpartylibs.xml new file mode 100644 index 0000000..6a6b3dc --- /dev/null +++ b/thirdpartylibs.xml @@ -0,0 +1,9 @@ + + + + amd/src/svg.js + SVG.js + 3.2.4 + MIT + +