diff --git a/angular.json b/angular.json
index 935af78..5cd350e 100644
--- a/angular.json
+++ b/angular.json
@@ -120,7 +120,8 @@
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
- "browserTarget": "demo:build"
+ "browserTarget": "demo:build",
+ "host": "0.0.0.0"
},
"configurations": {
"production": {
@@ -149,4 +150,4 @@
}
}},
"defaultProject": "library"
-}
\ No newline at end of file
+}
diff --git a/package-lock.json b/package-lock.json
index a797eba..026ebe1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1219,9 +1219,9 @@
"dev": true
},
"@babel/runtime": {
- "version": "7.7.7",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.7.tgz",
- "integrity": "sha512-uCnC2JEVAu8AKB5do1WRIsvrdJ0flYx/A/9f/6chdacnEZ7LmavjdsDXr5ksYBegxtuTPR5Va9/+13QF/kFkCA==",
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.4.tgz",
+ "integrity": "sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ==",
"dev": true,
"requires": {
"regenerator-runtime": "^0.13.2"
@@ -1344,15 +1344,38 @@
"fastq": "^1.6.0"
}
},
+ "@octokit/auth-token": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.0.tgz",
+ "integrity": "sha512-eoOVMjILna7FVQf96iWc3+ZtE/ZT6y8ob8ZzcqKY1ibSQCnu4O/B7pJvzMx5cyZ/RjAff6DAdEb0O0Cjcxidkg==",
+ "dev": true,
+ "requires": {
+ "@octokit/types": "^2.0.0"
+ }
+ },
+ "@octokit/core": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-2.4.2.tgz",
+ "integrity": "sha512-fUx/Qt774cgiPhb3HRKfdl6iufVL/ltECkwkCg373I4lIPYvAPY4cbidVZqyVqHI+ThAIlFlTW8FT4QHChv3Sg==",
+ "dev": true,
+ "requires": {
+ "@octokit/auth-token": "^2.4.0",
+ "@octokit/graphql": "^4.3.1",
+ "@octokit/request": "^5.3.1",
+ "@octokit/types": "^2.0.0",
+ "before-after-hook": "^2.1.0",
+ "universal-user-agent": "^5.0.0"
+ }
+ },
"@octokit/endpoint": {
- "version": "5.5.1",
- "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.1.tgz",
- "integrity": "sha512-nBFhRUb5YzVTCX/iAK1MgQ4uWo89Gu0TH00qQHoYRCsE12dWcG1OiLd7v2EIo2+tpUKPMOQ62QFy9hy9Vg2ULg==",
+ "version": "5.5.3",
+ "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.3.tgz",
+ "integrity": "sha512-EzKwkwcxeegYYah5ukEeAI/gYRLv2Y9U5PpIsseGSFDk+G3RbipQGBs8GuYS1TLCtQaqoO66+aQGtITPalxsNQ==",
"dev": true,
"requires": {
"@octokit/types": "^2.0.0",
"is-plain-object": "^3.0.0",
- "universal-user-agent": "^4.0.0"
+ "universal-user-agent": "^5.0.0"
},
"dependencies": {
"is-plain-object": {
@@ -1372,10 +1395,57 @@
}
}
},
+ "@octokit/graphql": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.3.1.tgz",
+ "integrity": "sha512-hCdTjfvrK+ilU2keAdqNBWOk+gm1kai1ZcdjRfB30oA3/T6n53UVJb7w0L5cR3/rhU91xT3HSqCd+qbvH06yxA==",
+ "dev": true,
+ "requires": {
+ "@octokit/request": "^5.3.0",
+ "@octokit/types": "^2.0.0",
+ "universal-user-agent": "^4.0.0"
+ },
+ "dependencies": {
+ "universal-user-agent": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.1.tgz",
+ "integrity": "sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg==",
+ "dev": true,
+ "requires": {
+ "os-name": "^3.1.0"
+ }
+ }
+ }
+ },
+ "@octokit/plugin-paginate-rest": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.0.1.tgz",
+ "integrity": "sha512-xtW3AQoGDD0un/AkPjIndTdFO+O/My0I15TArvrbJirBCV91R1ElrE3gRcsUJENP3t/vveiQ9C6XQjo9sS2xQg==",
+ "dev": true,
+ "requires": {
+ "@octokit/types": "^2.0.1"
+ }
+ },
+ "@octokit/plugin-request-log": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz",
+ "integrity": "sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw==",
+ "dev": true
+ },
+ "@octokit/plugin-rest-endpoint-methods": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-3.2.0.tgz",
+ "integrity": "sha512-k+RLsegQn4s0wvAFYuk3R18FVKRg3ktvzIGW6MkmrSiSXBwYfaEsv4CuPysyef0DL+74DRj/X9MLJYlbleUO+Q==",
+ "dev": true,
+ "requires": {
+ "@octokit/types": "^2.0.1",
+ "deprecation": "^2.3.1"
+ }
+ },
"@octokit/request": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.1.tgz",
- "integrity": "sha512-5/X0AL1ZgoU32fAepTfEoggFinO3rxsMLtzhlUX+RctLrusn/CApJuGFCd0v7GMFhF+8UiCsTTfsu7Fh1HnEJg==",
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.2.tgz",
+ "integrity": "sha512-7NPJpg19wVQy1cs2xqXjjRq/RmtSomja/VSWnptfYwuBxLdbYh2UjhGi0Wx7B1v5Iw5GKhfFDQL7jM7SSp7K2g==",
"dev": true,
"requires": {
"@octokit/endpoint": "^5.5.0",
@@ -1385,7 +1455,7 @@
"is-plain-object": "^3.0.0",
"node-fetch": "^2.3.0",
"once": "^1.4.0",
- "universal-user-agent": "^4.0.0"
+ "universal-user-agent": "^5.0.0"
},
"dependencies": {
"is-plain-object": {
@@ -1406,9 +1476,9 @@
}
},
"@octokit/request-error": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.0.tgz",
- "integrity": "sha512-DNBhROBYjjV/I9n7A8kVkmQNkqFAMem90dSxqvPq57e2hBr7mNTX98y3R2zDpqMQHVRpBDjsvsfIGgBzy+4PAg==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.1.tgz",
+ "integrity": "sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA==",
"dev": true,
"requires": {
"@octokit/types": "^2.0.0",
@@ -1417,29 +1487,21 @@
}
},
"@octokit/rest": {
- "version": "16.36.0",
- "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.36.0.tgz",
- "integrity": "sha512-zoZj7Ya4vWBK4fjTwK2Cnmu7XBB1p9ygSvTk2TthN6DVJXM4hQZQoAiknWFLJWSTix4dnA3vuHtjPZbExYoCZA==",
+ "version": "17.0.0",
+ "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-17.0.0.tgz",
+ "integrity": "sha512-nSlmyy1DBEOsC4voRbk/SN56V/iuZfxZzjFFz+ocb2MAYwHC+z1TyVOMV9W630dVn9ukioJO34VD5NSYwcgFWg==",
"dev": true,
"requires": {
- "@octokit/request": "^5.2.0",
- "@octokit/request-error": "^1.0.2",
- "atob-lite": "^2.0.0",
- "before-after-hook": "^2.0.0",
- "btoa-lite": "^1.0.0",
- "deprecation": "^2.0.0",
- "lodash.get": "^4.4.2",
- "lodash.set": "^4.3.2",
- "lodash.uniq": "^4.5.0",
- "octokit-pagination-methods": "^1.1.0",
- "once": "^1.4.0",
- "universal-user-agent": "^4.0.0"
+ "@octokit/core": "^2.4.0",
+ "@octokit/plugin-paginate-rest": "^2.0.0",
+ "@octokit/plugin-request-log": "^1.0.0",
+ "@octokit/plugin-rest-endpoint-methods": "^3.0.0"
}
},
"@octokit/types": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.0.2.tgz",
- "integrity": "sha512-StASIL2lgT3TRjxv17z9pAqbnI7HGu9DrJlg3sEBFfCLaMEqp+O3IQPUF6EZtQ4xkAu2ml6kMBBCtGxjvmtmuQ==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.2.0.tgz",
+ "integrity": "sha512-iEeW3XlkxeM/CObeoYvbUv24Oe+DldGofY+3QyeJ5XKKA6B+V94ePk14EDCarseWdMs6afKZPv3dFq8C+SY5lw==",
"dev": true,
"requires": {
"@types/node": ">= 8"
@@ -1526,9 +1588,9 @@
}
},
"@semantic-release/commit-analyzer": {
- "version": "6.3.3",
- "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-6.3.3.tgz",
- "integrity": "sha512-Pyv1ZL2u5AIOY4YbxFCAB5J1PEh5yON8ylbfiPiriDGGW6Uu1U3Y8lysMtWu+FUD5x7tSnyIzhqx0+fxPxqbgw==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-8.0.1.tgz",
+ "integrity": "sha512-5bJma/oB7B4MtwUkZC2Bf7O1MHfi4gWe4mA+MIQ3lsEV0b422Bvl1z5HRpplDnMLHH3EXMoRdEng6Ds5wUqA3A==",
"dev": true,
"requires": {
"conventional-changelog-angular": "^5.0.0",
@@ -1536,7 +1598,8 @@
"conventional-commits-parser": "^3.0.7",
"debug": "^4.0.0",
"import-from": "^3.0.0",
- "lodash": "^4.17.4"
+ "lodash": "^4.17.4",
+ "micromatch": "^4.0.2"
},
"dependencies": {
"debug": {
@@ -1557,6 +1620,16 @@
"resolve-from": "^5.0.0"
}
},
+ "micromatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+ "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.0.5"
+ }
+ },
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -1770,22 +1843,22 @@
}
},
"@semantic-release/github": {
- "version": "5.5.5",
- "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-5.5.5.tgz",
- "integrity": "sha512-Wo9OIULMRydbq+HpFh9yiLvra1XyEULPro9Tp4T5MQJ0WZyAQ3YQm74IdT8Pe/UmVDq2nfpT1oHrWkwOc4loHg==",
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-7.0.4.tgz",
+ "integrity": "sha512-qQi41eGIa/tne7T8rvQK+xJNoyadOmd5mVsNZUUqZCVueiUkCItspJ7Mgy5ZWuhwlo28+hKeT/4zJ6MIG6er2Q==",
"dev": true,
"requires": {
- "@octokit/rest": "^16.27.0",
+ "@octokit/rest": "^17.0.0",
"@semantic-release/error": "^2.2.0",
"aggregate-error": "^3.0.0",
"bottleneck": "^2.18.1",
"debug": "^4.0.0",
"dir-glob": "^3.0.0",
"fs-extra": "^8.0.0",
- "globby": "^10.0.0",
- "http-proxy-agent": "^2.1.0",
- "https-proxy-agent": "^3.0.0",
- "issue-parser": "^5.0.0",
+ "globby": "^11.0.0",
+ "http-proxy-agent": "^4.0.0",
+ "https-proxy-agent": "^5.0.0",
+ "issue-parser": "^6.0.0",
"lodash": "^4.17.4",
"mime": "^2.4.3",
"p-filter": "^2.0.0",
@@ -1793,6 +1866,15 @@
"url-join": "^4.0.0"
},
"dependencies": {
+ "agent-base": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz",
+ "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==",
+ "dev": true,
+ "requires": {
+ "debug": "4"
+ }
+ },
"array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
@@ -1818,40 +1900,38 @@
}
},
"globby": {
- "version": "10.0.1",
- "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz",
- "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==",
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz",
+ "integrity": "sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==",
"dev": true,
"requires": {
- "@types/glob": "^7.1.1",
"array-union": "^2.1.0",
"dir-glob": "^3.0.1",
- "fast-glob": "^3.0.3",
- "glob": "^7.1.3",
- "ignore": "^5.1.1",
- "merge2": "^1.2.3",
+ "fast-glob": "^3.1.1",
+ "ignore": "^5.1.4",
+ "merge2": "^1.3.0",
"slash": "^3.0.0"
}
},
+ "http-proxy-agent": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
+ "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+ "dev": true,
+ "requires": {
+ "@tootallnate/once": "1",
+ "agent-base": "6",
+ "debug": "4"
+ }
+ },
"https-proxy-agent": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz",
- "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
+ "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
"dev": true,
"requires": {
- "agent-base": "^4.3.0",
- "debug": "^3.1.0"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
- "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
- "dev": true,
- "requires": {
- "ms": "^2.1.1"
- }
- }
+ "agent-base": "6",
+ "debug": "4"
}
},
"ignore": {
@@ -2023,9 +2103,9 @@
}
},
"@semantic-release/release-notes-generator": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-7.3.5.tgz",
- "integrity": "sha512-LGjgPBGjjmjap/76O0Md3wc04Y7IlLnzZceLsAkcYRwGQdRPTTFUJKqDQTuieWTs7zfHzQoZqsqPfFxEN+g2+Q==",
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-9.0.1.tgz",
+ "integrity": "sha512-bOoTiH6SiiR0x2uywSNR7uZcRDl22IpZhj+Q5Bn0v+98MFtOMhCxFhbrKQjhbYoZw7vps1mvMRmFkp/g6R9cvQ==",
"dev": true,
"requires": {
"conventional-changelog-angular": "^5.0.0",
@@ -2147,6 +2227,12 @@
"defer-to-connect": "^1.0.1"
}
},
+ "@tootallnate/once": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.0.0.tgz",
+ "integrity": "sha512-KYyTT/T6ALPkIRd2Ge080X/BsXvy9O0hcWTtMWkPvwAwF99+vn6Dv4GzrFT/Nn1LePr+FFDbRXXlqmsy9lw2zA==",
+ "dev": true
+ },
"@types/color-name": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
@@ -3009,12 +3095,6 @@
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
"dev": true
},
- "atob-lite": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz",
- "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=",
- "dev": true
- },
"autoprefixer": {
"version": "9.6.0",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.0.tgz",
@@ -3593,12 +3673,6 @@
"https-proxy-agent": "^2.2.1"
}
},
- "btoa-lite": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz",
- "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=",
- "dev": true
- },
"buffer": {
"version": "4.9.2",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
@@ -5340,12 +5414,12 @@
"dev": true
},
"env-ci": {
- "version": "4.5.2",
- "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-4.5.2.tgz",
- "integrity": "sha512-lS+edpNp2+QXEPkx6raEMIjKxKKWnJ4+VWzovYJ2NLYiJAYenSAXotFfVdgaFxdbVnvAbUI8epQDa1u12ERxfQ==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-5.0.1.tgz",
+ "integrity": "sha512-xXgohoOAFFF1Y3EdsSKP7olyH/DLS6ZD3aglV6mDFAXBqBXLJSsZLrOZdYfDs5mOmgNaP3YYynObzwF3QkC24g==",
"dev": true,
"requires": {
- "execa": "^3.2.0",
+ "execa": "^4.0.0",
"java-properties": "^1.0.0"
},
"dependencies": {
@@ -5361,9 +5435,9 @@
}
},
"execa": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz",
- "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.0.tgz",
+ "integrity": "sha512-JbDUxwV3BoT5ZVXQrSVbAiaXhXUkIwvbhPIwZ0N13kX+5yCzOhUNdocxB/UQRuYOHRYYwAxKYwJYc0T4D12pDA==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.0",
@@ -5373,7 +5447,6 @@
"merge-stream": "^2.0.0",
"npm-run-path": "^4.0.0",
"onetime": "^5.1.0",
- "p-finally": "^2.0.0",
"signal-exit": "^3.0.2",
"strip-final-newline": "^2.0.0"
}
@@ -5411,12 +5484,6 @@
"mimic-fn": "^2.1.0"
}
},
- "p-finally": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz",
- "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==",
- "dev": true
- },
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -7472,6 +7539,12 @@
"glogg": "^1.0.0"
}
},
+ "hammerjs": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
+ "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=",
+ "dev": true
+ },
"handle-thing": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz",
@@ -8483,9 +8556,9 @@
"dev": true
},
"issue-parser": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-5.0.0.tgz",
- "integrity": "sha512-q/16W7EPHRL0FKVz9NU++TUsoygXGj6JOi88oulyAcQG+IEZ0T6teVdE+VLbe19OfL/tbV8Wi3Dfo0HedeHW0Q==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-6.0.0.tgz",
+ "integrity": "sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==",
"dev": true,
"requires": {
"lodash.capitalize": "^4.2.1",
@@ -9980,12 +10053,6 @@
"integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=",
"dev": true
},
- "lodash.get": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
- "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
- "dev": true
- },
"lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
@@ -10033,12 +10100,6 @@
"integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=",
"dev": true
},
- "lodash.set": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
- "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=",
- "dev": true
- },
"lodash.tail": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz",
@@ -10078,12 +10139,6 @@
"integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=",
"dev": true
},
- "lodash.uniq": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
- "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
- "dev": true
- },
"lodash.uniqby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz",
@@ -10264,23 +10319,90 @@
}
},
"marked": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz",
- "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==",
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.0.tgz",
+ "integrity": "sha512-MyUe+T/Pw4TZufHkzAfDj6HarCBWia2y27/bhuYkTaiUnfDYFnCP3KUN+9oM7Wi6JA2rymtVYbQu3spE0GCmxQ==",
"dev": true
},
"marked-terminal": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-3.3.0.tgz",
- "integrity": "sha512-+IUQJ5VlZoAFsM5MHNT7g3RHSkA3eETqhRCdXv4niUMAKHQ7lb1yvAcuGPmm4soxhmtX13u4Li6ZToXtvSEH+A==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.0.0.tgz",
+ "integrity": "sha512-mzU3VD7aVz12FfGoKFAceijehA6Ocjfg3rVimvJbFAB/NOYCsuzRVtq3PSFdPmWI5mhdGeEh3/aMJ5DSxAz94Q==",
"dev": true,
"requires": {
- "ansi-escapes": "^3.1.0",
+ "ansi-escapes": "^4.3.0",
"cardinal": "^2.1.1",
- "chalk": "^2.4.1",
+ "chalk": "^3.0.0",
"cli-table": "^0.3.1",
- "node-emoji": "^1.4.1",
- "supports-hyperlinks": "^1.0.1"
+ "node-emoji": "^1.10.0",
+ "supports-hyperlinks": "^2.0.0"
+ },
+ "dependencies": {
+ "ansi-escapes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz",
+ "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.8.1"
+ }
+ },
+ "ansi-styles": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+ "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+ "dev": true,
+ "requires": {
+ "@types/color-name": "^1.1.1",
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+ "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+ "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ },
+ "type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "dev": true
+ }
}
},
"matchdep": {
@@ -14866,12 +14988,6 @@
"integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
"dev": true
},
- "octokit-pagination-methods": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz",
- "integrity": "sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==",
- "dev": true
- },
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
@@ -15028,6 +15144,12 @@
"integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
"dev": true
},
+ "p-each-series": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz",
+ "integrity": "sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==",
+ "dev": true
+ },
"p-filter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz",
@@ -16794,21 +16916,21 @@
}
},
"semantic-release": {
- "version": "15.14.0",
- "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-15.14.0.tgz",
- "integrity": "sha512-Cn43W35AOLY0RMcDbtwhJODJmWg6YCs1+R5jRQsTmmkEGzkV4B2F/QXkjVZpl4UbH91r93GGH0xhoq9kh7I5PA==",
+ "version": "17.0.4",
+ "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-17.0.4.tgz",
+ "integrity": "sha512-5y9QRSrZtdvACmlpX5DvEVsvFuKRDUVn7JVJFxPVLGrGofDf1d0M/+hA1wFmCjiJZ+VCY8bYaSqVqF14KCF9rw==",
"dev": true,
"requires": {
- "@semantic-release/commit-analyzer": "^6.1.0",
+ "@semantic-release/commit-analyzer": "^8.0.0",
"@semantic-release/error": "^2.2.0",
- "@semantic-release/github": "^5.1.0",
- "@semantic-release/npm": "^5.0.5",
- "@semantic-release/release-notes-generator": "^7.1.2",
+ "@semantic-release/github": "^7.0.0",
+ "@semantic-release/npm": "^7.0.0",
+ "@semantic-release/release-notes-generator": "^9.0.0",
"aggregate-error": "^3.0.0",
"cosmiconfig": "^6.0.0",
"debug": "^4.0.0",
- "env-ci": "^4.0.0",
- "execa": "^3.2.0",
+ "env-ci": "^5.0.0",
+ "execa": "^4.0.0",
"figures": "^3.0.0",
"find-versions": "^3.0.0",
"get-stream": "^5.0.0",
@@ -16816,17 +16938,40 @@
"hook-std": "^2.0.0",
"hosted-git-info": "^3.0.0",
"lodash": "^4.17.15",
- "marked": "^0.7.0",
- "marked-terminal": "^3.2.0",
- "p-locate": "^4.0.0",
+ "marked": "^0.8.0",
+ "marked-terminal": "^4.0.0",
+ "micromatch": "^4.0.2",
+ "p-each-series": "^2.1.0",
"p-reduce": "^2.0.0",
"read-pkg-up": "^7.0.0",
"resolve-from": "^5.0.0",
- "semver": "^6.0.0",
+ "semver": "^7.1.1",
+ "semver-diff": "^3.1.1",
"signale": "^1.2.1",
"yargs": "^15.0.1"
},
"dependencies": {
+ "@semantic-release/npm": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-7.0.3.tgz",
+ "integrity": "sha512-3wOXMtAdJkaAnW5183iSmWSimtUmOx7m6g/DWPYRs2Gq6iyB+ztMmhgwbn6luNcM9t6pGbgHvRPEXpWkygMxCA==",
+ "dev": true,
+ "requires": {
+ "@semantic-release/error": "^2.2.0",
+ "aggregate-error": "^3.0.0",
+ "execa": "^4.0.0",
+ "fs-extra": "^8.0.0",
+ "lodash": "^4.17.15",
+ "nerf-dart": "^1.0.0",
+ "normalize-url": "^5.0.0",
+ "npm": "^6.10.3",
+ "rc": "^1.2.8",
+ "read-pkg": "^5.0.0",
+ "registry-auth-token": "^4.0.0",
+ "semver": "^7.1.2",
+ "tempy": "^0.4.0"
+ }
+ },
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
@@ -16834,9 +16979,9 @@
"dev": true
},
"ansi-styles": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.0.tgz",
- "integrity": "sha512-7kFQgnEaMdRtwf6uSfUnVr9gSGC7faurn+J/Mv90/W+iTtN0405/nLdopfMWwchyxhbGYl6TC4Sccn9TUkGAgg==",
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+ "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
"dev": true,
"requires": {
"@types/color-name": "^1.1.1",
@@ -16893,6 +17038,12 @@
"which": "^2.0.1"
}
},
+ "crypto-random-string": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
+ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
+ "dev": true
+ },
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
@@ -16909,9 +17060,9 @@
"dev": true
},
"execa": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz",
- "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.0.tgz",
+ "integrity": "sha512-JbDUxwV3BoT5ZVXQrSVbAiaXhXUkIwvbhPIwZ0N13kX+5yCzOhUNdocxB/UQRuYOHRYYwAxKYwJYc0T4D12pDA==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.0",
@@ -16921,15 +17072,14 @@
"merge-stream": "^2.0.0",
"npm-run-path": "^4.0.0",
"onetime": "^5.1.0",
- "p-finally": "^2.0.0",
"signal-exit": "^3.0.2",
"strip-final-newline": "^2.0.0"
}
},
"figures": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz",
- "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
"dev": true,
"requires": {
"escape-string-regexp": "^1.0.5"
@@ -17008,12 +17158,28 @@
"p-locate": "^4.1.0"
}
},
+ "micromatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+ "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+ "dev": true,
+ "requires": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.0.5"
+ }
+ },
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
+ "normalize-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-5.0.0.tgz",
+ "integrity": "sha512-bAEm2fx8Dq/a35Z6PIRkkBBJvR56BbEJvhpNtvCZ4W9FyORSna77fn+xtYFjqk5JpBS+fMnAOG/wFgkQBmB7hw==",
+ "dev": true
+ },
"npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -17032,12 +17198,6 @@
"mimic-fn": "^2.1.0"
}
},
- "p-finally": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz",
- "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==",
- "dev": true
- },
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
@@ -17086,6 +17246,14 @@
"find-up": "^4.1.0",
"read-pkg": "^5.2.0",
"type-fest": "^0.8.1"
+ },
+ "dependencies": {
+ "type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "dev": true
+ }
}
},
"require-main-filename": {
@@ -17100,6 +17268,29 @@
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
"dev": true
},
+ "semver": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.3.tgz",
+ "integrity": "sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==",
+ "dev": true
+ },
+ "semver-diff": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz",
+ "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==",
+ "dev": true,
+ "requires": {
+ "semver": "^6.3.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -17135,12 +17326,38 @@
"ansi-regex": "^5.0.0"
}
},
+ "temp-dir": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz",
+ "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==",
+ "dev": true
+ },
+ "tempy": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.4.0.tgz",
+ "integrity": "sha512-mKnScm8aXv+cG6l1Nzp6mERGgC4UblbPnSDeQp83JgZ7xqDcnl+7u3+6zXnf1UE7YluDUTEIna1iKYwCSaOk9g==",
+ "dev": true,
+ "requires": {
+ "temp-dir": "^2.0.0",
+ "type-fest": "^0.10.0",
+ "unique-string": "^2.0.0"
+ }
+ },
"type-fest": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
- "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz",
+ "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==",
"dev": true
},
+ "unique-string": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
+ "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==",
+ "dev": true,
+ "requires": {
+ "crypto-random-string": "^2.0.0"
+ }
+ },
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -17162,9 +17379,9 @@
}
},
"yargs": {
- "version": "15.0.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.0.2.tgz",
- "integrity": "sha512-GH/X/hYt+x5hOat4LMnCqMd8r5Cv78heOMIJn1hr7QPPBqfeC6p89Y78+WB9yGDvfpCvgasfmWLzNzEioOUD9Q==",
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.1.0.tgz",
+ "integrity": "sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg==",
"dev": true,
"requires": {
"cliui": "^6.0.0",
@@ -18353,20 +18570,29 @@
}
},
"supports-hyperlinks": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz",
- "integrity": "sha512-HHi5kVSefKaJkGYXbDuKbUGRVxqnWGn3J2e39CYcNJEfWciGq2zYtOhXLTlvrOZW1QU7VX67w7fMmWafHX9Pfw==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz",
+ "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==",
"dev": true,
"requires": {
- "has-flag": "^2.0.0",
- "supports-color": "^5.0.0"
+ "has-flag": "^4.0.0",
+ "supports-color": "^7.0.0"
},
"dependencies": {
"has-flag": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
- "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
+ },
+ "supports-color": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+ "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
}
}
},
@@ -19000,9 +19226,9 @@
}
},
"universal-user-agent": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz",
- "integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz",
+ "integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==",
"dev": true,
"requires": {
"os-name": "^3.1.0"
diff --git a/package.json b/package.json
index a9acb3b..fac0144 100644
--- a/package.json
+++ b/package.json
@@ -45,6 +45,7 @@
"gulp": "^4.0.2",
"gulp-string-replace": "^1.1.2",
"gulp-util": "^3.0.8",
+ "hammerjs": "^2.0.8",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.1.0",
@@ -54,7 +55,7 @@
"karma-jasmine-html-reporter": "^1.4.0",
"ng-packagr": "^5.1.0",
"protractor": "~5.4.0",
- "semantic-release": "^15.13.12",
+ "semantic-release": "^17.0.2",
"ts-node": "^7.0.1",
"tsickle": "^0.35.0",
"tslint": "~5.15.0",
diff --git a/projects/demo/src/app/app.component.html b/projects/demo/src/app/app.component.html
index f172862..166d089 100644
--- a/projects/demo/src/app/app.component.html
+++ b/projects/demo/src/app/app.component.html
@@ -1,17 +1,23 @@
-
-
-
Loading Map...
+
+
Loading Map...
+
+
{{ model.zoom * 100 }}%
+
{{ model.center | json }}
+
+
diff --git a/projects/demo/src/app/app.component.scss b/projects/demo/src/app/app.component.scss
index 937f705..7d0c39e 100644
--- a/projects/demo/src/app/app.component.scss
+++ b/projects/demo/src/app/app.component.scss
@@ -83,3 +83,20 @@ button {
margin: .25rem;
flex: 1
}
+
+.map svg {
+ * {
+ shape-rendering: optimizeSpeed;
+ }
+}
+
+.map-outlet {
+ &.zooming {
+ svg {
+ [id*="plant"],
+ [id*="chair"] {
+ display: none;
+ }
+ }
+ }
+}
diff --git a/projects/demo/src/app/app.component.ts b/projects/demo/src/app/app.component.ts
index ce1d614..dd39a5a 100644
--- a/projects/demo/src/app/app.component.ts
+++ b/projects/demo/src/app/app.component.ts
@@ -1,7 +1,7 @@
import { Component, ViewEncapsulation } from '@angular/core';
-import { MapRangeComponent } from 'projects/library/src/lib/components/overlays/map-range/map-range.component';
import { MapPinComponent } from 'projects/library/src/lib/components/overlays/map-pin/map-pin.component';
+import { MapRadiusComponent } from 'projects/library/src/lib/components/overlays/map-radius/map-radius.component';
import * as dayjs from 'dayjs';
@@ -18,7 +18,15 @@ export class AppComponent {
this.updatePointsOfInterest();
this.model.show = {};
this.model.map = {};
- this.model.map.src = 'assets/australia.svg';
+ this.model.map.src = 'assets/level_10.svg';
+ this.model.map.text = [
+ { id: 'area-10.06-status', content: 'Meeting Room\n10.06' },
+ { id: 'area-10.05-status', content: 'Meeting Room\n10.05' },
+ { id: 'scanner-2', content: 'Scanner', show_after_zoom: 2, styles: { 'color': 'red' } }
+ ];
+ this.model.map.listeners = [
+ { id: 'area-10.06-status', event: 'click', callback: () => console.log('Clicked: 10.06') }
+ ];
this.model.zoom = 1;
this.model.center = { x: 0.25, y: 0.75 };
this.model.count = Array(3).fill(0);
@@ -36,7 +44,7 @@ export class AppComponent {
public toggleMap() {
this.model.map.src =
- this.model.map.src.indexOf('180') >= 0 ? 'assets/level_01.svg' : 'assets/australia-180-rot.svg';
+ this.model.map.src.indexOf('180') >= 0 ? 'assets/level_10.svg' : 'assets/australia-180-rot.svg';
}
public zoom(value: number) {
@@ -49,7 +57,7 @@ export class AppComponent {
this.model.zoom = +(this.model.zoom * (1 / (1 - value / 100))).toFixed(5);
if (this.model.zoom < 1) {
this.model.zoom = 1;
- }
+ }
}
}
@@ -57,45 +65,50 @@ export class AppComponent {
this.model.map.poi = [];
if (this.model.show.radius) {
this.model.map.poi.push({
- id: 'Nyada',
coordinates: { x: 3000, y: 3000 },
- content: MapRangeComponent,
- data: { text: `I'm somewhere in this circle`, diameter: 10 }
+ content: MapRadiusComponent,
+ data: { text: `I'm somewhere in this circle`, diameter: 5 }
});
}
if (this.model.show.pin) {
this.model.fixed = !this.model.fixed;
const fixed = this.model.fixed;
this.model.map.poi.push({
- id: fixed ? 'AU-NSW' : 'Nyada',
- coordinates: fixed ? null : { x: 5000, y: 7500 },
+ id: fixed ? 'area-10.05-status' : undefined,
+ coordinates: fixed ? null : { x: 7500, y: 1000 },
content: MapPinComponent,
data: {
text: fixed ? 'NSW is here' : `I'm currently round here`
}
});
- const focus: any = {};
+ let focus: any = null;
if (fixed) {
- focus.id = 'AU-NSW';
+ focus = 'area-10.05-status';
} else {
- focus.coordinates = { x: 5000, y: 7500 };
+ focus = { x: 0.75, y: 0.25 };
}
this.model.map.focus = focus;
this.model.map.styles = {
- '#AU-NSW': { fill: ['#123456', '#345612', '#561234'][Math.floor(Math.random() * 3)] },
- '#AU.NT:hover': {
- fill: ['#654321', '#436521', '#216543'][Math.floor(Math.random() * 3)],
+ '#area-10.05-status': {
+ fill: ['#123456', '#345612', '#561234'][Math.floor(Math.random() * 3)],
transition: 'fill 200ms'
+ },
+ '#area-10.05-status:hover': {
+ fill: ['#654321', '#436521', '#216543'][Math.floor(Math.random() * 3)]
}
};
}
if (this.model.show.hover) {
this.model.map.poi.push({
- id: 'AU.NT',
+ id: 'area-10.05-status',
coordinates: null,
content: MapPinComponent,
data: { text: 'This state is WA' }
});
}
}
+
+ log(content) {
+ console.log('Map Event:', content);
+ }
}
diff --git a/projects/demo/src/app/app.module.ts b/projects/demo/src/app/app.module.ts
index e1a3531..0494a33 100644
--- a/projects/demo/src/app/app.module.ts
+++ b/projects/demo/src/app/app.module.ts
@@ -5,6 +5,8 @@ import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AInteractiveMapModule } from 'projects/library/src/public-api';
+import 'hammerjs';
+
@NgModule({
declarations: [
AppComponent
diff --git a/projects/demo/src/assets/level_10.svg b/projects/demo/src/assets/level_10.svg
new file mode 100644
index 0000000..d45afbd
--- /dev/null
+++ b/projects/demo/src/assets/level_10.svg
@@ -0,0 +1 @@
+
diff --git a/projects/library/src/lib/classes/map-render-feature.spec.ts b/projects/library/src/lib/classes/map-render-feature.spec.ts
new file mode 100644
index 0000000..aa9e6fa
--- /dev/null
+++ b/projects/library/src/lib/classes/map-render-feature.spec.ts
@@ -0,0 +1,7 @@
+// import { MapRenderFeature } from './map-render-feature';
+
+// describe('MapFeature', () => {
+// it('should create an instance', () => {
+// expect(new MapRenderFeature(null, null)).toBeTruthy();
+// });
+// });
diff --git a/projects/library/src/lib/classes/map-render-feature.ts b/projects/library/src/lib/classes/map-render-feature.ts
new file mode 100644
index 0000000..4f387d4
--- /dev/null
+++ b/projects/library/src/lib/classes/map-render-feature.ts
@@ -0,0 +1,57 @@
+import { TemplateRef, Type } from '@angular/core';
+
+import { Point, RenderFeature } from '../helpers/type.helpers';
+import { RenderableMap } from './renderable-map';
+import { log } from '../settings';
+
+export class MapRenderFeature {
+ /** ID of an element to render */
+ public readonly id: string;
+ /** Coordinates with the map */
+ public readonly coordinates: Point;
+ /** Content to render on the map */
+ public readonly content: RenderFeature;
+ /** Data to pass to the content */
+ public readonly data: any;
+ /** Data to pass to the content */
+ public readonly show_after_zoom: number;
+
+ /** Type of content being rendered by this feature */
+ public get content_type(): 'component' | 'template' | 'html' {
+ return this.content instanceof Type
+ ? 'component'
+ : this.content instanceof TemplateRef
+ ? 'template'
+ : 'html';
+ }
+
+ constructor(data: { [name: string]: any }, map: RenderableMap) {
+ const coordinates = this.processCoordinates(data.id || data.coordinates, map);
+ this.id = data.id || JSON.stringify(coordinates);
+ this.coordinates = coordinates;
+ this.content = data.content;
+ this.data = data.data || data.styles;
+ this.show_after_zoom = data.show_after_zoom;
+ }
+
+ private processCoordinates(data: string | Point, map: RenderableMap): Point {
+ if (!map) { return; }
+ if (typeof data === 'string') {
+ const element = map.element_map[data];
+ if (element) {
+ return element.coordinates;
+ } else {
+ log('MAP', `No element for id "${data}"`, undefined, 'warn');
+ }
+ } else {
+ if (data.x <= 1 && data.x >= 0 && data.y <= 1 && data.y >= 0) {
+ return data;
+ } else {
+ return {
+ x: data.x / 10000,
+ y: data.y / (10000 * map.dimensions.y)
+ };
+ }
+ }
+ }
+}
diff --git a/projects/library/src/lib/classes/map-styles.spec.ts b/projects/library/src/lib/classes/map-styles.spec.ts
new file mode 100644
index 0000000..8a9e81c
--- /dev/null
+++ b/projects/library/src/lib/classes/map-styles.spec.ts
@@ -0,0 +1,7 @@
+// import { MapStyles } from './map-styles';
+
+// describe('MapStyles', () => {
+// it('should create an instance', () => {
+// expect(new MapStyles({}, null)).toBeTruthy();
+// });
+// });
diff --git a/projects/library/src/lib/classes/map-styles.ts b/projects/library/src/lib/classes/map-styles.ts
new file mode 100644
index 0000000..701c2a2
--- /dev/null
+++ b/projects/library/src/lib/classes/map-styles.ts
@@ -0,0 +1,63 @@
+import { HashMap } from '../helpers/type.helpers';
+import { cleanCssSelector } from '../helpers/map.helpers';
+import { RenderableMap } from './renderable-map';
+
+export class MapStyles {
+ /** Mapping of CSS selectors to override CSS properties */
+ public readonly styles: HashMap
>;
+ /** CSS string that can be injected into the DOM */
+ private _css: string;
+ /** Element rendering the map styles */
+ private _element: HTMLStyleElement;
+ /** CSS string that can be injected into the DOM */
+ public get css(): string {
+ return this._css;
+ }
+
+ constructor(styles: HashMap>, private map: RenderableMap) {
+ this.styles = styles;
+ this._css = this._processStyles(styles);
+ this._renderStyleElement(this.css);
+ }
+
+ /** Cleanup map styles */
+ public destroy() {
+ if (this._element) {
+ this._element.parentElement.removeChild(this._element);
+ delete this._element;
+ this._element = null;
+ }
+ }
+
+ /**
+ * Convert style map into CSS string
+ * @param styles Mapping of CSS selectors to override CSS properties
+ */
+ private _processStyles(styles: HashMap>): string {
+ let css = '';
+ for (const selector in this.styles) {
+ if (this.styles.hasOwnProperty(selector)) {
+ let style = `.map[id="${this.map ? this.map.id : 'map-0'}"] ${cleanCssSelector(selector)} { `;
+ for (const property in this.styles[selector]) {
+ if (this.styles[selector][property]) {
+ style += `${property}: ${this.styles[selector][property]}; `;
+ }
+ }
+ style += '} ';
+ css += style;
+ }
+ }
+ return css;
+ }
+
+ /** Render Style Element on the DOM */
+ private _renderStyleElement(css: string) {
+ if (this.map) {
+ const element = document.createElement('style');
+ element.id = `placeos-${this.map.id}`;
+ element.innerHTML = css;
+ document.head.appendChild(element);
+ this._element = element;
+ }
+ }
+}
diff --git a/projects/library/src/lib/classes/renderable-map.spec.ts b/projects/library/src/lib/classes/renderable-map.spec.ts
new file mode 100644
index 0000000..e608631
--- /dev/null
+++ b/projects/library/src/lib/classes/renderable-map.spec.ts
@@ -0,0 +1,7 @@
+// import { RenderableMap } from './renderable-map';
+
+// describe('RenderableMap', () => {
+// it('should create an instance', () => {
+// expect(new RenderableMap('', '')).toBeTruthy();
+// });
+// });
diff --git a/projects/library/src/lib/classes/renderable-map.ts b/projects/library/src/lib/classes/renderable-map.ts
new file mode 100644
index 0000000..f27a60c
--- /dev/null
+++ b/projects/library/src/lib/classes/renderable-map.ts
@@ -0,0 +1,80 @@
+import { HashMap, Point } from '../helpers/type.helpers';
+import { getPosition } from '../helpers/map.helpers';
+
+export interface MapElement {
+ readonly id: string;
+ readonly coordinates: Point;
+}
+
+let COUNTER = 0;
+
+export class RenderableMap {
+ /** ID of the map */
+ public readonly id: string;
+ /** URL of the map */
+ public readonly url: string;
+ /** File contents of URL */
+ public readonly raw_data: string;
+ /** List of available ID selectors in the map data */
+ public readonly available_ids: readonly string[];
+ /** Dimensions ratio of the map */
+ public readonly dimensions: Point;
+
+ /** Mapping of element id's to their locations with the map data */
+ private _element_map: HashMap = {};
+
+ public get element_map(): HashMap {
+ return { ...this._element_map };
+ }
+
+ constructor(url: string, map_data: string) {
+ this.id = `map-${++COUNTER}`;
+ this.url = url;
+ const raw_data = this._cleanMapData(map_data);
+ this.raw_data = raw_data;
+ const { id_list, dimensions } = this._processMapData();
+ this.available_ids = id_list;
+ this.dimensions = dimensions;
+ }
+
+ /** Process map data and generate lookup table */
+ private _processMapData() {
+ const element = document.createElement('div');
+ element.style.setProperty('position', 'absolute');
+ element.style.setProperty('top', '-9999px');
+ element.style.setProperty('left', '-9999px');
+ element.style.setProperty('height', '1000px');
+ element.style.setProperty('width', '1000px');
+ element.innerHTML = this.raw_data;
+ document.body.appendChild(element);
+ const svg_el: SVGElement = element.querySelector('svg');
+ const box = svg_el.getBoundingClientRect();
+ const dimensions = { x: 1, y: box.height / box.width };
+ const id_elements = element.querySelectorAll('[id]');
+ const id_list: string[] = [];
+ this._element_map = {};
+ id_elements.forEach(el => {
+ const el_box = el.getBoundingClientRect();
+ this._element_map[el.id] = {
+ id: el.id,
+ coordinates: getPosition(box, el_box)
+ };
+ id_list.push(el.id);
+ });
+ return { id_list, dimensions };
+ }
+
+ /** Clean map styles */
+ private _cleanMapData(map_data: string) {
+ let raw_data = '';
+ // Prevent non SVG files from being used
+ if (map_data.match(/<\/svg>/g)) {
+ // Prevent Adobe generic style names from being used
+ raw_data = map_data.replace(/cls\-/gm, `${this.id}-`);
+ raw_data = raw_data.replace(/\.map/gm, `svg .map`);
+ // Remove title tags and content from the map
+ raw_data = raw_data.replace(/.*<\/title>/gm, '');
+ }
+ return raw_data;
+ }
+}
diff --git a/projects/library/src/lib/components/map-feature/map-feature.class.spec.ts b/projects/library/src/lib/components/map-feature/map-feature.class.spec.ts
deleted file mode 100644
index e69de29..0000000
diff --git a/projects/library/src/lib/components/map-feature/map-feature.class.ts b/projects/library/src/lib/components/map-feature/map-feature.class.ts
deleted file mode 100644
index c210fac..0000000
--- a/projects/library/src/lib/components/map-feature/map-feature.class.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-
-import { Injector, TemplateRef, Injectable } from '@angular/core';
-import { Subscription } from 'rxjs';
-
-import { AMapComponent } from '../map/map.component';
-import { IReadonlyMapPoint, MapOverlayContent, IMapFeature } from '../map.interfaces';
-
-export class AMapFeature {
- /** Map Element selector */
- readonly id: string;
- /** Map coordinates */
- readonly coordinates: IReadonlyMapPoint;
- /** Content to render at position */
- readonly content: MapOverlayContent;
- /** Content render method. Determined automatically from `content` value */
- readonly method: 'component' | 'text' | 'template';
- /** Data to inject into the content template/component */
- private _data: T;
- /** Inject for passing data into components */
- private _inject: Injector;
- /** Location of the feature on the map */
- private _position: IReadonlyMapPoint;
-
- constructor(private _map: AMapComponent, private _injector: Injector, data: IMapFeature) {
- if (!this._map || !this._injector) {
- throw new Error('Cannot build map feature without map or injector');
- }
- this.id = data.id;
- this.coordinates = data.coordinates;
- this._data = data.data;
- this.content = data.content;
-
- this.method = 'component';
-
- if (typeof this.content === 'string') {
- this.method = 'text';
- } else if (this.content instanceof TemplateRef) {
- this.method = 'template';
- }
- }
-
- /** Location of the feature on the map */
- public get position(): IReadonlyMapPoint {
- return this._position || { x: 0, y: 0 };
- }
-
- public set position(position: IReadonlyMapPoint) {
- this._position = position;
- }
-
- /** Current zoom level of the map */
- public get zoom(): number {
- return this._map.zoom || 0;
- }
-
- /** Listen for changes to the map's zoom value */
- public zoomChanges(next: (v) => void): Subscription {
- return this._map.zoomChange.subscribe(next);
- }
-
- /** Center position of the map */
- public get center(): IReadonlyMapPoint {
- return this._map.center || { x: .5, y: .5 };
- }
-
- /** Listen for changes to the map's center poistion */
- public centerChanges(next: (v) => void): Subscription {
- return this._map.centerChange.subscribe(next);
- }
-
- /** Data to inject into the content template/component */
- public get data(): any {
- return this._data;
- }
-
- public set data(data: any) {
- this._data = data;
- }
-
- /** Angular Injector for this map feature */
- public get injector(): Injector {
- if (!this._inject) {
- this._inject = Injector.create([
- { provide: AMapFeature, useValue: this }
- ], this._injector);
- }
- return this._inject;
- }
-}
diff --git a/projects/library/src/lib/components/map-outlet/map-outlet.component.html b/projects/library/src/lib/components/map-outlet/map-outlet.component.html
new file mode 100644
index 0000000..9b692a1
--- /dev/null
+++ b/projects/library/src/lib/components/map-outlet/map-outlet.component.html
@@ -0,0 +1,26 @@
+
diff --git a/projects/library/src/lib/components/map-outlet/map-outlet.component.scss b/projects/library/src/lib/components/map-outlet/map-outlet.component.scss
new file mode 100644
index 0000000..a807a04
--- /dev/null
+++ b/projects/library/src/lib/components/map-outlet/map-outlet.component.scss
@@ -0,0 +1,38 @@
+
+:host,
+.map-container {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ box-sizing: border-box;
+}
+
+.map-container {
+ width: calc(100% - 2em);
+ height: calc(100% - 2em);
+ margin: 1em;
+}
+
+.map-outlet {
+ position: relative;
+ will-change: height, width, transform;
+ top: 50%;
+ left: 50%;
+ transform-origin: left top;
+
+ * {
+ user-select: none;
+ }
+}
+
+.map {
+ z-index: 1;
+}
+
+map-text-outlet {
+ z-index: 2;
+}
+
+map-overlay-outlet {
+ z-index: 3;
+}
diff --git a/projects/library/src/lib/components/map-outlet/map-outlet.component.spec.ts b/projects/library/src/lib/components/map-outlet/map-outlet.component.spec.ts
new file mode 100644
index 0000000..bb99b78
--- /dev/null
+++ b/projects/library/src/lib/components/map-outlet/map-outlet.component.spec.ts
@@ -0,0 +1,24 @@
+// import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+// import { MapOutletComponent } from './map-outlet.component';
+
+// describe('MapOutletComponent', () => {
+// let component: MapOutletComponent;
+// let fixture: ComponentFixture;
+
+// beforeEach(async(() => {
+// TestBed.configureTestingModule({
+// declarations: [MapOutletComponent]
+// }).compileComponents();
+// }));
+
+// beforeEach(() => {
+// fixture = TestBed.createComponent(MapOutletComponent);
+// component = fixture.componentInstance;
+// fixture.detectChanges();
+// });
+
+// it('should create', () => {
+// expect(component).toBeTruthy();
+// });
+// });
diff --git a/projects/library/src/lib/components/map-outlet/map-outlet.component.ts b/projects/library/src/lib/components/map-outlet/map-outlet.component.ts
new file mode 100644
index 0000000..cc08023
--- /dev/null
+++ b/projects/library/src/lib/components/map-outlet/map-outlet.component.ts
@@ -0,0 +1,260 @@
+import {
+ Component,
+ OnInit,
+ Input,
+ ViewChild,
+ ElementRef,
+ EventEmitter,
+ Output,
+ SimpleChanges,
+ OnChanges,
+ Renderer2,
+ OnDestroy
+} from '@angular/core';
+
+import { RenderableMap } from '../../classes/renderable-map';
+import { Point, MapEvent } from '../../helpers/type.helpers';
+import { eventToPoint, staggerChange, cleanCssSelector } from '../../helpers/map.helpers';
+import { MapRenderFeature } from '../../classes/map-render-feature';
+import { MapListener } from '../../helpers/map.interfaces';
+import { log } from '../../settings';
+
+@Component({
+ selector: 'a-map-outlet',
+ templateUrl: './map-outlet.component.html',
+ styleUrls: ['./map-outlet.component.scss']
+})
+export class MapOutletComponent implements OnInit, OnChanges, OnDestroy {
+ /** Details of the map */
+ @Input() map: RenderableMap;
+ /** Zoom level of the map as a whole number. 1 = 100% zoom */
+ @Input() public zoom: number;
+ /**
+ * Position of the center point of the component on the map displayed
+ *
+ * For example:
+ *
+ * { x: 0, y: 0 }
+ * Places the map top left corner in the middle of the component
+ *
+ * { x: 0.5, y: 0.5 }
+ * Places the center of the map in the middle of the component
+ *
+ * { x: 1, y: 1 }
+ * Places the bottom right corner of the map in the middle of the component
+ */
+ @Input() public center: Point;
+ /** List of features to render over the map */
+ @Input() public features: MapRenderFeature[] = [];
+ /** List of features to render over the map */
+ @Input() public listeners: MapListener[] = [];
+ /** List of text to render over the map */
+ @Input() public text: MapRenderFeature[] = [];
+ /** Emitter for changes to the zoom value */
+ @Output() public zoomChange = new EventEmitter();
+ /** Emitter for changes to the center value */
+ @Output() public centerChange = new EventEmitter();
+ /** Emitter for changes to the zoom value */
+ @Output() public events = new EventEmitter();
+ /** Local zoom value used to rendered the map */
+ public local_zoom: number = 1;
+ /** Local zoom value used to rendered the map */
+ public local_center: Point = { x: 0.5, y: 0.5 };
+
+ /** Element reference to the map display element */
+ @ViewChild('element', { static: true }) public map_element: ElementRef;
+ /** Element reference to the map container element */
+ @ViewChild('container', { static: true }) private _container: ElementRef;
+ /** Bounding box for the map */
+ private _box: ClientRect;
+ /** Promise for handling changes to zoom values */
+ private zoom_promise: Promise;
+ /** Promise for handling changes to center position values */
+ private center_promise: Promise;
+ /** Store of latest difference change between zoom values */
+ private _zoom_diff: number;
+
+ private dimensions: Point = { x: 1, y: 1 };
+ /** List of active listeners */
+ private _event_handlers: (() => void)[] = [];
+
+ /** Width of the map outlet container */
+ public get width(): string {
+ if (!this.map) {
+ return '0';
+ }
+ return `${(this.local_zoom * this.size_dimension * .9).toFixed(2)}px`;
+ }
+ /** Height of the map outlet container */
+ public get height(): string {
+ if (!this.map) {
+ return '0';
+ }
+ const height = (this.local_zoom * this.size_dimension * this.map.dimensions.y) * .9;
+ return `${height.toFixed(2)}px`;
+ }
+ /** Position of the map outlet container */
+ public get transformX(): number {
+ return -(this.local_center ? this.local_center.x : 0.5) * 100;
+ }
+ /** Position of the map outlet container */
+ public get transformY(): number {
+ return -(this.local_center ? this.local_center.y : 0.5) * 100;
+ }
+
+ /** Get width of the map render box */
+ public get size_dimension(): number {
+ return this._box
+ ? this.dimensions.y < this.map.dimensions.y
+ ? this._box.width * (this.dimensions.y / this.map.dimensions.y)
+ : this._box.width
+ : 100;
+ }
+
+ constructor(private _renderer: Renderer2) { }
+
+ public ngOnInit(): void {
+ this.updateContainerBox();
+ }
+
+ public ngOnChanges(changes: SimpleChanges): void {
+ if (changes.zoom) {
+ this.staggerZoom();
+ }
+ if (changes.center) {
+ this.staggerCenter();
+ }
+ if (changes.listeners || changes.map) {
+ this.updateListeners();
+ }
+ }
+
+ public ngOnDestroy(): void {
+ this._event_handlers.forEach(item => item ? item() : '');
+ delete this._event_handlers;
+ this._event_handlers = [];
+ }
+
+ /**
+ * Emitted the position of the mouse click relative to the map
+ * @param event Mouse or touch event
+ */
+ public emitPointerPostion(event: MouseEvent | TouchEvent) {
+ const point = eventToPoint(event);
+ const box = this.map_element.nativeElement.getBoundingClientRect();
+ const position = {
+ x: +((point.x - box.left) / box.width).toFixed(4),
+ y: +((point.y - box.top) / box.height).toFixed(4)
+ };
+ this.events.emit({ type: 'click', metadata: position } as MapEvent);
+ }
+
+ /** Update the bound box of the container bounding box */
+ public updateContainerBox() {
+ if (this._container && this._container.nativeElement) {
+ this._box = this._container.nativeElement.getBoundingClientRect();
+ this.dimensions = { x: 1, y: this._box.height / this._box.width };
+ }
+ }
+
+
+ /**
+ * Update the zoom level of the map
+ * @param new_zoom New zoom level
+ */
+ public updateZoom(new_zoom: number) {
+ this.zoomChange.emit(new_zoom);
+ this.staggerZoom();
+ }
+
+
+ /**
+ * Stagger the changes of the zoom value to have it animate smoothly
+ */
+ private staggerZoom() {
+ this._zoom_diff = Math.abs(this.zoom - this.local_zoom);
+ if (!this.zoom_promise) {
+ this.zoom_promise = staggerChange(this.zoom - this.local_zoom, () => {
+ let change = this.zoom - this.local_zoom;
+ const direction = change < 0 ? -1 : 1;
+ const change_value = Math.max(0.02, Math.min(0.75, Math.abs(this._zoom_diff) / 10));
+ this.local_zoom +=
+ this._zoom_diff > change_value ? (direction < 0 ? -change_value : change_value) : change;
+ this.local_zoom = Math.max(1, Math.min(10, this.local_zoom));
+ const not_done = Math.abs(change) < change_value ? 0 : change;
+ if (!not_done) {
+ this.local_zoom = this.zoom;
+ }
+ return not_done;
+ });
+ this.zoom_promise.then(() => (this.zoom_promise = null));
+ }
+ }
+
+ /**
+ * Update the center location of the map
+ * @param new_center New center coordinates
+ */
+ public updateCenter(new_center: Point) {
+ this.centerChange.emit(new_center);
+ this.staggerCenter();
+ }
+
+ /**
+ * Stagger the changes of the center values to have it animate smoothly
+ */
+ private staggerCenter() {
+ if (!this.center_promise) {
+ this.center_promise = staggerChange(1, () => {
+ const change = {
+ x: this.center.x - this.local_center.x,
+ y: this.center.y - this.local_center.y
+ };
+ const direction = {
+ x: change.x < 0 ? -1 : 1,
+ y: change.y < 0 ? -1 : 1
+ };
+ const change_value = {
+ x: Math.max(0.01, Math.min(0.05, Math.abs(change.x) / 5)),
+ y: Math.max(0.01, Math.min(0.05, Math.abs(change.y) / 5))
+ };
+ this.local_center = {
+ x:
+ this.local_center.x +
+ (Math.abs(change.x) > change_value.x ? (direction.x < 0 ? -1 : 1) * change_value.x : change.x),
+ y:
+ this.local_center.y +
+ (Math.abs(change.y) > change_value.y ? (direction.y < 0 ? -1 : 1) * change_value.y : change.y)
+ };
+ return Math.abs(change.x) < change_value.x && Math.abs(change.y) < change_value.y ? 0 : 1;
+ });
+ this.center_promise.then(() => (this.center_promise = null));
+ }
+ }
+
+ /**
+ * Update event handlers for map elements
+ */
+ private updateListeners(): void {
+ if (!this.map_element || !this.map) {
+ setTimeout(() => this.updateListeners(), 50);
+ return;
+ }
+ this._event_handlers.forEach(item => item ? item() : '');
+ delete this._event_handlers;
+ this._event_handlers = [];
+ for (const item of this.listeners) {
+ if (this.map.available_ids.indexOf(item.id) >= 0) {
+ const selector = `#${cleanCssSelector(item.id)}`;
+ const element = this.map_element.nativeElement.querySelector(selector);
+ if (element) {
+ this._event_handlers.push(
+ this._renderer.listen(element, item.event, item.callback)
+ );
+ continue;
+ }
+ }
+ log('LISTEN', `Update to listen to "${item.event}" on element "${item.id}"`);
+ }
+ }
+}
diff --git a/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.html b/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.html
index 00075db..a8961a2 100644
--- a/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.html
+++ b/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.html
@@ -1,20 +1,20 @@
-
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
+
+
diff --git a/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.scss b/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.scss
index 48bbad7..b89fec0 100644
--- a/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.scss
+++ b/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.scss
@@ -1,20 +1,6 @@
-
-.map-overlay-outlet {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 1000;
- pointer-events: none;
-}
-
-.item {
+.map-overlay {
position: absolute;
- top: -1000vh;
- left: -1000vw;
height: 1px;
width: 1px;
- pointer-events: auto;
}
diff --git a/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.spec.ts b/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.spec.ts
new file mode 100644
index 0000000..55be766
--- /dev/null
+++ b/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MapOverlayOutletComponent } from './map-overlay-outlet.component';
+
+describe('MapOverlayOutletComponent', () => {
+ let component: MapOverlayOutletComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ MapOverlayOutletComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MapOverlayOutletComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.ts b/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.ts
index ad2c992..8ca5202 100644
--- a/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.ts
+++ b/projects/library/src/lib/components/map-overlay-outlet/map-overlay-outlet.component.ts
@@ -1,105 +1,64 @@
-import {
- Component,
- Input,
- Output,
- EventEmitter,
- SimpleChanges,
- Renderer2,
- OnInit,
- OnChanges,
- TemplateRef,
- Injector,
- Injectable
-} from '@angular/core';
-
-import { BaseWidgetDirective } from '../../base.directive';
-
-import { MapUtilities } from '../../utlities/map.utilities';
-import { AMapFeature } from '../map-feature/map-feature.class';
-
+import { Component, Input, Injector, SimpleChanges, OnChanges, Type } from '@angular/core';
+import { MapRenderFeature } from '../../classes/map-render-feature';
+import { HashMap, Point } from '../../helpers/type.helpers';
+import { MapState, MAP_STATE, MAP_LOCATION, MAP_OVERLAY_DATA } from '../../helpers/map.interfaces';
+import { BehaviorSubject } from 'rxjs';
@Component({
selector: 'map-overlay-outlet',
templateUrl: './map-overlay-outlet.component.html',
styleUrls: ['./map-overlay-outlet.component.scss']
})
-export class MapOverlayOutletComponent extends BaseWidgetDirective implements OnInit, OnChanges {
- /** List of points of interest */
- @Input() items: AMapFeature[];
- /** Map elment render to the DOM */
- @Input() map: SVGElement;
- /** Map root element */
- @Input() container: HTMLDivElement;
- /** Zoom level as decimal */
- @Input() scale: number;
- /** Event emitter for Point of interest events */
- @Output() event = new EventEmitter();
+export class MapOverlayOutletComponent implements OnChanges {
+ /** List of text items to render on top of the map */
+ @Input() items: MapRenderFeature[] = [];
+ /** Rotation of the map */
+ @Input() zoom = 1;
+ /** Rotation of the map */
+ @Input() center: Point = { x: .5, y: .5 };
+ /** Rotation of the map */
+ @Input() rotation = 0;
+ /** List of injectors for overlay items */
+ public injectors: HashMap = {};
+ /** Emitter for changes to the state of the map */
+ private _state: BehaviorSubject = new BehaviorSubject({ zoom: 1, center: { x: 0.5, y: 0.5 } });
- protected list: AMapFeature[] = [];
+ constructor(private _injector: Injector) {}
- constructor(private injector: Injector, protected renderer: Renderer2) {
- super();
- }
-
- public ngOnInit() {
- if (this.isIE()) {
- this.renderer.listen('window', 'resize', () => {
- this.timeout('update', () => this.processItems(), 200);
- });
+ public ngOnChanges(changes: SimpleChanges): void {
+ if (changes.items && this.items) {
+ delete this.injectors;
+ this.injectors = {};
+ for (const item of this.items) {
+ if (item.content instanceof Type) {
+ this.injectors[item.id] = this._createInjector(item);
+ }
+ }
}
- }
-
- public ngOnChanges(changes: SimpleChanges) {
- if (changes.items || changes.map) {
- this.timeout('update', () => this.processItems(), changes.map && !changes.map.previousValue ? 1000 : 200);
+ if (changes.zoom || changes.center) {
+ this._state.next({
+ zoom: this.zoom || 1,
+ center: this.center || { x: 0.5, y: 0.5 }
+ });
}
}
- public processItems() {
- if (!this.items) { return; }
- if (this.items.length <= 0) { this.list = []; return; }
- this.timeout('process', () => {
- this.list = [...this.items];
- this.updateItems();
- });
- }
-
- public updateItems() {
- if (this.map) {
- const view_box = this.map.getAttribute('viewBox').split(' ');
- const map_box = this.map.getBoundingClientRect();
- const box = this.container.getBoundingClientRect();
- const x_scale = Math.max(1, (map_box.width / map_box.height) / (+view_box[2] / +view_box[3]));
- const y_scale = Math.max(1, (map_box.height / map_box.width) / (+view_box[3] / +view_box[2]));
- for (const feature of this.list) {
- this.calculatePosition(feature, { x_scale, y_scale, view: view_box, map: map_box, cntr: box });
- }
- }
+ public trackByFn(item: MapRenderFeature, index: number) {
+ return item.id || JSON.stringify(item.coordinates) || index;
}
/**
- * Calculate render position of the given point of interest
- * @param item POI Item
+ * Create injector for overlay element
+ * @param item Feature needing a injector
*/
- public calculatePosition(item: AMapFeature, details: { [name: string]: any }) {
- const el = item.id ? this.map.querySelector(MapUtilities.cleanCssSelector(`#${item.id}`)) : null;
- if (el || item.coordinates) {
- const pos_box = this.isIE() && item.coordinates ? { width: +details.view[2], height: +details.view[3] } : details.cntr;
- const position = MapUtilities.getPosition(pos_box, el, item.coordinates) || { x: .5, y: .5 };
- if (this.isIE() && item.coordinates) {
- // Normalise dimensions
- position.x = position.x / details.x_scale + (details.x_scale - 1) / 2;
- position.y = position.y / details.y_scale + (details.y_scale - 1) / 2;
- }
- item.position = position;
- }
- }
-
- public isIE() {
- return navigator.appName == 'Microsoft Internet Explorer' || !!(navigator.userAgent.match(/Trident/) || navigator.userAgent.match(/rv:11/)) || !!navigator.userAgent.match(/MSIE/g);
- }
-
- public trackByFn(index: number, item: AMapFeature) {
- return item ? item.id || `${item.position.x},${item.position.y}` : index;
+ private _createInjector(item: MapRenderFeature) {
+ return Injector.create({
+ providers: [
+ { provide: MAP_STATE, useValue: this._state },
+ { provide: MAP_LOCATION, useValue: item.coordinates },
+ { provide: MAP_OVERLAY_DATA, useValue: item.data }
+ ],
+ parent: this._injector
+ });
}
}
diff --git a/projects/library/src/lib/components/map-renderer/map-renderer.component.ts b/projects/library/src/lib/components/map-renderer/map-renderer.component.ts
deleted file mode 100644
index 55959f0..0000000
--- a/projects/library/src/lib/components/map-renderer/map-renderer.component.ts
+++ /dev/null
@@ -1,198 +0,0 @@
-import { Component, Input, ElementRef, ViewChild, Output, EventEmitter, Renderer2, SimpleChanges, OnInit, OnChanges } from '@angular/core';
-import { MapUtilities } from '../../utlities/map.utilities';
-import { MapService } from '../../services/map.service';
-import { BaseWidgetDirective } from '../../base.directive';
-import { IMapPoint } from '../map.interfaces';
-import { AMapFeature } from '../map-feature/map-feature.class';
-
-@Component({
- selector: 'aca-map-renderer',
- templateUrl: `./map-renderer.template.html`,
- styleUrls: [`./map-renderer.styles.scss`]
-})
-export class MapRendererComponent extends BaseWidgetDirective implements OnInit, OnChanges {
- /** Zoom level of the map */
- @Input() public scale = 1;
- /** Point within the map to center in the view */
- @Input() public center: IMapPoint = { x: .5, y: .5 };
- /** URL of the Map SVG to render */
- @Input() public src = '';
- /** CSS styles to apply to the map */
- @Input() public css = '';
- /** Re-renders the map on changes to this */
- @Input() public redraw: any = null;
- /** List of points of interest */
- @Input() public items: AMapFeature[];
- /** Change emitter for SVG DOM element */
- @Output() public map = new EventEmitter();
-
- /** Block to render SVG element */
- @ViewChild('renderBlock', { static: true }) public render_block: ElementRef;
- /** Canvas to render static images of map when zooming */
- @ViewChild('canvas', { static: true }) private canvas: ElementRef;
- @ViewChild('content', { static: true }) private content: ElementRef;
- @ViewChild('container', { static: true }) private container: ElementRef;
-
- public model: { [name: string]: any } = {};
-
- constructor(private service: MapService, private renderer: Renderer2, private el: ElementRef) {
- super();
- this.model.is_IE = navigator.appName == 'Microsoft Internet Explorer' || !!(navigator.userAgent.match(/Trident/) || navigator.userAgent.match(/rv:11/)) || !!navigator.userAgent.match(/MSIE/g);
- }
-
- public ngOnInit() {
- this.subs.obs.resize = this.renderer.listen('window', 'resize', () => this.resize());
- this.model.center = { x: .5, y: .5 };
- this.model.position = { x: -50, y: -50 };
- this.model.loading = true;
- if (this.el) { this.renderer.setAttribute(this.el.nativeElement, `map-${this.id}`, 'true') }
- }
-
- public ngOnChanges(changes: SimpleChanges) {
- super.ngOnChanges(changes);
- if (changes.scale || changes.center) {
- this.update();
- }
- if (changes.src) {
- this.loadMap();
- }
- if (changes.redraw || changes.css) {
- this.renderImage();
- }
- }
-
- public get isIE() {
- return this.model.is_IE;
- }
-
- /**
- * Update display of map
- */
- public update() {
- this.timeout('update', () => {
- this.model.zooming = false;
- this.model.panning = false;
- this.updateZoom();
- this.updatePosition();
- }, 5);
- }
-
- /**
- * Update the drawn zoom level of the map
- */
- public updateZoom() {
- const scale = (this.scale || 1) * 100;
- if (!this.model.zoom) { this.model.zoom = scale; }
- if (this.model.zoom !== scale) {
- this.model.zooming = true;
- const dir = scale - this.model.zoom < 0 ? -1 : 1;
- this.model.zoom += Math.min(Math.max(.1, Math.abs(scale - this.model.zoom) / 10), 50) * dir;
- if (Math.abs(scale - this.model.zoom) < .5) { this.model.zoom = scale }
- this.update();
- }
- }
-
- /**
- * Update the drawn position of the map
- */
- public updatePosition() {
- const center = this.center || { x: .5, y: .5};
- if (!this.model.center) { this.model.center = center; }
- if (this.model.center.x !== center.x) {
- this.model.panning = true;
- const dir = center.x - this.model.center.x < 0 ? -1 : 1;
- this.model.center.x += Math.min(Math.max(.0001, Math.abs(center.x - this.model.center.x) / 5), .1) * dir;
- if (Math.abs(center.x - this.model.center.x) < .005) { this.model.center.x = center.x }
- this.update();
- }
- if (this.model.center.y !== center.y) {
- this.model.panning = true;
- const dir = center.y - this.model.center.y < 0 ? -1 : 1;
- this.model.center.y += Math.min(Math.max(.0001, Math.abs(center.y - this.model.center.y) / 5), .1) * dir;
- if (Math.abs(center.y - this.model.center.y) < .005) { this.model.center.y = center.y }
- this.update();
- }
- // Generate draw position
- this.model.position = {
- x: -50 -((this.model.center.x - .5) * 100),
- y: -50 -((this.model.center.y - .5) * 100)
- };
- }
-
- /**
- * Load map data from SVG file
- */
- private loadMap() {
- this.model.loading = true;
- this.map.emit(null);
- this.model.map_data = '';
- this.service.loadMap(this.src).then((data) => {
- this.model.map_data = data;
- this.timeout('load', () => {
- if (this.content) {
- this.model.loading = true;
- this.model.map = this.content.nativeElement.querySelector('svg');
- this.renderImage();
- this.timeout('resize', () => this.resize());
- if (this.model.map) {
- this.renderer.setAttribute(this.model.map, 'preserveAspectRatio', 'xMidYMid meet');
- this.renderer.setStyle(this.model.map, 'width', '100%');
- }
- this.map.emit(this.model.map);
- }
- });
- }, () => this.service.log('Error', `Unable to load map '${this.src}'`));
- }
-
- /**
- * Render SVG map to an image to draw while zooming
- */
- private renderImage() {
- this.timeout('render', () => {
- if (!this.content || !this.model.map) {
- return this.renderImage();
- }
- let box = this.model.map.getBoundingClientRect();
- let width = window.devicePixelRatio * window.innerWidth;
- let ratio = (box.width / box.height) || 1;
- if (this.model.img) { delete this.model.img; }
- this.model.img = document.createElement('img');
- const canvas = this.canvas.nativeElement;
- const context = canvas.getContext('2d');
- this.model.img.onerror = (err) => console.log(err);
- this.model.img.onload = () => {
- canvas.width = width;
- canvas.height = width / ratio;
- context.drawImage(this.model.img, 0, 0, canvas.width, canvas.height);
- };
- const data_with_styles = (this.model.map_data || '').replace(``, `${this.css}`)
- .replace('