還暦過ぎたエンジニアの挑戦

還暦過ぎても好奇心だけは忘れない エンジニア ひかるです

MENU

スイッチでランプを点けよう2【スイッチ】

こんな記事(ディシジョンテーブルのこと )で前置きが長くなってしまいましたが、
Vue.jsで簡単にブラウザ上の表示をコントロールできることに感激したので第2弾は
「3路スイッチの回路」
イメージです。


材料

  1. スイッチはwebで使えるスイッチ で紹介したマテリアルアイコンを使います。
    今回は2か所あります。

  2. 画像はランプがOFF状態の時のものとONの状態の時のものをソースの imgBathPath に指定したディレクトリに用意します。
    スイッチのon/offで画像を差し替えるので、onの画像とoffの画像は大きさを揃えておくのがポイントです。

ランプがOFFの時の画像 ランプ点灯時の画像
スイッチライン左上
スイッチライン左上
スイッチライン右上
スイッチライン右上

それぞれの画像の名称は何でもよいのですが、

on/offの画像の差し替え用共通メソッド

function imageColor(img, lightOn) {
    var suffix = lightOn ? '_on.png' : '_off.png';
    return imgBathPath + img + suffix;
}

を用意していますので、~_on.png、~_off.pngというような、対になる名前にしておきます。

imageColor(画像の名前の~の部分, ランプのon|off状態)

でその画像のpathを取得できるようにしておこうということです。


作り方

Vue.jsのdataの記述
  1. 状態を扱う変数の定義はいずれもbool値にしてtrue|falseで判断するようにしておきます
    1. lightOn : ランプが点いている(true)か点いていない(false)か 画像のパスを取得するときに使います。
    2. switchA_on : 図の左下のスイッチをswitchAとしてラインを右上がりの状態をon(true)とします。
    3. switchB_on : 同様に右下のスイッチをswitchBとします。
  2. 画像のsrc属性に使う変数をすべて用意し、初期状態はランプがoffの状態になるようにそれぞれ初期値を設定しておきます。
Vue.jsのmethods
  1. 用意するのは2つのスイッチがクリックされたときのメソッドです。
    単純にメソッド名はswitchAとswitchBにします。
  2. 2つとも同じような動きですので、その内容を switchA を例に書くと
    1. スイッチの状態を反転させる
      offの時にクリックされたらonに、onの時にクリックされたらoffにするということですが、こういう時のコードの書き方はお決まりの
      this.switchA_on = this.switchA_on === false;
      ですね。
    2. ランプの状態を反転させる
      スイッチのon/offとは連動していない3路スイッチですから別に書きますが、それに応じてそれぞれの画像も切り替えるので、それらは外部メソッド(lightSwitch)にしてVueの中ではコールするだけにします。

まとめるとソースはこんな感じになります

var switch2 = new Vue({
    el: '#switch2',
    data: {
        // 初期値
        lightOn: false,
        switchA_on: false,
        switchB_on: false,
        // src属性の初期値
        lamp: imageColor('110658', false),
        baseLine: imageColor('base2', false),
        baseLine1: imageColor('base_line', false),
        baseLine2: imageColor('base_line', false),
        switchA_off_img: imageColor('left', false),
        switchA_on_img: imageColor('right', false),
        switchB_off_img: imageColor('left', false),
        switchB_on_img: imageColor('right', false)
    },
    methods: {
        switchA: function(e) {
            // スイッチAをクリックした時
            this.switchA_on = this.switchA_on === false;
            lightSwitch();
        },
        switchB: function(e) {
            // スイッチBをクリックした時
            this.switchB_on = this.switchB_on === false;
            lightSwitch();
        },
    }
})

外部メソッドlightSwitch()のソース

