2024-03-06 12:27:53 +00:00
|
|
|
import QtQuick 2.14
|
|
|
|
import QtQuick.Controls 2.14
|
|
|
|
import QtQuick.Layouts 1.14
|
|
|
|
|
|
|
|
import StatusQ.Core 0.1
|
|
|
|
import StatusQ.Core.Theme 0.1
|
|
|
|
import StatusQ.Controls 0.1
|
|
|
|
import StatusQ.Components 0.1
|
2024-06-04 10:08:16 +00:00
|
|
|
import StatusQ.Popups 0.1
|
2024-03-06 12:27:53 +00:00
|
|
|
|
|
|
|
import Storybook 1.0
|
|
|
|
|
2024-06-04 10:08:16 +00:00
|
|
|
import utils 1.0
|
|
|
|
|
2024-03-06 12:27:53 +00:00
|
|
|
SplitView {
|
|
|
|
id: root
|
|
|
|
|
|
|
|
orientation: Qt.Vertical
|
|
|
|
|
|
|
|
QtObject {
|
|
|
|
id: d
|
|
|
|
//dummy data
|
|
|
|
property real stepSize: 1000
|
|
|
|
property real minStep: 12000
|
|
|
|
property real maxStep: 22000
|
|
|
|
|
|
|
|
property var graphTabsModel: [{text: "Price", enabled: true}, {text: "Balance", enabled: true}]
|
|
|
|
property var timeRangeTabsModel: [{text: "1H", enabled: true},
|
|
|
|
{text: "1D", enabled: true},{text: "7D", enabled: true},
|
|
|
|
{text: "1M", enabled: true}, {text: "6M", enabled: true},
|
|
|
|
{text: "1Y", enabled: true}, {text: "ALL", enabled: true}]
|
|
|
|
|
|
|
|
function minutes(minutes = 0) {
|
|
|
|
var newMinute = new Date(new Date().getTime() - (minutes * 60 * 1000)).toString();
|
|
|
|
if (newMinute.slice(10,12) === "00") {
|
|
|
|
var dateToday = new Date(Date.now()).toString();
|
|
|
|
return dateToday.slice(4,7) + " " + dateToday.slice(8,10);
|
|
|
|
}
|
|
|
|
return newMinute.slice(10,16);
|
|
|
|
}
|
|
|
|
|
|
|
|
function hour(hours = 0) {
|
|
|
|
var newHour = new Date(new Date().getTime() - (hours * 60 * 60 * 1000)).toString();
|
|
|
|
if (newHour.slice(10,12) === "00") {
|
|
|
|
var dateToday = new Date(Date.now()).toString();
|
|
|
|
return dateToday.slice(4,7) + " " + dateToday.slice(8,10);
|
|
|
|
}
|
|
|
|
return newHour.slice(10,16);
|
|
|
|
}
|
|
|
|
|
|
|
|
function day(before = 0) {
|
|
|
|
var newDay = new Date(Date.now() - before * 24 * 60 * 60 * 1000).toString();
|
|
|
|
return newDay.slice(4,7) + " " + newDay.slice(8,10);
|
|
|
|
}
|
|
|
|
|
|
|
|
function month(before = 0) {
|
|
|
|
var newMonth = new Date(Date.now() - before * 24 * 60 * 60 * 1000).toString();
|
|
|
|
return newMonth.slice(4,7) + " '" + newMonth.slice(newMonth.indexOf("G")-3, newMonth.indexOf("G")-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
property var timeRange: [
|
|
|
|
{'1H': [minutes(60), minutes(55), minutes(50), minutes(45), minutes(40), minutes(35), minutes(30), minutes(25), minutes(20), minutes(15), minutes(10), minutes(5), minutes()]},
|
|
|
|
{'1D': [hour(24), hour(23), hour(22), hour(21), hour(20), hour(19), hour(18), hour(17), hour(16), hour(15), hour(14), hour(13),
|
|
|
|
hour(12), hour(11), hour(10), hour(9), hour(8), hour(7), hour(6), hour(5), hour(4), hour(3), hour(2), hour(1), hour()]},
|
|
|
|
{'7D': [day(6), day(5), day(4), day(3), day(2), day(1), day()]},
|
|
|
|
{'1M': [day(30), day(28), day(26), day(24), day(22), day(20), day(18), day(16), day(14), day(12), day(10), day(8), day(6), day(4), day()]},
|
|
|
|
{'6M': [month(150), month(120), month(90), month(60), month(30), month()]},
|
|
|
|
{'1Y': [month(330), month(300), month(270), month(240), month(210), month(180), month(150), month(120), month(90), month(60), month(30), month()]},
|
|
|
|
{'ALL': ['2016', '2017', '2018', '2019', '2020', '2021', '2022']}
|
|
|
|
]
|
|
|
|
|
|
|
|
function generateData() {
|
|
|
|
var result = [];
|
|
|
|
for (var i = 0; i < timeRange[graphDetail.timeRangeTabBarIndex][graphDetail.selectedTimeRange].length; ++i) {
|
|
|
|
result[i] = Math.random() * (maxStep - minStep) + minStep;
|
|
|
|
}
|
2024-06-04 10:08:16 +00:00
|
|
|
return result;
|
2024-03-06 12:27:53 +00:00
|
|
|
}
|
|
|
|
|
2024-06-04 10:08:16 +00:00
|
|
|
readonly property var lineConfig: {
|
|
|
|
return {
|
|
|
|
type: 'line',
|
|
|
|
labels: d.timeRange[graphDetail.timeRangeTabBarIndex][graphDetail.selectedTimeRange],
|
|
|
|
datasets: [{
|
|
|
|
label: 'Price',
|
|
|
|
xAxisId: 'x-axis-1',
|
|
|
|
yAxisId: 'y-axis-1',
|
|
|
|
backgroundColor: (Theme.palette.name === "dark") ? 'rgba(136, 176, 255, 0.2)' : 'rgba(67, 96, 223, 0.2)',
|
|
|
|
borderColor: (Theme.palette.name === "dark") ? 'rgba(136, 176, 255, 1)' : 'rgba(67, 96, 223, 1)',
|
|
|
|
borderWidth: 3,
|
|
|
|
pointRadius: 0,
|
|
|
|
data: d.generateData()
|
|
|
|
}],
|
|
|
|
options: {
|
2024-03-06 12:27:53 +00:00
|
|
|
maintainAspectRatio: false,
|
|
|
|
responsive: true,
|
|
|
|
legend: {
|
|
|
|
display: false
|
|
|
|
},
|
|
|
|
tooltips: {
|
|
|
|
intersect: false,
|
|
|
|
displayColors: false,
|
|
|
|
callbacks: {
|
|
|
|
footer: function(tooltipItem, data) { return 'Vol: $43,042,678,876'; },
|
|
|
|
label: function(tooltipItem, data) {
|
|
|
|
let label = data.datasets[tooltipItem.datasetIndex].label || '';
|
|
|
|
if (label) {
|
|
|
|
label += ': ';
|
|
|
|
}
|
|
|
|
label += tooltipItem.yLabel.toFixed(2);
|
|
|
|
return label.slice(0,label.indexOf(":")+1)+ " $"+label.slice(label.indexOf(":")+2, label.length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
scales: {
|
|
|
|
xAxes: [{
|
|
|
|
id: 'x-axis-1',
|
|
|
|
position: 'bottom',
|
2024-06-04 10:08:16 +00:00
|
|
|
//type: 'linear',
|
2024-03-06 12:27:53 +00:00
|
|
|
gridLines: {
|
|
|
|
drawOnChartArea: false,
|
|
|
|
drawBorder: false,
|
|
|
|
drawTicks: false,
|
|
|
|
},
|
|
|
|
ticks: {
|
|
|
|
fontSize: 10,
|
|
|
|
fontColor: (Theme.palette.name === "dark") ? '#909090' : '#939BA1',
|
|
|
|
padding: 16
|
|
|
|
}
|
|
|
|
}],
|
|
|
|
yAxes: [{
|
2024-06-04 10:08:16 +00:00
|
|
|
position: 'left',
|
|
|
|
id: 'y-axis-1',
|
|
|
|
gridLines: {
|
|
|
|
borderDash: [8, 4],
|
|
|
|
drawBorder: false,
|
|
|
|
drawTicks: false,
|
|
|
|
color: (Theme.palette.name === "dark") ? '#909090' : '#939BA1'
|
|
|
|
},
|
|
|
|
beforeDataLimits: (axis) => {
|
|
|
|
axis.paddingTop = 25;
|
|
|
|
axis.paddingBottom = 0;
|
|
|
|
},
|
|
|
|
ticks: {
|
|
|
|
fontSize: 10,
|
|
|
|
fontColor: (Theme.palette.name === "dark") ? '#909090' : '#939BA1',
|
|
|
|
padding: 8,
|
|
|
|
min: d.minStep,
|
|
|
|
max: d.maxStep,
|
|
|
|
stepSize: d.stepSize,
|
|
|
|
callback: function(value, index, ticks) {
|
|
|
|
return '$' + value;
|
2024-03-06 12:27:53 +00:00
|
|
|
},
|
2024-06-04 10:08:16 +00:00
|
|
|
}
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
readonly property var barConfig: {
|
|
|
|
return {
|
|
|
|
type:"bar",
|
|
|
|
options: {
|
|
|
|
onHover: function(event, activeElements) {
|
|
|
|
if (activeElements.length === 0) {
|
|
|
|
toolTip.close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
toolTip.text = "StatusMenu triggered by " + activeElements[0]._model.label
|
|
|
|
toolTip.popup()
|
|
|
|
toolTip.x += 10
|
|
|
|
toolTip.y -= toolTip.height + 10
|
|
|
|
},
|
|
|
|
tooltips: {
|
|
|
|
enabled:false
|
|
|
|
},
|
|
|
|
scales:{
|
|
|
|
xAxes:[{
|
|
|
|
id: "x-axis-1",
|
|
|
|
position: "bottom",
|
|
|
|
stacked: false,
|
|
|
|
gridLines: {
|
|
|
|
drawOnChartArea: false,
|
|
|
|
drawBorder: false,
|
|
|
|
drawTicks: false
|
2024-03-06 12:27:53 +00:00
|
|
|
},
|
2024-06-04 10:08:16 +00:00
|
|
|
ticks: {
|
|
|
|
fontSize:10,
|
|
|
|
fontColor: "#939ba1",
|
|
|
|
padding:16
|
|
|
|
}
|
|
|
|
}],
|
|
|
|
yAxes: [{
|
|
|
|
position: "left",
|
|
|
|
id: "y-axis-1",
|
|
|
|
stacked: false,
|
|
|
|
gridLines: {
|
|
|
|
borderDash: [5,3],
|
|
|
|
lineWidth: 1,
|
|
|
|
drawBorder: false,
|
|
|
|
drawTicks: false,
|
|
|
|
color: "#33939ba1"
|
|
|
|
},
|
|
|
|
ticks: {
|
|
|
|
fontSize: 10,
|
|
|
|
fontColor: "#939ba1",
|
|
|
|
padding: 8,
|
|
|
|
maxTicksLimit: 10,
|
|
|
|
beginAtZero: true,
|
|
|
|
stepSize: 1
|
|
|
|
}
|
|
|
|
}]
|
2024-03-06 12:27:53 +00:00
|
|
|
}
|
2024-06-04 10:08:16 +00:00
|
|
|
},
|
|
|
|
labels:["16:40","16:50","17:00","17:10","17:20","17:30"],
|
|
|
|
datasets: [{
|
|
|
|
xAxisId: "x-axis-1",
|
|
|
|
yAxisId: "y-axis-1",
|
|
|
|
backgroundColor: "#334360df",
|
|
|
|
pointRadius: 0,
|
|
|
|
hoverBackgroundColor: "#334360df",
|
|
|
|
hoverBorderColor: "#4360df",
|
|
|
|
hoverBorderWidth: 2,
|
|
|
|
data: [8,3,5,4,3,10]
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
readonly property var crosshairConfig: {
|
|
|
|
//binding to regenerate data and reset zoom
|
|
|
|
chartType.currentText
|
|
|
|
const generateDataset = (shift, label, color) => {
|
|
|
|
var data = [];
|
|
|
|
var x = 0;
|
|
|
|
|
|
|
|
while (x < 30) {
|
|
|
|
data.push({ x: x, y: Math.sin(shift + x / 3) });
|
|
|
|
x += Math.random();
|
2024-03-06 12:27:53 +00:00
|
|
|
}
|
2024-06-04 10:08:16 +00:00
|
|
|
|
|
|
|
var dataset = {
|
|
|
|
backgroundColor: color,
|
|
|
|
borderColor: color,
|
|
|
|
showLine: true,
|
|
|
|
fill: false,
|
|
|
|
pointRadius: 2,
|
|
|
|
label: label,
|
|
|
|
data: data,
|
|
|
|
lineTension: 0,
|
|
|
|
interpolate: true
|
|
|
|
};
|
|
|
|
return dataset;
|
2024-03-06 12:27:53 +00:00
|
|
|
}
|
2024-06-04 10:08:16 +00:00
|
|
|
|
|
|
|
return {
|
|
|
|
type: "scatter",
|
|
|
|
options: {
|
|
|
|
plugins: {
|
|
|
|
crosshair: {
|
|
|
|
enabled: true,
|
|
|
|
sync: {
|
|
|
|
enabled: false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
tooltips: {
|
|
|
|
mode: "interpolate",
|
|
|
|
intersect: true,
|
|
|
|
},
|
|
|
|
scales: {
|
|
|
|
xAxes: [{
|
|
|
|
id: 'x-axis-1',
|
|
|
|
}],
|
|
|
|
yAxes: [{
|
|
|
|
position: 'left',
|
|
|
|
id: 'y-axis-1',
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
data: {
|
|
|
|
datasets: [
|
|
|
|
generateDataset(0, "A", "red"),
|
|
|
|
generateDataset(1, "B", "green"),
|
|
|
|
generateDataset(2, "C", "blue")
|
|
|
|
]
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
readonly property var minimisedConfig: {
|
|
|
|
let config = Object.assign({}, d.lineConfig)
|
|
|
|
config.datasets = [{
|
|
|
|
label: 'Price',
|
|
|
|
xAxisId: 'x-axis-1',
|
|
|
|
yAxisId: 'y-axis-1',
|
|
|
|
backgroundColor: "transparent",
|
|
|
|
borderColor: (Theme.palette.name === "dark") ? 'rgba(136, 176, 255, 1)' : 'rgba(67, 96, 223, 1)',
|
|
|
|
borderWidth: 3,
|
|
|
|
pointRadius: 0,
|
|
|
|
data: d.generateData()
|
|
|
|
}]
|
|
|
|
config.options = Object.assign({}, d.lineConfig.options)
|
|
|
|
|
|
|
|
config.options.scales = {
|
|
|
|
xAxes: [{
|
|
|
|
id: 'x-axis-1',
|
|
|
|
display: false
|
|
|
|
}],
|
|
|
|
yAxes: [{
|
|
|
|
id: 'y-axis-1',
|
|
|
|
display: false
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
return config;
|
|
|
|
}
|
|
|
|
|
|
|
|
readonly property var dataLabelsConfig: {
|
|
|
|
|
|
|
|
var DATA_COUNT = 8;
|
|
|
|
var labels = [];
|
|
|
|
|
|
|
|
for (var i = 0; i < DATA_COUNT; ++i) {
|
|
|
|
labels.push('' + i);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
type: 'line',
|
|
|
|
labels: labels,
|
|
|
|
datasets: [{
|
|
|
|
backgroundColor: "blue",
|
|
|
|
borderColor: "green",
|
|
|
|
data: [5, 10, 15, 10, 5, 0, 5, 10],
|
|
|
|
datalabels: {
|
|
|
|
align: 'start',
|
|
|
|
anchor: 'start'
|
|
|
|
}
|
|
|
|
}, {
|
|
|
|
backgroundColor:"red",
|
|
|
|
borderColor:"orance",
|
|
|
|
data: [58, 80, 60, 70, 50, 60, 70, 80],
|
|
|
|
}, {
|
|
|
|
backgroundColor: "yellow",
|
|
|
|
borderColor: "green",
|
|
|
|
data: [30, 40, 30, 40, 30, 40, 30, 40],
|
|
|
|
datalabels: {
|
|
|
|
align: 'end',
|
|
|
|
anchor: 'end'
|
|
|
|
}
|
|
|
|
}],
|
|
|
|
options: {
|
|
|
|
plugins: {
|
|
|
|
datalabels: {
|
|
|
|
backgroundColor: "red",
|
|
|
|
borderRadius: 4,
|
|
|
|
color: 'white',
|
|
|
|
font: {
|
|
|
|
weight: 'bold',
|
|
|
|
size: 12
|
|
|
|
},
|
|
|
|
formatter: Math.round,
|
|
|
|
padding: 6
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
// Core options
|
|
|
|
aspectRatio: 5 / 3,
|
|
|
|
layout: {
|
|
|
|
padding: {
|
|
|
|
top: 32,
|
|
|
|
right: 16,
|
|
|
|
bottom: 16,
|
|
|
|
left: 8
|
|
|
|
}
|
|
|
|
},
|
|
|
|
elements: {
|
|
|
|
line: {
|
|
|
|
fill: false
|
|
|
|
}
|
|
|
|
},
|
|
|
|
scales: {
|
|
|
|
yAxes: [{
|
|
|
|
stacked: true
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
StatusMenu {
|
|
|
|
id: toolTip
|
|
|
|
width: 243 //By design
|
2024-10-15 19:26:12 +00:00
|
|
|
topPadding: Theme.padding
|
2024-06-04 10:08:16 +00:00
|
|
|
bottomPadding: topPadding
|
|
|
|
leftPadding: topPadding
|
|
|
|
rightPadding: topPadding
|
|
|
|
parent: Overlay.overlay
|
|
|
|
property alias text: label.text
|
|
|
|
Label {
|
|
|
|
id: label
|
|
|
|
text: "Tooltip"
|
|
|
|
anchors.centerIn: parent
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Item {
|
|
|
|
SplitView.fillWidth: true
|
|
|
|
SplitView.fillHeight: true
|
|
|
|
|
|
|
|
StatusChartPanel {
|
|
|
|
id: graphDetail
|
|
|
|
height: 290
|
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.leftMargin: 24
|
|
|
|
anchors.right: parent.right
|
|
|
|
anchors.rightMargin: 24
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
graphsModel: d.graphTabsModel
|
|
|
|
timeRangeModel: d.timeRangeTabsModel
|
|
|
|
chart.type: d.lineConfig.type
|
|
|
|
chart.labels: d.lineConfig.labels
|
|
|
|
chart.datasets: d.lineConfig.datasets
|
|
|
|
chart.options: d.lineConfig.options
|
2024-03-06 12:27:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LogsAndControlsPanel {
|
|
|
|
id: logsAndControlsPanel
|
|
|
|
|
|
|
|
SplitView.minimumHeight: 100
|
|
|
|
SplitView.preferredHeight: 150
|
2024-06-04 10:08:16 +00:00
|
|
|
|
|
|
|
ComboBox {
|
|
|
|
id: chartType
|
|
|
|
model: d.lineConfig ? ["line", "bar", "with crosshair", "line minimised", "data labels"] : []
|
|
|
|
currentIndex: 0
|
|
|
|
onCurrentTextChanged: {
|
|
|
|
if (chartType.currentText === "line") {
|
|
|
|
graphDetail.chart.type = d.lineConfig.type;
|
|
|
|
graphDetail.chart.labels = d.lineConfig.labels;
|
|
|
|
graphDetail.chart.datasets = d.lineConfig.datasets;
|
|
|
|
graphDetail.chart.options = d.lineConfig.options;
|
|
|
|
graphDetail.chart.plugins = []
|
|
|
|
graphDetail.chart.rebuild();
|
|
|
|
} else if (chartType.currentText === "bar") {
|
|
|
|
graphDetail.chart.type = d.barConfig.type;
|
|
|
|
graphDetail.chart.labels = d.barConfig.labels;
|
|
|
|
graphDetail.chart.datasets = d.barConfig.datasets;
|
|
|
|
graphDetail.chart.options = d.barConfig.options;
|
|
|
|
graphDetail.chart.plugins = []
|
|
|
|
graphDetail.chart.rebuild();
|
|
|
|
} else if (chartType.currentText === "with crosshair") {
|
|
|
|
graphDetail.chart.type = d.crosshairConfig.type;
|
|
|
|
graphDetail.chart.options = d.crosshairConfig.options;
|
|
|
|
graphDetail.chart.datasets = d.crosshairConfig.data.datasets;
|
|
|
|
graphDetail.chart.plugins = []
|
|
|
|
graphDetail.chart.rebuild();
|
|
|
|
} else if (chartType.currentText === "line minimised") {
|
|
|
|
graphDetail.chart.type = d.minimisedConfig.type;
|
|
|
|
graphDetail.chart.labels = d.minimisedConfig.labels;
|
|
|
|
graphDetail.chart.datasets = d.minimisedConfig.datasets;
|
|
|
|
graphDetail.chart.options = d.minimisedConfig.options;
|
|
|
|
graphDetail.chart.plugins = []
|
|
|
|
graphDetail.chart.rebuild();
|
|
|
|
} else if (chartType.currentText === "data labels") {
|
|
|
|
graphDetail.chart.type = d.dataLabelsConfig.type;
|
|
|
|
graphDetail.chart.datasets = d.dataLabelsConfig.datasets;
|
|
|
|
graphDetail.chart.labels = d.dataLabelsConfig.labels;
|
|
|
|
graphDetail.chart.options = d.dataLabelsConfig.options;
|
|
|
|
graphDetail.chart.plugins = [graphDetail.chart.availablePlugins.datalabels]
|
|
|
|
graphDetail.chart.rebuild();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-03-06 12:27:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// category: Panels
|