ChartView not showing BarSets data - qt

in qml, i create a ChartView:
ChartView {
id : mChart
title: "Bash History Graph"
anchors.fill: parent
legend.alignment: Qt.AlignBottom
antialiasing: true
animationOptions: ChartView.SeriesAnimations
}
and in Component.onCompleted signal:
Component.onCompleted: {
var mHorSeries = Qt.createQmlObject('import QtCharts 2.2; HorizontalBarSeries {}', mChart);
var categoryAxisY=Qt.createQmlObject('import QtCharts 2.2;BarCategoryAxis {}',mChart);
var mBarSet = Qt.createQmlObject('import QtCharts 2.2; BarSet{}',mHorSeries);
categoryAxisY.categories = ["2007", "2008", "2009", "2010"];
mHorSeries.append("commands", [2, 2, 3, 4, 5, 6]);
mChart.setAxisY(categoryAxisY, mHorSeries);
}
this is the output.
any idea to fix the issue?
thanks.

A simple option to create series is to use createSeries(), then we add the axisY and the other properties:
ChartView {
id : mChart
title: "Bash History Graph"
anchors.fill: parent
antialiasing: true
animationOptions: ChartView.SeriesAnimations
legend.alignment: Qt.AlignBottom
Component.onCompleted: {
var mHorSeries = mChart.createSeries(ChartView.SeriesTypeHorizontalBar)
var categoryAxisY=Qt.createQmlObject('import QtCharts 2.2;BarCategoryAxis {}',mChart);
mHorSeries.axisY = categoryAxisY
categoryAxisY.categories = ["2007", "2008", "2009", "2010", "2011", "2012" ]
var mBarSet = mHorSeries.append("commands", [2, 2, 3, 4, 5, 6])
mChart.axisX(mHorSeries).min= 0 //Math.min.apply(null, mBarSet.values)
mChart.axisX(mHorSeries).max= 10 //Math.max.apply(null, mBarSet.values)
}
}

Related

y-Axis Maximum in QML BarSeries Not Updating

