@363045841yyt/klinechart 0.7.5-alpha.2 → 0.7.5
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/dist/components/IndicatorSelector.vue.d.ts.map +1 -1
- package/dist/components/KLineChart.vue.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +649 -625
- package/dist/klinechart.css +1 -1
- package/package.json +1 -1
- package/src/components/IndicatorSelector.vue +63 -61
- package/src/components/KLineChart.vue +73 -141
- package/src/index.ts +72 -0
|
@@ -118,7 +118,7 @@ import KLineTooltip from './KLineTooltip.vue'
|
|
|
118
118
|
import MarkerTooltip from './MarkerTooltip.vue'
|
|
119
119
|
import IndicatorSelector from './IndicatorSelector.vue'
|
|
120
120
|
import DrawingStyleToolbar from './DrawingStyleToolbar.vue'
|
|
121
|
-
import { Chart, type PaneSpec } from '@363045841yyt/klinechart-core/engine/chart'
|
|
121
|
+
import { Chart, type PaneSpec, type IndicatorInstance, type SubPaneInfo } from '@363045841yyt/klinechart-core/engine/chart'
|
|
122
122
|
import type { KLineData } from '@363045841yyt/klinechart-core/types/price'
|
|
123
123
|
import {
|
|
124
124
|
createChartStore,
|
|
@@ -639,40 +639,23 @@ function addSubPane(
|
|
|
639
639
|
|
|
640
640
|
const mergedParams = params ?? getDefaultParams(indicatorId)
|
|
641
641
|
|
|
642
|
-
// 使用高层 Facade API
|
|
642
|
+
// 使用高层 Facade API 创建副图指标(Signal 订阅自动同步本地状态和 scheduleDraw)
|
|
643
643
|
const paneId = chartRef.value?.addIndicator(indicatorId, 'sub', mergedParams)
|
|
644
644
|
if (!paneId) return false
|
|
645
645
|
|
|
646
646
|
// 创建 paneTitle 渲染器(UI 层职责)
|
|
647
647
|
mountSubPaneTitle(paneId, indicatorId)
|
|
648
648
|
|
|
649
|
-
// 更新本地状态
|
|
650
|
-
subPanes.value.push({
|
|
651
|
-
id: paneId,
|
|
652
|
-
indicatorId,
|
|
653
|
-
params: mergedParams,
|
|
654
|
-
})
|
|
655
|
-
|
|
656
|
-
scheduleRender()
|
|
657
649
|
return true
|
|
658
650
|
}
|
|
659
651
|
|
|
660
652
|
// 移除副图(使用高层 Facade API)
|
|
661
653
|
function removeSubPane(paneId: string): void {
|
|
662
|
-
const index = subPanes.value.findIndex((p) => p.id === paneId)
|
|
663
|
-
if (index === -1) return
|
|
664
|
-
|
|
665
|
-
const pane = subPanes.value[index]
|
|
666
|
-
if (!pane) return
|
|
667
|
-
|
|
668
654
|
// 移除 paneTitle 渲染器
|
|
669
655
|
unmountSubPaneTitle(paneId)
|
|
670
656
|
|
|
671
|
-
// 使用高层 Facade API
|
|
657
|
+
// 使用高层 Facade API 移除指标(Signal 订阅自动同步本地状态)
|
|
672
658
|
chartRef.value?.removeIndicator(paneId)
|
|
673
|
-
|
|
674
|
-
// 更新本地状态
|
|
675
|
-
subPanes.value.splice(index, 1)
|
|
676
659
|
}
|
|
677
660
|
|
|
678
661
|
// 清除所有副图(使用高层 Facade API)
|
|
@@ -683,32 +666,22 @@ function clearAllSubPanes(): void {
|
|
|
683
666
|
unmountSubPaneTitle(pane.id)
|
|
684
667
|
}
|
|
685
668
|
|
|
686
|
-
//
|
|
687
|
-
subPanes.value = []
|
|
669
|
+
// 清空本地状态(Signal 订阅自动同步 subPanes,只需要清理 UI 层状态)
|
|
688
670
|
subPaneCounters.clear()
|
|
689
671
|
paneTitleRendererNames.clear()
|
|
690
672
|
}
|
|
691
673
|
|
|
692
674
|
// 从语义化配置初始化指标状态(单向数据流:config → chart)
|
|
675
|
+
// Signal 订阅会自动同步本地状态,此处只需调用 Chart API
|
|
693
676
|
function initIndicatorsFromConfig(): void {
|
|
694
677
|
const config = props.semanticConfig
|
|
695
678
|
const chart = chartRef.value
|
|
696
679
|
if (!chart) return
|
|
697
680
|
|
|
698
|
-
// 初始化主图指标 - 直接调用Chart API
|
|
699
681
|
const mainIndicators = config.indicators?.main
|
|
700
682
|
if (mainIndicators) {
|
|
701
683
|
for (const indicator of mainIndicators) {
|
|
702
684
|
if (indicator.enabled) {
|
|
703
|
-
// 同步Vue状态(用于UI展示)
|
|
704
|
-
if (!mainActiveIndicators.value.includes(indicator.type)) {
|
|
705
|
-
mainActiveIndicators.value.push(indicator.type)
|
|
706
|
-
}
|
|
707
|
-
// 保存参数
|
|
708
|
-
if (indicator.params) {
|
|
709
|
-
indicatorParams.value[indicator.type] = indicator.params as Record<string, unknown>
|
|
710
|
-
}
|
|
711
|
-
// 启用指标(Chart内部管理渲染器)
|
|
712
685
|
chart.enableMainIndicator(
|
|
713
686
|
indicator.type,
|
|
714
687
|
indicator.params as Record<string, number | boolean | string>,
|
|
@@ -716,51 +689,12 @@ function initIndicatorsFromConfig(): void {
|
|
|
716
689
|
}
|
|
717
690
|
}
|
|
718
691
|
}
|
|
719
|
-
|
|
720
|
-
// 副图指标参数由 syncSubPanesFromChart 处理
|
|
721
692
|
}
|
|
722
693
|
|
|
723
|
-
// 监听主图指标参数变化,同步到Chart(状态由Chart管理,Vue只同步参数)
|
|
724
|
-
watch(
|
|
725
|
-
[activeIndicators, indicatorParams],
|
|
726
|
-
([indicators]) => {
|
|
727
|
-
const chart = chartRef.value
|
|
728
|
-
if (!chart) return
|
|
729
|
-
|
|
730
|
-
// 只更新mainIndicatorLegend的配置(用于图例显示)
|
|
731
|
-
// 渲染器的启用/禁用由Chart内部管理
|
|
732
|
-
chart.updateRendererConfig('mainIndicatorLegend', {
|
|
733
|
-
indicators: {
|
|
734
|
-
MA: {
|
|
735
|
-
enabled: indicators.includes('MA'),
|
|
736
|
-
params: indicatorParams.value['MA'] || {},
|
|
737
|
-
},
|
|
738
|
-
BOLL: {
|
|
739
|
-
enabled: indicators.includes('BOLL'),
|
|
740
|
-
params: indicatorParams.value['BOLL'] || {},
|
|
741
|
-
},
|
|
742
|
-
EXPMA: {
|
|
743
|
-
enabled: indicators.includes('EXPMA'),
|
|
744
|
-
params: indicatorParams.value['EXPMA'] || {},
|
|
745
|
-
},
|
|
746
|
-
ENE: {
|
|
747
|
-
enabled: indicators.includes('ENE'),
|
|
748
|
-
params: indicatorParams.value['ENE'] || {},
|
|
749
|
-
},
|
|
750
|
-
},
|
|
751
|
-
})
|
|
752
|
-
|
|
753
|
-
scheduleRender()
|
|
754
|
-
},
|
|
755
|
-
{ deep: true },
|
|
756
|
-
)
|
|
757
|
-
|
|
758
694
|
// 从 Chart 同步副图状态到本地(语义化配置后调用)
|
|
759
695
|
function syncSubPanesFromChart(): void {
|
|
760
696
|
const chartSubPaneEntries = chartRef.value?.getSubPaneEntries() ?? []
|
|
761
697
|
|
|
762
|
-
// 清空本地状态
|
|
763
|
-
subPanes.value = []
|
|
764
698
|
paneTitleRendererNames.clear()
|
|
765
699
|
|
|
766
700
|
for (const entry of chartSubPaneEntries) {
|
|
@@ -779,43 +713,21 @@ function syncSubPanesFromChart(): void {
|
|
|
779
713
|
|
|
780
714
|
// 创建 paneTitle 渲染器
|
|
781
715
|
mountSubPaneTitle(paneId, indicatorId)
|
|
782
|
-
|
|
783
|
-
// 更新本地状态
|
|
784
|
-
subPanes.value.push({
|
|
785
|
-
id: paneId,
|
|
786
|
-
indicatorId,
|
|
787
|
-
params: { ...params },
|
|
788
|
-
})
|
|
789
716
|
}
|
|
790
|
-
|
|
791
|
-
scheduleRender()
|
|
792
717
|
}
|
|
793
718
|
|
|
794
719
|
// 切换副图指标(使用 Chart API)
|
|
795
720
|
function switchSubIndicator(paneId: string, newIndicatorId: SubIndicatorType): void {
|
|
796
|
-
const pane = subPanes.value.find((p) => p.id === paneId)
|
|
797
|
-
if (!pane) return
|
|
798
|
-
|
|
799
721
|
const nextParams = getDefaultParams(newIndicatorId)
|
|
800
722
|
|
|
801
723
|
// 移除旧的 paneTitle 渲染器
|
|
802
724
|
unmountSubPaneTitle(paneId)
|
|
803
725
|
|
|
804
|
-
// 使用 Chart API 替换副图指标(paneId
|
|
726
|
+
// 使用 Chart API 替换副图指标(paneId 不变,只换指标类型,Signal 订阅自动同步本地状态)
|
|
805
727
|
chartRef.value?.replaceSubPaneIndicator(paneId, newIndicatorId, nextParams)
|
|
806
728
|
|
|
807
729
|
// 创建新的 paneTitle 渲染器
|
|
808
730
|
mountSubPaneTitle(paneId, newIndicatorId)
|
|
809
|
-
|
|
810
|
-
// 更新本地状态(paneId 保持不变)
|
|
811
|
-
const index = subPanes.value.findIndex((p) => p.id === paneId)
|
|
812
|
-
if (index !== -1) {
|
|
813
|
-
subPanes.value[index] = {
|
|
814
|
-
id: paneId,
|
|
815
|
-
indicatorId: newIndicatorId,
|
|
816
|
-
params: nextParams,
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
731
|
}
|
|
820
732
|
|
|
821
733
|
// 获取副图标题信息(带缓存,只在 crosshairIdx 或 data 变化时重算)
|
|
@@ -879,14 +791,12 @@ function handleIndicatorToggle(indicatorId: string, active: boolean) {
|
|
|
879
791
|
const existingIndicator = mainActiveIndicators.value.find((id) => id === indicatorId)
|
|
880
792
|
|
|
881
793
|
if (active && !existingIndicator) {
|
|
882
|
-
//
|
|
794
|
+
// 添加主图指标(Signal 订阅自动同步本地状态)
|
|
883
795
|
chart.addIndicator(indicatorId, 'main', indicatorParams.value[indicatorId])
|
|
884
|
-
mainActiveIndicators.value.push(indicatorId)
|
|
885
796
|
} else if (!active && existingIndicator) {
|
|
886
|
-
//
|
|
797
|
+
// 移除主图指标(Signal 订阅自动同步本地状态)
|
|
887
798
|
const instanceId = indicatorId.toUpperCase()
|
|
888
799
|
chart.removeIndicator(instanceId)
|
|
889
|
-
mainActiveIndicators.value = mainActiveIndicators.value.filter((id) => id !== indicatorId)
|
|
890
800
|
}
|
|
891
801
|
return
|
|
892
802
|
}
|
|
@@ -901,17 +811,10 @@ function handleIndicatorToggle(indicatorId: string, active: boolean) {
|
|
|
901
811
|
// 副图数量上限检查
|
|
902
812
|
if (subPanes.value.length >= maxSubPanes) return
|
|
903
813
|
|
|
904
|
-
// 使用高层 API
|
|
814
|
+
// 使用高层 API 添加副图指标(Signal 订阅自动同步本地状态)
|
|
905
815
|
const paneId = chart.addIndicator(indicatorId, 'sub', indicatorParams.value[indicatorId])
|
|
906
816
|
if (paneId) {
|
|
907
|
-
// 创建 paneTitle 渲染器
|
|
908
817
|
mountSubPaneTitle(paneId, indicatorId as SubIndicatorType)
|
|
909
|
-
// 同步本地状态
|
|
910
|
-
subPanes.value.push({
|
|
911
|
-
id: paneId,
|
|
912
|
-
indicatorId: indicatorId as SubIndicatorType,
|
|
913
|
-
params: { ...indicatorParams.value[indicatorId] },
|
|
914
|
-
})
|
|
915
818
|
} else if (subPanes.value.length > 0) {
|
|
916
819
|
// 添加失败(可能达到上限),替换最后一个
|
|
917
820
|
const lastPane = subPanes.value[subPanes.value.length - 1]
|
|
@@ -924,42 +827,13 @@ function handleIndicatorToggle(indicatorId: string, active: boolean) {
|
|
|
924
827
|
chart.removeIndicator(pane.id)
|
|
925
828
|
unmountSubPaneTitle(pane.id)
|
|
926
829
|
})
|
|
927
|
-
subPanes.value = subPanes.value.filter((p) => p.indicatorId !== indicatorId)
|
|
928
830
|
}
|
|
929
|
-
scheduleRender()
|
|
930
831
|
}
|
|
931
832
|
}
|
|
932
833
|
|
|
933
|
-
// 更新主图指标图例配置
|
|
934
|
-
function updateMainIndicatorLegendConfig() {
|
|
935
|
-
chartRef.value?.updateRendererConfig('mainIndicatorLegend', {
|
|
936
|
-
indicators: {
|
|
937
|
-
MA: {
|
|
938
|
-
enabled: activeIndicators.value.includes('MA'),
|
|
939
|
-
params: indicatorParams.value['MA'] || {},
|
|
940
|
-
},
|
|
941
|
-
BOLL: {
|
|
942
|
-
enabled: activeIndicators.value.includes('BOLL'),
|
|
943
|
-
params: indicatorParams.value['BOLL'] || {},
|
|
944
|
-
},
|
|
945
|
-
EXPMA: {
|
|
946
|
-
enabled: activeIndicators.value.includes('EXPMA'),
|
|
947
|
-
params: indicatorParams.value['EXPMA'] || {},
|
|
948
|
-
},
|
|
949
|
-
ENE: {
|
|
950
|
-
enabled: activeIndicators.value.includes('ENE'),
|
|
951
|
-
params: indicatorParams.value['ENE'] || {},
|
|
952
|
-
},
|
|
953
|
-
},
|
|
954
|
-
})
|
|
955
|
-
}
|
|
956
|
-
|
|
957
834
|
// 指标参数更新处理
|
|
958
835
|
function handleUpdateParams(indicatorId: string, params: Record<string, unknown>) {
|
|
959
|
-
//
|
|
960
|
-
indicatorParams.value[indicatorId] = params
|
|
961
|
-
|
|
962
|
-
// 主图指标参数更新 - 使用Chart API
|
|
836
|
+
// 主图指标参数更新 - 使用Chart API(Signal 订阅自动同步本地状态和 scheduleDraw)
|
|
963
837
|
if (
|
|
964
838
|
indicatorId === 'MA' ||
|
|
965
839
|
indicatorId === 'BOLL' ||
|
|
@@ -970,7 +844,6 @@ function handleUpdateParams(indicatorId: string, params: Record<string, unknown>
|
|
|
970
844
|
indicatorId,
|
|
971
845
|
params as Record<string, number | boolean | string>,
|
|
972
846
|
)
|
|
973
|
-
scheduleRender()
|
|
974
847
|
return
|
|
975
848
|
}
|
|
976
849
|
|
|
@@ -979,13 +852,9 @@ function handleUpdateParams(indicatorId: string, params: Record<string, unknown>
|
|
|
979
852
|
.filter((p) => p.indicatorId === indicatorId)
|
|
980
853
|
.forEach((pane) => {
|
|
981
854
|
chartRef.value?.updateSubPaneParams(pane.id, params)
|
|
982
|
-
pane.params = { ...params }
|
|
983
855
|
})
|
|
984
|
-
scheduleRender()
|
|
985
856
|
return
|
|
986
857
|
}
|
|
987
|
-
|
|
988
|
-
scheduleRender()
|
|
989
858
|
}
|
|
990
859
|
|
|
991
860
|
function handleReorderSubIndicators(orderedIndicatorIds: string[]) {
|
|
@@ -1206,12 +1075,75 @@ function setupChartCallbacks(chart: Chart): void {
|
|
|
1206
1075
|
chartTheme.value = theme
|
|
1207
1076
|
})
|
|
1208
1077
|
|
|
1078
|
+
// 订阅 indicators signal,派生 Vue 本地状态(SSOT: Chart 引擎)
|
|
1079
|
+
const unsubscribeIndicators = chart.indicators.subscribe(() => {
|
|
1080
|
+
const instances = chart.indicators.peek()
|
|
1081
|
+
|
|
1082
|
+
// 同步主图指标列表
|
|
1083
|
+
const mains = instances
|
|
1084
|
+
.filter((i): i is IndicatorInstance & { role: 'main' } => i.role === 'main')
|
|
1085
|
+
.map((i) => i.definitionId)
|
|
1086
|
+
mainActiveIndicators.value = mains
|
|
1087
|
+
|
|
1088
|
+
// 合并主图指标参数(不覆盖副图参数)
|
|
1089
|
+
const nextParams = { ...indicatorParams.value }
|
|
1090
|
+
for (const inst of instances) {
|
|
1091
|
+
if (inst.role === 'main' && inst.params && Object.keys(inst.params).length > 0) {
|
|
1092
|
+
nextParams[inst.definitionId] = { ...inst.params }
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
// 更新主图指标图例配置
|
|
1097
|
+
chart.updateRendererConfig('mainIndicatorLegend', {
|
|
1098
|
+
indicators: {
|
|
1099
|
+
MA: { enabled: mains.includes('MA'), params: nextParams['MA'] || {} },
|
|
1100
|
+
BOLL: { enabled: mains.includes('BOLL'), params: nextParams['BOLL'] || {} },
|
|
1101
|
+
EXPMA: { enabled: mains.includes('EXPMA'), params: nextParams['EXPMA'] || {} },
|
|
1102
|
+
ENE: { enabled: mains.includes('ENE'), params: nextParams['ENE'] || {} },
|
|
1103
|
+
},
|
|
1104
|
+
})
|
|
1105
|
+
|
|
1106
|
+
indicatorParams.value = nextParams
|
|
1107
|
+
})
|
|
1108
|
+
|
|
1109
|
+
// 订阅 subPanes signal,派生 Vue 本地状态
|
|
1110
|
+
// 注意:保持当前显示顺序(reorder 是 UI 层私有状态),仅同步新增/删除
|
|
1111
|
+
const unsubscribeSubPanes = chart.subPanes.subscribe(() => {
|
|
1112
|
+
const subPaneInfos = chart.subPanes.peek()
|
|
1113
|
+
const signalIds = new Set(subPaneInfos.map((sp) => sp.paneId))
|
|
1114
|
+
|
|
1115
|
+
// 保留 display order,移除已删除的 pane,追加新增的
|
|
1116
|
+
const merged = subPanes.value.filter((p) => signalIds.has(p.id))
|
|
1117
|
+
const existingIds = new Set(merged.map((p) => p.id))
|
|
1118
|
+
for (const sp of subPaneInfos) {
|
|
1119
|
+
if (!existingIds.has(sp.paneId)) {
|
|
1120
|
+
merged.push({
|
|
1121
|
+
id: sp.paneId,
|
|
1122
|
+
indicatorId: sp.indicatorId as SubIndicatorType,
|
|
1123
|
+
params: sp.params,
|
|
1124
|
+
})
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
subPanes.value = merged
|
|
1128
|
+
|
|
1129
|
+
// 合并副图指标参数(不覆盖主图参数)
|
|
1130
|
+
const nextParams = { ...indicatorParams.value }
|
|
1131
|
+
for (const sp of subPaneInfos) {
|
|
1132
|
+
if (sp.params && Object.keys(sp.params).length > 0) {
|
|
1133
|
+
nextParams[sp.indicatorId] = { ...sp.params }
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
indicatorParams.value = nextParams
|
|
1137
|
+
})
|
|
1138
|
+
|
|
1209
1139
|
// 保存 unsubscribe 函数以便清理
|
|
1210
1140
|
onUnmounted(() => {
|
|
1211
1141
|
unsubscribeViewport()
|
|
1212
1142
|
unsubscribeData()
|
|
1213
1143
|
unsubscribePaneRatios()
|
|
1214
1144
|
unsubscribeTheme()
|
|
1145
|
+
unsubscribeIndicators()
|
|
1146
|
+
unsubscribeSubPanes()
|
|
1215
1147
|
})
|
|
1216
1148
|
}
|
|
1217
1149
|
|
package/src/index.ts
CHANGED
|
@@ -29,10 +29,14 @@ import type {
|
|
|
29
29
|
ChartControllerFactory,
|
|
30
30
|
ChartMountOptions,
|
|
31
31
|
ChartViewport,
|
|
32
|
+
IndicatorDefinition,
|
|
32
33
|
IndicatorInstance,
|
|
33
34
|
InteractionSnapshot,
|
|
34
35
|
KLineData,
|
|
35
36
|
} from '@363045841yyt/klinechart-core'
|
|
37
|
+
import {
|
|
38
|
+
createIndicatorSelectorController,
|
|
39
|
+
} from '@363045841yyt/klinechart-core'
|
|
36
40
|
|
|
37
41
|
export type {
|
|
38
42
|
ChartController,
|
|
@@ -252,6 +256,74 @@ export function useViewport(
|
|
|
252
256
|
return vp
|
|
253
257
|
}
|
|
254
258
|
|
|
259
|
+
// ---------------------------------------------------------------------------
|
|
260
|
+
// useIndicatorSelector — composable
|
|
261
|
+
// ---------------------------------------------------------------------------
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Bridge the indicator selector signals into Vue refs.
|
|
265
|
+
*
|
|
266
|
+
* Creates an internal IndicatorSelectorController for menu/search/filter UI
|
|
267
|
+
* state (catalog from `controller.catalog`), and delegates add/remove to the
|
|
268
|
+
* ChartController engine methods.
|
|
269
|
+
*/
|
|
270
|
+
export function useIndicatorSelector(controller: ChartController): {
|
|
271
|
+
catalog: ReadonlyArray<IndicatorDefinition>
|
|
272
|
+
filteredMain: Ref<ReadonlyArray<IndicatorDefinition>>
|
|
273
|
+
filteredSub: Ref<ReadonlyArray<IndicatorDefinition>>
|
|
274
|
+
menuOpen: Ref<boolean>
|
|
275
|
+
searchQuery: Ref<string>
|
|
276
|
+
add: (definitionId: string) => string | null
|
|
277
|
+
remove: (instanceId: string) => boolean
|
|
278
|
+
openMenu: () => void
|
|
279
|
+
closeMenu: () => void
|
|
280
|
+
toggleMenu: () => void
|
|
281
|
+
setSearchQuery: (q: string) => void
|
|
282
|
+
isActive: (definitionId: string) => boolean
|
|
283
|
+
} {
|
|
284
|
+
const selector = createIndicatorSelectorController({
|
|
285
|
+
catalog: controller.catalog,
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
onScopeDispose(() => selector.dispose())
|
|
289
|
+
|
|
290
|
+
const filteredMain = coreSignalToVueRef(selector.filteredMain)
|
|
291
|
+
const filteredSub = coreSignalToVueRef(selector.filteredSub)
|
|
292
|
+
const menuOpen = coreSignalToVueRef(selector.menuOpen)
|
|
293
|
+
const searchQuery = coreSignalToVueRef(selector.searchQuery)
|
|
294
|
+
|
|
295
|
+
function add(definitionId: string): string | null {
|
|
296
|
+
const def = controller.catalog.find((d) => d.id === definitionId)
|
|
297
|
+
if (def === undefined) return null
|
|
298
|
+
return controller.addIndicator(definitionId, def.role)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function remove(instanceId: string): boolean {
|
|
302
|
+
return controller.removeIndicator(instanceId)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function isActive(definitionId: string): boolean {
|
|
306
|
+
return controller.indicators
|
|
307
|
+
.peek()
|
|
308
|
+
.some((i) => i.definitionId === definitionId)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return {
|
|
312
|
+
catalog: controller.catalog,
|
|
313
|
+
filteredMain,
|
|
314
|
+
filteredSub,
|
|
315
|
+
menuOpen,
|
|
316
|
+
searchQuery,
|
|
317
|
+
add,
|
|
318
|
+
remove,
|
|
319
|
+
openMenu: () => selector.openMenu(),
|
|
320
|
+
closeMenu: () => selector.closeMenu(),
|
|
321
|
+
toggleMenu: () => selector.toggleMenu(),
|
|
322
|
+
setSearchQuery: (q: string) => selector.setSearchQuery(q),
|
|
323
|
+
isActive,
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
255
327
|
// ---------------------------------------------------------------------------
|
|
256
328
|
// <KLineChart /> SFC-equivalent component
|
|
257
329
|
//
|