@uoa-css-lab/duckscatter 1.3.0

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.
Files changed (83) hide show
  1. package/.github/dependabot.yml +42 -0
  2. package/.github/workflows/ci.yaml +111 -0
  3. package/.github/workflows/release.yml +55 -0
  4. package/.prettierrc +11 -0
  5. package/LICENSE +22 -0
  6. package/README.md +250 -0
  7. package/dist/data/data-layer.d.ts +169 -0
  8. package/dist/data/data-layer.js +402 -0
  9. package/dist/data/index.d.ts +2 -0
  10. package/dist/data/index.js +2 -0
  11. package/dist/data/repository.d.ts +48 -0
  12. package/dist/data/repository.js +109 -0
  13. package/dist/diagnostics.d.ts +27 -0
  14. package/dist/diagnostics.js +71 -0
  15. package/dist/errors.d.ts +22 -0
  16. package/dist/errors.js +58 -0
  17. package/dist/event-emitter.d.ts +62 -0
  18. package/dist/event-emitter.js +82 -0
  19. package/dist/index.d.ts +12 -0
  20. package/dist/index.js +13 -0
  21. package/dist/renderer/gpu-layer.d.ts +204 -0
  22. package/dist/renderer/gpu-layer.js +611 -0
  23. package/dist/renderer/index.d.ts +3 -0
  24. package/dist/renderer/index.js +3 -0
  25. package/dist/renderer/shaders.d.ts +13 -0
  26. package/dist/renderer/shaders.js +216 -0
  27. package/dist/renderer/webgpu-context.d.ts +20 -0
  28. package/dist/renderer/webgpu-context.js +88 -0
  29. package/dist/scatter-plot.d.ts +210 -0
  30. package/dist/scatter-plot.js +450 -0
  31. package/dist/types.d.ts +171 -0
  32. package/dist/types.js +1 -0
  33. package/dist/ui/index.d.ts +1 -0
  34. package/dist/ui/index.js +1 -0
  35. package/dist/ui/label-layer.d.ts +176 -0
  36. package/dist/ui/label-layer.js +488 -0
  37. package/docs/image.png +0 -0
  38. package/eslint.config.js +72 -0
  39. package/examples/next/README.md +36 -0
  40. package/examples/next/app/components/ColorExpressionInput.tsx +41 -0
  41. package/examples/next/app/components/ControlPanel.tsx +30 -0
  42. package/examples/next/app/components/HoverControlPanel.tsx +69 -0
  43. package/examples/next/app/components/HoverInfoDisplay.tsx +40 -0
  44. package/examples/next/app/components/LabelFilterInput.tsx +46 -0
  45. package/examples/next/app/components/LabelList.tsx +106 -0
  46. package/examples/next/app/components/PointAlphaSlider.tsx +21 -0
  47. package/examples/next/app/components/PointLimitSlider.tsx +23 -0
  48. package/examples/next/app/components/PointList.tsx +105 -0
  49. package/examples/next/app/components/PointSizeScaleSlider.tsx +22 -0
  50. package/examples/next/app/components/ScatterPlotCanvas.tsx +150 -0
  51. package/examples/next/app/components/SearchBox.tsx +46 -0
  52. package/examples/next/app/components/Slider.tsx +76 -0
  53. package/examples/next/app/components/StatsDisplay.tsx +15 -0
  54. package/examples/next/app/components/TimeFilterSlider.tsx +169 -0
  55. package/examples/next/app/context/ScatterPlotContext.tsx +402 -0
  56. package/examples/next/app/favicon.ico +0 -0
  57. package/examples/next/app/globals.css +23 -0
  58. package/examples/next/app/layout.tsx +35 -0
  59. package/examples/next/app/page.tsx +15 -0
  60. package/examples/next/eslint.config.mjs +18 -0
  61. package/examples/next/next.config.ts +7 -0
  62. package/examples/next/package-lock.json +6572 -0
  63. package/examples/next/package.json +27 -0
  64. package/examples/next/postcss.config.mjs +7 -0
  65. package/examples/next/scripts/generate_labels.py +167 -0
  66. package/examples/next/tsconfig.json +34 -0
  67. package/package.json +43 -0
  68. package/src/data/data-layer.ts +515 -0
  69. package/src/data/index.ts +2 -0
  70. package/src/data/repository.ts +146 -0
  71. package/src/diagnostics.ts +108 -0
  72. package/src/errors.ts +69 -0
  73. package/src/event-emitter.ts +88 -0
  74. package/src/index.ts +40 -0
  75. package/src/renderer/gpu-layer.ts +757 -0
  76. package/src/renderer/index.ts +3 -0
  77. package/src/renderer/shaders.ts +219 -0
  78. package/src/renderer/webgpu-context.ts +98 -0
  79. package/src/scatter-plot.ts +533 -0
  80. package/src/types.ts +218 -0
  81. package/src/ui/index.ts +1 -0
  82. package/src/ui/label-layer.ts +648 -0
  83. package/tsconfig.json +19 -0
