2018/03/11

SVGで印鑑作ってみた。

SVGで印鑑ポイ画像ツール

を公開してから一か月ぐらいたってしましました。
本体はこちらSeal editer made with SVGです。

そろそろ何を作ったのか解説したいところです。
それでは本編です。

目次

目標

SVGを利用して、丸で囲まれた印鑑みたいな画像を作る。

サンプルコード

(本番サイトはbootstrap導入用になっていて掲載に向かないので、修正済みのものです。)
<!DOCTYPE html>
<html>
<head>
    <title>test023-SVGで印鑑っぽいの</title>
    <meta charset="utf-8">
    <style type="text/css">
        .waku {
            position: relative;
            border: 3px solid #000000;
            width: 200px;
            height: 200px;
        }

        .day {
            position: absolute;
            bottom: 0px;
            font-size: 39px;
            color: #000000;
        }
        .inkan {
            position: absolute;
            z-index: 10;

        }
        .box {
            float: left;
            padding: 10px;
        }
        .deg{
            width: 300px;
        }
    </style>
</head>
<body onload="startup()">
    <script src="http://d3js.org/d3.v3.js"></script>
    <script>
        var inkan = null;
        var w = 200;
        var h = 200;
        var svg = null;
        // 50x50のsvg領域を作る
        var startup = function () {
            svg = d3.select("#inkanarea")
                .append("svg")
                .attr("width", w)
                .attr("height", h)
                .attr("xmlns", "http://www.w3.org/2000/svg");

        }

        var makeinkan = function (inputelid, alertmsgid, inputdegid) {
            var collback = function () {

                var inputtext = document.getElementById(inputelid).value;
                var inputdeg = document.getElementById(inputdegid).value;
                d3.select("#name").remove();

                if (inputtext.length > 4) {
                    document.getElementById(alertmsgid).innerText =
                     "4文字以内での入力をお願いします";
                } else {
                    if (inputtext.length > 0) {
                        document.getElementById(alertmsgid).innerText =
                        "";

                        inkan = svg.append("g")
                        .attr("transform",
                         "translate(0.75,0.75) rotate(" +
                           inputdeg +",100,100)")
                        .attr("id", "name");

                        inkan.append("circle")
                        .attr("cx", "100")
                        .attr("cy", "100")
                        .attr("stroke", "#FF0000")
                        .attr("stroke-width", "5")
                        .attr("r", "90")
                        .attr("fill-opacity", "0")
                        .attr("stroke-opacity", "0.7");

                        var name = inkan.append("g")
                            .attr("text-anchor", "middle")
                            .attr("fill", "#FF0000")
                            .attr("fill-opacity", "0.7")

                        if (inputtext.length == 1) {
                            name.attr("font-size", "150");
                            name.append("text")
                                .attr("x", "100")
                                .attr("y", "155")
                                .text(inputtext);
                        }
                        if (inputtext.length == 2) {
                            name.attr("font-size", "95");

                            name.append("text")
                                .attr("x", "100")
                                .attr("y", "95")
                                .text(inputtext[0]);

                            name.append("text")
                                .attr("x", "100")
                                .attr("y", "175")
                                .text(inputtext[1]);
                        }
                        if (inputtext.length == 3) {
                            name.attr("font-size", "65");

                            name.append("text")
                                .attr("x", "100")
                                .attr("y", "70")
                                .text(inputtext[0]);

                            name.append("text")
                                .attr("x", "100")
                                .attr("y", "130")
                                .text(inputtext[1]);

                            name.append("text")
                                .attr("x", "100")
                                .attr("y", "185")
                                .text(inputtext[2]);
                        }

                        if (inputtext.length == 4) {
                            name.attr("font-size", "75");

                            name.append("text")
                                .attr("x", "132")
                                .attr("y", "91")
                                .text(inputtext[0]);

                            name.append("text")
                                .attr("x", "132")
                                .attr("y", "161")
                                .text(inputtext[1]);

                            name.append("text")
                                .attr("x", "67")
                                .attr("y", "91")
                                .text(inputtext[2]);

                            name.append("text")
                                .attr("x", "67")
                                .attr("y", "161")
                                .text(inputtext[3]);
                        }
                    }
                }
                //フォーカスが文字入力か角度入力の時再度呼び出しする。
                if (document.activeElement.id == inputelid ||
                    document.activeElement.id == inputdegid) {
                    setTimeout(collback, 10);
                }
            }
            setTimeout(collback, 10);
        }
    </script>
    <div>
        <div>印鑑っぽいものエディター</div>
        <div class="box">
            <label>お名前を入力してください:
                <input type="text" id="nameinput"
                 onfocus="makeinkan('nameinput','alertmsg','deg')">
            </label>
            <div>
                <span id="alertmsg"></span>
            </div>
            <label>回転角度をスライダで入力してください[-180~180]:<br>
                <input type="range" class="deg" id="deg"
       min="-180" max="180"
                   step="5" value="-20"
                   onchange="makeinkan('nameinput','alertmsg','deg')">
            </label>
        </div>
        <div class="box">
            <div class="waku">
                <div id="inkanarea" class="inkan">
                </div>
            </div>
        </div>
    </div>
</body>
</html>

実行例-表示例

Seal editer made with SVGを触ってもらえるとわかりやすいのですが、
「田中」さんの場合以下のようになります。

ポイント!

  • SVGで画像を作り直しするときは3.select([要素id]).remeve()を使うこと
    これをしないと書き換えができません。どんどん上書きされます。
    今回は全体を消してますが、部分書き換えを行いたいなら、その要素にidを割り当てておくことが必要ですね。
  • 太さ5の線で円を描くために、親要素で基準点をtranslate(-2.5,-2.5)に設定して、修正しています。
    SVGでの太さ指定って、基準点から広がるように指定されているようで、
    正方形に円を描くと、X軸+方向Y軸+方向の右下にずれてしまうので、修正しています。

終わりに

今回はSVGで印鑑画像を作成しました。
本番のサイトではダウンロード機能も付けているので、使ってもらえるとうれしいです。

今回の反省としては、対応文字数が4文字までで、 文字の配置位置をハードコーディングになっていること。
SVG内での接触判定して調整機能作ればいけるのだろうか?
ここまででとりあえず、D3.jsでの書き換えだったりの使い方はわかったので、
次はD3.jsを使ってグラフを描きたいところ。
ただ制作物として公開する価値あるグラフってなんだろう?・・・。

ご利用は自己責任で!
少しでもお役にたてれば幸いです。

0 件のコメント:

コメントを投稿

AWSに手を出してフレームワークも使ってみたが・・・。

サイトを作り直しました。 AWS上に構築した Content created by AXY を作り直しました。 具体的にはbottle.pyを使ったpythonで構築したサイトからPHP7を使用したサイトに再構築しています。 特別何か問題点があったというわけで...