Enhancements:
- The `start_date` parameter of `vertical_span` can take a list or tuple of dates to create multiple vertical lines. - Added style parameters to drawings. Bug Fixes: - `VerticalSpan.delete()` now works as intended. - Drawings no longer show up in the legend
This commit is contained in:
@ -76,7 +76,7 @@ ___
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
```{py:method} trend_line(start_time: str | datetime, start_value: NUM, end_time: str | datetime, end_value: NUM, color: COLOR, width: int) -> Line
|
```{py:method} trend_line(start_time: str | datetime, start_value: NUM, end_time: str | datetime, end_value: NUM, color: COLOR, width: int, style: LINE_STYLE) -> Line
|
||||||
|
|
||||||
Creates a trend line, drawn from the first point (`start_time`, `start_value`) to the last point (`end_time`, `end_value`).
|
Creates a trend line, drawn from the first point (`start_time`, `start_value`) to the last point (`end_time`, `end_value`).
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ ___
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
```{py:method} ray_line(start_time: str | datetime, value: NUM, color: COLOR, width: int) -> Line
|
```{py:method} ray_line(start_time: str | datetime, value: NUM, color: COLOR, width: int, style: LINE_STYLE) -> Line
|
||||||
|
|
||||||
Creates a ray line, drawn from the first point (`start_time`, `value`) and onwards.
|
Creates a ray line, drawn from the first point (`start_time`, `value`) and onwards.
|
||||||
|
|
||||||
@ -94,12 +94,14 @@ ___
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
```{py:method} vertical_span(start_time: TIME, end_time: TIME = None, color: COLOR = 'rgba(252, 219, 3, 0.2)')
|
```{py:method} vertical_span(start_time: TIME | list | tuple, end_time: TIME = None, color: COLOR = 'rgba(252, 219, 3, 0.2)')
|
||||||
|
|
||||||
Creates and returns a `VerticalSpan` object.
|
Creates and returns a `VerticalSpan` object.
|
||||||
|
|
||||||
If `end_time` is not given, then a single vertical line will be placed at `start_time`.
|
If `end_time` is not given, then a single vertical line will be placed at `start_time`.
|
||||||
|
|
||||||
|
If a list/tuple is passed to `start_time`, vertical lines will be placed at each time.
|
||||||
|
|
||||||
This should be used after calling [`set`](#AbstractChart.set).
|
This should be used after calling [`set`](#AbstractChart.set).
|
||||||
```
|
```
|
||||||
___
|
___
|
||||||
|
|||||||
@ -15,7 +15,7 @@ The following hotkeys can also be used when the Toolbox is enabled:
|
|||||||
| `alt R` | Ray Line |
|
| `alt R` | Ray Line |
|
||||||
| `⌘ Z` or `ctrl Z` | Undo |
|
| `⌘ Z` or `ctrl Z` | Undo |
|
||||||
|
|
||||||
Right-clicking on a drawing will open a context menu, allowing for color selection and deletion.
|
Right-clicking on a drawing will open a context menu, allowing for color selection, style selection and deletion.
|
||||||
___
|
___
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -121,7 +121,7 @@ class SeriesCommon(Pane):
|
|||||||
return
|
return
|
||||||
self._interval = common_interval.index[0]
|
self._interval = common_interval.index[0]
|
||||||
self.run_script(
|
self.run_script(
|
||||||
f'if ({self.id}.toolBox) {self.id}.toolBox.interval = {self._interval.total_seconds() * 1000}'
|
f'if ({self.id}.toolBox) {self.id}.interval = {self._interval.total_seconds() * 1000}'
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -163,7 +163,7 @@ class SeriesCommon(Pane):
|
|||||||
|
|
||||||
def marker(self, time: datetime = None, position: MARKER_POSITION = 'below',
|
def marker(self, time: datetime = None, position: MARKER_POSITION = 'below',
|
||||||
shape: MARKER_SHAPE = 'arrow_up', color: str = '#2196F3', text: str = ''
|
shape: MARKER_SHAPE = 'arrow_up', color: str = '#2196F3', text: str = ''
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Creates a new marker.\n
|
Creates a new marker.\n
|
||||||
:param time: Time location of the marker. If no time is given, it will be placed at the last bar.
|
:param time: Time location of the marker. If no time is given, it will be placed at the last bar.
|
||||||
@ -310,11 +310,11 @@ class HorizontalLine(Pane):
|
|||||||
|
|
||||||
|
|
||||||
class VerticalSpan(Pane):
|
class VerticalSpan(Pane):
|
||||||
def __init__(self, chart: 'AbstractChart', start_time: TIME, end_time: TIME = None,
|
def __init__(self, chart: 'AbstractChart', start_time: Union[TIME, tuple, list], end_time: TIME = None,
|
||||||
color: str = 'rgba(252, 219, 3, 0.2)'):
|
color: str = 'rgba(252, 219, 3, 0.2)'):
|
||||||
super().__init__(chart.win)
|
super().__init__(chart.win)
|
||||||
self._chart = chart
|
self._chart = chart
|
||||||
start_date, end_date = pd.to_datetime(start_time), pd.to_datetime(end_time)
|
start_time, end_time = pd.to_datetime(start_time), pd.to_datetime(end_time)
|
||||||
self.run_script(f'''
|
self.run_script(f'''
|
||||||
{self.id} = {chart.id}.chart.addHistogramSeries({{
|
{self.id} = {chart.id}.chart.addHistogramSeries({{
|
||||||
color: '{color}',
|
color: '{color}',
|
||||||
@ -327,12 +327,16 @@ class VerticalSpan(Pane):
|
|||||||
scaleMargins: {{top: 0, bottom: 0}}
|
scaleMargins: {{top: 0, bottom: 0}}
|
||||||
}})
|
}})
|
||||||
''')
|
''')
|
||||||
if end_date is None:
|
if end_time is None:
|
||||||
self.run_script(f'{self.id}.setData([{{time: {start_date.timestamp()}, value: 1}}])')
|
if isinstance(start_time, pd.DatetimeIndex):
|
||||||
|
data = [{'time': time.timestamp(), 'value': 1} for time in start_time]
|
||||||
|
else:
|
||||||
|
data = [{'time': start_time.timestamp(), 'value': 1}]
|
||||||
|
self.run_script(f'{self.id}.setData({data})')
|
||||||
else:
|
else:
|
||||||
self.run_script(f'''
|
self.run_script(f'''
|
||||||
{self.id}.setData(calculateTrendLine(
|
{self.id}.setData(calculateTrendLine(
|
||||||
{start_date.timestamp()}, 1, {end_date.timestamp()}, 1,
|
{start_time.timestamp()}, 1, {end_time.timestamp()}, 1,
|
||||||
{chart._interval.total_seconds() * 1000}, {chart.id}))
|
{chart._interval.total_seconds() * 1000}, {chart.id}))
|
||||||
''')
|
''')
|
||||||
|
|
||||||
@ -340,7 +344,7 @@ class VerticalSpan(Pane):
|
|||||||
"""
|
"""
|
||||||
Irreversibly deletes the vertical span.
|
Irreversibly deletes the vertical span.
|
||||||
"""
|
"""
|
||||||
self.run_script(f'{self._chart.id}.chart.removeSeries({self.id}.series); delete {self.id}')
|
self.run_script(f'{self._chart.id}.chart.removeSeries({self.id})')
|
||||||
|
|
||||||
|
|
||||||
class Line(SeriesCommon):
|
class Line(SeriesCommon):
|
||||||
@ -370,6 +374,10 @@ class Line(SeriesCommon):
|
|||||||
color: '{color}',
|
color: '{color}',
|
||||||
precision: 2,
|
precision: 2,
|
||||||
}}
|
}}
|
||||||
|
''')
|
||||||
|
|
||||||
|
def _push_to_legend(self):
|
||||||
|
self.run_script(f'''
|
||||||
{self._chart.id}.lines.push({self.id})
|
{self._chart.id}.lines.push({self.id})
|
||||||
if ('legend' in {self._chart.id}) {{
|
if ('legend' in {self._chart.id}) {{
|
||||||
{self._chart.id}.legend.lines.push({self._chart.id}.legend.makeLineRow({self.id}))
|
{self._chart.id}.legend.lines.push({self._chart.id}.legend.makeLineRow({self.id}))
|
||||||
@ -621,6 +629,7 @@ class AbstractChart(Candlestick, Pane):
|
|||||||
Creates and returns a Line object.)\n
|
Creates and returns a Line object.)\n
|
||||||
"""
|
"""
|
||||||
self._lines.append(Line(self, name, color, style, width, price_line, price_label))
|
self._lines.append(Line(self, name, color, style, width, price_line, price_label))
|
||||||
|
self._lines[-1]._push_to_legend()
|
||||||
return self._lines[-1]
|
return self._lines[-1]
|
||||||
|
|
||||||
def lines(self) -> List[Line]:
|
def lines(self) -> List[Line]:
|
||||||
@ -630,26 +639,24 @@ class AbstractChart(Candlestick, Pane):
|
|||||||
return self._lines.copy()
|
return self._lines.copy()
|
||||||
|
|
||||||
def trend_line(self, start_time: TIME, start_value: NUM, end_time: TIME, end_value: NUM,
|
def trend_line(self, start_time: TIME, start_value: NUM, end_time: TIME, end_value: NUM,
|
||||||
color: str = '#1E80F0', width: int = 2
|
color: str = '#1E80F0', width: int = 2, style: LINE_STYLE = 'solid'
|
||||||
) -> Line:
|
) -> Line:
|
||||||
line = Line(self, '', color, 'solid', width, False, False, False)
|
line = Line(self, '', color, style, width, False, False, False)
|
||||||
line._set_trend(start_time, start_value, end_time, end_value)
|
line._set_trend(start_time, start_value, end_time, end_value)
|
||||||
return line
|
return line
|
||||||
|
|
||||||
def ray_line(self, start_time: TIME, value: NUM,
|
def ray_line(self, start_time: TIME, value: NUM,
|
||||||
color: str = '#1E80F0', width: int = 2
|
color: str = '#1E80F0', width: int = 2, style: LINE_STYLE = 'solid'
|
||||||
) -> Line:
|
) -> Line:
|
||||||
line = Line(self, '', color, 'solid', width, False, False, False)
|
line = Line(self, '', color, style, width, False, False, False)
|
||||||
line._set_trend(start_time, value, start_time, value, ray=True)
|
line._set_trend(start_time, value, start_time, value, ray=True)
|
||||||
return line
|
return line
|
||||||
|
|
||||||
def vertical_span(self, start_time: TIME, end_time: TIME = None, color: str = 'rgba(252, 219, 3, 0.2)'):
|
def vertical_span(self, start_time: Union[TIME, tuple, list], end_time: TIME = None, color: str = 'rgba(252, 219, 3, 0.2)'):
|
||||||
"""
|
"""
|
||||||
Creates a vertical line or span across the chart.
|
Creates a vertical line or span across the chart.\n
|
||||||
:param start_time: Start time of the span.
|
Start time and end time can be used together, or end_time can be
|
||||||
:param end_time: End time of the span (can be omitted for a single vertical line).
|
omitted and a single time or a list of times can be passed to start_time.
|
||||||
:param color: CSS color.
|
|
||||||
:return:
|
|
||||||
"""
|
"""
|
||||||
return VerticalSpan(self, start_time, end_time, color)
|
return VerticalSpan(self, start_time, end_time, color)
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@ if (!window.Chart) {
|
|||||||
this.reSize = this.reSize.bind(this)
|
this.reSize = this.reSize.bind(this)
|
||||||
this.id = chartId
|
this.id = chartId
|
||||||
this.lines = []
|
this.lines = []
|
||||||
|
this.interval = null
|
||||||
this.wrapper = document.createElement('div')
|
this.wrapper = document.createElement('div')
|
||||||
this.div = document.createElement('div')
|
this.div = document.createElement('div')
|
||||||
this.scale = {
|
this.scale = {
|
||||||
@ -143,6 +144,12 @@ if (!window.Chart) {
|
|||||||
this.line = this.chart.series.createPriceLine(this.priceLine)
|
this.line = this.chart.series.createPriceLine(this.priceLine)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateStyle(style) {
|
||||||
|
this.chart.series.removePriceLine(this.line)
|
||||||
|
this.priceLine.lineStyle = style
|
||||||
|
this.line = this.chart.series.createPriceLine(this.priceLine)
|
||||||
|
}
|
||||||
|
|
||||||
deleteLine() {
|
deleteLine() {
|
||||||
this.chart.series.removePriceLine(this.line)
|
this.chart.series.removePriceLine(this.line)
|
||||||
this.chart.horizontal_lines.splice(this.chart.horizontal_lines.indexOf(this))
|
this.chart.horizontal_lines.splice(this.chart.horizontal_lines.indexOf(this))
|
||||||
@ -297,6 +304,7 @@ if (!window.Chart) {
|
|||||||
|
|
||||||
window.Legend = Legend
|
window.Legend = Legend
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncCharts(childChart, parentChart) {
|
function syncCharts(childChart, parentChart) {
|
||||||
syncCrosshairs(childChart.chart, parentChart.chart)
|
syncCrosshairs(childChart.chart, parentChart.chart)
|
||||||
syncRanges(childChart, parentChart)
|
syncRanges(childChart, parentChart)
|
||||||
@ -462,26 +470,28 @@ if (!window.ContextMenu) {
|
|||||||
|
|
||||||
let elem = document.createElement('span')
|
let elem = document.createElement('span')
|
||||||
elem.innerText = text
|
elem.innerText = text
|
||||||
|
elem.style.pointerEvents = 'none'
|
||||||
item.appendChild(elem)
|
item.appendChild(elem)
|
||||||
|
|
||||||
if (hover) {
|
if (hover) {
|
||||||
let arrow = document.createElement('span')
|
let arrow = document.createElement('span')
|
||||||
arrow.innerText = `►`
|
arrow.innerText = `►`
|
||||||
arrow.style.fontSize = '8px'
|
arrow.style.fontSize = '8px'
|
||||||
|
arrow.style.pointerEvents = 'none'
|
||||||
item.appendChild(arrow)
|
item.appendChild(arrow)
|
||||||
}
|
}
|
||||||
|
|
||||||
elem.addEventListener('mouseover', (event) => {
|
item.addEventListener('mouseover', (event) => {
|
||||||
item.style.backgroundColor = 'rgba(0, 122, 255, 0.3)'
|
item.style.backgroundColor = 'rgba(0, 122, 255, 0.3)'
|
||||||
if (this.hoverItem && this.hoverItem.closeAction) this.hoverItem.closeAction()
|
if (this.hoverItem && this.hoverItem.closeAction) this.hoverItem.closeAction()
|
||||||
this.hoverItem = {elem: elem, action: action, closeAction: hover}
|
this.hoverItem = {elem: elem, action: action, closeAction: hover}
|
||||||
})
|
})
|
||||||
elem.addEventListener('mouseout', (event) => item.style.backgroundColor = 'transparent')
|
item.addEventListener('mouseout', (event) => item.style.backgroundColor = 'transparent')
|
||||||
if (!hover) elem.addEventListener('click', (event) => {action(event); this.menu.style.display = 'none'})
|
if (!hover) item.addEventListener('click', (event) => {action(event); this.menu.style.display = 'none'})
|
||||||
else {
|
else {
|
||||||
let timeout
|
let timeout
|
||||||
elem.addEventListener('mouseover', () => timeout = setTimeout(() => action(item.getBoundingClientRect()), 100))
|
item.addEventListener('mouseover', () => timeout = setTimeout(() => action(item.getBoundingClientRect()), 100))
|
||||||
elem.addEventListener('mouseout', () => clearTimeout(timeout))
|
item.addEventListener('mouseout', () => clearTimeout(timeout))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
separator() {
|
separator() {
|
||||||
|
|||||||
@ -11,7 +11,6 @@ if (!window.ToolBox) {
|
|||||||
this.chart.cursor = 'default'
|
this.chart.cursor = 'default'
|
||||||
this.makingDrawing = false
|
this.makingDrawing = false
|
||||||
|
|
||||||
this.interval = 24 * 60 * 60 * 1000
|
|
||||||
this.activeBackgroundColor = 'rgba(0, 122, 255, 0.7)'
|
this.activeBackgroundColor = 'rgba(0, 122, 255, 0.7)'
|
||||||
this.activeIconColor = 'rgb(240, 240, 240)'
|
this.activeIconColor = 'rgb(240, 240, 240)'
|
||||||
this.iconColor = 'lightgrey'
|
this.iconColor = 'lightgrey'
|
||||||
@ -174,13 +173,13 @@ if (!window.ToolBox) {
|
|||||||
currentTime = this.chart.chart.timeScale().coordinateToTime(param.point.x)
|
currentTime = this.chart.chart.timeScale().coordinateToTime(param.point.x)
|
||||||
if (!currentTime) {
|
if (!currentTime) {
|
||||||
let barsToMove = param.logical - this.chart.chart.timeScale().coordinateToLogical(this.chart.chart.timeScale().timeToCoordinate(lastCandleTime))
|
let barsToMove = param.logical - this.chart.chart.timeScale().coordinateToLogical(this.chart.chart.timeScale().timeToCoordinate(lastCandleTime))
|
||||||
currentTime = dateToStamp(new Date(stampToDate(this.chart.candleData[this.chart.candleData.length - 1].time).getTime() + (barsToMove * this.interval)))
|
currentTime = dateToStamp(new Date(stampToDate(this.chart.candleData[this.chart.candleData.length - 1].time).getTime() + (barsToMove * this.chart.interval)))
|
||||||
}
|
}
|
||||||
let currentPrice = this.chart.series.coordinateToPrice(param.point.y)
|
let currentPrice = this.chart.series.coordinateToPrice(param.point.y)
|
||||||
|
|
||||||
|
|
||||||
if (!currentTime) return this.chart.chart.subscribeCrosshairMove(crosshairHandlerTrend)
|
if (!currentTime) return this.chart.chart.subscribeCrosshairMove(crosshairHandlerTrend)
|
||||||
let data = calculateTrendLine(firstTime, firstPrice, currentTime, currentPrice, this.interval, this.chart, ray)
|
let data = calculateTrendLine(firstTime, firstPrice, currentTime, currentPrice, this.chart.interval, this.chart, ray)
|
||||||
trendLine.from = [data[0].time, data[0].value]
|
trendLine.from = [data[0].time, data[0].value]
|
||||||
trendLine.to = [data[data.length - 1].time, data[data.length-1].value]
|
trendLine.to = [data[data.length - 1].time, data[data.length-1].value]
|
||||||
|
|
||||||
@ -263,14 +262,20 @@ if (!window.ToolBox) {
|
|||||||
let hoveringOver = null
|
let hoveringOver = null
|
||||||
let x, y
|
let x, y
|
||||||
let colorPicker = new ColorPicker(this.saveDrawings)
|
let colorPicker = new ColorPicker(this.saveDrawings)
|
||||||
|
let stylePicker = new StylePicker(this.saveDrawings)
|
||||||
|
|
||||||
let onClickDelete = () => this.deleteDrawing(contextMenu.drawing)
|
let onClickDelete = () => this.deleteDrawing(contextMenu.drawing)
|
||||||
let onClickColor = (rect) => colorPicker.openMenu(rect, contextMenu.drawing)
|
let onClickColor = (rect) => colorPicker.openMenu(rect, contextMenu.drawing)
|
||||||
|
let onClickStyle = (rect) => stylePicker.openMenu(rect, contextMenu.drawing)
|
||||||
let contextMenu = new ContextMenu()
|
let contextMenu = new ContextMenu()
|
||||||
contextMenu.menuItem('Color Picker', onClickColor, () =>{
|
contextMenu.menuItem('Color Picker', onClickColor, () =>{
|
||||||
document.removeEventListener('click', colorPicker.closeMenu)
|
document.removeEventListener('click', colorPicker.closeMenu)
|
||||||
colorPicker.container.style.display = 'none'
|
colorPicker.container.style.display = 'none'
|
||||||
})
|
})
|
||||||
|
contextMenu.menuItem('Style', onClickStyle, () => {
|
||||||
|
document.removeEventListener('click', stylePicker.closeMenu)
|
||||||
|
stylePicker.container.style.display = 'none'
|
||||||
|
})
|
||||||
contextMenu.separator()
|
contextMenu.separator()
|
||||||
contextMenu.menuItem('Delete Drawing', onClickDelete)
|
contextMenu.menuItem('Delete Drawing', onClickDelete)
|
||||||
|
|
||||||
@ -390,10 +395,10 @@ if (!window.ToolBox) {
|
|||||||
endBar = endBarIndex === -1 ? null : this.chart.candleData[endBarIndex + barsToMove]
|
endBar = endBarIndex === -1 ? null : this.chart.candleData[endBarIndex + barsToMove]
|
||||||
}
|
}
|
||||||
|
|
||||||
let endDate = endBar ? endBar.time : dateToStamp(new Date(stampToDate(hoveringOver.to[0]).getTime() + (barsToMove * this.interval)))
|
let endDate = endBar ? endBar.time : dateToStamp(new Date(stampToDate(hoveringOver.to[0]).getTime() + (barsToMove * this.chart.interval)))
|
||||||
let startValue = hoveringOver.from[1] + priceDiff
|
let startValue = hoveringOver.from[1] + priceDiff
|
||||||
let endValue = hoveringOver.to[1] + priceDiff
|
let endValue = hoveringOver.to[1] + priceDiff
|
||||||
let data = calculateTrendLine(startDate, startValue, endDate, endValue, this.interval, this.chart, hoveringOver.ray)
|
let data = calculateTrendLine(startDate, startValue, endDate, endValue, this.chart.interval, this.chart, hoveringOver.ray)
|
||||||
|
|
||||||
|
|
||||||
let logical = this.chart.chart.timeScale().getVisibleLogicalRange()
|
let logical = this.chart.chart.timeScale().getVisibleLogicalRange()
|
||||||
@ -439,9 +444,9 @@ if (!window.ToolBox) {
|
|||||||
let lastCandleTime = this.chart.candleData[this.chart.candleData.length - 1].time
|
let lastCandleTime = this.chart.candleData[this.chart.candleData.length - 1].time
|
||||||
if (!currentTime) {
|
if (!currentTime) {
|
||||||
let barsToMove = param.logical - this.chart.chart.timeScale().coordinateToLogical(this.chart.chart.timeScale().timeToCoordinate(lastCandleTime))
|
let barsToMove = param.logical - this.chart.chart.timeScale().coordinateToLogical(this.chart.chart.timeScale().timeToCoordinate(lastCandleTime))
|
||||||
currentTime = dateToStamp(new Date(stampToDate(this.chart.candleData[this.chart.candleData.length - 1].time).getTime() + (barsToMove * this.interval)))
|
currentTime = dateToStamp(new Date(stampToDate(this.chart.candleData[this.chart.candleData.length - 1].time).getTime() + (barsToMove * this.chart.interval)))
|
||||||
}
|
}
|
||||||
let data = calculateTrendLine(firstTime, firstPrice, currentTime, currentPrice, this.interval, this.chart)
|
let data = calculateTrendLine(firstTime, firstPrice, currentTime, currentPrice, this.chart.interval, this.chart)
|
||||||
hoveringOver.line.setData(data)
|
hoveringOver.line.setData(data)
|
||||||
|
|
||||||
this.chart.chart.timeScale().applyOptions({shiftVisibleRangeOnNewBar: true})
|
this.chart.chart.timeScale().applyOptions({shiftVisibleRangeOnNewBar: true})
|
||||||
@ -476,9 +481,9 @@ if (!window.ToolBox) {
|
|||||||
renderDrawings() {
|
renderDrawings() {
|
||||||
this.drawings.forEach((item) => {
|
this.drawings.forEach((item) => {
|
||||||
if ('price' in item) return
|
if ('price' in item) return
|
||||||
let startDate = dateToStamp(new Date(Math.round(stampToDate(item.from[0]).getTime() / this.interval) * this.interval))
|
let startDate = dateToStamp(new Date(Math.round(stampToDate(item.from[0]).getTime() / this.chart.interval) * this.chart.interval))
|
||||||
let endDate = dateToStamp(new Date(Math.round(stampToDate(item.to[0]).getTime() / this.interval) * this.interval))
|
let endDate = dateToStamp(new Date(Math.round(stampToDate(item.to[0]).getTime() / this.chart.interval) * this.chart.interval))
|
||||||
let data = calculateTrendLine(startDate, item.from[1], endDate, item.to[1], this.interval, this.chart, item.ray)
|
let data = calculateTrendLine(startDate, item.from[1], endDate, item.to[1], this.chart.interval, this.chart, item.ray)
|
||||||
item.from = [data[0].time, data[0].value]
|
item.from = [data[0].time, data[0].value]
|
||||||
item.to = [data[data.length - 1].time, data[data.length-1].value]
|
item.to = [data[data.length - 1].time, data[data.length-1].value]
|
||||||
item.line.setData(data)
|
item.line.setData(data)
|
||||||
@ -541,9 +546,9 @@ if (!window.ToolBox) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
let startDate = dateToStamp(new Date(Math.round(stampToDate(item.from[0]).getTime() / this.interval) * this.interval))
|
let startDate = dateToStamp(new Date(Math.round(stampToDate(item.from[0]).getTime() / this.chart.interval) * this.chart.interval))
|
||||||
let endDate = dateToStamp(new Date(Math.round(stampToDate(item.to[0]).getTime() / this.interval) * this.interval))
|
let endDate = dateToStamp(new Date(Math.round(stampToDate(item.to[0]).getTime() / this.chart.interval) * this.chart.interval))
|
||||||
let data = calculateTrendLine(startDate, item.from[1], endDate, item.to[1], this.interval, this.chart, item.ray)
|
let data = calculateTrendLine(startDate, item.from[1], endDate, item.to[1], this.chart.interval, this.chart, item.ray)
|
||||||
item.from = [data[0].time, data[0].value]
|
item.from = [data[0].time, data[0].value]
|
||||||
item.to = [data[data.length - 1].time, data[data.length-1].value]
|
item.to = [data[data.length - 1].time, data[data.length-1].value]
|
||||||
item.line.setData(data)
|
item.line.setData(data)
|
||||||
@ -554,9 +559,7 @@ if (!window.ToolBox) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
window.ToolBox = ToolBox
|
window.ToolBox = ToolBox
|
||||||
}
|
|
||||||
|
|
||||||
if (!window.ColorPicker) {
|
|
||||||
class ColorPicker {
|
class ColorPicker {
|
||||||
constructor(saveDrawings) {
|
constructor(saveDrawings) {
|
||||||
this.saveDrawings = saveDrawings
|
this.saveDrawings = saveDrawings
|
||||||
@ -685,4 +688,77 @@ if (!window.ColorPicker) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
window.ColorPicker = ColorPicker
|
window.ColorPicker = ColorPicker
|
||||||
|
class StylePicker {
|
||||||
|
constructor(saveDrawings) {
|
||||||
|
this.saveDrawings = saveDrawings
|
||||||
|
|
||||||
|
this.container = document.createElement('div')
|
||||||
|
this.container.style.position = 'absolute'
|
||||||
|
this.container.style.zIndex = '10000'
|
||||||
|
this.container.style.background = 'rgb(50, 50, 50)'
|
||||||
|
this.container.style.color = '#ececed'
|
||||||
|
this.container.style.display = 'none'
|
||||||
|
this.container.style.borderRadius = '5px'
|
||||||
|
this.container.style.padding = '3px 3px'
|
||||||
|
this.container.style.fontSize = '13px'
|
||||||
|
this.container.style.cursor = 'default'
|
||||||
|
|
||||||
|
let styles = [
|
||||||
|
{name: 'Solid', var: LightweightCharts.LineStyle.Solid},
|
||||||
|
{name: 'Dotted', var: LightweightCharts.LineStyle.Dotted},
|
||||||
|
{name: 'Dashed', var: LightweightCharts.LineStyle.Dashed},
|
||||||
|
{name: 'Large Dashed', var: LightweightCharts.LineStyle.LargeDashed},
|
||||||
|
{name: 'Sparse Dotted', var: LightweightCharts.LineStyle.SparseDotted},
|
||||||
|
]
|
||||||
|
styles.forEach((style) => {
|
||||||
|
this.container.appendChild(this.makeTextBox(style.name, style.var))
|
||||||
|
})
|
||||||
|
|
||||||
|
document.getElementById('wrapper').appendChild(this.container)
|
||||||
|
|
||||||
|
}
|
||||||
|
makeTextBox(text, style) {
|
||||||
|
let item = document.createElement('span')
|
||||||
|
item.style.display = 'flex'
|
||||||
|
item.style.alignItems = 'center'
|
||||||
|
item.style.justifyContent = 'space-between'
|
||||||
|
item.style.padding = '2px 10px'
|
||||||
|
item.style.margin = '1px 0px'
|
||||||
|
item.style.borderRadius = '3px'
|
||||||
|
item.innerText = text
|
||||||
|
|
||||||
|
item.addEventListener('mouseover', (event) => item.style.backgroundColor = 'rgba(0, 122, 255, 0.3)')
|
||||||
|
item.addEventListener('mouseout', (event) => item.style.backgroundColor = 'transparent')
|
||||||
|
|
||||||
|
item.addEventListener('click', (event) => {
|
||||||
|
this.style = style
|
||||||
|
this.updateStyle()
|
||||||
|
})
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStyle() {
|
||||||
|
if ('price' in this.drawing) this.drawing.updateStyle(this.style)
|
||||||
|
else {
|
||||||
|
this.drawing.line.applyOptions({lineStyle: this.style})
|
||||||
|
}
|
||||||
|
this.saveDrawings()
|
||||||
|
}
|
||||||
|
openMenu(rect, drawing) {
|
||||||
|
this.drawing = drawing
|
||||||
|
this.container.style.top = (rect.top-30)+'px'
|
||||||
|
this.container.style.left = rect.right+'px'
|
||||||
|
this.container.style.display = 'block'
|
||||||
|
setTimeout(() => document.addEventListener('mousedown', (event) => {
|
||||||
|
if (!this.container.contains(event.target)) {
|
||||||
|
this.closeMenu()
|
||||||
|
}
|
||||||
|
}), 10)
|
||||||
|
}
|
||||||
|
closeMenu(event) {
|
||||||
|
document.removeEventListener('click', this.closeMenu)
|
||||||
|
this.container.style.display = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.ColorPicker = ColorPicker
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user