/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Data Visualization module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.1
import QtDataVisualization 1.1
import "."
Item {
id: mainViewwidth: 800height: 600visible: true
property intselectedAxisLabel: -1
property realdragSpeedModifier: 100.0
property intcurrentMouseX: -1
property intcurrentMouseY: -1
property intpreviousMouseX: -1
property intpreviousMouseY: -1ListModel {
id: graphModelListElement{ xPos: 0.0; yPos: 0.0; zPos: 0.0; rotation: "@0,0,0,0" }
ListElement{ xPos: 1.0; yPos: 1.0; zPos: 1.0; rotation: "@45,1,1,1" }
}
Timer {
id: dataTimerinterval: 1running: truerepeat: true
property boolisIncreasing: true
property realrotationAngle: 0functiongenerateQuaternion() {
return"@"+Math.random() *360+","+Math.random() +","+Math.random() +","+Math.random()
}
functionappendRow() {
graphModel.append({"xPos": Math.random(),
"yPos": Math.random(),
"zPos": Math.random(),
"rotation": generateQuaternion()
});
}
onTriggered: {
rotationAngle=rotationAngle+1qtCube.setRotationAxisAndAngle(Qt.vector3d(1,0,1), rotationAngle)
scatterSeries.setMeshAxisAndAngle(Qt.vector3d(1,1,1), rotationAngle)
if (isIncreasing) {
for (var i = 0; i<10; i++)
appendRow()
if (graphModel.count>2002) {
scatterGraph.theme=isabelleThemeisIncreasing=false
}
} else {
graphModel.remove(2, 10);
if (graphModel.count==2) {
scatterGraph.theme=dynamicColorThemeisIncreasing=true
}
}
}
}
ThemeColor {
id: dynamicColor
ColorAnimation on color {
from: "red"to: "yellow"duration: 2000loops: Animation.Infinite
}
}
Theme3D {
id: dynamicColorThemetype: Theme3D.ThemeEbonybaseColors: [dynamicColor]
font.pointSize: 50labelBorderEnabled: truelabelBackgroundColor: "gold"labelTextColor: "black"
}
Theme3D {
id: isabelleThemetype: Theme3D.ThemeIsabellefont.pointSize: 50labelBorderEnabled: truelabelBackgroundColor: "gold"labelTextColor: "black"
}
Item {
id: dataViewanchors.bottom: parent.bottomwidth: parent.widthheight: parent.heightScatter3D {
id: scatterGraphinputHandler: nullwidth: dataView.widthheight: dataView.heighttheme: dynamicColorThemeshadowQuality: AbstractGraph3D.ShadowQualityLowscene.activeCamera.yRotation: 45.0scene.activeCamera.xRotation: 45.0scene.activeCamera.zoomLevel: 75.0Scatter3DSeries {
id: scatterSeriesitemLabelFormat: "X:@xLabel Y:@yLabel Z:@zLabel"mesh: Abstract3DSeries.MeshCubeItemModelScatterDataProxy {
itemModel: graphModelxPosRole: "xPos"yPosRole: "yPos"zPosRole: "zPos"rotationRole: "rotation"
}
}
customItemList: [
Custom3DItem {
id: qtCubemeshFile: ":/mesh/cube"textureFile: ":/texture/texture"position: Qt.vector3d(0.65,0.35,0.65)
scaling: Qt.vector3d(0.3,0.3,0.3)
}
]
onSelectedElementChanged: {
if (selectedElement>=AbstractGraph3D.ElementAxisXLabel&&selectedElement<=AbstractGraph3D.ElementAxisZLabel)
selectedAxisLabel=selectedElementelseselectedAxisLabel= -1
}
}
MouseArea {
anchors.fill: parenthoverEnabled: trueacceptedButtons: Qt.LeftButtononPositionChanged: {
currentMouseX=mouse.x;
currentMouseY=mouse.y;
if (pressed&&selectedAxisLabel!= -1)
dragAxis();
previousMouseX=currentMouseX;
previousMouseY=currentMouseY;
}
onPressed: {
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 timeselectedAxisLabel= -1currentMouseX= -1currentMouseY= -1previousMouseX= -1previousMouseY= -1
}
}
}
functiondragAxis() {
// Do nothing if previous mouse position is uninitializedif (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 axesswitch (selectedAxisLabel) {
caseAbstractGraph3D.ElementAxisXLabel:
var distance = ((moveX-moveY) *cameraMultiplier) /dragSpeedModifier// Check if we need to change min or max first to avoid invalid rangesif (distance>0) {
scatterGraph.axisX.min-=distancescatterGraph.axisX.max-=distance
} else {
scatterGraph.axisX.max-=distancescatterGraph.axisX.min-=distance
}
breakcaseAbstractGraph3D.ElementAxisYLabel:
distance=moveY/dragSpeedModifier// Check if we need to change min or max first to avoid invalid rangesif (distance>0) {
scatterGraph.axisY.max+=distancescatterGraph.axisY.min+=distance
} else {
scatterGraph.axisY.min+=distancescatterGraph.axisY.max+=distance
}
breakcaseAbstractGraph3D.ElementAxisZLabel:
distance= ((moveX+moveY) *cameraMultiplier) /dragSpeedModifier// Check if we need to change min or max first to avoid invalid rangesif (distance>0) {
scatterGraph.axisZ.max+=distancescatterGraph.axisZ.min+=distance
} else {
scatterGraph.axisZ.min+=distancescatterGraph.axisZ.max+=distance
}
break
}
}
NewButton {
id: rangeTogglewidth: parent.width/3// We're adding 3 buttons and want to divide them equallytext: "Use Preset Range"anchors.left: parent.left
property boolautoRange: trueonClicked: {
if (autoRange) {
text="Use Automatic Range"scatterGraph.axisX.min=0.3scatterGraph.axisX.max=0.7scatterGraph.axisY.min=0.3scatterGraph.axisY.max=0.7scatterGraph.axisZ.min=0.3scatterGraph.axisZ.max=0.7autoRange=falsedragSpeedModifier=200.0
} else {
text="Use Preset Range"autoRange=truedragSpeedModifier=100.0
}
scatterGraph.axisX.autoAdjustRange=autoRangescatterGraph.axisY.autoAdjustRange=autoRangescatterGraph.axisZ.autoAdjustRange=autoRange
}
}
NewButton {
id: orthoTogglewidth: parent.width/3text: "Display Orthographic"anchors.left: rangeToggle.rightonClicked: {
if (scatterGraph.orthoProjection) {
text="Display Orthographic";
scatterGraph.orthoProjection=false// Orthographic projection disables shadows, so we need to switch them back onscatterGraph.shadowQuality=AbstractGraph3D.ShadowQualityLow
} else {
text="Display Perspective";
scatterGraph.orthoProjection=true
}
}
}
NewButton {
id: exitButtonwidth: parent.width/3text: "Quit"anchors.left: orthoToggle.rightonClicked: Qt.quit(0);
}
}