1

I created the below image in html and JavaScript where the alphabets curve around the arc of the image. I am trying to convert the code I wrote and properly inject the functions inside of a QT project. However, my current implementation does not work due TypeError: Type errors. Can someone help with this?

Also if possible: I would like to rotate the alphabets to be vertical to the arc instead of horizontal.

import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Canvas {
        anchors.fill: parent

        Image {
            id: abcBar
            source: "alphabetBar.png"
            visible: false
        }


        onPaint: {
            var ctx = getContext('2d');
            ctx.save();
            ctx.canvas.width = 160;
            ctx.canvas.height = 432;
            ctx.font = "18px Roboto";
            ctx.textAlign = "center";
            ctx.fillStyle = "#000000"

            const centerX = 10;
            const centerY = ctx.canvas.height / 2;
            const angle = Math.PI;
            const radius = 130
            ctx.fillStyle = "#000000"
            ctx.restore();


            ctx.save();
            ctx.drawImage(abcBar, 0, 0, ctx.canvas.width, ctx.canvas.height);
            console.log('loaded')
            ctx.restore();

            const args = {
                ctx,
                text: "A • D • G • J • M • P • S • V • Z",
                offset: 0,
                G1: {
                    x: 20,
                    y: 80,
                },
                G2: {
                    x: 190,
                    y: 230,
                },
                G3: {
                    x: 0,
                    y: 372
                },
            }
            textOnCurve(args);
        }
    }


    function textOnCurve({ ctx, text, offset, G1, G2, G3, G4}){

        const x1 = G1.x;
        const y1 = G1.y;
        const x2 = G2.x;
        const y2 = G2.y;
        const x3 = G3.x;
        const y3 = G3.y;
        const x4 = G3.x;
        const y4 = G3.y;

        ctx.save();
        ctx.textAlign = "center";

        var widths = [];
        for (var i = 0; i < text.length; i++)
        {
            widths[widths.length] = ctx.measureText(text[i]).width;
        }

        ctx.beginPath();
        var ch = curveHelper(x1, y1, x2, y2, x3, y3, x4, y4);
        ctx.stroke();

        var pos = offset;
        var cpos = 0;
        for (var j = 0; j < text.length; j++)
        {
            pos += widths[j] / 2;
            cpos = ch.forward(pos);
            ch.tangent(cpos);
            ctx.setTransform(ch.vect.x, ch.vect.y, -ch.vect.y, ch.vect.x, ch.vec.x, ch.vec.y);
            ctx.fillText(text[j], 0, 0);
            pos += widths[j] / 2;
        }
        ctx.restore();
    }

    function curveHelper(x1, y1, x2, y2, x3, y3, x4, y4)
    {
        var tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4;
        var a, b, c, u;
        var vec, currentPos, vec1, vect, quad, currentDist;
        vec = { x: 0, y: 0 } ;
        vec1 = { x: 0, y: 0 } ;
        vect = { x: 0, y: 0 } ;
        quad = false;
        currentPos = 0;
        currentDist = 0;
        if (x4 === undefined || x4 === null)
        {
            quad = true;
            x4 = x3;
            y4 = y3;
        }
        var estLen = Math.sqrt((x4 - x1)* (x4 - x1)+ (y4 - y1)* (y4 - y1));
        var onePix = 1 / estLen;

        function posAtC(c)
        {
            tx1 = x1; ty1 = y1;
            tx2 = x2; ty2 = y2;
            tx3 = x3; ty3 = y3;
            tx1 += (tx2 - tx1)* c;
            ty1 += (ty2 - ty1)* c;
            tx2 += (tx3 - tx2)* c;
            ty2 += (ty3 - ty2)* c;
            tx3 += (x4 - tx3)* c;
            ty3 += (y4 - ty3)* c;
            tx1 += (tx2 - tx1)* c;
            ty1 += (ty2 - ty1)* c;
            tx2 += (tx3 - tx2)* c;
            ty2 += (ty3 - ty2)* c;
            vec.x = tx1 + (tx2 - tx1)* c;
            vec.y = ty1 + (ty2 - ty1)* c;
            return vec;
        }

        function posAtQ(c)
        {
            tx1 = x1; ty1 = y1;
            tx2 = x2; ty2 = y2;
            tx1 += (tx2 - tx1)* c;
            ty1 += (ty2 - ty1)* c;
            tx2 += (x3 - tx2)* c;
            ty2 += (y3 - ty2)* c;
            vec.x = tx1 + (tx2 - tx1)* c;
            vec.y = ty1 + (ty2 - ty1)* c;
            return vec;
        }

        function forward(dist)
        {
            var step;
            helper.posAt(currentPos);
            while (currentDist < dist)
            {
                vec1.x = vec.x;
                vec1.y = vec.y;
                currentPos += onePix;
                helper.posAt(currentPos);
                currentDist += step = Math.sqrt((vec.x - vec1.x)* (vec.x - vec1.x)+ (vec.y - vec1.y)* (vec.y - vec1.y));
            }
                currentPos -= ((currentDist - dist)/ step)* onePix
                currentDist -= step;
                helper.posAt(currentPos);
                currentDist += Math.sqrt((vec.x - vec1.x)* (vec.x - vec1.x)+ (vec.y - vec1.y)* (vec.y - vec1.y));
                return currentPos;
        }

        function tangentQ(pos)
        {
            a = (1 - pos)* 2;
            b = pos * 2;
            vect.x = a * (x2 - x1)+ b * (x3 - x2);
            vect.y = a * (y2 - y1)+ b * (y3 - y2);
            u = Math.sqrt(vect.x * vect.x + vect.y * vect.y);
            vect.x /= u;
            vect.y /= u;
        }

        function tangentC(pos)
        {
            a = (1 - pos)
            b = 6 * a * pos;
            a *= 3 * a;
            c = 3 * pos * pos;
            vect.x = -x1 * a + x2 * (a - b)+ x3 * (b - c)+ x4 * c;
            vect.y = -y1 * a + y2 * (a - b)+ y3 * (b - c)+ y4 * c;
            u = Math.sqrt(vect.x * vect.x + vect.y * vect.y);
            vect.x /= u;
            vect.y /= u;
        }

        var helper = {
            vec: vec,
            vect: vect,
            forward: forward,
        }

        if (quad)
        {
            helper.posAt = posAtQ;
            helper.tangent = tangentQ;
        } else
        {
            helper.posAt = posAtC;
            helper.tangent = tangentC;
        }
            return helper
    }
}

Illustration created in html alphabetBar.png

1 Answer 1

1

The reference to Image on line 35 is not going to work because it is a browser-specific JavaScript class which is not available in the QML JavaScript runtime. Even though it seems like the QML Image class you have commented out should be referencable in the runtime, no QML components are directly referencable in JavaScript as classes like this.

You will need to port your code to use Canvas::loadImage() as documented here:

https://doc.qt.io/qt-5/qml-qtquick-canvas.html#loadImage-method

Or you can uncomment your QML Image object and call Context2d::drawImage() with its id as the first argument as documented here:

https://doc.qt.io/qt-5/qml-qtquick-context2d.html#drawImage-method-2

Note, if you do that, the Image will appear twice in the window unless you set visible: false on the QML one.

Sign up to request clarification or add additional context in comments.

7 Comments

I have a question in regards to the font. I get the following error Context2D: The font families specified are invalid: Verdana. The font size also does not change as well. What could be the issue here?
Does your platform have the Verdana font available? Does it work if you use "sans-serif" instead?
Does not seem to work with any of them
Did you add your image to the top of your QRC resource file? source is relative to the component it's used in and main.qml is usually running from your QRC file.
Agh that's right! I had the wrong name for the source. Thanks
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.