@363045841yyt/klinechart 0.7.0 → 0.7.1

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 (30) hide show
  1. package/dist/index.cjs +5 -5
  2. package/dist/index.js +12693 -5720
  3. package/dist/klinechart.css +1 -1
  4. package/dist/src/core/chart.d.ts +201 -4
  5. package/dist/src/core/draw/pixelAlign.d.ts +7 -7
  6. package/dist/src/core/indicators/indicatorDefinitionRegistry.d.ts +30 -0
  7. package/dist/src/core/indicators/indicatorMetadata.d.ts +81 -0
  8. package/dist/src/core/indicators/indicatorRegistry.d.ts +57 -0
  9. package/dist/src/core/indicators/rsiState.d.ts +4 -0
  10. package/dist/src/core/indicators/scheduler.d.ts +27 -2
  11. package/dist/src/core/renderers/Indicator/cci.d.ts +2 -1
  12. package/dist/src/core/renderers/Indicator/ene.d.ts +0 -8
  13. package/dist/src/core/renderers/Indicator/fastk.d.ts +2 -1
  14. package/dist/src/core/renderers/Indicator/kst.d.ts +2 -1
  15. package/dist/src/core/renderers/Indicator/macd.d.ts +2 -1
  16. package/dist/src/core/renderers/Indicator/mom.d.ts +2 -1
  17. package/dist/src/core/renderers/Indicator/rsi.d.ts +3 -2
  18. package/dist/src/core/renderers/Indicator/scale/indicator_scale.d.ts +4 -1
  19. package/dist/src/core/renderers/Indicator/stoch.d.ts +2 -1
  20. package/dist/src/core/renderers/Indicator/wmsr.d.ts +2 -1
  21. package/dist/src/core/renderers/candle.d.ts +2 -1
  22. package/dist/src/core/theme/colors.d.ts +207 -228
  23. package/dist/src/plugin/PluginHost.d.ts +3 -0
  24. package/dist/src/plugin/types.d.ts +6 -0
  25. package/dist/src/utils/kLineDraw/MA.d.ts +5 -10
  26. package/dist/src/utils/kLineDraw/axis.d.ts +7 -7
  27. package/dist/src/utils/kLineDraw/grid.d.ts +2 -2
  28. package/dist/src/utils/kLineDraw/kLine.d.ts +1 -1
  29. package/dist/src/utils/kline/format.d.ts +4 -7
  30. package/package.json +111 -103
@@ -1,2 +1,2 @@
1
- .kline-tooltip[data-v-d0fe85e6]{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-d0fe85e6]{justify-content:space-between;gap:10px;margin-bottom:6px;font-weight:600;display:flex}.kline-tooltip__grid[data-v-d0fe85e6]{grid-template-columns:1fr;gap:2px;display:grid}.kline-tooltip__grid .row[data-v-d0fe85e6]{justify-content:space-between;gap:10px;display:flex}.kline-tooltip__grid .row span[data-v-d0fe85e6]:first-child{color:#0000008f}@supports (anchor-name:--kmap-anchor) and (position-anchor:--kmap-anchor){.kline-tooltip.use-anchor[data-v-d0fe85e6]{position-anchor:--kline-tooltip-anchor;left:anchor(left);top:anchor(top);position:absolute}.kline-tooltip.use-anchor.anchor-right-bottom[data-v-d0fe85e6]{transform:translate(14px,14px)}.kline-tooltip.use-anchor.anchor-left-bottom[data-v-d0fe85e6]{transform:translate(calc(-100% - 14px),14px)}}.marker-tooltip[data-v-5574cc25]{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-5574cc25]{justify-content:space-between;gap:10px;margin-bottom:6px;font-weight:600;display:flex}.marker-tooltip__content[data-v-5574cc25]{grid-template-columns:1fr;gap:2px;display:grid}.marker-tooltip__content .row[data-v-5574cc25]{justify-content:space-between;gap:10px;display:flex}.marker-tooltip__content .row span[data-v-5574cc25]:first-child{color:#0000008f}@supports (anchor-name:--kmap-anchor) and (position-anchor:--kmap-anchor){.marker-tooltip.use-anchor[data-v-5574cc25]{position-anchor:--marker-tooltip-anchor;left:anchor(left);top:anchor(top);position:absolute}.marker-tooltip.use-anchor.anchor-right-bottom[data-v-5574cc25]{transform:translate(12px,12px)}.marker-tooltip.use-anchor.anchor-left-bottom[data-v-5574cc25]{transform:translate(calc(-100% - 12px),12px)}}.params-overlay[data-v-bb1d1eb3]{-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-bb1d1eb3]{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-bb1d1eb3]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-left[data-v-bb1d1eb3]{align-items:baseline;gap:8px;display:flex}.header-right[data-v-bb1d1eb3]{align-items:center;gap:8px;display:flex}.params-title[data-v-bb1d1eb3]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.params-subtitle[data-v-bb1d1eb3]{color:#999;font-size:11px}.toggle-desc-btn[data-v-bb1d1eb3]{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-bb1d1eb3]:hover{color:#555;background:#f0f0f0;border-color:#ccc}.toggle-desc-btn.active[data-v-bb1d1eb3]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.toggle-desc-btn svg[data-v-bb1d1eb3]{width:14px;height:14px}.params-close[data-v-bb1d1eb3]{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:background .15s,color .15s,border-color .15s;display:flex}.params-close[data-v-bb1d1eb3]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.params-close svg[data-v-bb1d1eb3]{width:14px;height:14px}.indicator-description[data-v-bb1d1eb3]{background:#f0f7ff;border-bottom:1px solid #d6e8f5;padding:12px 20px}.indicator-description p[data-v-bb1d1eb3]{color:#2c5282;margin:0;font-size:12px;line-height:1.6}.params-body[data-v-bb1d1eb3]{flex-direction:column;gap:10px;padding:16px 20px;display:flex}.param-item[data-v-bb1d1eb3]{background:#f8f8f8;border:1px solid #e8e8e8;border-radius:8px;padding:10px 14px;transition:border-color .2s}.param-item[data-v-bb1d1eb3]:has(.param-input:focus){border-color:#bbb}.param-item.has-desc[data-v-bb1d1eb3]{padding:10px 14px 8px}.param-header[data-v-bb1d1eb3]{justify-content:space-between;align-items:center;gap:16px;display:flex}.param-label[data-v-bb1d1eb3]{flex-direction:column;gap:3px;display:flex}.param-label-text[data-v-bb1d1eb3]{color:#333;font-size:13px;font-weight:500}.param-range[data-v-bb1d1eb3]{color:#999;font-size:11px}.param-description[data-v-bb1d1eb3]{color:#666;border-top:1px dashed #e0e0e0;margin-top:8px;padding-top:8px;font-size:11px;line-height:1.5}.input-wrapper[data-v-bb1d1eb3]{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-bb1d1eb3]:focus-within{border-color:#999}.stepper-btn[data-v-bb1d1eb3]{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-bb1d1eb3]:hover:not(:disabled){color:#333;background:#e0e0e0}.stepper-btn[data-v-bb1d1eb3]:disabled{color:#ccc;cursor:not-allowed}.param-input[data-v-bb1d1eb3]{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-bb1d1eb3]::-webkit-inner-spin-button{-webkit-appearance:none}.param-input[data-v-bb1d1eb3]::-webkit-outer-spin-button{-webkit-appearance:none}.param-input[data-v-bb1d1eb3]:focus{outline:none}.params-footer[data-v-bb1d1eb3]{background:#f8f8f8;border-top:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-right[data-v-bb1d1eb3]{gap:8px;display:flex}.params-btn[data-v-bb1d1eb3]{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-bb1d1eb3]{flex-shrink:0;width:12px;height:12px}.params-btn.reset[data-v-bb1d1eb3]{color:#666;background:0 0;border-color:#d0d0d0}.params-btn.reset[data-v-bb1d1eb3]:hover{color:#e74c3c;background:#e74c3c14;border-color:#c0392b}.params-btn.cancel[data-v-bb1d1eb3]{color:#666;background:0 0;border-color:#d0d0d0}.params-btn.cancel[data-v-bb1d1eb3]:hover{color:#333;background:#f0f0f0;border-color:#bbb}.params-btn.confirm[data-v-bb1d1eb3]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.params-btn.confirm[data-v-bb1d1eb3]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.params-btn.confirm[data-v-bb1d1eb3]:active{box-shadow:none;transform:translateY(0)}.overlay-enter-active[data-v-bb1d1eb3],.overlay-leave-active[data-v-bb1d1eb3]{transition:opacity .2s}.overlay-enter-from[data-v-bb1d1eb3],.overlay-leave-to[data-v-bb1d1eb3]{opacity:0}.modal-enter-active[data-v-bb1d1eb3]{transition:all .22s cubic-bezier(.34,1.56,.64,1)}.modal-leave-active[data-v-bb1d1eb3]{transition:all .16s ease-in}.modal-enter-from[data-v-bb1d1eb3]{opacity:0;transform:scale(.88)translateY(-16px)}.modal-leave-to[data-v-bb1d1eb3]{opacity:0;transform:scale(.94)translateY(8px)}.slide-enter-active[data-v-bb1d1eb3],.slide-leave-active[data-v-bb1d1eb3]{transition:all .2s;overflow:hidden}.slide-enter-from[data-v-bb1d1eb3],.slide-leave-to[data-v-bb1d1eb3]{opacity:0;max-height:0;margin-top:0;padding-top:0;padding-bottom:0}.indicator-selector[data-v-e9eb306c]{width:80%;margin:20px;position:relative}.indicator-scroll-container[data-v-e9eb306c]{scrollbar-width:none;-webkit-overflow-scrolling:touch;text-align:center;width:100%;overflow:auto hidden}.indicator-scroll-container[data-v-e9eb306c]::-webkit-scrollbar{display:none}.indicator-list[data-v-e9eb306c]{gap:8px;margin:0 auto;padding:2px;display:inline-flex}.indicator-divider[data-v-e9eb306c]{background:#d9d9d9;align-self:center;width:1px;height:20px}.indicator-item[data-v-e9eb306c]{align-items:center;gap:4px;display:flex}.indicator-item.draggable[data-v-e9eb306c],.indicator-item.draggable .indicator-btn[data-v-e9eb306c],.indicator-item.draggable[data-v-e9eb306c]:hover,.indicator-item.draggable:hover .indicator-btn[data-v-e9eb306c]{cursor:move}.indicator-item.is-dragging[data-v-e9eb306c]{opacity:.6}.indicator-item.drag-over .indicator-btn[data-v-e9eb306c]{border-color:#1a1a1a;box-shadow:0 0 0 2px #1a1a1a1f}.indicator-btn-wrapper[data-v-e9eb306c]{position:relative}.indicator-btn[data-v-e9eb306c]{color:#666;cursor:pointer;white-space:nowrap;background:#fff;border:1px solid #e0e0e0;border-radius:16px;flex-shrink:0;justify-content:center;align-items:center;gap:4px;padding:6px 16px;font-size:13px;font-weight:500;transition:all .3s;display:flex;position:relative;overflow:hidden}.indicator-btn[data-v-e9eb306c]:hover:not(.hovering){color:#333;background:#f8f8f8;border-color:#ccc}.indicator-btn.active[data-v-e9eb306c]{color:#1a1a1a;background:#f8f8f8;border-color:#1a1a1a}.indicator-btn.active[data-v-e9eb306c]:hover:not(.hovering){background:#f0f0f0;border-color:#333}.btn-content[data-v-e9eb306c]{z-index:1;position:relative}.param-hint[data-v-e9eb306c]{opacity:.85;font-size:11px}.hover-overlay[data-v-e9eb306c]{-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:2;background:#ffffffd9;border-radius:16px;justify-content:center;align-items:center;gap:4px;display:flex;position:absolute;inset:0}.action-btn[data-v-e9eb306c]{color:#666;cursor:pointer;background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;width:24px;height:24px;padding:0;transition:all .2s;display:flex}.action-btn[data-v-e9eb306c]:hover{color:#333;background:#0000000f}.settings-btn[data-v-e9eb306c]:hover{color:#1a1a1a}.remove-btn[data-v-e9eb306c]:hover{color:#ff4d4f}.divider[data-v-e9eb306c]{background:#e0e0e0;width:1px;height:14px}.add-btn[data-v-e9eb306c]{color:#999;cursor:pointer;background:0 0;border:1px dashed #d9d9d9;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;width:32px;height:32px;padding:0;transition:all .3s;display:flex}.add-btn[data-v-e9eb306c]:hover{color:#1a1a1a;background:#1a1a1a0a;border-color:#1a1a1a}.selector-overlay[data-v-e9eb306c]{-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}.selector-modal[data-v-e9eb306c]{background:#fff;border:1px solid #e0e0e0;border-radius:12px;flex-direction:column;width:90vw;max-width:860px;max-height:85vh;display:flex;overflow:hidden;box-shadow:0 8px 40px #00000026}.modal-header[data-v-e9eb306c]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;flex-shrink:0;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-title[data-v-e9eb306c]{flex-direction:column;gap:2px;display:flex}.title-text[data-v-e9eb306c]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.title-sub[data-v-e9eb306c]{color:#999;font-size:11px}.modal-close[data-v-e9eb306c]{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 .15s;display:flex}.modal-close[data-v-e9eb306c]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.modal-close svg[data-v-e9eb306c]{width:14px;height:14px}.header-actions[data-v-e9eb306c]{align-items:center;gap:8px;display:flex}.view-toggle-btn[data-v-e9eb306c]{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 .15s;display:flex}.view-toggle-btn[data-v-e9eb306c]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.view-toggle-btn.active[data-v-e9eb306c]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.modal-body[data-v-e9eb306c]{flex-direction:column;flex:1;gap:20px;padding:20px;display:flex;overflow-y:auto}.indicator-section[data-v-e9eb306c]{flex-direction:column;gap:12px;display:flex}.section-header[data-v-e9eb306c]{align-items:center;gap:8px;display:flex}.section-title[data-v-e9eb306c]{color:#1a1a1a;font-size:13px;font-weight:600}.section-count[data-v-e9eb306c]{color:#999;background:#f0f0f0;border-radius:10px;padding:2px 8px;font-size:11px}.indicator-grid[data-v-e9eb306c]{grid-template-columns:repeat(auto-fill,minmax(195px,1fr));gap:10px;display:grid}.indicator-grid.compact[data-v-e9eb306c]{flex-wrap:wrap;gap:8px;display:flex}.indicator-grid.compact .indicator-card[data-v-e9eb306c]{white-space:nowrap;border-radius:16px;justify-content:center;align-items:center;min-height:32px;padding:6px 14px;display:inline-flex;position:relative}.indicator-grid.compact .indicator-card .card-tooltip[data-v-e9eb306c]{color:#fff;white-space:nowrap;pointer-events:none;opacity:0;z-index:10;background:#333;border-radius:6px;padding:4px 10px;font-size:12px;transition:opacity .15s;position:absolute;bottom:calc(100% + 6px);left:50%;transform:translate(-50%)}.indicator-grid.compact .indicator-card:hover .card-tooltip[data-v-e9eb306c]{opacity:1}.indicator-grid.compact .indicator-card .card-label[data-v-e9eb306c]{font-size:12px;font-weight:500}.indicator-card[data-v-e9eb306c]{cursor:pointer;text-align:left;background:#fff;border:1px solid #e8e8e8;border-radius:8px;flex-direction:column;gap:4px;padding:12px 14px;transition:all .15s;display:flex}.indicator-card[data-v-e9eb306c]:hover:not(.disabled){background:#fafafa;border-color:#1a1a1a;transform:translateY(-1px);box-shadow:0 2px 8px #0000000f}.indicator-card.active[data-v-e9eb306c]{background:#f8f8f8;border-color:#1a1a1a}.card-header[data-v-e9eb306c]{justify-content:space-between;align-items:center;gap:8px;display:flex}.card-label[data-v-e9eb306c]{color:#1a1a1a;font-size:13px;font-weight:600}.card-header-actions[data-v-e9eb306c]{align-items:center;gap:4px;display:flex}.card-settings-btn[data-v-e9eb306c]{color:#bbb;cursor:pointer;background:0 0;border:none;border-radius:4px;justify-content:center;align-items:center;width:20px;height:20px;padding:0;transition:all .15s;display:flex}.card-settings-btn[data-v-e9eb306c]:hover{color:#555;background:#f0f0f0}.card-name[data-v-e9eb306c]{color:#666;font-size:11px;line-height:1.4}.card-params[data-v-e9eb306c]{color:#999;margin-top:2px;font-size:10px}.section-divider[data-v-e9eb306c]{background:linear-gradient(90deg,#0000,#e0e0e0,#0000);height:1px;margin:4px 0}.modal-footer[data-v-e9eb306c]{background:#f8f8f8;border-top:1px solid #e8e8e8;flex-shrink:0;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-info[data-v-e9eb306c]{color:#666;font-size:12px}.info-text[data-v-e9eb306c]{color:#999}.btn[data-v-e9eb306c]{cursor:pointer;border:1px solid #0000;border-radius:7px;align-items:center;gap:5px;padding:6px 16px;font-size:13px;font-weight:500;line-height:1.4;transition:all .15s;display:flex}.btn-confirm[data-v-e9eb306c]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.btn-confirm[data-v-e9eb306c]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.fade-enter-active[data-v-e9eb306c],.fade-leave-active[data-v-e9eb306c]{transition:opacity .2s}.fade-enter-from[data-v-e9eb306c],.fade-leave-to[data-v-e9eb306c]{opacity:0}.overlay-enter-active[data-v-e9eb306c],.overlay-leave-active[data-v-e9eb306c]{transition:opacity .2s}.overlay-enter-from[data-v-e9eb306c],.overlay-leave-to[data-v-e9eb306c]{opacity:0}.modal-enter-active[data-v-e9eb306c]{transition:all .22s cubic-bezier(.34,1.56,.64,1)}.modal-leave-active[data-v-e9eb306c]{transition:all .16s ease-in}.modal-enter-from[data-v-e9eb306c]{opacity:0;transform:scale(.88)translateY(-16px)}.modal-leave-to[data-v-e9eb306c]{opacity:0;transform:scale(.94)translateY(8px)}@media (width<=640px){.selector-modal[data-v-e9eb306c]{width:95vw;max-height:90vh}.indicator-grid[data-v-e9eb306c]{grid-template-columns:1fr}.modal-body[data-v-e9eb306c]{padding:16px}}.drawing-style-toolbar[data-v-92699cb2]{-webkit-backdrop-filter:blur(8px);z-index:100;-webkit-user-select:none;user-select:none;pointer-events:auto;background:#fafbfce0;border:1px solid #e5e7eb;border-radius:6px;align-items:center;gap:6px;height:32px;padding:4px 8px;display:flex;position:absolute;top:8px;left:50%;transform:translate(-50%);box-shadow:0 1px 3px #0000000f}.toolbar-item[data-v-92699cb2]{justify-content:center;align-items:center;display:inline-flex}.color-item[data-v-92699cb2]{width:24px;height:24px;position:relative}.color-swatch[data-v-92699cb2]{cursor:pointer;border:1px solid #d1d5db;border-radius:4px;width:100%;height:100%;display:block}.color-input[data-v-92699cb2]{opacity:0;cursor:pointer;width:100%;height:100%;position:absolute;inset:0}.toolbar-select[data-v-92699cb2]{color:#374151;cursor:pointer;background:#fff;border:1px solid #d1d5db;border-radius:4px;outline:none;height:24px;padding:0 4px;font-size:12px}.toolbar-select[data-v-92699cb2]:hover{border-color:#9ca3af}.toolbar-btn[data-v-92699cb2]{color:#6b7280;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:4px;justify-content:center;align-items:center;width:24px;height:24px;padding:0;transition:border-color .15s,background .15s,color .15s;display:inline-flex}.toolbar-btn[data-v-92699cb2]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.delete-btn[data-v-92699cb2]:hover{color:#dc2626;background:#fef2f2;border-color:#fca5a5}.delete-icon[data-v-92699cb2]{width:14px;height:14px}.left-toolbar[data-v-20a39cb3]{box-sizing:border-box;-webkit-user-select:none;user-select:none;background:#fafbfc;border:1px solid #e5e7eb;border-radius:6px;flex-direction:column;flex:0 0 40px;align-items:center;gap:6px;padding:8px 5px;display:flex;box-shadow:0 1px 3px #0000000f}.left-toolbar__group[data-v-20a39cb3]{flex-direction:column;gap:4px;display:flex}.left-toolbar__divider[data-v-20a39cb3]{background:#e5e7eb;width:18px;height:1px}.left-toolbar__button[data-v-20a39cb3]{color:#6b7280;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:4px;justify-content:center;align-items:center;width:28px;height:28px;padding:0;transition:border-color .15s,background .15s,color .15s;display:inline-flex;position:relative}.left-toolbar__button[data-v-20a39cb3]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.left-toolbar__button.active[data-v-20a39cb3]{color:#1f2937;background:#e5e7eb;border-color:#9ca3af}.left-toolbar__button[data-v-20a39cb3]:focus-visible{border-color:#6b7280;outline:none}.tool-icon[data-v-20a39cb3]{width:16px;height:16px}.corner-indicator[data-v-20a39cb3]{cursor:pointer;width:8px;height:8px;position:absolute;bottom:0;right:0;overflow:hidden}.corner-indicator[data-v-20a39cb3]:after{content:"";opacity:.45;border-bottom:5px solid;border-left:5px solid #0000;width:0;height:0;transition:opacity .15s;position:absolute;bottom:0;right:0}.left-toolbar__button:hover .corner-indicator[data-v-20a39cb3]:after,.left-toolbar__button.active .corner-indicator[data-v-20a39cb3]:after{opacity:.7}.corner-indicator.open[data-v-20a39cb3]:after{opacity:.8}.tool-dropdown[data-v-20a39cb3]{-webkit-backdrop-filter:blur(8px);box-sizing:border-box;z-index:100;background:#fafbfcd1;border:1px solid #e5e7eb;border-radius:6px;flex-direction:row;align-items:center;gap:4px;height:40px;padding:0 5px;display:flex;position:absolute;top:50%;left:calc(100% + 13px);transform:translateY(-50%);box-shadow:0 1px 3px #0000000f}.tool-item[data-v-20a39cb3]{position:relative}.dropdown-enter-active[data-v-20a39cb3],.dropdown-leave-active[data-v-20a39cb3]{transition:opacity .15s,transform .15s}.dropdown-enter-from[data-v-20a39cb3],.dropdown-leave-to[data-v-20a39cb3]{opacity:0;transform:translateY(-50%)translate(-6px)}@media (width<=768px),(height<=640px){.left-toolbar[data-v-20a39cb3]{border-radius:5px;flex-basis:36px;gap:5px;padding:6px 4px}.left-toolbar__group[data-v-20a39cb3]{gap:3px}.left-toolbar__button[data-v-20a39cb3]{border-radius:3px;width:26px;height:26px}.left-toolbar__divider[data-v-20a39cb3]{width:16px}.corner-indicator[data-v-20a39cb3]{width:7px;height:7px}.corner-indicator[data-v-20a39cb3]:after{border-bottom-width:4px;border-left-width:4px}.tool-dropdown[data-v-20a39cb3]{height:36px}}.settings-overlay[data-v-20a39cb3]{-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}.settings-modal[data-v-20a39cb3]{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}.settings-header[data-v-20a39cb3]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-left[data-v-20a39cb3]{align-items:baseline;gap:8px;display:flex}.header-right[data-v-20a39cb3]{align-items:center;gap:8px;display:flex}.settings-title[data-v-20a39cb3]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.settings-subtitle[data-v-20a39cb3]{color:#999;font-size:11px}.settings-close[data-v-20a39cb3]{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:background .15s,color .15s,border-color .15s;display:flex}.settings-close[data-v-20a39cb3]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.settings-close svg[data-v-20a39cb3]{width:14px;height:14px}.settings-body[data-v-20a39cb3]{flex-direction:column;gap:10px;padding:16px 20px;display:flex}.settings-item[data-v-20a39cb3]{background:#f8f8f8;border:1px solid #e8e8e8;border-radius:8px;padding:8px 12px}.settings-label[data-v-20a39cb3]{color:#333;cursor:pointer;justify-content:space-between;align-items:center;font-size:13px;display:flex}.settings-checkbox[data-v-20a39cb3]{cursor:pointer;accent-color:#1a1a1a;width:16px;height:16px}.settings-select[data-v-20a39cb3]{color:#333;cursor:pointer;background:#fff;border:1px solid #d0d0d0;border-radius:6px;outline:none;min-width:140px;padding:4px 8px;font-size:12px}.settings-select[data-v-20a39cb3]:hover{border-color:#9ca3af}.settings-select[data-v-20a39cb3]:focus{border-color:#6b7280;box-shadow:0 0 0 2px #6b728026}.settings-section-divider[data-v-20a39cb3]{align-items:center;gap:8px;margin-top:4px;display:flex}.settings-section-divider[data-v-20a39cb3]:before,.settings-section-divider[data-v-20a39cb3]:after{content:"";border-top:1px solid #e0e0e0;flex:1}.settings-section-label[data-v-20a39cb3]{color:#999;white-space:nowrap;font-size:11px}.settings-item.experimental[data-v-20a39cb3]{background:#fdf8f3;border-color:#f0e0d0}.settings-footer[data-v-20a39cb3]{background:#f8f8f8;border-top:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-right[data-v-20a39cb3]{gap:8px;display:flex}.settings-btn[data-v-20a39cb3]{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}.settings-btn svg[data-v-20a39cb3]{flex-shrink:0;width:12px;height:12px}.settings-btn.reset[data-v-20a39cb3]{color:#666;background:0 0;border-color:#d0d0d0}.settings-btn.reset[data-v-20a39cb3]:hover{color:#e74c3c;background:#e74c3c14;border-color:#c0392b}.settings-btn.cancel[data-v-20a39cb3]{color:#666;background:0 0;border-color:#d0d0d0}.settings-btn.cancel[data-v-20a39cb3]:hover{color:#333;background:#f0f0f0;border-color:#bbb}.settings-btn.confirm[data-v-20a39cb3]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.settings-btn.confirm[data-v-20a39cb3]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.settings-btn.confirm[data-v-20a39cb3]:active{box-shadow:none;transform:translateY(0)}.chart-wrapper[data-v-6e29f63e]{--kmap-height:var(--kmap-chart-height,100%);--kmap-width:var(--kmap-chart-width,100%);width:var(--kmap-width);height:var(--kmap-height);flex-direction:column;justify-content:center;align-items:center;min-height:300px;display:flex}.chart-stage[data-v-6e29f63e]{align-items:stretch;gap:8px;width:95%;height:85%;min-height:255px;display:flex}.chart-main[data-v-6e29f63e]{flex:auto;align-items:stretch;gap:0;min-width:0;height:100%;display:flex;position:relative}.pane-separator-layer[data-v-6e29f63e]{pointer-events:none;z-index:20;position:absolute;inset:0}.pane-separator-line[data-v-6e29f63e]{opacity:1;box-sizing:border-box;border-top:1px solid #e5e7eb;height:0;transition:border-top-color .12s,border-top-width .12s,margin-top .12s,opacity .12s;position:absolute;left:0;right:0}.pane-separator-line.is-active[data-v-6e29f63e]{border-top-width:2px;border-top-color:#3b82f6;margin-top:-1px}.chart-stage.is-resizing-pane[data-v-6e29f63e],.chart-stage.is-hovering-pane-separator[data-v-6e29f63e]{cursor:ns-resize}.chart-stage.is-hovering-kline[data-v-6e29f63e]{cursor:pointer}.chart-stage.is-hovering-right-axis[data-v-6e29f63e]{cursor:ns-resize}.chart-stage.is-dragging[data-v-6e29f63e]{cursor:grabbing}.chart-container[data-v-6e29f63e]{height:100%;min-height:inherit;scrollbar-width:none;-ms-overflow-style:none;box-sizing:border-box;-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;touch-action:none;background:#fff;border:1px solid #e5e7eb;border-right:0;border-radius:6px 0 0 6px;flex:auto;position:relative;overflow:auto hidden}.chart-container[data-v-6e29f63e]::-webkit-scrollbar{display:none}.right-axis-host[data-v-6e29f63e]{height:100%;min-height:inherit;box-sizing:border-box;-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;touch-action:none;background:#fff;border:1px solid #e5e7eb;border-top-right-radius:6px;border-bottom-right-radius:6px;flex:none;position:relative;overflow:visible}.scroll-content[data-v-6e29f63e]{height:100%;min-height:inherit;position:relative}.canvas-layer[data-v-6e29f63e]{pointer-events:none;position:sticky;top:0;left:0}.tooltip-layer[data-v-6e29f63e]{pointer-events:none;z-index:30;position:absolute;inset:0}.tooltip-anchor[data-v-6e29f63e]{pointer-events:none;width:1px;height:1px;position:absolute}.tooltip-anchor.kline-tooltip-anchor.use-anchor[data-v-6e29f63e]{anchor-name:--kline-tooltip-anchor}.tooltip-anchor.marker-tooltip-anchor.use-anchor[data-v-6e29f63e]{anchor-name:--marker-tooltip-anchor}@media (width<=768px),(height<=640px){.chart-stage[data-v-6e29f63e]{gap:6px}}.plot-canvas{display:block;position:absolute;top:0;left:0}.right-axis{display:block;position:absolute;left:0}.x-axis-canvas{z-index:10;display:block;position:absolute;bottom:0;left:0}.right-axis{z-index:15}
1
+ .kline-tooltip[data-v-623c9424]{z-index:10;color:#000000c7;pointer-events:none;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-623c9424]{justify-content:space-between;gap:10px;margin-bottom:6px;font-weight:600;display:flex}.kline-tooltip__grid[data-v-623c9424]{grid-template-columns:1fr;gap:2px;display:grid}.kline-tooltip__grid .row[data-v-623c9424]{justify-content:space-between;gap:10px;display:flex}.kline-tooltip__grid .row span[data-v-623c9424]:first-child{color:#0000008f}@supports (anchor-name:--kmap-anchor) and (position-anchor:--kmap-anchor){.kline-tooltip.use-anchor[data-v-623c9424]{position-anchor:--kline-tooltip-anchor;left:anchor(left);top:anchor(top);position:absolute}.kline-tooltip.use-anchor.anchor-right-bottom[data-v-623c9424]{transform:translate(14px,14px)}.kline-tooltip.use-anchor.anchor-left-bottom[data-v-623c9424]{transform:translate(calc(-100% - 14px),14px)}}.marker-tooltip[data-v-5574cc25]{z-index:10;color:#000000c7;pointer-events:none;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-5574cc25]{justify-content:space-between;gap:10px;margin-bottom:6px;font-weight:600;display:flex}.marker-tooltip__content[data-v-5574cc25]{grid-template-columns:1fr;gap:2px;display:grid}.marker-tooltip__content .row[data-v-5574cc25]{justify-content:space-between;gap:10px;display:flex}.marker-tooltip__content .row span[data-v-5574cc25]:first-child{color:#0000008f}@supports (anchor-name:--kmap-anchor) and (position-anchor:--kmap-anchor){.marker-tooltip.use-anchor[data-v-5574cc25]{position-anchor:--marker-tooltip-anchor;left:anchor(left);top:anchor(top);position:absolute}.marker-tooltip.use-anchor.anchor-right-bottom[data-v-5574cc25]{transform:translate(12px,12px)}.marker-tooltip.use-anchor.anchor-left-bottom[data-v-5574cc25]{transform:translate(calc(-100% - 12px),12px)}}.params-overlay[data-v-bb1d1eb3]{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-bb1d1eb3]{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-bb1d1eb3]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-left[data-v-bb1d1eb3]{align-items:baseline;gap:8px;display:flex}.header-right[data-v-bb1d1eb3]{align-items:center;gap:8px;display:flex}.params-title[data-v-bb1d1eb3]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.params-subtitle[data-v-bb1d1eb3]{color:#999;font-size:11px}.toggle-desc-btn[data-v-bb1d1eb3]{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-bb1d1eb3]:hover{color:#555;background:#f0f0f0;border-color:#ccc}.toggle-desc-btn.active[data-v-bb1d1eb3]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.toggle-desc-btn svg[data-v-bb1d1eb3]{width:14px;height:14px}.params-close[data-v-bb1d1eb3]{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:background .15s,color .15s,border-color .15s;display:flex}.params-close[data-v-bb1d1eb3]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.params-close svg[data-v-bb1d1eb3]{width:14px;height:14px}.indicator-description[data-v-bb1d1eb3]{background:#f0f7ff;border-bottom:1px solid #d6e8f5;padding:12px 20px}.indicator-description p[data-v-bb1d1eb3]{color:#2c5282;margin:0;font-size:12px;line-height:1.6}.params-body[data-v-bb1d1eb3]{flex-direction:column;gap:10px;padding:16px 20px;display:flex}.param-item[data-v-bb1d1eb3]{background:#f8f8f8;border:1px solid #e8e8e8;border-radius:8px;padding:10px 14px;transition:border-color .2s}.param-item[data-v-bb1d1eb3]:has(.param-input:focus){border-color:#bbb}.param-item.has-desc[data-v-bb1d1eb3]{padding:10px 14px 8px}.param-header[data-v-bb1d1eb3]{justify-content:space-between;align-items:center;gap:16px;display:flex}.param-label[data-v-bb1d1eb3]{flex-direction:column;gap:3px;display:flex}.param-label-text[data-v-bb1d1eb3]{color:#333;font-size:13px;font-weight:500}.param-range[data-v-bb1d1eb3]{color:#999;font-size:11px}.param-description[data-v-bb1d1eb3]{color:#666;border-top:1px dashed #e0e0e0;margin-top:8px;padding-top:8px;font-size:11px;line-height:1.5}.input-wrapper[data-v-bb1d1eb3]{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-bb1d1eb3]:focus-within{border-color:#999}.stepper-btn[data-v-bb1d1eb3]{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-bb1d1eb3]:hover:not(:disabled){color:#333;background:#e0e0e0}.stepper-btn[data-v-bb1d1eb3]:disabled{color:#ccc;cursor:not-allowed}.param-input[data-v-bb1d1eb3]{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-bb1d1eb3]::-webkit-inner-spin-button{-webkit-appearance:none}.param-input[data-v-bb1d1eb3]::-webkit-outer-spin-button{-webkit-appearance:none}.param-input[data-v-bb1d1eb3]:focus{outline:none}.params-footer[data-v-bb1d1eb3]{background:#f8f8f8;border-top:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-right[data-v-bb1d1eb3]{gap:8px;display:flex}.params-btn[data-v-bb1d1eb3]{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-bb1d1eb3]{flex-shrink:0;width:12px;height:12px}.params-btn.reset[data-v-bb1d1eb3]{color:#666;background:0 0;border-color:#d0d0d0}.params-btn.reset[data-v-bb1d1eb3]:hover{color:#e74c3c;background:#e74c3c14;border-color:#c0392b}.params-btn.cancel[data-v-bb1d1eb3]{color:#666;background:0 0;border-color:#d0d0d0}.params-btn.cancel[data-v-bb1d1eb3]:hover{color:#333;background:#f0f0f0;border-color:#bbb}.params-btn.confirm[data-v-bb1d1eb3]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.params-btn.confirm[data-v-bb1d1eb3]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.params-btn.confirm[data-v-bb1d1eb3]:active{box-shadow:none;transform:translateY(0)}.overlay-enter-active[data-v-bb1d1eb3],.overlay-leave-active[data-v-bb1d1eb3]{transition:opacity .2s}.overlay-enter-from[data-v-bb1d1eb3],.overlay-leave-to[data-v-bb1d1eb3]{opacity:0}.modal-enter-active[data-v-bb1d1eb3]{transition:all .22s cubic-bezier(.34,1.56,.64,1)}.modal-leave-active[data-v-bb1d1eb3]{transition:all .16s ease-in}.modal-enter-from[data-v-bb1d1eb3]{opacity:0;transform:scale(.88)translateY(-16px)}.modal-leave-to[data-v-bb1d1eb3]{opacity:0;transform:scale(.94)translateY(8px)}.slide-enter-active[data-v-bb1d1eb3],.slide-leave-active[data-v-bb1d1eb3]{transition:all .2s;overflow:hidden}.slide-enter-from[data-v-bb1d1eb3],.slide-leave-to[data-v-bb1d1eb3]{opacity:0;max-height:0;margin-top:0;padding-top:0;padding-bottom:0}.indicator-selector[data-v-e9eb306c]{width:80%;margin:20px;position:relative}.indicator-scroll-container[data-v-e9eb306c]{scrollbar-width:none;-webkit-overflow-scrolling:touch;text-align:center;width:100%;overflow:auto hidden}.indicator-scroll-container[data-v-e9eb306c]::-webkit-scrollbar{display:none}.indicator-list[data-v-e9eb306c]{gap:8px;margin:0 auto;padding:2px;display:inline-flex}.indicator-divider[data-v-e9eb306c]{background:#d9d9d9;align-self:center;width:1px;height:20px}.indicator-item[data-v-e9eb306c]{align-items:center;gap:4px;display:flex}.indicator-item.draggable[data-v-e9eb306c],.indicator-item.draggable .indicator-btn[data-v-e9eb306c],.indicator-item.draggable[data-v-e9eb306c]:hover,.indicator-item.draggable:hover .indicator-btn[data-v-e9eb306c]{cursor:move}.indicator-item.is-dragging[data-v-e9eb306c]{opacity:.6}.indicator-item.drag-over .indicator-btn[data-v-e9eb306c]{border-color:#1a1a1a;box-shadow:0 0 0 2px #1a1a1a1f}.indicator-btn-wrapper[data-v-e9eb306c]{position:relative}.indicator-btn[data-v-e9eb306c]{color:#666;cursor:pointer;white-space:nowrap;background:#fff;border:1px solid #e0e0e0;border-radius:16px;flex-shrink:0;justify-content:center;align-items:center;gap:4px;padding:6px 16px;font-size:13px;font-weight:500;transition:all .3s;display:flex;position:relative;overflow:hidden}.indicator-btn[data-v-e9eb306c]:hover:not(.hovering){color:#333;background:#f8f8f8;border-color:#ccc}.indicator-btn.active[data-v-e9eb306c]{color:#1a1a1a;background:#f8f8f8;border-color:#1a1a1a}.indicator-btn.active[data-v-e9eb306c]:hover:not(.hovering){background:#f0f0f0;border-color:#333}.btn-content[data-v-e9eb306c]{z-index:1;position:relative}.param-hint[data-v-e9eb306c]{opacity:.85;font-size:11px}.hover-overlay[data-v-e9eb306c]{backdrop-filter:blur(4px);z-index:2;background:#ffffffd9;border-radius:16px;justify-content:center;align-items:center;gap:4px;display:flex;position:absolute;inset:0}.action-btn[data-v-e9eb306c]{color:#666;cursor:pointer;background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;width:24px;height:24px;padding:0;transition:all .2s;display:flex}.action-btn[data-v-e9eb306c]:hover{color:#333;background:#0000000f}.settings-btn[data-v-e9eb306c]:hover{color:#1a1a1a}.remove-btn[data-v-e9eb306c]:hover{color:#ff4d4f}.divider[data-v-e9eb306c]{background:#e0e0e0;width:1px;height:14px}.add-btn[data-v-e9eb306c]{color:#999;cursor:pointer;background:0 0;border:1px dashed #d9d9d9;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;width:32px;height:32px;padding:0;transition:all .3s;display:flex}.add-btn[data-v-e9eb306c]:hover{color:#1a1a1a;background:#1a1a1a0a;border-color:#1a1a1a}.selector-overlay[data-v-e9eb306c]{backdrop-filter:blur(4px);z-index:1000;background:#0000004d;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.selector-modal[data-v-e9eb306c]{background:#fff;border:1px solid #e0e0e0;border-radius:12px;flex-direction:column;width:90vw;max-width:860px;max-height:85vh;display:flex;overflow:hidden;box-shadow:0 8px 40px #00000026}.modal-header[data-v-e9eb306c]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;flex-shrink:0;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-title[data-v-e9eb306c]{flex-direction:column;gap:2px;display:flex}.title-text[data-v-e9eb306c]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.title-sub[data-v-e9eb306c]{color:#999;font-size:11px}.modal-close[data-v-e9eb306c]{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 .15s;display:flex}.modal-close[data-v-e9eb306c]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.modal-close svg[data-v-e9eb306c]{width:14px;height:14px}.header-actions[data-v-e9eb306c]{align-items:center;gap:8px;display:flex}.view-toggle-btn[data-v-e9eb306c]{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 .15s;display:flex}.view-toggle-btn[data-v-e9eb306c]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.view-toggle-btn.active[data-v-e9eb306c]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.modal-body[data-v-e9eb306c]{flex-direction:column;flex:1;gap:20px;padding:20px;display:flex;overflow-y:auto}.indicator-section[data-v-e9eb306c]{flex-direction:column;gap:12px;display:flex}.section-header[data-v-e9eb306c]{align-items:center;gap:8px;display:flex}.section-title[data-v-e9eb306c]{color:#1a1a1a;font-size:13px;font-weight:600}.section-count[data-v-e9eb306c]{color:#999;background:#f0f0f0;border-radius:10px;padding:2px 8px;font-size:11px}.indicator-grid[data-v-e9eb306c]{grid-template-columns:repeat(auto-fill,minmax(195px,1fr));gap:10px;display:grid}.indicator-grid.compact[data-v-e9eb306c]{flex-wrap:wrap;gap:8px;display:flex}.indicator-grid.compact .indicator-card[data-v-e9eb306c]{white-space:nowrap;border-radius:16px;justify-content:center;align-items:center;min-height:32px;padding:6px 14px;display:inline-flex;position:relative}.indicator-grid.compact .indicator-card .card-tooltip[data-v-e9eb306c]{color:#fff;white-space:nowrap;pointer-events:none;opacity:0;z-index:10;background:#333;border-radius:6px;padding:4px 10px;font-size:12px;transition:opacity .15s;position:absolute;bottom:calc(100% + 6px);left:50%;transform:translate(-50%)}.indicator-grid.compact .indicator-card:hover .card-tooltip[data-v-e9eb306c]{opacity:1}.indicator-grid.compact .indicator-card .card-label[data-v-e9eb306c]{font-size:12px;font-weight:500}.indicator-card[data-v-e9eb306c]{cursor:pointer;text-align:left;background:#fff;border:1px solid #e8e8e8;border-radius:8px;flex-direction:column;gap:4px;padding:12px 14px;transition:all .15s;display:flex}.indicator-card[data-v-e9eb306c]:hover:not(.disabled){background:#fafafa;border-color:#1a1a1a;transform:translateY(-1px);box-shadow:0 2px 8px #0000000f}.indicator-card.active[data-v-e9eb306c]{background:#f8f8f8;border-color:#1a1a1a}.card-header[data-v-e9eb306c]{justify-content:space-between;align-items:center;gap:8px;display:flex}.card-label[data-v-e9eb306c]{color:#1a1a1a;font-size:13px;font-weight:600}.card-header-actions[data-v-e9eb306c]{align-items:center;gap:4px;display:flex}.card-settings-btn[data-v-e9eb306c]{color:#bbb;cursor:pointer;background:0 0;border:none;border-radius:4px;justify-content:center;align-items:center;width:20px;height:20px;padding:0;transition:all .15s;display:flex}.card-settings-btn[data-v-e9eb306c]:hover{color:#555;background:#f0f0f0}.card-name[data-v-e9eb306c]{color:#666;font-size:11px;line-height:1.4}.card-params[data-v-e9eb306c]{color:#999;margin-top:2px;font-size:10px}.section-divider[data-v-e9eb306c]{background:linear-gradient(90deg,#0000,#e0e0e0,#0000);height:1px;margin:4px 0}.modal-footer[data-v-e9eb306c]{background:#f8f8f8;border-top:1px solid #e8e8e8;flex-shrink:0;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-info[data-v-e9eb306c]{color:#666;font-size:12px}.info-text[data-v-e9eb306c]{color:#999}.btn[data-v-e9eb306c]{cursor:pointer;border:1px solid #0000;border-radius:7px;align-items:center;gap:5px;padding:6px 16px;font-size:13px;font-weight:500;line-height:1.4;transition:all .15s;display:flex}.btn-confirm[data-v-e9eb306c]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.btn-confirm[data-v-e9eb306c]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.fade-enter-active[data-v-e9eb306c],.fade-leave-active[data-v-e9eb306c]{transition:opacity .2s}.fade-enter-from[data-v-e9eb306c],.fade-leave-to[data-v-e9eb306c]{opacity:0}.overlay-enter-active[data-v-e9eb306c],.overlay-leave-active[data-v-e9eb306c]{transition:opacity .2s}.overlay-enter-from[data-v-e9eb306c],.overlay-leave-to[data-v-e9eb306c]{opacity:0}.modal-enter-active[data-v-e9eb306c]{transition:all .22s cubic-bezier(.34,1.56,.64,1)}.modal-leave-active[data-v-e9eb306c]{transition:all .16s ease-in}.modal-enter-from[data-v-e9eb306c]{opacity:0;transform:scale(.88)translateY(-16px)}.modal-leave-to[data-v-e9eb306c]{opacity:0;transform:scale(.94)translateY(8px)}@media (width<=640px){.selector-modal[data-v-e9eb306c]{width:95vw;max-height:90vh}.indicator-grid[data-v-e9eb306c]{grid-template-columns:1fr}.modal-body[data-v-e9eb306c]{padding:16px}}.drawing-style-toolbar[data-v-92699cb2]{-webkit-backdrop-filter:blur(8px);z-index:100;user-select:none;pointer-events:auto;background:#fafbfce0;border:1px solid #e5e7eb;border-radius:6px;align-items:center;gap:6px;height:32px;padding:4px 8px;display:flex;position:absolute;top:8px;left:50%;transform:translate(-50%);box-shadow:0 1px 3px #0000000f}.toolbar-item[data-v-92699cb2]{justify-content:center;align-items:center;display:inline-flex}.color-item[data-v-92699cb2]{width:24px;height:24px;position:relative}.color-swatch[data-v-92699cb2]{cursor:pointer;border:1px solid #d1d5db;border-radius:4px;width:100%;height:100%;display:block}.color-input[data-v-92699cb2]{opacity:0;cursor:pointer;width:100%;height:100%;position:absolute;inset:0}.toolbar-select[data-v-92699cb2]{color:#374151;cursor:pointer;background:#fff;border:1px solid #d1d5db;border-radius:4px;outline:none;height:24px;padding:0 4px;font-size:12px}.toolbar-select[data-v-92699cb2]:hover{border-color:#9ca3af}.toolbar-btn[data-v-92699cb2]{color:#6b7280;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:4px;justify-content:center;align-items:center;width:24px;height:24px;padding:0;transition:border-color .15s,background .15s,color .15s;display:inline-flex}.toolbar-btn[data-v-92699cb2]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.delete-btn[data-v-92699cb2]:hover{color:#dc2626;background:#fef2f2;border-color:#fca5a5}.delete-icon[data-v-92699cb2]{width:14px;height:14px}.left-toolbar[data-v-20a39cb3]{box-sizing:border-box;user-select:none;background:#fafbfc;border:1px solid #e5e7eb;border-radius:6px;flex-direction:column;flex:0 0 40px;align-items:center;gap:6px;padding:8px 5px;display:flex;box-shadow:0 1px 3px #0000000f}.left-toolbar__group[data-v-20a39cb3]{flex-direction:column;gap:4px;display:flex}.left-toolbar__divider[data-v-20a39cb3]{background:#e5e7eb;width:18px;height:1px}.left-toolbar__button[data-v-20a39cb3]{color:#6b7280;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:4px;justify-content:center;align-items:center;width:28px;height:28px;padding:0;transition:border-color .15s,background .15s,color .15s;display:inline-flex;position:relative}.left-toolbar__button[data-v-20a39cb3]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.left-toolbar__button.active[data-v-20a39cb3]{color:#1f2937;background:#e5e7eb;border-color:#9ca3af}.left-toolbar__button[data-v-20a39cb3]:focus-visible{border-color:#6b7280;outline:none}.tool-icon[data-v-20a39cb3]{width:16px;height:16px}.corner-indicator[data-v-20a39cb3]{cursor:pointer;width:8px;height:8px;position:absolute;bottom:0;right:0;overflow:hidden}.corner-indicator[data-v-20a39cb3]:after{content:"";opacity:.45;border-bottom:5px solid;border-left:5px solid #0000;width:0;height:0;transition:opacity .15s;position:absolute;bottom:0;right:0}.left-toolbar__button:hover .corner-indicator[data-v-20a39cb3]:after,.left-toolbar__button.active .corner-indicator[data-v-20a39cb3]:after{opacity:.7}.corner-indicator.open[data-v-20a39cb3]:after{opacity:.8}.tool-dropdown[data-v-20a39cb3]{-webkit-backdrop-filter:blur(8px);box-sizing:border-box;z-index:100;background:#fafbfcd1;border:1px solid #e5e7eb;border-radius:6px;flex-direction:row;align-items:center;gap:4px;height:40px;padding:0 5px;display:flex;position:absolute;top:50%;left:calc(100% + 13px);transform:translateY(-50%);box-shadow:0 1px 3px #0000000f}.tool-item[data-v-20a39cb3]{position:relative}.dropdown-enter-active[data-v-20a39cb3],.dropdown-leave-active[data-v-20a39cb3]{transition:opacity .15s,transform .15s}.dropdown-enter-from[data-v-20a39cb3],.dropdown-leave-to[data-v-20a39cb3]{opacity:0;transform:translateY(-50%)translate(-6px)}@media (width<=768px),(height<=640px){.left-toolbar[data-v-20a39cb3]{border-radius:5px;flex-basis:36px;gap:5px;padding:6px 4px}.left-toolbar__group[data-v-20a39cb3]{gap:3px}.left-toolbar__button[data-v-20a39cb3]{border-radius:3px;width:26px;height:26px}.left-toolbar__divider[data-v-20a39cb3]{width:16px}.corner-indicator[data-v-20a39cb3]{width:7px;height:7px}.corner-indicator[data-v-20a39cb3]:after{border-bottom-width:4px;border-left-width:4px}.tool-dropdown[data-v-20a39cb3]{height:36px}}.settings-overlay[data-v-20a39cb3]{backdrop-filter:blur(4px);z-index:1000;background:#0000004d;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.settings-modal[data-v-20a39cb3]{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}.settings-header[data-v-20a39cb3]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-left[data-v-20a39cb3]{align-items:baseline;gap:8px;display:flex}.header-right[data-v-20a39cb3]{align-items:center;gap:8px;display:flex}.settings-title[data-v-20a39cb3]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.settings-subtitle[data-v-20a39cb3]{color:#999;font-size:11px}.settings-close[data-v-20a39cb3]{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:background .15s,color .15s,border-color .15s;display:flex}.settings-close[data-v-20a39cb3]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.settings-close svg[data-v-20a39cb3]{width:14px;height:14px}.settings-body[data-v-20a39cb3]{flex-direction:column;gap:10px;padding:16px 20px;display:flex}.settings-item[data-v-20a39cb3]{background:#f8f8f8;border:1px solid #e8e8e8;border-radius:8px;padding:8px 12px}.settings-label[data-v-20a39cb3]{color:#333;cursor:pointer;justify-content:space-between;align-items:center;font-size:13px;display:flex}.settings-checkbox[data-v-20a39cb3]{cursor:pointer;accent-color:#1a1a1a;width:16px;height:16px}.settings-select[data-v-20a39cb3]{color:#333;cursor:pointer;background:#fff;border:1px solid #d0d0d0;border-radius:6px;outline:none;min-width:140px;padding:4px 8px;font-size:12px}.settings-select[data-v-20a39cb3]:hover{border-color:#9ca3af}.settings-select[data-v-20a39cb3]:focus{border-color:#6b7280;box-shadow:0 0 0 2px #6b728026}.settings-section-divider[data-v-20a39cb3]{align-items:center;gap:8px;margin-top:4px;display:flex}.settings-section-divider[data-v-20a39cb3]:before,.settings-section-divider[data-v-20a39cb3]:after{content:"";border-top:1px solid #e0e0e0;flex:1}.settings-section-label[data-v-20a39cb3]{color:#999;white-space:nowrap;font-size:11px}.settings-item.experimental[data-v-20a39cb3]{background:#fdf8f3;border-color:#f0e0d0}.settings-footer[data-v-20a39cb3]{background:#f8f8f8;border-top:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-right[data-v-20a39cb3]{gap:8px;display:flex}.settings-btn[data-v-20a39cb3]{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}.settings-btn svg[data-v-20a39cb3]{flex-shrink:0;width:12px;height:12px}.settings-btn.reset[data-v-20a39cb3]{color:#666;background:0 0;border-color:#d0d0d0}.settings-btn.reset[data-v-20a39cb3]:hover{color:#e74c3c;background:#e74c3c14;border-color:#c0392b}.settings-btn.cancel[data-v-20a39cb3]{color:#666;background:0 0;border-color:#d0d0d0}.settings-btn.cancel[data-v-20a39cb3]:hover{color:#333;background:#f0f0f0;border-color:#bbb}.settings-btn.confirm[data-v-20a39cb3]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.settings-btn.confirm[data-v-20a39cb3]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.settings-btn.confirm[data-v-20a39cb3]:active{box-shadow:none;transform:translateY(0)}.chart-wrapper[data-v-9448d063]{--kmap-height:var(--kmap-chart-height,100%);--kmap-width:var(--kmap-chart-width,100%);--chart-bg:#fff;--chart-bg-secondary:#f8f9fa;--chart-border:#e5e7eb;--chart-border-active:#3b82f6;--chart-text:#374151;--chart-text-secondary:#6b7280;width:var(--kmap-width);height:var(--kmap-height);flex-direction:column;justify-content:center;align-items:center;min-height:300px;display:flex}.chart-wrapper[data-theme=dark][data-v-9448d063]{--chart-bg:#1a1a2e;--chart-bg-secondary:#16162a;--chart-border:#2d2d44;--chart-border-active:#60a5fa;--chart-text:#e5e7eb;--chart-text-secondary:#9ca3af}.chart-stage[data-v-9448d063]{align-items:stretch;gap:8px;width:95%;height:85%;min-height:255px;display:flex}.chart-main[data-v-9448d063]{flex:auto;align-items:stretch;gap:0;min-width:0;height:100%;display:flex;position:relative}.pane-separator-layer[data-v-9448d063]{pointer-events:none;z-index:20;position:absolute;inset:0}.pane-separator-line[data-v-9448d063]{border-top:1px solid var(--chart-border);opacity:1;box-sizing:border-box;height:0;transition:border-top-color .12s,border-top-width .12s,margin-top .12s,opacity .12s;position:absolute;left:0;right:0}.pane-separator-line.is-active[data-v-9448d063]{border-top-color:var(--chart-border-active);border-top-width:2px;margin-top:-1px}.chart-stage.is-resizing-pane[data-v-9448d063],.chart-stage.is-hovering-pane-separator[data-v-9448d063]{cursor:ns-resize}.chart-stage.is-hovering-kline[data-v-9448d063]{cursor:pointer}.chart-stage.is-hovering-right-axis[data-v-9448d063]{cursor:ns-resize}.chart-stage.is-dragging[data-v-9448d063]{cursor:grabbing}.chart-container[data-v-9448d063]{height:100%;min-height:inherit;scrollbar-width:none;-ms-overflow-style:none;border:1px solid var(--chart-border);box-sizing:border-box;background:var(--chart-bg);-webkit-touch-callout:none;user-select:none;touch-action:none;border-right:0;border-radius:6px 0 0 6px;flex:auto;position:relative;overflow:auto hidden}.chart-container[data-v-9448d063]::-webkit-scrollbar{display:none}.right-axis-host[data-v-9448d063]{height:100%;min-height:inherit;box-sizing:border-box;background:var(--chart-bg);border:1px solid var(--chart-border);-webkit-touch-callout:none;user-select:none;touch-action:none;border-top-right-radius:6px;border-bottom-right-radius:6px;flex:none;position:relative;overflow:visible}.scroll-content[data-v-9448d063]{height:100%;min-height:inherit;position:relative}.canvas-layer[data-v-9448d063]{pointer-events:none;position:sticky;top:0;left:0}.tooltip-layer[data-v-9448d063]{pointer-events:none;z-index:30;position:absolute;inset:0}.tooltip-anchor[data-v-9448d063]{pointer-events:none;width:1px;height:1px;position:absolute}.tooltip-anchor.kline-tooltip-anchor.use-anchor[data-v-9448d063]{anchor-name:--kline-tooltip-anchor}.tooltip-anchor.marker-tooltip-anchor.use-anchor[data-v-9448d063]{anchor-name:--marker-tooltip-anchor}@media (width<=768px),(height<=640px){.chart-stage[data-v-9448d063]{gap:6px}}.plot-canvas{display:block;position:absolute;top:0;left:0}.right-axis{display:block;position:absolute;left:0}.x-axis-canvas{z-index:10;display:block;position:absolute;bottom:0;left:0}.right-axis{z-index:15}
2
2
  /*$vite$:1*/
@@ -1,7 +1,8 @@
1
1
  import { KLineData } from '../types/price';
2
2
  import { ChartSettings } from '../config/chartSettings';
3
+ import { Signal } from '../../packages/core/src/reactivity/signal';
3
4
  import { VisibleRange, UpdateLevel } from './layout/pane';
4
- import { InteractionController } from './controller/interaction';
5
+ import { InteractionController, InteractionSnapshot } from './controller/interaction';
5
6
  import { PaneRenderer } from './paneRenderer';
6
7
  import { MarkerManager, CustomMarkerEntity } from './marker/registry';
7
8
  import { getPhysicalKLineConfig, calcKWidthPx } from './utils/klineConfig';
@@ -9,6 +10,7 @@ import { IndicatorScheduler } from './indicators/scheduler';
9
10
  import { SubPaneEntry } from './subPaneManager';
10
11
  import { PluginHostImpl, RendererPlugin, RendererPluginWithHost, PaneRole, PaneCapabilities } from '../plugin';
11
12
  import { SubIndicatorType } from './renderers/Indicator';
13
+ export type { InteractionSnapshot };
12
14
  export { getPhysicalKLineConfig, calcKWidthPx };
13
15
  /**
14
16
  * 图表 DOM 元素引用
@@ -92,10 +94,10 @@ type ResolvedChartOptions = Omit<ChartOptions, 'kWidth' | 'kGap'> & {
92
94
  export declare class Chart {
93
95
  private dom;
94
96
  private opt;
95
- private data;
97
+ private _internalData;
96
98
  private raf;
97
99
  private pendingUpdateLevel;
98
- private viewport;
100
+ private _internalViewport;
99
101
  private paneRenderers;
100
102
  private markerManager;
101
103
  private drawingStore;
@@ -119,7 +121,7 @@ export declare class Chart {
119
121
  /** 用户设置配置(传递给渲染器) */
120
122
  private settings;
121
123
  /** pane ratio 状态(按 paneId 维护,sum=1 仅对可见 pane) */
122
- private paneRatios;
124
+ private _internalPaneRatios;
123
125
  /** 视口变化回调(供外部同步 DPR/尺寸) */
124
126
  private onViewportChange?;
125
127
  /** 共享 X 轴上下文缓存 */
@@ -214,6 +216,7 @@ export declare class Chart {
214
216
  * @param opt 初始配置
215
217
  */
216
218
  constructor(dom: ChartDom, opt: ChartOptions);
219
+ private initCoreRenderers;
217
220
  private initResizeObserver;
218
221
  private updateObservedMetrics;
219
222
  private getEffectiveDpr;
@@ -284,6 +287,10 @@ export declare class Chart {
284
287
  updateOptions(partial: Partial<ChartOptions>): void;
285
288
  /** 更新 pane 布局配置
286
289
  * @param panes 新的 pane 配置数组
290
+ *
291
+ * 显式整盘替换:清空之前 user-resize 留下的 paneRatios 缓存,让 spec 中的 ratio
292
+ * 真正生效。`addPane`/`upsertPane`/`removePaneDefinition` 走 `applyPaneLayoutSpecs`
293
+ * 时仍保留 prev 值以记住用户拖拽过的高度——只有显式的 layout replacement 才重置。
287
294
  */
288
295
  updatePaneLayout(panes: PaneSpec[]): void;
289
296
  setPaneDefinitions(defs: PaneSpec[]): void;
@@ -417,4 +424,194 @@ export declare class Chart {
417
424
  /** 计算每个 pane 的布局(top 和 height) */
418
425
  private layoutPanes;
419
426
  private computeViewport;
427
+ private _viewportSignal;
428
+ private _dataSignal;
429
+ private _themeSignal;
430
+ private _indicatorsSignal;
431
+ private _subPanesSignal;
432
+ private _drawingToolSignal;
433
+ private _drawingsSignal;
434
+ private _paneRatiosSignal;
435
+ private _interactionSignal;
436
+ /** 视口状态信号 */
437
+ get viewport(): Signal<ViewportState>;
438
+ /** 数据信号 */
439
+ get data(): Signal<ReadonlyArray<KLineData>>;
440
+ /** 主题信号 */
441
+ get theme(): Signal<'light' | 'dark'>;
442
+ /** 指标实例列表信号 */
443
+ get indicators(): Signal<ReadonlyArray<IndicatorInstance>>;
444
+ /** 子图信息信号 */
445
+ get subPanes(): Signal<ReadonlyArray<SubPaneInfo>>;
446
+ /** 当前绘图工具信号 */
447
+ get drawingTool(): Signal<DrawingToolType | null>;
448
+ /** 绘图对象列表信号 */
449
+ get drawings(): Signal<ReadonlyArray<import('../plugin').DrawingObject>>;
450
+ /** 面板比例信号 */
451
+ get paneRatios(): Signal<Readonly<Record<string, number>>>;
452
+ /** 交互状态信号 */
453
+ get interactionState(): Signal<InteractionSnapshot>;
454
+ /**
455
+ * 设置数据(高层 API)
456
+ * 内部调用 updateData,并更新 data signal
457
+ */
458
+ setData(data: KLineData[]): void;
459
+ /**
460
+ * 追加数据(高层 API)
461
+ * 合并现有数据并更新
462
+ */
463
+ appendData(newData: KLineData[]): void;
464
+ /**
465
+ * 设置主题(高层 API)
466
+ */
467
+ setTheme(theme: 'light' | 'dark'): void;
468
+ /**
469
+ * 缩放到指定级别(高层 API)
470
+ * 计算并应用新的 render state,更新 viewport signal
471
+ */
472
+ zoomToLevel(level: number, anchorX?: number): void;
473
+ /**
474
+ * 放大(高层 API)
475
+ */
476
+ zoomIn(anchorX?: number): void;
477
+ /**
478
+ * 缩小(高层 API)
479
+ */
480
+ zoomOut(anchorX?: number): void;
481
+ /**
482
+ * 内部缩放实现
483
+ * 使用 computeZoom 纯函数计算精确的 scrollLeft
484
+ */
485
+ private applyZoom;
486
+ /**
487
+ * 统一指针事件处理(零配置)
488
+ * 自动判断区域并分发给 interaction controller
489
+ *
490
+ * @param e 指针事件
491
+ * @param drawingController 可选的绘图控制器,如果提供,会优先让绘图控制器处理事件
492
+ * @returns 是否被处理(如果 drawingController 处理了返回 true,否则返回 false)
493
+ */
494
+ handlePointerEvent(e: PointerEvent, drawingController?: {
495
+ onPointerDown?: (e: PointerEvent, container: HTMLElement) => boolean;
496
+ onPointerMove?: (e: PointerEvent, container: HTMLElement) => boolean;
497
+ onPointerUp?: (e: PointerEvent, container: HTMLElement) => boolean;
498
+ }): boolean;
499
+ /**
500
+ * 滚轮事件处理(高层 API)
501
+ * 使用 computeZoom 计算精确的 scrollLeft,更新 viewport signal
502
+ */
503
+ handleWheelEvent(e: WheelEvent): void;
504
+ /**
505
+ * 滚动事件处理(高层 API)
506
+ * 更新缓存的 scrollLeft 并触发交互 controller
507
+ */
508
+ handleScrollEvent(): void;
509
+ /**
510
+ * 双指捏合缩放处理(高层 API)
511
+ * @param delta 缩放增量(+1 放大 / -1 缩小)
512
+ * @param centerClientX 捏合中心在视口中的 X 坐标
513
+ */
514
+ handlePinchZoom(delta: number, centerClientX: number): void;
515
+ /**
516
+ * 更新 viewport signal(用于滚动事件,不更新 desiredScrollLeft)
517
+ */
518
+ private updateViewportSignal;
519
+ /**
520
+ * 添加指标(高层 API,显式指定 role)
521
+ * @param definitionId 指标定义 ID(如 'MA', 'MACD')
522
+ * @param role 'main' 主图指标 或 'sub' 副图指标
523
+ * @param params 指标参数
524
+ * @returns 实例 ID(成功)或 null(失败)
525
+ */
526
+ addIndicator(definitionId: string, role: 'main' | 'sub', params?: Record<string, unknown>): string | null;
527
+ /**
528
+ * 移除指标(高层 API)
529
+ * @param instanceId 指标实例 ID
530
+ * @returns 是否成功移除
531
+ */
532
+ removeIndicator(instanceId: string): boolean;
533
+ /**
534
+ * 更新指标参数(高层 API)
535
+ * @param instanceId 指标实例 ID
536
+ * @param params 新参数
537
+ * @returns 是否成功更新
538
+ */
539
+ updateIndicatorParams(instanceId: string, params: Record<string, unknown>): boolean;
540
+ /**
541
+ * 重新排序指标(高层 API)
542
+ * @param orderedInstanceIds 排序后的指标实例 ID 数组
543
+ * @returns 是否成功
544
+ */
545
+ reorderIndicators(orderedInstanceIds: string[]): boolean;
546
+ /**
547
+ * 同步 indicators signal
548
+ */
549
+ private syncIndicatorsSignal;
550
+ /**
551
+ * 同步 sub panes signal
552
+ */
553
+ private syncSubPanesSignal;
554
+ /**
555
+ * 调整子图大小(高层 API)
556
+ * @param paneId 面板 ID
557
+ * @param deltaY 垂直偏移量
558
+ * @returns 是否成功
559
+ */
560
+ resizeSubPane(paneId: string, deltaY: number): boolean;
561
+ /**
562
+ * 设置当前绘图工具(高层 API)
563
+ * @param tool 工具类型或 null 取消选择
564
+ */
565
+ setDrawingTool(tool: DrawingToolType | null): void;
566
+ /**
567
+ * 移除绘图(高层 API)
568
+ * @param drawingId 绘图 ID
569
+ */
570
+ removeDrawing(drawingId: string): void;
571
+ /**
572
+ * 清除所有绘图(高层 API)
573
+ */
574
+ clearDrawings(): void;
575
+ /**
576
+ * 更新设置(高层 API)
577
+ * 代理到现有的 updateSettings
578
+ */
579
+ updateSettingsFacade(settings: Record<string, unknown>): void;
580
+ /**
581
+ * 更新选项(高层 API)
582
+ * 代理到现有的 updateOptions
583
+ */
584
+ updateOptionsFacade(options: Partial<ChartOptions>): void;
585
+ }
586
+ export type ViewportState = {
587
+ zoomLevel: number;
588
+ plotWidth: number;
589
+ plotHeight: number;
590
+ dpr: number;
591
+ visibleFrom: number;
592
+ visibleTo: number;
593
+ desiredScrollLeft: number | undefined;
594
+ kWidth: number;
595
+ kGap: number;
596
+ };
597
+ export type IndicatorRole = 'main' | 'sub';
598
+ export interface IndicatorInstance {
599
+ id: string;
600
+ definitionId: string;
601
+ label: string;
602
+ name: string;
603
+ role: IndicatorRole;
604
+ paneId?: string;
605
+ params: Record<string, unknown>;
606
+ }
607
+ export interface SubPaneInfo {
608
+ paneId: string;
609
+ indicatorId: string;
610
+ params: Record<string, unknown>;
611
+ ratio: number;
612
+ }
613
+ export type DrawingToolType = 'trendline' | 'horizontal' | 'fib' | 'rectangle' | 'arrow';
614
+ export interface DrawingObject {
615
+ id: string;
616
+ type: DrawingToolType;
420
617
  }
@@ -7,14 +7,14 @@
7
7
  * @param dpr - 设备像素比
8
8
  * @returns 对齐后的逻辑坐标
9
9
  */
10
- export declare function roundToPhysicalPixel(value: number, dpr: number): number;
10
+ export declare function roundToPhysicalPixel(value: number, dpr: number, theme?: 'light' | 'dark'): number;
11
11
  /**
12
12
  * 将逻辑坐标对齐到物理像素中心(用于 1px 线条)
13
13
  * @param value - 逻辑坐标值
14
14
  * @param dpr - 设备像素比
15
15
  * @returns 对齐后的逻辑坐标
16
16
  */
17
- export declare function alignToPhysicalPixelCenter(value: number, dpr: number): number;
17
+ export declare function alignToPhysicalPixelCenter(value: number, dpr: number, theme?: 'light' | 'dark'): number;
18
18
  /**
19
19
  * 对齐矩形到物理像素边界
20
20
  * @param x - 矩形左边界 X 坐标
@@ -24,7 +24,7 @@ export declare function alignToPhysicalPixelCenter(value: number, dpr: number):
24
24
  * @param dpr - 设备像素比
25
25
  * @returns 对齐后的矩形信息
26
26
  */
27
- export declare function alignRect(x: number, y: number, width: number, height: number, dpr: number): {
27
+ export declare function alignRect(x: number, y: number, width: number, height: number, dpr: number, theme?: 'light' | 'dark'): {
28
28
  x: number;
29
29
  y: number;
30
30
  width: number;
@@ -38,7 +38,7 @@ export declare function alignRect(x: number, y: number, width: number, height: n
38
38
  * @param dpr - 设备像素比
39
39
  * @returns 对齐到物理像素的矩形信息,如果 y1 和 y2 相等则返回 null
40
40
  */
41
- export declare function createVerticalLineRect(centerX: number, y1: number, y2: number, dpr: number): {
41
+ export declare function createVerticalLineRect(centerX: number, y1: number, y2: number, dpr: number, theme?: 'light' | 'dark'): {
42
42
  x: number;
43
43
  y: number;
44
44
  width: number;
@@ -52,7 +52,7 @@ export declare function createVerticalLineRect(centerX: number, y1: number, y2:
52
52
  * @param dpr - 设备像素比
53
53
  * @returns 对齐到物理像素的矩形信息,如果 x1 和 x2 相等则返回 null
54
54
  */
55
- export declare function createHorizontalLineRect(x1: number, x2: number, centerY: number, dpr: number): {
55
+ export declare function createHorizontalLineRect(x1: number, x2: number, centerY: number, dpr: number, theme?: 'light' | 'dark'): {
56
56
  x: number;
57
57
  y: number;
58
58
  width: number;
@@ -67,7 +67,7 @@ export declare function createHorizontalLineRect(x1: number, x2: number, centerY
67
67
  * @param dpr - 设备像素比
68
68
  * @returns 对齐后的实体和影线信息
69
69
  */
70
- export declare function createAlignedKLine(rectX: number, rectY: number, kWidth: number, height: number, dpr: number): {
70
+ export declare function createAlignedKLine(rectX: number, rectY: number, kWidth: number, height: number, dpr: number, theme?: 'light' | 'dark'): {
71
71
  bodyRect: {
72
72
  x: number;
73
73
  y: number;
@@ -94,7 +94,7 @@ export declare function createAlignedKLine(rectX: number, rectY: number, kWidth:
94
94
  * @param dpr - 设备像素比
95
95
  * @returns 对齐后的实体和影线信息
96
96
  */
97
- export declare function createAlignedKLineFromPx(leftPx: number, rectY: number, widthPx: number, height: number, dpr: number): {
97
+ export declare function createAlignedKLineFromPx(leftPx: number, rectY: number, widthPx: number, height: number, dpr: number, theme?: 'light' | 'dark'): {
98
98
  bodyRect: {
99
99
  x: number;
100
100
  y: number;
@@ -0,0 +1,30 @@
1
+ import { IndicatorMetadata, IndicatorCategory, StateKey, RendererFactory } from './indicatorMetadata';
2
+ import { PluginHost } from '../../plugin';
3
+ export interface IndicatorDefinitionConfig {
4
+ name: string;
5
+ displayName: string;
6
+ category: IndicatorCategory;
7
+ stateKey: StateKey;
8
+ defaultPaneId: string;
9
+ paneIdField?: keyof import('./workerProtocol').IndicatorConfigSnapshot;
10
+ allowMainPane?: boolean;
11
+ applyResult?: (host: PluginHost, state: unknown, paneId: string) => void;
12
+ }
13
+ type IndicatorDefinitionClass = {
14
+ new (...args: never[]): unknown;
15
+ rendererFactory?: RendererFactory;
16
+ };
17
+ /**
18
+ * 标准类装饰器:在模块加载时收集指标定义
19
+ *
20
+ * 使用方式:
21
+ * @Indicator({ name: 'ma', ... })
22
+ * class MADefinition {
23
+ * static rendererFactory = createMARendererPlugin
24
+ * }
25
+ */
26
+ export declare function Indicator(config: IndicatorDefinitionConfig): <T extends IndicatorDefinitionClass>(value: T, context: ClassDecoratorContext<T>) => T;
27
+ export declare function getRegisteredIndicatorDefinitions(): readonly IndicatorMetadata[];
28
+ export declare function getRegisteredIndicatorDefinition(name: string): IndicatorMetadata | undefined;
29
+ export declare function clearRegisteredIndicatorDefinitionsForTest(): void;
30
+ export {};
@@ -0,0 +1,81 @@
1
+ import { PluginHost, RendererPluginWithHost } from '../../plugin';
2
+ import { IndicatorConfigSnapshot } from './workerProtocol';
3
+ /**
4
+ * 指标分类:主图/副图
5
+ */
6
+ export type IndicatorCategory = 'main' | 'sub' | 'oscillator' | 'volume';
7
+ /**
8
+ * State key 生成器类型
9
+ * - 主图指标:常量字符串
10
+ * - 副图指标:函数,接收 paneId 返回 key
11
+ */
12
+ export type StateKey = string | ((paneId: string) => string);
13
+ /**
14
+ * 渲染器工厂函数
15
+ */
16
+ export type RendererFactory = () => RendererPluginWithHost;
17
+ /**
18
+ * 指标元数据接口
19
+ */
20
+ export interface IndicatorMetadata<T = unknown> {
21
+ /**
22
+ * 指标唯一标识
23
+ * 如:'ma', 'boll', 'rsi', 'customIndicator'
24
+ */
25
+ name: string;
26
+ /**
27
+ * 显示名称(用于日志和调试)
28
+ */
29
+ displayName: string;
30
+ /**
31
+ * 分类:主图/副图
32
+ */
33
+ category: IndicatorCategory;
34
+ /**
35
+ * StateStore key
36
+ * - 主图指标:常量字符串(如 'indicator:ma:main')
37
+ * - 副图指标:函数 (paneId) => string
38
+ */
39
+ stateKey: StateKey;
40
+ /**
41
+ * 在 configSnapshot 中的 paneId 字段名
42
+ * 用于从配置中获取当前 pane ID
43
+ */
44
+ paneIdField?: keyof IndicatorConfigSnapshot;
45
+ /**
46
+ * 渲染器工厂函数
47
+ * 调用时创建该指标的渲染器实例
48
+ */
49
+ rendererFactory: RendererFactory;
50
+ /**
51
+ * 默认 pane ID
52
+ * - 主图指标:'main'
53
+ * - 副图指标:如 'sub_RSI'
54
+ */
55
+ defaultPaneId: string;
56
+ /**
57
+ * 是否启用(可选条件判断)
58
+ * 用于副图指标根据配置决定是否参与计算
59
+ */
60
+ isEnabled?: (config: IndicatorConfigSnapshot) => boolean;
61
+ /**
62
+ * 将指标计算结果写入 StateStore
63
+ * @param host - PluginHost
64
+ * @param state - 计算结果(由 composeRenderStates 或 composeVisibleSubIndicatorStates 产出)
65
+ * @param paneId - 目标 pane ID(从 configSnapshot 读取)
66
+ */
67
+ applyResult?: (host: PluginHost, state: unknown, paneId: string) => void;
68
+ /**
69
+ * 是否允许在主图显示(部分副图指标可切换至主图)
70
+ * - true:指标可放置在主图(如 WMA/SAR/Pivot 等叠加类指标)
71
+ * - false/undefined:仅限副图显示
72
+ */
73
+ allowMainPane?: boolean;
74
+ }
75
+ /**
76
+ * 提取 stateKey 对应的实际 key 值
77
+ * @param stateKey - 可以是字符串或函数
78
+ * @param paneId - pane ID(副图指标需要)
79
+ * @returns 实际的 state key 字符串
80
+ */
81
+ export declare function resolveStateKey(stateKey: StateKey, paneId?: string): string;
@@ -0,0 +1,57 @@
1
+ import { IndicatorMetadata } from './indicatorMetadata';
2
+ /**
3
+ * IndicatorRegistry - 指标注册表
4
+ *
5
+ * 管理所有已注册指标的元数据
6
+ * 支持运行时动态注册/注销指标
7
+ */
8
+ export declare class IndicatorRegistry {
9
+ private indicators;
10
+ /**
11
+ * 注册指标
12
+ * @param meta - 指标元数据
13
+ * @throws 如果 name 为空或元数据无效
14
+ */
15
+ register<T>(meta: IndicatorMetadata<T>): void;
16
+ /**
17
+ * 注销指标
18
+ * @param name - 指标名称
19
+ * @returns 是否成功注销
20
+ */
21
+ unregister(name: string): boolean;
22
+ /**
23
+ * 获取指定指标的元数据
24
+ * @param name - 指标名称
25
+ * @returns 元数据或 undefined
26
+ */
27
+ get(name: string): IndicatorMetadata | undefined;
28
+ /**
29
+ * 检查指标是否已注册
30
+ * @param name - 指标名称
31
+ */
32
+ has(name: string): boolean;
33
+ /**
34
+ * 获取所有已注册指标
35
+ */
36
+ getAll(): readonly IndicatorMetadata[];
37
+ /**
38
+ * 获取主图指标
39
+ */
40
+ getMainIndicators(): readonly IndicatorMetadata[];
41
+ /**
42
+ * 获取副图指标
43
+ */
44
+ getSubIndicators(): readonly IndicatorMetadata[];
45
+ /**
46
+ * 获取指标名称列表
47
+ */
48
+ getNames(): string[];
49
+ /**
50
+ * 清空所有注册指标
51
+ */
52
+ clear(): void;
53
+ /**
54
+ * 获取已注册指标数量
55
+ */
56
+ get size(): number;
57
+ }
@@ -27,6 +27,10 @@ export interface RSIRenderState extends BaseIndicatorState {
27
27
  /** 视口内所有 RSI 线的最大值 */
28
28
  visibleMax: number;
29
29
  }
30
+ /**
31
+ * RSI 状态的基础 StateStore 键名
32
+ */
33
+ export declare const RSI_STATE_KEY = "indicator:rsi";
30
34
  /**
31
35
  * 创建 RSI 状态的 StateStore 键名
32
36
  * 格式:indicator:rsi:{paneId}