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

### Respect for

https://qiita.com/noppefoxwolf/items/b4376392d98cea2446dd

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

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

## 使い方
アクセスしてテキストボックスに上段と下段に表示したいテキストを入力するゾ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513165/fae09185-5d1a-d2b1-1e8a-79babe5bd245.png)
あとは自動でルビ振りされたテキストがタイトルコール風に表示されるゾ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513165/722c2209-b3b2-527e-fc8b-88a25cd194af.png)

### 仕組み
もう語尾辞めていいっすか…

https://github.com/ichii731/php-examples/tree/main/kureshin

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

https://developer.yahoo.co.jp/webapi/jlp/furigana/v2/furigana.html

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

https://qiita.com/yhatt/items/4cd0c21b6bf5cf8af456

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

https://github.com/ichii731/php-examples/tree/main/kureshin

## HTML+Vue(フロント)
Vueやhtml2canvas

```html: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コード(ルビ振り処理)
一部省略しています。割と冗長かもしれんが短く書いたつもり…

```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;

```