Files
scheincommander/Devices3dView.qml

230 lines
7.6 KiB
QML

import QtQuick
import QtDataVisualization
import QtQuick.Controls
Item {
property int selectedAxisLabel: -1
property real dragSpeedModifier: 25.0
property int currentMouseX: -1
property int currentMouseY: -1
property int previousMouseX: -1
property int previousMouseY: -1
property alias model: itemModelScatterDataProxy.itemModel
property alias selectedItem: scatterSeries.selectedItem
// ThemeColor {
// id: dynamicColor
// ColorAnimation on color {
// from: "red"
// to: "yellow"
// duration: 2000
// loops: Animation.Infinite
// }
// }
Theme3D {
id: dynamicColorTheme
type: Theme3D.ThemeEbony
// baseColors: [dynamicColor]
font.pointSize: 50
labelBorderEnabled: true
labelBackgroundColor: "gold"
labelTextColor: "black"
}
Theme3D {
id: isabelleTheme
type: Theme3D.ThemeIsabelle
font.pointSize: 50
labelBorderEnabled: true
labelBackgroundColor: "gold"
labelTextColor: "black"
}
Item {
id: dataView
anchors.bottom: parent.bottom
width: parent.width
height: parent.height
//! [0]
Scatter3D {
id: scatterGraph
inputHandler: null
width: dataView.width
height: dataView.height
theme: isabelleTheme
shadowQuality: AbstractGraph3D.ShadowQualityLow
scene.activeCamera.yRotation: 45.0
scene.activeCamera.xRotation: 45.0
scene.activeCamera.zoomLevel: 75.0
axisX.min: -10
axisX.max: 10
axisY.min: -10
axisY.max: 10
axisZ.min: -10
axisZ.max: 10
Scatter3DSeries {
id: scatterSeries
itemLabelFormat: "X:@xLabel Y:@yLabel Z:@zLabel"
mesh: Abstract3DSeries.MeshCube
ItemModelScatterDataProxy {
id: itemModelScatterDataProxy
xPosRole: "positionX"
yPosRole: "positionY"
zPosRole: "positionZ"
//rotationRole: "rotation"
}
}
onSelectedElementChanged: {
switch (selectedElement) {
case Scatter3D.ElementSeries:
// console.log('series');
break;
case Scatter3D.ElementAxisXLabel:
case Scatter3D.ElementAxisYLabel:
case Scatter3D.ElementAxisZLabel:
// console.log('axis');
if (selectedElement >= AbstractGraph3D.ElementAxisXLabel
&& selectedElement <= AbstractGraph3D.ElementAxisZLabel)
selectedAxisLabel = selectedElement
else
selectedAxisLabel = -1
break;
}
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton
onPositionChanged: (mouse)=> {
currentMouseX = mouse.x;
currentMouseY = mouse.y;
if (pressed && selectedAxisLabel != -1)
dragAxis();
previousMouseX = currentMouseX;
previousMouseY = currentMouseY;
}
onPressed: (mouse)=> {
scatterGraph.scene.selectionQueryPosition = Qt.point(mouse.x, mouse.y);
}
onReleased: {
// We need to clear mouse positions and selected axis, because touch devices cannot
// track position all the time
selectedAxisLabel = -1
currentMouseX = -1
currentMouseY = -1
previousMouseX = -1
previousMouseY = -1
}
}
}
function dragAxis() {
// Do nothing if previous mouse position is uninitialized
if (previousMouseX === -1)
return
// Directional drag multipliers based on rotation. Camera is locked to 45 degrees, so we
// can use one precalculated value instead of calculating xx, xy, zx and zy individually
var cameraMultiplier = 0.70710678
// Calculate the mouse move amount
var moveX = currentMouseX - previousMouseX
var moveY = currentMouseY - previousMouseY
// Adjust axes
switch (selectedAxisLabel) {
case AbstractGraph3D.ElementAxisXLabel:
var distance = ((moveX - moveY) * cameraMultiplier) / dragSpeedModifier
// Check if we need to change min or max first to avoid invalid ranges
if (distance > 0) {
scatterGraph.axisX.min -= distance
scatterGraph.axisX.max -= distance
} else {
scatterGraph.axisX.max -= distance
scatterGraph.axisX.min -= distance
}
break
case AbstractGraph3D.ElementAxisYLabel:
distance = moveY / dragSpeedModifier
// Check if we need to change min or max first to avoid invalid ranges
if (distance > 0) {
scatterGraph.axisY.max += distance
scatterGraph.axisY.min += distance
} else {
scatterGraph.axisY.min += distance
scatterGraph.axisY.max += distance
}
break
case AbstractGraph3D.ElementAxisZLabel:
distance = ((moveX + moveY) * cameraMultiplier) / dragSpeedModifier
// Check if we need to change min or max first to avoid invalid ranges
if (distance > 0) {
scatterGraph.axisZ.max += distance
scatterGraph.axisZ.min += distance
} else {
scatterGraph.axisZ.min += distance
scatterGraph.axisZ.max += distance
}
break
}
}
Button {
id: rangeToggle
width: parent.width / 2 // We're adding 3 buttons and want to divide them equally
text: "Use Preset Range"
anchors.left: parent.left
property bool autoRange: true
onClicked: {
if (autoRange) {
text = "Use Automatic Range"
scatterGraph.axisX.min = -10
scatterGraph.axisX.max = 10
scatterGraph.axisY.min = -10
scatterGraph.axisY.max = 10
scatterGraph.axisZ.min = -10
scatterGraph.axisZ.max = 10
autoRange = false
dragSpeedModifier = 25.0
} else {
text = "Use Preset Range"
autoRange = true
dragSpeedModifier = 25.0
}
scatterGraph.axisX.autoAdjustRange = autoRange
scatterGraph.axisY.autoAdjustRange = autoRange
scatterGraph.axisZ.autoAdjustRange = autoRange
}
}
Button {
id: orthoToggle
width: parent.width / 2
text: "Display Orthographic"
anchors.left: rangeToggle.right
onClicked: {
if (scatterGraph.orthoProjection) {
text = "Display Orthographic";
scatterGraph.orthoProjection = false
// Orthographic projection disables shadows, so we need to switch them back on
scatterGraph.shadowQuality = AbstractGraph3D.ShadowQualityLow
} else {
text = "Display Perspective";
scatterGraph.orthoProjection = true
}
}
}
}