function draw(g, state, drawInfo) {
    var x = drawInfo.texArea[0];
    var y = drawInfo.texArea[1];
    var w = drawInfo.texArea[2] - drawInfo.texArea[0];
    var h = drawInfo.texArea[3] - drawInfo.texArea[1];

    var font = loadResource("font", "mtrsteamloco:fonts/source-han-sans.otf");
    var fontBold = loadResource("font", "mtrsteamloco:fonts/source-han-sans-bold.otf");

    g.setColor(Color.WHITE);
    g.fillRect(drawInfo.texArea[0], drawInfo.texArea[1], drawInfo.texArea[2], drawInfo.texArea[3]);

    var routeInfo = drawInfo.routeInfo;

    if (routeInfo != null && routeInfo != undefined) {
        var originalClip = g.getClip();
        var originalTransform = g.getTransform();
        var routeColor = routeInfo.routeColor;
        var arrowSide = drawInfo.arrowDirection ? Number(drawInfo.arrowDirection) : 0;

        var distance = (w * 0.8) / (routeInfo.drawStations.length - 1);
        g.setColor(routeColor);
        g.fillRect(x + w * 0.1, y + h * 0.47, w * 0.8, h * 0.06);
        g.setColor(rgbToColor(124, 124, 124));
        g.fillRect(x + w * 0.1 + (arrowSide != 2 ? w * 0.8 - drawInfo.index * distance : 0), y + h * 0.47, drawInfo.index * distance, h * 0.06);

        for (var i = 0; i < routeInfo.drawStations.length; i++) {
            var currentX = x + w * 0.1 + (arrowSide == 2 ? i * distance : w * 0.8 - i * distance);
            var nameOnTop = i % 2 == 1;
            var hasPassed = i < drawInfo.index;
            var thisStn = routeInfo.drawStations[i];

            if (thisStn.transInfo.length > 0) {
                if (nameOnTop)
                    g.setClip(
                        new Polygon(
                            [currentX - h * 0.03, currentX - h * 0.03, currentX, currentX + h * 0.03, currentX + h * 0.03],
                            [y + h * 0.5, y + h * 0.6, y + h * 0.625, y + h * 0.6, y + h * 0.5],
                            5
                        )
                    );
                else
                    g.setClip(
                        new Polygon(
                            [currentX - h * 0.03, currentX - h * 0.03, currentX, currentX + h * 0.03, currentX + h * 0.03],
                            [y + h * 0.5, y + h * 0.4, y + h * 0.375, y + h * 0.4, y + h * 0.5],
                            5
                        )
                    );
                var finalCjkName = "",
                    finalNonCjkName = "";
                for (var j = 0; j < thisStn.transInfo.length; j++) {
                    var thisX = currentX - h * 0.03 + ((h * 0.06) / thisStn.transInfo.length) * j;
                    var thisTrans = thisStn.transInfo[j];
                    g.setColor(hasPassed ? rgbToColor(124, 124, 124) : thisTrans.routeColor);
                    g.fillRect(thisX, y + h * 0.3, (h * 0.06) / thisStn.transInfo.length, h * 0.4);
                    if (hasCjkPart(thisTrans.routeName))
                        if (finalCjkName == "") finalCjkName += "换乘" + getMatching(thisTrans.routeName, true);
                        else finalCjkName += `  ${getMatching(thisTrans.routeName, true)}`;
                    if (hasNonCjkPart(thisTrans.routeName))
                        if (finalNonCjkName == "") finalNonCjkName += "Trancefer to " + getMatching(thisTrans.routeName, false);
                        else finalNonCjkName += `  ${getMatching(thisTrans.routeName, false)}`;
                }
                g.setClip(originalClip);
                g.setColor(hasPassed ? rgbToColor(124, 124, 124) : Color.BLACK);
                drawStrDL(g, fontBold, fontBold, `${finalCjkName} | ${finalNonCjkName}`, currentX, nameOnTop ? y + h * 0.65 : y + h * 0.275, h * 0.075, 1, 1);

                g.setColor(hasPassed ? rgbToColor(124, 124, 124) : Color.BLACK);
                g.fillOval(currentX - h * 0.06, y + h * 0.44, h * 0.12, h * 0.12);
                g.setColor(Color.WHITE);
                g.fillOval(currentX - h * 0.05, y + h * 0.45, h * 0.1, h * 0.1);
                g.drawImage(
                    changeImageColor(loadResource("img", "fangsu:ris/imgtrans.png"), hasPassed ? rgbToColor(124, 124, 124) : Color.BLACK),
                    currentX - h * 0.04,
                    y + h * 0.46,
                    h * 0.08,
                    h * 0.08,
                    null
                );
            } else {
                g.setColor(hasPassed ? rgbToColor(124, 124, 124) : Color.BLACK);
                g.fillOval(currentX - h * 0.04, y + h * 0.46, h * 0.08, h * 0.08);
                g.setColor(Color.WHITE);
                g.fillOval(currentX - h * 0.03, y + h * 0.47, h * 0.06, h * 0.06);
            }

            if (i == drawInfo.index) {
                var strWidth = getDLStringWidth(g, fontBold, fontBold, thisStn.stationName, h * 0.2);
                g.setColor(routeColor);
                g.fillRoundRect(currentX - strWidth * 0.5 - h * 0.0075, y + h * (nameOnTop ? 0.225 : 0.575), strWidth + h * 0.015, h * 0.2, h * 0.05, h * 0.05);
                g.setColor(isLightColor(routeColor) ? Color.BLACK : Color.WHITE);
                drawStrDL(g, fontBold, fontBold, thisStn.stationName, currentX, y + h * (nameOnTop ? 0.25 : 0.6), h * 0.15, 1, 1);
            } else {
                g.setColor(hasPassed ? rgbToColor(124, 124, 124) : Color.BLACK);
                drawStrDL(g, fontBold, fontBold, thisStn.stationName, currentX, y + h * (nameOnTop ? 0.25 : 0.6), h * 0.15, 1, 1);
            }
        }
    }
}
