Skip to content

Instantly share code, notes, and snippets.

@motsu0
Last active July 4, 2022 07:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save motsu0/5f2f7252ed70388d1c7cc3fe5496d294 to your computer and use it in GitHub Desktop.
Save motsu0/5f2f7252ed70388d1c7cc3fe5496d294 to your computer and use it in GitHub Desktop.
.img-sample{
width: 150px;
border: 1px solid #777;
}
/* */
.block{
box-sizing: border-box;
padding: 16px;
margin: 20px 0;
border-radius: 8px;
border: 3px outset #ccc;
}
h3.block__title{
margin: 0 0 16px 0;
}
/* */
.search-row{
margin: 16px 0;
}
.icon-google{
vertical-align: middle;
}
#bt-submit{
padding: 4px 12px;
margin-right: 12px;
cursor: pointer;
}
/* */
.list-books-outer{
box-sizing: border-box;
max-height: 500px;
padding: 16px;
overflow-y: auto;
background-color: #eee;
border: 2px inset #ddd;
}
.book{
box-sizing: border-box;
border: 1px solid #555;
background-color: #fff;
}
.book+.book{
margin: 12px 0;
}
.book__imgbox{
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
padding: 8px;
}
.book__img{
width: 100%;
height: 120px;
object-fit: contain;
}
.book__textbox{
box-sizing: border-box;
padding: 8px;
border: dashed #aaa;
border-width: 1px 0;
}
.book__linkbox{
display: flex;
justify-content: center;
flex-direction: column;
box-sizing: border-box;
padding: 8px;
}
.book__link,.bt-copy{
display: block;
margin: 4px 0;
cursor: pointer;
}
/* */
.settings-row{
margin: 12px 0;
}
.settings-img{
width: 200px;
max-width: 100%;
max-height: 200px;
object-fit: contain;
}
/* */
#preview,#output{
text-align: center;
}
#preview__body,#output__body{
margin: 16px auto;
}
#preview__body{
width: 100%;
overflow: hidden;
box-shadow: 0 0 0 1px #777
}
.preview__title{
text-align: center;
}
#preview__img{
display: block;
max-width: 100%;
margin: 0 auto;
}
#preview__table{
margin: 8px;
}
.preview__td{
line-height: 1.7em;
text-align: left;
word-break: break-all;
}
.preview__td:first-of-type{
word-break: keep-all;
white-space: nowrap;
}
.output__canvas{
display: block;
box-sizing: content-box;
margin: 0 auto;
border: 1px solid #777;
}
#bt-makeImg,#bt-dlImg{
margin: 16px auto;
cursor: pointer;
}
#bt-makeImg{
display: block;
}
/* */
.s-invisible{
visibility: hidden;
}
.s-hide{
display: none;
}
/* */
@media screen and (min-width:769px) {
.book{
display: flex;
}
.book__imgbox{
width: 15%;
}
.book__textbox{
flex-grow: 1;
width: 0;
border-width: 0 1px;
}
.book__linkbox{
width: 20%;
}
#preview__body{
width: 400px;
}
}
<div class="block">
<h3 class="block__title">Googleブックスから各情報を取得</h3>
<form id="search">
<div class="search__row">
検索ワード: <input type="text" id="input-keyword" placeholder="検索ワード" required>
</div>
<div class="search-row">
<button id="bt-submit">検索</button>
<img src="pathto/poweredbygoogle.png" alt="POWERED BY Google" class="icon-google">
</div>
<div class="search-row">
<div id="message"></div>
</div>
</form>
<div class="list-books-outer">
<div id="list-books"></div>
</div>
</div>
<div id="block-information" class="block">
<h3 class="block__title">書籍情報登録</h3>
<div class="settings-row">
タイトル: <input type="text" id="input-title" data-name="タイトル" placeholder="例:ももたろう">
</div>
<div class="settings-row">
ISBN-10: <input type="text" id="input-isbn10" data-name="ISBN-10" placeholder="例:1234567890">
</div>
<div class="settings-row">
ISBN-13: <input type="text" id="input-isbn13" data-name="ISBN-13" placeholder="例:1234567890123">
</div>
<div class="settings-row">
作者: <input type="text" id="input-author" data-name="作者" placeholder="例:山田太郎">
</div>
<div class="settings-row">
レーベル: <input type="text" id="input-label" data-name="レーベル" placeholder="例:◯◯文庫">
</div>
<div class="settings-row">
出版社: <input type="text" id="input-publisher" data-name="出版社" placeholder="例:◯✕社">
</div>
<div class="settings-row">
出版日: <input type="text" id="input-date" data-name="出版日" placeholder="例:2000年1月1日">
</div>
</div>
<div class="block">
<h3 class="block__title">書籍画像登録</h3>
<div id="settings-imgbox"></div>
<input type="file" id="input-img">
</div>
<div class="block">
<h3 class="block__title">設定</h3>
<div class="settings-row">
フォントサイズ: <input type="number" min="4" max="50" id="input-fontsize" value="16">px
</div>
<div class="settings-row">
完成画像の最大アスペクト比:
<select id="sel-aspect">
<option value="auto">標準(縦16:横9)</option>
<option value="device">使用中の機器に合わせる</option>
</select>
</div>
</div>
<div id="block-output" class="block">
<h3 class="block__title">出力結果</h3>
<div id="preview">
<div class="preview__title">プレビュー</div>
<div id="preview__body" style="font-size: 16px;">
<img src="" alt="" id="preview__img" class="s-hide">
<table id="preview__table"></table>
</div>
<button id="bt-makeImg">画像を生成</button>
</div>
<div id="output" class="s-hide">
<div class="preview__title">完成画像</div>
<div id="output__body"></div>
<a href="" id="bt-dlImg" download="book-information.png">画像を保存</a>
</div>
</div>
<script src="pathto/now-loading.js"></script>
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js" integrity="sha256-6H5VB5QyLldKH9oMFUmjxw2uWpPZETQXpCkBaDjquMs=" crossorigin="anonymous"></script>
const nowloading = new nowLoading();
const el_search = document.getElementById('search');
const el_input_keyword = document.getElementById('input-keyword');
const bt_submit = document.getElementById('bt-submit');
const el_message = document.getElementById('message');
const el_list_books = document.getElementById('list-books');
const el_block_information = document.getElementById('block-information');
const els_settings = {
title: document.getElementById('input-title'),
isbn10: document.getElementById('input-isbn10'),
isbn13: document.getElementById('input-isbn13'),
author: document.getElementById('input-author'),
label: document.getElementById('input-label'),
publisher: document.getElementById('input-publisher'),
date: document.getElementById('input-date')
}
const array_settings = ['title','isbn10','isbn13','author','label','publisher','date'];
const el_settings_imgbox = document.getElementById('settings-imgbox');
const els_settings_img = document.getElementsByClassName('settings-img');
const el_input_img = document.getElementById('input-img');
const el_input_fontsize = document.getElementById('input-fontsize');
const el_sel_aspect = document.getElementById('sel-aspect');
const el_block_output = document.getElementById('block-output');
const el_preview = document.getElementById('preview');
const el_preview__body = document.getElementById('preview__body');
const el_preview__img = document.getElementById('preview__img');
const el_preview__table = document.getElementById('preview__table');
const el_output = document.getElementById('output');
const el_output__body = document.getElementById('output__body');
const bt_makeImg = document.getElementById('bt-makeImg');
const bt_dlImg = document.getElementById('bt-dlImg');
let is_using = false;
let blob_output;
el_input_keyword.addEventListener('input',()=>{
if(el_input_keyword.value.length<2){
el_input_keyword.setCustomValidity('キーワードが短すぎます。');
}else{
el_input_keyword.setCustomValidity('');
}
});
el_search.addEventListener('submit',e=>{
e.preventDefault();
request();
});
el_input_img.addEventListener('input',checkFile);
array_settings.forEach(v=>{
els_settings[v].addEventListener('input',makePreview);
});
el_input_fontsize.addEventListener('input',makePreview);
el_sel_aspect.addEventListener('change',makePreview);
bt_makeImg.addEventListener('click',makeImg);
el_preview__img.onload = checkAspect;
function request(){
//初期化
if(is_using) return;
is_using = true;
bt_submit.classList.add('s-invisible');
el_message.textContent = '検索中...';
el_list_books.textContent= '';
//
const url_base = 'https://www.googleapis.com/books/v1/volumes';
const params = {
maxResults: 30
};
if(el_input_keyword.value!='') params.q = el_input_keyword.value;
const str_params = new URLSearchParams(params).toString();
const url = url_base + '?' + str_params;
fetch(url).then(response=>{
bt_submit.classList.remove('s-invisible');
el_message.textContent = '';
is_using = false;
if(response.ok){
return response.json();
}else{
throw new Error('通信に失敗しました。一日の利用制限数に達した可能性があります。');
}
}).then(data=>{
makeList(data);
}).catch(error=>{
writeMessage(error);
});
}
function writeMessage(str){
el_message.textContent = str;
}
function makeList(res){
if(res==false||res==undefined){
writeMessage('通信に失敗しました。一日の利用制限数に達した可能性があります。');
bt_submit.classList.remove('s-invisible');
is_using = false;
return;
}
res.items.forEach((item,i)=>{
//情報取得
const img_src = item.volumeInfo.imageLinks;
const title = item.volumeInfo.title || '';
const authors = item.volumeInfo.authors;
const isbn = item.volumeInfo.industryIdentifiers;
const date = item.volumeInfo.publishedDate;
const link = item.volumeInfo.canonicalVolumeLink;
//html作成
const el_book = document.createElement('div');
el_book.classList.add('book');
const el_book__imgbox = document.createElement('div');
el_book__imgbox.classList.add('book__imgbox');
if(img_src==undefined){
el_book__imgbox.textContent = '画像無し';
}else{
const img = document.createElement('img');
img.classList.add('book__img');
img.src = img_src.smallThumbnail;
el_book__imgbox.appendChild(img);
}
el_book.appendChild(el_book__imgbox);
//
const el_book__textbox = document.createElement('div');
el_book__textbox.classList.add('book__textbox');
if(title!=undefined){
const el_book__title = document.createElement('div');
el_book__title.classList.add('book__text');
el_book__title.textContent = title;
el_book__textbox.appendChild(el_book__title);
}
if(authors!=undefined){
const el_book__author = document.createElement('div');
el_book__author.classList.add('book__text');
el_book__author.textContent = authors.join('/');
el_book__textbox.appendChild(el_book__author);
}
el_book.appendChild(el_book__textbox);
//
const el_book__linkbox = document.createElement('div');
el_book__linkbox.classList.add('book__linkbox');
const el_link = document.createElement('a');
el_link.classList.add('book__link');
el_link.href = link;
el_link.textContent = 'Googleブックス';
el_book__linkbox.appendChild(el_link);
const bt_copy = document.createElement('button');
bt_copy.classList.add('bt-copy');
bt_copy.textContent = '情報を取得';
bt_copy.addEventListener('click',()=>{
copyInfo(bt_copy);
});
el_book__linkbox.appendChild(bt_copy);
el_book.appendChild(el_book__linkbox);
//データ登録
bt_copy.dataset.title = title;
if(authors!=undefined) bt_copy.dataset.author = authors.join('/');
if(isbn!=undefined){
isbn.forEach(v=>{
if(v.type=='ISBN_10'){
bt_copy.dataset.isbn10 = v.identifier;
}else if(v.type=='ISBN_13'){
bt_copy.dataset.isbn13 = v.identifier;
}
});
}
bt_copy.dataset.date = date;
//
el_list_books.appendChild(el_book);
});
}
function copyInfo(el){
array_settings.forEach(v=>{
if(el.dataset[v]==undefined||el.dataset[v]=='undefined'){
els_settings[v].value = '';
}else{
els_settings[v].value = el.dataset[v];
}
});
makePreview();
//移動
const x = window.pageXOffset;
const y = window.pageYOffset + el_block_information.getBoundingClientRect().top;
window.scrollTo({
top:y,
left:x,
behavior: 'smooth'
});
}
function checkFile(e){
const files = e.target.files;
if(files.length==0) return;
const file = files[0];
e.target.value = '';
if(file.type.indexOf('image')==-1){
el_settings_imgbox.textContent = '画像を選択してください。';
return;
}
el_settings_imgbox.textContent = '';
const reader = new FileReader();
reader.onload = ev=>{
const img = document.createElement('img');
img.classList.add('settings-img');
img.src = ev.target.result;
el_settings_imgbox.appendChild(img);
makePreview();
}
reader.readAsDataURL(file);
}
function makePreview(){
//初期処理
el_output.classList.add('s-hide');
el_preview.classList.remove('s-hide');
//フォントサイズ
const fs = (()=>{
let temp = Number(el_input_fontsize.value);
if(temp<4){
return 4;
}else if(temp>50){
return 50;
}else{
return temp;
}
})();
el_preview__body.style.fontSize = fs+'px';
//画像
if(els_settings_img.length>0){
el_preview__img.classList.remove('s-hide');
if(el_preview__img.src!=els_settings_img[0].src){
el_preview__img.src = els_settings_img[0].src;
el_preview__img.alt = '画像';
}
}else{
el_preview__img.classList.add('s-hide');
el_preview__img.alt = '';
}
//データテーブル
el_preview__table.textContent = '';
array_settings.forEach(v=>{
if(els_settings[v].value=='') return;
const el_tr = document.createElement('tr');
const el_td_name = document.createElement('td');
el_td_name.classList.add('preview__td');
el_td_name.textContent = els_settings[v].dataset.name;
el_tr.appendChild(el_td_name);
const el_td_colon = document.createElement('td');
el_td_colon.classList.add('preview__td');
el_td_colon.textContent = ':';
el_tr.appendChild(el_td_colon);
const el_td_val = document.createElement('td');
el_td_val.classList.add('preview__td');
el_td_val.textContent = els_settings[v].value;
el_tr.appendChild(el_td_val);
el_preview__table.appendChild(el_tr);
});
if(el_preview__table.textContent==''){
el_preview__table.classList.add('s-hide');
}else{
el_preview__table.classList.remove('s-hide');
}
checkAspect();
}
function checkAspect(){
const w_now = el_preview__body.clientWidth;
const rate = (()=>{
if(el_sel_aspect.value=='auto'){
return 16/9;
}else{
return window.screen.height/window.screen.width;
}
})();
const h_max = w_now*rate;
el_preview__body.style.height = '';
el_preview__img.style.height = ''
const diff = el_preview__body.clientHeight - h_max;
if(diff>0){
el_preview__img.style.height = Math.max(el_preview__img.clientHeight-diff,0) + 'px';
}
if(el_preview__body.clientHeight - h_max>10){
el_preview__body.style.height = h_max+'px';
}
}
function makeImg(){
if(el_preview__table.textContent==''&&el_preview__img.alt=='') return;
//初期処理
nowloading.start();
el_output__body.textContent = '';
//
setTimeout(()=>{
html2canvas(el_preview__body,{
scale: 2
}).then(canvas => {
canvas.classList.add('output__canvas');
el_output__body.appendChild(canvas);
canvas.toBlob(blob=>{
bt_dlImg.href = URL.createObjectURL(blob);
URL.revokeObjectURL(blob);
});
//後処理
el_preview.classList.add('s-hide');
el_output.classList.remove('s-hide');
//移動
const x = window.pageXOffset;
const y = window.pageYOffset + el_block_output.getBoundingClientRect().top;
window.scrollTo(x,y);
nowloading.stop();
});
},1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment