PDA

View Full Version : Creating a Drag-able Line 2D Chart



marrierius
15th November 2016, 15:00
I want to create a 2D line chart with the properties that

1. point will be enlarged when mouse catches it;
2. point can move up and down with mouse movement and line will change correspondingly.

Is that possible to do it with QChart? What are the main functions/commands to use?

P.S., I am really new to Qt. Any comments/advice will be of great help. Thanks.

d_stranz
15th November 2016, 20:30
QXYSeries (the base class for QLineSeries) has several signals that are emitted when the mouse interacts with a point in the series: clicked(), doubleClicked(), hovered(), pressed(), and released().


1. point will be enlarged when mouse catches it;

Connect a slot to one of the signals described above. Unfortunately, QtCharts does not let you change the color or size properties for a single point in a series; however, you can simulate "enlarging a point" by temporarily creating a QScatterSeries with a single point in it that has the same coordinates as the point that was selected. Display this new series while you are moving the point with the mouse, and set the scatter and selected point coordinates to be the same.


2. point can move up and down with mouse movement and line will change correspondingly.

This is harder, since the line series is not a QGraphicsItem and so it does not emit mouse interaction signals. You could implement an event handler in the window that holds the QChart (maybe your QMainWindow), and install that handler on the QChart. Listen for mouseMoveEvent (QGraphicsItem::mouseMoveEvent()). If you receive this event following the signal from the line series, then move the line point and the scatter point to the new position given in the event. You do this by calling QXYSeries::replace() with the new position of both points. The line and scatter points will automatically be redrawn.

