mirror of https://gitee.com/antv-l7/antv-l7
feat(point image): add point image
This commit is contained in:
parent
a995815284
commit
89b25133a1
|
@ -6,7 +6,7 @@ import getDecorators from 'inversify-inject-decorators';
|
|||
import { TYPES } from './types';
|
||||
|
||||
/** Service interfaces */
|
||||
import { IIconService} from './services/asset/IIconService';
|
||||
import { IIconService } from './services/asset/IIconService';
|
||||
import { ICameraService } from './services/camera/ICameraService';
|
||||
import { IGlobalConfigService } from './services/config/IConfigService';
|
||||
import { ICoordinateSystemService } from './services/coordinate/ICoordinateSystemService';
|
||||
|
|
|
@ -15,7 +15,10 @@ export interface IICONMap {
|
|||
[key: string]: IIconValue;
|
||||
}
|
||||
export interface IIconService {
|
||||
canvasHeight: number;
|
||||
init(): void;
|
||||
addImage(id: string, image: IImage): void;
|
||||
getTexture(): ITexture2D;
|
||||
getIconMap(): IICONMap;
|
||||
getCanvas(): HTMLCanvasElement;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import { inject, injectable } from 'inversify';
|
||||
import { TYPES } from '../../types';
|
||||
import { buildIconMaping } from '../../utils/font_util';
|
||||
import { gl } from '../renderer/gl';
|
||||
import { IRendererService } from '../renderer/IRendererService';
|
||||
import { ITexture2D } from '../renderer/ITexture2D';
|
||||
import {
|
||||
IIcon,
|
||||
|
@ -13,23 +16,24 @@ const MAX_CANVAS_WIDTH = 1024;
|
|||
const imageSize = 64;
|
||||
@injectable()
|
||||
export default class IconService implements IIconService {
|
||||
public canvasHeight: number;
|
||||
private textrure: ITexture2D;
|
||||
private canvas: HTMLCanvasElement;
|
||||
private iconData: IIcon[];
|
||||
private iconMap: IICONMap;
|
||||
private canvasHeigth: number;
|
||||
private textrure: ITexture2D;
|
||||
private ctx: CanvasRenderingContext2D;
|
||||
|
||||
constructor() {
|
||||
public init() {
|
||||
this.iconData = [];
|
||||
this.iconMap = {};
|
||||
this.canvas = document.createElement('canvas');
|
||||
// this.texture =
|
||||
this.ctx = this.canvas.getContext('2d') as CanvasRenderingContext2D;
|
||||
}
|
||||
|
||||
public async addImage(id: string, image: IImage) {
|
||||
const imagedata = (await this.loadImage(image)) as HTMLImageElement;
|
||||
public addImage(id: string, image: IImage) {
|
||||
let imagedata = new Image();
|
||||
this.loadImage(image).then((img) => {
|
||||
imagedata = img as HTMLImageElement;
|
||||
});
|
||||
this.iconData.push({
|
||||
id,
|
||||
image: imagedata,
|
||||
|
@ -42,28 +46,35 @@ export default class IconService implements IIconService {
|
|||
MAX_CANVAS_WIDTH,
|
||||
);
|
||||
this.iconMap = mapping;
|
||||
this.canvasHeigth = canvasHeight;
|
||||
this.canvasHeight = canvasHeight;
|
||||
this.updateIconAtlas();
|
||||
}
|
||||
|
||||
public getTexture(): ITexture2D {
|
||||
throw new Error('Method not implemented.');
|
||||
return this.textrure;
|
||||
}
|
||||
|
||||
public getIconMap() {
|
||||
return this.iconMap;
|
||||
}
|
||||
public getCanvas() {
|
||||
return this.canvas;
|
||||
}
|
||||
|
||||
private updateIconAtlas() {
|
||||
this.canvas.width = MAX_CANVAS_WIDTH;
|
||||
this.canvas.height = this.canvasHeigth;
|
||||
this.canvas.height = this.canvasHeight;
|
||||
Object.keys(this.iconMap).forEach((item: string) => {
|
||||
const { x, y, image } = this.iconMap[item];
|
||||
this.ctx.drawImage(image, x, y, imageSize, imageSize);
|
||||
});
|
||||
// this.texture.magFilter = THREE.LinearFilter;
|
||||
// this.texture.minFilter = THREE.LinearFilter;
|
||||
// this.texture.needsUpdate = true;
|
||||
// const { createTexture2D } = this.rendererService;
|
||||
// this.textrure = createTexture2D({
|
||||
// data: this.canvas,
|
||||
// width: this.canvas.width,
|
||||
// height: this.canvasHeight,
|
||||
// mag: gl.LINEAR,
|
||||
// });
|
||||
}
|
||||
|
||||
private loadImage(url: IImage) {
|
||||
|
@ -73,6 +84,7 @@ export default class IconService implements IIconService {
|
|||
return;
|
||||
}
|
||||
const image = new Image();
|
||||
image.crossOrigin = 'anonymous';
|
||||
image.onload = () => {
|
||||
resolve(image);
|
||||
};
|
||||
|
|
|
@ -33,6 +33,7 @@ export interface ITexture2DInitializationOptions {
|
|||
*/
|
||||
data?:
|
||||
| undefined
|
||||
| HTMLCanvasElement
|
||||
| HTMLImageElement
|
||||
| number[]
|
||||
| number[][]
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import { IImage } from '../asset/IIconService';
|
||||
import { ILayer } from '../layer/ILayerService';
|
||||
import { IMapConfig } from '../map/IMapService';
|
||||
import { IRenderConfig } from '../renderer/IRendererService';
|
||||
|
||||
|
||||
export interface ISceneService {
|
||||
init(config: IMapConfig & IRenderConfig): void;
|
||||
addLayer(layer: ILayer): void;
|
||||
addImage(id: string, image: IImage): void;
|
||||
render(): void;
|
||||
destroy(): void;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { inject, injectable } from 'inversify';
|
|||
import { AsyncParallelHook, AsyncSeriesHook } from 'tapable';
|
||||
import { TYPES } from '../../types';
|
||||
import { createRendererContainer } from '../../utils/dom';
|
||||
import { IIconService, IImage } from '../asset/IIconService';
|
||||
import { ICameraService, IViewport } from '../camera/ICameraService';
|
||||
import { IGlobalConfig, IGlobalConfigService } from '../config/IConfigService';
|
||||
import { IInteractionService } from '../interaction/IInteractionService';
|
||||
|
@ -12,7 +13,6 @@ import { IMapCamera, IMapService } from '../map/IMapService';
|
|||
import { IRendererService } from '../renderer/IRendererService';
|
||||
import { IShaderModuleService } from '../shader/IShaderModuleService';
|
||||
import { ISceneService } from './ISceneService';
|
||||
|
||||
/**
|
||||
* will emit `loaded` `resize` `destroy` event
|
||||
*/
|
||||
|
@ -45,6 +45,9 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
@inject(TYPES.IShaderModuleService)
|
||||
private readonly shaderModule: IShaderModuleService;
|
||||
|
||||
@inject(TYPES.IIconService)
|
||||
private readonly iconService: IIconService;
|
||||
|
||||
/**
|
||||
* 是否首次渲染
|
||||
*/
|
||||
|
@ -76,6 +79,10 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
|
||||
public init(globalConfig: IGlobalConfig) {
|
||||
this.configService.setAndCheckConfig(globalConfig);
|
||||
|
||||
// 初始化资源管理 字体,图片
|
||||
this.iconService.init();
|
||||
|
||||
/**
|
||||
* 初始化底图
|
||||
*/
|
||||
|
@ -151,6 +158,9 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
this.interactionService.destroy();
|
||||
window.removeEventListener('resize', this.handleWindowResized, false);
|
||||
}
|
||||
public addImage(id: string, img: IImage) {
|
||||
this.iconService.addImage(id, img);
|
||||
}
|
||||
|
||||
private handleWindowResized = () => {
|
||||
this.emit('resize');
|
||||
|
@ -174,7 +184,6 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
this.render();
|
||||
}
|
||||
};
|
||||
|
||||
private handleMapCameraChanged = (viewport: IViewport) => {
|
||||
this.cameraService.update(viewport);
|
||||
this.render();
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// Blinn-Phong model
|
||||
// apply lighting in vertex shader instead of fragment shader
|
||||
// @see https://learnopengl.com/Advanced-Lighting/Advanced-Lighting
|
||||
// TODO: support point light、spot light & sun light
|
||||
uniform float u_ambient : 1.0;
|
||||
uniform float u_diffuse : 1.0;
|
||||
uniform float u_specular : 1.0;
|
||||
|
|
|
@ -59,6 +59,8 @@ export default class BaseLayer implements ILayer {
|
|||
public styleAttributes: {
|
||||
[key: string]: Required<ILayerStyleAttribute>;
|
||||
} = {};
|
||||
@lazyInject(TYPES.IIconService)
|
||||
protected readonly iconService: IIconService;
|
||||
|
||||
protected layerSource: Source;
|
||||
|
||||
|
@ -71,9 +73,6 @@ export default class BaseLayer implements ILayer {
|
|||
@lazyInject(TYPES.IRendererService)
|
||||
private readonly rendererService: IRendererService;
|
||||
|
||||
@lazyInject(TYPES.IIconService)
|
||||
private readonly iconService: IIconService;
|
||||
|
||||
constructor(initializationOptions: Partial<ILayerInitializationOptions>) {
|
||||
this.initializationOptions = initializationOptions;
|
||||
}
|
||||
|
@ -140,7 +139,7 @@ export default class BaseLayer implements ILayer {
|
|||
return this;
|
||||
}
|
||||
public style(options: ILayerStyleOptions): ILayer {
|
||||
this.styleOption = options; // TODO: merge 默认同类型
|
||||
this.styleOption = options;
|
||||
return this;
|
||||
}
|
||||
public render(): ILayer {
|
||||
|
|
|
@ -85,10 +85,9 @@ export default class DataEncodePlugin implements ILayerPlugin {
|
|||
id: record._id,
|
||||
coordinates: record.coordinates,
|
||||
};
|
||||
// TODO: 数据过滤
|
||||
Object.keys(attributes).forEach((attributeName: string) => {
|
||||
const attribute = attributes[attributeName];
|
||||
// const { type } = attribute; // TODO: 支持常量 或变量
|
||||
// const { type } = attribute;
|
||||
// if (type === StyleScaleType.CONSTANT) {
|
||||
// return;
|
||||
// }
|
||||
|
|
|
@ -7,11 +7,12 @@ export default class ImageBuffer extends BaseBuffer {
|
|||
}
|
||||
protected buildFeatures() {
|
||||
const layerData = this.data as IEncodeFeature[];
|
||||
this.attributes.uv = new Float32Array(this.verticesCount * 2);
|
||||
layerData.forEach((item: IEncodeFeature, index: number) => {
|
||||
const { color = [0, 0, 0, 0], size, id, shape, coordinates } = item;
|
||||
const { x, y } = this.iconMap[shape as string];
|
||||
const { x, y } = this.iconMap[shape as string] || { x: 0, y: 0 };
|
||||
const coor = coordinates as Position;
|
||||
this.attributes.vertices.set([coor[0], coor[1], coor[2] || 0], index * 3);
|
||||
this.attributes.positions.set(coor, index * 3);
|
||||
this.attributes.colors.set(color, index * 4);
|
||||
this.attributes.pickingIds.set([id as number], index);
|
||||
this.attributes.sizes.set([size as number], index); //
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
gl,
|
||||
IIconService,
|
||||
IRendererService,
|
||||
IShaderModuleService,
|
||||
lazyInject,
|
||||
|
@ -7,8 +8,11 @@ import {
|
|||
} from '@l7/core';
|
||||
import BaseLayer from '../core/BaseLayer';
|
||||
import ExtrudeBuffer from './buffers/ExtrudeBuffer';
|
||||
import ImageBuffer from './buffers/ImageBuffer';
|
||||
import extrude_frag from './shaders/extrude_frag.glsl';
|
||||
import extrude_vert from './shaders/extrude_vert.glsl';
|
||||
import image_frag from './shaders/image_frag.glsl';
|
||||
import image_vert from './shaders/image_vert.glsl';
|
||||
|
||||
export default class PointLayer extends BaseLayer {
|
||||
public name: string = 'PointLayer';
|
||||
|
@ -19,6 +23,7 @@ export default class PointLayer extends BaseLayer {
|
|||
@lazyInject(TYPES.IRendererService)
|
||||
private readonly renderer: IRendererService;
|
||||
|
||||
|
||||
protected renderModels() {
|
||||
this.models.forEach((model) =>
|
||||
model.draw({
|
||||
|
@ -35,20 +40,28 @@ export default class PointLayer extends BaseLayer {
|
|||
vs: extrude_vert,
|
||||
fs: extrude_frag,
|
||||
});
|
||||
this.shaderModule.registerModule('pointImage', {
|
||||
vs: image_vert,
|
||||
fs: image_frag,
|
||||
});
|
||||
|
||||
this.models = [];
|
||||
const { vs, fs, uniforms } = this.shaderModule.getModule('point');
|
||||
const buffer = new ExtrudeBuffer({
|
||||
data: this.getEncodedData(),
|
||||
});
|
||||
buffer.computeVertexNormals('miters', false);
|
||||
const { vs, fs, uniforms } = this.shaderModule.getModule('pointImage');
|
||||
// const buffer = new ExtrudeBuffer({
|
||||
// data: this.getEncodedData(),
|
||||
// });
|
||||
// buffer.computeVertexNormals('miters', false);
|
||||
const {
|
||||
createAttribute,
|
||||
createBuffer,
|
||||
createElements,
|
||||
createTexture2D,
|
||||
createModel,
|
||||
} = this.renderer;
|
||||
|
||||
const buffer = new ImageBuffer({
|
||||
data: this.getEncodedData(),
|
||||
iconMap: this.iconService.getIconMap(),
|
||||
});
|
||||
this.models.push(
|
||||
createModel({
|
||||
attributes: {
|
||||
|
@ -78,27 +91,40 @@ export default class PointLayer extends BaseLayer {
|
|||
data: buffer.attributes.sizes,
|
||||
type: gl.FLOAT,
|
||||
}),
|
||||
size: 3,
|
||||
size: 1,
|
||||
}),
|
||||
a_shape: createAttribute({
|
||||
a_uv: createAttribute({
|
||||
buffer: createBuffer({
|
||||
data: buffer.attributes.miters,
|
||||
data: buffer.attributes.uv,
|
||||
type: gl.FLOAT,
|
||||
}),
|
||||
size: 3,
|
||||
size: 2,
|
||||
}),
|
||||
// a_shape: createAttribute({
|
||||
// buffer: createBuffer({
|
||||
// data: buffer.attributes.miters,
|
||||
// type: gl.FLOAT,
|
||||
// }),
|
||||
// size: 3,
|
||||
// }),
|
||||
},
|
||||
uniforms: {
|
||||
...uniforms,
|
||||
u_opacity: this.styleOption.opacity as number,
|
||||
u_texture: createTexture2D({
|
||||
data: this.iconService.getCanvas(),
|
||||
width: 1024,
|
||||
height: this.iconService.canvasHeight,
|
||||
}),
|
||||
},
|
||||
fs,
|
||||
vs,
|
||||
count: buffer.indexArray.length,
|
||||
elements: createElements({
|
||||
data: buffer.indexArray,
|
||||
type: gl.UNSIGNED_INT,
|
||||
}),
|
||||
primitive: gl.POINTS,
|
||||
count: buffer.verticesCount,
|
||||
// elements: createElements({
|
||||
// data: buffer.indexArray,
|
||||
// type: gl.UNSIGNED_INT,
|
||||
// }),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
uniform sampler2D u_texture;
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_uv;
|
||||
void main(){
|
||||
vec2 pos=v_uv+gl_PointCoord / 512.*64.;
|
||||
pos.y=1.-pos.y;
|
||||
vec2 pos= v_uv + gl_PointCoord / vec2(1024.,128.)*64.;
|
||||
pos.y= 1.- pos.y;
|
||||
vec4 textureColor=texture2D(u_texture,pos);
|
||||
if(v_color == vec4(0.)){
|
||||
gl_FragColor= textureColor;
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
precision highp float;
|
||||
attribute vec3 a_Position;
|
||||
attribute vec4 a_color;
|
||||
attribute vec2 a_uv;
|
||||
attribute float a_size;
|
||||
attribute float a_shape;
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_uv;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
#pragma include "projection"
|
||||
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, 1.0));
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||
gl_PointSize = a_size;
|
||||
v_uv = uv;
|
||||
|
||||
}
|
|
@ -107,7 +107,7 @@ export default function(
|
|||
: null;
|
||||
}
|
||||
}
|
||||
const lineDistance = lineSegmentDistance(cur, last); // TODO: 根据平面坐标计算距离
|
||||
const lineDistance = lineSegmentDistance(cur, last);
|
||||
const d = lineDistance + attrDistance[attrDistance.length - 1];
|
||||
direction(lineA, cur, last);
|
||||
if (!lineNormal) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
container,
|
||||
IImage,
|
||||
ILayer,
|
||||
IMapConfig,
|
||||
IMapService,
|
||||
|
@ -73,10 +74,14 @@ class Scene {
|
|||
public render(): void {
|
||||
this.sceneService.render();
|
||||
}
|
||||
|
||||
public addImage(id: string, img: IImage) {
|
||||
this.sceneService.addImage(id, img);
|
||||
}
|
||||
public destroy() {
|
||||
this.sceneService.destroy();
|
||||
}
|
||||
|
||||
// 资源管理
|
||||
}
|
||||
|
||||
export { Scene };
|
||||
|
|
|
@ -108,6 +108,7 @@ export const getImage = (requestParameters: any, callback: any) => {
|
|||
callback(err);
|
||||
} else if (imgData) {
|
||||
const img = new window.Image();
|
||||
img.crossOrigin = 'anonymous';
|
||||
const URL = window.URL || window.webkitURL;
|
||||
img.onload = () => {
|
||||
callback(null, img);
|
||||
|
|
|
@ -7,6 +7,7 @@ import Point3D from './components/Point3D';
|
|||
import Line from './components/Line';
|
||||
import ImageLayer from './components/Image';
|
||||
import GridHeatMap from './components/GridHeatmap';
|
||||
import PointImage from './components/pointImage';
|
||||
// @ts-ignore
|
||||
import notes from './Map.md';
|
||||
|
||||
|
@ -21,4 +22,5 @@ storiesOf('地图底图测试', module)
|
|||
.add('Point3D', () => <Point3D />)
|
||||
.add('Line', () => <Line />)
|
||||
.add('GridHeatMap', () => <GridHeatMap />)
|
||||
.add('Image', () => <ImageLayer />);
|
||||
.add('Image', () => <ImageLayer />)
|
||||
.add('pointImage', () => <PointImage />);
|
||||
|
|
|
@ -28,9 +28,9 @@ export default class ImageLayerDemo extends React.Component {
|
|||
},
|
||||
},
|
||||
);
|
||||
scene.addLayer(layer);
|
||||
// scene.addLayer(layer);
|
||||
scene.render();
|
||||
this.scene = scene;
|
||||
console.log(scene);
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
|
|
@ -19,6 +19,10 @@ export default class Point3D extends React.Component {
|
|||
style: 'mapbox://styles/mapbox/streets-v9',
|
||||
zoom: 1,
|
||||
});
|
||||
scene.addImage(
|
||||
'00',
|
||||
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*kzTMQqS2QdUAAAAAAAAAAABkARQnAQ',
|
||||
);
|
||||
const pointLayer = new Point({});
|
||||
const p1 = {
|
||||
type: 'FeatureCollection',
|
||||
|
@ -39,13 +43,8 @@ export default class Point3D extends React.Component {
|
|||
.shape('scalerank', [ 'triangleColumn', 'squareColumn', 'hexagonColumn' ,'cylinder' ])
|
||||
.size([25, 10]);
|
||||
scene.addLayer(pointLayer);
|
||||
// function run() {
|
||||
// scene.render();
|
||||
// requestAnimationFrame(run);
|
||||
// }
|
||||
// requestAnimationFrame(run);
|
||||
scene.render();
|
||||
this.scene = scene;
|
||||
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
import { Point } from '@l7/layers';
|
||||
import { Scene } from '@l7/scene';
|
||||
import * as React from 'react';
|
||||
import data from './data.json';
|
||||
export default class PointImage 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,
|
||||
});
|
||||
scene.addImage(
|
||||
'00',
|
||||
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*kzTMQqS2QdUAAAAAAAAAAABkARQnAQ',
|
||||
);
|
||||
const pointLayer = new Point({});
|
||||
const p1 = {
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [83.671875, 44.84029065139799],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
pointLayer
|
||||
.source(data)
|
||||
// .color('blue')
|
||||
.shape('00')
|
||||
.size(14);
|
||||
scene.addLayer(pointLayer);
|
||||
scene.render();
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue