"use strict";
/*global require*/
var defined = require("terriajs-cesium/Source/Core/defined").default;
var loadJson = require("../Core/loadJson");
var when = require("terriajs-cesium/Source/ThirdParty/when").default;
var inherit = require("../Core/inherit");
/**
* A one-dimensional scale of colours used to visually represent a numerical value.
* Implemented as an Array of {color, offset} objects, where the first object has an offset of 0,
* the last has an offset of 1, and the others are ordered in between.
* It can be instantiated directly from three formats:
* - String, eg. 'red-black'
* - Array of strings, eg. ['red', 'black']
* - Array of objects with the properties 'color' and 'offset', eg. [{color: 'red', offset: 0}, ...].
*
* @param {String|String[]|Object[]} param
*/
var ColorMap = function(param) {
var array;
if (typeof param === "string" || param instanceof String) {
array = stringToArray(param);
}
if (param instanceof Array && param.length > 0) {
if (typeof param[0] === "string" || param[0] instanceof String) {
array = simpleArrayToArray(param);
} else {
array = param;
}
}
// array is now an array of objects with the properties 'color' and 'offset'.
if (defined(array)) {
array.forEach(function(e) {
this.push(e);
}, this);
}
};
inherit(Array, ColorMap);
// Without this, the array is expressed as an object in JSON.
ColorMap.prototype.toJSON = function() {
return this.slice();
};
/**
* Given a simple array of css color strings, eg. ["red", "orange", "black"],
* return an evenly spaced array suitable to instantiate a color map.
* @private
* @param {String[]} simpleArray A simple array of css color strings, eg. ["red", "orange", "black"].
* @return {Object[]} An array of {color, offset} objects.
*/
function simpleArrayToArray(simpleArray) {
return simpleArray
.map(function(el, index) {
return {
color: el,
offset: simpleArray.length === 1 ? 0 : index / (simpleArray.length - 1)
};
})
.filter(function(o) {
return o.color !== "";
});
}
/**
* Convert 'red-black' to ['red', 'black'].
* @private
* @param {String} s A hyphen-separated css color string.
* @return {String[]} An array of css color strings, split by hyphen.
*/
function stringToArray(s) {
if (!s) {
return undefined;
}
// a marginally useful feature of this is that "red-white---blue" is a legal way to specify an offset color map.
return simpleArrayToArray(s.split("-"));
}
/**
* Access the Color Brewer color definitions.
* @return {Promise} The contents of the ColorBrewer JSON file
*/
ColorMap.colorBrewerFile = function() {
if (ColorMap.colorBrewerJSON) {
return when(ColorMap.colorBrewerJSON);
} else {
// store the promise so we don't send off lots of requests for the same file.
// TODO: don't hardcode the path. 'build/TerriaJS/' can come from Terria.baseUrl, but how do we get a Terria instance?
ColorMap.colorBrewerJSON = loadJson(
"build/TerriaJS/data/colorbrewer.json"
).then(function(j) {
ColorMap.colorBrewerJSON = j;
return j;
});
return ColorMap.colorBrewerJSON;
}
};
/**
* Returns a promise resolving to the color map specified by the specified color palette.
* @param {String} [colorPalette] A [ColorBrewer](http://colorbrewer2.org/) palette name, eg. "7-class Set3" or "10-class BrBG".
* @return {Promise.<ColorMap>} A promise that resolves to the {@link ColorMap} once it is loaded, or undefined if the palette is invalid.
*/
ColorMap.loadFromPalette = function(palette) {
var colorBrewerDefaultClasses = 7;
if (!palette) {
return when(undefined);
}
var matches = palette.match(/^((\d+)-class *)?([^-]+)/i);
if (matches) {
var name = matches[3];
var classes = matches[2] ? matches[2] : colorBrewerDefaultClasses;
return ColorMap.colorBrewerFile().then(function(j) {
if (j && j[name] && j[name][classes]) {
return new ColorMap(simpleArrayToArray(j[name][classes]));
} else {
return undefined;
}
});
}
return when(undefined);
};
module.exports = ColorMap;