shape onModel improvements; vline fixes; time entry; couple bugs remain with dca dragging
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
"socket.io-client": "^4.7.2",
|
"socket.io-client": "^4.7.2",
|
||||||
"vue": "^3.2.0",
|
"vue": "^3.2.0",
|
||||||
"vue-router": "^4.0.0",
|
"vue-router": "^4.0.0",
|
||||||
|
"vue-scroll-picker": "^1.2.2",
|
||||||
"vuetify": "^3.4.6",
|
"vuetify": "^3.4.6",
|
||||||
"webfontloader": "^1.0.0"
|
"webfontloader": "^1.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -216,7 +216,13 @@ function handleCrosshairMovement(point) {
|
|||||||
draggingShapeIds = chart.selection().allSources();
|
draggingShapeIds = chart.selection().allSources();
|
||||||
// console.log('dragging selected', draggingShapeIds)
|
// console.log('dragging selected', draggingShapeIds)
|
||||||
for (const shapeId of 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();
|
const points = shape.getPoints();
|
||||||
// console.log(`dragging ${shapeId}`, shape, points1, points2, points3)
|
// console.log(`dragging ${shapeId}`, shape, points1, points2, points3)
|
||||||
// invokeCallbacks(shapeCallbacks[shapeId], 'onDrag', shapeId, shape, points)
|
// invokeCallbacks(shapeCallbacks[shapeId], 'onDrag', shapeId, shape, points)
|
||||||
|
|||||||
@@ -146,9 +146,10 @@ export class Shape {
|
|||||||
this.setProps(newProps)
|
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) {
|
updateModel(changes) {
|
||||||
|
const oldModel = {...this.model}
|
||||||
if (this.debug) console.log('updateModel', this.id, changes)
|
if (this.debug) console.log('updateModel', this.id, changes)
|
||||||
const changedKeys = []
|
const changedKeys = []
|
||||||
for (const k of Object.keys(changes)) {
|
for (const k of Object.keys(changes)) {
|
||||||
@@ -158,7 +159,7 @@ export class Shape {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (changedKeys.length)
|
if (changedKeys.length)
|
||||||
this.onModel(this.model, changedKeys)
|
this.onModel(this.model, oldModel, changedKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
colorProps() {
|
colorProps() {
|
||||||
@@ -195,32 +196,38 @@ export class Shape {
|
|||||||
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
|
||||||
if( this.ourPoints && this.ourPoints.length ) {
|
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))
|
// createShape(this.type, this.points, {overrides:this.props}, new ShapeTVCallbacks(this))
|
||||||
const options = {...this.creationOptions}
|
options = {...options}
|
||||||
options['overrides'] = this.ourProps
|
options['overrides'] = props
|
||||||
this.tvPoints = [...this.ourPoints]
|
this.tvPoints = [...points]
|
||||||
this.tvCallbacks = new ShapeTVCallbacks(this);
|
this.tvCallbacks = new ShapeTVCallbacks(this);
|
||||||
createShape(this.type, this.ourPoints, options, this.tvCallbacks)
|
createShape(this.type, points, options, this.tvCallbacks)
|
||||||
if (this.debug) console.log('created', this.type.name, this.ourPoints, this.id)
|
if (this.debug) console.log('created', this.type.name, points, this.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
createOrDraw() {
|
createOrDraw() {
|
||||||
if(this.id) return
|
if(this.id) return
|
||||||
if(this.ourPoints && this.ourPoints.length)
|
if(this.ourPoints && this.ourPoints.length)
|
||||||
this.doCreate(this.ourPoints)
|
this.create()
|
||||||
else
|
else
|
||||||
this.draw()
|
this.draw()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tvShape() {
|
tvShape() {
|
||||||
|
try {
|
||||||
return this.id === null ? null : chart.getShapeById(this.id);
|
return this.id === null ? null : chart.getShapeById(this.id);
|
||||||
}
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error(`Could not get chart shape ${this.id}`)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
setPoints(points) {
|
setPoints(points) {
|
||||||
@@ -233,12 +240,14 @@ export class Shape {
|
|||||||
this.delete()
|
this.delete()
|
||||||
else {
|
else {
|
||||||
if (this.id === null)
|
if (this.id === null)
|
||||||
this.doCreate()
|
this.create()
|
||||||
else if (dirtyPoints(this.tvPoints, points)) {
|
else if (dirtyPoints(this.tvPoints, points)) {
|
||||||
const s = this.tvShape();
|
const s = this.tvShape();
|
||||||
let sbm = false
|
let sbm = false
|
||||||
if( draggingShapeIds.length ) {
|
if( draggingShapeIds.length ) {
|
||||||
const dragShape = chart.getShapeById(draggingShapeIds[0])
|
let dragShape
|
||||||
|
try {
|
||||||
|
dragShape = chart.getShapeById(draggingShapeIds[0])
|
||||||
const sbms = [...dragShape._model._sourcesBeingMoved]
|
const sbms = [...dragShape._model._sourcesBeingMoved]
|
||||||
// console.log('shape setPoints', this.id, dragShape, sbm)
|
// console.log('shape setPoints', this.id, dragShape, sbm)
|
||||||
sbm = !sbms.length
|
sbm = !sbms.length
|
||||||
@@ -247,6 +256,10 @@ export class Shape {
|
|||||||
// 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 (this.debug) console.log('adjusting tv points', this.tvPoints, points, dragging, this.beingDragged())
|
||||||
// if ( dragging && !this.beingDragged())
|
// if ( dragging && !this.beingDragged())
|
||||||
// s.setSelectionEnabled(false)
|
// s.setSelectionEnabled(false)
|
||||||
@@ -328,7 +341,10 @@ export class Shape {
|
|||||||
onRedraw() {} // the mouse moved while in drawing mode
|
onRedraw() {} // the mouse moved while in drawing mode
|
||||||
onUndraw() {} // drawing was canceled by clicking on a different tool
|
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)
|
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
|
onMove(points) {} // the shape was moved by dragging a drawing element not the control point
|
||||||
onDrag(points) {}
|
onDrag(points) {}
|
||||||
onHide(props) {}
|
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) {
|
function nearestOhlcStart(time) {
|
||||||
const period = useChartOrderStore().intervalSecs
|
const period = useChartOrderStore().intervalSecs
|
||||||
return Math.round(time/period) * period
|
return Math.round(time/period) * period
|
||||||
@@ -534,11 +541,22 @@ export class VLine extends Line {
|
|||||||
// Model
|
// Model
|
||||||
this.model.time = null
|
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
|
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() {
|
delete() {
|
||||||
this.model.time = null
|
this.model.time = null
|
||||||
|
this.shapeTime = null
|
||||||
super.delete()
|
super.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,29 +564,38 @@ export class VLine extends Line {
|
|||||||
setModel(model) {
|
setModel(model) {
|
||||||
// console.log('VLine setModel', this.id, {...this.model}, model)
|
// console.log('VLine setModel', this.id, {...this.model}, model)
|
||||||
super.setModel(model)
|
super.setModel(model)
|
||||||
if (model.time === null) {
|
if (model.time === null)
|
||||||
this.model.time = null
|
|
||||||
this.delete()
|
this.delete()
|
||||||
}
|
|
||||||
else if (model.time !== this.model.time) {
|
else if (model.time !== this.model.time) {
|
||||||
this.model.time = model.time
|
this.model.time = model.time
|
||||||
const time = nearestOhlcStart(model.time);
|
this.setPoints([{time: model.time, price: 0}])
|
||||||
this.setPoints([{time, price:0}])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setPoints(points) {
|
setPoints(points) {
|
||||||
// console.error('VLine 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);
|
super.setPoints(points);
|
||||||
}
|
}
|
||||||
|
if (this.debug) console.error('VLine setPoints', points)
|
||||||
|
}
|
||||||
|
|
||||||
onPoints(points) {
|
onPoints(points) {
|
||||||
const orig = this.ourPoints && this.ourPoints.length ? this.ourPoints[0].time : null
|
|
||||||
super.onPoints(points);
|
|
||||||
const time = points[0].time;
|
const time = points[0].time;
|
||||||
if (!timeAdjustmentTooSmall(orig, time))
|
if ( time !== this.shapeTime ) {
|
||||||
|
super.onPoints(points);
|
||||||
this.updateModel({time: time})
|
this.updateModel({time: time})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
276
src/components/AbsoluteTimeEntry.vue
Normal file
276
src/components/AbsoluteTimeEntry.vue
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
<template>
|
||||||
|
<div class="d-flex root">
|
||||||
|
<!--
|
||||||
|
<vue-scroll-picker :options="yearMonthItems" v-model="yearMonth" class="picker"/>
|
||||||
|
<vue-scroll-picker :options="wdItems" v-model="day" class="picker"/>
|
||||||
|
-->
|
||||||
|
<!-- <v-select :items="yearMonthItems" v-model="yearMonthItem"/>-->
|
||||||
|
<!-- <v-text-field v-model="day"/>-->
|
||||||
|
<!--
|
||||||
|
<v-tooltip v-model="showPicker">
|
||||||
|
<v-date-picker :show-adjacent-months="true" v-model="now"/>
|
||||||
|
</v-tooltip>
|
||||||
|
-->
|
||||||
|
<v-text-field type="number" v-model="year"
|
||||||
|
rounded="0" :hide-details="hideDetails" single-line class="all year" maxlength="4"/>
|
||||||
|
<!-- <v-text-field type="number" min="1" max="31" v-model="day" :label="wdFormat.format(day)"-->
|
||||||
|
<!-- :hide-details="hideDetails" style="min-width: 3em; width: 3em" class="all month"/>-->
|
||||||
|
<v-select v-model="month" :items="monthItems"
|
||||||
|
rounded="0" :hide-details="hideDetails" single-line class="all month"/>
|
||||||
|
<v-text-field type="number" v-model="day"
|
||||||
|
rounded="0" :hide-details="hideDetails" single-line class="all year"
|
||||||
|
min="1" :max="daysInMonth(...yearMonth)" maxlength="2"/>
|
||||||
|
<v-text-field type="time" v-model="time"
|
||||||
|
rounded="0" :hide-details="hideDetails" single-line class="all"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {useStore} from "@/store/store";
|
||||||
|
import {computed, nextTick, ref} from "vue";
|
||||||
|
import {VueScrollPicker} from "vue-scroll-picker";
|
||||||
|
import {useDate} from "vuetify";
|
||||||
|
import {mixin} from "@/common.js";
|
||||||
|
|
||||||
|
const s = useStore()
|
||||||
|
const props = defineProps(['modelValue'])
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
const showPicker = ref(false)
|
||||||
|
|
||||||
|
const hideDetails = true
|
||||||
|
|
||||||
|
const date = useDate()
|
||||||
|
|
||||||
|
const now = computed(()=>new Date(1000*props.modelValue))
|
||||||
|
|
||||||
|
const dRef = ref(s.utc ? now.value.getUTCDate() : now.value.getDate())
|
||||||
|
const ymRef = ref([date.getYear(now.value), date.getMonth(now.value)])
|
||||||
|
|
||||||
|
const year = computed({
|
||||||
|
get() { return date.getYear(now.value) },
|
||||||
|
set(v) { update({year:v}) }
|
||||||
|
})
|
||||||
|
|
||||||
|
const month = computed({
|
||||||
|
get() { return date.getMonth(now.value) },
|
||||||
|
set(v) { update({month:v}) }
|
||||||
|
})
|
||||||
|
|
||||||
|
const day = computed({
|
||||||
|
get() { return now.value.getDate() },
|
||||||
|
set(v) { update({day:v}) },
|
||||||
|
})
|
||||||
|
|
||||||
|
const time = computed({
|
||||||
|
get() {
|
||||||
|
let hour, min
|
||||||
|
if( s.utc ) {
|
||||||
|
hour = now.value.getUTCHours()
|
||||||
|
min = now.value.getUTCMinutes()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hour = now.value.getHours()
|
||||||
|
min = now.value.getMinutes()
|
||||||
|
}
|
||||||
|
return hour.toString().padStart(2,'0') + ':' + min.toString().padStart(2,'0')
|
||||||
|
},
|
||||||
|
set(v) {
|
||||||
|
const [hour,minute] = v.split(':')
|
||||||
|
update({hour:hour, minute:minute})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const curYearMonth = computed(()=>[date.getYear(now.value), date.getMonth(now.value)])
|
||||||
|
|
||||||
|
function extendPast(ms) {
|
||||||
|
console.log('extend past', ms)
|
||||||
|
const before = []
|
||||||
|
let cur = ms.length ? ms[0] : curYearMonth.value
|
||||||
|
for (let i=0; i<12; i++) {
|
||||||
|
cur = prevMonth(...cur)
|
||||||
|
before.push(cur)
|
||||||
|
}
|
||||||
|
before.reverse()
|
||||||
|
console.log('extended', before)
|
||||||
|
return [...before, ...ms]
|
||||||
|
}
|
||||||
|
|
||||||
|
function extendFuture(ms) {
|
||||||
|
console.log('extend future', ms)
|
||||||
|
const after = []
|
||||||
|
let cur = ms.length ? ms[ms.length-1] : curYearMonth.value
|
||||||
|
for (let i=0; i<12; i++) {
|
||||||
|
cur = nextMonth(...cur)
|
||||||
|
after.push(cur)
|
||||||
|
}
|
||||||
|
console.log('extended by', after)
|
||||||
|
return [...ms, ...after]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function dtFormat(format) {
|
||||||
|
return new Intl.DateTimeFormat(s.utc ? 'utc':undefined, format)
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo utc
|
||||||
|
const yFormat = dtFormat({year:'numeric'})
|
||||||
|
const mFormat = dtFormat({month: 'long'})
|
||||||
|
const ymFormat = dtFormat({year:'numeric', month: 'long'})
|
||||||
|
const wdFormat = dtFormat({weekday:'short'})
|
||||||
|
const dFormat = dtFormat({day:'numeric'})
|
||||||
|
|
||||||
|
const monthItems = []
|
||||||
|
for( let i=0; i<12; i++ )
|
||||||
|
monthItems.push({value: i, title: mFormat.format(new Date(0, i))})
|
||||||
|
|
||||||
|
function ymItem(ym) {
|
||||||
|
const d = new Date(...ym);
|
||||||
|
const name = yFormat.format(d) + ' ' + mFormat.format(d)
|
||||||
|
// return {title: name, value: ym} // v-select
|
||||||
|
return {name, value: ym} // vue-scroll-picker
|
||||||
|
}
|
||||||
|
|
||||||
|
function wdItem(ym, day) {
|
||||||
|
const d = new Date(...ym, day)
|
||||||
|
const name = dFormat.format(d) + ' ' + wdFormat.format(d)
|
||||||
|
return {name, value: day}
|
||||||
|
}
|
||||||
|
|
||||||
|
const wdItems = computed(()=>{
|
||||||
|
const ym = yearMonth.value
|
||||||
|
const wds = []
|
||||||
|
for (let d=1; d<=daysInMonth(...yearMonth.value); d++)
|
||||||
|
wds.push(wdItem(ym,d))
|
||||||
|
return wds
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const yearMonth = computed({
|
||||||
|
get() { return ymRef.value },
|
||||||
|
set(v) {
|
||||||
|
const [y, m] = v
|
||||||
|
const lastDay = daysInMonth(y,m);
|
||||||
|
const d = now.value.getDate() <= lastDay ? now.value.getDate() : lastDay
|
||||||
|
console.log('update yearmonth', v)
|
||||||
|
update({year:y, month:m, day:d})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const monthOptions = ref(extendFuture(extendPast([yearMonth.value])))
|
||||||
|
|
||||||
|
const yearMonthItems = computed({
|
||||||
|
get() {return monthOptions.value.map((ym) => ymItem(ym))},
|
||||||
|
set(v) {yearMonth.value = v}
|
||||||
|
})
|
||||||
|
|
||||||
|
function daysInMonth(year, month) {
|
||||||
|
return new Date(year, month+1, 0).getDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
const dayItems = computed(()=>{
|
||||||
|
const days = []
|
||||||
|
for (let i=1; i<=daysInMonth(...yearMonth.value); i++)
|
||||||
|
days.push(i)
|
||||||
|
return days
|
||||||
|
})
|
||||||
|
|
||||||
|
function nextMonth( year, month ) {
|
||||||
|
month++
|
||||||
|
if( month===12 ) {
|
||||||
|
month = 0
|
||||||
|
year++
|
||||||
|
}
|
||||||
|
return [year, month]
|
||||||
|
}
|
||||||
|
|
||||||
|
function prevMonth( year, month ) {
|
||||||
|
month--
|
||||||
|
if( month===-1 ) {
|
||||||
|
month = 11
|
||||||
|
year--
|
||||||
|
}
|
||||||
|
return [year, month]
|
||||||
|
}
|
||||||
|
|
||||||
|
function update(fields={}) {
|
||||||
|
console.error('update', fields)
|
||||||
|
if (!Object.keys(fields).length) return
|
||||||
|
if (newValue===null) {
|
||||||
|
newValue = {}
|
||||||
|
nextTick(doUpdate)
|
||||||
|
}
|
||||||
|
mixin(newValue, fields)
|
||||||
|
console.log('triggering update', fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
function doUpdate() {
|
||||||
|
console.log('doUpdate')
|
||||||
|
|
||||||
|
let dirty = false
|
||||||
|
if (newValue.year===undefined)
|
||||||
|
newValue.year = date.getYear(now.value)
|
||||||
|
else
|
||||||
|
dirty ||= newValue.year !== date.getYear(now.value)
|
||||||
|
if (newValue.month===undefined)
|
||||||
|
newValue.month = date.getMonth(now.value)
|
||||||
|
else
|
||||||
|
dirty ||= newValue.month !== date.getMonth(now.value)
|
||||||
|
if (newValue.day===undefined)
|
||||||
|
newValue.day = now.value.getDate()
|
||||||
|
else
|
||||||
|
dirty ||= newValue.day !== now.value.getDate()
|
||||||
|
if (newValue.hour===undefined)
|
||||||
|
newValue.hour = date.getHours(now.value)
|
||||||
|
else
|
||||||
|
dirty ||= newValue.hour !== date.getHours(now.value)
|
||||||
|
if (newValue.minute===undefined)
|
||||||
|
newValue.minute = date.getMinutes(now.value)
|
||||||
|
else
|
||||||
|
dirty ||= newValue.minute !== date.getMinutes(now.value)
|
||||||
|
|
||||||
|
if (dirty) {
|
||||||
|
const d = s.utc ?
|
||||||
|
new Date(Date.UTC(newValue.year, newValue.month, newValue.day, newValue.hour, newValue.minute)) :
|
||||||
|
new Date(newValue.year, newValue.month, newValue.day, newValue.hour, newValue.minute)
|
||||||
|
const ts = Math.round(d.getTime() / 1000);
|
||||||
|
console.log('doUpdate value', ts)
|
||||||
|
newValue = null
|
||||||
|
emit('update:modelValue', ts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let newValue = null
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.root {
|
||||||
|
$height: 3.3em;
|
||||||
|
margin-bottom: 0;
|
||||||
|
height: $height;
|
||||||
|
min-height: $height;
|
||||||
|
max-height: $height;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.year {
|
||||||
|
width: 6em;
|
||||||
|
max-width: 6em;
|
||||||
|
min-width: 6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month {
|
||||||
|
width: 10em;
|
||||||
|
max-width: 10em;
|
||||||
|
min-width: 5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.day {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker {
|
||||||
|
width: 8em;
|
||||||
|
height: 2em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import "/public/charting_library/charting_library.js"
|
import "/charting_library/charting_library.js?url"
|
||||||
// import "/public/datafeeds/udf/dist/bundle.js"
|
// import "/datafeeds/udf/dist/bundle.js?url"
|
||||||
import {onMounted, ref} from "vue";
|
import {onMounted, ref} from "vue";
|
||||||
import {initWidget} from "@/charts/chart.js";
|
import {initWidget} from "@/charts/chart.js";
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,53 @@
|
|||||||
<template>
|
<template>
|
||||||
<rung-builder name='DCA' :order="order" :builder="builder"
|
<rung-builder name='DCA' :order="order" :builder="builder"
|
||||||
v-model:value-a="absTimeA" v-model:value-b="absTimeB" :mode="1" :flip="flipped"
|
v-model:value-a="absTimeA" v-model:value-b="absTimeB"
|
||||||
:shape="VLine"
|
:shape="VLine"
|
||||||
|
:mode="1" :flip="flipped" :orientation="0"
|
||||||
:get-model-value="getModelValue" :set-model-value="setModelValue"
|
:get-model-value="getModelValue" :set-model-value="setModelValue"
|
||||||
:get-points-value="getPointsValue"
|
:get-points-value="getPointsValue"
|
||||||
:set-values="setValues" :set-weights="setWeights"
|
:set-values="setValues" :set-weights="setWeights"
|
||||||
:std-width="stdWidth" :build-tranches="buildTranches">
|
:std-width="stdWidth" :build-tranches="buildTranches">
|
||||||
|
|
||||||
|
<!--
|
||||||
<v-list style="background-color: inherit">
|
<v-list style="background-color: inherit">
|
||||||
<v-list-item v-for="t in absoluteTimes">{{t}}</v-list-item>
|
<v-list-item v-for="t in absoluteTimes">{{t}}</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<absolute-time-entry v-model="absTimeA"/>
|
||||||
|
</td>
|
||||||
|
<td class="weight">{{ weights.length ? allocationText(weights[0]) : '' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="weights.length>2" v-for="i in weights.length-2" class="ml-5">
|
||||||
|
<td class="pl-5">{{ times[1+i] }}</td>
|
||||||
|
<td class="weight">{{ allocationText(weights[1+i]) }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="weights.length>1">
|
||||||
|
<td>
|
||||||
|
<!--
|
||||||
|
<v-text-field type="number" v-model="lowerPrice" min="0"
|
||||||
|
density="compact" hide-details class="mx-1 my-2" variant="outlined"
|
||||||
|
label="Price"
|
||||||
|
:color="color" :base-color="color"
|
||||||
|
style="flex: 6em"
|
||||||
|
/>
|
||||||
|
-->
|
||||||
|
</td>
|
||||||
|
<td class="weight">{{ allocationText(weights[weights.length-1]) }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
</rung-builder>
|
</rung-builder>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {builderDefaults, MIN_EXECUTION_TIME, useChartOrderStore} from "@/orderbuild.js";
|
import {allocationText, builderDefaults, MIN_EXECUTION_TIME, useChartOrderStore} from "@/orderbuild.js";
|
||||||
import {VLine} from "@/charts/shape.js";
|
import {VLine} from "@/charts/shape.js";
|
||||||
import {sideColor} from "@/misc.js";
|
import {sideColor} from "@/misc.js";
|
||||||
import {useTheme} from "vuetify";
|
import {useTheme} from "vuetify";
|
||||||
@@ -22,6 +56,8 @@ import {DISTANT_FUTURE, MAX_FRACTION, newTranche} from "@/blockchain/orderlib.js
|
|||||||
import RungBuilder from "@/components/chart/RungBuilder.vue";
|
import RungBuilder from "@/components/chart/RungBuilder.vue";
|
||||||
import {computed, ref, watchEffect} from "vue";
|
import {computed, ref, watchEffect} from "vue";
|
||||||
import {chart, dragging} from "@/charts/chart.js";
|
import {chart, dragging} from "@/charts/chart.js";
|
||||||
|
import AbsoluteTimeEntry from "@/components/AbsoluteTimeEntry.vue";
|
||||||
|
import TimeEntry from "@/components/TimeEntry.vue";
|
||||||
|
|
||||||
const s = useStore()
|
const s = useStore()
|
||||||
const os = useOrderStore()
|
const os = useOrderStore()
|
||||||
@@ -50,10 +86,9 @@ builderDefaults(props.builder, {
|
|||||||
color: defaultColor,
|
color: defaultColor,
|
||||||
})
|
})
|
||||||
|
|
||||||
const rawTimes = ref([])
|
const times = ref([])
|
||||||
const weights = ref([])
|
const weights = ref([])
|
||||||
|
|
||||||
const times = computed(()=>rawTimes.value.map((t)=>Math.round(t)))
|
|
||||||
const endTimes = computed(()=>{
|
const endTimes = computed(()=>{
|
||||||
if (props.builder.rungs === 1)
|
if (props.builder.rungs === 1)
|
||||||
return DISTANT_FUTURE
|
return DISTANT_FUTURE
|
||||||
@@ -63,10 +98,10 @@ const endTimes = computed(()=>{
|
|||||||
})
|
})
|
||||||
const absoluteTimes = computed(()=>{
|
const absoluteTimes = computed(()=>{
|
||||||
// console.log('absoluteTimes', props.builder.relative, times.value)
|
// console.log('absoluteTimes', props.builder.relative, times.value)
|
||||||
if (!props.builder.relative)
|
// if (!props.builder.relative)
|
||||||
return times.value
|
return times.value
|
||||||
const now = s.clock
|
// const now = s.clock
|
||||||
return times.value.map((t)=>now+t)
|
// return times.value.map((t)=>now+t)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@@ -77,7 +112,7 @@ watchEffect(()=>{
|
|||||||
const range = chart.getVisibleRange()
|
const range = chart.getVisibleRange()
|
||||||
const width = range.to - range.from
|
const width = range.to - range.from
|
||||||
const now = s.clock
|
const now = s.clock
|
||||||
const extra = (Math.max(0,endTime - now) + minWidth.value) / width
|
const extra = (Math.max(0,endTime - now) + stdWidth.value/2) / width
|
||||||
// console.log('visrange', range, width, absV)
|
// console.log('visrange', range, width, absV)
|
||||||
if (range.to < endTime) {
|
if (range.to < endTime) {
|
||||||
// console.log('scrolling')
|
// console.log('scrolling')
|
||||||
@@ -93,39 +128,38 @@ watchEffect(()=>{
|
|||||||
const absTimeA = computed({
|
const absTimeA = computed({
|
||||||
get() {
|
get() {
|
||||||
let result = props.builder.timeA
|
let result = props.builder.timeA
|
||||||
if (props.builder.relative)
|
// if (props.builder.relative)
|
||||||
result += s.clock
|
// result += s.clock
|
||||||
// console.log('absTimeA', result)
|
console.log('get absTimeA', result)
|
||||||
return result
|
return result
|
||||||
},
|
},
|
||||||
set(v) {
|
set(v) {
|
||||||
// console.log('set absTimeA', props.builder.timeA, v)
|
console.error('set absTimeA', props.builder.timeA, v)
|
||||||
if (props.builder.relative)
|
// if (props.builder.relative)
|
||||||
v -= s.clock
|
// v -= s.clock
|
||||||
props.builder.timeA = v
|
props.builder.timeA = v
|
||||||
// console.log('absTimeA=',props.builder.timeA)
|
console.log('absTimeA=',props.builder.timeA)
|
||||||
scroll()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const absTimeB = computed({
|
const absTimeB = computed({
|
||||||
get() {
|
get() {
|
||||||
let result = props.builder.timeB
|
let result = props.builder.timeB
|
||||||
if (props.builder.relative)
|
// if (props.builder.relative)
|
||||||
result += s.clock
|
// result += s.clock
|
||||||
// console.log('absTimeB', result)
|
// console.log('absTimeB', result)
|
||||||
return result
|
return result
|
||||||
},
|
},
|
||||||
set(v) {
|
set(v) {
|
||||||
// console.log('set absTimeB', props.builder.timeB, v)
|
console.error('set absTimeB', props.builder.timeB, v)
|
||||||
const absV = v
|
// if ( v !== null && props.builder.relative )
|
||||||
if ( v !== null && props.builder.relative )
|
// v -= s.clock
|
||||||
v -= s.clock
|
|
||||||
props.builder.timeB = v
|
props.builder.timeB = v
|
||||||
const maxA = v - minWidth.value;
|
const maxA = v - minWidth.value;
|
||||||
if (props.builder.timeA > maxA)
|
if (props.builder.timeA > maxA) {
|
||||||
|
console.log('scootching A to', maxA)
|
||||||
props.builder.timeA = maxA
|
props.builder.timeA = maxA
|
||||||
// console.log('absTimeB=',props.builder.timeB)
|
}
|
||||||
scroll()
|
console.log('absTimeB=',props.builder.timeB)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -135,37 +169,6 @@ const flipped = computed(()=>{
|
|||||||
return a !== null && b !== null && a > b
|
return a !== null && b !== null && a > b
|
||||||
})
|
})
|
||||||
|
|
||||||
const higherIndex = computed(()=>flipped.value ? 0 : weights.value.length-1)
|
|
||||||
const lowerIndex = computed(()=>!flipped.value ? 0 : weights.value.length-1)
|
|
||||||
const innerIndexes = computed(()=>{
|
|
||||||
const n = times.value.length
|
|
||||||
const f = flipped.value
|
|
||||||
const result = []
|
|
||||||
for (let i=1; i<n-1; i++)
|
|
||||||
result.push(f?i:n-1-i)
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
|
|
||||||
const earlierTime = computed({
|
|
||||||
get() { return !flipped.value ? props.builder.timeA : props.builder.timeB },
|
|
||||||
set(v) {
|
|
||||||
if (!flipped.value)
|
|
||||||
props.builder.timeA = v
|
|
||||||
else
|
|
||||||
props.builder.timeB = v
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const laterTime = computed({
|
|
||||||
get() { return !flipped.value ? props.builder.timeA : props.builder.timeB },
|
|
||||||
set(v) {
|
|
||||||
if (!flipped.value)
|
|
||||||
props.builder.timeA = v
|
|
||||||
else
|
|
||||||
props.builder.timeB = v
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
function buildTranches() {
|
function buildTranches() {
|
||||||
const order = props.order
|
const order = props.order
|
||||||
const builder = props.builder
|
const builder = props.builder
|
||||||
@@ -201,7 +204,8 @@ function getPointsValue(points) {
|
|||||||
|
|
||||||
function setModelValue(model, value) {
|
function setModelValue(model, value) {
|
||||||
// console.log('DCA set model value', model, value)
|
// console.log('DCA set model value', model, value)
|
||||||
const v = value === null ? null : props.builder.relative ? s.clock + Math.round(value) : Math.round(value)
|
// const v = value === null ? null : props.builder.relative ? s.clock + Math.round(value) : Math.round(value)
|
||||||
|
const v = value === null ? null : Math.round(value)
|
||||||
if (model.time !== v) {
|
if (model.time !== v) {
|
||||||
// console.log('DCA do set time', v)
|
// console.log('DCA do set time', v)
|
||||||
model.time = v
|
model.time = v
|
||||||
@@ -209,12 +213,15 @@ function setModelValue(model, value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setValues(values) {
|
function setValues(values) {
|
||||||
|
times.value = values.map((t)=>Math.round(t))
|
||||||
|
/*
|
||||||
if (!props.builder.relative)
|
if (!props.builder.relative)
|
||||||
rawTimes.value = values
|
rawTimes.value = values
|
||||||
else {
|
else {
|
||||||
const now = s.clock
|
const now = s.clock
|
||||||
rawTimes.value = values.map((v)=>v-now)
|
rawTimes.value = values.map((v)=>v-now)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
function setWeights(ws) { weights.value = ws }
|
function setWeights(ws) { weights.value = ws }
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
Click the chart!
|
Click the chart!
|
||||||
</div>
|
</div>
|
||||||
<div v-if="rungs>1" class="mx-2 d-flex align-center">
|
<div v-if="rungs>1" class="mx-2 d-flex align-center">
|
||||||
<v-slider v-if="rungs>1" direction="vertical" min="-100" max="100" v-model="skew100"
|
<v-slider v-if="rungs>1" :direction="orientation?'vertical':'horizontal'" min="-100" max="100" v-model="skew100"
|
||||||
class="no-slider-bg ml-2 mr-4" hide-details/>
|
class="no-slider-bg ml-2 mr-4" hide-details/>
|
||||||
<v-text-field type="number" v-model="skew100" min="-100" max="100"
|
<v-text-field type="number" v-model="skew100" min="-100" max="100"
|
||||||
density="compact" hide-details variant="outlined" label="Skew" step="5"
|
density="compact" hide-details variant="outlined" label="Skew" step="5"
|
||||||
@@ -41,7 +41,7 @@ import {useTheme} from "vuetify";
|
|||||||
import {linspace, sideColor} from "@/misc.js";
|
import {linspace, sideColor} from "@/misc.js";
|
||||||
import {computed, onUnmounted, watchEffect} from "vue";
|
import {computed, onUnmounted, watchEffect} from "vue";
|
||||||
import Color from "color";
|
import Color from "color";
|
||||||
import {cancelDrawing, chart} from "@/charts/chart.js";
|
import {cancelDrawing} from "@/charts/chart.js";
|
||||||
|
|
||||||
const os = useOrderStore()
|
const os = useOrderStore()
|
||||||
const co = useChartOrderStore()
|
const co = useChartOrderStore()
|
||||||
@@ -57,6 +57,7 @@ const props = defineProps({
|
|||||||
shape: Function, // shape() -> Shape
|
shape: Function, // shape() -> Shape
|
||||||
mode: { type: Number, default: 0 }, // rung addition mode: 0 = split, 1 = extend
|
mode: { type: Number, default: 0 }, // rung addition mode: 0 = split, 1 = extend
|
||||||
flip: { type: Boolean, default: false }, // if true, the skew slider is flipped upside-down
|
flip: { type: Boolean, default: false }, // if true, the skew slider is flipped upside-down
|
||||||
|
orientation: { type: Number, default: 1 }, // 0 = horizontal slider, 1 = vertical
|
||||||
getModelValue: Function, // getModelValue(model) -> value
|
getModelValue: Function, // getModelValue(model) -> value
|
||||||
setModelValue: Function, // setModelValue(model,value) -> void
|
setModelValue: Function, // setModelValue(model,value) -> void
|
||||||
getPointsValue: Function, // getValueFromPoints(points) -> value
|
getPointsValue: Function, // getValueFromPoints(points) -> value
|
||||||
@@ -89,6 +90,7 @@ const rungs = computed({
|
|||||||
props.builder.rungs = 1
|
props.builder.rungs = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const prevR = props.builder.rungs
|
||||||
r = Number(r)
|
r = Number(r)
|
||||||
props.builder.rungs = r
|
props.builder.rungs = r
|
||||||
const b = valueB.value
|
const b = valueB.value
|
||||||
@@ -115,8 +117,10 @@ const rungs = computed({
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// from multi to multi
|
// from multi to multi
|
||||||
if (props.mode===1)
|
if (props.mode===1) {
|
||||||
valueB.value = valueA.value + props.stdWidth * (r-1)
|
const width = (valueB.value - valueA.value) / (prevR-1)
|
||||||
|
valueB.value = valueA.value + width * (r-1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -182,82 +186,62 @@ function createShape(value, model, onModel, onDelete) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function translateOnDrag(shape) {
|
function translateOnModel(shape) {
|
||||||
const oldOnPoints = shape.onPoints
|
const oldOnModel = shape.onModel
|
||||||
shape.onPoints = function (points) {
|
shape.onModel = function (model, oldModel) {
|
||||||
|
oldOnModel.call(this, ...arguments)
|
||||||
// console.log('translateOnDrag', this.beingDragged(), shape.ourPoints)
|
// console.log('translateOnDrag', this.beingDragged(), shape.ourPoints)
|
||||||
if (!this.beingDragged()) {
|
if (!this.beingDragged()) {
|
||||||
oldOnPoints.call(this, points)
|
oldOnModel.call(this, ...arguments)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const prev = props.getModelValue(this.model)
|
const prev = props.getModelValue(oldModel)
|
||||||
oldOnPoints.call(this, points)
|
|
||||||
const cur = props.getModelValue(this.model)
|
const cur = props.getModelValue(this.model)
|
||||||
const delta = cur - prev
|
const delta = cur - prev
|
||||||
// console.log('delta', points, shape.ourPoints, prev, cur, delta)
|
// console.log('delta', shape.id, prev, cur, delta)
|
||||||
if (delta !== 0) {
|
if (delta !== 0) {
|
||||||
valueA.value += delta
|
valueA.value += delta
|
||||||
|
if (rungs.value > 1)
|
||||||
valueB.value += delta
|
valueB.value += delta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// function translateOnDrag(shape) {
|
function setModelColor(model) {
|
||||||
// const oldOnPoints = shape.onPoints
|
if (model.color && model.color !== color.value)
|
||||||
// shape.onPoints = function (points) {
|
color.value = model.color
|
||||||
// console.log('translateOnDrag', this.beingDragged(), shape.ourPoints)
|
}
|
||||||
// if (!this.beingDragged()) {
|
|
||||||
// oldOnPoints.call(this, points)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // todo vectorize
|
|
||||||
// const prev = props.getPointsValue(shape.ourPoints)
|
|
||||||
// const cur = props.getPointsValue(points)
|
|
||||||
// const delta = cur - prev
|
|
||||||
// console.log('delta', points, shape.ourPoints, prev, cur, delta)
|
|
||||||
// if (delta !== 0) {
|
|
||||||
// valueA.value += delta
|
|
||||||
// valueB.value += delta
|
|
||||||
// }
|
|
||||||
// oldOnPoints.call(this, points)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
const shapeA = createShape(valueA.value, {color: defaultColor},
|
const shapeA = createShape(valueA.value, {color: defaultColor},
|
||||||
function (model) {
|
function (model) {
|
||||||
const value = props.getModelValue(model);
|
const value = props.getModelValue(model);
|
||||||
if (value!==null && value!==undefined)
|
if (value !== valueA.value)
|
||||||
valueA.value = value;
|
valueA.value = value;
|
||||||
if (model.color)
|
setModelColor(model)
|
||||||
color.value = model.color
|
|
||||||
},
|
},
|
||||||
deleteSelf)
|
deleteSelf)
|
||||||
|
|
||||||
if (props.mode===1)
|
if (props.mode===1)
|
||||||
translateOnDrag(shapeA)
|
translateOnModel(shapeA)
|
||||||
|
|
||||||
const shapeB = createShape(valueB.value, {color:defaultColor},
|
const shapeB = createShape(valueB.value, {color:defaultColor},
|
||||||
function (model) {
|
function (model) {
|
||||||
const value = props.getModelValue(model);
|
const value = props.getModelValue(model);
|
||||||
if (value!==null && value!==undefined)
|
if (value !== valueB.value)
|
||||||
valueB.value = value;
|
valueB.value = value;
|
||||||
if (model.color)
|
setModelColor(model)
|
||||||
color.value = model.color
|
|
||||||
},
|
},
|
||||||
deleteSelf)
|
deleteSelf)
|
||||||
|
|
||||||
function interiorOnModel(model) {
|
function interiorOnModel(model) {
|
||||||
if (model.color)
|
setModelColor(model)
|
||||||
color.value = model.color
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let interiorShapes = []
|
let interiorShapes = []
|
||||||
|
|
||||||
function createInteriorShape(index) {
|
function createInteriorShape(index) {
|
||||||
const shape = new props.shape(makeModel(index), interiorOnModel, deleteSelf)
|
const shape = new props.shape(makeModel(index), interiorOnModel, deleteSelf)
|
||||||
translateOnDrag(shape)
|
translateOnModel(shape)
|
||||||
interiorShapes.push(shape)
|
interiorShapes.push(shape)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,6 +372,9 @@ if (!valueA.value)
|
|||||||
:deep(.v-slider.v-input--vertical > .v-input__control) {
|
:deep(.v-slider.v-input--vertical > .v-input__control) {
|
||||||
min-height: 5em !important;
|
min-height: 5em !important;
|
||||||
}
|
}
|
||||||
|
:deep(.v-slider.v-input--horizontal > .v-input__control) {
|
||||||
|
min-width: 5em !important;
|
||||||
|
}
|
||||||
:deep(.v-slider.no-slider-bg .v-slider-track__fill) {
|
:deep(.v-slider.no-slider-bg .v-slider-track__fill) {
|
||||||
background-color: inherit !important;
|
background-color: inherit !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import { loadFonts } from './webfontloader'
|
|||||||
import vuetify from './vuetify'
|
import vuetify from './vuetify'
|
||||||
import pinia from '../store/pinia.js'
|
import pinia from '../store/pinia.js'
|
||||||
import router from '../router'
|
import router from '../router'
|
||||||
|
import vsp from "vue-scroll-picker";
|
||||||
|
|
||||||
|
import "vue-scroll-picker/lib/style.css";
|
||||||
|
|
||||||
export function registerPlugins (app) {
|
export function registerPlugins (app) {
|
||||||
loadFonts()
|
loadFonts()
|
||||||
@@ -16,4 +19,5 @@ export function registerPlugins (app) {
|
|||||||
.use(vuetify)
|
.use(vuetify)
|
||||||
.use(router)
|
.use(router)
|
||||||
.use(pinia)
|
.use(pinia)
|
||||||
|
.use(vsp)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1368,6 +1368,11 @@ vue-router@^4.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@vue/devtools-api" "^6.5.1"
|
"@vue/devtools-api" "^6.5.1"
|
||||||
|
|
||||||
|
vue-scroll-picker@^1.2.2:
|
||||||
|
version "1.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue-scroll-picker/-/vue-scroll-picker-1.2.2.tgz#e99e4020c642105d2db736ac15fed2c4c0a0e082"
|
||||||
|
integrity sha512-Wsnib0EmtqPzmGdYvleHeC60lPFOjug4Iz1OmgDjuUsBZikmoBNzZwCTHgjBZiu6daIwRvGuuolQq86RznhjRA==
|
||||||
|
|
||||||
vue@^3.2.0:
|
vue@^3.2.0:
|
||||||
version "3.4.21"
|
version "3.4.21"
|
||||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.4.21.tgz#69ec30e267d358ee3a0ce16612ba89e00aaeb731"
|
resolved "https://registry.yarnpkg.com/vue/-/vue-3.4.21.tgz#69ec30e267d358ee3a0ce16612ba89e00aaeb731"
|
||||||
|
|||||||
Reference in New Issue
Block a user