[Design Guideline] Componentのvariationを増やしたい

とりあえずComponentにどんなものがあるか、ざっと一つ一つ見ていきます。

・Accordion
・Activity Timeline
・Alert
・App Launcher
・Avatar, Avatar Group
・Badges
・Brand Band
・Breadcrumbs
・(builder Header)
・Button Groups
・Button Icons
・Buttons
・Cards
・Carousel
・Chat
・Checkbox, Checkbox Button, Checkbox Button Group
・Checkbox Toggle
・Color Picker
・Combobox
・Counter
・Data Tables
・Datepickers, Datetime Picker
・Docked Composer
・Docked Form Footer
・Docked Utility Bar
・Drop Zone
・Dueling Picklist
・Dynamic Icons
・Dynamic Menu
・Expandable Section
・Expression
・Feeds
・File Selector, Files
・Form Element
・Global Header
・Global Navigation
・Icons
・Illustration
・Input
・List Builder
・Lookups
・Map
・Menu
・Modals
・Notifications
・Page Headers
・Panels
・Path
・Picklist
・Pills
・Popovers
・Progress bar
・Progress Indicator
・Progress Ring
・Prompt
・Publishers
・Radio Button Group, Radio Group
・Rich Text Editor
・Scoped Notifications
・Scoped Tabs
・Select
・Setup Assistant
・Slider
・Spinners
・Split View
・Summary Detail
・Tabs
・Textarea
・Tiles
・Timepicker
・Toast
・Tooltips
・Tree Grid
・Trees
・Trial Bar
・Vertical Navigation
・Vertical Tabs
・Visual Picker

ざっと見ていき、興味があったのは、loading spinner, toggle, search instance result, color picker, progressStep.jsあたり。触っておくか。
それと、デザインだからフォントもカバーしておかないと。
なんか自分でもよく分からないテンションになってきました。

[Design Guideline] 項目を考える

デザインガイドラインの項目を考えます。

・Overall
— Clarity, Efficiency, Consistency, Beauty

・Basic
— Component, Layout
— Header
— Bar, Styles, Colors, Back Button, Menu, Settings, Help Menu, Save, Status, In process Action, Alert, Utility, Search, Toggle
— Layout
— Columns, Style, Panels, Body, Horizontal tabs, Accordions, Navigation, Color Picker
— Modals
— Validation
— warning, alert, Confirmation modal, Error Icon, Error Alert

・Charts
— Bar chats, Dot Plot, Line Chart, Scatter Plot, Pie Chart, Tree map, Heat map, Matrix Chart, Metric, Flat Gauge, Polar Gauge, Rating Chart, Map, Funnel Chart, Color

・Data Entry
— text input, sizing, input help, date picker, lookup, Checkbox, radio, checkbox toggle, Label

・Displaying Data
— table, tree grid, title, interactive guide, Feed

・Empty State
— 404 message

・Iconography
— Design Principle, Accessibility, Informational Icons, Decorative Icons, Grid System, Key Line Shape, Object Icon

所感
– Localizationしたサービスを作りたい
– デフォルトでUser Feedbackを考えないと行けない
– Loading, toggle, SearchのInstance Resultなどは実装できる様になっておきたい。
– Error, Alertなどは最初にしっかり考えておかないといけないのね

なんだかんだで、ローカリゼーションしたサービスを作りたい。在日外国人向けとかからスタートしたいね。

Design Guidelineを作りたい

ざっくりとでもいいので、デザインガイドラインとコーディングガイドラインを作りたい
デザインガイドラインの目的は、デザインの品質向上と一貫性の担保
各社のデザインページをざっと見てみる。

Apple: Human Interface Guideline
https://developer.apple.com/design/resources/
L Sketch, PSD, XDで作成している

Microsoft: Fluent Design System, Inclusive Design
https://www.microsoft.com/design/fluent
https://www.microsoft.com/design/inclusive

Airbnb: design
https://airbnb.design

Ubuntu: design
https://design.ubuntu.com

wework: office design
https://www.wework.com/ideas/category/office-design-space

salesforce: design
https://www.lightningdesignsystem.com/guidelines/overview/

やるべきことはこの辺りか
– ターゲットユーザの整理
– デザインガイドラインに書いていく項目の洗い出し

パッと見たところだと、salesforceが一番参考になりそうな印象
とりあえずあまりノウハウがないので、作りながら修正していくパターンにしよう

[Xd] Adobe Xdを始めよう

とりあえずmacにインストールしました。

とりあえずGetting Started のVideoに沿ってやるか。

とりあえず新規作成画面

なるほど、Cacooみたいなこともできるのね。
1920 x 1080だとちょっとWFとしては描きにくいから、カスタムサイズか。
チュートリアルだけだとモチベーションのフォーカスが難しいから、次実際にワイヤー描く時になったらXdでやってみるか。

OK、悪くない。

[PHP] 拡張子不明の画像名を変数として持ち、imgフォルダ内にあれば表示

imgフォルダ内に画像が複数(数千枚)置いてあり、拡張子は不明だが、ファイル名だけ変数として持っており、該当のファイル名があればその画像を表示、無ければplaceholderの画像を表示したい。

まず画像を用意します。

拡張子分foreachで探してみたが、

$name = "cat";
$cfg = array('jpg', 'jpeg', 'png', 'gif');

foreach($cfg as $key){
	if(file_exists("img/" .$name . "." . $key)){
		echo "<img src='img/" . $name . "." .$key."' width='150px' height='100px'>";
	}
}

これだと、拡張子の配列分回さないといけないのと、画像が無ければ、placeholderの表示ができない。

globとワイルドカードを使う

$name = "cat";
$result = glob("img/" . $name . ".*");

if(in_array($result)) {
	echo '<img src="'.$result[0].'" width="150px" height="100px">';
} else {
	echo '<img src="/img/150x150.png">';
}

OK!上等!
続いて、少々細かいことを調査していきます。

[JavaScript] 複数住所を登録する為、住所を追加するボタン

amazonの様に、住所を複数追加できる様にしたい。

	<h1>住所追加</h1>
	<div >
		<form>
		<button id="btn1" type="button" onclick="clickBtn1()">住所を追加する</button>
		<div id="address1">
			<input type="text" name="zipcode_1" value="" placeholder="郵便番号"><br>
			<input type="text" name="address1_1" value="" placeholder="住所1"><br>
			<input type="text" name="address2_1" value="" placeholder="住所2"><br>
		</div>
		</form>
	</div>
	<script>
		document.getElementById("address1").style.display = "none";

		function clickBtn1(){
			const address1 = document.getElementById("address1");
			if(address1.style.display=="block"){
				document.getElementById("btn1").textContent = "住所を追加する";
				document.getElementsByName("zipcode_1").value = "";
				document.getElementsByName("address1_1").value = "";
				document.getElementsByName("address2_1").value = "";
				address1.style.display ="none";
			} else{
				document.getElementById("btn1").textContent = "追加しない";
				address1.style.display ="block";
			}
		}
	</script>

ここに更に住所を追加するボタンを加える。
– buttonではなく、spanタグにして少しスタイリングする
– 住所1を閉じる時は、住所2を初期化する必要がある

	<h1>住所追加</h1>
	<div >
		<form>
		<span id="btn1" onclick="clickBtn1()">住所を追加する</span>
		<div id="address1">
			<input type="text" name="zipcode_1" value="" placeholder="郵便番号"><br>
			<input type="text" name="address1_1" value="" placeholder="住所1"><br>
			<input type="text" name="address2_1" value="" placeholder="住所2"><br><br>

			<span id="btn2" onclick="clickBtn2()">住所を追加する</span>
		</div>

		<div id="address2">
			<input type="text" name="zipcode_2" value="" placeholder="郵便番号"><br>
			<input type="text" name="address1_2" value="" placeholder="住所1"><br>
			<input type="text" name="address2_2" value="" placeholder="住所2"><br><br>
		</div>
		</form>
	</div>
	<script>
