Merge pull request #45 from antvis/encode

add component
This commit is contained in:
@thinkinggis 2019-10-25 10:59:37 +08:00 committed by GitHub
commit b61be25c30
64 changed files with 3848 additions and 118 deletions

View File

@ -2,7 +2,6 @@ import { configure, addParameters } from '@storybook/react';
import '@storybook/addon-console';
import { create } from '@storybook/theming';
import '!style-loader!css-loader!sass-loader!./iframe.scss';
addParameters({
options: {
isFullscreen: false,

397
.storybook/l7.css Normal file
View File

@ -0,0 +1,397 @@
.l7-marker {
position: absolute !important;
top: 0;
left: 0;
z-index: 5;
}
.l7-popup-anchor-top,
.l7-popup-anchor-top-left,
.l7-popup-anchor-top-right {
-webkit-flex-direction: column;
flex-direction: column;
}
.l7-popup-anchor-bottom,
.l7-popup-anchor-bottom-left,
.l7-popup-anchor-bottom-right {
-webkit-flex-direction: column-reverse;
flex-direction: column-reverse;
}
.l7-popup-anchor-left {
-webkit-flex-direction: row;
flex-direction: row;
}
.l7-popup-anchor-right {
-webkit-flex-direction: row-reverse;
flex-direction: row-reverse;
}
.l7-popup {
position: absolute;
top: 0;
left: 0;
display: -webkit-flex;
display: flex;
will-change: transform;
pointer-events: none;
z-index: 5;
}
.l7-popup-tip {
width: 0;
height: 0;
border: 10px solid transparent;
z-index: 1;
}
.l7-popup-anchor-top .l7-popup-tip {
-webkit-align-self: center;
align-self: center;
border-top: none;
border-bottom-color: #fff;
}
.l7-popup-anchor-top-left .l7-popup-tip {
-webkit-align-self: flex-start;
align-self: flex-start;
border-top: none;
border-left: none;
border-bottom-color: #fff;
}
.l7-popup-anchor-top-right .l7-popup-tip {
-webkit-align-self: flex-end;
align-self: flex-end;
border-top: none;
border-right: none;
border-bottom-color: #fff;
}
.l7-popup-anchor-bottom .l7-popup-tip {
-webkit-align-self: center;
align-self: center;
border-bottom: none;
border-top-color: #fff;
}
.l7-popup-anchor-bottom-left .l7-popup-tip {
-webkit-align-self: flex-start;
align-self: flex-start;
border-bottom: none;
border-left: none;
border-top-color: #fff;
}
.l7-popup-anchor-bottom-right .l7-popup-tip {
-webkit-align-self: flex-end;
align-self: flex-end;
border-bottom: none;
border-right: none;
border-top-color: #fff;
}
.l7-popup-anchor-left .l7-popup-tip {
-webkit-align-self: center;
align-self: center;
border-left: none;
border-right-color: #fff;
}
.l7-popup-anchor-right .l7-popup-tip {
-webkit-align-self: center;
align-self: center;
border-right: none;
border-left-color: #fff;
}
.l7-popup-close-button {
position: absolute;
right: 0;
top: 0;
border: 0;
padding: 0;
font-size: 25px;
line-height: 20px;
border-radius: 0 3px 0 0;
cursor: pointer;
background-color: transparent;
}
.l7-popup-close-button:hover {
background-color: rgba(0, 0, 0, 0.05);
}
.l7-popup-content {
position: relative;
background: #fff;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
padding: 10px 10px 15px;
pointer-events: auto;
}
.l7-popup-anchor-top-left .l7-popup-content {
border-top-left-radius: 0;
}
.l7-popup-anchor-top-right .l7-popup-content {
border-top-right-radius: 0;
}
.l7-popup-anchor-bottom-left .l7-popup-content {
border-bottom-left-radius: 0;
}
.l7-popup-anchor-bottom-right .l7-popup-content {
border-bottom-right-radius: 0;
}
.l7-popup-track-pointer {
display: none;
}
.l7-popup-track-pointer * {
pointer-events: none;
user-select: none;
}
.l7-map:hover .l7-popup-track-pointer {
display: flex;
}
.l7-map:active .l7-popup-track-pointer {
display: none;
}
.l7-popup-close-button {
position: absolute;
right: 0;
top: 0;
border: 0;
border-radius: 0 3px 0 0;
cursor: pointer;
background-color: transparent;
}
.l7-popup-close-button:hover {
background-color: rgba(0, 0, 0, 0.05);
}
.l7-popup-content {
position: relative;
background: #fff;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
padding: 10px 10px 15px;
pointer-events: auto;
}
/* general toolbar styles */
.l7-bar {
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
border-radius: 4px;
}
.l7-bar a,
.l7-bar a:hover {
background-color: #fff;
border-bottom: 1px solid #ccc;
width: 26px;
height: 26px;
line-height: 26px;
display: block;
text-align: center;
text-decoration: none;
color: black;
}
.l7-bar a,
.l7-control-layers-toggle {
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}
.l7-bar a:hover {
background-color: #f4f4f4;
}
.l7-bar a:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.l7-bar a:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: none;
}
.l7-bar a.l7-disabled {
cursor: default;
background-color: #f4f4f4;
color: #bbb;
}
/* control positioning */
.l7-control-container {
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
}
.l7-control-hide {
display: none;
}
.l7-control {
position: relative;
z-index: 800;
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
.l7-top,
.l7-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.l7-top {
top: 0;
}
.l7-right {
right: 0;
}
.l7-bottom {
bottom: 0;
}
.l7-left {
left: 0;
}
.l7-control {
float: left;
clear: both;
}
.l7-right .l7-control {
float: right;
}
.l7-top .l7-control {
margin-top: 10px;
}
.l7-bottom .l7-control {
margin-bottom: 10px;
}
.l7-left .l7-control {
margin-left: 10px;
}
.l7-right .l7-control {
margin-right: 10px;
}
/* attribution and scale controls */
.l7-control-container .l7-control-attribution {
background: #fff;
background: rgba(255, 255, 255, 0.7);
margin: 0;
}
.l7-control-attribution,
.l7-control-scale-line {
padding: 0 5px;
color: #333;
}
.l7-control-attribution a {
text-decoration: none;
}
.l7-control-attribution a:hover {
text-decoration: underline;
}
.l7-container .l7-control-attribution,
.l7-container .l7-control-scale {
font-size: 11px;
}
.l7-left .l7-control-scale {
margin-left: 5px;
}
.l7-bottom .l7-control-scale {
margin-bottom: 5px;
}
.l7-control-scale-line {
border: 2px solid #777;
border-top: none;
line-height: 1.1;
padding: 2px 5px 1px;
font-size: 11px;
white-space: nowrap;
overflow: hidden;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: #fff;
background: rgba(255, 255, 255, 0.5);
}
.l7-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
border-bottom: none;
margin-top: -2px;
}
.l7-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
}
.l7-touch .l7-control-attribution,
.l7-touch .l7-control-layers,
.l7-touch .l7-bar {
box-shadow: none;
}
.l7-touch .l7-control-layers,
.l7-touch .l7-bar {
border: 2px solid rgba(0,0,0,0.2);
background-clip: padding-box;
}
/* layers control */
.l7-control-layers {
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
background: #fff;
border-radius: 5px;
}
.l7-control-layers-toggle {
background-image: url(../images/layers.svg);
width: 36px;
height: 36px;
}
.l7-retina .l7-control-layers-toggle {
background-image: url(../images/layers.svg);
background-size: 26px 26px;
}
.l7-touch .l7-control-layers-toggle {
width: 44px;
height: 44px;
}
.l7-control-layers .l7-control-layers-list,
.l7-control-layers-expanded .l7-control-layers-toggle {
display: none;
}
.l7-control-layers-expanded .l7-control-layers-list {
display: block;
position: relative;
}
.l7-control-layers-expanded {
padding: 6px 10px 6px 6px;
color: #333;
background: #fff;
}
.l7-control-layers-scrollbar {
overflow-y: scroll;
overflow-x: hidden;
padding-right: 5px;
}
.l7-control-layers-selector {
margin-top: 2px;
position: relative;
top: 1px;
}
.l7-control-layers label {
display: block;
}
.l7-control-layers-separator {
height: 0;
border-top: 1px solid #ddd;
margin: 5px -10px 5px -6px;
}

View File

@ -27,9 +27,13 @@ module.exports = ({ config }) => {
},
],
enforce: 'pre',
});
},{
test: /\.stories\.css?$/,
use: ['style-loader', 'css-loader'],
},
);
config.resolve.extensions.push('.ts', '.tsx', '.js', '.glsl');
return config;
};
};

View File

@ -77,4 +77,4 @@ module.exports = (api) => {
},
ignore: ['node_modules'],
};
}
}

231
package-lock.json generated
View File

@ -5524,6 +5524,16 @@
"@babel/plugin-syntax-typescript": "^7.3.3"
}
},
"babel-plugin-css-modules-transform": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/babel-plugin-css-modules-transform/-/babel-plugin-css-modules-transform-1.6.2.tgz",
"integrity": "sha512-zBsI54N5n979vfYpqFzQ6oRwEiVcmLH5REyaincNW+Ecl52nvRsQPYIbDcJzHePrXI20YSRUw6G/qbPwZZDgfg==",
"dev": true,
"requires": {
"css-modules-require-hook": "^4.0.6",
"mkdirp": "^0.5.1"
}
},
"babel-plugin-dynamic-import-node": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz",
@ -8289,6 +8299,84 @@
}
}
},
"css-modules-require-hook": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/css-modules-require-hook/-/css-modules-require-hook-4.2.3.tgz",
"integrity": "sha1-Z5LKQSsV4j5vm+agfc739Xf/kE0=",
"dev": true,
"requires": {
"debug": "^2.2.0",
"generic-names": "^1.0.1",
"glob-to-regexp": "^0.3.0",
"icss-replace-symbols": "^1.0.2",
"lodash": "^4.3.0",
"postcss": "^6.0.1",
"postcss-modules-extract-imports": "^1.0.0",
"postcss-modules-local-by-default": "^1.0.1",
"postcss-modules-resolve-imports": "^1.3.0",
"postcss-modules-scope": "^1.0.0",
"postcss-modules-values": "^1.1.1",
"seekout": "^1.0.1"
},
"dependencies": {
"postcss": {
"version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
"integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
"dev": true,
"requires": {
"chalk": "^2.4.1",
"source-map": "^0.6.1",
"supports-color": "^5.4.0"
}
},
"postcss-modules-extract-imports": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz",
"integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==",
"dev": true,
"requires": {
"postcss": "^6.0.1"
}
},
"postcss-modules-local-by-default": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz",
"integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=",
"dev": true,
"requires": {
"css-selector-tokenizer": "^0.7.0",
"postcss": "^6.0.1"
}
},
"postcss-modules-scope": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz",
"integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=",
"dev": true,
"requires": {
"css-selector-tokenizer": "^0.7.0",
"postcss": "^6.0.1"
}
},
"postcss-modules-values": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz",
"integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=",
"dev": true,
"requires": {
"icss-replace-symbols": "^1.1.0",
"postcss": "^6.0.1"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"css-select": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
@ -8307,6 +8395,57 @@
"integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==",
"dev": true
},
"css-selector-tokenizer": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz",
"integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==",
"dev": true,
"requires": {
"cssesc": "^0.1.0",
"fastparse": "^1.1.1",
"regexpu-core": "^1.0.0"
},
"dependencies": {
"cssesc": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz",
"integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=",
"dev": true
},
"jsesc": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
"integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
"dev": true
},
"regexpu-core": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz",
"integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=",
"dev": true,
"requires": {
"regenerate": "^1.2.1",
"regjsgen": "^0.2.0",
"regjsparser": "^0.1.4"
}
},
"regjsgen": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
"integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
"dev": true
},
"regjsparser": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
"integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
"dev": true,
"requires": {
"jsesc": "~0.5.0"
}
}
}
},
"css-to-react-native": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-2.3.2.tgz",
@ -9927,6 +10066,12 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
"fastparse": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
"integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
"dev": true
},
"fastq": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz",
@ -11038,6 +11183,41 @@
"globule": "^1.0.0"
}
},
"generic-names": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/generic-names/-/generic-names-1.0.3.tgz",
"integrity": "sha1-LXhqEhruUIh2eWk56OO/+DbCCRc=",
"dev": true,
"requires": {
"loader-utils": "^0.2.16"
},
"dependencies": {
"big.js": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
"integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==",
"dev": true
},
"json5": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
"dev": true
},
"loader-utils": {
"version": "0.2.17",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz",
"integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=",
"dev": true,
"requires": {
"big.js": "^3.1.3",
"emojis-list": "^2.0.0",
"json5": "^0.5.0",
"object-assign": "^4.0.1"
}
}
}
},
"genfun": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz",
@ -16836,6 +17016,51 @@
}
}
},
"postcss-modules-resolve-imports": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/postcss-modules-resolve-imports/-/postcss-modules-resolve-imports-1.3.0.tgz",
"integrity": "sha1-OY0wALla6WlCDN9M2D+oBn8cXq4=",
"dev": true,
"requires": {
"css-selector-tokenizer": "^0.7.0",
"icss-utils": "^3.0.1",
"minimist": "^1.2.0"
},
"dependencies": {
"icss-utils": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-3.0.1.tgz",
"integrity": "sha1-7nDTroysOMa+XtkehRsn7tNDrQ8=",
"dev": true,
"requires": {
"postcss": "^6.0.2"
}
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
},
"postcss": {
"version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
"integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
"dev": true,
"requires": {
"chalk": "^2.4.1",
"source-map": "^0.6.1",
"supports-color": "^5.4.0"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"postcss-modules-scope": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz",
@ -18969,6 +19194,12 @@
}
}
},
"seekout": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/seekout/-/seekout-1.0.2.tgz",
"integrity": "sha1-CbqfG9W0b7sTRxjrGaaDgsuxuck=",
"dev": true
},
"select": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",

View File

@ -27,11 +27,13 @@
"babel-jest": "^24.8.0",
"babel-loader": "^8.0.6",
"babel-plugin-const-enum": "^0.0.2",
"babel-plugin-css-modules-transform": "^1.6.2",
"babel-plugin-inline-import": "^3.0.0",
"babel-plugin-transform-postcss": "^0.3.0",
"clean-webpack-plugin": "^0.1.19",
"commitizen": "^4.0.3",
"copy-webpack-plugin": "^4.5.2",
"css-loader": "^3.0.0",
"css-loader": "^3.2.0",
"cz-conventional-changelog": "^3.0.2",
"dat.gui": "^0.7.2",
"enzyme": "^3.6.0",
@ -45,6 +47,8 @@
"lint-staged": "^9.2.4",
"node-sass": "^4.12.0",
"npm-run-all": "^4.1.5",
"postcss": "^7.0.18",
"postcss-plugin": "^1.0.0",
"prettier": "^1.14.2",
"raw-loader": "^1.0.0",
"react": "^16.8.6",
@ -52,7 +56,7 @@
"react-dom": "^16.8.6",
"rimraf": "^2.6.2",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"style-loader": "^1.0.0",
"styled-components": "^3.4.6",
"stylelint": "^9.5.0",
"stylelint-config-recommended": "^2.1.0",

3
packages/component/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
lib
esm
dist

View File

@ -0,0 +1,33 @@
{
"name": "@l7/component",
"version": "0.0.1",
"description": "",
"main": "/dist/index.js",
"module": "esm/index.js",
"types": "esm/index.d.ts",
"sideEffects": true,
"files": [
"lib",
"esm",
"README.md"
],
"scripts": {
"tsc": "tsc --project tsconfig.build.json",
"build": "BABEL_ENV=build babel src --root-mode upward --out-dir dist --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments",
"watch": "BABEL_ENV=build babel src --watch --root-mode upward --out-dir dist --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments",
"lint:ts": "run-p -c lint:ts-*",
"test": "jest"
},
"author": "lzxue",
"license": "ISC",
"dependencies": {
"@l7/core": "0.0.1",
"@l7/utils": "0.0.1",
"@turf/distance": "^6.0.1",
"eventemitter3": "^3.1.0",
"inversify": "^5.0.1",
"inversify-inject-decorators": "^3.1.0",
"inversify-logging": "^0.2.1"
},
"devDependencies": {}
}

View File

