第07章 - 样式系统详解

第07章:样式系统详解

7.1 样式系统概述

7.1.1 样式类型体系

Mapsui 提供了丰富的样式类型来定义要素的视觉外观:

                        IStyle (接口)
                           │
                      BaseStyle (基类)
                           │
       ┌───────────────────┼───────────────────┐
       │                   │                   │
  VectorStyle         SymbolStyle          LabelStyle
       │                   │
       │            ┌──────┼──────┐
       │            │      │      │
       │       ImageStyle  │   CalloutStyle
       │                   │
       └──────────────RasterStyle

7.1.2 IStyle 接口

public interface IStyle
{
    /// <summary>
    /// 最小可见分辨率
    /// </summary>
    double MinVisible { get; set; }
    
    /// <summary>
    /// 最大可见分辨率
    /// </summary>
    double MaxVisible { get; set; }
    
    /// <summary>
    /// 是否启用
    /// </summary>
    bool Enabled { get; set; }
    
    /// <summary>
    /// 不透明度 (0-1)
    /// </summary>
    double Opacity { get; set; }
}

7.2 VectorStyle - 矢量样式

7.2.1 基本属性

VectorStyle 用于线和面要素的样式定义:

var vectorStyle = new VectorStyle
{
    // 填充样式
    Fill = new Brush(new Color(255, 0, 0, 128)),  // 半透明红色
    
    // 边框/轮廓样式
    Outline = new Pen(Color.Black, 2),
    
    // 线样式(用于线要素)
    Line = new Pen(Color.Blue, 3)
    {
        PenStyle = PenStyle.Dash,
        StrokeCap = PenStrokeCap.Round,
        StrokeJoin = StrokeJoin.Round
    }
};

7.2.2 Brush - 画刷

// 纯色画刷
var solidBrush = new Brush(Color.Red);

// 带透明度的画刷
var transparentBrush = new Brush(new Color(255, 0, 0, 128));

// 从十六进制颜色创建
var hexBrush = new Brush(Color.FromString("#FF5722"));

// 使用图片填充
var imageBrush = new Brush
{
    FillStyle = FillStyle.Bitmap,
    // BitmapId = ... // 设置图片 ID
};

7.2.3 Pen - 画笔

// 基本画笔
var basicPen = new Pen(Color.Blue, 2);

// 自定义画笔
var customPen = new Pen
{
    Color = Color.Green,
    Width = 3,
    PenStyle = PenStyle.Dash,           // 虚线
    StrokeCap = PenStrokeCap.Round,     // 圆形线帽
    StrokeJoin = StrokeJoin.Round,      // 圆形连接
    DashArray = new float[] { 5, 3 }    // 自定义虚线模式
};

// 画笔样式枚举
public enum PenStyle
{
    Solid,           // 实线
    Dash,            // 虚线
    Dot,             // 点线
    DashDot,         // 点划线
    DashDotDot,      // 双点划线
    UserDefined      // 自定义
}

7.2.4 多边形和线样式示例

// 多边形样式
public static VectorStyle CreatePolygonStyle()
{
    return new VectorStyle
    {
        Fill = new Brush(new Color(66, 133, 244, 100)),
        Outline = new Pen(new Color(66, 133, 244), 2)
        {
            StrokeJoin = StrokeJoin.Round
        }
    };
}

// 线样式
public static VectorStyle CreateLineStyle()
{
    return new VectorStyle
    {
        Line = new Pen(Color.Orange, 4)
        {
            StrokeCap = PenStrokeCap.Round,
            StrokeJoin = StrokeJoin.Round
        }
    };
}

// 道路样式(带边框效果)
public static IStyle[] CreateRoadStyle()
{
    return new IStyle[]
    {
        // 底层(边框)
        new VectorStyle
        {
            Line = new Pen(Color.Gray, 8)
            {
                StrokeCap = PenStrokeCap.Round
            }
        },
        // 顶层(填充)
        new VectorStyle
        {
            Line = new Pen(Color.White, 6)
            {
                StrokeCap = PenStrokeCap.Round
            }
        }
    };
}

7.3 SymbolStyle - 符号样式

