本記事は、株式会社 函館ラボラトリが運営する「Bラボ」における、大人向け「看板アプリ(デジタルサイネージ)を作るコース」用テキストです。
一からコードを書くわけではなく、あらかじめ用意したコードの一部を改変しながら、デジタルサイネージを作っていきましょう。
テンプレートプログラムは、下記GitHubリポジトリのLongTerm/Part2_Start
ディレクトリに入っています。
(12/16時点、本テキストは執筆中です)
前回のおさらい
RModuleのスクリーンショットを表示できる状態にしました。
ここからは「時刻」などを表示するモジュールを追加し、RModuleは実際のデータに連動するようにします。
背景画像の表示
まずは背景画像を読み込みます。
関数setup
内で読み込みます。
void setup() {
frameRate(1);
noCursor();
colorMode(HSB, 360, 100, 100, 100);
// 色の初期設定。
WHITE_COLOR = color(0, 0, 100);
NEARLY_WHITE_COLOR = color(100, 2, 98);
NEARLY_GREEN_COLOR = color(100, 5, 98);
BLACK_COLOR = color(0, 0, 0);
LIGHT_COLOR = color(0, 0, 80);
GRAY_COLOR = color(0, 0, 50);
GREEN_COLOR = color(150, 100, 60);
// デジタルサイネージの背景画像を読み込む。
background = pImageCut(loadImage("background.jpg"), CENTER, CENTER, width, height); // 追加
// 初期化用関数initialize()を、draw()で画面が描画されているときに並行し実行(非同期処理)。
thread("initialize");
}
関数drawModules
内で、背景画像を表示できるようにします。
void drawModules() {
image(background, 0, 0); // 追加
if (nowPageID == 0) {
drawWeatherRModule(Area.area1);
drawBusRModule(Area.area3);
drawGomiRModule(Area.area5);
} else if (nowPageID == 1) {
// ModuleやRModuleの描画用関数を呼び出す
drawTemperatureRModule(Area.area1);
drawBrightnessRModule(Area.area2);
drawTwitterRModule(Area.area3);
drawOpenCloseRModule(Area.area5);
} else if (nowPageID == 2) {
// ModuleやRModuleの描画用関数を呼び出す
}
}
実行してみると、背景画像が表示されるようになっています。
テキスト描画用関数の準備
このあとの実装で、文字を表示する関数text
が使われます。
文字を表示するには、「サイズ」「色」「左揃え/中央揃え/右揃え」などの設定が必要です。
これを毎回数行にわたって書かなくてもいいように、1つの関数を呼ぶだけで良くします。
// 表示するテキストのスタイルを指定して描画。
void drawText(int alignX, int alignY, color c, int size, String text, int x, int y) {
pushStyle();
textAlign(alignX, alignY);
textSize(size);
fill(c);
if (alignY == BASELINE) {
text(text, x, y+size);
} else {
text(text, x, y);
}
popStyle();
}
// 表示するテキストのスタイルを指定して描画。テキストの自動改行に対応したバージョン。
void drawText(int alignX, int alignY, color c, int size, String text, int x, int y, int w, int h) {
pushStyle();
textAlign(alignX, alignY);
textSize(size);
fill(c);
if (alignY == BASELINE) {
text(text, x, y+size, w, h);
} else {
text(text, x, y, w, h);
}
popStyle();
}
デジタルサイネージが設置されている場所を表示する
設置場所を画面の右上に表示してみましょう。
下記記事の「LocationModule」を実装します。
void drawLocationModule() {
// 文字が画像と同化するのを避けるため、背景画像の色に応じて文字色反転。
blendMode(EXCLUSION);
drawText(RIGHT, BASELINE, WHITE_COLOR, 36, LOCATION, width-100, 30);
// 他モジュールの描画時にも色が反転してしまうため、もとに戻す。
blendMode(BLEND);
}
関数drawModules
の中で呼び出します。
void drawModules() {
image(background, 0, 0);
if (nowPageID == 0) {
drawWeatherRModule(Area.area1);
drawBusRModule(Area.area3);
drawGomiRModule(Area.area5);
} else if (nowPageID == 1) {
// ModuleやRModuleの描画用関数を呼び出す
drawTemperatureRModule(Area.area1);
drawBrightnessRModule(Area.area2);
drawTwitterRModule(Area.area3);
drawOpenCloseRModule(Area.area5);
} else if (nowPageID == 2) {
// ModuleやRModuleの描画用関数を呼び出す
}
drawLocationModule(); // 追加
}
時刻を表示する
時刻を画面の左上に表示してみましょう。
下記記事にある内容を進めていきます。
曜日を算出する関数をつくります。
// Zellerの公式を使った曜日計算
Youbi calcYoubi(int year, int month, int day) {
final Youbi[] youbi = Youbi.values();
if (month < 3) {
year--;
month += 12;
}
return youbi[(year+year/4-year/100+year/400+(13*month+8)/5+day)%7];
}
曜日を文字列として出すための関数をつくります。
// 曜日を日本語表記にする。月〜金でも祝日の場合は「月・祝」のように表示。
String youbiToString(Youbi youbi) {
String str = "";
switch (youbi) {
case Sun:
str = "日";
break;
case Mon:
str = "月";
if (isHoliday) str += "・祝";
break;
case Tue:
str = "火";
if (isHoliday) str += "・祝";
break;
case Wed:
str = "水";
if (isHoliday) str += "・祝";
break;
case Thu:
str = "木";
if (isHoliday) str += "・祝";
break;
case Fri:
str = "金";
if (isHoliday) str += "・祝";
break;
case Sat:
str = "土";
break;
}
return str;
}
日付と時刻を表示します。
void drawDateModule() {
// 文字が画像と同化するのを避けるため、背景画像の色に応じて文字色反転。
blendMode(EXCLUSION);
String timeText = month + "月" + day + "日" + "(" + youbiString + ")" + nf(hour, 2) + ":" + nf(minute, 2) + ":" + nf(second, 2);
drawText(LEFT, BASELINE, WHITE_COLOR, 36, timeText, 100, 30);
// 他モジュールの描画時にも色が反転してしまうため、もとに戻す。
blendMode(BLEND);
}
関数setup()
内で、フォントを使用できるように設定します。
void setup() {
frameRate(1);
noCursor();
colorMode(HSB, 360, 100, 100, 100);
// 色の初期設定。
WHITE_COLOR = color(0, 0, 100);
NEARLY_WHITE_COLOR = color(100, 2, 98);
NEARLY_GREEN_COLOR = color(100, 5, 98);
BLACK_COLOR = color(0, 0, 0);
LIGHT_COLOR = color(0, 0, 80);
GRAY_COLOR = color(0, 0, 50);
GREEN_COLOR = color(150, 100, 60);
// フォントを読み込み、デジタルサイネージで使うフォントとして設定。
textFont(createFont("Noto Sans CJK jp Bold", 32)); // 追加
// デジタルサイネージの背景画像を読み込む。
background = pImageCut(loadImage("background.jpg"), CENTER, CENTER, width, height);
// 初期化用関数initialize()を、draw()で画面が描画されているときに並行し実行(非同期処理)。
thread("initialize");
}
関数drawModules
の中で呼び出します。
void drawModules() {
image(background, 0, 0);
if (nowPageID == 0) {
drawWeatherRModule(Area.area1);
drawBusRModule(Area.area3);
drawGomiRModule(Area.area5);
} else if (nowPageID == 1) {
// ModuleやRModuleの描画用関数を呼び出す
drawTemperatureRModule(Area.area1);
drawBrightnessRModule(Area.area2);
drawTwitterRModule(Area.area3);
drawOpenCloseRModule(Area.area5);
} else if (nowPageID == 2) {
// ModuleやRModuleの描画用関数を呼び出す
}
drawDateModule(); // 追加
drawLocationModule();
}
実行すると、左上に時刻が表示されます。
(ただし、現時点では曜日は「null」になります)
ページ切り替えまでの時間がわかるようにする
ページが切り替わってから、1秒経つごとに伸びていくバーを作ります。
下記記事で解説されている「ProgressBarModule」です。
ProgressBarModuleを描画する関数を作ります。
void drawProgressBarModule() {
// 残り秒数を割合として算出(%)
float progressRate = (second % STAY_SECOND) / float(STAY_SECOND-1);
// 時間が経過したぶんだけ、白いバーが緑で塗りつぶされていく
noStroke();
fill(WHITE_COLOR);
rect(0, height-PROGRESSBAR_HEIGHT, width, PROGRESSBAR_HEIGHT);
fill(GREEN_COLOR);
rect(0, height-PROGRESSBAR_HEIGHT, width * progressRate, PROGRESSBAR_HEIGHT);
}
関数drawModules
内で呼び出します。
void drawModules() {
image(background, 0, 0);
if (nowPageID == 0) {
drawWeatherRModule(Area.area1);
drawBusRModule(Area.area3);
drawGomiRModule(Area.area5);
} else if (nowPageID == 1) {
// ModuleやRModuleの描画用関数を呼び出す
drawTemperatureRModule(Area.area1);
drawBrightnessRModule(Area.area2);
drawTwitterRModule(Area.area3);
drawOpenCloseRModule(Area.area5);
} else if (nowPageID == 2) {
// ModuleやRModuleの描画用関数を呼び出す
}
drawDateModule();
drawLocationModule();
drawProgressBarModule(); // 追加
}
実行すると、画面下にバーが表示されます。
現在表示中のページが何番目かを可視化する
複数のページがあるうちで、現在何ページ目が表示されているかを可視化します。
下記記事で解説されている「PageControlModule」です。
PageControlModuleを描画する関数を作ります。
void drawPageControlModule() {
for (int page = 0; page < PAGE_ALL_COUNT; page++) {
// ページ番号をもとに点を横に並べる
float x = width/2 + 30 * (page-(PAGE_ALL_COUNT-1)/2.0);
float y = 1020;
// 現在のページだけは白の点(緑の枠線付き)、それ以外は緑の点を打つ
if (page == nowPageID) {
fill(WHITE_COLOR);
stroke(GREEN_COLOR);
strokeWeight(5);
circle(x, y, 20);
} else {
fill(GREEN_COLOR);
noStroke();
circle(x, y, 15);
}
}
}
関数drawModules
内で呼び出します。
void drawModules() {
image(background, 0, 0);
if (nowPageID == 0) {
drawWeatherRModule(Area.area1);
drawBusRModule(Area.area3);
drawGomiRModule(Area.area5);
} else if (nowPageID == 1) {
// ModuleやRModuleの描画用関数を呼び出す
drawTemperatureRModule(Area.area1);
drawBrightnessRModule(Area.area2);
drawTwitterRModule(Area.area3);
drawOpenCloseRModule(Area.area5);
} else if (nowPageID == 2) {
// ModuleやRModuleの描画用関数を呼び出す
}
drawDateModule();
drawLocationModule();
drawProgressBarModule();
drawPageControlModule(); // 追加
}
実行すると、画面下に点がいくつか表示されます。
画像を全画面表示する
広告画像を全画面表示するために、「FullImageModule」を実装します。
下記記事で解説しているものです。
描画用関数を実装します。
void drawFullImageModule(PImage pImage) {
image(pImage, 0, 0, width, height);
}
関数drawModules
内で呼び出します。
void drawModules() {
image(background, 0, 0);
if (nowPageID == 0) {
drawWeatherRModule(Area.area1);
drawBusRModule(Area.area3);
drawGomiRModule(Area.area5);
} else if (nowPageID == 1) {
// ModuleやRModuleの描画用関数を呼び出す
drawTemperatureRModule(Area.area1);
drawBrightnessRModule(Area.area2);
drawTwitterRModule(Area.area3);
drawOpenCloseRModule(Area.area5);
} else if (nowPageID == 2) {
// ModuleやRModuleの描画用関数を呼び出す
drawFullImageModule(adImage[0]); // 追加
}
drawDateModule();
drawLocationModule();
drawProgressBarModule();
drawPageControlModule();
}
実行すると、3ページ目に全画面表示の画像が表示されるようになっています。
次回
次はPart3です。
Part3では、Part2時点でスクリーンショットになっている部分を、Web APIやセンサなどに連動させていきます。