Warning, /webapps/qmlonline/qml/examples/canvasadvanced.qml is written in an unsupported language. File is not indexed.
0001 import QtQuick 2.13
0002 import QtQuick.Controls 2.5
0003
0004 Item {
0005 id: root
0006 anchors.fill: parent
0007 focus: true
0008
0009 MouseArea {
0010 id: globalMouse
0011 hoverEnabled: true
0012 anchors.fill: parent
0013 }
0014
0015 ListModel {
0016 id: listModel
0017 }
0018
0019 Canvas {
0020 id: canvas
0021 anchors.fill: parent
0022 property var path: listModel
0023
0024 function getArea() {
0025 // Shoelace algorithm
0026 // Ref: https://en.wikipedia.org/wiki/Shoelace_formula
0027 var sum = 0
0028
0029 for(var i = 0; i < path.count; i++) {
0030 var point = path.get(i)
0031 var nextPoint = i + 1 != path.count ? path.get(i + 1) : path.get(0)
0032
0033 sum += point.xPos*nextPoint.yPos - nextPoint.xPos*point.yPos
0034 }
0035
0036 return Math.abs(sum) / 2
0037 }
0038
0039 function getCentroid() {
0040 // Calculate the centroid of a non-self-intersecting closed polygon defined by n vertices
0041 // Ref: https://en.wikipedia.org/wiki/Centroid
0042 var areaMultiplied = 6*getArea()
0043 var centroid = {xPos: 0, yPos: 0}
0044
0045 for(var i = 0; i < path.count; i++) {
0046 var point = path.get(i)
0047 var nextPoint = i + 1 != path.count ? path.get(i + 1) : path.get(0)
0048
0049 var multiplier = point.xPos*nextPoint.yPos - nextPoint.xPos*point.yPos
0050 centroid.xPos += (point.xPos + nextPoint.xPos)*multiplier
0051 centroid.yPos += (point.yPos + nextPoint.yPos)*multiplier
0052 }
0053
0054 centroid.xPos = Math.abs(centroid.xPos/areaMultiplied)
0055 centroid.yPos = Math.abs(centroid.yPos/areaMultiplied)
0056 return centroid
0057 }
0058
0059 onPaint: {
0060 var context = getContext("2d");
0061 context.reset();
0062
0063 // Do not paint if there isn't enough points to create a line
0064 if(path.count < 2){
0065 return;
0066 }
0067
0068 var firstPoint = path.get(0)
0069 context.beginPath()
0070 context.moveTo(firstPoint.xPos, firstPoint.yPos)
0071 context.lineWidth = 2
0072 context.strokeStyle = "red"
0073 context.textAlign = "center"
0074
0075 for(var i = 1; i < path.count; i++) {
0076 // Create line with 2 points
0077 var previousPoint = path.get(i - 1)
0078 var point = path.get(i)
0079
0080 // Calculate line middle point
0081 var middlePoint = {xPos: (point.xPos + previousPoint.xPos)/2, yPos: (point.yPos + previousPoint.yPos)/2}
0082 // Translated line to the origin
0083 var translatedLine = {xPos: point.xPos - previousPoint.xPos, yPos: point.yPos - previousPoint.yPos}
0084 // Calculate relative distance between the line points
0085 var relativeDistance = Math.hypot(translatedLine.yPos, translatedLine.xPos)
0086 // Calculate line angle
0087 var angle = Math.atan(translatedLine.yPos/translatedLine.xPos)
0088
0089 // Translate and rotate context to draw distance text
0090 context.save();
0091 context.translate(middlePoint.xPos, middlePoint.yPos);
0092 context.rotate(angle);
0093 context.fillStyle = "blue"
0094 context.fillText(relativeDistance.toFixed(2), 0, -5);
0095 // Restore from translation and rotation
0096 context.restore()
0097
0098 // Draw line to the next point
0099 context.lineTo(point.xPos, point.yPos)
0100 }
0101
0102 // If there is enough points to create a polygon, fill it and add area information
0103 if(path.count > 2) {
0104 var centerPoint = getCentroid()
0105 context.fillStyle = "green"
0106 context.fillText(getArea().toFixed(2), centerPoint.xPos, centerPoint.yPos)
0107 context.fillStyle = "#22000033"
0108 context.fill()
0109 }
0110 context.stroke()
0111 }
0112 }
0113
0114 Repeater {
0115 id: repeater
0116 model: canvas.path
0117 delegate: Rectangle {
0118 width: 10
0119 height: width
0120 color: "black"
0121 radius: width
0122 x: xPos - width/2
0123 y: yPos - height/2
0124 MouseArea {
0125 anchors.fill: parent
0126 drag.target: parent
0127 onPositionChanged: {
0128 canvas.path.get(index).xPos = parent.x + width/2
0129 canvas.path.get(index).yPos = parent.y + height/2
0130 canvas.requestPaint()
0131 }
0132 }
0133 }
0134 }
0135
0136 Keys.onPressed: {
0137 switch(event.key) {
0138 case Qt.Key_N:
0139 var newPoint = {xPos: globalMouse.mouseX, yPos: globalMouse.mouseY}
0140 print("New point:", JSON.stringify(newPoint))
0141 event.accepted = true
0142
0143 canvas.path.append({xPos: globalMouse.mouseX, yPos: globalMouse.mouseY})
0144 canvas.requestPaint()
0145 break;
0146
0147 case Qt.Key_D:
0148 var lastIndex = canvas.path.count - 1
0149 print("Delete last point:", JSON.stringify(canvas.path.get(lastIndex)))
0150 event.accepted = true
0151
0152 canvas.path.remove(lastIndex, 1)
0153 canvas.requestPaint()
0154 break;
0155
0156 default:
0157 print("We don't handle it.")
0158 event.accepted = false
0159 }
0160 }
0161
0162 Label {
0163 anchors.top: parent.top
0164 text: "New Point: 'N', Delete Point: 'D'"
0165 font.pixelSize: 30
0166 }
0167 }