@ -0,0 +1,96 @@
import { IControlService, IMapService, lazyInject, TYPES } from '@l7/core';
import { DOM } from '@l7/utils';
import { EventEmitter } from 'eventemitter3';
export enum PositionType {
'TOPRIGHT' = 'topright',
'TOPLEFT' = 'topleft',
'BOTTOMRIGHT' = 'bottomright',
'BOTTOMLEFT' = 'bottomleft',
}
export type PositionName =
| 'topright'
| 'topleft'
| 'bottomright'
| 'bottomleft';
export interface IControlOption {
position: PositionName;
[key: string]: any;
}
export default class Control extends EventEmitter {
public controlOption: IControlOption;
protected mapsService: IMapService;
@lazyInject(TYPES.IControlService)
private readonly controlService: IControlService;
private container: HTMLElement;
private isShow: boolean;
constructor(cfg?: Partial<IControlOption>) {
super();
this.controlOption = {
...this.getDefault(),
...(cfg || {}),
};
}
public getDefault() {
return {
position: PositionType.TOPRIGHT,
};
}
public setPosition(position: PositionName) {
const controlService = this.controlService;
if (controlService) {
controlService.removeControl(this);
}
this.controlOption.position = position;
if (controlService) {
controlService.addControl(this, this.mapsService);
}
return this;
}
public addTo(mapService: IMapService) {
this.remove();
this.isShow = true;
this.mapsService = mapService;
this.container = this.onAdd(mapService);
const container = this.container;
const pos = this.controlOption.position;
const corner = this.controlService.controlCorners[pos];
DOM.addClass(container, 'l7-control');
if (pos.indexOf('bottom') !== -1) {
corner.insertBefore(container, corner.firstChild);
} else {
corner.appendChild(container);
}
return this;
}
public onAdd(Map: IMapService): HTMLElement {
throw new Error('Method not implemented.');
}
public hide() {
const container = this.container;
DOM.addClass(container, 'l7-control-hide');
this.isShow = false;
}
public show() {
const container = this.container;
DOM.removeClass(container, 'l7-control-hide');
this.isShow = true;
}
public remove() {
if (!this.mapsService) {
return this;
}
DOM.remove(this.container);
}
public _refocusOnMap(e: MouseEvent) {
// if map exists and event is not a keyboard event
if (this.mapsService && e && e.screenX > 0 && e.screenY > 0) {
const container = this.mapsService.getContainer();
if (container !== null) {
container.focus();
}
}
}
}

View File

@ -0,0 +1,47 @@
import { IMapService } from '@l7/core';
import { bindAll, DOM, lnglatDistance } from '@l7/utils';
import Control, {
IControlOption,
PositionName,
PositionType,
} from './BaseControl';
export interface ILayerControlOption extends IControlOption {
collapsed: boolean;
autoZIndex: boolean;
hideSingleBase: boolean;
sortLayers: boolean;
}
export default class Layers extends Control {
private layerControlInputs: any[];
private layers: any[];
private lastZIndex: number;
private handlingClick: boolean;
constructor(cfg: Partial<ILayerControlOption>) {
super(cfg);
this.layerControlInputs = [];
this.layers = [];
this.lastZIndex = 0;
this.handlingClick = false;
// const baseLayers = this.get('baseLayers');
// const overlays = this.get('overlayers');
// for (const i in baseLayers) {
// this._addLayer(baseLayers[i], i);
// }
// for (const i in overlays) {
// this._addLayer(overlays[i], i, true);
// }
// bindAll([ '_checkDisabledLayers', '_onLayerChange', 'collapse', 'extend', 'expand', '_onInputClick' ], this);
}
public getDefault() {
return {
collapsed: true,
position: PositionType.TOPRIGHT,
autoZIndex: true,
hideSingleBase: false,
sortLayers: false,
};
}
}

View File

@ -0,0 +1,104 @@
import { IMapService } from '@l7/core';
import { bindAll, DOM, lnglatDistance } from '@l7/utils';
import Control, { IControlOption, PositionType } from './BaseControl';
export interface IScaleControlOption extends IControlOption {
maxWidth: number;
metric: boolean;
updateWhenIdle: boolean;
imperial: boolean;
}
export default class Scale extends Control {
private mScale: HTMLElement;
private iScale: HTMLElement;
constructor(cfg?: Partial<IScaleControlOption>) {
super(cfg);
bindAll(['update'], this);
}
public getDefault() {
return {
position: PositionType.BOTTOMLEFT,
maxWidth: 100,
metric: true,
updateWhenIdle: false,
imperial: false,
};
}
public onAdd(MapService: IMapService) {
const className = 'l7-control-scale';
const container = DOM.create('div', className);
this.addScales(className + '-line', container);
const { updateWhenIdle } = this.controlOption;
// TODO: 高德地图和MapBox地图事件不一致问题
this.mapsService.on(updateWhenIdle ? 'moveend' : 'mapmove', this.update);
this.update();
return container;
}
public onRemove(MapService: IMapService) {
const { updateWhenIdle } = this.controlOption;
this.mapsService.off(updateWhenIdle ? 'moveend' : 'mapmove', this.update);
}
public update() {
const mapsService = this.mapsService;
const { maxWidth } = this.controlOption;
const y = mapsService.getSize()[1] / 2;
const p1 = mapsService.containerToLngLat([0, y]);
const p2 = mapsService.containerToLngLat([maxWidth, y]);
const maxMeters = lnglatDistance([p1.lng, p1.lat], [p2.lng, p2.lat]);
this.updateScales(maxMeters);
}
public updateScales(maxMeters: number) {
const { metric, imperial } = this.controlOption;
if (metric && maxMeters) {
this.updateMetric(maxMeters);
}
if (imperial && maxMeters) {
this.updateImperial(maxMeters);
}
}
private updateMetric(maxMeters: number) {
const meters = this.getRoundNum(maxMeters);
const label = meters < 1000 ? meters + ' m' : meters / 1000 + ' km';
this.updateScale(this.mScale, label, meters / maxMeters);
}
private updateImperial(maxMeters: number) {
const maxFeet = maxMeters * 3.2808399;
let maxMiles: number;
let miles: number;
let feet: number;
if (maxFeet > 5280) {
maxMiles = maxFeet / 5280;
miles = this.getRoundNum(maxMiles);
this.updateScale(this.iScale, miles + ' mi', miles / maxMiles);
} else {
feet = this.getRoundNum(maxFeet);
this.updateScale(this.iScale, feet + ' ft', feet / maxFeet);
}
}
private updateScale(scale: HTMLElement, text: string, ratio: number) {
const { maxWidth } = this.controlOption;
scale.style.width = Math.round(maxWidth * ratio) + 'px';
scale.innerHTML = text;
}
private getRoundNum(num: number) {
const pow10 = Math.pow(10, (Math.floor(num) + '').length - 1);
let d = num / pow10;
d = d >= 10 ? 10 : d >= 5 ? 5 : d >= 3 ? 3 : d >= 2 ? 2 : 1;
return pow10 * d;
}
private addScales(className: string, container: HTMLElement) {
const { metric, imperial } = this.controlOption;
if (metric) {
this.mScale = DOM.create('div', className, container);
}
if (imperial) {
this.iScale = DOM.create('div', className, container);
}
}
}

View File

@ -0,0 +1,111 @@
import { IMapService } from '@l7/core';
import { bindAll, DOM } from '@l7/utils';
import Control, { IControlOption, PositionType } from './BaseControl';
export interface IZoomControlOption extends IControlOption {
zoomInText: string;
zoomInTitle: string;
zoomOutText: string;
zoomOutTitle: string;
}
export default class Zoom extends Control {
private disabled: boolean;
private zoomInButton: HTMLElement;
private zoomOutButton: HTMLElement;
constructor(cfg?: Partial<IZoomControlOption>) {
super(cfg);
bindAll(['updateDisabled', 'zoomIn', 'zoomOut'], this);
}
public getDefault() {
return {
position: PositionType.TOPLEFT,
zoomInText: '+',
zoomInTitle: 'Zoom in',
zoomOutText: '&#x2212;',
zoomOutTitle: 'Zoom out',
};
}
public onAdd(MapService: IMapService) {
const zoomName = 'l7-control-zoom';
const container = DOM.create('div', zoomName + ' l7-bar');
this.zoomInButton = this.createButton(
this.controlOption.zoomInText,
this.controlOption.zoomInTitle,
zoomName + '-in',
container,
this.zoomIn,
);
this.zoomOutButton = this.createButton(
this.controlOption.zoomOutText,
this.controlOption.zoomOutTitle,
zoomName + '-out',
container,
this.zoomOut,
);
this.mapsService.on('zoomend', this.updateDisabled);
this.mapsService.on('zoomchange', this.updateDisabled);
this.updateDisabled();
return container;
}
public onRemove() {
this.mapsService.off('zoomend', this.updateDisabled);
this.mapsService.off('zoomchange', this.updateDisabled);
}
public disable() {
this.disabled = true;
this.updateDisabled();
return this;
}
public enable() {
this.disabled = false;
this.updateDisabled();
return this;
}
private zoomIn() {
if (
!this.disabled &&
this.mapsService.getZoom() < this.mapsService.getMaxZoom()
) {
this.mapsService.zoomIn();
}
}
private zoomOut() {
if (
!this.disabled &&
this.mapsService.getZoom() > this.mapsService.getMinZoom()
) {
this.mapsService.zoomOut();
}
}
private createButton(
html: string,
tile: string,
className: string,
container: HTMLElement,
fn: (...arg: any[]) => any,
) {
const link = DOM.create('a', className, container) as HTMLLinkElement;
link.innerHTML = html;
link.href = '#';
link.addEventListener('click', fn);
return link;
}
private updateDisabled() {
const mapsService = this.mapsService;
const className = 'l7-disabled';
DOM.removeClass(this.zoomInButton, className);
DOM.removeClass(this.zoomOutButton, className);
if (this.disabled || mapsService.getZoom() <= mapsService.getMinZoom()) {
DOM.addClass(this.zoomOutButton, className);
}
if (this.disabled || mapsService.getZoom() >= mapsService.getMaxZoom()) {
DOM.addClass(this.zoomInButton, className);
}
}
}

View File

@ -0,0 +1,397 @@
.l7-marker {
position: absolute !important;
top: 0;
left: 0;
z-index: 5;
}
.l7-popup-anchor-top,
.l7-popup-anchor-top-left,
.l7-popup-anchor-top-right {
-webkit-flex-direction: column;
flex-direction: column;
}
.l7-popup-anchor-bottom,
.l7-popup-anchor-bottom-left,
.l7-popup-anchor-bottom-right {
-webkit-flex-direction: column-reverse;
flex-direction: column-reverse;
}
.l7-popup-anchor-left {
-webkit-flex-direction: row;
flex-direction: row;
}
.l7-popup-anchor-right {
-webkit-flex-direction: row-reverse;
flex-direction: row-reverse;
}
.l7-popup {
position: absolute;
top: 0;
left: 0;
display: -webkit-flex;
display: flex;
will-change: transform;
pointer-events: none;
z-index: 5;
}
.l7-popup-tip {
width: 0;
height: 0;
border: 10px solid transparent;
z-index: 1;
}
.l7-popup-anchor-top .l7-popup-tip {
-webkit-align-self: center;
align-self: center;
border-top: none;
border-bottom-color: #fff;
}
.l7-popup-anchor-top-left .l7-popup-tip {
-webkit-align-self: flex-start;
align-self: flex-start;
border-top: none;
border-left: none;
border-bottom-color: #fff;
}
.l7-popup-anchor-top-right .l7-popup-tip {
-webkit-align-self: flex-end;
align-self: flex-end;
border-top: none;
border-right: none;
border-bottom-color: #fff;
}
.l7-popup-anchor-bottom .l7-popup-tip {
-webkit-align-self: center;
align-self: center;
border-bottom: none;
border-top-color: #fff;
}
.l7-popup-anchor-bottom-left .l7-popup-tip {
-webkit-align-self: flex-start;
align-self: flex-start;
border-bottom: none;
border-left: none;
border-top-color: #fff;
}
.l7-popup-anchor-bottom-right .l7-popup-tip {
-webkit-align-self: flex-end;
align-self: flex-end;
border-bottom: none;
border-right: none;
border-top-color: #fff;
}
.l7-popup-anchor-left .l7-popup-tip {
-webkit-align-self: center;
align-self: center;
border-left: none;
border-right-color: #fff;
}
.l7-popup-anchor-right .l7-popup-tip {
-webkit-align-self: center;
align-self: center;
border-right: none;
border-left-color: #fff;
}
.l7-popup-close-button {
position: absolute;
right: 0;
top: 0;
border: 0;
padding: 0;
font-size: 25px;
line-height: 20px;
border-radius: 0 3px 0 0;
cursor: pointer;
background-color: transparent;
}
.l7-popup-close-button:hover {
background-color: rgba(0, 0, 0, 0.05);
}
.l7-popup-content {
position: relative;
background: #fff;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
padding: 10px 10px 15px;
pointer-events: auto;
}
.l7-popup-anchor-top-left .l7-popup-content {
border-top-left-radius: 0;
}
.l7-popup-anchor-top-right .l7-popup-content {
border-top-right-radius: 0;
}
.l7-popup-anchor-bottom-left .l7-popup-content {
border-bottom-left-radius: 0;
}
.l7-popup-anchor-bottom-right .l7-popup-content {
border-bottom-right-radius: 0;
}
.l7-popup-track-pointer {
display: none;
}
.l7-popup-track-pointer * {
pointer-events: none;
user-select: none;
}
.l7-map:hover .l7-popup-track-pointer {
display: flex;
}
.l7-map:active .l7-popup-track-pointer {
display: none;
}
.l7-popup-close-button {
position: absolute;
right: 0;
top: 0;
border: 0;
border-radius: 0 3px 0 0;
cursor: pointer;
background-color: transparent;
}
.l7-popup-close-button:hover {
background-color: rgba(0, 0, 0, 0.05);
}
.l7-popup-content {
position: relative;
background: #fff;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
padding: 10px 10px 15px;
pointer-events: auto;
}
/* general toolbar styles */
.l7-bar {
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
border-radius: 4px;
}
.l7-bar a,
.l7-bar a:hover {
background-color: #fff;
border-bottom: 1px solid #ccc;
width: 26px;
height: 26px;
line-height: 26px;
display: block;
text-align: center;
text-decoration: none;
color: black;
}
.l7-bar a,
.l7-control-layers-toggle {
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}
.l7-bar a:hover {
background-color: #f4f4f4;
}
.l7-bar a:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.l7-bar a:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: none;
}
.l7-bar a.l7-disabled {
cursor: default;
background-color: #f4f4f4;
color: #bbb;
}
/* control positioning */
.l7-control-container {
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
}
.l7-control-hide {
display: none;
}
.l7-control {
position: relative;
z-index: 800;
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
.l7-top,
.l7-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.l7-top {
top: 0;
}
.l7-right {
right: 0;
}
.l7-bottom {
bottom: 0;
}
.l7-left {
left: 0;
}
.l7-control {
float: left;
clear: both;
}
.l7-right .l7-control {
float: right;
}
.l7-top .l7-control {
margin-top: 10px;
}
.l7-bottom .l7-control {
margin-bottom: 10px;
}
.l7-left .l7-control {
margin-left: 10px;
}
.l7-right .l7-control {
margin-right: 10px;
}
/* attribution and scale controls */
.l7-control-container .l7-control-attribution {
background: #fff;
background: rgba(255, 255, 255, 0.7);
margin: 0;
}
.l7-control-attribution,
.l7-control-scale-line {
padding: 0 5px;
color: #333;
}
.l7-control-attribution a {
text-decoration: none;
}
.l7-control-attribution a:hover {
text-decoration: underline;
}
.l7-container .l7-control-attribution,
.l7-container .l7-control-scale {
font-size: 11px;
}
.l7-left .l7-control-scale {
margin-left: 5px;
}
.l7-bottom .l7-control-scale {
margin-bottom: 5px;
}
.l7-control-scale-line {
border: 2px solid #777;
border-top: none;
line-height: 1.1;
padding: 2px 5px 1px;
font-size: 11px;
white-space: nowrap;
overflow: hidden;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: #fff;
background: rgba(255, 255, 255, 0.5);
}
.l7-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
border-bottom: none;
margin-top: -2px;
}
.l7-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
}
.l7-touch .l7-control-attribution,
.l7-touch .l7-control-layers,
.l7-touch .l7-bar {
box-shadow: none;
}
.l7-touch .l7-control-layers,
.l7-touch .l7-bar {
border: 2px solid rgba(0,0,0,0.2);
background-clip: padding-box;
}
/* layers control */
.l7-control-layers {
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
background: #fff;
border-radius: 5px;
}
.l7-control-layers-toggle {
background-image: url(../images/layers.svg);
width: 36px;
height: 36px;
}
.l7-retina .l7-control-layers-toggle {
background-image: url(../images/layers.svg);
background-size: 26px 26px;
}
.l7-touch .l7-control-layers-toggle {
width: 44px;
height: 44px;
}
.l7-control-layers .l7-control-layers-list,
.l7-control-layers-expanded .l7-control-layers-toggle {
display: none;
}
.l7-control-layers-expanded .l7-control-layers-list {
display: block;
position: relative;
}
.l7-control-layers-expanded {
padding: 6px 10px 6px 6px;
color: #333;
background: #fff;
}
.l7-control-layers-scrollbar {
overflow-y: scroll;
overflow-x: hidden;
padding-right: 5px;
}
.l7-control-layers-selector {
margin-top: 2px;
position: relative;
top: 1px;
}
.l7-control-layers label {
display: block;
}
.l7-control-layers-separator {
height: 0;
border-top: 1px solid #ddd;
margin: 5px -10px 5px -6px;
}