7.3.1 基本属性

SymbolStyle 用于点要素的样式定义:

var symbolStyle = new SymbolStyle
{
    // 大小缩放
    SymbolScale = 1.0,
    
    // 填充
    Fill = new Brush(Color.Red),
    
    // 轮廓
    Outline = new Pen(Color.White, 2),
    
    // 偏移
    SymbolOffset = new Offset(0, 10),
    
    // 旋转角度(度)
    SymbolRotation = 45,
    
    // 是否随地图旋转
    RotateWithMap = false
};

7.3.2 符号类型

// 圆形符号(默认)
var circleSymbol = new SymbolStyle
{
    SymbolScale = 0.5,
    Fill = new Brush(Color.Blue),
    Outline = new Pen(Color.White, 1)
};

// 方形符号
var squareSymbol = new SymbolStyle
{
    SymbolScale = 0.5,
    SymbolType = SymbolType.Rectangle,
    Fill = new Brush(Color.Green)
};

// 三角形符号
var triangleSymbol = new SymbolStyle
{
    SymbolScale = 0.5,
    SymbolType = SymbolType.Triangle,
    Fill = new Brush(Color.Yellow)
};

7.3.3 Offset - 偏移

// 绝对偏移(像素)
var absoluteOffset = new Offset(0, -20);  // 向上偏移 20 像素

// 相对偏移
var relativeOffset = new RelativeOffset(0, -0.5);  // 相对于符号高度偏移

7.4 ImageStyle - 图像样式

7.4.1 使用图像作为符号

// 从嵌入资源加载图像
var imageStyle = new ImageStyle
{
    ImageSource = "embedded://MyApp.Resources.marker.png"
};

// 从 URL 加载图像
var urlImageStyle = new ImageStyle
{
    ImageSource = "https://example.com/marker.png"
};

// 从文件加载图像
var fileImageStyle = new ImageStyle
{
    ImageSource = "file://path/to/marker.png"
};

7.4.2 配置图像样式

var imageStyle = new ImageStyle
{
    ImageSource = "embedded://MyApp.Resources.marker.png",
    
    // 缩放
    SymbolScale = 0.5,
    
    // 偏移(使图像底部对准点位置)
    SymbolOffset = new Offset(0, -16),
    
    // 旋转
    SymbolRotation = 0,
    
    // 是否随地图旋转
    RotateWithMap = false
};

7.4.3 SVG 图像支持

// 使用 SVG 图像
var svgStyle = new ImageStyle
{
    ImageSource = "embedded://MyApp.Resources.icon.svg",
    SymbolScale = 1.0
};

7.5 LabelStyle - 标签样式

7.5.1 基本标签样式

var labelStyle = new LabelStyle
{
    // 文本内容
    Text = "北京",
    
    // 字体设置
    Font = new Font
    {
        FontFamily = "Microsoft YaHei",
        Size = 14,
        Bold = false,
        Italic = false
    },
    
    // 颜色
    ForeColor = Color.Black,
    BackColor = new Brush(Color.White),
    
    // 偏移
    Offset = new Offset(0, -25),
    
    // 对齐
    HorizontalAlignment = LabelStyle.HorizontalAlignmentEnum.Center,
    VerticalAlignment = LabelStyle.VerticalAlignmentEnum.Top,
    
    // 光晕效果
    Halo = new Pen(Color.White, 2)
};

7.5.2 动态标签文本

// 使用要素属性作为标签文本
var dynamicLabelStyle = new LabelStyle
{
    LabelColumn = "name",  // 使用 "name" 属性的值作为标签
    Font = new Font { Size = 12 },
    ForeColor = Color.Black
};

// 使用格式化委托
var formattedLabelStyle = new LabelStyle
{
    LabelMethod = feature =>
    {
        var name = feature["name"]?.ToString() ?? "";
        var pop = feature["population"];
        return $"{name}\n人口: {pop:N0}";
    },
    Font = new Font { Size = 10 }
};

7.5.3 标签优化

