@363045841yyt/klinechart 0.7.6 → 0.7.8
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 +4 -4
- package/dist/components/ChartSettingsDialog.vue.d.ts +14 -0
- package/dist/components/ChartSettingsDialog.vue.d.ts.map +1 -0
- package/dist/components/ColorPresetPanel.vue.d.ts +12 -0
- package/dist/components/ColorPresetPanel.vue.d.ts.map +1 -0
- package/dist/components/IndicatorSelector.vue.d.ts.map +1 -1
- package/dist/components/KLineChart.vue.d.ts +2 -0
- package/dist/components/KLineChart.vue.d.ts.map +1 -1
- package/dist/components/KLineTooltip.vue.d.ts +8 -1
- package/dist/components/KLineTooltip.vue.d.ts.map +1 -1
- package/dist/components/LeftToolbar.vue.d.ts +4 -3
- package/dist/components/LeftToolbar.vue.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.css +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +973 -796
- package/package.json +1 -1
- package/src/components/ChartSettingsDialog.vue +624 -0
- package/src/components/ColorPresetPanel.vue +289 -0
- package/src/components/DrawingStyleToolbar.vue +11 -11
- package/src/components/IndicatorParams.vue +56 -56
- package/src/components/IndicatorSelector.vue +88 -83
- package/src/components/KLineChart.vue +74 -19
- package/src/components/KLineTooltip.vue +17 -11
- package/src/components/LeftToolbar.vue +35 -393
- package/src/components/MarkerTooltip.vue +4 -4
- package/src/components/index.ts +1 -0
|
@@ -560,7 +560,7 @@ onUnmounted(() => {
|
|
|
560
560
|
width: 1px;
|
|
561
561
|
height: 20px;
|
|
562
562
|
align-self: center;
|
|
563
|
-
background:
|
|
563
|
+
background: var(--klc-color-axis-line);
|
|
564
564
|
}
|
|
565
565
|
|
|
566
566
|
.indicator-item {
|
|
@@ -581,8 +581,7 @@ onUnmounted(() => {
|
|
|
581
581
|
}
|
|
582
582
|
|
|
583
583
|
.indicator-item.drag-over .indicator-btn {
|
|
584
|
-
|
|
585
|
-
box-shadow: 0 0 0 2px rgba(26, 26, 26, 0.12);
|
|
584
|
+
box-shadow: 0 0 0 2px color-mix(in srgb, var(--klc-color-foreground) 12%, transparent);
|
|
586
585
|
}
|
|
587
586
|
|
|
588
587
|
.indicator-btn-wrapper {
|
|
@@ -593,10 +592,10 @@ onUnmounted(() => {
|
|
|
593
592
|
position: relative;
|
|
594
593
|
flex-shrink: 0;
|
|
595
594
|
padding: 6px 16px;
|
|
596
|
-
border:
|
|
595
|
+
border: none;
|
|
597
596
|
border-radius: 16px;
|
|
598
|
-
background:
|
|
599
|
-
color:
|
|
597
|
+
background: var(--klc-color-tag-bg-white);
|
|
598
|
+
color: var(--klc-color-axis-text);
|
|
600
599
|
font-size: 13px;
|
|
601
600
|
font-weight: 500;
|
|
602
601
|
cursor: pointer;
|
|
@@ -610,20 +609,17 @@ onUnmounted(() => {
|
|
|
610
609
|
}
|
|
611
610
|
|
|
612
611
|
.indicator-btn:hover:not(.hovering) {
|
|
613
|
-
background:
|
|
614
|
-
|
|
615
|
-
color: #333;
|
|
612
|
+
background: var(--klc-color-tag-bg-hover);
|
|
613
|
+
color: var(--klc-color-foreground);
|
|
616
614
|
}
|
|
617
615
|
|
|
618
616
|
.indicator-btn.active {
|
|
619
|
-
background:
|
|
620
|
-
|
|
621
|
-
color: #1a1a1a;
|
|
617
|
+
background: var(--klc-color-tag-bg-hover);
|
|
618
|
+
color: var(--klc-color-foreground);
|
|
622
619
|
}
|
|
623
620
|
|
|
624
621
|
.indicator-btn.active:hover:not(.hovering) {
|
|
625
|
-
background:
|
|
626
|
-
border-color: #333;
|
|
622
|
+
background: var(--klc-color-tag-bg-hover);
|
|
627
623
|
}
|
|
628
624
|
|
|
629
625
|
.btn-content {
|
|
@@ -647,7 +643,7 @@ onUnmounted(() => {
|
|
|
647
643
|
align-items: center;
|
|
648
644
|
justify-content: center;
|
|
649
645
|
gap: 4px;
|
|
650
|
-
background:
|
|
646
|
+
background: color-mix(in srgb, var(--klc-color-background) 85%, transparent);
|
|
651
647
|
backdrop-filter: blur(4px);
|
|
652
648
|
border-radius: 16px;
|
|
653
649
|
z-index: 2;
|
|
@@ -660,7 +656,7 @@ onUnmounted(() => {
|
|
|
660
656
|
border: none;
|
|
661
657
|
border-radius: 50%;
|
|
662
658
|
background: transparent;
|
|
663
|
-
color:
|
|
659
|
+
color: var(--klc-color-axis-text);
|
|
664
660
|
cursor: pointer;
|
|
665
661
|
display: flex;
|
|
666
662
|
align-items: center;
|
|
@@ -669,12 +665,12 @@ onUnmounted(() => {
|
|
|
669
665
|
}
|
|
670
666
|
|
|
671
667
|
.action-btn:hover {
|
|
672
|
-
background:
|
|
673
|
-
color:
|
|
668
|
+
background: var(--klc-color-tag-bg-hover);
|
|
669
|
+
color: var(--klc-color-foreground);
|
|
674
670
|
}
|
|
675
671
|
|
|
676
672
|
.settings-btn:hover {
|
|
677
|
-
color:
|
|
673
|
+
color: var(--klc-color-foreground);
|
|
678
674
|
}
|
|
679
675
|
|
|
680
676
|
.remove-btn:hover {
|
|
@@ -684,7 +680,7 @@ onUnmounted(() => {
|
|
|
684
680
|
.divider {
|
|
685
681
|
width: 1px;
|
|
686
682
|
height: 14px;
|
|
687
|
-
background:
|
|
683
|
+
background: var(--klc-color-border-button);
|
|
688
684
|
}
|
|
689
685
|
|
|
690
686
|
/* 添加按钮 */
|
|
@@ -693,10 +689,10 @@ onUnmounted(() => {
|
|
|
693
689
|
width: 32px;
|
|
694
690
|
height: 32px;
|
|
695
691
|
padding: 0;
|
|
696
|
-
border:
|
|
692
|
+
border: none;
|
|
697
693
|
border-radius: 50%;
|
|
698
694
|
background: transparent;
|
|
699
|
-
color:
|
|
695
|
+
color: var(--klc-color-axis-text);
|
|
700
696
|
cursor: pointer;
|
|
701
697
|
display: flex;
|
|
702
698
|
align-items: center;
|
|
@@ -705,9 +701,8 @@ onUnmounted(() => {
|
|
|
705
701
|
}
|
|
706
702
|
|
|
707
703
|
.add-btn:hover {
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
background: rgba(26, 26, 26, 0.04);
|
|
704
|
+
color: var(--klc-color-foreground);
|
|
705
|
+
background: var(--klc-color-tag-bg-hover);
|
|
711
706
|
}
|
|
712
707
|
|
|
713
708
|
/* ─────────────────────────────────────────────────────────────────
|
|
@@ -728,8 +723,8 @@ onUnmounted(() => {
|
|
|
728
723
|
|
|
729
724
|
/* 弹窗容器 */
|
|
730
725
|
.selector-modal {
|
|
731
|
-
background:
|
|
732
|
-
border: 1px solid
|
|
726
|
+
background: var(--klc-color-tag-bg-white);
|
|
727
|
+
border: 1px solid var(--klc-color-axis-line);
|
|
733
728
|
border-radius: 12px;
|
|
734
729
|
box-shadow: 0 8px 40px rgba(0, 0, 0, 0.15);
|
|
735
730
|
width: 90vw;
|
|
@@ -746,8 +741,8 @@ onUnmounted(() => {
|
|
|
746
741
|
justify-content: space-between;
|
|
747
742
|
align-items: center;
|
|
748
743
|
padding: 16px 20px;
|
|
749
|
-
background:
|
|
750
|
-
border-bottom: 1px solid
|
|
744
|
+
background: var(--klc-color-background);
|
|
745
|
+
border-bottom: 1px solid var(--klc-color-border-chart);
|
|
751
746
|
flex-shrink: 0;
|
|
752
747
|
}
|
|
753
748
|
|
|
@@ -760,18 +755,18 @@ onUnmounted(() => {
|
|
|
760
755
|
.title-text {
|
|
761
756
|
font-size: 14px;
|
|
762
757
|
font-weight: 600;
|
|
763
|
-
color:
|
|
758
|
+
color: var(--klc-color-foreground);
|
|
764
759
|
letter-spacing: 0.2px;
|
|
765
760
|
}
|
|
766
761
|
|
|
767
762
|
.title-sub {
|
|
768
763
|
font-size: 11px;
|
|
769
|
-
color:
|
|
764
|
+
color: var(--klc-color-axis-text);
|
|
770
765
|
}
|
|
771
766
|
|
|
772
767
|
.modal-close {
|
|
773
|
-
background:
|
|
774
|
-
border: 1px solid
|
|
768
|
+
background: var(--klc-color-tag-bg-white);
|
|
769
|
+
border: 1px solid var(--klc-color-border-button);
|
|
775
770
|
border-radius: 6px;
|
|
776
771
|
width: 28px;
|
|
777
772
|
height: 28px;
|
|
@@ -779,15 +774,15 @@ onUnmounted(() => {
|
|
|
779
774
|
align-items: center;
|
|
780
775
|
justify-content: center;
|
|
781
776
|
cursor: pointer;
|
|
782
|
-
color:
|
|
777
|
+
color: var(--klc-color-axis-text);
|
|
783
778
|
transition: all 0.15s;
|
|
784
779
|
padding: 0;
|
|
785
780
|
}
|
|
786
781
|
|
|
787
782
|
.modal-close:hover {
|
|
788
|
-
background:
|
|
789
|
-
color:
|
|
790
|
-
border-color:
|
|
783
|
+
background: var(--klc-color-tag-bg-hover);
|
|
784
|
+
color: var(--klc-color-foreground);
|
|
785
|
+
border-color: var(--klc-color-axis-line);
|
|
791
786
|
}
|
|
792
787
|
|
|
793
788
|
.modal-close svg {
|
|
@@ -802,8 +797,8 @@ onUnmounted(() => {
|
|
|
802
797
|
}
|
|
803
798
|
|
|
804
799
|
.view-toggle-btn {
|
|
805
|
-
background:
|
|
806
|
-
border: 1px solid
|
|
800
|
+
background: var(--klc-color-tag-bg-white);
|
|
801
|
+
border: 1px solid var(--klc-color-border-button);
|
|
807
802
|
border-radius: 6px;
|
|
808
803
|
width: 28px;
|
|
809
804
|
height: 28px;
|
|
@@ -811,21 +806,21 @@ onUnmounted(() => {
|
|
|
811
806
|
align-items: center;
|
|
812
807
|
justify-content: center;
|
|
813
808
|
cursor: pointer;
|
|
814
|
-
color:
|
|
809
|
+
color: var(--klc-color-axis-text);
|
|
815
810
|
transition: all 0.15s;
|
|
816
811
|
padding: 0;
|
|
817
812
|
}
|
|
818
813
|
|
|
819
814
|
.view-toggle-btn:hover {
|
|
820
|
-
background:
|
|
821
|
-
color:
|
|
822
|
-
border-color:
|
|
815
|
+
background: var(--klc-color-tag-bg-hover);
|
|
816
|
+
color: var(--klc-color-foreground);
|
|
817
|
+
border-color: var(--klc-color-axis-line);
|
|
823
818
|
}
|
|
824
819
|
|
|
825
820
|
.view-toggle-btn.active {
|
|
826
|
-
background:
|
|
827
|
-
border-color:
|
|
828
|
-
color:
|
|
821
|
+
background: var(--klc-color-tag-bg-white);
|
|
822
|
+
border-color: var(--klc-color-border-button);
|
|
823
|
+
color: var(--klc-color-foreground);
|
|
829
824
|
}
|
|
830
825
|
|
|
831
826
|
/* 弹窗主体 */
|
|
@@ -838,26 +833,36 @@ onUnmounted(() => {
|
|
|
838
833
|
gap: 20px;
|
|
839
834
|
}
|
|
840
835
|
|
|
836
|
+
.modal-body::-webkit-scrollbar {
|
|
837
|
+
width: 8px;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
.modal-body::-webkit-scrollbar-thumb {
|
|
841
|
+
background: var(--klc-color-axis-line);
|
|
842
|
+
border: 2px solid var(--klc-color-tag-bg-white);
|
|
843
|
+
border-radius: 999px;
|
|
844
|
+
}
|
|
845
|
+
|
|
841
846
|
/* 搜索框 */
|
|
842
847
|
.search-box {
|
|
843
848
|
display: flex;
|
|
844
849
|
align-items: center;
|
|
845
850
|
gap: 10px;
|
|
846
851
|
padding: 10px 14px;
|
|
847
|
-
border: 1px solid
|
|
852
|
+
border: 1px solid var(--klc-color-border-button);
|
|
848
853
|
border-radius: 8px;
|
|
849
854
|
transition: all 0.2s ease;
|
|
850
855
|
}
|
|
851
856
|
|
|
852
857
|
.search-box:focus-within {
|
|
853
|
-
background:
|
|
854
|
-
border-color:
|
|
855
|
-
box-shadow: 0 0 0 2px
|
|
858
|
+
background: var(--klc-color-tag-bg-white);
|
|
859
|
+
border-color: var(--klc-color-foreground);
|
|
860
|
+
box-shadow: 0 0 0 2px color-mix(in srgb, var(--klc-color-foreground) 8%, transparent);
|
|
856
861
|
}
|
|
857
862
|
|
|
858
863
|
.search-icon {
|
|
859
864
|
flex-shrink: 0;
|
|
860
|
-
color:
|
|
865
|
+
color: var(--klc-color-axis-text);
|
|
861
866
|
}
|
|
862
867
|
|
|
863
868
|
.search-input {
|
|
@@ -865,12 +870,12 @@ onUnmounted(() => {
|
|
|
865
870
|
border: none;
|
|
866
871
|
background: transparent;
|
|
867
872
|
font-size: 13px;
|
|
868
|
-
color:
|
|
873
|
+
color: var(--klc-color-foreground);
|
|
869
874
|
outline: none;
|
|
870
875
|
}
|
|
871
876
|
|
|
872
877
|
.search-input::placeholder {
|
|
873
|
-
color:
|
|
878
|
+
color: var(--klc-color-axis-text);
|
|
874
879
|
}
|
|
875
880
|
|
|
876
881
|
/* 无结果提示 */
|
|
@@ -880,7 +885,7 @@ onUnmounted(() => {
|
|
|
880
885
|
align-items: center;
|
|
881
886
|
justify-content: center;
|
|
882
887
|
padding: 48px 20px;
|
|
883
|
-
color:
|
|
888
|
+
color: var(--klc-color-axis-text);
|
|
884
889
|
gap: 12px;
|
|
885
890
|
}
|
|
886
891
|
|
|
@@ -891,13 +896,13 @@ onUnmounted(() => {
|
|
|
891
896
|
.no-results p {
|
|
892
897
|
margin: 0;
|
|
893
898
|
font-size: 14px;
|
|
894
|
-
color:
|
|
899
|
+
color: var(--klc-color-axis-text);
|
|
895
900
|
font-weight: 500;
|
|
896
901
|
}
|
|
897
902
|
|
|
898
903
|
.no-results-hint {
|
|
899
904
|
font-size: 12px;
|
|
900
|
-
color:
|
|
905
|
+
color: var(--klc-color-axis-text);
|
|
901
906
|
}
|
|
902
907
|
|
|
903
908
|
/* 指标区域 */
|
|
@@ -916,13 +921,13 @@ onUnmounted(() => {
|
|
|
916
921
|
.section-title {
|
|
917
922
|
font-size: 13px;
|
|
918
923
|
font-weight: 600;
|
|
919
|
-
color:
|
|
924
|
+
color: var(--klc-color-foreground);
|
|
920
925
|
}
|
|
921
926
|
|
|
922
927
|
.section-count {
|
|
923
928
|
font-size: 11px;
|
|
924
|
-
color:
|
|
925
|
-
background:
|
|
929
|
+
color: var(--klc-color-axis-text);
|
|
930
|
+
background: var(--klc-color-grid-minor);
|
|
926
931
|
padding: 2px 8px;
|
|
927
932
|
border-radius: 10px;
|
|
928
933
|
}
|
|
@@ -959,8 +964,8 @@ onUnmounted(() => {
|
|
|
959
964
|
transform: translateX(-50%);
|
|
960
965
|
padding: 4px 10px;
|
|
961
966
|
border-radius: 6px;
|
|
962
|
-
background:
|
|
963
|
-
color:
|
|
967
|
+
background: var(--klc-color-foreground);
|
|
968
|
+
color: var(--klc-color-background);
|
|
964
969
|
font-size: 12px;
|
|
965
970
|
white-space: nowrap;
|
|
966
971
|
pointer-events: none;
|
|
@@ -984,24 +989,24 @@ onUnmounted(() => {
|
|
|
984
989
|
flex-direction: column;
|
|
985
990
|
gap: 4px;
|
|
986
991
|
padding: 12px 14px;
|
|
987
|
-
border: 1px solid
|
|
992
|
+
border: 1px solid var(--klc-color-border-chart);
|
|
988
993
|
border-radius: 8px;
|
|
989
|
-
background:
|
|
994
|
+
background: var(--klc-color-tag-bg-white);
|
|
990
995
|
cursor: pointer;
|
|
991
996
|
transition: all 0.15s;
|
|
992
997
|
text-align: left;
|
|
993
998
|
}
|
|
994
999
|
|
|
995
1000
|
.indicator-card:hover:not(.disabled) {
|
|
996
|
-
border-color:
|
|
997
|
-
background:
|
|
1001
|
+
border-color: var(--klc-color-foreground);
|
|
1002
|
+
background: var(--klc-color-background);
|
|
998
1003
|
transform: translateY(-1px);
|
|
999
1004
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
1000
1005
|
}
|
|
1001
1006
|
|
|
1002
1007
|
.indicator-card.active {
|
|
1003
|
-
border-color:
|
|
1004
|
-
background:
|
|
1008
|
+
border-color: var(--klc-color-foreground);
|
|
1009
|
+
background: var(--klc-color-tag-bg-hover);
|
|
1005
1010
|
}
|
|
1006
1011
|
|
|
1007
1012
|
.card-header {
|
|
@@ -1014,7 +1019,7 @@ onUnmounted(() => {
|
|
|
1014
1019
|
.card-label {
|
|
1015
1020
|
font-size: 13px;
|
|
1016
1021
|
font-weight: 600;
|
|
1017
|
-
color:
|
|
1022
|
+
color: var(--klc-color-foreground);
|
|
1018
1023
|
}
|
|
1019
1024
|
|
|
1020
1025
|
.card-header-actions {
|
|
@@ -1033,32 +1038,32 @@ onUnmounted(() => {
|
|
|
1033
1038
|
border: none;
|
|
1034
1039
|
border-radius: 4px;
|
|
1035
1040
|
background: transparent;
|
|
1036
|
-
color:
|
|
1041
|
+
color: var(--klc-color-axis-text);
|
|
1037
1042
|
cursor: pointer;
|
|
1038
1043
|
transition: all 0.15s;
|
|
1039
1044
|
}
|
|
1040
1045
|
|
|
1041
1046
|
.card-settings-btn:hover {
|
|
1042
|
-
background:
|
|
1043
|
-
color:
|
|
1047
|
+
background: var(--klc-color-tag-bg-hover);
|
|
1048
|
+
color: var(--klc-color-foreground);
|
|
1044
1049
|
}
|
|
1045
1050
|
|
|
1046
1051
|
.card-name {
|
|
1047
1052
|
font-size: 11px;
|
|
1048
|
-
color:
|
|
1053
|
+
color: var(--klc-color-axis-text);
|
|
1049
1054
|
line-height: 1.4;
|
|
1050
1055
|
}
|
|
1051
1056
|
|
|
1052
1057
|
.card-params {
|
|
1053
1058
|
font-size: 10px;
|
|
1054
|
-
color:
|
|
1059
|
+
color: var(--klc-color-axis-text);
|
|
1055
1060
|
margin-top: 2px;
|
|
1056
1061
|
}
|
|
1057
1062
|
|
|
1058
1063
|
/* 区域分隔线 */
|
|
1059
1064
|
.section-divider {
|
|
1060
1065
|
height: 1px;
|
|
1061
|
-
background: linear-gradient(90deg, transparent,
|
|
1066
|
+
background: linear-gradient(90deg, transparent, var(--klc-color-border-button), transparent);
|
|
1062
1067
|
margin: 4px 0;
|
|
1063
1068
|
}
|
|
1064
1069
|
|
|
@@ -1068,18 +1073,18 @@ onUnmounted(() => {
|
|
|
1068
1073
|
align-items: center;
|
|
1069
1074
|
justify-content: space-between;
|
|
1070
1075
|
padding: 12px 20px;
|
|
1071
|
-
background:
|
|
1072
|
-
border-top: 1px solid
|
|
1076
|
+
background: var(--klc-color-background);
|
|
1077
|
+
border-top: 1px solid var(--klc-color-border-chart);
|
|
1073
1078
|
flex-shrink: 0;
|
|
1074
1079
|
}
|
|
1075
1080
|
|
|
1076
1081
|
.footer-info {
|
|
1077
1082
|
font-size: 12px;
|
|
1078
|
-
color:
|
|
1083
|
+
color: var(--klc-color-axis-text);
|
|
1079
1084
|
}
|
|
1080
1085
|
|
|
1081
1086
|
.info-text {
|
|
1082
|
-
color:
|
|
1087
|
+
color: var(--klc-color-axis-text);
|
|
1083
1088
|
}
|
|
1084
1089
|
|
|
1085
1090
|
/* 按钮样式 */
|
|
@@ -1098,14 +1103,14 @@ onUnmounted(() => {
|
|
|
1098
1103
|
}
|
|
1099
1104
|
|
|
1100
1105
|
.btn-confirm {
|
|
1101
|
-
background:
|
|
1102
|
-
border-color:
|
|
1103
|
-
color:
|
|
1106
|
+
background: var(--klc-color-foreground);
|
|
1107
|
+
border-color: var(--klc-color-foreground);
|
|
1108
|
+
color: var(--klc-color-background);
|
|
1104
1109
|
}
|
|
1105
1110
|
|
|
1106
1111
|
.btn-confirm:hover {
|
|
1107
|
-
background:
|
|
1108
|
-
border-color:
|
|
1112
|
+
background: var(--klc-color-foreground);
|
|
1113
|
+
border-color: var(--klc-color-foreground);
|
|
1109
1114
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
|
|
1110
1115
|
transform: translateY(-1px);
|
|
1111
1116
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div ref="chartWrapperRef" class="chart-wrapper" :data-theme="chartTheme">
|
|
2
|
+
<div ref="chartWrapperRef" class="chart-wrapper" :data-theme="chartTheme" :style="themeCssVars">
|
|
3
3
|
<div
|
|
4
4
|
class="chart-stage"
|
|
5
5
|
:class="{
|
|
@@ -75,6 +75,8 @@
|
|
|
75
75
|
:set-el="setTooltipEl"
|
|
76
76
|
:use-anchor="useAnchorPositioning"
|
|
77
77
|
:anchor-placement="tooltipAnchorPlacement"
|
|
78
|
+
:up-color="tooltipColors.upColor"
|
|
79
|
+
:down-color="tooltipColors.downColor"
|
|
78
80
|
/>
|
|
79
81
|
<MarkerTooltip
|
|
80
82
|
v-if="hoveredMarker || hoveredCustomMarker"
|
|
@@ -136,6 +138,8 @@ import {
|
|
|
136
138
|
DrawingInteractionController,
|
|
137
139
|
} from '@363045841yyt/klinechart-core/controllers'
|
|
138
140
|
import type { DrawingObject, DrawingStyle } from '@363045841yyt/klinechart-core/plugin'
|
|
141
|
+
import type { ChartSettings } from '@363045841yyt/klinechart-core/config'
|
|
142
|
+
import { resolveThemeColors, themeToCssVars, lightTheme, darkTheme, type ColorPresetSettings } from '@363045841yyt/klinechart-core'
|
|
139
143
|
import LeftToolbar from './LeftToolbar.vue'
|
|
140
144
|
|
|
141
145
|
const props = withDefaults(
|
|
@@ -179,6 +183,7 @@ const props = withDefaults(
|
|
|
179
183
|
const emit = defineEmits<{
|
|
180
184
|
(e: 'zoomLevelChange', level: number, kWidth: number): void
|
|
181
185
|
(e: 'toggleFullscreen'): void
|
|
186
|
+
(e: 'themeChange', theme: 'light' | 'dark'): void
|
|
182
187
|
}>()
|
|
183
188
|
|
|
184
189
|
const containerRef = ref<HTMLDivElement | null>(null)
|
|
@@ -219,11 +224,58 @@ kGap.value = kGapFromKWidth(kWidth.value, viewportDpr.value)
|
|
|
219
224
|
/* ========== 主题状态 ========== */
|
|
220
225
|
const chartTheme = ref<'light' | 'dark'>('light')
|
|
221
226
|
|
|
227
|
+
const chartSettings = ref<ChartSettings>({})
|
|
228
|
+
|
|
229
|
+
const tooltipColors = computed(() => {
|
|
230
|
+
const isAsiaMarket = chartSettings.value.isAsiaMarket ?? false
|
|
231
|
+
const colors = resolveThemeColors(chartTheme.value, isAsiaMarket as boolean | undefined)
|
|
232
|
+
return {
|
|
233
|
+
upColor: colors.candleUpBody,
|
|
234
|
+
downColor: colors.candleDownBody,
|
|
235
|
+
}
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
const themeCssVars = computed(() => {
|
|
239
|
+
const theme = chartTheme.value === 'dark' ? darkTheme : lightTheme
|
|
240
|
+
const overrides = (chartSettings.value.colorPresetSettings as ColorPresetSettings | undefined)?.[chartTheme.value]
|
|
241
|
+
if (overrides && Object.keys(overrides).length > 0) {
|
|
242
|
+
return themeToCssVars({ ...theme, colors: { ...theme.colors, ...overrides } })
|
|
243
|
+
}
|
|
244
|
+
return themeToCssVars(theme)
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
/* ========== 主题切换(支持 light / dark / auto 跟随系统) ========== */
|
|
248
|
+
let autoThemeMediaQuery: MediaQueryList | null = null
|
|
249
|
+
|
|
250
|
+
function onSystemThemeChange(e: MediaQueryListEvent) {
|
|
251
|
+
controller.value?.setTheme(e.matches ? 'dark' : 'light')
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function applyThemeFromSettings(ctrl: ChartController | null, themeSetting: string | undefined) {
|
|
255
|
+
if (!ctrl || !themeSetting) return
|
|
256
|
+
|
|
257
|
+
if (themeSetting === 'auto') {
|
|
258
|
+
const mq = window.matchMedia('(prefers-color-scheme: dark)')
|
|
259
|
+
ctrl.setTheme(mq.matches ? 'dark' : 'light')
|
|
260
|
+
if (autoThemeMediaQuery !== mq) {
|
|
261
|
+
autoThemeMediaQuery?.removeEventListener('change', onSystemThemeChange)
|
|
262
|
+
autoThemeMediaQuery = mq
|
|
263
|
+
mq.addEventListener('change', onSystemThemeChange)
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
autoThemeMediaQuery?.removeEventListener('change', onSystemThemeChange)
|
|
267
|
+
autoThemeMediaQuery = null
|
|
268
|
+
ctrl.setTheme(themeSetting as 'light' | 'dark')
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
222
272
|
function scheduleRender() {
|
|
223
273
|
/* Controller auto-renders on state changes */
|
|
224
274
|
}
|
|
225
275
|
|
|
226
|
-
function handleSettingsChange(settings:
|
|
276
|
+
function handleSettingsChange(settings: ChartSettings) {
|
|
277
|
+
chartSettings.value = settings
|
|
278
|
+
applyThemeFromSettings(controller.value, settings.theme as string)
|
|
227
279
|
controller.value?.updateSettingsFacade(settings)
|
|
228
280
|
|
|
229
281
|
if (settings.performanceTest10kKlines) {
|
|
@@ -735,7 +787,14 @@ function handleReorderSubIndicators(orderedIndicatorIds: string[]) {
|
|
|
735
787
|
/* 计算总宽度:从 Vue 响应式状态读取,zoom 变化时自动重算 */
|
|
736
788
|
const axisHostWidth = computed(() => props.rightAxisWidth + props.priceLabelWidth)
|
|
737
789
|
|
|
738
|
-
const totalWidth = computed(() =>
|
|
790
|
+
const totalWidth = computed(() => {
|
|
791
|
+
void dataVersion.value
|
|
792
|
+
void viewWidth.value
|
|
793
|
+
void kWidth.value
|
|
794
|
+
void kGap.value
|
|
795
|
+
void viewportDpr.value
|
|
796
|
+
return controller.value?.getContentWidth() ?? 0
|
|
797
|
+
})
|
|
739
798
|
|
|
740
799
|
function scrollToRight() {
|
|
741
800
|
const container = containerRef.value
|
|
@@ -872,7 +931,9 @@ function setupChartCallbacks(ctrl: ChartController): void {
|
|
|
872
931
|
})
|
|
873
932
|
|
|
874
933
|
const unsubscribeTheme = ctrl.theme.subscribe(() => {
|
|
875
|
-
|
|
934
|
+
const newTheme = ctrl.theme.peek()
|
|
935
|
+
chartTheme.value = newTheme
|
|
936
|
+
emit('themeChange', newTheme)
|
|
876
937
|
})
|
|
877
938
|
|
|
878
939
|
const unsubscribeIndicators = ctrl.indicators.subscribe(() => {
|
|
@@ -936,11 +997,14 @@ function setupChartCallbacks(ctrl: ChartController): void {
|
|
|
936
997
|
unsubscribeTheme()
|
|
937
998
|
unsubscribeIndicators()
|
|
938
999
|
unsubscribeSubPanes()
|
|
1000
|
+
autoThemeMediaQuery?.removeEventListener('change', onSystemThemeChange)
|
|
939
1001
|
})
|
|
940
1002
|
}
|
|
941
1003
|
|
|
942
1004
|
function applyInitialSettings(ctrl: ChartController): void {
|
|
943
1005
|
const initialSettings = toolbarRef.value?.getSettings() ?? { showVolumePriceMarkers: true }
|
|
1006
|
+
chartSettings.value = initialSettings
|
|
1007
|
+
applyThemeFromSettings(ctrl, initialSettings.theme as string)
|
|
944
1008
|
ctrl.updateSettingsFacade(initialSettings)
|
|
945
1009
|
|
|
946
1010
|
if (initialSettings.performanceTest10kKlines) {
|
|
@@ -1070,12 +1134,12 @@ watch(
|
|
|
1070
1134
|
--kmap-height: var(--kmap-chart-height, 100%);
|
|
1071
1135
|
--kmap-width: var(--kmap-chart-width, 100%);
|
|
1072
1136
|
|
|
1073
|
-
--chart-bg:
|
|
1074
|
-
--chart-bg-secondary:
|
|
1075
|
-
--chart-border:
|
|
1076
|
-
--chart-border-active: #
|
|
1077
|
-
--chart-text:
|
|
1078
|
-
--chart-text-secondary:
|
|
1137
|
+
--chart-bg: var(--klc-color-chart-background);
|
|
1138
|
+
--chart-bg-secondary: var(--klc-color-chart-background);
|
|
1139
|
+
--chart-border: var(--klc-color-border-chart);
|
|
1140
|
+
--chart-border-active: #1890ff;
|
|
1141
|
+
--chart-text: var(--klc-color-foreground);
|
|
1142
|
+
--chart-text-secondary: var(--klc-color-axis-text);
|
|
1079
1143
|
|
|
1080
1144
|
display: flex;
|
|
1081
1145
|
align-items: center;
|
|
@@ -1086,15 +1150,6 @@ watch(
|
|
|
1086
1150
|
flex-direction: column;
|
|
1087
1151
|
}
|
|
1088
1152
|
|
|
1089
|
-
.chart-wrapper[data-theme='dark'] {
|
|
1090
|
-
--chart-bg: #1a1a2e;
|
|
1091
|
-
--chart-bg-secondary: #16162a;
|
|
1092
|
-
--chart-border: #2d2d44;
|
|
1093
|
-
--chart-border-active: #60a5fa;
|
|
1094
|
-
--chart-text: #e5e7eb;
|
|
1095
|
-
--chart-text-secondary: #9ca3af;
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
1153
|
.chart-stage {
|
|
1099
1154
|
width: 95%;
|
|
1100
1155
|
height: 85%;
|
|
@@ -67,7 +67,7 @@ export interface KLineData {
|
|
|
67
67
|
stockCode?: string
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
const props = defineProps<{
|
|
70
|
+
const props = withDefaults(defineProps<{
|
|
71
71
|
k: KLineData | null
|
|
72
72
|
index: number | null
|
|
73
73
|
data: ReadonlyArray<KLineData>
|
|
@@ -75,7 +75,14 @@ const props = defineProps<{
|
|
|
75
75
|
useAnchor?: boolean
|
|
76
76
|
anchorPlacement?: 'right-bottom' | 'left-bottom'
|
|
77
77
|
setEl?: (el: HTMLDivElement | null) => void
|
|
78
|
-
|
|
78
|
+
/** 涨的颜色(默认红涨) */
|
|
79
|
+
upColor?: string
|
|
80
|
+
/** 跌的颜色(默认绿跌) */
|
|
81
|
+
downColor?: string
|
|
82
|
+
}>(), {
|
|
83
|
+
upColor: '#ef4444',
|
|
84
|
+
downColor: '#22c55e',
|
|
85
|
+
})
|
|
79
86
|
|
|
80
87
|
const useAnchor = computed(() => props.useAnchor === true)
|
|
81
88
|
const anchorPlacementClass = computed(() =>
|
|
@@ -105,8 +112,6 @@ function formatSigned(val: number, unit: string): string {
|
|
|
105
112
|
return `${sign}${val.toFixed(2)}${unit}`
|
|
106
113
|
}
|
|
107
114
|
|
|
108
|
-
const UP_COLOR = '#ef4444'
|
|
109
|
-
const DOWN_COLOR = '#22c55e'
|
|
110
115
|
const NEUTRAL_COLOR = '#6b7280'
|
|
111
116
|
|
|
112
117
|
function calcDirection(k: KLineData, data: ReadonlyArray<KLineData>, idx: number | null): number {
|
|
@@ -121,21 +126,21 @@ const openColor = computed(() => {
|
|
|
121
126
|
const k = props.k
|
|
122
127
|
if (!k) return NEUTRAL_COLOR
|
|
123
128
|
const dir = calcDirection(k, props.data, props.index)
|
|
124
|
-
return dir > 0 ?
|
|
129
|
+
return dir > 0 ? props.upColor : dir < 0 ? props.downColor : NEUTRAL_COLOR
|
|
125
130
|
})
|
|
126
131
|
|
|
127
132
|
const closeColor = computed(() => {
|
|
128
133
|
const k = props.k
|
|
129
134
|
if (!k) return NEUTRAL_COLOR
|
|
130
135
|
const diff = k.close - k.open
|
|
131
|
-
return diff > 0 ?
|
|
136
|
+
return diff > 0 ? props.upColor : diff < 0 ? props.downColor : NEUTRAL_COLOR
|
|
132
137
|
})
|
|
133
138
|
|
|
134
139
|
const changeColor = computed(() => {
|
|
135
140
|
const k = props.k
|
|
136
141
|
if (!k) return NEUTRAL_COLOR
|
|
137
142
|
const pct = k.changePercent ?? (k.close - k.open) / k.open * 100
|
|
138
|
-
return pct > 0 ?
|
|
143
|
+
return pct > 0 ? props.upColor : pct < 0 ? props.downColor : NEUTRAL_COLOR
|
|
139
144
|
})
|
|
140
145
|
</script>
|
|
141
146
|
|
|
@@ -147,10 +152,10 @@ const changeColor = computed(() => {
|
|
|
147
152
|
max-width: 260px;
|
|
148
153
|
padding: 10px 12px;
|
|
149
154
|
border-radius: 8px;
|
|
150
|
-
background:
|
|
151
|
-
border: 1px solid
|
|
155
|
+
background: var(--klc-color-tooltip-bg);
|
|
156
|
+
border: 1px solid var(--klc-color-tooltip-border);
|
|
152
157
|
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
|
|
153
|
-
color:
|
|
158
|
+
color: var(--klc-color-tooltip-text);
|
|
154
159
|
font-size: 12px;
|
|
155
160
|
line-height: 1.4;
|
|
156
161
|
pointer-events: none;
|
|
@@ -178,7 +183,8 @@ const changeColor = computed(() => {
|
|
|
178
183
|
}
|
|
179
184
|
|
|
180
185
|
.kline-tooltip__grid .row span:first-child {
|
|
181
|
-
color:
|
|
186
|
+
color: var(--klc-color-tooltip-text);
|
|
187
|
+
opacity: 0.56;
|
|
182
188
|
}
|
|
183
189
|
|
|
184
190
|
@supports (anchor-name: --kmap-anchor) and (position-anchor: --kmap-anchor) {
|