function lightSwitch() {
    // ライトのon/off状態を切り替える
    switch2.lightOn = switch2.lightOn === false;
    
    // 中央の2本の線は一旦offの状態にしておく
    switch2.baseLine1 = imageColor('base_line', false);
    switch2.baseLine2 = imageColor('base_line', false);

    // ライトのon/off状態に応じて画像を変更する
    switch2.lamp = imageColor('110658', switch2.lightOn);
    switch2.baseLine = imageColor('base2', switch2.lightOn);
    if (switch2.switchA_on) {
        switch2.switchA_on_img = imageColor('right', switch2.lightOn);
        switch2.baseLine1 = imageColor('base_line', switch2.lightOn);
    } else {
        switch2.switchA_off_img = imageColor('left', switch2.lightOn);
        switch2.baseLine2 = imageColor('base_line', switch2.lightOn);
    }
    if (switch2.switchB_on) {
        switch2.switchB_on_img = imageColor('right', switch2.lightOn);
    } else {
        switch2.switchB_off_img = imageColor('left', switch2.lightOn);
    }
}

HTMLの記述

今回使用しているVue.jsの記法は3つです。

v-ifとv-else

スイッチとスイッチの画像のところで使用しました。
ちょっと注意すべきは v-ifとv-elseはどちらか一方しかDOM上には存在しないので、
うっかり存在しないほうの要素を参照しないようにすることです。

v-bind (省略形 :)

imgタグの属性に省略形で使用しました。
:src=(dataの変数名) で割り当てることができますのでHTMLが随分すっきりしますね。

v-on (省略形 @)

もちろんスイッチの要素に使用しました。
マテリアルアイコンの要素に省略形でクリック時に呼び出すメソッドを記述しました。
@click=(methodsのメソッド名)


最後に

全体のHTMLを含めたソース

<link rel="shortcut icon" href="https://blog.yutenji.biz/favicon">
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="vue.min.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
    [v-cloak] {
        display: none
    }

    body {
        font-family: "ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", "メイリオ", Meiryo, Osaka, "MS Pゴシック", "MS PGothic", sans-serif;
    }

    h1 {
        font-size: 14px;
        margin: 0;
    }

    #diagram1 {
        z-index: 10;
        position: relative;
    }

    #diagram1 img {
        margin-top: 10px;
    }

    .materials {
        position: absolute;
        cursor: pointer;
        font-size: 40px;
    }

    #switchA_on {
        top: 174px;
        left: 35px;
    }

    #switchA_off {
        top: 192px;
        left: 37px;
    }

    #switchB_on {
        top: 193px;
        left: 258px;
    }

    #switchB_off {
        top: 175px;
        left: 261px;
    }

    #switch_A {
        top: 265px;
        left: 36px;
    }

    #switch_B {
        top: 265px;
        left: 264px;
    }

    .switch_name {
        position: absolute;
        width: 100px;
        font-size: 12px;
    }

    #switch_A_name {
        top: 300px;
        left: 24px;
    }

    #switch_B_name {
        top: 300px;
        left: 252px;
    }

    .switchLine {
        position: absolute;
        z-index: 0;
    }

    #line1 {
        top: 205px;
        left: 65px;
    }

    #line2 {
        top: 236px;
        left: 65px;
    }

    #lamp1 {
        position: absolute;
        z-index: 20;
        left: 145px;
        top: 43px;
    }

    #lamp1 img {
        height: 50px;
    }
</style>
<div>
    <h1>スイッチ2 (3路スイッチ)</h1>
    <div id="switch2">
        <div id="lamp1">
            <img :src="lamp">
        </div>
        <div id="line1" class="switchLine">
            <img :src="baseLine1">
        </div>
        <div id="line2" class="switchLine">
            <img :src="baseLine2">
        </div>

        <div class="switchLine">
            <div v-if="switchA_on" id="switchA_on" class="switchLine"><img :src="switchA_on_img"></div>
            <div v-else id="switchA_off" class="switchLine"><img :src="switchA_off_img"></div>
        </div>
        <div class="switchLine">
            <div v-if="switchB_on" id="switchB_on" class="switchLine"><img :src="switchB_on_img"></div>
            <div v-else id="switchB_off" class="switchLine"><img :src="switchB_off_img"></div>
        </div>

        <div id="switch_A" class="material-icons materials">
            <div v-if="switchA_on" @click="switchA">toggle_on</div>
            <div v-else @click="switchA">toggle_off</div>
        </div>
        <div id="switch_A_name" class="switch_name">スイッチA</div>

        <div id="switch_B" class="material-icons materials">
            <div v-if="switchB_on" @click="switchB">toggle_on</div>
            <div v-else @click="switchB">toggle_off</div>
        </div>
        <div id="switch_B_name" class="switch_name">スイッチB</div>

        <div id="diagram1">
            <img :src="baseLine">
        </div>
    </div>
