fix: merge conflict

This commit is contained in:
thinkinggis 2020-03-07 20:17:59 +08:00
commit 541e00f45e
171 changed files with 5416 additions and 2021 deletions

View File

@ -82,3 +82,18 @@ yarn add -W -D typescript jest
```bash
yarn commit
```
## 发布
### 设置版本号
```bash
yarn run version:prerelease
```
设置完成后需要commit一下代码
### 发布
yarn run release

View File

@ -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';

View File

@ -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

View File

@ -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',

View File

@ -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

View File

@ -1,5 +1,5 @@
---
title: Marker 图层
title: Marker Layer
order: 3
---

View File

@ -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 地址

View File

@ -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 地址

View File

@ -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);
```

View File

@ -39,6 +39,19 @@ layer.animate(true);
[layer#style](./layer#style)
## 自定义动画频率
自定义动画频率需要 关闭默认动画,通过 setLight 方法不断更新时间
```javascript
layer.animate(false);
```
### setLight(time)
参数
time : 时间 毫秒
#### 完整代码
```javascript

View File

@ -0,0 +1,4 @@
---
title: Get Started
order: 0
---

View File

@ -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>
</>
);
});
```

View File

@ -1,5 +1,5 @@
---
title: 场景 Scene
title: Scene
order: 2
---

View File

@ -24,7 +24,7 @@ fetch(
.size(1.5)
.shape('line')
.color('color', v => {
return `rgb(${v[0]})`;
return `rgb(${v})`;
})
.animate({
interval: 0.6,

View File

@ -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);
});

View File

@ -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')
};
};

View File

@ -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',

View File

@ -14,7 +14,7 @@
"message": "chore: publish"
}
},
"version": "2.0.17",
"version": "2.0.34",
"npmClient": "yarn",
"useWorkspaces": true,
"publishConfig": {

View File

@ -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"

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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;
}
}

View File

@ -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 = {

View File

@ -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)

View File

@ -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"
}

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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,
// };
// }
}

View File

@ -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

View File

@ -4,8 +4,5 @@
export default {
properties: {
// 地图容器 ID
id: {
type: 'string',
},
},
};

View File

@ -0,0 +1,3 @@
export interface IPickingService {
init(): void;
}

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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,

View File

@ -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();

View File

@ -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<{

View File

@ -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 {

View File

@ -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 {

View File

@ -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;
}
/**

View File

@ -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;

View File

@ -87,6 +87,7 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
},
// @ts-ignore
uniforms: {
// @ts-ignore
u_Texture: null,
...uniforms,
...(this.config && this.convertOptionsToUniforms(this.config)),

View File

@ -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>) {

View File

@ -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));
}

View File

@ -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',
];

View File

@ -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`);
});
// TODOinit 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)')

View File

@ -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
);
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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'),

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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>

View File

@ -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>

74
packages/l7/demo/dot.html Normal file
View File

@ -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

View File

@ -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>

View File

@ -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"
}

View File

@ -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)

View File

@ -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"
}

View File

@ -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: {

View File

@ -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,
};
}

View File

@ -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();
};

View File

@ -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',

View File

@ -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
*/

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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);
}

View File

@ -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)));
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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));

View File

@ -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: 配置项发生变化,需要重新校验
// });
// }
// }

View File

@ -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)

View File

@ -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;

View File

@ -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,

View File

@ -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;
});
}

View File

@ -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;
}

View File

@ -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 矩阵、缩放等级

View File

@ -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();
}
});

View File

@ -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`);
});
}
}

View File

@ -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]];
},

View File

@ -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(),
}),
];
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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];

View File

@ -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({

View File

@ -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 ]

View File

@ -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)

View File

@ -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"
}

View File

@ -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,

View File

@ -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');
}
}
}

View File

@ -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;
}

View File

@ -14,8 +14,8 @@ export const MapTheme: {
{
id: 'background',
type: 'background',
paint: {
'background-color': 'white',
layout: {
visibility: 'none',
},
},
],

View File

@ -1,6 +1,4 @@
/// <reference types="amap-js-api" />
/// <reference path="../../../node_modules/eventemitter3/index.d.ts" />
import { IControl } from 'mapbox-gl';
interface Window {

View File

@ -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