document.getElementById("address1").style.display = "none";
		document.getElementById("address2").style.display = "none";

		function clickBtn1(){
			const address1 = document.getElementById("address1");
			if(address1.style.display=="block"){
				// 住所1
				document.getElementById("btn1").textContent = "住所を追加する";
				document.getElementsByName("zipcode_1").value = "";
				document.getElementsByName("address1_1").value = "";
				document.getElementsByName("address2_1").value = "";
				address1.style.display ="none";

				// 住所2
				document.getElementsByName("zipcode_2").value = "";
				document.getElementsByName("address1_2").value = "";
				document.getElementsByName("address2_2").value = "";
				document.getElementById("address2").style.display = "none";
				document.getElementById("btn2").textContent = "住所を追加する";
			} else{
				document.getElementById("btn1").textContent = "追加をやめる";
				address1.style.display ="block";
			}
		}

		function clickBtn2(){
			const address2 = document.getElementById("address2");
			if(address2.style.display=="block"){
				document.getElementById("btn2").textContent = "住所を追加する";
				document.getElementsByName("zipcode_2").value = "";
				document.getElementsByName("address1_2").value = "";
				document.getElementsByName("address2_2").value = "";
				address2.style.display ="none";
			} else{
				document.getElementById("btn2").textContent = "追加をやめる";
				address2.style.display ="block";
			}
		}
	</script>

OK! これを実装する

[mysql8.0.22] 2000件レコードでテーブルのカラム数28、48、116のselect文の実行時間の差

### レコード数: 2001件
mysql> select count(id) from orders2;
+———–+
| count(id) |
+———–+
| 2001 |
+———–+
1 row in set (0.04 sec)

### sql文
mysql.sql

select * from orders2 where supplier_num = 1;

### カラム数28
$ time (cat mysql.sql | mysql -u root -p test > /dev/null)
Enter password:

real 0m3.099s // プログラムの呼び出しから終了までにかかった実時間
user 0m0.009s // プログラム自体の処理時間(秒)(ユーザCPU時間)
sys 0m0.012s // プログラムを処理するために、OSが処理をした時間

### カラム数48
$ time (cat mysql.sql | mysql -u root -p test > /dev/null)
Enter password:

real 0m3.162s
user 0m0.013s
sys 0m0.009s

### カラム数116
$ time (cat mysql.sql | mysql -u root -p test > /dev/null)
Enter password:

real 0m3.504s
user 0m0.011s
sys 0m0.011s

確かにちょっと遅くなってるけど、カラム数50ぐらいだと、本当に誤差だな
商用環境ではテーブル結合により絞り込み検索を行うので検索スピードは変わってくるのが、レコード数が数千件程度では、カラム数が100を超えていてもそこまで影響はなさそうだな。

[laravel8.12.3] Seederでテストデータを2000件追加してMySQLの実行速度(ユーザCPU時間)を測定する

1. DatabaseSeeder
./database/seeds/DatabaseSeeder.php

 public function run()
    {
        $this->call(Orders1TableSeeder::class);
    }

2. make seeder
$ php artisan make:seeder Orders1TableSeeder

use Illuminate\Support\Facades\DB;

public function run()
    {
        DB::table('orders1')->insert([
            'user_id'=>rand(1,10),
            'supplier_num'=>rand(1,10),
            'supplier_id1'=>rand(1,10),
            'supplier_id2'=>rand(1,10),
            'supplier_id3'=>rand(1,10),
            'supplier_subtotal1'=>rand(100,10000),
            'supplier_subtotal2'=>rand(100,10000),
            'supplier_subtotal3'=>rand(100,10000),
            'total'=>rand(100,10000),
            'product_num'=>rand(1,10),
            'product_id1'=>rand(1,10),
            'product_id2'=>rand(1,10),
            'product_id3'=>rand(1,10),
            'product_id4'=>rand(1,10),
            'product_id5'=>rand(1,10),
            'qty1'=>rand(1,10),
            'qty2'=>rand(1,10),
            'qty3'=>rand(1,10),
            'qty4'=>rand(1,10),
            'qty5'=>rand(1,10),
            'subtotal1'=>rand(100,10000),
            'subtotal2'=>rand(100,10000),
            'subtotal3'=>rand(100,10000),
            'subtotal4'=>rand(100,10000),
            'subtotal5'=>rand(100,10000),
            'detail'=>'',
        ]);
    }

