SVGについて – テキストについて(4)

Posted コメントするカテゴリー: javascript

SVGについて – テキストについて(4)

テキストのtextLength属性 について試してみます。

前回のサンプルをもとに、textLength 属性の値を可変するサンプルを書きました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.params_box {
	padding-top: 30px;
}

.transform {
	width: 400px;
}
</style>


</head>
<body>
<svg width="500" height="200" viewBox="0 0 500 200">

	<text
		id="test_text1"
		x="50"
		y="50"
		dx="0"
		dy="0"
		transform="rotate(0, 20,40)"
	>
	テキストのテスト
	</text>

</svg>


<div>
	<div class="params_box">
		<span class="param_title">パラメータ1</span>
		<div><input type="range" class="transform" id="transform1" value="0" max="400"></div>
		<span>textLength :</span>
		<span class="params" id="transform1_value"></span>
	</div>

</div>


<script>

// スライダtransform1の要素を取得し、イベントを付与する
let transform1_dom = document.getElementById('transform1');
transform1_dom.addEventListener('input', function(e) {

	console.log("transform1_dom.value -> " + transform1_dom.value);

	// パターン内のDOM情報を取得する
	let test_text1_dom = document.getElementById('test_text1');
	console.log("test_text1_dom -> " + test_text1_dom);

	// パラメータ1~パラメータ5まで値をリスト(配列)形式にして角度を決定する
	let rotate_value = transform1_dom.value;

	// SVG要素のtextLength属性を変更する
	test_text1_dom.setAttribute('textLength', rotate_value);
	
	// 画面出力
	let transform1_value_dom = document.getElementById('transform1_value');
	transform1_value_dom.innerHTML = transform1_dom.value + '<br />';

});

</script>


</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、「テキストのテスト」という文字列が表示されます。

また、スライダを動かすと、0~400までの範囲で値が可変し、textLength属性の値を
動的に変更しています。

スライダを動かすとわかりますが、値が増えるほど、テキストの文字間隔が広がり、
値が減ると、文字間隔が狭くなることがわかります。

SVGについて – テキストについて(3)

Posted コメントするカテゴリー: javascript

SVGについて – テキストについて(3)

テキストのtransform属性のrotateについて

前回のサンプルの rotate の値は、単一の値を指定して、各文字列の角度を指定しました。

今回は、指定する角度を配列形式のリストで指定してみます。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
.params_box {
	padding-top: 30px;
}

#transform {
	width: 200px;
}
</style>


</head>
<body>
<svg width="200" height="200" viewBox="0 0 200 200">

	<text
		id="test_text1"
		x="50"
		y="50"
		dx="0"
		dy="0"
		transform="rotate(0, 20,40)"
	>
	テキストのテスト
	</text>

</svg>


<div>
	<div class="params_box">
		<span class="param_title">パラメータ1</span>
		<div><input type="range" id="transform1" value="0" max="360"></div>
		<span>transform (rotate) :</span>
		<span class="params" id="transform1_value"></span>
	</div>

	<div class="params_box">
		<span class="param_title">パラメータ2</span>
		<div><input type="range" id="transform2" value="0" max="360"></div>
		<span>transform (rotate) :</span>
		<span class="params" id="transform2_value"></span>
	</div>

	<div class="params_box">
		<span class="param_title">パラメータ3</span>
		<div><input type="range" id="transform3" value="0" max="360"></div>
		<span>transform (rotate) :</span>
		<span class="params" id="transform3_value"></span>
	</div>

	<div class="params_box">
		<span class="param_title">パラメータ4</span>
		<div><input type="range" id="transform4" value="0" max="360"></div>
		<span>transform (rotate) :</span>
		<span class="params" id="transform4_value"></span>
	</div>

	<div class="params_box">
		<span class="param_title">パラメータ5</span>
		<div><input type="range" id="transform5" value="0" max="360"></div>
		<span>transform (rotate) :</span>
		<span class="params" id="transform5_value"></span>
	</div>

</div>


<script>

// スライダtransform1の要素を取得し、イベントを付与する
let transform1_dom = document.getElementById('transform1');
transform1_dom.addEventListener('input', function(e) {

	console.log("transform1_dom.value -> " + transform1_dom.value);
	console.log("transform2_dom.value -> " + transform2_dom.value);
	console.log("transform3_dom.value -> " + transform3_dom.value);
	console.log("transform4_dom.value -> " + transform4_dom.value);
	console.log("transform5_dom.value -> " + transform5_dom.value);

	// パターン内のDOM情報を取得する
	let test_text1_dom = document.getElementById('test_text1');
	console.log("test_text1_dom -> " + test_text1_dom);

	// パラメータ1~パラメータ5まで値をリスト(配列)形式にして角度を決定する
	let rotate_value = transform1_dom.value
	                 + ',' + transform2_dom.value
	                 + ',' + transform3_dom.value
	                 + ',' + transform4_dom.value
	                 + ',' + transform5_dom.value;

	// SVG要素のtransform1属性を変更する
	test_text1_dom.setAttribute('rotate', rotate_value);
	
	// 画面出力
	let transform1_value_dom = document.getElementById('transform1_value');
	transform1_value_dom.innerHTML = transform1_dom.value + '<br />';

});

// スライダtransform2の要素を取得し、イベントを付与する
let transform2_dom = document.getElementById('transform2');
transform2_dom.addEventListener('input', function(e) {

	console.log("transform1_dom.value -> " + transform1_dom.value);
	console.log("transform2_dom.value -> " + transform2_dom.value);
	console.log("transform3_dom.value -> " + transform3_dom.value);
	console.log("transform4_dom.value -> " + transform4_dom.value);
	console.log("transform5_dom.value -> " + transform5_dom.value);

	// パターン内のDOM情報を取得する
	let test_text1_dom = document.getElementById('test_text1');
	console.log("test_text1_dom -> " + test_text1_dom);

	// パラメータ1~パラメータ5まで値をリスト(配列)形式にして角度を決定する
	let rotate_value = transform1_dom.value
	                 + ',' + transform2_dom.value
	                 + ',' + transform3_dom.value
	                 + ',' + transform4_dom.value
	                 + ',' + transform5_dom.value;

	// SVG要素のtransform2属性を変更する
	test_text1_dom.setAttribute('rotate', rotate_value);
	
	// 画面出力
	let transform2_value_dom = document.getElementById('transform2_value');
	transform2_value_dom.innerHTML = transform2_dom.value + '<br />';

});

// スライダtransform3の要素を取得し、イベントを付与する
let transform3_dom = document.getElementById('transform3');
transform3_dom.addEventListener('input', function(e) {

	console.log("transform1_dom.value -> " + transform1_dom.value);
	console.log("transform2_dom.value -> " + transform2_dom.value);
	console.log("transform3_dom.value -> " + transform3_dom.value);
	console.log("transform4_dom.value -> " + transform4_dom.value);
	console.log("transform5_dom.value -> " + transform5_dom.value);

	// パターン内のDOM情報を取得する
	let test_text1_dom = document.getElementById('test_text1');
	console.log("test_text1_dom -> " + test_text1_dom);

	// パラメータ1~パラメータ5まで値をリスト(配列)形式にして角度を決定する
	let rotate_value = transform1_dom.value
	                 + ',' + transform2_dom.value
	                 + ',' + transform3_dom.value
	                 + ',' + transform4_dom.value
	                 + ',' + transform5_dom.value;

	// SVG要素のtransform3属性を変更する
	test_text1_dom.setAttribute('rotate', rotate_value);
	
	// 画面出力
	let transform3_value_dom = document.getElementById('transform3_value');
	transform3_value_dom.innerHTML = transform3_dom.value + '<br />';

});

// スライダtransform4の要素を取得し、イベントを付与する
let transform4_dom = document.getElementById('transform4');
transform4_dom.addEventListener('input', function(e) {

	console.log("transform1_dom.value -> " + transform1_dom.value);
	console.log("transform2_dom.value -> " + transform2_dom.value);
	console.log("transform3_dom.value -> " + transform3_dom.value);
	console.log("transform4_dom.value -> " + transform4_dom.value);
	console.log("transform5_dom.value -> " + transform5_dom.value);

	// パターン内のDOM情報を取得する
	let test_text1_dom = document.getElementById('test_text1');
	console.log("test_text1_dom -> " + test_text1_dom);

	// パラメータ1~パラメータ5まで値をリスト(配列)形式にして角度を決定する
	let rotate_value = transform1_dom.value
	                 + ',' + transform2_dom.value
	                 + ',' + transform3_dom.value
	                 + ',' + transform4_dom.value
	                 + ',' + transform5_dom.value;

	// SVG要素のtransform4属性を変更する
	test_text1_dom.setAttribute('rotate', rotate_value);
	
	// 画面出力
	let transform4_value_dom = document.getElementById('transform4_value');
	transform4_value_dom.innerHTML = transform4_dom.value + '<br />';

});

// スライダtransform5の要素を取得し、イベントを付与する
let transform5_dom = document.getElementById('transform5');
transform5_dom.addEventListener('input', function(e) {

	console.log("transform1_dom.value -> " + transform1_dom.value);
	console.log("transform2_dom.value -> " + transform2_dom.value);
	console.log("transform3_dom.value -> " + transform3_dom.value);
	console.log("transform4_dom.value -> " + transform4_dom.value);
	console.log("transform5_dom.value -> " + transform5_dom.value);

	// パターン内のDOM情報を取得する
	let test_text1_dom = document.getElementById('test_text1');
	console.log("test_text1_dom -> " + test_text1_dom);

	// パラメータ1~パラメータ5まで値をリスト(配列)形式にして角度を決定する
	let rotate_value = transform1_dom.value
	                 + ',' + transform2_dom.value
	                 + ',' + transform3_dom.value
	                 + ',' + transform4_dom.value
	                 + ',' + transform5_dom.value;

	// SVG要素のtransform5属性を変更する
	test_text1_dom.setAttribute('rotate', rotate_value);
	
	// 画面出力
	let transform5_value_dom = document.getElementById('transform5_value');
	transform5_value_dom.innerHTML = transform5_dom.value + '<br />';

});

</script>


</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、「テキストのテスト」という文字列が表示されます。

スライダーは1から5まであり、1、2、3、4までのスライダを動かすと、それぞれ
1文字目、2文字目、3文字目、4文字目までの各文字が角度指定されて回転します。

ただ、スライダの5番目だけは挙動が異なり、5文字目以降の「のテスト」全体に効果がかかります。

このことから、setAttributeのrotateの指定は、上記の仕様で動作することがわかります。

SVGについて – テキストについて(2)

Posted コメントするカテゴリー: javascript

SVGについて – テキストについて(2)

テキストのtransform属性のrotateについて

SVGで出力したテキストのtransform属性について調べてみます。

MDNドキュメントを確認すると、「transform 属性は、要素とその要素の子に適用される変換定義のリストを定義します。」とあります。

ここでは、rotate の値を試してみます。

簡単なサンプルとして以下のコードを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
#transform {
	width: 200px;
}
</style>


</head>
<body>
<svg width="200" height="200" viewBox="0 0 200 200">

	<text
		id="test_text1"
		x="50"
		y="50"
		dx="0"
		dy="0"
		transform="rotate(0, 20,40)"
	>
	テキストのテスト
	</text>

</svg>


<div>
	<span class="param_title">パラメータ</span>

	<div class="params_box">
		<div><input type="range" id="transform" value="0" max="360"></div>
		<span>transform (rotate) :</span>
		<span class="params" id="transform_value"></span>
	</div>

</div>


<script>

// スライダtransformの要素を取得し、イベントを付与する
let transform_dom = document.getElementById('transform');
transform_dom.addEventListener('input', function(e) {

	console.log("transform_dom.value -> " + transform_dom.value);

	// パターン内のDOM情報を取得する
	let test_text1_dom = document.getElementById('test_text1');
	console.log("test_text1_dom -> " + test_text1_dom);

	// SVG要素のtransform属性を変更する
	test_text1_dom.setAttribute('transform', 'rotate(' + transform_dom.value + ')');
	
	// 画面出力
	let transform_value_dom = document.getElementById('transform_value');
	transform_value_dom.innerHTML = transform_dom.value + '<br />';

});

</script>


</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、「テキストのテスト」という文字列が表示されます。

さらに、画面上のスライダを移動すると、「id=”test_text1″」で定義したテキスト要素の
rotateが更新され、標示している文字列が回転します。

初期値は「0度」から始まり、最大値は「360度」になります。
viewboxのサイズの都合上、90度以上になると画面出力のエリア外になりますが、
360度に近づくにつれてまた画面上に出力されることがわかります。

テキストのrotate属性のについて

では次に、上記サンプルを少し変更し、

このサンプルを基に、text要素の各パラメータについて調べます。

SVGについて – テキストのrotate属性について

先程のサンプルのtransformをrotateに変更してみます。

これは前回投稿したサンプルと同じ結果になります。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style>
#transform {
	width: 200px;
}
</style>


</head>
<body>
<svg width="200" height="200" viewBox="0 0 200 200">

	<text
		id="test_text1"
		x="20"
		y="20"
		dx="0"
		dy="0"
	>
	テキストのテスト
	</text>

</svg>


<div>
	<span class="param_title">パラメータ</span>

	<div class="params_box">
		<div><input type="range" id="transform" value="0" max="360"></div>
		<span>rotate :</span>
		<span class="params" id="transform_value"></span>
	</div>

</div>


<script>

// スライダtransformの要素を取得し、イベントを付与する
let transform_dom = document.getElementById('transform');
transform_dom.addEventListener('input', function(e) {

	console.log("transform_dom.value -> " + transform_dom.value);

	// パターン内のDOM情報を取得する
	let test_text1_dom = document.getElementById('test_text1');
	console.log("test_text1_dom -> " + test_text1_dom);

	// SVG要素のrotateを変更する
	test_text1_dom.setAttribute('rotate', transform_dom.value);

	// 画面出力
	let transform_value_dom = document.getElementById('transform_value');
	transform_value_dom.innerHTML = transform_dom.value + '<br />';

});

</script>


</body>
</html>

サーバ上のHTMLはこちら(test2.html)

画面にアクアスすると、テキスト文字列が標示されます。

スライダを変更すると、1文字づつ各文字が回転します。

先程のテスト1では、 transform の属性として rotate の値を変更しています。
この場合は、テキスト全体を回転する動きになり、

テスト2では、テキストのDOM要素に対して各文字ごとに rotate が反映されて回転することがわかります。

SVGについて – テキストについて

Posted コメントするカテゴリー: javascript

SVGについて – テキストについて

SVGでテキスト出力について試してみます。

簡単なサンプルとして以下のコードを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="200" height="200" viewBox="0 0 200 200">

	<text
		x="0"
		y="20"
		dx="0"
		dy="0"
	>
	テキストのテスト
	</text>

</svg>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、「テキストのテスト」という文字列が表示されます。

viewBoxで指定した領域に、text要素を定義しているだけのシンプルなものです。

このサンプルを基に、text要素の各パラメータについて調べます。

SVGについて – テキストのrotate属性について

先程のサンプルのtext要素に、rotate属性を追加し値を20に設定してみます。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

</head>
<body>
<svg width="200" height="200" viewBox="0 0 200 200">

	<text
		x="0"
		y="20"
		dx="0"
		dy="0"
		rotate="20"
	>
	テキストのテスト
	</text>

</svg>

</body>
</html>

サーバ上のHTMLはこちら(test2.html)

画面にアクアスすると、各文字列に対して20度の角度がついていることがわかります。

SVGについて – グラデーションについて(その4)

Posted コメントするカテゴリー: javascript

