pco2699’s blog

学んだコード・技術について、保存しておく場所

Vue.jsで簡単なタイマーアプリ

つくりましたよ

Vue.js/Moment.jsで簡単なカウントダウン日付タイマーをつくりました

コード

js部

import moment from 'moment'
import Vue from 'vue'

let now_date = moment()

let date_format = 'YYYY:MM:DD HH:mm:ss'

let submission_date = moment('2017-09-22 23:59')
let presentaion_date = moment('2017-10-12 23:59')

const vm = new Vue({
  el: '#date',
  data: {
    now_date: now_date.format(date_format),
    submission_remain_days: now_date.diff(gga_submission_date, 'days'),
    presentaion_remain_days: now_date.diff(gga_presentaion_date, 'days')
  },
});

setInterval(()=>{
  vm.now_date = moment().format(date_format)
},1000)

html部

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Hello Vue</title>
  </head>
  <body>
    <div id="date">
      <div class="row">
        <span class="label">現在日付:</span> <span class="data">{{now_date}}</span>
      </div>
      <div class="row">
        <span class="label">提出締切: </span> <span class="data">{{gga_submission_remain_days * -1}} </span>
      </div>
      <div class="row">
        <span class="label">発表: </span> <span class="data">{{gga_presentaion_remain_days * -1}} </span>
      </div>
    </div>
    <script src="dist/bundle.js"></script>
  </body>
</html>

つまづきポイント

現在の日付を書き換えるのに、

let now_date = moment()

const vm = new Vue({
  el: '#date',
  data: {
    now_date: now_date.format(date_format), // ここでnow_dateをvmのdata部に設定
    submission_remain_days: now_date.diff(gga_submission_date, 'days'),
    presentaion_remain_days: now_date.diff(gga_presentaion_date, 'days')
  },
});

setInterval(()=>{
  now_date = moment().format(date_format) // 間違えてnow_date側のオブジェクトを取得しちゃっている...
},1000)

と、vueのdata部じゃなくて、設定するオブジェクト側を書き換えてたんだけど
もちろんこれは誤りで、ちゃんと、vueのdata部をsetInterval内で書き換えるようにしたらいけました。
(すごいシンプルな間違い。)

シンプルにView(html)とModel(js)をバインディングしてくれて非常に楽ですね〜
(ReactとかRiotとか使ったことないので、もっと楽かもだけど。)

Date型から強制的に「年月日」以外のデータを切り捨てる

環境

つまづきポイント

Swiftで日付の差分を計算してその間の日数を表示するロジックを書いてたら Date型で時・分が保存されてしまっていて、想定外の日数となっていた!

// 現在日付を取得(例えば 2017/07/12 12:01)
let today_date = Date()
// 期限を取得(例えば 2017/07/22 12:00)
let deadline_date = settings.object(forKey: "deadline_date") as? Date
    
// 現在の残り日数を計算
var deadline_days_now = calendar?.dateComponents([.day], from: today_date, to: deadline_date).day
// ->日付だけ計算すると10日のはずだけど、時・分が保存されてしまっていて9日になってしまう!

解決方法

一旦、DateからDateComponentsにしてDateに戻す関数を作成して強制的に切り捨てた

// Dateから年日月を抽出する関数
func roundDate(_ date: Date, calendar cal: Calendar) -> Date {
  return cal.date(from: DateComponents(year: cal.component(.year, from: date), month: cal.component(.month, from: date), day: cal.component(.day, from: date)))!
}

// 現在日付を取得(例えば 2017/07/12 12:01)
let today_date = Date()
// 期限を取得(例えば 2017/07/22 12:00)
let deadline_date = settings.object(forKey: "deadline_date") as? Date
// カレンダーを取得
let  calendar = Calendar(identifier: .gregorian)

// today_dateから年月日のみ抽出する -> 2017/07/12となる
let today_date_rounded =  roundDate(today_date!, calendar: calendar!)
// deadline_dateから年月日のみ抽出する -> 2017/07/22となる
let deadline_date_rounded =  roundDate(deadline_date!, calendar: calendar!)


// 現在の残り日数を計算
var deadline_days_now = calendar?.dateComponents([.day], from: today_date_rounded, to: deadline_date_rounded).day
// ->時・分が保存されてないので正しく計算されて10日になる

複数ページある場合のアプリ起動時のローカル通知の処理の設定方法

環境

つまづいたところ

LocalNotificationを実装したところ、アプリ立ち上げ中に時間になってもまったくローカル通知がなかった…

解決方法

複数ページあるiPhoneアプリの場合、ローカル通知のdelegateはAppDelegateにかく! (一つのViewControllerにuserNotificationCenterのdelegateを書いてたため、通知に音沙汰がなかったようです…)

import UserNotifications

class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

  var window: UIWindow?
  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

    
    //起動中に通知を受け取るためのdelegate設定
    UNUserNotificationCenter.current().delegate = self    
    return true
  }

// いろいろ書いてあるdelegateは省略...
  
  // アプリが foreground の時に通知を受け取った時に呼ばれるメソッド
 // AppDelegateの中にuserNotificationCenterのdelegateをかく!
  func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    completionHandler([.alert , .sound])
  }


}


UINavigationContollerの自動生成される「戻る」ボタンの書き換え

環境

前提条件

メイン画面(ViewController.swift) → 設定画面(SettingsViewController.swift)

やり方 その1

遷移先であるSettingsViewController.swiftを書き換える。 今回はこちらを採用。

  override func viewDidLoad() {
    super.viewDidLoad()
    
    //トップに戻るボタンを作成
    let leftButton = UIBarButtonItem(title: "戻る", style: UIBarButtonItemStyle.plain, target: self, action: #selector(goTop))
    self.navigationItem.leftBarButtonItem = leftButton
  }

  func goTop(){
    //トップ画面に戻る。
    self.navigationController?.popToRootViewController(animated: true)
  }

やり方 その2

遷移元であるViewController.swiftからbackbuttonを書き換える。 (実装してないが、たぶんいけるはず?)

  override func viewDidLoad() {
    super.viewDidLoad()

    //トップに戻るボタンを作成
    let backButton = UIBarButtonItem(title: "戻る", style: UIBarButtonItemStyle.plain, target: self, action: #selector(goTop))
    self.navigationItem.backBarButtonItem = backButton
  }

  func goTop(){
    //トップ画面に戻る。
    self.navigationController?.popToRootViewController(animated: true)
  }
  

わからんポイント

その一だと「<」と書かれた矢印も合わせて書き換えられてしまう。 どうすればいいか。

Python + Heroku + LINE BOT SDKでコーランを教えてくれるbotを作った

LINE BOT AWARDSでLINE BOTが盛り上がってるので作成してみました。
LINE BOT AWARDSにも「ローカライゼーション」部門でエントリしておきました。
ほぼ一発ネタなので、暇つぶしにでもフォローしてみてください。

つくったもの

言葉に対してなんでもコーランの開端の章の一節を返してくれるbot
「意味は?」とか聞くとそのコーランの意味を教えてくれたりします。
こんな感じです。 f:id:pco2699:20170303145726p:plain

なぜつくったか

  • 最近 海外に出かけるときは、なにかと物騒なのでコーランを覚えておいたほうが安全なのでは、と思ったため
  • これをきっかけにイスラム教の人と仲良くなれるかな、と思ったため (まだイスラム教の友達はいないけど..)

利用したもの

ソースコードはLINE BOT SDKの中のサンプルsimple-server-echoをベースに作りました。
その他に利用したものは以下。

Github

github.com

ライフゲームをNovation Launchpadに実装して、シーケンサーにしてみる

引き続き、前回紹介した「ジェネラティブアート」の本読んでます。 その中で、後半に出てくる「ライフゲーム」が面白かったので、ちょっと発展させて楽器にしてみました。

[普及版]ジェネラティブ・アート―Processingによる実践ガイド

つくったもの

こんな感じになりました
(我ながらTENORI-ON感がすごい音)
うす緑色の縦線が現在、鳴っている音で、Cメジャー・スケールで音を鳴らしてます。

youtu.be

ライフゲームとは

碁盤の目のような格子があって、それぞれの格子が周りの状態を見て 自立的に、一定のルールで自分の状態を決める。(これがセル・オートマトンと呼ばれるもの) で、このセル・オートマトン上で、以下のルールに従って格子の状態が決まるのがライフゲーム

  1. 生きている格子は、2つか3つの隣接セルが生きていればそのまま生き続ける。
    さもなければ過疎か過密のどちらかで死んでしまう。
  2. 死んだ格子の周囲に、ちょうど3個の生きた隣接セルがあれば奇跡が起こり
    その格子は生き返る。

百聞は一見にしかず、以下のサイトを見てみるとなにかよくわかる。

ライフゲーム

ちなみにGoogleで「ライフゲーム」で検索すると実は裏側で ライフゲームが動いているという。。。さすがGoogle f:id:pco2699:20161210153635p:plain

参考資料など

Launchpadをプログラミングするときは Novationから出ている Launchpad プログラミングリファレンスが参考になりました。

https://d19ulaff0trnck.cloudfront.net/sites/default/files/novation/downloads/4080/launchpad-programmers-reference.pdf

ソースコード

PythonMIDIライブラリmidoで実装しました。

gist7806d8a4dc543a2ca71ed23d360b294b

Processingを用いて間違った円を描く方法

3331α Art Hack Day 2016というアート×エンジニアリングの共演みたいな面白そうなハッカソンに応募したんだけど 見事に抽選(というか審査)に落ちて、参加できなかったので、悔しくて以下の本を買ってみました。

[普及版]ジェネラティブ・アート―Processingによる実践ガイド

この本おもしろくて、最初は単純の線を描く方法ばっかりなんだけど(実際、著者も「これは退屈だが」って書いてるあたりわかってる。) 「間違った円を描く方法」という章あたりから大分、様子がおかしくなってくる。
というわけなので、自分も、とっかかりとしてこの様子がおかしい円を描いてみることにした。

書いたもの

様子がおかしいというか、なんだか悪夢感がすごい円が描けました。 f:id:pco2699:20161103161922p:plain

実際にうごくやつ

実際に動くと悪夢感がさらにすごい。

Processing Demo

書いたコード

// setupでアニメーションを動かす前のセットアップを行う
void setup(){
  // キャンバスサイズの設定を横:500 縦:300に設定
  size(500,300);

  // 背景を白に設定
  background(255);

  // らせんの線の太さを細めに設定
  strokeWeight(0.5);

  // 形をなめらかに
  smooth();
}

// drawで実際にアニメーションの内容を設定
// このdrawで書いた内容が無限ループされる感じ
void draw(){
  // ループ毎に背景をリセット
  background(255);

  // らせんの中心を設定
  int centx = 250;
  int centy = 150;

  float x, y;

  // らせんを100個描くfor ループ
  for (int i = 0; i < 100; i++){
    float lastx = -999;
    float lasty = -999;
    float radius = 10;

    // 直径を乱数化するシードをランダムに設定
    float radiusNoise = random(10);
  
    // 線の色の濃さもランダムに
    stroke(random(20), random(50), random(70), 80);

    // らせんを描きはじめる角度をランダムに
    int startangle = int(random(360));

    // らせんを描きはじめる角度もランダムに
    int endangle = 1440 + int(random(1440));

    // 角度のステップもランダムに
    int anglestep = 5 + int(random(3));

    // らせんを描くforループ
    for (float ang = startangle; ang <= endangle; ang += anglestep){
      radiusNoise += 0.05;
      radius += 0.5;

      // 今回の直径を ランダムに0~100の間でランダムに加算
      float thisRadius = radius + (noise(radiusNoise) * 200) - 100;
      float rad = radians(ang);

      // らせんの中心から三角関数でx軸、y軸を設定
      x = centx + (thisRadius * cos(rad));
      y = centy + (thisRadius * sin(rad));

    // 前の座標から今回計算した座標へ線を引く
      if(lastx > -999) {
        line(x, y, lastx, lasty);
      }

      // 次のforループで利用するため今回のx,y座標を保存
      lastx = x;
      lasty = y;
    }
  }
}

感想

  • Javaベースだから、馴染みやすい文法で線とか絵がかけるProcessingすごい
  • こんなわかりやすいコードでこんなカオスな絵をかけるマットピアソンさん(↑の本の著者ね)すごい

しかも、この「間違った円を描く」章以降、かなりカオスな絵ばっかり出てくるので わくわくが止まらない。。。
また読み進んだら、ここにも載っけようかと思います。