UI fixes including loop suppression when model doesnt change
This commit is contained in:
@@ -37,18 +37,19 @@ export const ShapeType = {
|
||||
|
||||
|
||||
class Shape {
|
||||
constructor(type, model={}, onModel=null, onDelete=null) {
|
||||
constructor(type, model={}, onModel=null, onDelete=null, props=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
|
||||
this.points = null
|
||||
this.points = this.pointsFromModel()
|
||||
console.log('construct points', this.points)
|
||||
this.props = props === null ? this.propsFromModel() : mixin(props, this.propsFromModel())
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -67,15 +68,13 @@ class Shape {
|
||||
create() {
|
||||
if (this.id !== null) return
|
||||
// programatically create the shape using the current this.points
|
||||
const points = this.pointsFromModel()
|
||||
if( points && points.length ) {
|
||||
this.doCreate(points)
|
||||
if( this.points && this.points.length ) {
|
||||
this.doCreate()
|
||||
}
|
||||
}
|
||||
|
||||
doCreate(points) {
|
||||
const props = this.propsFromModel()
|
||||
createShape(this.type, points, {overrides:props}, new ShapeTVCallbacks(this))
|
||||
doCreate() {
|
||||
createShape(this.type, this.points, {overrides:this.props}, new ShapeTVCallbacks(this))
|
||||
}
|
||||
|
||||
createOrDraw() {
|
||||
@@ -96,7 +95,7 @@ class Shape {
|
||||
setModel(model, props=null) {
|
||||
for( const [k,v] of Object.entries(model))
|
||||
this.model[k] = v
|
||||
this.setPoints(this.pointsFromModel());
|
||||
this.setPointsIfDirty(this.pointsFromModel());
|
||||
let p
|
||||
const mp = this.propsFromModel();
|
||||
if (props===null) {
|
||||
@@ -111,6 +110,7 @@ class Shape {
|
||||
|
||||
|
||||
setPoints(points) {
|
||||
this.points = points
|
||||
if (points !== null && points.length) {
|
||||
if (this.id === null)
|
||||
this.doCreate(points)
|
||||
@@ -129,13 +129,19 @@ class Shape {
|
||||
}
|
||||
}
|
||||
}
|
||||
// todo delete if points is null or empty?
|
||||
}
|
||||
|
||||
|
||||
setPointsIfDirty(points) {
|
||||
if (dirtyPoints(this.points, points))
|
||||
this.setPoints(points)
|
||||
}
|
||||
|
||||
|
||||
setProps(props) {
|
||||
if(this.id) {
|
||||
if(this.id)
|
||||
this.tvShape().setProperties(props)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -169,6 +175,15 @@ class Shape {
|
||||
// Model synchronization
|
||||
//
|
||||
|
||||
onDirtyModel(toModel) {
|
||||
const old = {...this.model}
|
||||
toModel.call(this)
|
||||
const dirty = dirtyKeys(old, this.model)
|
||||
// console.log('onDirtyModel', old, this.model, dirty)
|
||||
if (dirty.length)
|
||||
this.onModel(this.model)
|
||||
}
|
||||
|
||||
pointsFromModel() {return null}
|
||||
pointsToModel() {} // set the model using this.points
|
||||
propsFromModel() {return null}
|
||||
@@ -198,6 +213,23 @@ class Shape {
|
||||
}
|
||||
|
||||
|
||||
function dirtyPoints(pointsA, pointsB) {
|
||||
if (pointsB===null)
|
||||
return pointsA !== null
|
||||
if (pointsA===null)
|
||||
return pointsB.length > 0
|
||||
if (pointsA.length!==pointsB.length)
|
||||
return true
|
||||
for (const i in pointsA) {
|
||||
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)
|
||||
@@ -212,6 +244,16 @@ function dirtyProps(propsA, propsB) {
|
||||
}
|
||||
|
||||
|
||||
// B is modifying A
|
||||
function dirtyKeys(propsA, propsB) {
|
||||
if (propsB===null)
|
||||
return propsA === null ? [] : [...Object.keys(propsA)]
|
||||
if (propsA===null)
|
||||
return [...Object.keys(propsB)]
|
||||
return [...(new Set(Object.keys(propsB)).union(new Set(Object.keys(propsA))))].filter((k)=> !(k in propsA) || propsA[k] !== propsB[k])
|
||||
}
|
||||
|
||||
|
||||
class ShapeTVCallbacks {
|
||||
// These methods are called by TradingView and provide some default handling before invoking our own Shape callbacks
|
||||
|
||||
@@ -230,16 +272,13 @@ class ShapeTVCallbacks {
|
||||
onPoints(shapeId, points) {
|
||||
this.shape.points = points
|
||||
this.shape.onPoints(points)
|
||||
this.shape.pointsToModel()
|
||||
this.shape.onModel(this.shape.model)
|
||||
this.shape.onDirtyModel(this.shape.pointsToModel)
|
||||
}
|
||||
|
||||
onProps(shapeId, props) {
|
||||
console.log('props', shapeId, props)
|
||||
this.shape.props = props
|
||||
this.shape.onProps(props)
|
||||
this.shape.propsToModel()
|
||||
this.shape.onModel(this.shape.model)
|
||||
this.shape.onDirtyModel(this.shape.propsToModel)
|
||||
}
|
||||
|
||||
onDraw() {
|
||||
@@ -296,8 +335,8 @@ class ShapeTVCallbacks {
|
||||
|
||||
|
||||
export class HLine extends Shape {
|
||||
constructor(model, onModel=null, onDelete=null) {
|
||||
super(ShapeType.HLine, model, onModel, onDelete)
|
||||
constructor(model, onModel=null, onDelete=null, props=null) {
|
||||
super(ShapeType.HLine, model, onModel, onDelete, props)
|
||||
}
|
||||
|
||||
pointsFromModel() {
|
||||
|
||||
Reference in New Issue
Block a user