SVGについて – グラデーションについて(その4)

パターンについて

前回のサンプルに対して、パターンを試してみます。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>

<style type="text/css">
.params {
	float: left;
}
.params_box {
	display: flex;
}
.param_title {
	font-weght: bold;
}
</style>

</head>
<body>
<svg width="200" height="200" viewBox="0 0 200 200">

	<defs>
		<radialGradient
			id="radial_gradient1"
		>
			<stop offset="0%" stop-color="#333"/>
			<stop offset="100%" stop-color="#fff"/>

		</radialGradient>
		
		<pattern
			id="test_pattern1"
			x="0"
			y="0"
			width="0.3"
			height="0.4"
		>
			<circle
				id="test_circle1"
				cx="23"
				cy="23"
				r="25"
				fill="url(#radial_gradient1)"
			/>
		</pattern>
		
	</defs>

	<rect
        x            = "0"
        y            = "0"
        width        = "150"
        height       = "150"
        fill         = "url(#test_pattern1)"
    />

</svg>


<div>
	<span class="param_title">patternタグのパラメータ</span>

	<div class="params_box">
		<input type="range" id="pattern_x" value="0">
		<div>x:</div>
		<div class="params" id="test_pattern_x"></div>
	</div>

	<div class="params_box">
		<input type="range" id="pattern_y" value="0">
		<div>y:</div>
		<div class="params" id="test_pattern_y"></div>
	</div>

</div>

<div>
	<span class="param_title">circleタグのパラメータ</span>

	<div class="params_box">
		<input type="range" id="circle_cx">
		<div>cx:</div>
		<div class="params" id="test_circle_cx"></div>
	</div>

	<div class="params_box">
		<input type="range" id="circle_cy">
		<div>cy:</div>
		<div class="params" id="test_circle_cy"></div>
	</div>

	<div class="params_box">
		<input type="range" id="circle_r">
		<div>r :</div>
		<div class="params" id="test_circle_r"></div>
	</div>

</div>


<script>

// スライダpattern_xの要素を取得し、イベントを付与する
let pattern_x_dom = document.getElementById('pattern_x');
pattern_x_dom.addEventListener('input', function(e) {

	console.log("pattern_x_dom.value -> " + pattern_x_dom.value);

	// パターン内の円情報(DOM)を取得する
	let test_pattern1_dom = document.getElementById('test_pattern1');
	console.log("test_pattern1_dom -> " + test_pattern1_dom);

	// SVG要素のcxを変更する
	test_pattern1_dom.setAttribute('x', pattern_x_dom.value);
	
	// 画面出力
	let test_pattern_x_dom = document.getElementById('test_pattern_x');
	test_pattern_x_dom.innerHTML = pattern_x_dom.value + '<br />';

});

// スライダpattern_yの要素を取得し、イベントを付与する
let pattern_y_dom = document.getElementById('pattern_y');
pattern_y_dom.addEventListener('input', function(e) {

	console.log("pattern_y_dom.value -> " + pattern_y_dom.value);

	// パターン内の円情報(DOM)を取得する
	let test_pattern1_dom = document.getElementById('test_pattern1');
	console.log("test_pattern1_dom -> " + test_pattern1_dom);

	// SVG要素のcxを変更する
	test_pattern1_dom.setAttribute('y', pattern_y_dom.value);
	
	// 画面出力
	let test_pattern_y_dom = document.getElementById('test_pattern_y');
	test_pattern_y_dom.innerHTML = pattern_y_dom.value + '<br />';

});


// スライダcircle_cxの要素を取得し、イベントを付与する
let circle_cx_dom = document.getElementById('circle_cx');
circle_cx_dom.addEventListener('input', function(e) {

	console.log("circle_cx_dom.value -> " + circle_cx_dom.value);

	// パターン内の円情報(DOM)を取得する
	let test_circle1_dom = document.getElementById('test_circle1');
	console.log("test_circle1_dom -> " + test_circle1_dom);

	// SVG要素のcxを変更する
	test_circle1_dom.setAttribute('cx', circle_cx_dom.value);
	
	// 画面出力
	let test_circle_cx_dom = document.getElementById('test_circle_cx');
	test_circle_cx_dom.innerHTML = circle_cx_dom.value + '<br />';

});

// スライダcircle_cyの要素を取得し、イベントを付与する
let circle_cy_dom = document.getElementById('circle_cy');
circle_cy_dom.addEventListener('input', function(e) {

	console.log("circle_cy_dom.value -> " + circle_cy_dom.value);

	// パターン内の円情報(DOM)を取得する
	let test_circle1_dom = document.getElementById('test_circle1');
	console.log("test_circle1_dom -> " + test_circle1_dom);

	// SVG要素のcxを変更する
	test_circle1_dom.setAttribute('cy', circle_cy_dom.value);
	
	// 画面出力
	let test_circle_cy_dom = document.getElementById('test_circle_cy');
	test_circle_cy_dom.innerHTML = circle_cy_dom.value + '<br />';

});

// スライダcircle_rの要素を取得し、イベントを付与する
let circle_r_dom = document.getElementById('circle_r');
circle_r_dom.addEventListener('input', function(e) {

	console.log("circle_r_dom.value -> " + circle_r_dom.value);

	// パターン内の円情報(DOM)を取得する
	let test_circle1_dom = document.getElementById('test_circle1');
	console.log("test_circle1_dom -> " + test_circle1_dom);

	// SVG要素のcxを変更する
	test_circle1_dom.setAttribute('r', circle_r_dom.value);
	
	// 画面出力
	let test_circle_r_dom = document.getElementById('test_circle_r');
	test_circle_r_dom.innerHTML = circle_r_dom.value + '<br />';

});

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、放射状のグラデーションの円が、パターン表示されたものが表示されます。

また、画面内のパラメータは、patternのDOM要素と、circleのDOM要素を、パラメータを変化させることにより、
動的に描画結果を見られるように設置しています。

初期状態から、各パラメータを変えることにより、各パラメータがどのように描画に影響するかが確認できます。

SVGについて – グラデーションについて(その3)

Posted コメントするカテゴリー: javascript

SVGについて – グラデーションについて(その3)

放射型グラデーション

放射型グラデーションはradialGradient要素で定義されています。

		<radialGradient
			id="radial_gradient1"
		>
			<stop offset="0%" stop-color="#333"/>
			<stop offset="100%" stop-color="#fff"/>

		</radialGradient>

全体は下記です。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="200" height="200" viewBox="0 0 200 200">

	<defs>
		<radialGradient
			id="radial_gradient1"
		>
			<stop offset="0%" stop-color="#333"/>
			<stop offset="100%" stop-color="#fff"/>

		</radialGradient>
	</defs>

	<rect
        x            = "0"
        y            = "0"
        width        = "150"
        height       = "150"
        fill         = "url(#radial_gradient1)"
    />

</svg>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、放射状のグラデーションの円が表示されます。

上記のサンプルはrect(矩形)に対してのグラデーション指定です。

次にcircleのグラデーションを試してみます。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="200" height="200" viewBox="0 0 200 200">

	<defs>
		<radialGradient
			id="radial_gradient2"
			cx="0.5"
			cy="0.5"
			r="0.5"
			fx="0.7"
			fy="0.3"
		>
			<stop offset="0%" stop-color="#333"/>
			<stop offset="100%" stop-color="#fff"/>

		</radialGradient>
	</defs>

	<rect
        x            = "0"
        y            = "0"
        width        = "150"
        height       = "150"
        fill         = "url(#radial_gradient2)"
    />

</svg>

</body>
</html>

サーバ上のHTMLはこちら(test2.html)

画面にアクセスすると、fxとfyで指定した位置が焦点とされ、やや右上の座標に放射状にグラデーションがかかる描画になります。

「radialGradient」に設定した各パラメータは、次の意味になります。

cx        グラデーションの中心点のX座標
cy        グラデーションの中心点のY座標
r         グラデーションの半径
fx        グラデーションの焦点のX軸方向の値
fy        グラデーションの焦点のY軸方向の値

放射型グラデーションのspreadMethodについて

前回のサンプルをもとに、放射型グラデーションのspreadMethod属性について、試してみます。

spreadMethod属性は、グラデーションが終了した後に塗りつぶされていない領域をどう出力するかを制御します。

属性の値は「pad」「reflect」「repeat」があります。

属性値:padの場合

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="200" height="200" viewBox="0 0 200 200">

	<defs>
		<radialGradient
			id="radial_gradient2"
			cx="0.5"
			cy="0.5"
			r="0.5"
			fx="0.7"
			fy="0.3"
			spreadMethod="pad"
		>
			<stop offset="0%" stop-color="#333"/>
			<stop offset="100%" stop-color="#fff"/>

		</radialGradient>
	</defs>

	<rect
        x            = "0"
        y            = "0"
        width        = "150"
        height       = "150"
        fill         = "url(#radial_gradient2)"
    />

</svg>

</body>
</html>

サーバ上のHTMLはこちら(test3.html)

画面にアクセスすると、さきほどのサンプルと同様の出力になり、あまり違いはわかりません(これは各パラメータの値によります)

spreadMethod属性が「pad」の場合は、グラデーションが終了すると、最終的なオフセットの値をもとに周囲を埋めて描画します。

属性値:reflectの場合

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="200" height="200" viewBox="0 0 200 200">

	<defs>
		<radialGradient
			id="radial_gradient2"
			cx="0.5"
			cy="0.5"
			r="0.5"
			fx="0.7"
			fy="0.3"
			spreadMethod="reflect"
		>
			<stop offset="0%" stop-color="#333"/>
			<stop offset="100%" stop-color="#fff"/>

		</radialGradient>
	</defs>

	<rect
        x            = "0"
        y            = "0"
        width        = "150"
        height       = "150"
        fill         = "url(#radial_gradient2)"
    />

</svg>

</body>
</html>

サーバ上のHTMLはこちら(test4.html)

画面にアクセスすると、spreadMethod属性が「reflect」なので、グラデーションが継続されて描画されますが、グラデーションの終わりから逆に反射した形で描画していることがわかります。

属性値:repeatの場合

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="200" height="200" viewBox="0 0 200 200">

	<defs>
		<radialGradient
			id="radial_gradient2"
			cx="0.5"
			cy="0.5"
			r="0.5"
			fx="0.7"
			fy="0.3"
			spreadMethod="repeat"
		>
			<stop offset="0%" stop-color="#333"/>
			<stop offset="100%" stop-color="#fff"/>

		</radialGradient>
	</defs>

	<rect
        x            = "0"
        y            = "0"
        width        = "150"
        height       = "150"
        fill         = "url(#radial_gradient2)"
    />

</svg>

</body>
</html>

サーバ上のHTMLはこちら(test5.html)

画面にアクセスすると、spreadMethod属性が「repeat」なので、グラデーションが最初の値から改めてグラデーションが開始されて描画されます。

SVGについて – グラデーションについて(その2)

Posted コメントするカテゴリー: javascript

SVGについて – グラデーションについて(その2)

線形グラデーションの透明度について

前回のサンプルに対して、パラメータを調整してみます。

下記の箇所で、グラデーションの開始位置と、色情報を指定していますが、

    <linearGradient
        id = "grad1"
        x1 = "0"
        y1 = "0"
        x2 = "1"
        y2 = "0"
    >
	    <stop offset="0%"   stop-color="#000000" />
	    <stop offset="100%" stop-color="#ffffff" />
    </linearGradient>

このパラメータの最初の色情報と、最後の色情報に対して、透明度を追加します。

    <linearGradient
        id = "grad1"
        x1 = "0"
        y1 = "0"
        x2 = "1"
        y2 = "0"
    >
	    <stop offset="0%"   stop-color="#000000" stop-opacity="0.2" />
	    <stop offset="100%" stop-color="#ffffff" stop-opacity="0.5" />
    </linearGradient>

全体は下記です。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="200" height="200" viewBox="0 0 200 200">

    <linearGradient
        id = "grad1"
        x1 = "0"
        y1 = "0"
        x2 = "1"
        y2 = "0"
    >
	    <stop offset="0%"   stop-color="#000000" stop-opacity="0.2" />
	    <stop offset="100%" stop-color="#ffffff" stop-opacity="0.5" />
    </linearGradient>

    <rect
        x            = "0"
        y            = "0"
        stroke       = "#cccccc"
        stroke-width = "1"
        width        = "150"
        height       = "150"
        fill         = "url(#grad1)"
    />

</svg>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、

stop-opacity

で、指定した値で色の透明度が決まります。

上記のサンプルの値を少し変えて比較してみます。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="200" height="200" viewBox="0 0 200 200">

    <linearGradient
        id = "grad1"
        x1 = "0"
        y1 = "0"
        x2 = "1"
        y2 = "0"
    >
	    <stop offset="0%"   stop-color="#000000" stop-opacity="0.7" />
	    <stop offset="100%" stop-color="#ffffff" stop-opacity="0.8" />
    </linearGradient>

    <rect
        x            = "0"
        y            = "0"
        stroke       = "#cccccc"
        stroke-width = "1"
        width        = "150"
        height       = "150"
        fill         = "url(#grad1)"
    />

</svg>

</body>
</html>

サーバ上のHTMLはこちら(test2.html)

画面にアクセスすると、最初に書いたサンプルより、濃い配色でSVGが出力されることがわかります。
stop-opacityの値が1に近づくほど、透明度は元の色に近くなります。

線形グラデーションの方向指定

linearGradient 要素に対して、x1, x2, y1, y2 の指定で、グラデーションの方向を決定できます。

先程のサンプルの、下記の箇所

    <linearGradient
        id = "grad1"
        x1 = "0"
        y1 = "0"
        x2 = "1"
        y2 = "0"
    >

を、以下に変更します。

    <linearGradient
        id = "grad1"
        x1 = "0"
        y1 = "0"
        x2 = "0"
        y2 = "1"
    >

全体です。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="200" height="200" viewBox="0 0 200 200">

    <linearGradient
        id = "grad1"
        x1 = "0"
        y1 = "0"
        x2 = "0"
        y2 = "1"
    >
	    <stop offset="0%"   stop-color="#000000" stop-opacity="0.7" />
	    <stop offset="100%" stop-color="#ffffff" stop-opacity="0.8" />
    </linearGradient>

    <rect
        x            = "0"
        y            = "0"
        stroke       = "#cccccc"
        stroke-width = "1"
        width        = "150"
        height       = "150"
        fill         = "url(#grad1)"
    />

</svg>

</body>
</html>

サーバ上のHTMLはこちら(test3.html)

画面にアクセスすると、グラデーションの方向が、上から下に変化していることがわかります。

SVGについて – グラデーションについて

Posted コメントするカテゴリー: javascript

SVGについて – グラデーションについて

線形グラデーション

図形の着色をグラデーション化します。

まずはシンプルなサンプルコードを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="200" height="200" viewBox="0 0 200 200">

    <linearGradient
        id = "grad1"
        x1 = "0"
        y1 = "0"
        x2 = "1"
        y2 = "0"
    >

    <stop offset="0%"   stop-color="#000000" />
    <stop offset="100%" stop-color="#ffffff" />

    </linearGradient>

    <rect
        x            = "0"
        y            = "0"
        stroke       = "#cccccc"
        stroke-width = "1"
        width        = "150"
        height       = "150"
        fill         = "url(#grad1)"
    />

