implement fill color option for boxes, start wx integration

This commit is contained in:
louisnw
2024-05-16 11:25:42 +01:00
parent f8c0a5754d
commit 906571e4fb
13 changed files with 175 additions and 137 deletions

View File

@ -7,7 +7,7 @@ import pandas as pd
from .table import Table
from .toolbox import ToolBox
from .drawings import HorizontalLine, TwoPointDrawing, VerticalSpan
from .drawings import Box, HorizontalLine, TrendLine, TwoPointDrawing, VerticalSpan
from .topbar import TopBar
from .util import (
Pane, Events, IDGen, as_enum, jbool, js_json, TIME, NUM, FLOAT,
@ -45,9 +45,9 @@ class Window:
return
self.loaded = True
# TODO this wont work for anything which isnt pywebview :( put it in the chart class ?
while not self.run_script_and_get('document.readyState == "complete"'):
continue # scary, but works
if hasattr(self, '_return_q'):
while not self.run_script_and_get('document.readyState == "complete"'):
continue # scary, but works
initial_script = ''
self.scripts.extend(self.final_scripts)
@ -283,13 +283,13 @@ class SeriesCommon(Pane):
:return: The id of the marker placed.
"""
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:
raise TypeError('Chart marker created before data was set.')
marker_id = self.win._id_gen.generate()
self.run_script(f"""
{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)}',
color: '{color}',
shape: '{marker_shape(shape)}',
@ -719,11 +719,11 @@ class AbstractChart(Candlestick, Pane):
end_time: TIME,
end_value: NUM,
round: bool = False,
color: str = '#1E80F0',
line_color: str = '#1E80F0',
width: int = 2,
style: LINE_STYLE = 'solid',
) -> TwoPointDrawing:
return TwoPointDrawing("TrendLine", *locals().values())
return TrendLine(*locals().values())
def box(
self,
@ -733,10 +733,11 @@ class AbstractChart(Candlestick, Pane):
end_value: NUM,
round: bool = False,
color: str = '#1E80F0',
fill_color: str = 'rgba(255, 255, 255, 0.2)',
width: int = 2,
style: LINE_STYLE = 'solid',
) -> TwoPointDrawing:
return TwoPointDrawing("Box", *locals().values())
return Box(*locals().values())
def ray_line(
self,

View File

@ -6,11 +6,11 @@ from typing import Union, Optional
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):
def __init__(self, chart, color, width, style, func=None):
def __init__(self, chart, func=None):
super().__init__(chart.win)
self.chart = chart
@ -34,13 +34,10 @@ class TwoPointDrawing(Drawing):
end_time: TIME,
end_value: NUM,
round: bool,
color,
width,
style,
options: dict,
func=None
):
super().__init__(chart, color, width, style, func)
super().__init__(chart, func)
def make_js_point(time, price):
formatted_time = self.chart._single_datetime_format(time)
@ -54,14 +51,14 @@ class TwoPointDrawing(Drawing):
"price": {price}
}}'''
options_string = '\n'.join(f'{key}: {val},' for key, val in options.items())
self.run_script(f'''
{self.id} = new {drawing_type}(
{make_js_point(start_time, start_value)},
{make_js_point(end_time, end_value)},
{{
lineColor: '{color}',
lineStyle: {as_enum(style, LINE_STYLE)},
width: {width},
{options_string}
}}
)
{chart.id}.series.attachPrimitive({self.id})
@ -70,7 +67,7 @@ class TwoPointDrawing(Drawing):
class HorizontalLine(Drawing):
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.run_script(f'''
@ -113,7 +110,7 @@ class HorizontalLine(Drawing):
class VerticalLine(Drawing):
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.run_script(f'''
@ -136,7 +133,68 @@ class VerticalLine(Drawing):
def label(self, text: str): # TODO
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):
def __init__(self, series: 'SeriesCommon', start_time: Union[TIME, tuple, list], end_time: Optional[TIME] = None,
color: str = 'rgba(252, 219, 3, 0.2)'):

File diff suppressed because one or more lines are too long

View File

@ -247,7 +247,7 @@ class PolygonAPI:
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
if not live:

View File

@ -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_SCRIPT_MESSAGE_RECEIVED, lambda e: emit_callback(self, e.GetString()))
self.webview.AddScriptMessageHandler('wx_msg')
self.webview.SetPage(abstract.TEMPLATE, '')
self.webview.AddUserScript(abstract.JS['toolbox']) if toolbox else None
self.webview.LoadURL(f'file:///{abstract.INDEX}')
# self.webview.AddUserScript(abstract.JS['toolbox']) if toolbox else None
def get_webview(self): return self.webview