- 投稿日:2020-03-22T22:04:46+09:00
Electronでカレンダーを作る⑤
前回まで
前回はカレンダーの表示月を切り替えたら画面も切り替わるようにした。
ただ、切り替える度に画面更新で数秒真っ白になるのでダサかった。レスポンシブルな感じのUIにしたい。
HTMLを最小限にする
HTML内にカレンダーの構造をそのまま書いているのでこれをごっそり削って最小限の記述にする。
カレンダーの構造自体はJavaScriptで作っていく。before
index.html<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>ElectronCalendar</title> <script text="text/javascript" src="./js/index.js"></script> <link rel="stylesheet" href="./css/index.css"> </head> <body> <div class="calendar-wrapper"> <div class="preMonthButton"> <button type="button" id="preMonth"><先月</button> </div> <div class="nextMonthButton"> <button type="button" id="nextMonth">来月></button> </div> <table id="table" class="calendar"> <caption id="caption"></caption> <thead> <tr> <th>日</th> <th>月</th> <th>火</th> <th>水</th> <th>木</th> <th>金</th> <th>土</th> </tr> </thead> <tbody> <tr id="row1"> <td id="cell1"></td> <td id="cell2"></td> <td id="cell3"></td> <td id="cell4"></td> <td id="cell5"></td> <td id="cell6"></td> <td id="cell7"></td> </tr> <tr id="row2"> <td id="cell8"></td> <td id="cell9"></td> ...略 <td id="cell34"></td> <td id="cell35"></td> </tr> <tr id="row6"> <td id="cell36"></td> <td id="cell37"></td> <td id="cell38"></td> <td id="cell39"></td> <td id="cell40"></td> <td id="cell41"></td> <td id="cell42"></td> </tr> </tbody> </table> </div> </body> </html>after
index.html<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>ElectronCalendar</title> <script text="text/javascript" src="./js/index.js"></script> <link rel="stylesheet" href="./css/index.css"> </head> <body> <div class="calendar-wrapper"> <div class="preMonthButton"> <button type="button" id="preMonth"><先月</button> </div> <div class="nextMonthButton"> <button type="button" id="nextMonth">来月></button> </div> <div id="calendars"> </div> </div> </body> </html><div id="calendars">ってなんでこのIDにしたか謎。
index.jsを改修する
index.js'use strict'; //momentモジュール const moment = require("moment"); // カレンダーをキャッシュしておくMap let calendarMap = new Map(); // 画面に表示されている月 let currentDispMonth; window.onload = function() { //URL文字列から初期表示の月を取得 const month = parseURLParam(location.search).month; //直近3か月のカレンダー作成 createLatestCalendar(month); //カレンダーの親要素取得 const root = document.getElementById('calendars'); //子要素としてパネルを追加 const callendar = calendarMap.get(month); root.appendChild(callendar.getPanel()); //カレンダー表示 display(callendar.createContents); //先月ボタン押下時 document.getElementById('preMonth').onclick = function() { const localMoment = moment(currentDispMonth); const preMonth = localMoment.add(-1,'month').format("YYYY-MM"); const beforPanel = calendarMap.get(currentDispMonth).getPanel(); const afterCallendar = calendarMap.get(preMonth); const afterPanel = afterCallendar.getPanel(); changePanel(beforPanel, afterPanel, afterCallendar.createContents); createLatestCalendar(preMonth); }; //来月ボタン押下時 document.getElementById('nextMonth').onclick = function() { const localMoment = moment(currentDispMonth); const nextMonth = localMoment.add(1,'month').format("YYYY-MM"); const beforPanel = calendarMap.get(currentDispMonth).getPanel(); const afterCallendar = calendarMap.get(nextMonth); const afterPanel = afterCallendar.getPanel(); changePanel(beforPanel, afterPanel, afterCallendar.createContents); createLatestCalendar(nextMonth); }; }; /** * URLパラメータを分解してkey:valueの形式で返す。 * @param URL */ function parseURLParam(URL) { // URLパラメータを"&"で分離する const params = URL.substr(1).split('&'); var paramsArray = []; var keyAndValue = null; for(var i = 0 ; i < params.length ; i++) { // "&"で分離したパラメータを"="で再分離 keyAndValue = params[i].split("="); // パラメータを連想配列でセット paramsArray[keyAndValue[0]] = keyAndValue[1]; } // 連想配列パラメータを返す return paramsArray; } /** * パネルを切り替える * @param beforPanel * @param afterPanel * @param callback パネル切り替え後に実行される関数 */ function changePanel(beforPanel, afterPanel, callback) { //カレンダーの親要素取得 const root = document.getElementById('calendars'); //afterPanelでbeforPanelを置き換え root.replaceChild(afterPanel, beforPanel); display(callback); } /** * カレンダーを表示する。 * @param callback 実行される関数 */ function display(callback) { callback(); } /** * 指定した月の直近(当月、先月、来月)のCallendarオブジェクトを作成する。 */ function createLatestCalendar(month) { //当月分 if(!calendarMap.get(month)) { const callendar = new Callendar(month); callendar.createPanel(); calendarMap.set(month, callendar); } const localMoment = moment(month); //先月分 const preMonth = localMoment.add(-1,'month').format("YYYY-MM"); if(!calendarMap.get(preMonth)) { const preCallendar = new Callendar(preMonth); preCallendar.createPanel(); calendarMap.set(preMonth, preCallendar); } //今月分 const nextMonth = localMoment.add(2,'month').format("YYYY-MM"); if(!calendarMap.get(nextMonth)) { const nextCallendar = new Callendar(nextMonth); nextCallendar.createPanel(); calendarMap.set(nextMonth, nextCallendar); } } /** * カレンダークラス * @param month(YYYY-MM) */ const Callendar = function(month) { //コンストラクタ this._month = month; this._moment = moment(this._month); this._panel = {}; //コールバック関数で利用するのでthisを固定しておく const _this = this; /** * カレンダーのパネルを作成する。 */ this.createPanel = function() { // カレンダーのパネルを作成 const panel = document.createElement('div'); panel.id = 'panel'; // 子要素にテーブルを追加 const table = panel.appendChild(document.createElement('table')); table.id = 'table'; table.classList.add('calendar'); // テーブルにキャプション追加 const caption = table.appendChild(document.createElement('caption')); caption.id = 'caption'; // ヘッダー追加 const header = table.appendChild(document.createElement('thead')); // ヘッダーのカラムを作成する。 const headerRow = header.appendChild(document.createElement('tr')); headerRow.appendChild(document.createElement('th')).innerText = '日'; headerRow.appendChild(document.createElement('th')).innerText = '月'; headerRow.appendChild(document.createElement('th')).innerText = '火'; headerRow.appendChild(document.createElement('th')).innerText = '水'; headerRow.appendChild(document.createElement('th')).innerText = '木'; headerRow.appendChild(document.createElement('th')).innerText = '金'; headerRow.appendChild(document.createElement('th')).innerText = '土'; // body作成 let cellNum = 1; for (let i = 1; i < 7; i++) { const row = table.appendChild(document.createElement('tr')); row.id = 'row' + i; for(let j = 1; j < 8; j++) { const cell = row.appendChild(document.createElement('td')); cell.id = 'cell' + cellNum; cellNum++; } } this._panel = panel; }; /** * カレンダーの内容を作成する。 */ this.createContents = function() { const __moment = _this._moment; //captionを表示 document.getElementById('caption').innerText = __moment.format("YYYY年MM月"); //当月の日数を取得 const daysOfMonth = __moment.daysInMonth(); //月初の曜日を取得(index.htmlと合わせるために+1する) const firstDayOfManth = __moment.startOf('month').day() + 1; //カレンダーの各セルに日付を表示させる let cellIndex = 0; for(let i = 1; i < daysOfMonth + 1; i++) { if(i === 1) { cellIndex += firstDayOfManth; } else { cellIndex++; } document.getElementById("cell" + cellIndex).innerText = i; } //6行目の第1セルが空白なら6行目自体を非表示にする。 if(document.getElementById("cell36").innerText === "") { document.getElementById('row6').style.display = "none"; } currentDispMonth = _this._month; }; /** * パネルを取得する。 */ this.getPanel = function() { return this._panel; }; /** * 月を取得する。 */ this.getMonth = function() { return this._month; }; };修正・追加点
①カレンダーの構造を動的に作るようにする。
Calendarオブジェクトでカレンダーの構造(HTML要素)を作成して持っておくようにする。
Calendarオブジェクトは月ごとに一つ作られる。display関数にCalendarクラスのcreateContentsメソッドをコールバック関数として渡すことで画面にカレンダーの内容が表示される。
index.js/** * カレンダーを表示する。 * @param callback 実行される関数 */ function display(callback) { callback(); }※コールバック関数をそのまま実行しているだけなのでコールバックという名前は不適なので修正したい。
②ボタンを押したら画面の更新無しでカレンダーを切り替えるようにする。
カレンダーの表示の切り替えは、changePanel関数でHTML要素を置き換える。
index.js/** * パネルを切り替える * @param beforPanel * @param afterPanel * @param callback パネル切り替え後に実行される関数 */ function changePanel(beforPanel, afterPanel, callback) { //カレンダーの親要素取得 const root = document.getElementById('calendars'); //afterPanelでbeforPanelを置き換え root.replaceChild(afterPanel, beforPanel); ※ display(callback); }※replaceChildメソッドの引数はreplaceChild(置き換えたいHTML要素(Node), 置き換え対象のHTML要素)となるので注意。
③カレンダーの切り替え毎に前後一ヶ月のCalendarオブジェクトを作っておくようにする。
初期表示では今月・先月・来月分のCalendarオブジェクトを作成しておき、今月分のカレンダーの表示させる。
以後、ボタン押下毎にCalendarオブジェクトが作られていく。index.js/** * 指定した月の直近(当月、先月、来月)のCallendarオブジェクトを作成する。 * 対象月のCalendarオブジェクトがキャッシュされているならそれを使い回す。 */ function createLatestCalendar(month) { //当月分 if(!calendarMap.get(month)) { const callendar = new Callendar(month); callendar.createPanel(); calendarMap.set(month, callendar); } const localMoment = moment(month); //先月分 const preMonth = localMoment.add(-1,'month').format("YYYY-MM"); if(!calendarMap.get(preMonth)) { const preCallendar = new Callendar(preMonth); preCallendar.createPanel(); calendarMap.set(preMonth, preCallendar); } //今月分 const nextMonth = localMoment.add(2,'month').format("YYYY-MM"); if(!calendarMap.get(nextMonth)) { const nextCallendar = new Callendar(nextMonth); nextCallendar.createPanel(); calendarMap.set(nextMonth, nextCallendar); } }なんかごちゃっとしてる。
index.js//先月ボタン押下時 document.getElementById('preMonth').onclick = function() { const localMoment = moment(currentDispMonth); const preMonth = localMoment.add(-1,'month').format("YYYY-MM"); const beforPanel = calendarMap.get(currentDispMonth).getPanel(); const afterCallendar = calendarMap.get(preMonth); const afterPanel = afterCallendar.getPanel(); changePanel(beforPanel, afterPanel, afterCallendar.createContents); createLatestCalendar(preMonth); }; //来月ボタン押下時 document.getElementById('nextMonth').onclick = function() { const localMoment = moment(currentDispMonth); const nextMonth = localMoment.add(1,'month').format("YYYY-MM"); const beforPanel = calendarMap.get(currentDispMonth).getPanel(); const afterCallendar = calendarMap.get(nextMonth); const afterPanel = afterCallendar.getPanel(); changePanel(beforPanel, afterPanel, afterCallendar.createContents); createLatestCalendar(nextMonth); };こっちもごちゃっとしてる。
・キャッシュしたCalendarオブジェクトの取得方法
Calendarオブジェクトはグローバル変数のMapに保存されているので月をキーにして取り出せる。
index.js// カレンダーをキャッシュしておくMap let calendarMap = new Map();動かす
$ electron .初期表示
来月ボタン押下時
画面更新で真っ白になることが無くなった!!!(画像じゃ分からない)
TODO
・コードをもっとスッキリさせたい。
・Electronの機能をもっと使いたい。あとがき
・Javaの型で縛るプログラミングに慣れているので動的型付け言語は自由だけど不自由。
・ロジックを書くのはやっぱり楽しい。プログラミングの醍醐味だと思う。
・Electronの記事なのにほぼHTML・JSの記事になってる・・・。今回に関してはipc通信の箇所すら削っちゃってる!!!
- 投稿日:2020-03-22T19:18:14+09:00
scratchblocksを使ってScratchのブロックをサイトに埋め込む
読む前に
この記事ではHTML5を使ったサイトでの作成を想定しています。
WordPressを使用する場合は、プラグインがあるのでそちらをご覧下さい。そもそもscratchblocksとは
blob8108氏が開発している、scratchのブロックをサイト上に埋め込むことの出来る、javascriptのプログラムです。
ソースコードはGithubで公開されています。下準備
head
タグ内に以下の二行を入れます。html<script src="https://scratchblocks.github.io/js/scratchblocks-v3.4-min.js"></script> <script src="https://scratchblocks.github.io/js/translations-all-v3.4.js"></script>一行目ではscratchblocksのプログラムを、二行目ではブロックの翻訳ファイルを読み込んでいます。
英語でのみ使う方は、二行目はなくても大丈夫です。ブロックを描写してみる
body
タグ内にブロック名を入力し、それを任意のタグで囲みます。(今回はclassにscratchblocks
を指定したdiv)html<body> <div class="scratchblocks"> hide </div> </body>そして、
</body>
の直前に、以下の一行を追記します。<script>scratchblocks.renderMatching('.scratchblocks');</script>引数には、CSSセレクタと同じ要領で、タグやclass、idを指定します。
この状態でファイルを開くと、以下の様に表示されます。See the Pen scratchblocks sample1 by Poteto143(活動少なめScratcher) (@poteto143) on CodePen.
hide
と入力した部分がScratchのブロックに置き換わりました。言語を指定する
このままの状態だと英語のブロック名しか使えません。
日本語でもブロックを正しく変換できるようするためには、scratchblocks.renderMatching()
の第二引数に、オブジェクトでlanguages
というオプションを指定します。html<script>scratchblocks.renderMatching('.scratchblock', {languages: ["en", "ja"], style: "scratch3" });</script>言語の指定はリストを渡します。
また、複数の言語を同時に指定することも可能です。
en
(英語)とja
(日本語)を指定して、「hide」と「隠す」をそれぞれブロックに変換すると以下の様になります。See the Pen scratchblocks sample2 by Poteto143(活動少なめScratcher) (@poteto143) on CodePen.
ブロックの見た目を最新の物にする
ここまでで描写されたブロックは全てバージョン2.0のScratchの物です。
先ほどのオブジェクトにstyle
というオプションを追加することで、バージョン3.0仕様のブロックの描写にも対応できます。See the Pen scratchblocks sample3 by Poteto143(活動少なめScratcher) (@poteto143) on CodePen.
3.0仕様のブロックを使う場合は
scratch3
と入力します。
2.0仕様のブロックを使う場合は省略するか、scratch2
と入力します。ブロックをインライン表示する
文と文の間にブロックを描写したい場合は、まず変換する部分を
span
タグで囲みます。
次に、scratchblocks.renderMatching()
の第一引数でspanタグを選択します。
最後に、第二引数のオブジェクトにinline
というオプションを追加します。See the Pen scratchblocks sample4 by Poteto143(活動少なめScratcher) (@poteto143) on CodePen.
インライン表示にする場合は
true
を、しない場合は省略するかfalse
を入力します。ブロックの記述方法
ブロックの記述方法については、Japanese Scratch-Wikiに記事がありますので、そちらをご覧下さい。
ブロックプラグイン (3.0)
- 投稿日:2020-03-22T16:31:13+09:00
謎の余白の正体 CSS編
- 投稿日:2020-03-22T14:55:29+09:00
HTMLページをHerokuにデプロイ
この記事について
(お金をかけずに)SPAやアプリをインターネットに公開したいのにgithub pagesはもう使用済みでどうしよう、と思っていたところ、Herokuをおすすめしてもらい、実際に無料で公開できたので、手順を記録しておきたく記事にしました。
今回はHTML、CSS、JSファイルで作ったSPA(Single Page Application)をHerokuにデプロイしました。とりあえずこの記事ではデプロイするところまでをまとめています。
デプロイ後のログの確認や、コードの追加修正を反映させる操作などについては、別途まとめたいと思っています。
1. まず、HTMLで作ったSPAをアプリにする
HTMLやCSS、JSファイルだけで構成されたディレクトリはherokuではアプリとして認識されないため、HTMLファイルがあるディレクトリと同じディレクトリに
index.php
とpackage.json
を追加して、phpアプリに変身させます。index.php<?php include_once("index.html"); ?>package.json{}HTMLとJavaScriptで作ったサイトがHerokuにデプロイできねええって時の対処法
↑の記事を参考にさせていただきました。2. Herokuアカウントを作る
Herokuでアカウントを作成します。
3. デプロイしていく
Getting Started on Heroku with PHPに沿ってデプロイをしていきます。
3-1. まず必要な準備
上記リンクに飛び、「Get started with php」をクリックすると、↓の画面に遷移します。
始める前に、必要なもの準備できてますか?!という確認です。
下記の3つの準備が整っていることを求められています。
- Herokuアカウントがあること
- PHPがローカルにインストールされていること
- Composerがローカルにインストールされていること
phpはMacにはデフォルトで入っているのでインストール不要でした。
ComposerはHomebrewからインストールします。
$ brew install composer
3-2. herokuをインストール
必要な準備が終わったら「I'm ready to start」をクリックして次に進みます。
次はherokuをインストールします。
インストールコマンドが載っているのでターミナルで実行。
$ brew install heroku/brew/heroku
3-3. herokuにログイン
herokuのインストールが完了したらログインしてみます。
$ heroku login
と打つと、
heroku: Press any key to open up the browser to login or q to exit:
と返されるので、Enterします。ログインした後に遷移するページは、そのページにも書いてありますが閉じてしまっても大丈夫なようです。
3-4. ツールのバージョン確認
php、composer、gitのバージョンを確認します。
バージョンの確認というか、インストールできてるかの確認です。下記それぞれのコマンドを実行してバージョンが表示されればインストールできているとわかります。
$ php -v
$ composer -v
$ git --version
3-5. herokuにデプロイするリポジトリをcloneする
githubからherokuにデプロイしたいリポジトリをローカルにcloneします。
$ git clone <url>
このリポジトリにはHTMLとCSS,JSで作られたSPAに、「1. まず、HTMLで作ったSPAをアプリにする」の手順で追加したphpファイルとjsonファイルが含まれています。
3-6. アプリをherokuにデプロイ
ローカルにクローンしたリポジトリに移動し、下記のコマンドを順番に実行していきます。
(1)
$ heroku create
Creating app... done,の後に続くワードが今回作成されたアプリ名になります。
(2)
$ git push heroku master
(3)$ heroku ps:scale web=1
(4)$ heroku open
これでデプロイ完了です! HTMLで作ったSPAが新しいタブに表示されるかと思います。
もし表示されなくても、Herokuのダッシュボードを見るとアプリ名が表示されているので、そこへ飛び、右上の「Open」をクリックするとSPAに遷移できます。終わりに
作ったものをデプロイしてURLを渡すだけで色々な人に見てもらえるようになるのは嬉しいですね。
プログラミングの勉強をし始めた時にも感じましたが、努力が何かしら形になるとモチベーション上がります!!SPA作ったとか、フレームワークのインストールができたとか、そういうことでも嬉しかったです。
デプロイ作業は今回初めてで、まだまだわからない事ばかりで手探り状態ですが、とりあえずできたので、しっかり運用できるようにしていきたいと思います。
- 投稿日:2020-03-22T13:13:05+09:00
初めてのレスポンシブ
初めまして
初めての投稿でして、先輩方よろしゅーおねがいします。
昨今の様々なニュースと機械学習組み合わせるときっと楽しんだろうって思ってsakura vpsでサイト立ち上げて 勉強開始してます。サイト立ち上げの苦労はまた今度。
今回はhtmlにつきものなレスポンシブってやつを勉強しました。
いろんなサイトをみてパクってきて再利用しようと思ったんですが、どうも複雑で。一部削除してもなぜか動いたり、期待した動きしなかったり。やっぱり基礎理解しないとダメだなって思って書きました。
実行例
下記にあります。
色々と色付けてわかりやすくしてみました。PCブラウザで枠幅を600以下にすると変わります。
https://dirtycode7.com/sample_css_responseive.html悩んでるところ
なぜかすべてを半角文字にするとダメになる。
別に支障ないんだけど、とっても気になる。今後
PCとスマホ、どうやって切り替えるか。先人の情報を見て考えます。
html部分
sample_css_responseive.html<!DOCTYPE html> <html> <head> <link rel="stylesheet" type="text/css" href="responseive.css" > <meta charset="utf-8"> <title>かなりシンプルなレスポンシブのサンプル</title> </head> <body> <div class="header"> かなーりシンプルなレスポンシブのサンプル (テーブルと枠の組み合わせ) </div> <div class="main"> <table class="main_table"> <tr> <th>1234567890123 </th> <td>ああああああああああああああああああああああああああああああああああああああ</td> </tr> <tr> <th>1234567890123 </th> <td>ああああああああああああ</td> </tr> <tr> <th>いいいいいいいいいいいいいいいいいいい </th> <td>うううううううううううううううううううううううううううううう</td> </tr> </table> </div> </body> </html>css部分
responseive.css/*********************************************/ /* フォント */ @import url('https://fonts.googleapis.com/css?family=Sawarabi+Gothic&display=swap'); /*********************************************/ /* 基本 */ html { position: relative; font-size: 1em; font-family: 'Sawarabi Gothic', sans-serif; color: #aaa; background-color: #000; } /*********************************************/ /* ヘッダー */ .header { font-size: 2em; font-weight: bolder; text-align: center; padding: 1em; margin: 1em 1em 1em 1em; background-color: #222; } /*********************************************/ /* メイン */ .main { padding: 1em; margin: 1em 1em 1em 1em; background-color: #222; } /*********************************************/ /* テーブル */ .main_table { padding: 1em; background-color: #444; } /* 左 */ .main_table th { width: 10em; text-align: left; background-color: #666; } /* 右 */ .main_table td { position: relative; padding: 0.5em; margin-bottom: 1em; border-radius: 16px; display: inline-block; font-size: 2em; color: #eee; background: #555; } /* 狭いとき */ @media only screen and (max-width:600px){ .header { color: #e00; } .main_table { } .main_table th { display: block; color: #0e0; } .main_table td { display: block; color: #00e; } .main_table tr:first-child th { } } /* EOF */github
下記にあります。
https://github.com/dirtycode7/sample_css_Responsive
- 投稿日:2020-03-22T11:16:55+09:00
ライブラリなしでTreeTableを実装する
始めに
開発現場によってはjQueryやAngular等のフレームワーク、ライブラリの使用が禁止されているところがあると聞いたことがあります。また、使用するフレームワークによって実装方法がバラついてしまうことがよくあると思います。
そういった状況下でも、問題なく開発が進められるように、フレームワーク、ライブラリを一切使用せずTreeTableを自作してみました。
作成したTreeTableはgitHubに公開しております。動作ブラウザ
・Google Chrome
・Microsoft Edge
・IE11この3つ以外のブラウザでは未検証です。注意ください。
ソースの準備
ソースはgitHubに公開しております。
構成としては至ってシンプルで下記の3つのみです。
動作確認は上記で記載したブラウザがあれば確認することができます。・サンプル用のhtml
・jsファイル
・cssファイルTreeTable使用方法
サンプルで確認
サンプルは2つTreeTableを用意しました。
1つは一番シンプルな作成方法、もう1つはカスタマイズした作成方法になります。
ここではシンプルに作成した場合のサンプルについて確認します。<script type="text/Javascript"> // test data1 const sampleDatas1 = [ { Prefectures: 'tokyo', Municipality: null, town: null, name: '東京都', value: 100 }, { Prefectures: 'tokyo', Municipality: 'chiyoda', town: null, name: '千代田区', value: 200 }, { Prefectures: 'tokyo', Municipality: 'chiyoda', town: 1, name: 'A町', value: 300 }, { Prefectures: 'tokyo', Municipality: 'chiyoda', town: 2, name: 'B町', value: 400 }, { Prefectures: 'tokyo', Municipality: 'chiyoda', town: 3, name: 'C町', value: 500 }, { Prefectures: 'tokyo', Municipality: 'chiyoda', town: 4, name: 'D町', value: 600 }, { Prefectures: 'tokyo', Municipality: 'chiyoda', town: 5, name: 'E町', value: 700 }, { Prefectures: 'tokyo', Municipality: 'chuou', town: null, name: '中央区', value: 800 }, { Prefectures: 'tokyo', Municipality: 'chuou', town: 1, name: 'F町', value: 1000 }, { Prefectures: 'tokyo', Municipality: 'chuou', town: 2, name: 'G町', value: 1100 }, { Prefectures: 'tokyo', Municipality: 'minato', town: null, name: '港区', value: 1200 }, { Prefectures: 'tokyo', Municipality: 'minato', town: 1, name: 'H町', value: 1300 }, { Prefectures: 'tokyo', Municipality: 'minato', town: 2, name: 'I町', value: 1400 }, ]; window.onload = function () { // 設定1 var settingJson1 = { // 作成する列(左から順に作成) columns: ['name', 'value'], // 階層識別列(親要素 - 子要素 - 孫要素) levelColumns:['Prefectures', 'Municipality', 'town'] }; // インスタンス生成 var treeTable1 = new treeTable(this.document.getElementById('sample-tree-table1'), settingJson1); // TreeTable作成 treeTable1.create(sampleDatas1); } </script> <div> <table id="sample-tree-table1"> <thead> <tr> <td>名称</td> <td>値</td> </tr> </thead> </table> </div>上記はシンプルに作成するパターンです。作成する際はシンプルですが、データがやや複雑に見えます。
サンプルで作成したデータは3階層のデータ構造となっています。
「東京都→区→町」
表にすると下図みたいな感じです。
またデータを渡す際は、表のようにソートされているデータにする必要があります。
都道府県 区 町 東京都 null null 東京都 千代田区 null 東京都 千代田区 A町 東京都 千代田区 B町 東京都 千代田区 C町 東京都 千代田区 D町 東京都 千代田区 E町 東京都 中央区 null 東京都 中央区 F町 東京都 中央区 G町 東京都 港区 null 東京都 港区 H町 東京都 港区 I町 設定値
必須 項目 設定値 初期値 説明 isOpen Boolean true 表示時、展開するかどうか。 isTreeStatusKeep Boolean false 画面遷移しても展開状態を維持するか。(※1) headerLabels 配列 なし 設定した場合、ヘッダ要素を作成。 必須 columns 配列 なし 表示する列要素。表示順は要素の順番。 必須 levelColumns 配列 なし 階層を識別するための列要素。 levelPadding 数値 20 階層毎の間隔。インデント。 onDrawCellValue function(value,cell,rowData){} なし セルに値を書き込む際のコールバックを設定。(※2) onDrawRow function (row,rowData){} なし 行を描画する際のコールバックを設定。 iconStyle Json 下記で説明 開閉アイコンの設定 iconStyle.openText 文字列 + ツリーを展開している際に表示するテキスト。 iconStyle.openCss 文字列 tree-icon-open ツリーを展開している際に適用するcss。 iconStyle.closeText 文字列 - ツリーを閉じている際に表示するテキスト。 iconStyle.closeCss 文字列 tree-icon-close ツリーを閉じている際に適用するcss。 上記設定値を用いたTreeTableの作成は公開しているソース内に含んでいます。
isTreeStatusKeep ※1
Web Storage APIを使用しています。
ブラウザや環境等により使えない場合は、設定値をtrueで渡しても必ずfalseになります。
私の環境はEdge、IE11が使えず、Chromeは使えました。onDrawCellValue ※2
指定した列の値を書き込む際のコールバックを設定します。
引数に設定する値は下記の3つです。
引数 内容 value セルに書き込む値 cell tdのDOM要素 rowData 1レコード分のデータ 指定する列は「columns」と対応する必要があります。
columns: ['text','value'], onDrawCellValue: { 'text': function (value, cell, rowData) { // 任意の処理 }, 'value': function (value, cell, rowData) { // 任意の処理 }, }参考にしたサイト
最後に
様々なフレームワーク、ライブラリがオープンソース化されることで、それに依存してしまうことがあると思います。
依存してしまった結果、これがないとできないといった事象が起きてしまうことが少なからずあり、個人の技量が問われるようになったと感じています。
オープンソースを活用して工数を減らすことはもちろん大事ですが、仕様を理解せず振り回されないよう、技術を磨いていきたいものです。
- 投稿日:2020-03-22T11:16:55+09:00
JavaScript ライブラリなしでTreeTableを実装する
始めに
開発現場によってはjQueryやAngular等のフレームワーク、ライブラリの使用が禁止されているところがあると聞いたことがあります。また、使用するフレームワークによって実装方法がバラついてしまうことがよくあると思います。
そういった状況下でも、問題なく開発が進められるように、フレームワーク、ライブラリを一切使用せずTreeTableを自作してみました。
作成したTreeTableはgitHubに公開しております。動作ブラウザ
・Google Chrome
・Microsoft Edge
・IE11この3つ以外のブラウザでは未検証です。注意ください。
ソースの準備
ソースはgitHubに公開しております。
構成としては至ってシンプルで下記の3つのみです。
動作確認は上記で記載したブラウザがあれば確認することができます。・サンプル用のhtml
・jsファイル
・cssファイルTreeTable使用方法
サンプルで確認
サンプルは2つTreeTableを用意しました。
1つは一番シンプルな作成方法、もう1つはカスタマイズした作成方法になります。
ここではシンプルに作成した場合のサンプルについて確認します。<script type="text/Javascript"> // test data1 const sampleDatas1 = [ { Prefectures: 'tokyo', Municipality: null, town: null, name: '東京都', value: 100 }, { Prefectures: 'tokyo', Municipality: 'chiyoda', town: null, name: '千代田区', value: 200 }, { Prefectures: 'tokyo', Municipality: 'chiyoda', town: 1, name: 'A町', value: 300 }, { Prefectures: 'tokyo', Municipality: 'chiyoda', town: 2, name: 'B町', value: 400 }, { Prefectures: 'tokyo', Municipality: 'chiyoda', town: 3, name: 'C町', value: 500 }, { Prefectures: 'tokyo', Municipality: 'chiyoda', town: 4, name: 'D町', value: 600 }, { Prefectures: 'tokyo', Municipality: 'chiyoda', town: 5, name: 'E町', value: 700 }, { Prefectures: 'tokyo', Municipality: 'chuou', town: null, name: '中央区', value: 800 }, { Prefectures: 'tokyo', Municipality: 'chuou', town: 1, name: 'F町', value: 1000 }, { Prefectures: 'tokyo', Municipality: 'chuou', town: 2, name: 'G町', value: 1100 }, { Prefectures: 'tokyo', Municipality: 'minato', town: null, name: '港区', value: 1200 }, { Prefectures: 'tokyo', Municipality: 'minato', town: 1, name: 'H町', value: 1300 }, { Prefectures: 'tokyo', Municipality: 'minato', town: 2, name: 'I町', value: 1400 }, ]; window.onload = function () { // 設定1 var settingJson1 = { // 作成する列(左から順に作成) columns: ['name', 'value'], // 階層識別列(親要素 - 子要素 - 孫要素) levelColumns:['Prefectures', 'Municipality', 'town'] }; // インスタンス生成 var treeTable1 = new treeTable(this.document.getElementById('sample-tree-table1'), settingJson1); // TreeTable作成 treeTable1.create(sampleDatas1); } </script> <div> <table id="sample-tree-table1"> <thead> <tr> <td>名称</td> <td>値</td> </tr> </thead> </table> </div>上記はシンプルに作成するパターンです。作成する際はシンプルですが、データがやや複雑に見えます。
サンプルで作成したデータは3階層のデータ構造となっています。
「東京都→区→町」
表にすると下図みたいな感じです。
またデータを渡す際は、表のようにソートされているデータにする必要があります。
都道府県 区 町 東京都 null null 東京都 千代田区 null 東京都 千代田区 A町 東京都 千代田区 B町 東京都 千代田区 C町 東京都 千代田区 D町 東京都 千代田区 E町 東京都 中央区 null 東京都 中央区 F町 東京都 中央区 G町 東京都 港区 null 東京都 港区 H町 東京都 港区 I町 設定値
必須 項目 設定値 初期値 説明 isOpen Boolean true 表示時、展開するかどうか。 isTreeStatusKeep Boolean false 画面遷移しても展開状態を維持するか。(※1) headerLabels 配列 なし 設定した場合、ヘッダ要素を作成。 必須 columns 配列 なし 表示する列要素。表示順は要素の順番。 必須 levelColumns 配列 なし 階層を識別するための列要素。 levelPadding 数値 20 階層毎の間隔。インデント。 onDrawCellValue function(value,cell,rowData){} なし セルに値を書き込む際のコールバックを設定。(※2) onDrawRow function (row,rowData){} なし 行を描画する際のコールバックを設定。 iconStyle Json 下記で説明 開閉アイコンの設定 iconStyle.openText 文字列 + ツリーを展開している際に表示するテキスト。 iconStyle.openCss 文字列 tree-icon-open ツリーを展開している際に適用するcss。 iconStyle.closeText 文字列 - ツリーを閉じている際に表示するテキスト。 iconStyle.closeCss 文字列 tree-icon-close ツリーを閉じている際に適用するcss。 上記設定値を用いたTreeTableの作成は公開しているソース内に含んでいます。
isTreeStatusKeep ※1
Web Storage APIを使用しています。
ブラウザや環境等により使えない場合は、設定値をtrueで渡しても必ずfalseになります。
私の環境はEdge、IE11が使えず、Chromeは使えました。onDrawCellValue ※2
指定した列の値を書き込む際のコールバックを設定します。
引数に設定する値は下記の3つです。
引数 内容 value セルに書き込む値 cell tdのDOM要素 rowData 1レコード分のデータ 指定する列は「columns」と対応する必要があります。
columns: ['text','value'], onDrawCellValue: { 'text': function (value, cell, rowData) { // 任意の処理 }, 'value': function (value, cell, rowData) { // 任意の処理 }, }参考にしたサイト
最後に
様々なフレームワーク、ライブラリがオープンソース化されることで、それに依存してしまうことがあると思います。
依存してしまった結果、これがないとできないといった事象が起きてしまうことが少なからずあり、個人の技量が問われるようになったと感じています。
オープンソースを活用して工数を減らすことはもちろん大事ですが、仕様を理解せず振り回されないよう、技術を磨いていきたいものです。
- 投稿日:2020-03-22T05:40:55+09:00
初心者によるプログラミング学習ログ 269日目
100日チャレンジの269日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
269日目は、おはようございます
— ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) March 21, 2020
269日目
・webサイト模写
・下層ページ 4ページ目作成
CSSの設計手法ってなにがいいんだろ?#早起きチャレンジ#駆け出しエンジニアと繋がりたい#100DaysOfCode