Jinuss's blog Jinuss's blog
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

前端可视化
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 核心基类

  • Control控件篇

    • Control基类介绍
    • 默认Controls控件渲染过程
    • Zoom缩放控件源码分析
    • Rotate旋转控件源码分析
    • ZoomToExtent控件源码分析
    • ZoomSlider滑块缩放控件源码分析
    • ScaleLine比例尺控件源码分析
    • Attribution属性控件源码分析
      • 概述
      • 源码分析
        • Attribution类控件源码实现如下
        • Attribution控件的主要方法
      • 总结
    • FullScreen全屏控件源码分析
    • OverviewMap鹰眼控件源码分析
    • MousePosition鼠标位置控件源码分析
  • Geom几何图形篇

  • Layer图层篇

  • Renderer篇

  • Feature篇

  • style样式篇

  • 《Openlayers源码》笔记
  • Control控件篇
东流
2024-12-11
目录

Attribution属性控件源码分析

# 概述

本文主要介绍 Openlayers 中Attribution属性控件的源码实现,该控件也是 Openlayers 中三个默认控件之一。默认情况下,控件会显示在地图的右下角,可以通过控件的类名设置CSS属性控制。实际应用中该控件主要显示与图层源source相关的所有属性,一般用来显示版权说明等等。

# 源码分析

Attribution控件继承自Control类,关于Control类,可以参考Control基类介绍 (opens new window).

# Attribution类控件源码实现如下

class Attribution extends Control {
  constructor(options) {
    options = options ? options : {};

    super({
      element: document.createElement("div"),
      render: options.render,
      target: options.target,
    });

    this.ulElement_ = document.createElement("ul");

    this.collapsed_ =
      options.collapsed !== undefined ? options.collapsed : true;

    this.userCollapsed_ = this.collapsed_;

    this.overrideCollapsible_ = options.collapsible !== undefined;

    this.collapsible_ =
      options.collapsible !== undefined ? options.collapsible : true;

    if (!this.collapsible_) {
      this.collapsed_ = false;
    }

    this.attributions_ = options.attributions;

    const className =
      options.className !== undefined ? options.className : "ol-attribution";

    const tipLabel =
      options.tipLabel !== undefined ? options.tipLabel : "Attributions";

    const expandClassName =
      options.expandClassName !== undefined
        ? options.expandClassName
        : className + "-expand";

    const collapseLabel =
      options.collapseLabel !== undefined ? options.collapseLabel : "\u203A";

    const collapseClassName =
      options.collapseClassName !== undefined
        ? options.collapseClassName
        : className + "-collapse";

    if (typeof collapseLabel === "string") {
      this.collapseLabel_ = document.createElement("span");
      this.collapseLabel_.textContent = collapseLabel;
      this.collapseLabel_.className = collapseClassName;
    } else {
      this.collapseLabel_ = collapseLabel;
    }

    const label = options.label !== undefined ? options.label : "i";

    if (typeof label === "string") {
      this.label_ = document.createElement("span");
      this.label_.textContent = label;
      this.label_.className = expandClassName;
    } else {
      this.label_ = label;
    }

    const activeLabel =
      this.collapsible_ && !this.collapsed_ ? this.collapseLabel_ : this.label_;

    this.toggleButton_ = document.createElement("button");
    this.toggleButton_.setAttribute("type", "button");
    this.toggleButton_.setAttribute("aria-expanded", String(!this.collapsed_));
    this.toggleButton_.title = tipLabel;
    this.toggleButton_.appendChild(activeLabel);

    this.toggleButton_.addEventListener(
      EventType.CLICK,
      this.handleClick_.bind(this),
      false
    );

    const cssClasses =
      className +
      " " +
      CLASS_UNSELECTABLE +
      " " +
      CLASS_CONTROL +
      (this.collapsed_ && this.collapsible_ ? " " + CLASS_COLLAPSED : "") +
      (this.collapsible_ ? "" : " ol-uncollapsible");
    const element = this.element;
    element.className = cssClasses;
    element.appendChild(this.toggleButton_);
    element.appendChild(this.ulElement_);

    this.renderedAttributions_ = [];

    this.renderedVisible_ = true;
  }

