POPSブログ

SVG.js foreignObject

385

  Category:  javascript2016/03/17 pops 

SVG.js foreignObjectについて調べてみます。一部当方独自の方法をも取りますが、一応正常に可動します。何も知らない者が「SVG」を触るのですから大変無謀なことです。

 

SVG.js foreignObjectのテスト

 

ご注意、Chrome.Firefox.IE11(一部機能しません)などSVGに対応したブラウザでご覧ください。Chromeを推奨します。
このページのJSは「IE11」では実行出来ません。

 

SVG.js 使用の基本的な説明


基本的な説明下記ページ参照ください。
【参照】当方の記事: SVG.js を使用してsvgコンテンツを作り表示します

このページとデモページにサンプルと共にJSを記載しています。余り説明などしていませんので、感覚的に違いなど理解ください。
Chrome.Firefox.IE11で確認しながら進めますが、その他のブラウザは未確認です。

 

SVG.jsのDropShadowはエラーで機能しません。カスタムDropShadowは独自のもので、4個をdropshadow-custom.jsで設定している。

【参照】当方の記事: SVG.js DropShadowの自作とBlur


 

SVG.js foreignObject


外部型オブジェクトの埋込みを<foreignObject>で行えますが、具体的には「svg」に「html」を埋め込むことにより、折り返しの出来る文字列(文章)を記述できます。ブラウザが描画できるものならば基本的に埋め込み可能な訳です。
SVG.jsでは原則プラグインsvg.foreignobject.jsが必要になりますが、プラグイン無しでも記述できます。

プラグインは次より取得できます、「svg.foreignobject.js


1. プラグインを利用して「html」を埋め込む。
2. foreignObject処理をプラグインを利用せず記述する。
3. svg()を利用して処理する。
4. 「IE11」はforeignObjectに対応していません。
(新しいWebブラウザ「Microsoft Edge」は当方では不明です)


SVG.js foreignObjectプラグイン書式

 

● SVG.js foreignObjectプラグイン書式には次の様に書かれていますが、これには問題があります。
innerTextでは、Firefoxは文字列をappendChild()出来ません。
innerHTMLならばappendChild()出来ますが「追加」では無く全て書き換えになります。

下記サンプルは、Firefoxで何も表示しません。「div」の中は「空っぽ」です。Firefox以外は問題有りません。


マニュアルの記述
var canvas=SVG('canvas').size(1024,550)
var fobj=canvas.foreignObject(100,100).attr({id:'fobj'})
var txt="some text that is quite long.  and it goes on and on. and it's pointless really. and the grammar is terrible. blah. blah. blah"
fobj.appendChild("div",{id:'mydiv',innerText:txt})

つまり、次の構造を作れば良い。(方法は問わない、正しければ表示します、アタリマエ)


<foreignObject>
	<div>PaPiPuPePo</div>
</foreignObject>

● Firefox対策としてinnerTextをinnerHTMLに変更して使います。(下記サンプル2番参照)


fobj.appendChild("div",{id:'mydiv',innerHTML:txt})

● HTMLですからCSSで処理できます。下記サンプルでは foreign-div-elm クラスを与えています。


/*foreignobject*/
.foreign-div-elm{
width:auto;
padding:2px;
font-size:12px;
color:#0000FF;
text-shadow: 1px 1px 2px #000;
}

プラグインを使用する方法

1番、innerText処理Firefox NG / 2番、innerHTML処理Firefox OK / 3番、innerHTML処理Firefox OK



1番、Firefoxで実行の状態は下記の様になる。つまり文字は表示しない。


<foreignObject y="70" x="0" height="100" width="160" id="fobj"><div id="mydiv"></div></foreignObject>

