/*
* niViz -- snow profiles visualization
* Copyright (C) 2015 WSL/SLF - Fluelastrasse 11 - 7260 Davos Dorf - Switzerland.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
(function (niviz) {
'use strict';
// --- Module Dependencies ---
var Value = niviz.Value;
var properties = Object.defineProperties;
/** @module niviz */
var Color = {
darkblue: [0, 0, 127],
blue: [0, 0, 255],
cyan: [0, 255, 255],
lightwhite: [240, 240, 240],
red: [255, 0, 0],
black : [0, 0, 0]
};
/**
* A Gradient represents a color gradient and its labels
*
* @class Gradient
* @constructor
*/
function Gradient(config) {
/**
* @property min
* @type Number
*/
this.min = parseFloat(config.min) || 0.0;
/**
* @property max
* @type Number
*/
this.max = (config.max !== undefined ? parseFloat(config.max) : 1.0);
/**
* @property steps
* @type Number
*/
this.steps = (config.steps !== undefined ? parseInt(config.steps) : 4);
if (this.steps <= 0) this.steps = 2;
/**
* @property palette
* @type Array< Array<Number> >
*/
this.palette = Gradient.palettes[config.palette] || Gradient.palettes.whiteblue;
/**
* @property gradienttype
* @type String
*/
this.gradienttype = config.gradient || 'linear';
this.color = config.color === 'own' ? this.own : this.linearcolor();
}
Gradient.palettes = {
bluemultired: [ Color.darkblue, Color.blue, Color.cyan,
Color.lightwhite, Color.red ],
whitemultiblue: [ Color.lightwhite, Color.cyan, Color.blue, Color.darkblue ],
whiteblue: [ Color.lightwhite, Color.blue ],
bluered: [ Color.blue, Color.red ],
whiteblack: [ Color.lightwhite, Color.black ]
};
properties(Gradient.prototype, {
/**
* A gradient string, that can be used to fill rectangles.
*
* @property gradient
* @type String
*/
gradient: {
get: function () {
if (this.gradienttype === 'grainshape')
return this.grainshape();
return this.lineargradient();
}
}
});
Gradient.prototype.own = function (layer) {
return layer.color;
};
Gradient.prototype.linearcolor = function () {
var steps = this.palette.length, span = this.max - this.min,
inc = span / (steps - 1), i, ii;
if (steps === 1) {
return function () {
return this.palette[0];
};
}
return function (value) {
value = value.avg || value.value;
if (value <= this.min) {
return rgbToHex.apply(null, this.palette[0]);
} else if (value >= this.max) {
return rgbToHex.apply(null, this.palette[steps - 1]);
}
var last = this.min, color;
for (i = 1, ii = steps; i < ii; ++i) {
var max = inc + last;
if (value <= max) {
color = getStepColor(this.palette[i - 1],
this.palette[i], (value - last) / inc);
return rgbToHex.apply(null, color);
}
last = max;
}
};
};
Gradient.prototype.lineargradient = function () {
var i, ii, span = this.max - this.min, inc = span / (this.steps - 1), factor = 1;
var result = {
gradient: [],
positions: [],
labels : []
};
for (i = 0, ii = this.palette.length; i < ii; ++i) {
var rate = Math.round(i / (ii - 1) * 100);
if (i) result.gradient.push('-');
result.gradient.push(rgbToHex.apply(null, this.palette[i]), ':', rate);
}
result.gradient = result.gradient.join('');
if (this.max < 2) factor = 100;
for (i = 0, ii = this.steps; i < ii; ++i) {
result.positions.push(i / (ii - 1));
result.labels.push(Math.round(i * inc * factor) / factor + this.min);
}
return result;
};
Gradient.prototype.grainshape = function () {
var i, ii;
var result = {
gradient: [],
positions: [],
nogutter: true,
lbls : ['PPgp', 'MM', 'IF', 'MFcr', 'MF', 'SH', 'DH', 'FC', 'RG', 'DF', 'PP'],
labels : ['PPgp', 'MM', 'IF', 'MFcr', 'MF', 'SH', 'DH', 'FC', 'RG', 'DF', 'PP']
};
for (i = 0, ii = result.labels.length; i < ii; ++i) {
var rate = Math.round((i + 1) / ii * 100),
last = Math.round((i) / ii * 100),
color = Value.GrainShape.type[result.labels[i]].color;
result.positions.push((i / ii + (i + 1) / ii) / 2);
if (i) result.gradient.push('-');
result.gradient.push(color, ':', last, '-', color, ':', rate);
}
result.gradient = result.gradient.join('');
for (i = 0, ii = result.labels.length; i < ii; ++i) {
result.labels[i] = Value.GrainShape.type[result.labels[i]].key;
}
return result;
};
Gradient.patternMFcr = function () {
var pat = document.createElement("canvas")
pat.width = 5;
pat.height = 5;
var pctx = pat.getContext('2d');
pctx.strokeStyle = '#000000';
pctx.lineWidth = 1;
pctx.beginPath();
pctx.moveTo(1, -1);
pctx.lineTo(1, 6);
pctx.fillStyle = '#FF0000';
pctx.fillRect(0, 0, 5, 5);
pctx.stroke();
return pat;
}();
// properties(Value.prototype, {
// /**
// * A string represantation of this value.
// *
// * @property text
// * @type String
// */
// text: {
// get: function () { return this.toString(); }
// },
// /**
// * The numeric value (defaults to `.value`) used for comparisons.
// *
// * @property numeric
// * @type Number
// */
// numeric: {
// get: function () { return Number(this.value); }
// }
// });
// Value.prototype.toString = function () {
// return String(this.value);
// };
function componentToHex(c) {
var hex = c.toString(16);
return hex.length === 1 ? '0' + hex : hex;
}
function rgbToHex(r, g, b) {
return '#' + componentToHex(r) + componentToHex(g) + componentToHex(b);
}
var getStepColor = function(colorA, colorB, value) {
return colorA.map(function(color, i) {
return (color + value * (colorB[i] - color)) & 255;
});
};
/*
function ts (value) {
var r, g, b;
if (value instanceof Value) value = value.value;
if (value <= -20) {
return '#00007F';
} else if (value < -15) {
value = Math.round((value + 20) / 5 * 128);
return '#0000' + componentToHex(value);
} else if (value < -10) {
value = (value + 15) / 5;
r = 0;
g = Math.round(255 * value);
b = 255;
return rgbToHex(r, g, b);
} else if (value < -5) {
value = (value + 10) / 5;
r = Math.round(240 * value);
g = Math.round(255 - 15 * value);
b = Math.round(255 - 15 * value);
return rgbToHex(r, g, b);
} else if (value < 0) {
value = (value + 5) / 5;
r = Math.round(15 * value + 240);
g = Math.round(240 * (1 - value));
b = Math.round(240 * (1 - value));
return rgbToHex(r, g, b);
} else {
return '#F00';
}
}
*/
// --- Module Exports ---
niviz.Gradient = Gradient;
}(niviz));