@arronqzy/react-view 1.0.22 → 1.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +11 -11
- package/src/panel/ReactViewPanel.tsx +109 -965
- package/src/panel/components/PanelConfigSidebar.tsx +297 -3712
- package/src/panel/components/PanelHistoryPopover.tsx +163 -0
- package/src/panel/components/PanelLayerDock.tsx +412 -0
- package/src/panel/components/PanelMenubar.tsx +149 -0
- package/src/panel/components/PanelWorkspaceDialogs.tsx +271 -0
- package/src/panel/components/config/PanelConfigAudioSection.tsx +334 -0
- package/src/panel/components/config/PanelConfigChartSection.tsx +799 -0
- package/src/panel/components/config/PanelConfigGeometrySection.tsx +233 -0
- package/src/panel/components/config/PanelConfigGridChildSpan.tsx +70 -0
- package/src/panel/components/config/PanelConfigGridSection.tsx +118 -0
- package/src/panel/components/config/PanelConfigMultiSelect.tsx +1291 -0
- package/src/panel/components/config/PanelConfigNodeInfo.tsx +169 -0
- package/src/panel/components/config/PanelConfigReferenceSection.tsx +99 -0
- package/src/panel/components/config/PanelConfigScene3dSection.tsx +6 -2
- package/src/panel/components/config/PanelConfigStyleSections.tsx +249 -0
- package/src/panel/components/config/PanelConfigTextSection.tsx +268 -0
- package/src/panel/components/config/PanelConfigVideoSection.tsx +133 -0
- package/src/panel/components/config/PanelConfigViewportSection.tsx +139 -0
- package/src/panel/components/config/helpers.ts +85 -0
- package/src/panel/icons.tsx +160 -0
- package/src/panel/utils/panelSelection.ts +57 -0
|
@@ -0,0 +1,799 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from "react";
|
|
2
|
+
import { useI18n } from "@arronqzy/i18n/react";
|
|
3
|
+
import {
|
|
4
|
+
Checkbox,
|
|
5
|
+
Collapsible,
|
|
6
|
+
CollapsibleContent,
|
|
7
|
+
CollapsibleTrigger,
|
|
8
|
+
Input,
|
|
9
|
+
Select,
|
|
10
|
+
SelectContent,
|
|
11
|
+
SelectItem,
|
|
12
|
+
SelectTrigger,
|
|
13
|
+
SelectValue,
|
|
14
|
+
Textarea,
|
|
15
|
+
} from "@arronqzy/ui";
|
|
16
|
+
import type { PanelChartConfig, PanelElement } from "../../types";
|
|
17
|
+
import { buildChartOption, getChartLabelsDisplayText, getChartValuesDisplayText } from "../../utils/chartOptionBuilder";
|
|
18
|
+
import { ConfigHintIcon } from "../ConfigHintIcon";
|
|
19
|
+
import {
|
|
20
|
+
type ConfigSectionHelpers,
|
|
21
|
+
type UpdateElement,
|
|
22
|
+
mergeOptionPatch,
|
|
23
|
+
patchChart,
|
|
24
|
+
} from "./helpers";
|
|
25
|
+
|
|
26
|
+
export function PanelConfigChartSection({
|
|
27
|
+
element,
|
|
28
|
+
helpers,
|
|
29
|
+
updateElement,
|
|
30
|
+
}: {
|
|
31
|
+
element: PanelElement;
|
|
32
|
+
helpers: ConfigSectionHelpers;
|
|
33
|
+
updateElement: UpdateElement;
|
|
34
|
+
}) {
|
|
35
|
+
const { t } = useI18n();
|
|
36
|
+
const {
|
|
37
|
+
renderSection,
|
|
38
|
+
renderFieldGroup,
|
|
39
|
+
renderColorField,
|
|
40
|
+
hasSearch,
|
|
41
|
+
isSectionExpanded,
|
|
42
|
+
setSectionExpanded,
|
|
43
|
+
optionCheckboxClass,
|
|
44
|
+
optionInputClass,
|
|
45
|
+
optionSelectTriggerClass,
|
|
46
|
+
renderOptionLabel,
|
|
47
|
+
renderFormatterLabel,
|
|
48
|
+
} = helpers;
|
|
49
|
+
const optionLabelTextClass = "truncate whitespace-nowrap text-[11px] leading-none";
|
|
50
|
+
const selectedElement = element;
|
|
51
|
+
const [isAdvancedOptionMode, setIsAdvancedOptionMode] = useState(false);
|
|
52
|
+
const [optionJsonText, setOptionJsonText] = useState("{}");
|
|
53
|
+
const [optionJsonError, setOptionJsonError] = useState<string | null>(null);
|
|
54
|
+
|
|
55
|
+
const selectedChartType = (selectedElement.materialType ?? "") as
|
|
56
|
+
| "bar"
|
|
57
|
+
| "line"
|
|
58
|
+
| "pie"
|
|
59
|
+
| "area"
|
|
60
|
+
| "scatter"
|
|
61
|
+
| "radar"
|
|
62
|
+
| "gauge"
|
|
63
|
+
| "funnel"
|
|
64
|
+
| "";
|
|
65
|
+
|
|
66
|
+
const updateSelectedChart = useCallback(
|
|
67
|
+
(patch: Partial<PanelChartConfig>) => {
|
|
68
|
+
updateElement(selectedElement.id, {
|
|
69
|
+
chart: patchChart(selectedElement.chart, patch),
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
[selectedElement, updateElement]
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const updateSelectedOptionForm = useCallback(
|
|
76
|
+
(patch: Record<string, unknown>) => {
|
|
77
|
+
updateSelectedChart({
|
|
78
|
+
option: mergeOptionPatch(
|
|
79
|
+
(selectedElement.chart?.option as Record<string, unknown> | undefined) ?? {},
|
|
80
|
+
patch
|
|
81
|
+
),
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
[selectedElement, updateSelectedChart]
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
setOptionJsonText(JSON.stringify(buildChartOption(selectedElement), null, 2));
|
|
89
|
+
setOptionJsonError(null);
|
|
90
|
+
}, [selectedElement]);
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<>
|
|
94
|
+
{renderSection(
|
|
95
|
+
"chartBasic",
|
|
96
|
+
t("panel.config.sectionChartBasic"),
|
|
97
|
+
<>
|
|
98
|
+
{renderFieldGroup(
|
|
99
|
+
t("panel.config.groupBasicDisplay"),
|
|
100
|
+
<>
|
|
101
|
+
<label className="block space-y-1.5" data-config-field="chart.title">
|
|
102
|
+
<div>{t("panel.config.title")}</div>
|
|
103
|
+
<Input
|
|
104
|
+
value={selectedElement.chart?.title ?? ""}
|
|
105
|
+
onChange={(e) => updateSelectedChart({ title: e.target.value })}
|
|
106
|
+
className="h-7"
|
|
107
|
+
/>
|
|
108
|
+
</label>
|
|
109
|
+
|
|
110
|
+
{renderColorField(
|
|
111
|
+
t("panel.config.primaryColor"),
|
|
112
|
+
selectedElement.chart?.color ?? "#3b82f6",
|
|
113
|
+
(next) => updateSelectedChart({ color: next || "#3b82f6" })
|
|
114
|
+
)}
|
|
115
|
+
</>
|
|
116
|
+
)}
|
|
117
|
+
{renderFieldGroup(
|
|
118
|
+
t("panel.config.groupData"),
|
|
119
|
+
<>
|
|
120
|
+
<label className="block space-y-1">
|
|
121
|
+
<div>{t("panel.config.labelsCsv")}</div>
|
|
122
|
+
<Input
|
|
123
|
+
value={getChartLabelsDisplayText(selectedElement.chart)}
|
|
124
|
+
onChange={(e) =>
|
|
125
|
+
updateSelectedChart({
|
|
126
|
+
labelsText: e.target.value,
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
className="h-7"
|
|
130
|
+
/>
|
|
131
|
+
</label>
|
|
132
|
+
|
|
133
|
+
<label className="block space-y-1">
|
|
134
|
+
<div>{t("panel.config.valuesCsv")}</div>
|
|
135
|
+
<Input
|
|
136
|
+
value={getChartValuesDisplayText(selectedElement.chart)}
|
|
137
|
+
onChange={(e) =>
|
|
138
|
+
updateSelectedChart({
|
|
139
|
+
valuesText: e.target.value,
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
className="h-7"
|
|
143
|
+
/>
|
|
144
|
+
</label>
|
|
145
|
+
</>
|
|
146
|
+
)}
|
|
147
|
+
|
|
148
|
+
{selectedChartType === "bar" ||
|
|
149
|
+
selectedChartType === "line" ||
|
|
150
|
+
selectedChartType === "area" ||
|
|
151
|
+
selectedChartType === "pie" ? (
|
|
152
|
+
renderFieldGroup(
|
|
153
|
+
t("panel.config.groupSeries"),
|
|
154
|
+
<>
|
|
155
|
+
{selectedChartType === "bar" ? (
|
|
156
|
+
<label className="block space-y-1">
|
|
157
|
+
<div>{t("panel.config.barWidthPx")}</div>
|
|
158
|
+
<Input
|
|
159
|
+
type="number"
|
|
160
|
+
min={1}
|
|
161
|
+
placeholder={t("panel.config.barWidthAuto")}
|
|
162
|
+
value={selectedElement.chart?.barWidth ?? ""}
|
|
163
|
+
onChange={(e) => {
|
|
164
|
+
const raw = e.target.value.trim();
|
|
165
|
+
updateSelectedChart({
|
|
166
|
+
barWidth: raw
|
|
167
|
+
? Math.max(1, Number(raw) || 1)
|
|
168
|
+
: undefined,
|
|
169
|
+
});
|
|
170
|
+
}}
|
|
171
|
+
className="h-7"
|
|
172
|
+
/>
|
|
173
|
+
</label>
|
|
174
|
+
) : null}
|
|
175
|
+
|
|
176
|
+
{selectedChartType === "line" || selectedChartType === "area" ? (
|
|
177
|
+
<label className="flex items-center gap-2">
|
|
178
|
+
<Checkbox
|
|
179
|
+
checked={selectedElement.chart?.smooth ?? true}
|
|
180
|
+
className="h-4 w-4 border-2 border-foreground/80 bg-background ring-1 ring-foreground/40 data-[state=checked]:border-primary data-[state=checked]:ring-primary/40"
|
|
181
|
+
onCheckedChange={(checked) =>
|
|
182
|
+
updateSelectedChart({ smooth: checked === true })
|
|
183
|
+
}
|
|
184
|
+
/>
|
|
185
|
+
<span>{t("panel.config.smooth")}</span>
|
|
186
|
+
</label>
|
|
187
|
+
) : null}
|
|
188
|
+
|
|
189
|
+
{selectedChartType === "pie" ? (
|
|
190
|
+
<div className="grid grid-cols-2 gap-2">
|
|
191
|
+
<label className="block space-y-1">
|
|
192
|
+
<div>{t("panel.config.pieInnerRadiusPct")}</div>
|
|
193
|
+
<Input
|
|
194
|
+
type="number"
|
|
195
|
+
min={0}
|
|
196
|
+
max={99}
|
|
197
|
+
value={selectedElement.chart?.pieInnerRadius ?? 30}
|
|
198
|
+
onChange={(e) =>
|
|
199
|
+
updateSelectedChart({
|
|
200
|
+
pieInnerRadius: Math.max(
|
|
201
|
+
0,
|
|
202
|
+
Math.min(99, Number(e.target.value) || 0)
|
|
203
|
+
),
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
className="h-7"
|
|
207
|
+
/>
|
|
208
|
+
</label>
|
|
209
|
+
<label className="block space-y-1">
|
|
210
|
+
<div>{t("panel.config.pieOuterRadiusPct")}</div>
|
|
211
|
+
<Input
|
|
212
|
+
type="number"
|
|
213
|
+
min={1}
|
|
214
|
+
max={100}
|
|
215
|
+
value={selectedElement.chart?.pieOuterRadius ?? 65}
|
|
216
|
+
onChange={(e) =>
|
|
217
|
+
updateSelectedChart({
|
|
218
|
+
pieOuterRadius: Math.max(
|
|
219
|
+
1,
|
|
220
|
+
Math.min(100, Number(e.target.value) || 1)
|
|
221
|
+
),
|
|
222
|
+
})
|
|
223
|
+
}
|
|
224
|
+
className="h-7"
|
|
225
|
+
/>
|
|
226
|
+
</label>
|
|
227
|
+
</div>
|
|
228
|
+
) : null}
|
|
229
|
+
</>
|
|
230
|
+
)
|
|
231
|
+
) : null}
|
|
232
|
+
{renderFieldGroup(
|
|
233
|
+
t("panel.config.groupChartDisplayMore"),
|
|
234
|
+
<>
|
|
235
|
+
<label className="flex items-center gap-2">
|
|
236
|
+
<Checkbox
|
|
237
|
+
checked={selectedElement.chart?.colorMode === "gradient"}
|
|
238
|
+
onCheckedChange={(checked) =>
|
|
239
|
+
updateSelectedChart({ colorMode: checked ? "gradient" : "solid" })
|
|
240
|
+
}
|
|
241
|
+
/>
|
|
242
|
+
<span>{t("panel.config.usePrimaryGradient")}</span>
|
|
243
|
+
</label>
|
|
244
|
+
{selectedElement.chart?.colorMode === "gradient" ? (
|
|
245
|
+
<div className="grid grid-cols-2 gap-2">
|
|
246
|
+
{renderColorField(
|
|
247
|
+
t("panel.config.gradientFrom"),
|
|
248
|
+
selectedElement.chart?.gradientFrom ?? selectedElement.chart?.color ?? "#3b82f6",
|
|
249
|
+
(next) => updateSelectedChart({ gradientFrom: next || "#3b82f6" })
|
|
250
|
+
)}
|
|
251
|
+
{renderColorField(
|
|
252
|
+
t("panel.config.gradientTo"),
|
|
253
|
+
selectedElement.chart?.gradientTo ?? "#22d3ee",
|
|
254
|
+
(next) => updateSelectedChart({ gradientTo: next || "#22d3ee" })
|
|
255
|
+
)}
|
|
256
|
+
<label className="block space-y-1 col-span-2">
|
|
257
|
+
<div>{t("panel.config.gradientDirection")}</div>
|
|
258
|
+
<Select
|
|
259
|
+
value={selectedElement.chart?.gradientDirection ?? "to-right"}
|
|
260
|
+
onValueChange={(value) =>
|
|
261
|
+
updateSelectedChart({
|
|
262
|
+
gradientDirection: value as
|
|
263
|
+
| "to-right"
|
|
264
|
+
| "to-bottom"
|
|
265
|
+
| "to-bottom-right"
|
|
266
|
+
| "to-top-right",
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
>
|
|
270
|
+
<SelectTrigger className="h-7">
|
|
271
|
+
<SelectValue placeholder={t("panel.config.selectGradientDirection")} />
|
|
272
|
+
</SelectTrigger>
|
|
273
|
+
<SelectContent>
|
|
274
|
+
<SelectItem value="to-right">{t("panel.config.dirToRight")}</SelectItem>
|
|
275
|
+
<SelectItem value="to-bottom">{t("panel.config.dirToBottom")}</SelectItem>
|
|
276
|
+
<SelectItem value="to-bottom-right">{t("panel.config.dirToBottomRight")}</SelectItem>
|
|
277
|
+
<SelectItem value="to-top-right">{t("panel.config.dirToTopRight")}</SelectItem>
|
|
278
|
+
</SelectContent>
|
|
279
|
+
</Select>
|
|
280
|
+
</label>
|
|
281
|
+
<div className="col-span-2 space-y-1">
|
|
282
|
+
<div className="text-[11px] text-muted-foreground">{t("panel.config.gradientPreview")}</div>
|
|
283
|
+
<div
|
|
284
|
+
className="h-6 rounded border border-border/60"
|
|
285
|
+
style={{
|
|
286
|
+
backgroundImage: `linear-gradient(${
|
|
287
|
+
(selectedElement.chart?.gradientDirection ?? "to-right") === "to-bottom"
|
|
288
|
+
? "to bottom"
|
|
289
|
+
: (selectedElement.chart?.gradientDirection ?? "to-right") === "to-bottom-right"
|
|
290
|
+
? "to bottom right"
|
|
291
|
+
: (selectedElement.chart?.gradientDirection ?? "to-right") === "to-top-right"
|
|
292
|
+
? "to top right"
|
|
293
|
+
: "to right"
|
|
294
|
+
}, ${selectedElement.chart?.gradientFrom ?? selectedElement.chart?.color ?? "#3b82f6"}, ${selectedElement.chart?.gradientTo ?? "#22d3ee"})`,
|
|
295
|
+
}}
|
|
296
|
+
/>
|
|
297
|
+
</div>
|
|
298
|
+
</div>
|
|
299
|
+
) : null}
|
|
300
|
+
<label className="block space-y-1.5">
|
|
301
|
+
<div>{t("panel.config.renderMode")}</div>
|
|
302
|
+
<Select
|
|
303
|
+
value={selectedElement.chart?.renderMode ?? "canvas"}
|
|
304
|
+
onValueChange={(value) =>
|
|
305
|
+
updateSelectedChart({ renderMode: value as "canvas" | "svg" })
|
|
306
|
+
}
|
|
307
|
+
>
|
|
308
|
+
<SelectTrigger className="h-7">
|
|
309
|
+
<SelectValue placeholder={t("panel.config.selectRenderMode")} />
|
|
310
|
+
</SelectTrigger>
|
|
311
|
+
<SelectContent>
|
|
312
|
+
<SelectItem value="canvas">Canvas</SelectItem>
|
|
313
|
+
<SelectItem value="svg">SVG</SelectItem>
|
|
314
|
+
</SelectContent>
|
|
315
|
+
</Select>
|
|
316
|
+
</label>
|
|
317
|
+
</>,
|
|
318
|
+
undefined,
|
|
319
|
+
{ groupKey: "chartDisplayMore", defaultOpen: false }
|
|
320
|
+
)}
|
|
321
|
+
{renderFieldGroup(
|
|
322
|
+
t("panel.config.groupTooltip"),
|
|
323
|
+
<>
|
|
324
|
+
<div className="grid grid-cols-2 gap-2">
|
|
325
|
+
<label className="flex items-center gap-2">
|
|
326
|
+
<Checkbox
|
|
327
|
+
checked={selectedElement.chart?.tooltipShow ?? true}
|
|
328
|
+
className="h-4 w-4 border-2 border-foreground/80 bg-background ring-1 ring-foreground/40 data-[state=checked]:border-primary data-[state=checked]:ring-primary/40"
|
|
329
|
+
onCheckedChange={(checked) =>
|
|
330
|
+
updateSelectedChart({ tooltipShow: checked === true })
|
|
331
|
+
}
|
|
332
|
+
/>
|
|
333
|
+
<span>{t("panel.config.showTooltip")}</span>
|
|
334
|
+
</label>
|
|
335
|
+
<label className="block space-y-1">
|
|
336
|
+
<div>{t("panel.config.tooltipTrigger")}</div>
|
|
337
|
+
<Select
|
|
338
|
+
value={selectedElement.chart?.tooltipTrigger ?? "axis"}
|
|
339
|
+
onValueChange={(value) =>
|
|
340
|
+
updateSelectedChart({ tooltipTrigger: value as "axis" | "item" })
|
|
341
|
+
}
|
|
342
|
+
>
|
|
343
|
+
<SelectTrigger className="h-7">
|
|
344
|
+
<SelectValue placeholder={t("panel.config.selectTooltipTrigger")} />
|
|
345
|
+
</SelectTrigger>
|
|
346
|
+
<SelectContent>
|
|
347
|
+
<SelectItem value="axis">axis</SelectItem>
|
|
348
|
+
<SelectItem value="item">item</SelectItem>
|
|
349
|
+
</SelectContent>
|
|
350
|
+
</Select>
|
|
351
|
+
</label>
|
|
352
|
+
</div>
|
|
353
|
+
<div className="grid grid-cols-2 gap-2">
|
|
354
|
+
{renderColorField(
|
|
355
|
+
t("panel.config.tooltipBgColor"),
|
|
356
|
+
selectedElement.chart?.tooltipBackgroundColor ?? "#0f172a",
|
|
357
|
+
(next) => updateSelectedChart({ tooltipBackgroundColor: next || "#0f172a" })
|
|
358
|
+
)}
|
|
359
|
+
{renderColorField(
|
|
360
|
+
t("panel.config.tooltipTextColor"),
|
|
361
|
+
selectedElement.chart?.tooltipTextColor ?? "#f8fafc",
|
|
362
|
+
(next) => updateSelectedChart({ tooltipTextColor: next || "#f8fafc" })
|
|
363
|
+
)}
|
|
364
|
+
</div>
|
|
365
|
+
<label className="block space-y-1">
|
|
366
|
+
{renderFormatterLabel(t("panel.config.tooltipFormatter"))}
|
|
367
|
+
<Input
|
|
368
|
+
value={selectedElement.chart?.tooltipFormatter ?? ""}
|
|
369
|
+
onChange={(e) =>
|
|
370
|
+
updateSelectedChart({ tooltipFormatter: e.target.value || undefined })
|
|
371
|
+
}
|
|
372
|
+
placeholder={t("panel.config.tooltipFormatterPlaceholder")}
|
|
373
|
+
className="h-7"
|
|
374
|
+
/>
|
|
375
|
+
</label>
|
|
376
|
+
</>,
|
|
377
|
+
undefined,
|
|
378
|
+
{ groupKey: "chartTooltip", defaultOpen: false }
|
|
379
|
+
)}
|
|
380
|
+
{selectedChartType === "bar" ||
|
|
381
|
+
selectedChartType === "line" ||
|
|
382
|
+
selectedChartType === "area" ||
|
|
383
|
+
selectedChartType === "scatter" ? (
|
|
384
|
+
renderFieldGroup(
|
|
385
|
+
t("panel.config.groupAxes"),
|
|
386
|
+
<>
|
|
387
|
+
<div className="grid grid-cols-2 gap-2">
|
|
388
|
+
<label className="block">
|
|
389
|
+
<div className="mb-1">{t("panel.config.xAxisName")}</div>
|
|
390
|
+
<Input
|
|
391
|
+
value={selectedElement.chart?.xAxisName ?? ""}
|
|
392
|
+
onChange={(e) => updateSelectedChart({ xAxisName: e.target.value })}
|
|
393
|
+
placeholder={t("panel.config.xAxisNamePlaceholder")}
|
|
394
|
+
className="h-7"
|
|
395
|
+
/>
|
|
396
|
+
</label>
|
|
397
|
+
<label className="block">
|
|
398
|
+
<div className="mb-1">{t("panel.config.yAxisName")}</div>
|
|
399
|
+
<Input
|
|
400
|
+
value={selectedElement.chart?.yAxisName ?? ""}
|
|
401
|
+
onChange={(e) => updateSelectedChart({ yAxisName: e.target.value })}
|
|
402
|
+
placeholder={t("panel.config.yAxisNamePlaceholder")}
|
|
403
|
+
className="h-7"
|
|
404
|
+
/>
|
|
405
|
+
</label>
|
|
406
|
+
</div>
|
|
407
|
+
<div className="grid grid-cols-2 gap-2">
|
|
408
|
+
<label className="flex items-center gap-2">
|
|
409
|
+
<Checkbox
|
|
410
|
+
checked={selectedElement.chart?.xAxisTickShow ?? true}
|
|
411
|
+
className="h-4 w-4 border-2 border-foreground/80 bg-background ring-1 ring-foreground/40 data-[state=checked]:border-primary data-[state=checked]:ring-primary/40"
|
|
412
|
+
onCheckedChange={(checked) =>
|
|
413
|
+
updateSelectedChart({ xAxisTickShow: checked === true })
|
|
414
|
+
}
|
|
415
|
+
/>
|
|
416
|
+
<span>{t("panel.config.xAxisTick")}</span>
|
|
417
|
+
</label>
|
|
418
|
+
<label className="flex items-center gap-2">
|
|
419
|
+
<Checkbox
|
|
420
|
+
checked={selectedElement.chart?.yAxisTickShow ?? true}
|
|
421
|
+
className="h-4 w-4 border-2 border-foreground/80 bg-background ring-1 ring-foreground/40 data-[state=checked]:border-primary data-[state=checked]:ring-primary/40"
|
|
422
|
+
onCheckedChange={(checked) =>
|
|
423
|
+
updateSelectedChart({ yAxisTickShow: checked === true })
|
|
424
|
+
}
|
|
425
|
+
/>
|
|
426
|
+
<span>{t("panel.config.yAxisTick")}</span>
|
|
427
|
+
</label>
|
|
428
|
+
</div>
|
|
429
|
+
<div className="grid grid-cols-2 gap-2">
|
|
430
|
+
{renderColorField(
|
|
431
|
+
t("panel.config.xAxisTickColor"),
|
|
432
|
+
selectedElement.chart?.xAxisTickColor ?? "#94a3b8",
|
|
433
|
+
(next) => updateSelectedChart({ xAxisTickColor: next || "#94a3b8" })
|
|
434
|
+
)}
|
|
435
|
+
{renderColorField(
|
|
436
|
+
t("panel.config.yAxisTickColor"),
|
|
437
|
+
selectedElement.chart?.yAxisTickColor ?? "#94a3b8",
|
|
438
|
+
(next) => updateSelectedChart({ yAxisTickColor: next || "#94a3b8" })
|
|
439
|
+
)}
|
|
440
|
+
</div>
|
|
441
|
+
<div className="grid grid-cols-2 gap-2">
|
|
442
|
+
<label className="flex items-center gap-2">
|
|
443
|
+
<Checkbox
|
|
444
|
+
checked={selectedElement.chart?.xAxisSplitLineShow ?? false}
|
|
445
|
+
className="h-4 w-4 border-2 border-foreground/80 bg-background ring-1 ring-foreground/40 data-[state=checked]:border-primary data-[state=checked]:ring-primary/40"
|
|
446
|
+
onCheckedChange={(checked) =>
|
|
447
|
+
updateSelectedChart({ xAxisSplitLineShow: checked === true })
|
|
448
|
+
}
|
|
449
|
+
/>
|
|
450
|
+
<span>{t("panel.config.xAxisSplitLine")}</span>
|
|
451
|
+
</label>
|
|
452
|
+
<label className="flex items-center gap-2">
|
|
453
|
+
<Checkbox
|
|
454
|
+
checked={selectedElement.chart?.yAxisSplitLineShow ?? true}
|
|
455
|
+
className="h-4 w-4 border-2 border-foreground/80 bg-background ring-1 ring-foreground/40 data-[state=checked]:border-primary data-[state=checked]:ring-primary/40"
|
|
456
|
+
onCheckedChange={(checked) =>
|
|
457
|
+
updateSelectedChart({ yAxisSplitLineShow: checked === true })
|
|
458
|
+
}
|
|
459
|
+
/>
|
|
460
|
+
<span>{t("panel.config.yAxisSplitLine")}</span>
|
|
461
|
+
</label>
|
|
462
|
+
</div>
|
|
463
|
+
<div className="grid grid-cols-2 gap-2">
|
|
464
|
+
{renderColorField(
|
|
465
|
+
t("panel.config.xAxisSplitLineColor"),
|
|
466
|
+
selectedElement.chart?.xAxisSplitLineColor ?? "#e2e8f0",
|
|
467
|
+
(next) => updateSelectedChart({ xAxisSplitLineColor: next || "#e2e8f0" })
|
|
468
|
+
)}
|
|
469
|
+
{renderColorField(
|
|
470
|
+
t("panel.config.yAxisSplitLineColor"),
|
|
471
|
+
selectedElement.chart?.yAxisSplitLineColor ?? "#e2e8f0",
|
|
472
|
+
(next) => updateSelectedChart({ yAxisSplitLineColor: next || "#e2e8f0" })
|
|
473
|
+
)}
|
|
474
|
+
</div>
|
|
475
|
+
<div className="grid grid-cols-2 gap-2">
|
|
476
|
+
{renderColorField(
|
|
477
|
+
t("panel.config.xAxisLabelColor"),
|
|
478
|
+
selectedElement.chart?.xAxisLabelColor ?? "#64748b",
|
|
479
|
+
(next) => updateSelectedChart({ xAxisLabelColor: next || "#64748b" })
|
|
480
|
+
)}
|
|
481
|
+
{renderColorField(
|
|
482
|
+
t("panel.config.yAxisLabelColor"),
|
|
483
|
+
selectedElement.chart?.yAxisLabelColor ?? "#64748b",
|
|
484
|
+
(next) => updateSelectedChart({ yAxisLabelColor: next || "#64748b" })
|
|
485
|
+
)}
|
|
486
|
+
</div>
|
|
487
|
+
<div className="grid grid-cols-2 gap-2">
|
|
488
|
+
<label className="block">
|
|
489
|
+
<div className="mb-1">{t("panel.config.xAxisLabelFontSize")}</div>
|
|
490
|
+
<Input
|
|
491
|
+
type="number"
|
|
492
|
+
min={8}
|
|
493
|
+
max={48}
|
|
494
|
+
value={selectedElement.chart?.xAxisLabelFontSize ?? 10}
|
|
495
|
+
onChange={(e) =>
|
|
496
|
+
updateSelectedChart({
|
|
497
|
+
xAxisLabelFontSize: Math.max(8, Math.min(48, Number(e.target.value) || 10)),
|
|
498
|
+
})
|
|
499
|
+
}
|
|
500
|
+
className="h-7"
|
|
501
|
+
/>
|
|
502
|
+
</label>
|
|
503
|
+
<label className="block">
|
|
504
|
+
<div className="mb-1">{t("panel.config.yAxisLabelFontSize")}</div>
|
|
505
|
+
<Input
|
|
506
|
+
type="number"
|
|
507
|
+
min={8}
|
|
508
|
+
max={48}
|
|
509
|
+
value={selectedElement.chart?.yAxisLabelFontSize ?? 10}
|
|
510
|
+
onChange={(e) =>
|
|
511
|
+
updateSelectedChart({
|
|
512
|
+
yAxisLabelFontSize: Math.max(8, Math.min(48, Number(e.target.value) || 10)),
|
|
513
|
+
})
|
|
514
|
+
}
|
|
515
|
+
className="h-7"
|
|
516
|
+
/>
|
|
517
|
+
</label>
|
|
518
|
+
</div>
|
|
519
|
+
<div className="grid grid-cols-2 gap-2">
|
|
520
|
+
<label className="flex items-center gap-2">
|
|
521
|
+
<Checkbox
|
|
522
|
+
checked={selectedElement.chart?.xAxisLabelAutoEllipsis ?? false}
|
|
523
|
+
className="h-4 w-4 border-2 border-foreground/80 bg-background ring-1 ring-foreground/40 data-[state=checked]:border-primary data-[state=checked]:ring-primary/40"
|
|
524
|
+
onCheckedChange={(checked) =>
|
|
525
|
+
updateSelectedChart({ xAxisLabelAutoEllipsis: checked === true })
|
|
526
|
+
}
|
|
527
|
+
/>
|
|
528
|
+
<span>{t("panel.config.xAxisLabelAutoEllipsis")}</span>
|
|
529
|
+
</label>
|
|
530
|
+
<label className="flex items-center gap-2">
|
|
531
|
+
<Checkbox
|
|
532
|
+
checked={selectedElement.chart?.yAxisLabelAutoEllipsis ?? false}
|
|
533
|
+
className="h-4 w-4 border-2 border-foreground/80 bg-background ring-1 ring-foreground/40 data-[state=checked]:border-primary data-[state=checked]:ring-primary/40"
|
|
534
|
+
onCheckedChange={(checked) =>
|
|
535
|
+
updateSelectedChart({ yAxisLabelAutoEllipsis: checked === true })
|
|
536
|
+
}
|
|
537
|
+
/>
|
|
538
|
+
<span>{t("panel.config.yAxisLabelAutoEllipsis")}</span>
|
|
539
|
+
</label>
|
|
540
|
+
</div>
|
|
541
|
+
</>,
|
|
542
|
+
undefined,
|
|
543
|
+
{ groupKey: "chartAxes", defaultOpen: false }
|
|
544
|
+
)
|
|
545
|
+
) : null}
|
|
546
|
+
|
|
547
|
+
</>,
|
|
548
|
+
true,
|
|
549
|
+
[
|
|
550
|
+
t("panel.config.searchKwChart"),
|
|
551
|
+
"title",
|
|
552
|
+
"tooltip",
|
|
553
|
+
t("panel.config.searchKwXAxis"),
|
|
554
|
+
t("panel.config.searchKwYAxis"),
|
|
555
|
+
"axis",
|
|
556
|
+
"label",
|
|
557
|
+
t("panel.config.searchKwTick"),
|
|
558
|
+
t("panel.config.searchKwSplit"),
|
|
559
|
+
"render",
|
|
560
|
+
"svg",
|
|
561
|
+
"canvas",
|
|
562
|
+
]
|
|
563
|
+
)}
|
|
564
|
+
|
|
565
|
+
{renderSection(
|
|
566
|
+
"chartAdvanced",
|
|
567
|
+
t("panel.config.sectionChartAdvanced"),
|
|
568
|
+
<>
|
|
569
|
+
{renderFieldGroup(
|
|
570
|
+
t("panel.config.groupCommonForm"),
|
|
571
|
+
<div className="grid grid-cols-1 gap-2">
|
|
572
|
+
<div className="rounded-lg border border-border/60 bg-background/70 p-3">
|
|
573
|
+
<Collapsible
|
|
574
|
+
open={isSectionExpanded("chartAdvancedLayout", false)}
|
|
575
|
+
onOpenChange={(open) => setSectionExpanded("chartAdvancedLayout", open)}
|
|
576
|
+
>
|
|
577
|
+
<div className="mb-2 flex items-center gap-1.5">
|
|
578
|
+
<CollapsibleTrigger asChild>
|
|
579
|
+
<button
|
|
580
|
+
type="button"
|
|
581
|
+
className="flex h-5 w-5 items-center justify-center rounded text-[11px] hover:bg-accent"
|
|
582
|
+
aria-label={isSectionExpanded("chartAdvancedLayout", false) ? t("panel.config.collapseLayoutCoord") : t("panel.config.expandLayoutCoord")}
|
|
583
|
+
>
|
|
584
|
+
{isSectionExpanded("chartAdvancedLayout", false) ? "▾" : "▸"}
|
|
585
|
+
</button>
|
|
586
|
+
</CollapsibleTrigger>
|
|
587
|
+
<div className="text-[11px] font-medium text-muted-foreground">{t("panel.config.groupLayoutAndCoord")}</div>
|
|
588
|
+
</div>
|
|
589
|
+
<CollapsibleContent>
|
|
590
|
+
<div className="grid grid-cols-2 gap-2">
|
|
591
|
+
<label className="block space-y-1.5">
|
|
592
|
+
<div className={optionLabelTextClass}>{t("panel.config.gridLeftForm")}</div>
|
|
593
|
+
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.grid?.left ?? 28)} onChange={(e) => updateSelectedOptionForm({ grid: { left: Number(e.target.value) || 0 } })} />
|
|
594
|
+
</label>
|
|
595
|
+
<label className="block space-y-1.5">
|
|
596
|
+
<div className={optionLabelTextClass}>{t("panel.config.gridRightForm")}</div>
|
|
597
|
+
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.grid?.right ?? 10)} onChange={(e) => updateSelectedOptionForm({ grid: { right: Number(e.target.value) || 0 } })} />
|
|
598
|
+
</label>
|
|
599
|
+
<label className="block space-y-1.5">
|
|
600
|
+
<div className={optionLabelTextClass}>{t("panel.config.gridTopForm")}</div>
|
|
601
|
+
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.grid?.top ?? 30)} onChange={(e) => updateSelectedOptionForm({ grid: { top: Number(e.target.value) || 0 } })} />
|
|
602
|
+
</label>
|
|
603
|
+
<label className="block space-y-1.5">
|
|
604
|
+
<div className={optionLabelTextClass}>{t("panel.config.gridBottomForm")}</div>
|
|
605
|
+
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.grid?.bottom ?? 20)} onChange={(e) => updateSelectedOptionForm({ grid: { bottom: Number(e.target.value) || 0 } })} />
|
|
606
|
+
</label>
|
|
607
|
+
<label className="block space-y-1.5">
|
|
608
|
+
<div className={optionLabelTextClass}>{t("panel.config.legendPositionForm")}</div>
|
|
609
|
+
<Select value={String((selectedElement.chart?.option as any)?.legend?.top ?? "top")} onValueChange={(value) => updateSelectedOptionForm({ legend: { top: value } })}>
|
|
610
|
+
<SelectTrigger className={optionSelectTriggerClass}><SelectValue placeholder={t("panel.config.selectLegendPosition")} /></SelectTrigger>
|
|
611
|
+
<SelectContent>
|
|
612
|
+
<SelectItem value="top">{t("panel.config.legendTop")}</SelectItem>
|
|
613
|
+
<SelectItem value="bottom">{t("panel.config.legendBottom")}</SelectItem>
|
|
614
|
+
<SelectItem value="left">{t("panel.config.legendLeft")}</SelectItem>
|
|
615
|
+
<SelectItem value="right">{t("panel.config.legendRight")}</SelectItem>
|
|
616
|
+
</SelectContent>
|
|
617
|
+
</Select>
|
|
618
|
+
</label>
|
|
619
|
+
<label className="block space-y-1.5">
|
|
620
|
+
<div className={optionLabelTextClass}>{t("panel.config.legendOrientForm")}</div>
|
|
621
|
+
<Select value={String((selectedElement.chart?.option as any)?.legend?.orient ?? "horizontal")} onValueChange={(value) => updateSelectedOptionForm({ legend: { orient: value } })}>
|
|
622
|
+
<SelectTrigger className={optionSelectTriggerClass}><SelectValue placeholder={t("panel.config.selectLegendOrient")} /></SelectTrigger>
|
|
623
|
+
<SelectContent>
|
|
624
|
+
<SelectItem value="horizontal">{t("panel.config.legendHorizontal")}</SelectItem>
|
|
625
|
+
<SelectItem value="vertical">{t("panel.config.legendVertical")}</SelectItem>
|
|
626
|
+
</SelectContent>
|
|
627
|
+
</Select>
|
|
628
|
+
</label>
|
|
629
|
+
<label className="block space-y-1.5">
|
|
630
|
+
{renderOptionLabel(t("panel.config.xAxisMin"), "xAxis.min", t("panel.config.xAxisMinHint"))}
|
|
631
|
+
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.xAxis?.min ?? 0)} onChange={(e) => updateSelectedOptionForm({ xAxis: { min: Number(e.target.value) || 0 } })} />
|
|
632
|
+
</label>
|
|
633
|
+
<label className="block space-y-1.5">
|
|
634
|
+
{renderOptionLabel(t("panel.config.xAxisMax"), "xAxis.max", t("panel.config.xAxisMaxHint"))}
|
|
635
|
+
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.xAxis?.max ?? 100)} onChange={(e) => updateSelectedOptionForm({ xAxis: { max: Number(e.target.value) || 0 } })} />
|
|
636
|
+
</label>
|
|
637
|
+
<label className="block space-y-1.5">
|
|
638
|
+
{renderOptionLabel(t("panel.config.yAxisMin"), "yAxis.min", t("panel.config.yAxisMinHint"))}
|
|
639
|
+
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.yAxis?.min ?? 0)} onChange={(e) => updateSelectedOptionForm({ yAxis: { min: Number(e.target.value) || 0 } })} />
|
|
640
|
+
</label>
|
|
641
|
+
<label className="block space-y-1.5">
|
|
642
|
+
{renderOptionLabel(t("panel.config.yAxisMax"), "yAxis.max", t("panel.config.yAxisMaxHint"))}
|
|
643
|
+
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.yAxis?.max ?? 100)} onChange={(e) => updateSelectedOptionForm({ yAxis: { max: Number(e.target.value) || 0 } })} />
|
|
644
|
+
</label>
|
|
645
|
+
<label className="block space-y-1.5">
|
|
646
|
+
{renderOptionLabel(t("panel.config.xAxisLabelRotate"), "xAxis.axisLabel.rotate", t("panel.config.rotateUnitHint"))}
|
|
647
|
+
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.xAxis?.axisLabel?.rotate ?? 0)} onChange={(e) => updateSelectedOptionForm({ xAxis: { axisLabel: { rotate: Number(e.target.value) || 0 } } })} />
|
|
648
|
+
</label>
|
|
649
|
+
<label className="block space-y-1.5">
|
|
650
|
+
{renderOptionLabel(t("panel.config.yAxisLabelRotate"), "yAxis.axisLabel.rotate", t("panel.config.rotateUnitHint"))}
|
|
651
|
+
<Input type="number" className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.yAxis?.axisLabel?.rotate ?? 0)} onChange={(e) => updateSelectedOptionForm({ yAxis: { axisLabel: { rotate: Number(e.target.value) || 0 } } })} />
|
|
652
|
+
</label>
|
|
653
|
+
</div>
|
|
654
|
+
</CollapsibleContent>
|
|
655
|
+
</Collapsible>
|
|
656
|
+
</div>
|
|
657
|
+
<div className="rounded-lg border border-border/60 bg-background/70 p-3">
|
|
658
|
+
<div className="space-y-2">
|
|
659
|
+
<Collapsible
|
|
660
|
+
open={isSectionExpanded("chartAdvancedHighFreq", true)}
|
|
661
|
+
onOpenChange={(open) => setSectionExpanded("chartAdvancedHighFreq", open)}
|
|
662
|
+
>
|
|
663
|
+
<div className="mb-2 flex items-center gap-1.5">
|
|
664
|
+
<CollapsibleTrigger asChild>
|
|
665
|
+
<button
|
|
666
|
+
type="button"
|
|
667
|
+
className="flex h-5 w-5 items-center justify-center rounded text-[11px] hover:bg-accent"
|
|
668
|
+
aria-label={isSectionExpanded("chartAdvancedHighFreq", true) ? t("panel.config.collapseHighFreq") : t("panel.config.expandHighFreq")}
|
|
669
|
+
>
|
|
670
|
+
{isSectionExpanded("chartAdvancedHighFreq", true) ? "▾" : "▸"}
|
|
671
|
+
</button>
|
|
672
|
+
</CollapsibleTrigger>
|
|
673
|
+
<div className="text-[11px] font-medium text-muted-foreground">{t("panel.config.groupHighFreq")}</div>
|
|
674
|
+
</div>
|
|
675
|
+
<CollapsibleContent>
|
|
676
|
+
<div className="grid grid-cols-1 gap-2">
|
|
677
|
+
<label className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1.5">
|
|
678
|
+
<Checkbox className={optionCheckboxClass} checked={Boolean((selectedElement.chart?.option as any)?.legend?.show ?? true)} onCheckedChange={(checked) => updateSelectedOptionForm({ legend: { show: checked === true } })} />
|
|
679
|
+
{renderOptionLabel(t("panel.config.showLegend"), "legend.show", t("panel.config.showLegendHint"))}
|
|
680
|
+
</label>
|
|
681
|
+
<label className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1.5">
|
|
682
|
+
<Checkbox className={optionCheckboxClass} checked={Boolean((selectedElement.chart?.option as any)?.grid?.containLabel ?? false)} onCheckedChange={(checked) => updateSelectedOptionForm({ grid: { containLabel: checked === true } })} />
|
|
683
|
+
{renderOptionLabel(t("panel.config.gridContainLabel"), "grid.containLabel", t("panel.config.gridContainLabelHint"))}
|
|
684
|
+
</label>
|
|
685
|
+
<label className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1.5">
|
|
686
|
+
<Checkbox className={optionCheckboxClass} checked={Boolean(Array.isArray((selectedElement.chart?.option as any)?.dataZoom) && (selectedElement.chart?.option as any)?.dataZoom.some((z: any) => z?.type === "inside"))} onCheckedChange={(checked) => { const prev = Array.isArray((selectedElement.chart?.option as any)?.dataZoom) ? [...(selectedElement.chart?.option as any).dataZoom] : []; const next = checked ? [...prev.filter((z: any) => z?.type !== "inside"), { type: "inside" }] : prev.filter((z: any) => z?.type !== "inside"); updateSelectedOptionForm({ dataZoom: next }); }} />
|
|
687
|
+
{renderOptionLabel(t("panel.config.zoomInside"), "dataZoom[type=inside]", t("panel.config.zoomInsideHint"))}
|
|
688
|
+
</label>
|
|
689
|
+
<label className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1.5">
|
|
690
|
+
<Checkbox className={optionCheckboxClass} checked={Boolean(Array.isArray((selectedElement.chart?.option as any)?.dataZoom) && (selectedElement.chart?.option as any)?.dataZoom.some((z: any) => z?.type === "slider"))} onCheckedChange={(checked) => { const prev = Array.isArray((selectedElement.chart?.option as any)?.dataZoom) ? [...(selectedElement.chart?.option as any).dataZoom] : []; const next = checked ? [...prev.filter((z: any) => z?.type !== "slider"), { type: "slider" }] : prev.filter((z: any) => z?.type !== "slider"); updateSelectedOptionForm({ dataZoom: next }); }} />
|
|
691
|
+
{renderOptionLabel(t("panel.config.zoomSlider"), "dataZoom[type=slider]", t("panel.config.zoomSliderHint"))}
|
|
692
|
+
</label>
|
|
693
|
+
<label className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1.5">
|
|
694
|
+
<Checkbox className={optionCheckboxClass} checked={Boolean((selectedElement.chart?.option as any)?.animation ?? false)} onCheckedChange={(checked) => updateSelectedOptionForm({ animation: checked === true })} />
|
|
695
|
+
{renderOptionLabel(t("panel.config.enableAnimation"), "animation", t("panel.config.enableAnimationHint"))}
|
|
696
|
+
</label>
|
|
697
|
+
<label className="block space-y-1.5">
|
|
698
|
+
{renderOptionLabel(t("panel.config.animationDuration"), "animationDuration", t("panel.config.animationDurationHint"))}
|
|
699
|
+
<Input type="number" min={0} className={optionInputClass} value={Number((selectedElement.chart?.option as any)?.animationDuration ?? 300)} onChange={(e) => updateSelectedOptionForm({ animationDuration: Math.max(0, Number(e.target.value) || 0) })} />
|
|
700
|
+
</label>
|
|
701
|
+
</div>
|
|
702
|
+
</CollapsibleContent>
|
|
703
|
+
</Collapsible>
|
|
704
|
+
<Collapsible
|
|
705
|
+
open={isSectionExpanded("chartAdvancedAxisPointer", false)}
|
|
706
|
+
onOpenChange={(open) => setSectionExpanded("chartAdvancedAxisPointer", open)}
|
|
707
|
+
>
|
|
708
|
+
<div className="mb-2 flex items-center gap-1.5">
|
|
709
|
+
<CollapsibleTrigger asChild>
|
|
710
|
+
<button
|
|
711
|
+
type="button"
|
|
712
|
+
className="flex h-5 w-5 items-center justify-center rounded text-[11px] hover:bg-accent"
|
|
713
|
+
aria-label={isSectionExpanded("chartAdvancedAxisPointer", false) ? t("panel.config.collapseAxisPointer") : t("panel.config.expandAxisPointer")}
|
|
714
|
+
>
|
|
715
|
+
{isSectionExpanded("chartAdvancedAxisPointer", false) ? "▾" : "▸"}
|
|
716
|
+
</button>
|
|
717
|
+
</CollapsibleTrigger>
|
|
718
|
+
<div className="text-[11px] font-medium text-muted-foreground">{t("panel.config.groupAxisPointer")}</div>
|
|
719
|
+
</div>
|
|
720
|
+
<CollapsibleContent>
|
|
721
|
+
<div className="grid grid-cols-1 gap-2">
|
|
722
|
+
<label className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1.5">
|
|
723
|
+
<Checkbox className={optionCheckboxClass} checked={Boolean((selectedElement.chart?.option as any)?.axisPointer?.show ?? false)} onCheckedChange={(checked) => updateSelectedOptionForm({ axisPointer: { show: checked === true } })} />
|
|
724
|
+
{renderOptionLabel(t("panel.config.showAxisPointer"), "axisPointer.show", t("panel.config.showAxisPointerHint"))}
|
|
725
|
+
</label>
|
|
726
|
+
<label className="block space-y-1.5 rounded-md bg-muted/30 px-2 py-1.5">
|
|
727
|
+
{renderOptionLabel(t("panel.config.axisPointerType"), "axisPointer.type", t("panel.config.axisPointerTypeHint"))}
|
|
728
|
+
<Select value={String((selectedElement.chart?.option as any)?.axisPointer?.type ?? "line")} onValueChange={(value) => updateSelectedOptionForm({ axisPointer: { type: value } })}>
|
|
729
|
+
<SelectTrigger className={optionSelectTriggerClass}><SelectValue placeholder={t("panel.config.selectAxisPointerType")} /></SelectTrigger>
|
|
730
|
+
<SelectContent>
|
|
731
|
+
<SelectItem value="line">{t("panel.config.axisPointerLine")}</SelectItem>
|
|
732
|
+
<SelectItem value="shadow">{t("panel.config.axisPointerShadow")}</SelectItem>
|
|
733
|
+
<SelectItem value="cross">{t("panel.config.axisPointerCross")}</SelectItem>
|
|
734
|
+
</SelectContent>
|
|
735
|
+
</Select>
|
|
736
|
+
</label>
|
|
737
|
+
<label className="flex items-center gap-2 rounded-md bg-muted/30 px-2 py-1.5">
|
|
738
|
+
<Checkbox className={optionCheckboxClass} checked={Boolean((selectedElement.chart?.option as any)?.axisPointer?.snap ?? false)} onCheckedChange={(checked) => updateSelectedOptionForm({ axisPointer: { snap: checked === true } })} />
|
|
739
|
+
{renderOptionLabel(t("panel.config.axisPointerSnap"), "axisPointer.snap", t("panel.config.axisPointerSnapHint"))}
|
|
740
|
+
</label>
|
|
741
|
+
</div>
|
|
742
|
+
</CollapsibleContent>
|
|
743
|
+
</Collapsible>
|
|
744
|
+
</div>
|
|
745
|
+
</div>
|
|
746
|
+
</div>
|
|
747
|
+
)}
|
|
748
|
+
{renderFieldGroup(
|
|
749
|
+
t("panel.config.groupJsonAdvanced"),
|
|
750
|
+
<>
|
|
751
|
+
<label className="flex items-center gap-2 rounded-md bg-background/70 px-2 py-1.5">
|
|
752
|
+
<Checkbox
|
|
753
|
+
checked={isAdvancedOptionMode}
|
|
754
|
+
className="h-4 w-4 border-2 border-foreground/80 bg-background ring-1 ring-foreground/40 data-[state=checked]:border-primary data-[state=checked]:ring-primary/40"
|
|
755
|
+
onCheckedChange={(checked) => setIsAdvancedOptionMode(checked === true)}
|
|
756
|
+
/>
|
|
757
|
+
<span>{t("panel.config.enableAdvancedJson")}</span>
|
|
758
|
+
<ConfigHintIcon label={t("panel.config.advancedJsonHintLabel")}>
|
|
759
|
+
{t("panel.config.advancedJsonHint")}
|
|
760
|
+
</ConfigHintIcon>
|
|
761
|
+
</label>
|
|
762
|
+
{isAdvancedOptionMode ? (
|
|
763
|
+
<>
|
|
764
|
+
<Textarea
|
|
765
|
+
value={optionJsonText}
|
|
766
|
+
onChange={(e) => {
|
|
767
|
+
const next = e.target.value;
|
|
768
|
+
setOptionJsonText(next);
|
|
769
|
+
try {
|
|
770
|
+
const parsed = JSON.parse(next) as Record<string, unknown>;
|
|
771
|
+
updateSelectedChart({ option: parsed });
|
|
772
|
+
setOptionJsonError(null);
|
|
773
|
+
} catch {
|
|
774
|
+
setOptionJsonError(t("panel.config.jsonInvalid"));
|
|
775
|
+
}
|
|
776
|
+
}}
|
|
777
|
+
spellCheck={false}
|
|
778
|
+
className="h-44 font-mono text-[11px]"
|
|
779
|
+
/>
|
|
780
|
+
{optionJsonError ? (
|
|
781
|
+
<div className="rounded border border-destructive/40 bg-destructive/10 px-2 py-1.5 text-[11px] text-destructive">
|
|
782
|
+
{optionJsonError}
|
|
783
|
+
</div>
|
|
784
|
+
) : (
|
|
785
|
+
<div className="rounded border border-emerald-500/30 bg-emerald-500/10 px-2 py-1.5 text-[11px] text-emerald-700 dark:text-emerald-300">
|
|
786
|
+
{t("panel.config.jsonValidApplied")}
|
|
787
|
+
</div>
|
|
788
|
+
)}
|
|
789
|
+
</>
|
|
790
|
+
) : null}
|
|
791
|
+
</>
|
|
792
|
+
)}
|
|
793
|
+
</>,
|
|
794
|
+
false,
|
|
795
|
+
["json", "option", t("panel.config.searchKwAdvanced"), "echarts"]
|
|
796
|
+
)}
|
|
797
|
+
</>
|
|
798
|
+
);
|
|
799
|
+
}
|