if (!window.TopBar) { class TopBar { constructor(chart) { this.makeSwitcher = this.makeSwitcher.bind(this) this.topBar = document.createElement('div') this.topBar.style.backgroundColor = pane.backgroundColor this.topBar.style.borderBottom = '2px solid '+pane.borderColor this.topBar.style.display = 'flex' this.topBar.style.alignItems = 'center' let createTopBarContainer = (justification) => { let div = document.createElement('div') div.style.display = 'flex' div.style.alignItems = 'center' div.style.justifyContent = justification div.style.flexGrow = '1' this.topBar.appendChild(div) return div } this.left = createTopBarContainer('flex-start') this.right = createTopBarContainer('flex-end') chart.wrapper.prepend(this.topBar) chart.topBar = this.topBar this.reSize = () => chart.reSize() this.reSize() } makeSwitcher(items, activeItem, callbackName, align='left') { let switcherElement = document.createElement('div'); switcherElement.style.margin = '4px 12px' let widget = { elem: switcherElement, callbackName: callbackName, intervalElements: null, onItemClicked: null, } widget.intervalElements = items.map((item)=> { let itemEl = document.createElement('button'); itemEl.style.border = 'none' itemEl.style.padding = '2px 5px' itemEl.style.margin = '0px 2px' itemEl.style.fontSize = '13px' itemEl.style.borderRadius = '4px' itemEl.style.backgroundColor = item === activeItem ? pane.activeBackgroundColor : 'transparent' itemEl.style.color = item === activeItem ? pane.activeColor : pane.color itemEl.innerText = item; document.body.appendChild(itemEl) itemEl.style.minWidth = itemEl.clientWidth + 1 + 'px' document.body.removeChild(itemEl) itemEl.addEventListener('mouseenter', () => itemEl.style.backgroundColor = item === activeItem ? pane.activeBackgroundColor : pane.hoverBackgroundColor) itemEl.addEventListener('mouseleave', () => itemEl.style.backgroundColor = item === activeItem ? pane.activeBackgroundColor : 'transparent') itemEl.addEventListener('mousedown', () => itemEl.style.backgroundColor = item === activeItem ? pane.activeBackgroundColor : pane.clickBackgroundColor) itemEl.addEventListener('mouseup', () => itemEl.style.backgroundColor = item === activeItem ? pane.activeBackgroundColor : pane.hoverBackgroundColor) itemEl.addEventListener('click', () => widget.onItemClicked(item)) switcherElement.appendChild(itemEl); return itemEl; }); widget.onItemClicked = (item)=> { if (item === activeItem) return widget.intervalElements.forEach((element, index) => { element.style.backgroundColor = items[index] === item ? pane.activeBackgroundColor : 'transparent' element.style.color = items[index] === item ? pane.activeColor : pane.color element.style.fontWeight = items[index] === item ? '500' : 'normal' }) activeItem = item; window.callbackFunction(`${widget.callbackName}_~_${item}`); } this.appendWidget(switcherElement, align, true) return widget } makeTextBoxWidget(text, align='left') { let textBox = document.createElement('div') textBox.style.margin = '0px 18px' textBox.style.fontSize = '16px' textBox.style.color = pane.color textBox.innerText = text this.appendWidget(textBox, align, true) return textBox } makeMenu(items, activeItem, separator, callbackName, align='right') { let menu = document.createElement('div') menu.style.position = 'absolute' menu.style.display = 'none' menu.style.zIndex = '100000' menu.style.backgroundColor = pane.backgroundColor menu.style.borderRadius = '2px' menu.style.border = '2px solid '+pane.borderColor menu.style.borderTop = 'none' menu.style.alignItems = 'flex-start' menu.style.maxHeight = '80%' menu.style.overflowY = 'auto' menu.style.scrollbar let menuOpen = false items.forEach(text => { let button = this.makeButton(text, null, false, false) button.elem.addEventListener('click', () => { widget.elem.innerText = button.elem.innerText+' ↓' window.callbackFunction(`${callbackName}_~_${button.elem.innerText}`) menu.style.display = 'none' menuOpen = false }); button.elem.style.margin = '4px 4px' button.elem.style.padding = '2px 2px' menu.appendChild(button.elem) }) let widget = this.makeButton(activeItem+' ↓', null, separator, true, align) widget.elem.addEventListener('click', () => { menuOpen = !menuOpen if (!menuOpen) return menu.style.display = 'none' let rect = widget.elem.getBoundingClientRect() menu.style.display = 'flex' menu.style.flexDirection = 'column' let center = rect.x+(rect.width/2) menu.style.left = center-(menu.clientWidth/2)+'px' menu.style.top = rect.y+rect.height+'px' }) document.body.appendChild(menu) } makeButton(defaultText, callbackName, separator, append=true, align='left') { let button = document.createElement('button') button.style.border = 'none' button.style.padding = '2px 5px' button.style.margin = '4px 10px' button.style.fontSize = '13px' button.style.backgroundColor = 'transparent' button.style.color = pane.color button.style.borderRadius = '4px' button.innerText = defaultText; document.body.appendChild(button) button.style.minWidth = button.clientWidth+1+'px' document.body.removeChild(button) let widget = { elem: button, callbackName: callbackName } button.addEventListener('mouseenter', () => button.style.backgroundColor = pane.hoverBackgroundColor) button.addEventListener('mouseleave', () => button.style.backgroundColor = 'transparent') if (callbackName) { button.addEventListener('click', () => window.callbackFunction(`${widget.callbackName}_~_${button.innerText}`)); } button.addEventListener('mousedown', () => { button.style.backgroundColor = pane.activeBackgroundColor button.style.color = pane.activeColor button.style.fontWeight = '500' }) button.addEventListener('mouseup', () => { button.style.backgroundColor = pane.hoverBackgroundColor button.style.color = pane.color button.style.fontWeight = 'normal' }) if (append) this.appendWidget(button, align, separator) return widget } makeSeparator(align='left') { let seperator = document.createElement('div') seperator.style.width = '1px' seperator.style.height = '20px' seperator.style.backgroundColor = pane.borderColor let div = align === 'left' ? this.left : this.right div.appendChild(seperator) } appendWidget(widget, align, separator) { let div = align === 'left' ? this.left : this.right if (separator) { if (align === 'left') div.appendChild(widget) this.makeSeparator(align) if (align === 'right') div.appendChild(widget) } else div.appendChild(widget) this.reSize() } } window.TopBar = TopBar } function makeSearchBox(chart) { let searchWindow = document.createElement('div') searchWindow.style.position = 'absolute' searchWindow.style.top = '0' searchWindow.style.bottom = '200px' searchWindow.style.left = '0' searchWindow.style.right = '0' searchWindow.style.margin = 'auto' searchWindow.style.width = '150px' searchWindow.style.height = '30px' searchWindow.style.padding = '5px' searchWindow.style.zIndex = '1000' searchWindow.style.alignItems = 'center' searchWindow.style.backgroundColor = 'rgba(30, 30, 30, 0.9)' searchWindow.style.border = '2px solid '+pane.borderColor searchWindow.style.borderRadius = '5px' searchWindow.style.display = 'none' let magnifyingGlass = document.createElement('div'); magnifyingGlass.innerHTML = `` let sBox = document.createElement('input'); sBox.type = 'text'; sBox.style.textAlign = 'center' sBox.style.width = '100px' sBox.style.marginLeft = '10px' sBox.style.backgroundColor = pane.mutedBackgroundColor sBox.style.color = pane.activeColor sBox.style.fontSize = '20px' sBox.style.border = 'none' sBox.style.outline = 'none' sBox.style.borderRadius = '2px' searchWindow.appendChild(magnifyingGlass) searchWindow.appendChild(sBox) chart.div.appendChild(searchWindow); let yPrice = null chart.chart.subscribeCrosshairMove((param) => { if (param.point) yPrice = param.point.y; }) chart.commandFunctions.push((event) => { if (selectedChart !== chart) return false if (searchWindow.style.display === 'none') { if (/^[a-zA-Z0-9]$/.test(event.key)) { searchWindow.style.display = 'flex'; sBox.focus(); return true } else return false } else if (event.key === 'Enter' || event.key === 'Escape') { if (event.key === 'Enter') window.callbackFunction(`search${chart.id}_~_${sBox.value}`) searchWindow.style.display = 'none' sBox.value = '' return true } else return false }) sBox.addEventListener('input', () => sBox.value = sBox.value.toUpperCase()) return { window: searchWindow, box: sBox, } } function makeSpinner(chart) { chart.spinner = document.createElement('div') chart.spinner.style.width = '30px' chart.spinner.style.height = '30px' chart.spinner.style.border = '4px solid rgba(255, 255, 255, 0.6)' chart.spinner.style.borderTop = '4px solid '+pane.activeBackgroundColor chart.spinner.style.borderRadius = '50%' chart.spinner.style.position = 'absolute' chart.spinner.style.top = '50%' chart.spinner.style.left = '50%' chart.spinner.style.zIndex = '1000' chart.spinner.style.transform = 'translate(-50%, -50%)' chart.spinner.style.display = 'none' chart.wrapper.appendChild(chart.spinner) let rotation = 0; const speed = 10; function animateSpinner() { rotation += speed chart.spinner.style.transform = `translate(-50%, -50%) rotate(${rotation}deg)` requestAnimationFrame(animateSpinner) } animateSpinner(); }