/* * === Gradation-color generator === * * updated 2003/08/01 * * mail : peace@skipup.com * home : http://www.skipup.com/~peace/ */ /** * グラデーション色を生成. * 任意色間,任意階調のグラデーションを生成. * * ■ 使用例 * ・黒→白のグラデーション配列(型はString型) * var gradation = new JGradation("#000000", "#ffffff"); * var black2white = gradation.toArray(256); * ・赤→緑→青のグラデーション配列(型はString型) * var gradation = new JGradation("#ff0000", "#00ff00", "#0000ff"); * var r2b2b = gradation.toArray(256); * ・コンストラクタに配列を使用 * var baseColors = new Array("#ff0000", "#00ff00", "#0000ff"); * var gradation = new JGradation(baseColors); * var r2b2b = gradation.toArray(256); * ・toArrayメソッドの戻り値の型を変更 * toArrayメソッドは通常はコンストラクタで指定した引数の型で返すが, * toArrayメソッドの引数に返り値の型を指定することが可能. * 以下はJColor型で返す例. * var gradation = new JGradation("#000000", "#ffffff"); * var black2white = gradation.toArray(256, JGradation.JCOLOR_TYPE); * 返り値の型には,文字列型,数値型,JColor型がある. * * ■ インスタンス変数. * int[][] colors グラデーションの基準色配列. * int returnType 返り値の型を示す. * * ■ カラー値の型 * JGradationクラスのカラー値の型は全部で3種類ある.括弧中の値は赤色を示す * 1. int型(0xff0000) * 2. String型("#ff0000", "ff0000") * 3. JColor型(new JColor(255, 0, 0)) * ドキュメント中のcolor型とはこれらの型を示している. * * ■ String型カラー値について * ルールとして,(メソッドなどに)入力として与えるString型カラー値は * 先頭の'#'を含んでいても含まなくても正常に動作する. * 但し,返り値は'#'を含まない形式で統一する. */ function class__JGradation__(window) { var classId = Object.getClassName(arguments.callee); function errorMessage(message) { if (location.protocol != "file:") return; alert(message); } var $colors = Object.privateId(); var $returnType = Object.privateId(); /** * コンストラクタ. * JGradation(color[] colors) * JGradation(color c0, color c1[, color c2[, color c3 ...]]) */ var F = window[classId] = function() { if (this.constructor !== F) this.constructor = F; var cs = arguments.length == 1 ? arguments[0] : arguments; this[$returnType] = getType(cs[0]); // 返り値の型を1番目の要素で判定. var n = cs.length; this[$colors] = new Array(n); for (var i = 0; i < n; i++) this[$colors][i] = toRGB(cs[i]); }; var FP = F.prototype; F.NUMBER_TYPE = 0; F.STRING_TYPE = 1; F.JCOLOR_TYPE = 2; /** * 16進法6桁のカラー文字列の桁合せに使用. */ var ZEROS = new Array("", "0", "00", "000", "0000", "00000", "000000"); /** * 返り値の型のデフォルト値を設定する. * カラー値を返す殆どのメソッドは返り値の型を指定出来るが, * 指定しない場合,ここで設定した型が返されるようになる. * 通常はここで設定しなくても, * コンストラクタで指定したカラー値をもとに初期化される. */ FP.setReturnType = function(returnType) { if (!(0 <= returnType && returnType <= 2)) { errorMessage("@" + classId + "#setReturnType"); return; } this[$returnType] = returnType; }; /** * 任意色間の内分点(内分色)を取得する. * 例えば,基準色配列が#000000, #ffffff,位置が0.5のとき#800000. * 基準色配列が#ff0000, #00ff00,#0000ff,位置が0.25のとき#808000; * 基準色で構成されるグラデーションの一部だけを取り出したいとき使用する. * color getInterpolate(double d) * color getInterpolate(double d, int returnType) * @param d 位置.[0.0, 1.0] * @return 内分色.型はreturnTypeに依る. */ FP.getInterpolate = function(d, returnType) { if (returnType === void 0) returnType = this[$returnType]; if (!(0 <= returnType && returnType <= 2)) { errorMessage("@" + classId + "#getInterpolate"); return null; } var cs = this[$colors]; switch (cs.length) { case 2 : return getInterpolate2(cs[0], cs[1], d, returnType); default : return getInterpolateX(cs, d, returnType); } }; /** * グラデーションの生成. * color[] toArray(int n) * color[] toArray(int n, int returnType) * @param n 配列の長さ. * @return グラデーションで構成される配列. * 型はreturnTypeに依る. */ FP.toArray = function(n, returnType) { if (returnType === void 0) returnType = this[$returnType]; if (!(0 <= returnType && returnType <= 2)) { errorMessage("@" + classId + "#toArray"); return null; } var cs = this[$colors]; switch (cs.length) { case 2 : return getGradation2( cs[0], cs[1], n, new Array(n), 0, returnType); case 3 : return getGradation3(cs[0], cs[1], cs[2], n, returnType); default : return getGradationX(cs, n, returnType); } }; /** * String toHTML(String text) */ /*FP.toHTML = function(text) { var n = text.length; var g = this.toArray(n, F.STRING_TYPE); var e = new Array(n); for (var i = 0; i < n; i++) e[i] = ("") + text.charAt(i) + "<\/span>"; return e.join(""); };*/ /** * String toString() */ FP.toString = function() { var nColors = this[$colors].length; var strColors = new Array(nColors); for (var i = 0; i < nColors; i++) { var c = this[$colors][i]; strColors[i] = '#' + toHexString(c[0]) + toHexString(c[1]) + toHexString(c[2]); } var type = "undefined"; switch (this[$returnType]) { case 0 : type = "number";break; case 1 : type = "String";break; case 2 : type = "JColor";break; } return classId + "[colors=(" + strColors.join(",") + ") length=" + nColors + " returnType=" + type + "]"; }; function getType(c) { switch ((typeof c).charAt(0)) { case 'n' : // number return F.NUMBER_TYPE; case 's' : // string return F.STRING_TYPE; case 'o' : // object return F.JCOLOR_TYPE; default : // $ERROR$ errorMessage("型が不正@" + classId + "#getType"); return -1; } } /** * String toHexString(int v) * @return 指定した整数を2桁の16進数文字列に変換したもの. */ function toHexString(v) { return v <= 0x00 ? "00" : (v < 0x10 ? "0" + v.toString(16) : (v <= 0xff ? v.toString(16) : "ff")); } /** * カラーをint型配列にコンバート. * int[] toRGB(String RRggBB) * int[] toRGB(JColor color) * int[] toRGB(int rgb) * @return r, g, bを要素とするint型配列. */ function toRGB(c) { switch (getType(c)) { case 0 : // Number return new Array( (c & 0xff0000) >>> 16, (c & 0x00ff00) >>> 8, (c & 0x0000ff)); case 1 : // String var v = parseInt( "0x" + (c.charAt(0) == '#' ? c.substring(1) : c)); return new Array( (v & 0xff0000) >>> 16, (v & 0x00ff00) >>> 8, (v & 0x0000ff)); case 2 : // JColor return c.toArray(false); default : // $ERROR$ return undefined; } } /** * 2色間の内分点(内分色)を取得する. * RGB3次元座標空間で,始点と終点を結ぶ半直線上の点を取得する. * color getInterpolate2(int[] startColor, int[] endColor, double d, int returnType) */ function getInterpolate2(c0, c1, d, returnType) { if (!(0.0 <= d && d <= 1.0)) { errorMessage("@" + classId + "#getInterpolate2"); return null; } var r = Math.floor((1.0 - d) * c0[0] + d * c1[0]), g = Math.floor((1.0 - d) * c0[1] + d * c1[1]), b = Math.floor((1.0 - d) * c0[2] + d * c1[2]); var n = (r << 16) | (g << 8) | b; switch (returnType) { case 0 : // Number return n; case 1 : // String var s = n.toString(16); return ZEROS[6 - s.length] + s; case 2 : // JColor return new JColor(n); default : // $ERROR$ return undefined; } } /** * 多色間の内分点(内分色)を取得する. * 引数で与える基準点(基準色)を結ぶ全体のラインを半直線と考え, * その半直線上に存在する点(色)を取得する. * color getInterpolateX(int[][] baseColors, double d, int returnType) */ function getInterpolateX(cs, d, returnType) { if (d < 0.0 || d > 1.0) { errorMessage("@" + classId + "#getInterpolateX"); return null; } // i | 0 1 2 3 4 // | ○――――○――――○――――○――――○ // d | 0.00 0.25 0.50 0.75 1.00 var i0; var e; { var m = cs.length - 1; for (i0 = 0; d > (i0 + 1) / m; i0++); // v = 1 / m, e = (d - i * v) / v e = d * m - i0; } return getInterpolate2(cs[i0], cs[i0 + 1], e, returnType); } /** * 2色間グラデーションを生成. * color[] getGradation2(int[] startColor, int[] endColor, int length, color[] result, int insertIndex, int returnType) * @param startColor 開始色. * @param endColor 終了色. * @param length 生成するグラデーション配列の長さ. * @param result グラデーション色を格納する配列. * 返り値はこの値の参照. * @param insertIndex resultに挿入する位置. * この位置からカラー値を挿入していく. * @param returnType 返り値の型. * @return グラデーションで構成される配列.引数resultの参照. * 型はreturnTypeに依存. */ function getGradation2(c0, c1, n, p, s, returnType) { var dr = (c1[0] - c0[0] + 0.0) / (n - 1), dg = (c1[1] - c0[1] + 0.0) / (n - 1), db = (c1[2] - c0[2] + 0.0) / (n - 1); var r = c0[0] + 0.0, g = c0[1] + 0.0, b = c0[2] + 0.0; for (var i = s, k = n + s; i < k; i++) { var c = (Math.round(r) << 16) | (Math.round(g) << 8) | Math.round(b); switch (returnType) { case 0 : // Number p[i] = c; break; case 1 : // String var d = c.toString(16); p[i] = ZEROS[6 - d.length] + d; break; case 2 : // JColor p[i] = new JColor(c); break; } r += dr; g += dg; b += db; } return p; } /* * 3色間はgetGradationXを使用しても問題ないが, * 多用することが多いため,別に関数を用意した. */ /** * 3色間グラデーションの生成. * color[] getGradation3(int[] startColor, int[] middleColor, int[] endColor, int length, int returnType) */ function getGradation3(c0, c1, c2, n, returnType) { var k = n - 3; // 補完色総数. // 各基準色間グラデーション配列の長さ(の基準). var L = Math.floor(k / 2) + 2; var l0 = L + (k & 1), l1 = L; // 0~1,1~2の長さ. var g = getGradation2(c0, c1, l0, new Array(n), 0, returnType); return getGradation2(c1, c2, l1, g, l0 - 1, returnType); } /* * 多色間グラデーション配列生成アルゴリズムのイメージ. * ●:基準色 * ○:補完色 * * ●○○●○○●○○●○● * ●○○●○○●○○●○○● * ●○○○●○○○●○○●○○● * 補完色が割り切れない場合,余り要素は前方にシフトする. */ /** * 多色間グラデーションの生成. * color[] getGradationX(int[][] baseColors, int length, int returnType) * @param baseColors 基色となるカラー配列.int[3][基色数] * @param length グラデーション配列の長さ. * @param returnType 返り値の型. * @return グラデーションで構成される配列. * 型はreturnTypeに依る. */ function getGradationX(cs, n, returnType) { var b = cs.length - 1; // 補完色の区画数(計算回数に等しい). var k = n - cs.length; // 補完色の総数. var m = Math.floor(k / b); // 各基準色間の基準となる補完色数. var r = k % b; // 補完色数の誤差分. var L = m + 2; // 各基準色間のグラデーション配列の基準長さ. var g = new Array(n); var s = 0; // グラデーション配列gへの挿入位置. for (var i = 0; i < b; i++) { var l = L + (i < r ? 1 : 0); getGradation2(cs[i], cs[i + 1], l, g, s, returnType); s += l - 1; } return g; } } class__JGradation__(window);