feat: polygon 支持text

This commit is contained in:
thinkinggis 2019-12-30 18:10:21 +08:00
parent 0a9558d8eb
commit 3114ab55a5
12 changed files with 118 additions and 44 deletions

View File

@ -12,7 +12,7 @@ import {
} from './IFontService'; } from './IFontService';
export const DEFAULT_CHAR_SET = getDefaultCharacterSet(); export const DEFAULT_CHAR_SET = getDefaultCharacterSet();
export const DEFAULT_FONT_FAMILY = 'sans-serif'; export const DEFAULT_FONT_FAMILY = 'sans-serif';
export const DEFAULT_FONT_WEIGHT = 'normal'; export const DEFAULT_FONT_WEIGHT = '800';
export const DEFAULT_FONT_SIZE = 24; export const DEFAULT_FONT_SIZE = 24;
export const DEFAULT_BUFFER = 3; export const DEFAULT_BUFFER = 3;
export const DEFAULT_CUTOFF = 0.25; export const DEFAULT_CUTOFF = 0.25;

View File

@ -16,16 +16,6 @@ export default class CityBuildingLayer extends BaseLayer {
}, },
}; };
} }
protected renderModels() {
this.models.forEach((model) =>
model.draw({
uniforms: this.layerModel.getUninforms(),
}),
);
return this;
}
protected buildModels() { protected buildModels() {
this.layerModel = new CityBuildModel(this); this.layerModel = new CityBuildModel(this);
this.models = this.layerModel.buildModels(); this.models = this.layerModel.buildModels();

View File

@ -2,6 +2,7 @@ import { IEncodeFeature } from '@antv/l7-core';
import { aProjectFlat, lngLatToMeters } from '@antv/l7-utils'; import { aProjectFlat, lngLatToMeters } from '@antv/l7-utils';
import earcut from 'earcut'; import earcut from 'earcut';
import { vec3 } from 'gl-matrix'; import { vec3 } from 'gl-matrix';
import { calculteCentroid } from '../utils/geo';
import getNormals from '../utils/polylineNormal'; import getNormals from '../utils/polylineNormal';
import extrudePolygon, { import extrudePolygon, {
extrude_PolygonNormal, extrude_PolygonNormal,
@ -24,7 +25,7 @@ const GeometryCache: IGeometryCache = {};
* @param feature feature * @param feature feature
*/ */
export function PointFillTriangulation(feature: IEncodeFeature) { export function PointFillTriangulation(feature: IEncodeFeature) {
const coordinates = feature.coordinates as number[]; const coordinates = calculteCentroid(feature.coordinates);
return { return {
vertices: [...coordinates, ...coordinates, ...coordinates, ...coordinates], vertices: [...coordinates, ...coordinates, ...coordinates, ...coordinates],
indices: [0, 1, 2, 2, 3, 0], indices: [0, 1, 2, 2, 3, 0],
@ -46,7 +47,6 @@ export function PointExtrudeTriangulation(feature: IEncodeFeature) {
vertices: positions, vertices: positions,
indices: index, indices: index,
normals, normals,
// normals: Array.from(computeVertexNormals(positions, index, 3, false)),
size: 5, size: 5,
}; };
} }
@ -56,7 +56,7 @@ export function PointExtrudeTriangulation(feature: IEncodeFeature) {
* @param feature feature * @param feature feature
*/ */
export function PointImageTriangulation(feature: IEncodeFeature) { export function PointImageTriangulation(feature: IEncodeFeature) {
const coordinates = feature.coordinates as number[]; const coordinates = calculteCentroid(feature.coordinates);
return { return {
vertices: [...coordinates], vertices: [...coordinates],
indices: [0], indices: [0],

View File

@ -8,10 +8,9 @@ export default class UpdateModelPlugin implements ILayerPlugin {
public apply(layer: ILayer) { public apply(layer: ILayer) {
layer.hooks.beforeRender.tap('UpdateModelPlugin', () => { layer.hooks.beforeRender.tap('UpdateModelPlugin', () => {
// 处理文本更新 // 处理文本更新
layer.layerModel.needUpdate(); if (layer.layerModel) {
// if (layer.layerModel.needUpdate()) { layer.layerModel.needUpdate();
// layer.layerModelNeedUpdate = true; }
// }
}); });
} }
} }

View File

@ -1,6 +1,7 @@
import { AttributeType, gl, IEncodeFeature, IModel } from '@antv/l7-core'; import { AttributeType, gl, IEncodeFeature, IModel } from '@antv/l7-core';
import BaseModel from '../../core/BaseModel'; import BaseModel from '../../core/BaseModel';
import { PointExtrudeTriangulation } from '../../core/triangulation'; import { PointExtrudeTriangulation } from '../../core/triangulation';
import { calculteCentroid } from '../../utils/geo';
import pointExtrudeFrag from '../shaders/extrude_frag.glsl'; import pointExtrudeFrag from '../shaders/extrude_frag.glsl';
import pointExtrudeVert from '../shaders/extrude_vert.glsl'; import pointExtrudeVert from '../shaders/extrude_vert.glsl';
interface IPointLayerStyleOptions { interface IPointLayerStyleOptions {
@ -100,7 +101,7 @@ export default class ExtrudeModel extends BaseModel {
}, },
size: 3, size: 3,
update: (feature: IEncodeFeature, featureIdx: number) => { update: (feature: IEncodeFeature, featureIdx: number) => {
const coordinates = feature.coordinates as number[]; const coordinates = calculteCentroid(feature.coordinates);
return [coordinates[0], coordinates[1], 0]; return [coordinates[0], coordinates[1], 0];
}, },
}, },

View File

@ -12,6 +12,7 @@ import {
import { rgb2arr } from '@antv/l7-utils'; import { rgb2arr } from '@antv/l7-utils';
import BaseModel from '../../core/BaseModel'; import BaseModel from '../../core/BaseModel';
import CollisionIndex from '../../utils/collision-index'; import CollisionIndex from '../../utils/collision-index';
import { calculteCentroid } from '../../utils/geo';
import { import {
getGlyphQuads, getGlyphQuads,
IGlyphQuad, IGlyphQuad,
@ -33,14 +34,12 @@ interface IPointTextLayerStyleOptions {
textAllowOverlap: boolean; textAllowOverlap: boolean;
} }
export function TextTriangulation(feature: IEncodeFeature) { export function TextTriangulation(feature: IEncodeFeature) {
const coordinates = feature.coordinates as number[]; const centroid = feature.centroid as number[]; // 计算中心点
const { glyphQuads } = feature; const { glyphQuads } = feature;
const vertices: number[] = []; const vertices: number[] = [];
const indices: number[] = []; const indices: number[] = [];
const coord = const coord =
coordinates.length === 2 centroid.length === 2 ? [centroid[0], centroid[1], 0] : centroid;
? [coordinates[0], coordinates[1], 0]
: coordinates;
glyphQuads.forEach((quad: IGlyphQuad, index: number) => { glyphQuads.forEach((quad: IGlyphQuad, index: number) => {
vertices.push( vertices.push(
...coord, ...coord,
@ -90,8 +89,8 @@ export default class TextModel extends BaseModel {
const { const {
fontWeight = 800, fontWeight = 800,
fontFamily, fontFamily,
stroke, stroke = '#fff',
strokeWidth, strokeWidth = 0,
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions; } = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
const { canvas } = this.fontService; const { canvas } = this.fontService;
return { return {
@ -235,7 +234,7 @@ export default class TextModel extends BaseModel {
*/ */
private initTextFont() { private initTextFont() {
const { const {
fontWeight = 'normal', fontWeight = '800',
fontFamily, fontFamily,
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions; } = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
const data = this.layer.getEncodedData(); const data = this.layer.getEncodedData();
@ -268,7 +267,7 @@ export default class TextModel extends BaseModel {
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions; } = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
const data = this.layer.getEncodedData(); const data = this.layer.getEncodedData();
this.glyphInfo = data.map((feature: IEncodeFeature) => { this.glyphInfo = data.map((feature: IEncodeFeature) => {
const { shape = '' } = feature; const { shape = '', coordinates } = feature;
const shaping = shapeText( const shaping = shapeText(
shape.toString(), shape.toString(),
mapping, mapping,
@ -281,6 +280,7 @@ export default class TextModel extends BaseModel {
const glyphQuads = getGlyphQuads(shaping, textOffset, false); const glyphQuads = getGlyphQuads(shaping, textOffset, false);
feature.shaping = shaping; feature.shaping = shaping;
feature.glyphQuads = glyphQuads; feature.glyphQuads = glyphQuads;
feature.centroid = calculteCentroid(coordinates);
return feature; return feature;
}); });
} }
@ -301,10 +301,10 @@ export default class TextModel extends BaseModel {
const collisionIndex = new CollisionIndex(width, height); const collisionIndex = new CollisionIndex(width, height);
const filterData = this.glyphInfo.filter((feature: IEncodeFeature) => { const filterData = this.glyphInfo.filter((feature: IEncodeFeature) => {
const { shaping, id = 0 } = feature; const { shaping, id = 0 } = feature;
const coordinates = feature.coordinates as [number, number]; const centroid = feature.centroid as [number, number];
const size = feature.size as number; const size = feature.size as number;
const fontScale: number = size / 24; const fontScale: number = size / 24;
const pixels = this.mapService.lngLatToContainer(coordinates); const pixels = this.mapService.lngLatToContainer(centroid);
const { box } = collisionIndex.placeCollisionBox({ const { box } = collisionIndex.placeCollisionBox({
x1: shaping.left * fontScale - padding[0], x1: shaping.left * fontScale - padding[0],
x2: shaping.right * fontScale + padding[0], x2: shaping.right * fontScale + padding[0],

View File

@ -1,5 +1,6 @@
import { IEncodeFeature } from '@antv/l7-core'; import { IEncodeFeature } from '@antv/l7-core';
import BaseLayer from '../core/BaseLayer'; import BaseLayer from '../core/BaseLayer';
import { PointType } from '../point/models/';
import PolygonModels, { PolygonModelType } from './models/'; import PolygonModels, { PolygonModelType } from './models/';
interface IPolygonLayerStyleOptions { interface IPolygonLayerStyleOptions {
@ -31,6 +32,42 @@ export default class PolygonLayer extends BaseLayer<IPolygonLayerStyleOptions> {
'shape', 'shape',
); );
const shape = shapeAttribute?.scale?.field as PolygonModelType; const shape = shapeAttribute?.scale?.field as PolygonModelType;
return shape || 'fill'; if (shape === 'fill') {
return 'fill';
} else if (shape === 'extrude') {
return 'extrude';
} else if (shape === 'line') {
return 'line';
} else {
return this.getPointModelType();
}
}
protected getPointModelType(): PolygonModelType {
// pointlayer
// 2D、 3d、 shape、image、text、normal、
const layerData = this.getEncodedData();
const { shape2d, shape3d } = this.getLayerConfig();
const iconMap = this.iconService.getIconMap();
const item = layerData.find((fe: IEncodeFeature) => {
return fe.hasOwnProperty('shape');
});
if (!item) {
return 'fill';
} else {
const shape = item.shape;
if (shape === 'dot') {
return 'point_normal';
}
if (shape2d?.indexOf(shape as string) !== -1) {
return 'point_fill';
}
if (shape3d?.indexOf(shape as string) !== -1) {
return 'point_extrude';
}
if (iconMap.hasOwnProperty(shape as string)) {
return 'point_image';
}
return 'text';
}
} }
} }

View File

@ -1,13 +1,32 @@
import LineModel from '../../line/models/line'; import LineModel from '../../line/models/line';
import PointExtrudeModel from '../../point/models/extrude';
import PointFillModel from '../../point/models/fill';
import IMageModel from '../../point/models/image';
import NormalModel from '../../point/models/normal';
import TextModel from '../../point/models/text';
import ExtrudeModel from './extrude'; import ExtrudeModel from './extrude';
import FillModel from './fill'; import FillModel from './fill';
export type PolygonModelType = 'fill' | 'extrude' | 'line'; export type PolygonModelType =
| 'fill'
| 'extrude'
| 'line'
| 'point_fill'
| 'point_image'
| 'point_normal'
| 'point_extrude'
| 'text';
const PolygonModels: { [key in PolygonModelType]: any } = { const PolygonModels: { [key in PolygonModelType]: any } = {
fill: FillModel, fill: FillModel,
line: LineModel, line: LineModel,
extrude: ExtrudeModel, extrude: ExtrudeModel,
}; text: TextModel,
point_fill: PointFillModel,
point_image: IMageModel,
point_normal: NormalModel,
point_extrude: PointExtrudeModel,
// point_fill: PointModels.fill,
};
export default PolygonModels; export default PolygonModels;

View File

@ -0,0 +1,27 @@
type Position = number[];
import { isNumber } from 'lodash';
export function calculteCentroid(
coord: Position | Position[] | Position[][],
): Position {
// let pos = coord as Position;
if (isNumber(coord[0])) {
return coord as Position;
} else if (isNumber(coord[0][0])) {
throw new Error('当前数据不支持标注');
} else if (isNumber(coord[0][0][0])) {
const coords = coord as Position[][];
let xSum = 0;
let ySum = 0;
let len = 0;
coords.forEach((coor: Position[]) => {
coor.forEach((pos) => {
xSum += pos[0];
ySum += pos[1];
len++;
});
});
return [xSum / len, ySum / len, 0];
} else {
throw new Error('当前数据不支持标注');
}
}

View File

@ -237,7 +237,7 @@ export function getGlyphQuads(
textOffset: [number, number] = [0, 0], textOffset: [number, number] = [0, 0],
alongLine: boolean, alongLine: boolean,
): IGlyphQuad[] { ): IGlyphQuad[] {
const { positionedGlyphs } = shaping; const { positionedGlyphs = [] } = shaping;
const quads: IGlyphQuad[] = []; const quads: IGlyphQuad[] = [];
for (const positionedGlyph of positionedGlyphs) { for (const positionedGlyph of positionedGlyphs) {

View File

@ -19,7 +19,7 @@ export default class ZoomComponent extends React.Component {
const scene = new Scene({ const scene = new Scene({
id: 'map', id: 'map',
map: new Mapbox({ map: new Mapbox({
style: 'mapbox://styles/mapbox/streets-v9', style: 'dark',
center: [110.19382669582967, 30.258134], center: [110.19382669582967, 30.258134],
pitch: 0, pitch: 0,
zoom: 3, zoom: 3,
@ -39,9 +39,10 @@ export default class ZoomComponent extends React.Component {
'#FF7A45', '#FF7A45',
'#CF1D49', '#CF1D49',
]) ])
.shape('fill') .shape('name', 'text')
.size(10)
.style({ .style({
opacity: 0.3, opacity: 1.0,
}); });
scene.addLayer(layer); scene.addLayer(layer);
const zoomControl = new Zoom({ const zoomControl = new Zoom({

View File

@ -64,14 +64,14 @@ export default class TextLayerDemo extends React.Component {
.size(12) .size(12)
.color('#fff') .color('#fff')
.style({ .style({
fontWeight: 200, // fontWeight: 200,
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left // textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
textOffset: [0, 0], // 文本相对锚点的偏移量 [水平, 垂直] // textOffset: [0, 0], // 文本相对锚点的偏移量 [水平, 垂直]
spacing: 2, // 字符间距 // spacing: 2, // 字符间距
padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近 // padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
stroke: 'red', // 描边颜色 // stroke: 'red', // 描边颜色
strokeWidth: 2, // 描边宽度 // strokeWidth: 2, // 描边宽度
strokeOpacity: 1.0, // strokeOpacity: 1.0,
}); });
scene.addLayer(pointLayer); scene.addLayer(pointLayer);