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 }