I am trying to know how PathView works. I follow the official doc to write some sample code, the code work well but the final result is not what I wanted?
The Code
import QtQuick
Rectangle {
id: root
border.color: "blue"
Component {
id: theDele
Rectangle {
id: rect
color: Qt.rgba(Math.random(), Math.random(),Math.random(), 1)
visible: PathView.onPath
width: 50; height: 50
scale: PathView.itemScale
rotation: PathView.itemAngle
property var rotX: PathView.itemAngle
transform: [
Translate {x: 25; y: 25}
]
Text {
anchors.centerIn: parent
text: index + "ABC"
}
}
}
PathView {
anchors.fill: parent
model: 100
pathItemCount: 10
delegate: theDele
path: Path {
startX: 0; startY: 100
PathAttribute {name: "itemAngle"; value: -90}
PathAttribute {name: "itemScale"; value: 0.5}
PathLine {x: 300; y: 100}
PathPercent {value: 0.2}
PathAttribute {name: "itemAngle"; value: 0}
PathAttribute {name: "itemScale"; value: 1}
PathLine {x: 300; y: 500}
PathPercent {value: 0.8}
PathAttribute {name: "itemAngle"; value: 90}
PathAttribute {name: "itemScale"; value: 0.5}
PathLine {x: 600; y: 500}
PathPercent { value: 1 }
}
}
}
I want work like this
In this demo, I try to draw three PathLine; 1st Line proportion is
0.2; 2nd Line proportion is 0.8;3rd Line proportion is 0.2.
So 1st Line should have 2 Items; 2nd Line should have 6 Items, and 3rd Line should have 2 Items. But This demo 2nd Line has 7 Items?
And 1st Line of all Items should scale 0.5, and rotate -90, And 2nd Line of all Items should scale 1, and rotate 0, And 3rd Line of all Items should scale 0.5, and rotate 90, But the demo items seem to scale and rotate linearly ?
Related
I need scale and rotate a Rectangle around mouse point. When the Rectangle is not rotated my solution works fine, but if I apply Rotation transform I face the problem - my Rectangle move to an unexpected point. In my solution I use a MouseArea for drag the Rectangle, Scale and Rotation transforms for scale and rotate.
import QtQuick 2.0
Rectangle {
id: root
color: "gray"
Rectangle {
color: "black"
width: 360
height: 200
opacity: 0.5
x: 500
y: 350
}
Rectangle {
id: sample
color: "green"
width: 360
height: 200
opacity: 0.5
x: 500
y: 350
property real currX: 0
property real currY: 0
property real currZoom: 1
property real maxZoom: 5
property real minZoom: 0.5
transform: [
Scale {
id: scaler
origin.x: sample.currX
origin.y: sample.currY
xScale: sample.currZoom
yScale: sample.currZoom
},
Rotation{
id: rotation
origin.x: 180
origin.y: 100
angle: 30
}
]
MouseArea{
id: mouseArea
anchors.fill: parent
drag.target: sample
onClicked: mouse => {
zoom(true, mouse.x, mouse.y)
}
onWheel: (wheel) => {
var isIn = wheel.angleDelta.y > 0
zoom(isIn, wheel.x, wheel.y)
}
function zoom(isIn, x, y) {
var prevZoom = sample.currZoom
var prevX = sample.currX
var prevY = sample.currY
sample.currX = x
sample.currY = y
sample.currZoom = calculateZoom(isIn, prevZoom)
sample.x = sample.x + (prevX - sample.currX) * (1 - prevZoom)
sample.y = sample.y + (prevY - sample.currY) * (1 - prevZoom)
printSamplePostion()
}
function calculateZoom(isIn, prevZoom) {
var newZoom = isIn ? prevZoom + 0.1 : prevZoom - 0.1
if (newZoom > mouseArea.maxZoom)
newZoom = mouseArea.maxZoom
if (newZoom < mouseArea.minZoom)
newZoom = mouseArea.minZoom
return newZoom
}
function printSamplePostion() {
console.log("== x: 500 y: 350 ======")
console.log("-- x: " + sample.x)
console.log("-- y: " + sample.y)
console.log("=======================")
}
}
}
}
Thanks in advance
UPDATE 1 - i can get it to work using Javascript - but that seems to be a little bit unoptimized (from 2-3% to 30% load with qmlscene.exe when activated) - complete recreation when the model changes (its not ever growing), is that the only way or is there a more "declarative" style available?
How can i add a PathLine to a ShapePath based on a Model?
i know how to use a Repeater from outside of Items but not how to implode them inside of Items
do i need some sort of Repeater-Delegate on pathElements?
and i don't want to use the LineSeries component
import QtQuick.Shapes 1.15
import QtQuick 2.15
Shape {
ListModel {
id: myPositions
ListElement { x: 0; y:38 }
ListElement { x: 10; y: 28 }
ListElement { x: 20; y: 30 }
ListElement { x: 30; y: 14 }
}
ShapePath {
strokeColor: "black"
strokeWidth: 1
fillColor: "transparent"
startX: 0
startY: 0
PathLine { x: 0; y: 38 }
PathLine { x: 10; y: 28 }
PathLine { x: 20; y: 30 }
PathLine { x: 30; y: 14 }
// Repeater {
// model: myPositions
// PathLine { x: model.x; y: model.y }
// }
}
}
UPDATE 1
import QtQuick.Shapes 1.15
import QtQuick 2.15
Shape {
ListModel {
id: myPositions
}
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Timer
{
interval: 100
running: true
repeat: true
property real myX: 0
onTriggered: {
myPositions.append({"x":myX, "y":getRandomInt(0,30)})
myX = myX + 10
}
}
function createPathLineElements(positionsModel, shapePath)
{
var pathElements = []
for (var i = 0; i < positionsModel.count; i++)
{
var pos = myPositions.get(i)
var pathLine = Qt.createQmlObject('import QtQuick 2.15; PathLine {}',
shapePath);
pathLine.x = pos.x
pathLine.y = pos.y
pathElements.push(pathLine)
}
return pathElements
}
ShapePath {
id: myPath
strokeColor: "black"
strokeWidth: 1
fillColor: "transparent"
startX: 0
startY: 0
pathElements: createPathLineElements(myPositions, myPath)
}
}
Use an Instantiator:
Shape {
ListModel {
id: myPositions
}
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Timer {
interval: 100
running: true
repeat: true
property real myX: 0
onTriggered: {
myPositions.append({"x":myX, "y":getRandomInt(0,30)})
myX = myX + 10
}
}
ShapePath {
id: myPath
fillColor: "transparent"
strokeColor: "red"
capStyle: ShapePath.RoundCap
joinStyle: ShapePath.RoundJoin
strokeWidth: 3
strokeStyle: ShapePath.SolidLine
}
Instantiator {
model: myPositions
onObjectAdded: myPath.pathElements.push(object)
PathLine {
x: model.x
y: model.y
}
}
}
You can't use repeater in that element.
The most performant way is to use QQuickItem in order to create a custom Item which draws incremental path.
Yet another simpler ways are:
1- Use PathSvg element and set its path runtime like below:
ShapePath {
fillColor: "transparent"
strokeColor: "red"
capStyle: ShapePath.RoundCap
joinStyle: ShapePath.RoundJoin
strokeWidth: 3
strokeStyle: ShapePath.SolidLine
PathSvg { id: ps; path: parent.p } //<== fill path property using js
property string p: ""
Component.onCompleted: {
for ( var i = 0; i < myModel.count; i++) {
p += "L %1 %2".arg(myModel.get(i).x).arg(myModel.get(i).y);
}
ps.path = p;
}
}
2- If you know steps, so you can pre-declare all PathLines and then set their values runtime. Just like a heart rate line on a health care monitor.
How do I place text at specific (x,y) locations within the plotting area of a QML ChartView type?
For example, I would like to place text at the location XYPoint{x: -3; Y: 20}
I don't want to place at window's(x,y), i want to put at plotting area's (x,y)
I read documentation,but i don't find any property !!!!!!
//ChartView for plotting points
ChartView{
id:chrt
anchors.fill: parent
height: parent.height
width: parent.width
legend.visible: false
backgroundColor: "black"
//X- axis
ValueAxis{
id: x_axis
min: -5
max: 0
tickCount: 6
}
//Right Y axis
ValueAxis{
id:right_y_axis
min:0
max:40
tickCount: 5
}
//Left Y axis
ValueAxis{
id:left_y_axis
min:0
max:40
tickCount: 5
}
//Line series for wave 1
LineSeries{
id:l1
axisY: left_y_axis
axisX:x_axis
color: "yellow"
width: 1
}
//Line series for wave 2
LineSeries{
id:l2
axisYRight: right_y_axis
style: Qt.DashLine
color: "yellow"
width: 0.6
}
}
Ok, you can use ChartView.mapToPosition to calculate the global position of the specified point from a series (or some another point inside the series), for example:
ChartView{
id:chart
anchors.fill: parent
backgroundColor: "black"
LineSeries{
id: series
XYPoint { x: 10; y: 5 }
XYPoint { x: 10; y: 1 }
XYPoint { x: 15; y: 5 }
XYPoint { x: 20; y: 10 }
XYPoint { x: 25; y: 5 }
XYPoint { x: 30; y: 20 }
XYPoint { x: 40; y: 10 }
}
Text {
id: txt
text: "Hello"
color: "white"
}
onWidthChanged: updatePointPosition();
onHeightChanged: updatePointPosition();
function updatePointPosition()
{
var p = chart.mapToPosition(series.at(3), series);
txt.x = p.x;
txt.y = p.y;
}
}
I have set a custom tooltip using the code
ChartView {
id: chart
anchors.fill: parent
antialiasing: true
ValueAxis {
id: axisY
tickCount: 3
}
DateTimeAxis{
id: xTime
gridVisible: false
}
ToolTip {
id: id_toolTip
contentItem: Text{
color: "#21be2b"
}
background: Rectangle {
border.color: "#21be2b"
}
}
SplineSeries{
id: chartseries
pointsVisible: true
pointLabelsVisible: false
useOpenGL: true
axisX: xTime
axisY: axisY
onClicked: {
id_toolTip.show("dd")
}
}
}
It gives an error when I click on the graph ..
TypeError: Property 'show' of object QQuickToolTip(0x37275d0) is not a function"
But below mentioned code will work.
chart.ToolTip.show("dd")
But I need custom tooltip
You can use the other properties as I show below:
ChartView {
id: chart
anchors.fill: parent
antialiasing: true
ValueAxis {
id: axisY
tickCount: 3
max: 4
min: 0
}
DateTimeAxis{
id: xTime
gridVisible: false
}
ToolTip {
id: id_tooltip
contentItem: Text{
color: "#21be2b"
text: id_tooltip.text
}
background: Rectangle {
border.color: "#21be2b"
}
}
SplineSeries{
id: chartseries
XYPoint { x: new Date('December 17, 1995 03:24:00').getTime() ; y: 0.0 }
XYPoint { x: new Date('December 18, 1995 04:25:00').getTime() ; y: 3.2 }
XYPoint { x: new Date('December 19, 1995 05:26:00').getTime() ; y: 2.4 }
XYPoint { x: new Date('December 20, 1995 06:27:00').getTime() ; y: 2.1 }
XYPoint { x: new Date('December 21, 1995 07:24:00').getTime() ; y: 0.0 }
XYPoint { x: new Date('December 22, 1995 08:25:00').getTime() ; y: 3.2 }
XYPoint { x: new Date('December 23, 1995 09:26:00').getTime() ; y: 2.4 }
XYPoint { x: new Date('December 24, 1995 10:27:00').getTime() ; y: 2.1 }
pointsVisible: true
pointLabelsVisible: false
useOpenGL: true
axisX: xTime
axisY: axisY
onClicked: {
var p = chart.mapToPosition(point)
var text = qsTr("x: %1, y: %2").arg(new Date(point.x).toLocaleDateString(Qt.locale("en_US"))).arg(point.y)
id_tooltip.x = p.x
id_tooltip.y = p.y - id_tooltip.height
id_tooltip.text = text
//id_tooltip.timeout = 1000
id_tooltip.visible = true
}
}
}
In the first case, id_toolTip.show("dd") , you try to call the show func of the instantiated version of QML::Tooltip whereas at the second case, chart.ToolTip.show("dd") you call the show function of the attached property Tooltip which exists for all the qml controls.
Acccording to the docs, if you don't provide a second parameter, then this means that show() is the func of the shared tooltip and not the one you instantiate. That might be the reason your code does not work.
How to change color of one particular point in chartview in qml.i.e now all x axis values are displaying in black color but i want odd number to be displayed in red color.I want as shown in image where label colors in y axis are of different colors.
here is my piece of code
ChartView {
id:chartView
width: 2*horizontalList.width
height:horizontalList.height
antialiasing: true
animationOptions: ChartView.SeriesAnimations
legend.visible:false
ValueAxis {
id: scaleAxisX
min: 0
max: pointsX.length
tickCount: pointsX.length+1
labelFormat: "%.0f"
titleVisible: false
gridVisible: true
}
ValueAxis {
id: scaleAxisY
min: 0
max: 1.0
tickCount: 6
//labelFormat: "%.0f"
titleVisible: false
gridVisible: false
labelsVisible: false
labelsColor: "#757575"
}
ScatterSeries {
id: scatterSeries
axisXTop: scaleAxisX
axisY: scaleAxisY
color: "black"
markerSize: 12
}
}
As shown in second image ,the top line with red circle is a X axis(valueAxis) of chartview.i want to make the number inside the red circle to be in red color.
You can add a different ScatterSeries with color value;
import QtQuick 2.0
import QtCharts 2.0
ChartView {
title: "Scatters"
anchors.fill: parent
antialiasing: true
ScatterSeries {
color: "black"
id: scatter1
name: "Scatter1"
XYPoint { x: 1; y: 1 }
XYPoint { x: 2; y: 2 }
XYPoint { x: 3; y: 3 }
XYPoint { x: 4; y: 4 }
}
ScatterSeries {
color: "red"
name: "Scatter2"
XYPoint { x: 1.5; y: 1.5 }
}
}