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 routeInfo = drawInfo.routeInfo;

    var CircularState = {
        NONE: "NONE",
        CLOCKWISE: "CLOCKWISE",
        ANTICLOCKWISE: "ANTICLOCKWISE"
    };

    if (routeInfo != null && routeInfo != undefined) {
        var font = loadResource("font", "mtrsteamloco:fonts/source-han-sans.otf");
        var fontBold = loadResource("font", "mtrsteamloco:fonts/source-han-sans-bold.otf");
        var headAlign = drawInfo.arrowDirection ? Number(drawInfo.arrowDirection) : 0;

        var widthStationName = getDLStringWidth(g, fontBold, fontBold, routeInfo.drawStations[routeInfo.drawStations.length - 1].stationName, h * 0.5);
        var widthRouteName =
            isNumLine(routeInfo.routeName) && hasCjkPart(routeInfo.routeName) && hasNonCjkPart(routeInfo.routeName)
                ? getDLStringWidth(g, fontBold, fontBold, `号线|${getMatching(routeInfo.routeName, false)}`, h * 0.2) +
                  getUnifiedStringWidth(g, fontBold, String(getCJKLineName(getMatching(routeInfo.routeName, true))), h * 0.225)
                : getDLStringWidth(g, fontBold, fontBold, routeInfo.routeName, h * 0.2);
        var nextStationWidth =
            getDLStringWidth(g, fontBold, fontBold, "下一站|Next Station", h * 0.2) +
            getDLStringWidth(g, fontBold, fontBold, routeInfo.drawStations[drawInfo.index + 1].stationName, h * 0.2) +
            h * 0.2;

        var leftBaseX = widthPercent(0.5) - (h * 0.3 + Math.max(widthRouteName, nextStationWidth) + widthStationName) * 0.5 + Math.max(widthRouteName, nextStationWidth) * 0.5;
        var rightBaseX = widthPercent(0.5) + (h * 0.3 + Math.max(widthRouteName, nextStationWidth) + widthStationName) * 0.5 - widthStationName * 0.5;

        g.setColor(isLightColor(routeInfo.routeColor) ? Color.BLACK : Color.WHITE);

        if (isNumLine(routeInfo.routeName) && hasCjkPart(routeInfo.routeName) && hasNonCjkPart(routeInfo.routeName)) {
            var numWidth = getUnifiedStringWidth(g, fontBold, String(getCJKLineName(getMatching(routeInfo.routeName, true))), h * 0.225);

            drawStrUnified(
                g,
                fontBold,
                String(getCJKLineName(getMatching(routeInfo.routeName, true))),
                leftBaseX + numWidth * 0.5 - drawStrDL(g, fontBold, fontBold, `号线|${getMatching(routeInfo.routeName, false)}`, leftBaseX + numWidth * 0.5, heightPercent(0.25), h * 0.2, 1, 0) * 0.5,
                heightPercent(0.45),
                h * 0.225,
                2
            );
        } else drawStrDL(g, fontBold, fontBold, routeInfo.routeName, leftBaseX, heightPercent(0.25), h * 0.2, 1, 1);

        drawStrDL(g, fontBold, fontBold, "下一站|Next Station", leftBaseX - h * 0.1, heightPercent(0.55), h * 0.2, 2, 2);
        drawStrDL(g, fontBold, fontBold, routeInfo.drawStations[drawInfo.index + 1].stationName, leftBaseX + h * 0.1, heightPercent(0.55), h * 0.2, 0, 0);

        drawStrDL(g, fontBold, fontBold, routeInfo.drawStations[routeInfo.drawStations.length - 1].stationName, rightBaseX, heightPercent(0.25), h * 0.5, 1, 1);
    }

    function widthPercent(p) {
        return x + w * p;
    }
    function heightPercent(p) {
        return y + h * p;
    }
}
