MJHD

エモさ駆動開発

jQueryとSVGでクリッカブルマップ

クリッカブルマップというのは,こんなの.

f:id:wait0000:20160104214251p:plain

今回はクリッカブルという名のもとでクリック機能に対応していないのだが,便宜上クリッカブルマップと呼ぶ. 実際,クリック対応も数行追加するだけで楽々と対応できる.

用意するもの

マップ画像の作成

f:id:wait0000:20160104214800p:plain
inkscapeを使い,適当に日本地図を書く.
そして,inkscapeXMLエディタを開き,各地域,都道府県などにidを追加する.
あとは,PlainSVGとして書き出すだけ.(今回はjapan-map.svgとして書き出した)

jQueryプラグインを書く

jquery.svg-japan-map.js

(function($) {
    $.fn.svgJapanMap = function(options) {

        function composeIdName(prefix, name, area) {
            var id = "#";
            
            if (prefix != "") {
                id += prefix + "-";
            }

            if (name != "") {
                id += name + "-"
            }

            id += area;
            return id;
        }

        var defaults = {
            svgFile: "",
            prefix:  "",
            onHover: function(e) {},
            onOut: function(e) {},
            associated: []
        };
        var setting = $.extend(defaults, options);

        setting.associated.push("");

        // SVGに設定したid
        var areas = [
            "hokkaido",
            "tohoku",
            "kanto",
            "chubu",
            "hokuriku",
            "kansai",
            "chugoku",
            "shikoku",
            "kyushu",
            "okinawa"
        ];

        var $this = this;

        $.get(setting.svgFile, function (data) {
            var in_event = "mouseenter";
            var out_event = "mouseleave";

            // たまにIEでうまく動かない対策
            if (navigator.userAgent.match("MSIE") || navigator.userAgent.match("Trident")) {
                in_event  = "mouseover";
                out_event = "mouseout";
            }

            $this.append($(data.documentElement));

            $.each(areas, function(i, area) {
                $.each(setting.associated, function(j, name) {
                    $(composeIdName(setting.prefix, name, area)).bind(in_event, function (e) {
                        e.areaName = area;
                        setting.onHover(e);

                        $.each(setting.associated, function (k, name2) {
                            $(composeIdName(setting.prefix, name2, area)).css({
                                "opacity": "0.5"
                            });
                        });

                        return false;
                    }).bind(out_event, function(e) {
                        setting.onOut(e);

                        $.each(setting.associated, function (k, name2) {
                            $(composeIdName(setting.prefix, name2, area)).css({
                                "opacity": "1.0"
                            });
                        });

                        return false;
                    });
                });
            });
        });

    };
})(jQuery);

こんな感じでSVGajax的にダウンロードしてDOMに無理やり埋め込む.
こうすることでjQueryのidセレクタを使い,各図形にイベントを設置できる.

今回は,合わせて左の丸や,地域名にも反応させたかったため,associateという設定項目を用意した.
合わせて,各図形にcircle-kanto,text-kantoなどとidを設定した.

使うだけ

<!DOCTYPE html>
<html>
    <head>
        <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
        <script src="./jquery.svg-japan-map.js"></script>
    </head>
    <body>

        <div id="map-holder"></div>
        <div id="map-popup" style="position: absolute; left: -100px; top: 0; width: 100px; height: 30px;"></div>

        <script>
$(document).ready(function() {
    $("#map-holder").svgJapanMap({
        svgFile: "./japan-map.svg",
        prefix: "",
        onHover: function(e) {
            $("#map-popup").text(e.areaName);
            $("#map-popup").css({
                "left": e.clientX + 10,
                "top":  e.clientY + 10
            });
        },
        onOut: function(e) {
            $("#map-popup").css({
                "left": -100,
                "top":  0
            });
        },
        associated: ["circle","text"]
    });
});
        </script>

    </body>
</html>

こんなコードを書いて完成.無事,ホバーに反応する日本地図ができた.