@363045841yyt/klinechart 0.5.5-alpha.0 → 0.5.6

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-f1125609]{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-f1125609]{flex-direction:column;gap:4px;display:flex}.left-toolbar__divider[data-v-f1125609]{background:#e5e7eb;width:18px;height:1px}.left-toolbar__button[data-v-f1125609]{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-f1125609]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.left-toolbar__button.active[data-v-f1125609]{color:#1f2937;background:#e5e7eb;border-color:#9ca3af}.left-toolbar__button[data-v-f1125609]:focus-visible{border-color:#6b7280;outline:none}.tool-icon[data-v-f1125609]{width:16px;height:16px}.corner-indicator[data-v-f1125609]{cursor:pointer;width:8px;height:8px;position:absolute;bottom:0;right:0;overflow:hidden}.corner-indicator[data-v-f1125609]: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-f1125609]:after,.left-toolbar__button.active .corner-indicator[data-v-f1125609]:after{opacity:.7}.corner-indicator.open[data-v-f1125609]:after{opacity:.8}.tool-dropdown[data-v-f1125609]{-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-f1125609]{position:relative}.dropdown-enter-active[data-v-f1125609],.dropdown-leave-active[data-v-f1125609]{transition:opacity .15s,transform .15s}.dropdown-enter-from[data-v-f1125609],.dropdown-leave-to[data-v-f1125609]{opacity:0;transform:translateY(-50%)translate(-6px)}@media (width<=768px),(height<=640px){.left-toolbar[data-v-f1125609]{border-radius:5px;flex-basis:36px;gap:5px;padding:6px 4px}.left-toolbar__group[data-v-f1125609]{gap:3px}.left-toolbar__button[data-v-f1125609]{border-radius:3px;width:26px;height:26px}.left-toolbar__divider[data-v-f1125609]{width:16px}.corner-indicator[data-v-f1125609]{width:7px;height:7px}.corner-indicator[data-v-f1125609]:after{border-bottom-width:4px;border-left-width:4px}.tool-dropdown[data-v-f1125609]{height:36px}}.chart-wrapper[data-v-c53b9583]{--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-c53b9583]{align-items:stretch;gap:8px;width:95%;height:85%;min-height:255px;display:flex}.chart-main[data-v-c53b9583]{flex:auto;align-items:stretch;gap:0;min-width:0;height:100%;display:flex;position:relative}.pane-separator-layer[data-v-c53b9583]{pointer-events:none;z-index:20;position:absolute;inset:0}.pane-separator-line[data-v-c53b9583]{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-c53b9583]{border-top-width:2px;border-top-color:#3b82f6;margin-top:-1px}.chart-stage.is-resizing-pane[data-v-c53b9583],.chart-stage.is-hovering-pane-separator[data-v-c53b9583]{cursor:ns-resize}.chart-stage.is-hovering-kline[data-v-c53b9583]{cursor:pointer}.chart-stage.is-hovering-right-axis[data-v-c53b9583]{cursor:ns-resize}.chart-stage.is-dragging[data-v-c53b9583]{cursor:grabbing}.chart-container[data-v-c53b9583]{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-c53b9583]::-webkit-scrollbar{display:none}.chart-container[data-v-c53b9583]:hover{cursor:crosshair}.chart-stage.is-resizing-pane .chart-container[data-v-c53b9583],.chart-stage.is-hovering-pane-separator .chart-container[data-v-c53b9583]{cursor:ns-resize}.chart-stage.is-hovering-kline .chart-container[data-v-c53b9583]{cursor:pointer}.chart-stage.is-dragging .chart-container[data-v-c53b9583]{cursor:grabbing}.right-axis-host[data-v-c53b9583]{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-c53b9583]{height:100%;min-height:inherit;position:relative}.canvas-layer[data-v-c53b9583]{pointer-events:none;position:sticky;top:0;left:0}.tooltip-layer[data-v-c53b9583]{pointer-events:none;z-index:30;position:absolute;inset:0}.tooltip-anchor[data-v-c53b9583]{pointer-events:none;width:1px;height:1px;position:absolute}.tooltip-anchor.kline-tooltip-anchor.use-anchor[data-v-c53b9583]{anchor-name:--kline-tooltip-anchor}.tooltip-anchor.marker-tooltip-anchor.use-anchor[data-v-c53b9583]{anchor-name:--marker-tooltip-anchor}@media (width<=768px),(height<=640px){.chart-stage[data-v-c53b9583]{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-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-0f3a76b5]{width:80%;margin:20px;position:relative}.indicator-scroll-container[data-v-0f3a76b5]{scrollbar-width:none;-webkit-overflow-scrolling:touch;text-align:center;width:100%;overflow:auto hidden}.indicator-scroll-container[data-v-0f3a76b5]::-webkit-scrollbar{display:none}.indicator-list[data-v-0f3a76b5]{gap:8px;margin:0 auto;padding:2px;display:inline-flex}.indicator-divider[data-v-0f3a76b5]{background:#d9d9d9;align-self:center;width:1px;height:20px}.indicator-item[data-v-0f3a76b5]{align-items:center;gap:4px;display:flex}.indicator-item.draggable[data-v-0f3a76b5],.indicator-item.draggable .indicator-btn[data-v-0f3a76b5],.indicator-item.draggable[data-v-0f3a76b5]:hover,.indicator-item.draggable:hover .indicator-btn[data-v-0f3a76b5]{cursor:move}.indicator-item.is-dragging[data-v-0f3a76b5]{opacity:.6}.indicator-item.drag-over .indicator-btn[data-v-0f3a76b5]{border-color:#1a1a1a;box-shadow:0 0 0 2px #1a1a1a1f}.indicator-btn-wrapper[data-v-0f3a76b5]{position:relative}.indicator-btn[data-v-0f3a76b5]{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-0f3a76b5]:hover:not(.hovering){color:#333;background:#f8f8f8;border-color:#ccc}.indicator-btn.active[data-v-0f3a76b5]{color:#1a1a1a;background:#f8f8f8;border-color:#1a1a1a}.indicator-btn.active[data-v-0f3a76b5]:hover:not(.hovering){background:#f0f0f0;border-color:#333}.btn-content[data-v-0f3a76b5]{z-index:1;position:relative}.param-hint[data-v-0f3a76b5]{opacity:.85;font-size:11px}.hover-overlay[data-v-0f3a76b5]{-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-0f3a76b5]{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-0f3a76b5]:hover{color:#333;background:#0000000f}.settings-btn[data-v-0f3a76b5]:hover{color:#1a1a1a}.remove-btn[data-v-0f3a76b5]:hover{color:#ff4d4f}.divider[data-v-0f3a76b5]{background:#e0e0e0;width:1px;height:14px}.add-btn[data-v-0f3a76b5]{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-0f3a76b5]:hover{color:#1a1a1a;background:#1a1a1a0a;border-color:#1a1a1a}.add-menu[data-v-0f3a76b5]{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-0f3a76b5]{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-0f3a76b5]{padding:4px 0}.menu-section[data-v-0f3a76b5]:not(:last-child){border-bottom:1px solid #f0f0f0}.menu-title[data-v-0f3a76b5]{color:#999;padding:4px 16px;font-size:12px;font-weight:500}.menu-items[data-v-0f3a76b5]{flex-direction:column;gap:2px;display:flex}.menu-item[data-v-0f3a76b5]{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-0f3a76b5]:hover:not(.disabled){background:#f5f5f5}.menu-item.disabled[data-v-0f3a76b5]{color:#999;cursor:not-allowed}.menu-item .param-hint[data-v-0f3a76b5]{color:#999;font-size:11px}.active-tag[data-v-0f3a76b5]{color:#1a1a1a;align-items:center;margin-left:auto;display:flex}.fade-enter-active[data-v-0f3a76b5],.fade-leave-active[data-v-0f3a76b5]{transition:opacity .2s}.fade-enter-from[data-v-0f3a76b5],.fade-leave-to[data-v-0f3a76b5]{opacity:0}.slide-enter-active[data-v-0f3a76b5],.slide-leave-active[data-v-0f3a76b5]{transition:all .2s}.slide-enter-from[data-v-0f3a76b5],.slide-leave-to[data-v-0f3a76b5]{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-1f5465f7]{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-1f5465f7]{flex-direction:column;gap:4px;display:flex}.left-toolbar__divider[data-v-1f5465f7]{background:#e5e7eb;width:18px;height:1px}.left-toolbar__button[data-v-1f5465f7]{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-1f5465f7]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.left-toolbar__button.active[data-v-1f5465f7]{color:#1f2937;background:#e5e7eb;border-color:#9ca3af}.left-toolbar__button[data-v-1f5465f7]:focus-visible{border-color:#6b7280;outline:none}.tool-icon[data-v-1f5465f7]{width:16px;height:16px}.corner-indicator[data-v-1f5465f7]{cursor:pointer;width:8px;height:8px;position:absolute;bottom:0;right:0;overflow:hidden}.corner-indicator[data-v-1f5465f7]: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-1f5465f7]:after,.left-toolbar__button.active .corner-indicator[data-v-1f5465f7]:after{opacity:.7}.corner-indicator.open[data-v-1f5465f7]:after{opacity:.8}.tool-dropdown[data-v-1f5465f7]{-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-1f5465f7]{position:relative}.dropdown-enter-active[data-v-1f5465f7],.dropdown-leave-active[data-v-1f5465f7]{transition:opacity .15s,transform .15s}.dropdown-enter-from[data-v-1f5465f7],.dropdown-leave-to[data-v-1f5465f7]{opacity:0;transform:translateY(-50%)translate(-6px)}@media (width<=768px),(height<=640px){.left-toolbar[data-v-1f5465f7]{border-radius:5px;flex-basis:36px;gap:5px;padding:6px 4px}.left-toolbar__group[data-v-1f5465f7]{gap:3px}.left-toolbar__button[data-v-1f5465f7]{border-radius:3px;width:26px;height:26px}.left-toolbar__divider[data-v-1f5465f7]{width:16px}.corner-indicator[data-v-1f5465f7]{width:7px;height:7px}.corner-indicator[data-v-1f5465f7]:after{border-bottom-width:4px;border-left-width:4px}.tool-dropdown[data-v-1f5465f7]{height:36px}}.settings-overlay[data-v-1f5465f7]{-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-1f5465f7]{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-1f5465f7]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-left[data-v-1f5465f7]{align-items:baseline;gap:8px;display:flex}.header-right[data-v-1f5465f7]{align-items:center;gap:8px;display:flex}.settings-title[data-v-1f5465f7]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.settings-subtitle[data-v-1f5465f7]{color:#999;font-size:11px}.settings-close[data-v-1f5465f7]{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-1f5465f7]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.settings-close svg[data-v-1f5465f7]{width:14px;height:14px}.settings-body[data-v-1f5465f7]{flex-direction:column;gap:10px;padding:16px 20px;display:flex}.settings-item[data-v-1f5465f7]{background:#f8f8f8;border:1px solid #e8e8e8;border-radius:8px;padding:8px 12px}.settings-label[data-v-1f5465f7]{color:#333;cursor:pointer;justify-content:space-between;align-items:center;font-size:13px;display:flex}.settings-checkbox[data-v-1f5465f7]{cursor:pointer;accent-color:#1a1a1a;width:16px;height:16px}.settings-footer[data-v-1f5465f7]{background:#f8f8f8;border-top:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-right[data-v-1f5465f7]{gap:8px;display:flex}.settings-btn[data-v-1f5465f7]{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-1f5465f7]{flex-shrink:0;width:12px;height:12px}.settings-btn.reset[data-v-1f5465f7]{color:#666;background:0 0;border-color:#d0d0d0}.settings-btn.reset[data-v-1f5465f7]:hover{color:#e74c3c;background:#e74c3c14;border-color:#c0392b}.settings-btn.cancel[data-v-1f5465f7]{color:#666;background:0 0;border-color:#d0d0d0}.settings-btn.cancel[data-v-1f5465f7]:hover{color:#333;background:#f0f0f0;border-color:#bbb}.settings-btn.confirm[data-v-1f5465f7]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.settings-btn.confirm[data-v-1f5465f7]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.settings-btn.confirm[data-v-1f5465f7]:active{box-shadow:none;transform:translateY(0)}.chart-wrapper[data-v-fff9d345]{--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-fff9d345]{align-items:stretch;gap:8px;width:95%;height:85%;min-height:255px;display:flex}.chart-main[data-v-fff9d345]{flex:auto;align-items:stretch;gap:0;min-width:0;height:100%;display:flex;position:relative}.pane-separator-layer[data-v-fff9d345]{pointer-events:none;z-index:20;position:absolute;inset:0}.pane-separator-line[data-v-fff9d345]{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-fff9d345]{border-top-width:2px;border-top-color:#3b82f6;margin-top:-1px}.chart-stage.is-resizing-pane[data-v-fff9d345],.chart-stage.is-hovering-pane-separator[data-v-fff9d345]{cursor:ns-resize}.chart-stage.is-hovering-kline[data-v-fff9d345]{cursor:pointer}.chart-stage.is-hovering-right-axis[data-v-fff9d345]{cursor:ns-resize}.chart-stage.is-dragging[data-v-fff9d345]{cursor:grabbing}.chart-container[data-v-fff9d345]{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-fff9d345]::-webkit-scrollbar{display:none}.chart-container[data-v-fff9d345]:hover{cursor:crosshair}.chart-stage.is-resizing-pane .chart-container[data-v-fff9d345],.chart-stage.is-hovering-pane-separator .chart-container[data-v-fff9d345]{cursor:ns-resize}.chart-stage.is-hovering-kline .chart-container[data-v-fff9d345]{cursor:pointer}.chart-stage.is-dragging .chart-container[data-v-fff9d345]{cursor:grabbing}.right-axis-host[data-v-fff9d345]{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-fff9d345]{height:100%;min-height:inherit;position:relative}.canvas-layer[data-v-fff9d345]{pointer-events:none;position:sticky;top:0;left:0}.tooltip-layer[data-v-fff9d345]{pointer-events:none;z-index:30;position:absolute;inset:0}.tooltip-anchor[data-v-fff9d345]{pointer-events:none;width:1px;height:1px;position:absolute}.tooltip-anchor.kline-tooltip-anchor.use-anchor[data-v-fff9d345]{anchor-name:--kline-tooltip-anchor}.tooltip-anchor.marker-tooltip-anchor.use-anchor[data-v-fff9d345]{anchor-name:--marker-tooltip-anchor}@media (width<=768px),(height<=640px){.chart-stage[data-v-fff9d345]{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*/
@@ -56,6 +56,40 @@ declare const _default: import('vue').DefineComponent<__VLS_Props, {
56
56
  initialZoomLevel: number;
57
57
  isFullscreen: boolean;
58
58
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
59
+ toolbarRef: import('vue').CreateComponentPublicInstanceWithMixins<Readonly<{
60
+ isFullscreen?: boolean;
61
+ }> & Readonly<{
62
+ onSelectTool?: ((toolId: string) => any) | undefined;
63
+ onToggleFullscreen?: (() => any) | undefined;
64
+ onZoomIn?: (() => any) | undefined;
65
+ onZoomOut?: (() => any) | undefined;
66
+ onSettingsChange?: ((settings: Record<string, boolean>) => any) | undefined;
67
+ }>, {
68
+ getSettings: () => Record<string, boolean>;
69
+ }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
70
+ selectTool: (toolId: string) => any;
71
+ toggleFullscreen: () => any;
72
+ zoomIn: () => any;
73
+ zoomOut: () => any;
74
+ settingsChange: (settings: Record<string, boolean>) => any;
75
+ }, import('vue').PublicProps, {}, false, {}, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, {}, any, import('vue').ComponentProvideOptions, {
76
+ P: {};
77
+ B: {};
78
+ D: {};
79
+ C: {};
80
+ M: {};
81
+ Defaults: {};
82
+ }, Readonly<{
83
+ isFullscreen?: boolean;
84
+ }> & Readonly<{
85
+ onSelectTool?: ((toolId: string) => any) | undefined;
86
+ onToggleFullscreen?: (() => any) | undefined;
87
+ onZoomIn?: (() => any) | undefined;
88
+ onZoomOut?: (() => any) | undefined;
89
+ onSettingsChange?: ((settings: Record<string, boolean>) => any) | undefined;
90
+ }>, {
91
+ getSettings: () => Record<string, boolean>;
92
+ }, {}, {}, {}, {}> | null;
59
93
  chartMainRef: HTMLDivElement;
60
94
  tooltipLayerRef: HTMLDivElement;
61
95
  containerRef: HTMLDivElement;
@@ -7,15 +7,21 @@ export interface ToolDef {
7
7
  type __VLS_Props = {
8
8
  isFullscreen?: boolean;
9
9
  };
10
- declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
10
+ export type { SettingItem } from '../config/chartSettings';
11
+ declare function getCurrentSettings(): Record<string, boolean>;
12
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {
13
+ getSettings: typeof getCurrentSettings;
14
+ }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {} & {
11
15
  selectTool: (toolId: string) => any;
12
16
  toggleFullscreen: () => any;
13
17
  zoomIn: () => any;
14
18
  zoomOut: () => any;
19
+ settingsChange: (settings: Record<string, boolean>) => any;
15
20
  }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
16
21
  onSelectTool?: ((toolId: string) => any) | undefined;
17
22
  onToggleFullscreen?: (() => any) | undefined;
18
23
  onZoomIn?: (() => any) | undefined;
19
24
  onZoomOut?: (() => any) | undefined;
20
- }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLElement>;
25
+ onSettingsChange?: ((settings: Record<string, boolean>) => any) | undefined;
26
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
21
27
  export default _default;
@@ -0,0 +1,3 @@
1
+ import { Ref } from 'vue';
2
+ export declare function provideFullscreenTeleportTarget(targetRef: Ref<HTMLElement | null>): void;
3
+ export declare function useFullscreenTeleportTarget(): import('vue').ComputedRef<string | HTMLElement>;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * 图表设置配置
3
+ */
4
+ export interface SettingItem {
5
+ key: string;
6
+ label: string;
7
+ type: 'boolean';
8
+ default: boolean;
9
+ }
10
+ /** 默认设置配置 */
11
+ export declare const DEFAULT_SETTINGS: SettingItem[];
12
+ /** localStorage 存储键名 */
13
+ export declare const SETTINGS_STORAGE_KEY = "kline-chart-settings";
@@ -105,6 +105,8 @@ export declare class Chart {
105
105
  private resizeObserver?;
106
106
  /** 最近一次观测到的容器尺寸 */
107
107
  private observedSize;
108
+ /** 用户设置配置(传递给渲染器) */
109
+ private settings;
108
110
  /** pane ratio 状态(按 paneId 维护,sum=1 仅对可见 pane) */
109
111
  private paneRatios;
110
112
  /** 视口变化回调(供外部同步 DPR/尺寸) */
@@ -142,6 +144,8 @@ export declare class Chart {
142
144
  setRendererEnabled(name: string, enabled: boolean): void;
143
145
  /** 获取所有渲染器 */
144
146
  getAllRenderers(): RendererPlugin[];
147
+ /** 更新用户设置(触发重绘) */
148
+ updateSettings(settings: Record<string, boolean>): void;
145
149
  /** 绘制一帧 */
146
150
  draw(): void;
147
151
  /**
@@ -62,6 +62,7 @@ export declare class DrawingInteractionController {
62
62
  * 回归线端点可能远离存储的锚点,需要额外检测
63
63
  */
64
64
  private hitTestRegressionEndpoints;
65
+ private getRegressionChannelGeometry;
65
66
  private getExtendMode;
66
67
  private anchorToScreen;
67
68
  private screenToAnchor;
@@ -1,4 +1,5 @@
1
1
  import { RendererPluginWithHost } from '../../../../plugin';
2
+ import { ScaleType } from '../../../utils/tickPosition';
2
3
  export interface IndicatorScaleRendererOptions {
3
4
  axisWidth: number;
4
5
  paneId: string;
@@ -6,6 +7,7 @@ export interface IndicatorScaleRendererOptions {
6
7
  label: string;
7
8
  decimals?: number;
8
9
  yPaddingPx?: number;
10
+ scaleType?: ScaleType;
9
11
  getCrosshair?: () => {
10
12
  y: number;
11
13
  price: number;
@@ -26,6 +28,7 @@ export interface DrawScaleTicksOptions {
26
28
  isMain: boolean;
27
29
  decimals?: number;
28
30
  hideEdgeTicks?: boolean;
31
+ scaleType?: ScaleType;
29
32
  formatLabel?: (value: number) => string;
30
33
  }
31
34
  export declare function drawScaleTicks(options: DrawScaleTicksOptions): void;
@@ -0,0 +1,66 @@
1
+ import { PriceRange } from './price';
2
+ /**
3
+ * LogFormula 接口
4
+ * 用于对数变换的动态偏移,保证极小值下的精度
5
+ *
6
+ * - logicalOffset: 逻辑偏移,使输出值落在合理范围
7
+ * - coordOffset: 坐标偏移,避免 log10(0) 并提升精度
8
+ */
9
+ export interface LogFormula {
10
+ logicalOffset: number;
11
+ coordOffset: number;
12
+ }
13
+ /**
14
+ * 真实价格 → log 逻辑空间
15
+ * 公式: sign(price) * (log10(|price| + coordOffset) + logicalOffset)
16
+ *
17
+ * @param price 真实价格(可为负数)
18
+ * @param f LogFormula
19
+ * @returns log 逻辑空间值
20
+ */
21
+ export declare function toLog(price: number, f: LogFormula): number;
22
+ /**
23
+ * log 逻辑空间 → 真实价格
24
+ * 公式: sign(logical) * (10^(|logical| - logicalOffset) - coordOffset)
25
+ *
26
+ * @param logical log 逻辑空间值
27
+ * @param f LogFormula
28
+ * @returns 真实价格
29
+ */
30
+ export declare function fromLog(logical: number, f: LogFormula): number;
31
+ /**
32
+ * 根据价格范围动态计算 LogFormula
33
+ *
34
+ * 对于常规价格范围 (diff >= 1),使用默认值。
35
+ * 对于极小价格范围 (diff < 1),自动增大 logicalOffset 以维持精度。
36
+ *
37
+ * @param range 价格范围,可为 null
38
+ * @returns 最优的 LogFormula
39
+ */
40
+ export declare function logFormulaForPriceRange(range: PriceRange | null): LogFormula;
41
+ /**
42
+ * 范围转 log 空间
43
+ * 将价格的 min/max 都转换到 log 空间
44
+ *
45
+ * @param range 真实价格范围
46
+ * @param f LogFormula
47
+ * @returns log 空间的价格范围
48
+ */
49
+ export declare function convertPriceRangeToLog(range: PriceRange, f: LogFormula): PriceRange;
50
+ /**
51
+ * 范围从 log 空间转回
52
+ * 将 log 空间的 min/max 转换回真实价格
53
+ *
54
+ * @param range log 空间的价格范围
55
+ * @param f LogFormula
56
+ * @returns 真实价格范围
57
+ */
58
+ export declare function convertPriceRangeFromLog(range: PriceRange, f: LogFormula): PriceRange;
59
+ /**
60
+ * 判断两个 LogFormula 是否相同
61
+ *
62
+ * @param a LogFormula A
63
+ * @param b LogFormula B
64
+ * @returns 是否相同
65
+ */
66
+ export declare function logFormulasAreSame(a: LogFormula, b: LogFormula): boolean;
@@ -1,4 +1,5 @@
1
1
  import { PriceRange } from './price';
2
+ import { ScaleType } from '../utils/tickPosition';
2
3
  /**
3
4
  * Pane 级别的价格坐标系(价格 -> pane 内 Y)
4
5
  * - y=0 在 pane 顶部,y=height 在 pane 底部
@@ -8,10 +9,15 @@ export declare class PriceScale {
8
9
  private height;
9
10
  private paddingTop;
10
11
  private paddingBottom;
11
- /** 价格偏移量(用于上下拖动平移价格轴) */
12
+ /** 价格偏移量(用于上下拖动平移价格轴)
13
+ * 在对数模式下,此偏移量为 log 空间偏移 */
12
14
  private priceOffset;
13
15
  /** 垂直缩放系数(1=默认,>1 放大,<1 缩小) */
14
16
  private verticalScale;
17
+ /** 刻度类型:线性或对数 */
18
+ private scaleType;
19
+ /** 对数变换公式(动态计算,适配极小价格) */
20
+ private logFormula;
15
21
  setRange(r: PriceRange): void;
16
22
  setHeight(h: number): void;
17
23
  setPadding(top: number, bottom: number): void;
@@ -20,7 +26,9 @@ export declare class PriceScale {
20
26
  getPaddingBottom(): number;
21
27
  /**
22
28
  * 设置价格偏移量
23
- * @param offset 价格偏移(正数向上平移,负数向下平移)
29
+ * @param offset 价格偏移
30
+ * - 线性模式:真实价格的线性偏移
31
+ * - 对数模式:log 空间的偏移量
24
32
  */
25
33
  setPriceOffset(offset: number): void;
26
34
  /**
@@ -41,13 +49,39 @@ export declare class PriceScale {
41
49
  */
42
50
  scaleByDelta(deltaY: number): void;
43
51
  getVerticalScale(): number;
52
+ /**
53
+ * 设置刻度类型
54
+ * 切换时会自动转换 priceOffset 以保持视口位置
55
+ */
56
+ setScaleType(type: ScaleType): void;
57
+ /**
58
+ * 获取当前刻度类型
59
+ */
60
+ getScaleType(): ScaleType;
61
+ /**
62
+ * 获取显示范围(考虑 priceOffset 和 verticalScale)
63
+ *
64
+ * 对数模式下:
65
+ * - 内部计算在 log 空间进行
66
+ * - 返回的价格为真实价格
67
+ */
44
68
  getDisplayRange(baseRange?: PriceRange): PriceRange;
69
+ /**
70
+ * 价格 → Y 坐标
71
+ * 统一使用 getDisplayRange 的结果进行映射
72
+ */
45
73
  priceToY(price: number): number;
74
+ /**
75
+ * Y 坐标 → 价格
76
+ * 统一使用 getDisplayRange 的结果进行映射
77
+ */
46
78
  yToPrice(y: number): number;
47
79
  /**
48
80
  * 根据像素偏移计算价格偏移
49
81
  * @param deltaY Y轴像素偏移(正数向下拖动)
50
82
  * @returns 对应的价格偏移量
83
+ * - 线性模式:真实价格的偏移
84
+ * - 对数模式:log 空间的偏移
51
85
  */
52
86
  deltaYToPriceOffset(deltaY: number): number;
53
87
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * 图表字体配置
3
+ * 字体栈:Trebuchet MS (Windows系统字体) -> Roboto -> Ubuntu -> 通用无衬线字体
4
+ * 通过 Google Fonts CDN 加载 Roboto 和 Ubuntu
5
+ */
6
+ /** 数字和文本的标准字体栈 */
7
+ export declare const FONT_FAMILY = "\"Trebuchet MS\", Roboto, Ubuntu, sans-serif";
8
+ /** 获取指定字号的字体字符串,用于 Canvas ctx.font */
9
+ export declare function getFont(size: number, options?: {
10
+ bold?: boolean;
11
+ }): string;
@@ -0,0 +1,24 @@
1
+ export interface TickPosition {
2
+ index: number;
3
+ t: number;
4
+ y: number;
5
+ }
6
+ export type ScaleType = 'linear' | 'log';
7
+ export interface CalculateTickPositionsOptions {
8
+ height: number;
9
+ paddingTop: number;
10
+ paddingBottom: number;
11
+ isMain?: boolean;
12
+ hideEdgeTicks?: boolean;
13
+ scaleType?: ScaleType;
14
+ }
15
+ export declare function calculateTickPositions(options: CalculateTickPositionsOptions): TickPosition[];
16
+ export interface TickPositionWithValue extends TickPosition {
17
+ value: number;
18
+ }
19
+ export interface CalculateValueTickPositionsOptions extends CalculateTickPositionsOptions {
20
+ valueMin: number;
21
+ valueMax: number;
22
+ logBase?: number;
23
+ }
24
+ export declare function calculateValueTickPositions(options: CalculateValueTickPositionsOptions): TickPositionWithValue[];
@@ -116,6 +116,7 @@ export interface PaneInfo {
116
116
  maxPrice: number;
117
117
  minPrice: number;
118
118
  };
119
+ getScaleType(): 'linear' | 'log';
119
120
  };
120
121
  priceRange: {
121
122
  maxPrice: number;
@@ -139,6 +140,59 @@ export declare function wrapPaneInfo(pane: {
139
140
  yAxis: PaneInfo['yAxis'];
140
141
  priceRange: PaneInfo['priceRange'];
141
142
  }): Readonly<PaneInfo>;
143
+ /** Y轴标签(价格标签) */
144
+ export interface YAxisLabel {
145
+ /** 关联的数据索引 */
146
+ dataIndex: number;
147
+ /** 价格值 */
148
+ price: number;
149
+ /** 标签在轴上的Y坐标(世界坐标,相对pane) */
150
+ y: number;
151
+ /** 标签类型,用于区分不同渲染外观 */
152
+ type?: 'lastPrice' | 'extrema' | 'anchor' | string;
153
+ /** 标签样式覆盖 */
154
+ style?: {
155
+ bgColor?: string;
156
+ borderColor?: string;
157
+ textColor?: string;
158
+ };
159
+ }
160
+ /** X轴标签(时间标签) */
161
+ export interface XAxisLabel {
162
+ /** 关联的数据索引 */
163
+ dataIndex: number;
164
+ /** 时间戳(毫秒) */
165
+ timestamp: number;
166
+ /** 标签在轴上的X坐标(世界坐标,未减去scrollLeft) */
167
+ x: number;
168
+ /** 标签样式覆盖 */
169
+ style?: {
170
+ bgColor?: string;
171
+ textColor?: string;
172
+ };
173
+ }
174
+ /** Y轴范围带(半透明填充区域) */
175
+ export interface YAxisRange {
176
+ /** 范围上界Y坐标(相对pane,canvas方向:小值=上方) */
177
+ topY: number;
178
+ /** 范围下界Y坐标(相对pane,canvas方向:大值=下方) */
179
+ bottomY: number;
180
+ /** 填充颜色(hex 或 rgba) */
181
+ color: string;
182
+ /** 填充不透明度 */
183
+ opacity: number;
184
+ }
185
+ /** X轴范围带(半透明填充区域) */
186
+ export interface XAxisRange {
187
+ /** 范围左界X坐标(世界坐标,未减去scrollLeft) */
188
+ leftX: number;
189
+ /** 范围右界X坐标(世界坐标,未减去scrollLeft) */
190
+ rightX: number;
191
+ /** 填充颜色(hex 或 rgba) */
192
+ color: string;
193
+ /** 填充不透明度 */
194
+ opacity: number;
195
+ }
142
196
  /** 渲染上下文 */
143
197
  /** MarkerManager 接口(用于 RenderContext) */
144
198
  export interface MarkerManagerLike {
@@ -181,6 +235,16 @@ export interface RenderContext {
181
235
  plotWidth: number;
182
236
  plotHeight: number;
183
237
  };
238
+ /** 用户设置配置(渲染器只读) */
239
+ settings?: Record<string, boolean>;
240
+ /** 需要在Y轴上绘制的标签列表(由各类标记渲染器填充) */
241
+ yAxisLabels?: YAxisLabel[];
242
+ /** 需要在X轴上绘制的标签列表(由各类标记渲染器填充) */
243
+ xAxisLabels?: XAxisLabel[];
244
+ /** 需要在Y轴上绘制的范围带列表(由绘图渲染器填充,先于标签绘制) */
245
+ yAxisRanges?: YAxisRange[];
246
+ /** 需要在X轴上绘制的范围带列表(由绘图渲染器填充,先于标签绘制) */
247
+ xAxisRanges?: XAxisRange[];
184
248
  }
185
249
  export type DrawingAnchor = {
186
250
  id: string;
@@ -252,6 +316,7 @@ export type DrawingGeometry = {
252
316
  bottom: number;
253
317
  };
254
318
  meta?: Record<string, unknown>;
319
+ computedAnchors?: DrawingAnchor[];
255
320
  };
256
321
  export type DrawingComputeContext = {
257
322
  pane: PaneInfo;
@@ -288,6 +353,7 @@ export interface DrawingDefinition<TParams = Record<string, unknown>> {
288
353
  export declare const GLOBAL_PANE_ID: unique symbol;
289
354
  /** 优先级推荐范围 */
290
355
  export declare const RENDERER_PRIORITY: {
356
+ readonly LAST_PRICE_LABEL: -25;
291
357
  readonly SYSTEM_YAXIS: -20;
292
358
  readonly SYSTEM_XAXIS: -20;
293
359
  readonly BACKGROUND: 0;
@@ -127,3 +127,40 @@ export declare function drawCrosshairPriceLabel(ctx: CanvasRenderingContext2D, o
127
127
  export declare function drawLastPriceDashedLine(ctx: CanvasRenderingContext2D, opts: LastPriceLineOptions): void;
128
128
  /** 底部时间轴(X方向随 scrollLeft 变化) */
129
129
  export declare function drawTimeAxis(ctx: CanvasRenderingContext2D, opts: TimeAxisOptions): void;
130
+ /** ============ 轴标签绘制函数 ============ */
131
+ export interface AxisPriceLabelOptions {
132
+ x: number;
133
+ y: number;
134
+ width: number;
135
+ height: number;
136
+ priceY: number;
137
+ price: number;
138
+ dpr: number;
139
+ bgColor?: string;
140
+ borderColor?: string;
141
+ textColor?: string;
142
+ fontSize?: number;
143
+ }
144
+ /**
145
+ * 在右侧价格轴上绘制价格标签
146
+ * 与 drawCrosshairPriceLabel 类似,但简化了参数(价格直接传入,无需计算)
147
+ */
148
+ export declare function drawAxisPriceLabel(ctx: CanvasRenderingContext2D, opts: AxisPriceLabelOptions): void;
149
+ export interface AxisTimeLabelOptions {
150
+ x: number;
151
+ y: number;
152
+ width: number;
153
+ height: number;
154
+ labelX: number;
155
+ timestamp: number;
156
+ dpr: number;
157
+ bgColor?: string;
158
+ textColor?: string;
159
+ fontSize?: number;
160
+ paddingX?: number;
161
+ }
162
+ /**
163
+ * 在底部时间轴上绘制时间标签
164
+ * 与 drawCrosshairTimeLabel 类似,但 labelX 是屏幕坐标(已处理 scrollLeft)
165
+ */
166
+ export declare function drawAxisTimeLabel(ctx: CanvasRenderingContext2D, opts: AxisTimeLabelOptions): void;
package/package.json CHANGED
@@ -1,7 +1,43 @@
1
1
  {
2
2
  "name": "@363045841yyt/klinechart",
3
- "version": "0.5.5-alpha.0",
3
+ "version": "0.5.6",
4
+ "description": "A lightweight financial K-line charting library with first-class AI Agent support, crisp ResizeObserver-driven rendering, and plugin-based architecture. Focused on quantitative trading scenarios with TradingView-level interaction experience.",
5
+ "author": "363045841 <slslswbsy@qq.com>",
4
6
  "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/363045841/KLineChartQuant.git"
10
+ },
11
+ "bugs": "https://github.com/363045841/KLineChartQuant/issues",
12
+ "homepage": "https://363045841.github.io/KLineChartQuant/",
13
+ "keywords": [
14
+ "kline-chart",
15
+ "candlestick-chart",
16
+ "financial-chart",
17
+ "tradingview",
18
+ "canvas",
19
+ "rendering-engine",
20
+ "resizeobserver",
21
+ "device-pixel-content-box",
22
+ "drawing-tools",
23
+ "chart-drawing",
24
+ "trend-line",
25
+ "fibonacci",
26
+ "high-performance",
27
+ "pixel-perfect",
28
+ "crisp-rendering",
29
+ "sharp-rendering",
30
+ "device-pixel-ratio",
31
+ "responsive",
32
+ "modern-ui",
33
+ "agent",
34
+ "ai-chart",
35
+ "visualization",
36
+ "quantitative-trading",
37
+ "technical-analysis",
38
+ "plugin-architecture",
39
+ "typescript"
40
+ ],
5
41
  "type": "module",
6
42
  "engines": {
7
43
  "node": "^20.19.0 || >=22.12.0"