feat(layers): add heatmap layer

This commit is contained in:
thinkinggis 2019-11-01 15:36:20 +08:00
commit e04b3b268b
96 changed files with 3127 additions and 23558 deletions

View File

@ -22,6 +22,8 @@ module.exports = (api) => {
'@babel/preset-typescript',
],
plugins: [
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-nullish-coalescing-operator',
[
'@babel/plugin-proposal-decorators',
{
@ -35,7 +37,6 @@ module.exports = (api) => {
loose: true,
}
],
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-transform-modules-commonjs',
[

View File

@ -50,13 +50,13 @@ ClearPass -> RenderPass -> [ ...其他后处理 Pass ] -> CopyPass
| -------- | --- | ------------- | --------- |
| ClearPass | normal | 无 | 清除 framebufferclearColor 为 [0, 0, 0, 0] |
| RenderPass | normal | 无 | 渲染到 framebuffer作为后续后处理的输入 |
| PickingPass | normal | 无 | 负责拾取,[详见](./PixelPickingEngine.md) |
| TAAPass | normal | 无 | [详见](./TAA.md) |
| CopyPass | post-processing | 无 | 作为后处理最后一个 Pass负责拷贝 framebuffer 到屏幕输出 |
| BlurHPass | post-processing | `blurRadius` 水平方向模糊半径,默认值为 `8.0` | [高斯模糊 blur9](https://github.com/Jam3/glsl-fast-gaussian-blur/blob/master/9.glsl) |
| BlurVPass | post-processing | `blurRadius` 垂直方向模糊半径,默认值为 `8.0` | 同上 |
剩余后处理效果见最后一节。
后续待实现 Pass 如下:
- [ ] PickingPass 负责拾取
- [ ] ShadowPass 负责生成 shadowMap供 PCF、CSM 等实时阴影技术使用
## 使用方法
@ -76,3 +76,92 @@ const layer = new PolygonLayer({
],
});
```
## 内置后处理效果
参考了 [glfx](https://github.com/evanw/glfx.js) 中的一些常用图像处理效果。可以按照名称引用,顺序决定了各个效果的应用次序。例如我们想依次应用噪声和模糊效果:
```typescript
const layer = new PolygonLayer({
passes: [
[
'noise', // 使用 NoisePass
{
amount: 0.5,
},
]
'blurH', // 使用 BlurHPass
'blurV', // 使用 BlurVPass
],
});
```
下面详细介绍各个后处理效果及其参数,在 DEMO 中也可以通过 GUI 任意调节参数。
### 高斯模糊
采用 [高斯模糊 blur9](https://github.com/Jam3/glsl-fast-gaussian-blur/blob/master/9.glsl)。
名称:`blurH/blurV`
参数:
* `blurRadius` 水平/垂直方向模糊半径,默认值为 `8.0`
效果如下:
![](./screenshots/blurpass.png)
### ColorHalftone
CMYK halftone 效果
名称:`colorHalftone`
参数:
* `angle` pattern 旋转角度,默认值为 0
* `size` pattern 大小,默认值为 8
* `center` `[x, y]` pattern 的中心,默认值为 `[0, 0]`
效果如下:
![](./screenshots/halftone.png)
### 噪声
噪声效果。
名称:`noise`
参数:
* `amount` 噪声程度,范围 `[0, 1]`,默认值为 `0.5`
效果如下:
![](./screenshots/noise.png)
### 六边形像素化处理
六边形像素化处理。
名称:`hexagonalPixelate`
参数:
* `scale` 六边形大小,默认值为 `10`
* `center` `[x, y]` pattern 的中心,默认值为 `[0.5, 0.5]`
效果如下:
![](./screenshots/hexagonalPixelate.png)
### Sepia
Sepia 颜色映射。
名称:`sepia`
参数:
* `amount` 程度,范围 `[0, 1]`,默认值为 `0.5`
效果如下:
![](./screenshots/sepia.png)

View File

@ -65,7 +65,7 @@ this.cameraService.jitterProjectionMatrix(
![](./screenshots/taa-step3.png)
这里我们选择当前帧权重为 0.9,历史帧为 0.1,最终的混合结果供后续后处理模块继续处理
这里我们选择当前帧权重为 0.9,历史帧为 0.1
```typescript
useFramebuffer(this.outputRenderTarget, () => {
@ -83,6 +83,23 @@ useFramebuffer(this.outputRenderTarget, () => {
});
```
最后我们将最终的混合结果“拷贝”给后处理模块,实现渐进增强的效果:
```typescript
useFramebuffer(
layer.multiPassRenderer.getPostProcessor().getReadFBO(),
() => {
this.copyModel.draw({
uniforms: {
u_Texture: this.copyRenderTarget,
},
});
},
);
// 调用后处理模块应用后续效果
layer.multiPassRenderer.getPostProcessor().render(layer);
```
## 最终效果
为了更直观地看到效果,在 DEMO 中我们可以调节相机抖动范围:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 KiB

23219
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,8 @@
"devDependencies": {
"@babel/cli": "^7.6.4",
"@babel/core": "^7.6.4",
"@babel/plugin-proposal-decorators": "^7.6.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.4.4",
"@babel/plugin-proposal-optional-chaining": "^7.6.0",
"@babel/preset-env": "^7.5.5",
"@babel/preset-react": "^7.0.0",
@ -111,6 +113,6 @@
}
},
"dependencies": {
"@babel/plugin-proposal-decorators": "^7.6.0"
"geotiff": "^1.0.0-beta.6"
}
}

View File

@ -2,9 +2,6 @@ import container, { lazyInject, lazyMultiInject } from './inversify.config';
import ClearPass from './services/renderer/passes/ClearPass';
import MultiPassRenderer from './services/renderer/passes/MultiPassRenderer';
import PixelPickingPass from './services/renderer/passes/PixelPickingPass';
import BlurHPass from './services/renderer/passes/post-processing/BlurHPass';
import BlurVPass from './services/renderer/passes/post-processing/BlurVPass';
import CopyPass from './services/renderer/passes/post-processing/CopyPass';
import RenderPass from './services/renderer/passes/RenderPass';
import TAAPass from './services/renderer/passes/TAAPass';
import { TYPES } from './types';
@ -30,9 +27,6 @@ export {
ClearPass,
RenderPass,
PixelPickingPass,
BlurHPass,
BlurVPass,
CopyPass,
TAAPass,
};

View File

@ -32,6 +32,18 @@ import StyleAttributeService from './services/layer/StyleAttributeService';
import LogService from './services/log/LogService';
import SceneService from './services/scene/SceneService';
import ShaderModuleService from './services/shader/ShaderModuleService';
/** PostProcessing passes */
import { IPostProcessingPass } from './services/renderer/IMultiPassRenderer';
import BlurHPass from './services/renderer/passes/post-processing/BlurHPass';
import BlurVPass from './services/renderer/passes/post-processing/BlurVPass';
import ColorHalfTonePass from './services/renderer/passes/post-processing/ColorHalfTonePass';
import CopyPass from './services/renderer/passes/post-processing/CopyPass';
import HexagonalPixelatePass from './services/renderer/passes/post-processing/HexagonalPixelatePass';
import InkPass from './services/renderer/passes/post-processing/InkPass';
import NoisePass from './services/renderer/passes/post-processing/NoisePass';
import SepiaPass from './services/renderer/passes/post-processing/SepiaPass';
// @see https://github.com/inversify/InversifyJS/blob/master/wiki/container_api.md#defaultscope
const container = new Container();
@ -140,4 +152,51 @@ export const lazyMultiInject = (
};
};
// 绑定 post processing passes
container
.bind<IPostProcessingPass<unknown>>(TYPES.INewablePostProcessingPass)
.to(CopyPass)
.whenTargetNamed('copy');
container
.bind<IPostProcessingPass<unknown>>(TYPES.INewablePostProcessingPass)
.to(BlurHPass)
.whenTargetNamed('blurH');
container
.bind<IPostProcessingPass<unknown>>(TYPES.INewablePostProcessingPass)
.to(BlurVPass)
.whenTargetNamed('blurV');
container
.bind<IPostProcessingPass<unknown>>(TYPES.INewablePostProcessingPass)
.to(NoisePass)
.whenTargetNamed('noise');
container
.bind<IPostProcessingPass<unknown>>(TYPES.INewablePostProcessingPass)
.to(SepiaPass)
.whenTargetNamed('sepia');
container
.bind<IPostProcessingPass<unknown>>(TYPES.INewablePostProcessingPass)
.to(ColorHalfTonePass)
.whenTargetNamed('colorHalftone');
container
.bind<IPostProcessingPass<unknown>>(TYPES.INewablePostProcessingPass)
.to(HexagonalPixelatePass)
.whenTargetNamed('hexagonalPixelate');
container
.bind<IPostProcessingPass<unknown>>(TYPES.INewablePostProcessingPass)
.to(InkPass)
.whenTargetNamed('ink');
container
.bind<interfaces.Factory<IPostProcessingPass<unknown>>>(
TYPES.IFactoryPostProcessingPass,
)
.toFactory<IPostProcessingPass<unknown>>((context) => {
return (named: string) => {
return context.container.getNamed<IPostProcessingPass<unknown>>(
TYPES.INewablePostProcessingPass,
named,
);
};
});
export default container;

View File

@ -4,6 +4,7 @@ import {
} from '../renderer/IAttribute';
import { IBufferInitializationOptions } from '../renderer/IBuffer';
import { IElements } from '../renderer/IElements';
import { IParseDataItem, IParserData } from '../source/ISourceService';
import { ILayer } from './ILayerService';
/**
@ -64,6 +65,7 @@ export interface IEncodeFeature {
pattern?: string;
id?: number;
coordinates: Position | Position[] | Position[][];
[key: string]: any;
}
export interface IVertexAttributeDescriptor
@ -129,6 +131,7 @@ export interface IStyleAttribute extends IStyleAttributeInitializationOptions {
export type Triangulation = (
feature: IEncodeFeature,
parserData: IParseDataItem,
) => {
vertices: number[];
indices: number[];
@ -158,6 +161,7 @@ export interface IStyleAttributeService {
createAttributesAndIndices(
encodedFeatures: IEncodeFeature[],
triangulation: Triangulation,
parserData: IParseDataItem[],
): {
attributes: {
[attributeName: string]: IAttribute;

View File

@ -4,7 +4,6 @@ import {
StyleScaleType,
} from '../layer/IStyleAttributeService';
import { IAttribute } from '../renderer/IAttribute';
import { IBuffer } from '../renderer/IBuffer';
import {
AttributeType,
IEncodeFeature,
@ -45,8 +44,6 @@ export default class StyleAttribute implements IStyleAttribute {
};
public vertexAttribute: IAttribute;
private buffer: IBuffer;
constructor(options: Partial<IStyleAttributeInitializationOptions>) {
this.setProps(options);
}

View File

@ -4,6 +4,7 @@ import { gl } from '../renderer/gl';
import { IAttribute } from '../renderer/IAttribute';
import { IElements } from '../renderer/IElements';
import { IRendererService } from '../renderer/IRendererService';
import { IParseDataItem } from '../source/ISourceService'
import { ILayer } from './ILayerService';
import {
IEncodeFeature,
@ -48,8 +49,7 @@ export default class StyleAttributeService implements IStyleAttributeService {
public registerStyleAttribute(
options: Partial<IStyleAttributeInitializationOptions>,
) {
let attributeToUpdate =
options.name && this.getLayerStyleAttribute(options.name);
let attributeToUpdate = this.getLayerStyleAttribute(options.name || '');
if (attributeToUpdate) {
attributeToUpdate.setProps(options);
} else {
@ -72,7 +72,7 @@ export default class StyleAttributeService implements IStyleAttributeService {
});
}
const { scale } = options;
if (scale) {
if (scale && attributeToUpdate) {
// TODO: 需要比较新旧值确定是否需要 rescale
// 需要重新 scale肯定也需要重新进行数据映射
attributeToUpdate.scale = scale;
@ -167,6 +167,7 @@ export default class StyleAttributeService implements IStyleAttributeService {
public createAttributesAndIndices(
features: IEncodeFeature[],
triangulation: Triangulation,
parserData: IParseDataItem[],
): {
attributes: {
[attributeName: string]: IAttribute;
@ -187,7 +188,7 @@ export default class StyleAttributeService implements IStyleAttributeService {
vertices: verticesForCurrentFeature,
normals: normalsForCurrentFeature,
size: vertexSize,
} = triangulation(feature);
} = triangulation(feature, parserData[featureIdx]);
indices.push(...indicesForCurrentFeature.map((i) => i + verticesNum));
vertices.push(...verticesForCurrentFeature);
if (normalsForCurrentFeature) {
@ -278,7 +279,9 @@ export default class StyleAttributeService implements IStyleAttributeService {
public clearAllAttributes() {
// 销毁关联的 vertex attribute buffer objects
this.attributes.forEach((attribute) => {
attribute.vertexAttribute.destroy();
if (attribute.vertexAttribute) {
attribute.vertexAttribute.destroy();
}
});
this.attributes = [];
}

View File

@ -12,9 +12,10 @@ export enum PassType {
* 2. PostProcessing eg. CopyPassBlurPass
* Pass render
*/
export interface IPass {
export interface IPass<InitializationOptions> {
getName(): string;
getType(): PassType;
init(layer: ILayer): void;
init(layer: ILayer, config?: Partial<InitializationOptions>): void;
render(layer: ILayer): void;
}
@ -22,24 +23,33 @@ export interface IPass {
* PostProcessing renderTarget
* PostProcessingPass renderTarget
*/
export interface IPostProcessingPass extends IPass {
export interface IPostProcessingPass<InitializationOptions>
extends IPass<InitializationOptions> {
setRenderToScreen(renderToScreen: boolean): void;
isEnabled(): boolean;
setEnabled(enabled: boolean): void;
updateOptions(config: Partial<InitializationOptions>): void;
}
export interface IPostProcessor {
getReadFBO(): IFramebuffer;
getWriteFBO(): IFramebuffer;
resize(viewportWidth: number, viewportHeight: number): void;
add(pass: IPostProcessingPass, layer: ILayer): void;
add<InitializationOptions>(
pass: IPostProcessingPass<InitializationOptions>,
layer: ILayer,
config?: Partial<InitializationOptions>,
): void;
render(layer: ILayer): Promise<unknown>;
getPostProcessingPassByName(
name: string,
): IPostProcessingPass<unknown> | undefined;
}
export interface IMultiPassRenderer {
getPostProcessor(): IPostProcessor;
resize(viewportWidth: number, viewportHeight: number): void;
add(pass: IPass): void;
add<InitializationOptions>(pass: IPass<InitializationOptions>): void;
render(): void;
getRenderFlag(): boolean;
setRenderFlag(enabled: boolean): void;

View File

@ -15,7 +15,7 @@ export interface IRenderConfig {
* multi pass
*/
enableMultiPassRenderer?: boolean;
passes?: IPass[];
passes?: Array<IPass<unknown>>;
}
export interface IClearOptions {

View File

@ -39,7 +39,8 @@ export interface ITexture2DInitializationOptions {
| number[][]
| Uint8Array
| Uint16Array
| Uint32Array;
| Uint32Array
| Uint8ClampedArray;
/**
*

View File

@ -4,7 +4,6 @@ import {
IModel,
IRendererService,
IShaderModuleService,
lazyInject,
} from '../../../index';
import { TYPES } from '../../../types';
import { ILayer } from '../../layer/ILayerService';
@ -18,11 +17,11 @@ import { IUniform } from '../IUniform';
*/
@injectable()
export default class BasePostProcessingPass<InitializationOptions = {}>
implements IPostProcessingPass {
@lazyInject(TYPES.IShaderModuleService)
implements IPostProcessingPass<InitializationOptions> {
@inject(TYPES.IShaderModuleService)
protected readonly shaderModule: IShaderModuleService;
@lazyInject(TYPES.IRendererService)
@inject(TYPES.IRendererService)
protected readonly rendererService: IRendererService;
protected config: Partial<InitializationOptions> | undefined;
@ -42,15 +41,19 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
*/
private model: IModel;
constructor(config?: Partial<InitializationOptions>) {
this.config = config;
private optionsToUpdate: Partial<InitializationOptions> = {};
public getName() {
return '';
}
public getType() {
return PassType.PostProcessing;
}
public init() {
public init(layer: ILayer, config?: Partial<InitializationOptions>) {
this.config = config;
const { createAttribute, createBuffer, createModel } = this.rendererService;
const { vs, fs, uniforms } = this.setupShaders();
@ -71,6 +74,7 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
uniforms: {
u_Texture: null,
...uniforms,
...(this.config && this.convertOptionsToUniforms(this.config)),
},
depth: {
enable: false,
@ -81,7 +85,8 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
public render(layer: ILayer) {
const postProcessor = layer.multiPassRenderer.getPostProcessor();
const { useFramebuffer } = this.rendererService;
const { useFramebuffer, getViewportSize } = this.rendererService;
const { width, height } = getViewportSize();
useFramebuffer(
this.renderToScreen ? null : postProcessor.getWriteFBO(),
@ -89,6 +94,8 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
this.model.draw({
uniforms: {
u_Texture: postProcessor.getReadFBO(),
u_ViewportSize: [width, height],
...this.convertOptionsToUniforms(this.optionsToUpdate),
},
});
},
@ -107,6 +114,13 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
this.renderToScreen = renderToScreen;
}
public updateOptions(config: Partial<InitializationOptions>) {
this.optionsToUpdate = {
...this.optionsToUpdate,
...config,
};
}
protected setupShaders(): {
vs: string;
fs: string;
@ -114,4 +128,12 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
} {
throw new Error('Method not implemented.');
}
protected convertOptionsToUniforms(
options: Partial<InitializationOptions>,
): {
[uniformName: string]: IUniform;
} | void {
throw new Error('Method not implemented.');
}
}

View File

@ -8,7 +8,8 @@ import { IRendererService } from '../IRendererService';
* ClearPass
*/
@injectable()
export default class ClearPass implements IPass {
export default class ClearPass<InitializationOptions = {}>
implements IPass<InitializationOptions> {
@lazyInject(TYPES.IRendererService)
protected readonly rendererService: IRendererService;
@ -16,6 +17,10 @@ export default class ClearPass implements IPass {
return PassType.Normal;
}
public getName() {
return 'clear';
}
public init() {
//
}

View File

@ -30,7 +30,7 @@ import PostProcessor from './PostProcessor';
*/
@injectable()
export default class MultiPassRenderer implements IMultiPassRenderer {
private passes: IPass[] = [];
private passes: Array<IPass<unknown>> = [];
private postProcessor: IPostProcessor;
private layer: ILayer;
@ -64,17 +64,21 @@ export default class MultiPassRenderer implements IMultiPassRenderer {
this.postProcessor.resize(width, height);
}
public add(pass: IPass) {
public add<T>(pass: IPass<T>, config?: Partial<T>) {
if (pass.getType() === PassType.PostProcessing) {
this.postProcessor.add(pass as IPostProcessingPass, this.layer);
this.postProcessor.add<T>(
pass as IPostProcessingPass<T>,
this.layer,
config,
);
} else {
pass.init(this.layer);
pass.init(this.layer, config);
this.passes.push(pass);
}
}
public insert(pass: IPass, index: number) {
pass.init(this.layer);
public insert<T>(pass: IPass<T>, config: Partial<T>, index: number) {
pass.init(this.layer, config);
this.passes.splice(index, 0, pass);
}
}

View File

@ -24,7 +24,7 @@ function decodePickingColor(color: Uint8Array): number {
* @see https://github.com/antvis/L7/blob/next/dev-docs/PixelPickingEngine.md
*/
@injectable()
export default class PixelPickingPass implements IPass {
export default class PixelPickingPass<InitializationOptions = {}> implements IPass<InitializationOptions> {
@lazyInject(TYPES.IRendererService)
protected readonly rendererService: IRendererService;
@ -53,6 +53,10 @@ export default class PixelPickingPass implements IPass {
return PassType.Normal;
}
public getName() {
return 'pixelPicking';
}
public init(layer: ILayer) {
this.layer = layer;
const { createTexture2D, createFramebuffer } = this.rendererService;

View File

@ -16,7 +16,7 @@ export default class PostProcessor implements IPostProcessor {
@lazyInject(TYPES.IRendererService)
protected readonly rendererService: IRendererService;
private passes: IPostProcessingPass[] = [];
private passes: Array<IPostProcessingPass<unknown>> = [];
private readFBO: IFramebuffer;
private writeFBO: IFramebuffer;
@ -75,16 +75,31 @@ export default class PostProcessor implements IPostProcessor {
});
}
public add(pass: IPostProcessingPass, layer: ILayer) {
pass.init(layer);
public add<T>(
pass: IPostProcessingPass<T>,
layer: ILayer,
config?: Partial<T>,
) {
pass.init(layer, config);
this.passes.push(pass);
}
public insert(pass: IPostProcessingPass, index: number, layer: ILayer) {
pass.init(layer);
public insert<T>(
pass: IPostProcessingPass<T>,
index: number,
layer: ILayer,
config?: Partial<T>,
) {
pass.init(layer, config);
this.passes.splice(index, 0, pass);
}
public getPostProcessingPassByName(
name: string,
): IPostProcessingPass<unknown> | undefined {
return this.passes.find((p) => p.getName() === name);
}
private isLastEnabledPass(index: number): boolean {
for (let i = index + 1; i < this.passes.length; i++) {
if (this.passes[i].isEnabled()) {

View File

@ -9,7 +9,8 @@ import { IRendererService } from '../IRendererService';
* RenderPass PostProcessor readFBO
*/
@injectable()
export default class RenderPass implements IPass {
export default class RenderPass<InitializationOptions = {}>
implements IPass<InitializationOptions> {
@lazyInject(TYPES.IRendererService)
protected readonly rendererService: IRendererService;
@ -17,6 +18,10 @@ export default class RenderPass implements IPass {
return PassType.Normal;
}
public getName() {
return 'render';
}
public init(layer: ILayer) {
//
}

View File

@ -38,7 +38,8 @@ let accumulatingId = 1;
* @see https://yuque.antfin-inc.com/yuqi.pyq/fgetpa/ri52hv
*/
@injectable()
export default class TAAPass implements IPass {
export default class TAAPass<InitializationOptions = {}>
implements IPass<InitializationOptions> {
@lazyInject(TYPES.IRendererService)
protected readonly rendererService: IRendererService;
@ -84,6 +85,10 @@ export default class TAAPass implements IPass {
return PassType.Normal;
}
public getName() {
return 'taa';
}
public init(layer: ILayer) {
const { createFramebuffer, createTexture2D } = this.rendererService;
this.sampleRenderTarget = createFramebuffer({
@ -258,13 +263,17 @@ export default class TAAPass implements IPass {
});
});
useFramebuffer(null, () => {
this.copyModel.draw({
uniforms: {
u_Texture: this.copyRenderTarget,
},
});
});
useFramebuffer(
layer.multiPassRenderer.getPostProcessor().getReadFBO(),
() => {
this.copyModel.draw({
uniforms: {
u_Texture: this.copyRenderTarget,
},
});
},
);
layer.multiPassRenderer.getPostProcessor().render(layer);
}
// 保存前序帧结果

View File

@ -1,27 +1,28 @@
import { injectable } from 'inversify';
import { lazyInject } from '../../../../index';
import { inject, injectable } from 'inversify';
import { isNil } from 'lodash';
import blur from '../../../../shaders/post-processing/blur.glsl';
import quad from '../../../../shaders/post-processing/quad.glsl';
import { TYPES } from '../../../../types';
import { IRendererService } from '../../IRendererService';
import { IUniform } from '../../IUniform';
import BasePostProcessingPass from '../BasePostProcessingPass';
export interface IBlurHPassConfig {
blurRadius: number;
}
const defaultConfig: IBlurHPassConfig = {
blurRadius: 8.0,
};
@injectable()
export default class BlurHPass extends BasePostProcessingPass<
IBlurHPassConfig
> {
@lazyInject(TYPES.IRendererService)
@inject(TYPES.IRendererService)
protected readonly rendererService: IRendererService;
public setupShaders() {
public getName() {
return 'blurH';
}
protected setupShaders() {
this.shaderModule.registerModule('blur-pass', {
vs: quad,
fs: blur,
@ -30,19 +31,29 @@ export default class BlurHPass extends BasePostProcessingPass<
const { vs, fs, uniforms } = this.shaderModule.getModule('blur-pass');
const { width, height } = this.rendererService.getViewportSize();
const { blurRadius } = {
...defaultConfig,
...this.config,
};
return {
vs,
fs,
uniforms: {
...uniforms,
u_BlurDir: [blurRadius, 0],
u_ViewportSize: [width, height],
},
};
}
protected convertOptionsToUniforms(
options: Partial<IBlurHPassConfig>,
): {
[uniformName: string]: IUniform;
} | void {
const uniforms: {
[key: string]: IUniform;
} = {};
if (!isNil(options.blurRadius)) {
uniforms.u_BlurDir = [options.blurRadius, 0];
}
return uniforms;
}
}

View File

@ -1,26 +1,27 @@
import { injectable } from 'inversify';
import { lazyInject } from '../../../../index';
import { inject, injectable } from 'inversify';
import { isNil } from 'lodash';
import blur from '../../../../shaders/post-processing/blur.glsl';
import quad from '../../../../shaders/post-processing/quad.glsl';
import { TYPES } from '../../../../types';
import { IRendererService } from '../../IRendererService';
import { IUniform } from '../../IUniform';
import BasePostProcessingPass from '../BasePostProcessingPass';
export interface IBlurVPassConfig {
blurRadius: number;
}
const defaultConfig: IBlurVPassConfig = {
blurRadius: 8.0,
};
@injectable()
export default class BlurVPass extends BasePostProcessingPass<
IBlurVPassConfig
> {
@lazyInject(TYPES.IRendererService)
@inject(TYPES.IRendererService)
protected readonly rendererService: IRendererService;
public getName() {
return 'blurV';
}
public setupShaders() {
this.shaderModule.registerModule('blur-pass', {
vs: quad,
@ -30,19 +31,29 @@ export default class BlurVPass extends BasePostProcessingPass<
const { vs, fs, uniforms } = this.shaderModule.getModule('blur-pass');
const { width, height } = this.rendererService.getViewportSize();
const { blurRadius } = {
...defaultConfig,
...this.config,
};
return {
vs,
fs,
uniforms: {
...uniforms,
u_BlurDir: [0, blurRadius],
u_ViewportSize: [width, height],
},
};
}
protected convertOptionsToUniforms(
options: Partial<IBlurVPassConfig>,
): {
[uniformName: string]: IUniform;
} | void {
const uniforms: {
[key: string]: IUniform;
} = {};
if (!isNil(options.blurRadius)) {
uniforms.u_BlurDir = [0, options.blurRadius];
}
return uniforms;
}
}

View File

@ -0,0 +1,71 @@
import { inject, injectable } from 'inversify';
import { isNil } from 'lodash';
import colorHalftone from '../../../../shaders/post-processing/colorhalftone.glsl';
import quad from '../../../../shaders/post-processing/quad.glsl';
import { TYPES } from '../../../../types';
import { IRendererService } from '../../IRendererService';
import { IUniform } from '../../IUniform';
import BasePostProcessingPass from '../BasePostProcessingPass';
export interface IColorHalftonePassConfig {
center: [number, number];
angle: number;
size: number;
}
@injectable()
export default class ColorHalftonePass extends BasePostProcessingPass<
IColorHalftonePassConfig
> {
@inject(TYPES.IRendererService)
protected readonly rendererService: IRendererService;
public getName() {
return 'colorHalftone';
}
protected setupShaders() {
this.shaderModule.registerModule('colorhalftone-pass', {
vs: quad,
fs: colorHalftone,
});
const { vs, fs, uniforms } = this.shaderModule.getModule(
'colorhalftone-pass',
);
const { width, height } = this.rendererService.getViewportSize();
return {
vs,
fs,
uniforms: {
...uniforms,
u_ViewportSize: [width, height],
},
};
}
protected convertOptionsToUniforms(
options: Partial<IColorHalftonePassConfig>,
): {
[uniformName: string]: IUniform;
} | void {
const uniforms: {
[key: string]: IUniform;
} = {};
if (!isNil(options.center)) {
uniforms.u_Center = options.center;
}
if (!isNil(options.angle)) {
uniforms.u_Angle = options.angle;
}
if (!isNil(options.size)) {
uniforms.u_Size = options.size;
}
return uniforms;
}
}

View File

@ -1,10 +1,15 @@
import { injectable } from 'inversify';
import copy from '../../../../shaders/post-processing/copy.glsl';
import quad from '../../../../shaders/post-processing/quad.glsl';
import { IUniform } from '../../IUniform';
import BasePostProcessingPass from '../BasePostProcessingPass';
@injectable()
export default class CopyPass extends BasePostProcessingPass {
public getName() {
return 'copy';
}
public setupShaders() {
this.shaderModule.registerModule('copy-pass', {
vs: quad,
@ -13,4 +18,12 @@ export default class CopyPass extends BasePostProcessingPass {
return this.shaderModule.getModule('copy-pass');
}
protected convertOptionsToUniforms(
options: Partial<{}>,
): {
[uniformName: string]: IUniform;
} | void {
return {};
}
}

View File

@ -0,0 +1,66 @@
import { inject, injectable } from 'inversify';
import { isNil } from 'lodash';
import hexagonalPixelate from '../../../../shaders/post-processing/hexagonalpixelate.glsl';
import quad from '../../../../shaders/post-processing/quad.glsl';
import { TYPES } from '../../../../types';
import { IRendererService } from '../../IRendererService';
import { IUniform } from '../../IUniform';
import BasePostProcessingPass from '../BasePostProcessingPass';
export interface IHexagonalPixelatePassConfig {
center: [number, number];
scale: number;
}
@injectable()
export default class HexagonalPixelatePass extends BasePostProcessingPass<
IHexagonalPixelatePassConfig
> {
@inject(TYPES.IRendererService)
protected readonly rendererService: IRendererService;
public getName() {
return 'hexagonalPixelate';
}
protected setupShaders() {
this.shaderModule.registerModule('hexagonalpixelate-pass', {
vs: quad,
fs: hexagonalPixelate,
});
const { vs, fs, uniforms } = this.shaderModule.getModule(
'hexagonalpixelate-pass',
);
const { width, height } = this.rendererService.getViewportSize();
return {
vs,
fs,
uniforms: {
...uniforms,
u_ViewportSize: [width, height],
},
};
}
protected convertOptionsToUniforms(
options: Partial<IHexagonalPixelatePassConfig>,
): {
[uniformName: string]: IUniform;
} | void {
const uniforms: {
[key: string]: IUniform;
} = {};
if (!isNil(options.center)) {
uniforms.u_Center = options.center;
}
if (!isNil(options.scale)) {
uniforms.u_Scale = options.scale;
}
return uniforms;
}
}

View File

@ -0,0 +1,57 @@
import { inject, injectable } from 'inversify';
import { isNil } from 'lodash';
import ink from '../../../../shaders/post-processing/ink.glsl';
import quad from '../../../../shaders/post-processing/quad.glsl';
import { TYPES } from '../../../../types';
import { IRendererService } from '../../IRendererService';
import { IUniform } from '../../IUniform';
import BasePostProcessingPass from '../BasePostProcessingPass';
export interface IInkPassConfig {
strength: number;
}
@injectable()
export default class InkPass extends BasePostProcessingPass<IInkPassConfig> {
@inject(TYPES.IRendererService)
protected readonly rendererService: IRendererService;
public getName() {
return 'ink';
}
protected setupShaders() {
this.shaderModule.registerModule('ink-pass', {
vs: quad,
fs: ink,
});
const { vs, fs, uniforms } = this.shaderModule.getModule('ink-pass');
const { width, height } = this.rendererService.getViewportSize();
return {
vs,
fs,
uniforms: {
...uniforms,
u_ViewportSize: [width, height],
},
};
}
protected convertOptionsToUniforms(
options: Partial<IInkPassConfig>,
): {
[uniformName: string]: IUniform;
} | void {
const uniforms: {
[key: string]: IUniform;
} = {};
if (!isNil(options.strength)) {
uniforms.u_Strength = options.strength;
}
return uniforms;
}
}

View File

@ -0,0 +1,44 @@
import { injectable } from 'inversify';
import { isNil } from 'lodash';
import noise from '../../../../shaders/post-processing/noise.glsl';
import quad from '../../../../shaders/post-processing/quad.glsl';
import { IUniform } from '../../IUniform';
import BasePostProcessingPass from '../BasePostProcessingPass';
export interface INoisePassConfig {
amount: number;
}
@injectable()
export default class NoisePass extends BasePostProcessingPass<
INoisePassConfig
> {
public getName() {
return 'noise';
}
public setupShaders() {
this.shaderModule.registerModule('noise-pass', {
vs: quad,
fs: noise,
});
return this.shaderModule.getModule('noise-pass');
}
protected convertOptionsToUniforms(
options: Partial<INoisePassConfig>,
): {
[uniformName: string]: IUniform;
} | void {
const uniforms: {
[key: string]: IUniform;
} = {};
if (!isNil(options.amount)) {
uniforms.u_Amount = options.amount;
}
return uniforms;
}
}

View File

@ -0,0 +1,44 @@
import { injectable } from 'inversify';
import { isNil } from 'lodash';
import quad from '../../../../shaders/post-processing/quad.glsl';
import sepia from '../../../../shaders/post-processing/sepia.glsl';
import { IUniform } from '../../IUniform';
import BasePostProcessingPass from '../BasePostProcessingPass';
export interface ISepiaPassConfig {
amount: number;
}
@injectable()
export default class SepiaPass extends BasePostProcessingPass<
ISepiaPassConfig
> {
public getName() {
return 'sepia';
}
public setupShaders() {
this.shaderModule.registerModule('sepia-pass', {
vs: quad,
fs: sepia,
});
return this.shaderModule.getModule('sepia-pass');
}
protected convertOptionsToUniforms(
options: Partial<ISepiaPassConfig>,
): {
[uniformName: string]: IUniform;
} | void {
const uniforms: {
[key: string]: IUniform;
} = {};
if (!isNil(options.amount)) {
uniforms.u_Amount = options.amount;
}
return uniforms;
}
}

View File

@ -3,6 +3,7 @@ import { uniq } from 'lodash';
import { extractUniforms } from '../../utils/shader-module';
import { IModuleParams, IShaderModuleService } from './IShaderModuleService';
import common from '../../shaders/common.glsl';
import decode from '../../shaders/decode.glsl';
import lighting from '../../shaders/lighting.glsl';
import pickingFrag from '../../shaders/picking.frag.glsl';
@ -21,6 +22,7 @@ export default class ShaderModuleService implements IShaderModuleService {
private rawContentCache: { [key: string]: IModuleParams } = {};
public registerBuiltinModules() {
this.registerModule('common', { vs: common, fs: common });
this.registerModule('decode', { vs: decode, fs: '' });
this.registerModule('projection', { vs: projection, fs: '' });
this.registerModule('sdf_2d', { vs: '', fs: sdf2d });

View File

@ -48,3 +48,16 @@ export type IJsonData = IJsonItem[];
export interface ISource {
data: IParserData;
}
export interface IRasterCfg {
extent: [number, number, number, number];
width: number;
height: number;
max: number;
min: number;
}
export interface IRasterParserDataItem extends IParseDataItem {
data: number[];
width: number;
height: number;
}

View File

@ -0,0 +1 @@
#define PI 3.14159265359

View File

@ -0,0 +1,44 @@
varying vec2 v_UV;
uniform sampler2D u_Texture;
uniform vec2 u_ViewportSize: [1.0, 1.0];
uniform vec2 u_Center : [0.5, 0.5];
uniform float u_Angle : 0;
uniform float u_Size : 8;
#pragma include "common"
float scale = PI / u_Size;
float pattern(float u_Angle, vec2 texSize, vec2 texCoord) {
float s = sin(u_Angle), c = cos(u_Angle);
vec2 tex = texCoord * texSize - u_Center * texSize;
vec2 point = vec2(
c * tex.x - s * tex.y,
s * tex.x + c * tex.y
) * scale;
return (sin(point.x) * sin(point.y)) * 4.0;
}
// https://github.com/evanw/glfx.js/blob/master/src/filters/fun/colorhalftone.js
vec4 colorHalftone_filterColor(vec4 color, vec2 texSize, vec2 texCoord) {
vec3 cmy = 1.0 - color.rgb;
float k = min(cmy.x, min(cmy.y, cmy.z));
cmy = (cmy - k) / (1.0 - k);
cmy = clamp(
cmy * 10.0 - 3.0 + vec3(
pattern(u_Angle + 0.26179, texSize, texCoord),
pattern(u_Angle + 1.30899, texSize, texCoord),
pattern(u_Angle, texSize, texCoord)
),
0.0,
1.0
);
k = clamp(k * 10.0 - 5.0 + pattern(u_Angle + 0.78539, texSize, texCoord), 0.0, 1.0);
return vec4(1.0 - cmy - k, color.a);
}
void main() {
gl_FragColor = vec4(texture2D(u_Texture, v_UV));
gl_FragColor = colorHalftone_filterColor(gl_FragColor, u_ViewportSize, v_UV);
}

View File

@ -0,0 +1,44 @@
varying vec2 v_UV;
uniform sampler2D u_Texture;
uniform vec2 u_ViewportSize: [1.0, 1.0];
uniform vec2 u_Center : [0.5, 0.5];
uniform float u_Scale : 10;
// https://github.com/evanw/glfx.js/blob/master/src/filters/fun/hexagonalpixelate.js
vec4 hexagonalPixelate_sampleColor(sampler2D texture, vec2 texSize, vec2 texCoord) {
vec2 tex = (texCoord * texSize - u_Center * texSize) / u_Scale;
tex.y /= 0.866025404;
tex.x -= tex.y * 0.5;
vec2 a;
if (tex.x + tex.y - floor(tex.x) - floor(tex.y) < 1.0) {
a = vec2(floor(tex.x), floor(tex.y));
}
else a = vec2(ceil(tex.x), ceil(tex.y));
vec2 b = vec2(ceil(tex.x), floor(tex.y));
vec2 c = vec2(floor(tex.x), ceil(tex.y));
vec3 TEX = vec3(tex.x, tex.y, 1.0 - tex.x - tex.y);
vec3 A = vec3(a.x, a.y, 1.0 - a.x - a.y);
vec3 B = vec3(b.x, b.y, 1.0 - b.x - b.y);
vec3 C = vec3(c.x, c.y, 1.0 - c.x - c.y);
float alen = length(TEX - A);
float blen = length(TEX - B);
float clen = length(TEX - C);
vec2 choice;
if (alen < blen) {
if (alen < clen) choice = a;
else choice = c;
} else {
if (blen < clen) choice = b;
else choice = c;
}
choice.x += choice.y * 0.5;
choice.y *= 0.866025404;
choice *= u_Scale / texSize;
return texture2D(texture, choice + u_Center);
}
void main() {
gl_FragColor = vec4(texture2D(u_Texture, v_UV));
gl_FragColor = hexagonalPixelate_sampleColor(u_Texture, u_ViewportSize, v_UV);
}

View File

@ -0,0 +1,34 @@
varying vec2 v_UV;
uniform sampler2D u_Texture;
uniform vec2 u_ViewportSize: [1.0, 1.0];
uniform float u_Strength : 0.6;
vec4 ink_sampleColor(sampler2D texture, vec2 texSize, vec2 texCoord) {
vec2 dx = vec2(1.0 / texSize.x, 0.0);
vec2 dy = vec2(0.0, 1.0 / texSize.y);
vec4 color = texture2D(texture, texCoord);
float bigTotal = 0.0;
float smallTotal = 0.0;
vec3 bigAverage = vec3(0.0);
vec3 smallAverage = vec3(0.0);
for (float x = -2.0; x <= 2.0; x += 1.0) {
for (float y = -2.0; y <= 2.0; y += 1.0) {
vec3 sample = texture2D(texture, texCoord + dx * x + dy * y).rgb;
bigAverage += sample;
bigTotal += 1.0;
if (abs(x) + abs(y) < 2.0) {
smallAverage += sample;
smallTotal += 1.0;
}
}
}
vec3 edge = max(vec3(0.0), bigAverage / bigTotal - smallAverage / smallTotal);
float power = u_Strength * u_Strength * u_Strength * u_Strength * u_Strength;
return vec4(color.rgb - dot(edge, edge) * power * 100000.0, color.a);
}
void main() {
gl_FragColor = vec4(texture2D(u_Texture, v_UV));
gl_FragColor = ink_sampleColor(u_Texture, u_ViewportSize, v_UV);
}

View File

@ -0,0 +1,22 @@
varying vec2 v_UV;
uniform sampler2D u_Texture;
uniform float u_Amount : 0.5;
float rand(vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
// https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/noise.js
vec4 noise_filterColor(vec4 color, vec2 texCoord) {
float diff = (rand(texCoord) - 0.5) * u_Amount;
color.r += diff;
color.g += diff;
color.b += diff;
return color;
}
void main() {
gl_FragColor = vec4(texture2D(u_Texture, v_UV));
gl_FragColor = noise_filterColor(gl_FragColor, v_UV);
}

View File

@ -0,0 +1,22 @@
varying vec2 v_UV;
uniform sampler2D u_Texture;
uniform float u_Amount : 0.5;
// https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/sepia.js
vec4 sepia_filterColor(vec4 color) {
float r = color.r;
float g = color.g;
float b = color.b;
color.r =
min(1.0, (r * (1.0 - (0.607 * u_Amount))) + (g * (0.769 * u_Amount)) + (b * (0.189 * u_Amount)));
color.g = min(1.0, (r * 0.349 * u_Amount) + (g * (1.0 - (0.314 * u_Amount))) + (b * 0.168 * u_Amount));
color.b = min(1.0, (r * 0.272 * u_Amount) + (g * 0.534 * u_Amount) + (b * (1.0 - (0.869 * u_Amount))));
return color;
}
void main() {
gl_FragColor = vec4(texture2D(u_Texture, v_UV));
gl_FragColor = sepia_filterColor(gl_FragColor);
}

View File

@ -8,6 +8,7 @@ const TYPES = {
ILayerStyleService: Symbol.for('ILayerStyleService'),
ILogService: Symbol.for('ILogService'),
IMapService: Symbol.for('IMapService'),
IFactoryMapService: Symbol.for('Factory<IMapService>'),
IRendererService: Symbol.for('IRendererService'),
IShaderModuleService: Symbol.for('IShaderModuleService'),
IIconService: Symbol.for('IIconService'),
@ -16,13 +17,8 @@ const TYPES = {
IControlService: Symbol.for('IControlService'),
IStyleAttributeService: Symbol.for('IStyleAttributeService'),
ILayerPlugin: Symbol.for('ILayerPlugin'),
/** multi-pass */
ClearPass: Symbol.for('ClearPass'),
RenderPass: Symbol.for('RenderPass'),
CopyPass: Symbol.for('CopyPass'),
BlurHPass: Symbol.for('BlurHPass'),
BlurVPass: Symbol.for('BlurVPass'),
INewablePostProcessingPass: Symbol.for('Newable<IPostProcessingPass>'),
IFactoryPostProcessingPass: Symbol.for('Factory<IPostProcessingPass>'),
};
export { TYPES };

View File

@ -22,9 +22,9 @@
"@l7/core": "^0.0.1",
"@l7/source": "^0.0.1",
"@l7/utils": "^0.0.1",
"@mapbox/martini": "^0.1.0",
"@turf/meta": "^6.0.2",
"@types/d3-color": "^1.2.2",
"inversify": "^5.0.1",
"d3-array": "^2.3.1",
"d3-color": "^1.4.0",
"d3-scale": "^3.1.0",
@ -32,6 +32,7 @@
"eventemitter3": "^3.1.0",
"gl-matrix": "^3.1.0",
"gl-vec2": "^1.3.0",
"inversify": "^5.0.1",
"lodash": "^4.17.15",
"merge-json-schemas": "1.0.0",
"polyline-miter-util": "^1.0.1",

View File

@ -28,7 +28,7 @@ import { isFunction } from 'lodash';
// @ts-ignore
import mergeJsonSchemas from 'merge-json-schemas';
import { SyncBailHook, SyncHook } from 'tapable';
import { normalizePasses } from '../plugins/MultiPassRendererPlugin';
import baseLayerSchema from './schema';
export interface ILayerModelInitializationOptions {
@ -106,6 +106,12 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
@lazyInject(TYPES.IRendererService)
protected readonly rendererService: IRendererService;
@lazyInject(TYPES.IShaderModuleService)
protected readonly shaderModuleService: IShaderModuleService;
@lazyInject(TYPES.IMapService)
protected readonly map: IMapService;
private encodedData: IEncodeFeature[];
private configSchema: object;
@ -117,12 +123,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
ILayerInitializationOptions & ChildLayerStyleOptions
>;
@lazyInject(TYPES.IShaderModuleService)
private readonly shaderModuleService: IShaderModuleService;
@lazyInject(TYPES.IMapService)
private readonly map: IMapService;
@lazyInject(TYPES.IInteractionService)
private readonly interactionService: IInteractionService;
@ -230,11 +230,26 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
};
return this;
}
public style(options: object): ILayer {
// @ts-ignore
public style(options: object & Partial<ILayerInitializationOptions>): ILayer {
const { passes, ...rest } = options;
// passes 特殊处理
if (passes) {
normalizePasses(passes).forEach(
(pass: [string, { [key: string]: unknown }]) => {
const postProcessingPass = this.multiPassRenderer
.getPostProcessor()
.getPostProcessingPassByName(pass[0]);
if (postProcessingPass) {
postProcessingPass.updateOptions(pass[1]);
}
},
);
}
this.styleOptions = {
...this.styleOptions,
...(options as object),
...rest,
};
return this;
}
@ -328,13 +343,14 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
});
const { vs, fs, uniforms } = this.shaderModuleService.getModule(moduleName);
const { createModel } = this.rendererService;
const parserData = this.getSource().data.dataArray;
const {
attributes,
elements,
} = this.styleAttributeService.createAttributesAndIndices(
this.encodedData,
triangulation,
parserData,
);
return createModel({
attributes,

View File

@ -141,7 +141,8 @@ export function RasterImageTriangulation(feature: IEncodeFeature) {
* @param feature
* @param segNum 线线
*/
export function LineArcTriangulation(feature: IEncodeFeature, segNum = 30) {
export function LineArcTriangulation(feature: IEncodeFeature) {
const segNum = 30;
const coordinates = feature.coordinates as IPosition[];
const positions = [];
const indexArray = [];
@ -179,6 +180,35 @@ export function LineArcTriangulation(feature: IEncodeFeature, segNum = 30) {
};
}
export function HeatmapTriangulation(feature: IEncodeFeature) {
const coordinates = feature.coordinates as number[];
if (coordinates.length === 2) {
coordinates.push(0);
}
const size = feature.size as number;
const dir = addDir(-1, 1);
const dir1 = addDir(1, 1);
const dir2 = addDir(-1, -1);
const dir3 = addDir(1, -1);
// [x,y,z, dirx ,diry, weight]
const positions = [
...coordinates,
...dir,
...coordinates,
...dir2,
...coordinates,
...dir3,
...coordinates,
...dir1,
];
const indexArray = [0, 1, 2, 3, 0, 2];
return {
vertices: positions,
indices: indexArray,
size: 5,
};
}
/**
* 3d geomerty
* @param shape 3D形状
@ -259,3 +289,9 @@ function getHeatmapGeometry(shape: ShapeType2D | ShapeType3D): IExtrudeGeomety {
const geometry = fillPolygon([path]);
return geometry;
}
// 热力图计算范围
function addDir(dirX: number, dirY: number) {
const x = (dirX + 1) / 2;
const y = (dirY + 1) / 2;
return [x, y];
}

View File

@ -1,46 +0,0 @@
// import BufferBase, { IEncodeFeature, Position } from '../../core/BaseBuffer';
// import extrudePolygon, {
// fillPolygon,
// IExtrudeGeomety,
// } from '../../point/shape/extrude';
// import {
// geometryShape,
// ShapeType2D,
// ShapeType3D,
// } from '../../point/shape/Path';
// export default class GridHeatMapBuffer extends BufferBase {
// private verticesOffset: number = 0;
// protected buildFeatures() {
// this.verticesOffset = 0;
// const layerData = this.data as IEncodeFeature[];
// layerData.forEach((feature: IEncodeFeature) => {
// this.calculateFill(feature);
// });
// }
// protected calculateFeatures() {
// const layerData = this.data as IEncodeFeature[];
// const shape = layerData[0].shape as ShapeType3D | ShapeType2D;
// this.verticesCount = layerData.length;
// this.indexCount = 0;
// this.instanceGeometry = this.getGeometry(shape as
// | ShapeType2D
// | ShapeType3D);
// }
// protected calculateFill(feature: IEncodeFeature) {
// feature.bufferInfo = { verticesOffset: this.verticesOffset };
// const coordinates = feature.coordinates as Position;
// this.encodeArray(feature, 1);
// this.attributes.positions.set([...coordinates, 1], this.verticesOffset * 3);
// this.verticesOffset++;
// }
// private getGeometry(shape: ShapeType2D | ShapeType3D): IExtrudeGeomety {
// const path = geometryShape[shape]
// ? geometryShape[shape]()
// : geometryShape.circle();
// // const geometry = ShapeType2D[str as ShapeType2D]
// // ? fillPolygon([path])
// // : extrudePolygon([path]);
// const geometry = fillPolygon([path]);
// return geometry;
// }
// }

View File

@ -0,0 +1,314 @@
import {
AttributeType,
gl,
IEncodeFeature,
IFramebuffer,
ILayer,
ILayerPlugin,
ILogService,
IModel,
IStyleAttributeService,
ITexture2D,
lazyInject,
TYPES,
} from '@l7/core';
import BaseLayer from '../core/BaseLayer';
import { HeatmapTriangulation } from '../core/triangulation';
import { generateColorRamp, IColorRamp } from '../utils/color';
import heatmap3DFrag from './shaders/heatmap_3d_frag.glsl';
import heatmap3DVert from './shaders/heatmap_3d_vert.glsl';
import heatmapColorFrag from './shaders/heatmap_frag.glsl';
import heatmapFrag from './shaders/heatmap_framebuffer_frag.glsl';
import heatmapVert from './shaders/heatmap_framebuffer_vert.glsl';
import heatmapColorVert from './shaders/heatmap_vert.glsl';
import { heatMap3DTriangulation } from './triangulation';
interface IHeatMapLayerStyleOptions {
opacity: number;
intensity: number;
radius: number;
rampColors: IColorRamp;
}
export default class HeatMapLayer extends BaseLayer<IHeatMapLayerStyleOptions> {
public name: string = 'HeatMapLayer';
protected texture: ITexture2D;
protected colorTexture: ITexture2D;
protected heatmapFramerBuffer: IFramebuffer;
private intensityModel: IModel;
private colorModel: IModel;
protected getConfigSchema() {
return {
properties: {
opacity: {
type: 'number',
minimum: 0,
maximum: 1,
},
},
};
}
protected renderModels() {
const { clear, useFramebuffer } = this.rendererService;
useFramebuffer(this.heatmapFramerBuffer, () => {
clear({
color: [0, 0, 0, 0],
depth: 1,
stencil: 0,
framebuffer: this.heatmapFramerBuffer,
});
this.drawIntensityMode();
});
this.draw3DHeatMap();
// this.drawIntensityMode();
return this;
}
protected buildModels() {
this.registerBuiltinAttributes(this);
this.intensityModel = this.buildHeatMapIntensity();
this.models = [this.intensityModel];
// this.colorModel = this.buildHeatmapColor();
this.colorModel = this.buildHeatmapColor();
this.models.push(this.colorModel);
const { rampColors } = this.getStyleOptions();
const imageData = generateColorRamp(rampColors as IColorRamp);
const {
createFramebuffer,
clear,
getViewportSize,
createTexture2D,
useFramebuffer,
} = this.rendererService;
const { width, height } = getViewportSize();
this.heatmapFramerBuffer = createFramebuffer({
color: createTexture2D({
width,
height,
wrapS: gl.CLAMP_TO_EDGE,
wrapT: gl.CLAMP_TO_EDGE,
min: gl.NEAREST,
mag: gl.NEAREST,
}),
});
this.colorTexture = createTexture2D({
data: imageData.data,
width: imageData.width,
height: imageData.height,
wrapS: gl.CLAMP_TO_EDGE,
wrapT: gl.CLAMP_TO_EDGE,
min: gl.NEAREST,
mag: gl.NEAREST,
flipY: true,
});
}
private registerBuiltinAttributes(layer: ILayer) {
layer.styleAttributeService.registerStyleAttribute({
name: 'dir',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Dir',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 2,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
return [vertex[3], vertex[4]];
},
},
});
// point layer size;
layer.styleAttributeService.registerStyleAttribute({
name: 'size',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Size',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 1,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
const { size = 2 } = feature;
return [size as number];
},
},
});
}
private buildHeatMapIntensity(): IModel {
return this.buildLayerModel({
moduleName: 'heatmapintensity',
vertexShader: heatmapVert,
fragmentShader: heatmapFrag,
triangulation: HeatmapTriangulation,
depth: {
enable: false,
},
blend: {
enable: true,
func: {
srcRGB: gl.ONE,
srcAlpha: 1,
dstRGB: gl.ONE,
dstAlpha: 1,
},
},
});
}
private buildHeatmapColor(): IModel {
this.shaderModuleService.registerModule('heatmapColor', {
vs: heatmapColorVert,
fs: heatmapColorFrag,
});
const { vs, fs, uniforms } = this.shaderModuleService.getModule(
'heatmapColor',
);
const {
createAttribute,
createElements,
createBuffer,
createModel,
} = this.rendererService;
return createModel({
vs,
fs,
attributes: {
a_Position: createAttribute({
buffer: createBuffer({
data: [-1, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0],
type: gl.FLOAT,
}),
size: 3,
}),
a_Uv: createAttribute({
buffer: createBuffer({
data: [0, 1, 1, 1, 0, 0, 1, 0],
type: gl.FLOAT,
}),
size: 2,
}),
},
uniforms: {
...uniforms,
},
depth: {
enable: false,
},
count: 6,
elements: createElements({
data: [0, 2, 1, 2, 3, 1],
type: gl.UNSIGNED_INT,
count: 6,
}),
});
}
private drawIntensityMode() {
const { opacity, intensity = 10, radius = 5 } = this.getStyleOptions();
this.intensityModel.draw({
uniforms: {
u_Opacity: opacity || 1.0,
u_radius: radius,
u_intensity: intensity,
},
});
}
private drawColorMode() {
const { opacity } = this.getStyleOptions();
this.colorModel.draw({
uniforms: {
u_Opacity: opacity || 1.0,
u_colorTexture: this.colorTexture,
u_texture: this.heatmapFramerBuffer,
},
});
}
private draw3DHeatMap() {
const { opacity } = this.getStyleOptions();
const mapbounds = this.map.getBounds();
this.colorModel.draw({
uniforms: {
u_Opacity: opacity || 1.0,
u_colorTexture: this.colorTexture,
u_texture: this.heatmapFramerBuffer,
u_extent: [-179.9476, -60.0959, 179.9778, 79.5651],
},
});
}
private build3dHeatMap() {
const { getViewportSize } = this.rendererService;
const { width, height } = getViewportSize();
const triangulation = heatMap3DTriangulation(256, 128);
this.shaderModuleService.registerModule('heatmap3dColor', {
vs: heatmap3DVert,
fs: heatmap3DFrag,
});
const { vs, fs, uniforms } = this.shaderModuleService.getModule(
'heatmap3dColor',
);
const {
createAttribute,
createElements,
createBuffer,
createModel,
} = this.rendererService;
return createModel({
vs,
fs,
attributes: {
a_Position: createAttribute({
buffer: createBuffer({
data: triangulation.vertices,
type: gl.FLOAT,
}),
size: 3,
}),
a_Uv: createAttribute({
buffer: createBuffer({
data: triangulation.uvs,
type: gl.FLOAT,
}),
size: 2,
}),
},
primitive: gl.TRIANGLES,
uniforms: {
...uniforms,
},
depth: {
enable: false,
},
elements: createElements({
data: triangulation.indices,
type: gl.UNSIGNED_INT,
count: triangulation.indices.length,
}),
});
}
}

View File

@ -0,0 +1,16 @@
uniform sampler2D u_texture;
uniform sampler2D u_colorTexture;
uniform float u_Opacity;
varying vec2 v_texCoord;
void main(){
float intensity = texture2D(u_texture, v_texCoord).r;
vec2 ramp_pos = vec2(
fract(16.0 * (1.0 - intensity)),
floor(16.0 * (1.0 - intensity)) / 16.0);
// vec4 color = texture2D(u_colorTexture,vec2(0.5,1.0-intensity));
vec4 color = texture2D(u_colorTexture,ramp_pos);
gl_FragColor = color;
gl_FragColor.a = color.a * smoothstep(0.1,0.5,intensity) * u_Opacity;
}

View File

@ -0,0 +1,23 @@
precision highp float;
attribute vec3 a_Position;
attribute vec2 a_Uv;
uniform sampler2D u_texture;
uniform vec4 u_extent;
varying vec2 v_texCoord;
uniform mat4 u_ModelMatrix;
#pragma include "projection"
void main() {
v_texCoord = a_Uv;
vec2 minxy = project_position(vec4(u_extent.xy, 0, 1.0)).xy;
vec2 maxxy = project_position(vec4(u_extent.zw, 0, 1.0)).xy;
vec2 step = (maxxy - minxy);
vec2 pos = minxy + (vec2(a_Position.x, a_Position.y ) + vec2(1.0)) / vec2(2.0) * step;
float intensity = texture2D(u_texture, v_texCoord).r;
gl_Position = project_common_position_to_clipspace(vec4(pos.xy, 0, 1.0));
v_texCoord = (gl_Position.xy + vec2(1.0)) / vec2(2.0) * gl_Position.w;
// v_texCoord.y = 1.0 - v_texCoord.y;
}

View File

@ -0,0 +1,16 @@
uniform sampler2D u_texture;
uniform sampler2D u_colorTexture;
uniform float u_Opacity;
varying vec2 v_texCoord;
void main(){
float intensity = texture2D(u_texture, v_texCoord).r;
vec2 ramp_pos = vec2(
fract(16.0 * (1.0 - intensity)),
floor(16.0 * (1.0 - intensity)) / 16.0);
// vec4 color = texture2D(u_colorTexture,vec2(0.5,1.0-intensity));
vec4 color = texture2D(u_colorTexture,ramp_pos);
gl_FragColor = color;
gl_FragColor.a = color.a * smoothstep(0.1,0.5,intensity) * u_Opacity;
}

View File

@ -0,0 +1,12 @@
precision highp float;
uniform float u_intensity;
varying float v_weight;
varying vec2 v_extrude;
void main(){
float GAUSS_COEF = 0.3989422804014327;
float d = -0.5 * 3.0 * 3.0 * dot(v_extrude, v_extrude);
float val = v_weight * u_intensity * GAUSS_COEF * exp(d);
gl_FragColor = vec4(val, val, val, val);
}

View File

@ -0,0 +1,27 @@
precision highp float;
attribute vec3 a_Position;
attribute float a_Size;
attribute vec2 a_Dir;
uniform float u_intensity;
uniform float u_radius;
varying vec2 v_extrude;
varying float v_weight;
uniform mat4 u_ModelMatrix;
#pragma include "projection"
void main(){
v_weight = a_Size;
float GAUSS_COEF = 0.3989422804014327;
float ZERO = 1.0 / 255.0 / 16.0;
float extrude_x = a_Dir.x * 2.0 -1.0;
float extrude_y = a_Dir.y * 2.0 -1.0;
vec2 extrude_dir = normalize(vec2(extrude_x,extrude_y));
float S = sqrt(-2.0 * log(ZERO / a_Size / u_intensity / GAUSS_COEF)) / 3.0;
v_extrude = extrude_dir * S;
vec2 offset = project_pixel(v_extrude * u_radius);
vec4 project_pos = project_position(vec4(a_Position.xy, 0.0, 1.0));
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, 0.0, 1.0));
}

View File

@ -0,0 +1,10 @@
precision highp float;
attribute vec3 a_Position;
attribute vec2 a_Uv;
uniform sampler2D u_texture;
varying vec2 v_texCoord;
void main() {
v_texCoord = a_Uv;
float intensity = texture2D(u_texture, v_texCoord).r;
gl_Position = vec4(a_Position.xy,intensity -0.5, 1.);
}

View File

@ -0,0 +1,36 @@
import { IEncodeFeature, IParseDataItem } from '@l7/core';
// @ts-ignore
import Martini from '@mapbox/martini';
export function heatMap3DTriangulation(width: number, height: number) {
const indices = [];
const vertices = [];
const uvs = [];
const gridX1 = width + 1;
const gridY1 = height + 1;
const widthHalf = width / 2;
const heightHalf = height / 2;
for (let iy = 0; iy < gridY1; iy++) {
const y = iy - heightHalf;
for (let ix = 0; ix < gridX1; ix++) {
const x = ix - widthHalf;
vertices.push(x / widthHalf, -y / heightHalf, 0);
uvs.push(ix / width);
uvs.push(1 - iy / height);
}
}
for (let iy = 0; iy < height; iy++) {
for (let ix = 0; ix < width; ix++) {
const a = ix + gridX1 * iy;
const b = ix + gridX1 * (iy + 1);
const c = ix + 1 + gridX1 * (iy + 1);
const d = ix + 1 + gridX1 * iy;
indices.push(a, b, d);
indices.push(b, c, d);
}
}
return {
vertices,
indices,
uvs,
};
}

View File

@ -1,16 +1,19 @@
import { container, ILayerPlugin, TYPES } from '@l7/core';
import BaseLayer from './core/BaseLayer';
import HeatMapGridLayer from './heatmap/grid';
import HeatMapLayer from './heatmap/heatmap';
import ArcLineLayer from './line/arc';
import Arc2DLineLayer from './line/arc2d';
import LineLayer from './line/index';
import Point3dLayer from './point/extrude';
import PointImageLayer from './point/image';
import PointLayer from './point/index';
import TextLayer from './point/text';
// import Point from './point/point';
import PolygonLayer from './polygon';
import Polygon3DLayer from './polygon/polygon3D';
import ImageLayer from './raster/image';
import RasterLayer from './raster/raster';
import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin';
import DataMappingPlugin from './plugins/DataMappingPlugin';
@ -76,7 +79,9 @@ export {
HeatMapGridLayer,
ArcLineLayer,
Arc2DLineLayer,
// Line,
RasterLayer,
HeatMapLayer,
TextLayer,
// ImageLayer,
// HeatMapLayer,
};

View File

@ -26,7 +26,7 @@ export default class LineLayer extends BaseLayer<IPointLayerStyleOptions> {
this.models.forEach((model) =>
model.draw({
uniforms: {
u_Opacity: opacity || 0,
u_Opacity: opacity || 1.0,
},
}),
);

View File

@ -193,7 +193,7 @@ export default class FeatureScalePlugin implements ILayerPlugin {
}
private getDefaultType(firstValue: unknown) {
let type = ScaleTypes.QUANTIZE;
let type = ScaleTypes.LINEAR;
if (typeof firstValue === 'string') {
type = dateRegex.test(firstValue) ? ScaleTypes.TIME : ScaleTypes.CAT;
}

View File

@ -1,33 +1,22 @@
import {
BlurHPass,
BlurVPass,
ClearPass,
CopyPass,
IGlobalConfigService,
ILayer,
ILayerPlugin,
IPostProcessingPass,
IRendererService,
lazyInject,
MultiPassRenderer,
PixelPickingPass,
RenderPass,
TAAPass,
TYPES,
} from '@l7/core';
import { inject, injectable } from 'inversify';
const builtinPostProcessingPassMap: {
[key: string]: new (config?: { [key: string]: any }) => IPostProcessingPass;
} = {
blurH: BlurHPass,
blurV: BlurVPass,
};
import { inject, injectable, interfaces, multiInject } from 'inversify';
/**
* 'blurH' -> ['blurH', {}]
*/
function normalizePasses(
export function normalizePasses(
passes: Array<string | [string, { [key: string]: unknown }]>,
) {
return passes.map((pass: string | [string, { [key: string]: unknown }]) => {
@ -57,6 +46,11 @@ export default class MultiPassRendererPlugin implements ILayerPlugin {
@inject(TYPES.IRendererService)
private readonly rendererService: IRendererService;
@inject(TYPES.IFactoryPostProcessingPass)
private readonly postProcessingPassFactory: (
name: string,
) => IPostProcessingPass<unknown>;
private enabled: boolean;
public apply(layer: ILayer) {
@ -110,7 +104,7 @@ export default class MultiPassRendererPlugin implements ILayerPlugin {
multiPassRenderer.add(new PixelPickingPass());
}
// TAA pass if enabled
// use TAA pass if enabled instead of render pass
if (enableTAA) {
multiPassRenderer.add(new TAAPass());
} else {
@ -121,13 +115,16 @@ export default class MultiPassRendererPlugin implements ILayerPlugin {
// post processing
normalizePasses(passes).forEach(
(pass: [string, { [key: string]: unknown }]) => {
const PostProcessingPassClazz = builtinPostProcessingPassMap[pass[0]];
multiPassRenderer.add(new PostProcessingPassClazz(pass[1]));
const [passName, initializationOptions] = pass;
multiPassRenderer.add(
this.postProcessingPassFactory(passName),
initializationOptions,
);
},
);
// 末尾为固定的 CopyPass
multiPassRenderer.add(new CopyPass());
multiPassRenderer.add(this.postProcessingPassFactory('copy'));
return multiPassRenderer;
}

View File

@ -26,7 +26,7 @@ export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
this.models.forEach((model) =>
model.draw({
uniforms: {
u_Opacity: opacity || 0,
u_Opacity: opacity || 1.0,
},
}),
);

View File

@ -46,7 +46,7 @@ export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
this.models.forEach((model) =>
model.draw({
uniforms: {
u_Opacity: opacity || 0,
u_Opacity: opacity || 1.0,
u_texture: createTexture2D({
data: this.iconService.getCanvas(),
width: 1024,

View File

@ -44,7 +44,7 @@ export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
this.models.forEach((model) =>
model.draw({
uniforms: {
u_Opacity: opacity || 0,
u_Opacity: opacity || 1.0,
},
}),
);
@ -118,8 +118,8 @@ export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
vertex: number[],
attributeIdx: number,
) => {
const { size = 2 } = feature;
return [size as number];
const { size } = feature;
return Array.isArray(size) ? [size[0]] : [size as number];
},
},
});

View File

@ -13,7 +13,9 @@ uniform vec4 u_activeColor : [1.0, 0.0, 0.0, 1.0];
varying vec2 v_uv;
varying float v_gamma_scale;
varying vec4 v_color;
#pragma include "projection"
void main() {
v_color = a_color;
v_uv = a_tex / u_sdf_map_size;
@ -24,10 +26,10 @@ void main() {
vec4 project_pos = project_position(vec4(a_Position, 1.0));
vec4 projected_position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
gl_Position = vec4(projected_position.xy / projected_position.w
+ a_offset * fontScale / u_viewport_size * 2., 0.0, 1.0);
v_gamma_scale = gl_Position.w;
}

View File

@ -0,0 +1,188 @@
import {
AttributeType,
gl,
IEncodeFeature,
IFontOptions,
ILayer,
ILayerPlugin,
ILogService,
IStyleAttributeService,
lazyInject,
TYPES,
} from '@l7/core';
import BaseLayer from '../core/BaseLayer';
import { getGlyphQuads, shapeText } from '../utils/symbol-layout';
import textFrag from './shaders/text_frag.glsl';
import textVert from './shaders/text_vert.glsl';
interface IPointTextLayerStyleOptions {
opacity: number;
textAnchor: string;
textOffset: [number, number];
spacing: number;
padding: [number, number];
stroke: string;
strokeWidth: number;
strokeOpacity: number;
fontWeight: string;
fontFamily: string;
textAllowOverlap: boolean;
}
export function PointTriangulation(feature: IEncodeFeature) {
const coordinates = feature.coordinates as number[];
return {
vertices: [...coordinates, ...coordinates, ...coordinates, ...coordinates],
indices: [0, 1, 2, 2, 3, 0],
size: coordinates.length,
};
}
export default class TextLayer extends BaseLayer<IPointTextLayerStyleOptions> {
public name: string = 'PointLayer';
protected getConfigSchema() {
return {
properties: {
opacity: {
type: 'number',
minimum: 0,
maximum: 1,
},
},
};
}
protected renderModels() {
const { opacity } = this.getStyleOptions();
this.models.forEach((model) =>
model.draw({
uniforms: {
u_Opacity: opacity || 1.0,
},
}),
);
return this;
}
protected buildModels() {
this.registerBuiltinAttributes(this);
this.models = [
this.buildLayerModel({
moduleName: 'pointText',
vertexShader: textVert,
fragmentShader: textFrag,
triangulation: PointTriangulation,
depth: { enable: false },
blend: {
enable: true,
func: {
srcRGB: gl.SRC_ALPHA,
srcAlpha: 1,
dstRGB: gl.ONE_MINUS_SRC_ALPHA,
dstAlpha: 1,
},
},
}),
];
}
private registerBuiltinAttributes(layer: ILayer) {
layer.styleAttributeService.registerStyleAttribute({
name: 'textOffsets',
type: AttributeType.Attribute,
descriptor: {
name: 'a_textOffsets',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.STATIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 2,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
const extrude = [-1, -1, 1, -1, 1, 1, -1, 1];
const extrudeIndex = (attributeIdx % 4) * 2;
return [extrude[extrudeIndex], extrude[extrudeIndex + 1]];
},
},
});
// point layer size;
layer.styleAttributeService.registerStyleAttribute({
name: 'size',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Size',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 1,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
const { size } = feature;
return Array.isArray(size) ? [size[0]] : [size as number];
},
},
});
// point layer size;
layer.styleAttributeService.registerStyleAttribute({
name: 'shape',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Shape',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 1,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
const { shape = 2 } = feature;
const shape2d = layer.configService.getConfig().shape2d as string[];
const shapeIndex = shape2d.indexOf(shape as string);
return [shapeIndex];
},
},
});
}
private iniTextFont() {
const { fontWeight = 'normal', fontFamily } = this.getStyleOptions();
const data = this.getEncodedData();
const characterSet: string[] = [];
data.forEach((item: IEncodeFeature) => {
let { text = '' } = item;
text = text.toString();
for (const char of text) {
// 去重
if (characterSet.indexOf(char) === -1) {
characterSet.push(char);
}
}
});
this.fontService.setFontOptions({
characterSet,
fontWeight,
fontFamily,
});
}
}

View File

@ -40,7 +40,7 @@ export default class PolygonLayer extends BaseLayer<IPolygonLayerStyleOptions> {
this.models.forEach((model) =>
model.draw({
uniforms: {
u_Opacity: opacity || 0,
u_Opacity: opacity || 1.0,
},
}),
);

View File

@ -26,7 +26,7 @@ export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
this.models.forEach((model) =>
model.draw({
uniforms: {
u_Opacity: opacity || 0,
u_Opacity: opacity || 1.0,
},
}),
);

View File

@ -10,8 +10,8 @@ varying vec4 v_Color;
#pragma include "picking"
void main() {
v_Color =a_Color;
vec4 project_pos = project_position(vec4(a_Position,1.0));
v_Color = a_Color;
vec4 project_pos = project_position(vec4(a_Position, 1.0));
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
setPickingColor(a_PickingColor);

View File

@ -1,33 +0,0 @@
// import BaseBuffer, { IEncodeFeature, Position } from '../../core/BaseBuffer';
// interface IImageFeature extends IEncodeFeature {
// images: any[];
// }
// export default class ImageBuffer extends BaseBuffer {
// protected calculateFeatures() {
// this.verticesCount = 6;
// this.indexCount = 6;
// }
// protected buildFeatures() {
// this.attributes.uv = new Float32Array(this.verticesCount * 2);
// const layerData = this.data as IImageFeature[];
// const coordinates = layerData[0].coordinates as Position[];
// const positions: number[] = [
// ...coordinates[0],
// 0,
// coordinates[1][0],
// coordinates[0][1],
// 0,
// ...coordinates[1],
// 0,
// ...coordinates[0],
// 0,
// ...coordinates[1],
// 0,
// coordinates[0][0],
// coordinates[1][1],
// 0,
// ];
// this.attributes.positions.set(positions, 0);
// this.attributes.uv.set([0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0], 0);
// }
// }

View File

@ -0,0 +1,25 @@
import { IEncodeFeature, IParseDataItem } from '@l7/core';
// @ts-ignore
import Martini from '@mapbox/martini';
export function RasterTriangulation(
feature: IEncodeFeature,
parserData: IParseDataItem,
) {
const { coordinates, data, min, max, width, height } = parserData;
const maxlength = Math.max(width, height);
const gridSize = Math.pow(2, Math.ceil(Math.log2(maxlength))) + 1;
const terrain = new Float32Array(gridSize * gridSize);
for (let i = 0; i < width; i++) {
for (let j = 0; j < height; j++) {
terrain[i * gridSize + j] = data[i * width + j];
}
}
const martini = new Martini(gridSize);
const tile = martini.createTile(terrain);
const mesh = tile.getMesh(1024);
return {
vertices: Array.from(mesh.vertices) as number[],
indices: Array.from(mesh.triangles) as number[],
size: 2,
};
}

View File

@ -0,0 +1,104 @@
import {
AttributeType,
gl,
IEncodeFeature,
ILayer,
ILayerPlugin,
ILogService,
IRasterParserDataItem,
IStyleAttributeService,
ITexture2D,
lazyInject,
TYPES,
} from '@l7/core';
import BaseLayer from '../core/BaseLayer';
import { generateColorRamp, IColorRamp } from '../utils/color';
import { RasterTriangulation } from './buffers/triangulation';
import rasterFrag from './shaders/raster_frag.glsl';
import rasterVert from './shaders/raster_vert.glsl';
interface IRasterLayerStyleOptions {
opacity: number;
min: number;
max: number;
extent: [number, number, number, number];
rampColors: IColorRamp;
}
export default class ImageLayer extends BaseLayer<IRasterLayerStyleOptions> {
public name: string = 'RasterLayer';
protected texture: ITexture2D;
protected colorTexture: ITexture2D;
protected getConfigSchema() {
return {
properties: {
opacity: {
type: 'number',
minimum: 0,
maximum: 1,
},
},
};
}
protected renderModels() {
const { opacity } = this.getStyleOptions();
const parserDataItem = this.getSource().data.dataArray[0];
const { coordinates, width, height, min, max } = parserDataItem;
this.models.forEach((model) =>
model.draw({
uniforms: {
u_Opacity: opacity || 1,
u_texture: this.texture,
u_min: min,
u_width: width,
u_height: height,
u_max: max,
u_colorTexture: this.colorTexture,
u_extent: [...coordinates[0], ...coordinates[1]],
},
}),
);
return this;
}
protected buildModels() {
const parserDataItem = this.getSource().data.dataArray[0];
const { createTexture2D } = this.rendererService;
this.texture = createTexture2D({
data: parserDataItem.data,
width: parserDataItem.width,
height: parserDataItem.height,
format: gl.LUMINANCE,
type: gl.FLOAT,
});
const { rampColors } = this.getStyleOptions();
const imageData = generateColorRamp(rampColors as IColorRamp);
this.colorTexture = createTexture2D({
data: imageData.data,
width: imageData.width,
height: imageData.height,
flipY: true,
});
this.models = [
this.buildLayerModel({
moduleName: 'Raster',
vertexShader: rasterVert,
fragmentShader: rasterFrag,
triangulation: RasterTriangulation,
primitive: gl.TRIANGLES,
depth: { enable: false },
blend: {
enable: true,
func: {
srcRGB: gl.SRC_ALPHA,
srcAlpha: 1,
dstRGB: gl.ONE_MINUS_SRC_ALPHA,
dstAlpha: 1,
},
},
}),
];
}
}

View File

@ -0,0 +1,9 @@
varying vec4 v_color;
uniform float u_Opacity: 1.0;
#define PI 3.141592653589793
void main() {
gl_FragColor = v_color;
gl_FragColor.a *= u_Opacity;
}

View File

@ -0,0 +1,40 @@
precision highp float;
uniform mat4 u_ModelMatrix;
attribute vec3 a_Position;
uniform vec4 u_extent;
uniform sampler2D u_texture;
uniform sampler2D u_colorTexture;
uniform float u_min;
uniform float u_max;
uniform float u_width;
uniform float u_height;
varying vec2 v_texCoord;
varying vec4 v_color;
#pragma include "projection"
void main() {
vec2 uv = a_Position.xy / vec2(u_width, u_height);
vec2 minxy = project_position(vec4(u_extent.xy, 0, 1.0)).xy;
vec2 maxxy = project_position(vec4(u_extent.zw, 0, 1.0)).xy;
float value = texture2D(u_texture, vec2(uv.x,1.0 - uv.y)).x;
vec2 step = (maxxy - minxy) / vec2(u_width, u_height);
vec2 pos = minxy + vec2(a_Position.x, a_Position.y ) * step;
// v_texCoord = a_Uv;
value = clamp(value,u_min,u_max);
float value1 = (value - u_min) / (u_max -u_min);
vec2 ramp_pos = vec2(
fract(16.0 * (1.0 - value1)),
floor(16.0 * (1.0 - value1)) / 16.0);
v_color = texture2D(u_colorTexture,ramp_pos);
// if(uv.x > 1.0 || uv.y > 1.0) {
// v_color = vec4(0.);
// }
// vec2 range = u_extent.zw - u_extent.xy;
// vec4 project_pos = project_position(vec4(pos, 0, 1.0));
gl_Position = project_common_position_to_clipspace(vec4(pos.xy, project_scale(value) * 50., 1.0));
}

View File

@ -1,4 +1,8 @@
import * as d3 from 'd3-color';
export interface IColorRamp {
positions: number[];
colors: string[];
}
export function rgb2arr(str: string) {
const color = d3.color(str) as d3.RGBColor;
const arr = [0, 0, 0, 0];
@ -10,3 +14,23 @@ export function rgb2arr(str: string) {
}
return arr;
}
export function generateColorRamp(colorRamp: IColorRamp): ImageData {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
canvas.width = 256;
canvas.height = 1;
const gradient = ctx.createLinearGradient(0, 0, 256, 0);
let data = null;
const min = colorRamp.positions[0];
const max = colorRamp.positions[colorRamp.positions.length - 1];
for (let i = 0; i < colorRamp.colors.length; ++i) {
const value = (colorRamp.positions[i] - min) / (max - min);
gradient.addColorStop(value, colorRamp.colors[i]);
}
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 256, 1);
data = new Uint8ClampedArray(ctx.getImageData(0, 0, 256, 1).data);
return new ImageData(data, 16, 16);
}

View File

@ -0,0 +1,260 @@
/**
*
* @param {string} anchor
* @return {alignment} alignment
*/
function getAnchorAlignment(anchor: string) {
let horizontalAlign = 0.5;
let verticalAlign = 0.5;
switch (anchor) {
case 'right':
case 'top-right':
case 'bottom-right':
horizontalAlign = 1;
break;
case 'left':
case 'top-left':
case 'bottom-left':
horizontalAlign = 0;
break;
default:
horizontalAlign = 0.5;
}
switch (anchor) {
case 'bottom':
case 'bottom-right':
case 'bottom-left':
verticalAlign = 1;
break;
case 'top':
case 'top-right':
case 'top-left':
verticalAlign = 0;
break;
default:
verticalAlign = 0.5;
}
return { horizontalAlign, verticalAlign };
}
// justify right = 1, left = 0, center = 0.5
function justifyLine(
positionedGlyphs: any,
glyphMap: any,
start: number,
end: number,
justify: number,
) {
if (!justify) {
return;
}
const lastPositionedGlyph = positionedGlyphs[end];
const glyph = lastPositionedGlyph.glyph;
if (glyph) {
const lastAdvance = glyphMap[glyph].advance * lastPositionedGlyph.scale;
const lineIndent = (positionedGlyphs[end].x + lastAdvance) * justify;
for (let j = start; j <= end; j++) {
positionedGlyphs[j].x -= lineIndent;
}
}
}
// justify right=1 left=0 center=0.5
// horizontalAlign right=1 left=0 center=0.5
// verticalAlign right=1 left=0 center=0.5
function align(
positionedGlyphs: any[],
justify: number,
horizontalAlign: number,
verticalAlign: number,
maxLineLength: number,
lineHeight: number,
lineCount: number,
) {
const shiftX = (justify - horizontalAlign) * maxLineLength;
const shiftY = (-verticalAlign * lineCount + 0.5) * lineHeight;
for (const glyphs of positionedGlyphs) {
glyphs.x += shiftX;
glyphs.y += shiftY;
}
}
function shapeLines(
shaping: any,
glyphMap: any,
lines: any[],
lineHeight: number,
textAnchor: string,
textJustify: string,
spacing: number,
) {
// buffer 为 4
const yOffset = -8;
let x = 0;
let y = yOffset;
let maxLineLength = 0;
const positionedGlyphs = shaping.positionedGlyphs;
const justify =
textJustify === 'right' ? 1 : textJustify === 'left' ? 0 : 0.5;
const lineStartIndex = positionedGlyphs.length;
lines.forEach((line) => {
line.split('').forEach((char: string) => {
const glyph = glyphMap[char];
const baselineOffset = 0;
if (glyph) {
positionedGlyphs.push({
glyph: char,
x,
y: y + baselineOffset,
vertical: false, // TODO目前只支持水平方向
scale: 1,
metrics: glyph,
});
x += glyph.advance + spacing;
}
});
// 左右对齐
if (positionedGlyphs.length !== lineStartIndex) {
const lineLength = x - spacing;
maxLineLength = Math.max(lineLength, maxLineLength);
justifyLine(
positionedGlyphs,
glyphMap,
lineStartIndex,
positionedGlyphs.length - 1,
justify,
);
}
x = 0;
y += lineHeight;
});
const { horizontalAlign, verticalAlign } = getAnchorAlignment(textAnchor);
align(
positionedGlyphs,
justify,
horizontalAlign,
verticalAlign,
maxLineLength,
lineHeight,
lines.length,
);
// 计算包围盒
const height = y - yOffset;
shaping.top += -verticalAlign * height;
shaping.bottom = shaping.top + height;
shaping.left += -horizontalAlign * maxLineLength;
shaping.right = shaping.left + maxLineLength;
}
/**
*
*
* @param {string} text
* @param {*} glyphs mapping
* @param {number} lineHeight
* @param {string} textAnchor
* @param {string} textJustify
* @param {number} spacing
* @param {[number, number]} translate &
* @return {boolean|shaping}
*/
export function shapeText(
text: string,
glyphs: any,
lineHeight: number,
textAnchor: string,
textJustify: string,
spacing: number,
translate: [number, number],
) {
// TODO处理换行
const lines = text.split('\n');
const positionedGlyphs: any[] = [];
const shaping = {
positionedGlyphs,
top: translate[1],
bottom: translate[1],
left: translate[0],
right: translate[0],
lineCount: lines.length,
text,
};
shapeLines(
shaping,
glyphs,
lines,
lineHeight,
textAnchor,
textJustify,
spacing,
);
if (!positionedGlyphs.length) {
return false;
}
return shaping;
}
export function getGlyphQuads(
shaping: any,
textOffset: [number, number],
alongLine: boolean,
) {
const { positionedGlyphs } = shaping;
const quads = [];
for (const positionedGlyph of positionedGlyphs) {
const rect = positionedGlyph.metrics;
// The rects have an addditional buffer that is not included in their size.
const rectBuffer = 4;
const halfAdvance = (rect.advance * positionedGlyph.scale) / 2;
const glyphOffset = alongLine
? [positionedGlyph.x + halfAdvance, positionedGlyph.y]
: [0, 0];
const builtInOffset = alongLine
? [0, 0]
: [
positionedGlyph.x + halfAdvance + textOffset[0],
positionedGlyph.y + textOffset[1],
];
const x1 =
(0 - rectBuffer) * positionedGlyph.scale - halfAdvance + builtInOffset[0];
const y1 = (0 - rectBuffer) * positionedGlyph.scale + builtInOffset[1];
const x2 = x1 + rect.width * positionedGlyph.scale;
const y2 = y1 + rect.height * positionedGlyph.scale;
const tl = { x: x1, y: y1 };
const tr = { x: x2, y: y1 };
const bl = { x: x1, y: y2 };
const br = { x: x2, y: y2 };
// TODO处理字符旋转的情况
quads.push({ tl, tr, bl, br, tex: rect, glyphOffset });
}
return quads;
}

View File

@ -22,6 +22,7 @@ export default class ReglTexture2D implements ITexture2D {
type = gl.UNSIGNED_BYTE,
width,
height,
flipY = false,
format = gl.RGBA,
mipmap = false,
wrapS = gl.CLAMP_TO_EDGE,
@ -46,6 +47,7 @@ export default class ReglTexture2D implements ITexture2D {
mag: filterMap[mag],
min: filterMap[min],
alignment,
flipY,
colorSpace: colorSpaceMap[colorSpace],
premultiplyAlpha,
aniso,

View File

@ -21,6 +21,7 @@ import {
} from '@l7/core';
import { AMapService, MapboxService } from '@l7/maps';
import { ReglRendererService } from '@l7/renderer';
import { interfaces } from 'inversify';
import { Map } from 'mapbox-gl';
// 绑定渲染引擎服务
@ -28,6 +29,24 @@ container
.bind<IRendererService>(TYPES.IRendererService)
.to(ReglRendererService)
.inSingletonScope();
// // 绑定地图服务 AMap & Mapbox
// container
// .bind<IMapService>(TYPES.IMapService)
// .to(AMapService)
// .whenTargetNamed(MapType.amap)
// .inSingletonScope();
// container
// .bind<IMapService>(TYPES.IMapService)
// .to(MapboxService)
// .inSingletonScope();
// // 地图服务工厂,根据 name 返回指定服务
// container
// .bind<interfaces.Factory<IMapService>>(TYPES.IFactoryMapService)
// .toFactory<IMapService>((context) => {
// return (named: string) => {
// return context.container.getNamed<IMapService>(TYPES.IMapService, named);
// };
// });
// 缓存当前地图类型,便于 DEMO 中切换底图时动态绑定
let mapType: MapType;
@ -52,7 +71,6 @@ class Scene {
private iconService: IIconService;
// private mapType: MapType;
public constructor(config: IMapConfig & IRenderConfig) {
const { type = MapType.amap } = config;

View File

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

View File

@ -1,5 +1,5 @@
import { IParserData } from '@l7/core';
import { getImage } from '@l7/utils';
import { IParserData } from '../interface';
interface IImageCfg {
extent: [number, number, number, number];
}

View File

@ -0,0 +1,19 @@
import { IParserData, IRasterCfg } from '@l7/core';
export default function raster(data: number[], cfg: IRasterCfg): IParserData {
const { extent, width, height, min, max } = cfg;
const resultData = {
_id: 1,
dataArray: [
{
_id: 1,
data: Array.from(data),
width,
height,
min,
max,
coordinates: [[extent[0], extent[1]], [extent[2], extent[3]]],
},
],
};
return resultData;
}

View File

@ -2,6 +2,7 @@ import { storiesOf } from '@storybook/react';
import * as React from 'react';
import Arc2DLineDemo from './components/Arc2DLine';
import ArcLineDemo from './components/Arcline';
import HeatMapDemo from './components/heatMap';
import GridHeatMap from './components/heatMapgrid';
import LineLayer from './components/Line';
import PointDemo from './components/Point';
@ -9,15 +10,18 @@ import Point3D from './components/Point3D';
import PointImage from './components/pointImage';
import Polygon3D from './components/polygon3D';
import ImageLayerDemo from './components/rasterImage';
import RasterLayerDemo from './components/RasterLayer';
// @ts-ignore
storiesOf('图层', module)
.add('点图层', () => <PointDemo />)
.add('3D点', () => <Point3D />)
.add('图片标注', () => <PointImage />)
.add('面3d图层', () => <Polygon3D />)
.add('线图层', () => <LineLayer />)
.add('3D弧线', () => <ArcLineDemo />)
.add('2D弧线', () => <Arc2DLineDemo />)
.add('网格热力图', () => <GridHeatMap />)
// .add('点图层', () => <PointDemo />)
// .add('3D点', () => <Point3D />)
// .add('图片标注', () => <PointImage />)
// .add('面3d图层', () => <Polygon3D />)
// .add('线图层', () => <LineLayer />)
// .add('3D弧线', () => <ArcLineDemo />)
// .add('2D弧线', () => <Arc2DLineDemo />)
// .add('网格热力图', () => <GridHeatMap />)
.add('热力图', () => <HeatMapDemo />)
// .add('栅格', () => <RasterLayerDemo />)
.add('图片', () => <ImageLayerDemo />);

View File

@ -57,6 +57,7 @@ export default class Point3D extends React.Component {
scene.addLayer(pointLayer);
console.log(pointLayer);
scene.render();
this.scene = scene;
}
public render() {

View File

@ -39,6 +39,7 @@ export default class Point3D extends React.Component {
.size([15, 10]);
scene.addLayer(pointLayer);
scene.render();
this.scene = scene;
}
public render() {

View File

@ -0,0 +1,92 @@
import { RasterLayer } from '@l7/layers';
import { Scene } from '@l7/scene';
// @ts-ignore
import * as GeoTIFF from 'geotiff/dist/geotiff.bundle.js';
import * as React from 'react';
export default class ImageLayerDemo extends React.Component {
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const scene = new Scene({
center: [121.268, 30.3628],
id: 'map',
pitch: 0,
type: 'mapbox',
style: 'mapbox://styles/mapbox/streets-v9',
zoom: 2,
});
const tiffdata = await this.getTiffData();
const layer = new RasterLayer({});
layer
.source(tiffdata.data, {
parser: {
type: 'raster',
width: tiffdata.width,
height: tiffdata.height,
min: 0,
max: 8000,
extent: [73.482190241, 3.82501784112, 135.106618732, 57.6300459963],
},
})
.style({
opacity: 0.8,
rampColors: {
colors: [
'#002466',
'#0D408C',
'#105CB3',
'#1A76C7',
'#2894E0',
'#3CB4F0',
'#65CEF7',
'#98E3FA',
'#CFF6FF',
'#E8FCFF',
],
positions: [0, 0.02, 0.05, 0.1, 0.2, 0.3, 0.5, 0.6, 0.8, 1.0],
},
});
scene.addLayer(layer);
console.log(layer);
scene.render();
this.scene = scene;
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
private async getTiffData() {
const response = await fetch(
'https://gw.alipayobjects.com/os/rmsportal/XKgkjjGaAzRyKupCBiYW.dat',
);
const arrayBuffer = await response.arrayBuffer();
const tiff = await GeoTIFF.fromArrayBuffer(arrayBuffer);
const image = await tiff.getImage();
const width = image.getWidth();
const height = image.getHeight();
const values = await image.readRasters();
return {
data: values[0],
width,
height,
min: 0,
max: 8000,
};
}
}

View File

@ -0,0 +1,77 @@
import { PointLayer } from '@l7/layers';
import { Scene } from '@l7/scene';
import * as React from 'react';
import data from '../data/data.json';
export default class Point3D extends React.Component {
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public componentDidMount() {
const scene = new Scene({
center: [120.19382669582967, 30.258134],
id: 'map',
pitch: 0,
type: 'mapbox',
style: 'mapbox://styles/mapbox/streets-v9',
zoom: 1,
});
const pointLayer = new PointLayer({});
const p1 = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: [83.671875, 44.84029065139799],
},
},
],
};
pointLayer
.source(data)
.color('name', [
'#FFF5B8',
'#FFDC7D',
'#FFAB5C',
'#F27049',
'#D42F31',
'#730D1C',
])
.shape('subregion',[
'circle',
'triangle',
'square',
'pentagon',
'hexagon',
'octogon',
'hexagram',
'rhombus',
'vesica',
])
.size('scalerank', [2, 4, 6, 8, 10]);
scene.addLayer(pointLayer);
console.log(pointLayer);
scene.render();
this.scene = scene;
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}

View File

@ -0,0 +1,70 @@
import { HeatMapLayer } from '@l7/layers';
import { Scene } from '@l7/scene';
// @ts-ignore
import * as React from 'react';
export default class HeatMapLayerDemo extends React.Component {
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/d3564b06-670f-46ea-8edb-842f7010a7c6.json',
);
const scene = new Scene({
center: [121.268, 30.3628],
id: 'map',
pitch: 0,
type: 'mapbox',
style: 'mapbox://styles/mapbox/dark-v10',
zoom: 2,
});
const layer = new HeatMapLayer({});
layer
.source(await response.json())
.size('mag', [0, 1]) // weight映射通道
.style({
intensity: 2,
radius: 20,
opacity: 1,
rampColors: {
colors: [
'#2E8AE6',
'#69D1AB',
'#DAF291',
'#FFD591',
'#FF7A45',
'#CF1D49',
],
positions: [0, 0.2, 0.4, 0.6, 0.8, 1.0],
},
});
scene.addLayer(layer);
console.log(layer);
// requestAnimationFrame(run);
scene.render();
this.scene = scene;
// function run() {
// scene.render();
// requestAnimationFrame(run);
// }
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}

View File

@ -58,6 +58,7 @@ export default class GridHeatMap extends React.Component {
]);
scene.addLayer(layer);
scene.render();
this.scene = scene;
}
public render() {

View File

@ -42,6 +42,7 @@ export default class PointImage extends React.Component {
.size(30);
scene.addLayer(pointLayer);
scene.render();
this.scene = scene;
}
public render() {

View File

@ -56,6 +56,7 @@ export default class Polygon3D extends React.Component {
});
scene.addLayer(layer);
scene.render();
this.scene = scene;
}
public render() {

View File

@ -29,8 +29,8 @@ export default class ImageLayerDemo extends React.Component {
},
);
scene.addLayer(layer);
console.log(layer);
scene.render();
this.scene = scene;
}
public render() {

View File

@ -1,8 +1,18 @@
import { storiesOf } from '@storybook/react';
import * as React from 'react';
import Blur from './components/Blur';
import ColorHalftone from './components/ColorHalftone';
import HexagonalPixelate from './components/HexagonalPixelate';
import Ink from './components/Ink';
import Noise from './components/Noise';
import Sepia from './components/Sepia';
import TAA from './components/TAA';
// @ts-ignore
storiesOf('MultiPassRenderer', module)
.add('ColorHalftone', () => <ColorHalftone />)
.add('HexagonalPixelate', () => <HexagonalPixelate />)
.add('Ink', () => <Ink />)
.add('Blur', () => <Blur />)
.add('Noise', () => <Noise />)
.add('Sepia', () => <Sepia />)
.add('TAA(Temporal Anti-Aliasing)', () => <TAA />);

View File

@ -37,7 +37,12 @@ export default class Mapbox extends React.Component {
enablePicking: true,
enableHighlight: true,
passes: [
'blurH',
[
'blurH',
{
blurRadius: 8,
},
],
[
'blurV',
{
@ -67,6 +72,46 @@ export default class Mapbox extends React.Component {
scene.render();
this.scene = scene;
/*** 运行时修改样式属性 ***/
const gui = new dat.GUI();
this.gui = gui;
const styleOptions = {
blurVRadius: 8,
blurHRadius: 8,
};
const pointFolder = gui.addFolder('Blur 配置');
pointFolder
.add(styleOptions, 'blurVRadius', 0, 100)
.onChange((blurRadius: number) => {
layer.style({
passes: [
[
'blurV',
{
blurRadius,
},
],
],
});
scene.render();
});
pointFolder
.add(styleOptions, 'blurHRadius', 0, 100)
.onChange((blurRadius: number) => {
layer.style({
passes: [
[
'blurH',
{
blurRadius,
},
],
],
});
scene.render();
});
pointFolder.open();
}
public render() {

View File

@ -0,0 +1,153 @@
// @ts-ignore
import { PolygonLayer } from '@l7/layers';
// @ts-ignore
import { Scene } from '@l7/scene';
import * as dat from 'dat.gui';
import * as React from 'react';
export default class ColorHalftone extends React.Component {
private gui: dat.GUI;
private $stats: Node;
private scene: Scene;
public componentWillUnmount() {
if (this.gui) {
this.gui.destroy();
}
if (this.$stats) {
document.body.removeChild(this.$stats);
}
this.scene.destroy();
}
public async componentDidMount() {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json',
);
const data = await response.json();
const scene = new Scene({
id: 'map',
type: 'mapbox',
style: 'mapbox://styles/mapbox/streets-v9',
center: [110.19382669582967, 50.258134],
pitch: 0,
zoom: 3,
});
const layer = new PolygonLayer({
enablePicking: true,
enableHighlight: true,
passes: [
[
'colorHalftone',
{
size: 8,
},
],
],
});
layer
.source(data)
.size('name', [0, 10000, 50000, 30000, 100000])
.color('name', [
'#2E8AE6',
'#69D1AB',
'#DAF291',
'#FFD591',
'#FF7A45',
'#CF1D49',
])
.shape('fill')
.style({
opacity: 0.8,
});
scene.addLayer(layer);
scene.render();
this.scene = scene;
/*** 运行时修改样式属性 ***/
const gui = new dat.GUI();
this.gui = gui;
const styleOptions = {
angle: 0,
size: 8,
centerX: 0.5,
centerY: 0.5,
};
const pointFolder = gui.addFolder('ColorHalftone 配置');
pointFolder
.add(styleOptions, 'centerX', 0, 1)
.onChange((centerX: number) => {
layer.style({
passes: [
[
'colorHalftone',
{
center: [centerX, styleOptions.centerY],
},
],
],
});
scene.render();
});
pointFolder
.add(styleOptions, 'centerY', 0, 1)
.onChange((centerY: number) => {
layer.style({
passes: [
[
'colorHalftone',
{
center: [styleOptions.centerX, centerY],
},
],
],
});
scene.render();
});
pointFolder.add(styleOptions, 'angle', 0, 10).onChange((angle: number) => {
layer.style({
passes: [
[
'colorHalftone',
{
angle,
},
],
],
});
scene.render();
});
pointFolder.add(styleOptions, 'size', 0, 20).onChange((size: number) => {
layer.style({
passes: [
[
'colorHalftone',
{
size,
},
],
],
});
scene.render();
});
pointFolder.open();
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}

View File

@ -0,0 +1,139 @@
// @ts-ignore
import { PolygonLayer } from '@l7/layers';
// @ts-ignore
import { Scene } from '@l7/scene';
import * as dat from 'dat.gui';
import * as React from 'react';
export default class HexagonalPixelate extends React.Component {
private gui: dat.GUI;
private $stats: Node;
private scene: Scene;
public componentWillUnmount() {
if (this.gui) {
this.gui.destroy();
}
if (this.$stats) {
document.body.removeChild(this.$stats);
}
this.scene.destroy();
}
public async componentDidMount() {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json',
);
const data = await response.json();
const scene = new Scene({
id: 'map',
type: 'mapbox',
style: 'mapbox://styles/mapbox/streets-v9',
center: [110.19382669582967, 50.258134],
pitch: 0,
zoom: 3,
});
const layer = new PolygonLayer({
enablePicking: true,
enableHighlight: true,
passes: [
[
'hexagonalPixelate',
{
scale: 10,
},
],
],
});
layer
.source(data)
.size('name', [0, 10000, 50000, 30000, 100000])
.color('name', [
'#2E8AE6',
'#69D1AB',
'#DAF291',
'#FFD591',
'#FF7A45',
'#CF1D49',
])
.shape('fill')
.style({
opacity: 0.8,
});
scene.addLayer(layer);
scene.render();
this.scene = scene;
/*** 运行时修改样式属性 ***/
const gui = new dat.GUI();
this.gui = gui;
const styleOptions = {
scale: 10,
centerX: 0.5,
centerY: 0.5,
};
const pointFolder = gui.addFolder('HexagonalPixelate 配置');
pointFolder
.add(styleOptions, 'centerX', 0, 1)
.onChange((centerX: number) => {
layer.style({
passes: [
[
'hexagonalPixelate',
{
center: [centerX, styleOptions.centerY],
},
],
],
});
scene.render();
});
pointFolder
.add(styleOptions, 'centerY', 0, 1)
.onChange((centerY: number) => {
layer.style({
passes: [
[
'hexagonalPixelate',
{
center: [styleOptions.centerX, centerY],
},
],
],
});
scene.render();
});
pointFolder.add(styleOptions, 'scale', 0, 50).onChange((scale: number) => {
layer.style({
passes: [
[
'hexagonalPixelate',
{
scale,
},
],
],
});
scene.render();
});
pointFolder.open();
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}

View File

@ -0,0 +1,109 @@
// @ts-ignore
import { PolygonLayer } from '@l7/layers';
// @ts-ignore
import { Scene } from '@l7/scene';
import * as dat from 'dat.gui';
import * as React from 'react';
export default class Ink extends React.Component {
private gui: dat.GUI;
private $stats: Node;
private scene: Scene;
public componentWillUnmount() {
if (this.gui) {
this.gui.destroy();
}
if (this.$stats) {
document.body.removeChild(this.$stats);
}
this.scene.destroy();
}
public async componentDidMount() {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json',
);
const data = await response.json();
const scene = new Scene({
id: 'map',
type: 'mapbox',
style: 'mapbox://styles/mapbox/streets-v9',
center: [110.19382669582967, 50.258134],
pitch: 0,
zoom: 3,
});
const layer = new PolygonLayer({
enablePicking: true,
enableHighlight: true,
passes: [
[
'ink',
{
strength: 0.6,
},
],
],
});
layer
.source(data)
.size('name', [0, 10000, 50000, 30000, 100000])
.color('name', [
'#2E8AE6',
'#69D1AB',
'#DAF291',
'#FFD591',
'#FF7A45',
'#CF1D49',
])
.shape('fill')
.style({
opacity: 0.8,
});
scene.addLayer(layer);
scene.render();
this.scene = scene;
/*** 运行时修改样式属性 ***/
const gui = new dat.GUI();
this.gui = gui;
const styleOptions = {
strength: 0.6,
};
const pointFolder = gui.addFolder('Ink 配置');
pointFolder
.add(styleOptions, 'strength', 0, 1)
.onChange((strength: number) => {
layer.style({
passes: [
[
'ink',
{
strength,
},
],
],
});
scene.render();
});
pointFolder.open();
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}

View File

@ -0,0 +1,100 @@
// @ts-ignore
import { PolygonLayer } from '@l7/layers';
// @ts-ignore
import { Scene } from '@l7/scene';
import * as dat from 'dat.gui';
import * as React from 'react';
export default class Noise extends React.Component {
private gui: dat.GUI;
private $stats: Node;
private scene: Scene;
public componentWillUnmount() {
if (this.gui) {
this.gui.destroy();
}
if (this.$stats) {
document.body.removeChild(this.$stats);
}
this.scene.destroy();
}
public async componentDidMount() {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json',
);
const data = await response.json();
const scene = new Scene({
id: 'map',
type: 'mapbox',
style: 'mapbox://styles/mapbox/streets-v9',
center: [110.19382669582967, 50.258134],
pitch: 0,
zoom: 3,
});
const layer = new PolygonLayer({
enablePicking: true,
enableHighlight: true,
passes: ['noise'],
});
layer
.source(data)
.size('name', [0, 10000, 50000, 30000, 100000])
.color('name', [
'#2E8AE6',
'#69D1AB',
'#DAF291',
'#FFD591',
'#FF7A45',
'#CF1D49',
])
.shape('fill')
.style({
opacity: 0.8,
});
scene.addLayer(layer);
scene.render();
this.scene = scene;
/*** 运行时修改样式属性 ***/
const gui = new dat.GUI();
this.gui = gui;
const styleOptions = {
amount: 1,
};
const pointFolder = gui.addFolder('Noise 配置');
pointFolder.add(styleOptions, 'amount', 0, 1).onChange((amount: number) => {
layer.style({
passes: [
[
'noise',
{
amount,
},
],
],
});
scene.render();
});
pointFolder.open();
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}

View File

@ -0,0 +1,100 @@
// @ts-ignore
import { PolygonLayer } from '@l7/layers';
// @ts-ignore
import { Scene } from '@l7/scene';
import * as dat from 'dat.gui';
import * as React from 'react';
export default class Sepia extends React.Component {
private gui: dat.GUI;
private $stats: Node;
private scene: Scene;
public componentWillUnmount() {
if (this.gui) {
this.gui.destroy();
}
if (this.$stats) {
document.body.removeChild(this.$stats);
}
this.scene.destroy();
}
public async componentDidMount() {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json',
);
const data = await response.json();
const scene = new Scene({
id: 'map',
type: 'mapbox',
style: 'mapbox://styles/mapbox/streets-v9',
center: [110.19382669582967, 50.258134],
pitch: 0,
zoom: 3,
});
const layer = new PolygonLayer({
enablePicking: true,
enableHighlight: true,
passes: ['sepia'],
});
layer
.source(data)
.size('name', [0, 10000, 50000, 30000, 100000])
.color('name', [
'#2E8AE6',
'#69D1AB',
'#DAF291',
'#FFD591',
'#FF7A45',
'#CF1D49',
])
.shape('fill')
.style({
opacity: 0.8,
});
scene.addLayer(layer);
scene.render();
this.scene = scene;
/*** 运行时修改样式属性 ***/
const gui = new dat.GUI();
this.gui = gui;
const styleOptions = {
amount: 0.5,
};
const pointFolder = gui.addFolder('Sepia 配置');
pointFolder.add(styleOptions, 'amount', 0, 1).onChange((amount: number) => {
layer.style({
passes: [
[
'sepia',
{
amount,
},
],
],
});
scene.render();
});
pointFolder.open();
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}

View File

@ -79,7 +79,7 @@ export default class TAA extends React.Component {
const pointFolder = gui.addFolder('TAA 配置');
pointFolder
.add(styleOptions, 'jitterScale', 0, 100)
.onChange((jitterScale: boolean) => {
.onChange((jitterScale: number) => {
layer.style({
jitterScale,
});

249
yarn.lock
View File

@ -316,6 +316,14 @@
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-syntax-json-strings" "^7.2.0"
"@babel/plugin-proposal-nullish-coalescing-operator@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.4.4.tgz#41c360d59481d88e0ce3a3f837df10121a769b39"
integrity sha512-Amph7Epui1Dh/xxUxS2+K22/MUi6+6JVTvy3P58tja3B6yKTSjwwx0/d83rF7551D6PVSSoplQb8GCwqec7HRw==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-syntax-nullish-coalescing-operator" "^7.2.0"
"@babel/plugin-proposal-object-rest-spread@7.5.5":
version "7.5.5"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.5.tgz#61939744f71ba76a3ae46b5eea18a54c16d22e58"
@ -399,6 +407,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-syntax-nullish-coalescing-operator@^7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.2.0.tgz#f75083dfd5ade73e783db729bbd87e7b9efb7624"
integrity sha512-lRCEaKE+LTxDQtgbYajI04ddt6WW0WJq57xqkAZ+s11h4YgfRHhVA/Y2VhfPzzFD4qeLHWg32DMp9HooY4Kqlg==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e"
@ -905,7 +920,7 @@
dependencies:
regenerator-runtime "^0.13.2"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3":
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3":
version "7.6.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.3.tgz#935122c74c73d2240cafd32ddb5fc2a6cd35cf1f"
integrity sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==
@ -1124,10 +1139,10 @@
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.7.3.tgz#a166882c81c0c6040975dd30df24fae8549bd96f"
integrity sha512-14ZVlsB9akwvydAdaEnVnvqu6J2P6ySv39hYyl/aoB6w/V+bXX0tay8cF6paqbgZsN2n5Xh15uF4pE+GvE+itw==
"@emotion/is-prop-valid@0.8.3":
version "0.8.3"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.3.tgz#cbe62ddbea08aa022cdf72da3971570a33190d29"
integrity sha512-We7VBiltAJ70KQA0dWkdPMXnYoizlxOXpvtjmu5/MBnExd+u0PGgV27WCYanmLAbCwAU30Le/xA0CQs/F/Otig==
"@emotion/is-prop-valid@0.8.4":
version "0.8.4"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.4.tgz#cf1dcfc1812c226f05e1ba53592eb6b51e734990"
integrity sha512-QBW8h6wVQgeQ55F52rNaprEJxtVR+/ScOP8/V1ScSpPzKqHdFB9QVqby0Z50sqS8mcaeIl5vR1vQpKwJbIS6NQ==
dependencies:
"@emotion/memoize" "0.7.3"
@ -1136,10 +1151,10 @@
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.3.tgz#5b6b1c11d6a6dddf1f2fc996f74cf3b219644d78"
integrity sha512-2Md9mH6mvo+ygq1trTeVp2uzAKwE2P7In0cRpD/M9Q70aH8L+rxMLbb3JCN2JoSWsV2O+DdFjfbbXoMoLBczow==
"@emotion/serialize@^0.11.12":
version "0.11.13"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.13.tgz#49b93e8e6f7dba70bbf0ecd697bb4e03f45d8cde"
integrity sha512-Tw+z6oIFCXeznoH25TozFoOUJ9BIyKBgZ9Gif3ej9aqPeP/Dzct8WIXSsz08xxyt1RPlKokvJ3fzMDq0UjL3RQ==
"@emotion/serialize@^0.11.12", "@emotion/serialize@^0.11.14":
version "0.11.14"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.14.tgz#56a6d8d04d837cc5b0126788b2134c51353c6488"
integrity sha512-6hTsySIuQTbDbv00AnUO6O6Xafdwo5GswRlMZ5hHqiFx+4pZ7uGWXUQFW46Kc2taGhP89uXMXn/lWQkdyTosPA==
dependencies:
"@emotion/hash" "0.7.3"
"@emotion/memoize" "0.7.3"
@ -1152,23 +1167,23 @@
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.3.tgz#689f135ecf87d3c650ed0c4f5ddcbe579883564a"
integrity sha512-c3Q6V7Df7jfwSq5AzQWbXHa5soeE4F5cbqi40xn0CzXxWW9/6Mxq48WJEtqfWzbZtW9odZdnRAkwCQwN12ob4A==
"@emotion/styled-base@^10.0.22":
version "10.0.22"
resolved "https://registry.yarnpkg.com/@emotion/styled-base/-/styled-base-10.0.22.tgz#2b6e86e477ed81bd74aa6cef5f403d500503df5b"
integrity sha512-ikSuAcz86BcmlZM5EysqCH0EUssYm5ardrWNVM3Ri5ODpOlKPrT//jVozJU2uK3q5GRcqZHLqagP/nd9beNUfQ==
"@emotion/styled-base@^10.0.23":
version "10.0.23"
resolved "https://registry.yarnpkg.com/@emotion/styled-base/-/styled-base-10.0.23.tgz#21244fa25f4c867033e670cf9d7bd0262b4f74ce"
integrity sha512-94QowN2S09nCXRz9dXBiMaEcUcXn9kHM8uFExpsspwswHWnkpFn6jTewotQEgI7RROnAXDZ8fvSTkCdqtn3sfw==
dependencies:
"@babel/runtime" "^7.5.5"
"@emotion/is-prop-valid" "0.8.3"
"@emotion/serialize" "^0.11.12"
"@emotion/is-prop-valid" "0.8.4"
"@emotion/serialize" "^0.11.14"
"@emotion/utils" "0.11.2"
"@emotion/styled@^10.0.14":
version "10.0.22"
resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-10.0.22.tgz#ee398710876ebda5a418f84359516c6a1c5c41b1"
integrity sha512-3+dnBk8NjXnddI8Gi2VJLMmup0bCG8HQkZLaeNky+GSLl8VyxQfuaK5I5aDVvgQ3UzkxrcZrFB3vHYU/iUakBA==
version "10.0.23"
resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-10.0.23.tgz#2f8279bd59b99d82deade76d1046249ddfab7c1b"
integrity sha512-gNr04eqBQ2iYUx8wFLZDfm3N8/QUOODu/ReDXa693uyQGy2OqA+IhPJk+kA7id8aOfwAsMuvZ0pJImEXXKtaVQ==
dependencies:
"@emotion/styled-base" "^10.0.22"
babel-plugin-emotion "^10.0.22"
"@emotion/styled-base" "^10.0.23"
babel-plugin-emotion "^10.0.23"
"@emotion/stylis@0.8.4":
version "0.8.4"
@ -2114,6 +2129,11 @@
resolved "https://registry.yarnpkg.com/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.4.1.tgz#c0a03cf75f8b0ad7b57849d6c7e91b0aec4b640f"
integrity sha512-yyKza9S6z3ELKuf6w5n6VNUB0Osu6Z93RXPfMHLIlNWohu3KqxewLOq4lMXseYJ92GwkRAxd207Pr/Z98cwmvw==
"@mapbox/martini@^0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@mapbox/martini/-/martini-0.1.0.tgz#1801b9234140e1136f37939157ba647d46f1ea30"
integrity sha512-sAk7M4l1Zw0vIRIH1QpT+dy548w0Mh5fMP+r2sNPVzM9q8BV2nur76Qiv7cQ1NJzbYdCX182qUxbRnUljT4grg==
"@mapbox/point-geometry@0.1.0", "@mapbox/point-geometry@^0.1.0", "@mapbox/point-geometry@~0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz#8a83f9335c7860effa2eeeca254332aa0aeed8f2"
@ -2983,9 +3003,9 @@
integrity sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==
"@types/jest@^24.0.18":
version "24.0.20"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.20.tgz#729d5fe8684e7fb06368d3bd557ac6d91289d861"
integrity sha512-M8ebEkOpykGdLoRrmew7UowTZ1DANeeP0HiSIChl/4DGgmnSC1ntitNtkyNSXjMTsZvXuaxJrxjImEnRWNPsPw==
version "24.0.21"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.21.tgz#2c0a25440e025bb265f4a17d8b79b11b231426bf"
integrity sha512-uyqFvx78Tuy0h5iLCPWRCvi5HhWwEqhIj30doitp191oYLqlCxUyAJHdWVm5+Nr271/vPnkyt6rWeEIjGowBTg==
dependencies:
"@types/jest-diff" "*"
@ -3007,9 +3027,9 @@
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/node@*", "@types/node@^12.0.2", "@types/node@^12.11.1", "@types/node@^12.7.3":
version "12.11.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a"
integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA==
version "12.12.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.0.tgz#ff3201972d6dc851a9275308a17b9b5094e68057"
integrity sha512-6N8Sa5AaENRtJnpKXZgvc119PKxT1Lk9VPy4kfT8JF23tIe1qDfaGkBR2DRKJFIA7NptMz+fps//C6aLi1Uoug==
"@types/normalize-package-data@^2.4.0":
version "2.4.0"
@ -3906,15 +3926,15 @@ babel-plugin-dynamic-import-node@2.3.0, babel-plugin-dynamic-import-node@^2.3.0:
dependencies:
object.assign "^4.1.0"
babel-plugin-emotion@^10.0.14, babel-plugin-emotion@^10.0.22:
version "10.0.22"
resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.22.tgz#7860b39f96dcc1b79e326987ce29d4fcfff96f52"
integrity sha512-e3Yo9+GD6ovrcZlt2Unjgfyy0gfdz0+8httltToWL+biFMhLPPT1PJlc0GHy9i+vtPSrTBNY2hawfPJnuG2L3g==
babel-plugin-emotion@^10.0.14, babel-plugin-emotion@^10.0.22, babel-plugin-emotion@^10.0.23:
version "10.0.23"
resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.23.tgz#040d40bf61dcab6d31dd6043d10e180240b8515b"
integrity sha512-1JiCyXU0t5S2xCbItejCduLGGcKmF3POT0Ujbexog2MI4IlRcIn/kWjkYwCUZlxpON0O5FC635yPl/3slr7cKQ==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@emotion/hash" "0.7.3"
"@emotion/memoize" "0.7.3"
"@emotion/serialize" "^0.11.12"
"@emotion/serialize" "^0.11.14"
babel-plugin-macros "^2.0.0"
babel-plugin-syntax-jsx "^6.18.0"
convert-source-map "^1.5.0"
@ -4693,9 +4713,9 @@ can-use-dom@^0.1.0:
integrity sha1-IsxKNKCrxDlQ9CxkEQJKP2NmtFo=
caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001004:
version "1.0.30001005"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001005.tgz#823054210be638c725521edcb869435dae46728d"
integrity sha512-g78miZm1Z5njjYR216a5812oPiLgV1ssndgGxITHWUopmjUrCswMisA0a2kSB7a0vZRox6JOKhM51+efmYN8Mg==
version "1.0.30001006"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001006.tgz#5b6e8288792cfa275f007b2819a00ccad7112655"
integrity sha512-MXnUVX27aGs/QINz+QG1sWSLDr3P1A3Hq5EUWoIt0T7K24DuvMxZEnh3Y5aHlJW6Bz2aApJdSewdYLd8zQnUuw==
capture-exit@^2.0.0:
version "2.0.0"
@ -5168,11 +5188,9 @@ connect-history-api-fallback@^1.6.0:
integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==
console-browserify@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=
dependencies:
date-now "^0.1.4"
version "1.2.0"
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336"
integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==
console-control-strings@^1.0.0, console-control-strings@~1.1.0:
version "1.1.0"
@ -5361,17 +5379,17 @@ copy-webpack-plugin@^4.5.2:
serialize-javascript "^1.4.0"
core-js-compat@^3.1.1:
version "3.3.4"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.3.4.tgz#a151c6cd754edbfe6a4a2a66b9382df2ae74fbcd"
integrity sha512-7OK3/LPP8R3Ovasf3GilEOp+o1w0ZKJ75FMou2RDfTwIV69G5RkKCGFnqgBv/ZhR6xo9GCzlfVALyHmydbE7DA==
version "3.3.5"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.3.5.tgz#7abf70778b73dc74aa99d4075aefcd99b76f2c3a"
integrity sha512-44ZORuapx0MUht0MUk0p9lcQPh7n/LDXehimTmjCs0CYblpKZcqVd5w0OQDUDq5OQjEbazWObHDQJWvvHYPNTg==
dependencies:
browserslist "^4.7.2"
semver "^6.3.0"
core-js-pure@^3.0.1:
version "3.3.4"
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.3.4.tgz#01d2842f552a866265dc77ededb2ccd668ff2879"
integrity sha512-hqxt6XpR4zIMNUY920oNyAtwaq4yg8IScmXumnfyRWF9+ur7wtjr/4eCdfTJzY64jmi8WRCwIqNBKzYeOKdvnw==
version "3.3.5"
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.3.5.tgz#23dc7e44bb946bf1752b377709e8591faffb0bac"
integrity sha512-njLfaPe3tS+8Swgx/itYgJ1jiizCWtNXrK1VzMoXbT6LhiYbIAQioukPmZlB2wTieJY2g4fLRUh96WfXpN61oA==
core-js@^1.0.0:
version "1.2.7"
@ -5384,9 +5402,9 @@ core-js@^2.4.0, core-js@^2.5.0:
integrity sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==
core-js@^3.0.1, core-js@^3.0.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.3.4.tgz#6b0a23392958317bfb46e40b090529a923add669"
integrity sha512-BtibooaAmSOptGLRccsuX/dqgPtXwNgqcvYA6kOTTMzonRxZ+pJS4e+6mvVutESfXMeTnK8m3M+aBu3bkJbR+w==
version "3.3.5"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.3.5.tgz#58d20f48a95a07304b62ff752742b82b56431ed8"
integrity sha512-0J3K+Par/ZydhKg8pEiTcK/9d65/nqJOzY62uMkjeBmt05fDOt/khUVjDdh8TpeIuGQDy1yLDDCjiWN/8pFIuw==
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
@ -5609,21 +5627,13 @@ css-to-react-native@^2.0.3:
css-color-keywords "^1.0.0"
postcss-value-parser "^3.3.0"
css-tree@1.0.0-alpha.29:
version "1.0.0-alpha.29"
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.29.tgz#3fa9d4ef3142cbd1c301e7664c1f352bd82f5a39"
integrity sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg==
dependencies:
mdn-data "~1.1.0"
source-map "^0.5.3"
css-tree@1.0.0-alpha.33:
version "1.0.0-alpha.33"
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.33.tgz#970e20e5a91f7a378ddd0fc58d0b6c8d4f3be93e"
integrity sha512-SPt57bh5nQnpsTBsx/IXbO14sRc9xXu5MtMAVuo0BaQQmyf0NupNPPSoMaqiAF5tDFafYsTkfeH4Q/HCKXkg4w==
css-tree@1.0.0-alpha.37:
version "1.0.0-alpha.37"
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22"
integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==
dependencies:
mdn-data "2.0.4"
source-map "^0.5.3"
source-map "^0.6.1"
css-what@2.1, css-what@^2.1.2:
version "2.1.3"
@ -5655,12 +5665,12 @@ cssesc@^3.0.0:
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
csso@^3.5.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/csso/-/csso-3.5.1.tgz#7b9eb8be61628973c1b261e169d2f024008e758b"
integrity sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg==
csso@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/csso/-/csso-4.0.2.tgz#e5f81ab3a56b8eefb7f0092ce7279329f454de3d"
integrity sha512-kS7/oeNVXkHWxby5tHVxlhjizRCSv8QdU7hB2FpdAibDU8FjTAolhNjKNTiLzXtUrKT6HwClE81yXwEk1309wg==
dependencies:
css-tree "1.0.0-alpha.29"
css-tree "1.0.0-alpha.37"
cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
version "0.3.8"
@ -5820,11 +5830,6 @@ date-fns@^1.27.2:
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
date-now@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=
dateformat@^3.0.0:
version "3.0.3"
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
@ -6545,14 +6550,14 @@ es-to-primitive@^1.2.0:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@^0.10.51:
version "0.10.51"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.51.tgz#ed2d7d9d48a12df86e0299287e93a09ff478842f"
integrity sha512-oRpWzM2WcLHVKpnrcyB7OW8j/s67Ba04JCm0WnNv3RiABSvs7mrQlutB8DBv793gKcp0XENR8Il8WxGTlZ73gQ==
es5-ext@^0.10.35, es5-ext@^0.10.50:
version "0.10.52"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.52.tgz#bb21777e919a04263736ded120a9d665f10ea63f"
integrity sha512-bWCbE9fbpYQY4CU6hJbJ1vSz70EClMlDgJ7BmwI+zEJhxrwjesZRPglGJlsZhu0334U3hI+gaspwksH9IGD6ag==
dependencies:
es6-iterator "~2.0.3"
es6-symbol "~3.1.1"
next-tick "^1.0.0"
es6-symbol "~3.1.2"
next-tick "~1.0.0"
es5-shim@^4.5.13:
version "4.5.13"
@ -6585,13 +6590,13 @@ es6-shim@^0.35.5:
resolved "https://registry.yarnpkg.com/es6-shim/-/es6-shim-0.35.5.tgz#46f59dc0a84a1c5029e8ff1166ca0a902077a9ab"
integrity sha512-E9kK/bjtCQRpN1K28Xh4BlmP8egvZBGJJ+9GtnzOwt7mdqtrjHFuVGr7QJfdjBIKqrlU5duPf3pCBoDrkjVYFg==
es6-symbol@^3.1.1, es6-symbol@~3.1.1:
version "3.1.2"
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.2.tgz#859fdd34f32e905ff06d752e7171ddd4444a7ed1"
integrity sha512-/ZypxQsArlv+KHpGvng52/Iz8by3EQPxhmbuz8yFG89N/caTFBSbcXONDw0aMjy827gQg26XAjP4uXFvnfINmQ==
es6-symbol@^3.1.1, es6-symbol@~3.1.2:
version "3.1.3"
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
dependencies:
d "^1.0.1"
es5-ext "^0.10.51"
ext "^1.1.2"
escape-html@^1.0.3, escape-html@~1.0.3:
version "1.0.3"
@ -6829,6 +6834,13 @@ express@^4.17.0, express@^4.17.1:
utils-merge "1.0.1"
vary "~1.1.2"
ext@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/ext/-/ext-1.1.2.tgz#d1d216c83641bb4cb7684622b063cff44a19ce35"
integrity sha512-/KLjJdTNyDepCihrk4HQt57nAE1IRCEo5jUt+WgWGCr1oARhibDvmI2DMcSNWood1T9AUWwq+jaV1wvRqaXfnA==
dependencies:
type "^2.0.0"
extend-shallow@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
@ -7385,6 +7397,14 @@ geojson-vt@^3.2.1:
resolved "https://registry.yarnpkg.com/geojson-vt/-/geojson-vt-3.2.1.tgz#f8adb614d2c1d3f6ee7c4265cad4bbf3ad60c8b7"
integrity sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==
geotiff@^1.0.0-beta.6:
version "1.0.0-beta.6"
resolved "https://registry.yarnpkg.com/geotiff/-/geotiff-1.0.0-beta.6.tgz#500f256196a2c23517b73ccb36a45dc82a1f7a70"
integrity sha512-xdZ/MLcnrv1+6wQlQZQIs11zNJywylnV1pXqDw7Ao7bmLRpM421a39dXP5e6SG+vio0mnDUZkL2XknKbqppFzw==
dependencies:
pako "^1.0.3"
xmldom "0.1.*"
get-caller-file@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
@ -7783,9 +7803,9 @@ handle-thing@^2.0.0:
integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==
handlebars@^4.1.2, handlebars@^4.4.0:
version "4.4.5"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.4.5.tgz#1b1f94f9bfe7379adda86a8b73fb570265a0dddd"
integrity sha512-0Ce31oWVB7YidkaTq33ZxEbN+UDxMMgThvCe8ptgQViymL5DPis9uLdTA13MiRPhgvqyxIegugrP97iK3JeBHg==
version "4.5.1"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.1.tgz#8a01c382c180272260d07f2d1aa3ae745715c7ba"
integrity sha512-C29UoFzHe9yM61lOsIlCE5/mQVGrnIOrOq7maQl76L7tYPCgC1og0Ajt6uWnX4ZTxBPnjw+CUvawphwCfJgUnA==
dependencies:
neo-async "^2.6.0"
optimist "^0.6.1"
@ -10155,11 +10175,6 @@ mdn-data@2.0.4:
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b"
integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==
mdn-data@~1.1.0:
version "1.1.4"
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-1.1.4.tgz#50b5d4ffc4575276573c4eedb8780812a8419f01"
integrity sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@ -10267,7 +10282,7 @@ merge-descriptors@1.0.1:
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
merge-json-schemas@^1.0.0:
merge-json-schemas@1.0.0, merge-json-schemas@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/merge-json-schemas/-/merge-json-schemas-1.0.0.tgz#2d635eaa8401c5fa3d03f30f89349fc7cafee62f"
integrity sha1-LWNeqoQBxfo9A/MPiTSfx8r+5i8=
@ -10665,7 +10680,7 @@ nested-object-assign@^1.0.3:
resolved "https://registry.yarnpkg.com/nested-object-assign/-/nested-object-assign-1.0.3.tgz#5aca69390d9affe5a612152b5f0843ae399ac597"
integrity sha512-kgq1CuvLyUcbcIuTiCA93cQ2IJFSlRwXcN+hLcb2qLJwC2qrePHGZZa7IipyWqaWF6tQjdax2pQnVxdq19Zzwg==
next-tick@^1.0.0:
next-tick@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
@ -11384,7 +11399,7 @@ p-waterfall@^1.0.0:
dependencies:
p-reduce "^1.0.0"
pako@~1.0.5:
pako@^1.0.3, pako@~1.0.5:
version "1.0.10"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==
@ -11710,11 +11725,11 @@ pnp-webpack-plugin@1.4.3:
ts-pnp "^1.1.2"
polished@^3.3.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/polished/-/polished-3.4.1.tgz#1eb5597ec1792206365635811d465751f5cbf71c"
integrity sha512-GflTnlP5rrpDoigjczEkS6Ye7NDA4sFvAnlr5hSDrEvjiVj97Xzev3hZlLi3UB27fpxyTS9rWU64VzVLWkG+mg==
version "3.4.2"
resolved "https://registry.yarnpkg.com/polished/-/polished-3.4.2.tgz#b4780dad81d64df55615fbfc77acb52fd17d88cd"
integrity sha512-9Rch6iMZckABr6EFCLPZsxodeBpXMo9H4fRlfR/9VjMEyy5xpo1/WgXlJGgSjPyVhEZNycbW7UmYMNyWS5MI0g==
dependencies:
"@babel/runtime" "^7.4.5"
"@babel/runtime" "^7.6.3"
polyline-miter-util@^1.0.1:
version "1.0.1"
@ -12618,9 +12633,9 @@ react-test-renderer@^16.0.0-0:
scheduler "^0.17.0"
react-textarea-autosize@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-7.1.0.tgz#3132cb77e65d94417558d37c0bfe415a5afd3445"
integrity sha512-c2FlR/fP0qbxmlrW96SdrbgP/v0XZMTupqB90zybvmDVDutytUgPl7beU35klwcTeMepUIQEpQUn3P3bdshGPg==
version "7.1.1"
resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-7.1.1.tgz#66ff1b7d6e1ab759fdf35f09e60bdd0e15d8e143"
integrity sha512-dVDVXlUm5uUgWyZAL4gaxJiDb2xCWM/qk6Rl2ixXPSKNsngKhvAj3KbDS9mnQn/qIZSYVD+/iuZT/eQWmNjBLw==
dependencies:
"@babel/runtime" "^7.1.2"
prop-types "^15.6.0"
@ -13839,9 +13854,9 @@ source-map-resolve@^0.5.0, source-map-resolve@^0.5.2:
urix "^0.1.0"
source-map-support@^0.5.3, source-map-support@^0.5.6, source-map-support@~0.5.12:
version "0.5.13"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"
integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==
version "0.5.16"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
@ -13858,7 +13873,7 @@ source-map@^0.4.2:
dependencies:
amdefine ">=0.0.4"
source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0:
source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
@ -14453,16 +14468,16 @@ svg-tags@^1.0.0:
integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=
svgo@^1.2.2:
version "1.3.0"
resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.0.tgz#bae51ba95ded9a33a36b7c46ce9c359ae9154313"
integrity sha512-MLfUA6O+qauLDbym+mMZgtXCGRfIxyQoeH6IKVcFslyODEe/ElJNwr0FohQ3xG4C6HK6bk3KYPPXwHVJk3V5NQ==
version "1.3.1"
resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.1.tgz#115c1f9d7e3294dfc66288c8499e65c2a1479729"
integrity sha512-2iv3AHKL+x2/nAvkg+vTv01aK94OFU6wTRbnv/K43mf1OdKEEA8xaQl7Wjs5Vrh9AlyXvyPd8fg6s6YzYdQTnQ==
dependencies:
chalk "^2.4.1"
coa "^2.0.2"
css-select "^2.0.0"
css-select-base-adapter "^0.1.1"
css-tree "1.0.0-alpha.33"
csso "^3.5.1"
css-tree "1.0.0-alpha.37"
csso "^4.0.2"
js-yaml "^3.13.1"
mkdirp "~0.5.1"
object.values "^1.1.0"
@ -14937,6 +14952,11 @@ type@^1.0.1:
resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==
type@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3"
integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==
typed-styles@^0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9"
@ -14966,9 +14986,9 @@ uglify-js@3.4.x:
source-map "~0.6.1"
uglify-js@^3.1.4, uglify-js@^3.5.1:
version "3.6.4"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.4.tgz#88cc880c6ed5cf9868fdfa0760654e7bed463f1d"
integrity sha512-9Yc2i881pF4BPGhjteCXQNaXx1DCwm3dtOyBaG2hitHjLWOczw/ki8vD1bqyT3u6K0Ms/FpCShkmfg+FtlOfYA==
version "3.6.5"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.5.tgz#b0ee796d2ae7e25672e04f65629b997cd4b30bd6"
integrity sha512-7L3W+Npia1OCr5Blp4/Vw83tK1mu5gnoIURtT1fUVfQ3Kf8WStWV6NJz0fdoBJZls0KlweruRTLVe6XLafmy5g==
dependencies:
commander "~2.20.3"
source-map "~0.6.1"
@ -15763,6 +15783,11 @@ xml-name-validator@^3.0.0:
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==
xmldom@0.1.*:
version "0.1.27"
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9"
integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk=
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"