</div>
<script>
    var imgBathPath = '../../img/diagram/';
    var switch2 = new Vue({
        el: '#switch2',
        data: {
            // 初期値
            lightOn: false,
            switchA_on: false,
            switchB_on: false,
            // src属性の初期値
            lamp: imageColor('110658', false),
            baseLine: imageColor('base2', false),
            baseLine1: imageColor('base_line', false),
            baseLine2: imageColor('base_line', false),
            switchA_off_img: imageColor('left', false),
            switchA_on_img: imageColor('right', false),
            switchB_off_img: imageColor('left', false),
            switchB_on_img: imageColor('right', false)
        },
        methods: {
            switchA: function(e) {
                // スイッチAをクリックした時
                this.switchA_on = this.switchA_on === false;
                lightSwitch();
            },
            switchB: function(e) {
                // スイッチBをクリックした時
                this.switchB_on = this.switchB_on === false;
                lightSwitch();
            },
        }
    })

    function lightSwitch() {
        // ライトのon/off状態を切り替える
        switch2.lightOn = switch2.lightOn === false;
        // 中央の2本の線は一旦offの状態にしておく
        switch2.baseLine1 = imageColor('base_line', false);
        switch2.baseLine2 = imageColor('base_line', false);

        // ライトのon/off状態に応じて画像を変更する
        switch2.lamp = imageColor('110658', switch2.lightOn);
        switch2.baseLine = imageColor('base2', switch2.lightOn);
        if (switch2.switchA_on) {
            switch2.switchA_on_img = imageColor('right', switch2.lightOn);
            switch2.baseLine1 = imageColor('base_line', switch2.lightOn);
        } else {
            switch2.switchA_off_img = imageColor('left', switch2.lightOn);
            switch2.baseLine2 = imageColor('base_line', switch2.lightOn);
        }
        if (switch2.switchB_on) {
            switch2.switchB_on_img = imageColor('right', switch2.lightOn);
        } else {
            switch2.switchB_off_img = imageColor('left', switch2.lightOn);
        }
    }

    function imageColor(img, lightOn) {
        var suffix = lightOn ? '_on.png' : '_off.png';
        return imgBathPath + img + suffix;
    }
</script>

も載せておきます。💦

動的なページを作るときにVue.jsを使うとHTMLがすっきりして、エンジニアとデザイナーの仕事の棲み分けがはっきりするかもしれませんね。


ディシジョンテーブルのこと【スイッチ】

先日、スイッチでランプを点けようというこんな記事を書いたのですが、blog.yutenji.biz

あの時は単純に

  • スイッチをオンにする → ランプが点く
  • スイッチをオフにする → ランプが消える

でしたので、その動作をブラウザで表現するプログラムは比較的簡単でした。

ですが、今度は電気工事士を目指すエンジニアとして、😏
一歩進んで「3路スイッチの動作」を Vue.js を使ってブラウザで表現することを考えてみたいと思います。😄

3路スイッチとは

例えば、階段の照明を階上と階下と両方から点けたり切ったりできるようにするときに使うスイッチのことで、図示するとこんなイメージです。

f:id:hikaru217:20200528151850j:plainf:id:hikaru217:20200528151906j:plain
普通のスイッチ(左図)と3路スイッチ(右図)のイメージ

ちょっとプログラム的なハードルは上がりそうですね。
この3路スイッチの図のスイッチAをポチッと押した時

 が 

になるとすると、
ランプが点くかどうかは
スイッチBの状態によって変わるということですね。

