ongoing UI work; fixes; TV callback loop problems again/still
This commit is contained in:
@@ -42,7 +42,7 @@ export function initWidget(el) {
|
||||
autosize: true,
|
||||
// symbol: 'AAPL',
|
||||
symbol: 'UNIv3:WETH/USDC', // use this for ohlc
|
||||
interval: '1D',
|
||||
interval: '15',
|
||||
container: el,
|
||||
// datafeed: new Datafeeds.UDFCompatibleDatafeed("https://demo-feed-data.tradingview.com"),
|
||||
datafeed: datafeed, // use this for ohlc
|
||||
@@ -205,12 +205,15 @@ function handleCrosshairMovement(point) {
|
||||
|
||||
|
||||
let drawingEventQueue = []
|
||||
let eventLock = false // this is set to true before events are processed, in order to avoid any loops
|
||||
|
||||
|
||||
function handleDrawingEvent(id, event) {
|
||||
if (eventLock) return
|
||||
// it's important to decouple our actions from the TV thread. we must wait until the TV loop is completed
|
||||
// before interacting with the chart
|
||||
if (drawingEventQueue.length===0)
|
||||
setTimeout(drawingEventWorker,0)
|
||||
setTimeout(drawingEventWorker,1)
|
||||
drawingEventQueue.push([id,event])
|
||||
}
|
||||
|
||||
@@ -224,54 +227,60 @@ function drawingEventWorker() {
|
||||
|
||||
function doHandleDrawingEvent(id, event) {
|
||||
// console.log('drawing event', arguments)
|
||||
const shape = event === 'remove' ? null : chart.getShapeById(id);
|
||||
if (event === 'create') {
|
||||
const co = useChartOrderStore();
|
||||
const callbacks = co.drawingCallbacks
|
||||
console.log('drawing callbacks', callbacks)
|
||||
if (callbacks !== null) {
|
||||
shapeCallbacks[id] = callbacks
|
||||
co.drawing = false
|
||||
const points = shape.getPoints()
|
||||
const props = shape.getProperties()
|
||||
invokeCallbacks(shapeCallbacks[id], 'onCreate', id, points, props)
|
||||
invokeCallbacks(shapeCallbacks[id], 'onPoints', id, points)
|
||||
invokeCallbacks(shapeCallbacks[id], 'onProps', id, props)
|
||||
}
|
||||
} else if (event === 'points_changed') {
|
||||
if (id in shapeCallbacks) {
|
||||
const points = shape.getPoints()
|
||||
// console.log('points', points)
|
||||
invokeCallbacks(shapeCallbacks[id], 'onPoints', id, points)
|
||||
}
|
||||
} else if (event === 'properties_changed') {
|
||||
if (id in shapeCallbacks) {
|
||||
const props = shape.getProperties()
|
||||
// console.log('props', props)
|
||||
invokeCallbacks(shapeCallbacks[id], 'onProps', id, props)
|
||||
}
|
||||
} else if (event === 'move') {
|
||||
if (id in shapeCallbacks) {
|
||||
invokeCallbacks(shapeCallbacks[id], 'onMove', id)
|
||||
}
|
||||
} else if (event === 'remove') {
|
||||
if (id in shapeCallbacks) {
|
||||
invokeCallbacks(shapeCallbacks[id], 'onDelete', id)
|
||||
}
|
||||
} else if (event === 'click') {
|
||||
if (id in shapeCallbacks) {
|
||||
invokeCallbacks(shapeCallbacks[id], 'onClick', id)
|
||||
}
|
||||
} else if (event === 'hide') {
|
||||
if (id in shapeCallbacks) {
|
||||
invokeCallbacks(shapeCallbacks[id], 'onHide', id)
|
||||
}
|
||||
} else if (event === 'show') {
|
||||
if (id in shapeCallbacks) {
|
||||
invokeCallbacks(shapeCallbacks[id], 'onShow', id)
|
||||
}
|
||||
} else
|
||||
console.log('unknown drawing event', event)
|
||||
eventLock = true
|
||||
try {
|
||||
const shape = event === 'remove' ? null : chart.getShapeById(id);
|
||||
if (event === 'create') {
|
||||
const co = useChartOrderStore();
|
||||
const callbacks = co.drawingCallbacks
|
||||
console.log('drawing callbacks', callbacks)
|
||||
if (callbacks !== null) {
|
||||
shapeCallbacks[id] = callbacks
|
||||
co.drawing = false
|
||||
const points = shape.getPoints()
|
||||
const props = shape.getProperties()
|
||||
invokeCallbacks(shapeCallbacks[id], 'onCreate', id, points, props)
|
||||
invokeCallbacks(shapeCallbacks[id], 'onPoints', id, points)
|
||||
invokeCallbacks(shapeCallbacks[id], 'onProps', id, props)
|
||||
}
|
||||
} else if (event === 'points_changed') {
|
||||
if (id in shapeCallbacks) {
|
||||
const points = shape.getPoints()
|
||||
// console.log('points', points)
|
||||
invokeCallbacks(shapeCallbacks[id], 'onPoints', id, points)
|
||||
}
|
||||
} else if (event === 'properties_changed') {
|
||||
if (id in shapeCallbacks) {
|
||||
const props = shape.getProperties()
|
||||
// console.log('props', props)
|
||||
invokeCallbacks(shapeCallbacks[id], 'onProps', id, props)
|
||||
}
|
||||
} else if (event === 'move') {
|
||||
if (id in shapeCallbacks) {
|
||||
invokeCallbacks(shapeCallbacks[id], 'onMove', id)
|
||||
}
|
||||
} else if (event === 'remove') {
|
||||
if (id in shapeCallbacks) {
|
||||
invokeCallbacks(shapeCallbacks[id], 'onDelete', id)
|
||||
}
|
||||
} else if (event === 'click') {
|
||||
if (id in shapeCallbacks) {
|
||||
invokeCallbacks(shapeCallbacks[id], 'onClick', id)
|
||||
}
|
||||
} else if (event === 'hide') {
|
||||
if (id in shapeCallbacks) {
|
||||
invokeCallbacks(shapeCallbacks[id], 'onHide', id)
|
||||
}
|
||||
} else if (event === 'show') {
|
||||
if (id in shapeCallbacks) {
|
||||
invokeCallbacks(shapeCallbacks[id], 'onShow', id)
|
||||
}
|
||||
} else
|
||||
console.log('unknown drawing event', event)
|
||||
}
|
||||
finally {
|
||||
eventLock = false
|
||||
}
|
||||
}
|
||||
|
||||
export function deleteShapeId(id) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// noinspection JSPotentiallyInvalidUsageOfThis
|
||||
|
||||
import {invokeCallback} from "@/common.js";
|
||||
import {invokeCallback, mixin} from "@/common.js";
|
||||
import {chart, createShape, deleteShapeId, dragging, draggingShapeIds, drawShape} from "@/charts/chart.js";
|
||||
|
||||
|
||||
@@ -11,19 +11,21 @@ import {chart, createShape, deleteShapeId, dragging, draggingShapeIds, drawShape
|
||||
// shape.points
|
||||
// > [{time:17228394, price:42638.83}]
|
||||
//
|
||||
// shape.model is a vue ref({}) which stores the shape-specific control points, as defined by the shape subclass
|
||||
// use the shape.model.* fields in components to get reactive effects with the chart.
|
||||
// shape.model stores the shape-specific control points, as defined by the shape subclass, and may be a vue ref.
|
||||
// Use the shape.model.* fields in components to get reactive effects with the chart, or pass an onModel callback
|
||||
// to the constructor
|
||||
//
|
||||
|
||||
|
||||
/*
|
||||
The `name` field must match the user-facing name in the TradingView toolbar UI
|
||||
TradingView drawing tool codes:
|
||||
https://www.tradingview.com/charting-library-docs/latest/api/modules/Charting_Library/#supportedlinetools
|
||||
text anchored_text note anchored_note signpost double_curve arc icon emoji sticker arrow_up arrow_down arrow_left arrow_right price_label price_note arrow_marker flag vertical_line horizontal_line cross_line horizontal_ray trend_line info_line trend_angle arrow ray extended parallel_channel disjoint_angle flat_bottom anchored_vwap pitchfork schiff_pitchfork_modified schiff_pitchfork balloon comment inside_pitchfork pitchfan gannbox gannbox_square gannbox_fixed gannbox_fan fib_retracement fib_trend_ext fib_speed_resist_fan fib_timezone fib_trend_time fib_circles fib_spiral fib_speed_resist_arcs fib_channel xabcd_pattern cypher_pattern abcd_pattern callout triangle_pattern 3divers_pattern head_and_shoulders fib_wedge elliott_impulse_wave elliott_triangle_wave elliott_triple_combo elliott_correction elliott_double_combo cyclic_lines time_cycles sine_line long_position short_position forecast date_range price_range date_and_price_range bars_pattern ghost_feed projection rectangle rotated_rectangle circle ellipse triangle polyline path curve cursor dot arrow_cursor eraser measure zoom brush highlighter regression_trend fixed_range_volume_profile
|
||||
*/
|
||||
|
||||
export const ShapeType = {
|
||||
// this "enum" is a record of the TradingView keystrings
|
||||
|
||||
/*
|
||||
The `name` field must match the user-facing name in the TradingView toolbar UI
|
||||
TradingView drawing tool codes:
|
||||
https://www.tradingview.com/charting-library-docs/latest/api/modules/Charting_Library/#supportedlinetools
|
||||
text anchored_text note anchored_note signpost double_curve arc icon emoji sticker arrow_up arrow_down arrow_left arrow_right price_label price_note arrow_marker flag vertical_line horizontal_line cross_line horizontal_ray trend_line info_line trend_angle arrow ray extended parallel_channel disjoint_angle flat_bottom anchored_vwap pitchfork schiff_pitchfork_modified schiff_pitchfork balloon comment inside_pitchfork pitchfan gannbox gannbox_square gannbox_fixed gannbox_fan fib_retracement fib_trend_ext fib_speed_resist_fan fib_timezone fib_trend_time fib_circles fib_spiral fib_speed_resist_arcs fib_channel xabcd_pattern cypher_pattern abcd_pattern callout triangle_pattern 3divers_pattern head_and_shoulders fib_wedge elliott_impulse_wave elliott_triangle_wave elliott_triple_combo elliott_correction elliott_double_combo cyclic_lines time_cycles sine_line long_position short_position forecast date_range price_range date_and_price_range bars_pattern ghost_feed projection rectangle rotated_rectangle circle ellipse triangle polyline path curve cursor dot arrow_cursor eraser measure zoom brush highlighter regression_trend fixed_range_volume_profile
|
||||
*/
|
||||
Segment: {name: 'Trend Line', code: 'trend_line'},
|
||||
Ray: {name: 'Ray', code: 'ray'},
|
||||
Line: {name: 'Extended Line', code: 'extended'},
|
||||
@@ -47,8 +49,6 @@ class Shape {
|
||||
if (onDelete !== null )
|
||||
this.onDelete = onDelete
|
||||
this.lock = 0 // used to prevent callbacks when we are the ones forcing the chart change
|
||||
this.pointsLock = 0
|
||||
this.propsLock = 0
|
||||
this.create()
|
||||
}
|
||||
|
||||
@@ -93,11 +93,20 @@ class Shape {
|
||||
}
|
||||
|
||||
|
||||
setModel(model) {
|
||||
setModel(model, props=null) {
|
||||
for( const [k,v] of Object.entries(model))
|
||||
this.model[k] = v
|
||||
this.setPoints(this.pointsFromModel());
|
||||
this.setPropsIfDirty(this.propsFromModel())
|
||||
let p
|
||||
const mp = this.propsFromModel();
|
||||
if (props===null) {
|
||||
p = mp
|
||||
if (p===null)
|
||||
return
|
||||
}
|
||||
else if (mp !== null)
|
||||
p = mixin(props, mp)
|
||||
this.setPropsIfDirty(p)
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +117,6 @@ class Shape {
|
||||
else {
|
||||
const s = this.tvShape();
|
||||
if (!dragging) {
|
||||
this.pointsLock++
|
||||
s.setPoints(points)
|
||||
}
|
||||
else {
|
||||
@@ -126,7 +134,6 @@ class Shape {
|
||||
|
||||
setProps(props) {
|
||||
if(this.id) {
|
||||
this.propsLock++
|
||||
this.tvShape().setProperties(props)
|
||||
}
|
||||
}
|
||||
@@ -206,6 +213,8 @@ function dirtyProps(propsA, propsB) {
|
||||
|
||||
|
||||
class ShapeTVCallbacks {
|
||||
// These methods are called by TradingView and provide some default handling before invoking our own Shape callbacks
|
||||
|
||||
constructor(shape) {
|
||||
this.shape = shape
|
||||
}
|
||||
@@ -220,21 +229,14 @@ class ShapeTVCallbacks {
|
||||
|
||||
onPoints(shapeId, points) {
|
||||
this.shape.points = points
|
||||
if( this.shape.pointsLock ) {
|
||||
this.shape.pointsLock--
|
||||
return
|
||||
}
|
||||
this.shape.onPoints(points)
|
||||
this.shape.pointsToModel()
|
||||
this.shape.onModel(this.shape.model)
|
||||
}
|
||||
|
||||
onProps(shapeId, props) {
|
||||
console.log('props', shapeId, props)
|
||||
this.shape.props = props
|
||||
if( this.shape.propsLock ) {
|
||||
this.shape.propsLock--
|
||||
return
|
||||
}
|
||||
this.shape.onProps(props)
|
||||
this.shape.propsToModel()
|
||||
this.shape.onModel(this.shape.model)
|
||||
|
||||
Reference in New Issue
Block a user