@@ -0,0 +1,216 @@
1
+ /**
2
+ * 散布図レンダリング用WGSLシェーダーコード
3
+ */
4
+ /**
5
+ * ビューポート境界とLODに基づいて可視ポイントをフィルタリングするコンピュートシェーダー
6
+ * ワークグループローカルのアトミック操作を使用してグローバルアトミックの競合を軽減
7
+ */
8
+ export const filterComputeShader = `
9
+ struct Point {
10
+ x: f32,
11
+ y: f32,
12
+ color: u32,
13
+ size: f32,
14
+ }
15
+
16
+ struct FilterUniforms {
17
+ worldBoundsMin: vec2<f32>,
18
+ worldBoundsMax: vec2<f32>,
19
+ lodThreshold: u32,
20
+ totalPoints: u32,
21
+ activeFilterMask: u32,
22
+ _padding: u32,
23
+ filterRangeMin: vec4<f32>,
24
+ filterRangeMax: vec4<f32>,
25
+ }
26
+
27
+ @group(0) @binding(0) var<storage, read> allPoints: array<Point>;
28
+ @group(0) @binding(1) var<storage, read_write> visibleIndices: array<u32>;
29
+ @group(0) @binding(2) var<storage, read_write> counter: atomic<u32>;
30
+ @group(0) @binding(3) var<uniform> uniforms: FilterUniforms;
31
+ @group(0) @binding(4) var<storage, read> filterColumns: array<vec4<f32>>;
32
+
33
+ var<workgroup> localCount: atomic<u32>;
34
+ var<workgroup> localIndices: array<u32, 256>;
35
+ var<workgroup> globalOffset: u32;
36
+
37
+ fn pcgHash(input: u32) -> u32 {
38
+ let state = input * 747796405u + 2891336453u;
39
+ let word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
40
+ return (word >> 22u) ^ word;
41
+ }
42
+
43
+ @compute @workgroup_size(256)
44
+ fn main(
45
+ @builtin(global_invocation_id) globalId: vec3<u32>,
46
+ @builtin(local_invocation_id) localId: vec3<u32>
47
+ ) {
48
+ let idx = globalId.x;
49
+ let lid = localId.x;
50
+
51
+ if (lid == 0u) {
52
+ atomicStore(&localCount, 0u);
53
+ }
54
+ workgroupBarrier();
55
+
56
+ var myLocalSlot: u32 = 0xFFFFFFFFu;
57
+ if (idx < uniforms.totalPoints) {
58
+ let hash = pcgHash(idx);
59
+ var isVisible = hash <= uniforms.lodThreshold;
60
+
61
+ if (isVisible) {
62
+ let point = allPoints[idx];
63
+
64
+ isVisible = point.x >= uniforms.worldBoundsMin.x && point.x <= uniforms.worldBoundsMax.x &&
65
+ point.y >= uniforms.worldBoundsMin.y && point.y <= uniforms.worldBoundsMax.y;
66
+ }
67
+
68
+ if (isVisible && uniforms.activeFilterMask != 0u) {
69
+ let filterData = filterColumns[idx];
70
+
71
+ if ((uniforms.activeFilterMask & 1u) != 0u) {
72
+ isVisible = isVisible &&
73
+ filterData.x >= uniforms.filterRangeMin.x &&
74
+ filterData.x <= uniforms.filterRangeMax.x;
75
+ }
76
+ if ((uniforms.activeFilterMask & 2u) != 0u) {
77
+ isVisible = isVisible &&
78
+ filterData.y >= uniforms.filterRangeMin.y &&
79
+ filterData.y <= uniforms.filterRangeMax.y;
80
+ }
81
+ if ((uniforms.activeFilterMask & 4u) != 0u) {
82
+ isVisible = isVisible &&
83
+ filterData.z >= uniforms.filterRangeMin.z &&
84
+ filterData.z <= uniforms.filterRangeMax.z;
85
+ }
86
+ if ((uniforms.activeFilterMask & 8u) != 0u) {
87
+ isVisible = isVisible &&
88
+ filterData.w >= uniforms.filterRangeMin.w &&
89
+ filterData.w <= uniforms.filterRangeMax.w;
90
+ }
91
+ }
92
+
93
+ if (isVisible) {
94
+ myLocalSlot = atomicAdd(&localCount, 1u);
95
+ localIndices[myLocalSlot] = idx;
96
+ }
97
+ }
98
+ workgroupBarrier();
99
+
100
+ let count = atomicLoad(&localCount);
101
+ if (lid == 0u && count > 0u) {
102
+ globalOffset = atomicAdd(&counter, count);
103
+ }
104
+ workgroupBarrier();
105
+
106
+ if (lid < count) {
107
+ visibleIndices[globalOffset + lid] = localIndices[lid];
108
+ }
109
+ }
110
+ `;
111
+ /**
112
+ * カウンターから間接描画バッファを更新するコンピュートシェーダー
113
+ */
114
+ export const updateIndirectShader = `
115
+ struct DrawIndexedIndirect {
116
+ indexCount: u32,
117
+ instanceCount: u32,
118
+ firstIndex: u32,
119
+ baseVertex: u32,
120
+ firstInstance: u32,
121
+ }
122
+
123
+ @group(0) @binding(0) var<storage, read> counter: u32;
124
+ @group(0) @binding(1) var<storage, read_write> indirect: DrawIndexedIndirect;
125
+
126
+ @compute @workgroup_size(1)
127
+ fn main() {
128
+ indirect.indexCount = 6u;
129
+ indirect.instanceCount = counter;
130
+ indirect.firstIndex = 0u;
131
+ indirect.baseVertex = 0u;
132
+ indirect.firstInstance = 0u;
133
+ }
134
+ `;
135
+ export const scatterVertexShader = `
136
+ struct Point {
137
+ x: f32,
138
+ y: f32,
139
+ color: u32,
140
+ size: f32,
141
+ }
142
+
143
+ struct Uniforms {
144
+ viewMatrix: mat4x4<f32>,
145
+ zoomScale: f32,
146
+ viewportWidth: f32,
147
+ viewportHeight: f32,
148
+ pointAlpha: f32,
149
+ pointSizeScale: f32,
150
+ _padding1: f32,
151
+ _padding2: f32,
152
+ _padding3: f32,
153
+ }
154
+
155
+ struct VertexOutput {
156
+ @builtin(position) position: vec4<f32>,
157
+ @location(0) color: vec4<f32>,
158
+ @location(1) pointCoord: vec2<f32>,
159
+ }
160
+
161
+ @group(0) @binding(0) var<uniform> uniforms: Uniforms;
162
+ @group(0) @binding(1) var<storage, read> allPoints: array<Point>;
163
+ @group(0) @binding(2) var<storage, read> visibleIndices: array<u32>;
164
+
165
+ fn unpackColor(argb: u32) -> vec4<f32> {
166
+ let a = f32((argb >> 24u) & 0xFFu) / 255.0;
167
+ let r = f32((argb >> 16u) & 0xFFu) / 255.0;
168
+ let g = f32((argb >> 8u) & 0xFFu) / 255.0;
169
+ let b = f32(argb & 0xFFu) / 255.0;
170
+ return vec4<f32>(r, g, b, a);
171
+ }
172
+
173
+ @vertex
174
+ fn vertexMain(
175
+ @location(0) quadPosition: vec2<f32>,
176
+ @builtin(instance_index) instanceIdx: u32
177
+ ) -> VertexOutput {
178
+ var output: VertexOutput;
179
+
180
+ let pointIdx = visibleIndices[instanceIdx];
181
+ let point = allPoints[pointIdx];
182
+
183
+ let clipPos = uniforms.viewMatrix * vec4<f32>(point.x, point.y, 0.0, 1.0);
184
+
185
+ let pixelToClipX = 2.0 / uniforms.viewportWidth;
186
+ let pixelToClipY = 2.0 / uniforms.viewportHeight;
187
+ let zoomScale = uniforms.zoomScale;
188
+
189
+ let scaledSize = point.size * uniforms.pointSizeScale;
190
+ let offsetClip = vec2<f32>(
191
+ quadPosition.x * scaledSize * pixelToClipX * zoomScale,
192
+ quadPosition.y * scaledSize * pixelToClipY * zoomScale
193
+ );
194
+
195
+ output.position = clipPos + vec4<f32>(offsetClip, 0.0, 0.0);
196
+ output.color = unpackColor(point.color);
197
+
198
+ output.pointCoord = (quadPosition + 1.0) * 0.5;
199
+
200
+ return output;
201
+ }
202
+
203
+ @fragment
204
+ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
205
+ let d = input.pointCoord - vec2<f32>(0.5);
206
+ let distSq = dot(d, d);
207
+
208
+ if (distSq > 0.25) {
209
+ discard;
210
+ }
211
+
212
+ let alpha = smoothstep(0.25, 0.23, distSq);
213
+
214
+ return vec4<f32>(input.color.rgb, input.color.a * alpha * uniforms.pointAlpha);
215
+ }
216
+ `;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * WebGPUコンテキストを管理するクラス
3
+ */
4
+ export declare class WebGPUContext {
5
+ /** GPUデバイスインスタンス */
6
+ device: GPUDevice | null;
7
+ /** キャンバスのWebGPUコンテキスト */
8
+ context: GPUCanvasContext | null;
9
+ /** テクスチャフォーマット */
10
+ format: GPUTextureFormat;
11
+ /**
12
+ * WebGPUを初期化する
13
+ * @param canvas 描画対象のHTMLCanvasElement
14
+ */
15
+ initialize(canvas: HTMLCanvasElement): Promise<void>;
16
+ /**
17
+ * WebGPUリソースを破棄する
18
+ */
19
+ destroy(): void;
20
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * WebGPUコンテキストを管理するクラス
3
+ */
4
+ export class WebGPUContext {
5
+ constructor() {
6
+ /** GPUデバイスインスタンス */
7
+ this.device = null;
8
+ /** キャンバスのWebGPUコンテキスト */
9
+ this.context = null;
10
+ /** テクスチャフォーマット */
11
+ this.format = 'bgra8unorm';
12
+ }
13
+ /**
14
+ * WebGPUを初期化する
15
+ * @param canvas 描画対象のHTMLCanvasElement
16
+ */
17
+ async initialize(canvas) {
18
+ if (!navigator.gpu) {
19
+ throw new Error('WebGPU is not supported in this browser. ' +
20
+ 'Please use Chrome 113+, Edge 113+, or Safari 18+ with WebGPU enabled.');
21
+ }
22
+ let adapter = null;
23
+ try {
24
+ adapter = await navigator.gpu.requestAdapter({
25
+ powerPreference: 'high-performance',
26
+ });
27
+ }
28
+ catch {
29
+ // empty
30
+ }
31
+ if (!adapter) {
32
+ try {
33
+ adapter = await navigator.gpu.requestAdapter();
34
+ }
35
+ catch {
36
+ // empty
37
+ }
38
+ }
39
+ if (!adapter) {
40
+ try {
41
+ adapter = await navigator.gpu.requestAdapter({
42
+ powerPreference: 'low-power',
43
+ });
44
+ }
45
+ catch {
46
+ // empty
47
+ }
48
+ }
49
+ if (!adapter) {
50
+ throw new Error('Failed to get GPU adapter. Possible reasons:\n' +
51
+ '1. WebGPU is disabled in browser flags\n' +
52
+ '2. Your GPU is blocklisted\n' +
53
+ '3. GPU drivers need updating\n' +
54
+ '4. Running in a virtual machine without GPU access\n\n' +
55
+ 'For Chrome/Edge: Visit chrome://gpu to check WebGPU status\n' +
56
+ 'For Safari: Ensure macOS Sonoma 14.4+ with Safari 18+');
57
+ }
58
+ try {
59
+ this.device = await adapter.requestDevice();
60
+ }
61
+ catch (e) {
62
+ throw new Error(`Failed to get GPU device: ${e}`);
63
+ }
64
+ if (!this.device) {
65
+ throw new Error('Failed to get GPU device: Device is null');
66
+ }
67
+ this.context = canvas.getContext('webgpu');
68
+ if (!this.context) {
69
+ throw new Error('Failed to get WebGPU context from canvas');
70
+ }
71
+ this.format = navigator.gpu.getPreferredCanvasFormat();
72
+ this.context.configure({
73
+ device: this.device,
74
+ format: this.format,
75
+ alphaMode: 'premultiplied',
76
+ });
77
+ }
78
+ /**
79
+ * WebGPUリソースを破棄する
80
+ */
81
+ destroy() {
82
+ if (this.device) {
83
+ this.device.destroy();
84
+ this.device = null;
85
+ }
86
+ this.context = null;
87
+ }
88
+ }
@@ -0,0 +1,210 @@
1
+ import type { Label, ScatterPlotOptions, ScatterPlotEventMap, PointId, LabelIdentifier } from './types.js';
2
+ import { type ParquetData } from './data/index.js';
3
+ import { EventEmitter } from './event-emitter.js';
4
+ /**
5
+ * WebGPUを使用して散布図を描画するメインクラス
6
+ *
7
+ * このクラスは3つの異なるレイヤーのファサード/コーディネーターとして機能する:
8
+ * - DataLayer: データ取得とクエリ管理を担当
9
+ * - GpuLayer: WebGPUレンダリングと変換を管理(LODと境界計算もGPU側で実行)
10
+ * - LabelLayer: ラベル用の2Dキャンバスオーバーレイを担当
11
+ */
12
+ export declare class ScatterPlot extends EventEmitter<ScatterPlotEventMap> {
13
+ private readonly dataLayer;
14
+ private gpuLayer;
15
+ private labelLayer;
16
+ private readonly dataUrl;
17
+ private readonly labelUrl?;
18
+ /** GPUフィルターカラム名→インデックスのマッピング */
19
+ private gpuFilterColumnMapping;
20
+ /**
21
+ * ScatterPlotインスタンスを作成する
22
+ * @param options 散布図の設定オプション
23
+ */
24
+ constructor(options: ScatterPlotOptions);
25
+ /**
26
+ * WebGPUを初期化し、レンダリングリソースを作成する
27
+ */
28
+ initialize(): Promise<void>;
29
+ /**
30
+ * データ変更時のハンドラ(sizeSql, colorSql, whereConditions変更時)
31
+ */
32
+ private handleDataChanged;
33
+ /**
34
+ * URLからラベルデータを読み込み、エラーハンドリングを行う
35
+ * @param url ラベルデータのURL
36
+ */
37
+ private loadLabelsFromUrl;
38
+ /**
39
+ * 初期化エラーをScatterPlotError型に分類する
40
+ * @param e 発生した例外
41
+ * @returns 分類されたScatterPlotErrorオブジェクト
42
+ */
43
+ private categorizeInitError;
44
+ /**
45
+ * エラーイベントを発行する。リスナーが登録されていない場合はconsole.warnに出力する
46
+ * @param error 発行するエラーオブジェクト
47
+ */
48
+ private emitError;
49
+ /**
50
+ * 散布図をレンダリングする(GPUレイヤーとラベルの両方)
51
+ */
52
+ render(): void;
53
+ /**
54
+ * GeoJSONデータからラベルを読み込む
55
+ * @param geojsonData ラベルポイントを含むGeoJSON FeatureCollection
56
+ */
57
+ loadLabels(geojsonData: any): void;
58
+ /**
59
+ * プロットデータを更新して再レンダリングする
60
+ * @param options 更新する設定オプション
61
+ */
62
+ update(options: Partial<ScatterPlotOptions>): Promise<void>;
63
+ /**
64
+ * キャンバスをリサイズして再レンダリングする
65
+ * @param width 新しい幅(ピクセル)
66
+ * @param height 新しい高さ(ピクセル)
67
+ */
68
+ resize(width: number, height: number): void;
69
+ /**
70
+ * ズームレベルを設定する
71
+ * @param zoom ズームレベル(1.0 = 通常、>1.0 = ズームイン、<1.0 = ズームアウト)
72
+ */
73
+ setZoom(zoom: number): void;
74
+ /**
75
+ * 現在のズームレベルを取得する
76
+ * @returns 現在のズームレベル
77
+ */
78
+ getZoom(): number;
79
+ /**
80
+ * 指定した倍率でズームインする
81
+ * @param factor ズーム倍率(デフォルト: 1.2)
82
+ */
83
+ zoomIn(factor?: number): void;
84
+ /**
85
+ * 指定した倍率でズームアウトする
86
+ * @param factor ズーム倍率(デフォルト: 1.2)
87
+ */
88
+ zoomOut(factor?: number): void;
89
+ /**
90
+ * 指定した画面座標を中心にズームする
91
+ * @param newZoom 新しいズームレベル
92
+ * @param screenX 画面X座標(キャンバスピクセル単位)
93
+ * @param screenY 画面Y座標(キャンバスピクセル単位)
94
+ */
95
+ zoomToPoint(newZoom: number, screenX: number, screenY: number): void;
96
+ /**
97
+ * ズームとパンをデフォルト値にリセットする
98
+ */
99
+ resetView(): void;
100
+ /**
101
+ * パンオフセットを設定する
102
+ * @param x 正規化座標でのX方向パンオフセット(-1から1)
103
+ * @param y 正規化座標でのY方向パンオフセット(-1から1)
104
+ */
105
+ setPan(x: number, y: number): void;
106
+ /**
107
+ * 現在のパンオフセットを取得する
108
+ * @returns x, y座標を含むオブジェクト
109
+ */
110
+ getPan(): {
111
+ x: number;
112
+ y: number;
113
+ };
114
+ /**
115
+ * 指定した差分だけパンする
116
+ * @param dx 正規化座標でのX方向の差分
117
+ * @param dy 正規化座標でのY方向の差分
118
+ */
119
+ pan(dx: number, dy: number): void;
120
+ /**
121
+ * ラベルレイヤーのビュー変換をGPUレイヤーと同期する
122
+ */
123
+ private syncLabelViewTransform;
124
+ /**
125
+ * ラベルレイヤーからのポイントホバーイベントを処理する
126
+ * @param data ホバー中のポイントデータ(またはnull)
127
+ * @param userCallback ユーザー定義のコールバック
128
+ */
129
+ private handlePointHover;
130
+ /**
131
+ * GpuWhereConditionをGpuLayer用の形式に変換する
132
+ * @param conditions ユーザー指定のGPUフィルター条件
133
+ * @returns GpuLayer用のフィルター条件配列
134
+ */
135
+ private convertGpuWhereConditions;
136
+ /**
137
+ * カスタムSQLクエリを実行する
138
+ * @param query 実行するSQLクエリ文字列またはtoStringメソッドを持つオブジェクト
139
+ * @returns クエリ結果のParquetData
140
+ */
141
+ runQuery(query: string | {
142
+ toString: () => string;
143
+ }): Promise<ParquetData | undefined>;
144
+ /**
145
+ * 読み込まれたすべてのラベルを取得する
146
+ * @returns ラベルの配列
147
+ */
148
+ getLabels(): Label[];
149
+ /**
150
+ * IDを指定してプログラム的にポイントをホバー状態にする
151
+ * @param pointId ホバーするポイントのidColumn値
152
+ * @returns ポイントが見つかりホバーされた場合はtrue、そうでない場合はfalse
153
+ */
154
+ setPointHover(pointId: PointId): Promise<boolean>;
155
+ /**
156
+ * ポイントのホバー状態をクリアする
157
+ */
158
+ clearPointHover(): void;
159
+ /**
160
+ * 現在ホバー中のポイントデータを取得する
161
+ * @returns ホバー中の場合はポイントデータ、そうでない場合はnull
162
+ */
163
+ getHoveredPoint(): {
164
+ row: any[];
165
+ columns: string[];
166
+ } | null;
167
+ /**
168
+ * プログラム的にラベルをホバー状態にする
169
+ * @param identifier ラベル識別子(テキストまたはクラスターで識別)
170
+ * @returns ラベルが見つかりホバーされた場合はtrue、そうでない場合はfalse
171
+ */
172
+ setLabelHover(identifier: LabelIdentifier): boolean;
173
+ /**
174
+ * ラベルのホバー状態をクリアする
175
+ */
176
+ clearLabelHover(): void;
177
+ /**
178
+ * 現在ホバー中のラベルを取得する
179
+ * @returns ホバー中の場合はラベル、そうでない場合はnull
180
+ */
181
+ getHoveredLabel(): Label | null;
182
+ /**
183
+ * すべてのホバー状態をクリアする(ポイントとラベルの両方)
184
+ */
185
+ clearAllHover(): void;
186
+ /**
187
+ * グローバル透明度を設定する
188
+ * @param alpha 透明度 (0.0-1.0)
189
+ */
190
+ setPointAlpha(alpha: number): void;
191
+ /**
192
+ * 現在のグローバル透明度を取得する
193
+ * @returns 現在の透明度値 (0.0-1.0)
194
+ */
195
+ getPointAlpha(): number;
196
+ /**
197
+ * グローバルサイズスケールを設定する
198
+ * @param scale サイズスケール (0.01以上)
199
+ */
200
+ setPointSizeScale(scale: number): void;
201
+ /**
202
+ * 現在のグローバルサイズスケールを取得する
203
+ * @returns 現在のサイズスケール値
204
+ */
205
+ getPointSizeScale(): number;
206
+ /**
207
+ * リソースを破棄する
208
+ */
209
+ destroy(): Promise<void>;
210
+ }