The Qt Charts Diagram example (http://doc.qt.io/qt-5/qtwidgets-graphicsview-diagramscene-example.html) might also be of help. It is unfortunate that most of the examples given for Qt Chart create static charts. The Scatter Interactions example (http://doc.qt.io/qt-5/qtcharts-scatterinteractions-example.html) shows a simple way to connect to a clicked signal in a scatter series and then do something with the point that was selected.

marrierius
7th December 2016, 22:22
Thank you. It helps a lot.

pbljung
12th May 2017, 20:54
Here is QML that lets you move points to control the line shape. This draws a ScatterSeries for the line's markers, a SplineSeries for the line's curve, and 4 ScatterSeries to manipulate the selected line point. Clicking on a line's marker will highlight it. Clicking on the manipulation markers will move the highlighted point. Works fine on Qt 5.8.


import QtQuick 2.0
import QtCharts 2.2

Item {
width: 400
height: 300


property point selectedPoint : {}
property int selectedIndex : 0

ChartView {
id: chartView
anchors.fill: parent
legend.visible: false
antialiasing: true


SplineSeries {
id: scatterSeries0
color: "blue";
width: 3

XYPoint { x: 0; y: 0}
XYPoint { x: 0.2; y: 0.2}
XYPoint { x: 0.4; y: 0.4 }
XYPoint { x: 0.6; y: 0.6 }
XYPoint { x: 0.8; y: 0.8 }
XYPoint { x: 1; y: 1}

}

ScatterSeries {
id: scatterSeries1
color: "blue";
markerSize: 25
//borderWidth: 0
borderColor: "blue"

// nodes on top of lineseries
function findindex(p1) {
console.log("p1:"+p1)
var minDist = 100
var minIndex = -1
for (var i=0; i<scatterSeries1.count; i++) {
var p = scatterSeries1.at(i)
console.log("p:"+p)
var d = Math.sqrt(Math.pow(p.x-p1.x,2)+Math.pow(p.y-p1.y,2))
console.log("d:"+d)
if (d < minDist) { minDist = d; minIndex = i }
}
console.log("minIndex:"+minIndex+" minDist:"+minDist)
return minIndex
}

XYPoint { x: 0; y: 0}
XYPoint { x: 0.2; y: 0.2}
XYPoint { x: 0.4; y: 0.4 }
XYPoint { x: 0.6; y: 0.6 }
XYPoint { x: 0.8; y: 0.8 }
XYPoint { x: 1; y: 1}

onClicked: {
console.log("scatter onClicked: " + point);
selectedIndex = findindex(point)
selectedPoint = scatterSeries1.at(selectedIndex)

console.log("map:"+chartView.mapToPosition(selectedPoint, scatterSeries1))

scatterSeriesHighlight.clear()
scatterSeriesHighlight.append(selectedPoint.x, selectedPoint.y)

}


Component.onCompleted: scatterSeries0.clone()
}



ScatterSeries {
id: scatterSeriesHighlight
color: "#80FF0000";
markerSize: 50
}

ScatterSeries {
id: scatterSeriesTop
color: "#80808080";
markerSize: 50
markerShape: ScatterSeries.MarkerShapeRectangle
onPressed: color = "#80101010"
onReleased: color = "#80808080"

XYPoint { x: 0.5; y:0.9 }

onClicked: {

console.log("top onclicked")

scatterSeries1.remove(selectedIndex)
selectedPoint.y=selectedPoint.y+0.1
scatterSeries1.insert(selectedIndex, selectedPoint.x, selectedPoint.y)

scatterSeries0.remove(selectedIndex)
scatterSeries0.insert(selectedIndex, selectedPoint.x, selectedPoint.y)

scatterSeriesHighlight.clear()
scatterSeriesHighlight.append(selectedPoint.x, selectedPoint.y)
}
}

ScatterSeries {
id: scatterSeriesBottom
color: "#80808080";
markerSize: 50
markerShape: ScatterSeries.MarkerShapeRectangle
onPressed: color = "#80101010"
onReleased: color = "#80808080"

XYPoint { x: 0.5; y:0.1 }

onClicked: {

console.log("bottom onclicked")
scatterSeries1.remove(selectedIndex)
selectedPoint.y=selectedPoint.y-0.1
scatterSeries1.insert(selectedIndex, selectedPoint.x, selectedPoint.y)

scatterSeries0.remove(selectedIndex)
scatterSeries0.insert(selectedIndex, selectedPoint.x, selectedPoint.y)

scatterSeriesHighlight.clear()
scatterSeriesHighlight.append(selectedPoint.x, selectedPoint.y)
}

}

ScatterSeries {
id: scatterSeriesLeft
color: "#80808080";
markerSize: 50
markerShape: ScatterSeries.MarkerShapeRectangle
onPressed: color = "#80101010"
onReleased: color = "#80808080"

XYPoint { x: 0.1; y:0.5 }


onClicked: {

console.log("left onclicked")

scatterSeries1.remove(selectedIndex)
selectedPoint.x=selectedPoint.x-0.1
scatterSeries1.insert(selectedIndex, selectedPoint.x, selectedPoint.y)

scatterSeries0.remove(selectedIndex)
scatterSeries0.insert(selectedIndex, selectedPoint.x, selectedPoint.y)

scatterSeriesHighlight.clear()
scatterSeriesHighlight.append(selectedPoint.x, selectedPoint.y)
}
}

ScatterSeries {
id: scatterSeriesRight
color: "#80808080";
markerSize: 50
markerShape: ScatterSeries.MarkerShapeRectangle
onPressed: color = "#80101010"
onReleased: color = "#80808080"

XYPoint { x: 0.9; y:0.5 }

onClicked: {

console.log("right onclicked")

scatterSeries1.remove(selectedIndex)
selectedPoint.x=selectedPoint.x+0.1
scatterSeries1.insert(selectedIndex, selectedPoint.x, selectedPoint.y)

scatterSeries0.remove(selectedIndex)
scatterSeries0.insert(selectedIndex, selectedPoint.x, selectedPoint.y)

scatterSeriesHighlight.clear()
scatterSeriesHighlight.append(selectedPoint.x, selectedPoint.y)
}
}

}

}