...
http://www.h2.dion.ne.jp/~defghi/svgMemo/svgMemo_03.htm
SVG to Canvas to PNG
SVGをCanvasに変換描画、さらにCanvasからPNGに変換
図形・模様・文様・幾何学模様のタイル背景画像素材生成
画像をダブルクリックで背景画像のレビュー可能
Paths
線を描く操作を表す.大文字は絶対位置指定,小文字は現在位置からの相対位置指定に対応する. M,m 初期位置,位置のスキップ. L,l 直線を引く H,h 水平線を引く V,v 垂直線を引く C,c,S,s,Q,q,T,t 曲線を引く.端点と制御点とで曲線を指定する. A,a 円弧を引く Z,z 直近のM位置まで直線を引いて線を閉じる.なお,座標を重ねただけでは線が閉じられた事にはならない. B,b x軸の方向を設定する(他のコマンドによる描画に影響を及ぼす)† R,r Catmull-Romスプライン曲線を引く†
view source
JavaScript
$(function(){
var e = {};
var i = 0;
e.lis = $('#SVGs li');
/*
each内で全部toDataURLすると時間かかるため、
クリック(必要時)だけ生成する方法もある
*/
//色変更のフォーム
e.svgs = e.lis.find('svg');
e.paths =e.svgs.find('*');
e.paths_fill =e.paths.filter('[fill]');
e.paths_stroke = e.paths.filter('[stroke]');
var clickReset = function(){
e.lis.removeClass('clicked');
e.lis.find('.dl').remove();
e.lis.find('canvas').remove();
}
$('#fill').on('change', function(){
var val = $(this).val();
e.paths.css({fill:val});
clickReset();
});
$('#stroke').on('change', function(){
var val = $(this).val();
e.paths_stroke.css({stroke:val});
clickReset();
});
$('#zoom').on('change', function(){
var val = $(this).val();
e.svgs.attr({zoom:val});
clickReset();
});
$('#background').on('change', function(){
//なぜかjQueryのままだと新規タグを挿入できない
var val = $(this).val();
var ns = 'http://www.w3.org/2000/svg';
var ele = document.createElementNS(ns, 'svg:rect');
var $e = $(ele);
$e.attr({
x:-1000,
y:-1000,
width:2000,
height:2000,
fill:val,
class:'background',
});
e.svgs.each(function(){
var svg = $(this);
var eleC = $e.clone()[0];
svg.find('.background').remove();
var svg = $(this);
svg.prepend(eleC);
});
clickReset();
});
$('#transform').on('change', function(){
//なぜかjQueryのままだと新規タグを挿入できない
var val = $(this).val();
var ns = 'http://www.w3.org/2000/svg';
var ele = document.createElementNS(ns, 'svg:g');
var $e = $(ele);
$e.attr({
transform:val,
class:'transform',
});
console.log($e);
e.svgs.each(function(){
var svg = $(this);
var eleC = $e.clone()[0];
var g = svg.find('.transform');
if(g.length){
svg.html(g.html());
}
var svg = $(this);
svg.wrapInner(eleC);
});
clickReset();
});
e.svgs.on('dblclick', function(){
$('#svgSource').val($(this)[0].outerHTML);
});
e.lis.on('click', function(){
e.li = $(this);
if(e.li.hasClass('clicked')){return;}
e.li.addClass('clicked');
i++;
// SVG要素取得+生成
e.svg = e.li.find('svg'); //$('#svg');
var html = e.svg[0].outerHTML;
var canvasId = 'c'+i;
var canvas = $('<canvas>').attr({'id': canvasId}).appendTo(e.li)[0];
var pos = getViewBoxPos(html);
canvas.setAttribute('width', pos.w);
canvas.setAttribute('height', pos.h);
canvg(canvasId, pos.html);
e.a = $('<a>').addClass('dl').text('DL').appendTo(e.li).click(function(){$(this).remove();});
toPng(canvas, e.a);
//var data = e.canvas[0].toDataURL('image/png');
//e.canvas.remove();
});
e.lis.find('svg').on('click', function(){
var canvas = $(this).siblings('canvas')[0];
if(canvas){
var url = $(this).siblings('canvas')[0].toDataURL();
$('body').css({backgroundImage: 'url('+url+')'});
}
});
//画像変換
function toPng(canvas, a){
var url;// = canvas.toDataURL();
if($('#pngEncoder').prop('checked')){
//圧縮 canvastool.pngencoder.min.js
var encoder = new CanvasTool.PngEncoder(
canvas,
{
bitDepth: 8,
colourType: CanvasTool.PngEncoder.ColourType.INDEXED_COLOR
}
);
var png = encoder.convert();
url = 'data:image/png;base64,' + window.btoa(png);
} else {
url = canvas.toDataURL();
}
var link = url.replace('image/png', 'application/octet-stream');
var parent = a.parent();
var title = parent.find('svg').attr('id');
var h4 = parent.find('h4').text();
if(!title){title = h4;}
var size = canvas.width + 'x' + canvas.height;
var download = 'svg-'+title+'-'+size+'.png';
a.attr({href:link, download:download, title:download });
}
(function(){
// テキスト編集と同時に描画確認
var e = {};
e.Editor = $('#Editor');
e.svgArea = $('#svgArea');
e.textarea = $('#textarea');
console.log(e.textarea.val());
// textareaの内容をSVGエリアに描画
e.svgArea.html(e.textarea.val());
e.textarea.on('keyup',function(){
e.svgArea.html($(this).val());
});
$('#reload').on('click',function(){
$('iframe')[0].contentDocument.location.reload(true);
});
//背景確認
var canvasId = 'EditorCanvas';
$('#toPng').on('click', function(e){
var canvas = document.getElementById(canvasId);
var html = $('#svgArea svg')[0].outerHTML;
var pos = getViewBoxPos(html);
canvas.setAttribute('width', pos.w);
canvas.setAttribute('height', pos.h);
canvg(canvasId, pos.html);
var url = document.getElementById(canvasId).toDataURL();
$('#checkBG').css({backgroundImage: 'url('+url+')'});
$('#checkIMG').attr({src:url});
});
$('#isGrid').on('change',function(){
var isGrid = $(this).prop('checked');
if(isGrid){
$('#grid').show();
}else {
$('#grid').hide();
}
});
//座標確認
/*
var spanXY = $('#xy');
e.svgArea.on('mousemove', function(ev){
var x = ev.pageX - e.svgArea.position().left;
var y = ev.pageY - e.svgArea.position().top;
spanXY.text(x+':'+y);
});
*/
//要素確認
var spanElement = $('#svgSource');
e.svgArea.on('click', 'svg *', function(ev){
console.log($(this)[0]);
console.log($(this)[0].toString());
console.log($(this)[0].outerHTML);
//$(this)[0].nodeName
spanElement.val($(this)[0].outerHTML);
});
//無駄記述を消す
$('#delXMLNS').on('click', function(){
var val = e.textarea.val();
val = val.replace(/ xmlns:xlink="http:\/\/www.w3.org\/1999\/xlink"/img, '');
val = val.replace(/><\/([^>]*)>/img, ' />');
e.textarea.val(val);
});
//枠を追加
$('#addFrame').on('click', function(){
var val = e.textarea.val();
var pos = getViewBoxPos(val);
var rectTag = ' <rect x="0" y="0" ' +
'width="'+pos.w+'" height="'+pos.h+'"' +
' fill="none" stroke="rgba(200,0,0,.2)" />\n';
var rectTag2 = ' <rect x="'+x+'" y="'+y+'" ' +
'width="'+pos.w+'" height="'+pos.h+'"' +
' fill="none" stroke="rgba(0,0,200,.4)" />\n';
val = val.replace('</svg>', rectTag +rectTag2 + '</svg>');
e.textarea.val(val);
});
})();
//canvasの大きさをviewBoxに合わせ、倍率調整する
var getViewBoxPos = function(html){
var pos ={};
var matchViewBox;
var matchZoom;
var reViewBox = new RegExp('viewBox="([\-0-9]*) ([\-0-9]*) ([0-9]*) ([0-9]*)"', 'img');
var reZoom = new RegExp('zoom="([\-\.0-9]*)"', 'img');
matchViewBox = html.match(reViewBox);
//console.log(matchViewBox);
pos.zoom = 1;
pos.x = RegExp.$1 || 100;
pos.y = RegExp.$2 || 100;
pos.w = RegExp.$3 || 100;
pos.h = RegExp.$4 || 100;
matchZoom = html.match(reZoom);
if(matchZoom){
pos.zoom = RegExp.$1;
}
pos.x = pos.x * pos.zoom;
pos.y = pos.y * pos.zoom;
pos.w = pos.w * pos.zoom;
pos.h = pos.h * pos.zoom;
pos.html = html;
pos.html = pos.html.replace(/(<svg [^>]*>)/, '$1<g transfrom="scale('+pos.zoom+')">');
pos.html = pos.html.replace(/(<\/svg>)/, '</g>$1');
return pos;
}
});
// textarea tab indent
var el = document.getElementById('textarea');
tabIndent.render(el);
tabIndent.config.tab = ' ';
CSS
nav{
position:fixed;
left:0;
top:0;
height:40px;
background-color:#ffffff;
}
nav li,
nav a{
display:inline-block;
width:120px;
height:40px;
line-height:40px;
text-align:center;
color:#333333;
text-decoration:none;
}
nav a:hover{
background-color:#eeeeee;
}
#demo section{
padding-top:40px;
min-height:800px;
}
input{
width:120px;
}
input[type="checkbox"]{
width:20px;
}
#custom{
position:fixed;
right:0;
top:0;
z-index:2;
width:100%;
height:120px;
background-color:rgba(0,0,0,.5);
color:#FFFFFF;
font-size:12px;
font-family:monospace;
}
#custom span{
display:inline-block;
width:80px;
height:24px;
}
#custom input{
height:24px;
}
#custom textarea{
position:absolute;
right:0;
top:0;
width:480px;
height:120px;
}
#SVGs{
width:1020px;
padding-top:240px;
padding-bottom:720px;
-webkit-user-select:none;
}
#SVGs:after{
display:block;
content:"";
clear:both;
}
#SVGs li{
width:100px;
height:160px;
float:left;
line-height:16px;
border:1px solid #555555;
}
#SVGs svg{
width:100px;
height:100px;
background-color:#aaaaaa;
}
#SVGs canvas{
display:none;
}
#SVGs h4{
padding:2px auto;
height:36px;
font-size:10px;
font-weight:bold;
word-wrap:nowrap;
background-color:#ffffff;
}
#SVGs a{
display:inline-block;
margin:1px 4px;
padding:1px 4px;
background-color:#ffffff;
border:1px solid #aaaaaa;
border-radius:4px;
text-decoration:none;
cursor:pointer;
}
#SVGs a:hover{
background-color:#aaccff;
}
#SVGs a.clicked{
background-color:#aaaaaa;
}
.svg{
width:100px;
height:100px;
border:1px solid #ff0000;
}
#Editor{
position:relative;
left:0;
top:0;
border:1px solid #aaaaaa;
display:flex;
}
#Editor *{
box-sizing:border-box;
}
#Editor > div{
}
#textareaFrame{
width:calc(100% - 400px);
}
#Editor textarea{
z-index:99;
display:block;
width:100%;
min-height:200px;
font-size:12px;
font-family:monospace;
}
#Editor textarea:hover{
}
#textarea{
height:400px;
}
#svgFrame{
position:relative;
left:0;
top:0;
width:400px;
border:1px dotted #aaaaaa;
}
#svgArea{
width:400px;
height:400px;
}
#svgArea img,
#svgArea svg{
position:absolute;
left:0;
top:0;
width:400px;
height:400px;
}
#grid{
position:absolute;
left:0;
top:0;
width:400px;
height:400px;
}
#svgArea svg *:hover{
opacity: 0.5;
background-color:#ff0000;
}
#Editor #checkBG{
width:400px;
}
#Editor canvas{
display:none;
}
#viewArea{
width:400px;
height:600px;
background-image: url(../svg-icon/bg-alpha.svg);
}
#checkBG{
height:400px;
}
#checkIMG{
max-width:400px;
max-height:400px;
}
#samples{
width:1200px;
height:720px;
}
HTML
ページのソースを表示 : Ctrl+U , DevTools : F12
view-source:https://hi0a.com/demo/-svg/svg-to-canvas-to-png/
ABOUT
hi0a.com 「ひまアプリ」は無料で遊べるミニゲームや便利ツールを公開しています。
プログラミング言語の動作デモやWEBデザイン、ソースコード、フロントエンド等の開発者のための技術を公開しています。
必要な機能の関数をコピペ利用したり勉強に活用できます。
プログラムの動作サンプル結果は画面上部に出力表示されています。
環境:最新のブラウザ GoogleChrome / Windows / Android / iPhone 等の端末で動作確認しています。
画像素材や音素材は半分自作でフリー素材配布サイトも利用しています。LINK参照。
動く便利なものが好きなだけで技術自体に興味はないのでコードは汚いです。
途中放置や実験状態、仕様変更、API廃止等で動かないページもあります。