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.85) / (routeInfo.drawStations.length - 1);
        g.setColor(routeInfo.routeColor);
        g.fillRect(x + w * 0.075, y + h * 0.68, w * 0.85, h * 0.04);
        g.setColor(rgbToColor(124, 124, 124));
        g.fillRect(x + w * 0.075 + (headAlign != 2 ? w * 0.85 - drawInfo.index * distance : 0), y + h * 0.68, drawInfo.index * distance, h * 0.04);
        for (var i = 0; i < routeInfo.drawStations.length; i++) {
            var currentX = x + w * 0.075 + (headAlign == 2 ? i * distance : w * 0.85 - i * distance);
            var hasPassed = i < drawInfo.index;
            var thisStn = routeInfo.drawStations[i];
            if (thisStn.transInfo.length > 0) {
                var originalTransformForTrans = g.getTransform();
                var ribbonCenterY = (y + h * 0.68 - h * 0.1) + h * 0.05;
                if (thisStn.transInfo.length === 3) {
                    for (var j = 0; j < 3; j++) {
                        var centerX = currentX
                        var thisTrans = thisStn.transInfo[j];
                        var rotationAngle = 0;
                        var rectHeight = h * 0.1;
                        if (j === 0) {
                            rotationAngle = -Math.PI/4;
                            rectHeight = h * 0.14;
                            centerX -= h * 0.012;
                        } else if (j === 2) {
                            rotationAngle = Math.PI/4;
                            rectHeight = h * 0.14;
                            centerX += h * 0.012;
                        }
                        rotationAngle += Math.PI;
                        g.setTransform(AffineTransform.getRotateInstance(rotationAngle, centerX, ribbonCenterY + h * 0.05));
                        g.setColor(hasPassed ? rgbToColor(124, 124, 124) : thisTrans.routeColor);
                        g.fillRect(centerX - h * 0.01, (ribbonCenterY + h * 0.05) - rectHeight, h * 0.02, rectHeight);
                        g.setTransform(originalTransformForTrans);
                    }
                } else {
                    for (var j = 0; j < thisStn.transInfo.length; j++) {
                        var thisTrans = thisStn.transInfo[j];
                        var centerX = currentX - h * 0.03 + ((h * 0.06) / thisStn.transInfo.length) * (j + 0.5);
                        g.setColor(hasPassed ? rgbToColor(124, 124, 124) : thisTrans.routeColor);
                        var rectHeight = h * 0.1;
                        var rotationAngle = 0;
                        if (thisStn.transInfo.length === 2) {
                            if (j === 0) {
                                rotationAngle = Math.PI/8;
                                rectHeight = h * 0.11;
                                centerX += h * 0.012;
                            } else {
                                rotationAngle = -Math.PI/8;
                                rectHeight = h * 0.11;
                                centerX -= h * 0.012;
                            }
                            rotationAngle += Math.PI;
                        } else if (thisStn.transInfo.length === 1) {
                            rotationAngle = Math.PI;
                        }
                        g.setTransform(AffineTransform.getRotateInstance(rotationAngle, centerX, ribbonCenterY + h * 0.05));
                        g.fillRect(currentX - h * 0.01, (ribbonCenterY + h * 0.05) - rectHeight, h * 0.02, rectHeight);
                        g.setTransform(originalTransformForTrans);
                    }
                }
                if (thisStn.transInfo.length === 1) {
                    drawTransLineName(g, font, fontEN, thisStn.transInfo[0], currentX, y + h * 0.8, h, hasPassed);
                } 
                else if (thisStn.transInfo.length === 2) {
                    drawTransLineName(g, font, fontEN, thisStn.transInfo[0], currentX - h * 0.04, y + h * 0.8, h, hasPassed);
                    drawTransLineName(g, font, fontEN, thisStn.transInfo[1], currentX + h * 0.04, y + h * 0.8, h, hasPassed);
                }
                else if (thisStn.transInfo.length === 3) {
                    drawTransLineName(g, font, fontEN, thisStn.transInfo[2], currentX - h * 0.08, y + h * 0.8, h, hasPassed);
                    drawTransLineName(g, font, fontEN, thisStn.transInfo[1], currentX, y + h * 0.8, h, hasPassed);
                    drawTransLineName(g, font, fontEN, thisStn.transInfo[0], currentX + h * 0.08, y + h * 0.8, h, hasPassed);
                }
                g.setColor(hasPassed ? rgbToColor(124, 124, 124) : routeInfo.routeColor);
                g.fillOval(currentX - h * 0.04, y + h * 0.66, h * 0.08, h * 0.08);
                g.setColor(Color.WHITE);
                g.fillOval(currentX - h * 0.03, y + h * 0.67, h * 0.06, h * 0.06);
                if (thisStn.transInfo.length === 1) {
                    g.drawImage(changeImageColor(loadResource("img", "fangsu:ris/hz2trans1.png"), hasPassed ? rgbToColor(124, 124, 124) : routeInfo.routeColor),currentX - h * 0.03,y + h * 0.67,h * 0.06,h * 0.06,null);
                    g.drawImage(changeImageColor(loadResource("img", "fangsu:ris/hz2trans2.png"), hasPassed ? rgbToColor(124, 124, 124) : thisStn.transInfo[0].routeColor),currentX - h * 0.03,y + h * 0.67,h * 0.06,h * 0.06,null);
                } else if (thisStn.transInfo.length === 2) {
                    g.drawImage(changeImageColor(loadResource("img", "fangsu:ris/hz3trans1.png"), hasPassed ? rgbToColor(124, 124, 124) : routeInfo.routeColor),currentX - h * 0.03,y + h * 0.67,h * 0.06,h * 0.06,null);
                    g.drawImage(changeImageColor(loadResource("img", "fangsu:ris/hz3trans2.png"), hasPassed ? rgbToColor(124, 124, 124) : thisStn.transInfo[0].routeColor),currentX - h * 0.03,y + h * 0.67,h * 0.06,h * 0.06,null);
                    g.drawImage(changeImageColor(loadResource("img", "fangsu:ris/hz3trans3.png"), hasPassed ? rgbToColor(124, 124, 124) : thisStn.transInfo[1].routeColor),currentX - h * 0.03,y + h * 0.67,h * 0.06,h * 0.06,null);
                } else {
                    g.drawImage(changeImageColor(loadResource("img", "fangsu:ris/hz3trans1.png"), hasPassed ? rgbToColor(124, 124, 124) : thisStn.transInfo[0].routeColor),currentX - h * 0.03,y + h * 0.67,h * 0.06,h * 0.06,null);
                    g.drawImage(changeImageColor(loadResource("img", "fangsu:ris/hz3trans2.png"), hasPassed ? rgbToColor(124, 124, 124) : thisStn.transInfo[1].routeColor),currentX - h * 0.03,y + h * 0.67,h * 0.06,h * 0.06,null);
                    g.drawImage(changeImageColor(loadResource("img", "fangsu:ris/hz3trans3.png"), hasPassed ? rgbToColor(124, 124, 124) : thisStn.transInfo[2].routeColor),currentX - h * 0.03,y + h * 0.67,h * 0.06,h * 0.06,null);
                }
            } else {
                g.setColor(hasPassed ? rgbToColor(124, 124, 124) : routeInfo.routeColor);
                g.fillOval(currentX - h * 0.03, y + h * 0.67, h * 0.06, h * 0.06);
                g.setColor(Color.WHITE);
                g.fillOval(currentX - h * 0.02, y + h * 0.68, h * 0.04, h * 0.04);
            }
            g.setTransform(AffineTransform.getRotateInstance(-Math.PI/4, currentX, y + h * 0.8));
            var thisStnNameDL = String(thisStn.stationName).split('||')[0];
            var thisStnName = parseStr(thisStnNameDL);
            var thisCNWidth = getDLStringWidth(g, font, font, thisStnName[0], h * 0.07);
            if (i === drawInfo.index) {
                g.setColor(routeInfo.routeColor);
                g.fillRoundRect(currentX + h * 0.115, y + h * 0.8 - h * 0.17, thisCNWidth + h * 0.025, h * 0.075, h * 0.06, h * 0.07);
                g.fillOval(currentX + h * 0.155 + thisCNWidth, y + h * 0.8 - h * 0.255, h * 0.08, h * 0.08);
                var arrowImgPath = headAlign == 2 ? 
                    "fangsu:sign/routejtr.png" : 
                    "fangsu:sign/routejtl.png";
                g.drawImage(
                    loadResource("img", arrowImgPath), 
                    currentX + h * 0.155 + thisCNWidth, 
                    y + h * 0.8 - h * 0.255, 
                    h * 0.08, 
                    h * 0.08, 
                    null
                );
                g.setColor(Color.WHITE);
                drawStrDL(g, font, font, thisStnName[0], currentX + h * 0.125, y + h * 0.8 - h * 0.175, h * 0.07, 0, 0);
                g.setColor(routeInfo.routeColor);
                drawStrDL(g, fontEN, fontEN, thisStnName[1], currentX + h * 0.125, y + h * 0.8 - h * 0.1, h * 0.04, 0, 0);
            } else {
                g.setColor(hasPassed ? rgbToColor(124, 124, 124) : Color.BLACK);
                drawStrDL(g, font, fontEN, `${thisStnName[0]}|${thisStnName[1]}`, currentX + h * 0.125, y + h * 0.8 - h * 0.175, h * 0.1, 0, 0);
            }
            g.setTransform(originalTransform);
        }
    }
    function drawTransLineName(g, font, fontEN, transInfo, centerX, centerY, h, hasPassed) {
        var transRouteName = transInfo.routeName;
        var transRouteColor = hasPassed ? rgbToColor(124, 124, 124) : transInfo.routeColor;
        var fontSize = h * 0.046; 
        var paddingVertical = h * 0.046 * 0.1;
        var rectHeight = h * 0.046 + paddingVertical * 2;
        var capsuleRadius = rectHeight / 2;
        var match = transRouteName.match(/^([A-Za-z]*\d*|.)(.+)$/);
        var routeNumber = match != null ? match[1] : "";
        var routeSuffix = match != null ? match[2] : "";
        var routeSuffixParse = parseStr(routeSuffix);
        var routeSuffixStr = routeSuffixParse[0] + "|" + routeSuffixParse[1];
        if (routeNumber != "") {
            var maxSuffixWidth = getDLStringWidth(g, font, fontEN, "号线|Line 99", fontSize * 0.6);
            var origRouteSuffixWidth = getDLStringWidth(g, font, fontEN, routeSuffixStr, fontSize * 0.6);
            var routeSuffixWidth = origRouteSuffixWidth > maxSuffixWidth ? maxSuffixWidth : origRouteSuffixWidth;
            var maxNumWidth = getDLStringWidth(g, fontEN, fontEN, "99", fontSize * 0.9);
            var origRouteNumberWidth = getDLStringWidth(g, fontEN, fontEN, routeNumber, fontSize * 0.9);
            var routeNumberWidth = origRouteNumberWidth > maxNumWidth * 0.85 ? maxNumWidth * 0.85 : origRouteNumberWidth;
            var totalWidth = routeSuffixWidth + routeNumberWidth + fontSize * 0.2;
            var rectX = centerX - totalWidth / 2;
            g.setColor(transRouteColor);
            g.fillRoundRect(rectX, centerY - rectHeight / 2, totalWidth, rectHeight, h * 0.0125, h * 0.0125);
            var oldTransform = g.getTransform();
            g.setColor(Color.WHITE);
            g.translate(rectX + totalWidth - routeSuffixWidth - h * 0.0075, centerY - h * 0.012);
            g.scale(routeSuffixWidth / origRouteSuffixWidth, 1.0);
            g.translate(-(rectX + totalWidth - routeSuffixWidth - h * 0.0075), -(centerY - h * 0.012));
            drawStrDL(g, font, fontEN, routeSuffixStr, rectX + totalWidth - routeSuffixWidth - h * 0.005, centerY - h * 0.012, fontSize * 0.6, 0, 0);
            g.setTransform(oldTransform);
            g.translate(rectX + totalWidth - routeSuffixWidth - h * 0.0075, centerY + h * 0.0175);
            g.scale(routeNumberWidth / origRouteNumberWidth, 1.0);
            g.translate(-(rectX + totalWidth - routeSuffixWidth - h * 0.0075), -(centerY + h * 0.0175));
            drawStrUnified(g, fontEN, routeNumber, rectX + totalWidth - routeSuffixWidth - h * 0.005, centerY + h * 0.0175, fontSize * 0.9, 2);
            g.setTransform(oldTransform);
        } else {
            var maxRouteNameWidth = getDLStringWidth(g, font, fontEN, "四个汉字|w", fontSize);
            var origRouteNameWidth = getDLStringWidth(g, font, fontEN, transRouteName, fontSize);
            var routeNameWidth = origRouteNameWidth > maxRouteNameWidth ? maxRouteNameWidth : origRouteNameWidth;
            var totalWidth = routeNameWidth + fontSize * 0.2;
            var rectX = centerX - totalWidth / 2;
            g.setColor(transRouteColor);
            g.fillRoundRect(rectX, centerY - rectHeight / 2, totalWidth, rectHeight, capsuleRadius, capsuleRadius);
            var oldTransform = g.getTransform();
            g.setColor(Color.WHITE);
            g.translate(centerX, centerY);
            g.scale(routeNameWidth / origRouteNameWidth, 1.0);
            g.translate(-centerX, -centerY);
            drawStrDL(g, font, fontEN, transRouteName, centerX, centerY, fontSize, 1, 1);
            g.setTransform(oldTransform);
        }
    }
    function parseStr(src) {
        return String(src).split('|');
    }
}