10
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

高機能クレヨンしんちゃん(Vue・PHP)

Last updated at Posted at 2022-02-19

Respect for

小一時間暇だったので自動ルビ振り機能とかを搭載したクレしんタイトルコールジェネレーターを作ってみたゾ

https://tools.ic731.net/kureshin/

使い方

アクセスしてテキストボックスに上段と下段に表示したいテキストを入力するゾ
image.png
あとは自動でルビ振りされたテキストがタイトルコール風に表示されるゾ
image.png

仕組み

もう語尾辞めていいっすか…

  • 描画やフロントエンドはVue.jsで書いています
  • 画像出力機能はhtml2canvasを使いました。これ超便利だから使って見て下さい
  • 自動ルビ振り機能はPHP上でYahoo!ルビ振りAPIをリクエスト→HTMLとして返却することで実装しました

画面レイアウト

また、デザインやCSSは@yhattさんの投稿をパクって参考にしてアスペクト比4:3で設計しました。有難うございます!

もう特に書くことは無いのでソースコード載せときます。自分でお試しあれ(GitHubにもあげてます)

HTML+Vue(フロント)

Vueやhtml2canvas

index.html
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- Style by https://qiita.com/yhatt/items/4cd0c21b6bf5cf8af456 -->
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Kosugi+Maru&display=swap');
        .preview {
            aspect-ratio: 4 / 3;
            background: linear-gradient(to bottom, rgb(94% 51% 64%), rgb(95% 95% 50%));
            display: grid;
            place-content: center;
            width: 600px;

        }
        h1 {
            color: purple;
            font-family: 'Kosugi Maru', sans-serif;
            font-size: 30px;
            padding-left: 1em;
            line-height: 1.5;
        }
        h1::before {
            content: '';
            margin-left: -1em;
        }
        button {
            margin-top: 1em;
            height: 40px;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="preview">
            <h1 v-html="title"></h1>
        </div>
        <label>上段:
            <input type="text" v-model="top">
        </label>
        <br>
        <label>下段:
            <input type="text" v-model="bottom">
        </label>
        <br>
        <button @click="AddText">反映</button>
        <br>
        <button @click="generate">
            画像として保存
        </button>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.3.2/dist/html2canvas.min.js"></script>
    <script>
        new Vue({
            el: "#app",
            data: {
                top: "",
                bottom: "",
                title: "上段と下段を<br>入力してください"
            },
            methods: {
                AddText() {
                    if (!this.top == "" || !this.buttom == "") {
                        fetch("./addruby.php?sentence=" + this.top)
                            .then(res => res.text())
                            .then(data => {
                                this.title = data + "<br>";
                                return fetch("./addruby.php?sentence=" + this.bottom);
                            })
                            .then(res => res.text())
                            .then(data => {
                                this.title += data;
                            });
                    } else {
                        alert("入力してください");
                    }
                },
                generate() {
                    html2canvas(document.querySelector('.preview')).then((canvas) => {
                        const link = document.createElement('a')
                        link.href = canvas.toDataURL()
                        link.download = `image.png`
                        link.click()
                    })
                }
            },
        })
    </script>
</body>

</html>

PHPコード(ルビ振り処理)

一部省略しています。割と冗長かもしれんが短く書いたつもり…

addruby.php
<?php
$ch = curl_init();
$apikey = '<APIキー>';
$sentence = htmlspecialchars($_GET['sentence']);

$jayParsedAry = [
    'id' => '1234-1',
    'jsonrpc' => '2.0',
    'method' => 'jlp.furiganaservice.furigana',
    'params' => [
        'q' => $sentence,
        'grade' => 2
    ]
];

// CURLでリクエスト
curl_setopt($ch, CURLOPT_URL, 'https://jlp.yahooapis.jp/FuriganaService/V2/furigana');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($jayParsedAry, JSON_UNESCAPED_UNICODE));

$headers = [];
$headers = [
    'Content-Type: application/json',
    'User-Agent: Yahoo AppID: ' . $apikey
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$result = curl_exec($ch);
curl_close($ch);

$result = json_decode($result, true);

$surface = '';
// 各配列のsurfaceを結合
foreach ($result['result']['word'] as $value) {
    if (isset($value['furigana'])) {
        // もし["subword"]があればforeachで繰り返して結合
        if (isset($value['subword'])) {
            foreach ($value['subword'] as $subvalue) {
                // furiganaとsurfaceが同値だったら結合しない
                if ($subvalue['furigana'] === $subvalue['surface']) {
                    $surface .= $subvalue['furigana'];
                } else {
                    $surface .= '<ruby>' . $subvalue['surface'] . '<rt>' . $subvalue['furigana'] . '</rt></ruby>';
                }
            }
        } else {
            $surface .= '<ruby>' . $value['surface'] . '<rt>' . $value['furigana'] . '</rt></ruby>';
        }
    } else {
        $surface .= $value['surface'];
    }
}

echo $surface;

10
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?