LINK-GOTO-BACK(元のページに戻る)


SVG.js 各種Filter表示デモ(v2.0.2)。DEMO-042


解説の記事ページで収容出来ない、svg.filter.js(v2.0.2)のFilterデモなどを表示しています。解説などは少なめですので、コードをみて直感的に理解ください。このページではjquery-1.9.1を使用しています。TEXT文字Font指定が在っても、ブラウザ、マシン環境により違う文字が表示される場合があります。
2016/09/19 新規


DEMO

 

ご注意、Chrome.Firefox.IE11等、モダンブラウザでご覧ください(Chrome推奨)。但し、Mac、Android系の動作は不明です。


 

新しいsvg.filter.js(v2.0.2)を使用する


SVG.js プラグインsvg.filter.jsは svg.filter.js で取得ください。同ページにマニュアルもあります。
当方の都合で(過去記事全ての動作確認が未完了のため)、このページでは、svg.filter.v2.jsと名前を変えて使用しています。


SVG.js実行上、基礎的なSVGの知識が必要ですので、ぜひ下記サイトの解説記事とも参考にして下さい。

【参考】www.h2.dion.ne.jpの記事: svg要素の基本的な使い方まとめ、画像効果

【参考】triple-underscoreの記事: (SVG)1.1 第2版 /15 フィルタ効果


[ 目次 ]


1 svg.filter.jsの Effect Classes

2 svg()メソッド利用のFilter処理

3 外部ファイルを読み込みFilterを掛ける

4 サンプルJSの全表示と使用画像と参考リンク

 

 

1 svg.filter.jsの Effect Classes

▲[目次]

以前は無かった、Effect Classes等のマニュアル説明が付きました。全てに対処はまだ出来ませんが、工夫すればほぼsvg.filter.jsの記述に出来ます。
尚、各々の書式は余り詳細に書きませんので、「マニュアル」および「SVG規格」を参照ください。
SVGに関する多少の知識と、SVG規格に従い構成しますので、事前にそれらを知っておく必要が有ります。


1. svg.filter.jsの Effect Classesは完全では有りません(と思います)。処理出来ない部分は工夫しています。
2. 2重フィルターですと前のフィルターが消滅したり処理出来ないなどあるので、一括してDropShadowを処理している例が多い。
3. 確認のため、DEMOサンプルの大半にドラッグを設定しています。
4. フィルターによっては、ブラウザにより表示品質など若干の相違がある場合も有ります。
5. このテストはsvg.filter.js(v2.0.2)を使用した場合で、バージョンが変われば多少の違いは出ると思います。
6. 本ページ掲載のSVGは大半がNET上、またはInkscapeのパクリ物です。(1個だけ作ったもの有り)


svg.filter.jsのfilter処理関数

これは、独自の処理関数でこの中で操作することによりfilterを構成しますので、この部分は動的に削除できません。filterのIDなどは固有の名前を付けられてdefsに収容されます。
通常は、blur,offsetBlurなどエフェクト変数を宣言して処理します(名前は自由)。受け渡しのリザルト値と同じようなものと考えてよろしい。
defsに収容されるものは再利用が可能であるともいえる。関数内の具体的記述方法は次の様になる。


filter関数内の記述方法の注意点

1. 最初のメソッド実行は add をつけます。その後に続くメソッドチェーンには付けません。
2. 最初のメソッドに指定がなければインスタンスのSourceGraphic(source)が入ります。SourceAlpha(sourceAlpha)を入れたければ、in()で変更します。
(明示的に常に、in()で指定すればマチガイはありません)
3. メソッドチェーンの場合、前の結果であるresult値が、次のinに自動的に入ります。
(composite()など、第一引数にin指定のものなどは、記述を省きます、但しmerge()は除く)
4. 処理を分離(分割)する場合は変数に取り込みます。effectに成ります。次に受け渡しできます。
5. source、sourceAlphaは前にaddをつけます。effect、resultは付けません。
6. merge()をメソッドチェーンの中に入れないでください。上手く処理しない。
7. thisはfilterタグをめざす。filterの属性設定が必要なら、this.attr()で設定できます。
(filter関数をかけば、固有IDを付与されたfilterタグが生成されますので、filterのIDは this.attr('id')で取得できます)
8. var effect=this.svg()はマチガイ。effect変数ではなく単なるオブジェクト。
9. マチガイなく設定が記述されれば、対象インスタンスのfilter属性にurl(#)が書き込まれます。
10. Firefoxは規格に厳密ですから注意のこと。反対に Chrome、IE は甘いので少し間違っても動作する。


filter処理関数は次の様に書きます。


対象インスタンス.filter(function(add) {
	//処理完結
	add.offset()...
})

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

対象インスタンス.filter(function(add) {
	//処理受け渡し可能
	var offsetBlur=add.offset()...
	var effect=add.composite()...
	//2つを重ねる
	add.merge(offsetBlur,effect)
	//filterに属性を設定する
	this.attr()..
})

現実的にはチェーンメソッドで書く場合が多い。但しfilter削除の場合に問題有り(削除はめったに無いと思う)。


var image=draw.image()...
.filter(function(add) {
	//処理
})

defsにfilterが登録されます。defsはfilterなど有る無しに関わらず自動的に作られます。ID等はSVG.js固有の名前が付けられます。
但し、svg()で設定する部分はそのまま指定位置に挿入されます。生成されたSVGはブラウザのデベロッパーツールで確認できます。

上手く行かない場合に確認すれば、状況原因を有る程度把握することが可能と思います。


<defs><filter>
原始フイルターが書いた順番に作られます
.
.
</filter></defs>

Offset GaussianBlur Flood Blend Merge

▲[目次]

offset() gaussianBlur() flood() blend() merge()についての詳細は「SVG.js filterとDropShadow」を参照ください。

DropShadowを例にあげておきますが、下記の様にメソッドチェーン処理は、順序などが違うとエラーに成る場合があります。問題があれば分離して処理すれば解決することが多い。
簡単ですが、offset() gaussianBlur() flood() blend() merge() は下のサンプル例でわかると思います。

特に、merge()はメソッドチェーンではなく、区切って処理しないと問題が起きます。下記例の様にすれば問題は有りません。



svg.filter.jsでは
SourceGraphicは source と記述する
SourceAlphaは sourceAlpha と記述する

実際にはaddをつけて
add.source
add.sourceAlpha


//黒DropShadow
var shadow=add.offset(5,5).in(add.sourceAlpha).gaussianBlur(3)
add.merge(shadow,add.source)

//blend処理ならば
add.blend(add.source,shadow)

//拡張範囲を設定する
this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

文章で説明すれば

1. DropShadowは下になるので、merge()で重ねを調整しますが、受け渡しのため変数(effect)宣言する。
2. DropShadowは黒なので、sourceAlphaをinにセットする。(セット変更しないとsourceがはいる)
3. それをoffset()でずらして、ぼかし処理します。メソッドチェーンなので、結果は受け渡されます。
4. DropShadowが下になるように、merge()で重ねを調整します。merge()が無いと陰影が上になる。
5. 陰影が切れないようにfilter範囲を拡張します。IEがsize()では上下方向機能しない為attr()で設定。



//色指定DropShadow
var shadow=add.flood('#00F',1).composite(add.sourceAlpha,'in').offset(5,5).gaussianBlur(2)
add.merge(shadow,add.source)

文章で説明すれば

1. DropShadowは下になるので、merge()で重ねを調整しますが、受け渡しのため変数(effect)宣言する。
2. flood()で青色(透明度1)のrect形を作る(attr()でx y width height設定可能)。
3. composite()でインスタンスの形にマスク処理、メソッドチェーンなので第一引数は省略(この場合は書き様がない)。
4. それをoffset()でずらして、ぼかし処理します。メソッドチェーンなので、結果は受け渡されます。
5. 以下、上の例と同じ。


● filter処理のものにDropShadowを追加する場合、次は重要ですから「定格」として覚えておきましょう。


var shadow=add.offset(5,5).in(add.sourceAlpha).gaussianBlur(3)

1番、黒dropshadow / 2番、色指定dropshadow / 3番、ソースのdropshadow


サンプルJS


	//対象エレメントID
	var draw=SVG('svg-test-shadow01').size(160,160)

	var text=draw.text('黒dropshadow').font({leading:0.8})

	var rect=draw.rect(100,100).radius(10).attr({'fill':'#FFD700','stroke':'#FFF','stroke-width':2}).center(80,80)
	.draggable()//ドラッグ
	.filter(function(add){
		//黒DropShadow
		var shadow=add.offset(5,5).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,add.source)

		//blend処理ならば
		//add.blend(add.source,shadow)

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK
	})

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

	//対象エレメントID
	var draw=SVG('svg-test-shadow02').size(160,160)

	var text=draw.text('色指定dropshadow').font({leading:0.8})

	var rect=draw.rect(100,100).radius(10).attr({'fill':'#FFD700','stroke':'#FFF','stroke-width':2}).center(80,80)
	.draggable()//ドラッグ
	.filter(function(add){
		//色指定DropShadow
		var shadow=add.flood('#00F',1).composite(add.sourceAlpha,'in').offset(5,5).gaussianBlur(2)
		add.merge(shadow,add.source)

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK
	})

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

	//対象エレメントID
	var draw=SVG('svg-test-shadow03').size(160,160)

	var text=draw.text('ソースのdropshadow').font({leading:0.8})

	//var rect=draw.rect(100,100).radius(10).attr({'fill':'#FFD700','stroke':'#FFF','stroke-width':2}).center(80,80)
	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ
	.filter(function(add){
		//ソースのDropShadow
		var shadow=add.offset(10,10).in(add.source).gaussianBlur(3)
		add.merge(shadow,add.source)

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK
	})


unfilter()、フイルター削除

▲[目次]

