aboutsummaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorCharles Yin <charles.yin@nokia.com>2011-07-13 17:07:06 +1000
committerQt by Nokia <qt-info@nokia.com>2011-07-20 08:22:07 +0200
commit0a9c296731dd01bcf7d7c700a04917620c0ca6da (patch)
treeb523111b01f39d500ead5a1480f92c417bbfa3fb /examples
parent9d6e4d98c0cae77a99a158a4cb3dff9d6f6313fe (diff)
more on canvas stock chart example.
Change-Id: I7e92414d397b8a0bfdd514c9045677cd00422263 Reviewed-on: http://codereview.qt.nokia.com/1627 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Charles Yin <charles.yin@nokia.com>
Diffstat (limited to 'examples')
-rw-r--r--examples/declarative/canvas/stockchart/contents/Stocks.qml107
-rw-r--r--examples/declarative/canvas/stockchart/main.cpp6
-rw-r--r--examples/declarative/canvas/stockchart/model.cpp49
-rw-r--r--examples/declarative/canvas/stockchart/model.h58
-rw-r--r--examples/declarative/canvas/stockchart/stock.qml579
-rw-r--r--examples/declarative/canvas/stockchart/stockchart.pro3
-rw-r--r--examples/declarative/canvas/stockchart/stockchart.qrc1
7 files changed, 732 insertions, 71 deletions
diff --git a/examples/declarative/canvas/stockchart/contents/Stocks.qml b/examples/declarative/canvas/stockchart/contents/Stocks.qml
new file mode 100644
index 0000000000..7593a0ccee
--- /dev/null
+++ b/examples/declarative/canvas/stockchart/contents/Stocks.qml
@@ -0,0 +1,107 @@
+import QtQuick 2.0
+
+ListModel {
+ id:stocks
+ //Data from : http://en.wikipedia.org/wiki/NASDAQ-100
+
+ ListElement {name:"Activision Blizzard"; stockId:"ATVI"}
+ ListElement {name:"Adobe Systems Incorporated"; stockId:"ADBE"}
+ ListElement {name:"Akamai Technologies, Inc"; stockId:"AKAM"}
+ ListElement {name:"Alexion Pharmaceuticals"; stockId:"ALXN"}
+ ListElement {name:"Altera Corporation"; stockId:"ALTR"}
+ ListElement {name:"Amazon.com, Inc."; stockId:"AMZN"}
+ ListElement {name:"Amgen Inc."; stockId:"AMGN"}
+ ListElement {name:"Apollo Group, Inc."; stockId:"APOL"}
+ ListElement {name:"Apple Inc."; stockId:"AAPL"}
+ ListElement {name:"Applied Materials, Inc."; stockId:"AMAT"}
+ ListElement {name:"Autodesk, Inc."; stockId:"ADSK"}
+ ListElement {name:"Automatic Data Processing, Inc."; stockId:"ADP"}
+ ListElement {name:"Baidu.com, Inc."; stockId:"BIDU"}
+ ListElement {name:"Bed Bath & Beyond Inc."; stockId:"BBBY"}
+ ListElement {name:"Biogen Idec, Inc"; stockId:"BIIB"}
+ ListElement {name:"BMC Software, Inc."; stockId:"BMC"}
+ ListElement {name:"Broadcom Corporation"; stockId:"BRCM"}
+ ListElement {name:"C. H. Robinson Worldwide, Inc."; stockId:"CHRW"}
+ ListElement {name:"CA, Inc."; stockId:"CA"}
+ ListElement {name:"Celgene Corporation"; stockId:"CELG"}
+ ListElement {name:"Cephalon, Inc."; stockId:"CEPH"}
+ ListElement {name:"Cerner Corporation"; stockId:"CERN"}
+ ListElement {name:"Check Point Software Technologies Ltd."; stockId:"CHKP"}
+ ListElement {name:"Cisco Systems, Inc."; stockId:"CSCO"}
+ ListElement {name:"Citrix Systems, Inc."; stockId:"CTXS"}
+ ListElement {name:"Cognizant Technology Solutions Corporation"; stockId:"CTSH"}
+ ListElement {name:"Comcast Corporation"; stockId:"CMCSA"}
+ ListElement {name:"Costco Wholesale Corporation"; stockId:"COST"}
+ ListElement {name:"Ctrip.com International, Ltd."; stockId:"CTRP"}
+ ListElement {name:"Dell Inc."; stockId:"DELL"}
+ ListElement {name:"DENTSPLY International Inc."; stockId:"XRAY"}
+ ListElement {name:"DirecTV"; stockId:"DTV"}
+ ListElement {name:"Dollar Tree, Inc."; stockId:"DLTR"}
+ ListElement {name:"eBay Inc."; stockId:"EBAY"}
+ ListElement {name:"Electronic Arts Inc."; stockId:"ERTS"}
+ ListElement {name:"Expedia, Inc."; stockId:"EXPE"}
+ ListElement {name:"Expeditors International of Washington, Inc."; stockId:"EXPD"}
+ ListElement {name:"Express Scripts, Inc."; stockId:"ESRX"}
+ ListElement {name:"F5 Networks, Inc."; stockId:"FFIV"}
+ ListElement {name:"Fastenal Company"; stockId:"FAST"}
+ ListElement {name:"First Solar, Inc."; stockId:"FSLR"}
+ ListElement {name:"Fiserv, Inc."; stockId:"FISV"}
+ ListElement {name:"Flextronics International Ltd."; stockId:"FLEX"}
+ ListElement {name:"FLIR Systems, Inc."; stockId:"FLIR"}
+ ListElement {name:"Garmin Ltd."; stockId:"GRMN"}
+ ListElement {name:"Gilead Sciences, Inc."; stockId:"GILD"}
+ ListElement {name:"Google Inc."; stockId:"GOOG"}
+ ListElement {name:"Green Mountain Coffee Roasters, Inc."; stockId:"GMCR"}
+ ListElement {name:"Henry Schein, Inc."; stockId:"HSIC"}
+ ListElement {name:"Illumina, Inc."; stockId:"ILMN"}
+ ListElement {name:"Infosys Technologies"; stockId:"INFY"}
+ ListElement {name:"Intel Corporation"; stockId:"INTC"}
+ ListElement {name:"Intuit, Inc."; stockId:"INTU"}
+ ListElement {name:"Intuitive Surgical Inc."; stockId:"ISRG"}
+ ListElement {name:"Joy Global Inc."; stockId:"JOYG"}
+ ListElement {name:"KLA Tencor Corporation"; stockId:"KLAC"}
+ ListElement {name:"Lam Research Corporation"; stockId:"LRCX"}
+ ListElement {name:"Liberty Media Corporation, Interactive Series A"; stockId:"LINTA"}
+ ListElement {name:"Life Technologies Corporation"; stockId:"LIFE"}
+ ListElement {name:"Linear Technology Corporation"; stockId:"LLTC"}
+ ListElement {name:"Marvell Technology Group, Ltd."; stockId:"MRVL"}
+ ListElement {name:"Mattel, Inc."; stockId:"MAT"}
+ ListElement {name:"Maxim Integrated Products"; stockId:"MXIM"}
+ ListElement {name:"Microchip Technology Incorporated"; stockId:"MCHP"}
+ ListElement {name:"Micron Technology, Inc."; stockId:"MU"}
+ ListElement {name:"Microsoft Corporation"; stockId:"MSFT"}
+ ListElement {name:"Mylan, Inc."; stockId:"MYL"}
+ ListElement {name:"NetApp, Inc."; stockId:"NTAP"}
+ ListElement {name:"Netflix, Inc."; stockId:"NFLX"}
+ ListElement {name:"News Corporation, Ltd."; stockId:"NWSA"}
+ ListElement {name:"NII Holdings, Inc."; stockId:"NIHD"}
+ ListElement {name:"NVIDIA Corporation"; stockId:"NVDA"}
+ ListElement {name:"O'Reilly Automotive, Inc."; stockId:"ORLY"}
+ ListElement {name:"Oracle Corporation"; stockId:"ORCL"}
+ ListElement {name:"PACCAR Inc."; stockId:"PCAR"}
+ ListElement {name:"Paychex, Inc."; stockId:"PAYX"}
+ ListElement {name:"Priceline.com, Incorporated"; stockId:"PCLN"}
+ ListElement {name:"Qiagen N.V."; stockId:"QGEN"}
+ ListElement {name:"QUALCOMM Incorporated"; stockId:"QCOM"}
+ ListElement {name:"Research in Motion Limited"; stockId:"RIMM"}
+ ListElement {name:"Ross Stores Inc."; stockId:"ROST"}
+ ListElement {name:"SanDisk Corporation"; stockId:"SNDK"}
+ ListElement {name:"Seagate Technology Holdings"; stockId:"STX"}
+ ListElement {name:"Sears Holdings Corporation"; stockId:"SHLD"}
+ ListElement {name:"Sigma-Aldrich Corporation"; stockId:"SIAL"}
+ ListElement {name:"Staples Inc."; stockId:"SPLS"}
+ ListElement {name:"Starbucks Corporation"; stockId:"SBUX"}
+ ListElement {name:"Stericycle, Inc"; stockId:"SRCL"}
+ ListElement {name:"Symantec Corporation"; stockId:"SYMC"}
+ ListElement {name:"Teva Pharmaceutical Industries Ltd."; stockId:"TEVA"}
+ ListElement {name:"Urban Outfitters, Inc."; stockId:"URBN"}
+ ListElement {name:"VeriSign, Inc."; stockId:"VRSN"}
+ ListElement {name:"Vertex Pharmaceuticals"; stockId:"VRTX"}
+ ListElement {name:"Virgin Media, Inc."; stockId:"VMED"}
+ ListElement {name:"Vodafone Group, plc."; stockId:"VOD"}
+ ListElement {name:"Warner Chilcott, Ltd."; stockId:"WCRX"}
+ ListElement {name:"Whole Foods Market, Inc."; stockId:"WFM"}
+ ListElement {name:"Wynn Resorts Ltd."; stockId:"WYNN"}
+ ListElement {name:"Xilinx, Inc."; stockId:"XLNX"}
+ ListElement {name:"Yahoo! Inc."; stockId:"YHOO"}
+}
diff --git a/examples/declarative/canvas/stockchart/main.cpp b/examples/declarative/canvas/stockchart/main.cpp
index fd383189b5..e10f287022 100644
--- a/examples/declarative/canvas/stockchart/main.cpp
+++ b/examples/declarative/canvas/stockchart/main.cpp
@@ -48,12 +48,12 @@ int main(int argc, char ** argv)
QApplication app(argc, argv);
qmlRegisterType<StockModel>("StockChart", 1, 0, "StockModel");
-
+ qmlRegisterType<StockPrice>("StockChart", 1, 0, "StockPrice");
QSGView view;
- view.setResizeMode(QSGView::SizeRootObjectToView);
+ view.setResizeMode(QSGView::SizeViewToRootObject);
view.setSource(QUrl("qrc:stock.qml"));
- view.show();
+ view.showFullScreen();
view.raise();
return app.exec();
diff --git a/examples/declarative/canvas/stockchart/model.cpp b/examples/declarative/canvas/stockchart/model.cpp
index e5187793aa..5c1e13807a 100644
--- a/examples/declarative/canvas/stockchart/model.cpp
+++ b/examples/declarative/canvas/stockchart/model.cpp
@@ -82,6 +82,15 @@ int StockModel::rowCount(const QModelIndex & parent) const {
return _prices.count();
}
+StockPrice* StockModel::stockPriceAtIndex(int idx) const
+{
+ if (idx >=0 && idx < _prices.size()) {
+ return _prices[idx];
+ }
+ return 0;
+}
+
+
void StockModel::requestData()
{
if (!_updating) {
@@ -118,6 +127,11 @@ void StockModel::update(QNetworkReply *reply)
if (reply) {
if (reply->error() == QNetworkReply::NoError) {
beginResetModel();
+
+ foreach (StockPrice* p, _prices) {
+ p->deleteLater();
+ }
+
_prices.clear();
while (!reply->atEnd()) {
@@ -127,14 +141,14 @@ void StockModel::update(QNetworkReply *reply)
//data format:Date,Open,High,Low,Close,Volume,Adjusted close price
//example: 2011-06-24,6.03,6.04,5.88,5.88,20465200,5.88
if (fields.size() == 7) {
- StockPrice price;
- price.date = QDate::fromString(fields[0], Qt::ISODate);
- price.openPrice = fields[1].toFloat();
- price.highPrice = fields[2].toFloat();
- price.lowPrice = fields[3].toFloat();
- price.closePrice = fields[4].toFloat();
- price.volume = fields[5].toInt();
- price.adjustedPrice = fields[6].toFloat();
+ StockPrice* price = new StockPrice(this);
+ price->setDate(QDate::fromString(fields[0], Qt::ISODate));
+ price->setOpenPrice(fields[1].toFloat());
+ price->setHighPrice(fields[2].toFloat());
+ price->setLowPrice(fields[3].toFloat());
+ price->setClosePrice(fields[4].toFloat());
+ price->setVolume(fields[5].toInt());
+ price->setAdjustedPrice(fields[6].toFloat());
_prices.prepend(price);
}
}
@@ -144,6 +158,7 @@ void StockModel::update(QNetworkReply *reply)
}
reply->deleteLater();
endResetModel();
+ emit dataChanged(QModelIndex(), QModelIndex());
}
}
@@ -151,23 +166,23 @@ QVariant StockModel::data(const QModelIndex & index, int role) const {
if (index.row() < 0 || index.row() > _prices.count())
return QVariant();
- const StockPrice &price = _prices[index.row()];
+ const StockPrice* price = _prices[index.row()];
if (role == StockModel::DateRole)
- return price.date;
+ return price->date();
else if (role == StockModel::OpenPriceRole)
- return price.openPrice;
+ return price->openPrice();
else if (role == StockModel::ClosePriceRole)
- return price.closePrice;
+ return price->closePrice();
else if (role == StockModel::HighPriceRole)
- return price.highPrice;
+ return price->highPrice();
else if (role == StockModel::LowPriceRole)
- return price.lowPrice;
+ return price->lowPrice();
else if (role == StockModel::AdjustedPriceRole)
- return price.adjustedPrice;
+ return price->adjustedPrice();
else if (role == StockModel::VolumeRole)
- return price.volume;
+ return price->volume();
else if (role == StockModel::SectionRole)
- return price.date.year();
+ return price->date().year();
return QVariant();
}
diff --git a/examples/declarative/canvas/stockchart/model.h b/examples/declarative/canvas/stockchart/model.h
index fde99de223..c7a0235021 100644
--- a/examples/declarative/canvas/stockchart/model.h
+++ b/examples/declarative/canvas/stockchart/model.h
@@ -40,16 +40,54 @@
#include <QtCore/QAbstractListModel>
#include <QtCore/QDate>
-struct StockPrice
+class StockPrice : public QObject
{
- QDate date;
- qreal openPrice;
- qreal closePrice;
- qreal highPrice;
- qreal lowPrice;
- qint32 volume;
- qreal adjustedPrice;
+ Q_OBJECT
+ Q_PROPERTY(QDate date READ date)
+ Q_PROPERTY(qreal openPrice READ openPrice)
+ Q_PROPERTY(qreal closePrice READ closePrice)
+ Q_PROPERTY(qreal highPrice READ highPrice)
+ Q_PROPERTY(qreal lowPrice READ lowPrice)
+ Q_PROPERTY(qint32 volume READ volume)
+ Q_PROPERTY(qreal adjustedPrice READ adjustedPrice)
+public:
+
+ StockPrice(QObject *parent = 0)
+ : QObject(parent)
+ , _openPrice(-1)
+ , _closePrice(-1)
+ , _highPrice(-1)
+ , _lowPrice(-1)
+ , _volume(-1)
+ , _adjustedPrice(-1)
+ {
+ }
+ QDate date() const {return _date;}
+ qreal openPrice() const {return _openPrice; }
+ qreal closePrice() const {return _closePrice;}
+ qreal highPrice() const {return _highPrice;}
+ qreal lowPrice() const{return _lowPrice;}
+ qreal adjustedPrice() const{return _adjustedPrice;}
+ qint32 volume() const{return _volume;}
+
+ void setDate(const QDate& date){_date = date;}
+ void setOpenPrice(qreal price){_openPrice = price;}
+ void setClosePrice(qreal price){_closePrice = price;}
+ void setHighPrice(qreal price){_highPrice = price;}
+ void setLowPrice(qreal price){_lowPrice = price;}
+ void setAdjustedPrice(qreal price) {_adjustedPrice = price;}
+ void setVolume(qint32 volume) {_volume = volume;}
+
+private:
+ QDate _date;
+ qreal _openPrice;
+ qreal _closePrice;
+ qreal _highPrice;
+ qreal _lowPrice;
+ qint32 _volume;
+ qreal _adjustedPrice;
};
+
class QNetworkReply;
class QNetworkAccessManager;
class StockModel : public QAbstractListModel
@@ -107,13 +145,13 @@ signals:
public slots:
void requestData();
-
+ StockPrice* stockPriceAtIndex(int idx) const;
private slots:
void doRequest();
void update(QNetworkReply* reply);
private:
QString dataCycleString() const;
- QList<StockPrice> _prices;
+ QList<StockPrice*> _prices;
QString _stockName;
QDate _startDate;
QDate _endDate;
diff --git a/examples/declarative/canvas/stockchart/stock.qml b/examples/declarative/canvas/stockchart/stock.qml
index 15f6064fef..4117932c0a 100644
--- a/examples/declarative/canvas/stockchart/stock.qml
+++ b/examples/declarative/canvas/stockchart/stock.qml
@@ -39,74 +39,573 @@
****************************************************************************/
import QtQuick 2.0
import StockChart 1.0
+import "contents"
Rectangle {
id:container
- width: 700; height: 800
+ width: 1920; height: 1440
StockModel {
id:stockModel
- stockName: "NOK"
- }
- // Define a highlight with customised movement between items.
- Component {
- id: highlightBar
- Rectangle {
- width: 1000; height: 50
- color: "#FFFF88"
- y: view.currentItem.y;
- Behavior on y { SpringAnimation { spring: 2; damping: 0.1 } }
+ dataCycle: StockModel.Daily
+ onDataChanged: {
+ if (view.viewType == "chart") {
+ canvas.requestPaint();
+ }
}
+ property string description:"";
}
- // The delegate for each section header
- Component {
- id: sectionHeading
- Rectangle {
- width: container.width
- height: childrenRect.height
- color: "lightsteelblue"
- Text {
- text:stockModel.stockName + "(" + section + ")" + "Open\t High\t Low\t Close\t Volume\t Adjusted"
- horizontalAlignment:Text.AlignHCenter
- font.bold: true
- font.underline:true
+ Stocks {id:stocks}
+
+ Rectangle {
+ id: header
+ width: parent.width
+ height: childrenRect.height
+ color: "steelblue"
+
+ Text {
+ id:t
+ font.pointSize:15
+ horizontalAlignment:Text.AlignHCenter
+ font.bold: true
+ font.underline:true
+ }
+
+ function updateCurrent(price)
+ {
+ if (price !== undefined) {
+ t.text =Qt.formatDate(price.date, "yyyy-MM-dd") + " OPEN:"
+ + Math.round(price.openPrice*100)/100 + " HIGH:"
+ + Math.round(price.highPrice*100)/100 + " LOW:"
+ + Math.round(price.lowPrice*100)/100 + " CLOSE:"
+ + Math.round(price.closePrice*100)/100 + " VOLUME:"
+ + price.volume + " ADJ:"
+ + Math.round(price.adjustedPrice*100)/100;
}
}
}
+
ListView {
- id:view
+ id:stockList
width: parent.width
- anchors.fill: parent
- highlightFollowsCurrentItem: false
+ height: container.height
+ anchors.bottom: container.bottom
focus: true
keyNavigationWraps: true
- opacity: 0.8
- highlightRangeMode: ListView.StrictlyEnforceRange
spacing:1
+ opacity: 1
+ model: stocks
+
+ delegate : Rectangle {
+ height: 30
+ width: view.width
+ color: {
+ if (ListView.isCurrentItem)
+ return focus ? "lightyellow" : "pink";
+ return index % 2 == 0 ? "lightblue" : "lightsteelblue"
+ }
+ Text {
+ font.pointSize:20
+ text: index + ". " + stockId + " \t(" + name + ")";
+ }
+ MouseArea {
+ anchors.fill: parent;
+ onDoubleClicked: {
+ stockList.opacity = 0;
+ stockModel.stockName = stockId;
+ stockModel.description = "NASDAQ:" + stockId + " (" + name + ")";
+ view.opacity = 1;
+ view.viewType = "chart";
+ }
+ onClicked: stockList.currentIndex = index
+ }//mousearea
+ }//delegate
+ }
+
+ ListView {
+ id:view
+ width: container.width
+ height: container.height - 50
+ anchors.bottom: container.bottom
+ focus: true
+ keyNavigationWraps: true
+
+ spacing:1
+ opacity: 0
model: stockModel
- highlight: Rectangle { color: "lightsteelblue" }
- section.property: "year"
- section.criteria: ViewSection.FullString
- section.delegate: sectionHeading
- delegate: Text { text: Qt.formatDate(date, "yyyy-MM-dd") + "\t " + Math.round(openPrice*100)/100 + "\t " + Math.round(highPrice*100)/100 + "\t " + Math.round(lowPrice*100)/100 + "\t " + Math.round(closePrice*100)/100 + "\t " + volume + "\t " + Math.round(adjustedPrice*100)/100 }
+ highlightFollowsCurrentItem: false
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ preferredHighlightBegin:50
+ preferredHighlightEnd : height - 50
+ highlight: listHighlight
+
+ //header : Text {}
+ delegate: listDelegate
+ snapMode: ListView.SnapToItem
+ property string viewType : "list"
+ property int topIndex:indexAt(0,contentY);
+ property int bottomIndex:indexAt(0, contentY+height);
- property bool beginning:false
- Component.onCompleted: {
- view.positionViewAtBeginning();
+ Component {
+ id: listDelegate
+ Rectangle {
+ height: 20
+ width: view.width
+ border.color: "lightsteelblue"
+ border.width: 1
+ color: {
+ if (ListView.isCurrentItem)
+ return focus ? "lightyellow" : "pink";
+
+ return index % 2 == 0 ? "lightblue" : "lightsteelblue"
+ }
+ Text {
+ font.pointSize:13
+ text: index + ". " + Qt.formatDate(date, "yyyy-MM-dd")
+ + "\t " + Math.round(openPrice*100)/100
+ + "\t " + Math.round(highPrice*100)/100
+ + "\t " + Math.round(lowPrice*100)/100
+ + "\t " + Math.round(closePrice*100)/100
+ + "\t " + volume + "\t "
+ + Math.round(adjustedPrice*100)/100;
+ }
+ MouseArea {anchors.fill: parent; onClicked: view.currentIndex = index}
+ }
+ }
+
+ Component {
+ id: chartDelegate
+ Rectangle {
+ height: 20
+ width: view.width/view.count * canvas.scaleX
+ border.color: "lightsteelblue"
+ border.width: 1
+ color: {
+ if (ListView.isCurrentItem)
+ return focus ? "lightyellow" : "pink";
+
+ return index % 2 == 0 ? "lightblue" : "lightsteelblue"
+ }
+
+ Text {
+ anchors.bottom: parent.bottom
+ font.pointSize: {
+ if (parent.width <= 4)
+ return 1;
+ if (parent.width <= 50)
+ return parent.width/4;
+ return 15;
+ }
+ horizontalAlignment:Text.AlignHCenter
+ verticalAlignment:Text.AlignBottom
+ text:font.pointSize > 1 ? Qt.formatDate(date, "d/M/yy") : ""
+ }
+ MouseArea {anchors.fill: parent; onClicked: view.currentIndex = index}
+ }
+ }
+
+ Component {
+ id:chartHighlight
+ Rectangle { radius: 5; width:40; height: 20; color: "lightsteelblue" }
+ }
+
+ Component {
+ id:listHighlight
+ Rectangle { radius: 5; width:container.width; height: 20; color: "lightsteelblue" }
+ }
+
+
+
+
+ onViewTypeChanged : {
+ if (viewType == "list") {
+// container.width = 700;
+// container.height = 800;
+ view.orientation = ListView.Vertical;
+ view.delegate = listDelegate;
+// view.section.property = "year";
+// view.section.criteria = ViewSection.FullString;
+// view.section.delegate = sectionHeading;
+ view.highlight = listHighlight;
+ view.opacity = 1;
+ canvas.opacity = 0;
+ //view.height = 750;
+ // comment.opacity = 0;
+
+ } else if (viewType == "chart") {
+// container.width = 1600;
+// container.height = 800;
+ view.orientation = ListView.Horizontal;
+ view.delegate = chartDelegate;
+ //comment.opacity = 0.6;
+ var dataCycle = "Daily";
+
+ if (stockModel.dataCycle === StockModel.Weekly)
+ dataCycle = "Weekly";
+ else if (stockModel.dataCycle === StockModel.Monthly)
+ dataCycle = "Monthly";
+
+ comment.text = stockModel.description + "\n" +
+ Qt.formatDate(stockModel.startDate, "yyyy-MM-dd") + " - " +
+ Qt.formatDate(stockModel.endDate, "yyyy-MM-dd") + " " + dataCycle;
+
+ view.opacity = 1;
+ view.height = 30
+
+ canvas.opacity = 1;
+ canvas.requestPaint();
+ } else {
+ viewType = "list";
+ }
+ }
+
+
+ onCurrentIndexChanged: {
+ header.updateCurrent(stockModel.stockPriceAtIndex(view.currentIndex));
+ if (viewType == "chart") {
+ canvas.first = Math.round(view.currentIndex - view.currentIndex / canvas.scaleX);
+ canvas.last = Math.round(view.currentIndex + (view.count - view.currentIndex) / canvas.scaleX);
+
+ canvas.requestPaint();
+ }
+ }
+ onContentYChanged: { // keep "current" item visible
+ topIndex = indexAt(0,contentY);
+ bottomIndex = indexAt(0, contentY+height);
+
+ if (topIndex != -1 && currentIndex <= topIndex)
+ currentIndex = topIndex+1;
+ else if (bottomIndex != -1 && currentIndex >= bottomIndex)
+ currentIndex = bottomIndex-1;
+ if (viewType == "chart")
+ canvas.requestPaint();
+ }
+
+ onContentXChanged: { // keep "current" item visible
+ topIndex = indexAt(contentX,0);
+ bottomIndex = indexAt(contentX+width, 0);
+
+ if (topIndex != -1 && currentIndex <= topIndex)
+ currentIndex = topIndex+1;
+ else if (bottomIndex != -1 && currentIndex >= bottomIndex)
+ currentIndex = bottomIndex-1;
+ if (viewType == "chart")
+ canvas.requestPaint();
}
MouseArea {
anchors.fill: parent
onDoubleClicked: {
- if (view.beginning) {
- view.positionViewAtBeginning();
+ if (view.viewType == "list")
+ view.viewType = "chart";
+ else
+ view.viewType = "list";
+ }
+ }
+ }
+
+
+
+ Canvas {
+ id:canvas
+ anchors.top : header.bottom
+ anchors.bottom : view.top
+ width:container.width;
+ opacity:0
+
+ property int mouseX:0;
+ property int mouseY:0;
+ property int mousePressedX:0;
+ property int mousePressedY:0;
+ property int movedY:0
+ property real scaleX:1.0;
+ property real scaleY:1.0;
+ property int first:0;
+ property int last:view.count - 1;
+
+ onOpacityChanged: {
+ if (opacity > 0)
+ requestPaint();
+ }
+ Text {
+ id:comment
+ x:100
+ y:50
+ font.pointSize: 20
+ color:"white"
+ opacity: 0.7
+ focus:false
+ }
+
+// Text {
+// id:priceAxis
+// x:25
+// y:25
+// font.pointSize: 15
+// color:"yellow"
+// opacity: 0.7
+// focus: false
+// }
+// Text {
+// id:volumeAxis
+// x:canvas.width - 25
+// y:25
+// font.pointSize: 15
+// color:"yellow"
+// opacity: 0.7
+// }
+
+ PinchArea {
+ anchors.fill: parent
+ onPinchUpdated : {
+ var current = pinch.center;
+ var scale = pinch.scale;
+ console.log("center:" + pinch.center + " scale:" + pinch.scale);
+ //canvas.requestPaint();
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+
+ onDoubleClicked: {
+ if (stockModel.dataCycle == StockModel.Daily)
+ stockModel.dataCycle = StockModel.Weekly;
+ else if (stockModel.dataCycle == StockModel.Weekly)
+ stockModel.dataCycle = StockModel.Monthly;
+ else
+ stockModel.dataCycle = StockModel.Daily;
+ }
+
+ onPositionChanged: {
+ if (mouse.modifiers & Qt.ControlModifier) {
+ if (canvas.mouseX == 0 && canvas.mouseY == 0) {
+ canvas.mouseX = mouse.x;
+ canvas.mouseY = mouse.y;
+ }
+ } else{
+ var w = (view.width/view.count)*canvas.scaleX;
+
+ //canvas.movedY += Math.round((canvas.mousePressedY - mouse.y)/2);
+
+ var movedX = Math.round((canvas.mousePressedX - mouse.x)/w);
+ if (movedX != 0 || canvas.movedY != 0) {
+ if (canvas.first + movedX >= 0 && canvas.last + movedX < view.count) {
+ canvas.first += movedX;
+ canvas.last += movedX;
+ }
+ canvas.requestPaint();
+ }
+ }
+ }
+
+ onPressed: {
+ canvas.mousePressedX = mouse.x;
+ canvas.mousePressedY = mouse.y;
+ }
+
+ onReleased : {
+ if (mouse.modifiers & Qt.ControlModifier) {
+ var sx = mouse.x - canvas.mouseX;
+ var sy = canvas.mouseY - mouse.y;
+
+ if (Math.abs(sx) < 50) sx = 0;
+ if (Math.abs(sy) < 50) sy = 0;
+
+ if (sx > 0)
+ canvas.scaleX *= sx/100 +1;
+ else
+ canvas.scaleX *= 1/(-sx/100 + 1);
+
+ if (sy > 0)
+ canvas.scaleY *= sy/100 +1;
+ else
+ canvas.scaleY *= 1/(-sy/100 + 1);
+
+ if (canvas.scaleX < 1)
+ canvas.scaleX = 1;
+
+ //console.log("scaleX:" + canvas.scaleX + ", scaleY:" + canvas.scaleY);
+
+ canvas.first = Math.round(view.currentIndex - view.currentIndex / canvas.scaleX);
+ canvas.last = Math.round(view.currentIndex + (view.count - view.currentIndex) / canvas.scaleX);
+
+ canvas.mouseX = 0;
+ canvas.mouseY = 0;
+ canvas.mousePressedX = 0;
+ canvas.mousePressedY = 0;
+ canvas.requestPaint();
+ }
+ }
+ }
+
+ function showPriceAt(x) {
+ var w = (view.width/view.count)*canvas.scaleX;
+ header.updateCurrent(stockModel.stockPriceAtIndex(canvas.first + Math.round(x/w)));
+ //console.log("x:" + x + " w:" + w + " index:" + (canvas.first + Math.round(x/w)));
+ }
+
+ function drawPrice(ctx, from, to, color, price, points, highest)
+ {
+ ctx.globalAlpha = 0.7;
+ ctx.strokeStyle = color;
+ ctx.lineWidth = 1;
+ ctx.beginPath();
+
+ //price x axis
+// priceAxis.text = "price:" + Math.round(highest);
+ ctx.font = "bold 12px sans-serif";
+
+ ctx.strokeText("price", 25, 25);
+ for (var j = 1; j < 30; j++) {
+ var val = (highest * j) / 30;
+ val = canvas.height * (1 - val/highest);
+ ctx.beginPath();
+
+ ctx.moveTo(10, val);
+ if (j % 5)
+ ctx.lineTo(15, val);
+ else
+ ctx.lineTo(20, val);
+ ctx.stroke();
+ }
+
+ ctx.beginPath();
+ ctx.moveTo(10, 0);
+ ctx.lineTo(10, canvas.height);
+ ctx.stroke();
+
+
+ var w = canvas.width/points.length;
+ for (var i = 0; i < points.length; i++) {
+ var x = points[i].x;
+ var y = points[i][price];
+ y += canvas.movedY;
+
+ y = canvas.height * (1 - y/highest);
+ if (i == 0) {
+ ctx.moveTo(x+w/2, y);
} else {
- view.positionViewAtEnd();
+ ctx.lineTo(x+w/2, y);
}
- view.beginning = !view.beginning;
}
+ ctx.stroke();
+ }
+
+ function drawKLine(ctx, from, to, points, highest)
+ {
+ ctx.globalAlpha = 0.4;
+ ctx.lineWidth = 2;
+ for (var i = 0; i < points.length; i++) {
+ var x = points[i].x;
+ var open = canvas.height * (1 - points[i].open/highest) - canvas.movedY;
+ var close = canvas.height * (1 - points[i].close/highest) - canvas.movedY;
+ var high = canvas.height * (1 - points[i].high/highest) - canvas.movedY;
+ var low = canvas.height * (1 - points[i].low/highest) - canvas.movedY;
+
+ var top, bottom;
+ if (close <= open) {
+ ctx.fillStyle = Qt.rgba(1, 0, 0, 1);
+ ctx.strokeStyle = Qt.rgba(1, 0, 0, 1);
+ top = close;
+ bottom = open;
+ } else {
+ ctx.fillStyle = Qt.rgba(0, 1, 0, 1);
+ ctx.strokeStyle = Qt.rgba(0, 1, 0, 1);
+ top = open;
+ bottom = close;
+ }
+
+ var w1, w2;
+ w1 = canvas.width/points.length;
+ w2 = w1 > 10 ? w1/2 : w1;
+
+ ctx.fillRect(x + (w1 - w2)/2, top, w2, bottom - top);
+ ctx.beginPath();
+ ctx.moveTo(x+w1/2, high);
+ ctx.lineTo(x+w1/2, low);
+ ctx.stroke();
+ }
+ ctx.globalAlpha = 1;
+
+ }
+
+ function drawVolume(ctx, from, to, color, price, points, highest)
+ {
+ ctx.fillStyle = color;
+ ctx.globalAlpha = 0.6;
+ ctx.strokeStyle = Qt.rgba(0.8, 0.8, 0.8, 1);
+ ctx.lineWidth = 1;
+
+ //volume x axis
+// volumeAxis.text = "volume:" + Math.round(highest);
+ for (var j = 1; j < 30; j++) {
+ var val = (highest * j) / 30;
+ val = canvas.height * (1 - val/highest);
+ ctx.beginPath();
+ if (j % 5)
+ ctx.moveTo(canvas.width - 15, val);
+ else
+ ctx.moveTo(canvas.width - 20, val);
+ ctx.lineTo(canvas.width - 10, val);
+ ctx.stroke();
+ }
+
+ ctx.beginPath();
+ ctx.moveTo(canvas.width - 10, 0);
+ ctx.lineTo(canvas.width - 10, canvas.height);
+ ctx.stroke();
+
+ for (var i = 0; i < points.length; i++) {
+ var x = points[i].x;
+ var y = points[i][price];
+ y = canvas.height * (1 - y/highest);
+ ctx.fillRect(x, y, canvas.width/points.length, canvas.height - y);
+ }
+ }
+
+ onPaint: {
+ if (view.currentIndex <= 0)
+ first = 0;
+ if (last >= view.count)
+ last = view.count - 1;
+
+ //console.log("painting... first:" + first + ", last:" + last + " current:" + view.currentIndex);
+ var ctx = canvas.getContext("2d");
+ ctx.reset();
+
+ ctx.globalCompositeOperation = "source-over";
+ ctx.lineWidth = 1;
+ ctx.lineJoin = "round";
+ ctx.fillStyle = "rgba(0,0,0,0)";
+
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+
+
+ var highestPrice = 500/canvas.scaleY;
+ var highestValume = 600 * 1000 * 1000/canvas.scaleY;
+ var points = [];
+ for (var i = 0; i <= last - first; i++) {
+ var price = stockModel.stockPriceAtIndex(i + first);
+ points.push({
+ x: i*canvas.width/(last-first+1),
+ open: price.openPrice,
+ close: price.closePrice,
+ high:price.highPrice,
+ low:price.lowPrice,
+ volume:price.volume
+ });
+ }
+
+ drawPrice(ctx, first, last, Qt.rgba(1, 0, 0, 1),"high", points, highestPrice);
+ drawPrice(ctx, first, last, Qt.rgba(0, 1, 0, 1),"low", points, highestPrice);
+ drawPrice(ctx, first, last, Qt.rgba(0, 0, 1, 1),"open", points, highestPrice);
+ drawPrice(ctx, first, last, Qt.rgba(0.5, 0.5, 0.5, 1),"close", points, highestPrice);
+ drawVolume(ctx, first, last, Qt.rgba(0.3, 0.5, 0.7, 1),"volume", points, highestValume);
+ drawKLine(ctx, first, last, points, highestPrice);
}
}
}
diff --git a/examples/declarative/canvas/stockchart/stockchart.pro b/examples/declarative/canvas/stockchart/stockchart.pro
index 84f2a286ab..7101c4c14d 100644
--- a/examples/declarative/canvas/stockchart/stockchart.pro
+++ b/examples/declarative/canvas/stockchart/stockchart.pro
@@ -11,4 +11,5 @@ macx: CONFIG -= app_bundle
CONFIG += console
OTHER_FILES += \
- stock.qml
+ stock.qml \
+ contents/Stocks.qml
diff --git a/examples/declarative/canvas/stockchart/stockchart.qrc b/examples/declarative/canvas/stockchart/stockchart.qrc
index a67f5d6437..68702ab7a1 100644
--- a/examples/declarative/canvas/stockchart/stockchart.qrc
+++ b/examples/declarative/canvas/stockchart/stockchart.qrc
@@ -1,6 +1,7 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>stock.qml</file>
+ <file>contents/Stocks.qml</file>
</qresource>
</RCC>