日本の美しい風景写真をサクっと検索できるアプリ、(ほぼ)JavaScriptだけでできました。

写真検索 with FIND47オープンデータ」(src on GitHub)
1300以上のステキの写真オープンデータを、キーワードで素早く探せるアプリです。スペース区切りでAND検索にも対応しています。

webアプリの開発に必要なHTML、CSS、JavaScript。3つも言語があって一見ややこしい!?
実はすべてDOM(ドム、ドキュメント オブ オブジェクト)と呼ばれるドキュメント構造を触っているだけです。

HTML(エイチティーエムエル)、DOMを作るコンピューター言語
CSS(カスケードスタイルシート)、DOMを装飾するコンピューター言語
JavaScript(ジャバスクリプト)、DOMをコントロールするプログラミング言語

この中で最も強力なのが、JavaScript。DOMを作ることも装飾することもできるので、実は使用する言語はJavaScriptだけでOKです。

ただ、ブラウザが表示してくれる言語はHTMLなので、タグを2つだけ、文字コードを指定するmetaタグと、JavaScriptを使うscriptタグだけ使います。

<meta charset=utf-8><script type=module> document.body.textContent = "hello!"; </script>

こちら index.html というファイル名で保存してブラウザで開けば、hello! と表示されます。

document は、そのページのドキュメント構造。bodyという表示する中身のテキスト(textContent)に文字列を代入。

プログラミング言語なので、関数も計算も使えます。

document.body.textContent = "hello!" + Math.pow(2, 16);

Math.powは、階乗を計算する定義済みの関数です。(「Math.pow mdn」と知りたい用語 + mdn で検索しましょう)

繰り返しを使って、たくさん表示したいときは document.createElement という関数を使って要素を作って appendChild でドキュメント構造に追加していきます。

for (let i = 0; i < 16; i++) { const div = document.createElement("div"); div.textContent = Math.pow(2, i); document.body.appendChild(div); }

関数名が長くてちょっと大変ですね。

import { div } from "https://js.sabae.cc/stdom.js"; for (let i = 0; i < 16; i++) { div(Math.pow(2, i)); }

ドキュメント構造の操作を短く書ける便利な関数 stdom.js を使って(import)短くしました。
(C言語の stdio.h に習って、stdom.js、スタンダードドム、略してスタドム)

文字の色を付けたいときは stdom.js の style 関数を使います。

import { div, style } from "https://js.sabae.cc/stdom.js"; style({ div: { color: "red" }});

div要素が全部赤くなります。

FIND/47の写真オープンデータを活用したwebアプリ「写真検索」は、この応用例。 プログラムはこちら71行のJavaScriptとscriptタグ2行の合計73行。

<meta charset=utf-8><script type=module> import { create, add, style, h1, inp, div, link } from "https://js.sabae.cc/stdom.js"; import { CSV } from "https://code4sabae.github.io/js/CSV.js"; import { shuffle } from "https://js.sabae.cc/shuffle.js"; import { search } from "https://js.sabae.cc/search.js"; onload = async () => { // ページ構築 h1("写真検索 with FIND47オープンデータ"); const inputfilter = inp(); const res = div(); credit(); style({ a: { color: "gray !important" }}); // データ読み込み const url = "https://code4fukui.github.io/find47/find47images.csv"; const data = CSV.toJSON(await CSV.fetch(url)); console.log(data); shuffle(data); // 検索表示機能 inputfilter.onchange = inputfilter.onkeyup = () => { const hits = search(data, inputfilter.value); document.location.hash = "#" + inputfilter.value; console.log(hits, hits.length); res.innerHTML = ""; for (const d of hits) { const div = create("div"); div.style.margin = "1vw 0"; const img = new Image(); img.style.width = "60vw"; img.loading = "lazy"; // 画像は表示するときに読み込み img.src = d.url_thumb; div.appendChild(img); const div2 = create("div"); div2.style.display = "inline-block"; div2.style.width = "35vw"; div2.style.padding = "1vw"; div2.style.verticalAlign = "top"; div.appendChild(div2); const span2 = create("span"); span2.textContent = d.pref; span2.style.display = "block"; div2.appendChild(span2); const span = create("a"); span.textContent = d.title; span.href = d.url; span.style.display = "block"; div2.appendChild(span); const inpurl = create("input"); inpurl.value = d.url_thumb; inpurl.onfocus = () => inpurl.select(); div2.appendChild(inpurl); res.appendChild(div); } }; // 初期画面 inputfilter.value = decodeURIComponent(document.location.hash.substring(1)) || "福井"; inputfilter.onchange(); }; const credit = () => { add("hr"); link("写真 CC BY FIND47", "https://find47.jp/"); link("データ CC BY Code for Fukui", "https://github.com/code4fukui/find47/"); link("アプリ CC BY Code for Fukui", "https://fukuno.jig.jp/3226"); }; </script>

こちらのプログラムを index.html として保存して、ブラウザで開けば動きます。
構造はシンプルなのでゆっくり読んだり、改造してブラウザを再読み込みして試したりしてみると理解が深まります。

DOCTYPEが付いていない!? stdom.js でセットしているので、心配ご無用!

const doctype = document.implementation.createDocumentType("html", "", ""); if (document.doctype) { document.replaceChild(doctype, document.doctype); } else { document.insertBefore(doctype, document.childNodes[0]); }

中身が気になる方は、importしているJavaScriptもオープンソース、URLをブラウザでたどってみましょう。

オープンデータとオープンソースを活用すると、プログラミングがぐっと楽しくなりますね!

Tweet
クリエイティブ・コモンズ・ライセンス
この作品は「Creative Commons — CC BY 4.0」の下に提供されています。
CC BY / @taisukef / アイコン画像 / プロフィール画像 / RSS