@363045841yyt/klinechart 0.5.0-alpha.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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-c14eedcc]{-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-c14eedcc]{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-c14eedcc]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-left[data-v-c14eedcc]{align-items:baseline;gap:8px;display:flex}.header-right[data-v-c14eedcc]{align-items:center;gap:8px;display:flex}.params-title[data-v-c14eedcc]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.params-subtitle[data-v-c14eedcc]{color:#999;font-size:11px}.toggle-desc-btn[data-v-c14eedcc]{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-c14eedcc]:hover{color:#555;background:#f0f0f0;border-color:#ccc}.toggle-desc-btn.active[data-v-c14eedcc]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.toggle-desc-btn svg[data-v-c14eedcc]{width:14px;height:14px}.params-close[data-v-c14eedcc]{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-c14eedcc]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.params-close svg[data-v-c14eedcc]{width:14px;height:14px}.indicator-description[data-v-c14eedcc]{background:#f0f7ff;border-bottom:1px solid #d6e8f5;padding:12px 20px}.indicator-description p[data-v-c14eedcc]{color:#2c5282;margin:0;font-size:12px;line-height:1.6}.params-body[data-v-c14eedcc]{flex-direction:column;gap:10px;padding:16px 20px;display:flex}.param-item[data-v-c14eedcc]{background:#f8f8f8;border:1px solid #e8e8e8;border-radius:8px;padding:10px 14px;transition:border-color .2s}.param-item[data-v-c14eedcc]:has(.param-input:focus){border-color:#bbb}.param-item.has-desc[data-v-c14eedcc]{padding:10px 14px 8px}.param-header[data-v-c14eedcc]{justify-content:space-between;align-items:center;gap:16px;display:flex}.param-label[data-v-c14eedcc]{flex-direction:column;gap:3px;display:flex}.param-label-text[data-v-c14eedcc]{color:#333;font-size:13px;font-weight:500}.param-range[data-v-c14eedcc]{color:#999;font-size:11px}.param-description[data-v-c14eedcc]{color:#666;border-top:1px dashed #e0e0e0;margin-top:8px;padding-top:8px;font-size:11px;line-height:1.5}.input-wrapper[data-v-c14eedcc]{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-c14eedcc]:focus-within{border-color:#999}.stepper-btn[data-v-c14eedcc]{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-c14eedcc]:hover:not(:disabled){color:#333;background:#e0e0e0}.stepper-btn[data-v-c14eedcc]:disabled{color:#ccc;cursor:not-allowed}.param-input[data-v-c14eedcc]{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-c14eedcc]::-webkit-inner-spin-button{-webkit-appearance:none}.param-input[data-v-c14eedcc]::-webkit-outer-spin-button{-webkit-appearance:none}.param-input[data-v-c14eedcc]:focus{outline:none}.params-footer[data-v-c14eedcc]{background:#f8f8f8;border-top:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-right[data-v-c14eedcc]{gap:8px;display:flex}.params-btn[data-v-c14eedcc]{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-c14eedcc]{flex-shrink:0;width:12px;height:12px}.params-btn.reset[data-v-c14eedcc]{color:#666;background:0 0;border-color:#d0d0d0}.params-btn.reset[data-v-c14eedcc]:hover{color:#e74c3c;background:#e74c3c14;border-color:#c0392b}.params-btn.cancel[data-v-c14eedcc]{color:#666;background:0 0;border-color:#d0d0d0}.params-btn.cancel[data-v-c14eedcc]:hover{color:#333;background:#f0f0f0;border-color:#bbb}.params-btn.confirm[data-v-c14eedcc]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.params-btn.confirm[data-v-c14eedcc]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.params-btn.confirm[data-v-c14eedcc]:active{box-shadow:none;transform:translateY(0)}.overlay-enter-active[data-v-c14eedcc],.overlay-leave-active[data-v-c14eedcc]{transition:opacity .2s}.overlay-enter-from[data-v-c14eedcc],.overlay-leave-to[data-v-c14eedcc]{opacity:0}.modal-enter-active[data-v-c14eedcc]{transition:all .22s cubic-bezier(.34,1.56,.64,1)}.modal-leave-active[data-v-c14eedcc]{transition:all .16s ease-in}.modal-enter-from[data-v-c14eedcc]{opacity:0;transform:scale(.88)translateY(-16px)}.modal-leave-to[data-v-c14eedcc]{opacity:0;transform:scale(.94)translateY(8px)}.slide-enter-active[data-v-c14eedcc],.slide-leave-active[data-v-c14eedcc]{transition:all .2s;overflow:hidden}.slide-enter-from[data-v-c14eedcc],.slide-leave-to[data-v-c14eedcc]{opacity:0;max-height:0;margin-top:0;padding-top:0;padding-bottom:0}.indicator-selector[data-v-4b90c954]{width:80%;margin:20px;position:relative}.indicator-scroll-container[data-v-4b90c954]{scrollbar-width:none;-webkit-overflow-scrolling:touch;text-align:center;width:100%;overflow:auto hidden}.indicator-scroll-container[data-v-4b90c954]::-webkit-scrollbar{display:none}.indicator-list[data-v-4b90c954]{gap:8px;margin:0 auto;padding:2px;display:inline-flex}.indicator-divider[data-v-4b90c954]{background:#d9d9d9;align-self:center;width:1px;height:20px}.indicator-item[data-v-4b90c954]{align-items:center;gap:4px;display:flex}.indicator-item.draggable[data-v-4b90c954],.indicator-item.draggable .indicator-btn[data-v-4b90c954],.indicator-item.draggable[data-v-4b90c954]:hover,.indicator-item.draggable:hover .indicator-btn[data-v-4b90c954]{cursor:move}.indicator-item.is-dragging[data-v-4b90c954]{opacity:.6}.indicator-item.drag-over .indicator-btn[data-v-4b90c954]{border-color:#1a1a1a;box-shadow:0 0 0 2px #1a1a1a1f}.indicator-btn-wrapper[data-v-4b90c954]{position:relative}.indicator-btn[data-v-4b90c954]{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-4b90c954]:hover:not(.hovering){color:#333;background:#f8f8f8;border-color:#ccc}.indicator-btn.active[data-v-4b90c954]{color:#1a1a1a;background:#f8f8f8;border-color:#1a1a1a}.indicator-btn.active[data-v-4b90c954]:hover:not(.hovering){background:#f0f0f0;border-color:#333}.btn-content[data-v-4b90c954]{z-index:1;position:relative}.param-hint[data-v-4b90c954]{opacity:.85;font-size:11px}.hover-overlay[data-v-4b90c954]{-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-4b90c954]{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-4b90c954]:hover{color:#333;background:#0000000f}.settings-btn[data-v-4b90c954]:hover{color:#1a1a1a}.remove-btn[data-v-4b90c954]:hover{color:#ff4d4f}.divider[data-v-4b90c954]{background:#e0e0e0;width:1px;height:14px}.add-btn[data-v-4b90c954]{anchor-name:--indicator-add-btn;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-4b90c954]:hover{color:#1a1a1a;background:#1a1a1a0a;border-color:#1a1a1a}.add-menu[data-v-4b90c954]{white-space:nowrap;z-index:9999;background:#fff;border-radius:8px;padding:8px 0;position:fixed;transform:translate(-50%);box-shadow:0 6px 16px #00000014,0 3px 6px -4px #0000001f,0 9px 28px 8px #0000000d}@supports (anchor-name:--kmap-anchor) and (position-anchor:--kmap-anchor){.add-menu.use-anchor[data-v-4b90c954]{position-anchor:--indicator-add-btn;left:anchor(center);top:anchor(top);max-width:calc(100vw - 16px);position:fixed;transform:translate(-50%,calc(-100% - 8px))}}.menu-section[data-v-4b90c954]{padding:4px 0}.menu-section[data-v-4b90c954]:not(:last-child){border-bottom:1px solid #f0f0f0}.menu-title[data-v-4b90c954]{color:#999;padding:4px 16px;font-size:12px;font-weight:500}.menu-items[data-v-4b90c954]{flex-direction:column;gap:2px;display:flex}.menu-item[data-v-4b90c954]{text-align:left;color:#333;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;width:100%;padding:8px 16px;font-size:13px;transition:background .2s;display:flex}.menu-item[data-v-4b90c954]:hover:not(.disabled){background:#f5f5f5}.menu-item.disabled[data-v-4b90c954]{color:#999;cursor:not-allowed}.menu-item .param-hint[data-v-4b90c954]{color:#999;font-size:11px}.active-tag[data-v-4b90c954]{color:#1a1a1a;align-items:center;margin-left:auto;display:flex}.fade-enter-active[data-v-4b90c954],.fade-leave-active[data-v-4b90c954]{transition:opacity .2s}.fade-enter-from[data-v-4b90c954],.fade-leave-to[data-v-4b90c954]{opacity:0}.slide-enter-active[data-v-4b90c954],.slide-leave-active[data-v-4b90c954]{transition:all .2s}.slide-enter-from[data-v-4b90c954],.slide-leave-to[data-v-4b90c954]{opacity:0;transform:translate(-50%)translateY(8px)}.drawing-style-toolbar[data-v-088ccef5]{-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-088ccef5]{justify-content:center;align-items:center;display:inline-flex}.color-item[data-v-088ccef5]{width:24px;height:24px;position:relative}.color-swatch[data-v-088ccef5]{cursor:pointer;border:1px solid #d1d5db;border-radius:4px;width:100%;height:100%;display:block}.color-input[data-v-088ccef5]{opacity:0;cursor:pointer;width:100%;height:100%;position:absolute;inset:0}.toolbar-select[data-v-088ccef5]{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-088ccef5]:hover{border-color:#9ca3af}.toolbar-btn[data-v-088ccef5]{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-088ccef5]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.delete-btn[data-v-088ccef5]:hover{color:#dc2626;background:#fef2f2;border-color:#fca5a5}.delete-icon[data-v-088ccef5]{width:14px;height:14px}.left-toolbar[data-v-42a7d005]{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-42a7d005]{flex-direction:column;gap:4px;display:flex}.left-toolbar__divider[data-v-42a7d005]{background:#e5e7eb;width:18px;height:1px}.left-toolbar__button[data-v-42a7d005]{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-42a7d005]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.left-toolbar__button.active[data-v-42a7d005]{color:#1f2937;background:#e5e7eb;border-color:#9ca3af}.left-toolbar__button[data-v-42a7d005]:focus-visible{border-color:#6b7280;outline:none}.tool-icon[data-v-42a7d005]{width:16px;height:16px}.corner-indicator[data-v-42a7d005]{cursor:pointer;width:8px;height:8px;position:absolute;bottom:0;right:0;overflow:hidden}.corner-indicator[data-v-42a7d005]: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-42a7d005]:after,.left-toolbar__button.active .corner-indicator[data-v-42a7d005]:after{opacity:.7}.corner-indicator.open[data-v-42a7d005]:after{opacity:.8}.tool-dropdown[data-v-42a7d005]{-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-42a7d005]{position:relative}.dropdown-enter-active[data-v-42a7d005],.dropdown-leave-active[data-v-42a7d005]{transition:opacity .15s,transform .15s}.dropdown-enter-from[data-v-42a7d005],.dropdown-leave-to[data-v-42a7d005]{opacity:0;transform:translateY(-50%)translate(-6px)}@media (width<=768px),(height<=640px){.left-toolbar[data-v-42a7d005]{border-radius:5px;flex-basis:36px;gap:5px;padding:6px 4px}.left-toolbar__group[data-v-42a7d005]{gap:3px}.left-toolbar__button[data-v-42a7d005]{border-radius:3px;width:26px;height:26px}.left-toolbar__divider[data-v-42a7d005]{width:16px}.corner-indicator[data-v-42a7d005]{width:7px;height:7px}.corner-indicator[data-v-42a7d005]:after{border-bottom-width:4px;border-left-width:4px}.tool-dropdown[data-v-42a7d005]{height:36px}}.chart-wrapper[data-v-38a3c229]{--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-38a3c229]{align-items:stretch;gap:8px;width:95%;height:85%;min-height:255px;display:flex}.chart-container[data-v-38a3c229]{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-radius:6px;flex:auto;position:relative;overflow:auto hidden}.chart-container[data-v-38a3c229]::-webkit-scrollbar{display:none}.chart-container[data-v-38a3c229]:hover{cursor:crosshair}.chart-container.is-resizing-pane[data-v-38a3c229],.chart-container.is-hovering-pane-separator[data-v-38a3c229]{cursor:row-resize}.chart-container.is-hovering-kline[data-v-38a3c229]{cursor:pointer}.chart-container:hover.is-hovering-right-axis[data-v-38a3c229]{cursor:ns-resize}.chart-container.is-dragging[data-v-38a3c229]{cursor:grabbing}.scroll-content[data-v-38a3c229]{height:100%;min-height:inherit;position:relative}.canvas-layer[data-v-38a3c229]{pointer-events:none;position:sticky;top:0;left:0}.tooltip-anchor[data-v-38a3c229]{pointer-events:none;width:1px;height:1px;position:absolute}.tooltip-anchor.kline-tooltip-anchor.use-anchor[data-v-38a3c229]{anchor-name:--kline-tooltip-anchor}.tooltip-anchor.marker-tooltip-anchor.use-anchor[data-v-38a3c229]{anchor-name:--marker-tooltip-anchor}@media (width<=768px),(height<=640px){.chart-stage[data-v-38a3c229]{gap:6px}}.plot-canvas{display:block;position:absolute;top:0;left:0}.right-axis{display:block;position:absolute}.x-axis-canvas{z-index:10;display:block;position:absolute;bottom:0;left:0}.main,.sub{border-bottom:1px solid #e0e0e0;border-right:1px solid #e0e0e0}.x-axis-canvas{border-right:1px solid #e0e0e0}.right-axis{border-bottom:1px solid #e0e0e0;border-right:1px solid #e0e0e0}
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-c14eedcc]{-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-c14eedcc]{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-c14eedcc]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-left[data-v-c14eedcc]{align-items:baseline;gap:8px;display:flex}.header-right[data-v-c14eedcc]{align-items:center;gap:8px;display:flex}.params-title[data-v-c14eedcc]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.params-subtitle[data-v-c14eedcc]{color:#999;font-size:11px}.toggle-desc-btn[data-v-c14eedcc]{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-c14eedcc]:hover{color:#555;background:#f0f0f0;border-color:#ccc}.toggle-desc-btn.active[data-v-c14eedcc]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.toggle-desc-btn svg[data-v-c14eedcc]{width:14px;height:14px}.params-close[data-v-c14eedcc]{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-c14eedcc]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.params-close svg[data-v-c14eedcc]{width:14px;height:14px}.indicator-description[data-v-c14eedcc]{background:#f0f7ff;border-bottom:1px solid #d6e8f5;padding:12px 20px}.indicator-description p[data-v-c14eedcc]{color:#2c5282;margin:0;font-size:12px;line-height:1.6}.params-body[data-v-c14eedcc]{flex-direction:column;gap:10px;padding:16px 20px;display:flex}.param-item[data-v-c14eedcc]{background:#f8f8f8;border:1px solid #e8e8e8;border-radius:8px;padding:10px 14px;transition:border-color .2s}.param-item[data-v-c14eedcc]:has(.param-input:focus){border-color:#bbb}.param-item.has-desc[data-v-c14eedcc]{padding:10px 14px 8px}.param-header[data-v-c14eedcc]{justify-content:space-between;align-items:center;gap:16px;display:flex}.param-label[data-v-c14eedcc]{flex-direction:column;gap:3px;display:flex}.param-label-text[data-v-c14eedcc]{color:#333;font-size:13px;font-weight:500}.param-range[data-v-c14eedcc]{color:#999;font-size:11px}.param-description[data-v-c14eedcc]{color:#666;border-top:1px dashed #e0e0e0;margin-top:8px;padding-top:8px;font-size:11px;line-height:1.5}.input-wrapper[data-v-c14eedcc]{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-c14eedcc]:focus-within{border-color:#999}.stepper-btn[data-v-c14eedcc]{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-c14eedcc]:hover:not(:disabled){color:#333;background:#e0e0e0}.stepper-btn[data-v-c14eedcc]:disabled{color:#ccc;cursor:not-allowed}.param-input[data-v-c14eedcc]{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-c14eedcc]::-webkit-inner-spin-button{-webkit-appearance:none}.param-input[data-v-c14eedcc]::-webkit-outer-spin-button{-webkit-appearance:none}.param-input[data-v-c14eedcc]:focus{outline:none}.params-footer[data-v-c14eedcc]{background:#f8f8f8;border-top:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-right[data-v-c14eedcc]{gap:8px;display:flex}.params-btn[data-v-c14eedcc]{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-c14eedcc]{flex-shrink:0;width:12px;height:12px}.params-btn.reset[data-v-c14eedcc]{color:#666;background:0 0;border-color:#d0d0d0}.params-btn.reset[data-v-c14eedcc]:hover{color:#e74c3c;background:#e74c3c14;border-color:#c0392b}.params-btn.cancel[data-v-c14eedcc]{color:#666;background:0 0;border-color:#d0d0d0}.params-btn.cancel[data-v-c14eedcc]:hover{color:#333;background:#f0f0f0;border-color:#bbb}.params-btn.confirm[data-v-c14eedcc]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.params-btn.confirm[data-v-c14eedcc]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.params-btn.confirm[data-v-c14eedcc]:active{box-shadow:none;transform:translateY(0)}.overlay-enter-active[data-v-c14eedcc],.overlay-leave-active[data-v-c14eedcc]{transition:opacity .2s}.overlay-enter-from[data-v-c14eedcc],.overlay-leave-to[data-v-c14eedcc]{opacity:0}.modal-enter-active[data-v-c14eedcc]{transition:all .22s cubic-bezier(.34,1.56,.64,1)}.modal-leave-active[data-v-c14eedcc]{transition:all .16s ease-in}.modal-enter-from[data-v-c14eedcc]{opacity:0;transform:scale(.88)translateY(-16px)}.modal-leave-to[data-v-c14eedcc]{opacity:0;transform:scale(.94)translateY(8px)}.slide-enter-active[data-v-c14eedcc],.slide-leave-active[data-v-c14eedcc]{transition:all .2s;overflow:hidden}.slide-enter-from[data-v-c14eedcc],.slide-leave-to[data-v-c14eedcc]{opacity:0;max-height:0;margin-top:0;padding-top:0;padding-bottom:0}.indicator-selector[data-v-4b90c954]{width:80%;margin:20px;position:relative}.indicator-scroll-container[data-v-4b90c954]{scrollbar-width:none;-webkit-overflow-scrolling:touch;text-align:center;width:100%;overflow:auto hidden}.indicator-scroll-container[data-v-4b90c954]::-webkit-scrollbar{display:none}.indicator-list[data-v-4b90c954]{gap:8px;margin:0 auto;padding:2px;display:inline-flex}.indicator-divider[data-v-4b90c954]{background:#d9d9d9;align-self:center;width:1px;height:20px}.indicator-item[data-v-4b90c954]{align-items:center;gap:4px;display:flex}.indicator-item.draggable[data-v-4b90c954],.indicator-item.draggable .indicator-btn[data-v-4b90c954],.indicator-item.draggable[data-v-4b90c954]:hover,.indicator-item.draggable:hover .indicator-btn[data-v-4b90c954]{cursor:move}.indicator-item.is-dragging[data-v-4b90c954]{opacity:.6}.indicator-item.drag-over .indicator-btn[data-v-4b90c954]{border-color:#1a1a1a;box-shadow:0 0 0 2px #1a1a1a1f}.indicator-btn-wrapper[data-v-4b90c954]{position:relative}.indicator-btn[data-v-4b90c954]{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-4b90c954]:hover:not(.hovering){color:#333;background:#f8f8f8;border-color:#ccc}.indicator-btn.active[data-v-4b90c954]{color:#1a1a1a;background:#f8f8f8;border-color:#1a1a1a}.indicator-btn.active[data-v-4b90c954]:hover:not(.hovering){background:#f0f0f0;border-color:#333}.btn-content[data-v-4b90c954]{z-index:1;position:relative}.param-hint[data-v-4b90c954]{opacity:.85;font-size:11px}.hover-overlay[data-v-4b90c954]{-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-4b90c954]{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-4b90c954]:hover{color:#333;background:#0000000f}.settings-btn[data-v-4b90c954]:hover{color:#1a1a1a}.remove-btn[data-v-4b90c954]:hover{color:#ff4d4f}.divider[data-v-4b90c954]{background:#e0e0e0;width:1px;height:14px}.add-btn[data-v-4b90c954]{anchor-name:--indicator-add-btn;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-4b90c954]:hover{color:#1a1a1a;background:#1a1a1a0a;border-color:#1a1a1a}.add-menu[data-v-4b90c954]{white-space:nowrap;z-index:9999;background:#fff;border-radius:8px;padding:8px 0;position:fixed;transform:translate(-50%);box-shadow:0 6px 16px #00000014,0 3px 6px -4px #0000001f,0 9px 28px 8px #0000000d}@supports (anchor-name:--kmap-anchor) and (position-anchor:--kmap-anchor){.add-menu.use-anchor[data-v-4b90c954]{position-anchor:--indicator-add-btn;left:anchor(center);top:anchor(top);max-width:calc(100vw - 16px);position:fixed;transform:translate(-50%,calc(-100% - 8px))}}.menu-section[data-v-4b90c954]{padding:4px 0}.menu-section[data-v-4b90c954]:not(:last-child){border-bottom:1px solid #f0f0f0}.menu-title[data-v-4b90c954]{color:#999;padding:4px 16px;font-size:12px;font-weight:500}.menu-items[data-v-4b90c954]{flex-direction:column;gap:2px;display:flex}.menu-item[data-v-4b90c954]{text-align:left;color:#333;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;width:100%;padding:8px 16px;font-size:13px;transition:background .2s;display:flex}.menu-item[data-v-4b90c954]:hover:not(.disabled){background:#f5f5f5}.menu-item.disabled[data-v-4b90c954]{color:#999;cursor:not-allowed}.menu-item .param-hint[data-v-4b90c954]{color:#999;font-size:11px}.active-tag[data-v-4b90c954]{color:#1a1a1a;align-items:center;margin-left:auto;display:flex}.fade-enter-active[data-v-4b90c954],.fade-leave-active[data-v-4b90c954]{transition:opacity .2s}.fade-enter-from[data-v-4b90c954],.fade-leave-to[data-v-4b90c954]{opacity:0}.slide-enter-active[data-v-4b90c954],.slide-leave-active[data-v-4b90c954]{transition:all .2s}.slide-enter-from[data-v-4b90c954],.slide-leave-to[data-v-4b90c954]{opacity:0;transform:translate(-50%)translateY(8px)}.drawing-style-toolbar[data-v-088ccef5]{-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-088ccef5]{justify-content:center;align-items:center;display:inline-flex}.color-item[data-v-088ccef5]{width:24px;height:24px;position:relative}.color-swatch[data-v-088ccef5]{cursor:pointer;border:1px solid #d1d5db;border-radius:4px;width:100%;height:100%;display:block}.color-input[data-v-088ccef5]{opacity:0;cursor:pointer;width:100%;height:100%;position:absolute;inset:0}.toolbar-select[data-v-088ccef5]{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-088ccef5]:hover{border-color:#9ca3af}.toolbar-btn[data-v-088ccef5]{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-088ccef5]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.delete-btn[data-v-088ccef5]:hover{color:#dc2626;background:#fef2f2;border-color:#fca5a5}.delete-icon[data-v-088ccef5]{width:14px;height:14px}.left-toolbar[data-v-42a7d005]{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-42a7d005]{flex-direction:column;gap:4px;display:flex}.left-toolbar__divider[data-v-42a7d005]{background:#e5e7eb;width:18px;height:1px}.left-toolbar__button[data-v-42a7d005]{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-42a7d005]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.left-toolbar__button.active[data-v-42a7d005]{color:#1f2937;background:#e5e7eb;border-color:#9ca3af}.left-toolbar__button[data-v-42a7d005]:focus-visible{border-color:#6b7280;outline:none}.tool-icon[data-v-42a7d005]{width:16px;height:16px}.corner-indicator[data-v-42a7d005]{cursor:pointer;width:8px;height:8px;position:absolute;bottom:0;right:0;overflow:hidden}.corner-indicator[data-v-42a7d005]: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-42a7d005]:after,.left-toolbar__button.active .corner-indicator[data-v-42a7d005]:after{opacity:.7}.corner-indicator.open[data-v-42a7d005]:after{opacity:.8}.tool-dropdown[data-v-42a7d005]{-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-42a7d005]{position:relative}.dropdown-enter-active[data-v-42a7d005],.dropdown-leave-active[data-v-42a7d005]{transition:opacity .15s,transform .15s}.dropdown-enter-from[data-v-42a7d005],.dropdown-leave-to[data-v-42a7d005]{opacity:0;transform:translateY(-50%)translate(-6px)}@media (width<=768px),(height<=640px){.left-toolbar[data-v-42a7d005]{border-radius:5px;flex-basis:36px;gap:5px;padding:6px 4px}.left-toolbar__group[data-v-42a7d005]{gap:3px}.left-toolbar__button[data-v-42a7d005]{border-radius:3px;width:26px;height:26px}.left-toolbar__divider[data-v-42a7d005]{width:16px}.corner-indicator[data-v-42a7d005]{width:7px;height:7px}.corner-indicator[data-v-42a7d005]:after{border-bottom-width:4px;border-left-width:4px}.tool-dropdown[data-v-42a7d005]{height:36px}}.chart-wrapper[data-v-eede0b8f]{--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-eede0b8f]{align-items:stretch;gap:8px;width:95%;height:85%;min-height:255px;display:flex}.chart-main[data-v-eede0b8f]{flex:auto;align-items:stretch;gap:0;min-width:0;height:100%;display:flex;position:relative}.pane-separator-layer[data-v-eede0b8f]{pointer-events:none;z-index:20;position:absolute;inset:0}.pane-separator-line[data-v-eede0b8f]{opacity:1;background:#e5e7eb;height:1px;transition:background-color .12s,box-shadow .12s,opacity .12s;position:absolute;left:1px;right:1px;transform:translateY(-.5px)}.pane-separator-line.is-active[data-v-eede0b8f]{background:#3b82f6;box-shadow:0 0 0 .5px #3b82f6e6,0 0 6px #3b82f673,0 0 12px #3b82f640}.chart-stage.is-resizing-pane[data-v-eede0b8f],.chart-stage.is-hovering-pane-separator[data-v-eede0b8f]{cursor:ns-resize}.chart-stage.is-hovering-kline[data-v-eede0b8f]{cursor:pointer}.chart-stage.is-hovering-right-axis[data-v-eede0b8f]{cursor:ns-resize}.chart-stage.is-dragging[data-v-eede0b8f]{cursor:grabbing}.chart-container[data-v-eede0b8f]{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-eede0b8f]::-webkit-scrollbar{display:none}.chart-container[data-v-eede0b8f]:hover{cursor:crosshair}.chart-stage.is-resizing-pane .chart-container[data-v-eede0b8f],.chart-stage.is-hovering-pane-separator .chart-container[data-v-eede0b8f]{cursor:ns-resize}.chart-stage.is-hovering-kline .chart-container[data-v-eede0b8f]{cursor:pointer}.chart-stage.is-dragging .chart-container[data-v-eede0b8f]{cursor:grabbing}.right-axis-host[data-v-eede0b8f]{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-top-right-radius:6px;border-bottom-right-radius:6px;flex:none;position:relative;overflow:visible}.right-axis-host[data-v-eede0b8f]:after{content:"";pointer-events:none;box-sizing:border-box;border:1px solid #e5e7eb;border-top-right-radius:6px;border-bottom-right-radius:6px;position:absolute;inset:0}.scroll-content[data-v-eede0b8f]{height:100%;min-height:inherit;position:relative}.canvas-layer[data-v-eede0b8f]{pointer-events:none;position:sticky;top:0;left:0}.tooltip-anchor[data-v-eede0b8f]{pointer-events:none;width:1px;height:1px;position:absolute}.tooltip-anchor.kline-tooltip-anchor.use-anchor[data-v-eede0b8f]{anchor-name:--kline-tooltip-anchor}.tooltip-anchor.marker-tooltip-anchor.use-anchor[data-v-eede0b8f]{anchor-name:--marker-tooltip-anchor}@media (width<=768px),(height<=640px){.chart-stage[data-v-eede0b8f]{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:999}
2
2
  /*$vite$:1*/
@@ -25,6 +25,7 @@ declare function removeSubPane(paneId: string): void;
25
25
  declare function clearAllSubPanes(): void;
26
26
  declare function switchSubIndicator(paneId: string, newIndicatorId: SubIndicatorType): void;
27
27
  declare function scrollToRight(): void;
28
+ declare function applyZoomToLevel(targetLevel: number, anchorX?: number): void;
28
29
  declare const _default: import('vue').DefineComponent<__VLS_Props, {
29
30
  scheduleRender: typeof scheduleRender;
30
31
  scrollToRight: typeof scrollToRight;
@@ -33,9 +34,9 @@ declare const _default: import('vue').DefineComponent<__VLS_Props, {
33
34
  switchSubIndicator: typeof switchSubIndicator;
34
35
  clearAllSubPanes: typeof clearAllSubPanes;
35
36
  plugin: import('../plugin').PluginHostImpl | undefined;
36
- zoomToLevel: (level: number, anchorX?: number) => void | undefined;
37
- zoomIn: (anchorX?: number) => void | undefined;
38
- zoomOut: (anchorX?: number) => void | undefined;
37
+ zoomToLevel: typeof applyZoomToLevel;
38
+ zoomIn: (anchorX?: number) => void;
39
+ zoomOut: (anchorX?: number) => void;
39
40
  getZoomLevel: () => number;
40
41
  getZoomLevelCount: () => number;
41
42
  }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
@@ -58,5 +59,6 @@ declare const _default: import('vue').DefineComponent<__VLS_Props, {
58
59
  containerRef: HTMLDivElement;
59
60
  canvasLayerRef: HTMLDivElement;
60
61
  xAxisCanvasRef: HTMLCanvasElement;
62
+ rightAxisLayerRef: HTMLDivElement;
61
63
  }, HTMLDivElement>;
62
64
  export default _default;
@@ -0,0 +1,74 @@
1
+ import { UnwrapNestedRefs } from 'vue';
2
+ import { DrawingObject } from '../plugin';
3
+ /** 右侧空白绘制槽位数(逻辑 bar 数) */
4
+ export declare const TRAILING_DRAWING_SLOTS = 24;
5
+ export interface ChartStoreOptions {
6
+ initialZoomLevel: number;
7
+ minKWidth: number;
8
+ maxKWidth: number;
9
+ zoomLevels: number;
10
+ rightAxisWidth: number;
11
+ priceLabelWidth: number;
12
+ }
13
+ export declare function computeContentWidth(params: {
14
+ dataLength: number;
15
+ kWidth: number;
16
+ kGap: number;
17
+ viewWidth: number;
18
+ viewportDpr: number;
19
+ }): number;
20
+ export declare function createChartStore(opts: ChartStoreOptions): {
21
+ state: UnwrapNestedRefs<{
22
+ zoomLevel: number;
23
+ kWidth: number;
24
+ kGap: number;
25
+ viewportDpr: number;
26
+ dataLength: number;
27
+ dataVersion: number;
28
+ paneRatios: Record<string, number>;
29
+ drawings: {
30
+ id: string;
31
+ kind: import('../plugin').DrawingKind;
32
+ paneId: string;
33
+ visible: boolean;
34
+ locked?: boolean | undefined;
35
+ zIndex?: number | undefined;
36
+ anchors: {
37
+ id: string;
38
+ index: number;
39
+ time?: number | string | undefined;
40
+ price: number;
41
+ }[];
42
+ params: Record<string, unknown>;
43
+ style: {
44
+ stroke?: string | undefined;
45
+ strokeWidth?: number | undefined;
46
+ strokeStyle?: "solid" | "dashed" | "dotted" | undefined;
47
+ fill?: string | undefined;
48
+ fillOpacity?: number | undefined;
49
+ pointRadius?: number | undefined;
50
+ textColor?: string | undefined;
51
+ fontSize?: number | undefined;
52
+ };
53
+ }[];
54
+ selectedDrawingId: string | null;
55
+ drawingVersion: number;
56
+ viewWidth: number;
57
+ }>;
58
+ computed: {
59
+ axisHostWidth: import('vue').ComputedRef<number>;
60
+ totalWidth: import('vue').ComputedRef<number>;
61
+ };
62
+ actions: {
63
+ bumpDataVersion: () => void;
64
+ bumpDrawingVersion: () => void;
65
+ setDataLength: (length: number) => void;
66
+ setViewportDpr: (dpr: number) => void;
67
+ setViewWidth: (width: number) => void;
68
+ setZoomState: (level: number, newKWidth: number, newKGap: number) => void;
69
+ setPaneRatios: (ratios: Record<string, number>) => void;
70
+ setDrawings: (newDrawings: DrawingObject[]) => void;
71
+ setSelectedDrawingId: (id: string | null) => void;
72
+ };
73
+ };
74
+ export type ChartStore = ReturnType<typeof createChartStore>;
@@ -7,6 +7,11 @@ import { getPhysicalKLineConfig, calcKWidthPx } from './utils/klineConfig';
7
7
  import { PluginHostImpl, RendererPlugin, RendererPluginWithHost, PaneRole, PaneCapabilities } from '../plugin';
8
8
  import { SubIndicatorType } from './renderers/Indicator';
9
9
  export { getPhysicalKLineConfig, calcKWidthPx };
10
+ /**
11
+ * 图表 DOM 元素引用
12
+ * @property container 图表容器 div
13
+ * @property canvasLayer Canvas 层容器 div(包含所有绘制 canvas)
14
+ */
10
15
  /**
11
16
  * 图表 DOM 元素引用
12
17
  * @property container 图表容器 div
@@ -16,6 +21,7 @@ export { getPhysicalKLineConfig, calcKWidthPx };
16
21
  export type ChartDom = {
17
22
  container: HTMLDivElement;
18
23
  canvasLayer: HTMLDivElement;
24
+ rightAxisLayer: HTMLDivElement;
19
25
  xAxisCanvas: HTMLCanvasElement;
20
26
  };
21
27
  /**
@@ -105,8 +111,8 @@ export declare class Chart {
105
111
  private onViewportChange?;
106
112
  /** pane 布局回流回调(Chart -> UI 单向) */
107
113
  private onPaneLayoutChange?;
108
- /** 缩放级别变化回调 */
109
- private onZoomLevelChange?;
114
+ /** 数据变化回调(供外部同步 dataLength) */
115
+ private onDataChange?;
110
116
  /** 当前缩放级别(1 ~ zoomLevelCount) */
111
117
  private currentZoomLevel;
112
118
  /** 缩放级别总数 */
@@ -139,61 +145,19 @@ export declare class Chart {
139
145
  /** 绘制一帧 */
140
146
  draw(): void;
141
147
  /**
142
- * 以鼠标位置为中心缩放 K 线,保持鼠标指向的 K 线位置不变
143
- * @param mouseX 鼠标相对 container 左侧的 x 坐标
144
- * @param scrollLeft 当前 container 的 scrollLeft
145
- * @param deltaY 滚动方向(大于 0 缩小,小于 0 放大)
146
- */
147
- zoomAt(mouseX: number, scrollLeft: number, deltaY: number): void;
148
- /**
149
- * 应用缩放级别(在 scrollLeft 落地后调用)
150
- * @param level 缩放级别
151
- */
152
- applyZoom(level: number): void;
153
- /** 缩放回调 */
154
- private onZoomChange?;
155
- setOnZoomChange(cb: (level: number, kWidth: number, kGap: number, targetScrollLeft: number) => void): void;
156
- /**
157
- * 将缩放级别转换为 K 线宽度
158
- * @param level 缩放级别(1 ~ zoomLevels)
159
- * @returns K 线宽度(逻辑像素)
160
- */
161
- private zoomLevelToKWidth;
162
- /**
163
- * 缩放到指定级别
164
- * @param level 目标级别(1 ~ zoomLevels)
165
- * @param anchorX 缩放中心点(相对 container 左侧的 x 坐标,默认为中心)
166
- */
167
- zoomToLevel(level: number, anchorX?: number): void;
168
- /**
169
- * 获取当前缩放级别
170
- * @returns 当前级别(1 ~ zoomLevels)
171
- */
172
- getZoomLevel(): number;
173
- /**
174
- * 获取总缩放级别数
175
- * @returns 级别总数
148
+ * 应用渲染状态(由 Vue/Store 层在状态更新后调用)
149
+ * Chart 不拥有业务 SSOT,只负责接收参数并渲染
150
+ * 这是写入 opt.kWidth/kGap currentZoomLevel 的唯一入口
176
151
  */
152
+ applyRenderState(kWidth: number, kGap: number, zoomLevel?: number): void;
153
+ /** 获取总缩放级别数 */
177
154
  getZoomLevelCount(): number;
178
- /**
179
- * 放大一级
180
- * @param anchorX 缩放中心点(默认为中心)
181
- */
182
- zoomIn(anchorX?: number): void;
183
- /**
184
- * 缩小一级
185
- * @param anchorX 缩放中心点(默认为中心)
186
- */
187
- zoomOut(anchorX?: number): void;
188
- /**
189
- * 注册缩放级别变化回调
190
- * @param cb 回调函数,参数为 (level, kWidth)
191
- */
192
- setOnZoomLevelChange(cb: (level: number, kWidth: number) => void): void;
193
155
  /** 注册视口变化回调 */
194
156
  setOnViewportChange(cb: (viewport: Viewport) => void): void;
195
157
  /** 注册 pane 布局回流回调 */
196
158
  setOnPaneLayoutChange(cb: (panes: PaneSpec[]) => void): void;
159
+ /** 注册数据变化回调 */
160
+ setOnDataChange(cb: (data: KLineData[]) => void): void;
197
161
  /** 获取所有 PaneRenderer */
198
162
  getPaneRenderers(): PaneRenderer[];
199
163
  /** 获取 MarkerManager(供 InteractionController 使用) */
@@ -292,6 +256,11 @@ export declare class Chart {
292
256
  updateData(data: KLineData[]): void;
293
257
  /** 获取当前数据源(供 renderers 和 interaction 使用) */
294
258
  getData(): KLineData[];
259
+ private getTrailingSlotCount;
260
+ getLogicalSlotCount(): number;
261
+ getTimestampAtLogicalIndex(index: number): number | null;
262
+ /** 根据视口内 X 坐标反查逻辑索引(允许超出最后一根 K 线) */
263
+ getLogicalIndexAtX(mouseX: number): number | null;
295
264
  /** 根据视口内 X 坐标反查数据索引(用于绘图落点) */
296
265
  getDataIndexAtX(mouseX: number): number | null;
297
266
  /** 获取内容总宽度(用于外部 scroll-content 撑开 scrollWidth) */
@@ -1,6 +1,5 @@
1
1
  import { Chart } from '../chart';
2
2
  import { MarkerEntity, CustomMarkerEntity } from '../marker/registry';
3
- /** 标记 hover 事件数据 */
4
3
  export interface InteractionSnapshot {
5
4
  crosshairPos: {
6
5
  x: number;
@@ -20,6 +19,7 @@ export interface InteractionSnapshot {
20
19
  isDragging: boolean;
21
20
  isResizingPaneBoundary: boolean;
22
21
  isHoveringPaneBoundary: boolean;
22
+ hoveredPaneBoundaryId: string | null;
23
23
  isHoveringRightAxis: boolean;
24
24
  }
25
25
  /**
@@ -31,6 +31,7 @@ export declare class InteractionController {
31
31
  private dragMode;
32
32
  private dragStartX;
33
33
  private scrollStartX;
34
+ private applyPanScroll;
34
35
  /** 垂直拖动相关 */
35
36
  private dragStartY;
36
37
  private activePaneIdOnDrag;
@@ -98,11 +99,6 @@ export declare class InteractionController {
98
99
  getInteractionSnapshot(): InteractionSnapshot;
99
100
  setOnInteractionChange(callback: (snapshot: InteractionSnapshot) => void): void;
100
101
  private notifyInteractionChange;
101
- /**
102
- * 处理滚轮缩放事件
103
- * @param e WheelEvent
104
- */
105
- onWheel(e: WheelEvent): void;
106
102
  /**
107
103
  * [触屏]:处理 Pointer 按下事件
108
104
  * @param e PointerEvent
@@ -127,20 +123,6 @@ export declare class InteractionController {
127
123
  * @param e PointerEvent
128
124
  */
129
125
  onPointerLeave(e: PointerEvent): void;
130
- /**
131
- * 处理鼠标按下事件
132
- * @param e MouseEvent
133
- */
134
- onMouseDown(e: MouseEvent): void;
135
- /**
136
- * 处理鼠标移动事件
137
- * @param e MouseEvent
138
- */
139
- onMouseMove(e: MouseEvent): void;
140
- /** 处理鼠标抬起事件 */
141
- onMouseUp(): void;
142
- /** 处理鼠标离开事件 */
143
- onMouseLeave(): void;
144
126
  /** 处理滚动事件 */
145
127
  onScroll(): void;
146
128
  /**
@@ -158,14 +140,12 @@ export declare class InteractionController {
158
140
  start: number;
159
141
  end: number;
160
142
  } | null, kWidthPx?: number): void;
143
+ onRightAxisPointerDown(e: PointerEvent): void;
144
+ onRightAxisPointerMove(e: PointerEvent): void;
145
+ onRightAxisPointerUp(e: PointerEvent): void;
146
+ onRightAxisPointerLeave(e: PointerEvent): void;
161
147
  /** 检查是否正在拖拽 */
162
148
  isDraggingState(): boolean;
163
- /** 是否处于分隔线拖拽状态 */
164
- isResizingPaneBoundaryState(): boolean;
165
- /** 是否悬停在可拖拽分隔线上 */
166
- isHoveringPaneBoundaryState(): boolean;
167
- /** 是否悬停在右轴区域 */
168
- isHoveringRightAxisState(): boolean;
169
149
  /** 设置 marker hover 回调 */
170
150
  setOnMarkerHover(callback: (marker: MarkerEntity | null) => void): void;
171
151
  /** 设置 marker click 回调 */
@@ -176,15 +156,19 @@ export declare class InteractionController {
176
156
  setOnCustomMarkerClick(callback: (marker: CustomMarkerEntity) => void): void;
177
157
  /** 命中可拖拽分隔线(返回上方 paneId) */
178
158
  private hitTestPaneSeparator;
179
- /** 清除 hover 状态 */
180
- private clearHover;
159
+ private getPaneByY;
160
+ private getPlotPointerLocation;
161
+ private getRightAxisPointerLocation;
162
+ private beginScalePriceDrag;
163
+ clearHover(): void;
181
164
  private clearSeparatorState;
182
165
  /**
183
166
  * 从屏幕坐标更新 hover 状态
184
167
  * @param clientX 屏幕 x 坐标
185
168
  * @param clientY 屏幕 y 坐标
186
169
  */
187
- private updateHoverFromPoint;
170
+ private updateRightAxisHoverFromPoint;
171
+ private updatePlotHoverFromPoint;
188
172
  /**
189
173
  * 重置所有交互状态(数据更新时调用)
190
174
  */
@@ -2,7 +2,8 @@ import { DrawingObject, DrawingStyle } from '../../plugin';
2
2
  import { Chart } from '../chart';
3
3
  export type DrawingToolId = 'cursor' | 'trend-line' | 'ray' | 'h-line' | 'h-ray' | 'v-line' | 'crosshair-line' | 'info-line';
4
4
  export interface DrawingAnchorInput {
5
- time: number;
5
+ index: number;
6
+ time?: number;
6
7
  price: number;
7
8
  }
8
9
  export interface DrawingInteractionCallbacks {
@@ -31,6 +31,11 @@ export declare class PriceScale {
31
31
  * 重置价格偏移量
32
32
  */
33
33
  resetPriceOffset(): void;
34
+ /**
35
+ * 根据当前 range 和 verticalScale 对 priceOffset 进行 clamp,
36
+ * 防止视口完全离开数据范围。
37
+ */
38
+ private clampOffset;
34
39
  /**
35
40
  * 按拖拽位移缩放 Y 轴(deltaY < 0 放大,deltaY > 0 缩小)
36
41
  */
@@ -0,0 +1,30 @@
1
+ /**
2
+ * 缩放计算纯函数
3
+ * 无副作用、无 DOM 访问,供 Vue 层直接调用
4
+ */
5
+ export interface ZoomConfig {
6
+ minKWidth: number;
7
+ maxKWidth: number;
8
+ zoomLevelCount: number;
9
+ dpr: number;
10
+ }
11
+ export interface ZoomResult {
12
+ targetLevel: number;
13
+ newKWidth: number;
14
+ newKGap: number;
15
+ newScrollLeft: number;
16
+ }
17
+ /** 将缩放级别转换为 K 线宽度(逻辑像素) */
18
+ export declare function zoomLevelToKWidth(level: number, config: ZoomConfig): number;
19
+ /** 由 DPR 推导 K 线间隙(逻辑像素) */
20
+ export declare function kGapFromDpr(dpr: number): number;
21
+ /**
22
+ * 缩放一级(+1 放大 / -1 缩小)
23
+ * 返回新状态或 null(已达边界)
24
+ */
25
+ export declare function computeZoom(delta: number, mouseX: number, scrollLeft: number, currentLevel: number, currentKWidth: number, currentKGap: number, config: ZoomConfig): ZoomResult | null;
26
+ /**
27
+ * 缩放到指定级别
28
+ * 返回新状态或 null(级别不变或无效)
29
+ */
30
+ export declare function computeZoomToLevel(targetLevel: number, anchorX: number, scrollLeft: number, currentLevel: number, currentKWidth: number, currentKGap: number, config: ZoomConfig): ZoomResult | null;
@@ -177,7 +177,8 @@ export interface RenderContext {
177
177
  }
178
178
  export type DrawingAnchor = {
179
179
  id: string;
180
- time: number | string;
180
+ index: number;
181
+ time?: number | string;
181
182
  price: number;
182
183
  };
183
184
  export type DrawingKind = 'trend-line' | 'ray' | 'extended-line' | 'horizontal-line' | 'horizontal-ray' | 'vertical-line' | 'cross-line' | 'info-line' | 'parallel-channel' | 'regression-channel';
package/package.json CHANGED
@@ -1,65 +1,66 @@
1
- {
2
- "name": "@363045841yyt/klinechart",
3
- "version": "0.5.0-alpha.1",
4
- "type": "module",
5
- "engines": {
6
- "node": "^20.19.0 || >=22.12.0"
7
- },
8
- "scripts": {
9
- "dev": "vite",
10
- "dev:lan": "vite --host 0.0.0.0",
11
- "stockbao": "cd .. && cd stockbao && uv run python ./server.py",
12
- "aktools": "cd .. && cd aktoolshttp && uv run python -m aktools",
13
- "build": "run-p type-check \"build-only {@}\" --",
14
- "build-only": "vite build",
15
- "build:demo": "vite build --config vite.demo.config.ts",
16
- "preview": "vite preview",
17
- "type-check": "vue-tsc --build",
18
- "test:unit": "vitest",
19
- "format": "prettier --write --experimental-cli src/",
20
- "prepublishOnly": "pnpm run build-only"
21
- },
22
- "main": "./dist/index.cjs",
23
- "module": "./dist/index.js",
24
- "types": "./dist/index.d.ts",
25
- "exports": {
26
- ".": {
27
- "types": "./dist/index.d.ts",
28
- "import": "./dist/index.js",
29
- "require": "./dist/index.cjs"
30
- },
31
- "./style.css": "./dist/klinechart.css"
32
- },
33
- "files": [
34
- "dist"
35
- ],
36
- "peerDependencies": {
37
- "vue": "^3.5.0"
38
- },
39
- "dependencies": {
40
- "ajv": "^8.20.0",
41
- "axios": "^1.16.0"
42
- },
43
- "devDependencies": {
44
- "@iconify-json/tabler": "^1.2.34",
45
- "@tsconfig/node24": "^24.0.4",
46
- "@types/jsdom": "^28.0.1",
47
- "@types/node": "^25.6.0",
48
- "@vitejs/plugin-vue": "^6.0.6",
49
- "@vitest/coverage-v8": "^4.1.5",
50
- "@vue/test-utils": "^2.4.10",
51
- "@vue/tsconfig": "^0.9.1",
52
- "jsdom": "^29.1.1",
53
- "npm-run-all2": "^8.0.4",
54
- "prettier": "3.8.3",
55
- "typedoc": "^0.28.19",
56
- "typescript": "~6.0.3",
57
- "unplugin-icons": "^23.0.1",
58
- "unplugin-vue-components": "^32.0.0",
59
- "vite": "^8.0.10",
60
- "vite-plugin-dts": "^4.5.4",
61
- "vite-plugin-vue-devtools": "^8.1.1",
62
- "vitest": "^4.1.5",
63
- "vue-tsc": "^3.2.8"
64
- }
1
+ {
2
+ "name": "@363045841yyt/klinechart",
3
+ "version": "0.5.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": "^20.19.0 || >=22.12.0"
8
+ },
9
+ "scripts": {
10
+ "dev": "vite",
11
+ "dev:lan": "vite --host 0.0.0.0",
12
+ "stockbao": "cd .. && cd stockbao && uv run python ./server.py",
13
+ "aktools": "cd .. && cd aktoolshttp && uv run python -m aktools",
14
+ "build": "run-p type-check \"build-only {@}\" --",
15
+ "build-only": "vite build",
16
+ "build:demo": "vite build --config vite.demo.config.ts",
17
+ "preview": "vite preview",
18
+ "type-check": "vue-tsc --build",
19
+ "test:unit": "vitest",
20
+ "format": "prettier --write --experimental-cli src/",
21
+ "prepublishOnly": "pnpm run build-only"
22
+ },
23
+ "main": "./dist/index.cjs",
24
+ "module": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js",
30
+ "require": "./dist/index.cjs"
31
+ },
32
+ "./style.css": "./dist/klinechart.css"
33
+ },
34
+ "files": [
35
+ "dist"
36
+ ],
37
+ "peerDependencies": {
38
+ "vue": "^3.5.0"
39
+ },
40
+ "dependencies": {
41
+ "ajv": "^8.20.0",
42
+ "axios": "^1.16.0"
43
+ },
44
+ "devDependencies": {
45
+ "@iconify-json/tabler": "^1.2.34",
46
+ "@tsconfig/node24": "^24.0.4",
47
+ "@types/jsdom": "^28.0.1",
48
+ "@types/node": "^25.6.0",
49
+ "@vitejs/plugin-vue": "^6.0.6",
50
+ "@vitest/coverage-v8": "^4.1.5",
51
+ "@vue/test-utils": "^2.4.10",
52
+ "@vue/tsconfig": "^0.9.1",
53
+ "jsdom": "^29.1.1",
54
+ "npm-run-all2": "^8.0.4",
55
+ "prettier": "3.8.3",
56
+ "typedoc": "^0.28.19",
57
+ "typescript": "~6.0.3",
58
+ "unplugin-icons": "^23.0.1",
59
+ "unplugin-vue-components": "^32.0.0",
60
+ "vite": "^8.0.10",
61
+ "vite-plugin-dts": "^4.5.4",
62
+ "vite-plugin-vue-devtools": "^8.1.1",
63
+ "vitest": "^4.1.5",
64
+ "vue-tsc": "^3.2.8"
65
+ }
65
66
  }