表示サイズの属性を削除可能にしました
SVG画像の表示サイズは、幾つかの方法で指定されます。 ネット上から入手したSVGや、画像変換サービスで生成したSVGなどは、表示サイズが指定されている場合が殆どですが、SVGの扱いに慣れて来ると「指定が無い」方が扱い易くなります。
SVG画像のソースコードを入手後、実際に配置する場所に合わせてサイズや位置を調節するので、サイズ指定があると「やりにくいだけ」なのです。
サイズ指定は <svg>タグ内でインライン指定されている場合が殆どです。 サイズ指定を削除すると、SVG画像はベクトル描画コードに従って、多くの場合に想定外の大きさで描画されます。 これまでサイズ指定を意図的に残して来ましたが、配置先で無造作にSVG画像が拡大すると扱い難いと考えたからです。 しかし、サイズ指定が出来ないユーザーが扱うツールではないし、不要なサイズ指定のコードを省ける、よりラジカルな仕様を採り入れました。
コントロールの変更
SVG画像のソースコードで、サイズ指定は以下の方法で書き込まれます。
①「width="~" height="~"」の「属性指定」
➁「style="width: ~px; height: ~px;"」の「style属性」による指定
どちらも指定内容は同じですが、「Simple SVG」でそれらの指定を削除をする場合は、削除コードが異なるので分ける必要があります。
➁は、「F7」Style のボタンを「ON」にする事で削除されます。 これは既にある機能です。 今回追加したのは、①のサイズ指定の削除機能です。
下は新しいコントロールで、「F4」を ①のタイプの「サイズ指定の削除」に割り当てました。
「Fn」ボタンが足りないので、これまで「圧縮処理無し」のボタン「F4」を使いました。「圧縮処理無し」を指定する場合は、「F1」~「F3」で「ON」になった「Fn」を押すと「OFF」になる様に改めました。
ソースコードによってふるまいが異なるツール上の表示サイズ
少しややこしくなりますが、SVG画像に慣れると、難しい事ではないと思います。
◎ 下は、①のタイプの SVG画像を読込んだ状態です。
これは「F4 Size」を「ON」にすると、枠内いっぱいに拡大されます。 この ①のタイプは、サイズ指定が「style属性」では指定していないので、「F7 Style」を「ON」にしても、表示サイズは変わりません。
◎ 下は ➁のタイプの SVG画像の場合です。
「F7 Style」を「ON」にすると、枠内に拡大表示されます。 ➁のタイプは、サイズ指定が「width・heightの属性」で指定されていないので、「F4 Size」を「ON」にしても表示は変化しません。
以上の様に「F4」「F7」のどちらで表示サイズが変化するかは、画像のソースコードによって変わります。 もちろん、サイズ指定コードの削除が有効な方を選択すれば良いわけです。 もっとも、「F4」が効かない画像で「F4」を「ON」にしても全く無害です。 ただし「F7」は、サイズ指定以外の指定も一緒に削除する場合があります。 それが画像上で問題がある場合は、手作業で処理するか、「Style属性」の削除は諦めるかになります。
▪「F4」「F7」の両方が表示サイズに影響しない SVG画像もあります。
▪ 簡単には、画質に問題なければ、「F4」~「F7」は全て「ON」でOKです。
「F9」SVG画像の拡大表示
「F9」の拡大表示機能は、両方の枠内のSVG画像の表示サイズを、枠サイズまで強制的に拡大します。 これは、小さなSVG画像を拡大して、画質の比較をし易くするための機能です。 今回の仕様変更で、他のボタンで処理適用側のSVGが拡大するので、少し判り難くなったかも知れません。
▪ これを「ON」にすれば、両方とも拡大表示が強制されると考えてください。
枠内の中央配置のコードを変更
これまで、JavaScriptで表示枠のサイズを取得して、その値と、拡大表示したSVG画像のサイズから、枠内の中央に表示するための「margin値」を計算して、中央配置をさせていました。
これは間違いではないのですが、最近のCSSを上手く使えば、この操作が不要に出来る事に気付きました。 いわゆるセンタリングのCSSテクニックです。
画像の枠(コンテナ)と、枠内の画像に、それぞれ次の指定をします。
「flex」指定は有難い機能で、コンテナや画像のサイズが変化しても、常に画像がコンテナの中央に配置されます。「margin」「padding」は何も指定しておらず、「text-align: center」の様な感覚で、使える便利な指定です。
今回は、このCSSを使って配置する様に改めました。
「Simple SVG」を利用するには
このツールは Chrome / Edge / Firefox版の拡張機能「Tampermonkey」上で動作します。 以下に、このツールの導入手順を簡単に説明します。
❶「Tampermonkey」を導入します
◎ 使用しているブラウザに拡張機能「Tampermonkey」を導入する事が必要です。
既に「Tampermonkey」を導入している場合は、この手順 ❶ は不要です。
拡張機能の導入については、以下のページに簡単な説明があるので参照ください。
❷「Tampermonkey」にスクリプトを登録します
◎「Tampermonkey」の「+」マークの「新規スクリプト」タブを開きます。
◎「新規スクリプト」には、最初からテンプレートが記入されています。 これは全て削除して、完全に空白の編集枠に 下のコードをコピー&ペーストします。
〔コピー方法〕 軽量シンプルなツール「PreBox Button 」を使うと
コード枠内を「Ctrl+左Click」➔「Copy code 」を「左Click」
の操作で、掲載コードのコピーが可能になります。
◎ 最後に「ファイル」メニューの「保存」を押すと、ツールが使用可能になります。
〔 Simple SVG 〕 ver. 1.1
// ==UserScript== // @name Simple SVG // @namespace http://tampermonkey.net/ // @version 1.1 // @description 任意のブラウザ画面でpathコードを簡略化 シヨートカット「F10」 // @author Ameba Blog User // @match https://*/* // @run-at document-start // @grant none // ==/UserScript== if(!location.hostname.includes('example.com')){ window.addEventListener('keydown', check_key); function check_key(event){ if(event.keyCode==121){ // ショートカット「F10」 event.preventDefault(); event.stopImmediatePropagation(); let win_apper='left=100, top=100, width=1024, height=800'; window.open('https://example.com/', null , win_apper); }}} if(location.hostname.includes('example.com')){ env(); main(); } function env(){ let head=document.head; if(head){ let lang='<meta http-equiv="Content-Language" content="ja">'; head.insertAdjacentHTML('beforeend', lang); let pre_style=head.querySelector('style'); if(pre_style){ pre_style.remove(); }} let pre_div=document.querySelector('body > div'); if(pre_div){ pre_div.remove(); }} function main(){ let style= 'body { background: #000; } '+ '#base_board { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; '+ 'z-index: 1; background: #000; } '+ '#base_board div { box-sizing: content-box; } '+ '#work_contena { position: fixed; top: 0; width: 100%; } '+ '#help { font: normal 16px Meiryo; padding: 4px 50px 0; height: 30px; '+ 'margin: 20px 0 30px; color: #fff; background: #5a7582; white-space: nowrap; } '+ '#help .help_svg { vertical-align: -9px; cursor: pointer; } '+ '#help .help_svg:hover { filter: brightness(1.5); } '+ '.fn { font: bold 16px/24px Meiryo; margin-right: 6px; padding: 0 4px; height: 24px; '+ 'border: 1px solid #fff; border-radius: 3px; color: #000; background: #a3e1ff; '+ 'outline: none; cursor: pointer; } '+ '.fn:hover { background: #def2fc; } '+ '.fn .nf { margin: 0 -2px 0 2px; font-size: 13px; vertical-align: 1px; opacity: 0.2; } '+ '.fn.f_0, .fn.f_8, .fn.f_10 { width: 44px; } '+ '#panel { display: flex; color: #fff; padding-left: 40px; } '+ '.p_count, .p_compress, .p_size, .p_attr, .p_stroke, .p_style { '+ 'font: normal 16px Meiryo; height: 24px; margin-right: 10px; '+ 'padding: 11px 0 10px 10px; border: 1px solid #8f9fa7; } '+ '.p_count { min-width: 178px; flex-shrink: 0; padding-right: 12px; } '+ '.p_compress { width: 244px; flex-shrink: 0; white-space: nowrap; } '+ '.p_size { width: 98px; flex-shrink: 0; } '+ '.p_attr { width: 96px; flex-shrink: 0; } '+ '.p_stroke { width: 118px; flex-shrink: 0; } '+ '.p_style { width: 106px; flex-shrink: 0; } '+ '.or_panel, .ne_panel { font: normal 16px Meiryo; '+ 'position: absolute; top: 172px; color: #fff; } '+ '.or_panel { left: 8vw; } '+ '.ne_panel { left: 52vw; white-space: nowrap; } '+ '.detail t { font: normal 10px Meiryo; } '+ '.detail tt { display: inline-block; width: 215px; font: normal 16px Meiryo; } '+ '.plus, .detail { position: absolute; } '+ '.fade_out { opacity: 0; transition: opacity .4s; } '+ '.fade_in { opacity: 1; transition: opacity .4s; } '+ '.or, .ne { position: absolute; top: 200px; width: 40vw; height: 40vw; '+ 'display: flex; justify-content: center; overflow: hidden; background: #fff; } '+ '.or { left: 8vw; } '+ '.ne { left: 52vw; } '+ '.or svg, .ne svg { align-self: center; } '+ '.file_input { display: none; }'; let help_SVG= '<svg height="28" width="28" viewBox="0 0 210 220">'+ '<path d="M89 22C71 25 54 33 41 46C7 81 11 142 50 171C58 177 68 182 78 '+ '185C90 188 103 189 115 187C126 185 137 181 146 175C155 169 163 162 169 '+ '153C190 123 189 80 166 52C147 30 118 18 89 22z" style="fill: #97d4f3;"></path>'+ '<path d="M67 77C73 75 78 72 84 70C94 66 114 67 109 83C106 91 98 95 93 '+ '101C86 109 83 116 83 126L111 126C112 114 122 108 129 100C137 90 141 76 '+ '135 64C127 45 101 45 84 48C80 49 71 50 68 54C67 56 67 59 67 61L67 77M'+ '85 143L85 166L110 166L110 143L85 143z" style="fill:#000;"></path>'+ '</svg>'; let control= '<div id="base_board">'+ '<div id="work_contena">'+ '<div id="help">'+ '<button class="f_0 fn">ESC</button>Simple SVG 終了 '+ '<button class="f_8 fn">F8</button>画像コードの表示 '+ '<button class="f_9 fn">F9<span class="nf">⚪</span></button>'+ 'SVG画像の拡大表示 '+ '<button class="f_10 fn">F10</button>SVG画像ファイルの読込み '+ '<a class="help_svg">'+ help_SVG +'</a></div>'+ '<div id="panel">'+ '<div class="p_count"> </div>'+ '<div class="p_compress">'+ '<button class="f_1 fn">F1<span class="nf">⚪</span></button>S '+ '<button class="f_2 fn">F2<span class="nf">⚪</span></button>M '+ '<button class="f_3 fn">F3<span class="nf">⚪</span></button>L '+ '</div>'+ '<div class="p_size">'+ '<button class="f_4 fn">F4<span class="nf">⚪</span></button>Size</div>'+ '<div class="p_attr">'+ '<button class="f_5 fn">F5<span class="nf">⚪</span></button>Attr</div>'+ '<div class="p_stroke">'+ '<button class="f_6 fn">F6<span class="nf">⚪</span></button>Stroke</div>'+ '<div class="p_style">'+ '<button class="f_7 fn">F7<span class="nf">⚪</span></button>Style</div>'+ '</div>'+ '<div class="or_panel">デフォルト画像</div>'+ '<div class="ne_panel">処理適用画像 '+ '<span class="plus"></span><span class="detail"></span></div>'+ '<div class="or source"></div>'+ '<div class="ne source"></div>'+ '<input class="file_input" type="file">'+ '</div><style>' + style +'</style></div>'; document.body.insertAdjacentHTML('beforeend', control); let withdraw=0; // キー入力の有効フラグ let output_open=0; // 出力画面の表示フラグ let end_open=0; // 終了画面の表示フラグ let mag_view=0; // 拡大参照のフラグ let size_mode=0; // width・height属性の有無 let attr_mode=0; // 一般の属性整理の有無 let stroke_mode=0; // strokeスタイル属性の有無 let style_mode=0; // 一般のスタイル属性削除の有無 let f_mode=0; // 四捨五入の処理形式 let dot2; // 💢 2dot連結のd値数 let dot3; // 💢 3dot連結のd値数 let row_count; // コード1行の文字数 row_count=sessionStorage.getItem('SSVG')*1; if(!row_count){ row_count=80; // 🔴🔴 ソースコード 1行文字数の初期値設定 sessionStorage.setItem('SSVG', row_count); } disp_reset(); disp_result_plus(); help_link(); catch_key(); catch_mouse(); function catch_key(){ window.addEventListener('keydown', check_key); function check_key(event){ if(event.keyCode==27){ // ショートカット「ESC」 func_seletor(0); } if(withdraw==0){ for(let k=1; k<11; k++){ if(event.keyCode==k+111){ // ショートカット「F1」~「F10」 event.preventDefault(); event.stopImmediatePropagation(); func_seletor(k); }}} }} // catch_key() function catch_mouse(){ for(let k=0; k<11; k++){ if(document.querySelector('button.f_'+k)){ document.querySelector('button.f_'+k).onclick=()=>{ func_seletor(k); }}} } // catch_mouse() function func_seletor(n){ switch (n){ case 0: esc(); break; case 1: f_1(); break; case 2: f_2(); break; case 3: f_3(); break; case 4: f_4(); break; case 5: f_5(); break; case 6: f_6(); break; case 7: f_7(); break; case 8: f_8(); break; case 9: f_9(); break; default: file_read(); } } // func_seletor() function esc(){ if(end_open==0){ end_open=1; end_work(); } else{ end_open=0; end_work(); }} function f_1(){ if(f_mode==1){ f_mode=4; } else{ f_mode=1; } svg_arrange(); disp_result(); count_c(); } function f_2(){ if(f_mode==2){ f_mode=4; } else{ f_mode=2; } svg_arrange(); disp_result(); count_c(); } function f_3(){ if(f_mode==3){ f_mode=4; } else{ f_mode=3; } svg_arrange(); disp_result(); count_c(); } function f_4(){ if(size_mode==0){ size_mode=1; if(f_mode==0){ f_mode=4; } svg_arrange(); disp_result(); disp_size_mode(); count_c(); } else{ size_mode=0; svg_arrange(); disp_size_mode(); count_c(); }} function f_5(){ if(attr_mode==0){ attr_mode=1; if(f_mode==0){ f_mode=4; } svg_arrange(); disp_result(); disp_attr_mode(); count_c(); } else{ attr_mode=0; svg_arrange(); disp_attr_mode(); count_c(); }} function f_6(){ if(stroke_mode==0){ stroke_mode=1; if(f_mode==0){ f_mode=4; } svg_arrange(); disp_result(); disp_stroke_mode(); count_c(); } else{ stroke_mode=0; svg_arrange(); disp_stroke_mode(); count_c(); }} function f_7(){ if(style_mode==0){ style_mode=1; if(f_mode==0){ f_mode=4; } svg_arrange(); disp_result(); disp_style_mode(); count_c(); } else{ style_mode=0; svg_arrange(); disp_style_mode(); count_c(); }} function f_8(){ if(output_open==0){ output_open=1; output_disp(); } else if(output_open==1){ output_open=2; output_disp(); } else{ output_open=0; output_disp(); }} function f_9(){ if(mag_view==0){ mag_view=1; disp_mag_mode(); mag_fit(); } else{ mag_view=0; disp_mag_mode(); mag_fit(); }} function mag_fit(){ if(mag_view==1){ let view_div=document.querySelector('.or'); let width_or=view_div.getBoundingClientRect().width; let style= '<style class="mag">.source svg { '+ 'width: '+ width_or +'px !important; height: auto !important; }</style>'; document.body.insertAdjacentHTML('beforeend', style); } else{ if(document.querySelector('.mag')){ document.querySelector('.mag').remove(); }} } // mag_fit() function set_svg(img){ let view_div=document.querySelector('.or'); if(view_div){ view_div.innerHTML=img; let svg_img=document.querySelector('.or svg'); viewbox_add(svg_img); } function viewbox_add(Svg){ // viewBox属性を追加 let viewbox=Svg.getAttribute("viewBox"); let width=Svg.getAttribute("width"); let height=Svg.getAttribute("height"); if(!viewbox && height && width){ let value='0 0 '+ width +' '+ height; Svg.setAttribute("viewBox", value); } // viewBox属性を追加 Svg.removeAttribute("x"); // x値属性を削除 Svg.removeAttribute("y"); } // x値属性を削除 } // set_svg() function file_read(){ disp_reset(); let svg_ne=document.querySelector('.ne svg'); if(svg_ne){ svg_ne.remove(); } // 前処理のsvgを削除 let p_count=document.querySelector('.p_count'); if(p_count){ p_count.textContent=' '; } // 前処理の文字数カウントをリセット let file_input=document.querySelector('.file_input'); if(file_input){ file_input.click(); file_input.addEventListener('change' , function(){ if(!(file_input.value)) return; // ファイルが選択されない場合 let file_list=file_input.files; if(!file_list) return; // ファイルリストが選択されない場合 let file=file_list[0]; if(!file) return; // ファイルが無い場合 if(file.name.split('.').pop()=='svg'){ // ファイル名の確認 let file_reader=new FileReader(); file_reader.readAsText(file); file_reader.onload=function(){ let data_in=file_reader.result; set_svg(data_in); }} else{ alert( "❌ 扱えるファイルではありません\n"+ " 扱えるファイルは「.svg」ファイルです"); }}); } } // file_read() function svg_arrange(){ dot2=0; // 💢 dot3=0; // 💢 let svg_or; let path_or; let svg_ne svg_or=document.querySelector('.or svg'); // 処理元のSVG let ne=document.querySelector('.ne'); if(!svg_or || !ne){ // 元画像が無い場合は 処理表示を抑止する f_mode=0; attr_mode=0; stroke_mode=0; style_mode=0; } else if(svg_or && ne){ // 元のSVG画像が無いと動作しない if(ne.querySelector('svg')){ ne.querySelector('svg').remove(); } svg_ne=svg_or.cloneNode(true); ne.appendChild(svg_ne); if(size_mode==1){ size_off(svg_ne); } // attr属性削除を実行 if(attr_mode==1){ beautify(svg_ne); } // attr属性削除を実行 if(stroke_mode==1){ stroke_off(svg_ne); } // stroke属性削除を実行 if(style_mode==1){ style_off(svg_ne); } // style属性削除を実行 path_or=svg_ne.querySelectorAll('path'); // 処理対象のSVGの全てのpath for(let k=0; k<path_or.length; k++){ let d_or=path_or[k].getAttribute("d"); path_or[k].setAttribute("d", path_trim(d_or)); } function path_trim(D_or){ // d属性の加工 let d_all=[]; if(select_type(D_or)){ d_all=D_or.split(','); } // カンマ区切りの処理 else{ d_all=D_or.split(' '); } // スペース区切りの処理 if(f_mode<5){ let temp_d; temp_d=d_all.join(' '); // 全てスペース区切りに戻す if(f_mode==4){ return temp_d; } // 数値処理なしで出力 else{ return arrange_i_code(temp_d); }} function select_type(DD_or){ let regex=/,/; return regex.test(DD_or); } // カンマ有り true / 無し false function arrange_i_code(Temp_d){ // path全体の処理 let c_count=0; // 数として処理した文字数 let i_code=[]; // 全pathを1文字ずつにした配列 let i_code_new=[]; // 処理後の数と文字を格納する配列 i_code=Temp_d.split(''); // pathの全体を文字1個ずつに分解 for(let k=0; k<i_code.length; k++){ if(i_code[k].match(/[A-Za-z]| |-/g)){ if(c_count==0){ i_code_new.push(i_code[k]); } else{ i_code_new.push(arr_i_code(c_count, k)); c_count=0; }} else{ // 数字または「.」の場合 c_count+=1; }} return i_code_new.join(''); // 処理後のpath function arr_i_code(Count, K){ let tmp=[]; let tmp_num; // 再構成した数値(小数を含む) let tmp_round; // 四捨五入した数値 for(let i=0; i<Count; i++){ tmp.push(i_code[K-Count+i]); } if(count_dot(tmp)<2){ //「.」が1個以内 if(count_dot(tmp)==1){ tmp_num=parseFloat(tmp.join('')); if(f_mode==2 || f_mode==3){ if(tmp_num>=10 && f_mode==2){ // 🌐 tmp_round=Math.round(tmp_num); } else{ tmp_round=(Math.round(tmp_num*10))/10; }} else{ tmp_round=Math.round(tmp_num); }} else if(count_dot(tmp)==0){ tmp_round=parseInt(tmp.join('')); } return tmp_round.toString()+i_code[K]; } else if(count_dot(tmp)==2){ //「.」が2個 dot2+=1; // 💢 let sub_count=0; let sub_tmp1=[]; let sub_tmp2=[]; let tmp_num1; let tmp_num2; let r_tmp_num2; for(let i=0; i<tmp.length; i++){ if(sub_count==0){ sub_tmp1.push(tmp[i]); if(tmp[i]=="."){ sub_count=1; }} else if(sub_count==1){ if(tmp[i]!="."){ sub_tmp1.push(tmp[i]); } if(tmp[i]=="."){ sub_count=2; sub_tmp2.push(tmp[i]); }} else{ sub_tmp2.push(tmp[i]); }} tmp_num1=parseFloat(sub_tmp1.join('')); tmp_num2=parseFloat(sub_tmp2.join('')); r_tmp_num2=(Math.round(tmp_num2*10))/10; if(f_mode==2 || f_mode==3){ if(r_tmp_num2<1 && r_tmp_num2!=0){ if(tmp_num1>=10 && f_mode==2){ // 🌐 return (Math.round(tmp_num1)).toString()+ ' '+r_tmp_num2.toString().slice(1)+ i_code[K]; } else{ return ((Math.round(tmp_num1*10))/10).toString()+ ' '+r_tmp_num2.toString().slice(1)+ i_code[K]; }} else if(r_tmp_num2==0){ if(tmp_num1>=10 && f_mode==2){ // 🌐 return (Math.round(tmp_num1)).toString()+ ' 0'+i_code[K]; } else{ return ((Math.round(tmp_num1*10))/10).toString()+ ' 0'+i_code[K]; }} else{ if(tmp_num1>10 && f_mode==2){ // 🌐 return (Math.round(tmp_num1)).toString()+ ' 1'+i_code[K]; } else{ return ((Math.round(tmp_num1*10))/10).toString()+ ' 1'+i_code[K]; }}} else{ if(r_tmp_num2<1 && r_tmp_num2!=0){ return (Math.round(tmp_num1)).toString()+ ' '+r_tmp_num2.toString().slice(1)+ i_code[K]; } else if(r_tmp_num2==0){ return (Math.round(tmp_num1)).toString()+ ' 0'+i_code[K]; } else{ return (Math.round(tmp_num1)).toString()+ ' 1'+i_code[K]; }}} // 桁上がりして1.0になる else{ //「.」が3個以上 dot3+=1; // 💢 return tmp.join('')+i_code[K]; } function count_dot(arr){ let count=0; arr.forEach(function(item){ if(item=='.'){ count+=1; }}); return count; } } // arr_i_code } // arrange_i_code() } // path_trim }} // svg_arrange() function size_off(Svg){ Svg.removeAttribute("width"); // width属性を削除 Svg.removeAttribute("height"); // height属性を削除 } // size_off() function beautify(Svg){ Svg.removeAttribute("xmlns"); // xmlns属性を削除 Svg.removeAttribute("xml:space"); // xml:space属性を削除 Svg.removeAttribute("xmlns:xlink"); // xmlns:xlink属性を削除 Svg.removeAttribute("version"); // version属性を削除 Svg.removeAttribute("id"); // version属性を削除 Svg.removeAttribute("class"); // version属性を削除 } // beautify() function stroke_off(Svg){ let path_or=Svg.querySelectorAll('path'); // 処理元のSVGの全てのpath for(let k=0; k<path_or.length; k++){ let style_or=path_or[k].getAttribute("style"); if(style_or){ path_or[k].style.stroke=''; }} } // stroke_off() function style_off(Svg){ Svg.removeAttribute("style"); // style属性を削除 } // style_off() function count_c(){ let svg1_c=0; let svg2_c=0; let svg_all=document.querySelectorAll('.source svg'); if(svg_all[0] && svg_all[1]){ // 画像が無い場合は動作しない svg1_c=svg_all[0].outerHTML.length; svg2_c=svg_all[1].outerHTML.length; let p_count=document.querySelector('.p_count'); if(p_count){ p_count.innerHTML='文字数 <b>'+svg1_c+'</b> ▷ <b>'+svg2_c+'</b>'; } output_open=0; // コード出力パネルを閉じる output_disp(); } } // count_c() function disp_size_mode(){ let p_size=document.querySelector('.p_size .nf'); if(p_size){ if(size_mode==1){ p_size.textContent='🔴'; p_size.style.opacity='1'; } else{ p_size.textContent='⚪'; p_size.style.opacity='.2'; }}} function disp_attr_mode(){ let p_attr=document.querySelector('.p_attr .nf'); if(p_attr){ if(attr_mode==1){ p_attr.textContent='🔴'; p_attr.style.opacity='1'; } else{ p_attr.textContent='⚪'; p_attr.style.opacity='.2'; }}} function disp_stroke_mode(){ let p_stroke=document.querySelector('.p_stroke .nf'); if(p_stroke){ if(stroke_mode==1){ p_stroke.textContent='🔴'; p_stroke.style.opacity='1'; } else{ p_stroke.textContent='⚪'; p_stroke.style.opacity='.2'; }}} function disp_style_mode(){ let p_style=document.querySelector('.p_style .nf'); if(p_style){ if(style_mode==1){ p_style.textContent='🔴'; p_style.style.opacity='1'; } else{ p_style.textContent='⚪'; p_style.style.opacity='.2'; }}} function disp_mag_mode(){ let p_mag=document.querySelector('.f_9 .nf'); if(p_mag){ if(mag_view==1){ p_mag.style.opacity='1'; } else{ p_mag.style.opacity='.2'; }}} function disp_result_plus(){ let plus=document.querySelector('.ne_panel .plus'); let detail=document.querySelector('.ne_panel .detail'); let compress=document.querySelector('.p_compress'); let size=document.querySelector('.p_size'); let attr=document.querySelector('.p_attr'); let stroke=document.querySelector('.p_stroke'); let style=document.querySelector('.p_style'); if(plus && detail){ fade_con(compress); fade_con(size); fade_con(attr); fade_con(stroke); fade_con(style); function fade_con(property){ if(property){ property.onmouseover=()=>{ plus.textContent=select(property); plus.classList.add('fade_in'); plus.classList.remove('fade_out'); detail.classList.add('fade_out'); detail.classList.remove('fade_in'); } property.onmouseleave=()=>{ plus.classList.add('fade_out'); plus.classList.remove('fade_in'); detail.classList.add('fade_in'); detail.classList.remove('fade_out'); }} function select(proper){ switch (proper){ case size: return 'width・height属性を削除'; break; case attr: return '不要な属性指定を削除'; break; case stroke: return 'Stroke の指定を削除'; break; case style: return 'インラインのStyle指定を削除'; break; default: return 'pathコード文字数の圧縮レベル'; }}} }} // disp_result_plus() function disp_result(){ let nf_comp=document.querySelectorAll('.p_compress .nf'); for(let k=0; k<nf_comp.length; k++){ if(f_mode==(k+1)){ nf_comp[k].textContent='🔴'; nf_comp[k].style.opacity='1'; } else{ nf_comp[k].textContent='⚪'; nf_comp[k].style.opacity='.2'; }} let detail=document.querySelector('.ne_panel .detail'); if(detail){ let mode_text; if(f_mode==0){ mode_text=' '; } if(f_mode==1){ mode_text='<tt>S:通常の四捨五入</tt>'+ '<t>Dot2 </t>'+dot2 +' <t>Dot3 </t>'+dot3; } else if(f_mode==2){ mode_text='<tt>M:10以下を小数第1位出力</tt>'+ '<t>Dot2 </t>'+dot2 +' <t>Dot3 </t>'+dot3; } else if(f_mode==3){ mode_text='<tt>L:全数を小数第1位出力</tt>'+ '<t>Dot2 </t>'+dot2 +' <t>Dot3 </t>'+dot3; } else if(f_mode==4){ mode_text='<tt>Default:圧縮処理なし</tt>'; } detail.innerHTML=mode_text; } } // disp_result() function disp_reset(){ size_mode=0; disp_size_mode(); attr_mode=0; disp_attr_mode(); stroke_mode=0; disp_stroke_mode(); style_mode=0; disp_style_mode(); mag_view=0; disp_mag_mode(); mag_fit(); f_mode=0; disp_result(); output_open=0; output_disp(); } // disp_reset() function help_link(){ let help_svg=document.querySelector('#help .help_svg'); if(help_svg){ let help_url='https://ameblo.jp/personwritep/entry-12794615989.html'; help_svg.setAttribute('href', help_url); help_svg.setAttribute('target', '_blank'); }} function output(Svg){ let svgString=Svg.outerHTML; let stack=[]; findText(svgString); // タグ記号で区切る for(let k=0; k<stack.length; k++){ // pathタグは入れ子にならないので纏める if(stack[k].startsWith('<path') && stack[k+1]=='</path>'){ stack[k] +='</path>'; stack[k+1]=''; }} stack=stack.filter(item=>{ return item!=''; }); for(let k=0; k<stack.length; k++){ // row_countの文字ずつの行に区切る stack[k]=break_words(stack[k]); } return stack.join('\n').slice(0, -1) +';'; // 繋いで末尾の「+」を「;」に変更 function findText(text){ for(let index=0; true;){ let s=text.indexOf('<', index); // index位置から検索 if(s==-1){ break; } // '<' を見つけたら後方の処理へ let e=text.indexOf('>', s +1); // 発見した位置より後方の'>'を検索 if(e==-1){ break; } // '>' を見つけたら後方の処理へ stack.push('<'+ text.substring(s +1, e) +'>'); // s e の位置を切出す index=e +1; } return stack; } function break_words(source_code){ let s_arr=[]; for (let i=0; i<source_code.length; i+=row_count){ // コード1行の文字数の指定 s_arr.push(source_code.slice(i, i+row_count)); } let new_s_arr=[]; for (let i=0; i<s_arr.length; i++){ let row="'"+ s_arr[i] +"'+"; new_s_arr.push(row); } return new_s_arr.join('\n'); } } // output() function outpanel_set(Svg){ if(output_open==1){ let row_n=document.querySelector('.row_n'); if(row_n){ row_n.value=row_count; row_n.onchange=function(){ edit_row(row_n.value*1); }} function edit_row(row_set){ if(19<row_set && row_set<201){ // 文字数は 20~ 200 row_count=row_set; sessionStorage.setItem('SSVG', row_count); let SSVG_pre=document.querySelector('.output_SSVG pre'); if(SSVG_pre){ SSVG_pre.textContent=output(Svg); }}} window.addEventListener('keydown', (event)=>{ // ⇧⇩キーで inputにフォーカス if(output_open==1){ if(event.keyCode==40 || event.keyCode==38){ let row_n=document.querySelector('.row_n'); if(row_n){ row_n.focus(); }}}}); } let out_copy=document.querySelector('.out_copy'); if(out_copy){ out_copy.onclick=function(){ if(output_open==1){ copyToClipboard(output(Svg)); } else if(output_open==2){ let str=Svg.outerHTML.replace(/\r?\n/g, ''); // 改行削除 copyToClipboard(str); }} function copyToClipboard(value){ if(navigator.clipboard){ // navigator.clipboardが使えるか判定する return navigator.clipboard.writeText(value).then(function(){ // コピー out_copy.style.boxShadow='inset 0 0 0 20px #2196f350'; out_copy.style.outline='2px solid #fff'; setTimeout(()=>{ out_copy.style.boxShadow=''; out_copy.style.outline=''; }, 1000); }); }}} } // outpanel_set() function output_disp(){ if(output_open==1){ let Svg=document.querySelector('.ne svg'); if(Svg){ let panel= '<div class="output_SSVG">'+ '<div class="out_control">'+ '<span>1行の文字数の指定: '+ '<input class="row_n" type="number" min="20" max="200"></span> '+ 'クリップボードに: <input class="out_copy" type="submit" value="Copy">'+ ' <input class="outpanel_close" type="submit" value="✖">'+ '</div>'+ '<pre></pre>'+ '<style>'+ '.output_SSVG { position: relative; top: 160px; margin: 0 auto;'+ 'font: normal 16px/20px Meiryo; width: fit-content; min-width: 600px; '+ 'background: #fff; border: 2px solid #2196f3; z-index: 4; } '+ '.output_SSVG .out_control { padding: 6px 0 5px; text-align: center; '+ 'border-top: 1px solid #333; border-bottom: 1px solid #333; '+ 'background: #c7e5fc; } '+ '.output_SSVG .out_control input { font: normal 16px/24px Meiryo; } '+ '.row_n { width: 45px; padding: 2px 4px 0 12px; vertical-align: -1px; } '+ '.outpanel_close { position: absolute; right: 25px; } '+ '.output_SSVG pre, .output_SSVG .code_div { '+ 'font: normal 16px/20px Meiryo; margin: 0; padding: 30px 20px 30px 30px; '+ 'max-height: calc(100vh - 340px); overflow-y: scroll; } '+ '.output_SSVG .code_div '+ '{ width: 720px; min-width: 600px; resize: horizontal; } '+ '</style></div>'; if(!document.querySelector('.output_SSVG')){ document.body.insertAdjacentHTML('beforeend', panel); } let SSVG_pre=document.querySelector('.output_SSVG pre'); if(SSVG_pre){ SSVG_pre.textContent=output(Svg); } outpanel_set(Svg); let outpanel_close=document.querySelector('.outpanel_close'); if(outpanel_close){ outpanel_close.onclick=()=>{ close_output(); output_open=0; }}}} else if(output_open==2){ let Svg=document.querySelector('.ne svg'); if(Svg){ let out_control_span=document.querySelector('.out_control span'); if(out_control_span){ out_control_span.textContent='改行のないSVGコードを出力'; } let SSVG=document.querySelector('.output_SSVG'); let SSVG_pre=SSVG.querySelector('pre'); if(SSVG_pre){ SSVG_pre.remove(); } if(SSVG){ let code_div='<div class="code_div"></div>'; SSVG.insertAdjacentHTML('beforeend', code_div); let SSVG_div=document.querySelector('.output_SSVG .code_div'); if(SSVG_div){ SSVG_div.textContent=Svg.outerHTML; } outpanel_set(Svg); let outpanel_close=document.querySelector('.outpanel_close'); if(outpanel_close){ outpanel_close.onclick=()=>{ close_output(); output_open=0; }}}}} else if(output_open==0){ close_output(); } } // output_disp() function close_output(){ if(document.querySelector('.output_SSVG')){ document.querySelector('.output_SSVG').remove(); }} function end_work(){ if(end_open==1){ let panel= '<div class="alert_SSVG">'+ '<p>このウインドウを閉じますが、「F10」の待受け機能は全ての画面</p>'+ '<p>で動作をし続けます。 SVG画像の処理を終了する場合は、必ず</p>'+ '<p>Tampermonkey のダッシュボードで Simple SVG を「OFF」</P>'+ '<p>にしてください。</p>'+ '<p class="alert_cont">'+ '<input class="close_win" type="submit" value="ウインドウを閉じる"> '+ '<input class="cancel_win" type="submit" value="キャンセル"></p>'+ '<style>.alert_SSVG { position: fixed; top: 160px; left: calc(50% - 380px); '+ 'font: bold 20px/20px Meiryo; z-index: 5; padding: 20px 30px; '+ 'color: #fff; background: #455A64; border: 4px solid #2196f3; } '+ '.alert_cont { text-align: right; padding-right: 50px; } '+ '.alert_SSVG input { font: normal 16px Meiryo; padding: 3px 6px 2px; } '+ '</style></div>'; if(!document.querySelector('.alert_SSVG')){ document.body.insertAdjacentHTML('beforeend', panel); } document.querySelector('.close_win').onclick=()=>{ window.close(); } document.querySelector('.cancel_win').onclick=()=>{ end_open=0; document.querySelector('.alert_SSVG').remove(); }} else if(end_open==0){ if(document.querySelector('.alert_SSVG')){ document.querySelector('.alert_SSVG').remove(); }} } // end_work() } // main()
「Simple SVG」最新版について
旧いバージョンの JavaScriptツールは、アメーバのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。
●「Simple SVG」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。