UI fixes including loop suppression when model doesnt change
This commit is contained in:
@@ -140,7 +140,7 @@ export function createShape(shapeType, points, options={}, ...callbacks) {
|
|||||||
shapeId = chart.createMultipointShape(points, options)
|
shapeId = chart.createMultipointShape(points, options)
|
||||||
if( callbacks.length )
|
if( callbacks.length )
|
||||||
shapeCallbacks[shapeId] = callbacks
|
shapeCallbacks[shapeId] = callbacks
|
||||||
console.log(`created ${shapeType.name}`, shapeId)
|
// console.log(`created ${shapeType.name}`, shapeId)
|
||||||
const props = chart.getShapeById(shapeId).getProperties()
|
const props = chart.getShapeById(shapeId).getProperties()
|
||||||
invokeCallbacks(callbacks, 'onCreate', shapeId, points, props)
|
invokeCallbacks(callbacks, 'onCreate', shapeId, points, props)
|
||||||
return shapeId
|
return shapeId
|
||||||
@@ -160,7 +160,7 @@ const shapeCallbacks = {}
|
|||||||
|
|
||||||
function onSelectedLineToolChanged() {
|
function onSelectedLineToolChanged() {
|
||||||
const tool = widget.selectedLineTool();
|
const tool = widget.selectedLineTool();
|
||||||
console.log('line tool changed', tool)
|
// console.log('line tool changed', tool)
|
||||||
if( tool !== 'cursor' ) // 'cursor' cannot be selected manually and only happens just before the 'create' event is issued
|
if( tool !== 'cursor' ) // 'cursor' cannot be selected manually and only happens just before the 'create' event is issued
|
||||||
cancelDrawing();
|
cancelDrawing();
|
||||||
}
|
}
|
||||||
@@ -206,10 +206,13 @@ function handleCrosshairMovement(point) {
|
|||||||
|
|
||||||
let drawingEventQueue = []
|
let drawingEventQueue = []
|
||||||
let eventLock = false // this is set to true before events are processed, in order to avoid any loops
|
let eventLock = false // this is set to true before events are processed, in order to avoid any loops
|
||||||
|
let propsEvents = {}
|
||||||
|
|
||||||
function handleDrawingEvent(id, event) {
|
function handleDrawingEvent(id, event) {
|
||||||
if (eventLock) return
|
if (eventLock && event !== 'properties_changed') { // properties has its own locking mechanism
|
||||||
|
console.log('ignoring event', id, event)
|
||||||
|
return
|
||||||
|
}
|
||||||
// it's important to decouple our actions from the TV thread. we must wait until the TV loop is completed
|
// 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
|
// before interacting with the chart
|
||||||
if (drawingEventQueue.length===0)
|
if (drawingEventQueue.length===0)
|
||||||
@@ -219,21 +222,34 @@ function handleDrawingEvent(id, event) {
|
|||||||
|
|
||||||
|
|
||||||
function drawingEventWorker() {
|
function drawingEventWorker() {
|
||||||
|
eventLock = true
|
||||||
|
try {
|
||||||
const queue = drawingEventQueue
|
const queue = drawingEventQueue
|
||||||
drawingEventQueue = []
|
drawingEventQueue = []
|
||||||
for (const [id,event] of queue)
|
propsEvents = {}
|
||||||
|
// console.log('events locked', queue)
|
||||||
|
for (const [id, event] of queue) {
|
||||||
|
if (event === 'properties_changed')
|
||||||
|
propsEvents[id] = event
|
||||||
|
else
|
||||||
doHandleDrawingEvent(id, event)
|
doHandleDrawingEvent(id, event)
|
||||||
}
|
}
|
||||||
|
for (const [k,v] of Object.entries(propsEvents))
|
||||||
|
doHandleDrawingEvent(k, v)
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
eventLock = false
|
||||||
|
// console.log('events unlocked')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function doHandleDrawingEvent(id, event) {
|
function doHandleDrawingEvent(id, event) {
|
||||||
// console.log('drawing event', arguments)
|
// console.log('drawing event', id, event)
|
||||||
eventLock = true
|
|
||||||
try {
|
|
||||||
const shape = event === 'remove' ? null : chart.getShapeById(id);
|
const shape = event === 'remove' ? null : chart.getShapeById(id);
|
||||||
if (event === 'create') {
|
if (event === 'create') {
|
||||||
const co = useChartOrderStore();
|
const co = useChartOrderStore();
|
||||||
const callbacks = co.drawingCallbacks
|
const callbacks = co.drawingCallbacks
|
||||||
console.log('drawing callbacks', callbacks)
|
// console.log('drawing callbacks', callbacks)
|
||||||
if (callbacks !== null) {
|
if (callbacks !== null) {
|
||||||
shapeCallbacks[id] = callbacks
|
shapeCallbacks[id] = callbacks
|
||||||
co.drawing = false
|
co.drawing = false
|
||||||
@@ -250,11 +266,12 @@ function doHandleDrawingEvent(id, event) {
|
|||||||
invokeCallbacks(shapeCallbacks[id], 'onPoints', id, points)
|
invokeCallbacks(shapeCallbacks[id], 'onPoints', id, points)
|
||||||
}
|
}
|
||||||
} else if (event === 'properties_changed') {
|
} else if (event === 'properties_changed') {
|
||||||
if (id in shapeCallbacks) {
|
|
||||||
const props = shape.getProperties()
|
const props = shape.getProperties()
|
||||||
// console.log('props', props)
|
if (id in shapeCallbacks)
|
||||||
invokeCallbacks(shapeCallbacks[id], 'onProps', id, props)
|
invokeCallbacks(shapeCallbacks[id], 'onProps', id, props)
|
||||||
}
|
else
|
||||||
|
// otherwise it's an event on a shape we don't "own"
|
||||||
|
console.log('warning: ignoring setProperties on TV shape', id, props)
|
||||||
} else if (event === 'move') {
|
} else if (event === 'move') {
|
||||||
if (id in shapeCallbacks) {
|
if (id in shapeCallbacks) {
|
||||||
invokeCallbacks(shapeCallbacks[id], 'onMove', id)
|
invokeCallbacks(shapeCallbacks[id], 'onMove', id)
|
||||||
@@ -278,10 +295,6 @@ function doHandleDrawingEvent(id, event) {
|
|||||||
} else
|
} else
|
||||||
console.log('unknown drawing event', event)
|
console.log('unknown drawing event', event)
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
eventLock = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteShapeId(id) {
|
export function deleteShapeId(id) {
|
||||||
if( id in shapeCallbacks )
|
if( id in shapeCallbacks )
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import {
|
|||||||
import {jBars} from './jBars.js';
|
import {jBars} from './jBars.js';
|
||||||
import {metadata} from "@/version.js";
|
import {metadata} from "@/version.js";
|
||||||
import FlexSearch from "flexsearch";
|
import FlexSearch from "flexsearch";
|
||||||
|
import {useChartOrderStore} from "@/orderbuild.js";
|
||||||
|
|
||||||
|
|
||||||
const lastBarsCache = new Map();
|
const lastBarsCache = new Map();
|
||||||
|
|
||||||
@@ -158,6 +160,7 @@ export default {
|
|||||||
onResolveErrorCallback('cannot resolve symbol');
|
onResolveErrorCallback('cannot resolve symbol');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
useChartOrderStore().selectedSymbol = symbolItem
|
||||||
// Symbol information object
|
// Symbol information object
|
||||||
const symbolInfo = {
|
const symbolInfo = {
|
||||||
ticker: symbolItem.full_name,
|
ticker: symbolItem.full_name,
|
||||||
|
|||||||
@@ -37,18 +37,19 @@ export const ShapeType = {
|
|||||||
|
|
||||||
|
|
||||||
class Shape {
|
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
|
// 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.id = null // TradingView shapeId, or null if no TV shape created yet (drawing mode)
|
||||||
this.type = type // ShapeType
|
this.type = type // ShapeType
|
||||||
this.model = model // subclass-specific
|
this.model = model // subclass-specific
|
||||||
this.points = null // TradingView points for the given shape
|
this.points = null
|
||||||
this.props = null
|
this.points = this.pointsFromModel()
|
||||||
|
console.log('construct points', this.points)
|
||||||
|
this.props = props === null ? this.propsFromModel() : mixin(props, this.propsFromModel())
|
||||||
if (onModel !== null)
|
if (onModel !== null)
|
||||||
this.onModel = onModel
|
this.onModel = onModel
|
||||||
if (onDelete !== null )
|
if (onDelete !== null )
|
||||||
this.onDelete = onDelete
|
this.onDelete = onDelete
|
||||||
this.lock = 0 // used to prevent callbacks when we are the ones forcing the chart change
|
|
||||||
this.create()
|
this.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,15 +68,13 @@ class Shape {
|
|||||||
create() {
|
create() {
|
||||||
if (this.id !== null) return
|
if (this.id !== null) return
|
||||||
// programatically create the shape using the current this.points
|
// programatically create the shape using the current this.points
|
||||||
const points = this.pointsFromModel()
|
if( this.points && this.points.length ) {
|
||||||
if( points && points.length ) {
|
this.doCreate()
|
||||||
this.doCreate(points)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doCreate(points) {
|
doCreate() {
|
||||||
const props = this.propsFromModel()
|
createShape(this.type, this.points, {overrides:this.props}, new ShapeTVCallbacks(this))
|
||||||
createShape(this.type, points, {overrides:props}, new ShapeTVCallbacks(this))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createOrDraw() {
|
createOrDraw() {
|
||||||
@@ -96,7 +95,7 @@ class Shape {
|
|||||||
setModel(model, props=null) {
|
setModel(model, props=null) {
|
||||||
for( const [k,v] of Object.entries(model))
|
for( const [k,v] of Object.entries(model))
|
||||||
this.model[k] = v
|
this.model[k] = v
|
||||||
this.setPoints(this.pointsFromModel());
|
this.setPointsIfDirty(this.pointsFromModel());
|
||||||
let p
|
let p
|
||||||
const mp = this.propsFromModel();
|
const mp = this.propsFromModel();
|
||||||
if (props===null) {
|
if (props===null) {
|
||||||
@@ -111,6 +110,7 @@ class Shape {
|
|||||||
|
|
||||||
|
|
||||||
setPoints(points) {
|
setPoints(points) {
|
||||||
|
this.points = points
|
||||||
if (points !== null && points.length) {
|
if (points !== null && points.length) {
|
||||||
if (this.id === null)
|
if (this.id === null)
|
||||||
this.doCreate(points)
|
this.doCreate(points)
|
||||||
@@ -129,14 +129,20 @@ class Shape {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// todo delete if points is null or empty?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setPointsIfDirty(points) {
|
||||||
|
if (dirtyPoints(this.points, points))
|
||||||
|
this.setPoints(points)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
setProps(props) {
|
setProps(props) {
|
||||||
if(this.id) {
|
if(this.id)
|
||||||
this.tvShape().setProperties(props)
|
this.tvShape().setProperties(props)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
setPropsIfDirty(props) {
|
setPropsIfDirty(props) {
|
||||||
@@ -169,6 +175,15 @@ class Shape {
|
|||||||
// Model synchronization
|
// 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}
|
pointsFromModel() {return null}
|
||||||
pointsToModel() {} // set the model using this.points
|
pointsToModel() {} // set the model using this.points
|
||||||
propsFromModel() {return null}
|
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
|
// B is modifying A
|
||||||
function dirtyProps(propsA, propsB) {
|
function dirtyProps(propsA, propsB) {
|
||||||
if (propsB===null)
|
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 {
|
class ShapeTVCallbacks {
|
||||||
// These methods are called by TradingView and provide some default handling before invoking our own Shape callbacks
|
// 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) {
|
onPoints(shapeId, points) {
|
||||||
this.shape.points = points
|
this.shape.points = points
|
||||||
this.shape.onPoints(points)
|
this.shape.onPoints(points)
|
||||||
this.shape.pointsToModel()
|
this.shape.onDirtyModel(this.shape.pointsToModel)
|
||||||
this.shape.onModel(this.shape.model)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onProps(shapeId, props) {
|
onProps(shapeId, props) {
|
||||||
console.log('props', shapeId, props)
|
|
||||||
this.shape.props = props
|
this.shape.props = props
|
||||||
this.shape.onProps(props)
|
this.shape.onProps(props)
|
||||||
this.shape.propsToModel()
|
this.shape.onDirtyModel(this.shape.propsToModel)
|
||||||
this.shape.onModel(this.shape.model)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onDraw() {
|
onDraw() {
|
||||||
@@ -296,8 +335,8 @@ class ShapeTVCallbacks {
|
|||||||
|
|
||||||
|
|
||||||
export class HLine extends Shape {
|
export class HLine extends Shape {
|
||||||
constructor(model, onModel=null, onDelete=null) {
|
constructor(model, onModel=null, onDelete=null, props=null) {
|
||||||
super(ShapeType.HLine, model, onModel, onDelete)
|
super(ShapeType.HLine, model, onModel, onDelete, props)
|
||||||
}
|
}
|
||||||
|
|
||||||
pointsFromModel() {
|
pointsFromModel() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="component" :order="order" :builder="builder"/>
|
<component :is="component" v-bind="props"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|||||||
@@ -2,21 +2,22 @@
|
|||||||
<row-bar :color="color">
|
<row-bar :color="color">
|
||||||
<color-band :color="color"/>
|
<color-band :color="color"/>
|
||||||
<div :style="faintColorStyle" style="width: 100%" class="justify-start align-content-start">
|
<div :style="faintColorStyle" style="width: 100%" class="justify-start align-content-start">
|
||||||
<v-text-field type="number" inputmode="numeric" pattern="[0-9]*\.?[0-9]*" v-model="os.amount" variant="outlined" density="compact" hide-details
|
<v-text-field type="number" inputmode="numeric" pattern="[0-9]*\.?[0-9]*" v-model="order.amount" variant="outlined" density="compact" hide-details
|
||||||
min="0" :step="os.amount?Math.floor(os.amount/1000):1"
|
min="0" :step="order.amount?Math.floor(order.amount/1000):1"
|
||||||
style="max-width:24em; display: inline-grid"
|
style="max-width:24em; display: inline-grid"
|
||||||
class="py-2" :color="color"
|
class="py-2" :color="color"
|
||||||
:label="os.amountIsTokenA ? 'Amount':('Value in '+os.quote.s)"
|
:label="order.amountIsTokenA ? 'Amount':('Value in '+co.selectedSymbol.quote.s)"
|
||||||
>
|
>
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<v-btn :text="(os.buy ? 'Buy ' : 'Sell ') + os.base.s" variant="tonal" :color="color" @click="os.buy=!os.buy"/>
|
<v-btn :text="(order.buy ? 'Buy ' : 'Sell ') + co.selectedSymbol.base.s" variant="tonal" :color="color" @click="order.buy=!order.buy"/>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:append-inner>
|
<template v-slot:append-inner>
|
||||||
<v-btn :text="os.amountToken.s+(os.amountIsTokenA?'':' worth')" :color="color" variant="text" @click="os.amountIsTokenA=!os.amountIsTokenA"/>
|
<v-btn :text="order.amountIsTokenA?co.selectedSymbol.base.s:co.selectedSymbol.quote.s+' worth'"
|
||||||
|
:color="color" variant="text" @click="order.amountIsTokenA=!order.amountIsTokenA"/>
|
||||||
</template>
|
</template>
|
||||||
</v-text-field>
|
</v-text-field>
|
||||||
<template v-for="b in builders(order)">
|
<template v-for="b in builders(order)">
|
||||||
<builder-factory :order="order" :builder="b" :color="color"/>
|
<builder-factory :order="order" :builder="b"/>
|
||||||
</template>
|
</template>
|
||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
<span :style="colorStyle" class="ma-3">Add condition:</span>
|
<span :style="colorStyle" class="ma-3">Add condition:</span>
|
||||||
@@ -51,6 +52,7 @@ const props = defineProps(['order'])
|
|||||||
const co = useChartOrderStore()
|
const co = useChartOrderStore()
|
||||||
const os = useOrderStore()
|
const os = useOrderStore()
|
||||||
|
|
||||||
|
console.log('order', props.order)
|
||||||
function build(order, component, options={}) {
|
function build(order, component, options={}) {
|
||||||
order.builders.push(newBuilder(component, options))
|
order.builders.push(newBuilder(component, options))
|
||||||
}
|
}
|
||||||
@@ -61,7 +63,7 @@ function builders(order) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const theme = useTheme().current
|
const theme = useTheme().current
|
||||||
const color = computed(()=>os.buy?theme.value.colors.success:theme.value.colors.error)
|
const color = computed(()=>props.order.buy?theme.value.colors.success:theme.value.colors.error)
|
||||||
const lightColor = computed(() => lightenColor(color.value))
|
const lightColor = computed(() => lightenColor(color.value))
|
||||||
const faintColor = computed(() => lightenColor2(color.value))
|
const faintColor = computed(() => lightenColor2(color.value))
|
||||||
const colorStyle = computed(() => { return {'color': color.value} })
|
const colorStyle = computed(() => { return {'color': color.value} })
|
||||||
@@ -69,9 +71,9 @@ const bgColorStyle = computed(() => { return {'background-color': color.value} }
|
|||||||
const lightColorStyle = computed(() => { return {'background-color': lightColor.value} })
|
const lightColorStyle = computed(() => { return {'background-color': lightColor.value} })
|
||||||
const faintColorStyle = computed(() => { return {'background-color': faintColor.value} })
|
const faintColorStyle = computed(() => { return {'background-color': faintColor.value} })
|
||||||
|
|
||||||
const inToken = computed( ()=>os.buy ? os.tokenB : os.tokenA )
|
const inToken = computed( ()=>props.order.buy ? co.selectedSymbol.quote : co.selectedSymbol.base )
|
||||||
const maxAmount = computed(()=>{
|
const maxAmount = computed(()=>{
|
||||||
const balance = s.balances[inToken]
|
const balance = s.balances[inToken.value]
|
||||||
if( !balance )
|
if( !balance )
|
||||||
return 0
|
return 0
|
||||||
const divisor = os.amountIsTotal ? 1 : os.tranches
|
const divisor = os.amountIsTotal ? 1 : os.tranches
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {useChartOrderStore} from "@/orderbuild.js";
|
import {useChartOrderStore} from "@/orderbuild.js";
|
||||||
import Toolbar from "@/components/chart/Toolbar.vue";
|
import Toolbar from "@/components/chart/Toolbar.vue";
|
||||||
import BuilderFactory from "@/components/chart/BuilderFactory.vue";
|
|
||||||
import {addSymbolChangedCallback, removeSymbolChangedCallback} from "@/charts/chart.js";
|
import {addSymbolChangedCallback, removeSymbolChangedCallback} from "@/charts/chart.js";
|
||||||
import {onBeforeUnmount} from "vue";
|
import {onBeforeUnmount} from "vue";
|
||||||
import {useOrderStore} from "@/store/store.js";
|
import {useOrderStore} from "@/store/store.js";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- todo extract builder-panel --> <!-- :builder="builder" color-tag="limit" -->
|
<!-- todo extract builder-panel --> <!-- :builder="builder" color-tag="limit" -->
|
||||||
<row-bar :color="builder.color">
|
<row-bar :color="builder.color" :data-ignore="autoAdjust">
|
||||||
<color-band :color="builder.color"/>
|
<color-band :color="builder.color"/>
|
||||||
<div style="min-width: 3em; font-size: larger" :style="colorStyle"
|
<div style="min-width: 3em; font-size: larger" :style="colorStyle"
|
||||||
class="align-self-start ml-2 pt-3">{{ rungs === 1 ? 'Limit' : 'Ladder' }}</div>
|
class="align-self-start ml-2 pt-3">{{ rungs === 1 ? 'Limit' : 'Ladder' }}</div>
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {computed} from "vue";
|
import {computed, onBeforeUnmount, onMounted} from "vue";
|
||||||
import {chart} from "@/charts/chart.js";
|
import {chart} from "@/charts/chart.js";
|
||||||
import {useChartOrderStore} from "@/orderbuild.js";
|
import {useChartOrderStore} from "@/orderbuild.js";
|
||||||
import Color from "color";
|
import Color from "color";
|
||||||
@@ -94,7 +94,6 @@ const skew100 = computed( {
|
|||||||
set(v) {props.builder.skew = v/100; adjustShapes()}
|
set(v) {props.builder.skew = v/100; adjustShapes()}
|
||||||
} )
|
} )
|
||||||
|
|
||||||
|
|
||||||
// we keep two special control lines as the edge of the ranges and then deletable lines in-between
|
// we keep two special control lines as the edge of the ranges and then deletable lines in-between
|
||||||
|
|
||||||
const lineAPrice = computed({
|
const lineAPrice = computed({
|
||||||
@@ -126,15 +125,14 @@ const lineB = new HLine(
|
|||||||
)
|
)
|
||||||
|
|
||||||
const adjustInteriorLine = (line) => {
|
const adjustInteriorLine = (line) => {
|
||||||
console.log('interior line onModel')
|
|
||||||
props.builder.color = line.color
|
props.builder.color = line.color
|
||||||
adjustShapes()
|
adjustShapes()
|
||||||
}
|
}
|
||||||
|
|
||||||
let interiorLines = []
|
let interiorLines = []
|
||||||
|
|
||||||
function createInteriorLine(price) {
|
function createInteriorLine(price, lineProps) {
|
||||||
const line = new HLine({price: price, color: props.builder.color}, adjustInteriorLine, deleteBuilder)
|
const line = new HLine({price: price, color: props.builder.color}, adjustInteriorLine, deleteBuilder, lineProps)
|
||||||
line.onPoints = function (points) {
|
line.onPoints = function (points) {
|
||||||
const delta = points[0].price - this.model.price
|
const delta = points[0].price - this.model.price
|
||||||
if (delta !== 0) {
|
if (delta !== 0) {
|
||||||
@@ -225,6 +223,8 @@ const rungs = computed({
|
|||||||
const prices = computed(()=>{
|
const prices = computed(()=>{
|
||||||
let a = props.builder.priceA
|
let a = props.builder.priceA
|
||||||
let b = props.builder.priceB
|
let b = props.builder.priceB
|
||||||
|
|
||||||
|
|
||||||
const r = props.builder.rungs
|
const r = props.builder.rungs
|
||||||
// console.log('prices for', a, b, r)
|
// console.log('prices for', a, b, r)
|
||||||
if ( a===null || !r ) return [] // no data
|
if ( a===null || !r ) return [] // no data
|
||||||
@@ -264,7 +264,7 @@ const weights = computed(() => {
|
|||||||
|
|
||||||
const colors = computed( ()=> {
|
const colors = computed( ()=> {
|
||||||
const color = props.builder.color !== null ? props.builder.color
|
const color = props.builder.color !== null ? props.builder.color
|
||||||
: os.buy ? theme.value.colors.success : theme.value.colors.error
|
: props.buy ? theme.value.colors.success : theme.value.colors.error
|
||||||
const c = new Color(color).rgb()
|
const c = new Color(color).rgb()
|
||||||
const ws = weights.value;
|
const ws = weights.value;
|
||||||
const max = Math.max(...ws)
|
const max = Math.max(...ws)
|
||||||
@@ -274,24 +274,27 @@ const colors = computed( ()=> {
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const amountSymbol = computed(()=>props.order.amountIsTokenA ? co.selectedSymbol.base.s : co.selectedSymbol.quote.s )
|
||||||
|
|
||||||
|
|
||||||
function allocationText(weight) {
|
function allocationText(weight) {
|
||||||
const alloc = props.builder.allocation
|
const alloc = props.builder.allocation
|
||||||
if (alloc===null) return ''
|
if (alloc===null) return ''
|
||||||
const w = weight * alloc
|
const w = weight * alloc
|
||||||
|
// console.log('weight', weight, alloc, props.amount)
|
||||||
const a = props.order.amount * w
|
const a = props.order.amount * w
|
||||||
const t = os.amountToken
|
return `${(w*100).toFixed(1)}% = ${a.toLocaleString('fullwide')} ${amountSymbol.value}`
|
||||||
return `${(w*100).toFixed(1)}% ${a.toLocaleString('fullwide')} ${t.s}`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function adjustShapes() {
|
function adjustShapes() {
|
||||||
// this is where all the lines are created or adjusted
|
// this is where all the lines are created or adjusted
|
||||||
console.log('adjustShapes()')
|
// console.log('adjustShapes()')
|
||||||
|
|
||||||
const limits = prices.value
|
const limits = prices.value
|
||||||
const colorStrings = colors.value
|
const colorStrings = colors.value
|
||||||
|
// line properties
|
||||||
const lps = weights.value.map((w)=>{return {text:allocationText(w), textcolor:color.value}})
|
const lps = weights.value.map((w)=>{return {text:allocationText(w), textcolor:color.value}})
|
||||||
console.log('things', colorStrings, lps)
|
|
||||||
if( limits.length === 0 ) {
|
if( limits.length === 0 ) {
|
||||||
lineA.delete()
|
lineA.delete()
|
||||||
lineB.delete()
|
lineB.delete()
|
||||||
@@ -332,15 +335,18 @@ function adjustShapes() {
|
|||||||
for( let i=0; i<limits.length-2; i++ ) {
|
for( let i=0; i<limits.length-2; i++ ) {
|
||||||
const limit = limits[1+i]
|
const limit = limits[1+i]
|
||||||
if (i === interiorLines.length)
|
if (i === interiorLines.length)
|
||||||
createInteriorLine(limit)
|
createInteriorLine(limit, lps[1+i])
|
||||||
else if (!interiorLines[i].beingDragged())
|
else if (!interiorLines[i].beingDragged())
|
||||||
interiorLines[i].setModel({price:limit, color: colorStrings[1+i]}, lps[1+i])
|
interiorLines[i].setModel({price:limit, color: colorStrings[1+i]}, lps[1+i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const autoAdjust = computed(adjustShapes)
|
||||||
|
|
||||||
|
|
||||||
function deleteShapes() {
|
function deleteShapes() {
|
||||||
lineA.delete()
|
lineA.delete()
|
||||||
lineB.delete()
|
lineB.delete()
|
||||||
@@ -359,6 +365,8 @@ function deleteBuilder() {
|
|||||||
if (!props.builder.priceA)
|
if (!props.builder.priceA)
|
||||||
lineA.createOrDraw(); // initiate drawing mode
|
lineA.createOrDraw(); // initiate drawing mode
|
||||||
|
|
||||||
|
onMounted(adjustShapes)
|
||||||
|
onBeforeUnmount(deleteShapes)
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="bg-grey-lighten-1" style="width:1em"> </div>
|
<div class="bg-grey-lighten-1" style="width:1em"> </div>
|
||||||
<div style="min-width: 3em; font-size: larger" class="align-self-start ma-3">Market Order</div>
|
<div style="min-width: 3em; font-size: larger" class="align-self-start ma-3">Market Order</div>
|
||||||
<div>
|
<div>
|
||||||
<v-text-field type="number" v-model="os.slippage"
|
<v-text-field type="number" v-model="props.builder.slippage"
|
||||||
density="compact" hide-details class="mx-1 my-2" variant="outlined"
|
density="compact" hide-details class="mx-1 my-2" variant="outlined"
|
||||||
label="Max Slippage" min="0" max="100" step="0.01"
|
label="Max Slippage" min="0" max="100" step="0.01"
|
||||||
style="width: 9em;"
|
style="width: 9em;"
|
||||||
@@ -20,7 +20,6 @@ import {useChartOrderStore} from "@/orderbuild.js";
|
|||||||
import {builderDefaults} from "@/misc.js";
|
import {builderDefaults} from "@/misc.js";
|
||||||
import {useOrderStore} from "@/store/store.js";
|
import {useOrderStore} from "@/store/store.js";
|
||||||
|
|
||||||
const os = useOrderStore()
|
|
||||||
const co = useChartOrderStore()
|
const co = useChartOrderStore()
|
||||||
const props = defineProps(['order', 'builder'])
|
const props = defineProps(['order', 'builder'])
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ const co = useChartOrderStore()
|
|||||||
let shape = null
|
let shape = null
|
||||||
|
|
||||||
function newOrder() {
|
function newOrder() {
|
||||||
console.log('new order 1')
|
|
||||||
co.newOrder()
|
co.newOrder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,13 +30,14 @@ export const useChartOrderStore = defineStore('chart_orders', () => {
|
|||||||
|
|
||||||
const orders = ref([])
|
const orders = ref([])
|
||||||
const selectedOrder = ref(null)
|
const selectedOrder = ref(null)
|
||||||
|
const selectedSymbol = ref(null)
|
||||||
|
|
||||||
const drawing = ref(false)
|
const drawing = ref(false)
|
||||||
const drawingCallbacks = ref(null) // only during draw mode
|
const drawingCallbacks = ref(null) // only during draw mode
|
||||||
|
|
||||||
function newOrder() {
|
function newOrder() {
|
||||||
console.log('cos new order')
|
console.log('cos new order')
|
||||||
const order = { id:uuid(), amount:1, builders:[] }
|
const order = { id:uuid(), amount:1, builders:[], amountIsTokenA: true, buy: true }
|
||||||
orders.value.push(order)
|
orders.value.push(order)
|
||||||
selectedOrder.value = order
|
selectedOrder.value = order
|
||||||
}
|
}
|
||||||
@@ -52,7 +53,7 @@ export const useChartOrderStore = defineStore('chart_orders', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chartReady, orders, drawing, drawingCallbacks, newOrder, removeOrder,
|
chartReady, selectedSymbol, orders, drawing, drawingCallbacks, newOrder, removeOrder,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user