filterの削除ですが、url(#)で設定したものは簡単に削除できますが...
.filter(function(add){})、つまり、filter処理関数で設定したものは設定方法次第では削除できないようです(前バージョンも同じであった)。
該当するfilter属性にもアクセス変更も出来無い場合が発生します。
そもそもfilter削除することが頻繁にあるとは考えずらい。
驚く無かれ、頭がパーになる現象がおこっていた。(何時の日にか直るでショウ...)


書式
unfilter()だけならば、フイルターがdefsに残っている状態なので、また復活させることが出来ます。(6番参照)


//インスタンスのfilter属性を削除
インスタンス.unfilter()

//自動でdefsに収容のフイルターも削除
インスタンス.unfilter(true)

● url(#)で設定の削除 OK。(4番参照)


//filter処理
var rect=draw.rect()....
rect.attr({'filter':'url(#dropShadow2)'})//陰影

//filter削除 OK
rect.unfilter()

● この方法で設定すると削除できない NG。フイルター処理した要素では無く、filterタグに対してunfilter処理しているので、何らの効果も無い。(5番参照)

unfilter(true)でも同じこと、これは完全にバグでショウ。フイルター設定はこの記述方法が多いし、フイルター設定自体には何ら問題は無い。
生成された、HTMLを確認して驚いた。unfilter_rect2.attr({'filter':'none'})とインスタンス指定が「filter」タグに書き込まれている。コリャ何じゃ....


インスタンス=draw.rect()..........
.filter(function(add){
	//この中の処理は正常に行われます
})

//削除できない
インスタンス.unfilter()

● この方法で設定すると正常に機能して削除出来る OK。(6番参照)

ナンデスネン。削除の必要性があるなら、とりあえずこの書き方で...


インスタンス=draw.rect()..........
インスタンス.filter(function(add){
	//処理
})

//削除できる、インスタンスのfilter属性を削除
インスタンス.unfilter()

//defs登録のfilterをも削除
インスタンス.unfilter(true)

4番、url(#)で設定はOK / 5番、unfilter()機能せずNG、これは事件です/ 6番、unfilter()機能するOK、一件落着

ボタン、ON/OFF で陰影を表示したり、削除したり出来ます。


サンプルJS


	//対象エレメントID
	var draw=SVG('svg-test-unfilter01').size(160,160)

	var unfilter_rect=draw.rect(100,100).radius(10).attr({'fill':'#BC8F8F','stroke':'#CCC','stroke-width':2}).center(80,80)
	//.attr({'filter':'url(#dropShadow2)'})//陰影

	//ボタン
	var unfilter_btn1=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(145,145)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	unfilter_btn1.click(shadow_rect)

	//Func/toggleClass
	function shadow_rect(){
		//ダミーanimate/コールバックがほしいだけ
		this.animate(1).rotate(0).after(function() {
			unfilter_rect.toggleClass('active')
			if(unfilter_rect.hasClass('active')) {
				unfilter_rect.attr({'filter':'url(#dropShadow2)'})
			}else{
				unfilter_rect.unfilter()
			}
		})
	}

	var txt=draw.text('ボタン押 shadow on/off').font({leading:0.8})

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

	//対象エレメントID
	var draw=SVG('svg-test-unfilter02').size(160,160)

	var unfilter_txt2=draw.text('filter削除できず').font({leading:0.8})

	var unfilter_rect2=draw.rect(100,100).radius(10).attr({'fill':'#BC8F8F','stroke':'#CCC','stroke-width':2}).center(80,80)
	.filter(function(add){
		//ソースのDropShadow
		shadow=add.offset(10,10).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,add.source)

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})

	//filter属性を取得/何たることかfilterタグを目指す
	var flname=unfilter_rect2.attr('filter')
	unfilter_txt2.text(''+flname)

	//機能せず
	unfilter_rect2.unfilter()
	//attr()も機能せず/何たることかfilterタグを目指す、filter属性はあるわけない
	unfilter_rect2.attr({'filter':'none'})

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

	//対象エレメントID
	var draw=SVG('svg-test-unfilter03').size(160,160)

	var unfilter_txt3=draw.text('filter削除できず').font({leading:0.8})

	var unfilter_rect3=draw.rect(100,100).radius(10).attr({'fill':'#BC8F8F','stroke':'#CCC','stroke-width':2}).center(80,80)
	unfilter_rect3.filter(function(add){
		//ソースのDropShadow
		shadow=add.offset(10,10).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,add.source)

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})

	//filter属性を取得
	var flname3=unfilter_rect3.attr('filter')
	unfilter_txt3.text(''+flname3)

	//削除機能する
	unfilter_rect3.unfilter()

	//ボタン
	var unfilter_btn3=draw.circle(10).attr({'fill':'#FF0000','stroke':'#FFF','stroke-width':2}).center(145,145)
	.attr({'filter':'url(#dropShadow2)'})//陰影
	.style('cursor','pointer')
	unfilter_btn3.click(shadow_rect3)

	//Func/toggleClass
	function shadow_rect3(){
		//ダミーanimate/コールバックがほしいだけ
		this.animate(1).rotate(0).after(function() {
			unfilter_rect3.toggleClass('active')
			if(unfilter_rect3.hasClass('active')) {
				unfilter_rect3.attr({'filter':flname3})
			}else{
				unfilter_rect3.unfilter()
			}
		})
	}


composite() [feComposite]、PORTERDUFF合成

▲[目次]

composite()はマスクとして頻繁に使用されます。通常はマスク対象をSourceAlphaでマスクする場合が多い。
operator設定値を変えれば違う効果を与えられます。
チェーンメソッドで処理している場合は、in値を省略できます。前の処理のリザルト値が自動挿入されます。


書式
filter.composite(in1,in2,operator)
operator設定値
in out xor arithmetic

//マスク対象はeffectまたはresult
add.composite(マスク対象,add.sourceAlpha,'in')

//チェーンメソッド処理
var shadow=add.flood('#00F',1).composite(add.sourceAlpha,'in').offset(5,5).gaussianBlur(2)

inでのマスクは頻繁に使用されます。この例はタイガーマスクと呼ばれ耐火性があり強く叩くと穴が開く。
xorは逆に打ち抜きになりますが、この例では画像のパターン塗りのほうがキレイに成ります。
arithmeticは多少難しい。k1-k4属性が使用できますので、マスク効果の調整を行えます。
シミュレーション「feDistantLightの k1-k4 設定テスト」参照ください。


画像を塗りこんだ場合はドラッグ設定に注意。

7,8番インスタンス直接のドラッグは面白い結果になります。(グループ化すれば問題は有りません)

7番、composite in / 8番、composite xor / 9番、composite arithmetic


通常の画像塗りでも、ドラッグ設定はグループ化して行っていました。画像取り込みは同じ様です。
下記の様にテキトウなグループでラップすれば正常なドラッグが行えます。

7番グループ化


	var inner_group=draw.group()
	var circle=draw.circle(100).attr({'fill':'#000'}).center(80,80)
	inner_group.add(circle)
	.draggable()//ドラッグ
	circle.filter(function(add) {

		//中の処理は同じ

	})

8番グループ化


	var morph_group=draw.group()
	//200x200
	var image=draw.image('/main/images/grad_200.jpg').size(160,160).scale(100/160).center(80,80)
	var rect=draw.rect(100,100).radius(20).attr({'fill':image}).center(80,80)
	morph_group.add(rect)
	morph_group.draggable()//ドラッグ
	//カスタムinline-shadow
	rect.filter(function(add){

		//中の処理は同じ

	})

サンプルJS


	//対象エレメントID
	var draw=SVG('svg-test-filter10').size(160,160)

	var text=draw.text('composite in').font({leading:0.8})

	var circle=draw.circle(100).attr({'fill':'#000'}).center(80,80)
	.draggable()//ドラッグ
	.filter(function(add) {
		//135x136/testImage101.jpg
		var inner_image=add.image('/main/images/tigerbrand.jpg').size(100,100).move(30,30)
		//mask
		var mask=add.composite(inner_image,add.sourceAlpha,'in')
		//shadow
		var shadow=add.offset(2,2).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,mask)

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})

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

	//対象エレメントID
	var draw=SVG('svg-test-filter11').size(160,160)

	var text=draw.text('composite xor').font({leading:0.8})

	//200x200
	var image=draw.image('/main/images/grad_200.jpg').size(160,160).scale(100/160).center(80,80)
	var rect=draw.rect(100,100).radius(20).attr({'fill':image}).center(80,80)
	.draggable()//ドラッグ
	//カスタムinline-shadow
	.filter(function(add){

		//erode
		var morphology=add.morphology('erode','4').in(add.sourceAlpha)
		var inline=add.composite(add.source,morphology,'xor')//模様
		//shadow
		var morphology2=add.morphology('erode','4').in(add.sourceAlpha)
		var base=add.composite(add.sourceAlpha,morphology2,'xor')//黒
		var shadow=add.offset(2,2).in(base).gaussianBlur(3)
		add.merge(shadow,inline)//merge

	})

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

	//対象エレメントID
	var draw=SVG('svg-test-filter12').size(160,160)

	var text=draw.text('composite arithmetic').font({leading:0.8})

	var circle=draw.circle(100).attr({'fill':'#DC143C'}).center(80,80)
	.draggable()//ドラッグ
	.filter(function(add) {

/*
		//Bevel
		this.svg('<feGaussianBlur in="SourceAlpha" stdDeviation="3" result="blur"/><feSpecularLighting in="blur" surfaceScale="5" specularConstant="0.5" specularExponent="10" result="specOut" lighting-color="white"><fePointLight x="-5000" y="-10000" z="20000"/></feSpecularLighting><feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut2"/><feComposite in="SourceGraphic" in2="specOut2" operator="arithmetic" k1="0" k2="1" k3="1" k4="0" result="litPaint" />')
		var result=this.get(3).attr('result')//0
		var shadow=add.offset(5,5).in(add.sourceAlpha).gaussianBlur(5)
		add.merge(shadow,result)
*/

		//bevel
		//(surfaceScale,diffuseConstant,kernelUnitLength)
		var diffuse=add.diffuseLighting('5',1,'1').svg('<feDistantLight azimuth="225" elevation="35"/>')
		diffuse.attr({'lighting-color':'#FFF'}).gaussianBlur(1)
		var effect=add.composite(add.source,diffuse,'arithmetic').attr({'k1':1,'k2':0,'k3':0,'k4':0})
		var shadow=add.offset(2,2).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,effect)

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})


k1-k4属性は、下記の計算式で与えるそうですが、良く判らん。下記サイト記事を参照されたし。

【参考】SVG規格記事: フィルタ効果

【引用】arithmetic 演算は feDiffuseLighting, feSpecularLighting フィルタによる出力に地模様データを組み合わせるときに有用である。ディゾルブ(dissolve)の実装にも有用である。arithmetic 演算が選択された場合、結果の各画素は次の公式により算出される。


//i1=in i2=in2
result = k1*i1*i2 + k2*i1 + k3*i2 + k4

feDiffuseLightingのfeDistantLight(平行光源)テスト

k1-k4属性の状況を知るため、feDiffuseLightingのfeDistantLight(平行光源)の様子をシミュレーションしてみる。


1. 光源の種類により、光の当たる部分と、当たらない部分の「照明画像」が生成されます。
2. インスタンスの画像はSourceGraphicで取得できます。
3. その2つの重ね合わせの公式の計算要素が k1-k4 である。(透明度の調整と考えれば判り易い)


それが、arithmeticタイプです。これならば理解できる。2つの要素の重ね合わせ「度合い」の調整が出来る事である。


● feDiffuseLighting feDistantLightタイプの k1-k4 設定テスト

▲[目次]

次のようにinにSourceGraphic、in2にフィルタによる出力(図の画像)をセットしています。初期値はk1=1。
Lightingフィルタによる出力を便宜的に「照明画像」とここで呼ぶことにします。



var effect=add.composite(add.source,diffuse,'arithmetic')

k1. SourceGraphicと「照明画像」を同時に調整。
k2. SourceGraphicを調整。
k3. 「照明画像」を調整。
k4. 合成全体の透明度の調整でしょうか。


composite()、タイプ「arithmetic」の場合のみ k1-k4 の設定が使用できます。主に k1,k2 を調整します。
k1=0でk2,k3の調整を行っても良い。(k3の比率が多いと白っぽくなりすぎて困る)
k3操作による外側のグレー部分(本来透明であるが、グレーで表現されている)はマスクで除去しています。
k4操作は複雑なbevel作成時以外はほとんど無いと思う。


作り方の事由により「色変更」を多く行うと重くなります。(通常filter処理されたインスタンスの色変更は出来ない)


k3操作の場合に現れる画像は、とりあえずマスクして除去しています。k3設定0なら必要有りません。

light

処理Filter


//マスクなし
.filter(function(add) {
	var diffuse=add.diffuseLighting('5',1,'1').svg('<feDistantLight azimuth="225" elevation="35"/>')
	diffuse.attr({'lighting-color':'#FFF'}).gaussianBlur(1)
	var effect=add.composite(add.source,diffuse,'arithmetic').attr({'k1':1,'k2':0,'k3':0,'k4':0})
	var shadow=add.offset(2,2).in(add.sourceAlpha).gaussianBlur(3)
	add.merge(shadow,effect)
})

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

//マスク有り
.filter(function(add) {
	var diffuse=add.diffuseLighting('5',1,'1').svg('<feDistantLight azimuth="225" elevation="35"/>')
	diffuse.attr({'lighting-color':'#FFF'}).gaussianBlur(1)
	var effect=add.composite(add.source,diffuse,'arithmetic').attr({'k1':1,'k2':0,'k3':0,'k4':0})
	var mask=add.composite(effect,add.source,'in')
	var shadow=add.offset(2,2).in(add.sourceAlpha).gaussianBlur(3)
	add.merge(shadow,mask)
})

diffuseLighting() [feDiffuseLighting]、照明効果

▲[目次]

● まだ、diffuseLighting()の child effects が自動挿入されずに機能しませんが、svg()で加えることができます。
(ゴマカシですが、これは非常に上手くいった例です、将来的にはsvg()処理しなくとも良い様になると思いますが...)
kernelUnitLength:照明効果を計算する際の単位格子の大きさ、小さい値を取ると傾斜部の計算が緻密になるものの、計算量が増大するそうです。
(「svg要素の基本的な使い方まとめ」より引用)

11番、DistantLightはk調整の無いものであるが、TEXTには表示例の様に結構効果的と思います。


10番、DistantLight / 11番、DistantLight / 12番、PointLight


サンプルJS


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

	//TEXT
	var text=draw.text('diffuseLighting').font({leading:0.8})

	var bevel_rect1=draw.rect(100,100).radius(50).attr({'fill':'#DC143C'}).center(80,80)
	.draggable()//ドラッグ

	.filter(function(add) {

		//bevel
		//(surfaceScale,diffuseConstant,kernelUnitLength)
		var diffuse=add.diffuseLighting('5',1,'1').svg('<feDistantLight azimuth="225" elevation="35"/>')//<feDistantLight azimuth="225" elevation="10"/>
		diffuse.attr({'lighting-color':'#FFF'}).gaussianBlur(1)
		var composite=add.composite(add.source,diffuse,'arithmetic').attr({'k1':0.8,'k2':0.5,'k3':0,'k4':0})
		var shadow=add.offset(2,2).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,composite)

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})

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

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

	//TEXT
	var text=draw.text('diffuseLightingとshadow').font({leading:0.8})

	var bevel_text2=draw.text('POPS').attr({'fill':'#00F'}).move(80,60)
	.font({
		family:'Arial'
		,'size':50
		,'font-weight':'bold'
		,anchor:'middle'
		,leading:1
	})
	.draggable()//ドラッグ
	.filter(function(add) {

		var shadow=add.offset(0,0).in(add.sourceAlpha).gaussianBlur(5)

		//bevel
		//(surfaceScale,diffuseConstant,kernelUnitLength)
		//文字15 rect5
		var diffuse=add.diffuseLighting('15',1,'1').svg('<feDistantLight azimuth="225" elevation="15"/>')
		diffuse.attr({'lighting-color':'#FFF'})

		var blur=add.composite(diffuse,add.sourceAlpha,'in').gaussianBlur(2)
		var mask=add.composite(blur,add.sourceAlpha,'in')
		//screen
		var blend=add.blend(mask,add.source,'screen')
		//shadow追加
		add.merge(shadow,blend)

		//this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK
	})

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

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

	//TEXT
	var text=draw.text('diffuseLighting').font({leading:0.8})

	var bevel_rect3=draw.rect(100,100).radius(50).attr({'fill':'#DC143C'}).center(80,80)
	.draggable()//ドラッグ
	.filter(function(add) {

		//bevel
		//(surfaceScale,diffuseConstant,kernelUnitLength)
		//rect5
		var diffuse=add.diffuseLighting('5',1,'1').svg('<fePointLight x="60" y="60" z="10"/>')
		diffuse.attr({'lighting-color':'#FFF'})
		//Blurが在れば陰影がつく
		var blur=add.composite(diffuse,add.sourceAlpha,'in').gaussianBlur(2)
		//screen
		var blend=add.blend(blur,add.source,'screen')

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK
	})


