Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
giswqs
GitHub Repository: giswqs/geemap
Path: blob/master/js/vector_layer_editor.ts
2313 views
1
import { css, html, LitElement, nothing, TemplateResult } from "lit";
2
import { property, query } from "lit/decorators.js";
3
4
import { ColorPicker } from "./color_picker";
5
import { legacyStyles } from "./ipywidgets_styles";
6
import { LegendCustomization } from "./legend_customization";
7
import { PaletteEditor } from "./palette_editor";
8
import { flexStyles } from "./styles";
9
import { renderSelect } from "./utils";
10
11
import "./palette_editor";
12
13
export class VectorLayerEditor extends LitElement {
14
static get componentName() {
15
return `vector-layer-editor`;
16
}
17
18
static override styles = [
19
flexStyles,
20
legacyStyles,
21
css`
22
.style-by-attribute-checkbox {
23
vertical-align: middle;
24
}
25
`,
26
];
27
28
static pointShapes: Array<string> = [
29
"circle",
30
"square",
31
"diamond",
32
"cross",
33
"plus",
34
"pentagram",
35
"hexagram",
36
"triangle",
37
"triangle_up",
38
"triangle_down",
39
"triangle_left",
40
"triangle_right",
41
"pentagon",
42
"hexagon",
43
"star5",
44
"star6",
45
];
46
47
static lineTypes: Array<string> = [
48
"solid",
49
"dotted",
50
"dashed",
51
];
52
53
@property({ type: Array }) colormaps: Array<string> = [];
54
@property({ type: String }) newLayerName: string = "";
55
@property({ type: Number }) opacity: number = 1.0;
56
@property({ type: Number }) pointSize: number = 3.0;
57
@property({ type: String }) pointShape: string = VectorLayerEditor.pointShapes[0];
58
@property({ type: Number }) lineWidth: number = 2.0;
59
@property({ type: String }) lineType: string = VectorLayerEditor.lineTypes[0];
60
@property({ type: Number }) fillOpacity: number = 1.0;
61
@property({ type: Boolean }) shouldStyleByAttribute: boolean = false;
62
@property({ type: Array }) fields: Array<string> = [];
63
@property({ type: String }) selectedField: string = "";
64
@property({ type: Array }) fieldValues: Array<string> = [];
65
@property({ type: String }) selectedFieldValue: string = "";
66
67
@query("palette-editor") paletteEditor?: PaletteEditor;
68
@query("legend-customization") legendCustomization?: LegendCustomization;
69
@query("#color-picker") colorPicker!: ColorPicker;
70
@query("#fill-color-picker") fillColorPicker!: ColorPicker;
71
72
getVisualizationOptions(): any {
73
let visParams = {
74
layerName: this.newLayerName,
75
color: this.colorPicker.value,
76
opacity: this.opacity,
77
pointSize: this.pointSize,
78
pointShape: this.pointShape,
79
lineWidth: this.lineWidth,
80
lineType: this.lineType,
81
fillColor: this.fillColorPicker.value,
82
fillOpacity: this.fillOpacity,
83
shouldStyleByAttribute: this.shouldStyleByAttribute,
84
} as any;
85
if (this.shouldStyleByAttribute) {
86
visParams.palette = this.paletteEditor?.paletteTokens ?? [];
87
visParams.field = this.selectedField;
88
}
89
if (this.legendCustomization) {
90
visParams.legend = this.legendCustomization.getLegendData();
91
}
92
return visParams;
93
}
94
95
override render() {
96
return html`
97
<div class="vertical-flex">
98
<div class="horizontal-flex">
99
<span class="legacy-text">New layer name:</span>
100
<input
101
type="text"
102
class="legacy-text-input"
103
id="new-layer-name"
104
name="new-layer-name"
105
.value="${this.newLayerName}"
106
@change="${this.onNewLayerNameChanged}"
107
/>
108
</div>
109
<div class="horizontal-flex">
110
<color-picker id="color-picker"></color-picker>
111
<span class="legacy-text">Opacity:</span>
112
<input
113
type="range"
114
class="legacy-slider"
115
id="opacity"
116
name="opacity"
117
min="0"
118
max="1.0"
119
step="0.01"
120
.value=${this.opacity}
121
@input=${this.onOpacityChanged}
122
/>
123
<span class="legacy-text">${this.opacity.toFixed(2)}</span>
124
</div>
125
<div class="horizontal-flex">
126
<span class="legacy-text">Point size:</span>
127
<input
128
type="number"
129
class="legacy-text-input"
130
id="point-size"
131
name="point-size"
132
min="1"
133
max="50"
134
.value="${this.pointSize}"
135
@change="${this.onPointSizeChanged}"
136
/>
137
<span class="legacy-text">Point shape:</span>
138
${renderSelect(VectorLayerEditor.pointShapes, this.pointShape, this.onPointShapeChanged)}
139
</div>
140
<div class="horizontal-flex">
141
<span class="legacy-text">Line width:</span>
142
<input
143
type="number"
144
class="legacy-text-input"
145
id="line-width"
146
name="line-width"
147
min="1"
148
max="50"
149
.value="${this.lineWidth}"
150
@change="${this.onLineWidthChanged}"
151
/>
152
<span class="legacy-text">Line type:</span>
153
${renderSelect(VectorLayerEditor.lineTypes, this.lineType, this.onLineTypeChanged)}
154
</div>
155
<div class="horizontal-flex">
156
<span class="legacy-text">Fill:</span>
157
<color-picker id="fill-color-picker"></color-picker>
158
<span class="legacy-text">Opacity:</span>
159
<input
160
type="range"
161
class="legacy-slider"
162
id="fill-opacity"
163
name="fill-opacity"
164
min="0"
165
max="1.0"
166
step="0.01"
167
.value=${this.fillOpacity}
168
@input=${this.onFillOpacityChanged}
169
/>
170
<span class="legacy-text">${this.fillOpacity.toFixed(2)}</span>
171
</div>
172
<div class="horizontal-flex">
173
<span>
174
<input
175
class="style-by-attribute-checkbox"
176
type="checkbox"
177
.checked="${this.shouldStyleByAttribute}"
178
@change="${this.onShouldStyleByAttributeChanged}"
179
/>
180
<span class="legacy-text all-layers-text"
181
>Style by attribute</span
182
>
183
</span>
184
</div>
185
${this.renderStyleByAttributeSettings()}
186
${this.renderLegendCustomization()}
187
</div>
188
`;
189
}
190
191
private renderStyleByAttributeSettings(): TemplateResult | typeof nothing {
192
if (!this.shouldStyleByAttribute) {
193
return nothing;
194
}
195
return html`
196
<div class="horizontal-flex">
197
<span class="legacy-text">Field:</span>
198
${renderSelect(this.fields, this.selectedField, this.onStyleAttributeChanged)}
199
<span class="legacy-text">Values:</span>
200
${renderSelect(this.fieldValues, this.selectedFieldValue, this.onValueChanged)}
201
</div>
202
<palette-editor .colormaps="${this.colormaps}">
203
<slot></slot>
204
</palette-editor>
205
`;
206
}
207
208
private renderLegendCustomization(): TemplateResult | typeof nothing {
209
if (this.shouldStyleByAttribute) {
210
return html`<legend-customization></legend-customization>`;
211
}
212
return nothing;
213
}
214
215
private onNewLayerNameChanged(event: Event): void {
216
this.newLayerName = (event.target as HTMLInputElement).value;
217
}
218
219
private onOpacityChanged(event: Event): void {
220
this.opacity = (event.target as HTMLInputElement).valueAsNumber;
221
}
222
223
private onPointSizeChanged(event: Event): void {
224
this.pointSize = (event.target as HTMLInputElement).valueAsNumber;
225
}
226
227
private onPointShapeChanged(event: Event): void {
228
this.pointShape = (event.target as HTMLInputElement).value;
229
}
230
231
private onLineWidthChanged(event: Event): void {
232
this.lineWidth = (event.target as HTMLInputElement).valueAsNumber;
233
}
234
235
private onLineTypeChanged(event: Event): void {
236
this.lineType = (event.target as HTMLInputElement).value;
237
}
238
239
private onFillOpacityChanged(event: Event): void {
240
this.fillOpacity = (event.target as HTMLInputElement).valueAsNumber;
241
}
242
243
private onShouldStyleByAttributeChanged(event: Event): void {
244
this.shouldStyleByAttribute = (event.target as HTMLInputElement).checked;
245
this.dispatchEvent(new CustomEvent("calculate-fields", {}));
246
}
247
248
private onStyleAttributeChanged(event: Event): void {
249
this.selectedField = (event.target as HTMLInputElement).value;
250
this.dispatchEvent(new CustomEvent("calculate-field-values", {}));
251
}
252
253
private onValueChanged(event: Event): void {
254
this.selectedFieldValue = (event.target as HTMLInputElement).value;
255
}
256
}
257
258
// Without this check, there's a component registry issue when developing locally.
259
if (!customElements.get(VectorLayerEditor.componentName)) {
260
customElements.define(VectorLayerEditor.componentName, VectorLayerEditor);
261
}
262
263