mirror of https://gitee.com/antv-l7/antv-l7
fix: merge conflict
This commit is contained in:
commit
541e00f45e
|
@ -82,3 +82,18 @@ yarn add -W -D typescript jest
|
|||
```bash
|
||||
yarn commit
|
||||
```
|
||||
|
||||
## 发布
|
||||
|
||||
### 设置版本号
|
||||
|
||||
```bash
|
||||
yarn run version:prerelease
|
||||
```
|
||||
设置完成后需要commit一下代码
|
||||
|
||||
### 发布
|
||||
|
||||
yarn run release
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// tslint:disable-next-line:no-submodule-imports
|
||||
import '!style-loader!css-loader!sass-loader!./iframe.scss';
|
||||
// import '!style-loader!css-loader!sass-loader!./iframe.scss';
|
||||
import { addParameters, configure } from '@storybook/react';
|
||||
import { create } from '@storybook/theming';
|
||||
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.0.34](https://github.com/antvis/L7/compare/v2.0.32...v2.0.34) (2020-03-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- fix map reference ([79e16f5](https://github.com/antvis/L7/commit/79e16f5393c6c31cc088e946dc865cdddfde9b73))
|
||||
|
||||
# [2.0.0-beta.28](https://github.com/antvis/L7/compare/v2.0.0-beta.16...v2.0.0-beta.28) (2020-01-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// @see https://babeljs.io/docs/en/next/config-files#project-wide-configuration
|
||||
module.exports = api => {
|
||||
api.cache(() => process.env.NODE_ENV);
|
||||
|
||||
const isSite = api.env('site');
|
||||
const isCDNBundle = api.env('bundle');
|
||||
const isCommonJS = api.env('cjs');
|
||||
|
@ -45,14 +44,14 @@ module.exports = api => {
|
|||
{
|
||||
// https://babeljs.io/docs/en/babel-preset-env#usebuiltins
|
||||
// useBuiltIns: 'usage',
|
||||
// corejs: '3.0.0',
|
||||
...isCDNBundle ? { corejs: '2.0.0' } : {},
|
||||
useBuiltIns: isCDNBundle ? 'usage' : false,
|
||||
// set `modules: false` when building CDN bundle, let rollup do commonjs works
|
||||
// @see https://github.com/rollup/rollup-plugin-babel#modules
|
||||
modules: (isCDNBundle || isESModule) ? false : 'auto',
|
||||
targets: {
|
||||
chrome: 58,
|
||||
ie: 11
|
||||
browsers: [ 'ie >= 11' ]
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -70,6 +69,8 @@ module.exports = api => {
|
|||
'@babel/plugin-proposal-optional-chaining',
|
||||
'@babel/plugin-proposal-nullish-coalescing-operator',
|
||||
'@babel/plugin-syntax-async-generators',
|
||||
// '@babel/plugin-transform-parameters',
|
||||
'transform-node-env-inline',
|
||||
[
|
||||
'@babel/plugin-proposal-decorators',
|
||||
{
|
||||
|
@ -115,6 +116,7 @@ module.exports = api => {
|
|||
// isCDNBundle ? 'inline-webgl-constants' : {},
|
||||
],
|
||||
ignore: [
|
||||
// /node_modules\/(?![kdbush|supercluster|async])/,
|
||||
'node_modules',
|
||||
...!isTest ? [
|
||||
'**/*.test.tsx',
|
||||
|
|
|
@ -9,7 +9,14 @@ import babel from 'rollup-plugin-babel';
|
|||
import glsl from './rollup-plugin-glsl';
|
||||
import postcss from 'rollup-plugin-postcss';
|
||||
import url from 'postcss-url';
|
||||
|
||||
const { BUILD, MINIFY } = process.env;
|
||||
const minified = MINIFY === 'true';
|
||||
const production = BUILD === 'production';
|
||||
const outputFile = !production
|
||||
? 'packages/l7/dist/l7-dev.js'
|
||||
: minified
|
||||
? 'packages/l7/dist/l7.js'
|
||||
: 'packages/l7/dist/l7-dev.js';
|
||||
function resolveFile(filePath) {
|
||||
return path.join(__dirname, '..', filePath);
|
||||
}
|
||||
|
@ -18,7 +25,7 @@ module.exports = [
|
|||
{
|
||||
input: resolveFile('build/bundle.ts'),
|
||||
output: {
|
||||
file: resolveFile('packages/l7/dist/l7.js'),
|
||||
file: resolveFile(outputFile),
|
||||
format: 'umd',
|
||||
name: 'L7',
|
||||
globals: {
|
||||
|
@ -28,7 +35,7 @@ module.exports = [
|
|||
external: [
|
||||
'mapbox-gl'
|
||||
],
|
||||
treeshake: true,
|
||||
treeshake: minified,
|
||||
plugins: [
|
||||
alias(
|
||||
{
|
||||
|
@ -81,7 +88,8 @@ module.exports = [
|
|||
babel({
|
||||
extensions: [ '.js', '.ts' ]
|
||||
}),
|
||||
terser(),
|
||||
// terser(),
|
||||
minified ? terser() : false,
|
||||
analyze({
|
||||
summaryOnly: true,
|
||||
limit: 20
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: Marker 图层
|
||||
title: Marker Layer
|
||||
order: 3
|
||||
---
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ popup.setLnglat([112, 32]);
|
|||
popup.addTo(scene);
|
||||
```
|
||||
|
||||
#### setHtml
|
||||
#### setHTML
|
||||
|
||||
**参数**:html 字符串
|
||||
|
||||
|
@ -70,7 +70,7 @@ var html = `<p>省份
|
|||
${feature.s} </p><p>地区
|
||||
${feature.m}</p><p>数值
|
||||
${feature.t}</p>`;
|
||||
popup.setHtml(html);
|
||||
popup.setHTML(html);
|
||||
```
|
||||
|
||||
#### setDOMContent
|
||||
|
@ -150,7 +150,8 @@ popup.on('close', () => {});
|
|||
|
||||
```
|
||||
var html = '<p>'+feature.m+'</p>';
|
||||
const new L7.Popup().setLnglat([112, 32]).setHTML(html).addTo(scene);
|
||||
const popup= new L7.Popup().setLnglat([112, 32]).setHTML(html);
|
||||
scene.addPopup(popup);
|
||||
```
|
||||
|
||||
## demo 地址
|
||||
|
|
|
@ -59,7 +59,7 @@ popup.setLnglat([112, 32]);
|
|||
popup.addTo(scene);
|
||||
```
|
||||
|
||||
#### setHtml
|
||||
#### setHTML
|
||||
|
||||
**参数**:html 字符串
|
||||
|
||||
|
@ -70,7 +70,7 @@ var html = `<p>省份
|
|||
${feature.s} </p><p>地区
|
||||
${feature.m}</p><p>数值
|
||||
${feature.t}</p>`;
|
||||
popup.setHtml(html);
|
||||
popup.setHTML(html);
|
||||
```
|
||||
|
||||
#### setDOMContent
|
||||
|
@ -150,7 +150,8 @@ popup.on('close', () => {});
|
|||
|
||||
```
|
||||
var html = '<p>'+feature.m+'</p>';
|
||||
const new L7.Popup().setLnglat([112, 32]).setHTML(html).addTo(scene);
|
||||
const popup= new L7.Popup().setLnglat([112, 32]).setHTML(html);
|
||||
scene.addPopup(popup);
|
||||
```
|
||||
|
||||
## demo 地址
|
||||
|
|
|
@ -1,4 +1,73 @@
|
|||
---
|
||||
title: CityBuilding
|
||||
title: CityBuild
|
||||
order: 6
|
||||
---
|
||||
|
||||
## 使用
|
||||
|
||||
```javascript
|
||||
import { CityBuildingLayer } from '@antv/l7';
|
||||
```
|
||||
|
||||
### source
|
||||
|
||||
同 [PolygonLayer](./polygon_layer/extrude)
|
||||
|
||||
### size
|
||||
|
||||
同 [PolygonLayer](./polygon_layer/extrude)
|
||||
|
||||
### color
|
||||
|
||||
[PolygonLayer](./polygon_layer/extrude)
|
||||
|
||||
### animate
|
||||
|
||||
开启动画效果
|
||||
|
||||
```javascript
|
||||
layer.animate(true);
|
||||
```
|
||||
|
||||
### style
|
||||
|
||||
- baseColor 楼房颜色,
|
||||
- windowColor: 窗户颜色,
|
||||
- brightColor: 点亮窗户颜色
|
||||
|
||||
其他 style 配置项同
|
||||
|
||||
[layer#style](./layer#style)
|
||||
|
||||
## 自定义动画频率
|
||||
|
||||
自定义动画频率需要 关闭默认动画,通过 setLight 方法不断更新时间
|
||||
|
||||
```javascript
|
||||
layer.animate(false);
|
||||
```
|
||||
|
||||
### setLight(time)
|
||||
|
||||
参数
|
||||
time : 时间 毫秒
|
||||
|
||||
#### 完整代码
|
||||
|
||||
```javascript
|
||||
const pointLayer = new CityBuildingLayer();
|
||||
pointLayer
|
||||
.source(await response.json())
|
||||
.size('floor', [0, 500])
|
||||
.color('rgba(242,246,250,1.0)')
|
||||
.animate({
|
||||
enable: true,
|
||||
})
|
||||
.style({
|
||||
opacity: 1.0,
|
||||
baseColor: 'rgb(16,16,16)',
|
||||
windowColor: 'rgb(30,60,89)',
|
||||
brightColor: 'rgb(255,176,38)',
|
||||
});
|
||||
scene.addLayer(pointLayer);
|
||||
```
|
||||
|
|
|
@ -39,6 +39,19 @@ layer.animate(true);
|
|||
|
||||
[layer#style](./layer#style)
|
||||
|
||||
## 自定义动画频率
|
||||
|
||||
自定义动画频率需要 关闭默认动画,通过 setLight 方法不断更新时间
|
||||
|
||||
```javascript
|
||||
layer.animate(false);
|
||||
```
|
||||
|
||||
### setLight(time)
|
||||
|
||||
参数
|
||||
time : 时间 毫秒
|
||||
|
||||
#### 完整代码
|
||||
|
||||
```javascript
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Get Started
|
||||
order: 0
|
||||
---
|
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
title: 快速开始
|
||||
order: 0
|
||||
---
|
||||
|
||||
### 安装
|
||||
|
||||
```bash
|
||||
npm i @antv/l7-react
|
||||
```
|
||||
|
||||
### 示例
|
||||
|
||||
```javascript
|
||||
import { LineLayer, AMapScene } from '@antv/l7-react';
|
||||
export default React.memo(function Map() {
|
||||
const [data, setData] = React.useState();
|
||||
React.useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const response = await fetch(
|
||||
'https://gw.alipayobjects.com/os/basement_prod/32e1f3ab-8588-46cb-8a47-75afb692117d.json',
|
||||
);
|
||||
const raw = await response.json();
|
||||
setData(raw);
|
||||
};
|
||||
fetchData();
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<AMapScene
|
||||
map={{
|
||||
center: [110.19382669582967, 50.258134],
|
||||
pitch: 0,
|
||||
style: 'dark',
|
||||
zoom: 1,
|
||||
}}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
>
|
||||
{data && (
|
||||
<LineLayer
|
||||
key={'2'}
|
||||
source={{
|
||||
data,
|
||||
}}
|
||||
size={{
|
||||
values: 1,
|
||||
}}
|
||||
color={{
|
||||
values: '#fff',
|
||||
}}
|
||||
shape={{
|
||||
values: 'line',
|
||||
}}
|
||||
style={{
|
||||
opacity: 1,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</AMapScene>
|
||||
</>
|
||||
);
|
||||
});
|
||||
```
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: 场景 Scene
|
||||
title: Scene
|
||||
order: 2
|
||||
---
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ fetch(
|
|||
.size(1.5)
|
||||
.shape('line')
|
||||
.color('color', v => {
|
||||
return `rgb(${v[0]})`;
|
||||
return `rgb(${v})`;
|
||||
})
|
||||
.animate({
|
||||
interval: 0.6,
|
||||
|
|
|
@ -27,8 +27,7 @@ fetch('https://gw.alipayobjects.com/os/rmsportal/UEXQMifxtkQlYfChpPwT.txt')
|
|||
.shape('greatcircle')
|
||||
.color('#8C1EB2')
|
||||
.style({
|
||||
opacity: 0.8,
|
||||
blur: 0.99
|
||||
opacity: 0.8
|
||||
});
|
||||
scene.addLayer(layer);
|
||||
});
|
||||
|
|
|
@ -19,5 +19,6 @@ exports.onCreateWebpackConfig = ({ getConfig }) => {
|
|||
'@antv/l7-scene': path.resolve(__dirname, 'packages/scene/src'),
|
||||
'@antv/l7-source': path.resolve(__dirname, 'packages/source/src'),
|
||||
'@antv/l7-utils': path.resolve(__dirname, 'packages/utils/src'),
|
||||
'@antv/l7-react': path.resolve(__dirname, 'packages/react/src')
|
||||
};
|
||||
};
|
||||
|
|
|
@ -28,7 +28,7 @@ module.exports = {
|
|||
moduleFileExtensions: [ 'ts', 'tsx', 'js' ],
|
||||
modulePathIgnorePatterns: [ 'dist' ],
|
||||
moduleNameMapper: {
|
||||
'@antv/l7-(.+)$': '<rootDir>packages/$1/src'
|
||||
'@antv/l7-(.+)$': '<rootDir>packages/$1/src',
|
||||
},
|
||||
notify: true,
|
||||
notifyMode: 'always',
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"message": "chore: publish"
|
||||
}
|
||||
},
|
||||
"version": "2.0.17",
|
||||
"version": "2.0.34",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"publishConfig": {
|
||||
|
|
18
package.json
18
package.json
|
@ -7,7 +7,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@antv/g2": "^3.5.9",
|
||||
"@antv/gatsby-theme-antv": "^0.10.40",
|
||||
"@antv/gatsby-theme-antv": "^0.10.43",
|
||||
"@babel/cli": "^7.6.4",
|
||||
"@babel/core": "^7.6.4",
|
||||
"@babel/plugin-proposal-decorators": "^7.6.0",
|
||||
|
@ -15,6 +15,7 @@
|
|||
"@babel/plugin-proposal-object-rest-spread": "^7.7.4",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.6.0",
|
||||
"@babel/plugin-syntax-async-generators": "^7.7.4",
|
||||
"@babel/plugin-transform-parameters": "^7.8.4",
|
||||
"@babel/plugin-transform-runtime": "^7.7.6",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
|
@ -44,6 +45,7 @@
|
|||
"babel-plugin-lodash": "^3.3.4",
|
||||
"babel-plugin-transform-import-styles": "^0.0.11",
|
||||
"babel-plugin-transform-inline-environment-variables": "^0.4.3",
|
||||
"babel-plugin-transform-node-env-inline": "^0.4.3",
|
||||
"babel-plugin-transform-postcss": "^0.3.0",
|
||||
"babel-preset-gatsby": "^0.2.22",
|
||||
"babel-template": "^6.26.0",
|
||||
|
@ -62,7 +64,7 @@
|
|||
"eslint": "^6.6.0",
|
||||
"eslint-config-egg": "^7.5.1",
|
||||
"eslint-plugin-html": "^6.0.0",
|
||||
"gatsby": "2.19.5",
|
||||
"gatsby": "^2.19.15",
|
||||
"gatsby-plugin-google-analytics": "^2.1.27",
|
||||
"gatsby-remark-prettier": "^1.0.0",
|
||||
"geotiff": "^1.0.0-beta.6",
|
||||
|
@ -119,7 +121,7 @@
|
|||
"scripts": {
|
||||
"start": "yarn run site:clean && yarn run site:develop",
|
||||
"site:develop": "cross-env BABEL_ENV=site gatsby develop --open -H 0.0.0.0",
|
||||
"site:build": "yarn run site:clean && cross-env BABEL_ENV=site gatsby build --prefix-paths --no-uglify",
|
||||
"site:build": "yarn run site:clean && cross-env BABEL_ENV=site gatsby build --prefix-paths",
|
||||
"site:clean": "gatsby clean",
|
||||
"site:deploy": "yarn run site:build && gh-pages -d public",
|
||||
"site:publish": "gh-pages -d public",
|
||||
|
@ -143,11 +145,12 @@
|
|||
"release-cdn": "antv-bin upload -n @antv/l7",
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"test": "cross-env BABEL_ENV=test jest",
|
||||
"test-live": "cross-env BABEL_ENV=test DEBUG_MODE=1 jest --watch packages/scene/__tests__/index.spec.ts ",
|
||||
"test-live": "cross-env BABEL_ENV=test DEBUG_MODE=1 jest --watch",
|
||||
"coveralls": "jest --coverage && cat ./tests/coverage/lcov.info | coveralls",
|
||||
"tsc": "tsc",
|
||||
"watch": "yarn clean && lerna exec --parallel -- cross-env BABEL_ENV=cjs babel --watch src --root-mode upward --out-dir lib --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments",
|
||||
"bundle": "cross-env BABEL_ENV=bundle node_modules/.bin/rollup -c ./build/rollup.config.js",
|
||||
"watch": "yarn clean && lerna exec --parallel -- cross-env BABEL_ENV=cjs NODE_ENV=production babel --watch src --root-mode upward --out-dir lib --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments",
|
||||
"bundle": "cross-env BABEL_ENV=bundle node_modules/.bin/rollup -c ./build/rollup.config.js --environment BUILD:production,MINIFY:true",
|
||||
"bundle-dev": "cross-env BABEL_ENV=bundle node_modules/.bin/rollup -c ./build/rollup.config.js --environment 'BUILD:production,MINIFY:false'",
|
||||
"bundle:watch": "cross-env BABEL_ENV=bundle node_modules/.bin/rollup -c ./build/rollup.config.js --watch",
|
||||
"glsl-minify": "node_modules/.bin/glsl-minifier -i ./build/example.frag -o ./build/example.min.frag",
|
||||
"clean": "lerna run clean"
|
||||
|
@ -172,7 +175,8 @@
|
|||
}
|
||||
},
|
||||
"resolutions": {
|
||||
"../core-js": "3"
|
||||
"../core-js": "3",
|
||||
"d3-array": "1"
|
||||
},
|
||||
"tnpm": {
|
||||
"mode": "yarn"
|
||||
|
|
|
@ -3,6 +3,14 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.0.34](https://github.com/antvis/L7/compare/v2.0.32...v2.0.34) (2020-03-02)
|
||||
|
||||
**Note:** Version bump only for package @antv/l7-component
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.28](https://github.com/antvis/L7/compare/v2.0.0-beta.16...v2.0.0-beta.28) (2020-01-02)
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7-component",
|
||||
"version": "2.0.17",
|
||||
"version": "2.0.34",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -24,14 +24,14 @@
|
|||
"author": "lzxue",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@antv/l7-core": "^2.0.17",
|
||||
"@antv/l7-utils": "^2.0.17",
|
||||
"@antv/l7-core": "^2.0.34",
|
||||
"@antv/l7-utils": "^2.0.34",
|
||||
"@babel/runtime": "^7.7.7",
|
||||
"eventemitter3": "^4.0.0",
|
||||
"inversify": "^5.0.1",
|
||||
"load-styles": "^2.0.0"
|
||||
},
|
||||
"gitHead": "f2bd3c6473df79d815467b1677c6f985cf68800e",
|
||||
"gitHead": "a5d354b66873f700730248d015c5e539c54b34b7",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,18 +1,22 @@
|
|||
import { ILngLat, IMapService, IPoint, IPopup, TYPES } from '@antv/l7-core';
|
||||
import { bindAll, DOM } from '@antv/l7-utils';
|
||||
import {
|
||||
ILngLat,
|
||||
IMapService,
|
||||
IMarkerOption,
|
||||
IPoint,
|
||||
IPopup,
|
||||
TYPES,
|
||||
} from '@antv/l7-core';
|
||||
import {
|
||||
anchorTranslate,
|
||||
anchorType,
|
||||
applyAnchorClass,
|
||||
bindAll,
|
||||
DOM,
|
||||
} from '@antv/l7-utils';
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import { Container } from 'inversify';
|
||||
import { anchorTranslate, anchorType, applyAnchorClass } from './utils/anchor';
|
||||
// marker 支持 dragger 未完成
|
||||
|
||||
export interface IMarkerOption {
|
||||
element: HTMLElement | undefined;
|
||||
anchor: anchorType;
|
||||
color: string;
|
||||
offsets: number[];
|
||||
draggable: boolean;
|
||||
extData?: any;
|
||||
}
|
||||
// marker 支持 dragger 未完成
|
||||
export default class Marker extends EventEmitter {
|
||||
private markerOption: IMarkerOption;
|
||||
private defaultMarker: boolean;
|
||||
|
@ -252,32 +256,32 @@ export default class Marker extends EventEmitter {
|
|||
element.addEventListener('click', (e: MouseEvent) => {
|
||||
this.onMapClick(e);
|
||||
});
|
||||
element.addEventListener('click', this.eventHander);
|
||||
element.addEventListener('click', this.eventHandle);
|
||||
applyAnchorClass(element, anchor, 'marker');
|
||||
}
|
||||
private registerMarkerEvent(element: HTMLElement) {
|
||||
element.addEventListener('mousemove', this.eventHander);
|
||||
element.addEventListener('click', this.eventHander);
|
||||
element.addEventListener('mousedown', this.eventHander);
|
||||
element.addEventListener('mouseup', this.eventHander);
|
||||
element.addEventListener('dblclick', this.eventHander);
|
||||
element.addEventListener('contextmenu', this.eventHander);
|
||||
element.addEventListener('mouseover', this.eventHander);
|
||||
element.addEventListener('mouseout', this.eventHander);
|
||||
element.addEventListener('mousemove', this.eventHandle);
|
||||
element.addEventListener('click', this.eventHandle);
|
||||
element.addEventListener('mousedown', this.eventHandle);
|
||||
element.addEventListener('mouseup', this.eventHandle);
|
||||
element.addEventListener('dblclick', this.eventHandle);
|
||||
element.addEventListener('contextmenu', this.eventHandle);
|
||||
element.addEventListener('mouseover', this.eventHandle);
|
||||
element.addEventListener('mouseout', this.eventHandle);
|
||||
}
|
||||
private unRegisterMarkerEvent() {
|
||||
const element = this.getElement();
|
||||
element.removeEventListener('mousemove', this.eventHander);
|
||||
element.removeEventListener('click', this.eventHander);
|
||||
element.removeEventListener('mousedown', this.eventHander);
|
||||
element.removeEventListener('mouseup', this.eventHander);
|
||||
element.removeEventListener('dblclick', this.eventHander);
|
||||
element.removeEventListener('contextmenu', this.eventHander);
|
||||
element.removeEventListener('mouseover', this.eventHander);
|
||||
element.removeEventListener('mouseout', this.eventHander);
|
||||
element.removeEventListener('mousemove', this.eventHandle);
|
||||
element.removeEventListener('click', this.eventHandle);
|
||||
element.removeEventListener('mousedown', this.eventHandle);
|
||||
element.removeEventListener('mouseup', this.eventHandle);
|
||||
element.removeEventListener('dblclick', this.eventHandle);
|
||||
element.removeEventListener('contextmenu', this.eventHandle);
|
||||
element.removeEventListener('mouseover', this.eventHandle);
|
||||
element.removeEventListener('mouseout', this.eventHandle);
|
||||
}
|
||||
|
||||
private eventHander = (e: MouseEvent) => {
|
||||
private eventHandle = (e: MouseEvent) => {
|
||||
this.emit(e.type, {
|
||||
target: e,
|
||||
data: this.markerOption.extData,
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
import { IMapService, IMarker, TYPES } from '@antv/l7-core';
|
||||
import { bindAll, DOM, Satistics } from '@antv/l7-utils';
|
||||
import {
|
||||
bindAll,
|
||||
boundsContains,
|
||||
DOM,
|
||||
IBounds,
|
||||
padBounds,
|
||||
Satistics,
|
||||
} from '@antv/l7-utils';
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import { Container } from 'inversify';
|
||||
import { merge } from 'lodash';
|
||||
import Supercluster from 'supercluster';
|
||||
// @ts-ignore
|
||||
// tslint:disable-next-line:no-submodule-imports
|
||||
import Supercluster from 'supercluster/dist/supercluster';
|
||||
import Marker from './marker';
|
||||
type CallBack = (...args: any[]) => any;
|
||||
interface IMarkerStyleOption {
|
||||
|
@ -39,6 +48,7 @@ export default class MarkerLayer extends EventEmitter {
|
|||
private mapsService: IMapService<unknown>;
|
||||
private scene: Container;
|
||||
private zoom: number;
|
||||
private bbox: IBounds;
|
||||
|
||||
constructor(option?: Partial<IMarkerLayerOption>) {
|
||||
super();
|
||||
|
@ -66,8 +76,8 @@ export default class MarkerLayer extends EventEmitter {
|
|||
if (this.markerLayerOption.cluster) {
|
||||
this.initCluster();
|
||||
this.update();
|
||||
this.mapsService.on('zoom', this.update);
|
||||
this.mapsService.on('zoomchange', this.update);
|
||||
// 地图视野变化时,重新计算视野内的聚合点。
|
||||
this.mapsService.on('camerachange', this.update);
|
||||
}
|
||||
this.addMarkers();
|
||||
return this;
|
||||
|
@ -102,8 +112,7 @@ export default class MarkerLayer extends EventEmitter {
|
|||
this.markers.forEach((marker: IMarker) => {
|
||||
marker.remove();
|
||||
});
|
||||
this.mapsService.off('zoom', this.update);
|
||||
this.mapsService.off('zoomchange', this.update);
|
||||
this.mapsService.off('camerachange', this.update);
|
||||
this.markers = [];
|
||||
}
|
||||
|
||||
|
@ -142,23 +151,21 @@ export default class MarkerLayer extends EventEmitter {
|
|||
this.clusterIndex.load(this.points);
|
||||
}
|
||||
|
||||
private getClusterMarker(zoom: number) {
|
||||
const clusterPoint = this.clusterIndex.getClusters(
|
||||
[-180, -85, 180, 85],
|
||||
zoom,
|
||||
);
|
||||
private getClusterMarker(viewBounds: IBounds, zoom: number) {
|
||||
const viewBBox = viewBounds[0].concat(viewBounds[1]);
|
||||
const clusterPoint = this.clusterIndex.getClusters(viewBBox, zoom);
|
||||
this.clusterMarkers.forEach((marker: IMarker) => {
|
||||
marker.remove();
|
||||
});
|
||||
this.clusterMarkers = [];
|
||||
clusterPoint.forEach((feature) => {
|
||||
clusterPoint.forEach((feature: any) => {
|
||||
const { field, method } = this.markerLayerOption.clusterOption;
|
||||
// 处理聚合数据
|
||||
if (feature.properties && feature.properties?.cluster_id) {
|
||||
const clusterData = this.getLeaves(feature.properties?.cluster_id);
|
||||
feature.properties.clusterData = clusterData;
|
||||
if (field && method) {
|
||||
const columnData = clusterData?.map((item) => {
|
||||
const columnData = clusterData?.map((item: any) => {
|
||||
const data = {
|
||||
[field]: item.properties[field],
|
||||
};
|
||||
|
@ -167,14 +174,10 @@ export default class MarkerLayer extends EventEmitter {
|
|||
const column = Satistics.getColumn(columnData as any, field);
|
||||
const stat = Satistics.getSatByColumn(method, column);
|
||||
const fieldName = 'point_' + method;
|
||||
feature.properties[fieldName] = stat;
|
||||
feature.properties[fieldName] = stat.toFixed(2);
|
||||
}
|
||||
}
|
||||
const marker = this.clusterMarker(feature);
|
||||
// feature.properties && feature.properties.hasOwnProperty('point_count')
|
||||
// ? this.clusterMarker(feature)
|
||||
// : this.normalMarker(feature);
|
||||
|
||||
this.clusterMarkers.push(marker);
|
||||
marker.addTo(this.scene);
|
||||
});
|
||||
|
@ -207,13 +210,21 @@ export default class MarkerLayer extends EventEmitter {
|
|||
const marker_id = feature.properties.marker_id;
|
||||
return this.markers[marker_id];
|
||||
}
|
||||
|
||||
private update() {
|
||||
const zoom = this.mapsService.getZoom();
|
||||
if (Math.abs(zoom - this.zoom) > 1) {
|
||||
this.getClusterMarker(Math.floor(zoom));
|
||||
const bbox = this.mapsService.getBounds();
|
||||
if (
|
||||
!this.bbox ||
|
||||
Math.abs(zoom - this.zoom) >= 1 ||
|
||||
!boundsContains(this.bbox, bbox)
|
||||
) {
|
||||
this.bbox = padBounds(bbox, 0.5);
|
||||
this.zoom = Math.floor(zoom);
|
||||
this.getClusterMarker(this.bbox, this.zoom);
|
||||
}
|
||||
}
|
||||
|
||||
private generateElement(feature: any) {
|
||||
const el = DOM.create('div', 'l7-marker-cluster');
|
||||
const label = DOM.create('div', '', el);
|
||||
|
@ -226,14 +237,6 @@ export default class MarkerLayer extends EventEmitter {
|
|||
? feature.properties['point_' + method] || feature.properties[field]
|
||||
: feature.properties.point_count;
|
||||
span.textContent = text;
|
||||
// const elStyle = isFunction(style)
|
||||
// ? style(feature.properties.point_count)
|
||||
// : style;
|
||||
|
||||
// Object.keys(elStyle).forEach((key: string) => {
|
||||
// // @ts-ignore
|
||||
// el.style[key] = elStyle[key];
|
||||
// });
|
||||
return el;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
import { ILngLat, IMapService, IPoint, IPopup, TYPES } from '@antv/l7-core';
|
||||
import { bindAll, DOM } from '@antv/l7-utils';
|
||||
import {
|
||||
ILngLat,
|
||||
IMapService,
|
||||
IPoint,
|
||||
IPopup,
|
||||
IPopupOption,
|
||||
TYPES,
|
||||
} from '@antv/l7-core';
|
||||
import {
|
||||
anchorTranslate,
|
||||
anchorType,
|
||||
applyAnchorClass,
|
||||
bindAll,
|
||||
DOM,
|
||||
} from '@antv/l7-utils';
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import { Container } from 'inversify';
|
||||
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 mapsService: IMapService<unknown>;
|
||||
|
@ -72,7 +76,7 @@ export default class Popup extends EventEmitter implements IPopup {
|
|||
return this.setDOMContent(frag);
|
||||
}
|
||||
|
||||
public setLnglat(lngLat: ILngLat): this {
|
||||
public setLnglat(lngLat: ILngLat | number[]): this {
|
||||
this.lngLat = lngLat as ILngLat;
|
||||
if (Array.isArray(lngLat)) {
|
||||
this.lngLat = {
|
||||
|
|
|
@ -3,6 +3,14 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.0.34](https://github.com/antvis/L7/compare/v2.0.32...v2.0.34) (2020-03-02)
|
||||
|
||||
**Note:** Version bump only for package @antv/l7-core
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.28](https://github.com/antvis/L7/compare/v2.0.0-beta.16...v2.0.0-beta.28) (2020-01-02)
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7-core",
|
||||
"version": "2.0.17",
|
||||
"version": "2.0.34",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -15,14 +15,15 @@
|
|||
"tsc": "tsc --project tsconfig.build.json",
|
||||
"clean": "rimraf dist; rimraf es; rimraf lib;",
|
||||
"build": "run-p build:*",
|
||||
"build:cjs": "BABEL_ENV=cjs babel src --root-mode upward --out-dir lib --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments",
|
||||
"build:esm": "BABEL_ENV=esm babel src --root-mode upward --out-dir es --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments",
|
||||
"watch": "BABEL_ENV=cjs babel src --watch --root-mode upward --out-dir lib --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments"
|
||||
"build:cjs": "cross-env BABEL_ENV=cjs NODE_ENV=production babel src --root-mode upward --out-dir lib --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments",
|
||||
"build:esm": "cross-env BABEL_ENV=esm NODE_ENV=production babel src --root-mode upward --out-dir es --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments",
|
||||
"watch": "cross-env BABEL_ENV=cjs NODE_ENV=production babel src --watch --root-mode upward --out-dir lib --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments"
|
||||
},
|
||||
"author": "xiaoiver",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@antv/l7-utils": "^2.0.17",
|
||||
"@antv/async-hook": "^2.1.0",
|
||||
"@antv/l7-utils": "^2.0.34",
|
||||
"@babel/runtime": "^7.7.7",
|
||||
"@mapbox/tiny-sdf": "^1.1.1",
|
||||
"ajv": "^6.10.2",
|
||||
|
@ -36,7 +37,6 @@
|
|||
"merge-json-schemas": "^1.0.0",
|
||||
"probe.gl": "^3.1.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"tapable": "^2.0.0-beta.8",
|
||||
"viewport-mercator-project": "^6.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -46,7 +46,7 @@
|
|||
"@types/lodash": "^4.14.138",
|
||||
"@types/viewport-mercator-project": "^6.1.0"
|
||||
},
|
||||
"gitHead": "f2bd3c6473df79d815467b1677c6f985cf68800e",
|
||||
"gitHead": "a5d354b66873f700730248d015c5e539c54b34b7",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import { IControlService } from './services/component/IControlService';
|
|||
import { IGlobalConfigService } from './services/config/IConfigService';
|
||||
import { ICoordinateSystemService } from './services/coordinate/ICoordinateSystemService';
|
||||
import { IInteractionService } from './services/interaction/IInteractionService';
|
||||
import { IPickingService } from './services/interaction/IPickingService';
|
||||
import { ILayerService } from './services/layer/ILayerService';
|
||||
import { IStyleAttributeService } from './services/layer/IStyleAttributeService';
|
||||
import { ILogService } from './services/log/ILogService';
|
||||
|
@ -33,6 +34,7 @@ import PopupService from './services/component/PopupService';
|
|||
import GlobalConfigService from './services/config/ConfigService';
|
||||
import CoordinateSystemService from './services/coordinate/CoordinateSystemService';
|
||||
import InteractionService from './services/interaction/InteractionService';
|
||||
import PickingService from './services/interaction/PickingService';
|
||||
import LayerService from './services/layer/LayerService';
|
||||
import StyleAttributeService from './services/layer/StyleAttributeService';
|
||||
import LogService from './services/log/LogService';
|
||||
|
@ -180,6 +182,10 @@ export function createSceneContainer() {
|
|||
.bind<IInteractionService>(TYPES.IInteractionService)
|
||||
.to(InteractionService)
|
||||
.inSingletonScope();
|
||||
sceneContainer
|
||||
.bind<IPickingService>(TYPES.IPickingService)
|
||||
.to(PickingService)
|
||||
.inSingletonScope();
|
||||
sceneContainer
|
||||
.bind<IControlService>(TYPES.IControlService)
|
||||
.to(ControlService)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { anchorType } from '@antv/l7-utils';
|
||||
import { Container, injectable } from 'inversify';
|
||||
import { ILngLat, IMapService, IPoint } from '../map/IMapService';
|
||||
import { IPopup } from './IPopupService';
|
||||
|
@ -9,6 +10,14 @@ export interface IMarkerScene {
|
|||
export interface IMarkerServiceCfg {
|
||||
container: HTMLElement;
|
||||
}
|
||||
export interface IMarkerOption {
|
||||
element: HTMLElement | undefined;
|
||||
anchor: anchorType;
|
||||
color: string;
|
||||
offsets: number[];
|
||||
draggable: boolean;
|
||||
extData?: any;
|
||||
}
|
||||
export interface IMarker {
|
||||
addTo(scene: Container): void;
|
||||
remove(): void;
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
import { anchorType } from '@antv/l7-utils';
|
||||
import { Container } from 'inversify';
|
||||
import { ILngLat, IMapService } from '../map/IMapService';
|
||||
|
||||
export interface IPopupOption {
|
||||
closeButton: boolean;
|
||||
closeOnClick: boolean;
|
||||
maxWidth: string;
|
||||
anchor: anchorType;
|
||||
className: string;
|
||||
offsets: number[];
|
||||
}
|
||||
export interface IPopup {
|
||||
addTo(scene: Container): this;
|
||||
remove(): void;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import Ajv from 'ajv';
|
||||
// import Ajv from 'ajv';
|
||||
import { injectable, postConstruct } from 'inversify';
|
||||
import { merge } from 'lodash';
|
||||
import { ILayerConfig } from '../layer/ILayerService';
|
||||
import { IRenderConfig } from '../renderer/IRendererService';
|
||||
import { IGlobalConfigService, ISceneConfig } from './IConfigService';
|
||||
import mapConfigSchema from './mapConfigSchema';
|
||||
import sceneConfigSchema from './sceneConfigSchema';
|
||||
|
@ -10,10 +11,12 @@ import WarnInfo, { IWarnInfo } from './warnInfo';
|
|||
/**
|
||||
* 场景默认配置项
|
||||
*/
|
||||
const defaultSceneConfig: Partial<ISceneConfig> = {
|
||||
const defaultSceneConfig: Partial<ISceneConfig & IRenderConfig> = {
|
||||
id: 'map',
|
||||
logoPosition: 'bottomleft',
|
||||
logoVisible: true,
|
||||
antialias: true,
|
||||
preserveDrawingBuffer: false,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -55,7 +58,7 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
|
|||
zIndex: 0,
|
||||
blend: 'normal',
|
||||
pickedFeatureID: -1,
|
||||
enableMultiPassRenderer: true,
|
||||
enableMultiPassRenderer: false,
|
||||
enablePicking: true,
|
||||
active: false,
|
||||
activeColor: '#2f54eb',
|
||||
|
@ -75,10 +78,10 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
|
|||
};
|
||||
|
||||
// @see https://github.com/epoberezkin/ajv#options
|
||||
const ajv = new Ajv({
|
||||
allErrors: true,
|
||||
verbose: true,
|
||||
});
|
||||
// const ajv = new Ajv({
|
||||
// allErrors: true,
|
||||
// verbose: true,
|
||||
// });
|
||||
|
||||
@injectable()
|
||||
export default class GlobalConfigService implements IGlobalConfigService {
|
||||
|
@ -92,12 +95,12 @@ export default class GlobalConfigService implements IGlobalConfigService {
|
|||
/**
|
||||
* 场景配置项校验器
|
||||
*/
|
||||
private sceneConfigValidator: Ajv.ValidateFunction;
|
||||
// private sceneConfigValidator: Ajv.ValidateFunction;
|
||||
|
||||
/**
|
||||
* 地图配置项校验器
|
||||
*/
|
||||
private mapConfigValidator: Ajv.ValidateFunction;
|
||||
// private mapConfigValidator: Ajv.ValidateFunction;
|
||||
|
||||
/**
|
||||
* 全部图层配置项缓存
|
||||
|
@ -109,9 +112,9 @@ export default class GlobalConfigService implements IGlobalConfigService {
|
|||
/**
|
||||
* 保存每一种 Layer 配置项的校验器
|
||||
*/
|
||||
private layerConfigValidatorCache: {
|
||||
[layerName: string]: Ajv.ValidateFunction;
|
||||
} = {};
|
||||
// private layerConfigValidatorCache: {
|
||||
// [layerName: string]: Ajv.ValidateFunction;
|
||||
// } = {};
|
||||
|
||||
public getSceneConfig(sceneId: string) {
|
||||
return this.sceneConfigCache[sceneId];
|
||||
|
@ -128,13 +131,13 @@ export default class GlobalConfigService implements IGlobalConfigService {
|
|||
};
|
||||
}
|
||||
|
||||
public validateSceneConfig(data: object) {
|
||||
return this.validate(this.sceneConfigValidator, data);
|
||||
}
|
||||
// public validateSceneConfig(data: object) {
|
||||
// return this.validate(this.sceneConfigValidator, data);
|
||||
// }
|
||||
|
||||
public validateMapConfig(data: object) {
|
||||
return this.validate(this.mapConfigValidator, data);
|
||||
}
|
||||
// public validateMapConfig(data: object) {
|
||||
// return this.validate(this.mapConfigValidator, data);
|
||||
// }
|
||||
|
||||
public getLayerConfig<IChildLayerConfig>(
|
||||
layerId: string,
|
||||
|
@ -154,45 +157,45 @@ export default class GlobalConfigService implements IGlobalConfigService {
|
|||
};
|
||||
}
|
||||
|
||||
public registerLayerConfigSchemaValidator(layerName: string, schema: object) {
|
||||
if (!this.layerConfigValidatorCache[layerName]) {
|
||||
this.layerConfigValidatorCache[layerName] = ajv.compile(schema);
|
||||
}
|
||||
}
|
||||
// public registerLayerConfigSchemaValidator(layerName: string, schema: object) {
|
||||
// if (!this.layerConfigValidatorCache[layerName]) {
|
||||
// this.layerConfigValidatorCache[layerName] = ajv.compile(schema);
|
||||
// }
|
||||
// }
|
||||
|
||||
public validateLayerConfig(layerName: string, data: object) {
|
||||
return this.validate(this.layerConfigValidatorCache[layerName], data);
|
||||
}
|
||||
// public validateLayerConfig(layerName: string, data: object) {
|
||||
// return this.validate(this.layerConfigValidatorCache[layerName], data);
|
||||
// }
|
||||
|
||||
public clean() {
|
||||
this.sceneConfigCache = {};
|
||||
this.layerConfigCache = {};
|
||||
}
|
||||
|
||||
@postConstruct()
|
||||
private registerSceneConfigSchemaValidator() {
|
||||
this.sceneConfigValidator = ajv.compile(sceneConfigSchema);
|
||||
this.mapConfigValidator = ajv.compile(mapConfigSchema);
|
||||
}
|
||||
// @postConstruct()
|
||||
// private registerSceneConfigSchemaValidator() {
|
||||
// this.sceneConfigValidator = ajv.compile(sceneConfigSchema);
|
||||
// this.mapConfigValidator = ajv.compile(mapConfigSchema);
|
||||
// }
|
||||
|
||||
private validate(
|
||||
validateFunc: Ajv.ValidateFunction | undefined,
|
||||
data: object,
|
||||
) {
|
||||
if (validateFunc) {
|
||||
const valid = validateFunc(data);
|
||||
if (!valid) {
|
||||
return {
|
||||
valid,
|
||||
errors: validateFunc.errors,
|
||||
errorText: ajv.errorsText(validateFunc.errors),
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
valid: true,
|
||||
errors: null,
|
||||
errorText: null,
|
||||
};
|
||||
}
|
||||
// private validate(
|
||||
// validateFunc: Ajv.ValidateFunction | undefined,
|
||||
// data: object,
|
||||
// ) {
|
||||
// if (validateFunc) {
|
||||
// const valid = validateFunc(data);
|
||||
// if (!valid) {
|
||||
// return {
|
||||
// valid,
|
||||
// errors: validateFunc.errors,
|
||||
// errorText: ajv.errorsText(validateFunc.errors),
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// return {
|
||||
// valid: true,
|
||||
// errors: null,
|
||||
// errorText: null,
|
||||
// };
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import Ajv from 'ajv';
|
||||
// import Ajv from 'ajv';
|
||||
import { PositionName } from '../component/IControlService';
|
||||
import { ILayerConfig } from '../layer/ILayerService';
|
||||
import { IMapWrapper } from '../map/IMapService';
|
||||
|
@ -10,11 +10,11 @@ export interface ISceneConfig extends IRenderConfig {
|
|||
logoVisible?: boolean;
|
||||
}
|
||||
|
||||
interface IValidateResult {
|
||||
valid: boolean;
|
||||
errors: Ajv.ErrorObject[] | null | undefined;
|
||||
errorText: string | null;
|
||||
}
|
||||
// interface IValidateResult {
|
||||
// valid: boolean;
|
||||
// errors: Ajv.ErrorObject[] | null | undefined;
|
||||
// errorText: string | null;
|
||||
// }
|
||||
|
||||
export interface IGlobalConfigService {
|
||||
/**
|
||||
|
@ -28,13 +28,13 @@ export interface IGlobalConfigService {
|
|||
* 校验用户传入的场景配置项
|
||||
* @param data 场景配置项
|
||||
*/
|
||||
validateSceneConfig(data: object): IValidateResult;
|
||||
// validateSceneConfig(data: object): IValidateResult;
|
||||
|
||||
/**
|
||||
* 校验用户传入的地图配置项
|
||||
* @param data 地图配置项
|
||||
*/
|
||||
validateMapConfig(data: object): IValidateResult;
|
||||
// validateMapConfig(data: object): IValidateResult;
|
||||
|
||||
/**
|
||||
* 获取图层配置项
|
||||
|
@ -66,13 +66,13 @@ export interface IGlobalConfigService {
|
|||
* @param layerName 图层名
|
||||
* @param schema 校验规则描述
|
||||
*/
|
||||
registerLayerConfigSchemaValidator(layerName: string, schema: object): void;
|
||||
// registerLayerConfigSchemaValidator(layerName: string, schema: object): void;
|
||||
|
||||
/**
|
||||
* 校验用户传入的图层配置项
|
||||
* @param data 图层配置项
|
||||
*/
|
||||
validateLayerConfig(layerName: string, data: object): IValidateResult;
|
||||
// validateLayerConfig(layerName: string, data: object): IValidateResult;
|
||||
|
||||
/**
|
||||
* 清除场景和图层配置项 Cache,但是需要保留校验器
|
||||
|
|
|
@ -4,8 +4,5 @@
|
|||
export default {
|
||||
properties: {
|
||||
// 地图容器 ID
|
||||
id: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export interface IPickingService {
|
||||
init(): void;
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
import { decodePickingColor, encodePickingColor } from '@antv/l7-utils';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import {
|
||||
IMapService,
|
||||
IRendererService,
|
||||
IShaderModuleService,
|
||||
} from '../../index';
|
||||
import { TYPES } from '../../types';
|
||||
import { ICameraService } from '../camera/ICameraService';
|
||||
import {
|
||||
IInteractionService,
|
||||
IInteractionTarget,
|
||||
InteractionEvent,
|
||||
} from '../interaction/IInteractionService';
|
||||
import { ILayer, ILayerService } from '../layer/ILayerService';
|
||||
import { ILngLat } from '../map/IMapService';
|
||||
import { gl } from '../renderer/gl';
|
||||
import { IFramebuffer } from '../renderer/IFramebuffer';
|
||||
import { IPickingService } from './IPickingService';
|
||||
|
||||
const PICKSCALE = 1.0;
|
||||
@injectable()
|
||||
export default class PickingService implements IPickingService {
|
||||
@inject(TYPES.IRendererService)
|
||||
private rendererService: IRendererService;
|
||||
|
||||
@inject(TYPES.IInteractionService)
|
||||
private interactionService: IInteractionService;
|
||||
|
||||
@inject(TYPES.ILayerService)
|
||||
private layerService: ILayerService;
|
||||
private pickingFBO: IFramebuffer;
|
||||
|
||||
private width: number = 0;
|
||||
|
||||
private height: number = 0;
|
||||
|
||||
private alreadyInPicking: boolean = false;
|
||||
|
||||
public init() {
|
||||
const {
|
||||
createTexture2D,
|
||||
createFramebuffer,
|
||||
getViewportSize,
|
||||
} = this.rendererService;
|
||||
const { width, height } = getViewportSize();
|
||||
// 创建 picking framebuffer,后续实时 resize
|
||||
this.pickingFBO = createFramebuffer({
|
||||
color: createTexture2D({
|
||||
width,
|
||||
height,
|
||||
wrapS: gl.CLAMP_TO_EDGE,
|
||||
wrapT: gl.CLAMP_TO_EDGE,
|
||||
}),
|
||||
});
|
||||
|
||||
// 监听 hover 事件
|
||||
this.interactionService.on(
|
||||
InteractionEvent.Hover,
|
||||
this.pickingAllLayer.bind(this),
|
||||
);
|
||||
}
|
||||
private async pickingAllLayer(target: IInteractionTarget) {
|
||||
if (this.alreadyInPicking || this.layerService.alreadyInRendering) {
|
||||
return;
|
||||
}
|
||||
this.alreadyInPicking = true;
|
||||
await this.pickingLayers(target);
|
||||
this.layerService.renderLayers();
|
||||
this.alreadyInPicking = false;
|
||||
}
|
||||
private async pickingLayers(target: IInteractionTarget) {
|
||||
const { getViewportSize, useFramebuffer, clear } = this.rendererService;
|
||||
const { width, height } = getViewportSize();
|
||||
|
||||
if (this.width !== width || this.height !== height) {
|
||||
this.pickingFBO.resize({
|
||||
width: Math.round(width / PICKSCALE),
|
||||
height: Math.round(height / PICKSCALE),
|
||||
});
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
useFramebuffer(this.pickingFBO, () => {
|
||||
const layers = this.layerService.getLayers();
|
||||
layers
|
||||
.filter((layer) => layer.needPick())
|
||||
.reverse()
|
||||
.forEach((layer) => {
|
||||
clear({
|
||||
framebuffer: this.pickingFBO,
|
||||
color: [0, 0, 0, 0],
|
||||
stencil: 0,
|
||||
depth: 1,
|
||||
});
|
||||
|
||||
layer.hooks.beforePickingEncode.call();
|
||||
layer.renderModels();
|
||||
layer.hooks.afterPickingEncode.call();
|
||||
this.pickFromPickingFBO(layer, target);
|
||||
});
|
||||
});
|
||||
}
|
||||
private async pickingLayer(layer: ILayer, target: IInteractionTarget) {
|
||||
const { getViewportSize, useFramebuffer, clear } = this.rendererService;
|
||||
const { width, height } = getViewportSize();
|
||||
|
||||
if (this.width !== width || this.height !== height) {
|
||||
this.pickingFBO.resize({
|
||||
width: Math.round(width / PICKSCALE),
|
||||
height: Math.round(height / PICKSCALE),
|
||||
});
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
useFramebuffer(this.pickingFBO, () => {
|
||||
clear({
|
||||
framebuffer: this.pickingFBO,
|
||||
color: [0, 0, 0, 0],
|
||||
stencil: 0,
|
||||
depth: 1,
|
||||
});
|
||||
|
||||
layer.hooks.beforePickingEncode.call();
|
||||
layer.renderModels();
|
||||
layer.hooks.afterPickingEncode.call();
|
||||
this.pickFromPickingFBO(layer, target);
|
||||
});
|
||||
}
|
||||
|
||||
private pickFromPickingFBO = (
|
||||
layer: ILayer,
|
||||
{ x, y, lngLat, type }: IInteractionTarget,
|
||||
) => {
|
||||
const {
|
||||
getViewportSize,
|
||||
readPixels,
|
||||
useFramebuffer,
|
||||
} = this.rendererService;
|
||||
const { width, height } = getViewportSize();
|
||||
|
||||
const { enableHighlight, enableSelect } = layer.getLayerConfig();
|
||||
|
||||
const xInDevicePixel = x * window.devicePixelRatio;
|
||||
const yInDevicePixel = y * window.devicePixelRatio;
|
||||
if (
|
||||
xInDevicePixel > width ||
|
||||
xInDevicePixel < 0 ||
|
||||
yInDevicePixel > height ||
|
||||
yInDevicePixel < 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let pickedColors: Uint8Array | undefined;
|
||||
pickedColors = readPixels({
|
||||
x: Math.floor(xInDevicePixel / PICKSCALE),
|
||||
// 视口坐标系原点在左上,而 WebGL 在左下,需要翻转 Y 轴
|
||||
y: Math.floor((height - (y + 1) * window.devicePixelRatio) / PICKSCALE),
|
||||
width: 1,
|
||||
height: 1,
|
||||
data: new Uint8Array(1 * 1 * 4),
|
||||
framebuffer: this.pickingFBO,
|
||||
});
|
||||
if (
|
||||
pickedColors[0] !== 0 ||
|
||||
pickedColors[1] !== 0 ||
|
||||
pickedColors[2] !== 0
|
||||
) {
|
||||
const pickedFeatureIdx = decodePickingColor(pickedColors);
|
||||
const rawFeature = layer.getSource().getFeatureById(pickedFeatureIdx);
|
||||
const target = {
|
||||
x,
|
||||
y,
|
||||
type,
|
||||
lngLat,
|
||||
featureId: pickedFeatureIdx,
|
||||
feature: rawFeature,
|
||||
};
|
||||
if (!rawFeature) {
|
||||
// this.logger.error(
|
||||
// '未找到颜色编码解码后的原始 feature,请检查 fragment shader 中末尾是否添加了 `gl_FragColor = filterColor(gl_FragColor);`',
|
||||
// );
|
||||
} else {
|
||||
// trigger onHover/Click callback on layer
|
||||
layer.setCurrentPickId(pickedFeatureIdx);
|
||||
this.triggerHoverOnLayer(layer, target);
|
||||
}
|
||||
} else {
|
||||
const target = {
|
||||
x,
|
||||
y,
|
||||
lngLat,
|
||||
type: layer.getCurrentPickId() === null ? 'un' + type : 'mouseout',
|
||||
featureId: null,
|
||||
feature: null,
|
||||
};
|
||||
this.triggerHoverOnLayer(layer, {
|
||||
...target,
|
||||
type: 'unpick',
|
||||
});
|
||||
this.triggerHoverOnLayer(layer, target);
|
||||
layer.setCurrentPickId(null);
|
||||
}
|
||||
|
||||
if (enableHighlight) {
|
||||
this.highlightPickedFeature(layer, pickedColors);
|
||||
}
|
||||
if (
|
||||
enableSelect &&
|
||||
type === 'click' &&
|
||||
pickedColors?.toString() !== [0, 0, 0, 0].toString()
|
||||
) {
|
||||
this.selectFeature(layer, pickedColors);
|
||||
}
|
||||
};
|
||||
private triggerHoverOnLayer(
|
||||
layer: ILayer,
|
||||
target: {
|
||||
x: number;
|
||||
y: number;
|
||||
type: string;
|
||||
lngLat: ILngLat;
|
||||
feature: unknown;
|
||||
featureId: number | null;
|
||||
},
|
||||
) {
|
||||
layer.emit(target.type, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* highlight 如果直接修改选中 feature 的 buffer,存在两个问题:
|
||||
* 1. 鼠标移走时无法恢复
|
||||
* 2. 无法实现高亮颜色与原始原色的 alpha 混合
|
||||
* 因此高亮还是放在 shader 中做比较好
|
||||
* @example
|
||||
* this.layer.color('name', ['#000000'], {
|
||||
* featureRange: {
|
||||
* startIndex: pickedFeatureIdx,
|
||||
* endIndex: pickedFeatureIdx + 1,
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
private highlightPickedFeature(
|
||||
layer: ILayer,
|
||||
pickedColors: Uint8Array | undefined,
|
||||
) {
|
||||
const [r, g, b] = pickedColors;
|
||||
layer.hooks.beforeHighlight.call([r, g, b]);
|
||||
// this.layerService.renderLayers();
|
||||
}
|
||||
|
||||
private selectFeature(layer: ILayer, pickedColors: Uint8Array | undefined) {
|
||||
const [r, g, b] = pickedColors;
|
||||
layer.hooks.beforeSelect.call([r, g, b]);
|
||||
// this.layerService.renderLayers();
|
||||
}
|
||||
|
||||
private selectFeatureHandle(
|
||||
layer: ILayer,
|
||||
{ featureId }: Partial<IInteractionTarget>,
|
||||
) {
|
||||
const pickedColors = encodePickingColor(featureId as number);
|
||||
this.selectFeature(layer, new Uint8Array(pickedColors));
|
||||
}
|
||||
|
||||
private highlightFeatureHandle(
|
||||
layer: ILayer,
|
||||
{ featureId }: Partial<IInteractionTarget>,
|
||||
) {
|
||||
const pickedColors = encodePickingColor(featureId as number);
|
||||
this.highlightPickedFeature(layer, new Uint8Array(pickedColors));
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
// @ts-ignore
|
||||
import { SyncBailHook, SyncHook, SyncWaterfallHook } from '@antv/async-hook';
|
||||
import { Container } from 'inversify';
|
||||
import { SyncBailHook, SyncHook, SyncWaterfallHook } from 'tapable';
|
||||
import Clock from '../../utils/clock';
|
||||
import { ISceneConfig } from '../config/IConfigService';
|
||||
import { IMapService } from '../map/IMapService';
|
||||
|
@ -22,6 +23,7 @@ import {
|
|||
IScale,
|
||||
IScaleOptions,
|
||||
IStyleAttributeService,
|
||||
ScaleAttributeType,
|
||||
StyleAttrField,
|
||||
StyleAttributeOption,
|
||||
Triangulation,
|
||||
|
@ -84,19 +86,19 @@ export interface ILayer {
|
|||
dataState: IDataState; // 数据流状态
|
||||
pickedFeatureID: number;
|
||||
hooks: {
|
||||
init: SyncBailHook<void, boolean | void>;
|
||||
afterInit: SyncBailHook<void, boolean | void>;
|
||||
beforeRenderData: SyncWaterfallHook<boolean | void>;
|
||||
beforeRender: SyncBailHook<void, boolean | void>;
|
||||
afterRender: SyncHook<void>;
|
||||
beforePickingEncode: SyncHook<void>;
|
||||
afterPickingEncode: SyncHook<void>;
|
||||
beforeHighlight: SyncHook<[number[]]>;
|
||||
beforeSelect: SyncHook<[number[]]>;
|
||||
afterSelect: SyncHook<void>;
|
||||
afterHighlight: SyncHook<void>;
|
||||
beforeDestroy: SyncHook<void>;
|
||||
afterDestroy: SyncHook<void>;
|
||||
init: SyncBailHook;
|
||||
afterInit: SyncBailHook;
|
||||
beforeRenderData: SyncWaterfallHook;
|
||||
beforeRender: SyncBailHook;
|
||||
afterRender: SyncHook;
|
||||
beforePickingEncode: SyncHook;
|
||||
afterPickingEncode: SyncHook;
|
||||
beforeHighlight: SyncHook;
|
||||
beforeSelect: SyncHook;
|
||||
afterSelect: SyncHook;
|
||||
afterHighlight: SyncHook;
|
||||
beforeDestroy: SyncHook;
|
||||
afterDestroy: SyncHook;
|
||||
};
|
||||
models: IModel[];
|
||||
sourceOption: {
|
||||
|
@ -104,19 +106,21 @@ export interface ILayer {
|
|||
options?: ISourceCFG;
|
||||
};
|
||||
multiPassRenderer: IMultiPassRenderer;
|
||||
needPick(): boolean;
|
||||
getLayerConfig(): Partial<ILayerConfig & ISceneConfig>;
|
||||
getContainer(): Container;
|
||||
setContainer(container: Container): void;
|
||||
setCurrentPickId(id: number | null): void;
|
||||
getCurrentPickId(): number | null;
|
||||
prepareBuildModel(): void;
|
||||
renderModels(): void;
|
||||
buildModels(): void;
|
||||
buildLayerModel(
|
||||
options: ILayerModelInitializationOptions &
|
||||
Partial<IModelInitializationOptions>,
|
||||
): IModel;
|
||||
init(): ILayer;
|
||||
scale(field: string | IScaleOptions, cfg: IScale): ILayer;
|
||||
scale(field: string | number | IScaleOptions, cfg?: IScale): ILayer;
|
||||
size(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
color(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
shape(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
|
@ -137,6 +141,7 @@ export interface ILayer {
|
|||
style(options: unknown): ILayer;
|
||||
hide(): ILayer;
|
||||
show(): ILayer;
|
||||
getLegendItems(name: string): any;
|
||||
setIndex(index: number): ILayer;
|
||||
isVisible(): boolean;
|
||||
setMaxZoom(min: number): ILayer;
|
||||
|
@ -165,10 +170,10 @@ export interface ILayer {
|
|||
/**
|
||||
* 事件
|
||||
*/
|
||||
on(type: string, hander: (...args: any[]) => void): void;
|
||||
off(type: string, hander: (...args: any[]) => void): void;
|
||||
emit(type: string, hander: unknown): void;
|
||||
once(type: string, hander: (...args: any[]) => void): void;
|
||||
on(type: string, handler: (...args: any[]) => void): void;
|
||||
off(type: string, handler: (...args: any[]) => void): void;
|
||||
emit(type: string, handler: unknown): void;
|
||||
once(type: string, handler: (...args: any[]) => void): void;
|
||||
/**
|
||||
* JSON Schema 用于校验配置项
|
||||
*/
|
||||
|
@ -262,6 +267,7 @@ export interface ILayerConfig {
|
|||
*/
|
||||
export interface ILayerService {
|
||||
clock: Clock;
|
||||
alreadyInRendering: boolean;
|
||||
add(layer: ILayer): void;
|
||||
initLayers(): void;
|
||||
startAnimate(): void;
|
||||
|
|
|
@ -35,8 +35,11 @@ export type ScaleTypeName =
|
|||
| 'quantize'
|
||||
| 'threshold'
|
||||
| 'cat';
|
||||
|
||||
export type ScaleAttributeType = 'color' | 'size' | 'shape';
|
||||
export interface IScale {
|
||||
type: ScaleTypeName;
|
||||
field?: string;
|
||||
ticks?: any[];
|
||||
nice?: boolean;
|
||||
format?: () => any;
|
||||
|
@ -49,6 +52,7 @@ export enum StyleScaleType {
|
|||
}
|
||||
export interface IScaleOption {
|
||||
field?: string;
|
||||
attr?: ScaleAttributeType;
|
||||
type: ScaleTypeName;
|
||||
ticks?: any[];
|
||||
nice?: boolean;
|
||||
|
@ -115,6 +119,11 @@ type CallBack = (...args: any[]) => any;
|
|||
export type StyleAttributeField = string | string[] | number[];
|
||||
export type StyleAttributeOption = string | number | boolean | any[] | CallBack;
|
||||
export type StyleAttrField = string | string[] | number | number[];
|
||||
export interface IAttributeScale {
|
||||
field: string | number;
|
||||
func: unknown;
|
||||
option: IScaleOption | undefined;
|
||||
}
|
||||
|
||||
export interface IStyleAttributeInitializationOptions {
|
||||
name: string;
|
||||
|
@ -125,10 +134,7 @@ export interface IStyleAttributeInitializationOptions {
|
|||
names: string[] | number[];
|
||||
type: StyleScaleType;
|
||||
callback?: (...args: any[]) => [];
|
||||
scalers?: Array<{
|
||||
field: string | number;
|
||||
func: unknown;
|
||||
}>;
|
||||
scalers?: IAttributeScale[];
|
||||
};
|
||||
descriptor: IVertexAttributeDescriptor;
|
||||
}
|
||||
|
@ -186,6 +192,7 @@ export interface IStyleAttributeService {
|
|||
): void;
|
||||
getLayerStyleAttributes(): IStyleAttribute[] | undefined;
|
||||
getLayerStyleAttribute(attributeName: string): IStyleAttribute | undefined;
|
||||
getLayerAttributeScale(attributeName: string): any;
|
||||
createAttributesAndIndices(
|
||||
encodedFeatures: IEncodeFeature[],
|
||||
triangulation?: Triangulation,
|
||||
|
|
|
@ -10,6 +10,8 @@ import { ILayerModel, ILayerService } from './ILayerService';
|
|||
export default class LayerService implements ILayerService {
|
||||
public clock = new Clock();
|
||||
|
||||
public alreadyInRendering: boolean = false;
|
||||
|
||||
private layers: ILayer[] = [];
|
||||
|
||||
private layerRenderID: number;
|
||||
|
@ -18,8 +20,6 @@ export default class LayerService implements ILayerService {
|
|||
|
||||
private animateInstanceCount: number = 0;
|
||||
|
||||
private alreadyInRendering: boolean = false;
|
||||
|
||||
@inject(TYPES.IRendererService)
|
||||
private readonly renderService: IRendererService;
|
||||
|
||||
|
@ -69,11 +69,9 @@ export default class LayerService implements ILayerService {
|
|||
}
|
||||
|
||||
public renderLayers() {
|
||||
// TODO:脏检查,只渲染发生改变的 Layer
|
||||
if (this.alreadyInRendering) {
|
||||
return;
|
||||
}
|
||||
//
|
||||
this.alreadyInRendering = true;
|
||||
this.clear();
|
||||
this.updateRenderOrder();
|
||||
|
@ -82,7 +80,7 @@ export default class LayerService implements ILayerService {
|
|||
.filter((layer) => layer.isVisible())
|
||||
.forEach((layer) => {
|
||||
// trigger hooks
|
||||
layer.hooks.beforeRenderData.call(true);
|
||||
layer.hooks.beforeRenderData.call();
|
||||
layer.hooks.beforeRender.call();
|
||||
layer.render();
|
||||
layer.hooks.afterRender.call();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { isNil } from 'lodash';
|
||||
import {
|
||||
IAttributeScale,
|
||||
IScaleOption,
|
||||
IStyleAttribute,
|
||||
StyleScaleType,
|
||||
} from '../layer/IStyleAttributeService';
|
||||
|
@ -22,10 +24,7 @@ export default class StyleAttribute implements IStyleAttribute {
|
|||
field: string | string[];
|
||||
values: unknown[];
|
||||
callback?: (...args: any[]) => [];
|
||||
scalers?: Array<{
|
||||
field: string;
|
||||
func: unknown;
|
||||
}>;
|
||||
scalers?: IAttributeScale[];
|
||||
};
|
||||
public descriptor: IVertexAttributeDescriptor;
|
||||
public featureBufferLayout: Array<{
|
||||
|
|
|
@ -7,6 +7,7 @@ import { IRendererService } from '../renderer/IRendererService';
|
|||
import { IParseDataItem } from '../source/ISourceService';
|
||||
import { ILayer } from './ILayerService';
|
||||
import {
|
||||
IAttributeScale,
|
||||
IEncodeFeature,
|
||||
IStyleAttribute,
|
||||
IStyleAttributeInitializationOptions,
|
||||
|
@ -108,6 +109,15 @@ export default class StyleAttributeService implements IStyleAttributeService {
|
|||
);
|
||||
}
|
||||
|
||||
public getLayerAttributeScale(name: string) {
|
||||
const attribute = this.getLayerStyleAttribute(name);
|
||||
const scale = attribute?.scale?.scalers as IAttributeScale[];
|
||||
if (scale && scale[0]) {
|
||||
return scale[0].func;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public updateAttributeByFeatureRange(
|
||||
attributeName: string,
|
||||
features: IEncodeFeature[],
|
||||
|
@ -125,7 +135,6 @@ export default class StyleAttributeService implements IStyleAttributeService {
|
|||
const { elements, sizePerElement } = this.featureLayout;
|
||||
// 截取待更新的 feature 范围
|
||||
const featuresToUpdate = elements.slice(startFeatureIdx, endFeatureIdx);
|
||||
|
||||
// [n, n] 中断更新
|
||||
if (!featuresToUpdate.length) {
|
||||
return;
|
||||
|
@ -184,6 +193,11 @@ export default class StyleAttributeService implements IStyleAttributeService {
|
|||
};
|
||||
elements: IElements;
|
||||
} {
|
||||
// 每次创建的初始化化 LayerOut
|
||||
this.featureLayout = {
|
||||
sizePerElement: 0,
|
||||
elements: [],
|
||||
};
|
||||
if (triangulation) {
|
||||
this.triangulation = triangulation;
|
||||
}
|
||||
|
@ -196,7 +210,6 @@ export default class StyleAttributeService implements IStyleAttributeService {
|
|||
const indices: number[] = [];
|
||||
const normals: number[] = [];
|
||||
let size = 3;
|
||||
|
||||
features.forEach((feature, featureIdx) => {
|
||||
// 逐 feature 进行三角化
|
||||
const {
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import { injectable } from 'inversify';
|
||||
import Probe, { Log } from 'probe.gl';
|
||||
import { ILogService } from './ILogService';
|
||||
const Logger = new Log({ id: 'L7' }).enable(false);
|
||||
// !process.env.NODE_ENV === 'production',
|
||||
const Logger = new Log({ id: 'L7' }).enable(
|
||||
// @ts-ignore
|
||||
process.env.NODE_ENV !== 'production',
|
||||
);
|
||||
// // 只输出 debug 级别以上的日志信息
|
||||
Logger.priority = 5;
|
||||
|
||||
|
@ -12,7 +16,7 @@ export default class LogService implements ILogService {
|
|||
}
|
||||
|
||||
public warn(message: string): void {
|
||||
Logger.warn(message)();
|
||||
Logger.probe(1, message)();
|
||||
}
|
||||
|
||||
public info(message: string): void {
|
||||
|
|
|
@ -50,17 +50,19 @@ export interface IMapService<RawMap = {}> {
|
|||
zoomOut(): void;
|
||||
panTo(p: Point): void;
|
||||
panBy(pixel: Point): void;
|
||||
setPitch(pitch: number): void;
|
||||
fitBounds(bound: Bounds): void;
|
||||
setZoomAndCenter(zoom: number, center: Point): void;
|
||||
setCenter(center: [number, number]): void;
|
||||
setPitch(pitch: number): void;
|
||||
setZoom(zoom: number): void;
|
||||
setMapStyle(style: string): void;
|
||||
setMapStyle(style: any): void;
|
||||
|
||||
// coordinates methods
|
||||
pixelToLngLat(pixel: Point): ILngLat;
|
||||
lngLatToPixel(lnglat: Point): IPoint;
|
||||
containerToLngLat(pixel: Point): ILngLat;
|
||||
lngLatToContainer(lnglat: Point): IPoint;
|
||||
exportMap(type: 'jpg' | 'png'): string;
|
||||
}
|
||||
|
||||
export const MapServiceEvent = ['mapload'];
|
||||
|
@ -122,6 +124,8 @@ export interface IMapConfig<RawMap = {}> {
|
|||
maxZoom?: number;
|
||||
|
||||
attributionControl?: boolean;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,6 +16,8 @@ export interface IRenderConfig {
|
|||
*/
|
||||
enableMultiPassRenderer?: boolean;
|
||||
passes?: Array<IPass<unknown>>;
|
||||
antialias?: boolean;
|
||||
preserveDrawingBuffer?: boolean;
|
||||
}
|
||||
|
||||
export interface IClearOptions {
|
||||
|
@ -40,7 +42,7 @@ export interface IReadPixelsOptions {
|
|||
}
|
||||
|
||||
export interface IRendererService {
|
||||
init($container: HTMLDivElement): Promise<void>;
|
||||
init($container: HTMLDivElement, cfg: IRenderConfig): Promise<void>;
|
||||
clear(options: IClearOptions): void;
|
||||
createModel(options: IModelInitializationOptions): IModel;
|
||||
createAttribute(options: IAttributeInitializationOptions): IAttribute;
|
||||
|
|
|
@ -87,6 +87,7 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
|
|||
},
|
||||
// @ts-ignore
|
||||
uniforms: {
|
||||
// @ts-ignore
|
||||
u_Texture: null,
|
||||
...uniforms,
|
||||
...(this.config && this.convertOptionsToUniforms(this.config)),
|
||||
|
|
|
@ -38,6 +38,10 @@ export default class MultiPassRenderer implements IMultiPassRenderer {
|
|||
private layer: ILayer;
|
||||
private renderFlag: boolean;
|
||||
|
||||
private width: number = 0;
|
||||
|
||||
private height: number = 0;
|
||||
|
||||
public setLayer(layer: ILayer) {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
@ -58,11 +62,16 @@ export default class MultiPassRenderer implements IMultiPassRenderer {
|
|||
for (const pass of this.passes) {
|
||||
await pass.render(this.layer);
|
||||
}
|
||||
await this.postProcessor.render(this.layer);
|
||||
this.layer.renderModels();
|
||||
// await this.postProcessor.render(this.layer);
|
||||
}
|
||||
|
||||
public resize(width: number, height: number) {
|
||||
this.postProcessor.resize(width, height);
|
||||
if (this.width !== width || this.height !== height) {
|
||||
this.postProcessor.resize(width, height);
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
|
||||
public add<T>(pass: IPass<T>, config?: Partial<T>) {
|
||||
|
|
|
@ -60,7 +60,6 @@ export default class PixelPickingPass<
|
|||
getViewportSize,
|
||||
} = this.rendererService;
|
||||
const { width, height } = getViewportSize();
|
||||
|
||||
// 创建 picking framebuffer,后续实时 resize
|
||||
this.pickingFBO = createFramebuffer({
|
||||
color: createTexture2D({
|
||||
|
@ -75,11 +74,11 @@ export default class PixelPickingPass<
|
|||
this.interactionService.on(InteractionEvent.Hover, this.pickFromPickingFBO);
|
||||
this.interactionService.on(
|
||||
InteractionEvent.Select,
|
||||
this.selectFeatureHander.bind(this),
|
||||
this.selectFeatureHandle.bind(this),
|
||||
);
|
||||
this.interactionService.on(
|
||||
InteractionEvent.Active,
|
||||
this.highlightFeatureHander.bind(this),
|
||||
this.highlightFeatureHandle.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -131,7 +130,7 @@ export default class PixelPickingPass<
|
|||
* TODO:支持区域拾取
|
||||
*/
|
||||
private pickFromPickingFBO = ({ x, y, lngLat, type }: IInteractionTarget) => {
|
||||
if (!this.layer.isVisible()) {
|
||||
if (!this.layer.isVisible() || !this.layer.needPick()) {
|
||||
return;
|
||||
}
|
||||
const {
|
||||
|
@ -259,12 +258,12 @@ export default class PixelPickingPass<
|
|||
this.layerService.renderLayers();
|
||||
}
|
||||
|
||||
private selectFeatureHander({ featureId }: Partial<IInteractionTarget>) {
|
||||
private selectFeatureHandle({ featureId }: Partial<IInteractionTarget>) {
|
||||
const pickedColors = encodePickingColor(featureId as number);
|
||||
this.selectFeature(new Uint8Array(pickedColors));
|
||||
}
|
||||
|
||||
private highlightFeatureHander({ featureId }: Partial<IInteractionTarget>) {
|
||||
private highlightFeatureHandle({ featureId }: Partial<IInteractionTarget>) {
|
||||
const pickedColors = encodePickingColor(featureId as number);
|
||||
this.highlightPickedFeature(new Uint8Array(pickedColors));
|
||||
}
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
import { ISceneConfig } from '../config/IConfigService';
|
||||
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;
|
||||
destroyed: boolean;
|
||||
on(type: string, handle: (...args: any[]) => void): void;
|
||||
off(type: string, handle: (...args: any[]) => void): void;
|
||||
removeAllListeners(event?: string): this;
|
||||
init(config: IMapConfig & IRenderConfig): void;
|
||||
addLayer(layer: ILayer): void;
|
||||
getSceneConfig(): Partial<ISceneConfig>;
|
||||
render(): void;
|
||||
getSceneContainer(): HTMLDivElement;
|
||||
exportPng(): string;
|
||||
exportPng(type?: 'png' | 'jpg'): string;
|
||||
destroy(): void;
|
||||
}
|
||||
// scene 事件
|
||||
export const SceneEventList = ['loaded', 'maploaded', 'resize', 'destroy'];
|
||||
export const SceneEventList: string[] = [
|
||||
'loaded',
|
||||
'maploaded',
|
||||
'resize',
|
||||
'destroy',
|
||||
];
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
// @ts-ignore
|
||||
import { AsyncParallelHook } from '@antv/async-hook';
|
||||
import { DOM } from '@antv/l7-utils';
|
||||
import elementResizeEvent, { unbind } from 'element-resize-event';
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { AsyncParallelHook } from 'tapable';
|
||||
import { TYPES } from '../../types';
|
||||
import { createRendererContainer } from '../../utils/dom';
|
||||
import { IFontService } from '../asset/IFontService';
|
||||
|
@ -14,10 +15,11 @@ import { IPopupService } from '../component/IPopupService';
|
|||
import { IGlobalConfigService, ISceneConfig } from '../config/IConfigService';
|
||||
import { ICoordinateSystemService } from '../coordinate/ICoordinateSystemService';
|
||||
import { IInteractionService } from '../interaction/IInteractionService';
|
||||
import { IPickingService } from '../interaction/IPickingService';
|
||||
import { ILayer, ILayerService } from '../layer/ILayerService';
|
||||
import { ILogService } from '../log/ILogService';
|
||||
import { IMapCamera, IMapService } from '../map/IMapService';
|
||||
import { IRendererService } from '../renderer/IRendererService';
|
||||
import { IMapCamera, IMapConfig, IMapService } from '../map/IMapService';
|
||||
import { IRenderConfig, IRendererService } from '../renderer/IRendererService';
|
||||
import { IShaderModuleService } from '../shader/IShaderModuleService';
|
||||
import { ISceneService } from './ISceneService';
|
||||
|
||||
|
@ -26,6 +28,8 @@ import { ISceneService } from './ISceneService';
|
|||
*/
|
||||
@injectable()
|
||||
export default class Scene extends EventEmitter implements ISceneService {
|
||||
public destroyed: boolean = false;
|
||||
|
||||
@inject(TYPES.SceneID)
|
||||
private readonly id: string;
|
||||
/**
|
||||
|
@ -64,6 +68,9 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
@inject(TYPES.IInteractionService)
|
||||
private readonly interactionService: IInteractionService;
|
||||
|
||||
@inject(TYPES.IPickingService)
|
||||
private readonly pickingService: IPickingService;
|
||||
|
||||
@inject(TYPES.IShaderModuleService)
|
||||
private readonly shaderModuleService: IShaderModuleService;
|
||||
|
||||
|
@ -88,7 +95,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
private $container: HTMLDivElement | null;
|
||||
|
||||
private hooks: {
|
||||
init: AsyncParallelHook<unknown>;
|
||||
init: AsyncParallelHook;
|
||||
};
|
||||
|
||||
public constructor() {
|
||||
|
@ -101,7 +108,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
* 2. initRenderer:初始化渲染引擎
|
||||
* 3. initWorker:初始化 Worker
|
||||
*/
|
||||
init: new AsyncParallelHook(['config']),
|
||||
init: new AsyncParallelHook(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -110,13 +117,13 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
this.configService.setSceneConfig(this.id, sceneConfig);
|
||||
|
||||
// 校验场景配置项,失败则终止初始化过程
|
||||
const { valid, errorText } = this.configService.validateSceneConfig(
|
||||
this.configService.getSceneConfig(this.id),
|
||||
);
|
||||
if (!valid) {
|
||||
this.logger.error(errorText || '');
|
||||
return;
|
||||
}
|
||||
// const { valid, errorText } = this.configService.validateSceneConfig(
|
||||
// this.configService.getSceneConfig(this.id),
|
||||
// );
|
||||
// if (!valid) {
|
||||
// this.logger.error(errorText || '');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// 初始化 ShaderModule
|
||||
this.shaderModuleService.registerBuiltinModules();
|
||||
|
@ -163,7 +170,10 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
);
|
||||
this.$container = $container;
|
||||
if ($container) {
|
||||
await this.rendererService.init($container);
|
||||
await this.rendererService.init(
|
||||
$container,
|
||||
this.configService.getSceneConfig(this.id) as IRenderConfig,
|
||||
);
|
||||
elementResizeEvent(
|
||||
this.$container as HTMLDivElement,
|
||||
this.handleWindowResized,
|
||||
|
@ -174,15 +184,15 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
} else {
|
||||
this.logger.error('容器 id 不存在');
|
||||
}
|
||||
this.pickingService.init();
|
||||
|
||||
this.logger.debug(`scene ${this.id} renderer loaded`);
|
||||
});
|
||||
// TODO:init worker, fontAtlas...
|
||||
|
||||
// 执行异步并行初始化任务
|
||||
this.initPromise = this.hooks.init.promise(
|
||||
this.configService.getSceneConfig(this.id),
|
||||
);
|
||||
// @ts-ignore
|
||||
this.initPromise = this.hooks.init.promise();
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
@ -194,7 +204,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
}
|
||||
|
||||
public async render() {
|
||||
if (this.rendering) {
|
||||
if (this.rendering && this.destroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -202,10 +212,12 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
// 首次初始化,或者地图的容器被强制销毁的需要重新初始化
|
||||
if (!this.inited) {
|
||||
// 还未初始化完成需要等待
|
||||
|
||||
await this.initPromise;
|
||||
// FIXME: 初始化 marker 容器,可以放到 map 初始化方法中?
|
||||
if (this.destroyed) {
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
// FIXME: 初始化 marker 容器,可以放到 map 初始化方法中?
|
||||
this.logger.info(' render inited');
|
||||
this.layerService.initLayers();
|
||||
this.controlService.addControls();
|
||||
|
@ -226,24 +238,36 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
return this.$container as HTMLDivElement;
|
||||
}
|
||||
|
||||
public exportPng(): string {
|
||||
public exportPng(type?: 'png' | 'jpg'): string {
|
||||
const renderCanvas = this.$container?.getElementsByTagName('canvas')[0];
|
||||
// this.render();
|
||||
DOM.printCanvas(renderCanvas as HTMLCanvasElement);
|
||||
const layersPng = renderCanvas?.toDataURL('image/png') as string;
|
||||
this.render();
|
||||
const layersPng =
|
||||
type === 'jpg'
|
||||
? (renderCanvas?.toDataURL('image/jpeg') as string)
|
||||
: (renderCanvas?.toDataURL('image/png') as string);
|
||||
return layersPng;
|
||||
}
|
||||
|
||||
public getSceneConfig(): Partial<ISceneConfig> {
|
||||
return this.configService.getSceneConfig(this.id as string);
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
if (!this.inited) {
|
||||
this.destroyed = true;
|
||||
return;
|
||||
}
|
||||
this.emit('destroy');
|
||||
this.inited = false;
|
||||
|
||||
this.layerService.destroy();
|
||||
this.rendererService.destroy();
|
||||
this.map.destroy();
|
||||
|
||||
this.interactionService.destroy();
|
||||
this.controlService.destroy();
|
||||
this.markerService.destroy();
|
||||
this.removeAllListeners();
|
||||
this.map.destroy();
|
||||
this.inited = false;
|
||||
unbind(this.$container as HTMLDivElement, this.handleWindowResized);
|
||||
window
|
||||
.matchMedia('screen and (min-resolution: 2dppx)')
|
||||
|
|
|
@ -16,15 +16,15 @@
|
|||
#define SHIFT_LEFT23 8388608.0
|
||||
#define SHIFT_LEFT24 16777216.0
|
||||
|
||||
vec2 unpack_float(const float packedValue) {
|
||||
vec2 unpack_float(float packedValue) {
|
||||
int packedIntValue = int(packedValue);
|
||||
int v0 = packedIntValue / 256;
|
||||
return vec2(v0, packedIntValue - v0 * 256);
|
||||
}
|
||||
|
||||
vec4 decode_color(const vec2 encodedColor) {
|
||||
vec4 decode_color(vec2 encodedColor) {
|
||||
return vec4(
|
||||
unpack_float(encodedColor[0]) / 255.0,
|
||||
unpack_float(encodedColor[1]) / 255.0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,8 +59,8 @@ vec3 calc_directional_light(DirectionalLight light, vec3 normal, vec3 viewDir) {
|
|||
// float spec = pow(max(dot(viewDir, reflectDir), 0.0), SHININESS);
|
||||
// // attenuation
|
||||
// float distance = length(light.position - fragPos);
|
||||
// float attenuation = 1.0 / (light.constant + light.linear * distance +
|
||||
// light.quadratic * (distance * distance));
|
||||
// float attenuation = 1.0 / (light.constant + light.linear * distance +
|
||||
// light.quadratic * (distance * distance));
|
||||
|
||||
// vec3 ambient = light.ambient * u_Ambient;
|
||||
// vec3 diffuse = light.diffuse * diff * u_Diffuse;
|
||||
|
@ -94,4 +94,4 @@ vec3 calc_lighting(vec3 position, vec3 normal, vec3 viewDir) {
|
|||
// weight += calc_spot_light(u_SpotLights[i], normal, position, viewDir);
|
||||
// }
|
||||
return weight;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,31 +56,33 @@ vec3 project_normal(vec3 normal) {
|
|||
}
|
||||
|
||||
vec3 project_offset_normal(vec3 vector) {
|
||||
if (u_CoordinateSystem == COORDINATE_SYSTEM_LNGLAT
|
||||
if (u_CoordinateSystem < COORDINATE_SYSTEM_LNGLAT + 0.01 && u_CoordinateSystem >COORDINATE_SYSTEM_LNGLAT - 0.01
|
||||
|| u_CoordinateSystem == COORDINATE_SYSTEM_LNGLAT_OFFSET) {
|
||||
// normals generated by the polygon tesselator are in lnglat offsets instead of meters
|
||||
return normalize(vector * u_PixelsPerDegree);
|
||||
}
|
||||
return project_normal(vector);
|
||||
}
|
||||
|
||||
// || u_CoordinateSystem < COORDINATE_SYSTEM_P20_OFFSET + 0.01 && u_CoordinateSystem >COORDINATE_SYSTEM_P20_OFFSET - 0.01
|
||||
// reverse Y
|
||||
vec3 reverse_offset_normal(vec3 vector) {
|
||||
if (u_CoordinateSystem == COORDINATE_SYSTEM_P20) {
|
||||
if (u_CoordinateSystem == COORDINATE_SYSTEM_P20 ||u_CoordinateSystem == COORDINATE_SYSTEM_P20_OFFSET ) {
|
||||
return vector * vec3(1.0, -1.0, 1.0);
|
||||
}
|
||||
return vector;
|
||||
}
|
||||
|
||||
vec4 project_position(vec4 position) {
|
||||
float a = COORDINATE_SYSTEM_LNGLAT_OFFSET;
|
||||
float b = COORDINATE_SYSTEM_P20_OFFSET;
|
||||
float c = COORDINATE_SYSTEM_LNGLAT;
|
||||
if (u_CoordinateSystem == COORDINATE_SYSTEM_LNGLAT_OFFSET
|
||||
|| u_CoordinateSystem == COORDINATE_SYSTEM_P20_OFFSET) {
|
||||
float X = position.x - u_ViewportCenter.x;
|
||||
float Y = position.y - u_ViewportCenter.y;
|
||||
return project_offset(vec4(X, Y, position.z, position.w));
|
||||
}
|
||||
|
||||
if (u_CoordinateSystem == COORDINATE_SYSTEM_LNGLAT) {
|
||||
if (u_CoordinateSystem < COORDINATE_SYSTEM_LNGLAT + 0.01 && u_CoordinateSystem >COORDINATE_SYSTEM_LNGLAT - 0.01) {
|
||||
return vec4(
|
||||
project_mercator(position.xy) * WORLD_SCALE * u_ZoomScale,
|
||||
project_scale(position.z),
|
||||
|
@ -95,6 +97,7 @@ vec4 project_position(vec4 position) {
|
|||
position.w
|
||||
);
|
||||
}
|
||||
return position;
|
||||
|
||||
// TODO: 瓦片坐标系 & 常规世界坐标系
|
||||
}
|
||||
|
@ -115,7 +118,7 @@ vec2 project_pixel(vec2 pixel) {
|
|||
// P20 坐标系下,为了和 Web 墨卡托坐标系统一,zoom 默认减1
|
||||
return pixel * pow(2.0, (19.0 - u_Zoom));
|
||||
}
|
||||
return pixel;
|
||||
return pixel * -1.;
|
||||
}
|
||||
|
||||
vec4 project_common_position_to_clipspace(vec4 position, mat4 viewProjectionMatrix, vec4 center) {
|
||||
|
@ -146,3 +149,9 @@ vec4 unproject_clipspace_to_position(vec4 clipspacePos, mat4 u_InverseViewProjec
|
|||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
bool isEqual( float a, float b) {
|
||||
return a< b + 0.001 && a > b - 0.001;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ float sdCircle(vec2 p, float r) {
|
|||
}
|
||||
|
||||
float sdEquilateralTriangle(vec2 p) {
|
||||
const float k = sqrt(3.0);
|
||||
float k = sqrt(3.0);
|
||||
p.x = abs(p.x) - 1.0;
|
||||
p.y = p.y + 1.0/k;
|
||||
if( p.x + k*p.y > 0.0 ) p = vec2(p.x-k*p.y,-k*p.x-p.y)/2.0;
|
||||
|
@ -24,16 +24,16 @@ float sdBox(vec2 p, vec2 b) {
|
|||
}
|
||||
|
||||
float sdPentagon(vec2 p, float r) {
|
||||
const vec3 k = vec3(0.809016994,0.587785252,0.726542528);
|
||||
vec3 k = vec3(0.809016994,0.587785252,0.726542528);
|
||||
p.x = abs(p.x);
|
||||
p -= 2.0*min(dot(vec2(-k.x,k.y),p),0.0)*vec2(-k.x,k.y);
|
||||
p -= 2.0*min(dot(vec2( k.x,k.y),p),0.0)*vec2( k.x,k.y);
|
||||
p -= vec2(clamp(p.x,-r*k.z,r*k.z),r);
|
||||
p -= vec2(clamp(p.x,-r*k.z,r*k.z),r);
|
||||
return length(p)*sign(p.y);
|
||||
}
|
||||
|
||||
float sdHexagon(vec2 p, float r) {
|
||||
const vec3 k = vec3(-0.866025404,0.5,0.577350269);
|
||||
vec3 k = vec3(-0.866025404,0.5,0.577350269);
|
||||
p = abs(p);
|
||||
p -= 2.0*min(dot(k.xy,p),0.0)*k.xy;
|
||||
p -= vec2(clamp(p.x, -k.z*r, k.z*r), r);
|
||||
|
@ -41,7 +41,7 @@ float sdHexagon(vec2 p, float r) {
|
|||
}
|
||||
|
||||
float sdOctogon(vec2 p, float r) {
|
||||
const vec3 k = vec3(-0.9238795325, 0.3826834323, 0.4142135623 );
|
||||
vec3 k = vec3(-0.9238795325, 0.3826834323, 0.4142135623 );
|
||||
p = abs(p);
|
||||
p -= 2.0*min(dot(vec2( k.x,k.y),p),0.0)*vec2( k.x,k.y);
|
||||
p -= 2.0*min(dot(vec2(-k.x,k.y),p),0.0)*vec2(-k.x,k.y);
|
||||
|
@ -50,7 +50,7 @@ float sdOctogon(vec2 p, float r) {
|
|||
}
|
||||
|
||||
float sdHexagram(vec2 p, float r) {
|
||||
const vec4 k=vec4(-0.5,0.8660254038,0.5773502692,1.7320508076);
|
||||
vec4 k=vec4(-0.5,0.8660254038,0.5773502692,1.7320508076);
|
||||
p = abs(p);
|
||||
p -= 2.0*min(dot(k.xy,p),0.0)*k.xy;
|
||||
p -= 2.0*min(dot(k.yx,p),0.0)*k.yx;
|
||||
|
@ -68,7 +68,7 @@ float sdRhombus(vec2 p, vec2 b) {
|
|||
float sdVesica(vec2 p, float r, float d) {
|
||||
p = abs(p);
|
||||
float b = sqrt(r*r-d*d); // can delay this sqrt
|
||||
return ((p.y-b)*d>p.x*b)
|
||||
return ((p.y-b)*d>p.x*b)
|
||||
? length(p-vec2(0.0,b))
|
||||
: length(p-vec2(-d,0.0))-r;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ const TYPES = {
|
|||
IIconService: Symbol.for('IIconService'),
|
||||
IFontService: Symbol.for('IFontService'),
|
||||
IInteractionService: Symbol.for('IInteractionService'),
|
||||
IPickingService: Symbol.for('IPickingService'),
|
||||
IControlService: Symbol.for('IControlService'),
|
||||
IStyleAttributeService: Symbol.for('IStyleAttributeService'),
|
||||
ILayer: Symbol.for('ILayer'),
|
||||
|
|
|
@ -10,9 +10,14 @@ export function getAngle(angle: number | undefined) {
|
|||
}
|
||||
|
||||
export function createVec3(x: number | vec3 | vec4, y?: number, z?: number) {
|
||||
return x instanceof vec3
|
||||
? vec3.clone(x)
|
||||
: x instanceof vec4
|
||||
? vec3.fromValues(x[0], x[1], x[2])
|
||||
: vec3.fromValues(x, y as number, z as number);
|
||||
// @ts-ignore
|
||||
if (x instanceof vec3) {
|
||||
return vec3.clone(x as vec3);
|
||||
// @ts-ignore
|
||||
} else if (x instanceof vec4) {
|
||||
x = x as vec4;
|
||||
return vec3.fromValues(x[0], x[1], x[2]);
|
||||
} else {
|
||||
return vec3.fromValues(x as number, y as number, z as number);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,14 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.0.34](https://github.com/antvis/L7/compare/v2.0.32...v2.0.34) (2020-03-02)
|
||||
|
||||
**Note:** Version bump only for package @antv/l7
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.28](https://github.com/antvis/L7/compare/v2.0.0-beta.16...v2.0.0-beta.28) (2020-01-02)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>L7 IE</title>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
#map {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<link
|
||||
href="https://api.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.8.3/polyfill.min.js"></script>
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.js"></script>
|
||||
<script src="../dist/l7-dev.js"></script>
|
||||
<script>
|
||||
console.log(L7);
|
||||
const scene = new L7.Scene({
|
||||
id: "map",
|
||||
map: new L7.Mapbox({
|
||||
style: "dark", // 样式URL
|
||||
center: [108.6167, 19.1000],
|
||||
pitch: 0,
|
||||
zoom: 6
|
||||
})
|
||||
});
|
||||
|
||||
const data = {"list":[{"w":19.1000,"t":24.6000,"s":"海南","l":11,"m":"东方","j":108.6167,"h":"59838"},{"w":20.0000,"t":23.8000,"s":"海南","l":11,"m":"海口","j":110.2500,"h":"59758"},{"w":22.2750,"t":23.6000,"s":"广东","l":12,"m":"珠海","j":113.5669,"h":"59488"},{"w":20.3372,"t":23.4000,"s":"广东","l":12,"m":"徐闻","j":110.1794,"h":"59754"},{"w":19.2089,"t":23.2000,"s":"海南","l":12,"m":"琼海","j":110.4819,"h":"59855"},{"w":21.7358,"t":23.2000,"s":"广东","l":11,"m":"上川岛","j":112.7731,"h":"59673"},{"w":23.3853,"t":23.0000,"s":"广东","l":11,"m":"汕头","j":116.6792,"h":"59316"},{"w":22.5417,"t":23.0000,"s":"广东","l":12,"m":"深圳","j":114.0033,"h":"59493"},{"w":19.5167,"t":22.9000,"s":"海南","l":12,"m":"儋州","j":109.5833,"h":"59845"},{"w":21.1547,"t":22.7000,"s":"广东","l":12,"m":"湛江","j":110.3022,"h":"59658"},{"w":21.4500,"t":22.7000,"s":"广西","l":12,"m":"北海","j":109.1333,"h":"59644"},{"w":22.5000,"t":22.6000,"s":"广东","l":12,"m":"中山","j":113.4000,"h":"59485"},{"w":21.8453,"t":22.6000,"s":"广东","l":12,"m":"阳江","j":111.9783,"h":"59663"},{"w":22.3469,"t":22.6000,"s":"广东","l":12,"m":"信宜","j":110.9250,"h":"59456"},{"w":22.8000,"t":22.5000,"s":"广东","l":12,"m":"汕尾","j":115.3667,"h":"59501"},{"w":23.4275,"t":22.3000,"s":"广东","l":12,"m":"南澳","j":117.0292,"h":"59324"},{"w":22.7100,"t":22.3000,"s":"广东","l":12,"m":"罗定","j":111.6000,"h":"59462"},{"w":19.0333,"t":22.3000,"s":"海南","l":12,"m":"琼中","j":109.8333,"h":"59849"},{"w":21.5458,"t":22.2000,"s":"广东","l":11,"m":"电白","j":110.9886,"h":"59664"},{"w":22.9661,"t":21.9000,"s":"广东","l":12,"m":"东莞","j":113.7389,"h":"59289"},{"w":22.2472,"t":21.8000,"s":"广东","l":12,"m":"台山","j":112.7858,"h":"59478"},{"w":22.9836,"t":21.6000,"s":"广东","l":12,"m":"惠来","j":116.3014,"h":"59317"},{"w":22.9906,"t":21.0000,"s":"广东","l":12,"m":"高要","j":112.4786,"h":"59278"},{"w":23.9000,"t":20.8000,"s":"广西","l":12,"m":"百色","j":106.6000,"h":"59211"},{"w":23.0711,"t":20.4000,"s":"广东","l":12,"m":"惠阳","j":114.3744,"h":"59298"},{"w":23.4497,"t":20.4000,"s":"广东","l":12,"m":"揭西","j":115.8492,"h":"59306"},{"w":23.3353,"t":20.4000,"s":"广东","l":11,"m":"增城","j":113.8275,"h":"59294"},{"w":23.4167,"t":19.9000,"s":"广西","l":12,"m":"那坡","j":105.8333,"h":"59209"},{"w":24.9000,"t":19.7000,"s":"福建","l":11,"m":"崇武","j":118.9167,"h":"59133"},{"w":24.4833,"t":19.7000,"s":"福建","l":12,"m":"厦门","j":118.0667,"h":"59134"},{"w":23.7936,"t":19.6000,"s":"广东","l":12,"m":"河源","j":114.7297,"h":"59293"},{"w":23.7106,"t":19.4000,"s":"广东","l":12,"m":"清远","j":113.0850,"h":"59280"},{"w":23.1000,"t":19.4000,"s":"广西","l":12,"m":"靖西","j":106.4500,"h":"59218"},{"w":23.6000,"t":19.4000,"s":"广西","l":13,"m":"田东","j":107.1167,"h":"59224"},{"w":25.5167,"t":19.2000,"s":"福建","l":12,"m":"平潭","j":119.7833,"h":"58944"},{"w":25.0500,"t":19.2000,"s":"福建","l":12,"m":"龙岩","j":117.0167,"h":"58927"},{"w":23.2100,"t":19.0000,"s":"广东","l":12,"m":"广州","j":113.4822,"h":"59287"},{"w":21.9833,"t":18.9000,"s":"广西","l":12,"m":"钦州","j":108.6000,"h":"59632"}]}
|
||||
|
||||
scene.on('loaded',function(){
|
||||
const pointLayer = new L7.PointLayer({})
|
||||
.source(data.list, {
|
||||
parser: {
|
||||
type: "json",
|
||||
x: "j",
|
||||
y: "w"
|
||||
}
|
||||
})
|
||||
.shape("circle")
|
||||
.size(15)
|
||||
.color("t", [
|
||||
"#094D4A",
|
||||
"#146968",
|
||||
"#1D7F7E",
|
||||
"#289899",
|
||||
"#34B6B7",
|
||||
"#4AC5AF",
|
||||
"#5FD3A6",
|
||||
"#7BE39E",
|
||||
"#A1EDB8",
|
||||
"#CEF8D6"
|
||||
])
|
||||
.style({
|
||||
opacity: 1.0
|
||||
});
|
||||
|
||||
scene.addLayer(pointLayer);
|
||||
pointLayer.on('inited',function(){
|
||||
console.log('加载完成');
|
||||
})
|
||||
scene.render();
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>L7 IE</title>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
#map {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<link
|
||||
href="https://api.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.8.3/polyfill.min.js"></script>
|
||||
<!-- <script src="https://cdn.jsdelivr.net/npm/symbol-es6@0.1.2/symbol-es6.min.js"></script> -->
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.js"></script>
|
||||
|
||||
<script src="../dist/l7-dev.js"></script>
|
||||
<script>
|
||||
console.log(L7);
|
||||
const scene = new L7.Scene({
|
||||
id: "map",
|
||||
map: new L7.Mapbox({
|
||||
style: "dark", // 样式URL
|
||||
center: [108.6167, 19.1000],
|
||||
pitch: 0,
|
||||
zoom: 8
|
||||
})
|
||||
});
|
||||
|
||||
const data = {"list":[{"w":19.1000,"t":24.6000,"s":"海南","l":11,"m":"东方","j":108.6167,"h":"59838"},{"w":20.0000,"t":23.8000,"s":"海南","l":11,"m":"海口","j":110.2500,"h":"59758"},{"w":22.2750,"t":23.6000,"s":"广东","l":12,"m":"珠海","j":113.5669,"h":"59488"},{"w":20.3372,"t":23.4000,"s":"广东","l":12,"m":"徐闻","j":110.1794,"h":"59754"},{"w":19.2089,"t":23.2000,"s":"海南","l":12,"m":"琼海","j":110.4819,"h":"59855"},{"w":21.7358,"t":23.2000,"s":"广东","l":11,"m":"上川岛","j":112.7731,"h":"59673"},{"w":23.3853,"t":23.0000,"s":"广东","l":11,"m":"汕头","j":116.6792,"h":"59316"},{"w":22.5417,"t":23.0000,"s":"广东","l":12,"m":"深圳","j":114.0033,"h":"59493"},{"w":19.5167,"t":22.9000,"s":"海南","l":12,"m":"儋州","j":109.5833,"h":"59845"},{"w":21.1547,"t":22.7000,"s":"广东","l":12,"m":"湛江","j":110.3022,"h":"59658"},{"w":21.4500,"t":22.7000,"s":"广西","l":12,"m":"北海","j":109.1333,"h":"59644"},{"w":22.5000,"t":22.6000,"s":"广东","l":12,"m":"中山","j":113.4000,"h":"59485"},{"w":21.8453,"t":22.6000,"s":"广东","l":12,"m":"阳江","j":111.9783,"h":"59663"},{"w":22.3469,"t":22.6000,"s":"广东","l":12,"m":"信宜","j":110.9250,"h":"59456"},{"w":22.8000,"t":22.5000,"s":"广东","l":12,"m":"汕尾","j":115.3667,"h":"59501"},{"w":23.4275,"t":22.3000,"s":"广东","l":12,"m":"南澳","j":117.0292,"h":"59324"},{"w":22.7100,"t":22.3000,"s":"广东","l":12,"m":"罗定","j":111.6000,"h":"59462"},{"w":19.0333,"t":22.3000,"s":"海南","l":12,"m":"琼中","j":109.8333,"h":"59849"},{"w":21.5458,"t":22.2000,"s":"广东","l":11,"m":"电白","j":110.9886,"h":"59664"},{"w":22.9661,"t":21.9000,"s":"广东","l":12,"m":"东莞","j":113.7389,"h":"59289"},{"w":22.2472,"t":21.8000,"s":"广东","l":12,"m":"台山","j":112.7858,"h":"59478"},{"w":22.9836,"t":21.6000,"s":"广东","l":12,"m":"惠来","j":116.3014,"h":"59317"},{"w":22.9906,"t":21.0000,"s":"广东","l":12,"m":"高要","j":112.4786,"h":"59278"},{"w":23.9000,"t":20.8000,"s":"广西","l":12,"m":"百色","j":106.6000,"h":"59211"},{"w":23.0711,"t":20.4000,"s":"广东","l":12,"m":"惠阳","j":114.3744,"h":"59298"},{"w":23.4497,"t":20.4000,"s":"广东","l":12,"m":"揭西","j":115.8492,"h":"59306"},{"w":23.3353,"t":20.4000,"s":"广东","l":11,"m":"增城","j":113.8275,"h":"59294"},{"w":23.4167,"t":19.9000,"s":"广西","l":12,"m":"那坡","j":105.8333,"h":"59209"},{"w":24.9000,"t":19.7000,"s":"福建","l":11,"m":"崇武","j":118.9167,"h":"59133"},{"w":24.4833,"t":19.7000,"s":"福建","l":12,"m":"厦门","j":118.0667,"h":"59134"},{"w":23.7936,"t":19.6000,"s":"广东","l":12,"m":"河源","j":114.7297,"h":"59293"},{"w":23.7106,"t":19.4000,"s":"广东","l":12,"m":"清远","j":113.0850,"h":"59280"},{"w":23.1000,"t":19.4000,"s":"广西","l":12,"m":"靖西","j":106.4500,"h":"59218"},{"w":23.6000,"t":19.4000,"s":"广西","l":13,"m":"田东","j":107.1167,"h":"59224"},{"w":25.5167,"t":19.2000,"s":"福建","l":12,"m":"平潭","j":119.7833,"h":"58944"},{"w":25.0500,"t":19.2000,"s":"福建","l":12,"m":"龙岩","j":117.0167,"h":"58927"},{"w":23.2100,"t":19.0000,"s":"广东","l":12,"m":"广州","j":113.4822,"h":"59287"},{"w":21.9833,"t":18.9000,"s":"广西","l":12,"m":"钦州","j":108.6000,"h":"59632"}]}
|
||||
|
||||
|
||||
const pointLayer = new L7.PointLayer({})
|
||||
.source(data.list, {
|
||||
parser: {
|
||||
type: "json",
|
||||
x: "j",
|
||||
y: "w"
|
||||
}
|
||||
})
|
||||
.shape("cylinder")
|
||||
.size([5,5,10])
|
||||
.color("t", [
|
||||
"#094D4A",
|
||||
"#146968",
|
||||
"#1D7F7E",
|
||||
"#289899",
|
||||
"#34B6B7",
|
||||
"#4AC5AF",
|
||||
"#5FD3A6",
|
||||
"#7BE39E",
|
||||
"#A1EDB8",
|
||||
"#CEF8D6"
|
||||
])
|
||||
.style({
|
||||
opacity: 1.0
|
||||
});
|
||||
scene.addLayer(pointLayer);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>L7 IE</title>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
#map {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<link
|
||||
href="https://api.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.8.3/polyfill.min.js"></script>
|
||||
<!-- <script src="https://cdn.jsdelivr.net/npm/symbol-es6@0.1.2/symbol-es6.min.js"></script> -->
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.js"></script>
|
||||
|
||||
<script src="../dist/l7-dev.js"></script>
|
||||
<script>
|
||||
console.log(L7);
|
||||
const scene = new L7.Scene({
|
||||
id: "map",
|
||||
map: new L7.Mapbox({
|
||||
style: "dark", // 样式URL
|
||||
center: [108.6167, 19.1000],
|
||||
pitch: 0,
|
||||
zoom: 8
|
||||
})
|
||||
});
|
||||
|
||||
const data = {"list":[{"w":19.1000,"t":24.6000,"s":"海南","l":11,"m":"东方","j":108.6167,"h":"59838"},{"w":20.0000,"t":23.8000,"s":"海南","l":11,"m":"海口","j":110.2500,"h":"59758"},{"w":22.2750,"t":23.6000,"s":"广东","l":12,"m":"珠海","j":113.5669,"h":"59488"},{"w":20.3372,"t":23.4000,"s":"广东","l":12,"m":"徐闻","j":110.1794,"h":"59754"},{"w":19.2089,"t":23.2000,"s":"海南","l":12,"m":"琼海","j":110.4819,"h":"59855"},{"w":21.7358,"t":23.2000,"s":"广东","l":11,"m":"上川岛","j":112.7731,"h":"59673"},{"w":23.3853,"t":23.0000,"s":"广东","l":11,"m":"汕头","j":116.6792,"h":"59316"},{"w":22.5417,"t":23.0000,"s":"广东","l":12,"m":"深圳","j":114.0033,"h":"59493"},{"w":19.5167,"t":22.9000,"s":"海南","l":12,"m":"儋州","j":109.5833,"h":"59845"},{"w":21.1547,"t":22.7000,"s":"广东","l":12,"m":"湛江","j":110.3022,"h":"59658"},{"w":21.4500,"t":22.7000,"s":"广西","l":12,"m":"北海","j":109.1333,"h":"59644"},{"w":22.5000,"t":22.6000,"s":"广东","l":12,"m":"中山","j":113.4000,"h":"59485"},{"w":21.8453,"t":22.6000,"s":"广东","l":12,"m":"阳江","j":111.9783,"h":"59663"},{"w":22.3469,"t":22.6000,"s":"广东","l":12,"m":"信宜","j":110.9250,"h":"59456"},{"w":22.8000,"t":22.5000,"s":"广东","l":12,"m":"汕尾","j":115.3667,"h":"59501"},{"w":23.4275,"t":22.3000,"s":"广东","l":12,"m":"南澳","j":117.0292,"h":"59324"},{"w":22.7100,"t":22.3000,"s":"广东","l":12,"m":"罗定","j":111.6000,"h":"59462"},{"w":19.0333,"t":22.3000,"s":"海南","l":12,"m":"琼中","j":109.8333,"h":"59849"},{"w":21.5458,"t":22.2000,"s":"广东","l":11,"m":"电白","j":110.9886,"h":"59664"},{"w":22.9661,"t":21.9000,"s":"广东","l":12,"m":"东莞","j":113.7389,"h":"59289"},{"w":22.2472,"t":21.8000,"s":"广东","l":12,"m":"台山","j":112.7858,"h":"59478"},{"w":22.9836,"t":21.6000,"s":"广东","l":12,"m":"惠来","j":116.3014,"h":"59317"},{"w":22.9906,"t":21.0000,"s":"广东","l":12,"m":"高要","j":112.4786,"h":"59278"},{"w":23.9000,"t":20.8000,"s":"广西","l":12,"m":"百色","j":106.6000,"h":"59211"},{"w":23.0711,"t":20.4000,"s":"广东","l":12,"m":"惠阳","j":114.3744,"h":"59298"},{"w":23.4497,"t":20.4000,"s":"广东","l":12,"m":"揭西","j":115.8492,"h":"59306"},{"w":23.3353,"t":20.4000,"s":"广东","l":11,"m":"增城","j":113.8275,"h":"59294"},{"w":23.4167,"t":19.9000,"s":"广西","l":12,"m":"那坡","j":105.8333,"h":"59209"},{"w":24.9000,"t":19.7000,"s":"福建","l":11,"m":"崇武","j":118.9167,"h":"59133"},{"w":24.4833,"t":19.7000,"s":"福建","l":12,"m":"厦门","j":118.0667,"h":"59134"},{"w":23.7936,"t":19.6000,"s":"广东","l":12,"m":"河源","j":114.7297,"h":"59293"},{"w":23.7106,"t":19.4000,"s":"广东","l":12,"m":"清远","j":113.0850,"h":"59280"},{"w":23.1000,"t":19.4000,"s":"广西","l":12,"m":"靖西","j":106.4500,"h":"59218"},{"w":23.6000,"t":19.4000,"s":"广西","l":13,"m":"田东","j":107.1167,"h":"59224"},{"w":25.5167,"t":19.2000,"s":"福建","l":12,"m":"平潭","j":119.7833,"h":"58944"},{"w":25.0500,"t":19.2000,"s":"福建","l":12,"m":"龙岩","j":117.0167,"h":"58927"},{"w":23.2100,"t":19.0000,"s":"广东","l":12,"m":"广州","j":113.4822,"h":"59287"},{"w":21.9833,"t":18.9000,"s":"广西","l":12,"m":"钦州","j":108.6000,"h":"59632"}]}
|
||||
|
||||
|
||||
const pointLayer = new L7.PointLayer({})
|
||||
.source(data.list, {
|
||||
parser: {
|
||||
type: "json",
|
||||
x: "j",
|
||||
y: "w"
|
||||
}
|
||||
})
|
||||
.shape("dot")
|
||||
.size(15)
|
||||
.color("t", [
|
||||
"#094D4A",
|
||||
"#146968",
|
||||
"#1D7F7E",
|
||||
"#289899",
|
||||
"#34B6B7",
|
||||
"#4AC5AF",
|
||||
"#5FD3A6",
|
||||
"#7BE39E",
|
||||
"#A1EDB8",
|
||||
"#CEF8D6"
|
||||
])
|
||||
.style({
|
||||
opacity: 1.0
|
||||
});
|
||||
scene.addLayer(pointLayer);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>L7 IE</title>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
#map {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<link
|
||||
href="https://api.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.8.3/polyfill.min.js"></script>
|
||||
<!-- <script src="https://cdn.jsdelivr.net/npm/symbol-es6@0.1.2/symbol-es6.min.js"></script> -->
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.js"></script>
|
||||
|
||||
<script src="../dist/l7-dev.js"></script>
|
||||
<script>
|
||||
console.log(L7);
|
||||
const scene = new L7.Scene({
|
||||
id: "map",
|
||||
map: new L7.Mapbox({
|
||||
style: "dark", // 样式URL
|
||||
center: [108.6167, 19.1000],
|
||||
pitch: 0,
|
||||
zoom: 8
|
||||
})
|
||||
});
|
||||
|
||||
const data = {"list":[{"w":19.1000,"t":24.6000,"s":"海南","l":11,"m":"东方","j":108.6167,"h":"59838"},{"w":20.0000,"t":23.8000,"s":"海南","l":11,"m":"海口","j":110.2500,"h":"59758"},{"w":22.2750,"t":23.6000,"s":"广东","l":12,"m":"珠海","j":113.5669,"h":"59488"},{"w":20.3372,"t":23.4000,"s":"广东","l":12,"m":"徐闻","j":110.1794,"h":"59754"},{"w":19.2089,"t":23.2000,"s":"海南","l":12,"m":"琼海","j":110.4819,"h":"59855"},{"w":21.7358,"t":23.2000,"s":"广东","l":11,"m":"上川岛","j":112.7731,"h":"59673"},{"w":23.3853,"t":23.0000,"s":"广东","l":11,"m":"汕头","j":116.6792,"h":"59316"},{"w":22.5417,"t":23.0000,"s":"广东","l":12,"m":"深圳","j":114.0033,"h":"59493"},{"w":19.5167,"t":22.9000,"s":"海南","l":12,"m":"儋州","j":109.5833,"h":"59845"},{"w":21.1547,"t":22.7000,"s":"广东","l":12,"m":"湛江","j":110.3022,"h":"59658"},{"w":21.4500,"t":22.7000,"s":"广西","l":12,"m":"北海","j":109.1333,"h":"59644"},{"w":22.5000,"t":22.6000,"s":"广东","l":12,"m":"中山","j":113.4000,"h":"59485"},{"w":21.8453,"t":22.6000,"s":"广东","l":12,"m":"阳江","j":111.9783,"h":"59663"},{"w":22.3469,"t":22.6000,"s":"广东","l":12,"m":"信宜","j":110.9250,"h":"59456"},{"w":22.8000,"t":22.5000,"s":"广东","l":12,"m":"汕尾","j":115.3667,"h":"59501"},{"w":23.4275,"t":22.3000,"s":"广东","l":12,"m":"南澳","j":117.0292,"h":"59324"},{"w":22.7100,"t":22.3000,"s":"广东","l":12,"m":"罗定","j":111.6000,"h":"59462"},{"w":19.0333,"t":22.3000,"s":"海南","l":12,"m":"琼中","j":109.8333,"h":"59849"},{"w":21.5458,"t":22.2000,"s":"广东","l":11,"m":"电白","j":110.9886,"h":"59664"},{"w":22.9661,"t":21.9000,"s":"广东","l":12,"m":"东莞","j":113.7389,"h":"59289"},{"w":22.2472,"t":21.8000,"s":"广东","l":12,"m":"台山","j":112.7858,"h":"59478"},{"w":22.9836,"t":21.6000,"s":"广东","l":12,"m":"惠来","j":116.3014,"h":"59317"},{"w":22.9906,"t":21.0000,"s":"广东","l":12,"m":"高要","j":112.4786,"h":"59278"},{"w":23.9000,"t":20.8000,"s":"广西","l":12,"m":"百色","j":106.6000,"h":"59211"},{"w":23.0711,"t":20.4000,"s":"广东","l":12,"m":"惠阳","j":114.3744,"h":"59298"},{"w":23.4497,"t":20.4000,"s":"广东","l":12,"m":"揭西","j":115.8492,"h":"59306"},{"w":23.3353,"t":20.4000,"s":"广东","l":11,"m":"增城","j":113.8275,"h":"59294"},{"w":23.4167,"t":19.9000,"s":"广西","l":12,"m":"那坡","j":105.8333,"h":"59209"},{"w":24.9000,"t":19.7000,"s":"福建","l":11,"m":"崇武","j":118.9167,"h":"59133"},{"w":24.4833,"t":19.7000,"s":"福建","l":12,"m":"厦门","j":118.0667,"h":"59134"},{"w":23.7936,"t":19.6000,"s":"广东","l":12,"m":"河源","j":114.7297,"h":"59293"},{"w":23.7106,"t":19.4000,"s":"广东","l":12,"m":"清远","j":113.0850,"h":"59280"},{"w":23.1000,"t":19.4000,"s":"广西","l":12,"m":"靖西","j":106.4500,"h":"59218"},{"w":23.6000,"t":19.4000,"s":"广西","l":13,"m":"田东","j":107.1167,"h":"59224"},{"w":25.5167,"t":19.2000,"s":"福建","l":12,"m":"平潭","j":119.7833,"h":"58944"},{"w":25.0500,"t":19.2000,"s":"福建","l":12,"m":"龙岩","j":117.0167,"h":"58927"},{"w":23.2100,"t":19.0000,"s":"广东","l":12,"m":"广州","j":113.4822,"h":"59287"},{"w":21.9833,"t":18.9000,"s":"广西","l":12,"m":"钦州","j":108.6000,"h":"59632"}]}
|
||||
|
||||
|
||||
const pointLayer = new L7.PointLayer({})
|
||||
.source(data.list, {
|
||||
parser: {
|
||||
type: "json",
|
||||
x: "j",
|
||||
y: "w"
|
||||
}
|
||||
})
|
||||
.shape("s",'text')
|
||||
.size(15)
|
||||
.color("t", [
|
||||
"#094D4A",
|
||||
"#146968",
|
||||
"#1D7F7E",
|
||||
"#289899",
|
||||
"#34B6B7",
|
||||
"#4AC5AF",
|
||||
"#5FD3A6",
|
||||
"#7BE39E",
|
||||
"#A1EDB8",
|
||||
"#CEF8D6"
|
||||
])
|
||||
.style({
|
||||
opacity: 1.0
|
||||
});
|
||||
scene.addLayer(pointLayer);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7",
|
||||
"version": "2.0.17",
|
||||
"version": "2.0.34",
|
||||
"description": "A Large-scale WebGL-powered Geospatial Data Visualization",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -24,14 +24,14 @@
|
|||
"author": "antv",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@antv/l7-component": "^2.0.17",
|
||||
"@antv/l7-core": "^2.0.17",
|
||||
"@antv/l7-layers": "^2.0.17",
|
||||
"@antv/l7-maps": "^2.0.17",
|
||||
"@antv/l7-scene": "^2.0.17",
|
||||
"@antv/l7-component": "^2.0.34",
|
||||
"@antv/l7-core": "^2.0.34",
|
||||
"@antv/l7-layers": "^2.0.34",
|
||||
"@antv/l7-maps": "^2.0.34",
|
||||
"@antv/l7-scene": "^2.0.34",
|
||||
"@babel/runtime": "^7.7.7"
|
||||
},
|
||||
"gitHead": "f2bd3c6473df79d815467b1677c6f985cf68800e",
|
||||
"gitHead": "a5d354b66873f700730248d015c5e539c54b34b7",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
|
|
@ -3,6 +3,14 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.0.34](https://github.com/antvis/L7/compare/v2.0.32...v2.0.34) (2020-03-02)
|
||||
|
||||
**Note:** Version bump only for package @antv/l7-layers
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.28](https://github.com/antvis/L7/compare/v2.0.0-beta.16...v2.0.0-beta.28) (2020-01-02)
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7-layers",
|
||||
"version": "2.0.17",
|
||||
"version": "2.0.34",
|
||||
"description": "L7's collection of built-in layers",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -22,15 +22,16 @@
|
|||
"author": "xiaoiver",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@antv/l7-core": "^2.0.17",
|
||||
"@antv/l7-source": "^2.0.17",
|
||||
"@antv/l7-utils": "^2.0.17",
|
||||
"@antv/async-hook": "^2.1.0",
|
||||
"@antv/l7-core": "^2.0.34",
|
||||
"@antv/l7-source": "^2.0.34",
|
||||
"@antv/l7-utils": "^2.0.34",
|
||||
"@babel/runtime": "^7.7.7",
|
||||
"@mapbox/martini": "^0.1.0",
|
||||
"@turf/meta": "^6.0.2",
|
||||
"d3-array": "^2.3.1",
|
||||
"d3-array": "1",
|
||||
"d3-color": "^1.4.0",
|
||||
"d3-scale": "^3.1.0",
|
||||
"d3-scale": "2",
|
||||
"earcut": "^2.2.1",
|
||||
"eventemitter3": "^4.0.0",
|
||||
"gl-matrix": "^3.1.0",
|
||||
|
@ -38,8 +39,7 @@
|
|||
"inversify": "^5.0.1",
|
||||
"lodash": "^4.17.15",
|
||||
"merge-json-schemas": "1.0.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"tapable": "^2.0.0-beta.8"
|
||||
"reflect-metadata": "^0.1.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/d3-array": "^2.0.0",
|
||||
|
@ -49,7 +49,7 @@
|
|||
"@types/gl-matrix": "^2.4.5",
|
||||
"@types/lodash": "^4.14.138"
|
||||
},
|
||||
"gitHead": "f2bd3c6473df79d815467b1677c6f985cf68800e",
|
||||
"gitHead": "a5d354b66873f700730248d015c5e539c54b34b7",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
|
|
@ -8,7 +8,11 @@ export default class CityBuildingLayer extends BaseLayer {
|
|||
this.layerModel = new CityBuildModel(this);
|
||||
this.models = this.layerModel.buildModels();
|
||||
}
|
||||
|
||||
public setLight(t: number) {
|
||||
this.updateLayerConfig({
|
||||
time: t,
|
||||
});
|
||||
}
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
|
|
|
@ -9,6 +9,7 @@ interface ICityBuildLayerStyleOptions {
|
|||
baseColor: string;
|
||||
brightColor: string;
|
||||
windowColor: string;
|
||||
time: number;
|
||||
}
|
||||
export default class CityBuildModel extends BaseModel {
|
||||
public getUninforms() {
|
||||
|
@ -17,13 +18,14 @@ export default class CityBuildModel extends BaseModel {
|
|||
baseColor = 'rgb(16,16,16)',
|
||||
brightColor = 'rgb(255,176,38)',
|
||||
windowColor = 'rgb(30,60,89)',
|
||||
time = 0,
|
||||
} = this.layer.getLayerConfig() as ICityBuildLayerStyleOptions;
|
||||
return {
|
||||
u_opacity: opacity,
|
||||
u_baseColor: rgb2arr(baseColor),
|
||||
u_brightColor: rgb2arr(brightColor),
|
||||
u_windowColor: rgb2arr(windowColor),
|
||||
u_time: this.layer.getLayerAnimateTime(),
|
||||
u_time: this.layer.getLayerAnimateTime() || time,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// @ts-ignore
|
||||
import { SyncBailHook, SyncHook, SyncWaterfallHook } from '@antv/async-hook';
|
||||
import {
|
||||
BlendType,
|
||||
gl,
|
||||
|
@ -31,6 +33,7 @@ import {
|
|||
IStyleAttributeService,
|
||||
IStyleAttributeUpdateOptions,
|
||||
lazyInject,
|
||||
ScaleAttributeType,
|
||||
ScaleTypeName,
|
||||
ScaleTypes,
|
||||
StyleAttributeField,
|
||||
|
@ -44,7 +47,6 @@ import { Container } from 'inversify';
|
|||
import { isFunction, isObject } from 'lodash';
|
||||
// @ts-ignore
|
||||
import mergeJsonSchemas from 'merge-json-schemas';
|
||||
import { SyncBailHook, SyncHook, SyncWaterfallHook } from 'tapable';
|
||||
import { normalizePasses } from '../plugins/MultiPassRendererPlugin';
|
||||
import { BlendTypes } from '../utils/blend';
|
||||
import baseLayerSchema from './schema';
|
||||
|
@ -75,19 +77,19 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
};
|
||||
// 生命周期钩子
|
||||
public hooks = {
|
||||
init: new SyncBailHook<void, boolean | void>(),
|
||||
afterInit: new SyncBailHook<void, boolean | void>(),
|
||||
beforeRender: new SyncBailHook<void, boolean | void>(),
|
||||
beforeRenderData: new SyncWaterfallHook<void | boolean>(['data']),
|
||||
afterRender: new SyncHook<void>(),
|
||||
beforePickingEncode: new SyncHook<void>(),
|
||||
afterPickingEncode: new SyncHook<void>(),
|
||||
beforeHighlight: new SyncHook<[number[]]>(['pickedColor']),
|
||||
afterHighlight: new SyncHook<void>(),
|
||||
beforeSelect: new SyncHook<[number[]]>(['pickedColor']),
|
||||
afterSelect: new SyncHook<void>(),
|
||||
beforeDestroy: new SyncHook<void>(),
|
||||
afterDestroy: new SyncHook<void>(),
|
||||
init: new SyncBailHook(),
|
||||
afterInit: new SyncBailHook(),
|
||||
beforeRender: new SyncBailHook(),
|
||||
beforeRenderData: new SyncWaterfallHook(),
|
||||
afterRender: new SyncHook(),
|
||||
beforePickingEncode: new SyncHook(),
|
||||
afterPickingEncode: new SyncHook(),
|
||||
beforeHighlight: new SyncHook(['pickedColor']),
|
||||
afterHighlight: new SyncHook(),
|
||||
beforeSelect: new SyncHook(['pickedColor']),
|
||||
afterSelect: new SyncHook(),
|
||||
beforeDestroy: new SyncHook(),
|
||||
afterDestroy: new SyncHook(),
|
||||
};
|
||||
|
||||
// 待渲染 model 列表
|
||||
|
@ -170,6 +172,8 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
|
||||
private aniamateStatus: boolean = false;
|
||||
|
||||
// private pickingPassRender: IPass<'pixelPicking'>;
|
||||
|
||||
constructor(config: Partial<ILayerConfig & ChildLayerStyleOptions> = {}) {
|
||||
super();
|
||||
this.name = config.name || this.id;
|
||||
|
@ -228,7 +232,10 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
// 设置配置项
|
||||
const sceneId = this.container.get<string>(TYPES.SceneID);
|
||||
// 初始化图层配置项
|
||||
this.configService.setLayerConfig(sceneId, this.id, {});
|
||||
const { enableMultiPassRenderer = false } = this.rawConfig;
|
||||
this.configService.setLayerConfig(sceneId, this.id, {
|
||||
enableMultiPassRenderer,
|
||||
});
|
||||
|
||||
// 全局容器服务
|
||||
|
||||
|
@ -297,6 +304,8 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
|
||||
// 触发 init 生命周期插件
|
||||
this.hooks.init.call();
|
||||
// this.pickingPassRender = this.normalPassFactory('pixelPicking');
|
||||
// this.pickingPassRender.init(this);
|
||||
this.hooks.afterInit.call();
|
||||
|
||||
// 触发初始化完成事件;
|
||||
|
@ -360,7 +369,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
updateOptions?: Partial<IStyleAttributeUpdateOptions>,
|
||||
) {
|
||||
this.updateStyleAttribute('filter', field, values, updateOptions);
|
||||
this.dataState.dataMappingNeedUpdate = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -451,7 +459,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
}
|
||||
return this;
|
||||
}
|
||||
public scale(field: ScaleTypeName | IScaleOptions, cfg: IScale) {
|
||||
public scale(field: string | IScaleOptions, cfg: IScale) {
|
||||
if (isObject(field)) {
|
||||
this.scaleOptions = {
|
||||
...this.scaleOptions,
|
||||
|
@ -463,11 +471,21 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
return this;
|
||||
}
|
||||
public render(): ILayer {
|
||||
if (this.multiPassRenderer && this.multiPassRenderer.getRenderFlag()) {
|
||||
this.multiPassRenderer.render();
|
||||
} else {
|
||||
this.renderModels();
|
||||
}
|
||||
// if (
|
||||
// this.needPick() &&
|
||||
// this.multiPassRenderer &&
|
||||
// this.multiPassRenderer.getRenderFlag()
|
||||
// ) {
|
||||
// this.multiPassRenderer.render();
|
||||
// } else if (this.needPick() && this.multiPassRenderer) {
|
||||
// this.renderModels();
|
||||
// } else {
|
||||
// this.renderModels();
|
||||
// }
|
||||
|
||||
this.renderModels();
|
||||
// this.multiPassRenderer.render();
|
||||
// this.renderModels();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -504,14 +522,14 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
? options.color
|
||||
: this.getLayerConfig().highlightColor,
|
||||
});
|
||||
this.hooks.beforeSelect.callAsync(
|
||||
encodePickingColor(id as number) as number[],
|
||||
() => {
|
||||
this.hooks.beforeSelect
|
||||
.call(encodePickingColor(id as number) as number[])
|
||||
// @ts-ignore
|
||||
.then(() => {
|
||||
setTimeout(() => {
|
||||
this.reRender();
|
||||
}, 1);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -549,14 +567,14 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
? options.color
|
||||
: this.getLayerConfig().selectColor,
|
||||
});
|
||||
this.hooks.beforeSelect.callAsync(
|
||||
encodePickingColor(id as number) as number[],
|
||||
() => {
|
||||
this.hooks.beforeSelect
|
||||
.call(encodePickingColor(id as number) as number[])
|
||||
// @ts-ignore
|
||||
.then(() => {
|
||||
setTimeout(() => {
|
||||
this.reRender();
|
||||
}, 1);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
public setBlend(type: keyof typeof BlendType): void {
|
||||
|
@ -728,6 +746,30 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
}
|
||||
return this.configSchema;
|
||||
}
|
||||
public getLegendItems(name: string): any {
|
||||
const scale = this.styleAttributeService.getLayerAttributeScale(name);
|
||||
if (scale) {
|
||||
if (scale.ticks) {
|
||||
const items = scale.ticks().map((item: any) => {
|
||||
return {
|
||||
value: item,
|
||||
[name]: scale(item),
|
||||
};
|
||||
});
|
||||
return items;
|
||||
} else if (scale.invertExtent) {
|
||||
const items = scale.range().map((item: any) => {
|
||||
return {
|
||||
value: scale.invertExtent(item),
|
||||
[name]: item,
|
||||
};
|
||||
});
|
||||
return items;
|
||||
}
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public pick({ x, y }: { x: number; y: number }) {
|
||||
this.interactionService.triggerHover({ x, y });
|
||||
|
@ -789,17 +831,27 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
return this.layerService.clock.getElapsedTime() - this.animateStartTime;
|
||||
}
|
||||
|
||||
public needPick(): boolean {
|
||||
const {
|
||||
enableHighlight = true,
|
||||
enableSelect = true,
|
||||
} = this.getLayerConfig();
|
||||
const eventNames = this.eventNames().filter((name) => {
|
||||
return (
|
||||
name !== 'inited' && name !== 'add' && name !== 'remove' && 'dataupdate' // 非拾取事件排除
|
||||
);
|
||||
});
|
||||
return eventNames.length > 0 || enableHighlight || enableSelect;
|
||||
}
|
||||
|
||||
public buildModels() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
protected getConfigSchema() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
protected renderModels() {
|
||||
if (this.layerModelNeedUpdate) {
|
||||
public renderModels() {
|
||||
if (this.layerModelNeedUpdate && this.layerModel) {
|
||||
this.models = this.layerModel.buildModels();
|
||||
this.hooks.beforeRender.call();
|
||||
this.layerModelNeedUpdate = false;
|
||||
}
|
||||
this.models.forEach((model) => {
|
||||
|
@ -810,6 +862,10 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
return this;
|
||||
}
|
||||
|
||||
protected getConfigSchema() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
protected getModelType(): unknown {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
@ -819,6 +875,12 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
|
||||
private sourceEvent = () => {
|
||||
this.dataState.dataSourceNeedUpdate = true;
|
||||
const { autoFit } = this.getLayerConfig();
|
||||
if (autoFit) {
|
||||
this.fitBounds();
|
||||
}
|
||||
|
||||
this.emit('dataUpdate');
|
||||
this.reRender();
|
||||
};
|
||||
|
||||
|
|
|
@ -12,19 +12,7 @@ export default class HeatMapLayer extends BaseLayer<IHeatMapLayerStyleOptions> {
|
|||
this.layerModel = new HeatMapModels[shape](this);
|
||||
this.models = this.layerModel.buildModels();
|
||||
}
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected renderModels() {
|
||||
public renderModels() {
|
||||
const shape = this.getModelType();
|
||||
if (shape === 'heatmap') {
|
||||
// if (this.layerModelNeedUpdate) {
|
||||
|
@ -49,6 +37,18 @@ export default class HeatMapLayer extends BaseLayer<IHeatMapLayerStyleOptions> {
|
|||
);
|
||||
return this;
|
||||
}
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected getModelType(): HeatMapModelType {
|
||||
const shapeAttribute = this.styleAttributeService.getLayerStyleAttribute(
|
||||
'shape',
|
||||
|
|
|
@ -9,7 +9,7 @@ import PointLayer from './point';
|
|||
import PolygonLayer from './polygon';
|
||||
import RasterLayer from './raster';
|
||||
|
||||
import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin';
|
||||
// import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin';
|
||||
import DataMappingPlugin from './plugins/DataMappingPlugin';
|
||||
import DataSourcePlugin from './plugins/DataSourcePlugin';
|
||||
import FeatureScalePlugin from './plugins/FeatureScalePlugin';
|
||||
|
@ -27,10 +27,10 @@ import UpdateStyleAttributePlugin from './plugins/UpdateStyleAttributePlugin';
|
|||
* 校验传入参数配置项的正确性
|
||||
* @see /dev-docs/ConfigSchemaValidation.md
|
||||
*/
|
||||
container
|
||||
.bind<ILayerPlugin>(TYPES.ILayerPlugin)
|
||||
.to(ConfigSchemaValidationPlugin)
|
||||
.inRequestScope();
|
||||
// container
|
||||
// .bind<ILayerPlugin>(TYPES.ILayerPlugin)
|
||||
// .to(ConfigSchemaValidationPlugin)
|
||||
// .inRequestScope();
|
||||
/**
|
||||
* 获取 Source
|
||||
*/
|
||||
|
|
|
@ -12,7 +12,7 @@ import BaseModel from '../../core/BaseModel';
|
|||
import { ILineLayerStyleOptions, lineStyleType } from '../../core/interface';
|
||||
import { LineArcTriangulation } from '../../core/triangulation';
|
||||
import line_arc_frag from '../shaders/line_arc_frag.glsl';
|
||||
import line_arc2d_vert from '../shaders/line_bezier_vert.glsl';
|
||||
import line_arc2d_vert from '../shaders/line_arc_vert.glsl';
|
||||
const lineStyleObj: { [key: string]: number } = {
|
||||
solid: 0.0,
|
||||
dash: 1.0,
|
||||
|
|
|
@ -10,8 +10,8 @@ import {
|
|||
import BaseModel from '../../core/BaseModel';
|
||||
import { ILineLayerStyleOptions, lineStyleType } from '../../core/interface';
|
||||
import { LineArcTriangulation } from '../../core/triangulation';
|
||||
import line_arc_vert from '../shaders/line_arc_3d_vert.glsl';
|
||||
import line_arc_frag from '../shaders/line_arc_frag.glsl';
|
||||
import line_arc_vert from '../shaders/line_arc_vert.glsl';
|
||||
const lineStyleObj: { [key: string]: number } = {
|
||||
solid: 0.0,
|
||||
dash: 1.0,
|
||||
|
|
|
@ -11,8 +11,8 @@ import {
|
|||
import BaseModel from '../../core/BaseModel';
|
||||
import { ILineLayerStyleOptions, lineStyleType } from '../../core/interface';
|
||||
import { LineArcTriangulation } from '../../core/triangulation';
|
||||
import line_arc2d_vert from '../shaders/line_arc2d_vert.glsl';
|
||||
import line_arc_frag from '../shaders/line_arc_frag.glsl';
|
||||
import line_arc2d_vert from '../shaders/line_arc_great_circle_vert.glsl';
|
||||
const lineStyleObj: { [key: string]: number } = {
|
||||
solid: 0.0,
|
||||
dash: 1.0,
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
#define LineTypeSolid 0.0
|
||||
#define LineTypeDash 1.0
|
||||
#define Animate 0.0
|
||||
attribute vec3 a_Position;
|
||||
attribute vec4 a_Instance;
|
||||
attribute vec4 a_Color;
|
||||
attribute float a_Size;
|
||||
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform float segmentNumber;
|
||||
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_normal;
|
||||
varying float v_distance_ratio;
|
||||
uniform float u_line_type: 0.0;
|
||||
uniform vec2 u_dash_array: [10.0, 5.];
|
||||
|
||||
varying vec2 v_dash_array;
|
||||
|
||||
#pragma include "projection"
|
||||
#pragma include "project"
|
||||
#pragma include "picking"
|
||||
|
||||
float maps (float value, float start1, float stop1, float start2, float stop2) {
|
||||
return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));
|
||||
}
|
||||
|
||||
float getSegmentRatio(float index) {
|
||||
return smoothstep(0.0, 1.0, index / (segmentNumber - 1.0));
|
||||
}
|
||||
|
||||
float paraboloid(vec2 source, vec2 target, float ratio) {
|
||||
vec2 x = mix(source, target, ratio);
|
||||
vec2 center = mix(source, target, 0.5);
|
||||
float dSourceCenter = distance(source, center);
|
||||
float dXCenter = distance(x, center);
|
||||
return (dSourceCenter + dXCenter) * (dSourceCenter - dXCenter);
|
||||
}
|
||||
|
||||
vec3 getPos(vec2 source, vec2 target, float segmentRatio) {
|
||||
float vertex_height = paraboloid(source, target, segmentRatio);
|
||||
|
||||
return vec3(
|
||||
mix(source, target, segmentRatio),
|
||||
sqrt(max(0.0, vertex_height))
|
||||
);
|
||||
}
|
||||
vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) {
|
||||
// normalized direction of the line
|
||||
vec2 dir_screenspace = normalize(line_clipspace);
|
||||
// rotate by 90 degrees
|
||||
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
|
||||
|
||||
vec2 offset = dir_screenspace * offset_direction * a_Size / 2.0;
|
||||
|
||||
return offset;
|
||||
}
|
||||
vec2 getNormal(vec2 line_clipspace, float offset_direction) {
|
||||
// normalized direction of the line
|
||||
vec2 dir_screenspace = normalize(line_clipspace);
|
||||
// rotate by 90 degrees
|
||||
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
|
||||
return reverse_offset_normal(vec3(dir_screenspace,1.0)).xy * sign(offset_direction);
|
||||
}
|
||||
|
||||
void main() {
|
||||
v_color = a_Color;
|
||||
vec2 source = project_position(vec4(a_Instance.rg, 0, 0)).xy;
|
||||
vec2 target = project_position(vec4(a_Instance.ba, 0, 0)).xy;
|
||||
float segmentIndex = a_Position.x;
|
||||
float segmentRatio = getSegmentRatio(segmentIndex);
|
||||
float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
|
||||
|
||||
if(u_line_type == LineTypeDash) {
|
||||
v_distance_ratio = segmentIndex / segmentNumber;
|
||||
float total_Distance = pixelDistance(a_Instance.rg, a_Instance.ba) / 2.0 * PI;
|
||||
v_dash_array = pow(2.0, 20.0 - u_Zoom) * u_dash_array / (total_Distance / segmentNumber * segmentIndex);
|
||||
}
|
||||
if(u_aimate.x == Animate) {
|
||||
v_distance_ratio = segmentIndex / segmentNumber;
|
||||
}
|
||||
|
||||
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
|
||||
vec3 curr = getPos(source, target, segmentRatio);
|
||||
vec3 next = getPos(source, target, nextSegmentRatio);
|
||||
vec2 offset = getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y);
|
||||
v_normal = getNormal((next.xy - curr.xy) * indexDir, a_Position.y);
|
||||
|
||||
gl_Position = project_common_position_to_clipspace(vec4(curr.xy + project_pixel(offset), curr.z, 1.0));
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
|
@ -18,7 +18,7 @@ uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
|||
void main() {
|
||||
gl_FragColor = v_color;
|
||||
float blur = 1.- smoothstep(u_blur, 1., length(v_normal.xy));
|
||||
gl_FragColor.a *= (blur * u_opacity);
|
||||
gl_FragColor.a *= u_opacity * blur;
|
||||
if(u_line_type == LineTypeDash) {
|
||||
gl_FragColor.a *= blur * (1.0- step(v_dash_array.x, mod(v_distance_ratio, v_dash_array.x +v_dash_array.y)));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
#define LineTypeSolid 0.0
|
||||
#define LineTypeDash 1.0
|
||||
#define Animate 0.0
|
||||
attribute vec4 a_Color;
|
||||
attribute vec3 a_Position;
|
||||
attribute vec4 a_Instance;
|
||||
attribute float a_Size;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform float segmentNumber;
|
||||
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_normal;
|
||||
|
||||
varying float v_distance_ratio;
|
||||
uniform float u_line_type: 0.0;
|
||||
uniform vec2 u_dash_array: [10.0, 5.];
|
||||
varying vec2 v_dash_array;
|
||||
|
||||
#pragma include "projection"
|
||||
#pragma include "project"
|
||||
#pragma include "picking"
|
||||
|
||||
float maps (float value, float start1, float stop1, float start2, float stop2) {
|
||||
return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));
|
||||
}
|
||||
|
||||
float getSegmentRatio(float index) {
|
||||
return smoothstep(0.0, 1.0, index / (segmentNumber - 1.));
|
||||
}
|
||||
|
||||
float paraboloid(vec2 source, vec2 target, float ratio) {
|
||||
vec2 x = mix(source, target, ratio);
|
||||
vec2 center = mix(source, target, 0.5);
|
||||
float dSourceCenter = distance(source, center);
|
||||
float dXCenter = distance(x, center);
|
||||
return (dSourceCenter + dXCenter) * (dSourceCenter - dXCenter);
|
||||
}
|
||||
|
||||
vec3 getPos(vec2 source, vec2 target, float segmentRatio) {
|
||||
float vertex_height = paraboloid(source, target, segmentRatio);
|
||||
|
||||
return vec3(
|
||||
mix(source, target, segmentRatio),
|
||||
sqrt(max(0.0, vertex_height))
|
||||
);
|
||||
}
|
||||
vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) {
|
||||
// normalized direction of the line
|
||||
vec2 dir_screenspace = normalize(line_clipspace);
|
||||
// rotate by 90 degrees
|
||||
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
|
||||
vec2 offset = dir_screenspace * offset_direction * a_Size / 2.0;
|
||||
return offset;
|
||||
}
|
||||
vec2 getNormal(vec2 line_clipspace, float offset_direction) {
|
||||
// normalized direction of the line
|
||||
vec2 dir_screenspace = normalize(line_clipspace);
|
||||
// rotate by 90 degrees
|
||||
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
|
||||
return reverse_offset_normal(vec3(dir_screenspace,1.0)).xy * sign(offset_direction);
|
||||
}
|
||||
float getAngularDist (vec2 source, vec2 target) {
|
||||
vec2 delta = source - target;
|
||||
vec2 sin_half_delta = sin(delta / 2.0);
|
||||
float a =
|
||||
sin_half_delta.y * sin_half_delta.y +
|
||||
cos(source.y) * cos(target.y) *
|
||||
sin_half_delta.x * sin_half_delta.x;
|
||||
return 2.0 * atan(sqrt(a), sqrt(1.0 - a));
|
||||
}
|
||||
vec2 interpolate (vec2 source, vec2 target, float angularDist, float t) {
|
||||
// if the angularDist is PI, linear interpolation is applied. otherwise, use spherical interpolation
|
||||
if(abs(angularDist - PI) < 0.001) {
|
||||
return (1.0 - t) * source + t * target;
|
||||
}
|
||||
float a = sin((1.0 - t) * angularDist) / sin(angularDist);
|
||||
float b = sin(t * angularDist) / sin(angularDist);
|
||||
vec2 sin_source = sin(source);
|
||||
vec2 cos_source = cos(source);
|
||||
vec2 sin_target = sin(target);
|
||||
vec2 cos_target = cos(target);
|
||||
float x = a * cos_source.y * cos_source.x + b * cos_target.y * cos_target.x;
|
||||
float y = a * cos_source.y * sin_source.x + b * cos_target.y * sin_target.x;
|
||||
float z = a * sin_source.y + b * sin_target.y;
|
||||
return vec2(atan(y, x), atan(z, sqrt(x * x + y * y)));
|
||||
}
|
||||
|
||||
void main() {
|
||||
v_color = a_Color;
|
||||
vec2 source = radians(a_Instance.rg);
|
||||
vec2 target = radians(a_Instance.ba);
|
||||
float angularDist = getAngularDist(source, target);
|
||||
float segmentIndex = a_Position.x;
|
||||
float segmentRatio = getSegmentRatio(segmentIndex);
|
||||
float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
|
||||
if(u_line_type == LineTypeDash) {
|
||||
v_distance_ratio = segmentIndex / segmentNumber;
|
||||
float total_Distance = pixelDistance(a_Instance.rg, a_Instance.ba);
|
||||
v_dash_array = pow(2.0, 20.0 - u_Zoom) * u_dash_array / (total_Distance / segmentNumber * segmentIndex);
|
||||
}
|
||||
if(u_aimate.x == Animate) {
|
||||
v_distance_ratio = segmentIndex / segmentNumber;
|
||||
}
|
||||
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
|
||||
v_distance_ratio = segmentIndex / segmentNumber;
|
||||
vec4 curr = project_position(vec4(degrees(interpolate(source, target, angularDist, segmentRatio)), 0.0, 1.0));
|
||||
vec4 next = project_position(vec4(degrees(interpolate(source, target, angularDist, nextSegmentRatio)), 0.0, 1.0));
|
||||
v_normal = getNormal((next.xy - curr.xy) * indexDir, a_Position.y);
|
||||
vec2 offset = project_pixel(getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y));
|
||||
// vec4 project_pos = project_position(vec4(curr.xy, 0, 1.0));
|
||||
gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, curr.z, 1.0));
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
@ -1,91 +1,85 @@
|
|||
#define LineTypeSolid 0.0
|
||||
#define LineTypeDash 1.0
|
||||
#define Animate 0.0
|
||||
attribute vec4 a_Color;
|
||||
attribute vec3 a_Position;
|
||||
attribute vec4 a_Instance;
|
||||
attribute vec4 a_Color;
|
||||
attribute float a_Size;
|
||||
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform float segmentNumber;
|
||||
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_normal;
|
||||
|
||||
varying float v_distance_ratio;
|
||||
uniform float u_line_type: 0.0;
|
||||
uniform vec2 u_dash_array: [10.0, 5.];
|
||||
|
||||
varying vec2 v_dash_array;
|
||||
|
||||
#pragma include "projection"
|
||||
#pragma include "project"
|
||||
#pragma include "picking"
|
||||
|
||||
float maps (float value, float start1, float stop1, float start2, float stop2) {
|
||||
return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));
|
||||
float bezier3(vec3 arr, float t) {
|
||||
float ut = 1. - t;
|
||||
return (arr.x * ut + arr.y * t) * ut + (arr.y * ut + arr.z * t) * t;
|
||||
}
|
||||
vec2 midPoint(vec2 source, vec2 target) {
|
||||
vec2 center = target - source;
|
||||
float r = length(center);
|
||||
float theta = atan(center.y, center.x);
|
||||
float thetaOffset = 0.314;
|
||||
float r2 = r / 2.0 / cos(thetaOffset);
|
||||
float theta2 = theta + thetaOffset;
|
||||
vec2 mid = vec2(r2*cos(theta2) + source.x, r2*sin(theta2) + source.y);
|
||||
return mid;
|
||||
}
|
||||
|
||||
float getSegmentRatio(float index) {
|
||||
return smoothstep(0.0, 1.0, index / (segmentNumber - 1.0));
|
||||
return smoothstep(0.0, 1.0, index / (segmentNumber - 1.));
|
||||
}
|
||||
|
||||
float paraboloid(vec2 source, vec2 target, float ratio) {
|
||||
vec2 x = mix(source, target, ratio);
|
||||
vec2 center = mix(source, target, 0.5);
|
||||
float dSourceCenter = distance(source, center);
|
||||
float dXCenter = distance(x, center);
|
||||
return (dSourceCenter + dXCenter) * (dSourceCenter - dXCenter);
|
||||
}
|
||||
|
||||
vec3 getPos(vec2 source, vec2 target, float segmentRatio) {
|
||||
float vertex_height = paraboloid(source, target, segmentRatio);
|
||||
|
||||
return vec3(
|
||||
mix(source, target, segmentRatio),
|
||||
sqrt(max(0.0, vertex_height))
|
||||
);
|
||||
vec2 interpolate (vec2 source, vec2 target, float t) {
|
||||
// if the angularDist is PI, linear interpolation is applied. otherwise, use spherical interpolation
|
||||
vec2 mid = midPoint(source, target);
|
||||
vec3 x = vec3(source.x, mid.x, target.x);
|
||||
vec3 y = vec3(source.y, mid.y, target.y);
|
||||
return vec2(bezier3(x ,t), bezier3(y,t));
|
||||
}
|
||||
vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) {
|
||||
// normalized direction of the line
|
||||
vec2 dir_screenspace = normalize(line_clipspace);
|
||||
// rotate by 90 degrees
|
||||
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
|
||||
|
||||
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
|
||||
vec2 offset = dir_screenspace * offset_direction * a_Size / 2.0;
|
||||
|
||||
return offset;
|
||||
}
|
||||
vec2 getNormal(vec2 line_clipspace, float offset_direction) {
|
||||
// normalized direction of the line
|
||||
vec2 dir_screenspace = normalize(line_clipspace);
|
||||
// rotate by 90 degrees
|
||||
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
|
||||
return reverse_offset_normal(vec3(dir_screenspace,1.0)).xy * sign(offset_direction);
|
||||
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
|
||||
return reverse_offset_normal(vec3(dir_screenspace,1.0)).xy * sign(offset_direction);
|
||||
}
|
||||
|
||||
void main() {
|
||||
v_color = a_Color;
|
||||
vec2 source = project_position(vec4(a_Instance.rg, 0, 0)).xy;
|
||||
vec2 target = project_position(vec4(a_Instance.ba, 0, 0)).xy;
|
||||
vec2 source = a_Instance.rg;
|
||||
vec2 target = a_Instance.ba;
|
||||
float segmentIndex = a_Position.x;
|
||||
float segmentRatio = getSegmentRatio(segmentIndex);
|
||||
float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
|
||||
|
||||
if(u_line_type == LineTypeDash) {
|
||||
v_distance_ratio = segmentIndex / segmentNumber;
|
||||
float total_Distance = pixelDistance(a_Instance.rg, a_Instance.ba) / 2.0 * PI;
|
||||
v_dash_array = pow(2.0, 20.0 - u_Zoom) * u_dash_array / (total_Distance / segmentNumber * segmentIndex);
|
||||
}
|
||||
if(u_aimate.x == Animate) {
|
||||
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
|
||||
if(u_line_type == LineTypeDash) {
|
||||
v_distance_ratio = segmentIndex / segmentNumber;
|
||||
float total_Distance = pixelDistance(a_Instance.rg, a_Instance.ba) / 2.0 * PI;
|
||||
v_dash_array = pow(2.0, 20.0 - u_Zoom) * u_dash_array / (total_Distance / segmentNumber * segmentIndex);
|
||||
}
|
||||
if(u_aimate.x == Animate) {
|
||||
v_distance_ratio = segmentIndex / segmentNumber;
|
||||
}
|
||||
|
||||
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
|
||||
vec3 curr = getPos(source, target, segmentRatio);
|
||||
vec3 next = getPos(source, target, nextSegmentRatio);
|
||||
vec2 offset = getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y);
|
||||
vec4 curr = project_position(vec4(interpolate(source, target, segmentRatio), 0.0, 1.0));
|
||||
vec4 next = project_position(vec4(interpolate(source, target, nextSegmentRatio), 0.0, 1.0));
|
||||
v_normal = getNormal((next.xy - curr.xy) * indexDir, a_Position.y);
|
||||
vec2 offset = project_pixel(getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y));
|
||||
|
||||
gl_Position = project_common_position_to_clipspace(vec4(curr.xy + project_pixel(offset), curr.z, 1.0));
|
||||
gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, 0, 1.0));
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ void main() {
|
|||
}
|
||||
v_normal = vec2(reverse_offset_normal(a_Normal) * sign(a_Miter));
|
||||
v_color = a_Color;
|
||||
vec3 size = a_Miter * a_Size.x * reverse_offset_normal(a_Normal); //v_normal * vec3(1., -1., 1.0);
|
||||
vec3 size = a_Miter * a_Size.x * reverse_offset_normal(a_Normal);
|
||||
vec2 offset = project_pixel(size.xy);
|
||||
v_side = a_Miter * a_Size.x;
|
||||
vec4 project_pos = project_position(vec4(a_Position.xy, 0, 1.0));
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
import {
|
||||
IGlobalConfigService,
|
||||
ILayer,
|
||||
ILayerPlugin,
|
||||
ILogService,
|
||||
TYPES,
|
||||
} from '@antv/l7-core';
|
||||
import { inject, injectable } from 'inversify';
|
||||
// import {
|
||||
// IGlobalConfigService,
|
||||
// ILayer,
|
||||
// ILayerPlugin,
|
||||
// ILogService,
|
||||
// TYPES,
|
||||
// } from '@antv/l7-core';
|
||||
// import { inject, injectable } from 'inversify';
|
||||
|
||||
/**
|
||||
* Layer 初始化阶段以及重绘阶段首先校验传入参数,如果校验失败则中断后续插件处理。
|
||||
*/
|
||||
@injectable()
|
||||
export default class ConfigSchemaValidationPlugin implements ILayerPlugin {
|
||||
@inject(TYPES.IGlobalConfigService)
|
||||
private readonly configService: IGlobalConfigService;
|
||||
// /**
|
||||
// * Layer 初始化阶段以及重绘阶段首先校验传入参数,如果校验失败则中断后续插件处理。
|
||||
// */
|
||||
// @injectable()
|
||||
// export default class ConfigSchemaValidationPlugin implements ILayerPlugin {
|
||||
// @inject(TYPES.IGlobalConfigService)
|
||||
// private readonly configService: IGlobalConfigService;
|
||||
|
||||
@inject(TYPES.ILogService)
|
||||
private readonly logger: ILogService;
|
||||
// @inject(TYPES.ILogService)
|
||||
// private readonly logger: ILogService;
|
||||
|
||||
public apply(layer: ILayer) {
|
||||
layer.hooks.init.tap('ConfigSchemaValidationPlugin', () => {
|
||||
this.configService.registerLayerConfigSchemaValidator(
|
||||
layer.name as string,
|
||||
layer.getConfigSchemaForValidation(),
|
||||
);
|
||||
// public apply(layer: ILayer) {
|
||||
// layer.hooks.init.tap('ConfigSchemaValidationPlugin', () => {
|
||||
// this.configService.registerLayerConfigSchemaValidator(
|
||||
// layer.name as string,
|
||||
// layer.getConfigSchemaForValidation(),
|
||||
// );
|
||||
|
||||
const { valid, errorText } = this.configService.validateLayerConfig(
|
||||
layer.name as string,
|
||||
layer.getLayerConfig(),
|
||||
);
|
||||
// const { valid, errorText } = this.configService.validateLayerConfig(
|
||||
// layer.name as string,
|
||||
// layer.getLayerConfig(),
|
||||
// );
|
||||
|
||||
if (!valid) {
|
||||
this.logger.error(errorText || '');
|
||||
// 中断 init 过程
|
||||
return false;
|
||||
}
|
||||
});
|
||||
layer.hooks.beforeRender.tap('ConfigSchemaValidationPlugin', () => {
|
||||
// TODO: 配置项发生变化,需要重新校验
|
||||
});
|
||||
}
|
||||
}
|
||||
// if (!valid) {
|
||||
// this.logger.error(errorText || '');
|
||||
// // 中断 init 过程
|
||||
// return false;
|
||||
// }
|
||||
// });
|
||||
// layer.hooks.beforeRender.tap('ConfigSchemaValidationPlugin', () => {
|
||||
// // TODO: 配置项发生变化,需要重新校验
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -27,27 +27,45 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
|||
}: { styleAttributeService: IStyleAttributeService },
|
||||
) {
|
||||
layer.hooks.init.tap('DataMappingPlugin', () => {
|
||||
// 初始化重新生成 map
|
||||
this.generateMaping(layer, { styleAttributeService });
|
||||
});
|
||||
|
||||
layer.hooks.beforeRenderData.tap('DataMappingPlugin', (flag) => {
|
||||
if (flag || layer.dataState.dataMappingNeedUpdate) {
|
||||
layer.dataState.dataMappingNeedUpdate = false;
|
||||
this.generateMaping(layer, { styleAttributeService });
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
layer.hooks.beforeRenderData.tap('DataMappingPlugin', () => {
|
||||
layer.dataState.dataMappingNeedUpdate = false;
|
||||
this.generateMaping(layer, { styleAttributeService });
|
||||
return true;
|
||||
});
|
||||
|
||||
// remapping before render
|
||||
layer.hooks.beforeRender.tap('DataMappingPlugin', () => {
|
||||
const attributes = styleAttributeService.getLayerStyleAttributes() || [];
|
||||
const filter = styleAttributeService.getLayerStyleAttribute('filter');
|
||||
const { dataArray } = layer.getSource().data;
|
||||
const attributesToRemapping = attributes.filter(
|
||||
(attribute) => attribute.needRemapping,
|
||||
(attribute) => attribute.needRemapping, // 如果filter变化
|
||||
);
|
||||
let filterData = dataArray;
|
||||
// 数据过滤完 再执行数据映射
|
||||
if (filter?.needRemapping && filter?.scale) {
|
||||
filterData = dataArray.filter((record: IParseDataItem) => {
|
||||
return this.applyAttributeMapping(filter, record)[0];
|
||||
});
|
||||
}
|
||||
if (attributesToRemapping.length) {
|
||||
layer.setEncodedData(this.mapping(attributesToRemapping, dataArray));
|
||||
// 过滤数据
|
||||
if (filter?.needRemapping) {
|
||||
layer.setEncodedData(this.mapping(attributes, filterData));
|
||||
} else {
|
||||
layer.setEncodedData(
|
||||
this.mapping(
|
||||
attributesToRemapping,
|
||||
filterData,
|
||||
layer.getEncodedData(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.debug('remapping finished');
|
||||
}
|
||||
});
|
||||
|
@ -62,17 +80,16 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
|||
const filter = styleAttributeService.getLayerStyleAttribute('filter');
|
||||
const { dataArray } = layer.getSource().data;
|
||||
let filterData = dataArray;
|
||||
// 数据过滤完 在执行数据映射
|
||||
// 数据过滤完 再执行数据映射
|
||||
if (filter?.scale) {
|
||||
filterData = dataArray.filter((record: IParseDataItem) => {
|
||||
return this.applyAttributeMapping(filter, record)[0];
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: FIXME
|
||||
if (!filterData) {
|
||||
return;
|
||||
}
|
||||
// if (!filterData) {
|
||||
// return;
|
||||
// }
|
||||
// mapping with source data
|
||||
layer.setEncodedData(this.mapping(attributes, filterData));
|
||||
}
|
||||
|
@ -80,11 +97,14 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
|||
private mapping(
|
||||
attributes: IStyleAttribute[],
|
||||
data: IParseDataItem[],
|
||||
predata?: IEncodeFeature[],
|
||||
): IEncodeFeature[] {
|
||||
return data.map((record: IParseDataItem) => {
|
||||
return data.map((record: IParseDataItem, i) => {
|
||||
const preRecord = predata ? predata[i] : {};
|
||||
const encodeRecord: IEncodeFeature = {
|
||||
id: record._id,
|
||||
coordinates: record.coordinates,
|
||||
...preRecord,
|
||||
};
|
||||
attributes
|
||||
.filter((attribute) => attribute.scale !== undefined)
|
||||
|
|
|
@ -10,14 +10,11 @@ export default class DataSourcePlugin implements ILayerPlugin {
|
|||
layer.hooks.init.tap('DataSourcePlugin', () => {
|
||||
const { data, options } = layer.sourceOption;
|
||||
layer.setSource(new Source(data, options));
|
||||
// if (layer.getSource().data.dataArray.length === 0) {
|
||||
// return true;
|
||||
// }
|
||||
this.updateClusterData(layer);
|
||||
});
|
||||
|
||||
// 检测数据不否需要更新
|
||||
layer.hooks.beforeRenderData.tap('DataSourcePlugin', (flag) => {
|
||||
layer.hooks.beforeRenderData.tap('DataSourcePlugin', () => {
|
||||
const neeUpdate1 = this.updateClusterData(layer);
|
||||
const neeUpdate2 = layer.dataState.dataSourceNeedUpdate;
|
||||
layer.dataState.dataSourceNeedUpdate = false;
|
||||
|
|
|
@ -64,16 +64,13 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
|||
this.caculateScalesForAttributes(attributes || [], dataArray);
|
||||
});
|
||||
|
||||
// 检测数据是不否需要更新
|
||||
layer.hooks.beforeRenderData.tap('FeatureScalePlugin', (flag) => {
|
||||
if (flag) {
|
||||
this.scaleOptions = layer.getScaleOptions();
|
||||
const attributes = styleAttributeService.getLayerStyleAttributes();
|
||||
const { dataArray } = layer.getSource().data;
|
||||
this.caculateScalesForAttributes(attributes || [], dataArray);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
// 检测数据是否需要更新
|
||||
layer.hooks.beforeRenderData.tap('FeatureScalePlugin', () => {
|
||||
this.scaleOptions = layer.getScaleOptions();
|
||||
const attributes = styleAttributeService.getLayerStyleAttributes();
|
||||
const { dataArray } = layer.getSource().data;
|
||||
this.caculateScalesForAttributes(attributes || [], dataArray);
|
||||
return true;
|
||||
});
|
||||
|
||||
layer.hooks.beforeRender.tap('FeatureScalePlugin', () => {
|
||||
|
@ -146,6 +143,7 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
|||
return {
|
||||
field: scale.field,
|
||||
func: scale.scale,
|
||||
option: scale.option,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -160,13 +158,17 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
|||
) {
|
||||
const scalekey = [field, attribute.name].join('_');
|
||||
const values = attribute.scale?.values;
|
||||
if (this.scaleCache[scalekey]) {
|
||||
return this.scaleCache[scalekey];
|
||||
}
|
||||
const styleScale = this.createScale(field, values, dataArray);
|
||||
this.scaleCache[scalekey] = styleScale;
|
||||
|
||||
return this.scaleCache[scalekey];
|
||||
// if (this.scaleCache[scalekey]) {
|
||||
// return this.scaleCache[scalekey];
|
||||
// }
|
||||
const styleScale = this.createScale(
|
||||
field,
|
||||
attribute.name,
|
||||
values,
|
||||
dataArray,
|
||||
);
|
||||
// this.scaleCache[scalekey] = styleScale;
|
||||
return styleScale;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -188,11 +190,15 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
|||
|
||||
private createScale(
|
||||
field: string | number,
|
||||
name: string,
|
||||
values: unknown[] | string | undefined,
|
||||
data?: IParseDataItem[],
|
||||
): IStyleScale {
|
||||
// 首先查找全局默认配置例如 color
|
||||
const scaleOption: IScale | undefined = this.scaleOptions[field];
|
||||
// scale 支持根据视觉通道和字段
|
||||
const scaleOption: IScale | undefined =
|
||||
this.scaleOptions[name] && this.scaleOptions[name].field === field
|
||||
? this.scaleOptions[name]
|
||||
: this.scaleOptions[field];
|
||||
const styleScale: IStyleScale = {
|
||||
field,
|
||||
scale: undefined,
|
||||
|
|
|
@ -13,13 +13,12 @@ export default class LayerModelPlugin implements ILayerPlugin {
|
|||
layer.buildModels();
|
||||
});
|
||||
|
||||
layer.hooks.beforeRenderData.tap('DataSourcePlugin', (flag) => {
|
||||
layer.hooks.beforeRenderData.tap('DataSourcePlugin', () => {
|
||||
// 更新Model 配置项
|
||||
if (flag) {
|
||||
layer.prepareBuildModel();
|
||||
// 初始化 Model
|
||||
layer.buildModels();
|
||||
}
|
||||
layer.prepareBuildModel();
|
||||
// 初始化 Model
|
||||
layer.buildModels();
|
||||
layer.layerModelNeedUpdate = false;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -76,11 +76,11 @@ export default class MultiPassRendererPlugin implements ILayerPlugin {
|
|||
});
|
||||
|
||||
layer.hooks.beforeRender.tap('MultiPassRendererPlugin', () => {
|
||||
if (this.enabled) {
|
||||
// 渲染前根据 viewport 调整 FBO size
|
||||
const { width, height } = rendererService.getViewportSize();
|
||||
layer.multiPassRenderer.resize(width, height);
|
||||
}
|
||||
// if (this.enabled) {
|
||||
// // 渲染前根据 viewport 调整 FBO size
|
||||
// const { width, height } = rendererService.getViewportSize();
|
||||
// layer.multiPassRenderer.resize(width, height);
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -103,26 +103,26 @@ export default class MultiPassRendererPlugin implements ILayerPlugin {
|
|||
}
|
||||
|
||||
// use TAA pass if enabled instead of render pass
|
||||
if (enableTAA) {
|
||||
multiPassRenderer.add(normalPassFactory('taa'));
|
||||
} else {
|
||||
// render all layers in this pass
|
||||
multiPassRenderer.add(normalPassFactory('render'));
|
||||
}
|
||||
// if (enableTAA) {
|
||||
// multiPassRenderer.add(normalPassFactory('taa'));
|
||||
// } else {
|
||||
// // render all layers in this pass
|
||||
// multiPassRenderer.add(normalPassFactory('render'));
|
||||
// }
|
||||
|
||||
// post processing
|
||||
normalizePasses(passes).forEach(
|
||||
(pass: [string, { [key: string]: unknown }]) => {
|
||||
const [passName, initializationOptions] = pass;
|
||||
multiPassRenderer.add(
|
||||
postProcessingPassFactory(passName),
|
||||
initializationOptions,
|
||||
);
|
||||
},
|
||||
);
|
||||
// normalizePasses(passes).forEach(
|
||||
// (pass: [string, { [key: string]: unknown }]) => {
|
||||
// const [passName, initializationOptions] = pass;
|
||||
// multiPassRenderer.add(
|
||||
// postProcessingPassFactory(passName),
|
||||
// initializationOptions,
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
|
||||
// 末尾为固定的 CopyPass
|
||||
multiPassRenderer.add(postProcessingPassFactory('copy'));
|
||||
// multiPassRenderer.add(postProcessingPassFactory('copy'));
|
||||
|
||||
return multiPassRenderer;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ export default class ShaderUniformPlugin implements ILayerPlugin {
|
|||
this.coordinateSystemService.refresh();
|
||||
|
||||
const { width, height } = this.rendererService.getViewportSize();
|
||||
|
||||
layer.models.forEach((model) =>
|
||||
model.addUniforms({
|
||||
// 相机参数,包含 VP 矩阵、缩放等级
|
||||
|
|
|
@ -9,6 +9,7 @@ export default class UpdateModelPlugin implements ILayerPlugin {
|
|||
layer.hooks.beforeRender.tap('UpdateModelPlugin', () => {
|
||||
// 处理文本更新
|
||||
if (layer.layerModel) {
|
||||
// console.log(layer.layerModelNeedUpdate);
|
||||
layer.layerModel.needUpdate();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -22,25 +22,21 @@ export default class UpdateStyleAttributePlugin implements ILayerPlugin {
|
|||
}: { styleAttributeService: IStyleAttributeService },
|
||||
) {
|
||||
layer.hooks.init.tap('UpdateStyleAttributePlugin', () => {
|
||||
this.updateStyleAtrribute(layer, { styleAttributeService });
|
||||
this.initStyleAttribute(layer, { styleAttributeService });
|
||||
});
|
||||
|
||||
layer.hooks.beforeRenderData.tap('styleAttributeService', (flag) => {
|
||||
if (flag) {
|
||||
// styleAttributeService.createAttributesAndIndices(
|
||||
// layer.getEncodedData(),
|
||||
// );
|
||||
layer.layerModelNeedUpdate = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
layer.hooks.beforeRenderData.tap('styleAttributeService', () => {
|
||||
layer.layerModelNeedUpdate = true;
|
||||
return true;
|
||||
});
|
||||
|
||||
layer.hooks.beforeRender.tap('UpdateStyleAttributePlugin', () => {
|
||||
if (layer.layerModelNeedUpdate) {
|
||||
return;
|
||||
}
|
||||
this.updateStyleAtrribute(layer, { styleAttributeService });
|
||||
});
|
||||
}
|
||||
|
||||
private updateStyleAtrribute(
|
||||
layer: ILayer,
|
||||
{
|
||||
|
@ -48,10 +44,20 @@ export default class UpdateStyleAttributePlugin implements ILayerPlugin {
|
|||
}: { styleAttributeService: IStyleAttributeService },
|
||||
) {
|
||||
const attributes = styleAttributeService.getLayerStyleAttributes() || [];
|
||||
const filter = styleAttributeService.getLayerStyleAttribute('filter');
|
||||
const shape = styleAttributeService.getLayerStyleAttribute('shape');
|
||||
if (
|
||||
(filter && filter.needRegenerateVertices) ||
|
||||
(shape && shape.needRegenerateVertices) // TODO:Shape 更新重新build
|
||||
) {
|
||||
layer.layerModelNeedUpdate = true;
|
||||
attributes.forEach((attr) => (attr.needRegenerateVertices = false));
|
||||
return;
|
||||
}
|
||||
attributes
|
||||
.filter((attribute) => attribute.needRegenerateVertices)
|
||||
.forEach((attribute) => {
|
||||
// 精确更新某个/某些 feature(s),需要传入 featureIdx
|
||||
// 精确更新某个/某些 feature(s),需要传入 featureIdx d
|
||||
styleAttributeService.updateAttributeByFeatureRange(
|
||||
attribute.name,
|
||||
layer.getEncodedData(), // 获取经过 mapping 最新的数据
|
||||
|
@ -64,4 +70,26 @@ export default class UpdateStyleAttributePlugin implements ILayerPlugin {
|
|||
);
|
||||
});
|
||||
}
|
||||
|
||||
private initStyleAttribute(
|
||||
layer: ILayer,
|
||||
{
|
||||
styleAttributeService,
|
||||
}: { styleAttributeService: IStyleAttributeService },
|
||||
) {
|
||||
const attributes = styleAttributeService.getLayerStyleAttributes() || [];
|
||||
attributes
|
||||
.filter((attribute) => attribute.needRegenerateVertices)
|
||||
.forEach((attribute) => {
|
||||
// 精确更新某个/某些 feature(s),需要传入 featureIdx d
|
||||
styleAttributeService.updateAttributeByFeatureRange(
|
||||
attribute.name,
|
||||
layer.getEncodedData(), // 获取经过 mapping 最新的数据
|
||||
attribute.featureRange.startIndex,
|
||||
attribute.featureRange.endIndex,
|
||||
);
|
||||
attribute.needRegenerateVertices = false;
|
||||
this.logger.debug(`init vertex attributes: ${attribute.name} finished`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ interface IPointLayerStyleOptions {
|
|||
opacity: number;
|
||||
strokeWidth: number;
|
||||
stroke: string;
|
||||
strokeOpacity: number;
|
||||
}
|
||||
export default class FillModel extends BaseModel {
|
||||
public getUninforms(): IModelUniform {
|
||||
|
@ -25,11 +26,13 @@ export default class FillModel extends BaseModel {
|
|||
opacity = 1,
|
||||
stroke = 'rgb(0,0,0,0)',
|
||||
strokeWidth = 1,
|
||||
strokeOpacity = 1,
|
||||
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
|
||||
return {
|
||||
u_opacity: opacity,
|
||||
u_stroke_width: strokeWidth,
|
||||
u_stroke_color: rgb2arr(stroke),
|
||||
u_stroke_opacity: strokeOpacity,
|
||||
};
|
||||
}
|
||||
public getAnimateUniforms(): IModelUniform {
|
||||
|
@ -84,7 +87,7 @@ export default class FillModel extends BaseModel {
|
|||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
) => {
|
||||
const extrude = [-1, -1, 1, -1, 1, 1, -1, 1];
|
||||
const extrude = [1, 1, -1, 1, -1, -1, 1, -1];
|
||||
const extrudeIndex = (attributeIdx % 4) * 2;
|
||||
return [extrude[extrudeIndex], extrude[extrudeIndex + 1]];
|
||||
},
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
IModelUniform,
|
||||
ITexture2D,
|
||||
} from '@antv/l7-core';
|
||||
import { rgb2arr } from '@antv/l7-utils';
|
||||
import { boundsContains, padBounds, rgb2arr } from '@antv/l7-utils';
|
||||
import BaseModel from '../../core/BaseModel';
|
||||
import CollisionIndex from '../../utils/collision-index';
|
||||
import { calculteCentroid } from '../../utils/geo';
|
||||
|
@ -84,18 +84,34 @@ export default class TextModel extends BaseModel {
|
|||
private glyphInfo: IEncodeFeature[];
|
||||
private currentZoom: number = -1;
|
||||
private extent: [[number, number], [number, number]];
|
||||
private textureHeight: number = 0;
|
||||
private textCount: number = 0;
|
||||
private preTextStyle: Partial<IPointTextLayerStyleOptions> = {};
|
||||
private glyphInfoMap: {
|
||||
[key: string]: {
|
||||
shaping: any;
|
||||
glyphQuads: IGlyphQuad[];
|
||||
centroid: number[];
|
||||
};
|
||||
} = {};
|
||||
|
||||
public getUninforms(): IModelUniform {
|
||||
const {
|
||||
fontWeight = 800,
|
||||
fontFamily = 'sans-serif',
|
||||
opacity = 1.0,
|
||||
stroke = '#fff',
|
||||
strokeWidth = 0,
|
||||
strokeOpacity = 1,
|
||||
textAnchor = 'center',
|
||||
textAllowOverlap = false,
|
||||
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||
this.updateTexture();
|
||||
const { canvas } = this.fontService;
|
||||
const { canvas, mapping } = this.fontService;
|
||||
if (Object.keys(mapping).length !== this.textCount) {
|
||||
this.updateTexture();
|
||||
}
|
||||
this.preTextStyle = {
|
||||
textAnchor,
|
||||
textAllowOverlap,
|
||||
};
|
||||
return {
|
||||
u_opacity: opacity,
|
||||
u_stroke_opacity: strokeOpacity,
|
||||
|
@ -109,6 +125,14 @@ export default class TextModel extends BaseModel {
|
|||
|
||||
public buildModels(): IModel[] {
|
||||
this.extent = this.textExtent();
|
||||
const {
|
||||
textAnchor = 'center',
|
||||
textAllowOverlap = true,
|
||||
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||
this.preTextStyle = {
|
||||
textAnchor,
|
||||
textAllowOverlap,
|
||||
};
|
||||
this.initGlyph();
|
||||
this.updateTexture();
|
||||
this.filterGlyphs();
|
||||
|
@ -127,15 +151,15 @@ export default class TextModel extends BaseModel {
|
|||
const {
|
||||
textAllowOverlap = false,
|
||||
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||
// textAllowOverlap 发生改变
|
||||
const zoom = this.mapService.getZoom();
|
||||
const extent = this.mapService.getBounds();
|
||||
const flag =
|
||||
extent[0][0] < this.extent[0][0] ||
|
||||
extent[0][1] < this.extent[0][1] ||
|
||||
extent[1][0] > this.extent[1][0] ||
|
||||
extent[1][1] < this.extent[1][1];
|
||||
|
||||
if (!textAllowOverlap && (Math.abs(this.currentZoom - zoom) > 1 || flag)) {
|
||||
const flag = boundsContains(this.extent, extent);
|
||||
// 文本不能压盖则进行过滤
|
||||
if (
|
||||
(!textAllowOverlap && (Math.abs(this.currentZoom - zoom) > 1 || !flag)) ||
|
||||
textAllowOverlap !== this.preTextStyle.textAllowOverlap
|
||||
) {
|
||||
this.filterGlyphs();
|
||||
this.layer.models = [
|
||||
this.layer.buildLayerModel({
|
||||
|
@ -227,12 +251,7 @@ export default class TextModel extends BaseModel {
|
|||
}
|
||||
private textExtent(): [[number, number], [number, number]] {
|
||||
const bounds = this.mapService.getBounds();
|
||||
const step =
|
||||
Math.min(bounds[1][0] - bounds[0][0], bounds[1][1] - bounds[1][0]) / 2;
|
||||
return [
|
||||
[bounds[0][0] - step, bounds[0][1] - step],
|
||||
[bounds[1][0] + step, bounds[1][1] + step],
|
||||
];
|
||||
return padBounds(bounds, 0.5);
|
||||
}
|
||||
/**
|
||||
* 生成文字纹理
|
||||
|
@ -240,7 +259,7 @@ export default class TextModel extends BaseModel {
|
|||
private initTextFont() {
|
||||
const {
|
||||
fontWeight = '800',
|
||||
fontFamily,
|
||||
fontFamily = 'sans-serif',
|
||||
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||
const data = this.layer.getEncodedData();
|
||||
const characterSet: string[] = [];
|
||||
|
@ -264,6 +283,7 @@ export default class TextModel extends BaseModel {
|
|||
* 生成文字布局
|
||||
*/
|
||||
private generateGlyphLayout() {
|
||||
// TODO:更新文字布局
|
||||
const { mapping } = this.fontService;
|
||||
const {
|
||||
spacing = 2,
|
||||
|
@ -272,7 +292,7 @@ export default class TextModel extends BaseModel {
|
|||
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||
const data = this.layer.getEncodedData();
|
||||
this.glyphInfo = data.map((feature: IEncodeFeature) => {
|
||||
const { shape = '', coordinates } = feature;
|
||||
const { shape = '', coordinates, id } = feature;
|
||||
const shaping = shapeText(
|
||||
shape.toString(),
|
||||
mapping,
|
||||
|
@ -286,6 +306,13 @@ export default class TextModel extends BaseModel {
|
|||
feature.shaping = shaping;
|
||||
feature.glyphQuads = glyphQuads;
|
||||
feature.centroid = calculteCentroid(coordinates);
|
||||
if (id) {
|
||||
this.glyphInfoMap[id] = {
|
||||
shaping,
|
||||
glyphQuads,
|
||||
centroid: calculteCentroid(coordinates),
|
||||
};
|
||||
}
|
||||
return feature;
|
||||
});
|
||||
}
|
||||
|
@ -298,6 +325,7 @@ export default class TextModel extends BaseModel {
|
|||
textAllowOverlap = false,
|
||||
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||
if (textAllowOverlap) {
|
||||
this.layer.setEncodedData(this.glyphInfo);
|
||||
return;
|
||||
}
|
||||
this.currentZoom = this.mapService.getZoom();
|
||||
|
@ -343,10 +371,26 @@ export default class TextModel extends BaseModel {
|
|||
private updateTexture() {
|
||||
const { createTexture2D } = this.rendererService;
|
||||
const { canvas } = this.fontService;
|
||||
this.textureHeight = canvas.height;
|
||||
this.texture = createTexture2D({
|
||||
data: canvas,
|
||||
width: canvas.width,
|
||||
height: canvas.height,
|
||||
});
|
||||
}
|
||||
|
||||
private rebuildModel() {
|
||||
// 避让 anchor,等属性变化时需要重新构建model
|
||||
this.filterGlyphs();
|
||||
return [
|
||||
this.layer.buildLayerModel({
|
||||
moduleName: 'pointText',
|
||||
vertexShader: textVert,
|
||||
fragmentShader: textFrag,
|
||||
triangulation: TextTriangulation,
|
||||
depth: { enable: false },
|
||||
blend: this.getBlend(),
|
||||
}),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
|
||||
uniform float u_opacity : 1;
|
||||
varying vec4 v_color;
|
||||
|
||||
#pragma include "picking"
|
||||
|
||||
void main() {
|
||||
gl_FragColor = v_color;
|
||||
gl_FragColor.a = u_opacity;
|
||||
gl_FragColor.a =gl_FragColor.a * u_opacity;
|
||||
|
||||
gl_FragColor = filterColor(gl_FragColor);
|
||||
}
|
||||
|
|
|
@ -4,14 +4,12 @@ uniform mat4 u_ModelMatrix;
|
|||
attribute float a_Size;
|
||||
attribute vec4 a_Color;
|
||||
varying vec4 v_color;
|
||||
|
||||
#pragma include "projection"
|
||||
#pragma include "picking"
|
||||
|
||||
void main() {
|
||||
v_color = a_Color;
|
||||
vec4 project_pos = project_position(vec4(a_Position, 1.0)) + vec4(a_Size / 2.,-a_Size /2.,0.,0.);
|
||||
gl_Position = project_common_position_to_clipspace(project_pos);
|
||||
gl_PointSize = a_Size * 2.0 * u_DevicePixelRatio;
|
||||
setPickingColor(a_PickingColor);
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -57,19 +57,7 @@ export default class RasterLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
|||
});
|
||||
this.models = [this.buildRasterModel()];
|
||||
}
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected renderModels() {
|
||||
public renderModels() {
|
||||
const { opacity, heightRatio = 10 } = this.getLayerConfig();
|
||||
const parserDataItem = this.getSource().data.dataArray[0];
|
||||
const { coordinates, width, height, min, max } = parserDataItem;
|
||||
|
@ -91,6 +79,18 @@ export default class RasterLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
|||
|
||||
return this;
|
||||
}
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private buildRasterModel() {
|
||||
const source = this.getSource();
|
||||
const sourceFeature = source.data.dataArray[0];
|
||||
|
|
|
@ -57,20 +57,7 @@ export default class Raster2dLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
|||
}),
|
||||
];
|
||||
}
|
||||
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected renderModels() {
|
||||
public renderModels() {
|
||||
const { opacity } = this.getLayerConfig();
|
||||
const parserDataItem = this.getSource().data.dataArray[0];
|
||||
const { min, max } = parserDataItem;
|
||||
|
@ -91,6 +78,18 @@ export default class Raster2dLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
|||
return this;
|
||||
}
|
||||
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private registerBuiltinAttributes() {
|
||||
// point layer size;
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
|
|
|
@ -17,8 +17,8 @@ export function computeNormal(out: vec2, dir: vec2) {
|
|||
return vec2.set(out, -dir[1], dir[0]);
|
||||
}
|
||||
export function direction(out: vec2, a: vec2, b: vec2) {
|
||||
const a1 = aProjectFlat([a[0], a[1]]);
|
||||
const b1 = aProjectFlat([b[0], b[1]]);
|
||||
const a1 = aProjectFlat([a[0], a[1]]) as [number, number];
|
||||
const b1 = aProjectFlat([b[0], b[1]]) as [number, number];
|
||||
vec2.sub(out, a1, b1);
|
||||
vec2.normalize(out, out);
|
||||
return out;
|
||||
|
@ -63,6 +63,7 @@ export default function(
|
|||
points: number[][],
|
||||
closed: boolean,
|
||||
indexOffset: number,
|
||||
isDash: boolean = true,
|
||||
) {
|
||||
const lineA = vec2.fromValues(0, 0);
|
||||
const lineB = vec2.fromValues(0, 0);
|
||||
|
@ -108,8 +109,11 @@ export default function(
|
|||
: null;
|
||||
}
|
||||
}
|
||||
const lineDistance = lineSegmentDistance(cur, last);
|
||||
const d = lineDistance + attrDistance[attrDistance.length - 1];
|
||||
let d = 0;
|
||||
if (isDash) {
|
||||
const lineDistance = lineSegmentDistance(cur, last);
|
||||
d = lineDistance + attrDistance[attrDistance.length - 1];
|
||||
}
|
||||
direction(lineA, cur, last);
|
||||
if (!lineNormal) {
|
||||
lineNormal = vec2.create();
|
||||
|
@ -218,15 +222,15 @@ export default function(
|
|||
attrPos[i * 3],
|
||||
attrPos[i * 3 + 1],
|
||||
attrPos[i * 3 + 2],
|
||||
attrDistance[i],
|
||||
attrDistance[i], // dash
|
||||
miters[i],
|
||||
totalDistance,
|
||||
totalDistance, // dash
|
||||
);
|
||||
}
|
||||
return {
|
||||
normals: out,
|
||||
attrIndex,
|
||||
attrPos: pickData, // [x,y,z, distance, miter ]
|
||||
attrPos: pickData, // [x,y,z, distance, miter ,tatal ]
|
||||
};
|
||||
}
|
||||
// [x,y,z, distance, miter ]
|
||||
|
|
|
@ -3,6 +3,17 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.0.34](https://github.com/antvis/L7/compare/v2.0.32...v2.0.34) (2020-03-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix map reference ([79e16f5](https://github.com/antvis/L7/commit/79e16f5393c6c31cc088e946dc865cdddfde9b73))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [2.0.0-beta.28](https://github.com/antvis/L7/compare/v2.0.0-beta.16...v2.0.0-beta.28) (2020-01-02)
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7-maps",
|
||||
"version": "2.0.17",
|
||||
"version": "2.0.34",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -23,21 +23,21 @@
|
|||
"author": "xiaoiver",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@antv/l7-core": "^2.0.17",
|
||||
"@antv/l7-utils": "^2.0.17",
|
||||
"@antv/l7-core": "^2.0.34",
|
||||
"@antv/l7-utils": "^2.0.34",
|
||||
"@babel/runtime": "^7.7.7",
|
||||
"@types/amap-js-api": "^1.4.6",
|
||||
"gl-matrix": "^3.1.0",
|
||||
"inversify": "^5.0.1",
|
||||
"mapbox-gl": "^1.2.1",
|
||||
"viewport-mercator-project": "^6.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/amap-js-api": "^1.4.6",
|
||||
"@types/gl-matrix": "^2.4.5",
|
||||
"@types/mapbox-gl": "^0.54.3",
|
||||
"@types/viewport-mercator-project": "^6.1.0"
|
||||
},
|
||||
"gitHead": "f2bd3c6473df79d815467b1677c6f985cf68800e",
|
||||
"gitHead": "a5d354b66873f700730248d015c5e539c54b34b7",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
|
|
|
@ -21,16 +21,16 @@ export default class BaseMapWrapper<RawMap> implements IMapWrapper {
|
|||
this.config = config;
|
||||
}
|
||||
|
||||
public setContainer(sceneContainer: Container, id: string) {
|
||||
public setContainer(sceneContainer: Container, id: string | HTMLDivElement) {
|
||||
// // 首先使用全局配置服务校验地图参数
|
||||
const { valid, errorText } = this.configService.validateMapConfig(
|
||||
this.config,
|
||||
);
|
||||
// const { valid, errorText } = this.configService.validateMapConfig(
|
||||
// this.config,
|
||||
// );
|
||||
|
||||
if (!valid) {
|
||||
this.logger.error(errorText || '');
|
||||
return;
|
||||
}
|
||||
// if (!valid) {
|
||||
// this.logger.error(errorText || '');
|
||||
// return;
|
||||
// }
|
||||
// 绑定用户传入的原始地图参数
|
||||
sceneContainer.bind<Partial<IMapConfig>>(TYPES.MapConfig).toConstantValue({
|
||||
...this.config,
|
||||
|
|
|
@ -22,6 +22,8 @@ import { IAMapEvent, IAMapInstance } from '../../typings/index';
|
|||
import { MapTheme } from './theme';
|
||||
import Viewport from './Viewport';
|
||||
let mapdivCount = 0;
|
||||
// @ts-ignore
|
||||
window.forceWebGL = true;
|
||||
|
||||
const AMAP_API_KEY: string = '15cd8a57710d40c9b7c0e3cc120f1200';
|
||||
const AMAP_VERSION: string = '1.4.15';
|
||||
|
@ -129,15 +131,13 @@ export default class AMapService
|
|||
lat: center.getLat(),
|
||||
};
|
||||
}
|
||||
|
||||
public setCenter(lnglat: [number, number]): void {
|
||||
this.map.setCenter(lnglat);
|
||||
}
|
||||
public getPitch(): number {
|
||||
return this.map.getPitch();
|
||||
}
|
||||
|
||||
public setPitch(pitch: number): void {
|
||||
return this.map.setPitch(pitch);
|
||||
}
|
||||
|
||||
public getRotation(): number {
|
||||
// 统一返回逆时针旋转角度
|
||||
return 360 - this.map.getRotation();
|
||||
|
@ -173,6 +173,9 @@ export default class AMapService
|
|||
return this.map.setRotation(rotation);
|
||||
}
|
||||
|
||||
public setPitch(pitch: number) {
|
||||
return this.map.setPitch(pitch);
|
||||
}
|
||||
public zoomIn(): void {
|
||||
this.map.zoomIn();
|
||||
}
|
||||
|
@ -244,6 +247,7 @@ export default class AMapService
|
|||
if (mapInstance) {
|
||||
this.map = mapInstance as AMap.Map & IAMapInstance;
|
||||
this.$mapContainer = this.map.getContainer();
|
||||
this.removeLogoControl();
|
||||
setTimeout(() => {
|
||||
this.map.on('camerachange', this.handleCameraChanged);
|
||||
resolve();
|
||||
|
@ -259,6 +263,10 @@ export default class AMapService
|
|||
viewMode: '3D',
|
||||
...rest,
|
||||
});
|
||||
map.on('complete', () => {
|
||||
this.removeLogoControl();
|
||||
});
|
||||
|
||||
// 监听地图相机事件
|
||||
map.on('camerachange', this.handleCameraChanged);
|
||||
// @ts-ignore
|
||||
|
@ -296,6 +304,18 @@ export default class AMapService
|
|||
|
||||
this.viewport = new Viewport();
|
||||
}
|
||||
|
||||
public exportMap(type: 'jpg' | 'png'): string {
|
||||
const renderCanvas = this.getContainer()?.getElementsByClassName(
|
||||
'amap-layer',
|
||||
)[0] as HTMLCanvasElement;
|
||||
const layersPng =
|
||||
type === 'jpg'
|
||||
? (renderCanvas?.toDataURL('image/jpeg') as string)
|
||||
: (renderCanvas?.toDataURL('image/png') as string);
|
||||
return layersPng;
|
||||
}
|
||||
|
||||
public emit(name: string, ...args: any[]) {
|
||||
this.eventEmitter.emit(name, ...args);
|
||||
}
|
||||
|
@ -394,4 +414,12 @@ export default class AMapService
|
|||
document.head.appendChild(script);
|
||||
});
|
||||
}
|
||||
|
||||
private removeLogoControl(): void {
|
||||
// @ts-ignore
|
||||
const logo = document.getElementsByClassName('amap-logo');
|
||||
if (logo && logo[0]) {
|
||||
logo[0].setAttribute('style', 'display: none !important');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,12 +107,12 @@ export default class MapboxService
|
|||
return this.map.getCenter();
|
||||
}
|
||||
|
||||
public getPitch(): number {
|
||||
return this.map.getPitch();
|
||||
public setCenter(lnglat: [number, number]): void {
|
||||
this.map.setCenter(lnglat);
|
||||
}
|
||||
|
||||
public setPitch(pitch: number) {
|
||||
return this.map.setPitch(pitch);
|
||||
public getPitch(): number {
|
||||
return this.map.getPitch();
|
||||
}
|
||||
|
||||
public getRotation(): number {
|
||||
|
@ -139,6 +139,10 @@ export default class MapboxService
|
|||
this.map.zoomIn();
|
||||
}
|
||||
|
||||
public setPitch(pitch: number) {
|
||||
return this.map.setPitch(pitch);
|
||||
}
|
||||
|
||||
public zoomOut(): void {
|
||||
this.map.zoomOut();
|
||||
}
|
||||
|
@ -170,7 +174,7 @@ export default class MapboxService
|
|||
});
|
||||
}
|
||||
|
||||
public setMapStyle(style: string): void {
|
||||
public setMapStyle(style: any): void {
|
||||
this.map.setStyle(this.getMapStyle(style));
|
||||
}
|
||||
// TODO: 计算像素坐标
|
||||
|
@ -237,7 +241,7 @@ export default class MapboxService
|
|||
this.$mapContainer = this.creatAmapContainer(id);
|
||||
// @ts-ignore
|
||||
this.map = new mapboxgl.Map({
|
||||
container: id,
|
||||
container: this.$mapContainer,
|
||||
style: this.getMapStyle(style),
|
||||
attributionControl,
|
||||
bearing: rotation,
|
||||
|
@ -270,6 +274,14 @@ export default class MapboxService
|
|||
return this.$mapContainer;
|
||||
}
|
||||
|
||||
public exportMap(type: 'jpg' | 'png'): string {
|
||||
const renderCanvas = this.map.getCanvas();
|
||||
const layersPng =
|
||||
type === 'jpg'
|
||||
? (renderCanvas?.toDataURL('image/jpeg') as string)
|
||||
: (renderCanvas?.toDataURL('image/png') as string);
|
||||
return layersPng;
|
||||
}
|
||||
public onCameraChanged(callback: (viewport: IViewport) => void): void {
|
||||
this.cameraChangedCallback = callback;
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@ export const MapTheme: {
|
|||
{
|
||||
id: 'background',
|
||||
type: 'background',
|
||||
paint: {
|
||||
'background-color': 'white',
|
||||
layout: {
|
||||
visibility: 'none',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
/// <reference types="amap-js-api" />
|
||||
/// <reference path="../../../node_modules/eventemitter3/index.d.ts" />
|
||||
|
||||
import { IControl } from 'mapbox-gl';
|
||||
|
||||
interface Window {
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.0.34](https://github.com/antvis/L7/compare/v2.0.32...v2.0.34) (2020-03-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix map reference ([79e16f5](https://github.com/antvis/L7/commit/79e16f5393c6c31cc088e946dc865cdddfde9b73))
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue