From 5afdc839579fad3a66790498b9281eb211e501e8 Mon Sep 17 00:00:00 2001 From: tim Date: Tue, 3 Sep 2024 23:34:03 -0400 Subject: [PATCH] datafeed fixes; line drawing fix --- src/blockchain/contract.js | 1 + src/blockchain/wallet.js | 6 +-- src/charts/chart-misc.js | 37 +++++++++++++ src/charts/chart.js | 18 +++---- src/charts/datafeed.js | 3 +- src/charts/shape.js | 78 ++++++++++------------------ src/components/AbsoluteTimeEntry.vue | 2 +- src/components/Withdraw.vue | 2 +- src/components/chart/RungBuilder.vue | 1 + 9 files changed, 80 insertions(+), 68 deletions(-) diff --git a/src/blockchain/contract.js b/src/blockchain/contract.js index 00b1ecf..3c74cdc 100644 --- a/src/blockchain/contract.js +++ b/src/blockchain/contract.js @@ -31,6 +31,7 @@ export async function queryHelperContract(helper, provider) { // use newContract(addr, 'IVaultImpl', provider, 'IVault') to get the ABI from IVault.sol/IVaultImpl.json export async function newContract(addr, name, provider) { const abi = await abiCache.get(name) + console.log(`${name} ABI`, abi) return new ethers.Contract(addr, abi, provider) } diff --git a/src/blockchain/wallet.js b/src/blockchain/wallet.js index 5e052ef..970148d 100644 --- a/src/blockchain/wallet.js +++ b/src/blockchain/wallet.js @@ -1,8 +1,8 @@ import {BrowserProvider, ethers} from "ethers"; import {useStore} from "@/store/store"; import {socket} from "@/socket.js"; -import {newContract, vaultAddress, vaultContract} from "@/blockchain/contract.js"; import {SingletonCoroutine, timestamp, uuid} from "@/misc.js"; +import {newContract, vaultAddress, vaultContract} from "@/blockchain/contract.js"; import {defineStore} from "pinia"; import {ref} from "vue"; import {metadataMap, version} from "@/version.js"; @@ -493,8 +493,8 @@ export async function detectUpgrade() { newContract(info.factory, 'IVaultFactory', provider), newContract(s.vault, 'IVault', provider), ]) - const vaultImpl = await vault.impl() - const latestImpl = await factory.impl() + const vaultImpl = await vault.implementation() + const latestImpl = await factory.implementation() console.log('vaultImpl / latestImpl', vaultImpl, latestImpl) if ( vaultImpl !== latestImpl ) { s.upgrade = latestImpl diff --git a/src/charts/chart-misc.js b/src/charts/chart-misc.js index 209a241..f8d30bd 100644 --- a/src/charts/chart-misc.js +++ b/src/charts/chart-misc.js @@ -1,4 +1,5 @@ import {useChartOrderStore} from "@/orderbuild.js"; +import {unique} from "@/misc.js"; // Sunday January 4th, 2009 just before Bitcoin Genesis @@ -22,3 +23,39 @@ export function pointsToTvOhlcStart(points, periodSeconds=null) { return {time: nearestOhlcStart(p.time, periodSeconds), price: p.price} }) } + +export function dirtyPoints(pointsA, pointsB) { + if (pointsA === undefined) + return true + if (pointsB === undefined) + return false + 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 === null && b !== null || a !== null && b === null || + a.time !== b.time || a.price !== b.price) + return true + } + return false +} // B is modifying A +function dirtyKeys(propsA, propsB) { + if (propsB === null) + return propsA === null ? [] : [...Object.keys(propsA)] + if (propsA === null) + return [...Object.keys(propsB)] + const keys = unique([...Object.keys(propsA), ...Object.keys(propsB)]) + return keys.filter((k) => propsB[k] !== undefined && (!(k in propsA) || propsA[k] !== propsB[k])) +} + +export function dirtyItems(a, b) { + const result = {} + for (const k of dirtyKeys(a, b)) + result[k] = b[k] + return result +} \ No newline at end of file diff --git a/src/charts/chart.js b/src/charts/chart.js index 1fbf5ea..259ea72 100644 --- a/src/charts/chart.js +++ b/src/charts/chart.js @@ -3,6 +3,7 @@ import {invokeCallbacks, prototype} from "@/common.js"; import {DataFeed, initFeeDropdown, lookupSymbol} from "@/charts/datafeed.js"; import {intervalToSeconds, SingletonCoroutine} from "@/misc.js"; import {useStore} from "@/store/store.js"; +import {dirtyPoints} from "@/charts/chart-misc.js"; export let widget = null export let chart = null @@ -213,6 +214,7 @@ function onSelectedLineToolChanged() { } export let dragging = false +export let draggingShapeIds = [] function mouseDown() { // console.log('mouseDown') // todo push into drawing event queue instead, then set dragging there @@ -226,9 +228,6 @@ function mouseUp() { } -export let draggingShapeIds = [] - - function handleCrosshairMovement(point) { crosshairHandler.invoke(point) // delayed invocation to await selection to register later in the tv loop } @@ -255,11 +254,10 @@ function doHandleCrosshairMovement(point) { catch (e) { continue } - const points = shape.getPoints(); - - // console.log('dragging', shapeId) - // invokeCallbacks(shapeCallbacks[shapeId], 'onDrag', shapeId, shape, points) - // console.log('calling onPoints') + const points = structuredClone(shape.getPoints()); + const lpbe = shape._model._linePointBeingEdited + points[lpbe] = point + // console.log('drag calling onPoints', points, shape, lpbe) invokeCallbacks(shapeCallbacks[shapeId], 'onPoints', shapeId, shape, points) } } @@ -281,7 +279,7 @@ function handleDrawingEvent(id, event) { // 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,1) + setTimeout(drawingEventWorker,0) drawingEventQueue.push([id,event]) } @@ -337,7 +335,7 @@ function doHandleDrawingEvent(id, event) { if (dragging) return if (id in shapeCallbacks) { const points = shape.getPoints() - // console.log('points', points) + // console.log('points', id, points, dragStartPoints) invokeCallbacks(shapeCallbacks[id], 'onPoints', id, shape, points) } } else if (event === 'properties_changed') { diff --git a/src/charts/datafeed.js b/src/charts/datafeed.js index a21e153..7c1c96f 100644 --- a/src/charts/datafeed.js +++ b/src/charts/datafeed.js @@ -558,6 +558,7 @@ export const DataFeed = { updatePushedCache(key, ohlcs) { + if (ohlcs.length===0) return log('updatePushedCache', key, ohlcs) if (!(key in this.pushedBars)) this.pushedBars[key] = ohlcs @@ -579,8 +580,8 @@ export const DataFeed = { pushToTV(key, ohlcs) { - if (ohlcs.length===0) return log('pushing bars to tv', ohlcs) + if (ohlcs.length===0) return this.updatePushedCache(key, ohlcs); // we cache the raw bars before inversion so they match dexorder data sources const sub = subByKey[key] if (sub===undefined) { diff --git a/src/charts/shape.js b/src/charts/shape.js index 88a225d..6c6c477 100644 --- a/src/charts/shape.js +++ b/src/charts/shape.js @@ -2,10 +2,9 @@ import {invokeCallback, mixin} from "@/common.js"; import {chart, createShape, deleteShapeId, dragging, draggingShapeIds, drawShape, widget} from "@/charts/chart.js"; -import {unique} from "@/misc.js"; import {allocationText} from "@/orderbuild.js"; import Color from "color"; -import {pointsToTvOhlcStart} from "@/charts/chart-misc.js"; +import {dirtyItems, dirtyPoints, pointsToTvOhlcStart} from "@/charts/chart-misc.js"; // @@ -140,7 +139,7 @@ export class Shape { } if (this.debug && this.id) - console.log('newProps', chart.getShapeById(this.id).getProperties(), newProps) + console.log('newProps', this.id, chart.getShapeById(this.id).getProperties(), newProps) this.setProps(newProps) } @@ -206,7 +205,7 @@ export class Shape { this.tvCallbacks = new ShapeTVCallbacks(this); const id = createShape(this.type, this.tvPoints, options, this.tvCallbacks) // todo set id? - if (this.debug) console.log('created', this.type.name, this.tvPoints, id) + if (this.debug) console.log('created', id, this.type.name, this.tvPoints) } onCreate(points, props) { @@ -239,7 +238,7 @@ export class Shape { setPoints(points) { // setting points to null will delete the shape from the chart. setting points to a valid value will cause the // shape to be drawn. - if (this.debug) console.log('setPoints', this.id, this.ourPoints, points) + if (this.debug) console.error('setPoints', this.id, this.ourPoints, points) this.ourPoints = points if (points === null || !points.length) this.delete() @@ -249,12 +248,27 @@ export class Shape { else { points = pointsToTvOhlcStart(points) if (dirtyPoints(this.tvPoints, points)) { + /* + setPoints(e) { + if (this._source.isFixed()) + return; + const t = o(this._source); + if (t !== e.length) + throw new Error(`Wrong points count. Required: ${t}, provided: ${e.length}`); + const i = this._pointsConverter.apiPointsToDataSource(e); + this._model.startChangingLinetool(this._source), + this._model.changeLinePoints(this._source, i), + this._model.endChangingLinetool(!0), + this._source.createServerPoints() + } + */ const s = this.tvShape(); const lbe = s._model._lineBeingEdited const lpbc = s._model._linePointBeingChanged const lpbe = s._model._linePointBeingEdited if (lpbc!==null) - s._model.endChangingLinetool(lbe, lpbc) + s._model.endChangingLinetool(!0) + // s._source.createServerPoints() // todo necessary? s.setPoints(points) if (lpbc!==null) s._model.startChangingLinetool(lbe, lpbc, lpbe) @@ -267,7 +281,7 @@ export class Shape { setProps(props) { if (!props || Object.keys(props).length===0) return - if (this.debug) console.log('setProps', props) + if (this.debug) console.log('setProps', this.id, props) this.ourProps = mixin(props, this.ourProps) if(this.id) { const p = dirtyItems(this.tvProps, props) @@ -278,7 +292,7 @@ export class Shape { } onProps(props) { // the display properties of an existing shape were changed - if (this.debug) console.log('shape onProps', this.model, props) + if (this.debug) console.log('shape onProps', this.id, this.model, props) if (props.textcolor && typeof props.textcolor !== 'object' && props.textcolor !== this.tvProps.textcolor) this.updateModel({color:props.textcolor}) else if (props.linecolor && typeof props.linecolor !== 'object' && props.linecolor !== this.tvProps.linecolor) @@ -323,46 +337,6 @@ export class Shape { } -function dirtyPoints(pointsA, pointsB) { - if (pointsA === undefined) - return true - if (pointsB === undefined) - return false - 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 === null && b !== null || a !== null && b === null || - a.time !== b.time || a.price !== b.price ) - return true - } - return false -} - -// B is modifying A -function dirtyKeys(propsA, propsB) { - if (propsB===null) - return propsA === null ? [] : [...Object.keys(propsA)] - if (propsA===null) - return [...Object.keys(propsB)] - const keys = unique([...Object.keys(propsA), ...Object.keys(propsB)]) - return keys.filter((k)=> propsB[k] !== undefined && (!(k in propsA) || propsA[k] !== propsB[k])) -} - - -function dirtyItems(a, b) { - const result = {} - for (const k of dirtyKeys(a,b)) - result[k] = b[k] - return result -} - - class ShapeTVCallbacks { // These methods are called by TradingView and provide some default handling before invoking our own Shape callbacks @@ -380,7 +354,7 @@ class ShapeTVCallbacks { onPoints(shapeId, _tvShape, points) { if (!this.enabled) return // possible when shape is deleted and re-created - if (this.shape.debug) console.log('tvcb onPoints', points) + if (this.shape.debug) console.log('tvcb onPoints', shapeId, points) if (!dragging || this.shape.beingDragged()) this.shape.onPoints(points) this.shape.tvPoints = points @@ -388,7 +362,7 @@ class ShapeTVCallbacks { onProps(shapeId, _tvShape, props) { if (!this.enabled) return // possible when shape is deleted and re-created - if (this.shape.debug) console.error('tvOnProps', props) + if (this.shape.debug) console.log('tvOnProps', shapeId, props) if (!dragging) // do not listen to props during redraw this.shape.onProps(props) this.shape.tvProps = props @@ -421,7 +395,7 @@ class ShapeTVCallbacks { onDrag(shapeId, _tvShape, points) { if (!this.enabled) return // possible when shape is deleted and re-created - if (this.shape.debug) console.log('onDrag') + if (this.shape.debug) console.log('onDrag', shapeId) invokeCallback(this.shape, 'onDrag', points) } @@ -452,7 +426,7 @@ export class Line extends Shape { onDrag(points) { const s = this.tvShape(); if (this.debug) { - console.log('shape', s) + console.log('shape', s.id, s) console.log('currentMovingPoint', s._source.currentMovingPoint()) console.log('startMovingPoint', s._source.startMovingPoint()) console.log('isBeingEdited', s._source.isBeingEdited()) diff --git a/src/components/AbsoluteTimeEntry.vue b/src/components/AbsoluteTimeEntry.vue index adcc6d9..e2a517a 100644 --- a/src/components/AbsoluteTimeEntry.vue +++ b/src/components/AbsoluteTimeEntry.vue @@ -23,7 +23,7 @@ const emit = defineEmits(['update:modelValue']) const hideDetails = true -const now = computed(()=>DateTime.fromSeconds(props.modelValue).setZone(s.timeZone)) +const now = computed(()=>DateTime.fromSeconds(props.modelValue?props.modelValue:0).setZone(s.timeZone)) const year = computed({ get() { return now.value.year }, diff --git a/src/components/Withdraw.vue b/src/components/Withdraw.vue index 336288f..39586fd 100644 --- a/src/components/Withdraw.vue +++ b/src/components/Withdraw.vue @@ -45,7 +45,7 @@ function withdraw() { const vaultAddr = props.vault const valueStr = floatAmount.value.toString(); const amount = FixedNumber.fromString(valueStr,{decimals:props.token.d, width:256, signed: false}).value; - console.log('pending withdrawl', valueStr, amount, props.token.s) + console.log('pending withdrawal', valueStr, amount, props.token.s) if( amount === 0n ) return pendTransaction(async (signer)=>{ diff --git a/src/components/chart/RungBuilder.vue b/src/components/chart/RungBuilder.vue index 4027b5c..bd0190e 100644 --- a/src/components/chart/RungBuilder.vue +++ b/src/components/chart/RungBuilder.vue @@ -148,6 +148,7 @@ const rungsDisabled = computed(()=>endpoints.value[0]===null) const values = computed(()=>{ let [a, b] = endpoints.value + // console.log('generating values for endpoints', a, b) a = vectorize(a) b = vectorize(b) const r = props.builder.rungs