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
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