第07章-样式与主题渲染
第07章:样式与主题渲染
7.1 样式系统概述
7.1.1 样式类层次结构
Style (抽象基类)
│
├── VectorStyle 矢量样式(点、线、面)
│
└── LabelStyle 标注样式
7.1.2 样式基类
namespace SharpMap.Styles
{
public abstract class Style : IStyle
{
// 启用/禁用
public bool Enabled { get; set; }
// 最小可见比例尺
public double MinVisible { get; set; }
// 最大可见比例尺
public double MaxVisible { get; set; }
}
}
7.2 VectorStyle 矢量样式
7.2.1 基本属性
using SharpMap.Styles;
using System.Drawing;
using System.Drawing.Drawing2D;
var style = new VectorStyle();
// 填充设置(多边形内部)
style.Fill = new SolidBrush(Color.LightGreen);
// 边框设置(多边形边界)
style.Outline = new Pen(Color.DarkGreen, 2);
style.EnableOutline = true;
// 线设置(线要素)
style.Line = new Pen(Color.Blue, 3);
// 点设置
style.PointColor = Brushes.Red;
style.PointSize = 10;
// 符号设置
style.Symbol = null; // 使用点符号图片
style.SymbolOffset = new PointF(0, 0);
style.SymbolRotation = 0;
style.SymbolScale = 1.0f;
7.2.2 多边形样式
// 纯色填充
var solidStyle = new VectorStyle
{
Fill = new SolidBrush(Color.FromArgb(150, 100, 200, 100)),
Outline = new Pen(Color.DarkGreen, 2),
EnableOutline = true
};
// 渐变填充
var gradientStyle = new VectorStyle
{
Fill = new LinearGradientBrush(
new Point(0, 0),
new Point(100, 100),
Color.LightBlue,
Color.DarkBlue),
EnableOutline = true,
Outline = new Pen(Color.Navy, 1)
};
// 图案填充
var hatchStyle = new VectorStyle
{
Fill = new HatchBrush(HatchStyle.DiagonalCross, Color.Black, Color.White),
EnableOutline = true,
Outline = new Pen(Color.Black, 1)
};
// 透明填充(仅边框)
var outlineOnlyStyle = new VectorStyle
{
Fill = null,
EnableOutline = true,
Outline = new Pen(Color.Red, 2)
};
7.2.3 线样式
// 实线
var solidLineStyle = new VectorStyle
{
Line = new Pen(Color.Blue, 3)
{
LineJoin = LineJoin.Round,
StartCap = LineCap.Round,
EndCap = LineCap.Round
}
};
// 虚线
var dashedLineStyle = new VectorStyle
{
Line = new Pen(Color.Red, 2)
{
DashStyle = DashStyle.Dash
}
};
// 点线
var dottedLineStyle = new VectorStyle
{
Line = new Pen(Color.Green, 2)
{
DashStyle = DashStyle.Dot
}
};
// 自定义虚线模式
var customDashStyle = new VectorStyle
{
Line = new Pen(Color.Orange, 2)
{
DashStyle = DashStyle.Custom,
DashPattern = new float[] { 5, 2, 1, 2 } // 长线-短空-短线-短空
}
};
// 带箭头的线
var arrowLineStyle = new VectorStyle
{
Line = new Pen(Color.Blue, 2)
{
EndCap = LineCap.ArrowAnchor
}
};
// 双线(道路效果)
public class DoubleLineLayer : VectorLayer
{
public override void Render(Graphics g, Map map)
{
// 先渲染粗线(背景)
var backgroundStyle = new VectorStyle
{
Line = new Pen(Color.Black, 6)
};
Style = backgroundStyle;
base.Render(g, map);
// 再渲染细线(前景)
var foregroundStyle = new VectorStyle
{
Line = new Pen(Color.Yellow, 4)
};
Style = foregroundStyle;
base.Render(g, map);
}
}
7.2.4 点样式
// 简单圆点
var circleStyle = new VectorStyle
{
PointColor = Brushes.Red,
PointSize = 10
};
// 使用图片符号
var imageStyle = new VectorStyle
{
Symbol = Image.FromFile("marker.png"),
SymbolScale = 1.0f,
SymbolOffset = new PointF(0, -16) // 图标底部对齐点位置
};
// 自定义符号渲染
public class CustomSymbolRenderer
{
public static Bitmap CreateStarSymbol(int size, Color fillColor, Color outlineColor)
{
var bitmap = new Bitmap(size, size);
using (var g = Graphics.FromImage(bitmap))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
// 计算五角星顶点
var points = new PointF[10];
float outerRadius = size / 2f - 2;
float innerRadius = outerRadius * 0.4f;
float centerX = size / 2f;
float centerY = size / 2f;
for (int i = 0; i < 10; i++)
{
float radius = i % 2 == 0 ? outerRadius : innerRadius;
float angle = (float)(i * Math.PI / 5 - Math.PI / 2);
points[i] = new PointF(
centerX + radius * (float)Math.Cos(angle),
centerY + radius * (float)Math.Sin(angle)
);
}
using (var brush = new SolidBrush(fillColor))
using (var pen = new Pen(outlineColor, 1))
{
g.FillPolygon(brush, points);
g.DrawPolygon(pen, points);
}
}
return bitmap;
}
}
// 使用自定义符号
var starSymbol = CustomSymbolRenderer.CreateStarSymbol(24, Color.Gold, Color.DarkOrange);
var starStyle = new VectorStyle
{
Symbol = starSymbol,
SymbolOffset = new PointF(0, 0)
};
7.3 LabelStyle 标注样式
7.3.1 基本属性
using SharpMap.Styles;
var labelStyle = new LabelStyle();
// 字体
labelStyle.Font = new Font("Microsoft YaHei", 12, FontStyle.Bold);
// 颜色
labelStyle.ForeColor = Color.Black;
labelStyle.BackColor = new SolidBrush(Color.FromArgb(200, 255, 255, 200));
// 光晕
labelStyle.Halo = new Pen(Color.White, 3);
// 对齐
labelStyle.HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Center;
labelStyle.VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Middle;
// 偏移
labelStyle.Offset = new PointF(0, -15);
// 旋转
labelStyle.Rotation = 0;
// 碰撞检测
labelStyle.CollisionDetection = true;
labelStyle.CollisionBuffer = new SizeF(10, 10);
7.3.2 高级标注样式
// 带背景框的标注
var boxLabelStyle = new LabelStyle
{
Font = new Font("Arial", 10, FontStyle.Bold),
ForeColor = Color.White,
BackColor = new SolidBrush(Color.FromArgb(200, 0, 100, 200)),
HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Center,
VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Middle
};
// 带光晕效果的标注
var haloLabelStyle = new LabelStyle
{
Font = new Font("Arial", 12),
ForeColor = Color.Black,
BackColor = null,
Halo = new Pen(Color.White, 3),
HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Center,
VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Bottom,
Offset = new PointF(0, -5)
};
// 道路标注(沿线显示)
var roadLabelStyle = new LabelStyle
{
Font = new Font("Arial", 9),
ForeColor = Color.FromArgb(100, 100, 100),
BackColor = null,
Halo = new Pen(Color.FromArgb(200, 255, 255, 255), 2),
HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Center,
VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Middle,
IgnoreLength = false, // 线太短时不显示标注
CollisionDetection = true
};
7.4 主题渲染
7.4.1 ITheme 接口
namespace SharpMap.Rendering.Thematics
{
public interface ITheme
{
IStyle GetStyle(FeatureDataRow row);
}
}
7.4.2 唯一值主题
using SharpMap.Rendering.Thematics;
// 创建唯一值主题
var uniqueTheme = new UniqueValuesTheme<string>("LAND_TYPE");
// 添加各值对应的样式
uniqueTheme.AddStyle("Forest", new VectorStyle
{
Fill = new SolidBrush(Color.DarkGreen),
Outline = new Pen(Color.Black, 1),
EnableOutline = true
});
uniqueTheme.AddStyle("Water", new VectorStyle
{
Fill = new SolidBrush(Color.Blue),
Outline = new Pen(Color.DarkBlue, 1),
EnableOutline = true
});
uniqueTheme.AddStyle("Urban", new VectorStyle
{
Fill = new SolidBrush(Color.Gray),
Outline = new Pen(Color.Black, 1),
EnableOutline = true
});
// 设置默认样式(其他值使用)
uniqueTheme.DefaultStyle = new VectorStyle
{
Fill = new SolidBrush(Color.LightGray),
Outline = new Pen(Color.Gray, 1),
EnableOutline = true
};
// 应用到图层
vectorLayer.Theme = uniqueTheme;
7.4.3 分级主题
// 创建分级主题
var gradientTheme = new GradientTheme("POPULATION", 0, 1000000,
new VectorStyle
{
Fill = new SolidBrush(Color.FromArgb(255, 255, 200)),
Outline = new Pen(Color.Black, 1),
EnableOutline = true
},
new VectorStyle
{
Fill = new SolidBrush(Color.FromArgb(255, 0, 0)),
Outline = new Pen(Color.Black, 1),
EnableOutline = true
});
vectorLayer.Theme = gradientTheme;
7.4.4 自定义主题
public class CustomTheme : ITheme
{
private readonly string _attributeName;
private readonly Dictionary<string, VectorStyle> _styles;
private readonly VectorStyle _defaultStyle;
public CustomTheme(string attributeName)
{
_attributeName = attributeName;
_styles = new Dictionary<string, VectorStyle>();
_defaultStyle = new VectorStyle
{
Fill = new SolidBrush(Color.LightGray),
Outline = new Pen(Color.Gray, 1),
EnableOutline = true
};
}
public void AddStyle(string value, VectorStyle style)
{
_styles[value] = style;
}
public IStyle GetStyle(FeatureDataRow row)
{
var value = row[_attributeName]?.ToString();
if (!string.IsNullOrEmpty(value) && _styles.ContainsKey(value))
{
return _styles[value];
}
return _defaultStyle;
}
}
// 使用自定义主题
var customTheme = new CustomTheme("CATEGORY");
customTheme.AddStyle("A", new VectorStyle { Fill = new SolidBrush(Color.Red) });
customTheme.AddStyle("B", new VectorStyle { Fill = new SolidBrush(Color.Blue) });
customTheme.AddStyle("C", new VectorStyle { Fill = new SolidBrush(Color.Green) });
vectorLayer.Theme = customTheme;
7.4.5 数值分级主题
public class ClassBreaksTheme : ITheme
{
private readonly string _attributeName;
private readonly List<(double minValue, double maxValue, VectorStyle style)> _breaks;
private readonly VectorStyle _defaultStyle;
public ClassBreaksTheme(string attributeName)
{
_attributeName = attributeName;
_breaks = new List<(double, double, VectorStyle)>();
_defaultStyle = new VectorStyle
{
Fill = new SolidBrush(Color.White),
EnableOutline = true,
Outline = new Pen(Color.Gray, 1)
};
}
public void AddBreak(double minValue, double maxValue, VectorStyle style)
{
_breaks.Add((minValue, maxValue, style));
}
public IStyle GetStyle(FeatureDataRow row)
{
if (row[_attributeName] == DBNull.Value)
return _defaultStyle;
double value = Convert.ToDouble(row[_attributeName]);
foreach (var breakItem in _breaks)
{
if (value >= breakItem.minValue && value < breakItem.maxValue)
{
return breakItem.style;
}
}
return _defaultStyle;
}
}
// 使用数值分级主题
var populationTheme = new ClassBreaksTheme("POPULATION");
populationTheme.AddBreak(0, 100000, new VectorStyle
{
Fill = new SolidBrush(Color.FromArgb(255, 255, 178)),
Outline = new Pen(Color.Black, 1),
EnableOutline = true
});
populationTheme.AddBreak(100000, 500000, new VectorStyle
{
Fill = new SolidBrush(Color.FromArgb(254, 204, 92)),
Outline = new Pen(Color.Black, 1),
EnableOutline = true
});
populationTheme.AddBreak(500000, 1000000, new VectorStyle
{
Fill = new SolidBrush(Color.FromArgb(253, 141, 60)),
Outline = new Pen(Color.Black, 1),
EnableOutline = true
});
populationTheme.AddBreak(1000000, double.MaxValue, new VectorStyle
{
Fill = new SolidBrush(Color.FromArgb(227, 26, 28)),
Outline = new Pen(Color.Black, 1),
EnableOutline = true
});
vectorLayer.Theme = populationTheme;
7.4.6 条件主题
public class ConditionalTheme : ITheme
{
private readonly List<(Func<FeatureDataRow, bool> condition, VectorStyle style)> _conditions;
private readonly VectorStyle _defaultStyle;
public ConditionalTheme(VectorStyle defaultStyle = null)
{
_conditions = new List<(Func<FeatureDataRow, bool>, VectorStyle)>();
_defaultStyle = defaultStyle ?? new VectorStyle
{
Fill = new SolidBrush(Color.LightGray),
EnableOutline = true
};
}
public void AddCondition(Func<FeatureDataRow, bool> condition, VectorStyle style)
{
_conditions.Add((condition, style));
}
public IStyle GetStyle(FeatureDataRow row)
{
foreach (var item in _conditions)
{
if (item.condition(row))
{
return item.style;
}
}
return _defaultStyle;
}
}
// 使用条件主题
var conditionalTheme = new ConditionalTheme();
// 首都城市 - 红色五角星
conditionalTheme.AddCondition(
row => row["IS_CAPITAL"]?.ToString() == "Y",
new VectorStyle
{
Symbol = CreateStarSymbol(24, Color.Red),
PointSize = 24
});
// 大城市 - 大蓝点
conditionalTheme.AddCondition(
row => Convert.ToDouble(row["POPULATION"] ?? 0) > 1000000,
new VectorStyle
{
PointColor = Brushes.Blue,
PointSize = 12
});
// 普通城市 - 小黑点
conditionalTheme.AddCondition(
row => true, // 默认条件
new VectorStyle
{
PointColor = Brushes.Black,
PointSize = 6
});
citiesLayer.Theme = conditionalTheme;
7.5 动态样式
7.5.1 基于比例尺的样式
public class ScaleBasedTheme : ITheme
{
private readonly Map _map;
private readonly Dictionary<double, VectorStyle> _scaleStyles;
public ScaleBasedTheme(Map map)
{
_map = map;
_scaleStyles = new Dictionary<double, VectorStyle>();
}
public void AddScaleStyle(double minScale, VectorStyle style)
{
_scaleStyles[minScale] = style;
}
public IStyle GetStyle(FeatureDataRow row)
{
double currentScale = _map.MapScale;
VectorStyle selectedStyle = null;
double selectedScale = 0;
foreach (var kvp in _scaleStyles)
{
if (currentScale >= kvp.Key && kvp.Key >= selectedScale)
{
selectedScale = kvp.Key;
selectedStyle = kvp.Value;
}
}
return selectedStyle ?? new VectorStyle();
}
}
// 使用
var scaleTheme = new ScaleBasedTheme(map);
// 大比例尺(详细)
scaleTheme.AddScaleStyle(0, new VectorStyle
{
Fill = new SolidBrush(Color.LightGreen),
Outline = new Pen(Color.DarkGreen, 2),
EnableOutline = true
});
// 中等比例尺
scaleTheme.AddScaleStyle(50000, new VectorStyle
{
Fill = new SolidBrush(Color.Green),
Outline = new Pen(Color.DarkGreen, 1),
EnableOutline = true
});
// 小比例尺(概览)
scaleTheme.AddScaleStyle(500000, new VectorStyle
{
Fill = new SolidBrush(Color.DarkGreen),
EnableOutline = false
});
7.5.2 高亮样式
public class HighlightManager
{
private readonly VectorLayer _layer;
private readonly VectorStyle _normalStyle;
private readonly VectorStyle _highlightStyle;
private HashSet<uint> _highlightedIds;
public HighlightManager(VectorLayer layer, VectorStyle normalStyle, VectorStyle highlightStyle)
{
_layer = layer;
_normalStyle = normalStyle;
_highlightStyle = highlightStyle;
_highlightedIds = new HashSet<uint>();
// 设置主题
_layer.Theme = new HighlightTheme(this, normalStyle, highlightStyle);
}
public void Highlight(uint id)
{
_highlightedIds.Add(id);
}
public void ClearHighlight()
{
_highlightedIds.Clear();
}
public bool IsHighlighted(uint id) => _highlightedIds.Contains(id);
private class HighlightTheme : ITheme
{
private readonly HighlightManager _manager;
private readonly VectorStyle _normalStyle;
private readonly VectorStyle _highlightStyle;
public HighlightTheme(HighlightManager manager, VectorStyle normalStyle, VectorStyle highlightStyle)
{
_manager = manager;
_normalStyle = normalStyle;
_highlightStyle = highlightStyle;
}
public IStyle GetStyle(FeatureDataRow row)
{
if (row["OID"] != DBNull.Value)
{
uint id = Convert.ToUInt32(row["OID"]);
if (_manager.IsHighlighted(id))
{
return _highlightStyle;
}
}
return _normalStyle;
}
}
}
7.6 标注主题
7.6.1 动态标注样式
public class LabelTheme : ITheme
{
private readonly string _sizeColumn;
private readonly Font _baseFont;
public LabelTheme(string sizeColumn, Font baseFont)
{
_sizeColumn = sizeColumn;
_baseFont = baseFont;
}
public IStyle GetStyle(FeatureDataRow row)
{
double size = Convert.ToDouble(row[_sizeColumn] ?? 10);
// 根据数值调整字体大小
float fontSize = Math.Max(8, Math.Min(24, (float)(size / 100000)));
return new LabelStyle
{
Font = new Font(_baseFont.FontFamily, fontSize, _baseFont.Style),
ForeColor = Color.Black,
Halo = new Pen(Color.White, 2),
HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Center,
VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Middle,
CollisionDetection = true
};
}
}
// 使用
labelLayer.Theme = new LabelTheme("POPULATION", new Font("Arial", 10, FontStyle.Bold));
7.7 本章小结
本章详细介绍了 SharpMap 的样式系统和主题渲染:
- VectorStyle:掌握了多边形、线、点的样式设置
- LabelStyle:学习了标注样式的各种配置
- 唯一值主题:了解了基于属性值的分类渲染
- 分级主题:掌握了数值分级渲染方法
- 自定义主题:学习了实现自定义主题的方法
- 动态样式:了解了基于比例尺和高亮的动态样式
7.8 参考资源
下一章预告:第08章将详细介绍标注与标签图层的高级配置,包括碰撞检测、沿线标注等功能。

浙公网安备 33010602011771号