specularLighting() [feSpecularLighting]、鏡面反射効果

▲[目次]

specularLighting()鏡面反射、と言う効果で鏡面の様に反射します。上のdiffuseLighting()の正反対に成ります。
文字に対しては、k1-k4の調整なしでもよろしい様ですが、その他は鏡面反射が強すぎますので状態をみて見ます。


● feSpecularLighting feDistantLightタイプの k1-k4 設定テスト

▲[目次]

k2,k3で調整します。k3は鏡面反射の度合いになります。k1は1に固定するのが良いようです。


下記サンプルは、「svg要素の基本的な使い方まとめ、画像効果」掲載サンプルを引用書き換えたものです。
【引用】このフィルターはfeGaussianBlurと組み合わせ,図形に立体感を持たせる常套手段として用いられる。


//svg
this.svg('<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur"/><feSpecularLighting in="blur" lighting-color="white" surfaceScale="5" result="light" specularConstant="1"><feDistantLight azimuth="-135" elevation="45"/></feSpecularLighting><feMerge result="merge"><feMergeNode in="SourceGraphic"/><feMergeNode in="light"/></feMerge><feComposite in="merge" in2="SourceGraphic" operator="in"/>')

svg.fliter.js形式に書き換えれば、サンプルの様になる。3番目はkを調整してみました。

k調整の無いfeSpecularLightingは、記述が簡単ではあるが、文字は良いとしても反射が強すぎます。


サンプルJS


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

	//Back
	var rect=draw.rect(160,160).attr({'fill':'#E6E6FA'})
	//TEXT
	var text=draw.text('specularLighting').font({leading:0.8})

	//文字描画
	var bevel_text4=draw.text('POPS').attr({fill:'#000'}).move(80,60)
	.font({
		family:'Times New Roman'//
		,size:50
		,'font-weight':'bolder'
		,anchor:'middle'
		,leading:1
	})

	.filter(function(add) {

		//FirefoxOK
		var blur=add.gaussianBlur(2).in(add.sourceAlpha)
		var light=add.specularLighting('5',1,1,1).in(blur).attr({'lighting-color':'white'}).svg('<feDistantLight azimuth="-135" elevation="45"/>')
		var merge=add.merge(add.source,light)
		add.composite(merge,add.source,'in')

	})

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

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

	//TEXT
	var text=draw.text('specularLighting').font({leading:0.8})

	//circle
	var circle=draw.circle(100).attr({'fill':'#DC143C'}).center(80,80)
	.filter(function(add) {

		//FirefoxOK
		var blur=add.gaussianBlur(2).in(add.sourceAlpha)
		var light=add.specularLighting('5',1,1,1).in(blur).attr({'lighting-color':'white'}).svg('<feDistantLight azimuth="-135" elevation="45"/>')
		var merge=add.merge(add.source,light)
		var mask=add.composite(merge,add.source,'in')
		//shadow
		var shadow=add.offset(2,2).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,mask)

	})

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

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

	//TEXT
	var text=draw.text('specularLighting k調整').font({leading:0.8})

	//circle
	var circle=draw.circle(100).attr({'fill':'#DC143C'}).center(80,80)
	.filter(function(add) {

		//FirefoxOK
		var blur=add.gaussianBlur(2).in(add.sourceAlpha)
		var light=add.specularLighting('5',1,1,1).in(blur).attr({'lighting-color':'white'}).svg('<feDistantLight azimuth="-135" elevation="45"/>')
		var effect=add.composite(add.source,light,'arithmetic').attr({'k1':1,'k2':1,'k3':0.3,'k4':0})
		var mask=add.composite(effect,add.source,'in')
		//shadow
		var shadow=add.offset(2,2).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,mask)

	})


● feSpecularLighting fePointLightタイプの k1-k4 設定テスト

▲[目次]

PointLight点光源に成ります。specularExponent 光の収束度合いを調整できます。1でフラット値を大きくするに従い明るい部分が狭まる(ここでは初期値20です)。但し、光源の位置高さは固定です。

主に、k2,k3で調整します。k3は鏡面反射の度合いになります。k1は0に固定するのが良いようです。(自由ですが)

光源色を#BBBBBB(ビタミンB6)にしています。鏡面反射が激しいのを和らげます。この方法がベターだ。


サンプルJS


.filter(function(add) {

	//bevel
	//(surfaceScale, diffuseConstant, specularExponent, kernelUnitLength)
	var blur=add.gaussianBlur(2).in(add.sourceAlpha)
	var light=add.specularLighting('5',0.75,20,1).in(blur).attr({'lighting-color':'#bbbbbb'}).svg('<fePointLight x="-5000" y="-10000" z="20000"/>')
	var effect=add.composite(add.source,light,'arithmetic').attr({'k1':0,'k2':1,'k3':1,'k4':0})
	var mask=add.composite(effect,add.source,'in')
	//shadow
	var shadow=add.offset(2,2).in(add.sourceAlpha).gaussianBlur(3)
	add.merge(shadow,mask)
})

その他のBevelボタンなど

▲[目次]

色々なBevelボタンがありますが、結構Inkscapeのfilterが多い。svg()を利用すれば手軽に利用可能です。またNETでのパクリ物も利用できます。現在は数が少ないのですがダンダン増えると予想されます。

● パクリBevelボタン等です。結構複雑で自分で簡単に作ることは中々難しく、作れ無いが本音だ。SVG.jsメソッドなどで処理出来ないものは、svg()で処理してみました。
処理の仕方次第で結構ちがいます。見栄えのよいもの2点を表示します。

bevel

 

サンプル以外のベベルの例を下記に示す。余りよくは無い。


//bevel IE OK
this.svg('<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur"/><feOffset dy="-1" dx="-1"/><feComposite in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="hlDiff"/><feFlood flood-color="black" flood-opacity=".7"/><feComposite in2="hlDiff" operator="in"/><feComposite in2="SourceGraphic" operator="over" result="withGlow"/><feOffset in="blur" dy="3" dx="3"/><feComposite in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowDiff"/><feFlood flood-color="white" flood-opacity="1"/><feComposite in2="shadowDiff" operator="in"/><feComposite in2="withGlow" operator="over"/>')

//bevel2 IE NG
this.svg('<feColorMatrix in="SourceGraphic" result="result0" values="1 0 0 0 0, 0 1 0 0 0, 0 0 1 0 0, 0 0 0 0.85 0"/><feGaussianBlur stdDeviation="7" in="SourceAlpha"/><feSpecularLighting result="result1" specularExponent="25" specularConstant="0.89999998" surfaceScale="5"><feDistantLight azimuth="225" elevation="60"/></feSpecularLighting><feComposite in2="result0" operator="atop"/>')

//Inkscapeネオン
this.attr({'color-interpolation-filters':'sRGB'})
this.svg('<feGaussianBlur stdDeviation="1" result="result1"/><feComposite in2="result1" in="result1" result="result4" operator="in"/><feGaussianBlur stdDeviation="7" result="result6" in="result4"/><feComposite in2="result4" operator="over" in="result6" result="result8"/><feComposite in2="result8" operator="in" result="fbSourceGraphic" in="result6"/><feSpecularLighting specularExponent="45" specularConstant="2" surfaceScale="2.5" lighting-color="rgb(255,255,255)" result="result1" in="fbSourceGraphic"><fePointLight z="20000" y="-10000" x="-5000"/></feSpecularLighting><feComposite in2="fbSourceGraphic" operator="in" result="result2" in="result1"/><feComposite in2="result2" k3="1.5" k2="1.2" operator="arithmetic" result="result4" in="fbSourceGraphic"/><feComposite in2="result4" operator="over" in="result9" result="result9"/><feBlend in2="result9" mode="screen"/>')

bevel2、bevel4は「Inkscape」のフィルターを再編集しsvg()処理しました。
bevel3は「SVG規格ページ」のサンプルです。このような少しの修正なら幾らでも出来ますネ。


サンプルJS


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

	//TEXT
	var text=draw.text('bevel3 IE OK / drag').font({leading:0.8})

	var btngroup=draw.group()
	var circle1=draw.circle(100).attr({'fill':'#DC143C'}).center(80,80)
	btngroup.add(circle1)

	//bevel3 IE OK
	circle1.filter(function(add){

		//svg()
		//bevel3 IE OK
		this.svg('<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/><feOffset in="blur" dx="4" dy="4" result="offsetBlur"/><feSpecularLighting in="blur" surfaceScale="5" specularConstant=".75" specularExponent="20" lighting-color="#bbbbbb" result="specOut"><fePointLight x="-5000" y="-10000" z="20000"/></feSpecularLighting><feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/><feComposite in="SourceGraphic" in2="specOut" operator="arithmetic" k1="0" k2="1" k3="1" k4="0" result="litPaint"/><feMerge><feMergeNode in="offsetBlur"/><feMergeNode in="litPaint"/></feMerge>')

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK
	})

	btngroup.draggable()//ドラッグ

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

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

	//TEXT
	var text=draw.text('bevel4 / drag').font({leading:0.8})

	var btngroup2=draw.group()//
	var circle1=draw.circle(100).attr({'fill':'#DC143C'}).center(80,80)
	btngroup2.add(circle1)

	circle1.filter(function(add){

		//svg()
		this.svg('<feGaussianBlur stdDeviation="2.3" in="SourceAlpha" result="result0"/><feMorphology in="SourceAlpha" radius="6.6" result="result1"/><feGaussianBlur stdDeviation="8.9" in="result1"/><feColorMatrix values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.3 0" result="result91"/><feComposite in2="result91" in="result0" operator="out" result="result2"/><feGaussianBlur stdDeviation="1.7" result="result4"/><feDiffuseLighting surfaceScale="10" result="result92"><feDistantLight azimuth="225" elevation="45" /></feDiffuseLighting><feBlend in2="SourceGraphic" mode="multiply" result="result93"/><feComposite in2="SourceAlpha" operator="in" result="result3"/><feSpecularLighting in="result4" surfaceScale="5" specularExponent="17.9" result="result94"><feDistantLight azimuth="225" elevation="45"/></feSpecularLighting><feComposite in2="result3" operator="atop"/>')
		this.attr({'color-interpolation-filters':'sRGB'})

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK
	})

	btngroup2.attr({'filter':'url(#dropShadow2)'})//陰影
	.draggable()//ドラッグ

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

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

	//TEXT
	var text=draw.text('svg()立体風陰影Filter').font({leading:0.8})

	//LOGO文字
	var logotext=draw.text('POPS').attr({'fill':'#FF69B4'}).move(80,60)
	.font({
		family:'Arial'
		,'size':50
		,'font-weight':'bold'
		,anchor:'middle'
		,leading:1
	})

	//立体風
	.filter(function(add) {

		//現在convolveMatrix()の形態が違うので、メソッドでは出来ない
		//svg()方式のみ
		this.svg('<feConvolveMatrix order="4 4" kernelMatrix="1 0 0 0, 0 1 0 0, 0 0 1 0, 0 0 0 1" in="SourceAlpha" result="BEVEL" /><feOffset dx="2" dy ="2" in="BEVEL" result="OFFSET" /><feMerge><feMergeNode in="OFFSET" /><feMergeNode in="SourceGraphic" /></feMerge>')

	})


componentTransfer() [feComponentTransfer]、色の変換

▲[目次]

画素のRGBAの毎に、減色(discrete)、反転(table)、ネガポジ変換(linear)、明度調整、コントラスト調整、色バランス、等の色調補正(gamma)、閾値による切り抜き(thresholding)などに用いる。
type属性には、identity table discrete linear gammaがある。詳細はマニュアルの画像フィルター、SVG規格を参照されたし。

type属性 identity は「恒等変換」つまり元のまま。componentTransfer()フィルター解除をする為のものみたいだ。書式は


add.componentTransfer({
	rgb:{type:'identity'}
})

tableValues書式、以下同じである。


tableValues:[1,0]
tableValues:'1,0'

ブラウザにより見た目が若干違う場合があります。

3番目dot絵はパクリをsvg.filter.js用に変換してみました。svgのfilterを使ってドット階調っぽい効果をつける
(IE11は対応していません)



サンプルJS


	//対象エレメントID
	var draw=SVG('svg-test-filter13').size(160,160)

	var text=draw.text('invert').font({leading:0.8})

	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ
	//invert
	.filter(function(add) {

		add.componentTransfer({
			rgb:{type:'table',tableValues:'1,0'}
		})
		//これでも同じ結果になる
		//add.componentTransfer({
			//rgb:{type:'linear',slope:-1,intercept:1}
		//})

	})

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

	//対象エレメントID
	var draw=SVG('svg-test-filter14').size(160,160)

	var text=draw.text('posterize減色').font({leading:0.8})

	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ
	//posterize
	.filter(function(add) {
		add.componentTransfer({
			rgb:{type:'discrete',tableValues:'0,0.2,0.4,0.6,0.8,1'}
		})
	})

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

	//dot絵
	//http://defghi1977-onblog.blogspot.jp/2012/03/svgfilter_19.html
	//対象エレメントID
	var draw=SVG('svg-test-filter15').size(160,160)

	//200x200
	var image=draw.image('/main/images/lady01.png').size(160,160).center(80,80)
	.filter(function(add) {

		//4階調
		//画像をグレーに変換
		var alpha=add.colorMatrix('luminanceToAlpha').in(add.source)

		//画像の明度を階段状に取得する
		var a1=add.componentTransfer({rgb:{type:'discrete',tableValues:'1,1,1,0,1'}}).in(alpha)
		var a2=add.componentTransfer({rgb:{type:'discrete',tableValues:'1,1,0,1,1'}}).in(alpha)
		var a3=add.componentTransfer({rgb:{type:'discrete',tableValues:'1,0,1,1,1'}}).in(alpha)
		var a4=add.componentTransfer({rgb:{type:'discrete',tableValues:'0,1,1,1,1'}}).in(alpha)

		//明度階調をドットで表すための単位図形
		var dotTileBg=add.flood('#FFF',0).attr({'x':0,'y':0,'width':2,'height':2})
		var dot=add.flood('#000',1).attr({'x':0,'y':0,'width':1,'height':1})
		var dotUnit=add.merge(dotTileBg,dot)

		//明度階調毎のパターン図形を生成
		var dotTile1=add.tile().in(dotUnit).attr({'x':0,'y':0,'width':160,'height':160})
		var predotTile2=add.offset(1,0).in(dotTile1)
		var predotTile3=add.offset(0,1).in(dotTile1)
		var dotTile2=add.merge(dotTile1,predotTile2)
		var dotTile3=add.merge(dotTile1,predotTile2,predotTile3)
		var dotTile4=add.flood('#000',1)

		//階調毎に図形を切り抜き,重ねあわせる
		var b1=add.composite(dotTile1,a1,'out')
		var b2=add.composite(dotTile2,a2,'out')
		var b3=add.composite(dotTile3,a3,'out')
		var b4=add.composite(dotTile4,a4,'out')
		//出力
		add.merge(b1,b2,b3,b4)

	})


colorMatrix() [feColorMatrix]、色の行列変換

▲[目次]

4x5行列による変換です。よく使いそうなものについては予め定義されている。
type属性は、matrix saturate hueRotate luminanceToAlpha、ですが matrix 以外は簡略形式です。
この辺SVGは親切だ。


Matrixの初期値
values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"

実行しても何も変わらない、Matrix解除に有効か
add.colorMatrix('matrix','1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0')

matrixを変えた場合の効果は、実際には認識しがたい。Flex用だが下記サイトの「シミュレーション」で確認できます。
Flex ColorMatrixFilters


全てmatrixの書式で行うのが大変なため、実際はmatrix処理なのですが、SVGでは簡略方式が用意されています。
タイプ saturate hueRotate luminanceToAlpha が実行可能です。svg.filter.jsでは次の書式で行えます。
タイプmatrixを使用する事はほとんど無いと思います、必要なら各自勉強して下さい。


彩度調整、0は白黒になる
saturate、0-1の値を指定
add.colorMatrix('saturate',0)

hsl色に変換
hue rotate、0-360の値を指定
add.colorMatrix('hueRotate',180)

白黒にして反転
luminanceToAlpha、値なし
add.colorMatrix('luminanceToAlpha')

簡単な desaturate と hueRotate の状況をみることが出来ます。



サンプルJS



	//colorMatrix
	//対象エレメントID
	var draw=SVG('svg-test-filter16').size(160,160)

	var desaturate_elm
	var desaturate_v=0
	var slider_text=draw.text('desaturate').font({leading:0.8})

	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ
	.filter(function(add) {
		//desaturate
		add.colorMatrix('saturate', 0)
		//sum
		desaturate_elm=this.get(0)
	})

	//slider
	var slider_group=draw.group()
	slider_group.rect(0,0,100,10)
	//100幅の所、角丸のため110幅にしている
	var btn_base=slider_group.rect(110,8).attr({'fill':'#CCC','stroke':'#888','stroke-width':1}).radius(4).center(50,5)
	var guidline=slider_group.path('M 0 5 L 100 5').attr({'fill':'none','stroke':'#F00','stroke-width':1})
	var drag_btn=slider_group.circle(10).attr({'fill':'#F00','stroke':'#000','stroke-width':2}).center(0,5)
	.draggable(function(x,y) {

		//ベースの範囲内に補正/group2を基本とした値になる
		if(x < -5){x=-5}
		if(x > 95){x=95}

		desaturate_v=Math.floor((x+5)/100*100)/100

  		return {x:x,y:0}
	})
	.on('dragmove.namespace',function(event){

		desaturate_elm.attr({'values':desaturate_v})
		slider_text.text('saturate '+desaturate_v)

	})
	slider_group.move(30,145)

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

	//対象エレメントID
	var draw=SVG('svg-test-filter17').size(160,160)

	var hueRotate_elm
	var hueRotate_v=180
	var slider_text2=draw.text('hueRotate 180').font({leading:0.8})

	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ
	.filter(function(add) {
		//hueRotate
		add.colorMatrix('hueRotate',180)
		//sum
		hueRotate_elm=this.get(0)
	})

	//slider2
	var slider_group2=draw.group()
	slider_group2.rect(0,0,100,10)
	//100幅の所、角丸のため110幅にしている
	var btn_base=slider_group2.rect(110,8).attr({'fill':'#CCC','stroke':'#888','stroke-width':1}).radius(4).center(50,5)
	var guidline=slider_group2.path('M 0 5 L 100 5').attr({'fill':'none','stroke':'#F00','stroke-width':1})
	var drag_btn=slider_group2.circle(10).attr({'fill':'#F00','stroke':'#000','stroke-width':2}).center(50,5)
	.draggable(function(x,y) {

		//ベースの範囲内に補正/group2を基本とした値になる
		if(x < -5){x=-5}
		if(x > 95){x=95}

		hueRotate_v=Math.round((x+5)*3.6*100)/100

  		return {x:x,y:0}
	})
	.on('dragmove.namespace',function(event){

		hueRotate_elm.attr({'values':hueRotate_v})
		slider_text2.text('hueRotate '+hueRotate_v)

	})
	slider_group2.move(30,145)

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

	//対象エレメントID
	var draw=SVG('svg-test-filter18').size(160,160)

	var text=draw.text('luminanceToAlpha').font({leading:0.8})

	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ
	.filter(function(add) {
		//luminanceToAlpha
		add.colorMatrix('luminanceToAlpha')
	})

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

	//対象エレメントID
	var draw=SVG('svg-test-filter19').size(160,160)

	var text=draw.text('sepiatone').font({leading:0.8})

	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ
	.filter(function(add) {
		//sepiatone
  		add.colorMatrix('matrix',[ .343, .669, .119, 0, 0
				, .249, .626, .130, 0, 0
				, .172, .334, .111, 0, 0
				, .000, .000, .000, 1, 0 ])
	})

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

	//対象エレメントID
	var draw=SVG('svg-test-filter20').size(160,160)

	var text=draw.text('colorize').font({leading:0.8})

	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ
	.filter(function(add) {
		//colorize
		add.colorMatrix('matrix',[ 1.0, 0, 0, 0, 0
				, 0, 0.2, 0, 0, 0
				, 0, 0, 0.2, 0, 0
				, 0, 0, 0, 1.0, 0 ])
	})

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

	//対象エレメントID
	var draw=SVG('svg-test-filter21').size(160,160)

	var text=draw.text('matrixテキトウ調整').font({leading:0.8})

	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ
	.filter(function(add) {
		//テキトウ調整
		add.colorMatrix('matrix',[1,0.65,0,0,0,0,1,0,0,0,0,0.73,0.43,0,0,0,0,0,1,0])
	})


colorize専用Matrix値の計算 / Matrixは直感的に判らないですね


利用方法、取得したストリングを下記の様に挿入する。


.filter(function(add){
	//colorize
	add.colorMatrix('matrix','ストリング')
})

convolveMatrix() [feConvolveMatrix]、行列コンボリューションフィルタ効果

▲[目次]

ぼかし、輪郭抽出、シャープ、エンボス、の効果を簡単に得ることが出来ます。

まだ、convolveMatrix()は暫定的で、引数はkernelMatrix属性だけです。orderは自動計算されます。
targetX,targetY,edgeMode,divisor,bias,preserveAlpha属性の設定は、attr()で可能ですが、svg()で処理した方が無難かもしれません。


filter.convolveMatrix(matrix)

下記kernelMatrix実行結果は同じです
var matrix=add.convolveMatrix([1,0,0, 0,1,0, 0,0,1])
var matrix=add.convolveMatrix('1 0 0, 0 1 0, 0 0 1')
var matrix=add.convolveMatrix('1 0 0 0 1 0 0 0 1')

【ジェネレーター】tsudoi.orgの記事: feConvolveMatrix-行列コンボリューションフィルタ効果


var image=draw.image(..).....
.filter(function(add) {
	//svg()で処理
	this.svg('得られたHTMLのインデントなど除去して並べる')
})

もし16番、エンボスをconvolveMatrix()形式で書くなら、下記の様になる。


var emboss=add.convolveMatrix('-2 -1 0, -1 1 1, 0 1 2')
.attr({'order':'3','edgeMode':'none','divisor':1,'bias':0,'preserveAlpha':true})
var shadow=add.offset(0,0).in(add.sourceAlpha).gaussianBlur(3)
add.merge(shadow,emboss)

● 14番、マニュアル例
feConvolveMatrixは色々あるようで難しいから、問題があればsvg()で処理すれば良い。

● 15,16番、ジェネレーター出力のシャープ、エンボスの例です。(陰影処理のため、最後にresult属性を入れました)


14番、画像convolveMatrix(ぼかし) / 15番、画像feConvolveMatrix(シャープ) / 16番、エンボス


14番、SVG.jsのconvolveMatrix()の処理は限られていますが、(まだ暫定的なものと思う)
15番、feConvolveMatrixのサンプルHTMLを得られれば結構沢山の処理が出来る様です。
下記サイトにジェネレーターがあります。のでsvg()形式で記述すれば簡単にエフェクトを作れます。(サンプルはシャープネス)

filter.image()は角形画像ですから、composite()でマスクして使用します。
画像読み込みはfilter処理関数内で行います。関数内のインスタンス(オブジェクト)はリザルト値となります。
draw.image()では取り込まれませんので注意ください(ステージに描画されてしまう)。


//処理関数
.filter(function(add) {
	//filter内の画像読み込み
	var リザルト=add.image('/main/images/wall.gif').size(70,70)....

	処理

})

サンプルJS


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

	//TEXT
	var text=draw.text('convolveMatrix画像専用').font({leading:0.8})

	//画像
	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ
	.filter(function(add){
		//マニュアルサンプルより
		var matrix=add.convolveMatrix([1,0,0, 0,1,0, 0,0,1])
		var shadow=add.offset(0,0).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,matrix)

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})

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

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

	//TEXT
	var text=draw.text('画像 feConvolveMatrix').font({leading:0.8})

	var image=draw.image('/main/images/testImage101.jpg').size(100,100).center(80,80)

	.draggable()//ドラッグ
	.filter(function(add) {

		//svg()/シャープネス/result属性追加して処理
		this.svg('<feConvolveMatrix order="3 3" edgeMode="none" kernelMatrix="0 -1 0 -1 5 -1 0 -1 0" divisor="1" bias="0" preserveAlpha="true" result="result0"></feConvolveMatrix>')

	})

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

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

	//TEXT
	var text=draw.text('画像 feConvolveMatrix').font({leading:0.8})

	var image=draw.image('/main/images/testImage101.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ
	//embossing 
	.filter(function(add) {

/*
		this.svg('<feConvolveMatrix order="3 3" edgeMode="none" kernelMatrix="-2 -1 0, -1 1 1, 0 1 2" divisor="1" bias="0" preserveAlpha="true" result="result0"></feConvolveMatrix>')
		var result=this.get(0).attr('result')//0
		var shadow=add.offset(2,2).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,result)
*/
		var emboss=add.convolveMatrix('-2 -1 0, -1 1 1, 0 1 2')
		.attr({'order':'3','edgeMode':'none','divisor':1,'bias':0,'preserveAlpha':true})
		var shadow=add.offset(0,0).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,emboss)

	})


displacementMap() [feDisplacementMap]、空間変異

▲[目次]

feTurbulance(パーリンノイズ)と組み合わせて画像をfeDisplacementMap(空間変異)変形させた。feTurbulanceで複雑な揺らぎを表現できるが、どのような形になるかアタマで考えてもわからない。下記シミュレーションで少しは理解できると思います。
SVGでは簡単に出来る様になっています。詳細は「SVG規格」など参照ください。


● 簡易perlin-noiseの操作

同じperlin-noiseでの、diffuseLighting処理、displacementMap処理の状態です。diffuseLighting処、displacementMapの条件が違えばまた別のものになります。

このような感じですから余り利用することは少ないと思います。現実的にはInkscapeのエフェクトをパクるのが早道かも...


画像パーリンノイズは「svg要素の基本的な使い方まとめ、画像効果」よりのパクリです。

17番、画像パーリンノイズFilter / 18番、画像パーリンノイズ2 / 19番、画像パーリンノイズ3


サンプルJS


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

	//TEXT
	var text=draw.text('画像パーリンノイズ').font({leading:0.8})

	//image
	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ
	//noise-filter
	.filter(function(add){

		//パーリンノイズ
		//(baseFrequency, numOctaves, seed, stitchTiles, type)
		var noise=add.turbulence('0.995',1,1,'noStitch','fractalNoise')
		//dispmap処理
		//(in1, in2, scale, xChannelSelector, yChannelSelector)
		var dispmap=add.displacementMap(add.source,add.noise,20,'R','G')

	})

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

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

	//TEXT
	var text=draw.text('画像パーリンノイズ2').font({leading:0.8})

	//image
	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ
	//noise-filter
	.filter(function(add){

		//パーリンノイズ2
		var noise=add.turbulence('0.1',10,3,'stitch','fractalNoise')
		//dispmap処理
		var dispmap=add.displacementMap(add.source,add.noise,20,'R','G')

	})

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

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

	//TEXT
	var text=draw.text('画像パーリンノイズ3').font({leading:0.8})

	//image
	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ
	//noise-filter
	.filter(function(add){

		//パーリンノイズ3
		var noise=add.turbulence('0.01 0.05',1,3,'noStitch','fractalNoise')
		//dispmap処理
		var dispmap=add.displacementMap(add.source,add.noise,20,'R','G')

	})


feTurbulance / perlin noise


サンプルJS


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

	var noise_rect1=draw.rect(160,160).attr({'fill':'#000'})

	//noise-filter
	.filter(function(add){
		//パーリンノイズ
		//(baseFrequency, numOctaves, seed, stitchTiles, type)
		var noise=add.turbulence('0.05',2,1,'noStitch','turbulence')
	})

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

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

	var noise_rect2=draw.rect(160,160).attr({'fill':'#000'})

	//noise-filter
	.filter(function(add){
		//パーリンノイズ
		var noise=add.turbulence('0.1',4,1,'noStitch','fractalNoise')

	})

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

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

	var noise_rect3=draw.rect(160,160).attr({'fill':'#000'})

	//noise-filter
	.filter(function(add){
		//パーリンノイズ
		var noise=add.turbulence('0.4',4,1,'noStitch','fractalNoise')

	})


perlin noiseのdiffuseLighting処理


サンプルJS


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

	var noise_rect4=draw.rect(160,160).attr({'fill':'#FFF'})

	//noise-filter
	.filter(function(add){

		//Chrome注意
		//(baseFrequency, numOctaves, seed, stitchTiles, type)/(surfaceScale,diffuseConstant,kernelUnitLength)
		var noise=add.turbulence('0.04',5,1,'noStitch','fractalNoise').in(add.sourceAlpha).diffuseLighting('2',null,'1').svg('<feDistantLight azimuth="45" elevation="35"/>')
		var diffuse=this.get(1)
		diffuse.attr({'lighting-color':'white'})//設定なきは白色

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})

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

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

	var noise_rect4=draw.rect(160,160).attr({'fill':'#FFF'})

	//noise-filter/設定違い
	.filter(function(add){

		//Chrome注意
		var noise=add.turbulence('0.4',2,1,'noStitch','fractalNoise').in(add.sourceAlpha).diffuseLighting('2',null,'1').svg('<feDistantLight azimuth="45" elevation="35"/>')
		var diffuse=this.get(1)//diffuseLighting
		diffuse.attr({'lighting-color':'white'})//Chrome修正

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})

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

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

	var noise_rect4=draw.rect(160,160).attr({'fill':'#FFF'})

	//noise-filter/設定違い
	.filter(function(add){

		//Chrome注意
		var noise=add.turbulence('0.02',2,1,'noStitch','turbulence').in(add.sourceAlpha).diffuseLighting('2',null,'1').svg('<feDistantLight azimuth="45" elevation="35"/>')
		var diffuse=this.get(1)//diffuseLighting
		diffuse.attr({'lighting-color':'white'})//Chrome修正

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})


パール模様をレクトに描画します。塗りこみ模様または背景として利用可能です。


var noise_rect=draw.rect(160,160)
.filter(function(add){
	this.svg('<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="10" seed="3" stitchTiles="noStitch"/>')
	this.attr({'filterUnits':'userSpaceOnUse','x':0,'y':0,'width':160,'height':160})
})
-----------------------------------------
svg.filter.js形式ならば

//(baseFrequency, numOctaves, seed, stitchTiles, type)
add.turbulence(0.01,10,3,'noStitch','turbulence')
this.attr({'filterUnits':'userSpaceOnUse','x':0,'y':0,'width':160,'height':160})

このような模様などを図形に塗りこむ場合はマスクしないと塗りこめないことが多いので一応注意します。composite()が便利。


add.composite(noise,add.sourceAlpha,'in')

サンプルJS




morphology() [feMorphology]、侵食膨張

▲[目次]

morphology()は画像の侵食、膨張を行います。文字の場合はグループの中でstroke違いのTEXTを複数重ねたほうが簡単と言えばそれまでですが、ここではmorphology()で処理してみます。予想以上に煩雑ですからヨク理解して下さい。


● morphology()でoutlineを作る。通常は白色で使用することが多いと思います。
例えば、filter処理関数内で次書式で黒のアウトライン(重ねればアウトラインに見える、マスクすればラインに成る)が得られます。


var morphology=add.morphology('dilate','3').in(add.sourceAlpha)//黒色

dilate は大きく、erode は小さくなります

matrix

 

morphology()で得られたoutlineは黒色なので、通常のMatrixでは白になりません。
そこで特殊な設定のcolorMatrix()で白にします。白以外の指定も可能です。

色指定の方法、10進のRGB値を255で割った値を代入すると指定の色に出来る(0-1の値)。
メンドウなので、色変換のジェネレータを作ってみました。若干薄い色になりますが簡単にMatrixのデータが得られます。



'1 0 0 0 0, 0 1 0 0 0, 0 0 1 0 0, 0 0 0 1 0'//通常のMatrixでは変化なし
'-1 0 0 1 0, 0 -1 0 1 0, 0 0 -1 1 0, 0 0 0 1 0'//特殊な設定で白にする

'-1 0 0 0.5 0, 0 -1 0 0.5 0, 0 0 -1 0.5 0, 0 0 0 1 0'//#808080に近い灰色

'-1 0 0 R 0, 0 -1 0 G 0, 0 0 -1 B 0, 0 0 0 1 0'//それぞれを変化させれば自由な色になる

'-1 0 0 0 0, 0 -1 0 0 0, 0 0 -1 0 0, 0 0 0 1 0'//黒でMatrixの意味なし

それぞれの色と変化


//白にする
var morphology=add.morphology('dilate','3').in(add.sourceAlpha)//黒色
var cmatrix=add.colorMatrix('matrix','-1 0 0 1 0, 0 -1 0 1 0, 0 0 -1 1 0, 0 0 0 1 0').in(morphology)//白

----------------------------------------------
//指定色にする
var morphology=add.morphology('dilate','3').in(add.sourceAlpha)//黒色
var cmatrix=add.colorMatrix('matrix','-1 0 0 0.929 0, 0 -1 0 0.639 0, 0 0 -1 0.694 0, 0 0 0 1 0').in(morphology)//指定色

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

//文字が、白黒以外の色で着色されていれば多少変化があるが、使用したくは無い
var cmatrix=add.colorMatrix('luminanceToAlpha').in(morphology)

● feMorphology用colorMatrix簡易変換(OutLine色専用)

▲[目次]

齢のせいか色が若干薄めのようだ。

各RGBバーを調整して色を得ます。もし、10進の色がわかれば、バーの調整で設定が得られます。


【参考】RGB10進値がわかるカラーチャート資料: WEBカラーチャート



カスタムmorphologyは周囲に陰影をつけて、ふくらみを表現したものですが、内側のラインのぼかしではラインが細くなるので、外側ラインを加えているのがミソです。別途INNER-SHADOWよりふくらみを強調できると思います。specularLighting()と比較して画像が白っぽくならないのが最大の利点です。

サンプルJS


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

	//TEXT
	var text=draw.text('カスタムmorphology').font({leading:0.8})

	var image=draw.image('/main/images/testImage108.jpg').size(160,160).scale(100/160).center(80,80)
	var image_rect=draw.rect(100,100).radius(10).attr({'fill':image}).center(80,80)

	//カスタムinline-shadow
	.filter(function(add){

		//2つのラインを組み合わせ調整
		var morphology=add.morphology('erode','6').in(add.sourceAlpha)
		var morphology2=add.morphology('erode','3').in(add.sourceAlpha)
		var inlinebase=add.composite(add.sourceAlpha,morphology2,'xor').gaussianBlur(2)
		var inlineblur=add.composite(add.sourceAlpha,morphology,'xor').gaussianBlur(3)
		var inline=add.merge(inlinebase,inlineblur)
		var shadow=inline.composite(add.sourceAlpha,'in')
		var dp_shadow=add.offset(2,2).in(add.sourceAlpha).gaussianBlur(5)
		add.merge(dp_shadow,add.source,shadow)//merge

	})

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

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

	//TEXT
	var text=draw.text('feMorphology outline').font({leading:0.8})

	//SVG文字
	var logo_text10=draw.text('ViVa').attr({'fill':'#F00','stroke':'#FFF','stroke-width':1}).move(80,45)
	.font({
		family:'Times New Roman'
		,'size':65
		,'font-weight':'bold'
		,anchor:'middle'
		,leading:1
	})

	//morphology
	.filter(function(add){

		//Firefox、radius値文字形のこと
		var morphology=add.morphology('dilate','3').in(add.sourceAlpha)//黒色
		var cmatrix=add.colorMatrix('matrix','-1 0 0 0.929 0, 0 -1 0 0.639 0, 0 0 -1 0.694 0, 0 0 0 1 0').in(morphology)
		//outlineでshadowを作る
		var shadow=add.morphology('dilate','3').in(add.sourceAlpha).offset(5,5).gaussianBlur(5)
		var merge=add.merge(shadow,cmatrix,add.source)//merge

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})

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

	//TEXT
	var text=draw.text('feMorphology outline').font({leading:0.8})

	//SVG文字
	var logo_text11=draw.text('POPS').attr({'fill':'#BBB','stroke':'#FFF','stroke-width':1}).move(80,60)
	.font({
		family:'Arial'
		,'size':50
		,'font-weight':'bold'
		,anchor:'middle'
		,leading:1
	})

	//画像morphology
	.filter(function(add){

		//outlineで画像をmask
		var base_image=add.image('/main/images/textback13.png').size(640,100).move(0,30)
		var morphology=add.morphology('dilate','3').in(add.sourceAlpha)
		var base=add.composite(base_image,morphology,'in')
		//outlineでshadowを作る
		var shadow=add.morphology('dilate','3').in(add.sourceAlpha).offset(5,5).gaussianBlur(3)
		var merge=add.merge(shadow,base,add.source)//merge

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})


文字のMorphology拡張、豪華Kokekokkou

この例では陰影は小さくなっています。手間隙のかかるKokekokkouです。


サンプルJS


	//morphologyTEXTグループなし
	//エレメントID
	var draw=SVG('svgtext-fliter-0a').size(640,100)

	//文字
	var koke_text=draw.text('Hello Kokekokkou').move(320,15)
	.font({
		family:'Times New Roman'
		,size:65
		,'font-weight':'bolder'
		,anchor:'middle'
		,leading:1
	})
	.attr({'fill':'#F00'})
	.filter(function(add) {

		//outline-shadow
		var morphology=add.morphology('dilate','3').in(add.sourceAlpha)
		var cmatrix=add.colorMatrix('matrix','-1 0 0 1 0, 0 -1 0 1 0, 0 0 -1 1 0, 0 0 0 1 0').in(morphology)
		//shadow/中の文字の大きさ
		var shadow=add.offset(5,5).in(add.sourceAlpha).gaussianBlur(5)
		add.merge(shadow,cmatrix,add.source)//merge

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})


文字のMorphology拡張見せ掛けのウッチャリ2段重ねでハッケヨイ

Morphology拡張は行っていません。stroke文字を下においてのゴマカシです。(Houhokekyoに手間隙かけられるか!)


サンプルJS


	//morphologyTEXTグループなし
	//エレメントID
	var draw=SVG('svgtext-fliter-0b').size(640,100)

	//文字2
	var hokekyo2_text=draw.text('Hello Houhokekyo').move(320,15)
	.font({
		family:'Arial'
		,size:65
		,'font-weight':'bolder'
		,anchor:'middle'
		,leading:1
	})
	.attr({'fill':'#FFF','stroke':'#FFF','stroke-width':6})
	.filter(function(add) {
		var shadow=add.offset(5,5).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,add.source)//merge

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK
	})

	//文字1
	var hokekyo1_text=draw.text('Hello Houhokekyo').move(320,15)
	.font({
		family:'Arial'
		,size:65
		,'font-weight':'bolder'
		,anchor:'middle'
		,leading:1
	})
	.attr({'fill':'#928c36'})


image() [feImage]とtile() [feTile]、画像の挿入敷き詰め

▲[目次]

● tileフィルター、画像フィルターが追加なっています。どちらもフィルター処理関数、.filter(function(add){...})の中で使用するものです。画像は角形ですので、角丸、円形などグラフイック要素に入れる場合は通常composite()でマスクすることになります。fill:imageと似通っている面がありますが、スケールの変更は機能しません。


20番、tile画像Filter / 21番、tile画像Filter / 22番、画像Filter


サンプルJS


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

	//TEXT
	var text=draw.text('tile画像Filter drag').font({leading:0.8})

	//グループ化
	var logo_group=draw.group()

	//LOGO文字
	var logotext2=draw.text('POPS').attr({'fill':'#000'}).move(80,60)
	.font({
		family:'Arial'
		,'size':50
		,'font-weight':'bold'
		,anchor:'middle'
		,leading:1
	})

	//add
	logo_group.add(logotext2)
	.draggable()//ドラッグ
	.attr({'filter':'url(#dropShadow2)'})//陰影

	//tile
	logotext2.filter(function(add) {

		//画像加工なしのため完全読み込みでなくともOK
		//size設定重要/Firefoxはin設定重要
		var logoimage=add.image('/main/images/wall.gif').size(70,70).attr({'in':'SourceGraphic'})

		//pattern/こちら推奨
		var tilepattern=add.tile().in(logoimage)
		add.composite(tilepattern,add.sourceAlpha,'in')

	})

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

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

	//TEXT
	var text=draw.text('tile画像Filter drag').font({leading:0.8})

	//グループ化
	var rect_group=draw.group()
	var tile_rect=draw.rect(100,100).radius(10).attr({'fill':'#CCC'}).center(80,80)
	//add
	rect_group.add(tile_rect)
	var stroke_rect=draw.rect(100,100).radius(10).attr({'fill':'none','stroke':'#FFF','stroke-width':2}).center(80,80)
	//add
	rect_group.add(stroke_rect)
	.draggable()//ドラッグ
	.attr({'filter':'url(#dropShadow2)'})//陰影

	//tile-filter
	tile_rect.filter(function(add) {

		//画像加工なしのため完全読み込みでなくともOK
		//size設定重要/Firefoxはin設定重要
		var logoimage=add.image('/main/images/wall.gif').size(70,70).attr({'in':'SourceGraphic'})
		//pattern/こちら推奨
		var tilepattern=add.tile().in(logoimage)
		add.composite(tilepattern,add.sourceAlpha,'in')
	})


 

svg.filter.js標準の「画像Filter」とDropShadow

▲[目次]

通常、画像にFilter処理した場合、2重にDropShadowを処理出来ませんので、グループ化してグループ側にDropShadow処理します。但し、Filter処理によってはDropShadowが掛からない場合もあります。
メンドウなので、画像にFilter処理した際にDropShadowも描いてみます。但しこの場合もDropShadow処理出来ない事もあります。このような時は原因を確認して修正なりしますが、意外と判らないから困る。


標準画像FilterにDropShadowを追加しています。


サンプルJS


	//dropshadowの追加
	//エレメントID
	var draw=SVG('add-dropshadow-1a').size(160,160)

	//TEXT
	var text=draw.text('dropshadowの追加 drag').font({leading:0.8})

	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ

	//セピア色sepiatone
	.filter(function(add){

		//filterの種類
		var effect=add.colorMatrix('matrix',[.343,.669,.119,0,0
			,.249,.626,.130,0,0
			,.172,.334,.111,0,0
			,.000,.000,.000,1,0])
		//shadow
		var shadow=add.offset(0,0).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,effect)

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})

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

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

	//TEXT
	var text=draw.text('dropshadowの追加 drag').font({leading:0.8})

	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ

	//hue rotate 180
	.filter(function(add){

		//filterの種類
		var effect=add.colorMatrix('hueRotate',180)
		//shadow
		var shadow=add.offset(5,5).in(add.sourceAlpha).gaussianBlur(2)
		add.merge(shadow,effect)

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})

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

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

	//TEXT
	var text=draw.text('dropshadowの追加 drag').font({leading:0.8})

	var image=draw.image('/main/images/testImage102.jpg').size(100,100).center(80,80)
	.draggable()//ドラッグ

	//posterize
	.filter(function(add){

		//filterの種類
		var effect=add.componentTransfer({
			rgb:{type:'discrete',tableValues:'0,0.2,0.4,0.6,0.8,1'}
		})
		//shadow
		var shadow=add.offset(5,5).in(add.sourceAlpha).gaussianBlur(5)
		add.merge(shadow,effect)

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})


INNER-SHADOW

▲[目次]

場合によってはこのような効果も良い。3番は画像が白くならない利点がある。それら全てパクリである。
1,2番目は、Learning SVG: lesson 2を参照ください。
3番目は、JSFiddleの記事を参照ください。

1,2番目、INNER-SHADOW/3番は上下2方向にINNER-SHADOWを処理。


1,2番目をsvg.filter.js方式に書き換えれば下記の様になる。offsetの設定方向違いだけ。


.filter(function(add) {
	var blur=add.offset(5,5).in(add.sourceAlpha).gaussianBlur(2)
	var shadowDiff=add.composite(blur,add.sourceAlpha,'arithmetic').attr({'k1':0,'k2':-1,'k3':1,'k4':0})
	var effect=add.flood('#000',1).composite(shadowDiff,'in').composite(add.source,'over')
})
----------------------------------------
.filter(function(add) {
	var blur=add.offset(-5,-5).in(add.sourceAlpha).gaussianBlur(2)
	var shadowDiff=add.composite(blur,add.sourceAlpha,'arithmetic').attr({'k1':0,'k2':-1,'k3':1,'k4':0})
	var effect=add.flood('#000',1).composite(shadowDiff,'in').composite(add.source,'over')
})

サンプルJS


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

	//TEXT
	var text=draw.text('inner-shadow').font({leading:0.8})

	var image=draw.image('/main/images/testImage108.jpg').size(100,100).center(80,80)
	//inner-shadow
	.filter(function(add) {

		this.svg('<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur"/><feOffset dy="5" dx="5"/><feComposite in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowDiff"/><feFlood flood-color="black" flood-opacity="1"/><feComposite in2="shadowDiff" operator="in"/><feComposite in2="SourceGraphic" operator="over"/>')

	})

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

	//TEXT
	var text=draw.text('inner-shadow').font({leading:0.8})

	var image=draw.image('/main/images/testImage108.jpg').size(100,100).center(80,80)
	//inner-shadow
	.filter(function(add) {

		this.svg('<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur"/><feOffset dy="-5" dx="-5"/><feComposite in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowDiff"/><feFlood flood-color="black" flood-opacity="1"/><feComposite in2="shadowDiff" operator="in"/><feComposite in2="SourceGraphic" operator="over"/>')

	})

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

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

	//TEXT
	var text=draw.text('inner-shadow').font({leading:0.8})

	var image=draw.image('/main/images/testImage108.jpg').size(100,100).center(80,80)
	//inner-shadow
	.filter(function(add) {

		this.svg('<feGaussianBlur in="SourceAlpha" stdDeviation="3" result="blur"></feGaussianBlur><feOffset dy="4" dx="5"></feOffset><feComposite in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowDiff"></feComposite><feFlood flood-color="#000" flood-opacity="1"></feFlood><feComposite in2="shadowDiff" operator="in"></feComposite><feComposite in2="SourceGraphic" operator="over" result="firstfilter"></feComposite><feGaussianBlur in="firstfilter" stdDeviation="3" result="blur2"></feGaussianBlur><feOffset dy="-4" dx="-5"></feOffset><feComposite in2="firstfilter" operator="arithmetic" k2="-1" k3="1" result="shadowDiff"></feComposite><feFlood flood-color="#000" flood-opacity="1"></feFlood><feComposite in2="shadowDiff" operator="in"></feComposite><feComposite in2="firstfilter" operator="over"></feComposite>')

	})


 

大きなTEXTにfilter設定した場合の例

▲[目次]

大きなTEXTにベベルなどを設定して様子を見ます。これらのエフェクトはInkscapeに沢山有りますので困らないでしょう。
但し、svg.filter.js処理で上手く行かない場合は、SVGをヨク確認ください。それなりの理由はあるはずです。


TEXT-1、Inkscapeプラスチック


サンプルJS


	//TEXT-1
	//エレメントID
	var draw=SVG('svgtext-fliter-1a').size(640,100)

	//文字描画
	var text1=draw.text('POPSWEB')
	.font({
		family:'Times New Roman'
		,size:80
		,'font-weight':'bolder'
		,anchor:'middle'
		,leading:1
	})

	//move暫定値で配置
	text1.attr({fill:'#333','stroke':'#FFF','stroke-width':1}).move(320,5)

	//Inkscape-plastic
	.filter(function(add) {

		this.svg('<feGaussianBlur in="SourceGraphic" result="result6" stdDeviation="5"/><feComposite in2="SourceGraphic" in="result6" operator="xor"/><feGaussianBlur result="result2" stdDeviation="5"/><feComposite in2="SourceGraphic" operator="atop" result="result91"/><feComposite in2="result91" result="result4" in="result2" operator="xor"/><feGaussianBlur in="result4" result="result3" stdDeviation="5"/><feSpecularLighting lighting-color="rgb(255,255,255)" in="result3" result="result5" specularExponent="35" specularConstant="3" surfaceScale="12"><feDistantLight elevation="45" azimuth="235"/></feSpecularLighting><feComposite in2="result5" in="SourceGraphic" k3="0.7" k2="0.8" operator="arithmetic" result="result7"/><feComposite in2="SourceGraphic" in="result7" operator="in" result="result8"/>')
		effect=this.get(8).attr('result')
		var shadow=add.offset(4,4).in(add.sourceAlpha).gaussianBlur(2)
		add.blend(effect,shadow)

		this.attr({'color-interpolation-filters':'sRGB'})

	})


TEXT-2、文字のMorphology拡張、東京五輪ピック2020

この例に限り、陰影をつけるなら、グループ化してグループにurl()で処理する方法が簡単です。(前ページ参照)

カーニングで文字間をつめています。ここで Firefox のみfilter処理出来ませんので、グループで処理しています。


サンプルJS


	//TEXT-2/グループなし
	//エレメントID
	var draw=SVG('svgtext-fliter-1b').size(640,100)

	//ストリング
	var main_strings="ViVa Tokyo Golympic 2020!"

	//空文字
	var k_text=draw.text('')
	.font({
		family:'Times New Roman'
		,size:65
		,'font-weight':'bolder'
		,anchor:'left'
		,leading:1
	})

	//カーニングと画像塗り
	var spikes=main_strings.length
	k_text.text(function(add) {
		for (var i=0; i<spikes;i++){

			//虹色hsl直接
			var angle_no=Math.floor(i/spikes*360)//0-360
			var color='hsl(' + angle_no + ',100%,50%)'
			//1文字
			var tx=main_strings.charAt(i)
			add.tspan(tx).attr({'dx':-10,'fill':color,'stroke':'#CCC','stroke-width':1})
			//ここでのfilter、Firefox対応していません

		}
	})

	//move位置移動
	k_text.move(50,15)

	//TEXT全体の処理morph-shadow
	.filter(function(add) {

		//outline-shadow
		var morphology=add.morphology('dilate','3').in(add.sourceAlpha)
		var cmatrix=add.colorMatrix('matrix','-1 0 0 1 0, 0 -1 0 1 0, 0 0 -1 1 0, 0 0 0 1 0').in(morphology)
		//shadow/中の文字の大きさ
		var shadow=add.offset(5,5).in(add.sourceAlpha).gaussianBlur(5)
		add.merge(shadow,cmatrix,add.source)//merge

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})

	var txt=draw.text('2 カーニングと虹色塗り move位置移動').font({leading:0.8})


TEXT-3、Inkscape金属


サンプルJS


	//TEXT-3
	//エレメントID
	var draw=SVG('svgtext-fliter-1c').size(640,100)

	//Back
	var rect=draw.rect(640,100).attr({'fill':'#000'})

	//文字描画
	var text3=draw.text('POPSWEB')
	.font({
		family:'Arial'
		,size:80
		,'font-weight':'bolder'
		,anchor:'middle'
		,leading:1
	})

	//move暫定値で配置
	text3.attr({fill:'#DAA520'}).move(320,5)

	//Inkscape-brightmetal
	.filter(function(add) {

		this.svg('<feGaussianBlur result="result6" stdDeviation="5" in="SourceGraphic"/><feComposite in2="SourceGraphic" in="result6" operator="xor" result="result10"/><feGaussianBlur result="result2" stdDeviation="5"/><feComposite in2="SourceGraphic" operator="atop" in="result10" result="result91"/><feComposite in2="result91" result="result4" in="result2" operator="xor"/><feGaussianBlur in="result4" result="result3" stdDeviation="4"/><feSpecularLighting result="result5" specularExponent="5" specularConstant="1.1" surfaceScale="18"><feDistantLight azimuth="235" elevation="55"/></feSpecularLighting><feComposite in2="result5" in="result3" k3="1.1" k2="0.5" operator="arithmetic" result="result7" k1="0.5"/><feComposite in2="SourceGraphic" in="result7" operator="atop" result="result8"/>')
		var effect=this.get(8).attr('result')
		//濃い色
		var shadow=add.flood('#B8860B',1).composite(add.sourceAlpha,'in').offset(0,0).gaussianBlur(10)
		//IE用にメンドウ処理
		var merge=add.merge(shadow,effect)
		add.merge(shadow,merge)

		this.attr({'color-interpolation-filters':'sRGB'})

	})


TEXT-4、ベベル風のFilterテストです。


