九保すこひ@フリーランスエンジニア|累計300万PVのブログ運営中
さてさて、この間ある記事を読んで「面白そう!」という思う内容がありました。
それは・・・・・・
QRコードで駐車エリアを保存し、後でそれがどこだったかが分かる
というシステムでした。
つまり、大きなショッピングセンターにお買い物にいって「あれ、ウチの車どこに停めたっけ!?」がなくなるシステムということですね。
そして、この記事を読んでみて「へぇ、QRコードのこんな使い方があるんだ!」と感心すると同時に、どうしても自分で作ってみたくなりました。
そこで❗
今回はLaravel
を使ってこの「駐車位置・保存システム」を実装してみたいと思います。
ぜひ学習のお役にたてますと嬉しいです。😊✨
(最後に、今回実際に開発したソースコード一式をダウンロードできますよ👍)
「ペーパー・ドライバーです 📝」
開発環境: Laravel 8.x、Vue 3
目次
やりたいこと
今回実装するのは、以下の流れです。
- 駐車したエリアにあるQRコードを読み取る(= エリアデータをブラウザに保存)
- (お買い物に行く)
- 出口に設置されたQRコードを読み取ると、保存エリアにマークがついた地図が表示される
なお、今回テストで使う地図は以下になります。
※ 今回はテストなのでたった4エリアですが、実際はもっとたくさんあることを想定しています。
では、楽しくやっていきましょう❗
パッケージをインストールする
先にPHP
でQRコード
を作成することができるように「php-qrcode」というパッケージをインストールしておきます。
以下のコマンドを実行してください。
composer require chillerlan/php-qrcode
そして、画像を操作できる「intervention」です。
同じくインストールしてください。
composer require intervention/image
ルートをつくる
では、続いてルートをつくります。
routes/web.php
<?php use Illuminate\Support\Facades\Route; use \App\Http\Controllers\ParkingController; // 👈 ここも忘れず! // 省略 Route::prefix('parking')->group(function(){ Route::get('/qr_code/{parking?}', [ParkingController::class, 'qr_code'])->name('parking.qr_code'); Route::get('/show', [ParkingController::class, 'show'])->name('parking.show'); });
1つ目のルートがQRコードを表示するページです。
なお、{parking?}
とハテナマークがついているのは、「パラメータがなくてもOK 👍」にするためです。
つまり、以下のようなURLがOKになります。
- http://******/parking/qrcode/1 :数字はIDで可変
- http://******/parking/qrcode : こっちもOK
そして、2つ目ですが、これは「駐車位置のパラメータがある or ない」でそれぞれ以下のように動作が変わるようにしています。
- パラメータがある: そのパラメータをブラウザへ保存
- パラメータがない: すでに保存されたデータから地図を表示
モデル&マイグレーションをつくる
続いて、データを管理するモデルとマイグレーション(DBテーブル)をつくります。
以下のコマンドを実行してください。
php artisan make:model Parking -m
すると、モデルとマイグレーションのファイルが作成されるので、マイグレーションを以下のように変更してください。
database/migrations/****_**_**_******_create_parkings_table.php
// 省略 public function up() { Schema::create('parkings', function (Blueprint $table) { $table->id(); $table->string('name')->comment('エリア名'); $table->integer('location_x')->comment('エリア位置:X軸'); $table->integer('location_y')->comment('エリア位置:Y軸'); $table->timestamps(); }); } // 省略
なお、この中のlocation_x
とlocation_y
は、最初に見てもらった地図画像上で「そのエリアがどこにあるの?」が分かる座標になります。
単位はピクセルです。
駐車エリアの情報を登録する
そして、DBテーブル「parkings」に登録するデータをつくります。
以下のコマンドでSeeder
ファイルを作成してください。
php artisan make:seed ParkingsTableSeeder
すると、ファイルが作成されるので、中身を以下のように変更します。
database/seeders/ParkingsTableSeeder.php
// 省略 public function run() { $areas = [ [ 'name' => 'ライオンエリア', 'location_x' => 160, 'location_y' => 265, ], [ 'name' => '猫エリア', 'location_x' => 480, 'location_y' => 265, ], [ 'name' => 'うさぎエリア', 'location_x' => 160, 'location_y' => 410, ], [ 'name' => 'パンダエリア', 'location_x' => 480, 'location_y' => 410, ], ]; foreach ($areas as $area) { $parking = new Parking(); $parking->name = $area['name']; $parking->location_x = $area['location_x']; $parking->location_y = $area['location_y']; $parking->save(); } } // 省略
続いて、このファイルが有効になるようにLaravel
に登録します。
database/seeders/DatabaseSeeder.php
<?php namespace Database\Seeders; use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { // User::factory(10)->create(); $this->call(ParkingsTableSeeder::class); // 👈 ここを追加しました } }
では、以下のコマンドを実行してDBテーブルを構築しましょう。
php artisan migrate:fresh --seed
実行するとテーブルはこうなります。
コントローラーをつくる
次に、コントローラーをつくります。
以下のコマンドを実行してください。
php artisan make:controller ParkingController
すると、ファイルが作成されるので中身を以下のように変更します。
app/Http/Controllers/ParkingController.php
<?php namespace App\Http\Controllers; use App\Models\Parking; use chillerlan\QRCode\QRCode; use Illuminate\Http\Request; class ParkingController extends Controller { public function qr_code(Parking $parking) { $url = route('parking.show', [ 'x' => $parking->location_x, 'y' => $parking->location_y ]); $data = (new QRCode())->render($url); return \Image::make($data)->response(); } public function show(Request $request) { return view('parking.show')->with([ 'x' => intval($request->x), 'y' => intval($request->y) ]); } }
この中でやっているのは以下のとおりです。
qr_code()
このメソッドでQRコードを作成します。
やっている事は、該当するID番号の「駐車エリア・データ」を取得し、その位置情報をx
、y
として「/parking/show」のURLに含め、それをQRコード化しています。
つまり、以下のようなURLになります。
http://******/parking/show?x=160&y=410
show()
ここでは、2つのコンテンツを切り替えることになります。
その詳細は次のとおりです。
- 位置情報のパラメータがある場合: そのデータを
localStorage
へ保存 - パラメータがない場合: 保存されている駐車エリアを表示
つまり、上の項目が駐車した直後に読み取るQRコードで、下が駐車位置を探すときのQRコードになります。
ビューをつくる
では、最後にビューをつくります。
以下のファイルを作成してください。
resources/views/parking/show.blade.php
<html> <head> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"> </head> <body> <div id="app"> <!-- 駐車したエリアのデータを保存する場合 --> <div v-if="mode=='save'"> <div class="p-3 text-center" v-if="locationSaved"> 駐車位置を保存しました。 </div> </div> <!-- 駐車したエリアのデータを表示する場合 --> <div id="canvas-box" v-else-if="mode=='show'"> <canvas id="canvas"></canvas> </div> </div> <script src="https://unpkg.com/vue@3.0.2/dist/vue.global.prod.js"></script> <script> Vue.createApp({ data() { return { location: { x: {{ $x }}, y: {{ $y }}, }, locationSaved: false, canvas: null, context: null, mapImage: null } }, methods: { save() { try { const parkingData = JSON.stringify(this.location); localStorage.setItem('parking_location', parkingData); this.locationSaved = true; } catch (e) { console.log(e); alert('残念ながらブラウザが対応していません。'); } }, show() { this.context.drawImage(this.mapImage, 0, 0, this.canvas.width, this.canvas.height); const parkingData = JSON.parse( localStorage.getItem('parking_location') ); const parkingX = parkingData.x; const parkingY = parkingData.y; const radius = this.canvas.width * 0.085; const x = this.canvas.width * parkingX / this.mapImage.width; const y = this.canvas.height * parkingY / this.mapImage.height; this.context.arc(x, y, radius, 0, 2 * Math.PI); this.context.strokeStyle = '#ffff99'; this.context.lineWidth = 10; this.context.stroke(); } }, computed: { mode() { return (this.location.x > 0 && this.location.y > 0) ? 'save' : 'show'; } }, mounted() { if(this.mode === 'save') { this.save(); } else if(this.mode === 'show') { this.mapImage = new Image; this.mapImage.onload = () => { const canvasWidth = document.querySelector('#canvas-box').clientWidth; const canvasHeight = canvasWidth * this.mapImage.height / this.mapImage.width; this.canvas = document.querySelector('#canvas'); this.canvas.width = canvasWidth; this.canvas.height = canvasHeight; this.context = this.canvas.getContext('2d'); this.show(); }; this.mapImage.src = '/images/parking_map.png'; } } }).mount('#app'); </script> </body> </html>
このビューは、パラメータの状態によって以下2つのmode
になります。
- save: 駐車した場所を「保存」する
- show: 駐車した場所を「表示」する
ではひとつずつご紹介します。
saveモードの場合
ページが表示されるとすぐにsave()
メソッドが実行されます。
このメソッドの中では、ブラウザのlocalStorage
へデータを保存することになりますが、念のためlocalStorage
が使えないブラウザのことも考え、try ~ catch
で例外処理をつけています。
show モードの場合
このモードの場合、いろいろとやっているのですが、目的は「横幅いっぱいに地図を表示する」です。
つまり、今回の地図画像は640 x 480 ピクセル
ですが、表示する環境はそれぞれ違ってきますので、100%
の横幅にします。
ただ、そうなってくると、location_x
、location_y
として取得した値が「拡大 or 縮小」している地図に対して、正しい位置ではなくなってしまいます。
そのため、位置を「割合」にすることでこれを解決しています。(こういう計算って難しいですよね・・・💧)
テストしてみる
では、実際にテストしてみましょう❗
なお、地図はこうなっています。
駐車位置を保存するテスト
まずは「ライオンエリア」に車を停めることを想定してやってみます。
ブラウザで「http://******/parking/qr_code/1」にアクセスしてください。
QRコードが表示されるのでこれを読み取り、ブラウザで表示します。
すると、駐車位置がブラウザに保存されます。
では、本当にlocalStorageに保存されてるか確認してみましょう。
まずは1段階目は成功ですね👍
駐車位置を表示するテスト
そして、次は「お買い物後」を想定してテストします。
今回はパラメータをつけずにQRコード・ページへアクセスします。URLは、「http://******/parking/qr_code」です。
すると、またQRコードが表示されるので、再度読み取ってブラウザで表示します。
すると・・・・・・
はい❗
うまく「ライオンエリア」に○マークがつきました。
成功です😊✨
では、念のために同じ手順で「うさぎエリア」だった場合でもテストしてみます。
- 「http://******/parking/qr_code/3」へアクセス
- QRコード読み取り(駐車位置を保存)
- 「http://******/parking/qr_code」へアクセス
- QRコード読み取り
- 確認
すると・・・・・・
はい❗
今度は「うさぎエリア」に○マークがつきました。
こちらも成功です😊✨
ダウンロードする
以下から今回実際に開発したソースコード一式をダウンロードすることができます。
【Laravel】QRコードで駐車位置・表示システムをつくる※ ただし、マイグレーションなどはご自身で実行してください。
※ また、地図に含まれているイラストはフリーライセンスで公開していないので、この中には含まれていません。テストする場合は、このページからダウンロードして使ってください。
おわりに
ということで、今回はQRコードを使った「駐車位置システム」を作ってみました。
ちなみに、今回は駐車位置を表示するだけでしたが、当初は「現在地からどう行けばそのエリアに到着できるか?」という2地点を想定していました。
しかし、あまりにも複雑になりそうで断念することになりました(また、2階・3階などの情報も扱ってみたかったんですが・・・それもやっちゃうと学習には不向きになるという結論になり、これもやめました😅)
とはいえ、基本のコードを使っていろいろ拡張ができると思いますので、ぜひ試して見てくださいね。
ではでは〜❗
「えっ、カビキラーって、
こんな落ちるんですね😳」