サンプルJS


	//対象エレメントID
	var draw=SVG('foreignobject-1a').size(160,160)

	var txt=draw.text('1 プラグイン Firefox NG').font({leading:0.8})

	//SVG文字
	var svg_text=draw.text('POPS').attr({'fill':'#FF0000'}).move(80,20)
	.font({
		family:'Arial'
		,size:50
		,'font-weight':'bold'
		,anchor:'middle'
		,leading:1
	})
	svg_text.attr({'filter':'url(#dropShadow2)'})

	//foreignObject
	var fobj=draw.foreignObject(160,100).attr({id:'fobj'})
	fobj.move(0,70)
	//Firefox/appendChild()が機能しないdiv生成するがテキストが入りません
	var div_text="SVGのテキストは1行のみの段落で折り返しができません。但し、foreignObjectを利用すると通常のHTMLテキストですので自動的に折り返します。(CSS調整)"
	fobj.appendChild('div',{id:'mydiv',innerText:div_text})

	//-------------

	//対象エレメントID
	var draw=SVG('foreignobject-1b').size(160,160)

	var txt=draw.text('2 プラグイン Firefox OK').font({leading:0.8})

	//SVG文字
	var svg_text=draw.text('POPS').attr({'fill':'#FF69B4'}).move(80,20)
	.font({
		family:'Arial'
		,size:50
		,'font-weight':'bold'
		,anchor:'middle'
		,leading:1
	})
	svg_text.attr({'filter':'url(#dropShadow2)'})

	//foreignObject
	var fobj2=draw.foreignObject(160,100).attr({id:'fobj2'})
	fobj2.move(0,70)

	//innerHTMLはFirefox OK
	var div_text2="SVGのテキストは1行のみの段落で折り返しができません。但し、foreignObjectを利用すると通常のHTMLテキストですので自動的に折り返します。(CSS調整)"
	//OK
	fobj2.appendChild('div',{id:'mydiv2',innerHTML:div_text2})
	//OK
	fobj2.getChild(0).setAttribute('class','foreign-div-elm')

	//-------------

	//対象エレメントID
	var draw=SVG('foreignobject-1c').size(160,160)

	var txt=draw.text('3 プラグイン Firefox OK').font({leading:0.8})

	//SVG文字
	var svg_text=draw.text('POPS').attr({'fill':'#DB7093'}).move(80,20)
	.font({
		family:'Arial'
		,size:50
		,'font-weight':'bold'
		,anchor:'middle'
		,leading:1
	})
	svg_text.attr({'filter':'url(#dropShadow2)'})

	//foreignObject文字/ChromeのみOK
	var fobj3=draw.foreignObject(160,100).attr({id:'fobj3'})
	fobj3.move(0,70)

	//Firefox OK
	//div生成
	var divelm=document.createElement('div')
	divelm.id='mydiv3'
	divelm.setAttribute('class','foreign-div-elm')
	//TEXT
	divelm.innerHTML='SVGのテキストは1行のみの段落で折り返しができません。但し、foreignObjectを利用すると通常のHTMLテキストですので自動的に折り返します。(CSS調整)'
	//append中にいれる
	fobj3.appendChild(divelm)


プラグインを使用しない方法

SVG.jsでforeignObjectエレメントを作り、中に「div」を入れてやれば良い訳ですが、SVG.jsインスタンスと違いadd()が出来ませんので、appendChild()で処理します。この辺の処理方法は自由です。
「div」さえ中にあれば、後はどんなHTML要素も入れることが可能です。


1.「svg」エレメントはcreateElementNS()で作ります。こちらが簡単です。
(SVG.jsでは element()メソッドで作れます、IDは自動で生成されます)
2.「html」エレメントはcreateElement()で作ります。
(SVG.jsでは作れませんので、javascriptで作ります、createElementNS()で作れば異常な振る舞いをします)
3. svg()メソッドを利用する。(埋め込み内容、場合によっては簡単)


element()メソッドはcreateElementNS処理です。「div」も作れますがこれでは「マズイ」訳です。


foreignObjectエレメントを作り処理する

SVG.jsでforeignObjectエレメントを作り、中に「div」を入れる


foreignObjectエレメントをつくる
var fobj_element=draw.element('foreignObject')
idを取得します
var fobj_id=fobj_element.attr('id')

基本的に大きさ位置設定が必要です
fobj_element.attr({'width':400,'height':100,'x':50,'y':100})

-------------------------------------------

divエレメント生成、ID、クラスを設定します
var div_ement=document.createElement('div')
div_ement.id='foreign-div'
div_ement.setAttribute('class','foreign-div-elm')

-------------------------------------------

divエレメントは自己で生成しているのでjQuey等で利用できる
$('#foreign-div')....

svg()メソッドで処理する

svg()にforeignObjectなど直接入れることが出来ます。問題がある場合は別途グループでラップすれば解決する場合が多い。
サンプル3番参照ください。


svg(<g>foreignObject処理の記述</g>)
つまり
インスタンス=draw.svg(<g><foreignObject><div>......</div></foreignObject></g>)

別途グループでラップ
var group=draw.group()
インスタンス=group.svg(<g><foreignObject><div>......</div></foreignObject></g>)

dropShadow処理

● dropShadow処理

dropShadow処理はDIV要素であることから、CSSで処理していますが、グループでラップしてグループにSVGのdropShadowを処理できます。foreignObjectには処理しないでください。


グループ.attr({'filter':'url(#dropShadow2)'})

● svg()のdropShadow処理

サンプル3番のsvg()形式で、下記の様にdropShadow処理すると、ステージ全てにdropShadowがかかる「摩訶不思議」現象が発生します。こんな場合は別途グループでラップします。