</svg>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、縦150、横150の正方形が表示され、
内部の背景色は、黒(#000000)から白(#ffffff)へグラデーションで着色されます。

グラデーションの描画について、次回以降の投稿で詳細を調べていきます。

SVGについて – 塗りについて

Posted コメントするカテゴリー: javascript

SVGについて – 塗りについて

図形を着色する

stroke属性が図形を囲む線の着色、fill属性が図形内部の着色です。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="200" height="200" viewBox="0 0 200 200">
    <path 
        d            = "M 20 20
                        A 20 20 0 0 1 100 100"
        stroke       = "#4f4f4f"
        stroke-width = "1"
        fill         = "#cccccc"
    />
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

実行結果

stroke属性の値は

色名
RGB値
16進数
RGBA値

の表記方法になります。

透明度を決定する

図形を囲む線の透明度はstroke-opacity属性、
図形の透明度はfill-opacity属性でそれぞれ決定します。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="200" height="200" viewBox="0 0 200 200">
    <path 
        d              = "M 20 20
                          A 20 20 0 0 1 100 100"
        stroke         = "#4f4f4f"
        stroke-width   = "1"
        stroke-opacity = "0.3"
        fill           = "#cccccc"
        fill-opacity   = "0.3"
    />
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test2.html)

実行結果

ストローク(線の種類)を決定する

ストロークの属性(stroke-linecap)を指定すると、ストロークの端の描画方法を制御できます。
属性の値と効果は以下になります。

stroke-width      幅
stroke-linecap    形状
    butt    ストローク方向に垂直な直線
    square  ストロークの終端をstroke-widthの半分の値で描画(垂直)
    round   ストロークの終端を丸める(非垂直に描画)

サンプル

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div>例1 (butt)</div>
<svg width="200" height="200" viewBox="0 0 200 200">
    <path 
        d              = "M 30 30
                          A 30 30 0 0 1 110 110"
        stroke         = "#4f4f4f"
        stroke-width   = "15"
        stroke-linecap = "butt"
        stroke-opacity = "0.3"
        fill           = "#cccccc"
        fill-opacity   = "0.3"
    />
</svg>

<div>例2 (square)</div>
<svg width="200" height="200" viewBox="0 0 200 200">
    <path 
        d              = "M 30 30
                          A 30 30 0 0 1 110 110"
        stroke         = "#4f4f4f"
        stroke-width   = "15"
        stroke-linecap = "square"
        stroke-opacity = "0.3"
        fill           = "#cccccc"
        fill-opacity   = "0.3"
    />
</svg>

<div>例3 (round)</div>
<svg width="200" height="200" viewBox="0 0 200 200">
    <path 
        d              = "M 30 30
                          A 30 30 0 0 1 110 110"
        stroke         = "#4f4f4f"
        stroke-width   = "15"
        stroke-linecap = "round"
        stroke-opacity = "0.3"
        fill           = "#cccccc"
        fill-opacity   = "0.3"
    />
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test3.html)

実行結果

例1 (butt)

例2 (square)

例3 (round)

ストローク(線の種類)を決定する (破線)

ストロークの線種(stroke-dasharray)を制御できます。

値は「カンマ区切りで複数の数値」で指定できます。
下記の例では、「stroke-dasharray = “15, 5″」としており、
動作例を見てみると、実線で15ピクセル描画した後、5ピクセルの空白、その次にまた実線で15ピクセル、空白で5ピクセルという順で線が描画されています。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div>例1</div>
<svg width="200" height="200" viewBox="0 0 200 200">
    <path 
        d                = "M 30 30
                            A 30 30 0 0 1 110 110"
        stroke           = "#4f4f4f"
        stroke-width     = "15"
        stroke-linecap   = "butt"
        stroke-dasharray = "15, 5"
        stroke-opacity   = "0.3"
        fill             = "#cccccc"
        fill-opacity     = "0.3"
    />
</svg>

</body>
</html>

実行結果

サーバ上のHTMLはこちら(test4.html)

stroke-dasharrayの値をカンマ区切りで複数の数値を記載したパターンを試します。
下記のサンプルを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div>例1</div>
<svg width="200" height="200" viewBox="0 0 200 200">
    <path 
        d                = "M 30 30
                            A 30 30 0 0 1 110 110"
        stroke           = "#4f4f4f"
        stroke-width     = "15"
        stroke-linecap   = "butt"
        stroke-dasharray = "15, 5, 30"
        stroke-opacity   = "0.3"
        fill             = "#cccccc"
        fill-opacity     = "0.3"
    />
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test5.html)

画面にアクセスすると下記のような表示になります。

実行結果

この破線の描画ルールは、「15, 5, 30」の各ピクセルごとに、実線 → 空白 → 実線 という幅で破線が描画されています。
また、始点から終点まで上記のルールを繰り返して描画します。

各、実線と空白、そして幅のルールがわかりやすいように数値と色をつけたものが下記の図です。

最初、赤文字で「15, 5, 30」の間隔で破線(実線 → 空白 → 実線)を描画し、
次に、青文字で「15, 5, 30」の間隔で破線(空白 → 実線 → 空白)を描画しています。

その次に、また赤文字の「15, 5, 30」の間隔で描画がされ、その後、青文字での描画 → 赤文字での描画 ・・・と線分が終わるまで繰り返されます。


(注:図形のサイズは、数値をわかりやすくする為に拡大しています)

SVGについて – パス(円孤)について

Posted コメントするカテゴリー: javascript

SVGについて – パス(円孤)について

円孤について(正円)

今回はパス(円孤)の使い方について、調べてみます。

円孤を出力するコマンドは Aで記載します。
円孤は開始、終了の座標の値により、描かれるパスが変わり正円と楕円になります。
また、x軸とy軸 の方向にどれだけの長さで線を描画するかで、正円か楕円かが決まります。
(注:円の種類を決める目的で座標を決める訳ではなく、結果的に正円か楕円の描画になるかならないかです)

簡単なサンプルを書きました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="200" height="200" viewBox="0 0 200 200">
    <path 
        d            = "M 20 20
                        A 20 20 0 0 1 100 100"
        stroke       = "#4f4f4f"
        stroke-width = "1"
        fill         = "#cccccc"
    />
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、以下の円孤が表示されます。

孤がどのように描画されるかのポイントとなる点は、 M と A のパラメータの値です。

例えば、以下のパラメータの場合、

M 20 20
A 20 20 0 0 1 100 100

それぞれのパラメータの意味は次のようになります。

パラメータの値の下の行に、汎用的な名称を記載しています。

M 20 20
  x1 y1

A 20 20 0 0  1  100 100
  rx ry k f1 f2 x2  y2

各パラメータの意味は以下のようになります。

x1     円弧の開始 x座標
y1     円弧の開始 y座標
rx     円のx軸半径
ry     円のy軸半径
k      回転度(プラスで右方向、マイナスで左方向)
f1     0 : 180未満の円弧
       1 : 180以上の円弧
f2     0 : 正の角度で動き始めるか (反時計回りに描画)
       1 : 負の角度で動き始めるか (時計回りに描画)
x2     円弧の終了 x座標
y2     円弧の終了 y座標

上記のサンプルでは、描画される孤は x軸方向、y軸方向の開始座標、終了座標が同じ座標を示しており、正円の軌道になります。

円孤について(楕円)

サンプルを少し変更して、次のコードを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="200" height="200" viewBox="0 0 200 200">
    <path 
        d            = "M 30 30
                        A 20 30 0 0 1 100 150"
        stroke       = "#4f4f4f"
        stroke-width = "1"
        fill         = "#cccccc"
    />
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test2.html)

画面にアクセスすると、以下の円孤が表示されます。

先ほどのサンプルから、A のパラメータを以下のように変更しました。

A 20 30 0 0 1 100 150

最初のサンプルとは違い、開始点から描画される円の「x方向の半径」、「y方向の半径」が異なります。
また、引数の最後の終了x座標、終了y座標も異なります。

このパラメータ指定の場合は、正円の孤にはならず、楕円上の軌道で描画されます。

円孤について(他のパラメータ)

それでは、2つ目のサンプルを調整し、他のパラメータを変更してみます。

Aのパラメータの第三引数が回転度になるので、
それぞれ、0度、45度、90度、135度、180度の指定を試してみます。

Aのみを抜粋すると、以下です。

A 20 30   0 0 1 100 150
A 20 30  45 0 1 100 150
A 20 30  90 0 1 100 150
A 20 30 135 0 1 100 150
A 20 30 180 0 1 100 150

HTML全体は次のようになります。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div>0度</div>
<svg width="200" height="200" viewBox="0 0 200 200">
    <path 
        d            = "M 30 30
                        A 20 30 0 0 1 100 150"
        stroke       = "#4f4f4f"
        stroke-width = "1"
        fill         = "#cccccc"
    />
</svg>


<div>45度</div>
<svg width="200" height="200" viewBox="0 0 200 200">
    <path 
        d            = "M 30 30
                        A 20 30 45 0 1 100 150"
        stroke       = "#4f4f4f"
        stroke-width = "1"
        fill         = "#cccccc"
    />
</svg>


<div>90度</div>
<svg width="200" height="200" viewBox="0 0 200 200">
    <path 
        d            = "M 30 30
                        A 20 30 90 0 1 100 150"
        stroke       = "#4f4f4f"
        stroke-width = "1"
        fill         = "#cccccc"
    />
</svg>


<div>135度</div>
<svg width="200" height="200" viewBox="0 0 200 200">
    <path 
        d            = "M 30 30
                        A 20 30 135 0 1 100 150"
        stroke       = "#4f4f4f"
        stroke-width = "1"
        fill         = "#cccccc"
    />
</svg>


<div>180度</div>
<svg width="200" height="200" viewBox="0 0 200 200">
    <path 
        d            = "M 30 30
                        A 20 30 180 1 1 100 150"
        stroke       = "#4f4f4f"
        stroke-width = "1"
        fill         = "#cccccc"
    />
</svg>


</body>
</html>

サーバ上のHTMLはこちら(test3.html)

画面にアクセスすると、以下の円孤が表示されます。

それぞれの度数によって、楕円の座標の描画が回転して描画されます。
ただ、0度の出力と、180度の出力は同じ結果になります。

SVGについて – パス(2次ベジェ曲線)について

Posted コメントするカテゴリー: javascript

SVGについて – パス(2次ベジェ曲線)について

2次ベジェ曲線について

前回の投稿は3次ベジェ曲線でしたが、今回はパス(2次ベジェ曲線)の使い方について、調べてみます。

2次ベジェ曲線は「Q」コマンドを使って指定します。
3次ベジェ曲線は制御点を2箇所持ちましたが、2次ベジェ曲線は制御点を1つだけ持ちます。

前回のサンプルを調整して以下のHTMLを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>
 
<svg width="300" height="250" viewBox="0 0 300 250">
    <path 
        d            = "M 10,10 Q 160,240 290,10"
        stroke       = "#4f4f4f"
        stroke-width = "1"
        fill         = "transparent"
    />
</svg>
 
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、以下のベジェ曲線が表示されます。

ポイントとなる点は、dのパラメータの値です。

        d            = "M 10,10 Q 160,200 290,10"

まず、最初の「M 10, 10」で、曲線の始点を決めています。
次に「Q 160,200」で、始点から次の曲線までの座標(制御点)を決定し、
その制御点から終点への座標への曲線を決定しています。

2次ベジェ曲線について – 複数の制御点を持つ場合

2次ベジェ曲線の制御点を組み合わせることができます。
制御点を組み合わせる場合は Tコマンド を使います。
下記サンプルを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>
 
<svg width="300" height="300" viewBox="0 0 300 300">
    <path 
        d            = "M 10,150 Q 50 10, 150 150 T 290,150"
        stroke       = "#4f4f4f"
        stroke-width = "1"
        fill         = "transparent"
    />
</svg>
 
</body>
</html>

サーバ上のHTMLはこちら(test2.html)

画面にアクセスすると、以下のベジェ曲線が表示されます。

今回はシンプルな例でしたが、状況に合わせて制御点を追加してベジェ曲線をコントロールします。

SVGについて – パス(ベジェ曲線)について

Posted コメントするカテゴリー: javascript

SVGについて – パス(ベジェ曲線)について

パス(ベジェ曲線)の使い方について、調べてみます。

SVGで扱えるベジェ曲線は2種類で、
三次ベジェ曲線「C」と二次ベジェ曲線「Q」です。

三次ベジェ曲線

まずは三次ベジェ曲線を試します。

前回のサンプルを調整して以下のHTMLを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>
 
<svg width="300" height="250" viewBox="0 0 300 250">
    <path 
        d            = "M 10,10 C 20,50 270,50 290,10"
        stroke       = "#4f4f4f"
        stroke-width = "2"
        fill         = "transparent"
    />
</svg>
 
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、以下のベジェ曲線が表示されます。

ポイントとなる点は、dのパラメータの値です。

        d            = "M 10,10 C 20,50 270,50 290,10"

まず、最初の「M 10, 10」で、曲線の始点を決めています。
次に「C 20,50」で、始点から次の曲線までの座標(制御点)を決定し、
「270,50」で、終点への座標(制御点)を決定しています。

上記の場合は「10, 10」から次の点までは「20, 50」さらに次の点までは「270,50」という値で座標を決定しています。

一番最後の「290,10」は曲線の終点です。

複数の三次ベジェ曲線

上記の例をさらに発展させて、複数の制御点を持つベジェ曲線を試してみます。

複数の制御点については

        d            = "M 10,10 C 20,50 270,50 290,10"

上記のdのパラメータに、S を追加します。

以下のHTMLを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>
 
<svg width="300" height="250" viewBox="0 0 300 250">
    <path 
        d            = "M 10,10 C 20,50 100,50 120,10 S 130,60 250,200"
        stroke       = "#4f4f4f"
        stroke-width = "1"
        fill         = "transparent"
    />
</svg>
 
</body>
</html>

サーバ上のHTMLはこちら(test2.html)

画面にアクセスすると、以下のベジェ曲線が表示されます。

パタメータのdは、以下のように設定しています。

        d            = "M 10,10 C 20,50 100,50 120,10 S 130,60 250,200"

最初の始点「M 10,10」から開始し、最初の制御点「C 20,50」に向けて曲線が描画され、
次の終点に向かう制御点「100,50」から終点「120,10」にむけて曲線が描画されます。

その後に「S 130,60」の制御点が決定されますが、ここでは、終点に向かう制御点「100,50」から
対向する形で曲線が描画されます。

最後は終点「250,200」まで曲線が描画されて終わります。

SVGについて – パスについて

Posted コメントするカテゴリー: javascript

SVGについて – パスについて

パスの使い方について、調べてみます。

下記の簡単なサンプルを用意しました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>
 
<svg width="300" height="250">
    <path 
    	d            = "M 10,10 90,150 120,20 10,10"
    	stroke       = "#999999"
    	stroke-width = "1"
    	fill         = "#cccccc"
    />
</svg>
 
</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、以下のように画面上に3角形の図形が表示されます。

先程のHTML内で、パスを表す箇所は次のように書きました。

<path 
	d            = "M 10,10 90,150 120,20 10,10"
	stroke       = "#999999"
	stroke-width = "1"
	fill         = "#cccccc"
/>

便宜上、それぞれのパラメータごとに、改行して表記し、パラメータ名と値の縦の記載を揃えています。
実際のプログラミングでは必ずしも上記のように書かなくとも良いですが、
ここではパラメータと名称を把握しやすくする為に、この形にしています。

パラメータの d は形状によって定義されています。

また、値の M は、Move toコマンドといい、省略した意味で M と記載されています。

d            = "M 10,10 90,150 120,20 10,10"

パラメータ名 d の 値である一番最初の「M 10,10」は

座標 x = 10 y = 10 の座標位置にパスを移動する。という意味になります。

また、

d            = "M 10,10 90,150 120,20 10,10"

