implement fill color option for boxes, start wx integration
This commit is contained in:
@ -7,7 +7,7 @@ import pandas as pd
|
|||||||
|
|
||||||
from .table import Table
|
from .table import Table
|
||||||
from .toolbox import ToolBox
|
from .toolbox import ToolBox
|
||||||
from .drawings import HorizontalLine, TwoPointDrawing, VerticalSpan
|
from .drawings import Box, HorizontalLine, TrendLine, TwoPointDrawing, VerticalSpan
|
||||||
from .topbar import TopBar
|
from .topbar import TopBar
|
||||||
from .util import (
|
from .util import (
|
||||||
Pane, Events, IDGen, as_enum, jbool, js_json, TIME, NUM, FLOAT,
|
Pane, Events, IDGen, as_enum, jbool, js_json, TIME, NUM, FLOAT,
|
||||||
@ -45,7 +45,7 @@ class Window:
|
|||||||
return
|
return
|
||||||
self.loaded = True
|
self.loaded = True
|
||||||
|
|
||||||
# TODO this wont work for anything which isnt pywebview :( put it in the chart class ?
|
if hasattr(self, '_return_q'):
|
||||||
while not self.run_script_and_get('document.readyState == "complete"'):
|
while not self.run_script_and_get('document.readyState == "complete"'):
|
||||||
continue # scary, but works
|
continue # scary, but works
|
||||||
|
|
||||||
@ -283,13 +283,13 @@ class SeriesCommon(Pane):
|
|||||||
:return: The id of the marker placed.
|
:return: The id of the marker placed.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
time = self._last_bar['time'] if not time else self._single_datetime_format(time)
|
formatted_time = self._last_bar['time'] if not time else self._single_datetime_format(time)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
raise TypeError('Chart marker created before data was set.')
|
raise TypeError('Chart marker created before data was set.')
|
||||||
marker_id = self.win._id_gen.generate()
|
marker_id = self.win._id_gen.generate()
|
||||||
self.run_script(f"""
|
self.run_script(f"""
|
||||||
{self.id}.markers.push({{
|
{self.id}.markers.push({{
|
||||||
time: {time if isinstance(time, float) else f"'{time}'"},
|
time: {time if isinstance(formatted_time, float) else f"'{formatted_time}'"},
|
||||||
position: '{marker_position(position)}',
|
position: '{marker_position(position)}',
|
||||||
color: '{color}',
|
color: '{color}',
|
||||||
shape: '{marker_shape(shape)}',
|
shape: '{marker_shape(shape)}',
|
||||||
@ -719,11 +719,11 @@ class AbstractChart(Candlestick, Pane):
|
|||||||
end_time: TIME,
|
end_time: TIME,
|
||||||
end_value: NUM,
|
end_value: NUM,
|
||||||
round: bool = False,
|
round: bool = False,
|
||||||
color: str = '#1E80F0',
|
line_color: str = '#1E80F0',
|
||||||
width: int = 2,
|
width: int = 2,
|
||||||
style: LINE_STYLE = 'solid',
|
style: LINE_STYLE = 'solid',
|
||||||
) -> TwoPointDrawing:
|
) -> TwoPointDrawing:
|
||||||
return TwoPointDrawing("TrendLine", *locals().values())
|
return TrendLine(*locals().values())
|
||||||
|
|
||||||
def box(
|
def box(
|
||||||
self,
|
self,
|
||||||
@ -733,10 +733,11 @@ class AbstractChart(Candlestick, Pane):
|
|||||||
end_value: NUM,
|
end_value: NUM,
|
||||||
round: bool = False,
|
round: bool = False,
|
||||||
color: str = '#1E80F0',
|
color: str = '#1E80F0',
|
||||||
|
fill_color: str = 'rgba(255, 255, 255, 0.2)',
|
||||||
width: int = 2,
|
width: int = 2,
|
||||||
style: LINE_STYLE = 'solid',
|
style: LINE_STYLE = 'solid',
|
||||||
) -> TwoPointDrawing:
|
) -> TwoPointDrawing:
|
||||||
return TwoPointDrawing("Box", *locals().values())
|
return Box(*locals().values())
|
||||||
|
|
||||||
def ray_line(
|
def ray_line(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@ -6,11 +6,11 @@ from typing import Union, Optional
|
|||||||
|
|
||||||
from lightweight_charts.util import js_json
|
from lightweight_charts.util import js_json
|
||||||
|
|
||||||
from .util import NUM, Pane, as_enum, LINE_STYLE, TIME
|
from .util import NUM, Pane, as_enum, LINE_STYLE, TIME, snake_to_camel
|
||||||
|
|
||||||
|
|
||||||
class Drawing(Pane):
|
class Drawing(Pane):
|
||||||
def __init__(self, chart, color, width, style, func=None):
|
def __init__(self, chart, func=None):
|
||||||
super().__init__(chart.win)
|
super().__init__(chart.win)
|
||||||
self.chart = chart
|
self.chart = chart
|
||||||
|
|
||||||
@ -34,13 +34,10 @@ class TwoPointDrawing(Drawing):
|
|||||||
end_time: TIME,
|
end_time: TIME,
|
||||||
end_value: NUM,
|
end_value: NUM,
|
||||||
round: bool,
|
round: bool,
|
||||||
color,
|
options: dict,
|
||||||
width,
|
|
||||||
style,
|
|
||||||
func=None
|
func=None
|
||||||
):
|
):
|
||||||
super().__init__(chart, color, width, style, func)
|
super().__init__(chart, func)
|
||||||
|
|
||||||
|
|
||||||
def make_js_point(time, price):
|
def make_js_point(time, price):
|
||||||
formatted_time = self.chart._single_datetime_format(time)
|
formatted_time = self.chart._single_datetime_format(time)
|
||||||
@ -54,14 +51,14 @@ class TwoPointDrawing(Drawing):
|
|||||||
"price": {price}
|
"price": {price}
|
||||||
}}'''
|
}}'''
|
||||||
|
|
||||||
|
options_string = '\n'.join(f'{key}: {val},' for key, val in options.items())
|
||||||
|
|
||||||
self.run_script(f'''
|
self.run_script(f'''
|
||||||
{self.id} = new {drawing_type}(
|
{self.id} = new {drawing_type}(
|
||||||
{make_js_point(start_time, start_value)},
|
{make_js_point(start_time, start_value)},
|
||||||
{make_js_point(end_time, end_value)},
|
{make_js_point(end_time, end_value)},
|
||||||
{{
|
{{
|
||||||
lineColor: '{color}',
|
{options_string}
|
||||||
lineStyle: {as_enum(style, LINE_STYLE)},
|
|
||||||
width: {width},
|
|
||||||
}}
|
}}
|
||||||
)
|
)
|
||||||
{chart.id}.series.attachPrimitive({self.id})
|
{chart.id}.series.attachPrimitive({self.id})
|
||||||
@ -70,7 +67,7 @@ class TwoPointDrawing(Drawing):
|
|||||||
|
|
||||||
class HorizontalLine(Drawing):
|
class HorizontalLine(Drawing):
|
||||||
def __init__(self, chart, price, color, width, style, text, axis_label_visible, func):
|
def __init__(self, chart, price, color, width, style, text, axis_label_visible, func):
|
||||||
super().__init__(chart, color, width, style, func)
|
super().__init__(chart, func)
|
||||||
self.price = price
|
self.price = price
|
||||||
self.run_script(f'''
|
self.run_script(f'''
|
||||||
|
|
||||||
@ -113,7 +110,7 @@ class HorizontalLine(Drawing):
|
|||||||
|
|
||||||
class VerticalLine(Drawing):
|
class VerticalLine(Drawing):
|
||||||
def __init__(self, chart, time, color, width, style, text, axis_label_visible, func):
|
def __init__(self, chart, time, color, width, style, text, axis_label_visible, func):
|
||||||
super().__init__(chart, color, width, style, func)
|
super().__init__(chart, func)
|
||||||
self.time = time
|
self.time = time
|
||||||
self.run_script(f'''
|
self.run_script(f'''
|
||||||
|
|
||||||
@ -137,6 +134,67 @@ class VerticalLine(Drawing):
|
|||||||
self.run_script(f'{self.id}.updateLabel("{text}")')
|
self.run_script(f'{self.id}.updateLabel("{text}")')
|
||||||
|
|
||||||
|
|
||||||
|
class Box(TwoPointDrawing):
|
||||||
|
def __init__(self,
|
||||||
|
chart,
|
||||||
|
start_time: TIME,
|
||||||
|
start_value: NUM,
|
||||||
|
end_time: TIME,
|
||||||
|
end_value: NUM,
|
||||||
|
round: bool,
|
||||||
|
line_color: str,
|
||||||
|
fill_color: str,
|
||||||
|
width: int,
|
||||||
|
style: LINE_STYLE,
|
||||||
|
func=None):
|
||||||
|
|
||||||
|
super().__init__(
|
||||||
|
"Box",
|
||||||
|
chart,
|
||||||
|
start_time,
|
||||||
|
start_value,
|
||||||
|
end_time,
|
||||||
|
end_value,
|
||||||
|
round,
|
||||||
|
{
|
||||||
|
"lineColor": f'"{line_color}"',
|
||||||
|
"fillColor": f'"{fill_color}"',
|
||||||
|
"width": width,
|
||||||
|
"lineStyle": as_enum(style, LINE_STYLE)
|
||||||
|
},
|
||||||
|
func
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TrendLine(TwoPointDrawing):
|
||||||
|
def __init__(self,
|
||||||
|
chart,
|
||||||
|
start_time: TIME,
|
||||||
|
start_value: NUM,
|
||||||
|
end_time: TIME,
|
||||||
|
end_value: NUM,
|
||||||
|
round: bool,
|
||||||
|
line_color: str,
|
||||||
|
width: int,
|
||||||
|
style: LINE_STYLE,
|
||||||
|
func=None):
|
||||||
|
|
||||||
|
super().__init__(
|
||||||
|
"TrendLine",
|
||||||
|
chart,
|
||||||
|
start_time,
|
||||||
|
start_value,
|
||||||
|
end_time,
|
||||||
|
end_value,
|
||||||
|
round,
|
||||||
|
{
|
||||||
|
"lineColor": f'"line_color"',
|
||||||
|
"width": width,
|
||||||
|
"lineStyle": as_enum(style, LINE_STYLE)
|
||||||
|
},
|
||||||
|
func
|
||||||
|
)
|
||||||
|
|
||||||
class VerticalSpan(Pane):
|
class VerticalSpan(Pane):
|
||||||
def __init__(self, series: 'SeriesCommon', start_time: Union[TIME, tuple, list], end_time: Optional[TIME] = None,
|
def __init__(self, series: 'SeriesCommon', start_time: Union[TIME, tuple, list], end_time: Optional[TIME] = None,
|
||||||
color: str = 'rgba(252, 219, 3, 0.2)'):
|
color: str = 'rgba(252, 219, 3, 0.2)'):
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -247,7 +247,7 @@ class PolygonAPI:
|
|||||||
|
|
||||||
df = await async_get_bar_data(ticker, timeframe, start_date, end_date, limit)
|
df = await async_get_bar_data(ticker, timeframe, start_date, end_date, limit)
|
||||||
|
|
||||||
self._chart.set(df, render_drawings=_tickers.get(self._chart) == ticker)
|
self._chart.set(df, keep_drawings=_tickers.get(self._chart) == ticker)
|
||||||
_tickers[self._chart] = ticker
|
_tickers[self._chart] = ticker
|
||||||
|
|
||||||
if not live:
|
if not live:
|
||||||
|
|||||||
@ -63,8 +63,8 @@ class WxChart(abstract.AbstractChart):
|
|||||||
self.webview.Bind(wx.html2.EVT_WEBVIEW_LOADED, lambda e: wx.CallLater(500, self.win.on_js_load))
|
self.webview.Bind(wx.html2.EVT_WEBVIEW_LOADED, lambda e: wx.CallLater(500, self.win.on_js_load))
|
||||||
self.webview.Bind(wx.html2.EVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, lambda e: emit_callback(self, e.GetString()))
|
self.webview.Bind(wx.html2.EVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, lambda e: emit_callback(self, e.GetString()))
|
||||||
self.webview.AddScriptMessageHandler('wx_msg')
|
self.webview.AddScriptMessageHandler('wx_msg')
|
||||||
self.webview.SetPage(abstract.TEMPLATE, '')
|
self.webview.LoadURL(f'file:///{abstract.INDEX}')
|
||||||
self.webview.AddUserScript(abstract.JS['toolbox']) if toolbox else None
|
# self.webview.AddUserScript(abstract.JS['toolbox']) if toolbox else None
|
||||||
|
|
||||||
def get_webview(self): return self.webview
|
def get_webview(self): return self.webview
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,9 @@ export class ColorPicker {
|
|||||||
private _opacityLabel: HTMLDivElement;
|
private _opacityLabel: HTMLDivElement;
|
||||||
private rgba: number[] | undefined;
|
private rgba: number[] | undefined;
|
||||||
|
|
||||||
constructor(saveDrawings: Function) {
|
constructor(saveDrawings: Function,
|
||||||
|
private colorOption: string,
|
||||||
|
) {
|
||||||
this.saveDrawings = saveDrawings
|
this.saveDrawings = saveDrawings
|
||||||
|
|
||||||
this._div = document.createElement('div');
|
this._div = document.createElement('div');
|
||||||
@ -114,12 +116,12 @@ export class ColorPicker {
|
|||||||
updateColor() {
|
updateColor() {
|
||||||
if (!Drawing.lastHoveredObject || !this.rgba) return;
|
if (!Drawing.lastHoveredObject || !this.rgba) return;
|
||||||
const oColor = `rgba(${this.rgba[0]}, ${this.rgba[1]}, ${this.rgba[2]}, ${this.opacity})`
|
const oColor = `rgba(${this.rgba[0]}, ${this.rgba[1]}, ${this.rgba[2]}, ${this.opacity})`
|
||||||
Drawing.lastHoveredObject.applyOptions({lineColor: oColor})
|
Drawing.lastHoveredObject.applyOptions({[this.colorOption]: oColor})
|
||||||
this.saveDrawings()
|
this.saveDrawings()
|
||||||
}
|
}
|
||||||
openMenu(rect: DOMRect) {
|
openMenu(rect: DOMRect) {
|
||||||
if (!Drawing.lastHoveredObject) return;
|
if (!Drawing.lastHoveredObject) return;
|
||||||
this.rgba = ColorPicker.extractRGBA(Drawing.lastHoveredObject._options.lineColor)
|
this.rgba = ColorPicker.extractRGBA(Drawing.lastHoveredObject._options[this.colorOption])
|
||||||
this.opacity = this.rgba[3];
|
this.opacity = this.rgba[3];
|
||||||
this._updateOpacitySlider();
|
this._updateOpacitySlider();
|
||||||
this._div.style.top = (rect.top-30)+'px'
|
this._div.style.top = (rect.top-30)+'px'
|
||||||
|
|||||||
@ -1,5 +1,21 @@
|
|||||||
import { Drawing } from "../drawing/drawing";
|
import { Drawing } from "../drawing/drawing";
|
||||||
|
import { DrawingTool } from "../drawing/drawing-tool";
|
||||||
import { GlobalParams } from "../general/global-params";
|
import { GlobalParams } from "../general/global-params";
|
||||||
|
import { ColorPicker } from "./color-picker";
|
||||||
|
import { StylePicker } from "./style-picker";
|
||||||
|
|
||||||
|
|
||||||
|
export function camelToTitle(inputString: string) {
|
||||||
|
const result = [];
|
||||||
|
for (const c of inputString) {
|
||||||
|
if (result.length == 0) {
|
||||||
|
result.push(c.toUpperCase());
|
||||||
|
} else if (c == c.toUpperCase()) {
|
||||||
|
result.push(' '+c);
|
||||||
|
} else result.push(c);
|
||||||
|
}
|
||||||
|
return result.join('');
|
||||||
|
}
|
||||||
|
|
||||||
interface Item {
|
interface Item {
|
||||||
elem: HTMLSpanElement;
|
elem: HTMLSpanElement;
|
||||||
@ -13,8 +29,12 @@ declare const window: GlobalParams;
|
|||||||
export class ContextMenu {
|
export class ContextMenu {
|
||||||
private div: HTMLDivElement
|
private div: HTMLDivElement
|
||||||
private hoverItem: Item | null;
|
private hoverItem: Item | null;
|
||||||
|
private items: HTMLElement[] = []
|
||||||
|
|
||||||
constructor() {
|
constructor(
|
||||||
|
private saveDrawings: Function,
|
||||||
|
private drawingTool: DrawingTool,
|
||||||
|
) {
|
||||||
this._onRightClick = this._onRightClick.bind(this);
|
this._onRightClick = this._onRightClick.bind(this);
|
||||||
this.div = document.createElement('div');
|
this.div = document.createElement('div');
|
||||||
this.div.classList.add('context-menu');
|
this.div.classList.add('context-menu');
|
||||||
@ -35,6 +55,50 @@ export class ContextMenu {
|
|||||||
|
|
||||||
private _onRightClick(ev: MouseEvent) {
|
private _onRightClick(ev: MouseEvent) {
|
||||||
if (!Drawing.hoveredObject) return;
|
if (!Drawing.hoveredObject) return;
|
||||||
|
|
||||||
|
for (const item of this.items) {
|
||||||
|
this.div.removeChild(item);
|
||||||
|
}
|
||||||
|
this.items = [];
|
||||||
|
|
||||||
|
for (const optionName of Object.keys(Drawing.hoveredObject._options)) {
|
||||||
|
let subMenu;
|
||||||
|
if (optionName.toLowerCase().includes('color')) {
|
||||||
|
subMenu = new ColorPicker(this.saveDrawings, optionName);
|
||||||
|
} else if (optionName === 'lineStyle') {
|
||||||
|
subMenu = new StylePicker(this.saveDrawings)
|
||||||
|
} else continue;
|
||||||
|
|
||||||
|
let onClick = (rect: DOMRect) => subMenu.openMenu(rect)
|
||||||
|
this.menuItem(camelToTitle(optionName), onClick, () => {
|
||||||
|
document.removeEventListener('click', subMenu.closeMenu)
|
||||||
|
subMenu._div.style.display = 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let onClickDelete = () => this.drawingTool.delete(Drawing.lastHoveredObject);
|
||||||
|
this.separator()
|
||||||
|
this.menuItem('Delete Drawing', onClickDelete)
|
||||||
|
|
||||||
|
// const colorPicker = new ColorPicker(this.saveDrawings)
|
||||||
|
// const stylePicker = new StylePicker(this.saveDrawings)
|
||||||
|
|
||||||
|
// let onClickDelete = () => this._drawingTool.delete(Drawing.lastHoveredObject);
|
||||||
|
// let onClickColor = (rect: DOMRect) => colorPicker.openMenu(rect)
|
||||||
|
// let onClickStyle = (rect: DOMRect) => stylePicker.openMenu(rect)
|
||||||
|
|
||||||
|
// contextMenu.menuItem('Color Picker', onClickColor, () => {
|
||||||
|
// document.removeEventListener('click', colorPicker.closeMenu)
|
||||||
|
// colorPicker._div.style.display = 'none'
|
||||||
|
// })
|
||||||
|
// contextMenu.menuItem('Style', onClickStyle, () => {
|
||||||
|
// document.removeEventListener('click', stylePicker.closeMenu)
|
||||||
|
// stylePicker._div.style.display = 'none'
|
||||||
|
// })
|
||||||
|
// contextMenu.separator()
|
||||||
|
// contextMenu.menuItem('Delete Drawing', onClickDelete)
|
||||||
|
|
||||||
|
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
this.div.style.left = ev.clientX + 'px';
|
this.div.style.left = ev.clientX + 'px';
|
||||||
this.div.style.top = ev.clientY + 'px';
|
this.div.style.top = ev.clientY + 'px';
|
||||||
@ -70,6 +134,9 @@ export class ContextMenu {
|
|||||||
item.addEventListener('mouseover', () => timeout = setTimeout(() => action(item.getBoundingClientRect()), 100))
|
item.addEventListener('mouseover', () => timeout = setTimeout(() => action(item.getBoundingClientRect()), 100))
|
||||||
item.addEventListener('mouseout', () => clearTimeout(timeout))
|
item.addEventListener('mouseout', () => clearTimeout(timeout))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.items.push(item);
|
||||||
|
|
||||||
}
|
}
|
||||||
public separator() {
|
public separator() {
|
||||||
const separator = document.createElement('div')
|
const separator = document.createElement('div')
|
||||||
@ -78,6 +145,8 @@ export class ContextMenu {
|
|||||||
separator.style.margin = '3px 0px'
|
separator.style.margin = '3px 0px'
|
||||||
separator.style.backgroundColor = window.pane.borderColor
|
separator.style.backgroundColor = window.pane.borderColor
|
||||||
this.div.appendChild(separator)
|
this.div.appendChild(separator)
|
||||||
|
|
||||||
|
this.items.push(separator);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,6 @@ import { Box } from "../box/box";
|
|||||||
import { Drawing } from "../drawing/drawing";
|
import { Drawing } from "../drawing/drawing";
|
||||||
import { ContextMenu } from "../context-menu/context-menu";
|
import { ContextMenu } from "../context-menu/context-menu";
|
||||||
import { GlobalParams } from "./global-params";
|
import { GlobalParams } from "./global-params";
|
||||||
import { StylePicker } from "../context-menu/style-picker";
|
|
||||||
import { ColorPicker } from "../context-menu/color-picker";
|
|
||||||
import { IChartApi, ISeriesApi, SeriesType } from "lightweight-charts";
|
import { IChartApi, ISeriesApi, SeriesType } from "lightweight-charts";
|
||||||
import { HorizontalLine } from "../horizontal-line/horizontal-line";
|
import { HorizontalLine } from "../horizontal-line/horizontal-line";
|
||||||
import { RayLine } from "../horizontal-line/ray-line";
|
import { RayLine } from "../horizontal-line/ray-line";
|
||||||
@ -42,7 +40,7 @@ export class ToolBox {
|
|||||||
this._commandFunctions = commandFunctions;
|
this._commandFunctions = commandFunctions;
|
||||||
this._drawingTool = new DrawingTool(chart, series, () => this.removeActiveAndSave());
|
this._drawingTool = new DrawingTool(chart, series, () => this.removeActiveAndSave());
|
||||||
this.div = this._makeToolBox()
|
this.div = this._makeToolBox()
|
||||||
this._makeContextMenu();
|
new ContextMenu(this.saveDrawings, this._drawingTool);
|
||||||
|
|
||||||
commandFunctions.push((event: KeyboardEvent) => {
|
commandFunctions.push((event: KeyboardEvent) => {
|
||||||
if ((event.metaKey || event.ctrlKey) && event.code === 'KeyZ') {
|
if ((event.metaKey || event.ctrlKey) && event.code === 'KeyZ') {
|
||||||
@ -130,27 +128,6 @@ export class ToolBox {
|
|||||||
this.saveDrawings()
|
this.saveDrawings()
|
||||||
}
|
}
|
||||||
|
|
||||||
private _makeContextMenu() {
|
|
||||||
const contextMenu = new ContextMenu()
|
|
||||||
const colorPicker = new ColorPicker(this.saveDrawings)
|
|
||||||
const stylePicker = new StylePicker(this.saveDrawings)
|
|
||||||
|
|
||||||
let onClickDelete = () => this._drawingTool.delete(Drawing.lastHoveredObject);
|
|
||||||
let onClickColor = (rect: DOMRect) => colorPicker.openMenu(rect)
|
|
||||||
let onClickStyle = (rect: DOMRect) => stylePicker.openMenu(rect)
|
|
||||||
|
|
||||||
contextMenu.menuItem('Color Picker', onClickColor, () => {
|
|
||||||
document.removeEventListener('click', colorPicker.closeMenu)
|
|
||||||
colorPicker._div.style.display = 'none'
|
|
||||||
})
|
|
||||||
contextMenu.menuItem('Style', onClickStyle, () => {
|
|
||||||
document.removeEventListener('click', stylePicker.closeMenu)
|
|
||||||
stylePicker._div.style.display = 'none'
|
|
||||||
})
|
|
||||||
contextMenu.separator()
|
|
||||||
contextMenu.menuItem('Delete Drawing', onClickDelete)
|
|
||||||
}
|
|
||||||
|
|
||||||
// renderDrawings() {
|
// renderDrawings() {
|
||||||
// if (this.mouseDown) return
|
// if (this.mouseDown) return
|
||||||
// this.drawings.forEach((item) => {
|
// this.drawings.forEach((item) => {
|
||||||
|
|||||||
@ -1,62 +0,0 @@
|
|||||||
// import { Handler } from "../general/handler"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// interface Command {
|
|
||||||
// type: string,
|
|
||||||
// id: string,
|
|
||||||
// method: string,
|
|
||||||
// args: string,
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// class Interpreter {
|
|
||||||
// private _tokens: string[];
|
|
||||||
// private cwd: string;
|
|
||||||
// private _i: number;
|
|
||||||
|
|
||||||
// private objects = {};
|
|
||||||
|
|
||||||
// constructor() {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private _next() {
|
|
||||||
// this._i++;
|
|
||||||
// this.cwd = this._tokens[this._i];
|
|
||||||
// return this.cwd;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private _handleCommand(command: string[]) {
|
|
||||||
// const type = this.cwd;
|
|
||||||
// switch (this.cwd) {
|
|
||||||
// case "auth":
|
|
||||||
// break;
|
|
||||||
// case "create":
|
|
||||||
// return this._create();
|
|
||||||
// case "obj":
|
|
||||||
// break;
|
|
||||||
// case "":
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private static readonly createMap = {
|
|
||||||
// "Handler": Handler,
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// // create, HorizontalLine, id
|
|
||||||
// private _create() {
|
|
||||||
// const type = this.cwd;
|
|
||||||
// this._next();
|
|
||||||
|
|
||||||
// Interpreter.createMap[type](...this.cwd)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private _obj() {
|
|
||||||
// const id = this._next();
|
|
||||||
// const method = this._next();
|
|
||||||
// const args = this._next();
|
|
||||||
// this.objects[id][method](args);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@ -19,4 +19,4 @@ if __name__ == '__main__':
|
|||||||
loader = unittest.TestLoader()
|
loader = unittest.TestLoader()
|
||||||
cases = [loader.loadTestsFromTestCase(module) for module in TEST_CASES]
|
cases = [loader.loadTestsFromTestCase(module) for module in TEST_CASES]
|
||||||
suite = unittest.TestSuite(cases)
|
suite = unittest.TestSuite(cases)
|
||||||
unittest.TextTestRunner().run(suite)
|
unittest.TextTestRunner(verbosity=2).run(suite)
|
||||||
@ -1,13 +1,10 @@
|
|||||||
import unittest
|
import unittest
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from util import BARS
|
from util import BARS, Tester
|
||||||
from lightweight_charts import Chart
|
from lightweight_charts import Chart
|
||||||
|
|
||||||
|
|
||||||
class TestChart(unittest.TestCase):
|
class TestChart(Tester):
|
||||||
def setUp(self):
|
|
||||||
self.chart = Chart()
|
|
||||||
|
|
||||||
def test_data_is_renamed(self):
|
def test_data_is_renamed(self):
|
||||||
uppercase_df = pd.DataFrame(BARS.copy()).rename({'date': 'Date', 'open': 'OPEN', 'high': 'HIgh', 'low': 'Low', 'close': 'close', 'volUME': 'volume'})
|
uppercase_df = pd.DataFrame(BARS.copy()).rename({'date': 'Date', 'open': 'OPEN', 'high': 'HIgh', 'low': 'Low', 'close': 'close', 'volUME': 'volume'})
|
||||||
result = self.chart._df_datetime_format(uppercase_df)
|
result = self.chart._df_datetime_format(uppercase_df)
|
||||||
@ -19,9 +16,6 @@ class TestChart(unittest.TestCase):
|
|||||||
self.assertEqual(result0, self.chart.lines()[0])
|
self.assertEqual(result0, self.chart.lines()[0])
|
||||||
self.assertEqual(result1, self.chart.lines()[1])
|
self.assertEqual(result1, self.chart.lines()[1])
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.chart.exit()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
@ -15,7 +15,7 @@ class TestReturns(Tester):
|
|||||||
self.assertIsNotNone(screenshot_data)
|
self.assertIsNotNone(screenshot_data)
|
||||||
|
|
||||||
def test_save_drawings(self):
|
def test_save_drawings(self):
|
||||||
self.chart.exit()
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
asyncio.create_task(self.chart.show_async());
|
asyncio.create_task(self.chart.show_async());
|
||||||
@ -28,7 +28,7 @@ class TestReturns(Tester):
|
|||||||
self.assertTrue(len(self.chart.toolbox.drawings) > 0)
|
self.assertTrue(len(self.chart.toolbox.drawings) > 0)
|
||||||
self.chart.exit()
|
self.chart.exit()
|
||||||
|
|
||||||
self.chart = Chart(toolbox=True, debug=True)
|
self.chart = Chart(toolbox=True, width=100, height=100)
|
||||||
self.chart.set(BARS)
|
self.chart.set(BARS)
|
||||||
self.chart.topbar.textbox('symbol', 'SYM', align='right')
|
self.chart.topbar.textbox('symbol', 'SYM', align='right')
|
||||||
self.chart.toolbox.save_drawings_under(self.chart.topbar['symbol'])
|
self.chart.toolbox.save_drawings_under(self.chart.topbar['symbol'])
|
||||||
|
|||||||
@ -2,21 +2,20 @@ import unittest
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
from lightweight_charts import Chart
|
from lightweight_charts import Chart
|
||||||
|
from util import Tester
|
||||||
|
|
||||||
|
|
||||||
class TestTopBar(unittest.TestCase):
|
class TestTopBar(Tester):
|
||||||
def test_switcher_fires_event(self):
|
def test_switcher_fires_event(self):
|
||||||
chart = Chart()
|
self.chart.topbar.switcher('a', ('1', '2'), func=lambda c: (self.assertEqual(c.topbar['a'].value, '2'), c.exit()))
|
||||||
chart.topbar.switcher('a', ('1', '2'), func=lambda c: (self.assertEqual(c.topbar['a'].value, '2'), c.exit()))
|
self.chart.run_script(f'{self.chart.topbar["a"].id}.intervalElements[1].dispatchEvent(new Event("click"))')
|
||||||
chart.run_script(f'{chart.topbar["a"].id}.intervalElements[1].dispatchEvent(new Event("click"))')
|
self.chart.show(block=True)
|
||||||
chart.show(block=True)
|
|
||||||
|
|
||||||
def test_button_fires_event(self):
|
def test_button_fires_event(self):
|
||||||
chart = Chart()
|
self.chart.topbar.button('a', '1', func=lambda c: (self.assertEqual(c.topbar['a'].value, '2'), c.exit()))
|
||||||
chart.topbar.button('a', '1', func=lambda c: (self.assertEqual(c.topbar['a'].value, '2'), c.exit()))
|
self.chart.topbar['a'].set('2')
|
||||||
chart.topbar['a'].set('2')
|
self.chart.run_script(f'{self.chart.topbar["a"].id}.elem.dispatchEvent(new Event("click"))')
|
||||||
chart.run_script(f'{chart.topbar["a"].id}.elem.dispatchEvent(new Event("click"))')
|
self.chart.show(block=True)
|
||||||
chart.show(block=True)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
Reference in New Issue
Block a user