3. db:seed
$ php artisan db:seed

mysql> select * from orders1;
+—-+———+————–+————–+————–+————–+——————–+——————–+——————–+———+————-+————-+————-+————-+————-+————-+——+——+——+——+——+———–+———–+———–+———–+———–+——–+————+————+
| id | user_id | supplier_num | supplier_id1 | supplier_id2 | supplier_id3 | supplier_subtotal1 | supplier_subtotal2 | supplier_subtotal3 | total | product_num | product_id1 | product_id2 | product_id3 | product_id4 | product_id5 | qty1 | qty2 | qty3 | qty4 | qty5 | subtotal1 | subtotal2 | subtotal3 | subtotal4 | subtotal5 | detail | created_at | updated_at |
+—-+———+————–+————–+————–+————–+——————–+——————–+——————–+———+————-+————-+————-+————-+————-+————-+——+——+——+——+——+———–+———–+———–+———–+———–+——–+————+————+
| 1 | 6 | 6 | 6 | 9 | 9 | 6713.00 | 7337.00 | 6092.00 | 9497.00 | 6 | 10 | 2 | 10 | 2 | 2 | 10 | 5 | 5 | 6 | 6 | 4003.00 | 7581.00 | 1475.00 | 2006.00 | 4347.00 | | NULL | NULL |
+—-+———+————–+————–+————–+————–+——————–+——————–+——————–+———+————-+————-+————-+————-+————-+————-+——+——+——+——+——+———–+———–+———–+———–+———–+——–+————+————+
1 row in set (0.00 sec)

mysql> truncate table orders1;

4. seederで2000件データを挿入する
for文で2000件入れる

    public function run()
    {
    	for($i=0;$i<=2000; $i++){
    		DB::table('orders1')->insert([
	            // 省略
	        ]);
    	}
        
    }

$ php artisan db:seed

5. mysql文
mysql.sql

select * from orders1 where supplier_num = 1;

$ time (cat mysql.sql | mysql -u root -p test > /dev/null)
Enter password:

real 0m3.099s // プログラムの呼び出しから終了までにかかった実時間
user 0m0.009s // プログラム自体の処理時間(秒)(ユーザCPU時間)
sys 0m0.012s // プログラムを処理するために、OSが処理をした時間

OK
これはカラム数29だが、カラム数を50, 100と増やした場合に、実行時間がどれ位変化するかテストする。
うむ、そこそこテストっぽいことやってる。

[laravel8.12.3] テーブル追加の手順

まず適当にテーブルを作ります。
$ php artisan make:migration create_orders1_table

続いて適当にカラムを作ります。
-> カラム数29
2020_11_26_122330_create_orders1_table.php

public function up()
    {
        Schema::create('orders1', function (Blueprint $table) {
            $table->id();
            $table->integer('user_id');
            $table->integer('supplier_num');
            $table->integer('supplier_id1')->nullable();
            $table->integer('supplier_id2')->nullable();
            $table->integer('supplier_id3')->nullable();
            $table->decimal('supplier_subtotal1', 10, 2)->nullable();
            $table->decimal('supplier_subtotal2', 10, 2)->nullable();
            $table->decimal('supplier_subtotal3', 10, 2)->nullable();
            $table->decimal('total', 10, 2);
            $table->integer('product_num');
            $table->integer('product_id1')->nullable();
            $table->integer('product_id2')->nullable();
            $table->integer('product_id3')->nullable();
            $table->integer('product_id4')->nullable();
            $table->integer('product_id5')->nullable();
            $table->integer('qty1')->nullable();
            $table->integer('qty2')->nullable();
            $table->integer('qty3')->nullable();
            $table->integer('qty4')->nullable();
            $table->integer('qty5')->nullable();
            $table->decimal('subtotal1', 10, 2)->nullable();
            $table->decimal('subtotal2', 10, 2)->nullable();
            $table->decimal('subtotal3', 10, 2)->nullable();
            $table->decimal('subtotal4', 10, 2)->nullable();
            $table->decimal('subtotal5', 10, 2)->nullable();
            $table->text('detail')->nullable();
            $table->timestamps();
        });
    }