「M 10,10」の次の「90,150」は、 x = 90 y = 150 の位置にパスを移動する。という意味になります。

試しに、上記の2つのパス移動だけのパラメータにしてみます。
先程の path情報の d の定義を、以下のように変更します。

<path 
	d            = "M 10,10 90,150"
	stroke       = "#999999"
	stroke-width = "1"
	fill         = "#cccccc"
/>

HTML全体では、次のように書きました。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>
 
<svg width="300" height="250">
    <path 
    	d            = "M 10,10 90,150"
    	stroke       = "#999999"
    	stroke-width = "1"
    	fill         = "#cccccc"
    />
</svg>
 
</body>
</html>

サーバ上のHTMLはこちら(test2.html)

画面にアクセスすると、次のように出力されます。

出力画面をみるとわかるように、最初の x = 10 y = 10 の位置から、x = 90 y = 150 の位置にパスが移動(描画)されていることがわかります。

ここで、最初のサンプルに戻ります。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>
 
<svg width="300" height="250">
    <path 
    	d            = "M 10,10 90,150 120,20 10,10"
    	stroke       = "#999999"
    	stroke-width = "1"
    	fill         = "#cccccc"
    />
</svg>
 
</body>
</html>

コードを改めて確認すると、パラメータ d の値は「M 10,10 90,150 120,20 10,10」となっており、

1つ目のパス → 10,10
2つ目のパス → 90,150
3つ目のパス → 120,20
4つ目のパス → 10,10

という情報を持っています。

ここで登場する4つ目のパスは、1つ目のパスと同じ情報「10, 10」と記載しています。

こうすることで、パスが一周して閉じたかのように描画されます。

ただし、これは便宜的に図形が閉じる座標を書いただけにすぎません。

パスの値として、最後に Z を書くことで、パスを1つ目のパス(始点)に戻るようにすることができます。

<svg width="300" height="250">
    <path 
    	d            = "M 10,10 90,150 120,20 Z"
    	stroke       = "#999999"
    	stroke-width = "1"
    	fill         = "#cccccc"
    />
</svg>

HTML全体では、次のように書きます。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>
 
<svg width="300" height="250">
    <path 
    	d            = "M 10,10 90,150 120,20 Z"
    	stroke       = "#999"
    	stroke-width = "1"
    	fill         = "#cccccc"
    />
</svg>
 
</body>
</html>

サーバ上のHTMLはこちら(test3.html)

画面にアクセスすると、次のように出力されます。

一番最初に試したサンプルと同じ出力結果になることがわかります。

SVGについて – viewBoxについて

Posted コメントするカテゴリー: javascript

SVGについて – viewBoxについて

前回のサンプルHTMLコードで、SVGのDOM要素を以下のように指定しました。

<svg id="svg_tag" width="500" height="400" viewBox="0 0 500 400" xmlns="http://www.w3.org/2000/svg"></svg> 

この際、SVGのDOM要素の幅と高さを500と400に指定しています。
また、属性として「viewBox」という属性も合わせて「0 0 500 400」と指定しています。

この「viewBox」の値がどのような効果があるのかを比較してみます。
まず、わかりやすいように、比較用のHTMLサンプルを用意しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg id="svg_tag" width="500" height="400" viewBox="0 0 500 400" xmlns="http://www.w3.org/2000/svg"></svg> 

<script type="text/javascript">
let svg_dom = document.getElementById("svg_tag");
svg_dom.setAttribute("style", "background-color:#dbdbdb;");

let line = document.createElementNS('http://www.w3.org/2000/svg', 'line')
line.setAttribute('id'    , 'svg_line_id1');
line.setAttribute('x1'    , '10');
line.setAttribute('y1'    , '10');
line.setAttribute('x2'    , '490');
line.setAttribute('y2'    , '390');
line.setAttribute('stroke', '#000000');

svg_dom.appendChild(line);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、次のようなグレーのDOM領域に対して、DOM領域のx=0, y=0から10ピクセル離れた点から、
DOM領域全体のx=500, y=400から同様に10ピクセル離れた点までの直線が表示されます。

では次に、viewBoxの値のみを、ぞれぞれ半分にしてみます。

記述としては、以下になります。

<svg id="svg_tag" width="500" height="400" viewBox="0 0 250 200" xmlns="http://www.w3.org/2000/svg"></svg> 

HTML全体では、以下のようになります。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg id="svg_tag" width="500" height="400" viewBox="0 0 250 200" xmlns="http://www.w3.org/2000/svg"></svg> 

<script type="text/javascript">
let svg_dom = document.getElementById("svg_tag");
svg_dom.setAttribute("style", "background-color:#dbdbdb;");

let line = document.createElementNS('http://www.w3.org/2000/svg', 'line')
line.setAttribute('id'    , 'svg_line_id1');
line.setAttribute('x1'    , '10');
line.setAttribute('y1'    , '10');
line.setAttribute('x2'    , '490');
line.setAttribute('y2'    , '390');
line.setAttribute('stroke', '#000000');

svg_dom.appendChild(line);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test2.html)

画面にアクセスすると、ややわかりにくいですが、SVGのDOM要素の幅(500)と高さ(400)のグレー色になっている領域のサイズは変わらないですが、javascriptで定義したSVGの直線(line)は、2倍の大きさで描画されていることがわかります。

では、さらに、viewBoxの値のみを、ぞれぞれ2倍にしてみます。

記述としては、以下になります。

<svg id="svg_tag" width="500" height="400" viewBox="0 0 1000 800" xmlns="http://www.w3.org/2000/svg"></svg> 

HTML全体では、以下のようになります。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg id="svg_tag" width="500" height="400" viewBox="0 0 1000 800" xmlns="http://www.w3.org/2000/svg"></svg> 

<script type="text/javascript">
let svg_dom = document.getElementById("svg_tag");
svg_dom.setAttribute("style", "background-color:#dbdbdb;");

let line = document.createElementNS('http://www.w3.org/2000/svg', 'line')
line.setAttribute('id'    , 'svg_line_id1');
line.setAttribute('x1'    , '10');
line.setAttribute('y1'    , '10');
line.setAttribute('x2'    , '490');
line.setAttribute('y2'    , '390');
line.setAttribute('stroke', '#000000');

svg_dom.appendChild(line);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test3.html)

画面にアクセスすると、さきほどと同様に SVGのDOM要素の幅(500)と高さ(400)のグレー色になっている領域のサイズは変わらないですが、今度はjavascriptで定義したSVGの直線(line)は、半分(2分の1)の大きさで描画されていることがわかります。

ここまで試したことから、viewBoxの座標指定(開始X座標、開始Y座標、終了X座標、終了Y座標) はSVG内の要素をどのくらいの大きさで表示するかを決定していることがわかります。
また、SVGのDOM要素の幅(width)と高さ(height)は、画面上に表示するDOM要素のサイズを決定していることがわかります。

例えば、SVGのDOM要素の幅を500 x 400で決定しておき、SVG内の描画サイズを5倍の2500 x 2000で描画することもできるはずです。

実際にどのように表示されるかを検証してみました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg id="svg_tag" width="500" height="400" viewBox="0 0 2500 2000" xmlns="http://www.w3.org/2000/svg"></svg> 

<script type="text/javascript">
let svg_dom = document.getElementById("svg_tag");
svg_dom.setAttribute("style", "background-color:#dbdbdb;");

let line = document.createElementNS('http://www.w3.org/2000/svg', 'line')
line.setAttribute('id'    , 'svg_line_id1');
line.setAttribute('x1'    , '10');
line.setAttribute('y1'    , '10');
line.setAttribute('x2'    , '490');
line.setAttribute('y2'    , '390');
line.setAttribute('stroke', '#000000');

svg_dom.appendChild(line);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test4.html)

画面にアクセスすると、次のようになりました。

5倍のviewBoxの座標指定にすると、やや内容が確認しづらくなりました。
ただ、SVGはベクター情報ではなく、ラスター情報なので、描画サイズを大きくしても、小さくしても座標の計算に基づく表示をしていると言えます。

例は直線(line)のみでしたが、より複雑なベクター情報をもつSVG要素でもどうようの動きをします。
実際の開発時にはviewBoxのサイズ指定を考慮した実装にすると良いと思います。

SVGについて – javascriptでSVGの要素を制御する

Posted コメントするカテゴリー: javascript

SVGについて – javascriptでSVGの要素を制御する

javascriptでSVGの要素を動的に変更する方法を試してみます。

HTMLドキュメント内のdivタグにIDを付与し、javascriptでSVGを生成+描画する方法を試してみます。
簡単なサンプルを書きました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg id="svg_tag" width="500" height="400"  viewBox="0 0 500 400" xmlns="http://www.w3.org/2000/svg"></svg> 

<div id="move_line">直線(line)要素を回転させる(この文字をクリックすると動きます)</div>

<script type="text/javascript">
let line = document.createElementNS('http://www.w3.org/2000/svg', 'line')

line.setAttribute('id'    , 'svg_line_id1');
line.setAttribute('x1'    , '30');
line.setAttribute('y1'    , '50');
line.setAttribute('x2'    , '200');
line.setAttribute('y2'    , '150');
line.setAttribute('stroke', '#000000');

let svgtest_dom = document.getElementById("svg_tag");
svgtest_dom.appendChild(line);

let rotate_value = 0;

let element_move = document.getElementById('move_line');
element_move.addEventListener('click',  function() {
    let element_svg_line = document.getElementById('svg_line_id1');

    rotate_value += 10;
    element_svg_line.setAttribute("transform", "rotate(" + rotate_value + ", 100, 100)");

}, false);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスして「直線(line)要素を動かす」をクリックすると、svgで描画された直線(line)が 回転(rotate)します。
rotate_value をスクリプト内部で定義して、クリックするごとに10づつ値を加算しています。

ポイントとなる点は、14行目~21行目でjavascript内でline要素を生成していますが、
その際に16行目でsvg要素に対してidを付与しています。

こうすることでHTMLドキュメント上では、次のようにline要素にIDが追加されます。

<line id="svg_line_id1" x1="30" y1="50" x2="200" y2="150" stroke="#000000"></line>

このIDをもとに、30行目で

let element_svg_line = document.getElementById('svg_line_id1');

とすることで、getElementByIdでline要素を取得し、プロパティにアクセスすることができています。

また、transformは移動・回転・伸縮・傾斜を制御するプロパティですが、このプロパティ以外を設定することで様々な動きが可能になります。

SVGについて – ドキュメント内にSVGを表示する(createElementNS)

Posted コメントするカテゴリー: javascript

SVGについて – ドキュメント内にSVGを表示する(createElementNS)

SVGについて、描画の方法を試してみます。

前回の投稿ではHTML5ドキュメント内にSVGタグを直接記述してSVGを描画しましたが、
ここではjavascriptのcreateElementNSメソッドを使って描画してみます。

HTMLドキュメント内のdivタグにIDを付与し、javascriptでSVGを生成+描画する方法

HTMLドキュメント内のdivタグにIDを付与し、javascriptでSVGを生成+描画する方法を試してみます。
HTML全体のコードは次のように書きました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div id="svgtest"></div>

<script type="text/javascript">
let test1 = document.createElementNS('http://www.w3.org/2000/svg', 'svg');

test1.setAttribute("width", "600");
test1.setAttribute("height", "400");
test1.setAttribute("viewbox", "0 0 600 400");
test1.setAttribute("style", "background-color:#cccccc;");

let line = document.createElementNS('http://www.w3.org/2000/svg', 'line')

line.setAttribute('x1', '20');
line.setAttribute('y1', '50');
line.setAttribute('x2', '500');
line.setAttribute('y2', '300');
line.setAttribute('stroke', '#000000');

test1.appendChild(line);

let svgtest_dom = document.getElementById("svgtest");
svgtest_dom.appendChild(test1);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、グレーのSVG領域に、黒で直線(line)が描画されます。

HTMLドキュメント内にはsvgタグを書いていないので、
javascript側で

document.createElementNS('http://www.w3.org/2000/svg', 'svg');

を記述し、
svgオブジェクトをcreateElementNSで生成しています。

HTMLドキュメント内のsvgタグに、javascriptでSVGを描画する方法

また、

<div id="svgtest"></div>

のdivタグをHTMLに記述せず、ここをsvgタグにすることもできます。
次のHTMLを用意しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg id="svg_tag" width="500" height="400"  viewBox="0 0 500 400" xmlns="http://www.w3.org/2000/svg"></svg> 

<script type="text/javascript">
let line = document.createElementNS('http://www.w3.org/2000/svg', 'line')

line.setAttribute('x1', '30');
line.setAttribute('y1', '50');
line.setAttribute('x2', '400');
line.setAttribute('y2', '300');
line.setAttribute('stroke', '#000000');

let svgtest_dom = document.getElementById("svg_tag");
svgtest_dom.appendChild(line);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test2.html)

画面にアクセスすると、直線だけが描画されます。
一つ前のサンプルとの違いは、javascript内でsvgタグを生成していない為、
生成時に背景色を指定していた処理がない為、直線のみが描画されています。

HTMLドキュメント内のsvgタグに、javascriptでSVGを描画する方法(SVGの要素を変更)

先程のサンプルは直線のみを描画でしたが、直線の要素を円に変更して試してみます。
下記のHTMLサンプルを用意しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg id="svg_tag" width="500" height="400"  viewBox="0 0 500 400" xmlns="http://www.w3.org/2000/svg"></svg> 

<script type="text/javascript">
let circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle')

circle.setAttribute('cx', '50');
circle.setAttribute('cy', '50');
circle.setAttribute('r', '40');
circle.setAttribute('stroke', '#1');
circle.setAttribute('stroke-width', '300');
circle.setAttribute('fill', '#cccccc');

let svgtest_dom = document.getElementById("svg_tag");
svgtest_dom.appendChild(circle);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test3.html)

画面にアクセスすると、円(circle)の描画がされていることが確認できます。

SVGについて – ドキュメント内にSVGを表示する

Posted コメントするカテゴリー: javascript

SVGについて – ドキュメント内にSVGを表示する

SVGについて、描画の方法を試してみます。

まず、HTML5ドキュメント内にSVGタグを直接記述する方法です。

rect(四角形)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="150" height="100">
	<rect
		x="0"
		y="0"
		width="80"
		height="40"
		stroke="#000000"
		stroke-width="1"
		fill="#cccccc"
	/>
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

circle(円)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="150" height="100">
	<circle
		cx="25"
		cy="25"
		r="20"
		stroke="#000000"
		stroke-width="1"
		fill="#cccccc"
	/>
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test2.html)

ellipse(楕円)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="300" height="250" viewBox="0 0 500 300">
	<ellipse
		cx="90"
		cy="5"
		rx="80"
		ry="30"
		stroke="#000000"
		stroke-width="1"
		fill="#cccccc"
	/>
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test3.html)

line(直線)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="300" height="250" viewBox="0 0 500 300">
	<line
		x="20"
		y1="5"
		x2="150"
		y2="180"
		stroke="#000000"
		stroke-width="1"
		fill="#cccccc"
	/>
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test4.html)

path(折れ線)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="300" height="250">
	<path
		d="M 10,0 90,150 120,20 60,5"
		stroke="#999"
		stroke-width="1"
		fill="#cccccc"
	/>
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test5.html)

path(曲線)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="300" height="250">
	<path
		d="M 10,0 90,150 120,20 60,5"
		stroke="#999"
		stroke-width="1"
		fill="#cccccc"
	/>
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test6.html)

polyline(連続する線)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="300" height="250">
	<polyline
		points="10,15 25,120 50,180 75,95 98,250 105,140 130,175 135,210 150,165"
		stroke="#000000"
		stroke-width="1"
		fill="none"
	/>
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test7.html)