今のこの図の状態なら電気が通ってランプは点くというイメージです。

Vue.jsでプログラムする前に

この図を見てわかることは

  • 2つの3路スイッチの状態と
  • ランプが点くか点かないか

は別の状態として識別するようにしないとダメそうだということです。

でも、関連性があるのは明らかですね。

こんな時に使うと便利なのがディシジョンテーブル*1です。

縦列をみて、
「スイッチAとスイッチBがどういう状態の組み合わせの時に、ランプはどうなる」
という風に判断できるように整理します。

普通は○、×、レ点などで書きますが、今回のケースはシンプルなのでこんな風に画像で整理してみました。😓

スイッチAの状態
スイッチBの状態
ランプは→

まぁ、ここまでしなくても、頭の中でこんな風に整理できれば良いということです。

あとはそれぞれの状態に応じて画像を変更するだけで
実現できそうですね。

続く

*1:複雑な仕様を整理するときには欠かせない、表にして整理する手法のこと。またその表のこと

検索結果と同時に件数も取得する

mysql

SELECT count(*) over () as totalCount, * from  {テーブル};  

検索結果を得たらページネーション*1でわかりやすく表示したい。。。

みたいなことはエンジニアとしては良くある話ですが、全部で何ページあって、今は何ページ目を表示していますのように表現しようとすると、全部で検索結果は何件あるか

という情報も必要になります。

そういう時、実際の検索のSQLとは別に、
もう一度件数を取得するために同じ条件のSQLを再実行するのは仕方がないこと

のように思ってきましたが、こうやって書けばよいのですね

実行するとこんな感じで、すべての行のtotalCountに同じ値がセットされて返ってきました。

f:id:hikaru217:20200525160209j:plain
実行結果例

でも、MySQLのversion8以降で使えるようになった比較的新しい構文らしいですのでご注意を。


*1:検索結果が多い時、複数のページに分割して、読み取りやすくするナビゲーションのことです

スイッチでランプを点けよう【スイッチ】

前回(というべきか昨日ですが)、
webで使えるスイッチ
という記事を書いたのですが、せっかくですので今日はその続き。

そのものずばりで

「スイッチでランプを点けよう」

ということで今日のサンプルはこれです

スイッチのアイコンをクリックすると

ランプが点いたり消えたりする画像

完全に遊んでいますね。😅

しかしVus.jsおそるべしです。
こんなに簡単にできるとは。。。

ソースはこんな感じ

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<div class="sampleMaterial">
    <h1>スイッチ2</h1>
    <span id="switch1">
        <div id="lamp1">
            <span v-if="switch1On"><img src="../../img/diagram/110658_on.png"></span>
            <span v-else><img src="../../img/diagram/110658_off.png"></span>
        </div>
        <div id="diagram1">
            <span v-if="switch1On"><img src="../../img/diagram/base1on.jpg"></span>
            <span v-else><img src="../../img/diagram/base1.jpg"></span>
        </div>
        <span class="material-icons materials">
            <span v-if="switch1On" @click="toOff">toggle_on</span>
            <span v-else @click="toOn">toggle_off</span>
        </span>
    </span>
</div>
<script>
    var switch1 = new Vue({
        el: '#switch1',
        data: {
            switch1On: false
        },
        methods: {
            toOff: function(e) {
                this.switch1On = false;
            },
            toOn: function(e) {
                this.switch1On = true;
            }
        }
    })
</script>

スクリプトの部分は修正なし。

実は昨日のソースを少し書き換えたものなのですが、
スクリプトの部分は1文字も触っていません。
→ きっとここがポイントですね。

ランプと配線の画像を追加して、スタイルシートを修正しただけです。

その代わり、 cssのpositionの使い方をすっかり忘れていた(これこそ還暦エンジニアの敵?)のを思い出しました。
→ もしかすると今日の主題はこれですかね。

親要素の`position`を`relative`にして
自分の`position`は`absolute`にする

あとはtopleftを調整すればOKです。