I'm using a QML BarSeries to display some data and encountered a problem: the y-axis of the BarSeries doesn't update automatically.
Below is an mcve copied and modified from the BarSeries docs. It updates the bar series when the user clicks on the background.
// main.qml
import QtQuick 2.6
import QtQuick.Window 2.2
import QtCharts 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ChartView {
id: chartView
title: "Bar series"
anchors.fill: parent
legend.alignment: Qt.AlignBottom
antialiasing: true
BarSeries {
id: mySeries
axisX: BarCategoryAxis { categories: ["2007", "2008", "2009", "2010", "2011", "2012" ] }
BarSet { label: "Bob"; values: [2, 2, 3, 4, 5, 6] }
BarSet { label: "Susan"; values: [5, 1, 2, 4, 1, 7] }
BarSet { label: "James"; values: [3, 5, 8, 13, 5, 8] }
}
}
MouseArea {
anchors.fill: parent
onClicked: {
mySeries.clear(); // clear previous sets
// update with new sets
mySeries.append("Bob", [3, 5, 8, 13, 5, 8]);
mySeries.append("Susan", [2, 2, 3, 4, 5, 200]);
mySeries.append("James", [5, 1, 2, 4, 1, 7]);
}
}
}
From the code, we could see that the click on the mouse area should update the series to have a y-axis of up to 200 (due to Susan's new set of values).
The screenshots below show the columns updating but not the y-axis. (Note that I'm expecting the y-axis maximum to update to 200.)
Before the mouse click:
After the mouse click:
What changes should I make to update the maximum of the chart's y-axis?
After the multiple mySeries.append statements in MouseArea::onClicked, I tried doing chartView.update() but this worked to no avail.
I searched and researched but found nothing. Most answers from the web concern only QtCharts run from C++ or describe a different issue (unless I searched with the wrong keywords?).
For completeness, here's the main.cpp file:
#include <QApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv); // needs QT += widgets in qmake
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
I was able to solve this issue by attaching a custom ValueAxis to the BarSeries and manually, programmatically updating the new maximum with the ValueAxis::max property.
import QtQuick 2.6
import QtQuick.Window 2.2
import QtCharts 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ChartView {
id: chartView
title: "Bar series"
anchors.fill: parent
legend.alignment: Qt.AlignBottom
antialiasing: true
BarSeries {
id: mySeries
axisX: BarCategoryAxis { categories: ["2007", "2008", "2009", "2010", "2011", "2012" ] }
axisY: ValueAxis { // <- custom ValueAxis attached to the y-axis
id: valueAxis
}
BarSet { label: "Bob"; values: [2, 2, 3, 4, 5, 6] }
BarSet { label: "Susan"; values: [5, 1, 2, 4, 1, 7] }
BarSet { label: "James"; values: [3, 5, 8, 13, 5, 8] }
}
}
MouseArea {
anchors.fill: parent
onClicked: {
mySeries.clear();
mySeries.append("Bob", [3, 5, 8, 13, 5, 8]);
mySeries.append("Susan", [2, 2, 3, 4, 5, 200]);
mySeries.append("James", [5, 1, 2, 4, 1, 7]);
valueAxis.max = 200; // hard-code a new maximum
}
}
}
This works splendidly. Here's what the chart now looks like after a click on the background:
Here's a solution that dynamically calculates the new maximum (only the onClicked slot is shown, for brevity):
onClicked: {
mySeries.clear();
mySeries.append("Bob", [3, 5, 8, 13, 5, 8]);
mySeries.append("Susan", [2, 2, 3, 4, 5, 200]);
mySeries.append("James", [5, 1, 2, 4, 1, 7]);
// deduce the new min and max
var min = 1e8, max = -1e8;
for (var i = 0; i < mySeries.count; i++) {
// min = Math.min(min, ...mySeries.at(i).values); // modern js not yet supported?
// max = Math.min(max, ...mySeries.at(i).values);
min = Math.min(min, mySeries.at(i).values.reduce(function(a,b) {
return Math.min(a, b);
}));
max = Math.max(max, mySeries.at(i).values.reduce(function(a,b) {
return Math.max(a, b);
}));
}
// set the new min and max
valueAxis.min = min;
valueAxis.max = max;
// valueAxis.max = max * 1.05; // or give a little margin?
}
Of course, the minimum could be left out of the picture, but that entirely depends on your data and situation.

Mixed / complex text node inc FontAwsome for buttons and tags

I needed to make buttons and labels with a mixture of Arial and Fontawsome. The HTML 5 canvas is relatively crude in terms of any mixing of fonts, and though Konvajs has the convenience Label shape it does not accommodate Shapes other than a single text node, as far as I can see. Take a look at my answer snippet to see what I wanted, and how I solved it.
Here is my solution. The only trick is the centering of the text for which we have to use the shape.getWidth() method and store the total width and width of each element for final positioning.
Seems to work.
var s1 = new Konva.Stage({container: 'container1', width: 200, height: 200});
var layer1 = new Konva.Layer({draggable: false});
var bg1 = new Konva.Rect({width: 200, height: 200, fill: 'gold', })
layer1.add(bg1);
s1.add(layer1);
function MakeComplexText(opts){
var yOffset = 6;
var txtEle = [];
var maxW = 0;
var g = new Konva.Group({x: opts.pos.x, y: opts.pos.y});
g.add(new Konva.Rect({width: opts.pos.w, height: opts.pos.h, fill: opts.bgClr, stroke: opts.lineClr, strokeWidth: 1, cornerRadius: opts.cornerRadius}));
if (opts.symbolLeft != ""){
var t1 = new Konva.Text({name: 'symText1', y: yOffset + 1, width: 15, text: opts.symbolLeft, fontFamily: 'FontAwesome', fontSize: 11, fill: opts.textClr, align: 'left'});
txtEle.push({obj: t1, w: t1.getWidth()});
maxW = maxW + t1.getWidth();
g.add(t1);
}
var t = new Konva.Text({name: 'btnText', y: yOffset, height: opts.pos.h, text: opts.text, fontFamily: 'Arial', fontSize: 11, fontStyle: "Bold", fill: opts.textClr, align: 'center'})
txtEle.push({obj: t, w: t.getWidth()});
maxW = maxW + t.getWidth();
g.add(t);
if (opts.symbolRight != ""){
var t2 = new Konva.Text({name: 'symText2', y: yOffset + 1, width: 15, text: opts.symbolRight, fontFamily: 'FontAwesome', fontSize: 11, fill: opts.textClr, align: 'right'});
txtEle.push({obj: t2, w: t2.getWidth()});
maxW = maxW + t2.getWidth();
g.add(t2);
}
var xPos = (opts.pos.w - maxW)/2;
for (var i = 0; i < txtEle.length; i = i + 1){
txtEle[i].obj.x(xPos);
xPos = xPos + txtEle[i].w;
}
opts.parent.add(g);
return g;
}
// move button icon right only
var btnModeMoveR = MakeComplexText(
{parent: layer1, pos: {x:5, y:7, w: 75, h: 24}, text: "Move", textClr: "#666666", bgClr: "#cccccc", lineClr: "#666666", symbolLeft: "", symbolRight: "\uf047", cornerRadius: 0}
);
// move button with icons left & right
var btnModeMoveL = MakeComplexText(
{parent: layer1, pos: {x:5, y:37, w: 75, h: 24}, text: "Move", textClr: "#666666", bgClr: "#cccccc", lineClr: "#666666", symbolLeft: "\uf047", symbolRight: "\uf047", cornerRadius: 0}
);
// Reresh button icon left
var btnModeMoveL = MakeComplexText(
{parent: layer1, pos: {x:5, y:67, w: 75, h: 24}, text: "Refresh", textClr: "#666666", bgClr: "#cccccc", lineClr: "#666666", symbolLeft: "", symbolRight: "\uf021", cornerRadius: 0}
);
// to make a tooltip we combine a label and complex text in a group.
var g = new Konva.Group({ x: 5, y: 97});
var tooltip = new Konva.Label({x: 0, y: 0, width: 100});
tooltip.add(new Konva.Tag({
fill: "#cccccc",
pointerDirection: 'right',
pointerWidth: 10,
pointerHeight: 10,
lineJoin: 'round',
width: 80,
height: 24
}));
g.add(tooltip);
// edit button
var btnEdit = MakeComplexText(
{parent: g, pos: {x:0, y:0, w: 75, h: 24}, text: "Edit", textClr: "#666666", bgClr: "#cccccc", lineClr: "transparent", symbolLeft: "", symbolRight: "\uf14b", cornerRadius: 0}
);
layer1.add(g)
// btnEdit.moveTo(layer1);
s1.draw()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/konvajs/konva/1.6.5/konva.min.js"></script>
<div id='container1' style="display: inline-block; width: 400px, height: 400px; background-color: silver; overflow: hidden;"></div>

Adding rubberband zoom to ChartView via MouseArea

I have a ChartView item declared in QML and I need a rubberband-like zoom functionality. This can be achieved with semi-transparent rectangle and MouseArea item. The problem is with one rectangle it's only possible to select area from top-left to bottom-right due to the fact that Rectangle item with negative dim-s is either invisible or disabled. Although it's possible to apply transform to Rectangle
transform: Scale { origin.x: 0; origin.y: 0; xScale: -1}
I failed to find how to manipulate xScale/yScale properties from the outside.
Right now I draw 4 rectangles, one per each quadrant, with correct xScale/yScale and dims (code in the end).
So I wonder is there more elegant/easy solution to the problem?
ChartView {
id: chartViewTop
...
Rectangle{
id: rubberBandRec1
border.color: "black"
border.width: 1
opacity: 0.3
visible: false
transform: Scale { origin.x: 0; origin.y: 0; yScale: -1}
}
Rectangle{
id: rubberBandRec2
border.color: "black"
border.width: 1
opacity: 0.3
visible: false
transform: Scale { origin.x: 0; origin.y: 0; yScale: -1; xScale: -1}
}
Rectangle{
id: rubberBandRec3
border.color: "black"
border.width: 1
opacity: 0.3
visible: false
transform: Scale { origin.x: 0; origin.y: 0; xScale: -1}
}
Rectangle{
id: rubberBandRec4
border.color: "black"
border.width: 1
opacity: 0.3
visible: false
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onPressed: {
rubberBandRec1.x = mouseX; rubberBandRec1.y = mouseY; rubberBandRec1.visible = true;
rubberBandRec2.x = mouseX; rubberBandRec2.y = mouseY; rubberBandRec2.visible = true;
rubberBandRec3.x = mouseX; rubberBandRec3.y = mouseY; rubberBandRec3.visible = true;
rubberBandRec4.x = mouseX; rubberBandRec4.y = mouseY; rubberBandRec4.visible = true;
}
onMouseXChanged: {
rubberBandRec1.width = mouseX - rubberBandRec1.x;
rubberBandRec2.width = rubberBandRec2.x-mouseX;
rubberBandRec3.width = rubberBandRec3.x-mouseX;
rubberBandRec4.width = mouseX - rubberBandRec4.x;
}
onMouseYChanged: {
rubberBandRec1.height = rubberBandRec1.y - mouseY;
rubberBandRec2.height = rubberBandRec2.y - mouseY;
rubberBandRec3.height = mouseY - rubberBandRec3.y;
rubberBandRec4.height = mouseY - rubberBandRec4.y;
}
onReleased: {
var x = rubberBandRec4.x-(rubberBandRec4.width<0)*Math.abs(rubberBandRec4.width);
var y = rubberBandRec4.y-(rubberBandRec4.height<0)*Math.abs(rubberBandRec4.height);
if (Math.abs(rubberBandRec4.width*rubberBandRec4.height)>100)
chartViewTop.zoomIn(Qt.rect(x, y, Math.abs(rubberBandRec4.width),
Math.abs(rubberBandRec4.height)));
rubberBandRec1.visible = false;
rubberBandRec2.visible = false;
rubberBandRec3.visible = false;
rubberBandRec4.visible = false;
}
}
}
Set external properties for the scaling, and then just change these in the onMouseXChanged and onMouseYChanged events as follows. This appears to be working for me:
property int xScaleZoom: 0
property int yScaleZoom: 0
Rectangle{
id: recZoom
border.color: "steelblue"
border.width: 1
color: "steelblue"
opacity: 0.3
visible: false
transform: Scale { origin.x: 0; origin.y: 0; xScale: xScaleZoom; yScale: yScaleZoom}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onPressed: {
recZoom.x = mouseX;
recZoom.y = mouseY;
recZoom.visible = true;
}
onMouseXChanged: {
if (mouseX - recZoom.x >= 0) {
xScaleZoom = 1;
recZoom.width = mouseX - recZoom.x;
} else {
xScaleZoom = -1;
recZoom.width = recZoom.x - mouseX;
}
}
onMouseYChanged: {
if (mouseY - recZoom.y >= 0) {
yScaleZoom = 1;
recZoom.height = mouseY - recZoom.y;
} else {
yScaleZoom = -1;
recZoom.height = recZoom.y - mouseY;
}
}
onReleased: {
var x = (mouseX >= recZoom.x) ? recZoom.x : mouseX
var y = (mouseY >= recZoom.y) ? recZoom.y : mouseY
chartView.zoomIn(Qt.rect(x, y, recZoom.width, recZoom.height));
recZoom.visible = false;
}
}

Retrieving data from ASP.net sql database into amchart

i am facing quite a problem which is to create the nice graph from http://www.amcharts.com/ but i need to retrieve data from my sql database. But i don't know how to place inside. Please guide me. Below is the way how the graph displayed, but i wanted to work with data from database. Thank you.
<script type="text/javascript">
var chartData = generateChartData();
function generateChartData() {
var chartData = [];
var firstDate = new Date(2012, 0, 1);
firstDate.setDate(firstDate.getDate() - 500);
firstDate.setHours(0, 0, 0, 0);
for (var i = 0; i < 500; i++) {
var newDate = new Date(firstDate);
newDate.setDate(newDate.getDate() + i);
var value = Math.round(Math.random() * (40 + i)) + 100 + i;
chartData.push({
date: newDate,
value: value
});
}
return chartData;
}
AmCharts.makeChart("chartdiv", {
type: "stock",
pathToImages: "../amcharts/images/",
dataSets: [{
color: "#b0de09",
fieldMappings: [{
fromField: "value",
toField: "value"
}],
dataProvider: chartData,
categoryField: "date"
}],
panels: [{
showCategoryAxis: true,
title: "Value",
eraseAll: false,
labels: [{
x: 0,
y: 100,
text: "Click on the pencil icon on top-right to start drawing",
align: "center",
size: 16
}],
stockGraphs: [{
id: "g1",
valueField: "value",
bullet: "round",
bulletColor: "#FFFFFF",
bulletBorderColor: "#00BBCC",
bulletBorderAlpha: 1,
bulletBorderThickness: 2,
bulletSize: 7,
lineThickness: 2,
lineColor: "#00BBCC",
useDataSetColors: false
}],
stockLegend: {
valueTextRegular: " ",
markerType: "none"
},
drawingIconsEnabled: true
}],
chartScrollbarSettings: {
graph: "g1"
},
chartCursorSettings: {
valueBalloonsEnabled: true
},
periodSelector: {
position: "bottom",
periods: [{
period: "DD",
count: 10,
label: "10 days"
}, {
period: "MM",
count: 1,
label: "1 month"
}, {
period: "YYYY",
count: 1,
label: "1 year"
}, {
period: "YTD",
label: "YTD"
}, {
period: "MAX",
label: "MAX"
}]
}
});
</script>
Can you generate this script in your code behind ( using a string builder for example ) then use this
ScriptManager.RegisterStartupScript(this, this.GetType(), "", "'" + YourStringBuild.toString() + "'", true);

Fix qml item behavior

I have code on qml, which should divide it on 4 squares by click.
import QtQuick 2.0
Rectangle {
Component {
id: squareComponent
Rectangle {
property int sideLenght: 500
width: sideLenght
height: sideLenght
color: "orange"
MouseArea {
anchors.fill: parent
onClicked: {
var first = squareComponent.createObject(parent)
var second = squareComponent.createObject(parent)
var third = squareComponent.createObject(parent)
var fourth = squareComponent.createObject(parent)
var sideLenght = parent.sideLenght / 2
first.sideLenght = sideLenght
second.sideLenght = sideLenght
third.sideLenght = sideLenght
fourth.sideLenght = sideLenght
var x = parent.x
var y = parent.y
console.log(x, y)
first.x = x
first.y = y
first.color = "red"
console.log("first", first.x, first.y)
second.x = first.x + sideLenght
second.y = first.y
second.color = "orange"
console.log("second", second.x, second.y)
third.x = first.x
third.y = first.y + sideLenght
third.color = "blue"
console.log("third", third.x, third.y)
fourth.x = first.x + sideLenght
fourth.y = first.y + sideLenght
fourth.color = "black"
console.log("fourth", fourth.x, fourth.y, "\n\n")
parent.sideLenght = 0
}
}
}
}
Component.onCompleted: squareComponent.createObject(parent)
}
They are divided, but divided only correct square (0, 0), others are with an offset for x or y by the amount of the parent. Qt 5.0.1. How do I fix this behavior, is it a bug?
Logging says that the elements are right, but they are not in fact.
This is what I get as the output with QtQuick 1.1. Is this different in Qt 5.0.1?

Resources