サンプルJS


	//TEXT-4
	//エレメントID
	var draw=SVG('svgtext-fliter-1d').size(640,100)

	var image=draw.image('/main/images/line-grad4.jpg')

	//文字描画
	var text4=draw.text('POPSWEB KOUBOU')
	.font({
		family:'Times New Roman'//
		,size:50
		,'font-weight':'bolder'
		,anchor:'middle'
		,leading:1
	})

	//move暫定値で配置
	text4.attr({fill:'#000'}).move(320,25)

	.filter(function(add) {

		//ナントカ置き換えた/FirefoxOK
		var blur=add.gaussianBlur(2).in(add.sourceAlpha)
		var light=add.specularLighting('5',1,1,1).in(blur).attr({'lighting-color':'white'}).svg('<feDistantLight azimuth="-135" elevation="45"/>')
		var merge=add.merge(add.source,light)
		add.composite(merge,add.source,'in')

		//svg
		//this.svg('<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur"/><feSpecularLighting in="blur" lighting-color="white" surfaceScale="5" result="light" specularConstant="1"><feDistantLight azimuth="-135" elevation="45"/></feSpecularLighting><feMerge result="merge"><feMergeNode in="SourceGraphic"/><feMergeNode in="light"/></feMerge><feComposite in="merge" in2="SourceGraphic" operator="in"/>')

	})


TEXT-4B、ベベル風のFilterテストです。(画像塗りとshadow)

反射が強く、画像の模様がほとんど見えない。k調整できるように作れば別かも知れません。(IEは濃く仕上がる)


サンプルJS


	//TEXT-4B
	//エレメントID
	var draw=SVG('svgtext-fliter-1d2').size(640,100)

	//Back
	var rect=draw.rect(640,100).attr({'fill':'#F0F8FF'})
	//塗り用画像
	var image=draw.image('/main/images/textback13.png').size(640,100)

	//文字描画/画像塗り
	var text4=draw.text('POPSWEB KOUBOU')
	.font({
		family:'Georgia'//Times New Roman
		,size:50
		,'font-weight':'bolder'
		,anchor:'middle'
		,leading:1
	})

	//move暫定値で配置
	text4.attr({fill:image}).move(320,25)

	.filter(function(add) {

		//ナントカ置き換えた/FirefoxOK
		var blur=add.gaussianBlur(2).in(add.sourceAlpha)
		var light=add.specularLighting('5',1,1,1).in(blur).attr({'lighting-color':'#FFF'}).svg('<feDistantLight azimuth="-135" elevation="45"/>')
		var merge=add.merge(add.source,light)
		var composite=add.composite(merge,add.source,'in')
		//shadow
		var shadow=add.offset(5,5).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,composite)

	})


TEXT-5、ベベル風のFilterテストです。(11番、diffuseLightingとshadow)


サンプルJS


	//TEXT-5
	//エレメントID
	var draw=SVG('svgtext-fliter-1d3').size(640,100)

	//文字描画
	var text4b=draw.text('POPSWEB KOUBOU')
	.font({
		family:'Arial'
		,size:50
		,'font-weight':'bolder'
		,anchor:'left'
		,leading:1
	})

	//move暫定値で配置
	text4b.attr({fill:'#019FA1'}).move(70,25)

	.filter(function(add) {

		var shadow=add.offset(5,5).in(add.sourceAlpha).gaussianBlur(3)
		//bevel
		//(surfaceScale,diffuseConstant,kernelUnitLength)
		var diffuse=add.diffuseLighting('15',1,'2').svg('<feDistantLight azimuth="225" elevation="15"/>')
		diffuse.attr({'lighting-color':'#FFF'})

		var blur=add.composite(diffuse,add.sourceAlpha,'in').gaussianBlur(2)
		var mask=add.composite(blur,add.sourceAlpha,'in')
		//screen
		var blend=add.blend(mask,add.source,'screen')
		//shadow追加
		add.merge(shadow,blend)

	})


WebFontでの表示

WebFontテスト、feDistantLight(平行光線)では表面が白すぎるので、fePointLight(点光線)にした。
Font製作者より許可をえて、WebFont化したものをCSS3で読み込み表示


bevel

 


.filter(function(add) {

	//feDistantLight白すぎる
	var blur=add.gaussianBlur(2).in(add.sourceAlpha)
	var light=add.specularLighting('5',1,1,1).in(blur).attr({'lighting-color':'white'}).svg('<feDistantLight azimuth="-135" elevation="35"/>')
	var merge=add.merge(add.source,light)
	var effect=add.composite(merge,add.source,'in')
	//shadow
	var shadow=add.offset(5,5).in(add.sourceAlpha).gaussianBlur(10)
	add.merge(shadow,effect)

	this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

})

サンプルJS


	//webFont
	//エレメントID
	var draw=SVG('webfont-fliter-1a').size(640,100)

	//文字描画中央移動
	var webfont_text=draw.text('POPSWEB').attr({'fill':'#20B2AA'}).move(320,10)
	.font({
		family:'GauFontMilkChoco'
		,size:80
		,'font-weight':'bold'
		,anchor:'middle'
		,leading:1
	})

	.filter(function(add) {

		//bevel
		//(surfaceScale, diffuseConstant, specularExponent, kernelUnitLength)
		var blur=add.gaussianBlur(2).in(add.sourceAlpha)
		var light=add.specularLighting('5',0.75,20,1).in(blur).attr({'lighting-color':'#FFF'}).svg('<fePointLight x="-5000" y="-10000" z="20000"/>')
		var effect=add.composite(add.source,light,'arithmetic').attr({'k1':0,'k2':0.5,'k3':0.5,'k4':0})
		var mask=add.composite(effect,add.source,'in')
		//shadow
		var shadow=add.offset(2,2).in(add.sourceAlpha).gaussianBlur(3)
		add.merge(shadow,mask)

		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})



 

2 svg()メソッド利用のFilter処理

▲[目次]

SVG.jsメソッドを利用すれば簡単に、他サイトのSVG.Filter等を効果的に活用できます。但し、必ず全てのブラウザに対応動作するとは限りませんので確認ください。特に、Firefoxは色々と注意が必要です。(大変デスネ)

SVG.jsの形式に直さなくとも簡単に実行できますのでパクリ専門メソッドです。私や貴方にピッタリです。


1. SVGが簡略に書かれて、利用しにくいなら足りない部分を加筆修正する。
2. Inkscapeのものも修正が必要の場合がある。(TEXT-6参照、おそらく意図的だろうと思いますが)


filter処理関数での書き方では<filter>は自動的に生成されますので、ここを削除した他のHTMLを記述します。
defs収納の形式は<filter>をつけます。
filterの作り方によっては直接filter出来ないものも有り、私、素人では判りません。Inkscape のものは結構どんなものにも使えそうです。但し対応するかなどは結果をみなければ判りません。


● .filter(function(add){...})処理の場合。
filter.jsで管理されているので「SVG-HTML記述部分」が厳格に書かれていないと、Firefoxで処理しない場合が多い。
(パクリ材が結構簡略すぎる場合があり、甘いFirefox以外で動作して、辛いFirefoxで処理しない事が往々にして起こる)


//svg()方式
.filter(function(add) {
	this.svg('SVG-HTML記述部分')

	//filterタグ内部の属性設定
	this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK
	//color-interpolation-filtersの設定は
	this.attr({'color-interpolation-filters':'sRGB'})
})

前ページで説明の通りfilter処理関数内で次の様にしても、nanda_korya はエフェクト値にはなりませんから、Firefoxは認識せず処理しません。
そもそも、「エフェクト値」ではなく「オブジェクト」であり、Firefoxから見て「何だコリャ」に過ぎない。混同処理はしないほうが良いと思います。


//Firefox処理しません
.filter(function(add){
	var nanda_korya=this.svg('SVG-HTML記述部分')//このよう記述はしないこと
	add.composite(nanda_korya,add.sourceAlpha,'in')//Firefox認識せず
})

このような場合は、SVGの最終出力の「リザルト値」を加筆すれば、resultとして取り出し処理を続行できます。
Inkscape以外のSVGは簡略に書かれたものが多いので、上手く処理しない場合は「リザルト値」をキッチリ記載すればほとんど処理します。

処理対象タグが、filterタグの何番目にあるか調べれば、result値が取り出せます。composite()の引数は、effectまたはresult値ですから...


//Firefox処理します
.filter(function(add){
	this.svg('<SVG-HTML記述部分..... result="nanda_korya" />')
	//result値をとりだす
	var result=this.get(何番目か)//最初は0番
	add.composite(result,add.sourceAlpha,'in')
})

実際のInkscapeサンプル処理例

● 文字の場合はfilterの構成と多少ブラウザにより違いがあります。SVGの処理を確認して適正にSVG.js用に修正などしますが、次のサンプルをご覧ください。
Inkscape リキッドFilterを処理してみますが、これは少し特殊なようです。

最初のサンプルとしては偶然にも特殊なもになってしまったが、他のものは至って普通のようですから安心ください。

TEXT-6、Inkscape リキッドFilter。(FirefoxはこのFilterには対応していないようです)


Filterにもよりますが、ブラウザによっては、下図の様に表示が違う場合があります。特に文字の場合、Firefoxの見た目が違うようです。マスクまたは塗りにした場合同じになります。

Firefoxの tspan() plain() での振舞いが若干他のブラウザと違うところがあり、TEXTの根本的な解釈違いが原因と思いますが...

zuzu

サンプルJS


	//TEXT-6
	//エレメントID
	var draw=SVG('svgtext-fliter-1e').size(640,100)

	//白背景
	var back6=draw.rect(640,100).attr({'fill':'#FFF'})

	//文字描画
	var text6=draw.text('POPSWEB').attr({'fill':'#48D1CC'}).move(150,10)
	.font({
		family:'Impact'
		,size:80
		,'font-weight':'normal'
		,anchor:'left'
		,leading:1
	})
	//filter
	text6.filter(function(add) {
		this.attr({'color-interpolation-filters':'sRGB'})
		this.svg('<feGaussianBlur id="feGaussianBlur2989" stdDeviation="5" result="result8"/><feTurbulence seed="0" result="result7" type="turbulence" numOctaves="1" baseFrequency="0.02"/><feColorMatrix result="result5" values="1 0 0 0 0, 0 1 0 0 0, 0 0 1 0 0, 0 0 0 4 0"/><feComposite in2="result8" result="result6" operator="in" in="result8"/><feDisplacementMap in2="result6" in="result5" xChannelSelector="A" yChannelSelector="A" scale="120" result="result4"/><feComposite in2="result4" result="result2" operator="in" in="result8"/><feComposite in2="result2" result="fbSourceGraphic" in="SourceGraphic" operator="in"/>')
	})


以下、2例でfeTurbulenceを展開する高さを2倍にしています。理由は出来上がりのノイズを表示すれば判ります。(特殊のようだ)

clipマスク形式で処理すればブラウザが違っても表示は同じです。(色に注意、青色部分は透過して下の色が出ている)


サンプルJS


	//TEXT-6b
	//エレメントID
	var draw=SVG('svgtext-fliter-1e2').size(640,100)

	//色背景
	var maskrect6=draw.rect(640,200).attr({'fill':'#48D1CC'})
	//filter
	maskrect6.filter(function(add) {
		this.attr({'color-interpolation-filters':'sRGB'})
		this.svg('<feGaussianBlur id="feGaussianBlur2989" stdDeviation="5" result="result8"/><feTurbulence seed="0" result="result7" type="turbulence" numOctaves="1" baseFrequency="0.02"/><feColorMatrix result="result5" values="1 0 0 0 0, 0 1 0 0 0, 0 0 1 0 0, 0 0 0 4 0"/><feComposite in2="result8" result="result6" operator="in" in="result8"/><feDisplacementMap in2="result6" in="result5" xChannelSelector="A" yChannelSelector="A" scale="120" result="result4"/><feComposite in2="result4" result="result2" operator="in" in="result8"/><feComposite in2="result2" result="fbSourceGraphic" in="SourceGraphic" operator="in"/>')
	})
	//文字描画
	var text6=draw.text('POPSWEB').attr({'fill':'#FFF'}).move(150,10)
	text6.font({
		family:'Impact'
		,size:80
		,'font-weight':'normal'
		,anchor:'left'
		,leading:1
	})

	//clipマスク
	maskrect6.clipWith(text6)


パターン塗りにすれば、マスク形式と同じになります。ブラウザが違っても表示は同じです。(メンドウだが細やかな処理が出来る)


サンプルJS


	//TEXT-6c
	//エレメントID
	var draw=SVG('svgtext-fliter-1e3').size(640,100)

	//defs収容形式パターン塗り
	//filterパターンを収容
	var defs=draw.defs()
	defs.svg('<filter id="liquid" color-interpolation-filters="sRGB"><feGaussianBlur id="feGaussianBlur2989" stdDeviation="5" result="result8"/><feTurbulence seed="0" result="result7" type="turbulence" numOctaves="1" baseFrequency="0.02"/><feColorMatrix result="result5" values="1 0 0 0 0, 0 1 0 0 0, 0 0 1 0 0, 0 0 0 4 0"/><feComposite in2="result8" result="result6" operator="in" in="result8"/><feDisplacementMap in2="result6" in="result5" xChannelSelector="A" yChannelSelector="A" scale="120" result="result4"/><feComposite in2="result4" result="result2" operator="in" in="result8"/><feComposite in2="result2" result="fbSourceGraphic" in="SourceGraphic" operator="in"/></filter>')

	//白背景
	var back6=draw.rect(640,100).attr({'fill':'#FFF'})

	//パターンを作る
	var pattern=draw.pattern(640,100,function(add) {
		//font範囲は高さがあるので大きくとる
		add.rect(640,200).fill('#C71585')//#48D1CC/#C71585
		.attr({'filter':'url(#liquid)'})

	})

	//文字描画
	var text6=draw.text('POPSWEB').attr({'fill':pattern}).move(150,10)
	.font({
		family:'Impact'
		,size:80
		,'font-weight':'normal'
		,anchor:'left'
		,leading:1
	})

	.attr({'filter':'url(#dropShadow2)'})//陰影