polygon(多角形)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg width="300" height="250">
	<polygon
		points="10 15 25 120 50 180 75 95 98 250 105 140 130 175 135 210 150 135"
		stroke="#000000"
		stroke-width="1"
		fill="none"
	/>
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test8.html)

SVGについて

Posted コメントするカテゴリー: javascript

SVGについて

SVGについて試してみます。

SVGは Scalavle Vector Grapthics の略です。

画像ファイルには、ラスター形式(jpg、gif、png等)と、ベクター形式があり、SVGはベクター情報になります。

大きな特徴としては、SVGは拡大縮小しても描画精度には影響しません。
ラスター画像の場合は、拡大するとピクセル単位の表示が拡大され、画像の精度が荒くなります。

ここではSVGで表現できる方法を一つ一つ試してみようと思います。

下記に簡単なサンプルを用意しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 300">
	<defs>
		<linearGradient id="test1">
			<stop offset="0%" stop-color="#ccc" />
		</linearGradient>
	</defs>
	<rect x="10" y="10" width="300" height="200" stroke="#fff" storoke-width="20" fill="url(#test1)"/>
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、rectタグで指定したサイズの長方形が表示されます。
画面の大きさを変えた場合でも、長方形が拡大縮小されることがわかります。
ただし、この長方形は単色で塗りつぶしただけなので、SVGの特徴はわかりにくいです。
本来、ラスター画像なので、座標情報を元に画像が描画されているので、そのサンプルは別な投稿で試します。

「http://www.w3.org/2000/svg」という文字列は慣習的に決められており、この後のサンプルでも同じように記述します。

また、linearGradient要素に複数の色情報を記述すると、グラデーションで表示されます。
下記サンプルを試してみました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 300">
	<defs>
		<linearGradient id="test1">
			<stop offset="0%" stop-color="#cccccc" />
			<stop offset="50%" stop-color="#ffffff" />
			<stop offset="70%" stop-color="#b1d0d5" />
			<stop offset="90%" stop-color="#8eb5df" />
		</linearGradient>
	</defs>
	<rect x="10" y="10" width="300" height="200" stroke="#fff" storoke-width="20" fill="url(#test1)"/>
</svg>

</body>
</html>

サーバ上のHTMLはこちら(test2.html)

画面にアクセスすると、linearGradientタグ内に記載した値でグラデーションされた長方形が表示されます。
このサンプルも先程と同様、単純な長方形なので、まだSVGの特徴がつかめていません。
ここでは、SVGを出力する方法を試す程度にしておきます。

SVGの出力方法について

上記のサンプルは、あらかじめHTMLドキュメント内にSVG用のタグと、SVGの出力内容を記載する方法でした。

ここでは、別な方法としてjavascript内からSVGを生成して出力する方法を試します。

まず、HTMLドキュメント内にSVG描画用のDIVタグを記載し、その後にjavascriptでSVGを定義し、DIVタグに出力する方法です。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div id="svgtest"></div>

<script type="text/javascript">
let test1 = document.createElementNS('http://www.w3.org/2000/svg', 'svg');

test1.setAttribute("width"  , "600");
test1.setAttribute("height" , "400");
test1.setAttribute("viewbox", "0 0 600 400");
test1.setAttribute("style"  , "background-color:#e1e1e1;");

let line = document.createElementNS('http://www.w3.org/2000/svg', 'line')

line.setAttribute('x1'    , '30');
line.setAttribute('y1'    , '50');
line.setAttribute('x2'    , '300');
line.setAttribute('y2'    , '200');
line.setAttribute('stroke', '#000000');

test1.appendChild(line);

let svgtest_dom = document.getElementById("svgtest");
svgtest_dom.appendChild(test1);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test3.html)

画面にアクセスすると、横600、縦400の長方形に、SVG用を動的に生成したline要素が表示されます。

サンプルの中で「createElementNS」というメソッドが出てきましたが、
これは名前空間URIと修飾名(第二引数)の要素を生成する命令です。(第三引数はここでは省略しています)
修飾名には

svg
line
rect
circle
ellipse
path
polygon

等があり、svg領域にどんな描画出力をするかを決定します。

メディアの状態について

Posted コメントするカテゴリー: javascript

メディアの状態について

メディアの再生状態について、検証してみます。
前回の投稿のサンプルをもとに、メディアの再生状態を把握するプロパティを抜粋して下記のサンプルを用意しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<audio controls id="audiodata1">
	<source src="test.mp3" id="sound1">
</audio>

<div id="sound_play">サウンドを再生する</div>

<div id="sound_pause">サウンドを一時停止する</div>

<hr>
プロパティ出力<br />
<div id="property_result"></div>

<script type="text/javascript">

	// サウンド制御のDOM要素を取得
	let button_play = document.getElementById('sound_play');
	let button_pause = document.getElementById('sound_pause');

	// 再生イベント
	button_play.addEventListener('click', function() {
		let audiodata1 = document.getElementById("audiodata1");
		audiodata1.play();
		
		// プロパティの状態を確認する
		display_property();

	}, false);

	// 一時停止イベント
	button_pause.addEventListener('click', function() {
		let audiodata1 = document.getElementById("audiodata1");
		audiodata1.pause();

		// プロパティの状態を確認する
		display_property();

	}, false);

	function display_property()
	{
		// 結果確認用DOMを取得
		let property_result = document.getElementById("property_result");

		// サウンド制御のDOM要素を取得
		let audiodata1 = document.getElementById("audiodata1");

		// サウンドファイルのsource要素を取得
		let sound1 = document.getElementById('sound1');

		// 一旦表示を初期化する
		property_result.innerHTML = '';

		// メディアの長さ
		property_result.innerHTML += "duration        -> " + audiodata1.duration          + '<br />';
		// メディアの現在再生位置(秒)
		property_result.innerHTML += "currentTime     -> " + audiodata1.currentTime       + '<br />';

		// TimeRangesオブジェクト
		property_result.innerHTML += "buffered        -> " + audiodata1.buffered          + '<br />';
		property_result.innerHTML += "played          -> " + audiodata1.played            + '<br />';
		property_result.innerHTML += "seekable        -> " + audiodata1.seekable          + '<br />';

		// 開始位置と終了位置を取得
		property_result.innerHTML += "played.length   -> " + audiodata1.played.length     + '<br />';
		property_result.innerHTML += "buffered.length -> " + audiodata1.buffered.length   + '<br />';
		property_result.innerHTML += "seekable.length -> " + audiodata1.seekable.length   + '<br />';

		property_result.innerHTML += "played.start    -> " + audiodata1.played.start(0)   + '<br />';
		property_result.innerHTML += "buffered.start  -> " + audiodata1.buffered.start(0) + '<br />';
		property_result.innerHTML += "seekable.start  -> " + audiodata1.seekable.start(0) + '<br />';
		property_result.innerHTML += "played.end      -> " + audiodata1.played.end(0)     + '<br />';
		property_result.innerHTML += "buffered.end    -> " + audiodata1.buffered.end(0)   + '<br />';
		property_result.innerHTML += "seekable.end    -> " + audiodata1.seekable.end(0)   + '<br />';

		// 状態
		property_result.innerHTML += "readyState      -> " + audiodata1.readyState        + '<br />';
		property_result.innerHTML += "networkState    -> " + audiodata1.networkState      + '<br />';
		property_result.innerHTML += "error           -> " + audiodata1.error             + '<br />';
	}

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面上でサウンドの再生、一時停止、等の操作を行うと、audioタグから取得した要素のプロパティが表示されます。

主なプロパティの意味は、次になります。

durationは再生するファイルの長さ(秒)
currentTimeは再生した秒数

また、下の3つは TimeRangesオブジェクト です。

buffered
played
seekable

bufferedは現在バッファされている時間の範囲、
playedは再生された時間の範囲、
seekableは現在移動できる時間の範囲
をそれぞれ返します。

TimeRangesオブジェクト はそれぞれlengthプロパティと、start、endメソッドを持ち、
lengthはオブジェクトで表す範囲、startとendは開始時間と終了時間を秒単位で返します。

また、readyStateプロパティ、networkStateプロパティはメディアオブジェクトの状態の情報を持ちます。
上記サンプル画面のサウンドを再生、一時停止、再生を行うと

readyState -> 4
networkState -> 1

という結果が画面に表示されます。

readyStateはメディアデータがどの程度読み込まれているかを示します。
それぞれ値と意味は次のようになります。

0 : HAVE_NOTHING
メディアファイルはロード未完了

1 : HAVE_METADATA
メディアファイルはロード完了
現在再生位置はロード未完了
currentTime位置のメディアは再生不可

2 : HAVE_CURRENT_DATA
currentTimeのロード完了

3 : HAVE_FUTURE_DATA
ロード完了
再生可能
全データを再生するには不十分

4 : HAVE_ENOUGH_DATA
ロード完了
再生可能
全データを再生するには十分(但し未保証)

networkStateはメディア要素がネットワークをどれくらい利用しているかを取得
それぞれ値と意味は次のようになります。

0 : NETWORK_EMPTY
ネットワーク未使用

1 : NETWORK_IDLE
ネットワークからロード未使用(ロード未完了とは異なる)
現在必要データをバッファ済

2 : NETWORK_LOADING
ネットワークからデータロード中

3 : NETWORK_NO_SOURCE
再生可能なメディア無し

また、errorプロパティは、サンプル画面ではnullを表示していますが、
もしメディアの再生にエラーが生じた場合は次の表示になります。

1 : MEDIA_ERR_ABORTED
ユーザによる読み込み停止

2 : MEDIA_ERR_NETWORK
ネットワークエラーにより、ロード停止

3 : MEDIA_ERR_DECODE
エンコーディングエラーにより再生不可

4 : MEDIA_ERR_SRC_NOT_SUPPORTED
メディアの種類が、使用ブラウザでは再生不可

エラーが発生しなかった場合は、nullになり、通常再生が可能になります。

メディアの操作について

Posted コメントするカテゴリー: javascript

メディアの操作について

javascriptでメディアを取り扱う方法を試してみます。

ここでいうメディアは、文字列以外のデータとして、画像(canvas含む)、音声、動画、等のファイルです。
一つ一つ試しながら理解してみます。

音声や動画ファイルの再生について

サーバ上にある音声ファイル(mp3やwav等)の再生方法は多岐に渡ります。

audioタグ(DOM要素の埋め込み)を書く方法や、Web Audio APIを使う方法

ここでは、audioを使って再生を制御する方法を試してみます。
具体的には、音声ファイルの場合は、次のように書きます。
audioオブジェクトを使う為のDOM要素と、src属性でサーバ上の音声ファイルを定義します。

<audio src="test.mp3">

ただし、このDOM要素だけをHTML上に書いても何もなりません。
サーバ側に「test.mp3」という音声ファイルを置き、下記のHTMLを書いてみました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<audio src="test.mp3">

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスしてみると、音声も再生されず、画面上にも何も表示されません。
上記のHTMLはHTML5の audioタグを指定しているだけなので、実際に音声を再生させたり停止させたりするには、属性を追加しなければならないです。
また、音声ファイルに対してその他の処理をするには、javascript側でAPIを呼んで処理をするプログラムを書く必要があります。

audioについて – controls属性について

では、上記HTMLに対して、少し手を加えてみます。
先程の

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<audio controls src="test.mp3">

</body>
</html>

サーバ上のHTMLはこちら(test2.html)

実際に画面にアクセスしてみると、音声を再生する為の
再生ボタン
再生秒数
再生位置を示すバー
ボリューム
再生速度(chromeの場合)

のユーザインタフェースが表示され、音声の再生が可能になります。

注意点としては、音声の再生が可能にはなりますが、
最近の流れとして、スマホやタブレットでの再生、またOSのandroidやiOSでの再生事情を考慮すると
再生可否が担保できなかったり、再生用のユーザインタフェースが統一されていなかったりと、
色々と注意する点があるので、本実装に採用するかどうかはプロジェクトの方針によって決定するとよいと思います。

実際に、chromeとfirefoxでの表示の違いは以下のようになります。

chrome

firefox

では、ここで少し拡張をしてみます。
複数の音声を再生する為、サーバ側にtest2.mp3とtest3.mp3を置き、下記のHTMLを作成してアクセスしてみます。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<audio controls src="test.mp3">
<audio controls src="test2.mp3">
<audio controls src="test3.mp3">

</body>
</html>

サーバ上のHTMLはこちら(test3.html)

実際にアクセスしてみるとわかりますが、
上記のHTMLの書き方では、再生欄が3つ表示されるわけではありません。
この動きを解決するには、次のようにします。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<audio controls>
	<source src="test.mp3">
</audio>

<audio controls>
	<source src="test2.mp3">
</audio>

<audio controls>
	<source src="test3.mp3">
</audio>

</body>
</html>

サーバ上のHTMLはこちら(test4.html)

画面にアクセスすると、音声ファイルに応じた、再生欄が3つ表示されます。

それぞれのファイルに応じた秒数が表示されているので、ファイルごとに再生欄が出し分けられていることがわかります。

また、もしsrc属性に、ブラウザがサポートしないファイルを指定した場合、
再生ができない旨を表示する必要があります。
その場合は次のように書きます。

<audio controls>
	<source src="test.mp3">
	<div>非サポートのファイルです</div>
</audio>

上記のように書くと、ブラウザがmp3の再生に対応していない場合、「非サポートのファイルです」という表示になります。

タイプ選択について

メディアがブラウザで再生できるかを確認する方法があります。

実際の場面では、どんな種類のメディアファイルを扱うかはプロジェクトの方針により決まりますが、
例えばユーザからなんらかのファイルを受け付け、それを再生するような場面があった場合、
そのメディアが再生可能かどうかを確認するというケースがあります。

そのような場合には、
HTMLMediaElementインターフェイスのメソッド「canPlayType」を使って調べることができます。

canPlayTypeはプログラムの実行環境でそのメディアが再生できるかを返します。
例えば、前述のサンプルに対して、再生可否を調べるには以下のように下記ます。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<audio controls id="audiodata1">
	<source src="test.mp3">
</audio>

<div id="playability_result"></div>

<script type="text/javascript">

	// 音声1のDOM要素を取得
	let audiodata1 = document.getElementById("audiodata1");

	// 音声1の再生可否を取得
	let isPlayability1 = audiodata1.canPlayType('audio/mp3');

	// 音声1のDOM要素を取得し、画面に出力する
	let playability_result = document.getElementById("playability_result");
	playability_result.innerHTML += '再生可否 isPlayability1 -> ' + isPlayability1 + '<br />';

</script>

</body>
</html>

サーバ上のHTMLはこちら(test5.html)

画面にアクセスすると、対象のファイルが再生可能かどうかが表示されます。
今回の例では「probably」と表示され、再生ができることがわかります。

再生の制御について

画面上の audio タグから、メディアファイル(音声、映像)を制御することができます。
メソッドとして用意されているものは、下記です。

canPlayType()
load()
pause()
play()
captureStream()

一番最後の「captureStream」については、映像のファイルに対してのメソッドなので、
音声ファイルには使えません。

では、上記でサンプルで書いたコードに、playメソッドを使うように改修してみます。
下記HTMLを用意しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<audio controls id="audiodata1">
	<source src="test.mp3">
</audio>

<div id="sound_play">音声を再生する</div>

<script type="text/javascript">

	// 音声再生のDOM要素を取得
	let sound_play_button = document.getElementById('sound_play');

	// 音声再生イベント
	sound_play_button.addEventListener('click',  function() {

		// 音声1のDOM要素を取得
		let audiodata1 = document.getElementById("audiodata1");

		// 再生
		audiodata1.play();

	}, false);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test6.html)

