From 19a4df2b9b19451840ba71fcd5bb5dc899ea82f2 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 6 Feb 2024 23:33:51 -0400 Subject: [PATCH] more line manipulation cleanup --- src/charts/chart.js | 1 + src/charts/shape.js | 232 ++++++++++++++++++-------- src/components/chart/LimitBuilder.vue | 228 +++++++++---------------- 3 files changed, 249 insertions(+), 212 deletions(-) diff --git a/src/charts/chart.js b/src/charts/chart.js index 82a0695..4efa817 100644 --- a/src/charts/chart.js +++ b/src/charts/chart.js @@ -231,5 +231,6 @@ function handleDrawingEvent(id, event) { export function deleteShape(id) { if( id in shapeCallbacks ) delete shapeCallbacks[id] + console.log('removing entity', id) chart.removeEntity(id) } diff --git a/src/charts/shape.js b/src/charts/shape.js index 2c6579c..88436c8 100644 --- a/src/charts/shape.js +++ b/src/charts/shape.js @@ -2,7 +2,6 @@ import {invokeCallback} from "@/common.js"; import {chart, createShape, deleteShape, drawShape} from "@/charts/chart.js"; -import {watch} from "vue"; // @@ -35,15 +34,53 @@ export const ShapeType = { } +function updatePoints(shape, points) { + shape.lock++ + try { + chart.getShapeById(shape.id).setPoints(points) + } + finally { + shape.lock-- + } +} + + +function updateProps(shape, props) { + shape.lock++ + try { + chart.getShapeById(shape.id).setProps(props) + } + finally { + shape.lock-- + } +} + + +function delShape(shape) { + shape.lock++ + try { + deleteShape(shape.id) + } finally { + shape.lock-- + } + shape.lock = true + shape.lock = false +} + + class Shape { - constructor(type, model={}) { + constructor(type, model={}, onModel=null, onDelete=null) { // the Shape object manages synchronizing internal data with a corresponding TradingView shape this.id = null // TradingView shapeId, or null if no TV shape created yet (drawing mode) this.type = type // ShapeType this.model = model // subclass-specific this.points = null // TradingView points for the given shape this.props = null - watch(this.model, this.onModelChanged.bind(this)) + if (onModel !== null) + this.onModel = onModel + if (onDelete !== null ) + this.onDelete = onDelete + this.lock = 0 // used to prevent callbacks when we are the ones forcing the chart change this.create() } @@ -81,32 +118,51 @@ class Shape { this.draw() } + + setModel(model) { + for( const [k,v] of Object.entries(model)) + this.model[k] = v + this.setPointsIfDirty(this.pointsFromModel()); + this.setPropsIfDirty(this.propsFromModel()) + } + + setPoints(points) { invokeCallback(this, 'onPoints', points) if (points !== null && points.length) { if (this.id) { - const tvShape = chart.getShapeById(this.id); - setTimeout(()=>tvShape.setPoints(points),0) + updatePoints(this, points) } else this.doCreate(points) } } + + setPointsIfDirty(points) { + if (dirtyPoints(this.points, points)) + this.setPoints(points) + } + + setProps(props) { invokeCallback(this, 'onProps', props) if(this.id) { - console.log(`setting ${this.id} props`, this.props) - setTimeout(()=>chart.getShapeById(this.id).setProperties(props),0) + updateProps(this, props) } } + + setPropsIfDirty(props) { + if( dirtyProps(this.props, props) ) + this.setProps(props) + } + + delete() { - if (this.id) { - deleteShape(this.id) + if (this.id!==null) { + delShape(this) this.id = null } - else - invokeCallback(this, 'onDelete') } @@ -114,20 +170,13 @@ class Shape { // Model synchronization // - onModelChanged() { - const points = this.pointsFromModel() - if( points !== null ) - this.setPoints(points) - const props = this.propsFromModel() - if( props !== null ) - this.setProps(props) - } - pointsFromModel() {return null} pointsToModel() {} // set the model using this.points propsFromModel() {return null} propsToModel() {} // set the model using this.props + onModel(model) {} // called whenever points or props updates the model dictionary + // // Overridable shape callbacks @@ -149,12 +198,44 @@ class Shape { } +function dirtyPoints(pointsA, pointsB) { + if (pointsA === null) + return pointsB !== null + if (pointsB === null) + return true + if (pointsA.length !== pointsB.length) + return true + for (let i = 0; i < pointsA.length; i++) { + const a = pointsA[i]; + const b = pointsB[i]; + if (a.time !== b.time || a.price !== b.price) + return true + } + return false +} + + +// B is modifying A +function dirtyProps(propsA, propsB) { + if (propsB===null) + return propsA !== null + const entries = Object.entries(propsB); + if (propsA===null) + return entries.length > 0 + for( const [k,v] of entries) + if ( !(k in propsA) || propsA[k] !== v ) + return true + return false +} + + class ShapeTVCallbacks { constructor(shape) { this.shape = shape } onCreate(shapeId, points, props) { + if( this.shape.lock ) return if( this.id ) throw Error(`Created a shape ${shapeId}where one already existed ${this.id}`) this.shape.id=shapeId @@ -162,72 +243,91 @@ class ShapeTVCallbacks { } onPoints(shapeId, points) { - let dirty = this.shape.points === null || points.length !== this.shape.points.length - for( let i=0; !dirty && i 0) + return [{time:this.points[0].time, price:this.model.price}] + return [{time:0, price:this.model.price}] } pointsToModel() { - // console.log('pointsToModel', this.points, this.model) - this.model[this.priceAttr] = this.points[0].price - } - pointsFromModel() { - const price = this.model[this.priceAttr]; - // console.log('pointsFromModel', price) - return price === null || price === undefined ? null : [{time:price?.time || 0, price:price}] - } - propsToModel() { - console.log('propsToModel', this.props.linecolor) - this.model[this.colorAttr]=this.props.linecolor - console.log('set model from props', this.model) + this.model.price = this.points[0].price } + propsFromModel() { - console.log('propsFromModel', this.model[this.colorAttr]) - const result = this.model[this.colorAttr] ? {linecolor: this.model[this.colorAttr]} : null - console.log('get props from model', this.model[this.colorAttr], result) - return result + return this.model.color ? {linecolor: this.model.color} : null } + + propsToModel() {this.model.color=this.props.linecolor} + } diff --git a/src/components/chart/LimitBuilder.vue b/src/components/chart/LimitBuilder.vue index db87189..a00288c 100644 --- a/src/components/chart/LimitBuilder.vue +++ b/src/components/chart/LimitBuilder.vue @@ -4,7 +4,7 @@   {{ rungs === 1 ? 'Limit' : 'Ladder' }} - @@ -17,7 +17,7 @@ - + @@ -32,19 +32,47 @@