サンプル3番
var foreign_svg=draw.svg('<g><foreignObject id="fobj4"><div id="mydiv4">houhokekyo</div></foreignObject></g>')
foreign_svg.attr({'filter':'url(#dropShadow3)'})

-------------------------------------------

//回避策グループ化する
var group_svg=draw.group()
var foreign_svg=group_svg.svg(略す)
//dropShadow処理OK
group_svg.attr({'filter':'url(#dropShadow3)'})

以上の様にエレメントを作り、組み合わせますと、サンプル1番の様になります。
divエレメントのIDは自動生成されたものでは有りませんので、jQueryなどでの操作も可能かと思います。

プラグインを使用しない方法の方が細やかな処理ができると思います。


1番、foreignObjectエレメントを作る / 2番、foreignObjectエレメントを作る / 3番、svgで直接埋め込む

2番、一度文章を入れ、再度入れ直ししています。ドラッグ可能です。文字以外の表示が可能である証明。



サンプルJS


	//対象エレメントID
	var draw=SVG('foreignobject-2a').size(160,160)

	var txt=draw.text('1 foreignObject Firefox OK').font({leading:0.8})

	//SVG文字
	var svg_text=draw.text('POPS').attr({'fill':'#6496ED'}).move(80,20)
	.font({
		family:'Arial'
		,size:50
		,'font-weight':'bold'
		,anchor:'middle'
		,leading:1
	})
	svg_text.attr({'filter':'url(#dropShadow2)'})

	//Firefox OK
	var group=draw.group()
	//svg.js element
	var foreignObject=group.element('foreignObject')
	foreignObject.attr({'width':160,'height':100,'x':0,'y':70})
	//id取得
	var id_name=foreignObject.attr('id')
	//javascript
	var foreign=document.getElementById(id_name)
	//div生成
	var div_elm=document.createElement('div')
	div_elm.id='foreign-div'
	div_elm.setAttribute('class','foreign-div-elm')
	//TEXT
	div_elm.innerHTML='SVGのテキストは1行のみの段落で折り返しができません。但し、foreignObjectを利用すると通常のHTMLテキストですので自動的に折り返します。(CSS調整)'
	//append中にいれる
	foreign.appendChild(div_elm)

	//-------------

	//対象エレメントID
	var draw=SVG('foreignobject-2b').size(160,160)

	var txt=draw.text('2 foreignObject Firefox OK').font({leading:0.8})

	//SVG文字
	var svg_text=draw.text('POPS').attr({'fill':'#48D1CC'}).move(80,20)
	.font({
		family:'Arial'
		,size:50
		,'font-weight':'bold'
		,anchor:'middle'
		,leading:1
	})
	svg_text.attr({'filter':'url(#dropShadow2)'})

	//Firefox OK
	var group=draw.group()
	//svg.js element
	var foreignObject2=group.element('foreignObject')
	foreignObject2.attr({'width':160,'height':100,'x':0,'y':70})
	//id取得
	var id_name2=foreignObject2.attr('id')
	//javascript/foreign-obj2
	var foreign2=document.getElementById(id_name2)
	//div生成
	var div_elm2=document.createElement('div')
	div_elm2.id='foreign-div'
	div_elm2.setAttribute('class','foreign-div-elm')
	//TEXT1
	div_elm2.innerHTML='SVGのテキスト'
	//append中にいれる
	foreign2.appendChild(div_elm2)

	//2回目
	div_elm2.innerHTML='SVGのテキストSVGのテキストSVGのテキスト<br /><button class="button2" type="submit">Button</button>'
	foreign2.appendChild(div_elm2)

	//drag
	group.draggable().style('cursor','move')

	//-------------

	//対象エレメントID
	var draw=SVG('foreignobject-2c').size(160,160)

	var txt=draw.text('3 svg()処理 ALL OK').font({leading:0.8})

	//SVG文字
	var svg_text=draw.text('POPS').attr({'fill':'#00FF7F'}).move(80,20)
	.font({
		family:'Arial'
		,size:50
		,'font-weight':'bold'
		,anchor:'middle'
		,leading:1
	})
	svg_text.attr({'filter':'url(#dropShadow2)'})

	//svg()処理foreignObject文字/Firefox OK/IDはテキトウ
	var foreign_svg=draw.svg('<g><foreignObject id="fobj4" width="160" height="100" x="0" y="70"><div id="mydiv4" class="foreign-div-elm">SVGのテキストは1行のみの段落ですから折り返しができません。但し、foreignObjectを利用すると通常のテキストですので自動的に折り返します。(CSS調整)</div></foreignObject></g>')
	//書き換えOK
	//$('#mydiv4').html('SVGのテキスト<br /><button class="button2" type="submit">Button</button>')