// 避免标签重叠
var optimizedLabelStyle = new LabelStyle
{
    Text = "Label",
    CollisionDetection = true,  // 启用碰撞检测
    
    // 优先级(数值越高越优先显示)
    Priority = 1
};

7.6 CalloutStyle - 气泡样式

7.6.1 基本气泡样式

var calloutStyle = new CalloutStyle
{
    // 标题和副标题
    Title = "北京",
    Subtitle = "中国首都",
    
    // 气泡外观
    BalloonDefinition = new CalloutBalloonDefinition
    {
        RectRadius = 10,
        ShadowOffset = new Offset(4, 4),
        Padding = 8
    },
    
    // 箭头位置
    ArrowAlignment = ArrowAlignment.Bottom,
    
    // 锚点偏移
    Offset = new Offset(0, -20),
    
    // 颜色
    TitleFontColor = Color.Black,
    SubtitleFontColor = Color.Gray,
    Color = Color.White,
    StrokeColor = Color.LightGray
};

7.6.2 自定义内容气泡

// 使用自定义内容
var customCallout = new CalloutStyle
{
    Type = CalloutType.Custom,
    Content = CreateCustomCalloutContent(),  // 返回 SKImage
    
    ArrowAlignment = ArrowAlignment.Bottom,
    Offset = new Offset(0, -10)
};

private SKImage CreateCustomCalloutContent()
{
    // 使用 SkiaSharp 创建自定义内容
    var info = new SKImageInfo(200, 100);
    using var surface = SKSurface.Create(info);
    var canvas = surface.Canvas;
    
    // 绘制背景
    canvas.Clear(SKColors.White);
    
    // 绘制文本
    using var paint = new SKPaint
    {
        Color = SKColors.Black,
        TextSize = 14,
        IsAntialias = true
    };
    canvas.DrawText("自定义气泡内容", 10, 50, paint);
    
    return surface.Snapshot();
}

7.7 样式集合与分层样式

7.7.1 StyleCollection - 样式集合

// 使用样式集合为要素应用多个样式
var styleCollection = new StyleCollection
{
    // 底层样式 - 阴影效果
    new SymbolStyle
    {
        SymbolScale = 0.6,
        Fill = new Brush(new Color(0, 0, 0, 100)),
        SymbolOffset = new Offset(3, -3)
    },
    // 主体样式
    new SymbolStyle
    {
        SymbolScale = 0.5,
        Fill = new Brush(Color.Red),
        Outline = new Pen(Color.White, 2)
    },
    // 标签样式
    new LabelStyle
    {
        LabelColumn = "name",
        Font = new Font { Size = 12 },
        ForeColor = Color.Black,
        Offset = new Offset(0, -20)
    }
};

7.7.2 要素级别样式

// 在要素上设置样式
var feature = new PointFeature(point);
feature.Styles = new List<IStyle>
{
    new SymbolStyle
    {
        SymbolScale = 0.5,
        Fill = new Brush(Color.Blue)
    },
    new LabelStyle
    {
        Text = "Feature Label",
        Offset = new Offset(0, -20)
    }
};

7.8 专题样式

7.8.1 ThemeStyle - 专题样式

using Mapsui.Styles.Thematics;

// 创建专题样式
var themeStyle = new ThemeStyle(feature =>
{
    var value = Convert.ToDouble(feature["value"]);
    
    return new VectorStyle
    {
        Fill = new Brush(GetColorForValue(value))
    };
});

private Color GetColorForValue(double value)
{
    if (value < 100) return Color.Green;
    if (value < 500) return Color.Yellow;
    if (value < 1000) return Color.Orange;
    return Color.Red;
}

7.8.2 分级符号

// 根据属性值设置不同大小的符号
var graduatedStyle = new ThemeStyle(feature =>
{
    var population = Convert.ToDouble(feature["population"]);
    var scale = Math.Log10(population) / 10;  // 对数缩放
    
    return new SymbolStyle
    {
        SymbolScale = Math.Max(0.2, Math.Min(scale, 2.0)),
        Fill = new Brush(Color.Blue),
        Outline = new Pen(Color.White, 1)
    };
});

7.8.3 分类样式

