
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、夏休みもど真ん中ということで、こんなことを思い出したりしませんか?
「自由研究やったよね。当時はめんどうだったけど、今はやってみたいかも…」
「子供が自由研究の宿題をやってる。親として見本になりたいな」
「シンプルに誰得な面白いネタ、大好きなんだよね!」
そんな方に、今回はいつもと違い「夏の自由研究」的な記事をお届けします。
テーマは・・・・・・
テンポ&マッチング
です。
みなさん、「パーソナルテンポ」って聞いたことはあるでしょうか!?
パーソナルテンポとは、個人がもっている「心地よいテンポ」のことです。
例えば、気づいたら指でリズムをとってたりしませんか?
それがあなた固有のパーソナルテンポです。
今回はパーソナルテンポでマッチングできる機能をつくったら面白いんじゃないかと考えました。まさに自由研究です!
ちなみに、甲南大学で行われた144
人72
ペアを対象とした論文によると、やはり友人は似てる傾向があるという結果になっています。
つまり、「パーソナルテンポが似てる=仲良くなりやすい人」という仮説ですね。
そこで
今回は以下の手順で、マッチングできるように実装してみます。
- 30回「心地よいテンポ」でマウスをクリックする
- パーソナルテンポを計算
- Xに結果を投稿できるようにする(※)
※ハッシュタグ「#パーソナルテンポ測定」をつけるので、Xで似た人を探せるという流れです。
ぜひ最後まで読んでくださいね!(今すぐ試したい人はこちらこちら)
「測ったことないけど、
パーソナルテンポ、
めっちゃ早いと思います」
開発環境: Laravel 11.x、Vue 3
目次 [非表示]
【パッケージのインストール】パーソナルテンポ測定だけしたい方へ
せっかくなので、実際にページを作ってみました。
もし測定だけしたい方は、以下からどうぞ!
【パッケージのインストール】パーソナルテンポを測定する機能を開発する準備をする
1:PHPのパッケージをインストールする
今回は以下のテクノロジーを使って開発をすすめていきます。
- Vue 3
- Inertia.js
そこで、手っ取り早くLaravel Breeze
をインストールしましょう。
composer require laravel/breeze --dev
php artisan breeze:install
選択肢が表示されるので、Vue with Inertia
を選択&エンターキーを押す。
あとはそのままエンターキーを2回ターン!します。
これで完成です。
簡単ですね!
2:JavaScriptのパッケージをインストールする
以下2つのパッケージをインストールします。
- Lodash:便利機能が満載
- SweetAlert2:おしゃれなアラート表示
それぞれ以下2つのコマンドを実行してください。
npm i lodash --save-dev
npm i sweetalert2 --save-dev
インストールが完了したら、登録して有効にします。
resources/js/bootstrap.js
// 省略
// Lodash
import _ from 'lodash';
window._ = _;
// SweetAlert2
import Swal from 'sweetalert2';
window.Swal = Swal;
これで、_
とSwal
がJavaScript
内で使えるようになりました。
npm run dev
でVite
を起動しておいてください。
【コントローラーをつくる】パーソナルテンポ測定のベースになる部分をつくる
コントローラーの中では、ビューを呼び出すメソッドが1つだけでOK
です。
以下のコマンドを実行してください。
php artisan make:controller PersonalTempoController
コントローラー・ファイルが作成されるので中身を以下のようにします。
app/Http/Controllers/PersonalTempoController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class PersonalTempoController extends Controller
{
public function create()
{
return inertia('PersonalTempo/Create');
}
}
【ビュー】パーソナルテンポを実際に測定するJavaScript部分をつくる
今回はここがメインになります。
Vue 3
のSFC
(Single-File Component
)になります。
なお、画像は以下のものを使いました。(from ChatGPT
です)
resources/js/Pages/PersonalTempo/Create.vue
<template>
<Head title="パーソナルテンポ測定"></Head>
<div class="container mx-auto flex flex-col items-center justify-center min-h-screen p-4">
<h1 class="text-2xl font-bold mb-4">【すぐわかる】パーソナルテンポ測定</h1>
<ol class="list-decimal list-inside text-left mb-6">
<li>ドラムの中心をクリックするとスタート</li>
<li>そのまま「心地よいテンポ」で{{ clickMaxCount }}回クリックする</li>
<li>あなた固有のパーソナルテンポがわかります!</li>
</ol>
<div class="mb-6">
<img src="/images/drum.png" alt="ドラム" class="cursor-pointer" @click="onClick"/>
</div>
<div class="text-center" v-if="clickTimes.length > 0">回数: {{ clickTimes.length }}回</div>
</div>
</template>
<script setup>
import {computed, ref} from 'vue';
import {Head} from "@inertiajs/vue3";
// 共通
let mode = 'measuring'; // measuring, done
// テンポ測定
const clickMaxCount = ref(30);
const bpm = computed(() => {
const times = clickTimes.value;
if(times.length < 2) {
return 0;
}
let intervals = [];
for (let i = 1; i < times.length; i++) { // 時間の間隔を計算
intervals.push(times[i] - times[i - 1]);
}
const averageInterval = _.mean(intervals); // 平均値を取得 (ミリ秒)
return Math.round(60000 / averageInterval); // ミリ秒を BPM に変換
});
// クリックイベント
const clickTimes = ref([]);
const onClick = () => {
if (mode === 'done') {
return;
}
const currentTime = new Date().getTime();
clickTimes.value.push(currentTime);
if (clickTimes.value.length === clickMaxCount.value) {
mode = 'done';
Swal.fire({
title: `${bpm.value} BPM`,
html: `パーソナルテンポは<b>「${bpm.value} BPM</b>」です<br class="">※BPM = Beats Per Minute<br class="block sm:hidden">(1分間の拍数)の略です`,
icon: "info",
showCloseButton: true,
showCancelButton: true,
focusConfirm: false,
confirmButtonText: 'Xに結果を投稿する',
cancelButtonText: `もう一回やる`,
})
.then((result) => {
if (result.isConfirmed) {
location.href = intentUrl.value;
} else {
clickTimes.value = [];
mode = 'measuring';
}
});
}
};
// X に結果を投稿
const intentUrl = computed(() => {
const targetUrl = location.href;
const text = `私のパーソナルテンポは「${bpm.value} BPM」でした!\n\n${targetUrl}\n\n@SukohiKuhoh\n#パーソナルテンポ測定`;
return `https://twitter.com/intent/tweet?text=${encodeURIComponent(text)}`;
});
</script>
<style scoped>
.container {
max-width: 640px;
}
</style>
この中でやっていることは、以下4つです。
- ドラム画像をクリックしたときの時間を保存しておく
- 30回クリックされたら過去の時間の間隔を全て取得
- 間隔の平均値を出す
- BPM(Beats per Minute。1分間の拍数)に変換
- 結果を表示
ちなみに、インストールしたJavaScript
パッケージのLodash
を使っているのは以下です。
このようにいろんな処理を手っ取り早く取得できます。
_.mean(intervals); // 平均値を取得 (ミリ秒)
では、これで作業はこれで完了です!
お疲れ様でした。
【ルート】パーソナルテンポ測定するURLをつくる
最後にブラウザからアクセスするURL
をルートで指定します。
routes/web.php
<?php
use App\Http\Controllers\PersonalTempoController;
// 省略
Route::prefix('personal_tempo')->group(function () {
Route::get('create', [PersonalTempoController::class, 'create'])->name('personal_tempo.create');
});
// 省略
【テスト】パーソナルテンポが測定できるかチェックする
実際にパーソナルテンポ測定できるかチェックしてみましょう
1:ブラウザでアクセスする
ブラウザで「https://******/personal_tempo/create」にアクセスすると、以下のようにコンテンツが表示されました。
2:心地よいテンポでドラムをクリックする
では、30回ドラムの中心をクリックして試してみます。
どうなるでしょうか・・・・・・
はい
うまく計算できました。
※思ったとおり、BPM高めでしたね。こりゃ人生短いかも…
3:Xへの投稿リンクをクリックしてみる
最後にリンクをクリックしてみます。
うまくXへ移動するでしょうか・・・・・・
はい
X
の投稿フォームが自動で表示されました。
すべて成功です
【企業様へのご提案】パーソナルテンポ測定のようなコンテンツでSNSを拡散
今回のようなサービスを提供すると、診断結果をXへ投稿するよう誘導することができます。
つまり、人気のサービスになればなるほどXで拡散をしてもらえるわけですね。
もしこういったアイデアをお持ちの方は、ぜひお問い合わせからご相談ください。実現させていただきます。
お待ちしております。
おわりに
ということで、今回は「夏の自由研究」として100%私がやりたいだけの企画にしてみました。
実は、子供のころもメインの宿題そっちのけで自由研究をしていた記憶があります。このブログが続いているのもその延長線にあるからかもしれませんね。
ぜひ皆さんも昔を思い出しながら、冷たいサイダーでも飲みつついろんな研究をしてみてくださいね。
ではでは〜
「歩くのも
めちゃくちゃ
早いです」