第08章 - 矢量数据与样式
第08章 - 矢量数据与样式
8.1 Feature 要素详解
8.1.1 要素的概念
Feature(要素)是 OpenLayers 中表示地理实体的基本单元,由几何对象(Geometry)和属性(Properties)组成。
┌─────────────────────────────────────────────────────────────┐
│ Feature 结构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Feature │ │
│ │ │ │
│ │ ┌─────────────────────┐ ┌─────────────────────┐ │ │
│ │ │ Geometry │ │ Properties │ │ │
│ │ │ (几何对象) │ │ (属性) │ │ │
│ │ │ │ │ │ │ │
│ │ │ • Point │ │ • id: "1" │ │ │
│ │ │ • LineString │ │ • name: "北京" │ │ │
│ │ │ • Polygon │ │ • population: ... │ │ │
│ │ │ • Multi* │ │ • custom: ... │ │ │
│ │ │ │ │ │ │ │
│ │ └─────────────────────┘ └─────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ Style │ │ │
│ │ │ (样式) │ │ │
│ │ └─────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
8.1.2 创建要素
import Feature from 'ol/Feature';
import Point from 'ol/geom/Point';
import LineString from 'ol/geom/LineString';
import Polygon from 'ol/geom/Polygon';
import { fromLonLat } from 'ol/proj';
// 创建点要素
const pointFeature = new Feature({
geometry: new Point(fromLonLat([116.4074, 39.9042])),
name: '北京',
type: 'city',
population: 21540000
});
// 设置要素 ID
pointFeature.setId('beijing_1');
// 创建线要素
const lineFeature = new Feature({
geometry: new LineString([
fromLonLat([116.4074, 39.9042]),
fromLonLat([121.4737, 31.2304]),
fromLonLat([113.2644, 23.1291])
]),
name: '北京-上海-广州',
type: 'route'
});
// 创建面要素
const polygonFeature = new Feature({
geometry: new Polygon([[
fromLonLat([116.0, 39.0]),
fromLonLat([117.0, 39.0]),
fromLonLat([117.0, 40.0]),
fromLonLat([116.0, 40.0]),
fromLonLat([116.0, 39.0]) // 闭合
]]),
name: '区域A',
type: 'area'
});
// 使用构建器模式
function createFeature(geomType, coordinates, properties) {
const GeomClass = {
Point: Point,
LineString: LineString,
Polygon: Polygon
}[geomType];
const feature = new Feature({
geometry: new GeomClass(coordinates),
...properties
});
if (properties.id) {
feature.setId(properties.id);
}
return feature;
}
8.1.3 要素操作
// ID 操作
feature.setId('unique_id');
const id = feature.getId();
// 几何操作
const geometry = feature.getGeometry();
feature.setGeometry(new Point(fromLonLat([121.4737, 31.2304])));
// 属性操作
feature.set('name', '上海');
const name = feature.get('name');
// 获取所有属性
const properties = feature.getProperties();
// 结果: { geometry: Point, name: '上海', ... }
// 批量设置属性
feature.setProperties({
name: '新名称',
type: '新类型',
updated: Date.now()
});
// 删除属性
feature.unset('updated');
// 克隆要素
const clonedFeature = feature.clone();
// 样式操作
feature.setStyle(new Style({ ... }));
const style = feature.getStyle();
const styleFunction = feature.getStyleFunction();
// 事件监听
feature.on('change', () => {
console.log('要素变化');
});
feature.on('change:geometry', () => {
console.log('几何变化');
});
feature.on('propertychange', (event) => {
console.log('属性变化:', event.key);
});
8.2 Geometry 几何对象
8.2.1 几何类型
import Point from 'ol/geom/Point';
import MultiPoint from 'ol/geom/MultiPoint';
import LineString from 'ol/geom/LineString';
import MultiLineString from 'ol/geom/MultiLineString';
import LinearRing from 'ol/geom/LinearRing';
import Polygon from 'ol/geom/Polygon';
import MultiPolygon from 'ol/geom/MultiPolygon';
import Circle from 'ol/geom/Circle';
import GeometryCollection from 'ol/geom/GeometryCollection';
// Point - 点
const point = new Point([116.4074, 39.9042]);
// MultiPoint - 多点
const multiPoint = new MultiPoint([
[116.4074, 39.9042],
[121.4737, 31.2304]
]);
// LineString - 线
const line = new LineString([
[116.4074, 39.9042],
[121.4737, 31.2304]
]);
// MultiLineString - 多线
const multiLine = new MultiLineString([
[[116, 39], [117, 40]],
[[118, 38], [119, 39]]
]);
// Polygon - 多边形
const polygon = new Polygon([
// 外环
[[116, 39], [117, 39], [117, 40], [116, 40], [116, 39]],
// 内环(孔洞)
[[116.2, 39.2], [116.8, 39.2], [116.8, 39.8], [116.2, 39.8], [116.2, 39.2]]
]);
// MultiPolygon - 多面
const multiPolygon = new MultiPolygon([
[[[116, 39], [117, 39], [117, 40], [116, 40], [116, 39]]],
[[[118, 38], [119, 38], [119, 39], [118, 39], [118, 38]]]
]);
// Circle - 圆(仅用于编辑,不能序列化)
const circle = new Circle([116.4074, 39.9042], 1000); // 半径1000
// GeometryCollection - 几何集合
const collection = new GeometryCollection([point, line, polygon]);
8.2.2 几何操作
// 获取类型
const type = geometry.getType(); // 'Point', 'LineString', 'Polygon', etc.
// 获取坐标
const coords = point.getCoordinates(); // [x, y]
const lineCoords = line.getCoordinates(); // [[x1, y1], [x2, y2], ...]
const polygonCoords = polygon.getCoordinates(); // [[[...]], [[...]]]
// 设置坐标
point.setCoordinates([121.4737, 31.2304]);
line.setCoordinates([[116, 39], [117, 40], [118, 41]]);
// 获取范围
const extent = geometry.getExtent(); // [minX, minY, maxX, maxY]
// 获取长度/面积
import { getLength, getArea } from 'ol/sphere';
const length = getLength(line, { projection: 'EPSG:3857' }); // 米
const area = getArea(polygon, { projection: 'EPSG:3857' }); // 平方米
// 简化几何
const simplified = geometry.simplify(tolerance);
// 变换几何
geometry.transform('EPSG:4326', 'EPSG:3857');
// 克隆几何
const cloned = geometry.clone();
// 相交测试
const isIntersecting = geometry.intersectsCoordinate(coordinate);
const isInExtent = geometry.intersectsExtent(extent);
// 获取最近点
const closestPoint = geometry.getClosestPoint(coordinate);
// 平移几何
geometry.translate(deltaX, deltaY);
// 缩放几何
geometry.scale(sx, sy, anchor);
// 旋转几何
geometry.rotate(angle, anchor);
8.2.3 几何工具函数
import { buffer, union, intersection, difference } from 'ol/geom/flat/';
import { circular } from 'ol/geom/Polygon';
import { getCenter, getWidth, getHeight, boundingExtent } from 'ol/extent';
// 创建圆形多边形
const circularPolygon = circular(
[116.4074, 39.9042], // 中心点(经纬度)
1000, // 半径(米)
64 // 边数
);
// 计算几何中心
const center = getCenter(geometry.getExtent());
// 计算边界框
const bbox = boundingExtent([
[116, 39],
[117, 40],
[118, 39]
]);
// 几何验证
function isValidGeometry(geometry) {
const type = geometry.getType();
switch (type) {
case 'Polygon':
case 'MultiPolygon':
return geometry.getArea() > 0;
case 'LineString':
case 'MultiLineString':
return geometry.getLength() > 0;
case 'Point':
case 'MultiPoint':
return true;
default:
return true;
}
}
8.3 Style 样式系统
8.3.1 样式组成
import { Style, Fill, Stroke, Circle, Icon, Text, RegularShape } from 'ol/style';
// 完整样式示例
const fullStyle = new Style({
// 填充样式(用于面)
fill: new Fill({
color: 'rgba(66, 133, 244, 0.3)'
}),
// 描边样式(用于线和面的边界)
stroke: new Stroke({
color: '#4285F4',
width: 2,
lineDash: [4, 4], // 虚线
lineDashOffset: 0,
lineCap: 'round', // 线端样式: butt, round, square
lineJoin: 'round', // 连接样式: bevel, round, miter
miterLimit: 10
}),
// 点样式 - 圆形
image: new Circle({
radius: 8,
fill: new Fill({ color: '#4285F4' }),
stroke: new Stroke({ color: '#fff', width: 2 }),
displacement: [0, 0],
scale: 1,
rotation: 0
}),
// 文本样式
text: new Text({
text: '标签文本',
font: 'bold 14px sans-serif',
fill: new Fill({ color: '#333' }),
stroke: new Stroke({ color: '#fff', width: 3 }),
offsetX: 0,
offsetY: -20,
textAlign: 'center', // left, center, right
textBaseline: 'middle', // top, middle, bottom
rotation: 0,
scale: 1,
padding: [2, 4, 2, 4],
backgroundFill: new Fill({ color: 'rgba(255, 255, 255, 0.8)' }),
backgroundStroke: new Stroke({ color: '#ccc', width: 1 })
}),
// 几何函数(可选,修改渲染的几何)
geometry: function(feature) {
return feature.getGeometry();
},
// 渲染时机
zIndex: 0
});
8.3.2 点样式
// 圆形点
const circleStyle = new Style({
image: new Circle({
radius: 10,
fill: new Fill({ color: 'red' }),
stroke: new Stroke({ color: 'white', width: 2 })
})
});
// 图标点
const iconStyle = new Style({
image: new Icon({
src: '/images/marker.png',
anchor: [0.5, 1], // 锚点 [0-1, 0-1]
anchorXUnits: 'fraction', // 锚点单位: fraction, pixels
anchorYUnits: 'fraction',
scale: 1,
rotation: 0,
opacity: 1,
size: [32, 32], // 图标大小
offset: [0, 0], // 偏移
color: 'red' // 着色
})
});
// SVG 图标
const svgStyle = new Style({
image: new Icon({
src: 'data:image/svg+xml,' + encodeURIComponent(`
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10" fill="red"/>
</svg>
`),
scale: 1
})
});
// 规则形状
const shapeStyle = new Style({
image: new RegularShape({
points: 5, // 顶点数(5 = 五角星)
radius: 10, // 外半径
radius2: 5, // 内半径(用于星形)
angle: 0, // 旋转角度
fill: new Fill({ color: 'gold' }),
stroke: new Stroke({ color: 'orange', width: 2 }),
rotation: Math.PI // 旋转
})
});
// 三角形
const triangleStyle = new Style({
image: new RegularShape({
points: 3,
radius: 10,
fill: new Fill({ color: 'green' })
})
});
// 正方形
const squareStyle = new Style({
image: new RegularShape({
points: 4,
radius: 10,
angle: Math.PI / 4,
fill: new Fill({ color: 'blue' })
})
});
8.3.3 线样式
// 实线
const solidLine = new Style({
stroke: new Stroke({
color: '#4285F4',
width: 3
})
});
// 虚线
const dashedLine = new Style({
stroke: new Stroke({
color: '#FF5722',
width: 2,
lineDash: [10, 5] // [实线长度, 空白长度]
})
});
// 点划线
const dotDashLine = new Style({
stroke: new Stroke({
color: '#9C27B0',
width: 2,
lineDash: [1, 5, 10, 5]
})
});
// 渐变线(使用多个样式)
function createGradientLineStyle(feature) {
const geometry = feature.getGeometry();
const styles = [];
// 底层宽线
styles.push(new Style({
stroke: new Stroke({
color: 'rgba(0, 0, 0, 0.3)',
width: 6
})
}));
// 顶层细线
styles.push(new Style({
stroke: new Stroke({
color: '#4285F4',
width: 3
})
}));
return styles;
}
// 带箭头的线
function createArrowLineStyle(feature) {
const geometry = feature.getGeometry();
const coords = geometry.getCoordinates();
const styles = [];
// 线样式
styles.push(new Style({
stroke: new Stroke({
color: '#4285F4',
width: 2
})
}));
// 计算线段方向并添加箭头
for (let i = 0; i < coords.length - 1; i++) {
const start = coords[i];
const end = coords[i + 1];
const dx = end[0] - start[0];
const dy = end[1] - start[1];
const rotation = Math.atan2(dy, dx);
// 在中点添加箭头
const mid = [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2];
styles.push(new Style({
geometry: new Point(mid),
image: new RegularShape({
points: 3,
radius: 8,
rotation: -rotation + Math.PI / 2,
fill: new Fill({ color: '#4285F4' })
})
}));
}
return styles;
}
8.3.4 面样式
// 纯色填充
const solidFill = new Style({
fill: new Fill({
color: 'rgba(66, 133, 244, 0.5)'
}),
stroke: new Stroke({
color: '#4285F4',
width: 2
})
});
// 图案填充
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = 10;
canvas.height = 10;
// 创建斜线图案
context.strokeStyle = '#4285F4';
context.lineWidth = 1;
context.beginPath();
context.moveTo(0, 10);
context.lineTo(10, 0);
context.stroke();
const patternFill = new Style({
fill: new Fill({
color: context.createPattern(canvas, 'repeat')
}),
stroke: new Stroke({
color: '#4285F4',
width: 2
})
});
// 带标签的面
const labeledPolygon = new Style({
fill: new Fill({
color: 'rgba(66, 133, 244, 0.3)'
}),
stroke: new Stroke({
color: '#4285F4',
width: 2
}),
text: new Text({
text: '区域名称',
font: 'bold 14px sans-serif',
fill: new Fill({ color: '#333' }),
overflow: true
})
});
8.4 动态样式
8.4.1 样式函数
// 基于属性的样式
function attributeBasedStyle(feature, resolution) {
const type = feature.get('type');
const styleMap = {
school: new Style({
image: new Circle({
radius: 8,
fill: new Fill({ color: '#FF5722' })
})
}),
hospital: new Style({
image: new Circle({
radius: 8,
fill: new Fill({ color: '#E91E63' })
})
}),
park: new Style({
image: new Circle({
radius: 8,
fill: new Fill({ color: '#4CAF50' })
})
})
};
return styleMap[type] || new Style({
image: new Circle({
radius: 6,
fill: new Fill({ color: '#9E9E9E' })
})
});
}
// 基于分辨率的样式
function resolutionBasedStyle(feature, resolution) {
const zoom = Math.log2(156543.03392804097 / resolution);
// 高缩放级别显示详细样式
if (zoom >= 15) {
return new Style({
image: new Circle({
radius: 12,
fill: new Fill({ color: '#4285F4' }),
stroke: new Stroke({ color: '#fff', width: 2 })
}),
text: new Text({
text: feature.get('name'),
font: '12px sans-serif',
offsetY: -20
})
});
}
// 低缩放级别显示简单样式
return new Style({
image: new Circle({
radius: 6,
fill: new Fill({ color: '#4285F4' })
})
});
}
// 基于状态的样式
function stateBasedStyle(feature, resolution) {
const selected = feature.get('selected');
const hovered = feature.get('hovered');
if (selected) {
return new Style({
image: new Circle({
radius: 12,
fill: new Fill({ color: '#F44336' }),
stroke: new Stroke({ color: '#fff', width: 3 })
})
});
}
if (hovered) {
return new Style({
image: new Circle({
radius: 10,
fill: new Fill({ color: '#FF9800' }),
stroke: new Stroke({ color: '#fff', width: 2 })
})
});
}
return new Style({
image: new Circle({
radius: 8,
fill: new Fill({ color: '#4285F4' }),
stroke: new Stroke({ color: '#fff', width: 2 })
})
});
}
8.4.2 样式缓存
// 样式缓存管理器
class StyleCache {
constructor() {
this.cache = new Map();
}
getKey(type, color, size) {
return `${type}-${color}-${size}`;
}
getStyle(type, color, size) {
const key = this.getKey(type, color, size);
if (!this.cache.has(key)) {
this.cache.set(key, this.createStyle(type, color, size));
}
return this.cache.get(key);
}
createStyle(type, color, size) {
return new Style({
image: new Circle({
radius: size,
fill: new Fill({ color: color })
})
});
}
clear() {
this.cache.clear();
}
}
const styleCache = new StyleCache();
// 使用缓存的样式函数
function cachedStyleFunction(feature, resolution) {
const type = feature.get('type');
const color = typeColorMap[type] || '#999';
const size = Math.max(4, 10 - resolution / 100);
return styleCache.getStyle(type, color, Math.round(size));
}
8.4.3 动画样式
// 闪烁效果
function createBlinkingStyle(feature, resolution) {
const time = Date.now();
const blink = Math.sin(time / 200) > 0;
return new Style({
image: new Circle({
radius: blink ? 10 : 6,
fill: new Fill({ color: blink ? '#FF0000' : '#FF6666' })
})
});
}
// 需要持续渲染
map.on('postrender', () => {
map.render();
});
// 脉冲效果
function createPulseStyle(feature, resolution) {
const startTime = feature.get('pulseStart') || Date.now();
const elapsed = Date.now() - startTime;
const duration = 1000;
const progress = (elapsed % duration) / duration;
const radius = 5 + progress * 15;
const opacity = 1 - progress;
return [
// 脉冲圈
new Style({
image: new Circle({
radius: radius,
stroke: new Stroke({
color: `rgba(255, 0, 0, ${opacity})`,
width: 2
})
})
}),
// 中心点
new Style({
image: new Circle({
radius: 5,
fill: new Fill({ color: 'red' })
})
})
];
}
// 轨迹动画样式
class TrackAnimator {
constructor(layer, duration = 2000) {
this.layer = layer;
this.duration = duration;
this.startTime = null;
this.animating = false;
}
start() {
this.startTime = Date.now();
this.animating = true;
this.animate();
}
stop() {
this.animating = false;
}
animate() {
if (!this.animating) return;
const elapsed = Date.now() - this.startTime;
const progress = (elapsed % this.duration) / this.duration;
this.layer.setStyle((feature) => {
const geometry = feature.getGeometry();
if (geometry.getType() === 'LineString') {
return this.createTrackStyle(geometry, progress);
}
return null;
});
requestAnimationFrame(() => this.animate());
}
createTrackStyle(geometry, progress) {
const coords = geometry.getCoordinates();
const totalLength = coords.length - 1;
const currentIndex = Math.floor(progress * totalLength);
// 已走过的路径
const passedCoords = coords.slice(0, currentIndex + 1);
return [
// 完整路径(浅色)
new Style({
stroke: new Stroke({
color: 'rgba(66, 133, 244, 0.3)',
width: 4
})
}),
// 已走过路径(深色)
new Style({
geometry: new LineString(passedCoords),
stroke: new Stroke({
color: '#4285F4',
width: 4
})
}),
// 当前位置点
new Style({
geometry: new Point(coords[currentIndex]),
image: new Circle({
radius: 8,
fill: new Fill({ color: '#4285F4' }),
stroke: new Stroke({ color: '#fff', width: 2 })
})
})
];
}
}
8.5 标注与文本
8.5.1 文本样式详解
import { Text, Fill, Stroke, Style } from 'ol/style';
// 完整文本样式
const textStyle = new Text({
// 文本内容
text: '标签文本',
// 字体
font: 'bold 14px "Microsoft YaHei", sans-serif',
// 填充颜色
fill: new Fill({
color: '#333333'
}),
// 描边(轮廓)
stroke: new Stroke({
color: '#ffffff',
width: 3
}),
// 偏移
offsetX: 0,
offsetY: -20,
// 对齐
textAlign: 'center', // 'left', 'center', 'right', 'start', 'end'
textBaseline: 'middle', // 'top', 'middle', 'bottom', 'alphabetic', 'hanging'
// 旋转
rotation: 0,
// 缩放
scale: 1,
// 内边距
padding: [2, 4, 2, 4], // [top, right, bottom, left]
// 背景
backgroundFill: new Fill({
color: 'rgba(255, 255, 255, 0.8)'
}),
backgroundStroke: new Stroke({
color: '#cccccc',
width: 1
}),
// 溢出处理
overflow: false, // true 允许文本溢出
// 最大角度(用于沿线标注)
maxAngle: Math.PI / 4,
// 放置策略
placement: 'point' // 'point' 或 'line'
});
8.5.2 沿线标注
// 沿线标注样式
function lineLabel(feature) {
return new Style({
stroke: new Stroke({
color: '#4285F4',
width: 3
}),
text: new Text({
text: feature.get('name'),
font: '12px sans-serif',
placement: 'line',
fill: new Fill({ color: '#333' }),
stroke: new Stroke({ color: '#fff', width: 3 }),
maxAngle: Math.PI / 6,
overflow: true
})
});
}
// 多行文本
function multiLineText(feature) {
const name = feature.get('name');
const type = feature.get('type');
const text = `${name}\n(${type})`;
return new Style({
image: new Circle({
radius: 8,
fill: new Fill({ color: '#4285F4' })
}),
text: new Text({
text: text,
font: '12px sans-serif',
fill: new Fill({ color: '#333' }),
stroke: new Stroke({ color: '#fff', width: 2 }),
offsetY: -25,
textAlign: 'center'
})
});
}
8.5.3 标注避让
import VectorLayer from 'ol/layer/Vector';
// 启用标注避让
const labelLayer = new VectorLayer({
source: vectorSource,
declutter: true, // 启用避让
style: function(feature) {
return new Style({
image: new Circle({
radius: 6,
fill: new Fill({ color: '#4285F4' })
}),
text: new Text({
text: feature.get('name'),
font: '12px sans-serif',
offsetY: -15,
fill: new Fill({ color: '#333' }),
stroke: new Stroke({ color: '#fff', width: 2 })
})
});
}
});
// 自定义优先级
function prioritizedLabelStyle(feature) {
const priority = feature.get('priority') || 0;
return new Style({
image: new Circle({
radius: 6,
fill: new Fill({ color: '#4285F4' })
}),
text: new Text({
text: feature.get('name'),
font: '12px sans-serif',
offsetY: -15,
fill: new Fill({ color: '#333' }),
stroke: new Stroke({ color: '#fff', width: 2 })
}),
zIndex: priority // 优先级高的先渲染
});
}
8.6 实战示例
8.6.1 专题地图样式
// 分级设色(等级符号)
function choroplethStyle(feature) {
const value = feature.get('population');
let color;
if (value > 20000000) {
color = '#800026';
} else if (value > 10000000) {
color = '#BD0026';
} else if (value > 5000000) {
color = '#E31A1C';
} else if (value > 1000000) {
color = '#FC4E2A';
} else if (value > 500000) {
color = '#FD8D3C';
} else {
color = '#FFEDA0';
}
return new Style({
fill: new Fill({ color: color }),
stroke: new Stroke({ color: '#fff', width: 1 }),
text: new Text({
text: feature.get('name'),
font: '12px sans-serif',
fill: new Fill({ color: '#333' })
})
});
}
// 比例符号
function proportionalSymbolStyle(feature) {
const value = feature.get('value');
const maxValue = 100;
const minRadius = 5;
const maxRadius = 30;
const radius = minRadius + (value / maxValue) * (maxRadius - minRadius);
return new Style({
image: new Circle({
radius: radius,
fill: new Fill({ color: 'rgba(66, 133, 244, 0.6)' }),
stroke: new Stroke({ color: '#4285F4', width: 2 })
}),
text: new Text({
text: value.toString(),
font: 'bold 12px sans-serif',
fill: new Fill({ color: '#fff' })
})
});
}
// 点密度图
function dotDensityStyle(feature) {
const value = feature.get('population');
const dotsPerUnit = 10000; // 每个点代表10000人
const dotCount = Math.floor(value / dotsPerUnit);
const geometry = feature.getGeometry();
const extent = geometry.getExtent();
const styles = [];
// 底色
styles.push(new Style({
fill: new Fill({ color: 'rgba(255, 255, 255, 0.8)' }),
stroke: new Stroke({ color: '#ccc', width: 1 })
}));
// 生成随机点
for (let i = 0; i < dotCount; i++) {
const x = extent[0] + Math.random() * (extent[2] - extent[0]);
const y = extent[1] + Math.random() * (extent[3] - extent[1]);
if (geometry.intersectsCoordinate([x, y])) {
styles.push(new Style({
geometry: new Point([x, y]),
image: new Circle({
radius: 2,
fill: new Fill({ color: '#333' })
})
}));
}
}
return styles;
}
8.6.2 样式管理器
class StyleManager {
constructor() {
this.styles = new Map();
this.activeStyle = 'default';
}
register(name, styleFunction) {
this.styles.set(name, styleFunction);
}
get(name) {
return this.styles.get(name);
}
setActive(name) {
if (this.styles.has(name)) {
this.activeStyle = name;
}
}
getActiveStyle() {
return this.styles.get(this.activeStyle);
}
apply(layer) {
layer.setStyle(this.getActiveStyle());
}
}
// 使用示例
const styleManager = new StyleManager();
styleManager.register('default', defaultStyle);
styleManager.register('highlight', highlightStyle);
styleManager.register('choropleth', choroplethStyle);
// 切换样式
styleManager.setActive('choropleth');
styleManager.apply(vectorLayer);
8.7 本章小结
本章详细介绍了矢量数据与样式系统:
- Feature 要素:创建、操作、事件
- Geometry 几何:类型、操作、工具函数
- Style 样式:填充、描边、点样式、文本
- 动态样式:样式函数、缓存、动画
- 标注文本:文本样式、沿线标注、避让
- 实战示例:专题地图、样式管理
关键要点
- 理解 Feature、Geometry、Style 的关系
- 掌握各种几何类型的创建和操作
- 熟练使用样式函数实现动态效果
- 合理使用样式缓存优化性能
下一步
在下一章中,我们将详细学习栅格数据与瓦片服务,包括:
- 瓦片原理
- 自定义瓦片网格
- 瓦片缓存
- 瓦片预加载

浙公网安备 33010602011771号