[백업][가리사니] html 컬러피커를 만들어보자
html, javascript

이 문서는 가리사니 개발자 포럼에 올렸던 글의 백업 파일입니다. 오래된 문서가 많아 현재 상황과 맞지 않을 수 있습니다.

만들고 싶었던 스타일의 컬러피커는 HSL and HSV 의 어도비 스타일로 우선 오른쪽 바가 어떤형태로 작동하는지 알아야 했습니다.

1. 어도비스타일 컬러피커

[https://www.google.ca/search?q=photoshop+color+tool&tbm=isch 필자가 만들고 싶었던건 위 어도비 스타일의 컬러피커 입니다.

2. 오른쪽 무지개바?

필자는 처음에 저게 무슨 규칙으로 놓여저 있는지 알수가 없어서 위키백과를 찾아보던 도중.. 아래와 같은 문서를 보게되었습니다. [https://en.wikipedia.org/wiki/HSL_and_HSV 위 문서를 참고해보면 가시광선 스펙트럼의 적[빨강] -> 자[보라]를 뒤집어놓은 형태에서 눈에 보이지 않는 자외선이 자리잡아야할 공간에 다시 적색이 회귀하는 특이한 형태입니다.

특징

  1. 가시광선 스펙트럼이 뒤집어진 형태 자외선 부분이 다시 적색으로 회귀하고 있다.

3. 왼쪽에 파렛트

좌상단 : 흰색 FFFFFF 우상단 : 색상바에서 선택된 색상 하단(공통) : 검정색 이러한 특이한 형태를 하고 있습니다. 규칙 23 2. x방향 : 흰색 -> 선택된색까지의 그라데이션 3. y방향 : R, G, B 각각의 색상(0255)이 0에 수렴할때까지 1픽셀당 1씩 떨어진다.

4. 규칙정리

  1. 가시광선 스펙트럼이 뒤집어진 형태 자외선 부분이 다시 적색으로 회귀하고 있다. 이걸 구현하기위해선 스펙트럼의 특성을 알아야하지만, 각 색의 최대치와 최소치가 변하는 부분만 찾아서 그라데이션으로 구현하기로 했습니다. 그래서 찾아낸 최대치와 최소치가 되는 지점입니다. ff 00 00 - 빨강색 ff 00 ff - 보라색 00 00 ff - 파랑색 00 ff ff - 하늘색 00 ff 00 - 초록색 ff ff 00 - [색상 ff0]노랑색 ff 00 00 - 빨강색 주) 자스로 한색상마다 찍어주는경우 시간소모가 크기때문에 그라데이션 기능을 쓰기로했습니다. 필자의 컴퓨터로 1픽셀씩 찍었을경우 0.250 초 그라데이션을 썼을경우 0.008 초 걸렸습니다.
  2. x방향 : 흰색 -> 선택된색까지의 그라데이션
  3. y방향 : R, G, B 각각의 색상(0~255)이 0에 수렴할때까지 1픽셀당 1씩 떨어진다. 사실 이건 따로 설명할 필요가 없을정도로 간단합니다. 좌우 그라데이션을 0xFF ~ 지정된색 까지 주고 아래로는 if (r > 0) { r--; } 같은 방법으로 g b 이렇게 처리하면됩니다.

5. 구현

자료정리가 끝났으니 가볍게(?) 구현해봤습니다. 시간관계상 간단하게만 만들어봤습니다. 오른쪽의 스팩트럼을 누르면 표시됩니다. mousedown, mousemove, mouseup 을 함께써서 포토샵처럼 끌면서 볼수있도록 업그레이드 시켜보세요...

<html>
<head>
<script type="text/javascript">
// 2015-09-06 박용서 : 작성
// [/2015/09/06/%EB%B0%B1%EC%97%85-%EA%B0%80%EB%A6%AC%EC%82%AC%EB%8B%88-HTML-%EC%BB%AC%EB%9F%AC%ED%94%BC%EC%BB%A4%EB%A5%BC-%EB%A7%8C%EB%93%A4%EC%96%B4%EB%B3%B4%EC%9E%90.html](/2015/09/06/%EB%B0%B1%EC%97%85-%EA%B0%80%EB%A6%AC%EC%82%AC%EB%8B%88-HTML-%EC%BB%AC%EB%9F%AC%ED%94%BC%EC%BB%A4%EB%A5%BC-%EB%A7%8C%EB%93%A4%EC%96%B4%EB%B3%B4%EC%9E%90.html)
var cp = {
	bar : null, // color bar
	barc : null, // color bar context
	pal : null, // palette
	palc : null, // palette context
	pallc : null, // palette last color

	// 초기화
	init : function() {
		// 오른쪽 바를 새로고침한다.
		cp.initBar();

		// 팔렛트를 초기화한다.
		cp.initPalette();

		// 기본값 : 빨강색 선택
		cp.drawPalette(255, 0, 0);
	},

	// 색상바 초기화
	initBar : function() {
		var bar = cp.bar = document.getElementById('bar');
		var ctx = cp.barc = bar.getContext('2d');

		// 처음 크기가 멋대로 잡혀있다. (초기화)
		// ignore css?? init resize..;;
		var w = bar.width = 20;
		var h = bar.height = 256;

		// 그라디언트를 불러온다.
		var grd = ctx.createLinearGradient(0,0,w,h);
		grd.addColorStop(0,'#ff0000');
		grd.addColorStop(0.166,'#ff00ff');
		grd.addColorStop(0.333,'#0000ff');
		grd.addColorStop(0.5,'#00ffff');
		grd.addColorStop(0.666,'#00ff00');
		grd.addColorStop(0.834,'#ffff00');
		grd.addColorStop(1,'#ff0000');

		// 지정한 그라데이션을 그린다.
		ctx.fillStyle = grd;
		ctx.fillRect(0, 0, w, h);

		bar.onclick = function(e) {
			// y 좌표를 가져온다.
			var y = e.pageY - cp.bar.offsetTop;
			// 해당 위치의 색상을 가져온다.
			var c = cp.barc.getImageData(0, y, 1, 1).data;
			// r g b  순서대로 부른다.
			cp.drawPalette(c[0], c[1], c[2]);
		};
	},

	// 팔렛트를 초기화한다.
	initPalette : function() {
		var pal = cp.pal = document.getElementById('palette');
		cp.palc = pal.getContext('2d');

		// 이유는 모르겠지만.. 크기가 이상해서 다시 잡아준다.
		pal.width = 256;
		pal.height = 256;
	},

	// 팔렛트를 그린다.
	drawPalette : function(r, g, b) {
		// 마지막으로 선택된 컬러와 같다면 자원을 아까기위해 스킵한다.
		var nowColor = (r+'-'+g+'-'+b);
		if (cp.pallc == nowColor) { return; } else { cp.pallc = nowColor; }

		// 팔렛트의 컨텍스를 가져옴
		var palc = cp.palc;

		// 위에서부터 1픽셀씩 내려오면서 그림
		for (i = 0; i < 255; )
		{
			var leftColor = 255 - i; // 왼쪽 [상 -> 하] 명도 계산!

			// 그리기
			var grd = palc.createLinearGradient(0, 0, 256, 1);
			grd.addColorStop(0,'rgb('+leftColor+', '+leftColor+', '+leftColor+')');
			grd.addColorStop(1,'rgb('+r+', '+g+', '+b+')');
			palc.fillStyle = grd;
			palc.fillRect(0, i++, 256, i);

			// 위 설명대로 루프당 명도를 1씩 떨어뜨립니다.
			if (r > 0) { r--; }
			if (g > 0) { g--; }
			if (b > 0) { b--; }
		}
	}
};
</script>
<style>
#palette { width:256px; height:256px; }
#bar { width:20px; height:256px; }
</style>
</head>
<body onload="cp.init();">

<canvas id="palette"></canvas>
<canvas id="bar"></canvas>

</body>
</html>