画面にアクセスし「音声を再生する」をクリックすると、

<audio controls id="audiodata1">
	<source src="test.mp3">
</audio>

で指定したaudiodata1のDOM要素の音声が再生されます。

再生以外のその他のメソッドも試してみます。
次のHTMLを用意しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<audio controls id="audiodata1">
	<source src="test.mp3">
</audio>

<div id="sound_play">音声を再生する</div>

<div id="sound_pause">音声を一時停止する</div>

<script type="text/javascript">

	// 音声制御のDOM要素を取得
	let button_play = document.getElementById('sound_play');
	let button_pause = document.getElementById('sound_pause');

	// 音声再生イベント
	button_play.addEventListener('click',  function() {

		// 音声1のDOM要素を取得
		let audiodata1 = document.getElementById("audiodata1");

		// 再生
		audiodata1.play();

	}, false);

	// 音声再生イベント
	button_pause.addEventListener('click',  function() {

		// 音声1のDOM要素を取得
		let audiodata1 = document.getElementById("audiodata1");

		// 再生
		audiodata1.pause();

	}, false);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test7.html)

画面にアクセスし、音声を再生した後、「音声を一時停止する」をクリックすると、再生は一時停止します。
また「音声を一時停止する」をクリックすると再生は再開されます。
実際のアプリケーションでは、一時停止した後に、「音声を一時停止する」の文言を切り替えて、
「再生を再開する」旨の表示に切り替えるように工夫をします。

また、メソッドの他に、プロパティもあります。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<audio controls id="audiodata1">
	<source src="test.mp3">
</audio>

<div id="sound_play">音声を再生する</div>

<div id="sound_pause">音声を一時停止する</div>

<div id="sound_volume_up">音量を上げる</div>

<div id="sound_volume_down">音量を下げる</div>

<script type="text/javascript">

	// 音声制御のDOM要素を取得
	let button_play = document.getElementById('sound_play');
	let button_pause = document.getElementById('sound_pause');
	let button_volume_up = document.getElementById('sound_volume_up');
	let button_volume_down = document.getElementById('sound_volume_down');

	// 再生イベント
	button_play.addEventListener('click',  function() {
		let audiodata1 = document.getElementById("audiodata1");
		audiodata1.play();
	}, false);

	// 一時停止イベント
	button_pause.addEventListener('click',  function() {
		let audiodata1 = document.getElementById("audiodata1");
		audiodata1.pause();
	}, false);

	// 音量を上げる
	button_volume_up.addEventListener('click',  function() {
		let audiodata1 = document.getElementById("audiodata1");
		audiodata1.volume += 0.1;
	}, false);

	// 音量を下げる
	button_volume_down.addEventListener('click',  function() {
		let audiodata1 = document.getElementById("audiodata1");
		audiodata1.volume -= 0.1;
	}, false);

</script>

</body>
</html>

サーバ上のHTMLはこちら(test8.html)

画面にアクセスして、音声を再生した後、音量を上げる(または下げる) をクリックすると、音量が調整できます。
上記の例はほんの一例ですが、その他にもプロパティが用意されています。

これらはHTMLMediaElementのインタフェイスとして定義されています。
各プロパティの意味や使用方法はここでは書きませんが、実際の開発時には各プロパティを調査したうえで実装をします。

audioTracks
autoplay
buffered
controls
controlsList
crossOrigin
currentSrc
currentTime
defaultMuted
defaultPlaybackRate
disableRemotePlayback
duration
ended
loop
muted
paused
playbackRate
played
preload
preservesPitch
seekable
seeking
src
srcObject
textTracks
videoTracks
volume
error
networkState
readyState

(上記は、全てのプロパティを列挙はしていません)

上記のプロパティがどのような値を保持し、どのような値が取得できるのかを試してみます。
以下、プロパティの内容を出力するサンプルを書きました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<audio controls id="audiodata1">
	<source src="test.mp3">
</audio>

<div id="sound_play">サウンドを再生する</div>

<div id="sound_pause">サウンドを一時停止する</div>

<div id="sound_volume_up">音量を上げる</div>

<div id="sound_volume_down">音量を下げる</div>

<hr>
プロパティ出力<br />
<div id="property_result"></div>


<script type="text/javascript">

	// サウンド制御のDOM要素を取得
	let button_play = document.getElementById('sound_play');
	let button_pause = document.getElementById('sound_pause');
	let button_volume_up = document.getElementById('sound_volume_up');
	let button_volume_down = document.getElementById('sound_volume_down');

	// 再生イベント
	button_play.addEventListener('click',  function() {
		let audiodata1 = document.getElementById("audiodata1");
		audiodata1.play();
		display_property();
	}, false);

	// 一時停止イベント
	button_pause.addEventListener('click',  function() {
		let audiodata1 = document.getElementById("audiodata1");
		audiodata1.pause();
		display_property();
	}, false);

	// 音量を上げる
	button_volume_up.addEventListener('click',  function() {
		let audiodata1 = document.getElementById("audiodata1");
		audiodata1.volume += 0.1;
		display_property();
	}, false);

	// 音量を下げる
	button_volume_down.addEventListener('click',  function() {
		let audiodata1 = document.getElementById("audiodata1");
		audiodata1.volume -= 0.1;
		display_property();
	}, false);

	function display_property()
	{
		let property_result = document.getElementById("property_result");
		let audiodata_property = document.getElementById("audiodata1");

		// 一旦表示を初期化する
		property_result.innerHTML = '';

		property_result.innerHTML += "audioTracks              -> " + audiodata_property.audioTracks + '<br />';
		property_result.innerHTML += "autoplay                 -> " + audiodata_property.autoplay + '<br />';
		property_result.innerHTML += "buffered                 -> " + audiodata_property.buffered + '<br />';
		property_result.innerHTML += "controls                 -> " + audiodata_property.controls + '<br />';
		property_result.innerHTML += "controlsList             -> " + audiodata_property.controlsList + '<br />';
		property_result.innerHTML += "crossOrigin              -> " + audiodata_property.crossOrigin + '<br />';
		property_result.innerHTML += "currentSrc               -> " + audiodata_property.currentSrc + '<br />';
		property_result.innerHTML += "currentTime              -> " + audiodata_property.currentTime + '<br />';
		property_result.innerHTML += "defaultMuted             -> " + audiodata_property.defaultMuted + '<br />';
		property_result.innerHTML += "defaultPlaybackRate      -> " + audiodata_property.defaultPlaybackRate + '<br />';
		property_result.innerHTML += "disableRemotePlayback    -> " + audiodata_property.disableRemotePlayback + '<br />';
		property_result.innerHTML += "duration                 -> " + audiodata_property.duration + '<br />';
		property_result.innerHTML += "ended                    -> " + audiodata_property.ended + '<br />';
		property_result.innerHTML += "loop                     -> " + audiodata_property.loop + '<br />';
		property_result.innerHTML += "muted                    -> " + audiodata_property.muted + '<br />';
		property_result.innerHTML += "paused                   -> " + audiodata_property.paused + '<br />';
		property_result.innerHTML += "playbackRate             -> " + audiodata_property.playbackRate + '<br />';
		property_result.innerHTML += "played                   -> " + audiodata_property.played + '<br />';
		property_result.innerHTML += "preload                  -> " + audiodata_property.preload + '<br />';
		property_result.innerHTML += "preservesPitch           -> " + audiodata_property.preservesPitch + '<br />';
		property_result.innerHTML += "seekable                 -> " + audiodata_property.seekable + '<br />';
		property_result.innerHTML += "seeking                  -> " + audiodata_property.seeking + '<br />';
		property_result.innerHTML += "src                      -> " + audiodata_property.src + '<br />';
		property_result.innerHTML += "srcObject                -> " + audiodata_property.srcObject + '<br />';
		property_result.innerHTML += "textTracks               -> " + audiodata_property.textTracks + '<br />';
		property_result.innerHTML += "videoTracks              -> " + audiodata_property.videoTracks + '<br />';
		property_result.innerHTML += "volume                   -> " + audiodata_property.volume + '<br />';
		property_result.innerHTML += "error                    -> " + audiodata_property.error + '<br />';
		property_result.innerHTML += "networkState             -> " + audiodata_property.networkState + '<br />';
		property_result.innerHTML += "readyState               -> " + audiodata_property.readyState + '<br />';
	}

</script>

</body>
</html>

サーバ上のHTMLはこちら(test9.html)

画面にアクセスして、音声を再生、一時停止、等の操作をしたタイミングで、
各プロパティの値が更新されて内容を確認できます。

オフラインwebアプリケーションについて

Posted コメントするカテゴリー: javascript

オフラインwebアプリケーションについて

以前の投稿でOffline Web Applications について記載しましたが、ここでもう少し掘り下げて調べてみます。

注意点としては、この機能は現状では非推奨となっているので、
「こうゆう機能もある(あった)」という程度に留めておいてよいと思います。
(firefox62以降では使用できません)

オフラインwebアプリケーションを実現には、HTML5の仕組みのアプリケーションキャッシュ機能を使います。
具体的にはアプリケーション自身(HTML、CSS、javascript、画像、音声等のリソースを含む)のデータを全て保存します。

ブラウザのキャッシュとは違うので、ブラウザのキャッシュクリアをしてもデータは削除されず、
ユーザが意図して消さない限りは永続的に残ります。

こうすることでそのwebアプリケーションはオフライン環境でも動作する(アプリケーションからの通信を行わない前提になります)
ことが可能になります。
厳密に言うと、アプリケーションから通信が発生した場合、オンラインに切り替わった段階で通信処理が再開する。という動きになります。

また、全てのブラウザ(バージョン)で動作が保証されてはいないので、実行環境には注意が必要です。

アプリケーションキャッシュマニフェストについて

webアプリケーションキャッシュを使うには、マニフェストファイルが必要になります。
このファイルにはwebアプリケーションが必要とするURLの一覧が含まれています。

マニュフェストファイルの書き方

1行目に

CACHE MANIFEST

を記載します。

コメントは

#

と書きます。

セクションは

CACHE

NETWORK

FALLBACK

SETTINGS

があり、それぞれ次の意味になります。

CACHE
キャッシュするファイルを指定する

NETWORK
ここに書いたファイルはオンラインでサーバ接続が必要

FALLBACK
もしオンラインで接続することができない場合、ここに書いた代替のファイルにアクセスします。

具体的には以下のように書きます。
各ファイル名はダミーです。

CACHE MANIFEST
# ver1.0

CACHE:
test.html
test.css
test.js
images/test.png

NETWORK:
*

FALLBACK:
/fallback.php /dummy.html

マニュフェストファイルが更新された際に、キャッシュ内容の更新を行う為に、
2行目にはバージョン番号を記載することが多いです。

マニュフェストファイル自身の拡張子は指定されていません。
慣習的に.appcache等と指定する場合があります。
既に非推奨の機能なので、ここで実例を試すことはしませんが、後日、何か検証が必要な場面がでてきたら追記するかもしれません。

クッキーについて

Posted コメントするカテゴリー: javascript

クッキーについて

クッキーについてまとめます。
クッキーは Web Storage(localStorage、sessionStorage)よりも馴染みがあり、
歴史的理由から古くから使われている手法です。

サーバサイド言語からも操作でき、元々はサーバサイド側からの利用用途が多くあります。
また、javascriptからもクッキーを操作することができます。

有効期間やスコープはクッキーごとに指定でき、このあたりもWeb Storageとは異なります。

クッキー の仕様

クッキーの仕様についてまとめます。
以下の仕様があります。

保存ファイル
ブラウザごとにテキストファイル形式で保存

1サイトでの最大数
最大20個まで(ブラウザによる)

1つの最大容量
4096バイト(約4KB)

有効期限
保存時に個別に指定する

ブラウザ間の読み込み
共有は不可

スコープ
同一出身ポリシー内で利用

クッキー 使用可否の判定について

javascriptからクッキーが使用可能かを確認する方法があります。

Navigator.cookieEnabled

の値を取得することで、boolean(真/偽)値でクッキーが使用可能かがわかります。

クッキーの特徴について

クッキーの特徴(仕様)ついてまとめます。

・クッキーを保持する際は、サーバにHTTPヘッダが送信される(手法による)
・クッキーを保存する時に指定する
・有効期間を指定しないと、一時的な保存になる
・ブラウザの(最大)セッション期間との関連もあり、クッキー側だけで期間を自由に設定できない
・クッキー側からブラウザのセッション期間の上限を超えて保存する場合は、max-age属性(またはexpire属性)を使用する
・max-age属性とexpire属性を同時に設定した場合は、max-age属性が有効になる
・max-age属性は秒数で指定する
・max-age属性は負の値も設定できる
・expire属性は有効期限が切れる日時を指定する
・どちらの属性もブラウザのバージョンにより効かない場合がある
・path属性、domain属性
・path属性で設定されたパスに保存される
・path属性で設定されたパスに保存されたものは、サブディレクトリ(ネスト化)からは読み込み可能
・path属性で設定されたパスに保存されたものに、異なる親ディレクトリからは読み込みができない
・サブドメインから、メインドメイン側のクッキーを読み込みたい場合は、domain属性に「.ドメイン名」を指定し、path属性に「/」を指定すると読み込みができる。
・secure属性はネットワークを経由してクッキーを指定する論理値
・secure属性が「真」の場合は、https経由でのみクッキーの読み書きが可能
・クッキーの値にはセミコロン、カンマは使用不可です
・セミコロン、カンマを含む文字列を登録する場合は、文字列をエンコード(encodeURIComponent)して保存します(諸方法あり)

javascriptからクッキーの操作をする

javascriptからクッキーの操作をする方法をまとめます

クッキーの登録

基本的な形としては、

名前=値

となります。

コード上では、「test1」という名称のキーに、「testvalue123」という値を登録したい時は、次のように書きます。

document.cookie = "test1=testvalue123";

ただし、この方法では有効期限を設定していないので、デフォルトの保存期間になり、ブラウザを閉じると値が失われます。

では、上記の例に有効期限(秒)を設定して保持するように書きます。
例えば10分(600秒)の保持期間の場合は、次のように書きます。

document.cookie = "test1=testvalue123; max-age=600";

実際のアプリケーションでは、保持期間10分という時間を実用的な保持期間とすることは稀です。
また、値を格納する際は、秒→時間、時間→日、へと計算する工夫が必要です。

例えばクッキーの保持期間を1日(86,400秒)とする場合は、次のようになります。

// この場合は 
// 1秒 * 60で、60秒(1分)
// 60秒(1分) * 60(分) で、3600秒(1時間)
// 3600秒(1時間) * 24(時間)で、24時間(1日)
let cookie_test_time = 1 * 60 * 60 * 24;

document.cookie = "test1=testvalue123; max-age=" + cookie_test_time;

また、例えば5時間(18,000秒)にする場合は以下のようになります。

// この場合は 
// 1秒 * 60で、60秒(1分)
// 60秒(1分) * 60(分) で、3600秒(1時間)
// 3600秒(1時間) * 5(時間)で、5時間
let cookie_test_time = 1 * 60 * 60 * 5;

document.cookie = "test1=testvalue123; max-age=" + cookie_test_time;

計算式の一番最初の「1 *」は省略しても問題はないですが、ここでは秒を例える為に記載しています。

また、他の属性をパラメータに含める場合は、「;」(セミコロン)で区切って、続けて記述します。

クッキーの読み出し

javascriptからクッキーを読みだすと、domain属性で指定した範囲内のクッキーの値を全て読み込みます。

形としては

名前=値