他のパクリサンプル処理例

TEXT-7、waterFilterのclipWith()マスク処理。(defsに収容してマスク)

ほぼ同様な液体パターンです。作り方が違うせいか、clipWith()マスク処理専用になります。上記の様にTEXTに直接fliter処理できません。
fliterは下記サイトより引用しました。(引用元でもマスク処理で使用しています)

【引用元】SVG Text Effects Gallery


TEXT-7、clipWith()マスク処理で再現

SVG自体が文字に塗りこめる形に処理されていない為、使い難い。(feCompositeを加筆すればべつですが)


サンプルJS


	//TEXT-7/clipWith
	//エレメントID
	var draw=SVG('svgtext-fliter-1f').size(640,100)

	//黒背景
	var back7=draw.rect(640,100).attr({'fill':'#000'})
	//filterパターンを収容
	var defs=draw.defs()
	defs.svg('<filter id="water" width="640" height="100" filterUnits="userSpaceOnUse"><feTurbulence type="turbulence" baseFrequency="0.055" numOctaves="1"/><feColorMatrix type="luminanceToAlpha"/><feColorMatrix type="matrix" values="0 0 0 -1 1  0 0 0 -1 1  0 0 0 -1 1  0 0 0 0 1"/><feComponentTransfer><feFuncR type="table" tableValues="0 0 0 .4 1"/><feFuncG type="table" tableValues="0 .15 .5 .9 1"/><feFuncB type="table" tableValues="0 0 .6 .8 1"/><feFuncA type="linear" slope="1" intercept="0"/></feComponentTransfer></filter>')

	//文字描画中央移動
	var text7=draw.text('Water Effect').x(320)
	.font({
		family:'Impact'
		,size:80
		,'font-weight':'normal'
		,anchor:'middle'
		,leading:1
	})

	//filterパターン塗りレクト
	var maskrect=draw.rect(640,100)
	.attr({'filter':'url(#water)'})
	//マスク
	maskrect.clipWith(text7)


TEXT-7b、composite()マスクに修正、陰影もOK

文字に塗りこめる形に処理すれば、clipWith()はいらない。(パクリものは結構中途半端なので注意)


サンプルJS


	//TEXT-7b/composite
	//エレメントID
	var draw=SVG('svgtext-fliter-1f2').size(640,100)

	//文字描画中央移動
	var text7b=draw.text('Water Effect').x(320)
	.font({
		family:'Impact'
		,size:80
		,'font-weight':'normal'
		,anchor:'middle'
		,leading:1
	})

	//修正
	text7b.filter(function(add){

		this.svg('<feTurbulence type="turbulence" baseFrequency="0.055" numOctaves="1" result="result0"/><feColorMatrix type="luminanceToAlpha" in="result0" result="result1"/><feColorMatrix type="matrix" values="0 0 0 -1 1  0 0 0 -1 1  0 0 0 -1 1  0 0 0 0 1" in="result1" result="result2"/><feComponentTransfer in="result2" result="result3"><feFuncR type="table" tableValues="0 0 0 .4 1"/><feFuncG type="table" tableValues="0 .15 .5 .9 1"/><feFuncB type="table" tableValues="0 0 .6 .8 1"/><feFuncA type="linear" slope="1" intercept="0"/></feComponentTransfer>')
		var result=this.get(3).attr('result')
		var mask=add.composite(result,add.sourceAlpha,'in')
		var shadow=add.flood('#00F',1).composite(add.sourceAlpha,'in').offset(0,0).gaussianBlur(5)
		add.merge(shadow,mask)

		this.attr({'filterUnits':'userSpaceOnUse','x':0,'y':0,'width':640,'height':100})
	})


気まぐれに画像を入れてみた

TEXT-8、画像塗りこみFilter(画像Filter)
実際はインスタンスを画像塗りにしたほうがやり易いとは思いますが。


サンプルJS


	//エレメントID
	var draw=SVG('svgtext-fliter-1f3').size(640,100)

	//文字描画中央移動
	var text6c=draw.text('ImageFilter').x(320)
	.font({
		family:'Impact'
		,size:80
		,'font-weight':'normal'
		,anchor:'middle'
		,leading:1
	})

	//画像Filterと陰影
	.filter(function(add){

		var backimage=add.image('/main/images/textback13.png').size(640,100).move(0,0)//画像固定
		var base=add.composite(backimage,add.sourceAlpha,'in')
		var shadow=add.offset(5,5).in(add.sourceAlpha).gaussianBlur(10)
		add.merge(shadow,base)

		//画像をとめておかないとどこかに行く
		this.attr({'x':'-100%','y':'-100%','width':'400%','height':'400%'})//IE OK

	})


TEXT-9、雲

白以外の部分が透過しています。余り表示品質はよく有りません。将来は直るとは思いますが....


サンプルJS


	//TEXT-7/外部ファイル登録
	//エレメントID
	var draw=SVG('svgtext-fliter-1g').size(640,100)

	//白背景
	var back9=draw.rect(640,100).attr({'fill':'#FFF'})

	//文字描画
	var text9=draw.text('POPSWEB')

	.font({
		family:'Impact'
		,size:80
		,'font-weight':'normal'
		,anchor:'left'
		,leading:1
	})

	//移動
	.attr({'fill':'#00F'}).move(150,0)

	//雲
	text9.filter(function(add){

		//透過するので白ベースをadd
		this.svg('<feTurbulence result="result1" baseFrequency="0.02" numOctaves="5" type="fractalNoise"/><feComposite in2="result1" operator="in" in="SourceGraphic" result="result2"/><feColorMatrix in="result2" values="1 0 0 0 0, 0 1 0 0 0, 0 0 1 0 0, 0 0 0 3 -1" result="result3"/>')
		var result=this.get(2).attr('result')
		var base=add.flood('#FFF',1).composite(add.sourceAlpha,'in').gaussianBlur(1)
		var cloud=add.merge(base,result)

		//shadow
		var shadow=add.flood('#00BFFF',1).composite(add.sourceAlpha,'in').offset(0,0).gaussianBlur(3)
		add.merge(shadow,cloud)

		this.attr({'color-interpolation-filters':'sRGB'})
	})



 

3 外部ファイルを読み込みFilterを掛ける

▲[目次]

defsに登録するのもメンドウな場合、外部ファイルに記述しておき、ページに読み込む事により利用できます。
HTML5ならembed、objectタグなどで読み込めますが、このページはHTML5では有りませんので、jQueryでsvgファイルを読み込みます。
jQueryでsvgファイルを読み込みに関する方法は下記サイト記事を参考にしました。

【参考】sterfield.co.jpの記事: jQueryを使った外部SVGファイルの読み込み


TEXT-9、Inkscape 3D marble

ライブラリー登録のSVGを読み出して表示しました。filter-marble3d filter-wood3d filter-blotting 、の3種を登録しています。


lib

サンプルJS


	//TEXT-7/外部ファイル登録
	//エレメントID
	var draw=SVG('svglib-fliter-1a').size(640,100)

	//文字描画
	var text10=draw.text('POPSWEB')

	.font({
		family:'Impact'
		,size:80
		,'font-weight':'normal'
		,anchor:'left'
		,leading:1
	})

	//移動
	.attr({'fill':'#9370DB'}).move(150,0)

	//marble
	text10.attr({'filter':'url(#filter-marble3d)'})
	//wood
	//text10.attr({'filter':'url(#filter-wood3d)'})
	//blotting
	//text10.attr({'filter':'url(#filter-blotting)'})

    }


● Inkscapeで作ったエフェクト類をsvgファイルとして外部に保存して呼び出します。


1. Inkscapeで作ったsvgを開きエフェクト部分filterを取り出し、外部svgファイルのdefsに記述、編集します。
(filterタグのIDは必要ですが、その他のIDは無くとも動作します)
2. 使い易いように、filterのIDをテキトウに書き換えます。
3. defsに有りますので、表示はしませんが、ページのに影響ないように体裁を整えます。
4. jQueryで読み出します(一番簡単)。他の方法でも可能です。
5. 通常、SVG表示用では有りませんので、名前空間は記述無くとも良い。
(下記、ライブラリーSVGの表示ではリンクですのでエラーになるため名前空間を記述しました)


svgファイルとして外部に保存、ファイル名例、marble3d.svg などテキトウにつけます。


<?xml version="1.0" encoding="UTF-8"?>

<svg width="2" height="0" style="opacity:0; overflow:hidden;">
  <defs id="defs4">
    <filter id="filter-marble3d" color-interpolation-filters="sRGB">

	Inkscapeなどで作ったエフェクト 内容は略す

    </filter>
  </defs>
</svg>

ID名svgAreaのDiv要素にjQueryで読み出し。但し非表示です。
使用するページHTMLに読み出し箇所を書かねば成らないのがメンドウなだけですが。(読み出しJSはどこに書いても良い)


<div id="svgArea" style="width:0;height:0;margin:0;padding:0;opacity:0;overflow:hidden;">
<script type="text/javascript">
$(function(){
	$("#svgArea").load("/main/svg/marble3d.svg svg", function(){
		//
	});
});
</script>
</div>

filter-marble3dのfilter部分のみ抜粋して表示しています。詳細は下の「ライブラリーSVGの表示」で見ることが出来ます。
InkscapeのSVGを保存して開き、filter部分のみ抜き取ったものです。

サンプルJS


    <filter
       id="filter-marble3d"
       height="1.5"
       y="-0.25"
       width="1.5"
       x="-0.25"
       color-interpolation-filters="sRGB">
      <feGaussianBlur
         id="feGaussianBlur3017"
         stdDeviation="4"
         result="result8" />
      <feTurbulence
         id="feTurbulence3019"
         seed="50"
         result="result7"
         type="turbulence"
         numOctaves="7"
         baseFrequency="0.01 0.01" />
      <feColorMatrix
         id="feColorMatrix3021"
         result="result5"
         values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1.4 0 " />
      <feComposite
         id="feComposite3023"
         in2="result8"
         result="result6"
         in="result5"
         operator="in" />
      <feDisplacementMap
         id="feDisplacementMap3025"
         in2="result6"
         in="result5"
         xChannelSelector="A"
         yChannelSelector="A"
         scale="100"
         result="result4" />
      <feFlood
         id="feFlood3027"
         in="result4"
         flood-opacity="1"
         flood-color="rgb(224,224,224)"
         result="result9" />
      <feComposite
         id="feComposite3029"
         in2="result4"
         result="result2"
         operator="atop" />
      <feComposite
         id="feComposite3031"
         in2="SourceGraphic"
         in="result2"
         operator="atop"
         result="result9" />
      <feBlend
         id="feBlend3033"
         in2="result9"
         result="fbSourceGraphic"
         mode="darken" />
      <feGaussianBlur
         id="feGaussianBlur3035"
         stdDeviation="5"
         in="fbSourceGraphic"
         result="result0" />
      <feSpecularLighting
         id="feSpecularLighting3037"
         in="result0"
         result="result1"
         lighting-color="rgb(255,255,255)"
         surfaceScale="8"
         specularConstant="0.8"
         specularExponent="30">
        <feDistantLight
           id="feDistantLight3039"
           elevation="55"
           azimuth="235" />
      </feSpecularLighting>
      <feComposite
         id="feComposite3041"
         in2="fbSourceGraphic"
         in="result1"
         result="result2"
         operator="in" />
      <feComposite
         id="feComposite3043"
         in2="result2"
         in="fbSourceGraphic"
         result="result4"
         operator="arithmetic"
         k2="1"
         k3="1" />
    </filter>



 

4 サンプルJSの全表示と使用画像と参考リンク

▲[目次]

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

● サンプルJSの全表示2(このページ用) svg-sample19b.js


● ライブラリーSVGの表示 marble3d.svg / defsの保存ですから何も表示しません、ソースリストを開いてください。


● url(#)用DropShadow JS表示 svg-dropshadow.js / 注意、svg.jsを使用しますので、必ず、svg.jsを読み込み後にsvg-dropshadow.jsを読み込む事。
内容はjQuery用と同じです。jQueryのバージョン違いで2種あったものを、javascriptで記述しただけです。


使用画像

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

使用画像サンプル

 


その他、パクリサンプルとして、下記サイトを参考にしました。

【参考】www.w3.orgの記事: SVG Text Effects Gallery

【参考】ledrug.wordpress.comの記事: Learning SVG: lesson 2

【参考】www.smashingmagazine.comの記事: The Art Of The SVG Filter And Why It Is Awesome

 

新しいDropShadowについては「前ページ」を参照ください。

【参照】当方の記事: SVG.js filterとDropShadow


▲[目次]

詳細説明などは、記事ページなどを参照ください。

 

以上。

 

LINK-GOTO-BACK(元のページに戻る)