diff --git a/package-lock.json b/package-lock.json index 9ce32c4c..a4ad9844 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "0.18.0", "license": "AGPL", "dependencies": { - "@hpcc-js/wasm": "^1.12.4", "@material/mwc-button": "^0.27.0", "@material/mwc-checkbox": "^0.27.0", "@material/mwc-circular-progress": "^0.27.0", @@ -34,7 +33,11 @@ "@material/mwc-top-app-bar": "^0.27.0", "@mdi/js": "^5.8.55", "@types/leaflet": "^1.5.19", - "d3-graphviz": "^4.0.0", + "d3": "^7.8.2", + "d3-hierarchy": "^3.1.2", + "d3-scale-chromatic": "^3.0.0", + "d3-selection": "^3.0.0", + "d3-shape": "^3.2.0", "dayjs": "^1.8.36", "jwt-decode": "^3.1.2", "leaflet": "^1.7.1", @@ -1847,79 +1850,6 @@ "@hapi/hoek": "^8.3.0" } }, - "node_modules/@hpcc-js/wasm": { - "version": "1.12.4", - "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-1.12.4.tgz", - "integrity": "sha512-Vfc5VDfk2PB73JReo+CfihNdYtrOBFgxE2Kjr/ELO9kSnrktS+VpgQWqEYRRcltTbqg1xCtfLnL7b5vvhhUVtw==", - "dependencies": { - "yargs": "^17.1.1" - }, - "bin": { - "dot-wasm": "bin/cli.js" - } - }, - "node_modules/@hpcc-js/wasm/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@hpcc-js/wasm/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/@hpcc-js/wasm/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@hpcc-js/wasm/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/@hpcc-js/wasm/node_modules/yargs": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.2.1.tgz", - "integrity": "sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q==", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@hpcc-js/wasm/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "engines": { - "node": ">=10" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", @@ -6457,11 +6387,136 @@ "node": ">=4" } }, + "node_modules/d3": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.2.tgz", + "integrity": "sha512-WXty7qOGSHb7HR7CfOzwN1Gw04MUOzN8qh9ZUsvwycIMb4DYMpY9xczZ6jUorGtO6bR9BPMPaueIKwiDxu9uiQ==", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-yEEyEAbDrF8C6Ob2myOBLjwBLck1Z89jMGFee0oPsn95GqjerpaOA4ch+vc2l0FNFFwMD5N7OCSEN5eAlsUbgQ==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush/node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", + "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-dispatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz", @@ -6476,38 +6531,106 @@ "d3-selection": "2" } }, + "node_modules/d3-drag/node_modules/d3-selection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz", + "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==" + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-dsv/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/d3-ease": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz", "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==" }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-format": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" }, - "node_modules/d3-graphviz": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/d3-graphviz/-/d3-graphviz-4.0.0.tgz", - "integrity": "sha512-j+fRjPiLnMa3C2QLIWld13vJQzkd9uBhYXZJQSgKI7z2uTvCdMcrvvxJYg7vGdzqceMImKq5Is/oX8kDw+1xng==", - "dependencies": { - "@hpcc-js/wasm": "1.4.1", - "d3-dispatch": "^2.0.0", - "d3-format": "^2.0.0", - "d3-interpolate": "^2.0.1", - "d3-path": "^2.0.0", - "d3-timer": "^2.0.0", - "d3-transition": "^2.0.0", - "d3-zoom": "^2.0.0" + "node_modules/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "dependencies": { + "d3-array": "2.5.0 - 3" }, - "peerDependencies": { - "d3-selection": "^2.0.0" + "engines": { + "node": ">=12" } }, - "node_modules/d3-graphviz/node_modules/@hpcc-js/wasm": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-1.4.1.tgz", - "integrity": "sha512-WYeIuG/B1B1cTcM9D9bC6qDFSZnEcJ9R3SpTW5jh10sTh0hD1h1t/dZudfLwarJD+ce8q4/BP43BplbP3CeNkQ==" + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "engines": { + "node": ">=12" + } }, "node_modules/d3-interpolate": { "version": "2.0.1", @@ -6522,41 +6645,213 @@ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz", "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==" }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-selection": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz", - "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape/node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } }, "node_modules/d3-timer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==" }, - "node_modules/d3-transition": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz", - "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==", + "node_modules/d3/node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3/node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3/node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", "dependencies": { - "d3-color": "1 - 2", - "d3-dispatch": "1 - 2", - "d3-ease": "1 - 2", - "d3-interpolate": "1 - 2", - "d3-timer": "1 - 2" + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3/node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3/node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3/node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3/node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3/node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3/node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" }, "peerDependencies": { - "d3-selection": "2" + "d3-selection": "2 - 3" } }, - "node_modules/d3-zoom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz", - "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==", + "node_modules/d3/node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", "dependencies": { - "d3-dispatch": "1 - 2", - "d3-drag": "2", - "d3-interpolate": "1 - 2", - "d3-selection": "2", - "d3-transition": "2" + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" } }, "node_modules/dayjs": { @@ -6671,6 +6966,14 @@ "node": ">= 0.4" } }, + "node_modules/delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "dependencies": { + "robust-predicates": "^3.0.0" + } + }, "node_modules/delegate": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", @@ -7131,6 +7434,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, "engines": { "node": ">=6" } @@ -8198,6 +8502,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -9126,6 +9431,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/intersection-observer": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.7.0.tgz", @@ -9337,6 +9650,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "engines": { "node": ">=8" } @@ -12933,6 +13247,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -13075,6 +13390,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robust-predicates": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz", + "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==" + }, "node_modules/rollup": { "version": "2.60.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.60.2.tgz", @@ -13351,6 +13671,11 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, "node_modules/rxjs": { "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", @@ -13378,8 +13703,7 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/select": { "version": "1.1.2", @@ -13748,6 +14072,7 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -13761,6 +14086,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, "engines": { "node": ">=8" } @@ -13768,12 +14094,14 @@ "node_modules/string-width/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "node_modules/string-width/node_modules/strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.0" }, @@ -15277,6 +15605,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -15293,6 +15622,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, "engines": { "node": ">=8" } @@ -15301,6 +15631,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -15315,6 +15646,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -15325,12 +15657,14 @@ "node_modules/wrap-ansi/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/wrap-ansi/node_modules/strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.0" }, @@ -16820,63 +17154,6 @@ "@hapi/hoek": "^8.3.0" } }, - "@hpcc-js/wasm": { - "version": "1.12.4", - "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-1.12.4.tgz", - "integrity": "sha512-Vfc5VDfk2PB73JReo+CfihNdYtrOBFgxE2Kjr/ELO9kSnrktS+VpgQWqEYRRcltTbqg1xCtfLnL7b5vvhhUVtw==", - "requires": { - "yargs": "^17.1.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" - }, - "yargs": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.2.1.tgz", - "integrity": "sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q==", - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" - } - } - }, "@humanwhocodes/config-array": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", @@ -20760,11 +21037,184 @@ "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", "dev": true }, + "d3": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.2.tgz", + "integrity": "sha512-WXty7qOGSHb7HR7CfOzwN1Gw04MUOzN8qh9ZUsvwycIMb4DYMpY9xczZ6jUorGtO6bR9BPMPaueIKwiDxu9uiQ==", + "requires": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "dependencies": { + "d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" + }, + "d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==" + }, + "d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + } + }, + "d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==" + }, + "d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==" + }, + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "requires": { + "d3-color": "1 - 3" + } + }, + "d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==" + }, + "d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==" + }, + "d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "requires": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + } + }, + "d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + } + } + } + }, + "d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-yEEyEAbDrF8C6Ob2myOBLjwBLck1Z89jMGFee0oPsn95GqjerpaOA4ch+vc2l0FNFFwMD5N7OCSEN5eAlsUbgQ==", + "requires": { + "internmap": "1 - 2" + } + }, + "d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==" + }, + "d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "dependencies": { + "d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "requires": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + } + } + } + }, + "d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "requires": { + "d3-path": "1 - 3" + } + }, "d3-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" }, + "d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "requires": { + "d3-array": "^3.2.0" + } + }, + "d3-delaunay": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", + "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", + "requires": { + "delaunator": "5" + } + }, "d3-dispatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz", @@ -20777,6 +21227,38 @@ "requires": { "d3-dispatch": "1 - 2", "d3-selection": "2" + }, + "dependencies": { + "d3-selection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz", + "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==" + } + } + }, + "d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "requires": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } } }, "d3-ease": { @@ -20784,33 +21266,42 @@ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz", "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==" }, + "d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "requires": { + "d3-dsv": "1 - 3" + } + }, + "d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + } + }, "d3-format": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" }, - "d3-graphviz": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/d3-graphviz/-/d3-graphviz-4.0.0.tgz", - "integrity": "sha512-j+fRjPiLnMa3C2QLIWld13vJQzkd9uBhYXZJQSgKI7z2uTvCdMcrvvxJYg7vGdzqceMImKq5Is/oX8kDw+1xng==", + "d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", "requires": { - "@hpcc-js/wasm": "1.4.1", - "d3-dispatch": "^2.0.0", - "d3-format": "^2.0.0", - "d3-interpolate": "^2.0.1", - "d3-path": "^2.0.0", - "d3-timer": "^2.0.0", - "d3-transition": "^2.0.0", - "d3-zoom": "^2.0.0" - }, - "dependencies": { - "@hpcc-js/wasm": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@hpcc-js/wasm/-/wasm-1.4.1.tgz", - "integrity": "sha512-WYeIuG/B1B1cTcM9D9bC6qDFSZnEcJ9R3SpTW5jh10sTh0hD1h1t/dZudfLwarJD+ce8q4/BP43BplbP3CeNkQ==" - } + "d3-array": "2.5.0 - 3" } }, + "d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==" + }, "d3-interpolate": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", @@ -20824,40 +21315,83 @@ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz", "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==" }, + "d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==" + }, + "d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==" + }, + "d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==" + }, + "d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "requires": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + } + }, + "d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "requires": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + } + }, "d3-selection": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz", - "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" }, - "d3-timer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", - "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==" + "d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "requires": { + "d3-path": "^3.1.0" + }, + "dependencies": { + "d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==" + } + } }, - "d3-transition": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz", - "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==", + "d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", "requires": { - "d3-color": "1 - 2", - "d3-dispatch": "1 - 2", - "d3-ease": "1 - 2", - "d3-interpolate": "1 - 2", - "d3-timer": "1 - 2" + "d3-array": "2 - 3" } }, - "d3-zoom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz", - "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==", + "d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", "requires": { - "d3-dispatch": "1 - 2", - "d3-drag": "2", - "d3-interpolate": "1 - 2", - "d3-selection": "2", - "d3-transition": "2" + "d3-time": "1 - 3" } }, + "d3-timer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", + "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==" + }, "dayjs": { "version": "1.10.6", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.6.tgz", @@ -20944,6 +21478,14 @@ "object-keys": "^1.0.12" } }, + "delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "requires": { + "robust-predicates": "^3.0.0" + } + }, "delegate": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", @@ -21324,7 +21866,8 @@ "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true }, "escape-html": { "version": "1.0.3", @@ -22120,7 +22663,8 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true }, "get-func-name": { "version": "2.0.0", @@ -22790,6 +23334,11 @@ "side-channel": "^1.0.4" } }, + "internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" + }, "intersection-observer": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.7.0.tgz", @@ -22923,7 +23472,8 @@ "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true }, "is-generator-function": { "version": "1.0.10", @@ -25825,7 +26375,8 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true }, "require-from-string": { "version": "2.0.2", @@ -25933,6 +26484,11 @@ "glob": "^7.1.3" } }, + "robust-predicates": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.1.tgz", + "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==" + }, "rollup": { "version": "2.60.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.60.2.tgz", @@ -26150,6 +26706,11 @@ "queue-microtask": "^1.2.2" } }, + "rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, "rxjs": { "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", @@ -26176,8 +26737,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "select": { "version": "1.1.2", @@ -26474,6 +27034,7 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -26483,17 +27044,20 @@ "ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, "requires": { "ansi-regex": "^5.0.0" } @@ -27706,6 +28270,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -27715,12 +28280,14 @@ "ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -27729,6 +28296,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "requires": { "color-name": "~1.1.4" } @@ -27736,12 +28304,14 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, "requires": { "ansi-regex": "^5.0.0" } diff --git a/package.json b/package.json index 95d57394..69b6ad76 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,6 @@ "author": "David M. Straub", "license": "AGPL", "dependencies": { - "@hpcc-js/wasm": "^1.12.4", "@material/mwc-button": "^0.27.0", "@material/mwc-checkbox": "^0.27.0", "@material/mwc-circular-progress": "^0.27.0", @@ -103,7 +102,11 @@ "@material/mwc-top-app-bar": "^0.27.0", "@mdi/js": "^5.8.55", "@types/leaflet": "^1.5.19", - "d3-graphviz": "^4.0.0", + "d3": "^7.8.2", + "d3-hierarchy": "^3.1.2", + "d3-scale-chromatic": "^3.0.0", + "d3-selection": "^3.0.0", + "d3-shape": "^3.2.0", "dayjs": "^1.8.36", "jwt-decode": "^3.1.2", "leaflet": "^1.7.1", diff --git a/rollup.config.js b/rollup.config.js index 0a3d9521..f7b36f89 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -33,18 +33,6 @@ export default merge(baseConfig, { {src: './manifest.json', dest: 'dist/'}, {src: './images/**/*', dest: 'dist/images'}, {src: './fonts/**/*', dest: 'dist/fonts'}, - { - src: 'node_modules/@hpcc-js/wasm/dist/graphvizlib.wasm', - dest: 'dist/', - }, - { - src: 'node_modules/@hpcc-js/wasm/dist/graphvizlib.wasm', - dest: 'dist/@hpcc-js/wasm', - }, - { - src: 'node_modules/@hpcc-js/wasm/dist/index.min.js', - dest: 'dist/@hpcc-js/wasm', - }, ], }), replace({ diff --git a/src/GrampsJs.js b/src/GrampsJs.js index 6c07a0eb..f23fa3b1 100644 --- a/src/GrampsJs.js +++ b/src/GrampsJs.js @@ -63,7 +63,6 @@ import './views/GrampsjsViewSettingsOnboarding.js' import './views/GrampsjsViewRecent.js' import './views/GrampsjsViewMap.js' import './views/GrampsjsViewTree.js' -import './views/GrampsjsViewGraph.js' import './views/GrampsjsViewNewPerson.js' import './views/GrampsjsViewNewFamily.js' import './views/GrampsjsViewNewEvent.js' @@ -597,14 +596,6 @@ export class GrampsJs extends LitElement { .strings="${this._strings}" .settings="${this.settings}" > - - d.x0 - Math.PI / 2) // shifted by 90° + .endAngle(d => d.x1 - Math.PI / 2) // shifted by 90° + .padAngle(d => Math.min((d.x1 - d.x0) / 2, (2 * padding) / radius)) + .padRadius(radius / 2) + .innerRadius(d => d.y0) + .outerRadius(d => d.y1 - padding) + + // Construct an arc generator + const arcStroke = d3arc() + .startAngle(d => d.x0 - Math.PI / 2) // shifted by 90° + .endAngle(d => d.x1 - Math.PI / 2) // shifted by 90° + .padAngle(d => Math.min((d.x1 - d.x0) / 2, (2 * padding) / radius)) + .padRadius(radius / 2) + .innerRadius(d => d.y0) + .outerRadius(d => d.y0 + 3) + + const svg = create('svg') + .attr('viewBox', [ + marginRight - marginLeft - width / 2, + marginBottom - marginTop - height / 2, + width, + height, + ]) + .attr('width', width) + .attr('height', height) + .attr('style', 'max-width: 100%; height: auto; height: intrinsic;') + .attr('font-family', 'Inter var') + .attr('font-size', 12) + .attr('text-anchor', 'middle') + + const cell = svg.selectAll('a').data(root.descendants()).join('a') + + function arcVisible(d) { + return d.name_given !== null + } + + cell + .filter(d => arcVisible(d.data)) + .append('path') + .attr('d', arc) + .attr('fill', d => (color === null ? 'rgb(150, 150, 150)' : color(d))) + .attr('fill-opacity', 0.2) + .attr('id', d => d.data.id) // Unique id for each slice + + cell + .filter(d => d.depth > 0) + .filter(d => arcVisible(d.data)) + .append('path') + .attr('d', arcStroke) + .attr('fill', d => + d.data.id.slice(-1) === 'm' ? 'var(--color-girl)' : 'var(--color-boy)' + ) + + function clicked(event, d) { + dispatchEvent( + new CustomEvent('pedigree:person-selected', { + bubbles: true, + composed: true, + detail: {grampsId: d.data?.person?.gramps_id}, + }) + ) + } + + cell + .filter(d => arcVisible(d.data)) + .style('cursor', 'pointer') + .on('click', clicked) + + const fontSize = d => Math.min(12, (((d.y0 + d.y1) / 2) * (d.x1 - d.x0)) / 10) + + const clipString = (s, d, isCenter = false) => { + const length = isCenter + ? 2 * d.y1 + : ((d.x1 - d.x0) * (d.y1 + d.y0)) / 2 - padding + const nChar = length / (fontSize(d) * 0.6) + if (s.length <= nChar) { + return s + } + if (nChar < 2) { + return '' + } + return `${s.slice(0, nChar - 2)}…` + } + + cell + .filter(d => d.depth === 0) + .append('text') + .attr('font-weight', '500') + .attr('dy', '-0.6em') + .text(d => clipString(d.data.name_surname, d, true)) + + cell + .filter(d => d.depth === 0) + .append('text') + .attr('font-weight', '300') + .attr('dy', '0.6em') + .text(d => clipString(d.data.name_given, d, true)) + + const startOffset = d => + d.x0 >= Math.PI + ? (d.y1 + d.y0 / 2) * (d.x1 - d.x0) + (d.y1 - d.y0) - 3.5 * padding + : (d.y1 * (d.x1 - d.x0)) / 2 - padding + + cell + .filter(d => d.depth > 0) + .filter(d => ((d.y0 + d.y1) / 2) * (d.x1 - d.x0) > 50) + .append('text') + .attr('font-weight', '500') + .attr('font-size', fontSize) + .attr('dy', d => (d.y1 - d.y0) / 2 - 7 + 3) + // .attr("dx", (dx => 1) + .append('textPath') // append a textPath to the text element + .attr('xlink:href', d => `#${d.data.id}`) + .style('text-anchor', 'middle') + .attr('startOffset', startOffset) + .style('letter-spacing', d => + d.x0 < Math.PI ? `${(1 / d.y1) * 20}em` : `-${(1 / d.y1) * 10}em` + ) + .text(d => clipString(d.data.name_surname || '', d)) + + cell + .filter(d => d.depth > 0) + .filter(d => ((d.y0 + d.y1) / 2) * (d.x1 - d.x0) > 50) + .append('text') + .attr('font-weight', '300') + .attr('font-size', fontSize) + .attr('dy', d => (d.y1 - d.y0) / 2 + 7 + 3) + // .attr("dx", (dx => 1) + .append('textPath') // append a textPath to the text element + .attr('xlink:href', d => `#${d.data.id}`) + .style('text-anchor', 'middle') + .attr('startOffset', startOffset) + .style('letter-spacing', d => + d.x0 < Math.PI ? `${(1 / d.y1) * 40}em` : `-${(1 / d.y1) * 15}em` + ) + .text( + d => clipString(d.data.name_given || '', d) + // .slice(0, Math.floor(d.y1 * (d.x1 - d.x0) / 10)) + ) + + return svg.node() +} diff --git a/src/charts/TreeChart.js b/src/charts/TreeChart.js new file mode 100644 index 00000000..6c2ab9e6 --- /dev/null +++ b/src/charts/TreeChart.js @@ -0,0 +1,257 @@ +import {create} from 'd3-selection' +import {hierarchy, tree} from 'd3-hierarchy' +import {curveBumpX, link, symbolTriangle, symbol} from 'd3-shape' + +export function TreeChart( + data, + { + depth = 3, + padding = 20, // horizontal padding for first and last column + gapX = 20, // horizontal gap between boxes + gapY = 5, // vertical gap between boxes + stroke = '#555', // stroke for links + strokeWidth = 1, // stroke width for links + strokeOpacity = 0.4, // stroke opacity for links + strokeLinejoin, // stroke line join for links + strokeLinecap, // stroke line cap for links + curve = curveBumpX, // curve for the link + boxWidth = 190, + boxHeight = 90, + imgPadding = 10, + childrenTriangle = true, + getImageUrl = null, + } = {} +) { + // Create a hierarchical data structure based on the input data + const root = hierarchy(data) + + const descendants = root.descendants() + + tree() + .nodeSize([boxHeight + gapY, boxWidth + gapX]) + .separation((a, b) => (a.parent === b.parent ? 1 : 1))(root) + + // Center the tree. + let x0 = Infinity + let x1 = -x0 + root.each(d => { + if (d.x > x1) x1 = d.x + if (d.x < x0) x0 = d.x + }) + + // Compute the default height. + // if (height === undefined) height = x1 - x0 + dx * 2; + + // Use the required curve + if (typeof curve !== 'function') throw new Error('Unsupported curve') + + const width = depth * boxWidth + (depth - 1) * gapX + 2 * padding + const height = boxHeight * 2 ** (depth - 1) + (2 ** (depth - 1) - 1) * gapY + + const svg = create('svg') + .attr('viewBox', [-boxWidth / 2 - padding, -height / 2, width, height]) + .attr('width', width) + .attr('height', height) + .attr('style', 'max-width: 100%; height: auto; height: intrinsic;') + .attr('font-family', 'Inter var') + .attr('font-size', 13) + + svg + .append('g') + .attr('fill', 'none') + .attr('stroke', stroke) + .attr('stroke-opacity', strokeOpacity) + .attr('stroke-linecap', strokeLinecap) + .attr('stroke-linejoin', strokeLinejoin) + .attr('stroke-width', strokeWidth) + .selectAll('path') + .data(root.links()) + .join('path') + .attr( + 'd', + link(curve) + .x(d => d.y) + .y(d => d.x) + ) + + const node = svg + .append('g') + .selectAll('a') + .data(descendants) + .join('a') + .attr('transform', d => `translate(${d.y},${d.x})`) + + node + .append('rect') + .filter(d => d.data.person) + .attr('fill', d => + d.data.id.slice(-1) === 'm' ? 'var(--color-girl)' : 'var(--color-boy)' + ) + .attr('width', 24) + .attr('height', boxHeight - 1) + .attr('rx', 12) + .attr('ry', 12) + .attr( + 'transform', + `translate(${-boxWidth / 2 - 4},${-boxHeight / 2 + 0.5})` + ) + .attr('id', d => d.data.id) // Unique id for each rect + + function clicked(event, d) { + dispatchEvent( + new CustomEvent('pedigree:person-selected', { + bubbles: true, + composed: true, + detail: {grampsId: d.data?.person?.gramps_id}, + }) + ) + } + + node + .append('rect') + .filter(d => d.data.person) + .attr('fill', 'rgba(230, 230, 230)') + .attr('width', boxWidth) + .attr('height', boxHeight) + .attr('rx', 8) + .attr('ry', 8) + .attr('transform', `translate(${-boxWidth / 2},${-boxHeight / 2})`) + .attr('id', d => d.data.id) // Unique id for each slice + + function triangleClicked(e) { + svg.node().dispatchEvent( + new CustomEvent('pedigree:show-children', { + bubbles: true, + composed: true, + detail: {pageX: e.pageX, pageY: e.pageY}, + }) + ) + e.stopPropagation() + e.preventDefault() + } + + if (childrenTriangle) { + const triangle = symbol().type(symbolTriangle).size(200) + + node + .append('path') + .filter(d => d.depth === 0) + .attr('d', triangle) + .attr( + 'transform', + d => + `translate(${d.y - boxWidth / 2 - 12},${ + d.x + }) rotate(-90) scale(-1, 0.5)` + ) + .attr('fill', '#bbb') + .attr('id', 'triangle-children') + .on('click', triangleClicked) + } + + const imgRadius = (boxHeight - imgPadding * 2) / 2 + const textPadding = d => + getImageUrl(d) ? 2 * imgRadius + 2 * imgPadding : 2 * imgPadding + + const clipString = (s, length) => { + if (!s) { + return '' + } + const fontSize = 13 + const nChar = length / (fontSize * 0.6) + if (s.length <= nChar) { + return s + } + if (nChar < 2) { + return '' + } + return `${s.slice(0, nChar - 2)}…` + } + + const textWidth = d => + getImageUrl(d) + ? boxWidth - 2 * imgPadding - 2 * imgRadius + : boxWidth - 2 * imgRadius + + node + .append('text') + .filter(d => d.data.name_surname) + .attr('y', -boxHeight / 2 + 25) + .attr('x', d => -boxWidth / 2 + textPadding(d)) + .attr('text-anchor', 'start') + .attr('font-weight', '500') + .attr('fill', 'rgba(0, 0, 0, 0.9)') + .attr('paint-order', 'stroke') + .text(d => clipString(`${d.data.name_surname},`, textWidth(d))) + + node + .append('text') + .filter(d => d.data.name_given) + .attr('y', -boxHeight / 2 + 25 + 17) + .attr('x', d => -boxWidth / 2 + textPadding(d)) + .attr('width', 50) + .attr('text-anchor', 'start') + .attr('font-weight', '500') + .attr('fill', 'rgba(0, 0, 0, 0.9)') + .attr('paint-order', 'stroke') + .attr('text-overflow', 'ellipsis') + .attr('overflow', 'hidden') + .attr('width', 25) + .text(d => clipString(d.data.name_given, textWidth(d))) + + node + .append('text') + .filter(d => d.data.person?.profile?.birth?.date) + .attr('y', -boxHeight / 2 + 25 + 17 * 2) + .attr('x', d => -boxWidth / 2 + textPadding(d)) + .attr('text-anchor', 'start') + .attr('font-weight', '350') + .attr('fill', 'rgba(0, 0, 0, 0.9)') + .attr('paint-order', 'stroke') + .text(d => clipString(`*${d.data.person.profile.birth.date}`, textWidth(d))) + + node + .append('text') + .filter(d => d.data.person?.profile?.death?.date) + .attr('y', -boxHeight / 2 + 25 + 17 * 3) + .attr('x', d => -boxWidth / 2 + textPadding(d)) + .attr('text-anchor', 'start') + .attr('font-weight', '350') + .attr('fill', 'rgba(0, 0, 0, 0.9)') + + .attr('paint-order', 'stroke') + .text(d => clipString(`†${d.data.person.profile.death.date}`, textWidth(d))) + + node + .filter(getImageUrl) + .append('circle') + .attr('r', imgRadius) + .attr('cy', -boxHeight / 2 + imgRadius + imgPadding) + .attr('cx', -boxWidth / 2 + imgRadius + imgPadding) + .attr('fill', d => `url(#imgpattern-${d.data.id})`) + + const defs = svg.append('defs') + + const imgPattern = defs + .selectAll('.imgpattern') + .data(descendants) + .enter() + .append('pattern') + .attr('id', d => `imgpattern-${d.data.id}`) + .attr('height', 1) + .attr('width', 1) + .attr('x', '0') + .attr('y', '0') + + imgPattern + .append('image') + .attr('x', 0) + .attr('y', 0) + .attr('height', 70) + .attr('width', 70) + .attr('xlink:href', getImageUrl) + + node.style('cursor', 'pointer').on('click', clicked) + + return svg.node() +} diff --git a/src/charts/util.js b/src/charts/util.js new file mode 100644 index 00000000..ffad7ed1 --- /dev/null +++ b/src/charts/util.js @@ -0,0 +1,84 @@ +// Utility functions for d3.js charts. + +import {getThumbnailUrl, getThumbnailUrlCropped} from '../api.js' + +export const getPerson = (data, handle) => + data.find(person => person.handle === handle) || {} + +export const getPersonByGrampsId = (data, grampsId) => + data.find(person => person.gramps_id === grampsId) || {} + +export const getImageUrl = (person, size, square = true) => { + if (!person.media_list || person.media_list.length === 0) { + return '' + } + const [mediaRef] = person.media_list + if (!mediaRef.rect || mediaRef.rect.length === 0) { + return getThumbnailUrl(mediaRef.ref, size, square) + } + return getThumbnailUrlCropped(mediaRef.ref, mediaRef.rect, size, square) +} + +export const getTree = ( + data, + handle, + depth, + includeEmpty = true, + i = 0, + label = 'p' +) => { + if (depth === 0) { + return {} + } + const person = getPerson(data, handle) + const tree = { + name_given: person?.profile ? person?.profile?.name_given : null, + name_surname: person?.profile ? person?.profile?.name_surname : null, + id: label, + depth: i, + person, + } + if (depth === 1) { + return tree + } + const fatherHandle = + person?.extended?.primary_parent_family?.father_handle || '' + const motherHandle = + person?.extended?.primary_parent_family?.mother_handle || '' + tree.children = [] + if (fatherHandle || includeEmpty) { + tree.children.push( + getTree(data, fatherHandle, depth - 1, includeEmpty, i + 1, `${label}f`) + ) + } + if (motherHandle || includeEmpty) { + tree.children.push( + getTree(data, motherHandle, depth - 1, includeEmpty, i + 1, `${label}m`) + ) + } + return tree +} + +export const getDescendantTree = (data, handle, depth, i = 0, label = 'p') => { + if (depth === 0) { + return {} + } + const person = getPerson(data, handle) + const tree = { + name_given: person?.profile ? person?.profile?.name_given : null, + name_surname: person?.profile ? person?.profile?.name_surname : null, + id: label, + depth: i, + person, + } + if (depth === 1) { + return tree + } + const childHandles = (person?.extended?.families || []) + .flatMap(fam => fam.child_ref_list) + .map(cref => cref.ref) + tree.children = childHandles.map((childHandle, childInd) => + getTree(data, childHandle, depth - 1, false, i + 1, `${label}c${childInd}`) + ) + return tree +} diff --git a/src/components/GrampsjsFanChart.js b/src/components/GrampsjsFanChart.js new file mode 100644 index 00000000..c8f418c7 --- /dev/null +++ b/src/components/GrampsjsFanChart.js @@ -0,0 +1,69 @@ +import {html, css, LitElement} from 'lit' + +import {sharedStyles} from '../SharedStyles.js' +import {GrampsjsTranslateMixin} from '../mixins/GrampsjsTranslateMixin.js' +import {FanChart} from '../charts/FanChart.js' +import {getPersonByGrampsId, getTree} from '../charts/util.js' + +class GrampsjsFanChart extends GrampsjsTranslateMixin(LitElement) { + static get styles() { + return [ + sharedStyles, + css` + svg a { + text-decoration: none !important; + } + + div#container { + display: flex; + justify-content: center; + align-items: center; + } + `, + ] + } + + static get properties() { + return { + grampsId: {type: String}, + depth: {type: Number}, + data: {type: Array}, + } + } + + constructor() { + super() + this.grampsId = '' + this.depth = 5 + this.data = [] + } + + render() { + if (this.data.length === 0 || !this.grampsId) { + return '' + } + return html`${this.renderChart()}` + } + + renderChart() { + const {handle} = getPersonByGrampsId(this.data, this.grampsId) + if (!handle) { + return '' + } + const data = getTree(this.data, handle, this.depth) + const radius = this.depth * 60 + const margin = 5 + return html` +
+ ${FanChart(data, { + margin, + radius, + width: 2 * radius + margin, + height: 2 * radius + margin, + })} +
+ ` + } +} + +window.customElements.define('grampsjs-fan-chart', GrampsjsFanChart) diff --git a/src/components/GrampsjsGraph.js b/src/components/GrampsjsGraph.js deleted file mode 100644 index cfb9b812..00000000 --- a/src/components/GrampsjsGraph.js +++ /dev/null @@ -1,591 +0,0 @@ -/* eslint-disable lit-a11y/click-events-have-key-events */ -import {html, css, LitElement} from 'lit' - -import * as hpccWasm from '@hpcc-js/wasm' - -import '@material/mwc-dialog' -import '@material/mwc-icon' -import '@material/mwc-icon-button' -import '@material/mwc-list/mwc-list-item' - -import {sharedStyles} from '../SharedStyles.js' -import {fireEvent} from '../util.js' -import {GrampsjsTranslateMixin} from '../mixins/GrampsjsTranslateMixin.js' - -// transform 2D coordinates (x, y) to SVG coordinates. -// element can be the SVG itself or an element within it -// (possibly transformed) -function transformSvgCoords(svg, element, x, y) { - const point = svg.createSVGPoint() - point.x = x - point.y = y - const invertedSVGMatrix = element.getScreenCTM().inverse() - return point.matrixTransform(invertedSVGMatrix) -} - -// get a point in SVG coordinates from an event -function getPointFromEvent(svg, event) { - return transformSvgCoords(svg, svg, event.clientX, event.clientY) -} - -const _zoomDefault = 0.7 - -class GrampsjsGraph extends GrampsjsTranslateMixin(LitElement) { - static get styles() { - return [ - sharedStyles, - css` - :host { - width: 100%; - height: 100%; - } - - #controls { - z-index: 1; - position: absolute; - top: 85px; - left: 15px; - border-radius: 5px; - background-color: rgba(255, 255, 255, 0.9); - } - - #controls mwc-icon-button { - color: rgba(0, 0, 0, 0.3); - --mdc-icon-size: 26px; - --mdc-theme-text-disabled-on-light: rgba(0, 0, 0, 0.1); - } - - #graph { - width: 100%; - height: 100%; - overflow: hidden; - background-color: rgb(230, 230, 230); - } - - #graph svg text { - font-family: var(--grampsjs-body-font-family); - } - - #graph svg { - height: 100%; - width: 100%; - position: relative; - left: 0; - top: 0; - touch-action: none; - } - - #graph svg .edge path { - stroke-width: 1.5px; - stroke: #666; - } - - #graph svg .edge polygon { - fill: #666; - stroke: #666; - stroke-width: 0; - } - - g.node polygon, - g.node path, - g.node ellipse { - fill: #ffffff; - } - - g.node ellipse { - stroke: none; - } - - g#node1 polygon { - fill: #64b5f6; - } - - g#node1 path { - fill: #ef9a9a; - } - - g.node text { - font-weight: 400; - font-size: 13px; - } - - g.node text:last-of-type { - font-weight: 300; - font-size: 12px; - } - - g.node polygon, - g.node path, - g.node text { - cursor: pointer; - } - - g.node polygon, - g.node path, - g.node ellipse { - stroke-width: 1.5px; - } - - svg { - cursor: grab; - } - - mwc-dialog mwc-icon-button { - vertical-align: middle; - } - `, - ] - } - - static get properties() { - return { - src: {type: String}, - scale: {type: Number}, - disableBack: {type: Boolean}, - disableHome: {type: Boolean}, - nAnc: {type: Number}, - nDesc: {type: Number}, - _svg: {type: Object}, - _svgPointerDown: {type: Boolean}, - _zoomInPointerDown: {type: Boolean}, - _zoomOutPointerDown: {type: Boolean}, - _pointerOrigin: {type: Object}, - _interval: {type: Object}, - _evcache: {type: Array}, - _prevDiff: {type: Number}, - } - } - - constructor() { - super() - this.src = '' - this.scale = _zoomDefault - this.disableBack = false - this.disableHome = false - this._svgPointerDown = false - this._zoomInPointerDown = false - this._zoomOutPointerDown = false - this._evCache = [] - this._prevDiff = -1 - } - - render() { - return html` -
-
${this._renderControls()}
- ` - } - - _renderControls() { - return html` -
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - -

- ${this._('Max Ancestor Generations')}: - ${this.nAnc} - - - -

-

- ${this._('Max descendant Generations')}: - ${this.nDesc} - - - -

- ${this._('done')} - ${this._('Reset')} -
-
- ` - } - - _resetLevels() { - fireEvent(this, 'tree:setNAnc', {data: 3}) - fireEvent(this, 'tree:setNDesc', {data: 1}) - } - - _increaseNAnc() { - fireEvent(this, 'tree:increaseNAnc') - } - - _decreaseNAnc() { - fireEvent(this, 'tree:decreaseNAnc') - } - - _increaseNDesc() { - fireEvent(this, 'tree:increaseNDesc') - } - - _decreaseNDesc() { - fireEvent(this, 'tree:decreaseNDesc') - } - - _backToHomePerson() { - fireEvent(this, 'tree:home') - } - - _goToPerson() { - fireEvent(this, 'tree:person') - } - - _handleBack() { - fireEvent(this, 'tree:back') - } - - _zoomIn(f) { - this.scale *= f - } - - // zoom in when mouse clicked/touch starts - _zoomInDown() { - this._zoomIn(1.1) - this._zoomInPointerDown = true - setTimeout(() => { - if (this._zoomInPointerDown) { - this._interval = setInterval(() => { - if (this._zoomInPointerDown) { - this._zoomIn(1.04) - } - }, 20) - } - }, 700) - } - - // stop zooming in - _zoomInUp() { - this._zoomInPointerDown = false - clearInterval(this._interval) - } - - _zoomOut(f) { - this.scale /= f - } - - // zoom out when mouse clicked/touch starts - _zoomOutDown() { - this._zoomOut(1.1) - this._zoomOutPointerDown = true - setTimeout(() => { - if (this._zoomOutPointerDown) { - this._interval = setInterval(() => { - if (this._zoomOutPointerDown) { - this._zoomOut(1.04) - } - }, 20) - } - }, 700) - } - - // stop zooming out - _zoomOutUp() { - this._zoomOutPointerDown = false - clearInterval(this._interval) - } - - _resetZoom() { - this.scaleSvg(_zoomDefault) - this.centerSvg() - this.scale = _zoomDefault - } - - // click: find out if it is a person node: has title and no ellipse - _handleClick(event) { - const g = event.target.closest('g') - if (g !== null) { - const title = g.querySelector('title') - if (title.innerHTML && g.querySelector('ellipse') === null) { - // set new person gramps ID - return this._personSelected(title.innerHTML) - } - } - return null - } - - update(changed) { - super.update(changed) - if (changed.has('src')) { - this._renderGraph() - } - } - - updated(changed) { - if (changed.has('scale')) { - if (this._svg !== undefined) { - this.scaleSvg(this.scale) - } - } - } - - _renderGraph() { - hpccWasm.graphvizSync().then(graphviz => { - const div = this.shadowRoot.getElementById('graph') - if (div === null) { - return - } - div.innerHTML = graphviz.layout(this.src, 'svg', 'dot') - this._svg = this.shadowRoot.querySelector('svg') - if (this._svg === null) { - return - } - this._svg.querySelector('polygon[fill="white"]').style.fill = 'none' - // use arrow functions to bind correct 'this' - this._svg.addEventListener('pointerup', e => this._pUp(e)) - this._svg.addEventListener('pointerleave', e => this._pUp(e)) - this._svg.addEventListener('pointerdown', e => this._pDown(e)) - this._svg.addEventListener('pointermove', e => this._pMove(e)) - this._svg.addEventListener('wheel', e => this._wheel(e)) - this._svg.addEventListener('dblclick', e => this._dblclick(e)) - this.scaleSvg(this.scale) - this.centerSvg() - }) - } - - _dblclick(e) { - this._zoomIn(1.3) - e.preventDefault() - e.stopPropagation() - } - - // wheel zoom - _wheel(event) { - this.scale *= 1 - event.deltaY / 500 - } - - // start panning - _pDown(event) { - if (this._svg === undefined) { - return - } - this._svgPointerDown = true - this._pointerOrigin = getPointFromEvent(this._svg, event) - this._svg.style.cursor = 'grabbing' - // event cache for pinch zoom - this._evCache.push(event) - } - - _pMove(event) { - if (!this._svgPointerDown) { - return - } - // code for panning - event.preventDefault() - // code for pich zoom - for (let i = 0; i < this._evCache.length; i += 1) { - if (event.pointerId === this._evCache[i].pointerId) { - this._evCache[i] = event - break - } - } - // If two pointers are down, check for pinch gestures - if (this._evCache.length === 2) { - // Calculate the distance between the two pointers - const curDiff = Math.hypot( - this._evCache[0].clientX - this._evCache[1].clientX, - this._evCache[0].clientY - this._evCache[1].clientY - ) - - if (this._prevDiff > 0) { - const oldScale = this.scale - if (curDiff > this._prevDiff) { - // The distance between the two pointers has increased - } - if (curDiff < this._prevDiff) { - // The distance between the two pointers has decreased - } - this.scale = (oldScale * curDiff) / this._prevDiff - } - // Cache the distance for the next move event - this._prevDiff = curDiff - } else { - // code for panning - const pointerPosition = getPointFromEvent(this._svg, event) - const viewBox = this._svg.viewBox.baseVal - viewBox.x -= pointerPosition.x - this._pointerOrigin.x - viewBox.y -= pointerPosition.y - this._pointerOrigin.y - } - } - - removeEvent(ev) { - // Remove this event from the target's cache - for (let i = 0; i < this._evCache.length; i += 1) { - if (this._evCache[i].pointerId === ev.pointerId) { - this._evCache.splice(i, 1) - break - } - } - } - - // stop panning - _pUp(event) { - this._svgPointerDown = false - this._svg.style.cursor = 'grab' - // Remove this pointer from the cache and reset the target's - // background and border - this.removeEvent(event) - // If the number of pointers down is less than two then reset diff tracker - if (this._evCache.length < 2) { - this._prevDiff = -1 - } - } - - scaleSvg(s) { - const viewBox = this._svg.viewBox.baseVal - const container = this.shadowRoot.querySelector('#graph') - const bb = container.getBoundingClientRect() - const pt = 4 / 3 - const wOld = viewBox.width - const hOld = viewBox.height - viewBox.width = bb.width / pt / s - viewBox.height = bb.height / pt / s - // shift to scale around viewBox center - viewBox.x += (wOld - viewBox.width) / 2 - viewBox.y += (hOld - viewBox.height) / 2 - } - - centerSvg() { - const bbox = this._svg.getBBox() - const viewBox = this._svg.viewBox.baseVal - viewBox.x = bbox.x + bbox.width / 2 - viewBox.width / 2 - viewBox.y = bbox.y + bbox.height / 2 - viewBox.height / 2 - } - - // center the element given by selector in the center of the parent - // container - centerSvgOn(selectorString) { - const el = this.shadowRoot.querySelector(selectorString) - const cont = this.shadowRoot.querySelector('#graph') - if (el === null) { - return - } - const bbTarget = el.getBoundingClientRect() - const bbCont = cont.getBoundingClientRect() - const xCenterPxOld = bbTarget.left + bbTarget.width / 2 - const yCenterPxOld = bbTarget.bottom + bbTarget.height / 2 - const pointOld = transformSvgCoords( - this._svg, - this._svg, - xCenterPxOld, - yCenterPxOld - ) - const xCenterPxNew = bbCont.left + bbCont.width / 2 - const yCenterPxNew = bbCont.top + bbCont.height / 2 - const pointNew = transformSvgCoords( - this._svg, - this._svg, - xCenterPxNew, - yCenterPxNew - ) - const dx = pointNew.x - pointOld.x - const dy = pointNew.y - pointOld.y - const viewBox = this._svg.viewBox.baseVal - viewBox.x += -dx - viewBox.y += -dy - } - - _openMenuControls() { - const menu = this.shadowRoot.getElementById('menu-controls') - menu.open = true - } - - _handleResize() { - this.scaleSvg(this.scale) - } - - connectedCallback() { - super.connectedCallback() - window.addEventListener('resize', () => this._handleResize()) - } - - disconnectedCallback() { - window.removeEventListener('resize', () => this._handleResize()) - super.disconnectedCallback() - } - - _personSelected(grampsId) { - this.dispatchEvent( - new CustomEvent('pedigree:person-selected', { - bubbles: true, - composed: true, - detail: {grampsId}, - }) - ) - } -} - -window.customElements.define('grampsjs-graph', GrampsjsGraph) diff --git a/src/components/GrampsjsPedigree.js b/src/components/GrampsjsPedigree.js deleted file mode 100644 index d9d334a3..00000000 --- a/src/components/GrampsjsPedigree.js +++ /dev/null @@ -1,226 +0,0 @@ -import {html, css, LitElement} from 'lit' - -import {sharedStyles} from '../SharedStyles.js' -import './GrampsjsPedigreeCard.js' - -class GrampsjsPedigree extends LitElement { - static get styles() { - return [ - sharedStyles, - css` - div#container { - position: relative; - } - - div.card { - position: absolute; - } - - div.branch-right, - div.branch-left { - position: absolute; - border-color: #aaa; - border-style: solid; - border-width: 0px; - } - - div.branch-right.male { - border-top-left-radius: 15px; - border-left-width: 1px; - border-top-width: 1px; - } - - div.branch-right.female { - border-bottom-left-radius: 15px; - border-left-width: 1px; - border-bottom-width: 1px; - } - - div.branch-left.male { - border-bottom-width: 1px; - } - - div.branch-left.female { - border-top-width: 1px; - } - - div.icon svg path { - fill: #ccc; - } - - .gray { - color: #aaa; - } - `, - ] - } - - static get properties() { - return { - grampsId: {type: String}, - people: {type: Array}, - depth: {type: Number}, - } - } - - constructor() { - super() - this.people = [] - this.depth = 4 - } - - render() { - const ancestors = this._getTree() - const children = this._getChildren() - return html` -
- ${ancestors.map((g, i) => - i > this.depth - 1 - ? '' - : html` - ${g.map((p, j) => - Object.keys(p).length - ? html` -
- - - ${i === 0 - ? '' - : html` -
-
- `} -
- ` - : '' - )} - ` - )} - ${children.map((p, i) => - Object.keys(p).length - ? html` -
-  ${p.profile?.name_given || '…'} -
- ` - : '' - )} -
- ` - } - - _getTree() { - const ancestors = [] - ancestors.push([this._getPerson(this.grampsId)]) - if (this.depth === 1) { - return ancestors - } - ancestors.push(this._getParents(this.grampsId)) - if (this.depth === 2) { - return ancestors - } - for (let i = 3; i <= this.depth; i += 1) { - ancestors.push( - ancestors - .slice(-1)[0] - .map(p => this._getParents(p.gramps_id)) - .flat() - ) - } - return ancestors - } - - _getPerson(grampsId) { - return this.people.find(person => person.gramps_id === grampsId) || {} - } - - _getPersonByHandle(handle) { - return this.people.find(person => person.handle === handle) || {} - } - - _getParents(grampsId) { - const person = this._getPerson(grampsId) - const fatherHandle = - person?.profile?.primary_parent_family?.father?.handle || {} - const motherHandle = - person?.profile?.primary_parent_family?.mother?.handle || {} - const father = this._getPersonByHandle(fatherHandle) || {} - const mother = this._getPersonByHandle(motherHandle) || {} - return [father, mother] - } - - _getChildren() { - const person = this._getPerson(this.grampsId) - const families = person?.profile?.families || [] - const childHandles = families.map(family => - (family.children || []).map(child => child.handle) - ) - return childHandles - .flat() - .filter(h => h !== undefined) - .map(this._getPersonByHandle, this) - } - - _personSelected(person) { - this.dispatchEvent( - new CustomEvent('pedigree:person-selected', { - bubbles: true, - composed: true, - detail: {grampsId: person.gramps_id}, - }) - ) - } -} - -window.customElements.define('grampsjs-pedigree', GrampsjsPedigree) diff --git a/src/components/GrampsjsTreeChart.js b/src/components/GrampsjsTreeChart.js new file mode 100644 index 00000000..7a1ff416 --- /dev/null +++ b/src/components/GrampsjsTreeChart.js @@ -0,0 +1,160 @@ +import {html, css, LitElement} from 'lit' + +import '@material/mwc-menu' +import '@material/mwc-list/mwc-list-item' + +import {sharedStyles} from '../SharedStyles.js' +import {GrampsjsTranslateMixin} from '../mixins/GrampsjsTranslateMixin.js' +import {TreeChart} from '../charts/TreeChart.js' +import { + getDescendantTree, + getPersonByGrampsId, + getTree, + getImageUrl, +} from '../charts/util.js' +import {fireEvent, clickKeyHandler} from '../util.js' + +class GrampsjsTreeChart extends GrampsjsTranslateMixin(LitElement) { + static get styles() { + return [ + sharedStyles, + css` + svg a { + text-decoration: none !important; + } + + div#container { + display: flex; + justify-content: center; + align-items: center; + } + + mwc-menu { + --mdc-typography-subtitle1-font-size: 13px; + --mdc-menu-item-height: 36px; + } + `, + ] + } + + static get properties() { + return { + grampsId: {type: String}, + depth: {type: Number}, + data: {type: Array}, + } + } + + constructor() { + super() + this.grampsId = '' + this.depth = 5 + this.data = [] + } + + render() { + if (this.data.length === 0 || !this.grampsId) { + return '' + } + return html` +
+ ${this.renderChart()} ${this.renderChildrenMenu()} +
+ ` + } + + renderChart() { + const {handle} = getPersonByGrampsId(this.data, this.grampsId) + if (!handle) { + return '' + } + const data = getTree(this.data, handle, this.depth, false) + return html` +
+ ${TreeChart(data, { + depth: this.depth, + childrenTriangle: this._hasChildren(), + getImageUrl: d => getImageUrl(d?.data?.person || {}, 200), + })} +
+ ` + } + + _hasChildren() { + const {handle} = getPersonByGrampsId(this.data, this.grampsId) + const data = getDescendantTree(this.data, handle, 2) + if (data.children && data.children.length) { + return true + } + return false + } + + renderChildrenMenu() { + const {handle} = getPersonByGrampsId(this.data, this.grampsId) + const data = getDescendantTree(this.data, handle, 2) + const {children} = data + if (!children || !children.length) { + return '' + } + return html` + + ${children.map( + child => + html` + this._handleChild(child.person.gramps_id)} + @keydown=${clickKeyHandler} + >${child.name_given || html`$hellip;`} + ` + )} + + ` + } + + _handleChild(grampsId) { + fireEvent(this, 'pedigree:person-selected', {grampsId}) + this._closeMenu() + } + + _handleShowChildren() { + const triangle = this.renderRoot.querySelector('#triangle-children') + if (triangle !== null) { + this._openMenu() + } + } + + _openMenu() { + const menu = this.renderRoot.querySelector('mwc-menu') + if (menu !== null) { + menu.open = true + } + } + + _closeMenu() { + const menu = this.renderRoot.querySelector('mwc-menu') + if (menu !== null) { + menu.open = false + } + } + + update(changed) { + super.update(changed) + if (changed.has('data')) { + this._updateMenuAnchor() + } + } + + _updateMenuAnchor() { + const menu = this.renderRoot.querySelector('mwc-menu') + const triangle = this.renderRoot.querySelector('#triangle-children') + if (menu !== null && triangle !== null) { + menu.anchor = triangle + } + } +} + +window.customElements.define('grampsjs-tree-chart', GrampsjsTreeChart) diff --git a/src/icons.js b/src/icons.js index d3a3a7d4..5572239b 100644 --- a/src/icons.js +++ b/src/icons.js @@ -60,6 +60,8 @@ export const filePdfIcon = html` d="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2M10.1,11.4C10.08,11.44 9.81,13.16 8,16.09C8,16.09 4.5,17.91 5.33,19.27C6,20.35 7.65,19.23 9.07,16.59C9.07,16.59 10.89,15.95 13.31,15.77C13.31,15.77 17.17,17.5 17.7,15.66C18.22,13.8 14.64,14.22 14,14.41C14,14.41 12,13.06 11.5,11.2C11.5,11.2 12.64,7.25 10.89,7.3C9.14,7.35 9.8,10.43 10.1,11.4M10.91,12.44C10.94,12.45 11.38,13.65 12.8,14.9C12.8,14.9 10.47,15.36 9.41,15.8C9.41,15.8 10.41,14.07 10.91,12.44M14.84,15.16C15.42,15 17.17,15.31 17.1,15.64C17.04,15.97 14.84,15.16 14.84,15.16M7.77,17C7.24,18.24 6.33,19 6.1,19C5.87,19 6.8,17.4 7.77,17M10.91,10.07C10.91,10 10.55,7.87 10.91,7.92C11.45,8 10.91,10 10.91,10.07Z" /> ` +export const chartFanIconPath = + 'm13 2.0742v3.0469a7 7 0 0 1 5.9434 5.8789h3.0059a10 10 0 0 0-8.9492-8.9258zm-2 0.0019531a10 10 0 0 0-8.9277 8.9238h3.0508a7 7 0 0 1 5.877-5.873v-3.0508zm1 4.5605a5.3638 5.3638 0 0 0-5.2852 4.4688h2.7754a2.6819 2.6819 0 0 1 2.5098-1.7871 2.6819 2.6819 0 0 1 2.5273 1.7871h2.7598a5.3638 5.3638 0 0 0-5.2871-4.4688zm-5.2852 6.2578a5.3638 5.3638 0 0 0 5.2852 4.4688 5.3638 5.3638 0 0 0 5.2852-4.4688h-2.7754a2.6819 2.6819 0 0 1-2.5098 1.7871 2.6819 2.6819 0 0 1-2.5098-1.7871h-2.7754zm-4.6426 0.10547a10 10 0 0 0 8.9277 8.9238v-2.9863a7 7 0 0 1-5.8828-5.9375h-3.0449zm16.877 0a7 7 0 0 1-5.9492 5.9434v2.9805a10 10 0 0 0 8.9277-8.9238h-2.9785z' export function renderIcon(path, color = '#999999') { return html` + + ` + } +} + +window.customElements.define('grampsjs-view-fan-chart', GrampsjsViewFanChart) diff --git a/src/views/GrampsjsViewGraph.js b/src/views/GrampsjsViewGraph.js deleted file mode 100644 index 4e576896..00000000 --- a/src/views/GrampsjsViewGraph.js +++ /dev/null @@ -1,154 +0,0 @@ -import {html, css} from 'lit' - -import {GrampsjsView} from './GrampsjsView.js' -import '../components/GrampsjsGraph.js' -import {apiGet} from '../api.js' -import {fireEvent} from '../util.js' - -export class GrampsjsViewGraph extends GrampsjsView { - static get styles() { - return [ - super.styles, - css` - :host { - margin: 0; - margin-top: -4px; - } - - #outer-container { - height: calc(100vh - 68px); - } - `, - ] - } - - static get properties() { - return { - grampsId: {type: String}, - disableBack: {type: Boolean}, - disableHome: {type: Boolean}, - nAnc: {type: Number}, - nDesc: {type: Number}, - _data: {type: Array}, - _graph: {type: String}, - } - } - - constructor() { - super() - this.grampsId = '' - this._data = [] - this.nAnc = 3 - this.nDesc = 1 - this.disableBack = false - this.disableHome = false - this._graph = '' - } - - renderContent() { - return html` -
- this._changeNAnc(1)} - @tree:decreaseNAnc=${() => this._changeNAnc(-1)} - @tree:increaseNDesc=${() => this._changeNDesc(1)} - @tree:decreaseNDesc=${() => this._changeNDesc(-1)} - @tree:setNAnc=${this._setNAnc} - @tree:setNDesc=${this._setNDesc} - > - -
- ` - } - - _changeNAnc(n) { - if (n === 0 || this.nAnc + n < 0) { - return - } - this.nAnc += n - this._fetchData(this.grampsId) - } - - _setNAnc(event) { - this.nAnc = event.detail.data - this._fetchData(this.grampsId) - } - - _changeNDesc(n) { - if (n === 0 || this.nDesc + n < 0) { - return - } - this.nDesc += n - this._fetchData(this.grampsId) - } - - _setNDesc(event) { - this.nDesc = event.detail.data - this._fetchData(this.grampsId) - } - - _goToPerson() { - fireEvent(this, 'nav', {path: `person/${this.grampsId}`}) - } - - update(changed) { - super.update(changed) - if (changed.has('grampsId')) { - this._fetchData(this.grampsId) - } - } - - async _fetchData(grampsId) { - this.loading = true - const options = { - off: 'dot', - ratio: 'compress', - papermb: '0', - papermt: '0', - paperml: '0', - papermr: '0', - pid: grampsId, - maxascend: `${this.nAnc}`, - maxdescend: `${this.nDesc}`, - color: 'colored', - colormales: '#64B5F6', - colorfemales: '#EF9A9A', - colorfamilies: '#000000', - roundcorners: 'True', - papers: 'A0', - arrow: '', - // ranksep: '0.3' - } - const data = await apiGet( - `/api/reports/hourglass_graph/file?options=${encodeURIComponent( - JSON.stringify(options) - )}`, - false - ) - this.loading = false - if ('data' in data) { - this._graph = data.data.replace('()', '') - } else if ('error' in data) { - this.error = true - this._errorMessage = data.error - this._graph = '' - } - } - - _resizeHandler() { - clearTimeout(this._resizeTimer) - } - - firstUpdated() { - window.addEventListener('resize', this._resizeHandler.bind(this)) - this._fetchData(this.grampsId) - } -} - -window.customElements.define('grampsjs-view-graph', GrampsjsViewGraph) diff --git a/src/views/GrampsjsViewPedigree.js b/src/views/GrampsjsViewPedigree.js deleted file mode 100644 index 8b2bc247..00000000 --- a/src/views/GrampsjsViewPedigree.js +++ /dev/null @@ -1,291 +0,0 @@ -import {html, css} from 'lit' -import '@material/mwc-slider' -import '@material/mwc-button' -import '@material/mwc-icon' - -import {GrampsjsView} from './GrampsjsView.js' -import '../components/GrampsjsPedigree.js' -import {apiGet} from '../api.js' -import {fireEvent} from '../util.js' - -export class GrampsjsViewPedigree extends GrampsjsView { - static get styles() { - return [ - super.styles, - css` - mwc-slider { - --mdc-theme-secondary: #4fc3f7; - } - - #button-block { - float: left; - position: relative; - top: 10px; - } - - #pedigree-container { - clear: left; - } - - mwc-button { - --mdc-ripple-focus-opacity: 0; - --mdc-theme-primary: rgba(0, 0, 0, 0.7); - } - - #outer-container { - clear: left; - padding-top: 30px; - padding-left: 30px; - } - - #controls { - z-index: 1; - position: absolute; - top: 85px; - left: 15px; - border-radius: 5px; - background-color: rgba(255, 255, 255, 0.9); - } - - #controls mwc-icon-button { - color: rgba(0, 0, 0, 0.3); - --mdc-icon-size: 26px; - --mdc-theme-text-disabled-on-light: rgba(0, 0, 0, 0.1); - } - - #menu-controls mwc-list-item { - --mdc-ripple-color: transparent; - } - - mwc-slider { - padding: 15px; - padding-top: 50px; - } - - mwc-list-item.slider { - --mdc-menu-item-height: 70px; - } - `, - ] - } - - static get properties() { - return { - grampsId: {type: String}, - disableBack: {type: Boolean}, - disableHome: {type: Boolean}, - _data: {type: Array}, - _depth: {type: Number}, - _zoom: {type: Number}, - _history: {type: Array}, - } - } - - constructor() { - super() - this.grampsId = '' - this.disableBack = false - this.disableHome = false - this._data = [] - this._depth = 3 - this._zoom = 1 - this._history = [] - } - - renderContent() { - if (this._data.length === 0) { - return html` ${this._renderControls()} ` - } - return html` -
-
-
- -
-
- - ${this._renderControls()} -
- ` - } - - _renderControls() { - return html`
-
- -
-
- -
-
- - -

- ${this._('Max Ancestor Generations')}: - ${this._depth} - - - -

- ${this._('done')} - ${this._('Reset')} -
-
-
` - } - - _openMenuControls() { - const menu = this.shadowRoot.getElementById('menu-controls') - menu.open = true - } - - _backToHomePerson() { - fireEvent(this, 'tree:home') - } - - _prevPerson() { - fireEvent(this, 'tree:back') - } - - update(changed) { - super.update(changed) - if (changed.has('grampsId')) { - this._fetchData(this.grampsId) - // this._history.push(this.grampsId) - // limit history to 100 people - // this._history = this._history.slice(-100) - } - if (changed.has('_depth')) { - this.setZoom() - this._fetchData(this.grampsId) - } - if (changed.has('active')) { - this.setZoom() - const slider = this.shadowRoot.getElementById('slider') - if (slider) { - slider.layout() - } - } - } - - async _fetchData(grampsId) { - this.loading = true - const rules = { - function: 'or', - rules: [ - { - name: 'IsLessThanNthGenerationAncestorOf', - values: [grampsId, this._depth || 1], - }, - { - name: 'IsLessThanNthGenerationDescendantOf', - values: [grampsId, 1], - }, - ], - } - const data = await apiGet( - `/api/people/?rules=${encodeURIComponent(JSON.stringify(rules))}&locale=${ - this.strings?.__lang__ || 'en' - }&profile=self,families` - ) - this.loading = false - if ('data' in data) { - this.error = false - this._data = data.data - } else if ('error' in data) { - this.error = true - this._errorMessage = data.error - } - } - - _increaseDepth() { - this._depth += 1 - } - - _decreaseDepth() { - this._depth -= 1 - } - - _resetLevels() { - this._depth = 3 - } - - getZoom() { - const sec = this.shadowRoot.getElementById('pedigree-section') - if (sec === null) { - return 1 - } - const secWidth = sec.offsetWidth - const treeWidth = this._depth * 230 * this._zoom - const newZoom = ((secWidth - 24) / treeWidth) * this._zoom - if (newZoom > 1) { - return 1 - } - if (newZoom < 0.2) { - return 0.2 - } - return newZoom - } - - setZoom() { - this._zoom = this.getZoom() - } - - _resizeHandler() { - clearTimeout(this._resizeTimer) - this._resizeTimer = setTimeout(this.setZoom.bind(this), 250) - } - - firstUpdated() { - window.addEventListener('resize', this._resizeHandler.bind(this)) - // window.addEventListener('pedigree:person-selected', this._selectPerson.bind(this)) - this.setZoom() - this._fetchData(this.grampsId) - const btn = this.shadowRoot.getElementById('btn-controls') - const menu = this.shadowRoot.getElementById('menu-controls') - menu.anchor = btn - } - - async _selectPerson(event) { - const {grampsId} = event.detail - await this._fetchData(grampsId) - this.grampsId = grampsId - } -} - -window.customElements.define('grampsjs-view-pedigree', GrampsjsViewPedigree) diff --git a/src/views/GrampsjsViewTree.js b/src/views/GrampsjsViewTree.js index f2bc5843..c699eef6 100644 --- a/src/views/GrampsjsViewTree.js +++ b/src/views/GrampsjsViewTree.js @@ -2,20 +2,23 @@ import {css, html} from 'lit' import '@material/mwc-icon-button' import '@material/mwc-icon' +import '@material/mwc-tab-bar' +import '@material/mwc-tab' +import {mdiFamilyTree} from '@mdi/js' import {GrampsjsView} from './GrampsjsView.js' -import './GrampsjsViewGraph.js' -import './GrampsjsViewPedigree.js' +import './GrampsjsViewTreeChart.js' +import './GrampsjsViewFanChart.js' import {fireEvent} from '../util.js' +import {chartFanIconPath, renderIconSvg} from '../icons.js' export class GrampsjsViewTree extends GrampsjsView { static get styles() { return [ super.styles, css` - :host { - margin: 0; - margin-top: -4px; + mwc-tab-bar { + margin-bottom: 20px; } .with-margin { @@ -37,6 +40,14 @@ export class GrampsjsViewTree extends GrampsjsView { --mdc-theme-text-disabled-on-light: #666; --mdc-icon-size: 32px; } + + mwc-tab { + opacity: 0.8; + } + + mwc-tab[active] { + opacity: 1; + } `, ] } @@ -46,14 +57,16 @@ export class GrampsjsViewTree extends GrampsjsView { grampsId: {type: String}, view: {type: String}, _history: {type: Array}, + _currentTabId: {type: Number}, } } constructor() { super() this.grampsId = '' - this.view = 'pedigree' + this.view = 'ancestor' this._history = this.grampsId ? [this.grampsId] : [] + this._currentTabId = 0 } renderContent() { @@ -68,37 +81,49 @@ export class GrampsjsViewTree extends GrampsjsView { ` } return html` - ${this.view === 'pedigree' ? this._renderPedigree() : ''} - ${this.view === 'graph' ? this._renderGraph() : ''} - ${this._renderSelect()} + ${this.renderTabs()} + ${this._currentTabId === 0 ? this._renderPedigree() : ''} + ${this._currentTabId === 1 ? this._renderFan() : ''} ` } - _renderSelect() { + renderTabs() { return html` -
- + { - this.view = 'pedigree' + this._currentTabId = 0 }} - icon="text_rotation_none" - style="margin-left: -5px;" - > - ${renderIconSvg(mdiFamilyTree, 'var(--mdc-theme-primary)')} + + { - this.view = 'graph' + this._currentTabId = 1 }} - icon="text_rotate_vertical" - > -
+ hasImageIcon + label="${this._('Fan Chart')}" + >${renderIconSvg( + chartFanIconPath, + 'var(--mdc-theme-primary)' + )} + + ` } - _renderPedigree() { + _renderFan() { return html` - - + ` } - _renderGraph() { + _renderPedigree() { return html` - - + ` } - _handleSelect(event) { - if (event.detail.index === 0) { - this.view = 'pedigree' - } else if (event.detail.index === 1) { - this.view = 'graph' - } - } - _prevPerson() { this._history.pop() this.grampsId = this._history.pop() @@ -172,6 +189,14 @@ export class GrampsjsViewTree extends GrampsjsView { const {grampsId} = event.detail this.grampsId = grampsId } + + _handleTabActivated(event) { + this._currentTabId = event.detail.index + } + + _handleTabInteracted(event) { + this._currentTab = event.detail.tabId + } } window.customElements.define('grampsjs-view-tree', GrampsjsViewTree) diff --git a/src/views/GrampsjsViewTreeChart.js b/src/views/GrampsjsViewTreeChart.js new file mode 100644 index 00000000..19a38d69 --- /dev/null +++ b/src/views/GrampsjsViewTreeChart.js @@ -0,0 +1,31 @@ +import {html} from 'lit' + +import {GrampsjsViewTreeChartBase} from './GrampsjsViewTreeChartBase.js' +import '../components/GrampsjsTreeChart.js' + +export class GrampsjsViewTreeChart extends GrampsjsViewTreeChartBase { + constructor() { + super() + this.nAnc = 3 + this.nDesc = 1 + this._setDesc = false + } + + _resetLevels() { + this.nAnc = 3 + } + + renderChart() { + return html` + + + ` + } +} + +window.customElements.define('grampsjs-view-tree-chart', GrampsjsViewTreeChart) diff --git a/src/views/GrampsjsViewTreeChartBase.js b/src/views/GrampsjsViewTreeChartBase.js new file mode 100644 index 00000000..bf1e9527 --- /dev/null +++ b/src/views/GrampsjsViewTreeChartBase.js @@ -0,0 +1,216 @@ +import {css, html} from 'lit' + +import '@material/mwc-textfield' + +import {mdiAccountDetails, mdiHomeAccount} from '@mdi/js' +import {GrampsjsView} from './GrampsjsView.js' +import {apiGet} from '../api.js' +import {fireEvent} from '../util.js' +import {renderIcon} from '../icons.js' + +export class GrampsjsViewTreeChartBase extends GrampsjsView { + static get styles() { + return [ + super.styles, + css` + :host { + margin: 0; + margin-top: -4px; + } + + #controls mwc-icon-button { + color: rgba(0, 0, 0, 0.35); + --mdc-icon-size: 26px; + --mdc-theme-text-disabled-on-light: rgba(0, 0, 0, 0.1); + } + + #menu-controls mwc-textfield { + width: 4em; + } + `, + ] + } + + static get properties() { + return { + grampsId: {type: String}, + disableBack: {type: Boolean}, + disableHome: {type: Boolean}, + nAnc: {type: Number}, + nDesc: {type: Number}, + _data: {type: Array}, + _setAnc: {type: Boolean}, + _setDesc: {type: Boolean}, + } + } + + constructor() { + super() + this.grampsId = '' + this.nAnc = 3 + this.nDesc = 1 + this.disableBack = false + this.disableHome = false + this._data = [] + this._setAnc = true + this._setDesc = true + } + + renderContent() { + return html` +
+
${this.renderControls()}
+
${this.renderChart()}
+
+ ` + } + + renderControls() { + return html` + ${renderIcon( + mdiHomeAccount, + this.disableHome ? 'var(--mdc-theme-text-disabled-on-light)' : '' + )} + + ${renderIcon(mdiAccountDetails)} + + + + + + + + ${ + this._setDesc + ? html` + + + + + ` + : '' + } +
${this._('Max Ancestor Generations')} + +
${this._('Max Descendant Generations')} + +
+ ${this._('done')} + ${this._('Reset')} +
+ + + ` + } + + // eslint-disable-next-line class-methods-use-this + renderChart() { + return '' + } + + _backToHomePerson() { + fireEvent(this, 'tree:home') + } + + _prevPerson() { + fireEvent(this, 'tree:back') + } + + update(changed) { + super.update(changed) + if ( + changed.has('grampsId') || + changed.has('nAnc') || + changed.has('nDesc') + ) { + this._fetchData(this.grampsId) + } + } + + // eslint-disable-next-line class-methods-use-this + _resetLevels() {} + + _getPersonRules(grampsId) { + return { + function: 'or', + rules: [ + { + name: 'IsLessThanNthGenerationAncestorOf', + values: [grampsId, this.nAnc + 1], + }, + { + name: 'IsLessThanNthGenerationDescendantOf', + values: [grampsId, this.nDesc + 1], + }, + ], + } + } + + async _fetchData(grampsId) { + this.loading = true + const rules = this._getPersonRules(grampsId) + const data = await apiGet( + `/api/people/?rules=${encodeURIComponent(JSON.stringify(rules))}&locale=${ + this.strings?.__lang__ || 'en' + }&profile=self&extend=primary_parent_family,family_list` + ) + this.loading = false + if ('data' in data) { + this.error = false + this._data = data.data + } else if ('error' in data) { + this.error = true + this._errorMessage = data.error + } + } + + _goToPerson() { + fireEvent(this, 'tree:person') + } + + _handleBack() { + fireEvent(this, 'tree:back') + } + + _handleChangeAnc(e) { + this.nAnc = parseInt(e.target.value, 10) + } + + _handleChangeDesc(e) { + this.nDesc = parseInt(e.target.value, 10) + } + + _openMenuControls() { + const menu = this.shadowRoot.getElementById('menu-controls') + menu.open = true + } +}