Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
giswqs
GitHub Repository: giswqs/geemap
Path: blob/master/js/layer_manager_row.ts
2313 views
1
import type { RenderProps } from "@anywidget/types";
2
import { css, html, nothing, TemplateResult } from "lit";
3
import { property } from "lit/decorators.js";
4
import { classMap } from "lit/directives/class-map.js";
5
6
import { legacyStyles } from "./ipywidgets_styles";
7
import { materialStyles } from "./styles";
8
import { loadFonts } from "./utils";
9
import { LitWidget } from "./lit_widget";
10
11
export interface LayerManagerRowModel {
12
name: string;
13
visible: boolean;
14
opacity: number;
15
is_loading: boolean;
16
}
17
18
export class LayerManagerRow extends LitWidget<
19
LayerManagerRowModel,
20
LayerManagerRow
21
> {
22
static get componentName() {
23
return `layer-manager-row`;
24
}
25
26
static override styles = [
27
legacyStyles,
28
materialStyles,
29
css`
30
.row {
31
align-items: center;
32
display: flex;
33
gap: 4px;
34
}
35
36
.layer-name {
37
cursor: pointer;
38
flex-grow: 1;
39
max-width: 150px;
40
overflow: hidden;
41
text-overflow: ellipsis;
42
}
43
44
.row-button {
45
font-size: 16px;
46
height: 28px;
47
width: 28px;
48
}
49
50
.layer-opacity-slider {
51
width: 70px;
52
}
53
54
.layer-visibility-checkbox {
55
margin: 2px;
56
}
57
58
.spinner {
59
-webkit-animation: spin 2s linear infinite;
60
animation: spin 2s linear infinite;
61
border-radius: 50%;
62
border: 4px solid var(--jp-widgets-input-border-color);
63
border-top: 4px solid var(--jp-widgets-color);
64
height: 12px;
65
width: 12px;
66
}
67
68
@-webkit-keyframes spin {
69
0% {
70
-webkit-transform: rotate(0deg);
71
}
72
100% {
73
-webkit-transform: rotate(360deg);
74
}
75
}
76
77
@keyframes spin {
78
0% {
79
transform: rotate(0deg);
80
}
81
100% {
82
transform: rotate(360deg);
83
}
84
}
85
86
button.loading .spinner,
87
button.loading:hover .close-icon,
88
button.done-loading .close-icon {
89
display: block;
90
}
91
92
button.loading .close-icon,
93
button.loading:hover .spinner,
94
button.done-loading .spinner {
95
display: none;
96
}
97
98
.remove-layer-text {
99
flex-grow: 1;
100
padding-left: 22px;
101
}
102
103
.confirm-deletion-container {
104
margin-top: 4px;
105
}
106
107
.confirm-deletion-container button {
108
height: 28px;
109
width: 70px;
110
}
111
`,
112
];
113
114
modelNameToViewName(): Map<
115
keyof LayerManagerRowModel,
116
keyof LayerManagerRow | null
117
> {
118
return new Map([
119
["name", "name"],
120
["visible", "visible"],
121
["opacity", "opacity"],
122
["is_loading", "isLoading"],
123
]);
124
}
125
126
@property() name: string = "";
127
@property() visible: boolean = true;
128
@property() opacity: number = 1;
129
@property() isLoading: boolean = false;
130
@property() isConfirmDialogVisible: boolean = false;
131
132
override render(): TemplateResult {
133
return html`
134
<div class="row">
135
<input
136
type="checkbox"
137
class="layer-visibility-checkbox"
138
.checked="${this.visible}"
139
@click="${this.onLayerVisibilityChanged}"
140
/>
141
<span
142
class="legacy-text layer-name"
143
@click="${this.onLayerVisibilityChanged}"
144
>
145
${this.name}
146
</span>
147
<input
148
type="range"
149
class="legacy-slider layer-opacity-slider"
150
min="0"
151
max="1"
152
step="0.01"
153
.value="${this.opacity}"
154
@input="${this.onLayerOpacityChanged}"
155
/>
156
<button
157
class="legacy-button row-button settings-button"
158
@click="${this.onSettingsClicked}"
159
>
160
<span class="material-symbols-outlined">settings</span>
161
</button>
162
<button
163
class=${classMap({
164
"legacy-button": true,
165
"row-button": true,
166
"delete-button": true,
167
loading: this.isLoading,
168
"done-loading": !this.isLoading,
169
})}
170
@click="${this.onDeleteClicked}"
171
>
172
<div class="spinner"></div>
173
<span class="close-icon material-symbols-outlined"
174
>delete</span
175
>
176
</button>
177
</div>
178
${this.renderConfirmDialog()}
179
`;
180
}
181
182
private renderConfirmDialog(): TemplateResult | typeof nothing {
183
if (!this.isConfirmDialogVisible) {
184
return nothing;
185
}
186
return html`
187
<div class="row confirm-deletion-container">
188
<span class="legacy-text remove-layer-text">Remove layer?</span>
189
<button
190
class="legacy-button"
191
@click="${this.cancelDeletion}"
192
>
193
No
194
</button>
195
<button
196
class="legacy-button primary confirm-deletion-button"
197
@click="${this.confirmDeletion}"
198
>
199
Yes
200
</button>
201
</div>
202
`;
203
}
204
205
private onLayerVisibilityChanged(_event: Event) {
206
this.visible = !this.visible;
207
}
208
209
private onLayerOpacityChanged(event: Event) {
210
const target = event.target as HTMLInputElement;
211
this.opacity = parseFloat(target.value);
212
}
213
214
private onSettingsClicked(_: Event) {
215
this.model?.send({ type: "click", id: "settings" });
216
}
217
218
private onDeleteClicked(_: Event) {
219
this.isConfirmDialogVisible = true;
220
}
221
222
private confirmDeletion(_: Event) {
223
this.model?.send({ type: "click", id: "delete" });
224
}
225
226
private cancelDeletion(_: Event) {
227
this.isConfirmDialogVisible = false;
228
}
229
}
230
231
// Without this check, there's a component registry issue when developing locally.
232
if (!customElements.get(LayerManagerRow.componentName)) {
233
customElements.define(LayerManagerRow.componentName, LayerManagerRow);
234
}
235
236
function render({ model, el }: RenderProps<LayerManagerRowModel>) {
237
loadFonts();
238
const row = <LayerManagerRow>(
239
document.createElement(LayerManagerRow.componentName)
240
);
241
row.model = model;
242
el.appendChild(row);
243
}
244
245
export default { render };
246
247