Last active
February 7, 2023 07:41
-
-
Save motsu0/21a881191f308679412ee65587337bd2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.img-sample{ | |
width: 150px; | |
} | |
/* */ | |
.area-work{ | |
text-align: center; | |
} | |
#area-img{ | |
display: inline-block; | |
position: relative; | |
box-shadow: 0 0 0 1px #ccc; | |
overflow: hidden; | |
} | |
.monologue{ | |
padding: 20px 0 20px 20px; | |
position: absolute; | |
top: 0; | |
left: 0; | |
border: 2px solid #000; | |
background-color: #fff; | |
line-height: 1.2em; | |
user-select: none; | |
cursor: move; | |
font-size: 16px; | |
letter-spacing: 20px; | |
font-family: 'Noto Sans JP', sans-serif; | |
} | |
.letter-mini{ | |
display: inline-block; | |
transform: translate(5%, -10%); | |
} | |
#img-main{ | |
display: block; | |
width: 100%; | |
} | |
.area-file{ | |
margin: 16px 0; | |
text-align: center; | |
} | |
#label-file{ | |
display: inline-block; | |
padding: 8px 16px; | |
border: 1px solid #aaa; | |
border-radius: 4px; | |
background-color: #eee; | |
cursor: pointer; | |
} | |
#label-file.label-file--dragover{ | |
background-color: #ddd; | |
} | |
#label-file:hover{ | |
background-color: #ddd; | |
} | |
#message{ | |
margin-top: 12px; | |
color: #ee0000; | |
} | |
/* */ | |
.control__menu{ | |
display: flex; | |
column-gap: 4px; | |
} | |
.control__menu__item{ | |
flex-grow: 1; | |
background-color: #ddd; | |
cursor: pointer; | |
} | |
.control__menu__item.on{ | |
border-bottom: none; | |
background-color: #2ECC71; | |
color: white; | |
} | |
.control__block{ | |
height: 600px; | |
border: 2px solid #2ECC71; | |
overflow-y: auto; | |
} | |
/* */ | |
#textarea-input{ | |
margin-top: 24px; | |
} | |
.control__textarea{ | |
display: block; | |
width: 80%; | |
height: 100px; | |
margin: 12px auto; | |
resize: vertical; | |
} | |
/* */ | |
.settings{ | |
padding: 12px 0; | |
} | |
.settings:nth-child(n+2){ | |
border-top: 1px dashed #2ECC71; | |
} | |
.settings__row{ | |
margin: 8px 0; | |
} | |
.input-number{ | |
width: 60px; | |
} | |
.bt-del{ | |
border: none; | |
background-color: #ee0000; | |
color: #fff; | |
} | |
/* */ | |
#bt-dl{ | |
margin-top: 24px; | |
} | |
/* */ | |
.bt-control{ | |
display: block; | |
padding: 4px 8px; | |
margin: 12px auto; | |
cursor: pointer; | |
} | |
/* */ | |
.s-hide{ | |
display: none; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="area-work"> | |
<div id="area-img"> | |
<img src="" alt="" id="img-main" draggable="false"> | |
</div> | |
<div class="area-file"> | |
<label for="input-file" id="label-file">画像を読み込む</label> | |
<input type="file" class="s-hide" id="input-file" accept="image/*"> | |
<div id="message" class="s-hide">画像を選択してください。</div> | |
</div> | |
<div class="control"> | |
<div class="control__menu"> | |
<div class="control__menu__item on">新規</div> | |
<div class="control__menu__item">編集</div> | |
<div class="control__menu__item">出力</div> | |
</div> | |
<div class="control__block control-new"> | |
<textarea id="textarea-input" class="control__textarea" placeholder="追加したい文章(全角文字推奨)"></textarea> | |
<button id="bt-add" class="bt-control">モノローグを追加</button> | |
</div> | |
<div id="control-edit" class="control__block s-hide"> | |
</div> | |
<div class="control__block control-edit s-hide"> | |
<button id="bt-dl" class="bt-control">画像を保存</button> | |
</div> | |
</div> | |
</div> | |
<div class="settings s-hide" id="settings-origin"> | |
<textarea class="control__textarea"></textarea> | |
<button class="bt-control bt-textedit">テキスト更新</button> | |
<div class="settings__row"> | |
文字サイズ | |
<input type="number" class="input-fontsize input-number" min="0" value="16">px | |
</div> | |
<div class="settings__row"> | |
文字の色 | |
<input type="color" class="input-color" value="#000000"> | |
</div> | |
<div class="settings__row"> | |
フォント | |
<select class="sel-font"></select> | |
</div> | |
<div class="settings__row"> | |
枠の太さ | |
<input type="number" class="input-border-width input-number" min="0" value="2">px | |
</div> | |
<div class="settings__row"> | |
枠の色 | |
<input type="color" class="input-border-color" value="#000000"> | |
</div> | |
<div class="settings__row"> | |
背景色 | |
<input type="color" class="input-bg-color" value="#ffffff"> | |
</div> | |
<div class="settings__row"> | |
行間 | |
<input type="number" class="input-between input-number" min="0" value="20">px | |
</div> | |
<div class="settings__row"> | |
余白 | |
<input type="number" class="input-padding input-number" min="0" value="20">px | |
</div> | |
<button class="bt-del bt-control">削除</button> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="/js/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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const nowloading = new nowLoading(); | |
const el_area_img = document.getElementById('area-img'); | |
const el_img_main = document.getElementById('img-main'); | |
const el_input_file = document.getElementById('input-file'); | |
const el_label_file = document.getElementById('label-file'); | |
const el_message = document.getElementById('message'); | |
const els_monologue = document.getElementsByClassName('monologue'); | |
const el_textarea_input = document.getElementById('textarea-input'); | |
const els_control__menu__item = document.getElementsByClassName('control__menu__item'); | |
const els_control_block = document.getElementsByClassName('control__block'); | |
const bt_add = document.getElementById('bt-add'); | |
const el_control_edit = document.getElementById('control-edit'); | |
const el_settings_origin = document.getElementById('settings-origin'); | |
const bt_dl = document.getElementById('bt-dl'); | |
const fontset = [ | |
{ | |
name: 'Noto Sans JP', | |
css: '\'Noto Sans JP\', sans-serif' | |
}, | |
{ | |
name: 'Noto Serif JP', | |
css: '\'Noto Serif JP\', serif' | |
}, | |
{ | |
name: 'DotGothic16', | |
css: '\'DotGothic16\', sans-serif' | |
}, | |
{ | |
name: 'M PLUS 1p', | |
css: '\'M PLUS 1p\', sans-serif' | |
}, | |
{ | |
name: 'RocknRoll One', | |
css: '\'RocknRoll One\', sans-serif' | |
}, | |
{ | |
name: 'Sawarabi Gothic', | |
css: '\'Sawarabi Gothic\', sans-serif' | |
}, | |
{ | |
name: 'Shippori Mincho', | |
css: '\'Shippori Mincho\', serif' | |
}, | |
{ | |
name: 'Zen Kurenaido', | |
css: '\'Zen Kurenaido\', sans-serif' | |
}, | |
{ | |
name: 'Zen Maru Gothic', | |
css: '\'Zen Maru Gothic\', sans-serif' | |
} | |
]; | |
const array_replace = [ | |
['、','︑'], | |
['。','︒'], | |
['(','︵'], | |
[')','︶'], | |
['{','︷'], | |
['}','︸'], | |
['〔','︹'], | |
['〕','︺'], | |
['【','︻'], | |
['】','︼'], | |
['《','︽'], | |
['》','︾'], | |
['〈','︿'], | |
['〉','﹀'], | |
['「','﹁'], | |
['」','﹂'], | |
['『','﹃'], | |
['』','﹄'], | |
['[','﹇'], | |
[']','﹈'], | |
['―','︱'], | |
['ー','丨'], | |
['‥','︰'], | |
['…','︙'] | |
]; | |
const array_letter_mini = [ | |
'っ','ッ', | |
'ゃ','ャ', | |
'ゅ','ュ', | |
'ょ','ョ', | |
'ぁ','ァ', | |
'ぃ','ィ', | |
'ぅ','ゥ', | |
'ぇ','ェ', | |
'ぉ','ォ', | |
'ゎ','ヮ' | |
]; | |
let width_image = 1080; | |
init(); | |
function init(){ | |
nowloading.start(); | |
//リスナ設定 | |
[...els_control__menu__item].forEach((element,i,ar)=>{ | |
element.addEventListener('click',()=>{ | |
ar.forEach(el=>{ | |
el.classList.remove('on'); | |
}); | |
element.classList.add('on'); | |
[...els_control_block].forEach(el=>{ | |
el.classList.add('s-hide'); | |
}); | |
els_control_block[i].classList.remove('s-hide'); | |
}); | |
}); | |
bt_add.addEventListener('click',addMonologue); | |
bt_dl.addEventListener('click',downloadImg); | |
el_input_file.addEventListener('change',inputFile); | |
el_label_file.addEventListener('dragover',fileDragover); | |
el_label_file.addEventListener('drop',fileDrop); | |
el_label_file.addEventListener('dragleave',fileDragEnd); | |
//画像読み込み | |
el_img_main.addEventListener('load',()=>{ | |
el_area_img.style.width = ''; | |
width_image = el_img_main.naturalWidth; | |
const height = el_img_main.clientHeight; | |
const rate_h = height/window.screen.height; | |
if(rate_h>.8){ | |
el_area_img.style.width = (80/rate_h)+'%'; | |
} | |
}); | |
//フォント | |
const el_sel_font = el_settings_origin.getElementsByClassName('sel-font')[0]; | |
fontset.forEach(val=>{ | |
const el_option = document.createElement('option'); | |
el_option.textContent = val.name; | |
el_option.value = val.css; | |
el_sel_font.appendChild(el_option); | |
}); | |
//初期化終了 | |
nowloading.stop(); | |
} | |
// fileDragover => fileDrop => checkFile | |
// ↓ inputFile ↗ | |
// fileDragEnd | |
function fileDragover(e){ | |
e.preventDefault(); | |
e.target.classList.add('label-file--dragover'); | |
} | |
function fileDrop(e){ | |
e.preventDefault(); | |
nowloading.start(); | |
e.target.classList.remove('label-file--dragover'); | |
const files = e.dataTransfer.files; | |
if(files.length===0){ | |
nowloading.stop(); | |
return; | |
} | |
checkFile(files[0]); | |
} | |
function fileDragEnd(e){ | |
e.target.classList.remove('label-file--dragover'); | |
} | |
function inputFile(e){ | |
nowloading.start(); | |
el_message.classList.add('s-hide'); | |
const files = e.target.files; | |
if(files.length===0){ | |
nowloading.stop(); | |
return | |
} | |
checkFile(files[0]); | |
} | |
function checkFile(file){ | |
if(file.type.indexOf('image')===-1){ | |
nowloading.stop(); | |
el_message.classList.remove('s-hide'); | |
return; | |
} | |
const reader = new FileReader(); | |
reader.onload = ev=>{ | |
el_img_main.src = ev.target.result; | |
nowloading.stop(); | |
} | |
reader.readAsDataURL(file); | |
} | |
function addMonologue(){ | |
//文字取得 | |
const input_text = el_textarea_input.value; | |
if(input_text.length === 0) return; | |
const html_monologue = makeHtml(input_text); | |
//追加要素作成 | |
const el_monologue = document.createElement('div'); | |
el_monologue.classList.add('monologue'); | |
el_monologue.innerHTML = html_monologue; | |
el_area_img.appendChild(el_monologue); | |
//ドラッグアンドドロップ処理 | |
let x_pos = 0; | |
let y_pos = 0; | |
let x_cursor; | |
let y_cursor; | |
let is_dragging = false; | |
el_monologue.addEventListener('mousedown',dragStart); | |
el_monologue.addEventListener('touchstart',dragStart); | |
el_area_img.addEventListener('mousemove',drag); | |
el_area_img.addEventListener('touchmove',drag); | |
el_monologue.addEventListener('mouseup',dragEnd); | |
el_monologue.addEventListener('touchend',dragEnd); | |
el_area_img.addEventListener('mouseleave',dragEnd); | |
el_area_img.addEventListener('touchleave',dragEnd); | |
//編集機能追加 | |
const el_settings = el_settings_origin.cloneNode(true); | |
el_settings.id = ''; | |
el_settings.classList.remove('s-hide'); | |
// | |
const el_input_text = el_settings.getElementsByClassName('control__textarea')[0]; | |
el_input_text.value = el_textarea_input.value; | |
const bt_textedit = el_settings.getElementsByClassName('bt-textedit')[0]; | |
bt_textedit.addEventListener('click',changeText); | |
const el_input_fontsize = el_settings.getElementsByClassName('input-fontsize')[0]; | |
el_input_fontsize.addEventListener('input',()=>{changeFontsize(el_input_fontsize)}); | |
const el_input_color = el_settings.getElementsByClassName('input-color')[0]; | |
el_input_color.addEventListener('input',()=>{changeColor(el_input_color)}); | |
const el_sel_font = el_settings.getElementsByClassName('sel-font')[0]; | |
el_sel_font.addEventListener('change',changeFont); | |
const el_input_border_width = el_settings.getElementsByClassName('input-border-width')[0]; | |
el_input_border_width.addEventListener('input',()=>{changeBorderWidth(el_input_border_width)}); | |
const el_input_border_color = el_settings.getElementsByClassName('input-border-color')[0]; | |
el_input_border_color.addEventListener('input',()=>{changeBorderColor(el_input_border_color)}); | |
const el_input_bg_color = el_settings.getElementsByClassName('input-bg-color')[0]; | |
el_input_bg_color.addEventListener('input',()=>{changeBgColor(el_input_bg_color)}); | |
const el_input_between = el_settings.getElementsByClassName('input-between')[0]; | |
el_input_between.addEventListener('input',changePadding); | |
const el_input_padding = el_settings.getElementsByClassName('input-padding')[0]; | |
el_input_padding.addEventListener('input',changePadding); | |
const bt_del = el_settings.getElementsByClassName('bt-del')[0]; | |
bt_del.addEventListener('click',deleteMonologue); | |
// | |
el_control_edit.appendChild(el_settings); | |
//後処理 | |
el_textarea_input.value = ''; | |
//サブ関数 | |
function makeHtml(text){ | |
const array_line = text.split(/\n/); | |
const width = array_line.length; | |
const height = array_line.map(v=>v.length).reduce((p,c)=>Math.max(p,c)); | |
const array_input = array_line.map(v=>v.split('')); | |
const array_output = (new Array(height)).fill('').map(v=>(new Array(width).fill(''))); | |
for(r=0;r<height;r++){ | |
for(c=0;c<width;c++){ | |
const val = array_input[c][r]; | |
if(val==undefined){ | |
array_output[r][width-c] = ' '; | |
}else if(array_letter_mini.includes(val)){ | |
const el_span = document.createElement('span'); | |
el_span.classList.add('letter-mini'); | |
el_span.textContent = val; | |
array_output[r][width-c] = el_span.outerHTML; | |
}else{ | |
let val_replaced = val; | |
array_replace.forEach(set=>{ | |
val_replaced = val_replaced.replace(set[0],set[1]); | |
}); | |
array_output[r][width-c] = escHtml(val_replaced); | |
} | |
} | |
} | |
return array_output.map(line=>line.join('')).join('<br>'); | |
} | |
//サブ関数 ドラッグ | |
function dragStart(e){ | |
is_dragging = true; | |
const event = (()=>{ | |
if(e.type==='mousedown'){ | |
return e; | |
}else{ | |
return e.changedTouches[0]; | |
} | |
})(); | |
x_cursor = event.pageX; | |
y_cursor = event.pageY; | |
} | |
function drag(e){ | |
e.preventDefault(); | |
if(!is_dragging) return; | |
const event = (()=>{ | |
if(e.type==='mousemove'){ | |
return e; | |
}else{ | |
return e.changedTouches[0]; | |
} | |
})(); | |
x_pos += event.pageX - x_cursor; | |
y_pos += event.pageY - y_cursor; | |
x_cursor = event.pageX; | |
y_cursor = event.pageY; | |
el_monologue.style.transform = `translate(${x_pos}px,${y_pos}px)`; | |
} | |
function dragEnd(){ | |
is_dragging = false; | |
} | |
//サブ関数 編集 | |
function changeText(){ | |
el_monologue.innerHTML = makeHtml(el_input_text.value); | |
} | |
function changeFontsize(el_input){ | |
const value = (()=>{ | |
let temp = Number(el_input.value); | |
if(temp<4){ | |
temp = 4; | |
} | |
return temp; | |
})(); | |
el_monologue.style.fontSize = value+'px'; | |
} | |
function changeColor(el_input){ | |
el_monologue.style.color = el_input.value; | |
} | |
function changeFont(){ | |
el_monologue.style.fontFamily = el_sel_font.value; | |
} | |
function changeBorderWidth(el_input){ | |
const value = (()=>{ | |
let temp = Number(el_input.value); | |
if(temp<1){ | |
temp = 1; | |
} | |
return temp; | |
})(); | |
el_monologue.style.borderWidth = value+'px'; | |
} | |
function changeBorderColor(el_input){ | |
el_monologue.style.borderColor = el_input.value; | |
} | |
function changeBgColor(el_input){ | |
el_monologue.style.backgroundColor = el_input.value; | |
} | |
function changePadding(){ | |
const value_padding = (()=>{ | |
let temp = Number(el_input_padding.value); | |
if(temp<0){ | |
temp = 0; | |
} | |
return temp; | |
})(); | |
const value_between = (()=>{ | |
let temp = Number(el_input_between.value); | |
if(temp<0){ | |
temp = 0; | |
} | |
return temp; | |
})(); | |
const gap = value_padding - value_between; | |
if(gap>=0){ | |
el_monologue.style.padding = `${value_padding}px ${gap}px ${value_padding}px ${value_padding}px`; | |
}else{ | |
el_monologue.style.padding = `${value_padding}px 0px ${value_padding}px ${value_between}px`; | |
} | |
el_monologue.style.letterSpacing = value_between + 'px'; | |
} | |
function deleteMonologue(){ | |
el_settings.remove(); | |
el_monologue.remove(); | |
} | |
} | |
function downloadImg(){ | |
nowloading.start(); | |
setTimeout(()=>{ | |
const scale = (()=>{ | |
let temp = width_image / el_img_main.clientWidth; | |
if(temp<1) temp = 1; | |
return temp; | |
})(); | |
html2canvas(el_area_img,{ | |
scale: scale | |
}).then(canvas => { | |
canvas.toBlob(blob=>{ | |
const alink = document.createElement('a'); | |
alink.href = URL.createObjectURL(blob); | |
alink.download = 'img-monologue.png'; | |
alink.click(); | |
URL.revokeObjectURL(blob); | |
nowloading.stop(); | |
}); | |
}); | |
},1); | |
} | |
function escHtml(str){ | |
str = str.replace(/&/g, '&') | |
.replace(/</g, '<') | |
.replace(/>/g, '>') | |
.replace(/"/g, '"') | |
.replace(/'/g, '''); | |
return str; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment