POPSブログ

SVG.js Groupについて

376

  Category:  javascript2016/01/27 pops 

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

 

SVG.js Groupについてのテスト


ご注意、Chrome.Firefox.IE11(一部機能しません)などSVGに対応したブラウザでご覧ください。Chromeを推奨します。

 

DEMO その他の「デモ」など

● デモページは [ jqury-1.9 ] で動作しています。


Chromeでの閲覧を推奨します


DEMO、Groupに関連する「デモ」です。

DEMO-036




 

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


下記のJSおよびプラグインが必要になります。

SVG.js 配布サイト svgjs.com Downloadsよりsvg.js 1.0.1、svg.min.js 1.0.1が取得できます。

filterプラグイン svg.filter.jsフィルター処理用のJSです。

draggableプラグイン svg.draggable.jsドラッグ用のJSです。

ドキュメント 英字ドキュメント英字のマニュアル説明です。


filterプラグインは2年前のもので、DropShadow処理でエラーがでるので、DropShadowのみカスタムのJSを作り別の方法で対処します。Blur処理などで一応必要になります。
svg.jsは意外と頻繁に更新されていますが、古いバージョンの取得はできませんので、時間経過と共に記事の内容と異なる事が発生するかも知れません。マニュアル記載の例文が多いので結構助かります。(英文は判りませんが適当に解釈しまして...)
このページでは、version 2.2.5、BUILT:Mon Jan 11現在のsvg.jsを使用しています。

 

SAMPLEとデモのJSについて

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


Groupについて

原則、複数のパスで構成されたインスタンス、例えばパスで描かれたイラストなどを、1つにグルーピングする目的で利用します。
勿論、他のインスタンスと区別する、あるいは単なるレーヤー的な利用も可能です。


原則、draw層などに複数のパスを記載して、drawのメソッドであるGroupを設定してadd()でマトメ(移動)ます。


draw層のインスタンス
var rect1=draw.rect(100,100).attr({'fill':'#FF0'}).center(80,80)
var rect2=draw.rect(80,80).attr({'fill':'#F0F'}).center(80,80)

Group化し移動する
var group=draw.group()
group.add(rect1).add(rect2)

重なり順は変更できます
group.add(rect2).add(rect1)

Group SAMPLE、sample-5a, sample-5b, sample-5c

 

サンプルJS


	//Group基本
	//対象エレメントID
	var draw=SVG('sample-5a').size(160,160)

	var rect1=draw.rect(100,100).radius(10).attr({'fill':'#FFD700'}).center(80,80)
	var rect2=draw.rect(80,80).attr({'fill':'#DAA520'}).center(80,80)
	var rect3=draw.circle(60,60).attr({'fill':'#B8860B'}).center(80,80)

	var text=draw.text('1 要素をdraw層仮配置').font({leading:0.8})

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

	//Group基本
	//対象エレメントID
	var draw=SVG('sample-5b').size(160,160)

	var rect1=draw.rect(100,100).radius(10).attr({'fill':'#FFD700'}).center(80,80)
	var rect2=draw.rect(80,80).attr({'fill':'#DAA520'}).center(80,80)
	var rect3=draw.circle(60,60).attr({'fill':'#B8860B'}).center(80,80)

	//グループ化
	var group2=draw.group()
	group2.add(rect1).add(rect2).add(rect3)

	//グループにstroke
	group2.attr({'stroke':'#000','stroke-width':2})

	var text=draw.text('2 グループ化stroke追加').font({leading:0.8})

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

	//Group基本
	//対象エレメントID
	var draw=SVG('sample-5c').size(160,160)

	var rect1=draw.rect(100,100).radius(10).attr({'fill':'#FFD700'}).center(80,80)
	var rect2=draw.rect(80,80).attr({'fill':'#DAA520'}).center(80,80)
	var rect3=draw.circle(60,60).attr({'fill':'#B8860B'}).center(80,80)

	//グループ化
	var group3=draw.group()
	group3.add(rect1).add(rect2).add(rect3)
	//直接描画
	var rect4=group3.rect(30,30).attr({'fill':'#F00'}).center(80,80)

	//グループにstroke Shadow 回転
	group3.attr({'stroke':'#000','stroke-width':2})
	.attr({'filter':'url(#dropShadow2)'})
	.rotate(30)

	//1番目の要素の色変更
	group3.get(0).attr({'fill':'#00CED1'})

	var text=draw.text('3 グループ化追加と回転').font({leading:0.8})


Groupは複雑な、複数のgraphicを纏めて表示、まとめて動かす場合などに使用されますが、本来充分な計画性が必要のようです。本サンプルでは、本来の目的ではなく単にラップして区別するような事にの使用が多い。

下記、サンプル1番「1 group」のコードを参照ください、本来のgroupの操作です。その他は勝手にアレンジした方法です。


Group SAMPLE、sample-6a, sample-6b, sample-6c

 

サンプルJS

2-3番はgroup層がdraw層より小さくなっていますので範囲によっては切れる場合があります。


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

	//通常の方法
	var rect1=draw.rect(20,20).attr({'fill':'#F00'}).center(10,30)
	var rect2=draw.rect(20,20).attr({'fill':'#0F0'}).center(10,60)
	var rect3=draw.rect(20,20).attr({'fill':'#00F'}).center(10,90)

	var group=draw.group()
	group.add(rect1).add(rect2).add(rect3)

	//無い属性を追加
	group.attr({'stroke':'#000','stroke-width':2})
	//まとめて移動
	group.transform({'x':100})
	//子要素を指定して回転とBlur
	group.get(0).rotate(30)
	.filter(function(add) {
  		add.gaussianBlur(3)
		this.size('200%','200%').move('-50%', '-50%')
	})

	var text=draw.text('1 group 重要です').font({leading:0.8}).attr({'fill':'#F00'})

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

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

	var group=draw.group()
	group.rect()//範囲0重要

	var rect=group.rect(100,100).attr({'fill':'#000'}).center(80,80)
	.filter(function(add) {
  		add.gaussianBlur(3)
		this.size('200%','200%').move('-50%','-50%')
	})

	var rect=group.rect(100,100).attr({'fill':'#FFD700','stroke':'#FFF','stroke-width':2}).center(80,80)
	var rect=group.rect(80,80).attr({'fill':'#DAA520'}).center(80,80)
	var rect=group.rect(60,60).attr({'fill':'#B8860B'}).center(80,80)
	//画像hue rotate 180
	var image=group.image('/main/images/testImage108.jpg').size(160,160).center(80,80).scale(50/160)
	.filter(function(add){
		add.colorMatrix('hueRotate',180)
	})

	//ドラッグ
	group.draggable()

	var text=draw.text('2 group rect drag').font({leading:0.8})

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

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

	//rect暫定表示
	var rect=draw.rect(120,120).attr({'fill':'none','stroke':'#F00','stroke-width':1,'stroke-dasharray':4}).center(80,80)

	var group=draw.group()
	group.rect(0,0,120,120)//範囲
	group.x(20).y(20)

	var rect=group.rect(100,100).attr({'fill':'#FFD700','stroke':'#FFF','stroke-width':2}).center(60,60)
	var rect=group.rect(80,80).attr({'fill':'#DAA520'}).center(60,60)
	var rect=group.rect(60,60).attr({'fill':'#B8860B'}).center(60,60)

	//オリジナルdropShadow
	group.attr({'filter':'url(#dropShadow2)'})
	.draggable()

	var text=draw.text('3 group rect drag').font({leading:0.8})


add()で移動するので、個別にはgroup.get(0)などと子要素を指定して操作することになります。


	//グループ化
	var group=draw.group()
	group.add(rect1).add(rect2).add(rect3)

	//子要素を指定して回転
	group.get(0).rotate(30)

次の様な場合に、group.rect()が前にあるので、rect1指定はgroup.get(1)に成る。グループ陰影は最外側の外周部分に処理されます。(グループ内の要素全てに個別に陰影処理されるわけでは有りません)


	//グループ化
	var group=draw.group()
	group.rect()
	group.add(rect1).add(rect2).add(rect3)
	//groupにdropShadow
	.attr({'filter':'url(#dropShadow2)'})

Group SAMPLE、sample-6d, sample-6e, sample-6f

 

サンプルJS

3番、group層が回転している場合ドラッグは重いし自由に動かせない。


	//対象エレメントID
	var draw=SVG('sample-6d').size(160,160)

	//rect暫定表示
	var rect=draw.rect(100,100).attr({'fill':'none','stroke':'#F00','stroke-width':1,'stroke-dasharray':4}).center(80,80)

	var group=draw.group()
	group.rect(0,0,100,100)
	group.x(30).y(30)

	var rect=group.rect(100,100).attr({'fill':'#FFD700','stroke':'#FFF','stroke-width':2}).center(50,50)
	var rect=group.rect(80,80).attr({'fill':'#DAA520'}).center(50,50)
	var rect=group.rect(60,60).attr({'fill':'#B8860B'}).center(50,50)

	//オリジナルdropShadow
	group.attr({'filter':'url(#dropShadow2)'})
	.draggable()

	var text=draw.text('4 group範囲狭いNG drag').font({leading:0.8})

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

	//group画像塗り
	//対象エレメントID
	var draw=SVG('sample-6e').size(160,160)

	//image 100x100
	var image=draw.image('/main/images/testImage108.jpg').size(160,160).center(80,80).scale(100/160)
	//rect
	var rect=draw.rect(100,100).attr({
		'fill':image
		,'stroke':'#FFF'
		,'stroke-width':2
	})
	.radius(10)
	.center(80,80)
	//オリジナルdropShadow
	rect.attr({'filter':'url(#dropShadow2)'})

	var dg_group=draw.group()
	dg_group.rect()
	dg_group.add(rect).draggable()

	//dg_group.transform({x:30}).transform({y:30})
	//dg_group.transform({rotation:30})

	var text=draw.text('5 group.add画像塗りdrag').font({leading:0.8})

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

	//group画像塗り回転ドラッグが重い
	//対象エレメントID
	var draw=SVG('sample-6f').size(160,160)

	//image 100x100
	var image=draw.image('/main/images/testImage108.jpg').size(160,160).center(80,80).scale(100/160)
	//rect
	var rect=draw.rect(100,100).attr({
		'fill':image
		,'stroke':'#FFF'
		,'stroke-width':2
	})
	.radius(10)
	.center(80,80)
	//オリジナルdropShadow
	rect.attr({'filter':'url(#dropShadow2)'})

	var dg_group2=draw.group()
	dg_group2.rect()
	dg_group2.add(rect).draggable()

	//グループ回転、ドラッグ動きが悪い
	dg_group2.rotate(30)
	//同じ
	//dg_group2.transform({rotation:30})

	var text=draw.text('6 回転させるとドラッグが重い').font({leading:0.8})


Groupの<g>

Groupの<g>タグは特殊なもので、それ自体では大きさなどを持ちませんが、transform()で動かしたり出来るように作られています。グループ全体を動かせるので重宝します。

元来は、サンプル1の様に使用するのが目的と思います。(例としては分かり難いと思いますが...)


1. 原則、draw層に事前にフィルター無しのgraphic要素のみを作っておいて、add()で挿入(移動)します。
2. フィルターが必要ならば、Group要素全体に処理する事になります。(識別して個別に処理も可能)
3. 邪道的方法ですが、Group要素の中にgraphic要素を直接書き込むことも可能のようです。
4. Group要素を作った時の側近の「graphic要素の大きさ」が「g」要素に設定されます。
(Group要素の大きさなどは、その内容から継承されます)
5. コンテナーの代用として使用される事が多いと予想されますが、注意が必要です。
(コンテナー、レーヤーがないので単に他の要素と分離グループ化する方が多いのは事実)


● groupを作る

groupメソッドなどは、ほとんどdrawのメソッドに成りますから、書き方は単純です。groupインスタンス名は自由です。


drawのメソッドだから
var group=draw.group()

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

複数のgroupを羅列するなら
var group=draw.group()
var group2=draw.group()
var group3=draw.group()

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