これで、スイッチと配線とランプの画像の位置を調整しました。

配線図で書くとこんな感じであっているのかなぁ

f:id:hikaru217:20200524115648j:plain

しかし、こんなことをやっていて、本当に第2種電気工事士の試験に合格できるのでしょうかね?💦


今日のランプの画像はふに@ぐみさん のイラストを使わせていただきました。
久しぶりにillustratorをちょっと触れて楽しかったです。


webで使えるスイッチ【スイッチ】

今日は新しいカテゴリーを作りました。
題して「これだけ知りたい 部品集」

「知りたい~」 っていうのとはちょっと違うかもしれませんが、
要するにエンジニアとして仕事をする上で
「使いまわしのきくコード」
とか
「共通のデザイン」
とか、もしかすると
「便利なメソッド」
なんかかもしれない。

そんなものを思いついたときに書き溜めていこうと思う。(気合っ!)

初回の今日は題して
「webで使えるスイッチ」

material-iconとVue.jsで作ってみました。

こんな感じでクリックするたびに
on/off が切り替わるイメージですが、
イメージだけではなくて、
それに反応して応用が利くようにしておこうという魂胆です。

骨格はこんな感じ

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<div class="sampleMaterial">
    <h1>スイッチ</h1>
    <span id="switch1" class="materials">
        <span class="material-icons">
            <span v-if="switch1On" @click="toOff">toggle_on</span>
            <span v-else @click="toOn">toggle_off</span>
        </span>
    </span>
</div>
<script>
    var switch1 = new Vue({
        el: '#switch1',
        data: {
            switch1On: false
        },
        methods: {
            toOff: function(e) {
                this.switch1On = false;
            },
            toOn: function(e) {
                this.switch1On = true;
            }
        }
    })
</script>

で、例えばスイッチをonにしたときに、
「やぁっ!( ^^) _U~~」
と表示するなら

toOn: function(e) {
    this.switch1On = true;
    alert("やぁっ!( ^^) _U~~"); <= こんな感じで書き足す
}

すると

まあ、そこらへんに転がっていそうな部品ですが、Vue.jsなるものをちょっといじってみたかったので。。。

でも今日はここまでかな
続きはまた。


サーバー上のファイルを直接編集する-VSCode

例えば、
「このサイトのページはちょっとマージン取りすぎていて酷いな、ちゃんと表示されないから今すぐスタイルシートを修正したい~!直すところは1か所だけでいいんだけど。」

みたいな瞬間接着剤的に修正したい時に、

  1. ローカルのソースを修正して
  2. FTPで接続して
  3. それをサーバーにアップロードして

などと面倒くさ過ぎてやっていられない。

と思ったら、VSCodeでは
サーバー上のファイルを直接編集する
こともできてしまいます。

もちろん、あらかじめ接続先のサーバー情報などはconfigで設定しておきますが、

  1. VSCodeを開く
  2. F1を押す
    f:id:hikaru217:20200519192732j:plain
  3. ftp-simple : Remote directory open to workspace を選択する f:id:hikaru217:20200521215638j:plain
  4. 接続先のサーバーを選択する
    f:id:hikaru217:20200521223203j:plain
    という要領で目的のファイルを直接選択しても良いし、ディレクトリを指定してもよい。

すると、エクスプローラーに選択したディレクトリまたはファイルが表示されるので、
あとは目的のファイルを開いて修正をしてsaveするだけ
そのまま反映される。

しかしこれ、gitでバージョン管理しているファイルなどには安易にお勧めできないですね、、、

「その後」が大変そう。

publicではないメソッドをテストする

f:id:hikaru217:20200515140036p:plain
privateやprotectedのメソッドだってテストコードを書いておきたいときはある。
でも、あまり頻繁には使わない。
いつもどうだっけ? ってなる

$reflectionMethod = new \ReflectionMethod(クラスのインスタンス, テストするメソッド名);
$reflectionMethod->setAccessible(true);
$result = $reflectionMethod->invoke(クラスのインスタンス[, テストするメソッドの引数]);