// 根据类别显示不同样式
var categoryStyle = new ThemeStyle(feature =>
{
    var category = feature["type"]?.ToString();
    
    return category switch
    {
        "restaurant" => CreateRestaurantStyle(),
        "hotel" => CreateHotelStyle(),
        "shop" => CreateShopStyle(),
        _ => CreateDefaultStyle()
    };
});

private IStyle CreateRestaurantStyle()
{
    return new ImageStyle
    {
        ImageSource = "embedded://MyApp.Resources.restaurant.png",
        SymbolScale = 0.5
    };
}

7.9 样式工厂

7.9.1 创建样式工厂类

public static class StyleFactory
{
    public static IStyle CreatePointStyle(
        Color fillColor,
        Color? outlineColor = null,
        double scale = 0.5,
        double outlineWidth = 1)
    {
        return new SymbolStyle
        {
            SymbolScale = scale,
            Fill = new Brush(fillColor),
            Outline = outlineColor.HasValue
                ? new Pen(outlineColor.Value, outlineWidth)
                : null
        };
    }
    
    public static IStyle CreateLineStyle(
        Color color,
        double width = 2,
        PenStyle penStyle = PenStyle.Solid)
    {
        return new VectorStyle
        {
            Line = new Pen(color, width)
            {
                PenStyle = penStyle,
                StrokeCap = PenStrokeCap.Round,
                StrokeJoin = StrokeJoin.Round
            }
        };
    }
    
    public static IStyle CreatePolygonStyle(
        Color fillColor,
        Color? outlineColor = null,
        double outlineWidth = 1)
    {
        return new VectorStyle
        {
            Fill = new Brush(fillColor),
            Outline = outlineColor.HasValue
                ? new Pen(outlineColor.Value, outlineWidth)
                : null
        };
    }
    
    public static IStyle CreateLabelStyle(
        string text,
        Color? foreColor = null,
        double fontSize = 12,
        Offset? offset = null)
    {
        return new LabelStyle
        {
            Text = text,
            ForeColor = foreColor ?? Color.Black,
            Font = new Font { Size = fontSize },
            Offset = offset ?? Offset.Zero,
            Halo = new Pen(Color.White, 2)
        };
    }
    
    public static IStyle CreateMarkerStyle(
        string imageSource,
        double scale = 1.0,
        Offset? offset = null)
    {
        return new ImageStyle
        {
            ImageSource = imageSource,
            SymbolScale = scale,
            SymbolOffset = offset ?? Offset.Zero
        };
    }
}

7.9.2 使用样式工厂

// 使用样式工厂创建样式
var pointLayer = new MemoryLayer
{
    Features = pointFeatures,
    Style = StyleFactory.CreatePointStyle(
        Color.Red,
        Color.White,
        scale: 0.6
    )
};

var lineLayer = new MemoryLayer
{
    Features = lineFeatures,
    Style = StyleFactory.CreateLineStyle(
        Color.Blue,
        width: 3,
        penStyle: PenStyle.Dash
    )
};

7.10 本章小结

本章详细介绍了 Mapsui 的样式系统:

  1. 样式类型体系:IStyle 接口和各种样式类
  2. VectorStyle:矢量样式,用于线和面
  3. SymbolStyle:符号样式,用于点
  4. ImageStyle:图像样式,使用图片作为符号
  5. LabelStyle:标签样式,显示文本标注
  6. CalloutStyle:气泡样式,显示信息气泡
  7. 样式集合:组合多个样式
  8. 专题样式:根据属性值动态设置样式
  9. 样式工厂:统一创建样式的工厂类

在下一章中,我们将学习 Mapsui 的小部件(Widget)系统。

7.11 思考与练习

  1. 创建一个根据数值显示渐变色的专题样式。
  2. 实现一个带有阴影效果的自定义标签样式。
  3. 设计一个支持多种符号类型的 POI 图层。
  4. 创建一个道路分级显示的样式(不同等级道路不同宽度和颜色)。
  5. 实现一个交通状态可视化样式(根据拥堵程度显示不同颜色)。
posted @ 2026-01-08 14:40  我才是银古  阅读(3)  评论(0)    收藏  举报