diff --git a/package.json b/package.json
index 4aa47cf..9c5f5dd 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
"socket.io-client": "^4.7.2",
"vue": "^3.2.0",
"vue-router": "^4.0.0",
+ "vue-scroll-picker": "^1.2.2",
"vuetify": "^3.4.6",
"webfontloader": "^1.0.0"
},
diff --git a/src/charts/chart.js b/src/charts/chart.js
index 9b325ae..f850013 100644
--- a/src/charts/chart.js
+++ b/src/charts/chart.js
@@ -216,7 +216,13 @@ function handleCrosshairMovement(point) {
draggingShapeIds = chart.selection().allSources();
// console.log('dragging selected', draggingShapeIds)
for (const shapeId of draggingShapeIds) {
- const shape = chart.getShapeById(shapeId);
+ let shape
+ try {
+ shape = chart.getShapeById(shapeId);
+ }
+ catch (e) {
+ continue
+ }
const points = shape.getPoints();
// console.log(`dragging ${shapeId}`, shape, points1, points2, points3)
// invokeCallbacks(shapeCallbacks[shapeId], 'onDrag', shapeId, shape, points)
diff --git a/src/charts/shape.js b/src/charts/shape.js
index df7e97c..f433081 100644
--- a/src/charts/shape.js
+++ b/src/charts/shape.js
@@ -146,9 +146,10 @@ export class Shape {
this.setProps(newProps)
}
- onModel(model, changedKeys) {} // model was changed by a TradingView user action
+ onModel(model, oldModel, changedKeys) {} // model was changed by a TradingView user action
updateModel(changes) {
+ const oldModel = {...this.model}
if (this.debug) console.log('updateModel', this.id, changes)
const changedKeys = []
for (const k of Object.keys(changes)) {
@@ -158,7 +159,7 @@ export class Shape {
}
}
if (changedKeys.length)
- this.onModel(this.model, changedKeys)
+ this.onModel(this.model, oldModel, changedKeys)
}
colorProps() {
@@ -195,31 +196,37 @@ export class Shape {
if (this.id !== null) return
// programatically create the shape using the current this.points
if( this.ourPoints && this.ourPoints.length ) {
- this.doCreate()
+ this.doCreate(this.ourPoints, this.ourProps, this.creationOptions)
}
}
- doCreate() {
+ doCreate(points, props, options={}) {
// createShape(this.type, this.points, {overrides:this.props}, new ShapeTVCallbacks(this))
- const options = {...this.creationOptions}
- options['overrides'] = this.ourProps
- this.tvPoints = [...this.ourPoints]
+ options = {...options}
+ options['overrides'] = props
+ this.tvPoints = [...points]
this.tvCallbacks = new ShapeTVCallbacks(this);
- createShape(this.type, this.ourPoints, options, this.tvCallbacks)
- if (this.debug) console.log('created', this.type.name, this.ourPoints, this.id)
+ createShape(this.type, points, options, this.tvCallbacks)
+ if (this.debug) console.log('created', this.type.name, points, this.id)
}
createOrDraw() {
if(this.id) return
if(this.ourPoints && this.ourPoints.length)
- this.doCreate(this.ourPoints)
+ this.create()
else
this.draw()
}
tvShape() {
- return this.id === null ? null : chart.getShapeById(this.id);
+ try {
+ return this.id === null ? null : chart.getShapeById(this.id);
+ }
+ catch (e) {
+ console.error(`Could not get chart shape ${this.id}`)
+ return null
+ }
}
@@ -233,19 +240,25 @@ export class Shape {
this.delete()
else {
if (this.id === null)
- this.doCreate()
+ this.create()
else if (dirtyPoints(this.tvPoints, points)) {
const s = this.tvShape();
let sbm = false
if( draggingShapeIds.length ) {
- const dragShape = chart.getShapeById(draggingShapeIds[0])
- const sbms = [...dragShape._model._sourcesBeingMoved]
- // console.log('shape setPoints', this.id, dragShape, sbm)
- sbm = !sbms.length
- // if (!sbms.length) {
- // console.log('shape setPoints SBM return')
- // return
- // }
+ let dragShape
+ try {
+ dragShape = chart.getShapeById(draggingShapeIds[0])
+ const sbms = [...dragShape._model._sourcesBeingMoved]
+ // console.log('shape setPoints', this.id, dragShape, sbm)
+ sbm = !sbms.length
+ // if (!sbms.length) {
+ // console.log('shape setPoints SBM return')
+ // return
+ // }
+ }
+ catch (e) {
+ console.error(`could not get drag shape ${draggingShapeIds[0]}`)
+ }
}
if (this.debug) console.log('adjusting tv points', this.tvPoints, points, dragging, this.beingDragged())
// if ( dragging && !this.beingDragged())
@@ -328,7 +341,10 @@ export class Shape {
onRedraw() {} // the mouse moved while in drawing mode
onUndraw() {} // drawing was canceled by clicking on a different tool
onAddPoint() {} // the user clicked a point while drawing (that point is added to the points list)
- onCreate(points, props) {} // the user has finished creating all the control points. drawing mode is exited and the initial shape is created.
+ onCreate(points, props) {
+ this.tvPoints = points
+ this.tvProps = props
+ } // the user has finished creating all the control points. drawing mode is exited and the initial shape is created.
onMove(points) {} // the shape was moved by dragging a drawing element not the control point
onDrag(points) {}
onHide(props) {}
@@ -512,15 +528,6 @@ export class HLine extends Line {
}
-function timeAdjustmentTooSmall(orig, newValue) {
- // TradingView adjusts our lines to be at the start of the intervals, so
- // we ignore deltas smaller than one interval prior
- return newValue === undefined ||
- orig !== null && orig !== undefined && newValue !== null &&
- newValue < orig && orig - newValue < useChartOrderStore().intervalSecs
-}
-
-
function nearestOhlcStart(time) {
const period = useChartOrderStore().intervalSecs
return Math.round(time/period) * period
@@ -534,11 +541,22 @@ export class VLine extends Line {
// Model
this.model.time = null
+ // since VLines must be on the start of an OHLC boundry, we track that value separately
+ this.shapeTime = null
+
this.setModel(model) // call setModel at the end
}
+
+ doCreate(points, props, options = {}) {
+ this.shapeTime = nearestOhlcStart(points[0].time);
+ points = [{time: this.shapeTime, price:0}]
+ super.doCreate(points, props, options);
+ }
+
delete() {
this.model.time = null
+ this.shapeTime = null
super.delete()
}
@@ -546,28 +564,37 @@ export class VLine extends Line {
setModel(model) {
// console.log('VLine setModel', this.id, {...this.model}, model)
super.setModel(model)
- if (model.time === null) {
- this.model.time = null
+ if (model.time === null)
this.delete()
- }
else if (model.time !== this.model.time) {
this.model.time = model.time
- const time = nearestOhlcStart(model.time);
- this.setPoints([{time, price:0}])
+ this.setPoints([{time: model.time, price: 0}])
}
}
setPoints(points) {
- // console.error('VLine setPoints', points)
- super.setPoints(points);
+ if (this.debug) console.error('VLine setPoints...', points)
+ if (points !== null && points.length) {
+ // adjust shape to ohlc boundry
+ const time = nearestOhlcStart(points[0].time);
+ if (time !== this.shapeTime) {
+ this.shapeTime = time
+ super.setPoints([{time, price:0}]);
+ }
+ }
+ else {
+ this.shapeTime = null
+ super.setPoints(points);
+ }
+ if (this.debug) console.error('VLine setPoints', points)
}
onPoints(points) {
- const orig = this.ourPoints && this.ourPoints.length ? this.ourPoints[0].time : null
- super.onPoints(points);
const time = points[0].time;
- if (!timeAdjustmentTooSmall(orig, time))
+ if ( time !== this.shapeTime ) {
+ super.onPoints(points);
this.updateModel({time: time})
+ }
}
}
diff --git a/src/components/AbsoluteTimeEntry.vue b/src/components/AbsoluteTimeEntry.vue
new file mode 100644
index 0000000..c66201b
--- /dev/null
+++ b/src/components/AbsoluteTimeEntry.vue
@@ -0,0 +1,276 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/chart/Chart.vue b/src/components/chart/Chart.vue
index 7587c92..7ee2710 100644
--- a/src/components/chart/Chart.vue
+++ b/src/components/chart/Chart.vue
@@ -3,8 +3,8 @@