* feat: 修改 CanvasLayer drawingOnCanvas 的 参数

* style: lint style

* feat: 新增 geometryLayer plane
This commit is contained in:
YiQianYao 2022-03-18 11:00:42 +08:00 committed by GitHub
parent 74c6ee3ce7
commit 499684ee09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 477 additions and 30 deletions

View File

@ -126,6 +126,24 @@ export default class IconService extends EventEmitter implements IIconService {
this.iconData = [];
this.iconMap = {};
}
public loadImage(url: IImage) {
return new Promise((resolve, reject) => {
if (url instanceof HTMLImageElement) {
resolve(url);
return;
}
const image = new Image();
image.crossOrigin = 'anonymous';
image.onload = () => {
resolve(image);
};
image.onerror = () => {
reject(new Error('Could not load image at ' + url));
};
image.src = url instanceof File ? URL.createObjectURL(url) : url;
});
}
private update() {
this.updateIconMap();
this.updateIconAtlas();
@ -172,24 +190,6 @@ export default class IconService extends EventEmitter implements IIconService {
this.canvasHeight = canvasHeight;
}
private loadImage(url: IImage) {
return new Promise((resolve, reject) => {
if (url instanceof HTMLImageElement) {
resolve(url);
return;
}
const image = new Image();
image.crossOrigin = 'anonymous';
image.onload = () => {
resolve(image);
};
image.onerror = () => {
reject(new Error('Could not load image at ' + url));
};
image.src = url instanceof File ? URL.createObjectURL(url) : url;
});
}
/**
*
* @param url

View File

@ -0,0 +1,40 @@
import BaseLayer from '../core/BaseLayer';
import { IGeometryLayerStyleOptions } from '../core/interface';
import GeometryModels, { GeometryModelType } from './models';
export default class GeometryLayer extends BaseLayer<
IGeometryLayerStyleOptions
> {
public type: string = 'GeometryLayer';
public buildModels() {
const modelType = this.getModelType();
this.layerModel = new GeometryModels[modelType](this);
this.models = this.layerModel.initModels();
}
public rebuildModels() {
this.models = this.layerModel.buildModels();
}
protected getConfigSchema() {
return {
properties: {
opacity: {
type: 'number',
minimum: 0,
maximum: 1,
},
},
};
}
protected getDefaultConfig() {
const type = this.getModelType();
const defaultConfig = {
plane: {},
};
return defaultConfig[type];
}
protected getModelType(): GeometryModelType {
return 'plane';
}
}

View File

@ -0,0 +1,7 @@
import PlaneModel from './plane';
export type GeometryModelType = 'plane';
const GeometryModels: { [key in GeometryModelType]: any } = {
plane: PlaneModel,
};
export default GeometryModels;

View File

@ -0,0 +1,226 @@
import {
AttributeType,
gl,
IEncodeFeature,
IModelUniform,
ITexture2D,
} from '@antv/l7-core';
import { getMask, isMini } from '@antv/l7-utils';
// import { mat4, vec3 } from 'gl-matrix';
import BaseModel from '../../core/BaseModel';
import { IGeometryLayerStyleOptions } from '../../core/interface';
import planeFrag from '../shaders/plane_frag.glsl';
import planeVert from '../shaders/plane_vert.glsl';
function initPlane(
width = 1,
height = 1,
widthSegments = 1,
heightSegments = 1,
lng = 120,
lat = 30,
) {
// https://github.com/mrdoob/three.js/blob/dev/src/geometries/PlaneGeometry.js
const widthHalf = width / 2;
const heightHalf = height / 2;
const gridX = Math.floor(widthSegments);
const gridY = Math.floor(heightSegments);
const gridX1 = gridX + 1;
const gridY1 = gridY + 1;
const segmentWidth = width / gridX;
const segmentHeight = height / gridY;
const indices = [];
const positions = [];
for (let iy = 0; iy < gridY1; iy++) {
const y = iy * segmentHeight - heightHalf;
for (let ix = 0; ix < gridX1; ix++) {
const x = ix * segmentWidth - widthHalf;
positions.push(x + lng, -y + lat, 0);
positions.push(ix / gridX);
positions.push(1 - iy / gridY);
}
}
for (let iy = 0; iy < gridY; iy++) {
for (let ix = 0; ix < gridX; 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 { indices, positions };
}
export default class PlaneModel extends BaseModel {
protected texture: ITexture2D;
protected mapTexture: string | undefined;
public planeGeometryTriangulation = () => {
const {
width = 1,
height = 1,
widthSegments = 1,
heightSegments = 1,
center = [120, 30],
} = this.layer.getLayerConfig() as IGeometryLayerStyleOptions;
const { indices, positions } = initPlane(
width,
height,
widthSegments,
heightSegments,
...center,
);
return {
vertices: positions,
indices,
size: 5,
};
};
public getUninforms(): IModelUniform {
const {
opacity,
mapTexture,
} = this.layer.getLayerConfig() as IGeometryLayerStyleOptions;
if (this.mapTexture !== mapTexture) {
this.mapTexture = mapTexture;
this.texture.destroy();
this.updateTexture(mapTexture);
}
return {
u_opacity: opacity || 1,
u_mapFlag: mapTexture ? 1 : 0,
u_texture: this.texture,
// u_ModelMatrix: mat4.translate(mat4.create(), mat4.create(), [1, 0, 0])
// u_ModelMatrix: mat4.rotateZ(mat4.create(), mat4.create(), 10)
// u_ModelMatrix: mat4.rotateZ(mat4.create(), mat4.create(), 10)
// u_ModelMatrix: this.rotateZ()
};
}
// public rotateZ(): mat4 {
// const res = mat4.create()
// const roZero = mat4.translate(mat4.create(), mat4.create(), [-120, 0, -30])
// const rotate = mat4.rotateZ(mat4.create(), mat4.create(), 10)
// const roOrigin = mat4.translate(mat4.create(), mat4.create(), [120, 0, 30])
// mat4.multiply(res, res, roZero)
// mat4.multiply(res, res, rotate)
// mat4.multiply(res, res, roOrigin)
// return res
// }
public clearModels(): void {
this.texture.destroy();
}
public initModels() {
const {
mask = false,
maskInside = true,
mapTexture,
} = this.layer.getLayerConfig() as IGeometryLayerStyleOptions;
this.mapTexture = mapTexture;
const { createTexture2D } = this.rendererService;
this.texture = createTexture2D({
height: 0,
width: 0,
});
this.updateTexture(mapTexture);
return [
this.layer.buildLayerModel({
moduleName: 'geometry_plane',
vertexShader: planeVert,
fragmentShader: planeFrag,
triangulation: this.planeGeometryTriangulation,
primitive: gl.TRIANGLES,
// primitive: gl.POINTS,
depth: { enable: false },
blend: this.getBlend(),
stencil: getMask(mask, maskInside),
}),
];
}
public buildModels() {
return this.initModels();
}
public updateTexture(mapTexture: string | undefined): void {
const { createTexture2D } = this.rendererService;
if (mapTexture) {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => {
this.texture = createTexture2D({
data: img,
width: img.width,
height: img.height,
wrapS: gl.CLAMP_TO_EDGE,
wrapT: gl.CLAMP_TO_EDGE,
});
this.layerService.updateLayerRenderList();
this.layerService.renderLayers();
};
img.src = mapTexture;
} else {
this.texture = createTexture2D({
width: 0,
height: 0,
});
}
}
protected getConfigSchema() {
return {
properties: {
opacity: {
type: 'number',
minimum: 0,
maximum: 1,
},
},
};
}
protected registerBuiltinAttributes() {
// point layer size;
this.styleAttributeService.registerStyleAttribute({
name: 'uv',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Uv',
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]];
},
},
});
}
}

View File

@ -0,0 +1,21 @@
uniform sampler2D u_texture;
uniform float u_mapFlag;
uniform float u_opacity;
varying vec3 v_Color;
varying vec2 v_uv;
#pragma include "picking"
void main() {
// gl_FragColor = vec4(v_Color, u_opacity);
if(u_mapFlag > 0.0) {
gl_FragColor = texture2D(u_texture, vec2(v_uv.x, 1.0 - v_uv.y));
gl_FragColor.a *= u_opacity;
} else {
// gl_FragColor = vec4(v_uv, 0.0, u_opacity);
gl_FragColor = vec4(v_Color, u_opacity);
}
gl_FragColor = filterColor(gl_FragColor);
}

View File

@ -0,0 +1,46 @@
precision highp float;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
attribute vec3 a_Position;
attribute vec2 a_Uv;
attribute vec3 a_Color;
varying vec3 v_Color;
varying vec2 v_uv;
#pragma include "projection"
#pragma include "picking"
void main() {
v_Color = a_Color;
v_uv = a_Uv;
vec4 project_pos = project_position(vec4(a_Position, 1.0));
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy,0., 1.0));
// float x = 1.0;
// float y = 0.0;
// float z = 0.0;
// mat3 translateMatrix = mat3(
// 1.0, 0.0, 0.0
// 0.0, 1.0, 0.0
// -project_pos.x, -project_pos.y, 1.0
// );
// mat4 translateMatrix = mat4(
// 1.0, 0.0, 0.0, 0.0 ,
// 0.0, 1.0, 0.0, 0.0,
// 0.0, 0.0, 1.0, 0.0,
// 1.0, 0.0, 0.0, 1.0
// );
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
gl_Position = u_Mvp * (vec4(project_pos.xy, 0., 1.0));
} else {
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy, 0., 1.0));
}
setPickingColor(a_PickingColor);
gl_PointSize = 10.0;
}

View File

@ -2,6 +2,7 @@ import BaseModel from '../../core/BaseModel';
import {
CanvasUpdateType,
ICanvasLayerStyleOptions,
IDrawingOnCanvas,
} from '../../core/interface';
export default class CanvaModel extends BaseModel {
@ -121,7 +122,12 @@ export default class CanvaModel extends BaseModel {
} = this.layer.getLayerConfig() as ICanvasLayerStyleOptions;
if (this.ctx) {
drawingOnCanvas(this.ctx, this.mapService, [viewWidth, viewHeight]);
drawingOnCanvas({
canvas: this.canvas,
ctx: this.ctx,
mapService: this.mapService,
size: [viewWidth, viewHeight],
});
}
};

View File

@ -106,18 +106,37 @@ export interface IImageLayerStyleOptions {
maskInside?: boolean;
}
export interface IGeometryLayerStyleOptions {
opacity: number;
mask?: boolean;
maskInside?: boolean;
mapTexture?: string;
// planeGeometry
center?: [number, number];
width?: number;
height?: number;
widthSegments?: number;
heightSegments?: number;
}
export enum CanvasUpdateType {
'AWAYS' = 'aways',
'DRAGEND' = 'dragend',
}
export interface IDrawingOnCanvas {
canvas: HTMLCanvasElement;
ctx: CanvasRenderingContext2D;
mapService: IMapService;
size: [number, number];
}
export interface ICanvasLayerStyleOptions {
zIndex: number;
update: CanvasUpdateType | string;
drawingOnCanvas: (
ctx: CanvasRenderingContext2D,
mapService: IMapService,
size: [number, number],
) => void;
drawingOnCanvas: (option: IDrawingOnCanvas) => void;
}
export interface IHeatMapLayerStyleOptions {

View File

@ -289,6 +289,7 @@ export function RasterImageTriangulation(feature: IEncodeFeature) {
size: 5,
};
}
/**
* 3D弧线顶点
* @param feature

View File

@ -2,6 +2,7 @@ import { container, ILayerPlugin, TYPES } from '@antv/l7-core';
import CanvasLayer from './canvas';
import CityBuildingLayer from './citybuliding/building';
import BaseLayer from './core/BaseLayer';
import GeometryLayer from './Geometry';
import './glsl.d';
import HeatmapLayer from './heatmap';
import ImageLayer from './image';
@ -142,6 +143,7 @@ export {
PolygonLayer,
LineLayer,
CityBuildingLayer,
GeometryLayer,
CanvasLayer,
ImageLayer,
ImageTileLayer,

View File

@ -33,11 +33,7 @@ export default class Demo extends React.Component {
zIndex: 10,
update: 'aways',
// update: 'dragend',
drawingOnCanvas: (
ctx: CanvasRenderingContext2D,
mapService: IMapService,
size: [number, number],
) => {
drawingOnCanvas: ({ ctx, mapService, size }) => {
const [width, height] = size;
ctx.clearRect(0, 0, width, height);

View File

@ -0,0 +1,81 @@
import { GeometryLayer, Scene, IMapService } from '@antv/l7';
import { GaodeMap, Mapbox } from '@antv/l7-maps';
import * as React from 'react';
export default class Demo extends React.Component {
// @ts-ignore
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new GaodeMap({
// map: new Mapbox({
pitch: 0,
// style: 'dark',
center: [120, 30],
zoom: 5,
}),
});
this.scene = scene;
let layer = new GeometryLayer()
.source([{ lng: 120, lat: 30 }], {
parser: {
type: 'json',
x: 'lng',
y: 'lat',
},
})
.style({
width: 2,
height: 2,
opacity: 0.8,
widthSegments: 3,
heightSegments: 3,
center: [120, 30],
// mapTexture: 'https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*FG4fT7h5AYMAAAAAAAAAAAAAARQnAQ'
})
.active({
color: '#00f',
mix: 0.5,
})
.color('#ff0');
scene.on('loaded', () => {
scene.addLayer(layer);
setTimeout(() => {
// layer.style({
// mapTexture: ""
// })
layer.style({
mapTexture:
'https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*GJhASbfQTK8AAAAAAAAAAAAAARQnAQ',
});
scene.render();
}, 2000);
});
}
public render() {
return (
<>
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
</>
);
}
}

View File

@ -5,10 +5,12 @@ import Ocean from './components/ocean';
import Taifong from './components/taifeng'
import Radar from './components/radar';
import CanvasDemo from './components/canvas';
import Plane from './components/plane';
storiesOf('Object', module)
.add('water', () => <Water />)
.add('Ocean', () => <Ocean />)
.add('Taifong', () => <Taifong />)
.add('Radar', () => <Radar/>)
.add('CanvasDemo', () => <CanvasDemo/>)
.add('CanvasDemo', () => <CanvasDemo/>)
.add('Plane', () => <Plane/>)