  collectSourceAttributions_(frameState) {
    const layers = this.getMap().getAllLayers();
    const visibleAttributions = new Set(
      layers.flatMap((layer) => layer.getAttributions(frameState))
    );
    if (this.attributions_ !== undefined) {
      Array.isArray(this.attributions_)
        ? this.attributions_.forEach((item) => visibleAttributions.add(item))
        : visibleAttributions.add(this.attributions_);
    }

    if (!this.overrideCollapsible_) {
      const collapsible = !layers.some(
        (layer) => layer.getSource()?.getAttributionsCollapsible() === false
      );
      this.setCollapsible(collapsible);
    }
    return Array.from(visibleAttributions);
  }

  async updateElement_(frameState) {
    if (!frameState) {
      if (this.renderedVisible_) {
        this.element.style.display = "none";
        this.renderedVisible_ = false;
      }
      return;
    }

    const attributions = await Promise.all(
      this.collectSourceAttributions_(frameState).map((attribution) =>
        toPromise(() => attribution)
      )
    );

    const visible = attributions.length > 0;
    if (this.renderedVisible_ != visible) {
      this.element.style.display = visible ? "" : "none";
      this.renderedVisible_ = visible;
    }

    if (equals(attributions, this.renderedAttributions_)) {
      return;
    }

    removeChildren(this.ulElement_);

    // append the attributions
    for (let i = 0, ii = attributions.length; i < ii; ++i) {
      const element = document.createElement("li");
      element.innerHTML = attributions[i];
      this.ulElement_.appendChild(element);
    }

    this.renderedAttributions_ = attributions;
  }

  handleClick_(event) {
    event.preventDefault();
    this.handleToggle_();
    this.userCollapsed_ = this.collapsed_;
  }

  handleToggle_() {
    this.element.classList.toggle(CLASS_COLLAPSED);
    if (this.collapsed_) {
      replaceNode(this.collapseLabel_, this.label_);
    } else {
      replaceNode(this.label_, this.collapseLabel_);
    }
    this.collapsed_ = !this.collapsed_;
    this.toggleButton_.setAttribute("aria-expanded", String(!this.collapsed_));
  }

  getCollapsible() {
    return this.collapsible_;
  }

  setCollapsible(collapsible) {
    if (this.collapsible_ === collapsible) {
      return;
    }
    this.collapsible_ = collapsible;
    this.element.classList.toggle("ol-uncollapsible");
    if (this.userCollapsed_) {
      this.handleToggle_();
    }
  }

  setCollapsed(collapsed) {
    this.userCollapsed_ = collapsed;
    if (!this.collapsible_ || this.collapsed_ === collapsed) {
      return;
    }
    this.handleToggle_();
  }

  getCollapsed() {
    return this.collapsed_;
  }

  render(mapEvent) {
    this.updateElement_(mapEvent.frameState);
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203

# Attribution控件的主要方法

关于Attribution控件主要介绍它的两个方法,如下

  • collectSourceAttributions_方法

collectSourceAttributions_方法顾名思义就是获取图层源的属性作为一个集合;该方法内部先调用getMap().getAllLayers()方法获取所有图层,然后遍历图层获取图层源的属性信息;判断,若this.attributions_存在,则根据它的类型将其添加到visibleAttributions中;判断,若this.overrideCollapsible_为false,则获取图层源属性折叠信息,调用setCollapsible方法

  • updateElement_方法

updateElement_方法在控件的render方法中调用,本质上就是获取属性信息,更新信息。

# 总结

本文主要介绍了 Openlayers 中的Attribution属性控件,这个控件的非核心部分就是点击元素折叠显示,详见上面源码即可;另,核心部分就是collectSourceAttributions_方法,获取图层源的信息,这是基于Layer类和Source类实现的,关于这两个 Openlayers 的核心类,可以参考后面的文章。

编辑 (opens new window)
上次更新: 2024/12/20, 05:30:19
ScaleLine比例尺控件源码分析
FullScreen全屏控件源码分析

← ScaleLine比例尺控件源码分析 FullScreen全屏控件源码分析→

最近更新
01
GeoJSON
05-08
02
Circle
04-15
03
CircleMarker
04-15
更多文章>
Theme by Vdoing | Copyright © 2024-2025 东流 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式