Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create half-circle menu (sub item) with CSS, Java Script on mobile web?

I want to use a half-circle menu when I surf the mobile web with right hand.

Can somebody teach me how to create half-circle menu (sub item) with CSS, Java Script on mobile web?

the photo link:

1.There is a half-circle menu button, it could be opened and closed.

enter image description here

2.When I click one of main level item, the sub item could be drop down.

enter image description here

Sincerely thanks.

like image 453
Alan Chen Avatar asked Feb 21 '26 23:02

Alan Chen


1 Answers

You can use SVG to achieve this design in HTML5 since most mobile browsers nowadays support SVG.

Demo

http://jsfiddle.net/DerekL/dQBzd/show

Code

http://jsfiddle.net/DerekL/dQBzd/

function drawMenu(selected) {
    $("svg").empty();
    var texts = ["國際", "生活", "文教", "健康", "科技", "新奇"],
        subTexts = [
            ["這裡", "有一大堆", "目錄"],
            ["A", "B", "C"],
            ["A", "B", "C"],
            ["A", "B", "C"],
            ["資訊3C", "科學發展", "自然環境", "科技熱門"],
            ["A", "B", "C"]
        ];

    var isSelected = selected !== undefined,
        columns = texts.length,
        angle = 12,                       //Angle (degree) of each menu
        subAngle = 8,                     //Angle (degree) of each submenu
        angleOut = (180 - angle * columns - (isSelected ? subAngle * subTexts[selected].length : 0)) / 2 * Math.PI / 180;
    angle *= Math.PI / 180;
    subAngle *= Math.PI / 180;

    var originX = 300,
        originY = 300,
        upper = getXY(angleOut, 220),
        lower = getXY(Math.PI - angleOut, 220);

    $("<path/>").attr("d", [
        "M", upper[0], upper[1],
        "L", originX, originY,
        "L", lower[0], lower[1]
    ].join(" ")).appendTo("svg");

    for (var i = 0; i < columns; i++) {
        var group = $("<g>").addClass("item button").attr("data-menu", i).appendTo("svg");
        group.addClass(isSelected && selected == i ? "selected" : "");
        var angleCur = angleOut + angle * i +
            ((isSelected && selected < i) ? subAngle * subTexts[selected].length : 0),
            originX = 300,
            originY = 300,
            topL = getXY(angleCur, 300),
            topR = getXY(angleCur, 220),
            bottL = getXY(angleCur + angle, 300),
            bottR = getXY(angleCur + angle, 220);
        createSlice([topL, topR, bottL, bottR], group);
        $("<text>").html(texts[i]).attr({
            x: (topL[0] + topR[0] + bottL[0] + bottR[0]) / 4 - 50 / 2,
            y: (topL[1] + topR[1] + bottL[1] + bottR[1]) / 4 + 40 / 4
        }).appendTo(group);
        createSlice([
            getXY(angleCur, 220), getXY(angleCur, 50),
            getXY(angleCur + angle, 220), getXY(angleCur + angle, 50)
        ], group);
        if (isSelected && i == selected) {
            for (var j = 0; j < subTexts[selected].length; j++) {
                var angleSub = angleCur + angle + subAngle * j,
                    g = $("<g>").addClass("subItem").appendTo("svg");
                createSlice([
                    getXY(angleSub, 220), getXY(angleSub, 50),
                    getXY(angleCur + angle + subAngle * (j + 1), 220),
                    getXY(angleCur + angle + subAngle * (j + 1), 50)
                ], g);
                $("<text>").html(subTexts[selected][j]).attr({
                    x: 100,
                    y: 316,
                    transform: "rotate(" + [-((angleSub) * 180 / Math.PI - 90),
                        300, 300
                    ].join(",") + ")"
                }).appendTo(g);
            }
        }
    }

    (function () {
        var group = $("<g>").addClass("menu button").appendTo("svg"),
            top = getXY(angleOut, 50),
            bott = getXY(Math.PI - angleOut, 50);
        $("<path/>").attr("d", [
            "M", top[0], top[1],
            "L", originX, originY,
            "L", bott[0], bott[1],
            "A", 50, 50, angle * columns, 0, 1, top[0], top[1],
            "Z"
        ].join(" ")).addClass("button").appendTo(group);
        $("<text>").html("menu").attr({
            x: 255,
            y: 303
        }).appendTo(group);
    })();

    $("body").html($("body").html());

    $("svg g.item").click(function () {
        drawMenu(
            $(this).attr("class").indexOf("selected")!==-1?
            undefined:
            +$(this).data("menu")
        );
    });
}

function getXY(angle, len) {
    return [300 - len * Math.sin(angle),
        300 - len * Math.cos(angle)];
}

function createSlice(coords, parent) {
    var angle = 12 * Math.PI / 180,
        topL = coords[0],
        topR = coords[1],
        bottL = coords[2],
        bottR = coords[3];
    $("<path/>").attr("d", [
        "M", topL[0], topL[1],
        "L", topR[0], topR[1],
        "A", 300, 300, angle, 0, 0, bottR[0], bottR[1],
        "L", bottL[0], bottL[1],
        "A", 300, 300, angle, 0, 1, topL[0], topL[1],
        "Z"
    ].join(" ")).addClass("button").appendTo(parent);
}

drawMenu();   //You can also do drawMenu(index), where "index" is the selected menu

Basic Components

Paths (shapes):

<path/>

Texts:

<text>Text</text>

In my example, all SVG nodes are JavaScript-generated in order to calculate the correct coordinates for the lines.

Ain't nobody got time for dat!

Not everyone is willing to or has the patient to mess with these nasty SVG nodes. Don't worry, Raphaël to the rescue!

Raphaël is a rich vector graphic library that let you draw and animate vector graphics with very few code. If you are that kind of person then you should definitely try this out.

like image 186
Derek 朕會功夫 Avatar answered Feb 24 '26 11:02

Derek 朕會功夫



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!