mirror of https://gitee.com/antv-l7/antv-l7
feat: polygon 支持text
This commit is contained in:
parent
0a9558d8eb
commit
3114ab55a5
|
@ -12,7 +12,7 @@ import {
|
|||
} from './IFontService';
|
||||
export const DEFAULT_CHAR_SET = getDefaultCharacterSet();
|
||||
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_BUFFER = 3;
|
||||
export const DEFAULT_CUTOFF = 0.25;
|
||||
|
|
|
@ -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() {
|
||||
this.layerModel = new CityBuildModel(this);
|
||||
this.models = this.layerModel.buildModels();
|
||||
|
|
|
@ -2,6 +2,7 @@ import { IEncodeFeature } from '@antv/l7-core';
|
|||
import { aProjectFlat, lngLatToMeters } from '@antv/l7-utils';
|
||||
import earcut from 'earcut';
|
||||
import { vec3 } from 'gl-matrix';
|
||||
import { calculteCentroid } from '../utils/geo';
|
||||
import getNormals from '../utils/polylineNormal';
|
||||
import extrudePolygon, {
|
||||
extrude_PolygonNormal,
|
||||
|
@ -24,7 +25,7 @@ const GeometryCache: IGeometryCache = {};
|
|||
* @param feature 映射feature
|
||||
*/
|
||||
export function PointFillTriangulation(feature: IEncodeFeature) {
|
||||
const coordinates = feature.coordinates as number[];
|
||||
const coordinates = calculteCentroid(feature.coordinates);
|
||||
return {
|
||||
vertices: [...coordinates, ...coordinates, ...coordinates, ...coordinates],
|
||||
indices: [0, 1, 2, 2, 3, 0],
|
||||
|
@ -46,7 +47,6 @@ export function PointExtrudeTriangulation(feature: IEncodeFeature) {
|
|||
vertices: positions,
|
||||
indices: index,
|
||||
normals,
|
||||
// normals: Array.from(computeVertexNormals(positions, index, 3, false)),
|
||||
size: 5,
|
||||
};
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ export function PointExtrudeTriangulation(feature: IEncodeFeature) {
|
|||
* @param feature 映射feature
|
||||
*/
|
||||
export function PointImageTriangulation(feature: IEncodeFeature) {
|
||||
const coordinates = feature.coordinates as number[];
|
||||
const coordinates = calculteCentroid(feature.coordinates);
|
||||
return {
|
||||
vertices: [...coordinates],
|
||||
indices: [0],
|
||||
|
|
|
@ -8,10 +8,9 @@ export default class UpdateModelPlugin implements ILayerPlugin {
|
|||
public apply(layer: ILayer) {
|
||||
layer.hooks.beforeRender.tap('UpdateModelPlugin', () => {
|
||||
// 处理文本更新
|
||||
layer.layerModel.needUpdate();
|
||||
// if (layer.layerModel.needUpdate()) {
|
||||
// layer.layerModelNeedUpdate = true;
|
||||
// }
|
||||
if (layer.layerModel) {
|
||||
layer.layerModel.needUpdate();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { AttributeType, gl, IEncodeFeature, IModel } from '@antv/l7-core';
|
||||
import BaseModel from '../../core/BaseModel';
|
||||
import { PointExtrudeTriangulation } from '../../core/triangulation';
|
||||
import { calculteCentroid } from '../../utils/geo';
|
||||
import pointExtrudeFrag from '../shaders/extrude_frag.glsl';
|
||||
import pointExtrudeVert from '../shaders/extrude_vert.glsl';
|
||||
interface IPointLayerStyleOptions {
|
||||
|
@ -100,7 +101,7 @@ export default class ExtrudeModel extends BaseModel {
|
|||
},
|
||||
size: 3,
|
||||
update: (feature: IEncodeFeature, featureIdx: number) => {
|
||||
const coordinates = feature.coordinates as number[];
|
||||
const coordinates = calculteCentroid(feature.coordinates);
|
||||
return [coordinates[0], coordinates[1], 0];
|
||||
},
|
||||
},
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
import { rgb2arr } from '@antv/l7-utils';
|
||||
import BaseModel from '../../core/BaseModel';
|
||||
import CollisionIndex from '../../utils/collision-index';
|
||||
import { calculteCentroid } from '../../utils/geo';
|
||||
import {
|
||||
getGlyphQuads,
|
||||
IGlyphQuad,
|
||||
|
@ -33,14 +34,12 @@ interface IPointTextLayerStyleOptions {
|
|||
textAllowOverlap: boolean;
|
||||
}
|
||||
export function TextTriangulation(feature: IEncodeFeature) {
|
||||
const coordinates = feature.coordinates as number[];
|
||||
const centroid = feature.centroid as number[]; // 计算中心点
|
||||
const { glyphQuads } = feature;
|
||||
const vertices: number[] = [];
|
||||
const indices: number[] = [];
|
||||
const coord =
|
||||
coordinates.length === 2
|
||||
? [coordinates[0], coordinates[1], 0]
|
||||
: coordinates;
|
||||
centroid.length === 2 ? [centroid[0], centroid[1], 0] : centroid;
|
||||
glyphQuads.forEach((quad: IGlyphQuad, index: number) => {
|
||||
vertices.push(
|
||||
...coord,
|
||||
|
@ -90,8 +89,8 @@ export default class TextModel extends BaseModel {
|
|||
const {
|
||||
fontWeight = 800,
|
||||
fontFamily,
|
||||
stroke,
|
||||
strokeWidth,
|
||||
stroke = '#fff',
|
||||
strokeWidth = 0,
|
||||
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||
const { canvas } = this.fontService;
|
||||
return {
|
||||
|
@ -235,7 +234,7 @@ export default class TextModel extends BaseModel {
|
|||
*/
|
||||
private initTextFont() {
|
||||
const {
|
||||
fontWeight = 'normal',
|
||||
fontWeight = '800',
|
||||
fontFamily,
|
||||
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||
const data = this.layer.getEncodedData();
|
||||
|
@ -268,7 +267,7 @@ export default class TextModel extends BaseModel {
|
|||
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||
const data = this.layer.getEncodedData();
|
||||
this.glyphInfo = data.map((feature: IEncodeFeature) => {
|
||||
const { shape = '' } = feature;
|
||||
const { shape = '', coordinates } = feature;
|
||||
const shaping = shapeText(
|
||||
shape.toString(),
|
||||
mapping,
|
||||
|
@ -281,6 +280,7 @@ export default class TextModel extends BaseModel {
|
|||
const glyphQuads = getGlyphQuads(shaping, textOffset, false);
|
||||
feature.shaping = shaping;
|
||||
feature.glyphQuads = glyphQuads;
|
||||
feature.centroid = calculteCentroid(coordinates);
|
||||
return feature;
|
||||
});
|
||||
}
|
||||
|
@ -301,10 +301,10 @@ export default class TextModel extends BaseModel {
|
|||
const collisionIndex = new CollisionIndex(width, height);
|
||||
const filterData = this.glyphInfo.filter((feature: IEncodeFeature) => {
|
||||
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 fontScale: number = size / 24;
|
||||
const pixels = this.mapService.lngLatToContainer(coordinates);
|
||||
const pixels = this.mapService.lngLatToContainer(centroid);
|
||||
const { box } = collisionIndex.placeCollisionBox({
|
||||
x1: shaping.left * fontScale - padding[0],
|
||||
x2: shaping.right * fontScale + padding[0],
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { IEncodeFeature } from '@antv/l7-core';
|
||||
import BaseLayer from '../core/BaseLayer';
|
||||
import { PointType } from '../point/models/';
|
||||
import PolygonModels, { PolygonModelType } from './models/';
|
||||
|
||||
interface IPolygonLayerStyleOptions {
|
||||
|
@ -31,6 +32,42 @@ export default class PolygonLayer extends BaseLayer<IPolygonLayerStyleOptions> {
|
|||
'shape',
|
||||
);
|
||||
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';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,32 @@
|
|||
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 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 } = {
|
||||
fill: FillModel,
|
||||
line: LineModel,
|
||||
extrude: ExtrudeModel,
|
||||
};
|
||||
text: TextModel,
|
||||
point_fill: PointFillModel,
|
||||
point_image: IMageModel,
|
||||
point_normal: NormalModel,
|
||||
point_extrude: PointExtrudeModel,
|
||||
|
||||
// point_fill: PointModels.fill,
|
||||
};
|
||||
export default PolygonModels;
|
||||
|
|
|
@ -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('当前数据不支持标注');
|
||||
}
|
||||
}
|
|
@ -237,7 +237,7 @@ export function getGlyphQuads(
|
|||
textOffset: [number, number] = [0, 0],
|
||||
alongLine: boolean,
|
||||
): IGlyphQuad[] {
|
||||
const { positionedGlyphs } = shaping;
|
||||
const { positionedGlyphs = [] } = shaping;
|
||||
const quads: IGlyphQuad[] = [];
|
||||
|
||||
for (const positionedGlyph of positionedGlyphs) {
|
||||
|
|
|
@ -19,7 +19,7 @@ export default class ZoomComponent extends React.Component {
|
|||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new Mapbox({
|
||||
style: 'mapbox://styles/mapbox/streets-v9',
|
||||
style: 'dark',
|
||||
center: [110.19382669582967, 30.258134],
|
||||
pitch: 0,
|
||||
zoom: 3,
|
||||
|
@ -39,9 +39,10 @@ export default class ZoomComponent extends React.Component {
|
|||
'#FF7A45',
|
||||
'#CF1D49',
|
||||
])
|
||||
.shape('fill')
|
||||
.shape('name', 'text')
|
||||
.size(10)
|
||||
.style({
|
||||
opacity: 0.3,
|
||||
opacity: 1.0,
|
||||
});
|
||||
scene.addLayer(layer);
|
||||
const zoomControl = new Zoom({
|
||||
|
|
|
@ -64,14 +64,14 @@ export default class TextLayerDemo extends React.Component {
|
|||
.size(12)
|
||||
.color('#fff')
|
||||
.style({
|
||||
fontWeight: 200,
|
||||
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
||||
textOffset: [0, 0], // 文本相对锚点的偏移量 [水平, 垂直]
|
||||
spacing: 2, // 字符间距
|
||||
padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
|
||||
stroke: 'red', // 描边颜色
|
||||
strokeWidth: 2, // 描边宽度
|
||||
strokeOpacity: 1.0,
|
||||
// fontWeight: 200,
|
||||
// textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
||||
// textOffset: [0, 0], // 文本相对锚点的偏移量 [水平, 垂直]
|
||||
// spacing: 2, // 字符间距
|
||||
// padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
|
||||
// stroke: 'red', // 描边颜色
|
||||
// strokeWidth: 2, // 描边宽度
|
||||
// strokeOpacity: 1.0,
|
||||
});
|
||||
scene.addLayer(pointLayer);
|
||||
|
||||
|
|
Loading…
Reference in New Issue