View File

@ -0,0 +1,6 @@
import Control from './control/BaseControl';
import Scale from './control/scale';
import Zoom from './control/zoom';
import Marker from './marker';
import Popup from './popup';
export { Control, Scale, Zoom, Marker, Popup };

View File

@ -0,0 +1,186 @@
import { ILngLat, IMapService, IMarkerScene, IPopup } from '@l7/core';
import { bindAll, DOM } from '@l7/utils';
import { anchorTranslate, anchorType, applyAnchorClass } from './utils/anchor';
// marker 支持 dragger 未完成
export interface IMarkerOption {
element: HTMLElement | undefined;
anchor: anchorType;
color: string;
offset: number[];
draggable: boolean;
}
export default class Marker {
private markerOption: IMarkerOption;
private defaultMarker: boolean;
private popup: IPopup; // TODO: POPup
private mapservice: IMapService;
private lngLat: ILngLat;
private scene: IMarkerScene;
constructor(option?: Partial<IMarkerOption>) {
this.markerOption = {
...this.getDefault(),
...option,
};
bindAll(['update', 'onMove', 'onUp', 'addDragHandler', 'onMapClick'], this);
this.init();
}
public getDefault() {
return {
element: undefined, // DOM element
anchor: anchorType.BOTTOM,
offset: [0, 0],
color: '#5B8FF9',
draggable: false,
};
}
public addTo(scene: IMarkerScene) {
this.scene = scene;
const mapService = scene.getMapService();
const { element, draggable } = this.markerOption;
this.remove();
this.mapservice = mapService;
mapService.getMarkerContainer().appendChild(element as HTMLElement);
mapService.on('camerachange', this.update);
// this.setDraggable(draggable);
this.update();
return this;
}
public remove() {
if (this.mapservice) {
this.mapservice.off('click', this.onMapClick);
this.mapservice.off('move', this.update);
this.mapservice.off('moveend', this.update);
this.mapservice.off('mousedown', this.addDragHandler);
this.mapservice.off('touchstart', this.addDragHandler);
this.mapservice.off('mouseup', this.onUp);
this.mapservice.off('touchend', this.onUp);
delete this.mapservice;
}
const { element } = this.markerOption;
if (element) {
DOM.remove(element);
}
if (this.popup) {
this.popup.remove();
}
return this;
}
public setLnglat(lngLat: ILngLat) {
this.lngLat = lngLat;
if (this.popup) {
this.popup.setLnglat(this.lngLat);
}
return this;
}
public getLnglat(): ILngLat {
return this.lngLat;
}
public getElement(): HTMLElement {
return this.markerOption.element as HTMLElement;
}
public togglePopup() {
const popup = this.popup;
if (!popup) {
return this;
} else if (popup.isOpen()) {
popup.remove();
} else {
popup.addTo(this.scene);
}
return this;
}
public getPopup() {
return this.popup;
}
public getOffset(): number[] {
return this.markerOption.offset;
}
public setDraggable(draggable: boolean) {
throw new Error('Method not implemented.');
}
public isDraggable() {
return this.markerOption.draggable;
}
private update() {
if (!this.mapservice) {
return;
}
const { element, anchor } = this.markerOption;
this.updatePosition();
DOM.setTransform(element as HTMLElement, `${anchorTranslate[anchor]}`);
}
private onMapClick(e: MouseEvent) {
const { element } = this.markerOption;
if (this.popup && element) {
this.togglePopup();
}
}
private updatePosition() {
if (!this.mapservice) {
return;
}
const { element } = this.markerOption;
const { lng, lat } = this.lngLat;
const pos = this.mapservice.lngLatToContainer([lng, lat]);
if (element) {
element.style.left = pos.x + 'px';
element.style.top = pos.y + 'px';
}
}
private init() {
let { element } = this.markerOption;
const { color, anchor } = this.markerOption;
if (!element) {
this.defaultMarker = true;
element = DOM.create('div');
this.markerOption.element = element;
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttributeNS(null, 'display', 'block');
svg.setAttributeNS(null, 'height', '48px');
svg.setAttributeNS(null, 'width', '48px');
svg.setAttributeNS(null, 'viewBox', '0 0 1024 1024');
const path = document.createElementNS(
'http://www.w3.org/2000/svg',
'path',
);
path.setAttributeNS(
null,
'd',
'M512 490.666667C453.12 490.666667 405.333333 442.88 405.333333 384 405.333333 325.12 453.12 277.333333 512 277.333333 570.88 277.333333 618.666667 325.12 618.666667 384 618.666667 442.88 570.88 490.666667 512 490.666667M512 85.333333C346.88 85.333333 213.333333 218.88 213.333333 384 213.333333 608 512 938.666667 512 938.666667 512 938.666667 810.666667 608 810.666667 384 810.666667 218.88 677.12 85.333333 512 85.333333Z',
);
path.setAttributeNS(null, 'fill', color);
svg.appendChild(path);
element.appendChild(svg);
}
DOM.addClass(element, 'l7-marker');
element.addEventListener('click', (e: MouseEvent) => {
this.onMapClick(e);
});
applyAnchorClass(element, anchor, 'marker');
}
private addDragHandler(e: MouseEvent) {
throw new Error('Method not implemented.');
}
private onUp(e: MouseEvent) {
throw new Error('Method not implemented.');
}
}

View File

@ -0,0 +1,210 @@
import { ILngLat, IMapService, IMarkerScene, IPopup } from '@l7/core';
import { bindAll, DOM } from '@l7/utils';
import { EventEmitter } from 'eventemitter3';
import { anchorTranslate, anchorType, applyAnchorClass } from './utils/anchor';
/** colse event */
export interface IPopupOption {
closeButton: boolean;
closeOnClick: boolean;
maxWidth: string;
anchor: anchorType;
className: string;
offsets: number[];
}
export default class Popup extends EventEmitter implements IPopup {
private popupOption: IPopupOption;
private mapservice: IMapService;
private lngLat: ILngLat;
private content: HTMLElement;
private closeButton: HTMLElement;
private timeoutInstance: any;
private container: HTMLElement;
private tip: HTMLElement;
constructor(cfg?: Partial<IPopupOption>) {
super();
this.popupOption = {
...this.getdefault(),
...cfg,
};
bindAll(['update', 'onClickClose', 'remove'], this);
}
public addTo(scene: IMarkerScene) {
const mapService = scene.getMapService();
this.mapservice = mapService;
this.mapservice.on('camerachange', this.update);
this.update();
if (this.popupOption.closeOnClick) {
this.timeoutInstance = setTimeout(() => {
this.mapservice.on('click', this.onClickClose);
}, 30);
}
return this;
}
public setHTML(html: string) {
const frag = window.document.createDocumentFragment();
const temp = window.document.createElement('body');
let child: ChildNode | null;
temp.innerHTML = html;
while (true) {
child = temp.firstChild;
if (!child) {
break;
}
frag.appendChild(child);
}
return this.setDOMContent(frag);
}
public setLnglat(lngLat: ILngLat): this {
this.lngLat = lngLat;
if (this.mapservice) {
this.mapservice.on('camerachange', this.update);
}
this.update();
return this;
}
public getLnglat(): ILngLat {
return this.lngLat;
}
public setText(text: string) {
return this.setDOMContent(window.document.createTextNode(text));
}
public setMaxWidth(maxWidth: string): this {
this.popupOption.maxWidth = maxWidth;
this.update();
return this;
}
public setDOMContent(htmlNode: ChildNode | DocumentFragment) {
this.createContent();
this.content.appendChild(htmlNode);
this.update();
return this;
}
// 移除popup
public remove() {
if (this.content) {
this.removeDom(this.content);
}
if (this.container) {
this.removeDom(this.container);
delete this.container;
}
if (this.mapservice) {
// TODO: mapbox AMap 事件同步
this.mapservice.off('camerachange', this.update);
this.mapservice.off('click', this.onClickClose);
delete this.mapservice;
}
clearTimeout(this.timeoutInstance);
this.emit('close');
return this;
}
public isOpen() {
return !!this.mapservice;
}
private createContent() {
if (this.content) {
DOM.remove(this.content);
}
this.content = DOM.create('div', 'l7-popup-content', this.container);
if (this.popupOption.closeButton) {
this.closeButton = DOM.create(
'button',
'l7-popup-close-button',
this.content,
);
// this.closeButton.type = 'button';
this.closeButton.setAttribute('aria-label', 'Close popup');
this.closeButton.innerHTML = '&#215;';
this.closeButton.addEventListener('click', this.onClickClose);
}
}
private creatDom(tagName: string, className: string, container: HTMLElement) {
const el = window.document.createElement(tagName);
if (className !== undefined) {
el.className = className;
}
if (container) {
container.appendChild(el);
}
return el;
}
private removeDom(node: ChildNode) {
if (node.parentNode) {
node.parentNode.removeChild(node);
}
}
private getdefault() {
return {
closeButton: true,
closeOnClick: true,
maxWidth: '240px',
offsets: [0, 0],
anchor: anchorType.BOTTOM,
className: '',
};
}
private onClickClose() {
this.remove();
}
private update() {
const hasPosition = this.lngLat;
const { className, maxWidth, anchor } = this.popupOption;
if (!this.mapservice || !hasPosition || !this.content) {
return;
}
const markerContainer = this.mapservice.getMarkerContainer();
if (!this.container && markerContainer) {
this.container = this.creatDom(
'div',
'l7-popup',
markerContainer.parentNode as HTMLElement,
);
this.tip = this.creatDom('div', 'l7-popup-tip', this.container);
this.container.appendChild(this.content);
if (className) {
className
.split(' ')
.forEach((name) => this.container.classList.add(name));
}
this.container.addEventListener('mousedown', (e) => {
e.stopPropagation();
});
}
if (maxWidth && this.container.style.maxWidth !== maxWidth) {
this.container.style.maxWidth = maxWidth;
}
this.updatePosition();
DOM.setTransform(this.container, `${anchorTranslate[anchor]}`);
applyAnchorClass(this.container, anchor, 'popup');
}
private updatePosition() {
if (!this.mapservice) {
return;
}
const { lng, lat } = this.lngLat;
const { offsets } = this.popupOption;
const pos = this.mapservice.lngLatToContainer([lng, lat]);
this.container.style.left = pos.x + offsets[0] + 'px';
this.container.style.top = pos.y - offsets[1] + 'px';
}
}

View File

@ -0,0 +1,36 @@
export enum anchorType {
'CENTER' = 'center',
'TOP' = 'top',
'TOP-LEFT' = 'top-left',
'TOP-RIGHT' = 'top-right',
'BOTTOM' = 'bottom',
'BOTTOM-LEFT' = 'bottom-left',
'LEFT' = 'left',
'RIGHT' = 'right',
}
export const anchorTranslate = {
center: 'translate(-50%,-50%)',
top: 'translate(-50%,0)',
'top-left': 'translate(0,0)',
'top-right': 'translate(-100%,0)',
bottom: 'translate(-50%,-100%)',
'bottom-left': 'translate(0,-100%)',
'bottom-right': 'translate(-100%,-100%)',
left: 'translate(0,-50%)',
right: 'translate(-100%,-50%)',
};
export function applyAnchorClass(
element: HTMLElement,
anchor: string,
prefix: string,
) {
const classList = element.classList;
for (const key in anchorTranslate) {
if (anchorTranslate.hasOwnProperty(key)) {
classList.remove(`l7-${prefix}-anchor-${key}`);
}
}
classList.add(`l7-${prefix}-anchor-${anchor}`);
}

View File

@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"declarationDir": "./dist",
"rootDir": "./src",
"baseUrl": "./"
},
"include": ["./src"]
}

View File

