76
85

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

electron-vue でデスクトップアプリを作ってみた

Posted at

概要

その名も、HourTimer !
一時間を測るだけという、シンプルなデスクトップアプリです。

Vue.jsの勉強もかねて、、electron-vueを使ってみました。
日本語ドキュメント

こちらからダウンロードできますが、
配布サイトは適当に作ったので、クオリティは気にしないでくださいw
また、署名の問題でエラーが出てくるかもしれませんが、ウイルスなどはありません。
証拠に、ソースコードを公開しておきます。笑

アプリ概要

アプリの機能は、一時間を測るという単純なものです。
見た目はこんな感じ。
スクリーンショット 2018-06-17 18.19.58.png

再生ボタンを押すと、タイマーが起動します。
hourtimermov.mov.gif

停止ボタンでタイマーはストップします。
一度ストップすると、アプリを閉じてもMacを閉じても、
残り時間は保持される機能も付きです!

リセットボタンで、残り時間が一時間に戻ります。

以下、ソースコードをもとに、
実装などを紹介していきます!

まず、electron-vueとは?

electronは、javascriptを使ってデスクトップアプリを開発するフレームワーク、
Vue.jsはjavascriptの便利なライブラリです。

では、electron-vueとは何でしょうか?
日本語ドキュメントから引用すると、以下のように書いてあります。

vue で構築された electron アプリケーションを作成するためのボイラープレートです(名前から分かるように)。

ということです(名前からわかるように)!

説明については、日本語ドキュメントや、他の方のQiita記事でわかりやすいものがあるので、詳しくはそちらを御覧ください!
2017年度版 electron-vueで始めるVue.js

また、electronVue.js自体についても、公式のドキュメントが充実しています。
そちらをご覧くださいませ!

時間をカウントする実装

普段、javascriptを書いているのですが、時間を測る実装方法を知りませんでした。
そこでgoogleすると、以下のようなサイトがヒットしました!😀
Vue.js でタイマーを作る
Vue.js でシンプルなストップウォッチを作ってみた

どうやら、requestAnimationFrameというメソッドを使うのがよさげでしたので、使ってみました。

該当するファイルはTimer.vue
になります。
その中で,startTimer,stopTimerというメソッドが主です。

startTimer
...
    startTimer: function() {
      let vm = this;
      if (this.remainTime == 0) {
        this.remainTime = 3600000;
      }
      vm.isCount = true;
      vm.startedTime = Math.floor(performance.now() - vm.diffTime);
      (function loop() {
        let loopfps = vm.diffTime;
        vm.nowTime = Math.floor(performance.now());
        vm.diffTime = vm.nowTime - vm.startedTime;
        vm.remainTime -= vm.diffTime - loopfps;
        if (vm.remainTime % 10000 < 20) {
          localStorage.setItem("remainTime", vm.remainTime);
        }
        if (vm.remainTime > 0) {
          vm.animateFrame = requestAnimationFrame(loop);
        } else {
          vm.finishTimer();
        }
      })();
    }

ここから、時間をカウントする部分だけ切り取ると、、、

(function loop() {
  let preDiffTime = vm.diffTime;
  vm.nowTime = Math.floor(performance.now());
  vm.diffTime = vm.nowTime - vm.startedTime;
  vm.remainTime -= vm.diffTime - preDiffTime;

  if (vm.remainTime > 0) {
    vm.timeCountFrame = requestAnimationFrame(loop);
  } else {
    vm.finishTimer();
  }
 })();

残り時間は vm.remainTimeで、これが0になるまでカウントを続けます。
stopTimerメソッドではcancelAnimationFrame(this.timeCountFrame)を実行することで、カウントを止めています。

タイマーの見た目はどう実装する

できるだけ楽をしたかったので、円を描いているいい感じのライブラリを探しました。
そこでchart.js,vue-chartjsを見つけて

「円グラフを使えば楽にできるのでは・・・?🤔」

と思いつき、実装を試みたのですが・・・。
 
挫折しました😅

なので、素直にhtmlのcanvas要素を使いました!😆

canvasで困ったこと

canvasでタイマーを作成するにあたって困ったことがいくつか・・・。

canvasのレスポンシブ対応

単純にレスポンシブにすると、windowを大きくしたときにcanvas内がジャグジャグしてしまう問題にぶち当たりました。
解決策としては、あらかじめ大きく作ったcanvas要素を縮小・拡大することにしました。

<canvas id="timerLine" width="1000" height="1000"></canvas>

こんな感じ!

タイマーのアニメーション

canvasの中に円を描く事自体は簡単なのですが、canvasをどうやって動的に書き換えようか、少し悩みました。
結論としては、予め書いておいたベージュの円に上書きする形で、黒の円を描くことにしました。
TimerLine.vueが該当するファイルです。

TimerLine.vue
...
mounted: function() {
    const timerLine = document.getElementById("timerLine");
    this.ctx = timerLine.getContext("2d");
    let ctx = this.ctx;
    ctx.beginPath();
    ctx.lineWidth = 50;
    ctx.strokeStyle = "#F5E5B3";
    ctx.arc(500, 500, 450, 0 * Math.PI / 180, 360 * Math.PI / 180);
    ctx.stroke();
    ctx.closePath();
    let img = new Image();
    img.src = require("../assets/pencil.png");
    img.onload = function() {
      ctx.drawImage(img, 250, 250, 500, 500);
    };

    ctx.lineWidth = 51;
    ctx.strokeStyle = "#1D1C22";

    ctx.beginPath();
    let remainAngle = (60 - this.remainMin) * 6 - 90;
    ctx.arc(500, 500, 450, -90 * Math.PI / 180, remainAngle * Math.PI / 180);
    ctx.stroke();
    ctx.closePath();
  },
  updated: function() {
    if (this.remainMin == 60) {
      this.initTimer();
      return;
    }
    let ctx = this.ctx;
    ctx.strokeStyle = "#1D1C22";
    ctx.beginPath();
    let remainAngle = (60 - this.remainMin) * 6 - 90;
    ctx.arc(500, 500, 450, -90 * Math.PI / 180, remainAngle * Math.PI / 180);
    ctx.stroke();
    ctx.closePath();
  },

残り時間が一分減るごとに、6度分長い黒線を描いています。
vueのライフサイクルフックであるmounted,updatedを使用することで、canvasを動的に描くことは割と簡単に実装できました😚

アプリを閉じても残り時間を保持する

個人的に、これが一番欲しかった機能です。
しかし、実装はかなり単純で、localstorageを使うだけです。

Timer.vueのstopTimerメソッド
stopTimer: function() {
   cancelAnimationFrame(this.timeCountFrame);
   this.isCount = false;
   localStorage.setItem("remainTime", this.remainTime);
}

この三行目で,残り時間を
localStorageに保存しています。

あとの詳細については、実際のコードを見るのが早いと思います!
質問やissueなどしてくださると,泣いて喜びます😂

とりあえず作ってみた感想

いつもweb触っている人なら、electronを使えば簡単に、いつもと変わらない開発方法で
デスクトップアプリが開発できると実感しました!
今回のレベルだと、わざわざvueを使う必要がなかった気もしますが・・・
まあ、とりあえずよしとします!笑
人に見せられるレベルまで作れてよかったです!

今後実装してみたい機能

今回は、electronのAPIは叩いていないので、それらを使う機能を加えてみたい!
加えやすいのは、「通知を出す」とかかなあ・・・。

また、もともと「一日一時間頑張る」ために使うことを想定していたので、
毎日の頑張った時間を記録できる機能がつけれたらいいなあ、と思っています。

76
85
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
76
85

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?