@363045841yyt/klinechart 0.1.4 → 0.2.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.
- package/README.md +142 -243
- package/dist/components/IndicatorParams.vue.d.ts +28 -0
- package/dist/components/IndicatorSelector.vue.d.ts +10 -0
- package/dist/components/KLineChart.vue.d.ts +14 -17
- package/dist/components/MarkerTooltip.vue.d.ts +10 -0
- package/dist/core/chart.d.ts +84 -47
- package/dist/core/controller/interaction.d.ts +56 -18
- package/dist/core/layout/pane.d.ts +2 -0
- package/dist/core/marker/registry.d.ts +174 -0
- package/dist/core/paneRenderer.d.ts +7 -40
- package/dist/core/renderers/Indicator/boll.d.ts +28 -0
- package/dist/core/renderers/Indicator/bollLegend.d.ts +16 -0
- package/dist/core/renderers/Indicator/cci.d.ts +34 -0
- package/dist/core/renderers/Indicator/fastk.d.ts +34 -0
- package/dist/core/renderers/Indicator/index.d.ts +31 -0
- package/dist/core/renderers/Indicator/kst.d.ts +49 -0
- package/dist/core/renderers/Indicator/ma.d.ts +12 -0
- package/dist/core/renderers/Indicator/maLegend.d.ts +9 -0
- package/dist/core/renderers/Indicator/macd.d.ts +46 -0
- package/dist/core/renderers/Indicator/macdLegend.d.ts +10 -0
- package/dist/core/renderers/Indicator/mom.d.ts +34 -0
- package/dist/core/renderers/Indicator/rsi.d.ts +42 -0
- package/dist/core/renderers/Indicator/stoch.d.ts +43 -0
- package/dist/core/renderers/Indicator/wmsr.d.ts +34 -0
- package/dist/core/renderers/candle.d.ts +17 -4
- package/dist/core/renderers/crosshair.d.ts +13 -20
- package/dist/core/renderers/customMarkers.d.ts +6 -0
- package/dist/core/renderers/extremaMarkers.d.ts +3 -4
- package/dist/core/renderers/globalBorders.d.ts +8 -13
- package/dist/core/renderers/gridLines.d.ts +4 -3
- package/dist/core/renderers/lastPrice.d.ts +3 -3
- package/dist/core/renderers/paneTitle.d.ts +37 -10
- package/dist/core/renderers/subVolume.d.ts +7 -3
- package/dist/core/renderers/timeAxis.d.ts +9 -22
- package/dist/core/renderers/yAxis.d.ts +5 -12
- package/dist/core/scale/priceScale.d.ts +1 -0
- package/dist/core/theme/colors.d.ts +80 -0
- package/dist/core/utils/klineConfig.d.ts +28 -0
- package/dist/core/utils/tickCount.d.ts +7 -0
- package/dist/core/viewport/viewport.d.ts +5 -5
- package/dist/index.cjs +16 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +10540 -1064
- package/dist/klinechart.css +1 -1
- package/dist/plugin/ConfigManager.d.ts +31 -0
- package/dist/plugin/EventBus.d.ts +34 -0
- package/dist/plugin/HookSystem.d.ts +28 -0
- package/dist/plugin/PluginHost.d.ts +47 -0
- package/dist/plugin/PluginRegistry.d.ts +40 -0
- package/dist/plugin/index.d.ts +11 -0
- package/dist/plugin/rendererPluginManager.d.ts +73 -0
- package/dist/plugin/types.d.ts +185 -0
- package/dist/semantic/controller.d.ts +29 -0
- package/dist/semantic/drawShape.d.ts +14 -0
- package/dist/semantic/index.d.ts +8 -0
- package/dist/semantic/schema.json.d.ts +259 -0
- package/dist/semantic/types.d.ts +185 -0
- package/dist/semantic/validator.d.ts +42 -0
- package/dist/types/volumePrice.d.ts +26 -0
- package/dist/utils/kLineDraw/MA.d.ts +5 -5
- package/dist/utils/logger.d.ts +1 -0
- package/dist/utils/volumePrice.d.ts +54 -0
- package/package.json +11 -10
- package/dist/core/renderers/crosshairLabels.d.ts +0 -36
- package/dist/core/renderers/grid.d.ts +0 -6
- package/dist/core/renderers/ma.d.ts +0 -15
- package/dist/core/renderers/maLegend.d.ts +0 -19
- package/dist/core/renderers/paneBorder.d.ts +0 -26
- package/dist/core/renderers/paneSeparator.d.ts +0 -18
package/dist/klinechart.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
.kline-tooltip[data-v-95daa55c]{z-index:10;color:#000000c7;pointer-events:none;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);background:#ffffffeb;border:1px solid #0000001f;border-radius:8px;min-width:200px;max-width:260px;padding:10px 12px;font-size:12px;line-height:1.4;position:absolute;box-shadow:0 6px 18px #0000001f}.kline-tooltip__title[data-v-95daa55c]{justify-content:space-between;gap:10px;margin-bottom:6px;font-weight:600;display:flex}.kline-tooltip__grid[data-v-95daa55c]{grid-template-columns:1fr;gap:2px;display:grid}.kline-tooltip__grid .row[data-v-95daa55c]{justify-content:space-between;gap:10px;display:flex}.kline-tooltip__grid .row span[data-v-95daa55c]:first-child{color:#0000008f}.indicator-selector[data-v-
|
|
1
|
+
.kline-tooltip[data-v-95daa55c]{z-index:10;color:#000000c7;pointer-events:none;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);background:#ffffffeb;border:1px solid #0000001f;border-radius:8px;min-width:200px;max-width:260px;padding:10px 12px;font-size:12px;line-height:1.4;position:absolute;box-shadow:0 6px 18px #0000001f}.kline-tooltip__title[data-v-95daa55c]{justify-content:space-between;gap:10px;margin-bottom:6px;font-weight:600;display:flex}.kline-tooltip__grid[data-v-95daa55c]{grid-template-columns:1fr;gap:2px;display:grid}.kline-tooltip__grid .row[data-v-95daa55c]{justify-content:space-between;gap:10px;display:flex}.kline-tooltip__grid .row span[data-v-95daa55c]:first-child{color:#0000008f}.marker-tooltip[data-v-dd43da4f]{z-index:10;color:#000000c7;pointer-events:none;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);background:#ffffffeb;border:1px solid #0000001f;border-radius:8px;min-width:180px;max-width:260px;padding:10px 12px;font-size:12px;line-height:1.4;position:absolute;box-shadow:0 6px 18px #0000001f}.marker-tooltip__title[data-v-dd43da4f]{justify-content:space-between;gap:10px;margin-bottom:6px;font-weight:600;display:flex}.marker-tooltip__content[data-v-dd43da4f]{grid-template-columns:1fr;gap:2px;display:grid}.marker-tooltip__content .row[data-v-dd43da4f]{justify-content:space-between;gap:10px;display:flex}.marker-tooltip__content .row span[data-v-dd43da4f]:first-child{color:#0000008f}.params-overlay[data-v-730f2212]{-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:1000;background:#0000004d;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.indicator-params[data-v-730f2212]{background:#fff;border:1px solid #e0e0e0;border-radius:12px;width:90vw;min-width:340px;max-width:420px;overflow:hidden;box-shadow:0 8px 40px #00000026}.params-header[data-v-730f2212]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-left[data-v-730f2212]{align-items:baseline;gap:8px;display:flex}.header-right[data-v-730f2212]{align-items:center;gap:8px;display:flex}.params-title[data-v-730f2212]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.params-subtitle[data-v-730f2212]{color:#999;font-size:11px}.toggle-desc-btn[data-v-730f2212]{cursor:pointer;color:#888;background:#fff;border:1px solid #e0e0e0;border-radius:6px;justify-content:center;align-items:center;width:28px;height:28px;padding:0;transition:all .2s;display:flex}.toggle-desc-btn[data-v-730f2212]:hover{color:#555;background:#f0f0f0;border-color:#ccc}.toggle-desc-btn.active[data-v-730f2212]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.toggle-desc-btn svg[data-v-730f2212]{width:14px;height:14px}.params-close[data-v-730f2212]{cursor:pointer;color:#888;background:#fff;border:1px solid #e0e0e0;border-radius:6px;justify-content:center;align-items:center;width:26px;height:26px;padding:0;transition:background .15s,color .15s,border-color .15s;display:flex}.params-close[data-v-730f2212]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.params-close svg[data-v-730f2212]{width:13px;height:13px}.indicator-description[data-v-730f2212]{background:#f0f7ff;border-bottom:1px solid #d6e8f5;padding:12px 20px}.indicator-description p[data-v-730f2212]{color:#2c5282;margin:0;font-size:12px;line-height:1.6}.params-body[data-v-730f2212]{flex-direction:column;gap:10px;padding:16px 20px;display:flex}.param-item[data-v-730f2212]{background:#f8f8f8;border:1px solid #e8e8e8;border-radius:8px;padding:10px 14px;transition:border-color .2s}.param-item[data-v-730f2212]:has(.param-input:focus){border-color:#bbb}.param-item.has-desc[data-v-730f2212]{padding:10px 14px 8px}.param-header[data-v-730f2212]{justify-content:space-between;align-items:center;gap:16px;display:flex}.param-label[data-v-730f2212]{flex-direction:column;gap:3px;display:flex}.param-label-text[data-v-730f2212]{color:#333;font-size:13px;font-weight:500}.param-range[data-v-730f2212]{color:#999;font-size:11px}.param-description[data-v-730f2212]{color:#666;border-top:1px dashed #e0e0e0;margin-top:8px;padding-top:8px;font-size:11px;line-height:1.5}.input-wrapper[data-v-730f2212]{background:#fff;border:1px solid #d0d0d0;border-radius:7px;align-items:stretch;height:32px;transition:border-color .2s;display:flex;overflow:hidden}.input-wrapper[data-v-730f2212]:focus-within{border-color:#999}.stepper-btn[data-v-730f2212]{cursor:pointer;color:#666;background:#f0f0f0;border:none;flex-shrink:0;justify-content:center;align-items:center;width:28px;font-size:15px;font-weight:400;line-height:1;transition:background .15s,color .15s;display:flex}.stepper-btn[data-v-730f2212]:hover:not(:disabled){color:#333;background:#e0e0e0}.stepper-btn[data-v-730f2212]:disabled{color:#ccc;cursor:not-allowed}.param-input[data-v-730f2212]{text-align:center;color:#1a1a1a;appearance:textfield;background:0 0;border:none;border-left:1px solid #e8e8e8;border-right:1px solid #e8e8e8;width:60px;font-size:13px;font-weight:600}.param-input[data-v-730f2212]::-webkit-inner-spin-button{-webkit-appearance:none}.param-input[data-v-730f2212]::-webkit-outer-spin-button{-webkit-appearance:none}.param-input[data-v-730f2212]:focus{outline:none}.params-footer[data-v-730f2212]{background:#f8f8f8;border-top:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-right[data-v-730f2212]{gap:8px;display:flex}.params-btn[data-v-730f2212]{cursor:pointer;border:1px solid #0000;border-radius:7px;align-items:center;gap:5px;padding:6px 14px;font-size:13px;font-weight:500;line-height:1.4;transition:all .15s;display:flex}.params-btn svg[data-v-730f2212]{flex-shrink:0;width:12px;height:12px}.params-btn.reset[data-v-730f2212]{color:#666;background:0 0;border-color:#d0d0d0}.params-btn.reset[data-v-730f2212]:hover{color:#e74c3c;background:#e74c3c14;border-color:#c0392b}.params-btn.cancel[data-v-730f2212]{color:#666;background:0 0;border-color:#d0d0d0}.params-btn.cancel[data-v-730f2212]:hover{color:#333;background:#f0f0f0;border-color:#bbb}.params-btn.confirm[data-v-730f2212]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.params-btn.confirm[data-v-730f2212]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.params-btn.confirm[data-v-730f2212]:active{box-shadow:none;transform:translateY(0)}.overlay-enter-active[data-v-730f2212],.overlay-leave-active[data-v-730f2212]{transition:opacity .2s}.overlay-enter-from[data-v-730f2212],.overlay-leave-to[data-v-730f2212]{opacity:0}.modal-enter-active[data-v-730f2212]{transition:all .22s cubic-bezier(.34,1.56,.64,1)}.modal-leave-active[data-v-730f2212]{transition:all .16s ease-in}.modal-enter-from[data-v-730f2212]{opacity:0;transform:scale(.88)translateY(-16px)}.modal-leave-to[data-v-730f2212]{opacity:0;transform:scale(.94)translateY(8px)}.slide-enter-active[data-v-730f2212],.slide-leave-active[data-v-730f2212]{transition:all .2s;overflow:hidden}.slide-enter-from[data-v-730f2212],.slide-leave-to[data-v-730f2212]{opacity:0;max-height:0;margin-top:0;padding-top:0;padding-bottom:0}.indicator-selector[data-v-bd302de5]{width:80%;margin:20px;position:relative}.indicator-scroll-container[data-v-bd302de5]{white-space:nowrap;-webkit-overflow-scrolling:touch;scrollbar-width:none;justify-content:center;width:100%;display:flex;overflow:auto hidden}.indicator-scroll-container[data-v-bd302de5]::-webkit-scrollbar{display:none}.indicator-list[data-v-bd302de5]{gap:8px;padding:2px;display:flex}.indicator-item[data-v-bd302de5]{align-items:center;gap:4px;display:flex}.indicator-btn[data-v-bd302de5]{color:#666;cursor:pointer;white-space:nowrap;background:#fff;border:1px solid #e0e0e0;border-radius:16px;flex-shrink:0;align-items:center;gap:4px;padding:6px 16px;font-size:13px;font-weight:500;transition:all .45s cubic-bezier(.4,0,.2,1);display:flex}.indicator-btn[data-v-bd302de5]:hover{color:#333;background:#f8f8f8;border-color:#ccc}.indicator-btn.active[data-v-bd302de5]{color:#1a1a1a;background:#f8f8f8;border-color:#ccc}.indicator-btn.active[data-v-bd302de5]:hover{background:#f0f0f0;border-color:#bbb}.param-hint[data-v-bd302de5]{opacity:.85;font-size:11px}.settings-btn[data-v-bd302de5]{color:#999;cursor:pointer;background:#fff;border:1px solid #e0e0e0;border-radius:50%;justify-content:center;align-items:center;width:24px;height:24px;padding:0;font-size:12px;transition:all .2s;display:flex}.settings-btn[data-v-bd302de5]:hover{color:#333;background:#f8f8f8;border-color:#333}.chart-wrapper[data-v-379dcd6f]{flex-direction:column;justify-content:center;align-items:center;width:100%;height:100%;display:flex}.chart-container[data-v-379dcd6f]{scrollbar-width:none;-ms-overflow-style:none;-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;touch-action:none;width:95%;height:85%;position:relative;overflow:auto hidden}.chart-container[data-v-379dcd6f]::-webkit-scrollbar{display:none}.chart-container[data-v-379dcd6f]:hover{cursor:grab}.chart-container[data-v-379dcd6f]:active{cursor:grabbing}.scroll-content[data-v-379dcd6f]{height:100%;min-height:inherit;position:relative}.canvas-layer[data-v-379dcd6f]{pointer-events:none;position:sticky;top:0;left:0}.plot-canvas[data-v-379dcd6f]{display:block;position:absolute;top:0;left:0}.y-axis-canvas[data-v-379dcd6f]{display:block;position:absolute;top:0;right:0}.x-axis-canvas[data-v-379dcd6f]{display:block;position:absolute;left:0}
|
|
2
2
|
/*$vite$:1*/
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 配置管理器
|
|
3
|
+
*/
|
|
4
|
+
export declare class ConfigManager {
|
|
5
|
+
private configs;
|
|
6
|
+
private defaults;
|
|
7
|
+
/**
|
|
8
|
+
* 注册插件的默认配置
|
|
9
|
+
*/
|
|
10
|
+
registerDefaults(pluginName: string, defaults: Record<string, unknown>): void;
|
|
11
|
+
/**
|
|
12
|
+
* 获取配置
|
|
13
|
+
*/
|
|
14
|
+
get<K = unknown>(pluginName: string, key: string, defaultValue?: K): K;
|
|
15
|
+
/**
|
|
16
|
+
* 设置配置
|
|
17
|
+
*/
|
|
18
|
+
set(pluginName: string, key: string, value: unknown): void;
|
|
19
|
+
/**
|
|
20
|
+
* 批量设置配置
|
|
21
|
+
*/
|
|
22
|
+
setAll(pluginName: string, config: Record<string, unknown>): void;
|
|
23
|
+
/**
|
|
24
|
+
* 获取插件所有配置
|
|
25
|
+
*/
|
|
26
|
+
getAll(pluginName: string): Record<string, unknown>;
|
|
27
|
+
/**
|
|
28
|
+
* 清除插件配置
|
|
29
|
+
*/
|
|
30
|
+
clear(pluginName?: string): void;
|
|
31
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { EventHandler } from './types';
|
|
2
|
+
export declare class EventBus {
|
|
3
|
+
private listeners;
|
|
4
|
+
/**
|
|
5
|
+
* 订阅事件
|
|
6
|
+
*/
|
|
7
|
+
on<T = unknown>(event: string, handler: EventHandler<T>): void;
|
|
8
|
+
/**
|
|
9
|
+
* 取消订阅
|
|
10
|
+
*/
|
|
11
|
+
off<T = unknown>(event: string, handler: EventHandler<T>): void;
|
|
12
|
+
/**
|
|
13
|
+
* 发布事件
|
|
14
|
+
*/
|
|
15
|
+
emit<T = unknown>(event: string, data: T): void;
|
|
16
|
+
/**
|
|
17
|
+
* 订阅一次性事件
|
|
18
|
+
*
|
|
19
|
+
* 注册一个仅在事件首次触发时执行的回调。回调执行后会自动从监听队列中移除,
|
|
20
|
+
* 确保后续相同事件的 emit 不会再触发该逻辑。
|
|
21
|
+
*
|
|
22
|
+
* @param event - 事件名称
|
|
23
|
+
* @param handler - 待执行的回调函数
|
|
24
|
+
*/
|
|
25
|
+
once<T = unknown>(event: string, handler: EventHandler<T>): void;
|
|
26
|
+
/**
|
|
27
|
+
* 清除所有事件监听
|
|
28
|
+
*/
|
|
29
|
+
clear(): void;
|
|
30
|
+
/**
|
|
31
|
+
* 获取事件的监听器数量
|
|
32
|
+
*/
|
|
33
|
+
listenerCount(event: string): number;
|
|
34
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { HookFn } from './types';
|
|
2
|
+
export declare class HookSystem {
|
|
3
|
+
private hooks;
|
|
4
|
+
/**
|
|
5
|
+
* 注册钩子
|
|
6
|
+
*/
|
|
7
|
+
tap<T = unknown, R = unknown>(hookName: string, fn: HookFn<T, R>, priority?: number): void;
|
|
8
|
+
/**
|
|
9
|
+
* 移除钩子
|
|
10
|
+
*/
|
|
11
|
+
untap(hookName: string, fn: HookFn): void;
|
|
12
|
+
/**
|
|
13
|
+
* 触发钩子(异步)
|
|
14
|
+
*/
|
|
15
|
+
call<T = unknown, R = unknown>(hookName: string, context: T): Promise<R[]>;
|
|
16
|
+
/**
|
|
17
|
+
* 触发钩子(同步)
|
|
18
|
+
*/
|
|
19
|
+
callSync<T = unknown, R = unknown>(hookName: string, context: T): R[];
|
|
20
|
+
/**
|
|
21
|
+
* 清除所有钩子
|
|
22
|
+
*/
|
|
23
|
+
clear(): void;
|
|
24
|
+
/**
|
|
25
|
+
* 获取钩子数量
|
|
26
|
+
*/
|
|
27
|
+
hookCount(hookName: string): number;
|
|
28
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Plugin, PluginConfig, PluginHost, PluginState } from './types';
|
|
2
|
+
export declare class PluginHostImpl implements PluginHost {
|
|
3
|
+
private registry;
|
|
4
|
+
private eventBus;
|
|
5
|
+
private hookSystem;
|
|
6
|
+
private configManager;
|
|
7
|
+
private isDestroyed;
|
|
8
|
+
constructor();
|
|
9
|
+
readonly events: {
|
|
10
|
+
on: <T = unknown>(event: string, handler: (data: T) => void) => void;
|
|
11
|
+
off: <T = unknown>(event: string, handler: (data: T) => void) => void;
|
|
12
|
+
emit: <T = unknown>(event: string, data: T) => void;
|
|
13
|
+
once: <T = unknown>(event: string, handler: (data: T) => void) => void;
|
|
14
|
+
};
|
|
15
|
+
readonly hooks: {
|
|
16
|
+
tap: <T = unknown, R = unknown>(hookName: string, fn: (context: T) => R | Promise<R>, priority?: number) => void;
|
|
17
|
+
untap: (hookName: string, fn: (context: unknown) => unknown) => void;
|
|
18
|
+
call: <T = unknown, R = unknown>(hookName: string, context: T) => Promise<R[]>;
|
|
19
|
+
callSync: <T = unknown, R = unknown>(hookName: string, context: T) => R[];
|
|
20
|
+
};
|
|
21
|
+
getConfig<K = unknown>(pluginName: string, key: string, defaultValue?: K): K;
|
|
22
|
+
setConfig(pluginName: string, key: string, value: unknown): void;
|
|
23
|
+
getPlugin<T extends Plugin = Plugin>(name: string): T | undefined;
|
|
24
|
+
log(level: 'info' | 'warn' | 'error', message: string, ...args: unknown[]): void;
|
|
25
|
+
/**
|
|
26
|
+
* 安装插件
|
|
27
|
+
*/
|
|
28
|
+
use(plugin: Plugin, config?: PluginConfig): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* 移除插件
|
|
31
|
+
*/
|
|
32
|
+
remove(name: string): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* 获取所有插件
|
|
35
|
+
*/
|
|
36
|
+
getPlugins(): import('./types').PluginDescriptor[];
|
|
37
|
+
/**
|
|
38
|
+
* 获取插件状态
|
|
39
|
+
*/
|
|
40
|
+
getState(name: string): PluginState | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* 销毁宿主
|
|
43
|
+
*/
|
|
44
|
+
destroy(): Promise<void>;
|
|
45
|
+
private ensureNotDestroyed;
|
|
46
|
+
}
|
|
47
|
+
export declare function createPluginHost(): PluginHostImpl;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Plugin, PluginDescriptor, PluginState } from './types';
|
|
2
|
+
export declare class PluginRegistry {
|
|
3
|
+
private plugins;
|
|
4
|
+
/**
|
|
5
|
+
* 注册插件
|
|
6
|
+
*/
|
|
7
|
+
register(plugin: Plugin, config?: Record<string, unknown>): PluginDescriptor;
|
|
8
|
+
/**
|
|
9
|
+
* 注销插件
|
|
10
|
+
*/
|
|
11
|
+
unregister(name: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* 获取插件描述符
|
|
14
|
+
*/
|
|
15
|
+
get(name: string): PluginDescriptor | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* 获取插件实例
|
|
18
|
+
*/
|
|
19
|
+
getPlugin<T extends Plugin = Plugin>(name: string): T | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* 获取所有插件
|
|
22
|
+
*/
|
|
23
|
+
getAll(): PluginDescriptor[];
|
|
24
|
+
/**
|
|
25
|
+
* 获取所有已启用的插件
|
|
26
|
+
*/
|
|
27
|
+
getEnabled(): PluginDescriptor[];
|
|
28
|
+
/**
|
|
29
|
+
* 更新插件状态
|
|
30
|
+
*/
|
|
31
|
+
updateState(name: string, state: PluginState, error?: Error): void;
|
|
32
|
+
/**
|
|
33
|
+
* 检查插件是否存在
|
|
34
|
+
*/
|
|
35
|
+
has(name: string): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* 清除所有插件
|
|
38
|
+
*/
|
|
39
|
+
clear(): void;
|
|
40
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 插件系统入口
|
|
3
|
+
*/
|
|
4
|
+
export * from './types';
|
|
5
|
+
export { PluginRegistry } from './PluginRegistry';
|
|
6
|
+
export { PluginHostImpl, createPluginHost } from './PluginHost';
|
|
7
|
+
export { EventBus } from './EventBus';
|
|
8
|
+
export { HookSystem } from './HookSystem';
|
|
9
|
+
export { ConfigManager } from './ConfigManager';
|
|
10
|
+
export { RendererPluginManager } from './rendererPluginManager';
|
|
11
|
+
export type { RendererErrorEvent } from './rendererPluginManager';
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { RendererPlugin, RenderContext, PaneInfo, RendererPluginWithHost, PluginHost } from './types';
|
|
2
|
+
/** 渲染器错误事件(裁剪后,不含大数据) */
|
|
3
|
+
export interface RendererErrorEvent {
|
|
4
|
+
name: string;
|
|
5
|
+
error: {
|
|
6
|
+
message: string;
|
|
7
|
+
stack?: string;
|
|
8
|
+
};
|
|
9
|
+
paneId: string;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 渲染器插件管理器
|
|
14
|
+
*
|
|
15
|
+
* 启用状态优先级:
|
|
16
|
+
* 1. setEnabled() 运行时设置的状态(enabledState 中存在)
|
|
17
|
+
* 2. 插件初始 enabled 字段
|
|
18
|
+
* 3. 默认启用(enabled !== false)
|
|
19
|
+
*/
|
|
20
|
+
export declare class RendererPluginManager {
|
|
21
|
+
private plugins;
|
|
22
|
+
private pluginHost;
|
|
23
|
+
private enabledState;
|
|
24
|
+
private groupCache;
|
|
25
|
+
private mergedCache;
|
|
26
|
+
private knownPaneIds;
|
|
27
|
+
private cacheInvalid;
|
|
28
|
+
private onInvalidate;
|
|
29
|
+
/** 设置重绘回调(由 Chart 注入) */
|
|
30
|
+
setInvalidateCallback(cb: () => void): void;
|
|
31
|
+
/** 设置 PluginHost(用于支持 RendererPluginWithHost) */
|
|
32
|
+
setPluginHost(host: PluginHost): void;
|
|
33
|
+
/** 添加已知的 paneId */
|
|
34
|
+
addKnownPaneId(paneId: string): void;
|
|
35
|
+
/** 移除 paneId */
|
|
36
|
+
removeKnownPaneId(paneId: string): void;
|
|
37
|
+
/** 获取所有已知的 paneId */
|
|
38
|
+
getKnownPaneIds(): string[];
|
|
39
|
+
/** 注册渲染器插件 */
|
|
40
|
+
register(plugin: RendererPlugin | RendererPluginWithHost): void;
|
|
41
|
+
/** 移除渲染器插件 */
|
|
42
|
+
unregister(name: string): void;
|
|
43
|
+
/** 清空所有插件 */
|
|
44
|
+
clear(): void;
|
|
45
|
+
/**
|
|
46
|
+
* 归并两个已排序数组 O(n)
|
|
47
|
+
* 优先级相同时,pane 专属渲染器(a)先于 global 渲染器(b)
|
|
48
|
+
*/
|
|
49
|
+
private mergeSorted;
|
|
50
|
+
/** 重建缓存(统一管理所有缓存逻辑) */
|
|
51
|
+
private rebuildCache;
|
|
52
|
+
/** 获取指定 pane 的渲染器(已缓存,无穿透) */
|
|
53
|
+
getRenderers(paneId: string): RendererPlugin[];
|
|
54
|
+
/** 渲染指定 pane(带错误隔离) */
|
|
55
|
+
render(paneId: string, context: RenderContext): RendererErrorEvent[];
|
|
56
|
+
/** 渲染指定名称的插件(带错误隔离,用于系统渲染器) */
|
|
57
|
+
renderPlugin(name: string, context: RenderContext): RendererErrorEvent[];
|
|
58
|
+
/** 启用/禁用渲染器(修改独立状态,不影响原始插件对象) */
|
|
59
|
+
setEnabled(name: string, enabled: boolean): void;
|
|
60
|
+
/** 更新配置(自动触发重绘) */
|
|
61
|
+
updateConfig(name: string, config: Record<string, unknown>): boolean;
|
|
62
|
+
/** 获取所有渲染器插件 */
|
|
63
|
+
getAllPlugins(): RendererPlugin[];
|
|
64
|
+
/** 获取指定渲染器 */
|
|
65
|
+
getPlugin<T extends RendererPlugin = RendererPlugin>(name: string): T | undefined;
|
|
66
|
+
/** 通知数据更新(跳过禁用的插件) */
|
|
67
|
+
notifyDataUpdate(data: unknown[], range: {
|
|
68
|
+
start: number;
|
|
69
|
+
end: number;
|
|
70
|
+
}): void;
|
|
71
|
+
/** 通知尺寸变化 */
|
|
72
|
+
notifyResize(paneId: string, pane: PaneInfo): void;
|
|
73
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 插件系统核心类型定义
|
|
3
|
+
*/
|
|
4
|
+
/** 插件生命周期状态 */
|
|
5
|
+
export declare enum PluginState {
|
|
6
|
+
Registered = "registered",
|
|
7
|
+
Installed = "installed",
|
|
8
|
+
Error = "error"
|
|
9
|
+
}
|
|
10
|
+
/** 插件配置 */
|
|
11
|
+
export interface PluginConfig {
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
priority?: number;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
/** 插件元信息 */
|
|
17
|
+
export interface PluginMeta {
|
|
18
|
+
name: string;
|
|
19
|
+
version: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
author?: string;
|
|
22
|
+
}
|
|
23
|
+
/** 插件接口 */
|
|
24
|
+
export interface Plugin extends PluginMeta {
|
|
25
|
+
/** 安装插件 */
|
|
26
|
+
install(host: PluginHost, config?: Record<string, unknown>): void | Promise<void>;
|
|
27
|
+
/** 卸载插件 */
|
|
28
|
+
uninstall?(): void | Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
/** 插件描述符(注册时使用) */
|
|
31
|
+
export interface PluginDescriptor {
|
|
32
|
+
plugin: Plugin;
|
|
33
|
+
config?: PluginConfig;
|
|
34
|
+
state: PluginState;
|
|
35
|
+
error?: Error;
|
|
36
|
+
}
|
|
37
|
+
/** Hook 函数类型 */
|
|
38
|
+
export type HookFn<T = unknown, R = unknown> = (context: T) => R | Promise<R>;
|
|
39
|
+
/** Hook 描述符 */
|
|
40
|
+
export interface HookDescriptor<T = unknown, R = unknown> {
|
|
41
|
+
name: string;
|
|
42
|
+
fn: HookFn<T, R>;
|
|
43
|
+
priority: number;
|
|
44
|
+
}
|
|
45
|
+
/** 事件处理器 */
|
|
46
|
+
export type EventHandler<T = unknown> = (data: T) => void;
|
|
47
|
+
/** 插件宿主接口(暴露给插件使用的 API) */
|
|
48
|
+
export interface PluginHost {
|
|
49
|
+
/** 事件总线 */
|
|
50
|
+
readonly events: {
|
|
51
|
+
on<T = unknown>(event: string, handler: EventHandler<T>): void;
|
|
52
|
+
off<T = unknown>(event: string, handler: EventHandler<T>): void;
|
|
53
|
+
emit<T = unknown>(event: string, data: T): void;
|
|
54
|
+
once<T = unknown>(event: string, handler: EventHandler<T>): void;
|
|
55
|
+
};
|
|
56
|
+
/** Hook 系统 */
|
|
57
|
+
readonly hooks: {
|
|
58
|
+
tap<T = unknown, R = unknown>(hookName: string, fn: HookFn<T, R>, priority?: number): void;
|
|
59
|
+
untap(hookName: string, fn: HookFn): void;
|
|
60
|
+
call<T = unknown, R = unknown>(hookName: string, context: T): Promise<R[]>;
|
|
61
|
+
callSync<T = unknown, R = unknown>(hookName: string, context: T): R[];
|
|
62
|
+
};
|
|
63
|
+
/** 获取配置 */
|
|
64
|
+
getConfig<K = unknown>(pluginName: string, key: string, defaultValue?: K): K;
|
|
65
|
+
/** 设置配置 */
|
|
66
|
+
setConfig(pluginName: string, key: string, value: unknown): void;
|
|
67
|
+
/** 获取其他插件 */
|
|
68
|
+
getPlugin<T extends Plugin = Plugin>(name: string): T | undefined;
|
|
69
|
+
/** 日志工具 */
|
|
70
|
+
log(level: 'info' | 'warn' | 'error', message: string, ...args: unknown[]): void;
|
|
71
|
+
}
|
|
72
|
+
/** Pane 信息接口 */
|
|
73
|
+
export interface PaneInfo {
|
|
74
|
+
id: string;
|
|
75
|
+
top: number;
|
|
76
|
+
height: number;
|
|
77
|
+
yAxis: {
|
|
78
|
+
priceToY(price: number): number;
|
|
79
|
+
yToPrice(y: number): number;
|
|
80
|
+
getPaddingTop(): number;
|
|
81
|
+
getPaddingBottom(): number;
|
|
82
|
+
};
|
|
83
|
+
priceRange: {
|
|
84
|
+
maxPrice: number;
|
|
85
|
+
minPrice: number;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 创建 PaneInfo 的只读包装
|
|
90
|
+
*
|
|
91
|
+
* 设计决策:
|
|
92
|
+
* - 使用 Readonly<T> 类型标注而非 Object.freeze,避免热路径上的运行时开销
|
|
93
|
+
* - yAxis 方法通过闭包包装,隔离原始函数引用
|
|
94
|
+
* - 依赖团队代码规范约束插件行为,而非运行时强制
|
|
95
|
+
*/
|
|
96
|
+
export declare function wrapPaneInfo(pane: {
|
|
97
|
+
id: string;
|
|
98
|
+
top: number;
|
|
99
|
+
height: number;
|
|
100
|
+
yAxis: PaneInfo['yAxis'];
|
|
101
|
+
priceRange: PaneInfo['priceRange'];
|
|
102
|
+
}): Readonly<PaneInfo>;
|
|
103
|
+
/** 渲染上下文 */
|
|
104
|
+
/** MarkerManager 接口(用于 RenderContext) */
|
|
105
|
+
export interface MarkerManagerLike {
|
|
106
|
+
getCustomMarkers(): unknown[];
|
|
107
|
+
setCustomMarkerPosition(id: string, x: number, y: number, size: number, shape: string): void;
|
|
108
|
+
}
|
|
109
|
+
export interface RenderContext {
|
|
110
|
+
ctx: CanvasRenderingContext2D;
|
|
111
|
+
pane: PaneInfo;
|
|
112
|
+
data: unknown[];
|
|
113
|
+
range: {
|
|
114
|
+
start: number;
|
|
115
|
+
end: number;
|
|
116
|
+
};
|
|
117
|
+
scrollLeft: number;
|
|
118
|
+
kWidth: number;
|
|
119
|
+
kGap: number;
|
|
120
|
+
dpr: number;
|
|
121
|
+
paneWidth: number;
|
|
122
|
+
kLinePositions: number[];
|
|
123
|
+
markerManager?: MarkerManagerLike;
|
|
124
|
+
yAxisCtx?: CanvasRenderingContext2D;
|
|
125
|
+
xAxisCtx?: CanvasRenderingContext2D;
|
|
126
|
+
borderCtx?: CanvasRenderingContext2D;
|
|
127
|
+
}
|
|
128
|
+
/** 全局 Pane ID(渲染到所有 pane) */
|
|
129
|
+
export declare const GLOBAL_PANE_ID: unique symbol;
|
|
130
|
+
/** 优先级推荐范围 */
|
|
131
|
+
export declare const RENDERER_PRIORITY: {
|
|
132
|
+
readonly SYSTEM_YAXIS: -20;
|
|
133
|
+
readonly SYSTEM_XAXIS: -20;
|
|
134
|
+
readonly BACKGROUND: 0;
|
|
135
|
+
readonly GRID: 10;
|
|
136
|
+
readonly INDICATOR: 30;
|
|
137
|
+
readonly MAIN: 50;
|
|
138
|
+
readonly OVERLAY: 80;
|
|
139
|
+
readonly FOREGROUND: 100;
|
|
140
|
+
readonly SYSTEM_BORDER: 120;
|
|
141
|
+
readonly SYSTEM_CROSSHAIR: 150;
|
|
142
|
+
};
|
|
143
|
+
/** 渲染器插件接口(独立定义,不继承 Plugin) */
|
|
144
|
+
export interface RendererPlugin {
|
|
145
|
+
/** 唯一标识 */
|
|
146
|
+
readonly name: string;
|
|
147
|
+
/** 版本号 */
|
|
148
|
+
readonly version?: string;
|
|
149
|
+
/** 描述 */
|
|
150
|
+
readonly description?: string;
|
|
151
|
+
/** 调试用显示名称 */
|
|
152
|
+
readonly debugName?: string;
|
|
153
|
+
/** 渲染目标 pane('main' | 'sub' | GLOBAL_PANE_ID 表示所有) */
|
|
154
|
+
paneId: string | symbol;
|
|
155
|
+
/** 渲染优先级(数字越大越后渲染) */
|
|
156
|
+
priority: number;
|
|
157
|
+
/** 是否启用(仅作为初始值,运行时状态由 Manager 管理) */
|
|
158
|
+
enabled?: boolean;
|
|
159
|
+
/**
|
|
160
|
+
* 是否为系统渲染器
|
|
161
|
+
* 系统渲染器不会通过 getRenderers() 返回,只能通过 renderPlugin() 单独渲染
|
|
162
|
+
* 用于时间轴、全局边框等需要单独控制渲染时机的场景
|
|
163
|
+
*/
|
|
164
|
+
isSystem?: boolean;
|
|
165
|
+
/** 渲染方法 */
|
|
166
|
+
draw(context: RenderContext): void;
|
|
167
|
+
/** 数据更新时回调 */
|
|
168
|
+
onDataUpdate?(data: unknown[], range: {
|
|
169
|
+
start: number;
|
|
170
|
+
end: number;
|
|
171
|
+
}): void;
|
|
172
|
+
/** 容器尺寸变化时回调 */
|
|
173
|
+
onResize?(pane: PaneInfo): void;
|
|
174
|
+
/** 获取配置 */
|
|
175
|
+
getConfig?(): Record<string, unknown>;
|
|
176
|
+
/** 设置配置 */
|
|
177
|
+
setConfig?(config: Record<string, unknown>): void;
|
|
178
|
+
/** 卸载时清理资源 */
|
|
179
|
+
onUninstall?(): void;
|
|
180
|
+
}
|
|
181
|
+
/** 带插件系统能力的渲染器(可选) */
|
|
182
|
+
export interface RendererPluginWithHost extends RendererPlugin {
|
|
183
|
+
/** 安装时获取 PluginHost 访问权限 */
|
|
184
|
+
onInstall?(host: PluginHost): void;
|
|
185
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Chart } from '../core/chart';
|
|
2
|
+
import { SemanticChartConfig, ApplyResult } from './types';
|
|
3
|
+
/** 状态事件类型 */
|
|
4
|
+
export type SemanticEventType = 'config:loading' | 'config:ready' | 'config:error';
|
|
5
|
+
export declare class SemanticChartController {
|
|
6
|
+
private chart;
|
|
7
|
+
private validator;
|
|
8
|
+
private events;
|
|
9
|
+
constructor(chart: Chart);
|
|
10
|
+
/**
|
|
11
|
+
* 应用语义化配置
|
|
12
|
+
*/
|
|
13
|
+
applyConfig(config: SemanticChartConfig): Promise<ApplyResult>;
|
|
14
|
+
/**
|
|
15
|
+
* 订阅状态事件
|
|
16
|
+
*/
|
|
17
|
+
on(event: SemanticEventType, handler: (data?: unknown) => void): void;
|
|
18
|
+
/**
|
|
19
|
+
* 取消订阅
|
|
20
|
+
*/
|
|
21
|
+
off(event: SemanticEventType, handler: (data?: unknown) => void): void;
|
|
22
|
+
private doApplyConfig;
|
|
23
|
+
private applyIndicators;
|
|
24
|
+
private applyMAIndicator;
|
|
25
|
+
private applyBOLLIndicator;
|
|
26
|
+
private applySubIndicator;
|
|
27
|
+
private applyMarkers;
|
|
28
|
+
private applyChartOptions;
|
|
29
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { MarkerShapeType, MarkerStyle, MarkerLabel } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* 绘制标记形状
|
|
4
|
+
*/
|
|
5
|
+
export declare function drawShape(ctx: CanvasRenderingContext2D, shape: MarkerShapeType, x: number, y: number, size: number, style: MarkerStyle): void;
|
|
6
|
+
/**
|
|
7
|
+
* 绘制文本标注
|
|
8
|
+
* @param isAboveMarker 标记是否在K线上方(true → 文字在标记上方,false → 文字在标记下方)
|
|
9
|
+
*/
|
|
10
|
+
export declare function drawLabel(ctx: CanvasRenderingContext2D, label: MarkerLabel, x: number, y: number, markerSize: number, style: MarkerStyle, isAboveMarker?: boolean): void;
|
|
11
|
+
/**
|
|
12
|
+
* 点击测试(判断点是否在形状内)
|
|
13
|
+
*/
|
|
14
|
+
export declare function hitTestShape(mx: number, my: number, shape: MarkerShapeType, x: number, y: number, size: number): boolean;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 语义化图表配置模块
|
|
3
|
+
* 用于 Agent 通过 JSON 控制图表渲染
|
|
4
|
+
*/
|
|
5
|
+
export type { SemanticChartConfig, DataConfig, IndicatorsConfig, MainIndicatorConfig, SubIndicatorConfig, SubIndicatorType, MAParams, BOLLParams, MarkersConfig, CustomMarker, MarkerShapeType, MarkerStyle, MarkerLabel, LegendConfig, ChartOptions, ThemeConfig, ApplyResult, ValidationResult, SecurityResult, } from './types';
|
|
6
|
+
export { SemanticChartController, type SemanticEventType } from './controller';
|
|
7
|
+
export { SemanticConfigValidator, sanitizeParams, sanitizeColor, validateColor, validateSymbol, } from './validator';
|
|
8
|
+
export { drawShape, drawLabel, hitTestShape } from './drawShape';
|