@ -19,8 +19,9 @@
"author": "xiaoiver",
"license": "ISC",
"dependencies": {
"@l7/source": "0.0.1",
"@mapbox/tiny-sdf": "^1.1.1",
"eventemitter3": "^3.1.0",
"@l7/utils": "0.0.1",
"gl-matrix": "^3.1.0",
"hammerjs": "^2.0.8",
"inversify": "^5.0.1",
@ -29,6 +30,7 @@
"probe.gl": "^3.1.1",
"reflect-metadata": "^0.1.13",
"tapable": "^2.0.0-beta.8",
"mapbox-gl": "^1.2.1",
"viewport-mercator-project": "^6.2.1"
},
"devDependencies": {

View File

@ -50,6 +50,10 @@ export * from './services/config/IConfigService';
export * from './services/scene/ISceneService';
export * from './services/shader/IShaderModuleService';
export * from './services/asset/IIconService';
export * from './services/asset/IFontService';
export * from './services/component/IControlService';
export * from './services/component/IMarkerService';
export * from './services/component/IPopUpService';
export * from './services/log/ILogService';
/** 全部渲染服务接口 */

View File

@ -6,8 +6,10 @@ import getDecorators from 'inversify-inject-decorators';
import { TYPES } from './types';
/** Service interfaces */
import { IFontService } from './services/asset/IFontService';
import { IIconService } from './services/asset/IIconService';
import { ICameraService } from './services/camera/ICameraService';
import { IControlService } from './services/component/IControlService';
import { IGlobalConfigService } from './services/config/IConfigService';
import { ICoordinateSystemService } from './services/coordinate/ICoordinateSystemService';
import { IInteractionService } from './services/interaction/IInteractionService';
@ -17,8 +19,10 @@ import { ILogService } from './services/log/ILogService';
import { IShaderModuleService } from './services/shader/IShaderModuleService';
/** Service implements */
import FontService from './services/asset/FontService';
import IconService from './services/asset/IconService';
import CameraService from './services/camera/CameraService';
import ControlService from './services/component/ControlService';
import GlobalConfigService from './services/config/ConfigService';
import CoordinateSystemService from './services/coordinate/CoordinateSystemService';
import InteractionService from './services/interaction/InteractionService';
@ -26,7 +30,6 @@ import LayerService from './services/layer/LayerService';
import StyleAttributeService from './services/layer/StyleAttributeService';
import LogService from './services/log/LogService';
import ShaderModuleService from './services/shader/ShaderModuleService';
// @see https://github.com/inversify/InversifyJS/blob/master/wiki/container_api.md#defaultscope
const container = new Container();
@ -68,6 +71,14 @@ container
.bind<IInteractionService>(TYPES.IInteractionService)
.to(InteractionService)
.inSingletonScope();
container
.bind<IFontService>(TYPES.IFontService)
.to(FontService)
.inSingletonScope();
container
.bind<IControlService>(TYPES.IControlService)
.to(ControlService)
.inSingletonScope();
// @see https://github.com/inversify/InversifyJS/blob/master/wiki/inheritance.md#what-can-i-do-when-my-base-class-is-provided-by-a-third-party-module
decorate(injectable(), EventEmitter);

View File

@ -0,0 +1,243 @@
import { LRUCache } from '@l7/utils';
// @ts-ignore
import TinySDF from '@mapbox/tiny-sdf';
import { inject, injectable } from 'inversify';
import { buildMapping } from '../../utils/font_util';
import {
IFontAtlas,
IFontMapping,
IFontMappingItem,
IFontOptions,
IFontService,
} from './IFontService';
export const DEFAULT_CHAR_SET = getDefaultCharacterSet();
export const DEFAULT_FONT_FAMILY = 'sans-serif';
export const DEFAULT_FONT_WEIGHT = 'normal';
export const DEFAULT_FONT_SIZE = 24;
export const DEFAULT_BUFFER = 3;
export const DEFAULT_CUTOFF = 0.25;
export const DEFAULT_RADIUS = 8;
const MAX_CANVAS_WIDTH = 1024;
const BASELINE_SCALE = 1.0;
const HEIGHT_SCALE = 1.0;
const CACHE_LIMIT = 3;
const VALID_PROPS = [
'fontFamily',
'fontWeight',
'characterSet',
'fontSize',
'sdf',
'buffer',
'cutoff',
'radius',
];
function getDefaultCharacterSet() {
const charSet = [];
for (let i = 32; i < 128; i++) {
charSet.push(String.fromCharCode(i));
}
return charSet;
}
function setTextStyle(
ctx: CanvasRenderingContext2D,
fontFamily: string,
fontSize: number,
fontWeight: string,
) {
ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
ctx.fillStyle = 'black';
ctx.textBaseline = 'middle';
// ctx.textAlign = 'left';
}
function populateAlphaChannel(alphaChannel: number[], imageData: ImageData) {
// populate distance value from tinySDF to image alpha channel
for (let i = 0; i < alphaChannel.length; i++) {
imageData.data[4 * i + 3] = alphaChannel[i];
}
}
@injectable()
export default class FontService implements IFontService {
public fontAtlas: IFontAtlas;
private fontOptions: IFontOptions;
private key: string;
private cache: LRUCache = new LRUCache(CACHE_LIMIT);
public init() {
this.fontOptions = {
fontFamily: DEFAULT_FONT_FAMILY,
fontWeight: DEFAULT_FONT_WEIGHT,
characterSet: DEFAULT_CHAR_SET,
fontSize: DEFAULT_FONT_SIZE,
buffer: DEFAULT_BUFFER,
sdf: true,
cutoff: DEFAULT_CUTOFF,
radius: DEFAULT_RADIUS,
};
this.key = '';
}
public get scale() {
return HEIGHT_SCALE;
}
public get canvas(): HTMLCanvasElement {
const data = this.cache.get(this.key);
return data && data.data;
}
public get mapping(): IFontMapping {
const data = this.cache.get(this.key);
return data && data.mapping;
}
public setFontOptions(option: Partial<IFontOptions>) {
this.fontOptions = {
...this.fontOptions,
...option,
};
// const oldKey = this.key;
this.key = this.getKey();
const charSet = this.getNewChars(this.key, this.fontOptions.characterSet);
const cachedFontAtlas = this.cache.get(this.key);
if (cachedFontAtlas && charSet.length === 0) {
// update texture with cached fontAtlas
return;
}
// update fontAtlas with new settings
const fontAtlas = this.generateFontAtlas(
this.key,
charSet,
cachedFontAtlas,
);
this.fontAtlas = fontAtlas;
// update cache
this.cache.set(this.key, fontAtlas);
}
public destroy(): void {
this.cache.clear();
}
private generateFontAtlas(
key: string,
characterSet: string[],
cachedFontAtlas: IFontAtlas,
): IFontAtlas {
const {
fontFamily,
fontWeight,
fontSize,
buffer,
sdf,
radius,
cutoff,
} = this.fontOptions;
let canvas = cachedFontAtlas && cachedFontAtlas.data;
if (!canvas) {
canvas = document.createElement('canvas');
canvas.width = MAX_CANVAS_WIDTH;
}
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
setTextStyle(ctx, fontFamily, fontSize, fontWeight);
// 1. build mapping
const { mapping, canvasHeight, xOffset, yOffset } = buildMapping({
getFontWidth: (char) => ctx.measureText(char).width,
fontHeight: fontSize * HEIGHT_SCALE,
buffer,
characterSet,
maxCanvasWidth: MAX_CANVAS_WIDTH,
...(cachedFontAtlas && {
mapping: cachedFontAtlas.mapping,
xOffset: cachedFontAtlas.xOffset,
yOffset: cachedFontAtlas.yOffset,
}),
});
// 2. update canvas
// copy old canvas data to new canvas only when height changed
if (canvas.height !== canvasHeight) {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
canvas.height = canvasHeight;
ctx.putImageData(imageData, 0, 0);
}
setTextStyle(ctx, fontFamily, fontSize, fontWeight);
// 3. layout characters
if (sdf) {
const tinySDF = new TinySDF(
fontSize,
buffer,
radius,
cutoff,
fontFamily,
fontWeight,
);
// used to store distance values from tinySDF
// tinySDF.size equals `fontSize + buffer * 2`
const imageData = ctx.getImageData(0, 0, tinySDF.size, tinySDF.size);
for (const char of characterSet) {
populateAlphaChannel(tinySDF.draw(char), imageData);
// 考虑到描边,需要保留 sdf 的 buffer不能像 deck.gl 一样直接减去
ctx.putImageData(imageData, mapping[char].x, mapping[char].y);
}
} else {
for (const char of characterSet) {
ctx.fillText(
char,
mapping[char].x,
mapping[char].y + fontSize * BASELINE_SCALE,
);
}
}
return {
xOffset,
yOffset,
mapping,
data: canvas,
width: canvas.width,
height: canvas.height,
};
}
private getKey() {
const {
fontFamily,
fontWeight,
fontSize,
buffer,
sdf,
radius,
cutoff,
} = this.fontOptions;
if (sdf) {
return `${fontFamily} ${fontWeight} ${fontSize} ${buffer} ${radius} ${cutoff}`;
}
return `${fontFamily} ${fontWeight} ${fontSize} ${buffer}`;
}
private getNewChars(key: string, characterSet: string[]): string[] {
const cachedFontAtlas = this.cache.get(key);
if (!cachedFontAtlas) {
return characterSet;
}
const newChars: string[] = [];
const cachedMapping = cachedFontAtlas.mapping;
const cachedCharSet = new Set(Object.keys(cachedMapping));
const charSet = new Set(characterSet);
charSet.forEach((char: string) => {
if (!cachedCharSet.has(char)) {
newChars.push(char);
}
});
return newChars;
}
}

View File

@ -0,0 +1,48 @@
export interface IFontOptions {
fontFamily: string;
fontWeight: string;
characterSet: string[];
fontSize: number;
buffer: number;
sdf: boolean;
cutoff: number;
radius: number;
}
export interface IFontMappingOption {
characterSet: string[];
getFontWidth: (char: string, i: number) => number;
fontHeight: number;
buffer: number;
maxCanvasWidth: number;
mapping: IFontMapping;
xOffset: number;
yOffset: number;
}
export interface IFontMappingItem {
x: number;
y: number;
width: number;
height: number;
advance: number;
}
export interface IFontMapping {
[key: string]: IFontMappingItem;
[key: number]: IFontMappingItem;
}
export interface IFontAtlas {
xOffset: number;
yOffset: number;
mapping: IFontMapping;
data: HTMLCanvasElement;
width: number;
height: number;
}
export interface IFontService {
mapping: IFontMapping;
fontAtlas: IFontAtlas;
canvas: HTMLCanvasElement;
scale: number;
init(): void;
setFontOptions(option: Partial<IFontOptions>): void;
destroy(): void;
}

View File

@ -1,5 +1,7 @@
import EventEmitter from 'eventemitter3';
import { ITexture2D } from '../renderer/ITexture2D';
export type IImage = HTMLImageElement | File | string;
export type Listener = (...args: any[]) => void;
export interface IIconValue {
x: number;
y: number;
@ -16,6 +18,7 @@ export interface IICONMap {
}
export interface IIconService {
canvasHeight: number;
on(event: string, fn: EventEmitter.ListenerFn, context?: any): this;
init(): void;
addImage(id: string, image: IImage): void;
hasImage(id: string): boolean;
@ -23,4 +26,5 @@ export interface IIconService {
getTexture(): ITexture2D;
getIconMap(): IICONMap;
getCanvas(): HTMLCanvasElement;
destroy(): void;
}

View File

@ -1,8 +1,7 @@
import { EventEmitter } from 'eventemitter3';
import { inject, injectable } from 'inversify';
import { TYPES } from '../../types';
import { buildIconMaping } from '../../utils/font_util';
import { gl } from '../renderer/gl';
import { IRendererService } from '../renderer/IRendererService';
import { ITexture2D } from '../renderer/ITexture2D';
import {
IIcon,
@ -15,7 +14,7 @@ const BUFFER = 3;
const MAX_CANVAS_WIDTH = 1024;
const imageSize = 64;
@injectable()
export default class IconService implements IIconService {
export default class IconService extends EventEmitter implements IIconService {
public canvasHeight: number;
private textrure: ITexture2D;
private canvas: HTMLCanvasElement;
@ -31,23 +30,20 @@ export default class IconService implements IIconService {
public addImage(id: string, image: IImage) {
let imagedata = new Image();
if (this.hasImage(id)) {
throw new Error('Image Id already exists');
}
this.loadImage(image).then((img) => {
imagedata = img as HTMLImageElement;
this.iconData.push({
id,
image: imagedata,
width: imageSize,
height: imageSize,
});
this.update();
});
this.iconData.push({
id,
image: imagedata,
width: imageSize,
height: imageSize,
});
const { mapping, canvasHeight } = buildIconMaping(
this.iconData,
BUFFER,
MAX_CANVAS_WIDTH,
);
this.iconMap = mapping;
this.canvasHeight = canvasHeight;
this.updateIconAtlas();
}
public getTexture(): ITexture2D {
@ -57,15 +53,32 @@ export default class IconService implements IIconService {
public getIconMap() {
return this.iconMap;
}
public getCanvas() {
return this.canvas;
}
public hasImage(id: string): boolean {
throw new Error('Method not implemented.');
return this.iconMap.hasOwnProperty(id);
}
public removeImage(id: string): void {
throw new Error('Method not implemented.');
if (this.hasImage(id)) {
this.iconData = this.iconData.filter((icon) => {
return icon.id !== id;
});
delete this.iconMap[id];
this.update();
}
}
public destroy(): void {
this.iconData = [];
this.iconMap = {};
}
private update() {
this.updateIconMap();
this.updateIconAtlas();
this.emit('imageUpdate');
}
private updateIconAtlas() {
@ -75,13 +88,16 @@ export default class IconService implements IIconService {
const { x, y, image } = this.iconMap[item];
this.ctx.drawImage(image, x, y, imageSize, imageSize);
});
// const { createTexture2D } = this.rendererService;
// this.textrure = createTexture2D({
// data: this.canvas,
// width: this.canvas.width,
// height: this.canvasHeight,
// mag: gl.LINEAR,
// });
}
private updateIconMap() {
const { mapping, canvasHeight } = buildIconMaping(
this.iconData,
BUFFER,
MAX_CANVAS_WIDTH,
);
this.iconMap = mapping;
this.canvasHeight = canvasHeight;
}
private loadImage(url: IImage) {

View File

@ -0,0 +1,75 @@
import { DOM } from '@l7/utils';
import { inject, injectable } from 'inversify';
import { IMapService } from '../map/IMapService';
import {
IControl,
IControlCorners,
IControlService,
IControlServiceCfg,
} from './IControlService';
@injectable()
export default class ControlService implements IControlService {
public container: HTMLElement;
public controlCorners: IControlCorners;
public controlContainer: HTMLElement;
private controls: IControl[] = [];
public init(cfg: IControlServiceCfg) {
this.container = cfg.container;
this.initControlPos();
}
public addControl(ctr: IControl, mapService: IMapService): void {
ctr.addTo(mapService); // scene对象
this.controls.push(ctr);
}
public removeControl(ctr: IControl): this {
const index = this.controls.indexOf(ctr);
if (index > -1) {
this.controls.splice(index, 1);
}
ctr.remove();
return this;
}
public destroy(): void {
for (const ctr of this.controls) {
ctr.remove();
}
this.controls = [];
this.clearControlPos();
}
private initControlPos() {
const corners: IControlCorners = (this.controlCorners = {});
const l = 'l7-';
const container = (this.controlContainer = DOM.create(
'div',
l + 'control-container',
this.container,
));
function createCorner(vSide: string, hSide: string) {
const className = l + vSide + ' ' + l + hSide;
corners[vSide + hSide] = DOM.create('div', className, container);
}
createCorner('top', 'left');
createCorner('top', 'right');
createCorner('bottom', 'left');
createCorner('bottom', 'right');
}
private clearControlPos() {
for (const i in this.controlCorners) {
if (this.controlCorners[i]) {
DOM.remove(this.controlCorners[i]);
}
}
DOM.remove(this.controlContainer);
delete this.controlCorners;
delete this.controlContainer;
}
}

View File

@ -0,0 +1,33 @@
import { IMapService } from '../map/IMapService';
export enum PositionType {
'TOPRIGHT' = 'topright',
'TOPLEFT' = 'topleft',
'BOTTOMRIGHT' = 'bottomright',
'BOTTOMLEFT' = 'bottomleft',
}
export interface IControlOption {
position: PositionType;
}
export interface IControlServiceCfg {
container: HTMLElement;
}
export interface IControlCorners {
[key: string]: HTMLElement;
}
export interface IControl {
setPosition(pos: PositionType): void;
addTo(map: IMapService): void;
onAdd(map: IMapService): HTMLElement;
hide(): void;
show(): void;
remove(): void;
}
export interface IControlService {
container: HTMLElement;
controlCorners: IControlCorners;
controlContainer: HTMLElement;
init(cfg: IControlServiceCfg): void;
addControl(ctr: IControl, map: IMapService): void;
removeControl(ctr: IControl): void;
destroy(): void;
}

View File

@ -0,0 +1,13 @@
import { ILngLat, IMapService } from '../map/IMapService';
export interface IMarkerScene {
getMapService(): IMapService;
[key: string]: any;
}
export interface IMarker {
addTo(scene: IMarkerScene): void;
remove(): void;
setLnglat(lngLat: ILngLat): this;
getLnglat(): ILngLat;
getElement(): HTMLElement;
togglePopup(): this;
}

View File

@ -0,0 +1,12 @@
import { ILngLat, IMapService } from '../map/IMapService';
import { IMarkerScene } from './IMarkerService';
export interface IPopup {
addTo(scene: IMarkerScene): this;
remove(): void;
setLnglat(lngLat: ILngLat): this;
getLnglat(): ILngLat;
setHTML(html: string): this;
setText(text: string): this;
setMaxWidth(maxWidth: string): this;
isOpen(): boolean;
}

View File

@ -1,5 +1,5 @@
import { IStyleAttribute } from '@l7/core';
import { isNil } from 'lodash';
import { IStyleAttribute } from '../layer/IStyleAttributeService';
import { IAttribute } from '../renderer/IAttribute';
import { IBuffer } from '../renderer/IBuffer';
import {

View File

@ -1,3 +1,4 @@
import { Map } from 'mapbox-gl';
import { IViewport } from '../camera/ICameraService';
export type Point = [number, number];
export type Bounds = [[number, number], [number, number]];
@ -10,9 +11,23 @@ export interface IPoint {
y: number;
}
export interface IMapService {
map: AMap.Map | Map;
init(config: Partial<IMapConfig>): void;
destroy(): void;
onCameraChanged(callback: (viewport: IViewport) => void): void;
// init map
addMarkerContainer(): void;
getMarkerContainer(): HTMLElement;
// MapEvent // 定义事件类型
on(type: string, hander: (...args: any[]) => void): void;
off(type: string, hander: (...args: any[]) => void): void;
// get dom
getContainer(): HTMLElement | null;
getSize(): [number, number];
// get map status method
getMinZoom(): number;
getMaxZoom(): number;
// get map params
getType(): MapType;
getZoom(): number;
@ -55,6 +70,11 @@ export interface IMapConfig {
*/
id: string;
/**
*
*/
token?: string;
/**
*
*/
@ -79,6 +99,17 @@ export interface IMapConfig {
*
*/
style?: string;
/**
*
*/
minZoom?: number;
/**
*
*/
maxZoom?: number;
attributionControl?: boolean;
}
/**

View File

@ -1,11 +1,16 @@
import { EventEmitter } from 'eventemitter3';
import { IImage } from '../asset/IIconService';
import { ILayer } from '../layer/ILayerService';
import { IMapConfig } from '../map/IMapService';
import { IRenderConfig } from '../renderer/IRendererService';
export interface ISceneService {
on(type: string, hander: (...args: any[]) => void): void;
off(type: string, hander: (...args: any[]) => void): void;
removeAllListeners(event?: string): this;
init(config: IMapConfig & IRenderConfig): void;
addLayer(layer: ILayer): void;
render(): void;
destroy(): void;
}
export const SceneEventList = ['loaded', 'resize', 'destroy'];

View File

@ -3,8 +3,10 @@ import { inject, injectable } from 'inversify';
import { AsyncParallelHook, AsyncSeriesHook } from 'tapable';
import { TYPES } from '../../types';
import { createRendererContainer } from '../../utils/dom';
import { IFontService } from '../asset/IFontService';
import { IIconService, IImage } from '../asset/IIconService';
import { ICameraService, IViewport } from '../camera/ICameraService';
import { IControlService } from '../component/IControlService';
import { IGlobalConfig, IGlobalConfigService } from '../config/IConfigService';
import { IInteractionService } from '../interaction/IInteractionService';
import { ILayer, ILayerService } from '../layer/ILayerService';
@ -18,11 +20,18 @@ import { ISceneService } from './ISceneService';
*/
@injectable()
export default class Scene extends EventEmitter implements ISceneService {
@inject(TYPES.IIconService)
public readonly iconService: IIconService;
/**
* 使 Service
*/
@inject(TYPES.IIconService)
private readonly iconService: IIconService;
@inject(TYPES.IFontService)
private readonly fontService: IFontService;
@inject(TYPES.IControlService)
private readonly controlService: IControlService;
@inject(TYPES.ILogService)
private readonly logger: ILogService;
@ -78,8 +87,18 @@ export default class Scene extends EventEmitter implements ISceneService {
public init(globalConfig: IGlobalConfig) {
this.configService.setAndCheckConfig(globalConfig);
// 初始化资源管理 字体,图片
// 初始化资源管理 图片
this.iconService.init();
// 字体资源
this.fontService.init();
this.controlService.init({
container: document.getElementById(
this.configService.getConfig().id || 'map',
) as HTMLElement,
});
/**
*
*/
@ -136,6 +155,8 @@ export default class Scene extends EventEmitter implements ISceneService {
if (!this.inited) {
// 首次渲染需要等待底图、相机初始化
await this.hooks.init.promise(this.configService.getConfig());
// 初始化marker 容器
this.map.addMarkerContainer();
this.emit('loaded');
this.inited = true;
@ -152,6 +173,8 @@ export default class Scene extends EventEmitter implements ISceneService {
this.layerService.destroy();
this.configService.reset();
this.interactionService.destroy();
this.controlService.destroy();
this.removeAllListeners();
this.rendererService.destroy();
this.map.destroy();
window.removeEventListener('resize', this.handleWindowResized, false);

View File

@ -10,7 +10,9 @@ const TYPES = {
IRendererService: Symbol.for('IRendererService'),
IShaderModuleService: Symbol.for('IShaderModuleService'),
IIconService: Symbol.for('IIconService'),
IFontService: Symbol.for('IFontService'),
IInteractionService: Symbol.for('IInteractionService'),
IControlService: Symbol.for('IControlService'),
IStyleAttributeService: Symbol.for('IStyleAttributeService'),
/** multi-pass */

View File

@ -1,3 +1,5 @@
const docStyle = window.document.documentElement.style;
type ELType = HTMLElement | SVGElement;
export function createRendererContainer(domId: string): HTMLDivElement | null {
const $wrapper = document.getElementById(domId);
@ -6,7 +8,7 @@ export function createRendererContainer(domId: string): HTMLDivElement | null {
$container.style.cssText += `
position: absolute;
top: 0;
z-index:10;
z-index:2;
height: 100%;
width: 100%;
pointer-events: none;

View File

@ -1,10 +1,49 @@
import {
IIcon,
IICONMap,
IIconService,
IIconValue,
IImage,
} from '../services/asset/IIconService';
import { IFontMappingOption } from '../services/asset/IFontService';
import { IIcon, IICONMap } from '../services/asset/IIconService';
/**
* tiny-sdf glyph buffer 24 + 3 + 3 = 30
*/
const glyphSizeInSDF = 30;
export function buildMapping({
characterSet,
getFontWidth,
fontHeight,
buffer,
maxCanvasWidth,
mapping = {},
xOffset = 0,
yOffset = 0,
}: IFontMappingOption) {
let row = 0;
let x = xOffset;
Array.from(characterSet).forEach((char: string, i: number) => {
if (!mapping[char]) {
const width = getFontWidth(char, i);
if (x + glyphSizeInSDF > maxCanvasWidth) {
x = 0;
row++;
}
mapping[char] = {
x,
y: yOffset + row * glyphSizeInSDF,
width: glyphSizeInSDF,
height: glyphSizeInSDF,
advance: width,
};
x += glyphSizeInSDF;
}
});
const rowHeight = fontHeight + buffer * 2;
return {
mapping,
xOffset: x,
yOffset: yOffset + row * rowHeight,
canvasHeight: nextPowOfTwo(yOffset + (row + 1) * rowHeight),
};
}
export function buildIconMaping(
icons: IIcon[],
buffer: number,

View File

@ -1,3 +1,4 @@
declare module 'probe.gl' {
class Log {
constructor(options: { id: string });
@ -8,4 +9,5 @@ declare module 'probe.gl' {
info(message: string): () => any;
error(message: string): () => any;
}
}
}
/// <reference path="../../../node_modules/eventemitter3/index.d.ts" />

View File

@ -1,10 +1,12 @@
import {
IEncodeFeature,
IFontService,
IGlobalConfigService,
IIconService,
ILayer,
ILayerInitializationOptions,
ILayerPlugin,
IMapService,
IModel,
IMultiPassRenderer,
IRendererService,
@ -121,6 +123,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
@lazyInject(TYPES.IIconService)
protected readonly iconService: IIconService;
@lazyInject(TYPES.IFontService)
protected readonly fontService: IFontService;
protected layerSource: Source;
private encodedData: IEncodeFeature[];
@ -141,6 +146,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
@lazyInject(TYPES.IRendererService)
private readonly rendererService: IRendererService;
@lazyInject(TYPES.IMapService)
private readonly map: IMapService;
constructor(
styleOptions: Partial<ILayerInitializationOptions & ChildLayerStyleOptions>,
) {
@ -221,6 +229,14 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
}
return this;
}
/**
* zoom to layer Bounds
*/
public fitBounds(): void {
const source = this.getSource();
const extent = source.extent;
this.map.fitBounds([[extent[0], extent[1]], [extent[2], extent[3]]]);
}
public destroy() {
this.hooks.beforeDestroy.call(this);

View File

@ -4,7 +4,6 @@ export default class DataSourcePlugin implements ILayerPlugin {
public apply(layer: ILayer) {
layer.hooks.init.tap('DataSourcePlugin', () => {
const { data, options } = layer.sourceOption;
// @ts-ignore
layer.setSource(new Source(data, options));
});
}

View File

@ -2,8 +2,8 @@ uniform sampler2D u_texture;
varying vec4 v_color;
varying vec2 v_uv;
void main(){
vec2 pos= v_uv + gl_PointCoord / vec2(1024.,128.)*64.;
pos.y= 1.- pos.y;
vec2 pos= v_uv + gl_PointCoord / vec2(1024.,128.)* 64.;
// pos.y= 1.- pos.y;
vec4 textureColor=texture2D(u_texture,pos);
if(v_color == vec4(0.)){
gl_FragColor= textureColor;

View File

@ -0,0 +1,27 @@
uniform sampler2D u_sdf_map;
uniform float u_gamma_scale : 0.5;
uniform float u_font_size : 24;
uniform float u_opacity : 1.0;
uniform vec4 u_stroke : [0, 0, 0, 1];
uniform float u_strokeWidth : 2.0;
uniform float u_halo_blur : 0.5;
varying vec4 v_color;
varying vec2 v_uv;
varying float v_gamma_scale;
void main() {
// get sdf from atlas
float dist = texture2D(u_sdf_map, v_uv).a;
float fontScale = u_font_size / 24.0;
lowp float buff = (6.0 - u_strokeWidth / fontScale) / SDF_PX;
highp float gamma = (u_halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale);
highp float gamma_scaled = gamma * v_gamma_scale;
highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist);
gl_FragColor = mix(v_color * u_opacity, u_stroke, smoothstep(0., 0.5, 1. - dist)) * alpha;
}

View File

@ -0,0 +1,33 @@
attribute vec3 a_Position;
attribute vec2 a_tex;
attribute vec2 a_offset;
attribute vec4 a_color;
attribute float a_size;
uniform vec2 u_sdf_map_size;
uniform vec2 u_viewport_size;
uniform float u_activeId : 0;
uniform vec4 u_activeColor : [1.0, 0.0, 0.0, 1.0];
varying vec2 v_uv;
varying float v_gamma_scale;
varying vec4 v_color;
#pragma include "projection"
void main() {
v_color = a_color;
v_uv = a_tex / u_sdf_map_size;
// 文本缩放比例
float fontScale = a_size / 24.;
vec4 project_pos = project_position(vec4(a_Position, 1.0));
vec4 projected_position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
gl_Position = vec4(projected_position.xy / projected_position.w
+ a_offset * fontScale / u_viewport_size * 2., 0.0, 1.0);
v_gamma_scale = gl_Position.w;
}

View File

@ -24,6 +24,7 @@
"gl-matrix": "^3.1.0",
"inversify": "^5.0.1",
"mapbox-gl": "^1.2.1",
"@l7/utils": "0.0.1",
"viewport-mercator-project": "^6.2.1"
},
"devDependencies": {

View File

@ -13,24 +13,25 @@ import {
MapType,
TYPES,
} from '@l7/core';
import { DOM } from '@l7/utils';
import { inject, injectable } from 'inversify';
import { IAMapEvent, IAMapInstance } from '../../typings/index';
import Viewport from './Viewport';
const AMAP_API_KEY: string = '15cd8a57710d40c9b7c0e3cc120f1200';
const AMAP_VERSION: string = '1.4.8';
const LNGLAT_OFFSET_ZOOM_THRESHOLD = 12;
/// <reference path="../../../../../node_modules/@types/amap-js-api/index.d.ts" />
/**
* AMapService
*/
@injectable()
export default class AMapService implements IMapService {
public map: AMap.Map & IAMapInstance;
@inject(TYPES.ICoordinateSystemService)
private readonly coordinateSystemService: ICoordinateSystemService;
private map: AMap.Map;
private markerContainer: HTMLElement;
private $mapContainer: HTMLElement | null;
private $jsapi: HTMLScriptElement;
@ -39,6 +40,38 @@ export default class AMapService implements IMapService {
private cameraChangedCallback: (viewport: IViewport) => void;
// init
public addMarkerContainer(): void {
const mapContainer = this.map.getContainer();
if (mapContainer !== null) {
const amap = mapContainer.getElementsByClassName(
'amap-maps',
)[0] as HTMLElement;
this.markerContainer = DOM.create('div', 'l7_marker', amap);
}
}
public getMarkerContainer(): HTMLElement {
return this.markerContainer;
}
// map event
public on(type: string, handle: (...args: any[]) => void): void {
this.map.on(type, handle);
}
public off(type: string, handle: (...args: any[]) => void): void {
this.map.off(type, handle);
}
public getContainer(): HTMLElement | null {
return this.map.getContainer();
}
public getSize(): [number, number] {
const size = this.map.getSize();
return [size.getWidth(), size.getHeight()];
}
public getType() {
return MapType.amap;
}
@ -52,12 +85,15 @@ export default class AMapService implements IMapService {
lat: center.getLat(),
};
}
public getPitch(): number {
return this.map.getPitch();
}
public getRotation(): number {
return this.map.getRotation();
}
public getBounds(): Bounds {
// @ts-ignore
const amapBound = this.map.getBounds().toBounds();
@ -65,8 +101,17 @@ export default class AMapService implements IMapService {
const SW = amapBound.getSouthWest();
return [[NE.getLng(), NE.getLat()], [SW.getLng(), SW.getLat()]];
}
public setRotation(rotation: number): number {
return this.setRotation(rotation);
public getMinZoom(): number {
const zooms = this.map.get('zooms') as [number, number];
return zooms[0];
}
public getMaxZoom(): number {
const zooms = this.map.get('zooms') as [number, number];
return zooms[1];
}
public setRotation(rotation: number): void {
return this.map.setRotation(rotation);
}
public zoomIn(): void {
@ -131,7 +176,7 @@ export default class AMapService implements IMapService {
await new Promise((resolve) => {
// 异步加载高德地图
// @see https://lbs.amap.com/api/javascript-api/guide/abc/load
window.onLoad = (): void => {
window.onload = (): void => {
// @ts-ignore
this.map = new AMap.Map(id, {
mapStyle: style,

View File

@ -13,9 +13,17 @@ import {
MapType,
TYPES,
} from '@l7/core';
import { DOM } from '@l7/utils';
import { inject, injectable } from 'inversify';
import mapboxgl, { Map } from 'mapbox-gl';
import mapboxgl, { IControl, Map } from 'mapbox-gl';
import { IMapboxInstance } from '../../typings/index';
import Viewport from './Viewport';
const EventMap: {
[key: string]: any;
} = {
mapmove: 'move',
camerachange: 'move',
};
mapboxgl.accessToken =
'pk.eyJ1IjoieGlhb2l2ZXIiLCJhIjoiY2pxcmc5OGNkMDY3cjQzbG42cXk5NTl3YiJ9.hUC5Chlqzzh0FFd_aEc-uQ';
@ -28,17 +36,42 @@ let counter = 1;
*/
@injectable()
export default class MapboxService implements IMapService {
public map: Map & IMapboxInstance;
@inject(TYPES.ICoordinateSystemService)
private readonly coordinateSystemService: ICoordinateSystemService;
private map: Map & IMapboxInstance;
private viewport: Viewport;
private markerContainer: HTMLElement;
private cameraChangedCallback: (viewport: IViewport) => void;
private $mapContainer: HTMLElement | null;
private $link: HTMLLinkElement;
private viewport: Viewport;
// init
public addMarkerContainer(): void {
const container = this.map.getCanvasContainer();
this.markerContainer = DOM.create('div', 'l7_marker', container);
}
private cameraChangedCallback: (viewport: IViewport) => void;
public getMarkerContainer(): HTMLElement {
return this.markerContainer;
}
// map event
public on(type: string, handle: (...args: any[]) => void): void {
this.map.on(EventMap[type] || type, handle);
}
public off(type: string, handle: (...args: any[]) => void): void {
this.map.off(EventMap[type] || type, handle);
}
public getContainer(): HTMLElement | null {
return this.map.getContainer();
}
public getSize(): [number, number] {
const size = this.map.transform;
return [size.width, size.height];
}
// get mapStatus method
public getType() {
return MapType.mapbox;
@ -46,67 +79,92 @@ export default class MapboxService implements IMapService {
public getZoom(): number {
return this.map.getZoom();
}
public getCenter(): ILngLat {
return this.map.getCenter();
}
public getPitch(): number {
return this.map.getPitch();
}
public getRotation(): number {
return this.map.getBearing();
}
public getBounds(): Bounds {
return this.map.getBounds().toArray() as Bounds;
}
public getMinZoom(): number {
return this.map.getMinZoom();
}
public getMaxZoom(): number {
return this.map.getMaxZoom();
}
public setRotation(rotation: number): void {
this.map.setBearing(rotation);
}
public zoomIn(): void {
this.map.zoomIn();
}
public zoomOut(): void {
this.map.zoomOut();
}
public panTo(p: [number, number]): void {
this.map.panTo(p);
}
public panBy(pixel: [number, number]): void {
this.panTo(pixel);
}
public fitBounds(bound: Bounds): void {
this.map.fitBounds(bound);
}
public setMaxZoom(max: number): void {
this.map.setMaxZoom(max);
}
public setMinZoom(min: number): void {
this.map.setMinZoom(min);
}
public setZoomAndCenter(zoom: number, center: [number, number]): void {
this.map.flyTo({
zoom,
center,
});
}
public setMapStyle(style: string): void {
this.map.setStyle(style);
}
// TODO: 计算像素坐标
public pixelToLngLat(pixel: [number, number]): ILngLat {
return this.map.unproject(pixel);
}
public lngLatToPixel(lnglat: [number, number]): IPoint {
return this.map.project(lnglat);
}
public containerToLngLat(pixel: [number, number]): ILngLat {
throw new Error('Method not implemented.');
return this.map.unproject(pixel);
}
public lngLatToContainer(lnglat: [number, number]): IPoint {
throw new Error('Method not implemented.');
return this.map.project(lnglat);
}
public async init(mapConfig: IMapConfig): Promise<void> {
const { id, ...rest } = mapConfig;
const { id, attributionControl = false, ...rest } = mapConfig;
this.$mapContainer = document.getElementById(id);
this.$mapContainer!.classList.add(`${counter++}`);
@ -119,9 +177,9 @@ export default class MapboxService implements IMapService {
// @ts-ignore
this.map = new mapboxgl.Map({
container: id,
attributionControl,
...rest,
});
this.map.on('move', this.handleCameraChanged);
// 不同于高德地图,需要手动触发首次渲染
@ -130,6 +188,7 @@ export default class MapboxService implements IMapService {
this.$link = document.createElement('link');
this.$link.href =
'https://api.tiles.mapbox.com/mapbox-gl-js/v1.2.1/mapbox-gl.css';
this.removeLogoControl();
this.$link.rel = 'stylesheet';
document.head.appendChild(this.$link);
}
@ -147,7 +206,10 @@ export default class MapboxService implements IMapService {
public onCameraChanged(callback: (viewport: IViewport) => void): void {
this.cameraChangedCallback = callback;
}
// 同步不同底图的配置项
private initMapConig(): void {
throw new Error('Method not implemented.');
}
private handleCameraChanged = () => {
// @see https://github.com/mapbox/mapbox-gl-js/issues/2572
const { lat, lng } = this.map.getCenter().wrap();
@ -175,4 +237,16 @@ export default class MapboxService implements IMapService {
this.cameraChangedCallback(this.viewport);
};
private removeLogoControl(): void {
// @ts-ignore
const controls = this.map._controls as IControl[];
const logoCtr = controls.find((ctr: IControl) => {
if (ctr.hasOwnProperty('_updateLogo')) {
return true;
}
});
if (logoCtr) {
this.map.removeControl(logoCtr);
}
}
}

View File

@ -1,4 +1,7 @@
/// <reference path="../../../node_modules/@types/amap-js-api/index.d.ts" />
import { IControl } from 'mapbox-gl';
interface Window {
onLoad: () => void;
}
@ -8,23 +11,21 @@ interface IAMapEvent {
near: number;
far: number;
height: number;
pitch: number;
rotation: number;
pitch: number;
rotation: number;
aspect: number;
position: {x: number; y: number;};
}
position: { x: number; y: number };
};
}
interface IAMapInstance {
on(eventName: string, handler: (event: IAMapEvent) => void): void;
getZoom(): number;
getCenter(): {lat: number; lng: number};
[key:string]: Function;
get(key: string): unknown;
}
interface IMapboxInstance {
_controls: IControl[];
transform: {
width: number;
height: number;
}
};
}

View File

@ -22,6 +22,7 @@
"@l7/core": "^0.0.1",
"@l7/maps": "^0.0.1",
"@l7/renderer": "^0.0.1",
"mapbox-gl": "^1.2.1",
"inversify": "^5.0.1",
"inversify-inject-decorators": "^3.1.0",
"reflect-metadata": "^0.1.13"

View File

@ -1,23 +1,29 @@
import {
Bounds,
container,
IControl,
IControlService,
IIconService,
IImage,
ILayer,
ILngLat,
IMapConfig,
IMapService,
IMarker,
IPoint,
IRenderConfig,
IRendererService,
ISceneService,
MapType,
Point,
SceneEventList,
SceneService,
TYPES,
} from '@l7/core';
import { AMapService, MapboxService } from '@l7/maps';
import { ReglRendererService } from '@l7/renderer';
import { inject, injectable } from 'inversify';
import { Map } from 'mapbox-gl';
// 绑定渲染引擎服务
container
@ -41,10 +47,14 @@ let mapType: MapType;
* scene.render();
*/
class Scene {
private iconService: IIconService;
public map: AMap.Map | Map;
private sceneService: ISceneService;
private mapService: IMapService;
private mapType: MapType;
private controlService: IControlService;
private iconService: IIconService;
// private mapType: MapType;
public constructor(config: IMapConfig & IRenderConfig) {
const { type = MapType.amap } = config;
@ -77,9 +87,16 @@ class Scene {
this.sceneService.init(config);
this.mapService = container.get<IMapService>(TYPES.IMapService);
this.iconService = container.get<IIconService>(TYPES.IIconService);
this.controlService = container.get<IControlService>(TYPES.IControlService);
this.map = this.mapService.map; // 暴露原生map方法
mapType = this.mapService.getType();
}
public getMapService(): IMapService {
return this.mapService;
//
}
public addLayer(layer: ILayer): void {
this.sceneService.addLayer(layer);
}
@ -87,25 +104,65 @@ class Scene {
public render(): void {
this.sceneService.render();
}
// asset method
public addImage(id: string, img: IImage) {
// this.sceneService.
this.iconService.addImage(id, img);
}
public hasImage(id: string) {
this.iconService.hasImage(id);
}
public removeImage(id: string) {
this.iconService.removeImage(id);
}
// map control method
public addControl(ctr: IControl) {
this.controlService.addControl(ctr, this.mapService);
}
public removeControl(ctr: IControl) {
this.controlService.removeControl(ctr);
}
// marker
public addMarker(marker: IMarker) {
marker.addTo(this);
}
// map envent;
public on(type: string, handle: (...args: any[]) => void): void {
SceneEventList.indexOf(type) === -1
? this.mapService.on(type, handle)
: this.sceneService.on(type, handle);
}
public off(type: string, handle: (...args: any[]) => void): void {
SceneEventList.indexOf(type) === -1
? this.mapService.off(type, handle)
: this.sceneService.off(type, handle);
}
// map method
public getZoom(): number {
return this.mapService.getZoom();
}
public getCenter(): ILngLat {
return this.mapService.getCenter();
}
public getPitch(): number {
return this.mapService.getPitch();
}
public getRotation(): number {
return this.mapService.getRotation();
}
public getBounds(): Bounds {
return this.mapService.getBounds();
}
@ -118,21 +175,27 @@ class Scene {
public zoomIn(): void {
this.mapService.zoomIn();
}
public zoomOut(): void {
this.mapService.zoomOut();
}
public panTo(p: Point): void {
this.mapService.panTo(p);
}
public panBy(pixel: Point): void {
this.mapService.panTo(pixel);
}
public fitBounds(bound: Bounds): void {
this.mapService.fitBounds(bound);
}
public setZoomAndCenter(zoom: number, center: Point): void {
this.mapService.setZoomAndCenter(zoom, center);
}
public setMapStyle(style: string): void {
this.mapService.setMapStyle(style);
}
@ -141,12 +204,15 @@ class Scene {
public pixelToLngLat(pixel: Point): ILngLat {
return this.mapService.pixelToLngLat(pixel);
}
public lngLatToPixel(lnglat: Point): IPoint {
return this.mapService.lngLatToPixel(lnglat);
}
public containerToLngLat(pixel: Point): ILngLat {
return this.mapService.containerToLngLat(pixel);
}
public lngLatToContainer(lnglat: Point): IPoint {
return this.mapService.lngLatToContainer(lnglat);
}

View File

@ -28,6 +28,7 @@
"@turf/invariant": "^6.1.2",
"@turf/meta": "^6.0.2",
"d3-dsv": "^1.1.1",
"d3-hexbin": "^0.2.2",
"eventemitter3": "^3.1.0",
"gl-matrix": "^3.1.0",
"inversify": "^5.0.1",
@ -40,6 +41,7 @@
},
"devDependencies": {
"@types/d3-dsv": "^1.0.36",
"@types/d3-hexbin": "^0.2.3",
"@types/gl-matrix": "^2.4.5",
"@types/lodash": "^4.14.138",
"@types/viewport-mercator-project": "^6.1.0"

View File

@ -6,6 +6,7 @@ import json from './parser/json';
import Source from './source';
import { cluster } from './transform/cluster';
import { aggregatorToGrid } from './transform/grid';
import { pointToHexbin } from './transform/hexagon';
export default Source;
registerParser('geojson', geojson);
registerParser('image', image);
@ -13,6 +14,7 @@ registerParser('csv', csv);
registerParser('json', json);
registerTransform('cluster', cluster);
registerTransform('grid', aggregatorToGrid);
registerTransform('hexagon', pointToHexbin);
export {
getTransform,
registerTransform,

View File

@ -41,7 +41,6 @@ export default class Source extends EventEmitter {
});
this.init();
}
private excuteParser(): void {
const parser = this.parser;
const type: string = parser.type || 'geojson';

View File

@ -2,13 +2,8 @@
*
*/
import { IParserCfg, IParserData, ISourceCFG, ITransform } from '@l7/core';
import { max, mean, min, sum } from './statistics';
const statMap: { [key: string]: any } = {
min,
max,
mean,
sum,
};
import { statMap } from './statistics';
interface IGridHash {
[key: string]: any;
}

View File

@ -0,0 +1,60 @@
import { aProjectFlat, unProjectFlat } from '@l7/utils';
import { hexbin } from 'd3-hexbin';
const R_EARTH = 6378000;
import {
IParseDataItem,
IParserCfg,
IParserData,
ISourceCFG,
ITransform,
} from '@l7/core';
import { statMap } from './statistics';
interface IHexBinItem<T> extends Array<T> {
x: number;
y: number;
[key: string]: any;
}
interface IRawData {
coordinates: [number, number];
[key: string]: any;
}
export function pointToHexbin(data: IParserData, option: ITransform) {
const dataArray = data.dataArray;
const { size = 10 } = option;
const pixlSize = ((size / (2 * Math.PI * R_EARTH)) * (256 << 20)) / 2;
const screenPoints: IRawData[] = dataArray.map((point: IParseDataItem) => {
const [x, y] = aProjectFlat(point.coordinates);
return {
...point,
coordinates: [x, y],
};
});
const newHexbin = hexbin<IRawData>()
.radius(pixlSize)
.x((d: IRawData) => d.coordinates[0])
.y((d: IRawData) => d.coordinates[1]);
const hexbinBins = newHexbin(screenPoints);
const result: IParserData = {
dataArray: hexbinBins.map((hex: IHexBinItem<IRawData>, index: number) => {
if (option.field && option.method) {
const columns = getColumn(hex, option.field);
hex[option.method] = statMap[option.method](columns);
}
return {
[option.method]: hex[option.method],
count: hex.length,
coordinates: unProjectFlat([hex.x, hex.y]),
_id: index + 1,
};
}),
radius: pixlSize,
};
return result;
}
function getColumn(data: IHexBinItem<IRawData>, columnName: string) {
return data.map((item: IRawData) => {
return item[columnName];
});
}

View File

@ -69,3 +69,9 @@ function mean(x: number[]) {
}
export { sum, max, min, mean };
export const statMap: { [key: string]: any } = {
min,
max,
mean,
sum,
};

143
packages/utils/src/dom.ts Normal file
View File

@ -0,0 +1,143 @@
const docStyle = window.document.documentElement.style;
type ELType = HTMLElement | SVGElement;
export function createRendererContainer(domId: string): HTMLDivElement | null {
const $wrapper = document.getElementById(domId);
if ($wrapper) {
const $container = document.createElement('div');
$container.style.cssText += `
position: absolute;
top: 0;
z-index:2;
height: 100%;
width: 100%;
pointer-events: none;
`;
$container.id = 'l7_canvaslayer';
$wrapper.appendChild($container);
return $container;
}
return null;
}
export function trim(str: string) {
return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
}
// @function splitWords(str: String): String[]
// Trims and splits the string on whitespace and returns the array of parts.
export function splitWords(str: string) {
return trim(str).split(/\s+/);
}
function testProp(props: string[]): string {
if (!docStyle) {
return props[0];
}
for (const i in props) {
if (props[i] && props[i] in docStyle) {
return props[i];
}
}
return props[0];
}
export function create(
tagName: string,
className?: string,
container?: HTMLElement,
) {
const el = document.createElement(tagName);
el.className = className || '';
if (container) {
container.appendChild(el);
}
return el;
}
// @function remove(el: HTMLElement)
// Removes `el` from its parent element
export function remove(el: ELType) {
const parent = el.parentNode;
if (parent) {
parent.removeChild(el);
}
}
// @function addClass(el: HTMLElement, name: String)
// Adds `name` to the element's class attribute.
export function addClass(el: ELType, name: string) {
if (el.classList !== undefined) {
const classes = splitWords(name);
for (let i = 0, len = classes.length; i < len; i++) {
el.classList.add(classes[i]);
}
} else if (!hasClass(el, name)) {
const className = getClass(el);
setClass(el, (className ? className + ' ' : '') + name);
}
}
// @function removeClass(el: HTMLElement, name: String)
// Removes `name` from the element's class attribute.
export function removeClass(el: ELType, name: string) {
if (el.classList !== undefined) {
el.classList.remove(name);
} else {
setClass(
el,
trim((' ' + getClass(el) + ' ').replace(' ' + name + ' ', ' ')),
);
}
}
// @function hasClass(el: HTMLElement, name: String): Boolean
// Returns `true` if the element's class attribute contains `name`.
export function hasClass(el: ELType, name: string) {
if (el.classList !== undefined) {
return el.classList.contains(name);
}
const className = getClass(el);
return (
className.length > 0 &&
new RegExp('(^|\\s)' + name + '(\\s|$)').test(className)
);
}
// @function setClass(el: HTMLElement, name: String)
// Sets the element's class.
export function setClass(el: ELType, name: string) {
if (el instanceof HTMLElement) {
el.className = name;
} else {
// in case of SVG element
el.className.baseVal = name;
}
}
// @function getClass(el: HTMLElement): String
// Returns the element's class.
export function getClass(el: ELType) {
// Check if the element is an SVGElementInstance and use the correspondingElement instead
// (Required for linked SVG elements in IE11.)
if (el instanceof SVGElement) {
el = el.correspondingElement;
}
return el.className.baseVal === undefined
? el.className
: el.className.baseVal;
}
export function empty(el: ELType) {
while (el.firstChild) {
el.removeChild(el.firstChild);
}
}
const transformProp = testProp(['transform', 'WebkitTransform']);
export function setTransform(el: ELType, value: string) {
// @ts-ignore
el.style[transformProp] = value;
}

View File

@ -0,0 +1,8 @@
export function bindAll(fns: string[], context: any) {
fns.forEach((fn) => {
if (!context[fn]) {
return;
}
context[fn] = context[fn].bind(context);
});
}

View File

@ -1,4 +1,12 @@
import { BBox } from '@turf/helpers';
import {
BBox,
Coord,
degreesToRadians,
isObject,
radiansToLength,
Units,
} from '@turf/helpers';
const originShift = (2 * Math.PI * 6378137) / 2.0;
export type Point = [number, number] | [number, number, number];
/**
@ -6,7 +14,7 @@ export type Point = [number, number] | [number, number, number];
* @param {dataArray} data
* @return {Array} dataExtent
*/
export function extent(data: any[]) {
export function extent(data: any[]): BBox {
const dataExtent: BBox = [Infinity, Infinity, -Infinity, -Infinity];
data.forEach((item) => {
const { coordinates } = item;
@ -150,7 +158,40 @@ export function aProjectFlat(lnglat: number[]) {
const b = 0.5;
const c = -0.5 / Math.PI;
d = 0.5;
x = scale * (a * x + b) - 215440491;
y = scale * (c * y + d) - 106744817;
x = scale * (a * x + b);
y = scale * (c * y + d);
return [parseInt(x.toString(), 10), parseInt(y.toString(), 10)];
}
export function unProjectFlat(px: number[]): [number, number] {
const a = 0.5 / Math.PI;
const b = 0.5;
const c = -0.5 / Math.PI;
let d = 0.5;
const scale = 256 << 20;
let [x, y] = px;
x = (x / scale - b) / a;
y = (y / scale - d) / c;
y = (Math.atan(Math.pow(Math.E, y)) - Math.PI / 4) * 2;
d = Math.PI / 180;
const lat = y / d;
const lng = x / d;
return [lng, lat];
}
export function lnglatDistance(
coordinates1: [number, number],
coordinates2: [number, number],
units?: Units,
): number {
const dLat = degreesToRadians(coordinates2[1] - coordinates1[1]);
const dLon = degreesToRadians(coordinates2[0] - coordinates1[0]);
const lat1 = degreesToRadians(coordinates1[1]);
const lat2 = degreesToRadians(coordinates2[1]);
const a =
Math.pow(Math.sin(dLat / 2), 2) +
Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2);
return radiansToLength(
2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)),
(units = 'meters'),
);
}

View File

@ -1,3 +1,7 @@
export { djb2hash, BKDRHash } from './hash';
import * as DOM from './dom';
export * from './fetchData';
export * from './geo';
export * from './lru_cache';
export * from './event';
export { DOM };

View File

@ -0,0 +1,86 @@
/**
* LRU Cache class with limit
*
* Update order for each get/set operation
* Delete oldest when reach given limit
*/
type callback = (...args: any[]) => void;
interface ICache {
[key: string]: any;
}
export class LRUCache {
private limit: number;
private cache: ICache;
private destroy: (value: any, key: string) => void;
private order: any[];
constructor(limit = 50, destroy?: callback) {
this.limit = limit;
this.destroy = destroy || this.defaultDestroy;
this.order = [];
this.clear();
}
public clear() {
this.order.forEach((key) => {
this.delete(key);
});
this.cache = {};
// access/update order, first item is oldest, last item is newest
this.order = [];
}
public get(key: string) {
const value = this.cache[key];
if (value) {
// update order
this.deleteOrder(key);
this.appendOrder(key);
}
return value;
}
public set(key: string, value: any) {
if (!this.cache[key]) {
// if reach limit, delete the oldest
if (Object.keys(this.cache).length === this.limit) {
this.delete(this.order[0]);
}
this.cache[key] = value;
this.appendOrder(key);
} else {
// if found in cache, delete the old one, insert new one to the first of list
this.delete(key);
this.cache[key] = value;
this.appendOrder(key);
}
}
public delete(key: string) {
const value = this.cache[key];
if (value) {
this.deleteCache(key);
this.deleteOrder(key);
this.destroy(value, key);
}
}
private deleteCache(key: string) {
delete this.cache[key];
}
private deleteOrder(key: string) {
const index = this.order.findIndex((o) => o === key);
if (index >= 0) {
this.order.splice(index, 1);
}
}
private appendOrder(key: string) {
this.order.push(key);
}
private defaultDestroy(value: any, key: string) {
return null;
}
}

View File

@ -1,4 +1,6 @@
// @ts-ignore
import '!style-loader!css-loader!./css/l7.css';
import { Marker, Popup, Scale, Zoom } from '@l7/component';
import { PolygonLayer } from '@l7/layers';
// @ts-ignore
import { Scene } from '@l7/scene';
@ -19,7 +21,7 @@ export default class Mapbox extends React.Component {
id: 'map',
type: 'mapbox',
style: 'mapbox://styles/mapbox/streets-v9',
center: [110.19382669582967, 50.258134],
center: [110.19382669582967, 30.258134],
pitch: 0,
zoom: 3,
});
@ -43,6 +45,33 @@ export default class Mapbox extends React.Component {
});
scene.addLayer(layer);
scene.render();
scene.on('loaded', () => {
const zoomControl = new Zoom({
position: 'bottomright',
});
const scaleControl = new Scale();
const popup = new Popup({
offsets: [0, 20],
})
.setLnglat({
lng: 120.19382669582967,
lat: 30.258134,
})
.setText('hello')
.addTo(scene);
const maker = new Marker();
maker
.setLnglat({
lng: 120.19382669582967,
lat: 30.258134,
})
.addTo(scene);
scene.addControl(zoomControl);
scene.addControl(scaleControl);
console.log(layer);
// layer.fitBounds();
});
}
public render() {

View File

@ -0,0 +1,400 @@
.l7-marker {
position: absolute !important;
top: 0;
left: 0;
z-index: 5;
}
.l7-popup-anchor-top,
.l7-popup-anchor-top-left,
.l7-popup-anchor-top-right {
-webkit-flex-direction: column;
flex-direction: column;
}
.l7-popup-anchor-bottom,
.l7-popup-anchor-bottom-left,
.l7-popup-anchor-bottom-right {
-webkit-flex-direction: column-reverse;
flex-direction: column-reverse;
}
.l7-popup-anchor-left {
-webkit-flex-direction: row;
flex-direction: row;
}
.l7-popup-anchor-right {
-webkit-flex-direction: row-reverse;
flex-direction: row-reverse;
}
.l7-popup {
position: absolute;
top: 0;
left: 0;
display: -webkit-flex;
display: flex;
will-change: transform;
pointer-events: none;
z-index: 5;
}
.l7-popup-tip {
width: 0;
height: 0;
border: 10px solid transparent;
z-index: 1;
}
.l7-popup-anchor-top .l7-popup-tip {
-webkit-align-self: center;
align-self: center;
border-top: none;
border-bottom-color: #fff;
}
.l7-popup-anchor-top-left .l7-popup-tip {
-webkit-align-self: flex-start;
align-self: flex-start;
border-top: none;
border-left: none;
border-bottom-color: #fff;
}
.l7-popup-anchor-top-right .l7-popup-tip {
-webkit-align-self: flex-end;
align-self: flex-end;
border-top: none;
border-right: none;
border-bottom-color: #fff;
}
.l7-popup-anchor-bottom .l7-popup-tip {
-webkit-align-self: center;
align-self: center;
border-bottom: none;
border-top-color: #fff;
}
.l7-popup-anchor-bottom-left .l7-popup-tip {
-webkit-align-self: flex-start;
align-self: flex-start;
border-bottom: none;
border-left: none;
border-top-color: #fff;
}
.l7-popup-anchor-bottom-right .l7-popup-tip {
-webkit-align-self: flex-end;
align-self: flex-end;
border-bottom: none;
border-right: none;
border-top-color: #fff;
}
.l7-popup-anchor-left .l7-popup-tip {
-webkit-align-self: center;
align-self: center;
border-left: none;
border-right-color: #fff;
}
.l7-popup-anchor-right .l7-popup-tip {
-webkit-align-self: center;
align-self: center;
border-right: none;
border-left-color: #fff;
}
.l7-popup-close-button {
position: absolute;
right: 0;
top: 0;
border: 0;
padding: 0;
font-size: 25px;
line-height: 20px;
border-radius: 0 3px 0 0;
cursor: pointer;
background-color: transparent;
}
.l7-popup-close-button:hover {
background-color: rgba(0, 0, 0, 0.05);
}
.l7-popup-content {
position: relative;
background: #fff;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
padding: 10px 10px 15px;
pointer-events: auto;
}
.l7-popup-anchor-top-left .l7-popup-content {
border-top-left-radius: 0;
}
.l7-popup-anchor-top-right .l7-popup-content {
border-top-right-radius: 0;
}
.l7-popup-anchor-bottom-left .l7-popup-content {
border-bottom-left-radius: 0;
}
.l7-popup-anchor-bottom-right .l7-popup-content {
border-bottom-right-radius: 0;
}
.l7-popup-track-pointer {
display: none;
}
.l7-popup-track-pointer * {
pointer-events: none;
user-select: none;
}
.l7-map:hover .l7-popup-track-pointer {
display: flex;
}
.l7-map:active .l7-popup-track-pointer {
display: none;
}
.l7-popup-close-button {
position: absolute;
right: 0;
top: 0;
border: 0;
border-radius: 0 3px 0 0;
cursor: pointer;
background-color: transparent;
}
.l7-popup-close-button:hover {
background-color: rgba(0, 0, 0, 0.05);
}
.l7-popup-content {
position: relative;
background: #fff;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
padding: 10px 10px 15px;
pointer-events: auto;
}
/* general toolbar styles */
.l7-bar {
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
border-radius: 4px;
}
.l7-bar a,
.l7-bar a:hover {
background-color: #fff;
width: 36px;
height: 36px;
line-height: 30px;
font-size: 30px;
display: block;
text-align: center;
text-decoration: none;
color: #8E9DAB;
}
.l7-bar a,
.l7-control-layers-toggle {
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}
.l7-bar a:hover {
background-color: #f4f4f4;
}
.l7-bar a:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.l7-bar a:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: none;
}
.l7-bar a.l7-disabled {
cursor: default;
background-color: #f4f4f4;
color: #bbb;
}
/* control positioning */
.l7-control-container {
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
}
.l7-control-hide {
display: none;
}
.l7-control {
position: relative;
z-index: 800;
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
.l7-top,
.l7-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.l7-top {
top: 0;
}
.l7-right {
right: 0;
}
.l7-bottom {
bottom: 0;
}
.l7-left {
left: 0;
}
.l7-control {
float: left;
clear: both;
}
.l7-right .l7-control {
float: right;
}
.l7-top .l7-control {
margin-top: 10px;
}
.l7-bottom .l7-control {
margin-bottom: 10px;
}
.l7-left .l7-control {
margin-left: 10px;
}
.l7-right .l7-control {
margin-right: 10px;
}
/* attribution and scale controls */
.l7-control-container .l7-control-attribution {
background: #fff;
background: rgba(255, 255, 255, 0.7);
margin: 0;
}
.l7-control-attribution,
.l7-control-scale-line {
padding: 0 5px;
color: #333;
}
.l7-control-attribution a {
text-decoration: none;
}
.l7-control-attribution a:hover {
text-decoration: underline;
}
.l7-container .l7-control-attribution,
.l7-container .l7-control-scale {
font-size: 11px;
padding: 5px 5px 2px 5px;
background: rgba(255, 255, 255, 0.7);
}
.l7-left .l7-control-scale {
margin-left: 5px;
}
.l7-bottom .l7-control-scale {
margin-bottom: 5px;
}
.l7-control-scale-line {
border: 2px solid #8E9DAB;
border-top: none;
color: #8e9dab;
line-height: 1.1;
padding: 2px 5px 1px;
font-size: 11px;
white-space: nowrap;
overflow: hidden;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: #fff;
background: rgba(255, 255, 255, 0.8);
}
.l7-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
border-bottom: none;
margin-top: -2px;
}
.l7-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
}
.l7-touch .l7-control-attribution,
.l7-touch .l7-control-layers,
.l7-touch .l7-bar {
box-shadow: none;
}
.l7-touch .l7-control-layers,
.l7-touch .l7-bar {
border: 2px solid rgba(0,0,0,0.2);
background-clip: padding-box;
}
/* layers control */
.l7-control-layers {
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
background: #fff;
border-radius: 5px;
}
.l7-control-layers-toggle {
background-image: url(../images/layers.svg);
width: 36px;
height: 36px;
}
.l7-retina .l7-control-layers-toggle {
background-image: url(../images/layers.svg);
background-size: 26px 26px;
}
.l7-touch .l7-control-layers-toggle {
width: 44px;
height: 44px;
}
.l7-control-layers .l7-control-layers-list,
.l7-control-layers-expanded .l7-control-layers-toggle {
display: none;
}
.l7-control-layers-expanded .l7-control-layers-list {
display: block;
position: relative;
}
.l7-control-layers-expanded {
padding: 6px 10px 6px 6px;
color: #333;
background: #fff;
}
.l7-control-layers-scrollbar {
overflow-y: scroll;
overflow-x: hidden;
padding-right: 5px;
}
.l7-control-layers-selector {
margin-top: 2px;
position: relative;
top: 1px;
}
.l7-control-layers label {
display: block;
}
.l7-control-layers-separator {
height: 0;
border-top: 1px solid #ddd;
margin: 5px -10px 5px -6px;
}

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566292427369" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8341" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M256 341.333333l256 128 256-128-256-128-256 128z m276.864-208.384l341.034667 173.909334c20.736 10.581333 28.202667 34.56 16.682666 53.632a41.386667 41.386667 0 0 1-16.64 15.317333l-341.077333 173.909333a46.336 46.336 0 0 1-41.728 0L150.101333 375.808c-20.736-10.581333-28.202667-34.56-16.682666-53.632a41.386667 41.386667 0 0 1 16.64-15.317333l341.077333-173.909334c12.970667-6.613333 28.757333-6.613333 41.728 0z m0 587.349334a45.653333 45.653333 0 0 1-41.728 0l-341.034667-176.938667c-20.736-10.752-28.202667-35.157333-16.682666-54.528a41.642667 41.642667 0 0 1 16.64-15.573333 34.901333 34.901333 0 0 1 32.213333 0l308.906667 160.213333c12.928 6.741333 28.714667 6.741333 41.685333 0l308.864-160.213333a34.901333 34.901333 0 0 1 32.170667 0c20.736 10.752 28.202667 35.157333 16.682666 54.528a41.642667 41.642667 0 0 1-16.64 15.573333l-341.077333 176.938667z m0 170.666666a45.653333 45.653333 0 0 1-41.728 0l-341.034667-176.938666c-20.736-10.752-28.202667-35.157333-16.682666-54.528a41.642667 41.642667 0 0 1 16.64-15.573334 34.901333 34.901333 0 0 1 32.213333 0l308.906667 160.213334c12.928 6.741333 28.714667 6.741333 41.685333 0l308.864-160.213334a34.901333 34.901333 0 0 1 32.170667 0c20.736 10.752 28.202667 35.157333 16.682666 54.528a41.642667 41.642667 0 0 1-16.64 15.573334l-341.077333 176.938666z" fill="#000000" p-id="8342"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -1,3 +1,5 @@
import '!style-loader!css-loader!./css/l7.css';
import { Marker, Popup, Scale, Zoom } from '@l7/component';
import { Point } from '@l7/layers';
import { Scene } from '@l7/scene';
import * as React from 'react';
@ -15,7 +17,7 @@ export default class PointImage extends React.Component {
id: 'map',
pitch: 0,
type: 'mapbox',
style: 'mapbox://styles/mapbox/streets-v9',
style: 'mapbox://styles/mapbox/dark-v10',
zoom: 1,
});
scene.addImage(
@ -23,26 +25,41 @@ export default class PointImage extends React.Component {
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*kzTMQqS2QdUAAAAAAAAAAABkARQnAQ',
);
const pointLayer = new Point({});
const p1 = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: [83.671875, 44.84029065139799],
},
},
],
};
// console.log(zoomControl);
//
pointLayer
.source(data)
// .color('blue')
.shape('00')
.size(14);
.size(40);
scene.addLayer(pointLayer);
scene.render();
scene.on('loaded', () => {
const zoomControl = new Zoom({
position: 'bottomright',
});
const scaleControl = new Scale();
const popup = new Popup({
offsets: [0, 20],
})
.setLnglat({
lng: 120.19382669582967,
lat: 30.258134,
})
.setText('hello')
.addTo(scene);
const maker = new Marker();
maker
.setLnglat({
lng: 120.19382669582967,
lat: 30.258134,
})
.addTo(scene);
scene.addControl(zoomControl);
scene.addControl(scaleControl);
});
}
public render() {

254
yarn.lock
View File

@ -2057,7 +2057,7 @@
resolved "https://registry.yarnpkg.com/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz#8a83f9335c7860effa2eeeca254332aa0aeed8f2"
integrity sha1-ioP5M1x4YO/6Lu7KJUMyqgru2PI=
"@mapbox/tiny-sdf@^1.1.0":
"@mapbox/tiny-sdf@^1.1.0", "@mapbox/tiny-sdf@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@mapbox/tiny-sdf/-/tiny-sdf-1.1.1.tgz#16a20c470741bfe9191deb336f46e194da4a91ff"
integrity sha512-Ihn1nZcGIswJ5XGbgFAvVumOgWpvIjBX9jiRlIl46uQG9vJOF51ViBYHF95rEZupuyQbEmhLaDPLQlU7fUTsBg==
@ -2690,12 +2690,20 @@
"@svgr/plugin-svgo" "^4.3.1"
loader-utils "^1.2.3"
"@turf/distance@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/@turf/distance/-/distance-6.0.1.tgz#0761f28784286e7865a427c4e7e3593569c2dea8"
integrity sha512-q7t7rWIWfkg7MP1Vt4uLjSEhe5rPfCO2JjpKmk7JC+QZKEQkuvHEqy3ejW1iC7Kw5ZcZNR3qdMGGz+6HnVwqvg==
dependencies:
"@turf/helpers" "6.x"
"@turf/invariant" "6.x"
"@turf/helpers@6.x", "@turf/helpers@^6.1.4":
version "6.1.4"
resolved "https://registry.yarnpkg.com/@turf/helpers/-/helpers-6.1.4.tgz#d6fd7ebe6782dd9c87dca5559bda5c48ae4c3836"
integrity sha512-vJvrdOZy1ngC7r3MDA7zIGSoIgyrkWcGnNIEaqn/APmw+bVLF2gAW7HIsdTxd12s5wQMqEpqIQrmrbRRZ0xC7g==
"@turf/invariant@^6.1.2":
"@turf/invariant@6.x", "@turf/invariant@^6.1.2":
version "6.1.2"
resolved "https://registry.yarnpkg.com/@turf/invariant/-/invariant-6.1.2.tgz#6013ed6219f9ac2edada9b31e1dfa5918eb0a2f7"
integrity sha512-WU08Ph8j0J2jVGlQCKChXoCtI50BB3yEH21V++V0T4cR1T27HKCxkehV2sYMwTierfMBgjwSwDIsxnR4/2mWXg==
@ -2769,6 +2777,11 @@
resolved "https://registry.yarnpkg.com/@types/d3-dsv/-/d3-dsv-1.0.36.tgz#e91129d7c02b1b814838d001e921e8b9a67153d0"
integrity sha512-jbIWQ27QJcBNMZbQv0NSQMHnBDCmxghAxePxgyiPH1XPCRkOsTBei7jcdi3fDrUCGpCV3lKrSZFSlOkhUQVClA==
"@types/d3-hexbin@^0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@types/d3-hexbin/-/d3-hexbin-0.2.3.tgz#75a86a3d2e782ca3070ebcce789abdb88036abda"
integrity sha512-R/mmx2FJucHACRvGFoI+6jpr3mOAD6wuU2OjuCixxGRPHdmQNlMtBGBwxTmTs//kJvBzk9/vMhn47QOcY8Afrg==
"@types/d3-scale@^2.1.1":
version "2.1.1"
resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-2.1.1.tgz#405e58771ec6ae7b8f7b4178ee1887620759e8f7"
@ -3761,6 +3774,14 @@ babel-plugin-const-enum@^0.0.2:
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-syntax-typescript" "^7.3.3"
babel-plugin-css-modules-transform@^1.6.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/babel-plugin-css-modules-transform/-/babel-plugin-css-modules-transform-1.6.2.tgz#eecf4889637bf1c56cda25ee21df060775d1bd22"
integrity sha512-zBsI54N5n979vfYpqFzQ6oRwEiVcmLH5REyaincNW+Ecl52nvRsQPYIbDcJzHePrXI20YSRUw6G/qbPwZZDgfg==
dependencies:
css-modules-require-hook "^4.0.6"
mkdirp "^0.5.1"
babel-plugin-dynamic-import-node@2.3.0, babel-plugin-dynamic-import-node@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f"
@ -3950,6 +3971,14 @@ babel-plugin-transform-minify-booleans@^6.9.4:
resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz#acbb3e56a3555dd23928e4b582d285162dd2b198"
integrity sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=
babel-plugin-transform-postcss@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-postcss/-/babel-plugin-transform-postcss-0.3.0.tgz#1f2e5d047bbd0ce84ac443c4715003d3796ee237"
integrity sha512-Sn4coeHvw3PCc22KVWtrkFFTh/K3G1ZCl26O3HZyLBgna987oHqTjJui+ofVUmglaWqydmFiEQd999uXWrmQLQ==
dependencies:
debug "^2.6.0"
postcss-load-config "^1.1.0"
babel-plugin-transform-property-literals@^6.9.4:
version "6.9.4"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz#98c1d21e255736573f93ece54459f6ce24985d39"
@ -5267,6 +5296,19 @@ corejs-upgrade-webpack-plugin@^2.0.0:
resolve-from "^5.0.0"
webpack "^4.38.0"
cosmiconfig@^2.1.0, cosmiconfig@^2.1.1:
version "2.2.2"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-2.2.2.tgz#6173cebd56fac042c1f4390edf7af6c07c7cb892"
integrity sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==
dependencies:
is-directory "^0.3.1"
js-yaml "^3.4.3"
minimist "^1.2.0"
object-assign "^4.1.0"
os-homedir "^1.0.1"
parse-json "^2.2.0"
require-from-string "^1.1.0"
cosmiconfig@^5.0.0, cosmiconfig@^5.1.0, cosmiconfig@^5.2.0, cosmiconfig@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
@ -5404,7 +5446,7 @@ css-loader@^2.1.1:
postcss-value-parser "^3.3.0"
schema-utils "^1.0.0"
css-loader@^3.0.0:
css-loader@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.2.0.tgz#bb570d89c194f763627fcf1f80059c6832d009b2"
integrity sha512-QTF3Ud5H7DaZotgdcJjGMvyDj5F3Pn1j/sC6VBEOVp94cbwqyIBdcs/quzj4MC1BKQSrTpQznegH/5giYbhnCQ==
@ -5422,6 +5464,24 @@ css-loader@^3.0.0:
postcss-value-parser "^4.0.0"
schema-utils "^2.0.0"
css-modules-require-hook@^4.0.6:
version "4.2.3"
resolved "https://registry.yarnpkg.com/css-modules-require-hook/-/css-modules-require-hook-4.2.3.tgz#6792ca412b15e23e6f9be6a07dcef7f577ff904d"
integrity sha1-Z5LKQSsV4j5vm+agfc739Xf/kE0=
dependencies:
debug "^2.2.0"
generic-names "^1.0.1"
glob-to-regexp "^0.3.0"
icss-replace-symbols "^1.0.2"
lodash "^4.3.0"
postcss "^6.0.1"
postcss-modules-extract-imports "^1.0.0"
postcss-modules-local-by-default "^1.0.1"
postcss-modules-resolve-imports "^1.3.0"
postcss-modules-scope "^1.0.0"
postcss-modules-values "^1.1.1"
seekout "^1.0.1"
css-select-base-adapter@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7"
@ -5447,6 +5507,15 @@ css-select@^2.0.0:
domutils "^1.7.0"
nth-check "^1.0.2"
css-selector-tokenizer@^0.7.0:
version "0.7.1"
resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz#a177271a8bca5019172f4f891fc6eed9cbf68d5d"
integrity sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==
dependencies:
cssesc "^0.1.0"
fastparse "^1.1.1"
regexpu-core "^1.0.0"
css-to-react-native@^2.0.3:
version "2.3.2"
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.3.2.tgz#e75e2f8f7aa385b4c3611c52b074b70a002f2e7d"
@ -5492,6 +5561,11 @@ csscolorparser@~1.0.2:
resolved "https://registry.yarnpkg.com/csscolorparser/-/csscolorparser-1.0.3.tgz#b34f391eea4da8f3e98231e2ccd8df9c041f171b"
integrity sha1-s085HupNqPPpgjHizNjfnAQfFxs=
cssesc@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
integrity sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=
cssesc@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
@ -5591,6 +5665,11 @@ d3-format@1:
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.1.tgz#c45f74b17c5a290c072a4ba7039dd19662cd5ce6"
integrity sha512-TUswGe6hfguUX1CtKxyG2nymO+1lyThbkS1ifLX0Sr+dOQtAD5gkrffpHnx+yHNKUZ0Bmg5T4AjUQwugPDrm0g==
d3-hexbin@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/d3-hexbin/-/d3-hexbin-0.2.2.tgz#9c5837dacfd471ab05337a9e91ef10bfc4f98831"
integrity sha1-nFg32s/UcasFM3qeke8Qv8T5iDE=
d3-interpolate@1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.3.2.tgz#417d3ebdeb4bc4efcc8fd4361c55e4040211fd68"
@ -6721,6 +6800,11 @@ fast-levenshtein@~2.0.4:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
fastparse@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9"
integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==
fastq@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.6.0.tgz#4ec8a38f4ac25f21492673adb7eae9cfef47d1c2"
@ -7148,6 +7232,13 @@ gaze@^1.0.0:
dependencies:
globule "^1.0.0"
generic-names@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-1.0.3.tgz#2d786a121aee508876796939e8e3bff836c20917"
integrity sha1-LXhqEhruUIh2eWk56OO/+DbCCRc=
dependencies:
loader-utils "^0.2.16"
genfun@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537"
@ -7919,11 +8010,18 @@ iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-
dependencies:
safer-buffer ">= 2.1.2 < 3"
icss-replace-symbols@^1.1.0:
icss-replace-symbols@^1.0.2, icss-replace-symbols@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=
icss-utils@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-3.0.1.tgz#ee70d3ae8cac38c6be5ed91e851b27eed343ad0f"
integrity sha1-7nDTroysOMa+XtkehRsn7tNDrQ8=
dependencies:
postcss "^6.0.2"
icss-utils@^4.0.0, icss-utils@^4.1.0, icss-utils@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467"
@ -9050,7 +9148,7 @@ js-tokens@^3.0.2:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
js-yaml@^3.13.1:
js-yaml@^3.13.1, js-yaml@^3.4.3:
version "3.13.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
@ -9565,7 +9663,7 @@ lodash@4.17.14:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba"
integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==
lodash@4.17.15, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@~4.17.10:
lodash@4.17.15, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0, lodash@~4.17.10:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
@ -10892,7 +10990,7 @@ os-browserify@^0.3.0:
resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=
os-homedir@^1.0.0:
os-homedir@^1.0.0, os-homedir@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
@ -11451,6 +11549,16 @@ postcss-less@^3.1.0:
dependencies:
postcss "^7.0.14"
postcss-load-config@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-1.2.0.tgz#539e9afc9ddc8620121ebf9d8c3673e0ce50d28a"
integrity sha1-U56a/J3chiASHr+djDZz4M5Q0oo=
dependencies:
cosmiconfig "^2.1.0"
object-assign "^4.1.0"
postcss-load-options "^1.2.0"
postcss-load-plugins "^2.3.0"
postcss-load-config@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.0.tgz#c84d692b7bb7b41ddced94ee62e8ab31b417b003"
@ -11459,6 +11567,22 @@ postcss-load-config@^2.0.0:
cosmiconfig "^5.0.0"
import-cwd "^2.0.0"
postcss-load-options@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-load-options/-/postcss-load-options-1.2.0.tgz#b098b1559ddac2df04bc0bb375f99a5cfe2b6d8c"
integrity sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=
dependencies:
cosmiconfig "^2.1.0"
object-assign "^4.1.0"
postcss-load-plugins@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz#745768116599aca2f009fad426b00175049d8d92"
integrity sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=
dependencies:
cosmiconfig "^2.1.1"
object-assign "^4.1.0"
postcss-loader@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d"
@ -11482,6 +11606,13 @@ postcss-media-query-parser@^0.2.3:
resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244"
integrity sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=
postcss-modules-extract-imports@^1.0.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz#dc87e34148ec7eab5f791f7cd5849833375b741a"
integrity sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==
dependencies:
postcss "^6.0.1"
postcss-modules-extract-imports@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e"
@ -11489,6 +11620,14 @@ postcss-modules-extract-imports@^2.0.0:
dependencies:
postcss "^7.0.5"
postcss-modules-local-by-default@^1.0.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069"
integrity sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=
dependencies:
css-selector-tokenizer "^0.7.0"
postcss "^6.0.1"
postcss-modules-local-by-default@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz#dd9953f6dd476b5fd1ef2d8830c8929760b56e63"
@ -11508,6 +11647,23 @@ postcss-modules-local-by-default@^3.0.2:
postcss-selector-parser "^6.0.2"
postcss-value-parser "^4.0.0"
postcss-modules-resolve-imports@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/postcss-modules-resolve-imports/-/postcss-modules-resolve-imports-1.3.0.tgz#398d3000b95ae969420cdf4cd83fa8067f1c5eae"
integrity sha1-OY0wALla6WlCDN9M2D+oBn8cXq4=
dependencies:
css-selector-tokenizer "^0.7.0"
icss-utils "^3.0.1"
minimist "^1.2.0"
postcss-modules-scope@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90"
integrity sha1-1upkmUx5+XtipytCb75gVqGUu5A=
dependencies:
css-selector-tokenizer "^0.7.0"
postcss "^6.0.1"
postcss-modules-scope@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz#ad3f5bf7856114f6fcab901b0502e2a2bc39d4eb"
@ -11516,6 +11672,14 @@ postcss-modules-scope@^2.1.0:
postcss "^7.0.6"
postcss-selector-parser "^6.0.0"
postcss-modules-values@^1.1.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20"
integrity sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=
dependencies:
icss-replace-symbols "^1.1.0"
postcss "^6.0.1"
postcss-modules-values@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz#479b46dc0c5ca3dc7fa5270851836b9ec7152f64"
@ -11532,6 +11696,13 @@ postcss-modules-values@^3.0.0:
icss-utils "^4.0.0"
postcss "^7.0.6"
postcss-plugin@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/postcss-plugin/-/postcss-plugin-1.0.0.tgz#f763814565b87b93e13449fcf9d75941c566b070"
integrity sha1-92OBRWW4e5PhNEn8+ddZQcVmsHA=
dependencies:
postcss "^6.0.8"
postcss-reporter@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/postcss-reporter/-/postcss-reporter-6.0.1.tgz#7c055120060a97c8837b4e48215661aafb74245f"
@ -11602,6 +11773,15 @@ postcss-value-parser@^4.0.0:
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz#482282c09a42706d1fc9a069b73f44ec08391dc9"
integrity sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==
postcss@^6.0.1, postcss@^6.0.2, postcss@^6.0.8:
version "6.0.23"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324"
integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==
dependencies:
chalk "^2.4.1"
source-map "^0.6.1"
supports-color "^5.4.0"
postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.13, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.5, postcss@^7.0.6, postcss@^7.0.7:
version "7.0.17"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f"
@ -11611,6 +11791,15 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.13, postcss@^7.0.14, postcss@^7.0.1
source-map "^0.6.1"
supports-color "^6.1.0"
postcss@^7.0.18:
version "7.0.18"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.18.tgz#4b9cda95ae6c069c67a4d933029eddd4838ac233"
integrity sha512-/7g1QXXgegpF+9GJj4iN7ChGF40sYuGYJ8WZu8DZWnmhQ/G36hfdk3q9LBJmoK+lZ+yzZ5KYpOoxq7LF1BxE8g==
dependencies:
chalk "^2.4.2"
source-map "^0.6.1"
supports-color "^6.1.0"
potpack@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.1.tgz#d1b1afd89e4c8f7762865ec30bd112ab767e2ebf"
@ -12507,7 +12696,7 @@ regenerate-unicode-properties@^8.1.0:
dependencies:
regenerate "^1.4.0"
regenerate@^1.4.0:
regenerate@^1.2.1, regenerate@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
@ -12559,6 +12748,15 @@ regexp.prototype.flags@^1.2.0:
dependencies:
define-properties "^1.1.2"
regexpu-core@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b"
integrity sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=
dependencies:
regenerate "^1.2.1"
regjsgen "^0.2.0"
regjsparser "^0.1.4"
regexpu-core@^4.5.4:
version "4.5.5"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.5.tgz#aaffe61c2af58269b3e516b61a73790376326411"
@ -12571,11 +12769,23 @@ regexpu-core@^4.5.4:
unicode-match-property-ecmascript "^1.0.4"
unicode-match-property-value-ecmascript "^1.1.0"
regjsgen@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=
regjsgen@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd"
integrity sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==
regjsparser@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"
integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=
dependencies:
jsesc "~0.5.0"
regjsparser@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c"
@ -12728,6 +12938,11 @@ require-directory@^2.1.1:
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
require-from-string@^1.1.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-1.2.1.tgz#529c9ccef27380adfec9a2f965b649bbee636418"
integrity sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=
require-main-filename@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
@ -13028,6 +13243,14 @@ schema-utils@^2.0.0:
ajv "^6.10.2"
ajv-keywords "^3.4.1"
schema-utils@^2.0.1:
version "2.5.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.5.0.tgz#8f254f618d402cc80257486213c8970edfd7c22f"
integrity sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ==
dependencies:
ajv "^6.10.2"
ajv-keywords "^3.4.1"
scss-tokenizer@^0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
@ -13036,6 +13259,11 @@ scss-tokenizer@^0.2.3:
js-base64 "^2.1.8"
source-map "^0.4.2"
seekout@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/seekout/-/seekout-1.0.2.tgz#09ba9f1bd5b46fbb134718eb19a68382cbb1b9c9"
integrity sha1-CbqfG9W0b7sTRxjrGaaDgsuxuck=
select-hose@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
@ -13860,6 +14088,14 @@ style-loader@^0.23.1:
loader-utils "^1.1.0"
schema-utils "^1.0.0"
style-loader@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.0.0.tgz#1d5296f9165e8e2c85d24eee0b7caf9ec8ca1f82"
integrity sha512-B0dOCFwv7/eY31a5PCieNwMgMhVGFe9w+rh7s/Bx8kfFkrth9zfTZquoYvdw8URgiqxObQKcpW51Ugz1HjfdZw==
dependencies:
loader-utils "^1.2.3"
schema-utils "^2.0.1"
style-search@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"
@ -14003,7 +14239,7 @@ supports-color@^3.2.3:
dependencies:
has-flag "^1.0.0"
supports-color@^5.2.0, supports-color@^5.3.0:
supports-color@^5.2.0, supports-color@^5.3.0, supports-color@^5.4.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==