Canvas - keeping curved text centered
-
Hi all,
I'm recreating a watch face with working time/day/date. I'm pretty much there but can't workout how to keep the day name central to the top of the arc.
I thought I would go with using the index of the given day to call the angle for that text. I've failed and gone round in circles.
The day names vary slightly in length which is why I'm trying to use an array of angles to set the position within the day window of the watch face.
I've omitted a lot of code, the watch face/hands/date/etc, leaving just the code for Canvas including stuff I've tried/wanted to keep/play with.
Perhaps there is a better way than my current approach?
import QtQuick 2.6 import QtQuick.Controls 2.0 //originally Sailfish.Silica 1.0 //import "../images" Item { anchors.fill: parent Canvas { id: day smooth: true antialiasing: true anchors.fill: parent onPaint: { var ctx = getContext("2d"); var radius = 1080; var centerX = width/2; var centerY = height/2; var angle = Math.PI * .28; ctx.font = "bold 44px Mono Bold"; ctx.textAlign = "center"; var dayname = Qt.formatDate(new Date(), "dddd") //var days = {"sunday":-1.16, "monday":-1.16, "tuesday":-1.15, "wednesday":-1.11, "thursday":-1.13, "friday":-1.17, "saturday":-1.13}; //function getAnglePosition(day) { // return days[day]; //} //console.log(getAnglePosition(dayname)); var ang = [-1.16, -1.16, -1.15, -1.11, -1.13, -1.17, -1.13 ]; //var dayname = ["sunday","monday","tuesday","wednesday","thursday","friday","saturday"][new Date().getDay()] console.log(dayname) drawTextAlongArc(ctx, dayname, centerX, centerY, radius, angle); //console.log(days = Qt.formatDate(new Date(), "dddd")) //console.log(days) //var ang = [-1.16, -1.16, -1.15, -1.11, -1.13, -1.17, -1.13 ]; } function drawTextAlongArc(ctx, str, centerX, centerY, radius, angle) { ctx.save(); ctx.clearRect(0, 0, day.width, day.height); ctx.fillStyle = "white"; ctx.translate(centerX, centerY); //ctx.rotate(-1.15 * angle / 2); ctx.rotate(dayname.rotation * angle / 2); // rotate day name ctx.rotate(0.00 * (angle / str.length)); for (var n = 0; n < str.length; n++) { var char1 = str[n]; ctx.rotate(angle / str.length); ctx.save(); ctx.translate(0, -0.386 * radius); ctx.fillText(char1.toUpperCase(), 0, 0); ctx.restore(); } ctx.restore(); } Label { id: dayname //text: Qt.formatDate(new Date(), "dddd") //rotation: -1.15 } Timer { id: timer running: pageStack.depth === 1 repeat: true onTriggered: { day.requestPaint(); //console.log(day.drawTextAlongArc.dayname = Qt.formatDate(new Date(), "dddd")) //console.log(rotateDay.text = angleValue.value) } triggeredOnStart: true } } }
The end result looks something like the following image;
-
This is how it is done, with the help of ChatGPT!;
Canvas { id: canvas width: 400 height: 400 rotation: 180 anchors.centerIn: parent onPaint: { var ctx = getContext("2d"); ctx.clearRect(0, 0, width, height); / / Get the name of today var today = new Date(); var dayName = Qt.formatDate(today, "dddd").toUpperCase(); //var dayName = "wednesday".toUpperCase(); // Arc parameters var centerX = width / 2; var centerY = height / 2; var radius = 430; var totalArcLength = Math.PI * 0.24; // The length of the arc (3/4th of a circle) // Calculate dynamic letter spacing based on available arc length and number of letters var letterSpacing = totalArcLength / (dayName.length - 1); var startAngle = (Math.PI - totalArcLength) / 2; // Center the text on the arc ctx.font = "44px Mono Bold"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; for (var i = 0; i < dayName.length; i++) { var angle = startAngle + i * letterSpacing; var x = centerX + radius * Math.cos(angle); var y = centerY + radius * Math.sin(angle); ctx.save(); ctx.translate(x, y); ctx.rotate(angle + Math.PI / 2); // Rotate the context to align the text along the arc ctx.fillText(dayName[i], 0, 0); ctx.restore(); } } Component.onCompleted: canvas.requestPaint() } }
-
M Markkyboy has marked this topic as solved on