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 headAlign = drawInfo.arrowDirection ? Number(drawInfo.arrowDirection) : 0;
    g.setColor(Color.WHITE);
    g.fillRect(x, y, w, h);
    if (routeInfo != null && routeInfo != undefined) {
        const font = loadResource("font", "mtrsteamloco:fonts/simhei.otf");
        const fontEN = loadResource("font", "mtrsteamloco:fonts/arial.ttf");
        const originalTransform = g.getTransform();
        const distance = (w * 0.9) / (routeInfo.drawStations.length - 1);
        g.setColor(routeInfo.routeColor);
        g.fillRect(x + w * 0.05, y + h * 0.54, w * 0.9, h * 0.03);
        g.setColor(rgbToColor(124, 124, 124));
        g.fillRect(x + w * 0.05 + (headAlign != 2 ? w * 0.9 - drawInfo.index * distance : 0), y + h * 0.54, drawInfo.index * distance, h * 0.03);
        for (var i = 0; i < routeInfo.drawStations.length; i++) {
            var currentX = x + w * 0.05 + (headAlign == 2 ? i * distance : w * 0.9 - i * distance);
            var hasPassed = i < drawInfo.index;
            var thisStn = routeInfo.drawStations[i];
            var stationColor;
            if (i == drawInfo.index) {
                stationColor = Color.RED;
            } else if (hasPassed) {
                stationColor = rgbToColor(124, 124, 124);
            } else {
                stationColor = routeInfo.routeColor;
            }
            g.setColor(stationColor);
            var rectHeight = i != routeInfo.drawStations.length - 1 && i != 0 ? h * 0.06 : h * 0.09;
            g.fillRect(currentX - h * 0.025/2, y + h * 0.51, h * 0.025, rectHeight);
            if (thisStn.transInfo.length > 0) {
                for (var j = 0; j < thisStn.transInfo.length; j++) {
                    var lineY = y + h * 0.6 + j * h * 0.075;
                    drawTransLineName(g, font, fontEN, thisStn.transInfo[j], currentX, lineY, h, hasPassed);
                }
                g.setColor(stationColor);
                g.fillOval(currentX - h * 0.058 / 2, y + h * 0.468 + h * 0.06, h * 0.058, h * 0.058);
                g.setColor(Color.WHITE);
                g.fillOval(currentX - h * 0.038 / 2, y + h * 0.468 + h * 0.06 + h * 0.01, h * 0.038, h * 0.038);
                g.drawImage(
                    changeImageColor(loadResource("img", "fangsu:ris/imgtrans.png"), hasPassed ? rgbToColor(124, 124, 124) : Color.BLACK),
                    currentX - h * 0.038/2,
                    y + h * 0.468 + h * 0.06 + h * 0.01,
                    h * 0.038,
                    h * 0.038,
                    null
                );
            }
            var thisStnNameDL = String(thisStn.stationName).split('||')[0];
            var thisStnName = parseStr(thisStnNameDL);
            if (headAlign == 0 || headAlign == 1) {
                g.setTransform(AffineTransform.getRotateInstance(-Math.PI/4, currentX, y + h * 0.66));
                if (i == drawInfo.index) {
                    g.setColor(Color.RED);
                    drawStrDL(g, font, fontEN, `${thisStnName[0]}|${thisStnName[1]}`, currentX + h * 0.13, y + h * 0.66 - h * 0.2, h * 0.1, 0, 0);
                } else {
                    g.setColor(hasPassed ? rgbToColor(124, 124, 124) : Color.BLACK);
                    drawStrDL(g, font, fontEN, `${thisStnName[0]}|${thisStnName[1]}`, currentX + h * 0.13, y + h * 0.66 - h * 0.2, h * 0.1, 0, 0);
                }
                g.setTransform(originalTransform);
            } else {
                g.setTransform(AffineTransform.getRotateInstance(Math.PI/4, currentX, y + h * 0.66));
                if (i == drawInfo.index) {
                    g.setColor(Color.RED);
                    drawStrDL(g, font, fontEN, `${thisStnName[0]}|${thisStnName[1]}`, currentX - h * 0.13, y + h * 0.66 - h * 0.2, h * 0.1, 2, 2);
                } else {
                    g.setColor(hasPassed ? rgbToColor(124, 124, 124) : Color.BLACK);
                    drawStrDL(g, font, fontEN, `${thisStnName[0]}|${thisStnName[1]}`, currentX - h * 0.13, y + h * 0.66 - h * 0.2, h * 0.1, 2, 2);
                }
                g.setTransform(originalTransform);
            }
        }
        if (drawInfo.index != routeInfo.drawStations.length - 1) {
            const terminalStnDL = getNonExtraParts(routeInfo.drawStations[routeInfo.drawStations.length - 1].stationName);
            const terStaName = parseStr(terminalStnDL);
            const terText = `往${terStaName[0]}|To ${terStaName[1]}`
            if (headAlign == 0 || headAlign == 1) {
                g.drawImage(changeImageColor(loadResource("img", "fangsu:sign/jtl.png"), routeInfo.routeColor), x + w * 0.025, y + h * 0.85, h * 0.125, h * 0.125, null);
                drawStrDL(g, font, fontEN, terText, x + w * 0.025 + h * 0.15, y + h * 0.85, h * 0.125, 0, 0);
            } else {
                g.drawImage(changeImageColor(loadResource("img", "fangsu:sign/jtr.png"), routeInfo.routeColor), x + w * 0.975 - h * 0.125, y + h * 0.85, h * 0.125, h * 0.125, null);
                drawStrDL(g, font, fontEN, terText, x + w * 0.975 - h * 0.15, y + h * 0.85, h * 0.125, 2, 2);
            }
        }
    }
    function parseStr(src) {
        return String(src).split('|');
    }
    function drawTransLineName(g, font, fontEN, transInfo, centerX, centerY, h, hasPassed) {
        var transRouteColor = hasPassed ? rgbToColor(124, 124, 124) : transInfo.routeColor;
        var routeName = transInfo.routeName;
        var match = routeName.match(/^([A-Za-z]*\d*|.)(.+)$/);
        var routeNumber = match != null ? match[1] : "";
        var routeSuffix = match != null ? match[2] : "";
        var routeSuffixParse = parseStr(routeSuffix);
        var origRouteNumberWidth = getDLStringWidth(g, fontEN, fontEN, routeNumber, h * 0.05);
        var maxNumWidth = getDLStringWidth(g, fontEN, fontEN, "99", h * 0.05);
        var routeNumberWidth = origRouteNumberWidth > maxNumWidth * 0.9 ? maxNumWidth * 0.9 : origRouteNumberWidth;
        var oldTransform = g.getTransform();
        if (routeNumber != "") {
            g.setColor(hasPassed ? rgbToColor(124, 124, 124) : Color.BLACK);
            drawStrDL(g, font, fontEN, `${routeSuffixParse[0]}|${routeSuffixParse[1]}`, centerX, centerY, h * 0.05, 0, 0);
            g.setColor(transRouteColor);
            g.fillRoundRect(centerX - h * 0.05, centerY + h * 0.005, h * 0.05, h * 0.05, h * 0.0175, h * 0.0175);
            g.setColor(Color.WHITE);
            g.translate(centerX - h * 0.025, centerY + h * 0.045);
            g.scale(routeNumberWidth / origRouteNumberWidth, 1.0);
            g.translate(-(centerX - h * 0.025), - (centerY + h * 0.045));
            drawStrUnified(g, fontEN, routeNumber, centerX - h * 0.025, centerY + h * 0.045, h * 0.045, 1);
            g.setTransform(oldTransform);
        } else {
            var routeDL = parseStr(routeName);
            var origWidth = getDLStringWidth(g, font, fontEN, `${routeDL[0]}|${routeDL[1]}`, h * 0.045);
            var maxWidth = getDLStringWidth(g, font, fontEN, "三个字|a", h * 0.045);
            var Width = origWidth > maxWidth ? maxWidth : origWidth;
            g.setColor(transRouteColor);
            g.fillRoundRect(centerX - (Width + h * 0.02) / 2, centerY + h * 0.005, Width + h * 0.02, h * 0.05, h * 0.0175, h * 0.0175);
            g.setColor(Color.WHITE);
            g.translate(centerX, centerY);
            g.scale(Width / origWidth, 1.0);
            g.translate(-centerX, -centerY);
            drawStrDL(g, font, fontEN, `${routeDL[0]}|${routeDL[1]}`, centerX, centerY, h * 0.045, 1, 1);
            g.setTransform(oldTransform);
        }
    }
}