Skip to content

Commit 9810940

Browse files
committed
Fix #278 (display 'flex' instead of 'block')
Fix syncing of chart legends (#284).
1 parent 8715dda commit 9810940

2 files changed

Lines changed: 100 additions & 76 deletions

File tree

lightweight_charts/js/funcs.js

Lines changed: 99 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ if (!window.Chart) {
182182

183183
class Legend {
184184
constructor(chart) {
185+
this.legendHandler = this.legendHandler.bind(this)
186+
187+
this.chart = chart
185188
this.ohlcEnabled = false
186189
this.percentEnabled = false
187190
this.linesEnabled = false
@@ -207,80 +210,12 @@ if (!window.Chart) {
207210

208211
this.makeLines(chart)
209212

210-
let legendItemFormat = (num, decimal) => num.toFixed(decimal).toString().padStart(8, ' ')
211-
212-
let shorthandFormat = (num) => {
213-
const absNum = Math.abs(num)
214-
if (absNum >= 1000000) {
215-
return (num / 1000000).toFixed(1) + 'M';
216-
} else if (absNum >= 1000) {
217-
return (num / 1000).toFixed(1) + 'K';
218-
}
219-
return num.toString().padStart(8, ' ');
220-
}
221-
222-
chart.chart.subscribeCrosshairMove((param) => {
223-
let options = chart.series.options()
224-
if (!param.time) {
225-
this.candle.style.color = 'transparent'
226-
this.candle.innerHTML = this.candle.innerHTML.replace(options['upColor'], '').replace(options['downColor'], '')
227-
return
228-
}
229-
let data = param.seriesData.get(chart.series);
230-
this.candle.style.color = ''
231-
let str = '<span style="line-height: 1.8;">'
232-
if (data) {
233-
if (this.ohlcEnabled) {
234-
str += `O ${legendItemFormat(data.open, chart.precision)} `
235-
str += `| H ${legendItemFormat(data.high, chart.precision)} `
236-
str += `| L ${legendItemFormat(data.low, chart.precision)} `
237-
str += `| C ${legendItemFormat(data.close, chart.precision)} `
238-
}
239-
240-
if (this.percentEnabled) {
241-
let percentMove = ((data.close - data.open) / data.open) * 100
242-
let color = percentMove > 0 ? options['upColor'] : options['downColor']
243-
let percentStr = `${percentMove >= 0 ? '+' : ''}${percentMove.toFixed(2)} %`
244-
245-
if (this.colorBasedOnCandle) {
246-
str += `| <span style="color: ${color};">${percentStr}</span>`
247-
}
248-
else {
249-
str += '| ' + percentStr
250-
}
251-
}
252-
let volumeData = param.seriesData.get(chart.volumeSeries)
253-
if (volumeData) {
254-
str += this.ohlcEnabled ? `<br>V ${shorthandFormat(volumeData.value)}` : ''
255-
}
256-
}
257-
this.candle.innerHTML = str + '</span>'
258-
259-
this.lines.forEach((line) => {
260-
if (!this.linesEnabled) {
261-
line.row.style.display = 'none'
262-
return
263-
}
264-
line.row.style.display = 'flex'
265-
if (!param.seriesData.get(line.line.series)) return
266-
let price = param.seriesData.get(line.line.series).value
267-
268-
if (line.line.type === 'histogram') {
269-
price = shorthandFormat(price)
270-
}
271-
else {
272-
price = legendItemFormat(price, line.line.precision)
273-
}
274-
line.div.innerHTML = `<span style="color: ${line.solid};">▨</span> ${line.line.name} : ${price}`
275-
})
276-
277-
278-
});
213+
chart.chart.subscribeCrosshairMove(this.legendHandler)
279214
}
280215

281216
toJSON() {
282217
// Exclude the chart attribute from serialization
283-
const {lines, ...serialized} = this;
218+
const {lines, chart, ...serialized} = this;
284219
return serialized;
285220
}
286221

@@ -352,19 +287,108 @@ if (!window.Chart) {
352287
solid: line.color.startsWith('rgba') ? line.color.replace(/[^,]+(?=\))/, '1') : line.color
353288
}
354289
}
290+
291+
legendItemFormat(num, decimal) { return num.toFixed(decimal).toString().padStart(8, ' ') }
292+
293+
shorthandFormat(num) {
294+
const absNum = Math.abs(num)
295+
if (absNum >= 1000000) {
296+
return (num / 1000000).toFixed(1) + 'M';
297+
} else if (absNum >= 1000) {
298+
return (num / 1000).toFixed(1) + 'K';
299+
}
300+
return num.toString().padStart(8, ' ');
301+
}
302+
303+
legendHandler(param) {
304+
let options = this.chart.series.options()
305+
306+
if (!param.time) {
307+
this.candle.style.color = 'transparent'
308+
this.candle.innerHTML = this.candle.innerHTML.replace(options['upColor'], '').replace(options['downColor'], '')
309+
return
310+
}
311+
312+
let usingPoint = !param.point && param.time
313+
314+
let data, logical
315+
316+
if (usingPoint) {
317+
let coordinate = this.chart.chart.timeScale().timeToCoordinate(param.time)
318+
logical = this.chart.chart.timeScale().coordinateToLogical(coordinate)
319+
data = this.chart.series.dataByIndex(logical)
320+
}
321+
else {
322+
data = param.seriesData.get(this.chart.series);
323+
}
324+
325+
this.candle.style.color = ''
326+
let str = '<span style="line-height: 1.8;">'
327+
if (data) {
328+
if (this.ohlcEnabled) {
329+
str += `O ${this.legendItemFormat(data.open, this.chart.precision)} `
330+
str += `| H ${this.legendItemFormat(data.high, this.chart.precision)} `
331+
str += `| L ${this.legendItemFormat(data.low, this.chart.precision)} `
332+
str += `| C ${this.legendItemFormat(data.close, this.chart.precision)} `
333+
}
334+
335+
if (this.percentEnabled) {
336+
let percentMove = ((data.close - data.open) / data.open) * 100
337+
let color = percentMove > 0 ? options['upColor'] : options['downColor']
338+
let percentStr = `${percentMove >= 0 ? '+' : ''}${percentMove.toFixed(2)} %`
339+
340+
if (this.colorBasedOnCandle) {
341+
str += `| <span style="color: ${color};">${percentStr}</span>`
342+
} else {
343+
str += '| ' + percentStr
344+
}
345+
}
346+
let volumeData = param.seriesData.get(this.chart.volumeSeries)
347+
if (volumeData) {
348+
str += this.ohlcEnabled ? `<br>V ${this.shorthandFormat(volumeData.value)}` : ''
349+
}
350+
}
351+
this.candle.innerHTML = str + '</span>'
352+
353+
this.lines.forEach((line) => {
354+
if (!this.linesEnabled) {
355+
line.row.style.display = 'none'
356+
return
357+
}
358+
line.row.style.display = 'flex'
359+
360+
let price
361+
if (usingPoint) {
362+
price = line.line.series.dataByIndex(logical)
363+
}
364+
else {
365+
price = param.seriesData.get(line.line.series)
366+
}
367+
if (!price) return
368+
else price = price.value
369+
370+
if (line.line.type === 'histogram') {
371+
price = this.shorthandFormat(price)
372+
} else {
373+
price = this.legendItemFormat(price, line.line.precision)
374+
}
375+
line.div.innerHTML = `<span style="color: ${line.solid};">▨</span> ${line.line.name} : ${price}`
376+
})
377+
}
355378
}
356379

357380
window.Legend = Legend
358381
}
359382

