import QtQuick 2.10 import QtQuick.Controls 2.4 import QtQuick.Controls.Material 2.1 ListView { id: control property var flowchartData property var allFlowchartData property int rounds property int tileSize: app.height / 8 * 0.8 anchors.fill: parent anchors.margins: 10 model: rounds + 2 spacing: app.width * 0.1 orientation: ListView.LeftToRight boundsBehavior: ListView.StopAtBounds onFlowchartDataChanged: { prepareData() } function prepareData() { // array to store the restructured data var allData = [] for(var round in flowchartData['route_names']){ if(flowchartData['route_names'].hasOwnProperty(round) && parseInt(round) >= 0){ console.log(round) if(allData.length > 0){ allData[allData.length-1].push(round) allData[allData.length-1].push(flowchartData['route_names'][round]) } if(parseInt(round) === 0){ // this is the first round // find pairs (always wors vs. best (1-16; 1-15; ...)) (they are sorted by the rank of the better athlete (1-2-3-4-5-6-7-8) var qualificationResults = [] for(var x = 0; x < flowchartData['participants'].length; x++){ qualificationResults.push(flowchartData['participants'][x]) } qualificationResults.sort(function(a, b) { return parseInt(a["result_rank0"]) - parseInt(b["result_rank0"]); }); var nextRoundPairs = [] var nextRoundMatches = Math.pow(2, control.model-1) for(var i = 0; i < nextRoundMatches; i++){ nextRoundPairs.push([qualificationResults[i], qualificationResults[nextRoundMatches*2-i-1]]) } // build second round pairs (sorted by the rank of the better athlete and worst vs. best (1-8; 2-7; ... )) var sortedFirstRoundPairs = [] for(i = 0; i < nextRoundMatches; i += 1){ sortedFirstRoundPairs.push([nextRoundPairs.shift(), nextRoundPairs.pop()]) } // sort these pairs (containing two pairs of athletes) by the rank of the better athlete (1-4;2-3) var finalSortedFirstRoundPairs = [] for(i=0; i < nextRoundMatches/4; i++){ finalSortedFirstRoundPairs.push(sortedFirstRoundPairs[i]) finalSortedFirstRoundPairs.push(sortedFirstRoundPairs[nextRoundMatches/2-i-1]) } // convert the list of pairs of pairs of athletes back to a single list of pairs of athletes var finalFirstRoundPairs = [] for(i=0; i < finalSortedFirstRoundPairs.length; i++){ finalFirstRoundPairs.push(finalSortedFirstRoundPairs[i][0]) finalFirstRoundPairs.push(finalSortedFirstRoundPairs[i][1]) } // push the first round to all data allData.push(finalFirstRoundPairs) } else if(parseInt(round) > 0 ){ // this is not the first round var nextRound = [] // only used when the current round is the 1/2 final var smallFinal = [] var Final = [] for(var i = 0; i < allData[allData.length-1].length-2; i+=1){ var thisPair = allData[allData.length-1][i] var thisWinner var thisLooser var thisWinnerIsFirstOfNewPair = i%2 === 0 if(thisWinnerIsFirstOfNewPair){ nextRound.push([]) } //thisPair[0]["result_rank"] = thisPair[0]["result_rank"+round] //thisPair[1]["result_rank"] = thisPair[1]["result_rank"+round] if(parseInt(thisPair[0]["result_rank"+round]) < parseInt(thisPair[1]["result_rank"+round])){ thisWinner = thisPair[0] thisLooser = thisPair[1] } else { thisWinner = thisPair[1] thisLooser = thisPair[0] } console.log(thisWinner['firstname']+" has won in round " + round) //thisWinner.win = false //thisLooser.win = true if(round - control.rounds === 2){ // if we are in the 1/2 final Final.push(thisWinner) smallFinal.push(thisLooser) } else { nextRound[nextRound.length-1].push(thisWinner) } } if(smallFinal.length > 0 && Final.length > 0){ // Final allData.push([Final, parseInt(round)+2, flowchartData['route_names'][String(parseInt(round)+2)] + " / " + flowchartData['route_names'][String(parseInt(round)+1)] ]) // small Final allData.push([smallFinal, parseInt(round)+1]) break } else { //nextRound.push(round) //nextRound.push(flowchartData['route_names'][round]) allData.push(nextRound) } } } } control.allFlowchartData = allData } delegate: Column { id: roundCol property int thisIndex: index property int thisRound: control.allFlowchartData[roundCol.thisIndex][control.allFlowchartData[roundCol.thisIndex].length-2] property bool thisIsLastRound: thisIndex === control.model - 1 width: app.width * 0.5 height: control.height //spacing: app.width * 0.1 Label { id: roundNameLa width: parent.width horizontalAlignment: Text.AlignHCenter font.bold: true text: control.allFlowchartData[roundCol.thisIndex][control.allFlowchartData[roundCol.thisIndex].length-1] } Repeater { id: rectRep model: Math.max( Math.pow(2, control.model-1) * Math.pow(0.5, (index)), 2) delegate: Item { id: matchItm property bool lowerPart: (index%2 > 0) property int thisIndex: index property var thisMatchData: control.allFlowchartData[ thisIsSemifinal ? roundCol.thisIndex+1 : roundCol.thisIndex][matchItm.thisIndex] property bool thisIsFinal: roundCol.thisIsLastRound && thisIndex === rectRep.model - 2 property bool thisIsSemifinal: roundCol.thisIsLastRound && thisIndex === rectRep.model - 1 Component.onCompleted: { if(thisIsSemifinal){ console.log("this is semi final") console.log(thisMatchData) } console.log(thisMatchData) } height: !roundCol.thisIsLastRound ? (roundCol.height - roundNameLa.height) / rectRep.model - roundCol.spacing : (thisIsFinal ? (roundCol.height - roundNameLa.height) * 0.5 + control.tileSize * 0.5 : (roundCol.height - roundNameLa.height) - (roundCol.height - roundNameLa.height) * 0.5 + control.tileSize * 0.5 ) width: parent.width Canvas { id: lineCanvas width: app.width; height: app.height contextType: "2d" visible: !roundCol.thisIsLastRound property int targetX: matchItm.width + control.spacing property int targetY: matchItm.lowerPart ? 0:matchItm.height Path { id: myPath startX: matchRect.x + matchRect.width * matchRect.scale ; startY: matchRect.y + matchRect.height * 0.5 PathCurve { x: lineCanvas.targetX ; y: lineCanvas.targetY } } onPaint: { context.strokeStyle = Qt.rgba(.4,.6,.8); context.path = myPath; context.stroke(); } } Rectangle { id: matchRect anchors { centerIn: !matchItm.thisIsFinal ? parent:undefined bottom: matchItm.thisIsFinal ? parent.bottom:undefined } //anchors.verticalCenterOffset: matchItm.lowerPart ? 10:10 width: parent.width height: control.tileSize //scale: 0.9 color: "white" border.color: "lightgrey" border.width: 1 radius: height * 0.2 Material.elevation: 10 Grid { columns: app.landscape() ? 2:0 rows: app.landscape() ? 0:2 anchors.fill: parent anchors.margins: matchRect.radius * 0.5 Repeater { // for the two athletes model: 2 delegate: Row { height: app.landscape() ? parent.height:parent.height / 2 width: app.landscape() ? parent.width / 2 : parent.width spacing: app.landscape() ? width * 0.1:height * 0.05 Label { height: parent.height width: parent.width * 0.2 verticalAlignment: Text.AlignVCenter font.pixelSize: height * 0.6 fontSizeMode: Text.Fit minimumPixelSize: 1 text: matchItm.thisMatchData[index]['result_rank0'] } Label { height: parent.height width: parent.width * 0.5 verticalAlignment: Text.AlignVCenter font.pixelSize: height * 0.6 fontSizeMode: Text.Fit minimumPixelSize: 1 color: (parseInt(matchItm.thisMatchData[0]["result_rank" + roundCol.thisRound ]) < parseInt(matchItm.thisMatchData[1]["result_rank" + roundCol.thisRound])) === (index === 0 ? true:false) ? "green":"black" text: matchItm.thisMatchData[index]['firstname'] + " " + matchItm.thisMatchData[index]['lastname'] } /*Rectangle { id: hasWonRect anchors.verticalCenter: parent.verticalCenter height: width width: parent.width * 0.1 scale: 0.7 radius: width * 0.5 color: "green" visible: (parseInt(matchItm.thisMatchData[0]["result_rank" + roundCol.thisRound ]) < parseInt(matchItm.thisMatchData[1]["result_rank" + roundCol.thisRound])) === (index === 0 ? true:false) }*/ } } } } } } } }