の組み合わせで読み込まれます。
複数の名前がある場合は、「;」で区切られた形で連続したデータとして読み込まれます。

具体的には次のように書きます。

let load_cookie;

load_cookie = document.cookie;

上記の場合は、先程の例で保存した、「test1」という名称のキーと、「testvalue123」の値が取得できます。

また、値にセミコロンやカンマが含まれているデータは、文字列をデコードしたうえで処理をする必要があります。
その場合はjavascriptの組み込み関数の「decodeURIComponent」を使ってデコードをします。

クライアントサイドストレージ – Web Storageについて(その3)

Posted コメントするカテゴリー: javascript

クライアントサイドストレージ – Web Storageについて(その3)

前々回の投稿で少しだけ登場しましたが、

localStorageにキーと値を登録(更新)する時に

localStorage.test1 = "テストA";

と書くケースと、違うケースとして

localStorage.setItem("test1", "テストA");

と書く方法があると紹介しました。

ここでは、少し深く掘り下げて後者の書き方を試してようと思います。

具体的に後者の書き方のことを Strage API と呼び、
Strage API を使って、データの登録、呼び出し、削除等をプロパティを使って行うことができます。

Strage APIについて

Strage APIを使ったデータの操作についてまとめます。

データの登録、更新

setItem()メソッドを使います。

localStorage.setItem("test1", "テストA");

データの取得

getItem()メソッドを使います。

localStorage.getItem("test1");

上記の場合、「テストA」という文字列が取得できます。

データの削除

remoteItem()メソッドを使います。

localStorage.remoteItem("test1");

ローカルストレージからキー「test1」のデータを削除します。
キーと値の両方を削除します。

データの削除(ストレージからの全削除)

clear()メソッドを使います。

localStorage.clear();

全ローカルストレージを削除します。

Storage イベントについて

Storage APIを使用してデータの登録、更新、削除、等を行ったタイミングで、
windowオブジェクトでストレージイベントが発生します。

ここでポイントとなるのがwindowオブジェクトに対して発生するという点です。
具体的には、同じURLの画面をタブで2つ開いている場合や、画面内にフレームが存在し、
そのフレームで同一出身ポリシーの画面を開いている場合。ということが言えます。

また、登録するデータが既存と同じデータの場合は、このイベントは発生しません。
データが異なる場合にイベントが発生します。

Storage イベントを使う場合、addEventListener()を使用する他、windowオブジェクトに
onstorageプロパティを設定することでイベント発火を拾えます。

具体的には、次のような書き方になります。

addEventListenerを使う場合

window.addEventListener("storage", function(event)
{
    // ここで何らかの処理をする
    
});

onstorageプロパティを使う場合

window.onstorage = function(event)
{
    // ここで何らかの処理をする
    
}

Storage イベントの属性について

上記のaddEventListenerとonstorageプロパティの例では、
処理内容を全く記載していませんが、

functionの引数として渡ってくるイベントオブジェクト「event」に対しては、
次のようなプロパティがあります。

key
newValue
oldValue
storageArea
url

それぞれ、以下の意味があります。

key
 変更されたキーを表す
 clear()が呼び出された場合はnull

newValue
 key の新しい値
 removeItem()が呼び出された場合はnull

oldValue
 key の元の値
 新規登録時はnull

storageArea
 ストレージオブジェクトを取得(localStorage または sessionStorageの使用されているオブジェクト)

url
 keyが変更されたドキュメントのURL(文字列形式)

このStorage イベントを利用すると、同一出身ポリシーで呼び出されたwebアプリケーションで、
別タブや別ウィンドウで表示しているDOM操作を行ったタイミングで、
localStorageやsessionStorageを使いデータを保持し、値が変更されたタイミングでイベントを発火し、
別タブや別ウィンドウになんらかのイベントを発生させて同期を取るアプリケーションにすることができます。

クライアントサイドストレージ – Web Storageについて(その2)

Posted コメントするカテゴリー: javascript

クライアントサイドストレージ – Web Storageについて(その2)

クライアントサイドストレージのWeb Storageについて、補足です。

前回の投稿では、localStorage のサンプルを書きましたが、

ここでは、localStorage と sessionStorage の両方を取り上げて違いを見ていきたいと思います。

前回の投稿では、両者の違いは、「有効期限」「スコープ」と書きましたが、
もう少し具体的に違いをあげていきたいと思います。

localStorage と sessionStorage の違いについて

localStorrageとsessionStorageの違いをわかりやすく比較する為あ、下記の表にまとめました。

localStorragesessionStorage
保存容量5MB
(ブラウザにより5~10MB)
5MB
(ブラウザにより5~10MB)
有効期限永続的
(または削除するまで)
ウィンドウやタブを閉じるまで
(または削除するまで)
タブごとの挙動別タブでも共有されるタブごとに保持。共有されない
スコープ同一出身ポリシーごと同一出身ポリシーごと
スコープ
(別ウィンドウ、別タブ)
別タブ、
別ウィンドウ
からアクセス可能
別タブから可能

大きな違いは「有効期限」ですが、ブラウザのタブごとの挙動の違いも注意が必要です。

ただし、sessionStorageを使用し、別ウィンドウからアクセスした場合は、
アクセス負荷ですが、画面内部にiframeを使用して同一出身ポリシーの画面にアクセスした場合は、
同一出身内のsessionStorageの内容にアクセスすることができます。

クライアントサイドストレージ – Web Storageについて

Posted コメントするカテゴリー: javascript

クライアントサイドストレージ – Web Storageについて

クライアントサイドストレージのWeb Storageについて、実際に試してみます。

前回の投稿でも書きましたが、Web Storageは「localStorage」と「sessionStorage」から構成されています。

両方ともStorageオブジェクトを参照し、Storageオブジェクトは「キーと値の組み合わせ」の連想配列でデータを保持します。

sessionStorageとlocalStorageの違いは、

有効期限
スコープ

が違います。

また、データ保存容量は5MBまでです。(ブラウザにより異なるので注意が必要です)

実際にサンプルのコードを書いて試してみます。
以下のソースを用意しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div id="result"></div>

<script type="text/javascript">

// ローカルストレージのキー「test1」に値「テストA」を更新
localStorage.test1 = "テストA";

// ローカルストレージの値(ここでは「test1」を呼び出す)
let test_value = localStorage.test1;

// 値の確認用DOMの取得
let result = document.getElementById("result");

// 画面に出力して確認
result.innerHTML += 'ローカルストレージの値 -> ' + test_value + '<br />';

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、

と表示され、ローカルストレージに更新した値が確認できます。

また、開発者ツールのApplicationからLocal Storageに保存されているキーと値を確認できます。
上記サンプルにアクセスした場合、以下のように確認できます。

保存の方法は

localStorage.test1 = "テストA";

のように書きましたが、

windows.localStorage.setItem("test1", "テストA");

のように、localStorageのメソッドを使って更新する方法もあります。読み込みは「getItem(“test1”)」です。

ここで、上記のHTML(javascript)とは別のHTMLを作り、そこから localStorage に更新した キー test1 の値を呼び出してみます。

以下のHTMLを用意しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div id="result"></div>

<script type="text/javascript">

// ローカルストレージの値(ここでは「test1」を呼び出す)
let test_value = localStorage.test1;

// 値の確認用DOMの取得
let result = document.getElementById("result");

// 画面に出力して確認
result.innerHTML += '別画面で登録したローカルストレージの値 -> ' + test_value + '<br />';

</script>

</body>
</html>

サーバ上のHTMLはこちら(test2.html)

画面にアクセスすると、以下の表示になります。

また、開発者ツールを格納すると、以下の表示になります。

別画面で更新した値を保持していることがわかり、別なウィンドウを開いてアクセスしても同様の画面になり、値が保持されていることがわかります。

上記の動きは「localStorage」と「sessionStorage」両方とも同様の動きをします。

保存が可能なデータについて

「localStorage」と「sessionStorage」では、保存できるデータの種類があります。

上記サンプルのように、単純な文字列の他、オブジェクト、配列、も保存できます。

クライアントサイドストレージ

Posted コメントするカテゴリー: javascript

クライアントサイドストレージ

クライアントサイドストレージについてまとめます。

javascriptは基本的にクライアント側で動作させることが多く(一部例外はあります)、
ブラウザで実行する都度、データを生成したり、処理したり、サーバからデータを取得して出力する
といった動作がほとんどです。

また、ブラウザを再ロードすると、実行途中だったデータはjavascriptのプログラムと
ともにまた初期状態にもどった形になります。

その動作仕様で問題がないプログラムの場合はよいのですが、
処理途中のデータや、javascriptのプログラム動作中の状態を保持しておきたいシーンがでてきます。

その場合に使用する方法がクライアントサイドストレージと呼ばれる、
各マシンごとにデータを保持しておく仕組み(機能)があります。

また、クライアントサイドストレージで保持する機能には下記の種類があります。

・Web Storage
・クッキー
・Offline Web Applications(API)
・Webデータベース
・ファイルシステムAPI

このブログでは、上記のデータ保存方法を一つ一つ実際に動作するHTML+javascritを用意して試していこうと思います。

Web Storage

HTML5で用意されているAPIです。
このAPIはlocalStorageとsessionStorageから構成されています。

構造としては、キーと値を組み合わせたものを保存するものです。

実装する際には、この機能にブラウザが対応しているかを確認する必要があります。

クッキー

かなり歴史のある方法です。
クッキーに保存した情報はテキストデータで格納され、容量も大きくはありません。
また、クッキーはjavascriptだけではなく、サーバサイド言語からも取り扱うことができます。

Offline Web Applications(API)

Offline Web Applicationsは、HTML5で定義されているAPIです。
webぺージ、スクリプト、css、画像、をキャッシュすることができます。

またjavascriptのプログラム自身も保存できるので、オフライン環境で動作するwebアプリケーションとすることもできます。

Webデータベース

この方法はある程度の大きなデータベースを必要とする場合に有効です。

各ブラウザにはIndexedDB APIというAPIが用意されており、
オブジェクト指向データベースとして動作します。

ファイルシステムAPI

File and Directory Entries APIというAPIで、FileSystem上のファイルを読み書きする操作ができます。

javascriptからは任意のファイルシステムエントリのfilesystemプロパティからオブジェクトにアクセスができ、それらを作成、管理するAPIがあります。

Server-Sent Eventsについて

Posted コメントするカテゴリー: javascript

Server-Sent Eventsについて

Server Sent Eventsを使ってサーバ側からクライアント側への通信をする方法があります。

通信時にはEventSorceオブジェクトのインスタンスを生成し、そのコンストラクタに
サーバ側のURLを渡します。

サーバ側では、任意の処理を行い、クライアント側に処理結果を返し、
クライアント側では返されたオブジェクトのmessageイベントを処理します。

messageイベントには、dataプロパティがあり、サーバ側から返された文字列が格納されています。

また、typeプロパティにはデフォルトでmessageが格納されています。
実装の仕方によっては、サーバ側から返されたイベントソースが複数あり、その全てのイベントを受取る方法として
typeプロパティを使うこともあります。

Server-Sent Eventsのプロトコルについて

Server-Sent Eventsのプロトコルについては、HTTP/1.1で動作します。
これは1回のリクエスト&レスポンス(通信)で、1つの送信&受信を行う。と定義されています。

(ちなみにHTTP/2では、一回の通信で、複数の送信&受信をまとめて通信することができます)

EventSorceオブジェクトのインスタンスを生成したときに、クライアントサーバに接続されます。
サーバ側はこの接続をオープン状態のまま維持します。

サーバ側の処理について

サーバ側の処理は、Server-Sent Eventsで接続されているオープン状態の接続に対してテキストを送信します。
その際の「Content-Type」は以下のようにします。

Content-Type: text/event-stream

また、サーバ側では、「データ名:値」のセットになるように文字列を出力します。
データ名は任意で大丈夫ですが、クライアント側と合わせる必要があります。

例えば次のようになります。

data: sample123

テキストが送信されると、クライアント側でイベントが発生して、その内容を受信および処理ができます。

ここまでをふまえて、簡単なHTMLを用意しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<div id="sse"></div>

<script type="text/javascript">

// データ確認用のdivタグ
let dom_sse = document.getElementById("sse");

// EventSorceオブジェクトのインスタンスを生成
let testsse = new EventSource("server_sent_event.php");

// サーバ側から応答があった時の処理
testsse.onmessage = function(event) {

	// サーバ側から送られた内容を受信し、JSONパースをする
	let recieve_data = JSON.parse(event.data);

	// ログ出力で内容確認
	console.log("recieve_data.data1 -> " + recieve_data.data1);
	console.log("recieve_data.data2 -> " + recieve_data.data2);

	// サーバ側から受信したテキストをDOMへ描画(data1のみ)
	dom_sse.innerHTML += recieve_data.data1 + "<br />";

}

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

サーバ側のphpは次のように書きました。
「Content-Type」を「text/event-stream」にしている点と、
出力するデータの名称を「data:」として、値をjson形式にしている点、
それと、「ob_end_flush();」と「flush();」で、出力方法を制御している点に注意が必要です。

<?php

// server_sent_eventデモ

header("Cache-Control: no-store");
header("Content-Type: text/event-stream");

$sample_data = date("Y/m/d H:i:s");

// 返却用のサンプルデータを用意
$result_arr = array(
	"data1" => $sample_data,
	"data2" => "test1234"
);

echo "data: " . json_encode($result_arr) . "\n\n";

ob_end_flush();
flush();

?>

画面にアクセスして動きをみると、画面上に時刻が表示されることがわかります。
(日時はダミーです)

onmessageのテスト
2022/09/07 21:22:21
2022/09/07 21:22:24
2022/09/07 21:22:27
2022/09/07 21:22:30

また、通信が行われるタイミングは約3秒ごとに発生していますが、
これはどこで制御されているのかは不明なので、改めてわかった時点で内容を更新しようと思います。

JSONPについて

Posted コメントするカテゴリー: javascript

JSONPについて

これまで投稿したサンプルでは、同一出身ポリシーに基づき、
同一サーバ、同一ドメインでクライアントとサーバ側の通信をするサンプルを試しました。

ここでは、クライアントから異なるサーバ(ドメイン)に対しての通信方法を試してみます。

異なるサーバ間の通信はJSONPを使用して行います。

具体的にはクライアントからサーバ側に通信を行う際に、単純にjavascriptの
データや、画面上のフォーム情報を送るのではなく、
データを整形したうえでコールバック関数の形にし、コールバック関数名とデータを送信します。

サーバ側では、受信したデータをもとに、指定の処理を行い、クライアント側に
コールバック関数名と、処理結果をセットで返します。

例えば、送信するデータが下記のようなjson形式のデータの場合

[{1:aaa},{2:bbb},{3:ccc}]

以下のようなコールバック関数名をつけた形にして送信します。
(関数名はあえてわかりやすく書いています)

callbackTestFunction([{1:aaa},{2:bbb},{3:ccc}])

この「callbackTestFunction」と書いたコールバック関数名が、サーバ側からの
値が返却され後のjavascript側で動作する関数名になります。

次にサーバ側の処理ですが、phpで以下のように返却します。

// 返却用のサンプルデータを用意
$result_arr = array(
	"sample_value" => "test1",
	"status" => "ok"
);

// ヘッダ情報を確定
header( 'Content-Type: text/javascript; charset=utf-8' );

// クライアント側にコールバック関数名と共にサンプルデータをjsonエンコードして返却する
echo "callbackTestFunction(" . json_encode($result_arr). ")";

のように書きます。
さらにクライアント側では、サーバ側から返却された値を処理する為に
callbackTestFunction用のコールバック関数を書き、その内部でサーバからの返却値を処理します。