結局

  1. reflectionMethodのインスタンスを作って
  2. アクセス可能にして、
  3. invokeする3ステップで

y=x じゃないよ mac と win 両刀使いの悲劇

関数の話ではないです。

1. y=x
2. c*//windows
3. ]hikaru]

はもちろん、

1. y_x
2. c://windows
3. 'hikaru'

って入力したかったのよ。。。

昼間Macで仕事して、夜のプライベートにWindowsで入力すると、手癖というか、指の感覚でどうもうっかりキーを間違えちゃう割とありがちな話。

Macの _ のキーはWindowsでは = になる

同じようなキーの位置で違う文字だからなんですが、あまり、そういう人は少ないかなぁ

で、先日は逆のパターンで悲劇が起こりました。今だから書けるのだけど、、、


f:id:hikaru217:20200509073318g:plain
macとwin

Windowsの指の形でMacでついうっかりやってしまった件の現場検証をするとこんな感じ

  1. ある大事な設定ファイルを修正していた
  2. 保存するつもりで Ctrl + s -> 実際には fn + sだった
  3. しまったと思い、Command + s -> 本当に保存された
  4. その後、別の作業で中断
  5. 戻ってそのまま設定したことを確認する
  6. あれ?あら?動かないじゃん💦となる
  7. しばらく何が起きたんだとちょっと慌てる
  8. そのうち周囲まで巻き込んで事件に発展する

もう、、、
設定ファイルに余計な’s’が入力されていたのが原因だったのはいうまでもありません

関係者の皆様、ごめんなさい🙇‍♀️

よりによってxxxsがxxxssになっててすぐに気付けなかったんです(言い訳)


足枷でもある - mysql

mysql

データベースの設計をするときに、データの正規化、整合性を担保したいという気持ちはわからなくもない。
こっちのテーブルAにある値は別のテーブルBに存在するものじゃなきゃいけない。。。みたいなの

設計者の気持ちもわからなくはないが、でも、そういったことはシステムで塞いでおいたほうが良い。そんな定義をデータベースにされ、雁字搦めにされたのではいろいろと足枷になり、やりにくくてしょうがないこともある。

システムのバージョンアップに弊害がでることもあるし、 テストにじゃまだからこのデータは消したい!と思っても消せない。

えっ?そんな~
FOREIGN_KEYで削除できない!?
というときのマジック

SET FOREIGN_KEY_CHECKS=0;

これで心置きなくDELETEしよう

ついでにUPDATEするときのこれも

SET SQL_SAFE_UPDATES = 0;

データ変更もできないと仕事が止まるしね


コメントぐらい修正しようよ その2 - mysql

f:id:hikaru217:20200514215651p:plain

以前に書いた記事 blog.yutenji.biz
では、カラムのコメントの修正はカラムの再定義になる。。。
というところが、ちょっとだけリスクを感じるけど、
テーブルの説明文(COMMENT)は
ただ書く」 だけなので、サボらないようにしようと思う。

今日初めて見るシステムではなんだかさっぱりわからないからね。

ALTER TABLE (テーブル名) COMMENT 'テーブル説明文';

ほんとに簡単じゃん

INSERTしたオートインクリメントのIDを取得する - mysql

mysql
これもあまり普段は使わないので記憶もあいまいになる。
この関数ではAuto Increment のkeyしか掴めないんだけど。。。
って、そりゃそうだ
- 自分で指定したkeyならわかってるに決まっている! なにが使われているかわからないから掴みたい。

INSERT INTO ・・・;
set @auto_increment_id = LAST_INSERT_ID();

これで後は焼いて食うなり、煮て食うなりで

IF NOT EXISTSは必ず書くよ - mysql

mysql

CREATE TABLE IF NOT EXISTS テーブルネーム

ちょっとまずいケースがあったので。

CREATE TABLEは基本的に一度実行すれば良いことなので、どっちでも良いかな。。。
ぐらいに考えていたら今日はちょっと失敗した。

書いておいて害はないので、転ばぬ先の杖。
習慣にしようっと。。。