適当にmigrateします。
$ php artisan migrate
Migrating: 2020_11_26_122330_create_orders1_table
Migrated: 2020_11_26_122330_create_orders1_table (53.41ms)

mysql> describe orders1;
+——————–+—————–+——+—–+———+—————-+
| Field | Type | Null | Key | Default | Extra |
+——————–+—————–+——+—–+———+—————-+
| id | bigint unsigned | NO | PRI | NULL | auto_increment |
| user_id | int | NO | | NULL | |
| supplier_num | int | NO | | NULL | |
| supplier_id1 | int | YES | | NULL | |
| supplier_id2 | int | YES | | NULL | |
| supplier_id3 | int | YES | | NULL | |
| supplier_subtotal1 | decimal(10,2) | YES | | NULL | |
| supplier_subtotal2 | decimal(10,2) | YES | | NULL | |
| supplier_subtotal3 | decimal(10,2) | YES | | NULL | |
| total | decimal(10,2) | NO | | NULL | |
| product_num | int | NO | | NULL | |
| product_id1 | int | YES | | NULL | |
| product_id2 | int | YES | | NULL | |
| product_id3 | int | YES | | NULL | |
| product_id4 | int | YES | | NULL | |
| product_id5 | int | YES | | NULL | |
| qty1 | int | YES | | NULL | |
| qty2 | int | YES | | NULL | |
| qty3 | int | YES | | NULL | |
| qty4 | int | YES | | NULL | |
| qty5 | int | YES | | NULL | |
| subtotal1 | decimal(10,2) | YES | | NULL | |
| subtotal2 | decimal(10,2) | YES | | NULL | |
| subtotal3 | decimal(10,2) | YES | | NULL | |
| subtotal4 | decimal(10,2) | YES | | NULL | |
| subtotal5 | decimal(10,2) | YES | | NULL | |
| detail | text | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+——————–+—————–+——+—–+———+—————-+
29 rows in set (0.00 sec)

続いて、このテーブルにSeederでテストデータを入れたい。

[mysql8.0.22]実行速度(ユーザCPU時間)の確認方法

mysql> select version();
+———–+
| version() |
+———–+
| 8.0.22 |
+———–+
1 row in set (0.00 sec)

mysql> use test;
mysql> select * from users;
mysql> SELECT BENCHMARK(100,(SELECT id FROM users m0 WHERE (m0.id = 1)));
+————————————————————+
| BENCHMARK(100,(SELECT id FROM users m0 WHERE (m0.id = 1))) |
+————————————————————+
| 0 |
+————————————————————+
1 row in set (0.00 sec)

ん? 0秒ってこと?

$ touch mysql.sql

select * from users where id = 1;
$ mysql -u root -p "password" -D test <mysql.sql
$ cat mysql.sql | mysql -u root -p -vvv test | tail -n 3
Enter password: 

1 row in set (0.00 sec)

Bye

$ time (cat mysql.sql | mysql -u root -p test > /dev/null)
Enter password: 

real 0m2.544s // プログラムの呼び出しから終了までにかかった実時間(秒)
user 0m0.013s // プログラム自体の処理時間(秒)(ユーザCPU時間)
sys 0m0.007s // プログラムを処理するために、OSが処理をした時間(秒)(システム時間)

0.013s秒ってことか。

これをレコード4000件で、テーブルのカラム数10, 30, 100でテストしてみるか。
結構大変だな。