実際に動作するHTMLを用意しました。
javascriptを含むHTML全体のソースです。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<form id="testform" enctype="multipart/form-data">
	<div>
		<input type="text" name="text1" id="text1">
	</div>

	<div>
		<input type="button" id="sample_file_upload" value="JSONPのテスト">
	</div>
</form>

<div>通信時の処理内容</div>
<div id="ajax_result"></div>

<script type="text/javascript">

// ファイルアップロードボタンのDOMを取得
let element_sample_file_upload = document.getElementById('sample_file_upload');

element_sample_file_upload.addEventListener('click',  SendXMLHttpRequest, false);

// 通信処理を画面に出力する為、操作用DOMの取得
let result = document.getElementById("ajax_result");

// ボタン押下時の処理
function SendXMLHttpRequest()
{

	// 処理開始
	result.innerHTML += 'ファイルアップロードのテスト start' + '<br />';
	result.innerHTML += '通信処理の開始' + '<br />';

	// フォーム内容の取得
	let testform_data = document.getElementById("testform");

	// 送信用データ
	// フォーム内容を取得して、jsonpでの通信時のパラメータに付与する
	// デモ画面は入力項目が一つなので、URLのパラメータに直接指定する
	let form_data = new FormData(testform_data);
	let params = "text1=" + form_data.get('text1');

	// パラメータの全体を生成
	let url_params = "?" + params + "&callback=callbackTestFunction";

	// 同一出身ポリシーの制限があるので、スクリプトタグを生成して、外部サーバにアクセスする
	let tag_script = document.createElement("script");

	// ファイルタイプを指定する
	tag_script.type = "text/javascript";

	result.innerHTML += 'url_params -> ' + url_params + '<br />';

	// 実行するサーバとは別のドメインを指定
	tag_script.src = "https://propanlab.net/demo/blogsample/js/078/response.php" + url_params;

	document.body.appendChild(tag_script);

	result.innerHTML += '通信処理の終了' + '<br />';

}

// コールバック関数の処理
let callbackTestFunction = function(json)
{
	console.log(json.sample_value);
	console.log(json.status);
	console.log(json.demp_param);

	// 念のため画面にも出力
	result.innerHTML += 'JSONPで取得した値の確認' + '<br />';
	result.innerHTML += 'json.sample_value -> ' + json.sample_value + '<br />';
	result.innerHTML += 'json.status -> ' + json.status + '<br />';
	result.innerHTML += 'json.demp_param -> ' + json.demp_param + '<br />';

}

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

また、サーバ側のphpは以下のようにし、他ドメインのサーバ側に用意しました。

<?php

// コールバック関数名を取得し、そのまま返却時に使用
$demo_callback = $_GET["callback"];

// パラメータ「text1」の値をそのまま返す(デモ用なので)
$demo_param = $_GET["text1"];

// 返却用のサンプルデータを用意
$result_arr = array(
	"demp_param" => $demo_param,
	"sample_value" => "test1",
	"status" => "ok"
);

// ヘッダ情報を確定(javascript指定にします)
header("Content-Type: text/javascript; charset=utf-8");

// クライアント側にコールバック関数名と共にサンプルデータをjsonエンコードして返却する
echo $demo_callback . "(" . json_encode($result_arr). ")";

?>

実際に画面にアクセスすると、まず次のようになります。

次に、テキストエリアにテスト文字列を入力します。

その後に、「JSONPのテスト」ボタンを押下します。

その際の開発者ツールの通信部分は次のようになります。
別ドメインにあるphpプログラムにアクセスし、結果が返り画面が更新されます。

通信部分のサーバからの返却結果を確認すると次のようになります。

また、画面上のHTMLは次のように更新されます。
javascript側で動的に「script」タグを生成しているので、
htmlに出力した部分が

src="https://propanlab.net/demo/blogsample/js/078/response.php?text1=1234&amp;callback=callbackTestFunction

になり、
scriptタグで別サーバへ通信を行っていることがわかります。

ざっと試しましたが、本来の開発では値のチェックや
イレギュラーケースを考慮して実装する必要があります。

リクエストの中止について

Posted コメントするカテゴリー: javascript

リクエストの中止について

要領の大きいファイルを通信中に、処理を中止したい時があります。
通信処理を途中で中止する方法を試してみます。

通信処理中のHTTPリエクトを中止するには、abort()メソッドを呼び出して中止します。

abort()メソッドを呼び出すと、abortイベントが発生し、通信処理を停止します。

通信処理中のリクエストを中止する方法として、下記のようなHTMLを用意しました。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<form id="testform" enctype="multipart/form-data">
	<div>
		<input type="file" name="file1" id="file1">
	</div>
	
	<div>
		<label for="progress">進捗</label>
		<div id="percent"></div>
		<progress id="progress" value="0" max="100"></progress>
	</div>
	
	<div>
		<input type="button" id="sample_file_upload" value="ファイルアップロードのテスト">
	</div>

	<div>
		<input type="button" id="stop_file_upload" value="ファイルアップロードの中止">
	</div>

</form>

<div>通信時の処理内容</div>
<div id="ajax_result"></div>

<script type="text/javascript">

// ファイルアップロード中止ボタンのDOMを取得
let element_stop_file_upload = document.getElementById('stop_file_upload');
// ファイルアップロード中止ボタンを非表示にする
element_stop_file_upload.style.display = 'none';


// ファイルアップロードボタンのDOMを取得
let element_sample_file_upload = document.getElementById('sample_file_upload');

element_sample_file_upload.addEventListener('click',  SendXMLHttpRequest, false);

// ボタン押下時の処理
function SendXMLHttpRequest()
{

	// 通信処理を画面に出力する為、操作用DOMの取得
	let result = document.getElementById("ajax_result");
	result.innerHTML += 'ファイルアップロードのテスト start' + '<br />';
	result.innerHTML += '通信処理の開始' + '<br />';

	// フォーム内容の取得
	let testform_data = document.getElementById("testform");

	// 送信用データ
	let form_data = new FormData(testform_data);

	// 通信用XMLHttpRequestを生成
	let req = new XMLHttpRequest();

	// POST形式でサーバ側の「response.php」へデータ通信を行う
	req.open("POST", "response.php");

	// ファイル通信時の進捗確認用にプログレスバーを更新する
	req.upload.addEventListener("progress", function(e) {

		if (e.lengthComputable) {

			// ファイルアップロード中止ボタンを表示する
			// document.getElementById('stop_file_upload').style.display = 'block';
			element_stop_file_upload.style.display = 'block';

			let progress_value = Math.round(e.loaded / e.total * 100);

			// 進捗%表示用に値を更新する
			document.getElementById('percent').innerHTML = progress_value + "%";
			
			// プログレスバーの値にファイル転送値を代入する
			document.getElementById('progress').value = progress_value;

			// 進捗率が100%になったら終了の処理をする
			if (progress_value == 100) {
				// 通信が完了したらレスポンスをコンソールに出力する
				req.addEventListener('readystatechange', () => {
					// ここでレスポンス結果を制御する
					console.log("レスポンス結果");
				});

				result.innerHTML += '通信処理の終了' + '<br />';
				result.innerHTML += 'レファイルアップロードのテスト end' + '<br />';
			}

		}
	});

	// ファイルが選択されたときに処理を実行するようイベントリスナーに登録
	input_file = document.getElementById("file1");
	input_file.addEventListener('change', function(e) {
		form_data.append('file1', e.target.files[0]);
	});

	// ファイルアップロードの中止ボタン
	element_stop_file_upload.addEventListener('click', function(e) {
		req.abort();
	});
	
	// ファイル送信
	req.send(form_data);

}

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

上記の画面にアクセスし、サイズの大きいファイルを転送中に、
「アップロード中止」のボタンを押すと、転送が中止されます。

ポイントとなる箇所は以下の箇所です。

	// ファイルアップロードの中止ボタン
	element_stop_file_upload.addEventListener('click', function(e) {
		req.abort();
	});

通信用XMLHttpRequestを生成した後、XMLHttpRequestオブジェクトに対してabortメソッドを実行しています。

また、一度停止した通信処理は、またファイル送信処理を実行すると
最初からファイルが転送されます。

レジューム機能を伴ったアップロード方法にするには、転送するファイルに
一意なIDを付与し、そのIDをもとにサーバに転送済のファイル要領を確認し、
未転送バイトからのアップロードをする。といった一連の処理が必要になります。
(今回の投稿ではその方法は試しませんが、別な投稿でまとめるかもしれません)

ファイルアップロード時のプログレスイベント

Posted コメントするカテゴリー: javascript

ファイルアップロード時のプログレスイベント

前回投稿したファイルアップロード処理について、ファイル容量が大きい場合に
アップロードの状態を把握する為にプログラムイベントを使って、現在何パーセントの状態かを取得する方法を試します。

アップロード部分の処理は、前回までと同様の処理を書きますが、
ファイルの送信状況を把握する為のイベントとして、次のイベントを使います。

仕組みは、送信処理時(sendした時)にloadstartイベントが発火され、その後にprogressイベントが発生します。
このprogressイベントを使うことにより、ファイルの送信状況を画面に表示することができます。

また、通信の終わりには、XMLHttpRequestオブジェクトのstatusコードを判定し、
値が200の場合には正常に終了した。という送信状態を把握します。

通信時のエラーチェックについて

通信時になんらかの異常があってエラーになる場合があります。
一つはリクエストがタイムアウトした場合、二つ目はリクエストが中止された場合、三つ目はネットワークエラー等でリクエストが完了できない場合、です。

loadstartとloadendについて

さきほど「送信処理時(sendした時)にloadstartイベントが発火され」と書きましたが、
通信処理が終了した際には、ブラウザがload、abort、timeout、errorのイベントを発生させます。

この際、XHR2仕様ではloadendイベントが発生すると定義づけられています。
また、このイベントは、通信処理が成功しても失敗しても発生します。

通信時のXMLHttpRequestオブジェクトについて

通信時のXMLHttpRequestオブジェクトにイベントをaddEventListenerでメソッドを付与し、
プログレスイベント「ProgressEvent(インターフェイス)」にハンドラを登録することができます。
このハンドラに対し、onprogressやonload等のプロパティを設定する方法があります。
このプロパティにはtotal、lengthComputable、loaded、等のプロパティがあります。

それぞれ次のような意味です。

lengthComputable
通信時の進捗が測定可能かどうかを返す(true / false)

loaded
現時点までに転送されたバイト数(64ビット符号なし整数値)が返されます

total
転送するデータの総容量が格納されています。不明な場合は0です。

これらのプロパティを使用し、ファイル転送中の進捗状況を把握することができます。

アップロード処理の実例

実際に送信状態を把握するアップロード処理を確認してみます。

ファイルをアップロードする際、uploadプロパティが使用できます。
また、ProgressEventのプロパティとして、onprogressやonload等のプロパティも定義されています。

下記のようなHTMLを用意しました。
サーバ側のプログラムは、前回と同様の為ここでは記載を省きます。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テストHTML</title>
</head>
<body>

<form id="testform" enctype="multipart/form-data">
	<div>
		<input type="file" name="file1" id="file1">
	</div>
	
	<div>
		<label for="progress">進捗</label>
		<div id="percent"></div>
		<progress id="progress" value="0" max="100"></progress>
	</div>
	
	<div>
		<input type="button" id="sample_file_upload" value="ファイルアップロードのテスト">
	</div>
</form>

<div>通信時の処理内容</div>
<div id="ajax_result"></div>

<script type="text/javascript">

// ファイルアップロードボタンのDOMを取得
let element_sample_file_upload = document.getElementById('sample_file_upload');

element_sample_file_upload.addEventListener('click',  SendXMLHttpRequest, false);

// ボタン押下時の処理
function SendXMLHttpRequest()
{

	// 通信処理を画面に出力する為、操作用DOMの取得
	let result = document.getElementById("ajax_result");
	result.innerHTML += 'ファイルアップロードのテスト start' + '<br />';
	result.innerHTML += '通信処理の開始' + '<br />';

	// フォーム内容の取得
	let testform_data = document.getElementById("testform");

	// 送信用データ
	let form_data = new FormData(testform_data);

	// 通信用XMLHttpRequestを生成
	let req = new XMLHttpRequest();

	// POST形式でサーバ側の「response.php」へデータ通信を行う
	req.open("POST", "response.php");

	// ファイル通信時の進捗確認用にプログレスバーを更新する
	req.upload.addEventListener("progress", function(e) {

		if (e.lengthComputable) {

			let progress_value = Math.round(e.loaded / e.total * 100);

			// 進捗%表示用に値を更新する
			document.getElementById('percent').innerHTML = progress_value + "%";
			
			// プログレスバーの値にファイル転送値を代入する
			document.getElementById('progress').value = progress_value;

			// 進捗率が100%になったら終了の処理をする
			if (progress_value == 100) {
				// 通信が完了したらレスポンスをコンソールに出力する
				req.addEventListener('readystatechange', () => {
					// ここでレスポンス結果を制御する
					console.log("レスポンス結果");
				});

				result.innerHTML += '通信処理の終了' + '<br />';
				result.innerHTML += 'レファイルアップロードのテスト end' + '<br />';
			}

		}
	});

	// ファイルが選択されたときに処理を実行するようイベントリスナーに登録
	input_file = document.getElementById("file1");
	input_file.addEventListener('change', function(e) {
		form_data.append('file1', e.target.files[0]);
	});

	// ファイル送信
	req.send(form_data);

}

</script>

</body>
</html>

サーバ上のHTMLはこちら(test1.html)

画面にアクセスすると、まず次のような画面が表示されます。

次に、ファイルを選択します。

「ファイルアップロードのテスト」のボタンを押すと、ファイルのアップロードが開始されます。

この時、アップロードの進捗状態に応じて、プログレスバーの値が更新されていきます。
(同時に画面に進捗率を表示しています)

ファイルのアップロードが完了すると、プログレスバーは100%になり、処理が終わります。
実際には、100%になった後に、ユーザにはなんらかのアクションを求めるので、
継続的な操作をするUIにしたほうが、わかりやすく親切です。

アップロード処理のポイントと注意点

アップロード処理をする際のポイントとなる点は、

	// 通信用XMLHttpRequestを生成
	let req = new XMLHttpRequest();

で、XMLHttpRequestオブジェクト(ここでいうインスタンスのreqです)を生成した後、
reqに対して、progressイベントをaddEventListenerしている箇所です。

	// ファイル通信時の進捗確認用にプログレスバーを更新する
	req.upload.addEventListener("progress", function(e) {

		if (e.lengthComputable) {

			let progress_value = Math.round(e.loaded / e.total * 100);

			// 進捗%表示用に値を更新する
			document.getElementById('percent').innerHTML = progress_value + "%";
			
			// プログレスバーの値にファイル転送値を代入する
			document.getElementById('progress').value = progress_value;

		}
	});

それ以外は、前回ファイルのアップロードを投稿したサンプルと同じ処理にしています。

また、注意点として、実際に大きい容量のファイルをアップロードして試してみるとわかりますが
サーバ側で受信できない容量サイズのファイルは、javascript側でアップロード完了までの
プログレスバーの表示になりますが、サーバ側でファイル受信(容量制限)ができていないケースがあります。

HTML+css+javascriptの作りとして、見かけ上は処理が止まっていないので、
ファイルがアップロード成功したかのように見えますが、サーバサイドで正常にファイルアップロードが
成功したかどうかは、サーバ側プログラムで判断し、容量オーバやなんからのエラーだった場合には
クライアント(javascript)側にエラーのレスポンスを返す必要があります。