グループ化する

単に表示する場合は問題有りませんが、後でアニメーション等の操作が必要な時は、グループ化すればアニメーションなどの処理が楽になります(回転の場合は少し問題あり)。下記にそのサンプルを掲示します。


「黄色」、フエード out/in / 「青色」、スライド / 「赤色」、回転 on/off


回転させた場合に多少アニメが狂う影響があるようです。グループも範囲位置などで調整が必要となりますが、余り複雑なアニメは困難かも知れません。この辺は自己解決ください。(上のテストで「回転」を与えて「スライド」すると判る)
ここでの文字のグラデーションCSSはwebkitのみです。


サンプルJS/CSS


	//対象エレメントID
	var draw=SVG('foreignobject-3a').size(500,200)

	var image=draw.image('/main/images/flower103.jpg').move(0,0)
	var rect=draw.rect(400,200).radius(20).attr({'fill':'#FFFFFF','fill-opacity':0.5}).center(250,150).rotate(-30)

	//SVG文字
	var svg_text=draw.text('POPS WEB KOUBOU').attr({'fill':'#FFD700'}).move(50,30)
	.font({
		family:'Arial'
		,size:40
		,'font-weight':'bold'
		,anchor:'left'
		,leading:1
	})
	svg_text.attr({'filter':'url(#dropShadow2)'})

	//Firefox OK
	var group3=draw.group().x(0).y(0)
	group3.rect(0,0,500,200)//範囲
	//svg.js element
	var foreignObject3=group3.element('foreignObject')
	foreignObject3.attr({'width':400,'height':100,'x':50,'y':100})
	//id取得
	var id_name3=foreignObject3.attr('id')
	//javascript
	var foreign3=document.getElementById(id_name3)
	//div生成
	var div_elm3=document.createElement('div')
	div_elm3.id='foreign-div3'
	div_elm3.setAttribute('class','foreign-gradient')
	//TEXT
	div_elm3.innerHTML='SVGのテキストは1行のみの段落で折り返しができません。但し、foreignObjectを利用すると通常のHTMLテキストですので自動的に折り返します。テキストグラデーションはブラウザにより処理されない場合があります。<br>foreignObject部分はグループ化しておけば制御に何かと便利になります。<br>DIV部分はCSSで調整が可能となります。'
	//append中にいれる
	foreign3.appendChild(div_elm3)

	//group3.rotate(15)
	group3.attr({'filter':'url(#dropShadow3)'})

	//ボタン
	var hit_btn=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(480,10)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	hit_btn.click(function() {
		group3.toggleClass('rotate-on')
		if(group3.hasClass('rotate-on')) {
			group3.rotate(-15)
		}else{
			group3.rotate(0)
		}
	})

	//ボタン
	var hit_btn2=draw.circle(10).attr({'fill':'#0000FF','stroke':'#FFF','stroke-width':2}).center(460,10)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	hit_btn2.click(function() {
		group3.animate(100).x(0).y(300).after(function(){
			this.animate(1000).x(0).y(0)
		})

	})

	//ボタン
	var hit_btn3=draw.circle(10).attr({'fill':'#FFD700','stroke':'#FFF','stroke-width':2}).center(440,10)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	//CLICK-ACTION
	hit_btn3.click(function() {
		group3.toggleClass('fade-on')
		if(group3.hasClass('fade-on')) {
			group3.animate(1000).opacity(0)
		}else{
			group3.animate(1000).opacity(1)
		}
	})

	var txt=draw.text('透明度、スライド、角度変更テスト').font({size:10,leading:0.8}).attr({'fill':'#EEEEEE'}).move(280,5)

-------------------------------------

.foreign-gradient{
padding:2px;
font-size:12px;
color:#f00;
background: -webkit-linear-gradient(#f00,#ff0,#0f0);
-webkit-background-clip:text;
-webkit-text-fill-color:transparent;
}

 

サンプルJSの全表示

Chromeは文字化けしますのでエンコード(UTF-8)してご覧ください。

● サンプルJSの全表示1(解説ページ用) svg-sample12.js

使用画像

画像は原則使用者が用意ください。デモなどで使用した画像は下記に有ります。

使用画像サンプル

 


 

dropshadowは当方自作の dropshadow-custom.js を使用します。
なおこのページはjQuery1.6.4のため dropshadow-custom-ie.js に成ります。

DropShadowと基本的なことは下記記事を参照ください。

【参照】当方の記事: SVG.js を使用してsvgコンテンツを作り表示します

【参照】当方の記事: SVG.js DropShadowの自作とBlur


以上。

 


[ この記事のURL ]


タグ:javascript , SVG

 

ブログ記事一覧



[1]