余り利用しないかも知れませんが、groupをネストするなら
先のgroup
var group=draw.group()

先のgroupにgroup()を設定する、可能です
var nest_group=group.group()

ドキュメントに次の記載がある、groupの位置がパスの位置になると言う事であるが、group.rectなど直接記述できると私は受け止めています。実際に構築できます。


var group=draw.group()
group.path('M10,20L30,40')

groupにgraphic要素の取り込み。フィルター処理されたものは取り込まれません
SVG.jsでは、add()の記述を薦めている感じがある。本来のgroupの使用方法からは想かも知れない。


var rect=rect()........

var group=draw.group()
group.add(rect)

順序が逆ですが、こちら先に説明します。

● groupに直接記載する。

邪道ではあるがこの方が個人的に構成し易いのである。
group本来の使い方ではなく、単純に束ねる(group)ことでありDIV的な使いで、計画性はない。
groupにある、最初のgraphic要素が「g」の大きさになるので group.rect() で大きさを0にしているのが「ミソ」である。(サンプル2参照)、この時のcenter()対象はdraw層の大きさです。
group.rect(0,0,120,120)などと大きさを決めることが出来るが、strokeが切れたりの思わぬ現象があるので注意ください。(サンプル3.4参照)、この時のcenter()対象はgroupの大きさです。


groupを作り...直接書いてゆく、一応可能である
var group=draw.group()
group.rect()

var rect=draw.rect()....
var rect=draw.rect()....
var rect=draw.rect()....

group.rect()が無い場合。


groupを作り...
var group=draw.group()

最初のrect、graphic要素がgroupの大きさに設定される、画像は関係なし
var rect=draw.rect()....
var rect=draw.rect()....

 

● add()でgroupに挿入する。

group.add()サンプル、draw層より移動であり、filter設定と処理で少し面倒です。
一旦、group化すれば、変更はgroup全体に対する変更になる。そのため計画性、と組み立て設計など考慮する必要があるようです。個別の設定変更も出来るが、識別して個別の変更を行うため、面倒になる。

filterの無い単純な複数のgraphicを纏める目的で使用すればいい。例えば複数のパスで構成されたイラストなど...

 

Blur SAMPLE、sample-6g, sample-6h, sample-6i

 

サンプルJS

1番は完全な間違いでadd()が機能していない。2番の様にBlur処理したものはグループにadd()できない。3番、Blur処理したものは直接書き込み、Blur処理しないものだけadd()している。


	//簡単なのですが、問題あり
	//対象エレメントID
	var draw=SVG('sample-6g').size(160,160)

	//部材
	var backline=draw.rect(100,100).attr({'fill':'none','stroke':'#000','stroke-width':2}).center(80,80)
	.filter(function(add) {
  		add.gaussianBlur(3)
	})
	var rect1=draw.rect(100,100).attr({'fill':'none','stroke':'#FFD700','stroke-width':2}).center(80,80)
	var rect2=draw.rect(80,80).attr({'fill':'#DAA520'}).center(80,80)
	.filter(function(add) {
  		add.gaussianBlur(2)
	})
	var rect3=draw.rect(60,60).attr({'fill':'#B8860B'}).center(80,80)

	//group
	var add_group=draw.group()
	//addこれは機能しない
	add_group.add(backline,rect1,rect2,rect3)
	//add_group.add(backline).add(rect1).add(rect2).add(rect3)

	var text=draw.text('1 add()の使用間違い').font({leading:0.8})

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

	//簡単なのですが、問題あり
	//対象エレメントID
	var draw=SVG('sample-6h').size(160,160)

	//部材
	var backline2=draw.rect(100,100).attr({'fill':'none','stroke':'#000','stroke-width':2}).center(80,80)
	.filter(function(add) {
  		add.gaussianBlur(3)
	})
	var rect1b=draw.rect(100,100).attr({'fill':'none','stroke':'#FFD700','stroke-width':2}).center(80,80)
	var rect2b=draw.rect(80,80).attr({'fill':'#DAA520'}).center(80,80)
	.filter(function(add) {
  		add.gaussianBlur(2)
	})
	var rect3b=draw.rect(60,60).attr({'fill':'#B8860B'}).center(80,80)

	//group2
	var add_group2=draw.group()
	//add
	add_group2.add(backline2).add(rect1b).add(rect2b).add(rect3b)

	//回転
	add_group2.rotate(30)

	var text=draw.text('2 Blur物groupにadd()しない').font({leading:0.8})

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

	//対象エレメントID
	var draw=SVG('sample-6i').size(160,160)

	var rect5c=draw.rect(20,20).attr({'fill':'#000'}).center(80,80)
	.filter(function(add) {
  		add.gaussianBlur(3)
	})
	var rect4c=draw.rect(40,40).attr({'fill':'#FF0000'}).center(80,80)

	var add_group3=draw.group()
	var backline3=add_group3.rect(100,100).attr({'fill':'none','stroke':'#000','stroke-width':2}).center(80,80)
	.filter(function(add) {
  		add.gaussianBlur(3)
	})
	var rect1c=add_group3.rect(100,100).attr({'fill':'none','stroke':'#FFD700','stroke-width':2}).center(80,80)
	var rect2c=add_group3.rect(80,80).attr({'fill':'#DAA520'}).center(80,80)
	.filter(function(add) {
  		add.gaussianBlur(2)
	})
	var rect3c=add_group3.rect(60,60).attr({'fill':'#B8860B'}).center(80,80)

	add_group3.add(rect4c).add(rect5c)
	add_group3.rotate(30)

	var text=draw.text('3 group3 add()と混在').font({leading:0.8})


一旦、draw層に事前にgraphic要素を作っておいて、add()で挿入する方法です。add()で挿入を推奨している気配があるが、実際使用すると大変である。
1番は間違っているので、出力の「svg」を調べてみるとグループ層の中にrect要素が無い。移動していない。


部材を作る
var rect1=draw.rect()....
var rect2=draw.rect()....
var rect3=draw.rect()....

groupを作りadd()するが、Blur処理されたものは取り込めない
var group=draw.group()
group.add(rect1).add(rect2).add(rect3)

注意、これは機能しませんので使用しないこと
group.add(rect1,rect2,rect3)


add()サンプル1
add()する全てにcenter()を指定して配置する、add()の方法が悪いのでgroupに移動していない。よってgroupは空でエラーは無いが機能しない。

add()サンプル2
Blur処理したものはadd()しても動かない。その他は移動してgroupも機能一応機能する。

add()サンプル3
Blur処理するものはgroup層で記述してその他の物をadd()して見た。混在してもOKです。


add()サンプル1の出力を調べてみるとグループ層の中にrect要素が無いので当然transform()等が機能しない。


構造だけを簡素にして表示しています

<svg id="SvgjsSvg1158" width="160" height="160">
	<defs id="SvgjsDefs1159"><filter id="SvgjsFilter1165">...</filter></defs>
	<rect id="SvgjsRect1160"></rect>
	<rect id="SvgjsRect1163"></rect>
	<rect id="SvgjsRect1164"></rect>
	<rect id="SvgjsRect1167"></rect>
	<g id="SvgjsG1168">
		<filter id="SvgjsFilter1161">...</filter>
	</g>
</svg>

add()を実行することによりfilterもgroup層に移動させていますので、以前はBlurもadd()出来たのでしょうか?
バージョンアップと共に機能しない部分も出て来てるようですが、基本的にはそう問題にはならない。


● カスタムのDropShadowの設定なら、add()でgroupに移動してもOKですが、基本的にGroupの目的に合っているのかは判りません。「デモ」ページにサンプルを掲載します。

カスタムのDropShadowの設定とadd() デモページに進む


以上が基本的な「svgコンテンツ表示」の説明である。大体この程度の知識でほぼ描画できます。使用する事の無い機能などもありますので、その都度学習すればよいと思います。コマイところは順次これから記事にします。

 


 

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

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

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


コツさえ掴めば結構簡単だ。以上。

 


[ この記事のURL ]


タグ:javascript , SVG

 

ブログ記事一覧



[1]