360383
function syncCharts(childChart, parentChart) {
361384

362-
function crosshairHandler(chart, series, point) {
385+
function crosshairHandler(chart, point) {
363386
if (!point) {
364-
chart.clearCrosshairPosition()
387+
chart.chart.clearCrosshairPosition()
365388
return
366389
}
367-
chart.setCrosshairPosition(point.value || point.close, point.time, series);
390+
chart.chart.setCrosshairPosition(point.value || point.close, point.time, chart.series);
391+
chart.legend.legendHandler(point)
368392
}
369393

370394
function getPoint(series, param) {
@@ -376,10 +400,10 @@ function syncCharts(childChart, parentChart) {
376400
let setParentRange = (timeRange) => parentChart.chart.timeScale().setVisibleLogicalRange(timeRange)
377401

378402
let setParentCrosshair = (param) => {
379-
crosshairHandler(parentChart.chart, parentChart.series, getPoint(childChart.series, param))
403+
crosshairHandler(parentChart, getPoint(childChart.series, param))
380404
}
381405
let setChildCrosshair = (param) => {
382-
crosshairHandler(childChart.chart, childChart.series, getPoint(parentChart.series, param))
406+
crosshairHandler(childChart, getPoint(parentChart.series, param))
383407
}
384408

385409
let selected = parentChart

lightweight_charts/table.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,6 @@ def resize(self, width: NUM, height: NUM): self.run_script(f'{self.id}.reSize({w
109109
def visible(self, visible: bool):
110110
self.is_shown = visible
111111
self.run_script(f"""
112-
{self.id}.container.style.display = '{'block' if visible else 'none'}'
112+
{self.id}.container.style.display = '{'flex' if visible else 'none'}'
113113
{self.id}.container.{'add' if visible else 'remove'}EventListener('mousedown', {self.id}.onMouseDown)
114114
""")

0 commit comments

Comments
 (0)