mirror of
https://github.com/apache/superset.git
synced 2026-04-17 23:25:05 +00:00
Improve categorical color management (#5815)
* Create new classes for handling categorical colors * verify to pass existing unit tests * separate logic for forcing color and getting color * replace getColorFromScheme with CategoricalColorManager * organize static functions * migrate to new function * Remove ALL_COLOR_SCHEMES * move sequential colors to another file * extract categorical colors to separate file * move airbnb and lyft colors to separate files * fix missing toFunction() * Rewrite to support local and global force items, plus namespacing. * fix references * revert nvd3 * update namespace api * Update the visualizations * update usage with static functions * update unit test * add unit test * rename default namespace * add unit test for color namespace * add unit test for namespace * start unit test for colorschememanager * add unit tests for color scheme manager * check returns for chaining * complete unit test for the new classes * fix color tests * update unit tests * update unit tests * move color scheme registration to common * update unit test * rename sharedForcedColors to parentForcedColors * remove import
This commit is contained in:
committed by
Chris Williams
parent
bec0b4cc37
commit
f482a6cf99
@@ -8,6 +8,7 @@
|
||||
"test": "spec"
|
||||
},
|
||||
"scripts": {
|
||||
"tdd": "mocha --require ignore-styles --compilers js:babel-core/register --require spec/helpers/shim.js 'spec/**/*_spec.*' --watch --recursive",
|
||||
"test": "mocha --require ignore-styles --compilers js:babel-core/register --require spec/helpers/shim.js 'spec/**/*_spec.*'",
|
||||
"test:one": "mocha --require ignore-styles --compilers js:babel-core/register --require spec/helpers/shim.js",
|
||||
"cover": "babel-node node_modules/.bin/babel-istanbul cover _mocha -- --compilers babel-core/register --require spec/helpers/shim.js --require ignore-styles 'spec/**/*_spec.*'",
|
||||
|
||||
@@ -7,10 +7,10 @@ import { Creatable } from 'react-select';
|
||||
|
||||
import ColorSchemeControl from
|
||||
'../../../../src/explore/components/controls/ColorSchemeControl';
|
||||
import { ALL_COLOR_SCHEMES } from '../../../../src/modules/colors';
|
||||
import { getAllSchemes } from '../../../../src/modules/ColorSchemeManager';
|
||||
|
||||
const defaultProps = {
|
||||
options: Object.keys(ALL_COLOR_SCHEMES).map(s => ([s, s])),
|
||||
options: Object.keys(getAllSchemes()).map(s => ([s, s])),
|
||||
};
|
||||
|
||||
describe('ColorSchemeControl', () => {
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
import { it, describe, before } from 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import CategoricalColorNamespace, {
|
||||
getNamespace,
|
||||
getScale,
|
||||
getColor,
|
||||
DEFAULT_NAMESPACE,
|
||||
} from '../../../src/modules/CategoricalColorNamespace';
|
||||
import { registerScheme } from '../../../src/modules/ColorSchemeManager';
|
||||
|
||||
describe('CategoricalColorNamespace', () => {
|
||||
before(() => {
|
||||
registerScheme('testColors', ['red', 'green', 'blue']);
|
||||
registerScheme('testColors2', ['red', 'green', 'blue']);
|
||||
});
|
||||
it('The class constructor cannot be accessed directly', () => {
|
||||
expect(CategoricalColorNamespace).to.not.be.a('Function');
|
||||
});
|
||||
describe('static getNamespace()', () => {
|
||||
it('returns default namespace if name is not specified', () => {
|
||||
const namespace = getNamespace();
|
||||
expect(namespace !== undefined).to.equal(true);
|
||||
expect(namespace.name).to.equal(DEFAULT_NAMESPACE);
|
||||
});
|
||||
it('returns namespace with specified name', () => {
|
||||
const namespace = getNamespace('myNamespace');
|
||||
expect(namespace !== undefined).to.equal(true);
|
||||
expect(namespace.name).to.equal('myNamespace');
|
||||
});
|
||||
it('returns existing instance if the name already exists', () => {
|
||||
const ns1 = getNamespace('myNamespace');
|
||||
const ns2 = getNamespace('myNamespace');
|
||||
expect(ns1).to.equal(ns2);
|
||||
const ns3 = getNamespace();
|
||||
const ns4 = getNamespace();
|
||||
expect(ns3).to.equal(ns4);
|
||||
});
|
||||
});
|
||||
describe('.getScale()', () => {
|
||||
it('returns a CategoricalColorScale from given scheme name', () => {
|
||||
const namespace = getNamespace('test-get-scale1');
|
||||
const scale = namespace.getScale('testColors');
|
||||
expect(scale).to.not.equal(undefined);
|
||||
expect(scale.getColor('dog')).to.not.equal(undefined);
|
||||
});
|
||||
it('returns same scale if the scale with that name already exists in this namespace', () => {
|
||||
const namespace = getNamespace('test-get-scale2');
|
||||
const scale1 = namespace.getScale('testColors');
|
||||
const scale2 = namespace.getScale('testColors2');
|
||||
const scale3 = namespace.getScale('testColors2');
|
||||
const scale4 = namespace.getScale('testColors');
|
||||
expect(scale1).to.equal(scale4);
|
||||
expect(scale2).to.equal(scale3);
|
||||
});
|
||||
});
|
||||
describe('.setColor()', () => {
|
||||
it('overwrites color for all CategoricalColorScales in this namespace', () => {
|
||||
const namespace = getNamespace('test-set-scale1');
|
||||
namespace.setColor('dog', 'black');
|
||||
const scale = namespace.getScale('testColors');
|
||||
expect(scale.getColor('dog')).to.equal('black');
|
||||
expect(scale.getColor('boy')).to.not.equal('black');
|
||||
});
|
||||
it('can override forcedColors in each scale', () => {
|
||||
const namespace = getNamespace('test-set-scale2');
|
||||
namespace.setColor('dog', 'black');
|
||||
const scale = namespace.getScale('testColors');
|
||||
scale.setColor('dog', 'pink');
|
||||
expect(scale.getColor('dog')).to.equal('black');
|
||||
expect(scale.getColor('boy')).to.not.equal('black');
|
||||
});
|
||||
it('does not affect scales in other namespaces', () => {
|
||||
const ns1 = getNamespace('test-set-scale3.1');
|
||||
ns1.setColor('dog', 'black');
|
||||
const scale1 = ns1.getScale('testColors');
|
||||
const ns2 = getNamespace('test-set-scale3.2');
|
||||
const scale2 = ns2.getScale('testColors');
|
||||
expect(scale1.getColor('dog')).to.equal('black');
|
||||
expect(scale2.getColor('dog')).to.not.equal('black');
|
||||
});
|
||||
it('returns the namespace instance', () => {
|
||||
const ns1 = getNamespace('test-set-scale3.1');
|
||||
const ns2 = ns1.setColor('dog', 'black');
|
||||
expect(ns1).to.equal(ns2);
|
||||
});
|
||||
});
|
||||
describe('static getScale()', () => {
|
||||
it('getScale() returns a CategoricalColorScale with default scheme in default namespace', () => {
|
||||
const scale = getScale();
|
||||
expect(scale).to.not.equal(undefined);
|
||||
const scale2 = getNamespace().getScale();
|
||||
expect(scale).to.equal(scale2);
|
||||
});
|
||||
it('getScale(scheme) returns a CategoricalColorScale with specified scheme in default namespace', () => {
|
||||
const scale = getScale('testColors');
|
||||
expect(scale).to.not.equal(undefined);
|
||||
const scale2 = getNamespace().getScale('testColors');
|
||||
expect(scale).to.equal(scale2);
|
||||
});
|
||||
it('getScale(scheme, namespace) returns a CategoricalColorScale with specified scheme in specified namespace', () => {
|
||||
const scale = getScale('testColors', 'test-getScale');
|
||||
expect(scale).to.not.equal(undefined);
|
||||
const scale2 = getNamespace('test-getScale').getScale('testColors');
|
||||
expect(scale).to.equal(scale2);
|
||||
});
|
||||
});
|
||||
describe('static getColor()', () => {
|
||||
it('getColor(value) returns a color from default scheme in default namespace', () => {
|
||||
const value = 'dog';
|
||||
const color = getColor(value);
|
||||
const color2 = getNamespace().getScale().getColor(value);
|
||||
expect(color).to.equal(color2);
|
||||
});
|
||||
it('getColor(value, scheme) returns a color from specified scheme in default namespace', () => {
|
||||
const value = 'dog';
|
||||
const scheme = 'testColors';
|
||||
const color = getColor(value, scheme);
|
||||
const color2 = getNamespace().getScale(scheme).getColor(value);
|
||||
expect(color).to.equal(color2);
|
||||
});
|
||||
it('getColor(value, scheme, namespace) returns a color from specified scheme in specified namespace', () => {
|
||||
const value = 'dog';
|
||||
const scheme = 'testColors';
|
||||
const namespace = 'test-getColor';
|
||||
const color = getColor(value, scheme, namespace);
|
||||
const color2 = getNamespace(namespace).getScale(scheme).getColor(value);
|
||||
expect(color).to.equal(color2);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,96 @@
|
||||
import { it, describe } from 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import CategoricalColorScale from '../../../src/modules/CategoricalColorScale';
|
||||
|
||||
describe('CategoricalColorScale', () => {
|
||||
it('exists', () => {
|
||||
expect(CategoricalColorScale !== undefined).to.equal(true);
|
||||
});
|
||||
|
||||
describe('new CategoricalColorScale(colors, parentForcedColors)', () => {
|
||||
it('can create new scale when parentForcedColors is not given', () => {
|
||||
const scale = new CategoricalColorScale(['blue', 'red', 'green']);
|
||||
expect(scale).to.be.instanceOf(CategoricalColorScale);
|
||||
});
|
||||
it('can create new scale when parentForcedColors is given', () => {
|
||||
const parentForcedColors = {};
|
||||
const scale = new CategoricalColorScale(['blue', 'red', 'green'], parentForcedColors);
|
||||
expect(scale).to.be.instanceOf(CategoricalColorScale);
|
||||
expect(scale.parentForcedColors).to.equal(parentForcedColors);
|
||||
});
|
||||
});
|
||||
describe('.getColor(value)', () => {
|
||||
it('returns same color for same value', () => {
|
||||
const scale = new CategoricalColorScale(['blue', 'red', 'green']);
|
||||
const c1 = scale.getColor('pig');
|
||||
const c2 = scale.getColor('horse');
|
||||
const c3 = scale.getColor('pig');
|
||||
scale.getColor('cow');
|
||||
const c5 = scale.getColor('horse');
|
||||
|
||||
expect(c1).to.equal(c3);
|
||||
expect(c2).to.equal(c5);
|
||||
});
|
||||
it('returns different color for consecutive items', () => {
|
||||
const scale = new CategoricalColorScale(['blue', 'red', 'green']);
|
||||
const c1 = scale.getColor('pig');
|
||||
const c2 = scale.getColor('horse');
|
||||
const c3 = scale.getColor('cat');
|
||||
|
||||
expect(c1).to.not.equal(c2);
|
||||
expect(c2).to.not.equal(c3);
|
||||
expect(c3).to.not.equal(c1);
|
||||
});
|
||||
it('recycles colors when number of items exceed available colors', () => {
|
||||
const colorSet = {};
|
||||
const scale = new CategoricalColorScale(['blue', 'red', 'green']);
|
||||
const colors = [
|
||||
scale.getColor('pig'),
|
||||
scale.getColor('horse'),
|
||||
scale.getColor('cat'),
|
||||
scale.getColor('cow'),
|
||||
scale.getColor('donkey'),
|
||||
scale.getColor('goat'),
|
||||
];
|
||||
colors.forEach((color) => {
|
||||
if (colorSet[color]) {
|
||||
colorSet[color]++;
|
||||
} else {
|
||||
colorSet[color] = 1;
|
||||
}
|
||||
});
|
||||
expect(Object.keys(colorSet).length).to.equal(3);
|
||||
['blue', 'red', 'green'].forEach((color) => {
|
||||
expect(colorSet[color]).to.equal(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('.setColor(value, forcedColor)', () => {
|
||||
it('overrides default color', () => {
|
||||
const scale = new CategoricalColorScale(['blue', 'red', 'green']);
|
||||
scale.setColor('pig', 'pink');
|
||||
expect(scale.getColor('pig')).to.equal('pink');
|
||||
});
|
||||
it('does not override parentForcedColors', () => {
|
||||
const scale1 = new CategoricalColorScale(['blue', 'red', 'green']);
|
||||
scale1.setColor('pig', 'black');
|
||||
const scale2 = new CategoricalColorScale(['blue', 'red', 'green'], scale1.forcedColors);
|
||||
scale2.setColor('pig', 'pink');
|
||||
expect(scale1.getColor('pig')).to.equal('black');
|
||||
expect(scale2.getColor('pig')).to.equal('black');
|
||||
});
|
||||
it('returns the scale', () => {
|
||||
const scale = new CategoricalColorScale(['blue', 'red', 'green']);
|
||||
const output = scale.setColor('pig', 'pink');
|
||||
expect(scale).to.equal(output);
|
||||
});
|
||||
});
|
||||
describe('.toFunction()', () => {
|
||||
it('returns a function that wraps getColor', () => {
|
||||
const scale = new CategoricalColorScale(['blue', 'red', 'green']);
|
||||
const colorFn = scale.toFunction();
|
||||
expect(scale.getColor('pig')).to.equal(colorFn('pig'));
|
||||
expect(scale.getColor('cat')).to.equal(colorFn('cat'));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,141 @@
|
||||
import { it, describe, beforeEach } from 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import ColorSchemeManager, {
|
||||
getInstance,
|
||||
getScheme,
|
||||
getAllSchemes,
|
||||
getDefaultSchemeName,
|
||||
setDefaultSchemeName,
|
||||
registerScheme,
|
||||
registerMultipleSchemes,
|
||||
} from '../../../src/modules/ColorSchemeManager';
|
||||
|
||||
describe('ColorSchemeManager', () => {
|
||||
beforeEach(() => {
|
||||
const m = getInstance();
|
||||
m.clearScheme();
|
||||
m.registerScheme('test', ['red', 'green', 'blue']);
|
||||
m.registerScheme('test2', ['orange', 'yellow', 'pink']);
|
||||
m.setDefaultSchemeName('test');
|
||||
});
|
||||
it('The class constructor cannot be accessed directly', () => {
|
||||
expect(ColorSchemeManager).to.not.be.a('Function');
|
||||
});
|
||||
describe('static getInstance()', () => {
|
||||
it('returns a singleton instance', () => {
|
||||
const m1 = getInstance();
|
||||
const m2 = getInstance();
|
||||
expect(m1).to.not.equal(undefined);
|
||||
expect(m1).to.equal(m2);
|
||||
});
|
||||
});
|
||||
describe('.getScheme()', () => {
|
||||
it('.getScheme() returns default color scheme', () => {
|
||||
const scheme = getInstance().getScheme();
|
||||
expect(scheme).to.deep.equal(['red', 'green', 'blue']);
|
||||
});
|
||||
it('.getScheme(name) returns color scheme with specified name', () => {
|
||||
const scheme = getInstance().getScheme('test2');
|
||||
expect(scheme).to.deep.equal(['orange', 'yellow', 'pink']);
|
||||
});
|
||||
});
|
||||
describe('.getAllSchemes()', () => {
|
||||
it('returns all registered schemes', () => {
|
||||
const schemes = getInstance().getAllSchemes();
|
||||
expect(schemes).to.deep.equal({
|
||||
test: ['red', 'green', 'blue'],
|
||||
test2: ['orange', 'yellow', 'pink'],
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('.getDefaultSchemeName()', () => {
|
||||
it('returns default scheme name', () => {
|
||||
const name = getInstance().getDefaultSchemeName();
|
||||
expect(name).to.equal('test');
|
||||
});
|
||||
});
|
||||
describe('.setDefaultSchemeName()', () => {
|
||||
it('set default scheme name', () => {
|
||||
getInstance().setDefaultSchemeName('test2');
|
||||
const name = getInstance().getDefaultSchemeName();
|
||||
expect(name).to.equal('test2');
|
||||
getInstance().setDefaultSchemeName('test');
|
||||
});
|
||||
it('returns the ColorSchemeManager instance', () => {
|
||||
const instance = getInstance().setDefaultSchemeName('test');
|
||||
expect(instance).to.equal(getInstance());
|
||||
});
|
||||
});
|
||||
describe('.registerScheme(name, colors)', () => {
|
||||
it('sets schemename and color', () => {
|
||||
getInstance().registerScheme('test3', ['cyan', 'magenta']);
|
||||
const scheme = getInstance().getScheme('test3');
|
||||
expect(scheme).to.deep.equal(['cyan', 'magenta']);
|
||||
});
|
||||
it('returns the ColorSchemeManager instance', () => {
|
||||
const instance = getInstance().registerScheme('test3', ['cyan', 'magenta']);
|
||||
expect(instance).to.equal(getInstance());
|
||||
});
|
||||
});
|
||||
describe('.registerMultipleSchemes(object)', () => {
|
||||
it('sets multiple schemes at once', () => {
|
||||
getInstance().registerMultipleSchemes({
|
||||
test4: ['cyan', 'magenta'],
|
||||
test5: ['brown', 'purple'],
|
||||
});
|
||||
const scheme1 = getInstance().getScheme('test4');
|
||||
expect(scheme1).to.deep.equal(['cyan', 'magenta']);
|
||||
const scheme2 = getInstance().getScheme('test5');
|
||||
expect(scheme2).to.deep.equal(['brown', 'purple']);
|
||||
});
|
||||
it('returns the ColorSchemeManager instance', () => {
|
||||
const instance = getInstance().registerMultipleSchemes({
|
||||
test4: ['cyan', 'magenta'],
|
||||
test5: ['brown', 'purple'],
|
||||
});
|
||||
expect(instance).to.equal(getInstance());
|
||||
});
|
||||
});
|
||||
describe('static getScheme()', () => {
|
||||
it('is equivalent to getInstance().getScheme()', () => {
|
||||
expect(getInstance().getScheme()).to.equal(getScheme());
|
||||
});
|
||||
});
|
||||
describe('static getAllSchemes()', () => {
|
||||
it('is equivalent to getInstance().getAllSchemes()', () => {
|
||||
expect(getInstance().getAllSchemes()).to.equal(getAllSchemes());
|
||||
});
|
||||
});
|
||||
describe('static getDefaultSchemeName()', () => {
|
||||
it('is equivalent to getInstance().getDefaultSchemeName()', () => {
|
||||
expect(getInstance().getDefaultSchemeName()).to.equal(getDefaultSchemeName());
|
||||
});
|
||||
});
|
||||
describe('static setDefaultSchemeName()', () => {
|
||||
it('is equivalent to getInstance().setDefaultSchemeName()', () => {
|
||||
setDefaultSchemeName('test2');
|
||||
const name = getInstance().getDefaultSchemeName();
|
||||
expect(name).to.equal('test2');
|
||||
setDefaultSchemeName('test');
|
||||
});
|
||||
});
|
||||
describe('static registerScheme()', () => {
|
||||
it('is equivalent to getInstance().registerScheme()', () => {
|
||||
registerScheme('test3', ['cyan', 'magenta']);
|
||||
const scheme = getInstance().getScheme('test3');
|
||||
expect(scheme).to.deep.equal(['cyan', 'magenta']);
|
||||
});
|
||||
});
|
||||
describe('static registerMultipleSchemes()', () => {
|
||||
it('is equivalent to getInstance().registerMultipleSchemes()', () => {
|
||||
registerMultipleSchemes({
|
||||
test4: ['cyan', 'magenta'],
|
||||
test5: ['brown', 'purple'],
|
||||
});
|
||||
const scheme1 = getInstance().getScheme('test4');
|
||||
expect(scheme1).to.deep.equal(['cyan', 'magenta']);
|
||||
const scheme2 = getInstance().getScheme('test5');
|
||||
expect(scheme2).to.deep.equal(['brown', 'purple']);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,12 +1,21 @@
|
||||
import { it, describe } from 'mocha';
|
||||
import { it, describe, before } from 'mocha';
|
||||
import { expect } from 'chai';
|
||||
|
||||
import { ALL_COLOR_SCHEMES, getColorFromScheme, hexToRGB } from '../../../src/modules/colors';
|
||||
import { getColorFromScheme, hexToRGB } from '../../../src/modules/colors';
|
||||
import { getInstance } from '../../../src/modules/ColorSchemeManager';
|
||||
import airbnb from '../../../src/modules/colorSchemes/airbnb';
|
||||
import categoricalSchemes from '../../../src/modules/colorSchemes/categorical';
|
||||
|
||||
describe('colors', () => {
|
||||
before(() => {
|
||||
// Register color schemes
|
||||
getInstance()
|
||||
.registerScheme('bnbColors', airbnb.bnbColors)
|
||||
.registerMultipleSchemes(categoricalSchemes)
|
||||
.setDefaultSchemeName('bnbColors');
|
||||
});
|
||||
it('default to bnbColors', () => {
|
||||
const color1 = getColorFromScheme('CA');
|
||||
expect(color1).to.equal(ALL_COLOR_SCHEMES.bnbColors[0]);
|
||||
expect(airbnb.bnbColors).to.include(color1);
|
||||
});
|
||||
it('getColorFromScheme series with same scheme should have the same color', () => {
|
||||
const color1 = getColorFromScheme('CA', 'bnbColors');
|
||||
@@ -14,19 +23,18 @@ describe('colors', () => {
|
||||
const color3 = getColorFromScheme('CA', 'bnbColors');
|
||||
const color4 = getColorFromScheme('NY', 'bnbColors');
|
||||
|
||||
expect(color1).to.equal(ALL_COLOR_SCHEMES.bnbColors[0]);
|
||||
expect(color2).to.equal(ALL_COLOR_SCHEMES.googleCategory20c[0]);
|
||||
expect(color1).to.equal(color3);
|
||||
expect(color4).to.equal(ALL_COLOR_SCHEMES.bnbColors[1]);
|
||||
expect(color1).to.not.equal(color2);
|
||||
expect(color1).to.not.equal(color4);
|
||||
});
|
||||
it('getColorFromScheme forcing colors persists through calls', () => {
|
||||
expect(getColorFromScheme('boys', 'bnbColors', 'blue')).to.equal('blue');
|
||||
expect(getColorFromScheme('boys', 'bnbColors')).to.equal('blue');
|
||||
expect(getColorFromScheme('boys', 'googleCategory20c')).to.equal('blue');
|
||||
expect(getColorFromScheme('boys', 'googleCategory20c')).to.not.equal('blue');
|
||||
|
||||
expect(getColorFromScheme('girls', 'bnbColors', 'pink')).to.equal('pink');
|
||||
expect(getColorFromScheme('girls', 'bnbColors')).to.equal('pink');
|
||||
expect(getColorFromScheme('girls', 'googleCategory20c')).to.equal('pink');
|
||||
expect(getColorFromScheme('girls', 'googleCategory20c')).to.not.equal('pink');
|
||||
});
|
||||
it('getColorFromScheme is not case sensitive', () => {
|
||||
const c1 = getColorFromScheme('girls', 'bnbColors');
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
/* eslint-disable global-require */
|
||||
import $ from 'jquery';
|
||||
import airbnb from './modules/colorSchemes/airbnb';
|
||||
import categoricalSchemes from './modules/colorSchemes/categorical';
|
||||
import lyft from './modules/colorSchemes/lyft';
|
||||
import { getInstance } from './modules/ColorSchemeManager';
|
||||
|
||||
// Everything imported in this file ends up in the common entry file
|
||||
// be mindful of double-imports
|
||||
|
||||
@@ -25,8 +30,15 @@ $(document).ready(function () {
|
||||
});
|
||||
});
|
||||
|
||||
// Register color schemes
|
||||
getInstance()
|
||||
.registerScheme('bnbColors', airbnb.bnbColors)
|
||||
.registerMultipleSchemes(categoricalSchemes)
|
||||
.registerScheme('lyftColors', lyft.lyftColors)
|
||||
.setDefaultSchemeName('bnbColors');
|
||||
|
||||
export function appSetup() {
|
||||
// A set of hacks to allow apps to run within a FAB template
|
||||
// A set of hacks to allow apps to run within a FAB template
|
||||
// this allows for the server side generated menus to function
|
||||
window.$ = $;
|
||||
window.jQuery = $;
|
||||
|
||||
@@ -5,7 +5,6 @@ import { chart } from '../../chart/chartReducer';
|
||||
import { initSliceEntities } from './sliceEntities';
|
||||
import { getParam } from '../../modules/utils';
|
||||
import { applyDefaultFormData } from '../../explore/store';
|
||||
import { getColorFromScheme } from '../../modules/colors';
|
||||
import findFirstParentContainerId from '../util/findFirstParentContainer';
|
||||
import getEmptyLayout from '../util/getEmptyLayout';
|
||||
import newComponentFactory from '../util/newComponentFactory';
|
||||
@@ -19,6 +18,7 @@ import {
|
||||
CHART_TYPE,
|
||||
ROW_TYPE,
|
||||
} from '../util/componentTypes';
|
||||
import { getScale } from '../../modules/CategoricalColorNamespace';
|
||||
|
||||
export default function(bootstrapData) {
|
||||
const { user_id, datasources, common, editMode } = bootstrapData;
|
||||
@@ -41,7 +41,7 @@ export default function(bootstrapData) {
|
||||
if (dashboard.metadata && dashboard.metadata.label_colors) {
|
||||
const colorMap = dashboard.metadata.label_colors;
|
||||
Object.keys(colorMap).forEach(label => {
|
||||
getColorFromScheme(label, null, colorMap[label]);
|
||||
getScale().setColor(label, colorMap[label]);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -20,13 +20,13 @@ import AnnotationTypes, {
|
||||
requiresQuery,
|
||||
} from '../../../modules/AnnotationTypes';
|
||||
|
||||
import { ALL_COLOR_SCHEMES } from '../../../modules/colors';
|
||||
import PopoverSection from '../../../components/PopoverSection';
|
||||
import ControlHeader from '../ControlHeader';
|
||||
import { nonEmpty } from '../../validators';
|
||||
import vizTypes from '../../visTypes';
|
||||
|
||||
import { t } from '../../../locales';
|
||||
import { getScheme } from '../../../modules/ColorSchemeManager';
|
||||
|
||||
const AUTOMATIC_COLOR = '';
|
||||
|
||||
@@ -276,7 +276,7 @@ export default class AnnotationLayer extends React.PureComponent {
|
||||
description = t('Select the Annotation Layer you would like to use.');
|
||||
} else {
|
||||
label = t('Chart');
|
||||
description = `Use a pre defined Superset Chart as a source for annotations and overlays.
|
||||
description = `Use a pre defined Superset Chart as a source for annotations and overlays.
|
||||
'your chart must be one of these visualization types:
|
||||
'[${getSupportedSourceTypes(annotationType)
|
||||
.map(x => vizTypes[x].label).join(', ')}]'`;
|
||||
@@ -478,7 +478,7 @@ export default class AnnotationLayer extends React.PureComponent {
|
||||
|
||||
renderDisplayConfiguration() {
|
||||
const { color, opacity, style, width, showMarkers, hideLine, annotationType } = this.state;
|
||||
const colorScheme = [...ALL_COLOR_SCHEMES[this.props.colorScheme]];
|
||||
const colorScheme = [...getScheme(this.props.colorScheme)];
|
||||
if (color && color !== AUTOMATIC_COLOR &&
|
||||
!colorScheme.find(x => x.toLowerCase() === color.toLowerCase())) {
|
||||
colorScheme.push(color);
|
||||
|
||||
@@ -45,11 +45,15 @@ import {
|
||||
mainMetric,
|
||||
} from '../modules/utils';
|
||||
import * as v from './validators';
|
||||
import { colorPrimary, ALL_COLOR_SCHEMES, spectrums } from '../modules/colors';
|
||||
import { colorPrimary } from '../modules/colors';
|
||||
import { defaultViewport } from '../modules/geo';
|
||||
import ColumnOption from '../components/ColumnOption';
|
||||
import OptionDescription from '../components/OptionDescription';
|
||||
import { t } from '../locales';
|
||||
import { getAllSchemes } from '../modules/ColorSchemeManager';
|
||||
import sequentialSchemes from '../modules/colorSchemes/sequential';
|
||||
|
||||
const ALL_COLOR_SCHEMES = getAllSchemes();
|
||||
|
||||
const D3_FORMAT_DOCS = 'D3 format syntax: https://github.com/d3/d3-format';
|
||||
|
||||
@@ -371,7 +375,7 @@ export const controls = {
|
||||
clearable: false,
|
||||
description: '',
|
||||
renderTrigger: true,
|
||||
schemes: spectrums,
|
||||
schemes: sequentialSchemes,
|
||||
isLinear: true,
|
||||
},
|
||||
|
||||
|
||||
60
superset/assets/src/modules/CategoricalColorNamespace.js
Normal file
60
superset/assets/src/modules/CategoricalColorNamespace.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import CategoricalColorScale from './CategoricalColorScale';
|
||||
import { getScheme, getDefaultSchemeName } from './ColorSchemeManager';
|
||||
|
||||
class CategoricalColorNamespace {
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
this.scales = {};
|
||||
this.forcedItems = {};
|
||||
}
|
||||
|
||||
getScale(schemeName) {
|
||||
const name = schemeName || getDefaultSchemeName();
|
||||
const scale = this.scales[name];
|
||||
if (scale) {
|
||||
return scale;
|
||||
}
|
||||
const newScale = new CategoricalColorScale(
|
||||
getScheme(name),
|
||||
this.forcedItems,
|
||||
);
|
||||
this.scales[name] = newScale;
|
||||
return newScale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforce specific color for given value
|
||||
* This will apply across all color scales
|
||||
* in this namespace.
|
||||
* @param {*} value value
|
||||
* @param {*} forcedColor color
|
||||
*/
|
||||
setColor(value, forcedColor) {
|
||||
this.forcedItems[value] = forcedColor;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
const namespaces = {};
|
||||
export const DEFAULT_NAMESPACE = 'GLOBAL';
|
||||
|
||||
export function getNamespace(name = DEFAULT_NAMESPACE) {
|
||||
const instance = namespaces[name];
|
||||
if (instance) {
|
||||
return instance;
|
||||
}
|
||||
const newInstance = new CategoricalColorNamespace(name);
|
||||
namespaces[name] = newInstance;
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
export function getColor(value, scheme, namespace) {
|
||||
return getNamespace(namespace)
|
||||
.getScale(scheme)
|
||||
.getColor(value);
|
||||
}
|
||||
|
||||
export function getScale(scheme, namespace) {
|
||||
return getNamespace(namespace)
|
||||
.getScale(scheme);
|
||||
}
|
||||
64
superset/assets/src/modules/CategoricalColorScale.js
Normal file
64
superset/assets/src/modules/CategoricalColorScale.js
Normal file
@@ -0,0 +1,64 @@
|
||||
import { TIME_SHIFT_PATTERN } from '../utils/common';
|
||||
|
||||
export function cleanValue(value) {
|
||||
// for superset series that should have the same color
|
||||
return String(value).trim()
|
||||
.toLowerCase()
|
||||
.split(', ')
|
||||
.filter(k => !TIME_SHIFT_PATTERN.test(k))
|
||||
.join(', ');
|
||||
}
|
||||
|
||||
export default class CategoricalColorScale {
|
||||
/**
|
||||
* Constructor
|
||||
* @param {*} colors an array of colors
|
||||
* @param {*} parentForcedColors optional parameter that comes from parent
|
||||
* (usually CategoricalColorNamespace) and supersede this.forcedColors
|
||||
*/
|
||||
constructor(colors, parentForcedColors) {
|
||||
this.colors = colors;
|
||||
this.parentForcedColors = parentForcedColors;
|
||||
this.forcedColors = {};
|
||||
this.seen = {};
|
||||
this.fn = value => this.getColor(value);
|
||||
}
|
||||
|
||||
getColor(value) {
|
||||
const cleanedValue = cleanValue(value);
|
||||
|
||||
const parentColor = this.parentForcedColors && this.parentForcedColors[cleanedValue];
|
||||
if (parentColor) {
|
||||
return parentColor;
|
||||
}
|
||||
|
||||
const forcedColor = this.forcedColors[cleanedValue];
|
||||
if (forcedColor) {
|
||||
return forcedColor;
|
||||
}
|
||||
|
||||
const seenColor = this.seen[cleanedValue];
|
||||
const length = this.colors.length;
|
||||
if (seenColor !== undefined) {
|
||||
return this.colors[seenColor % length];
|
||||
}
|
||||
|
||||
const index = Object.keys(this.seen).length;
|
||||
this.seen[cleanedValue] = index;
|
||||
return this.colors[index % length];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforce specific color for given value
|
||||
* @param {*} value value
|
||||
* @param {*} forcedColor forcedColor
|
||||
*/
|
||||
setColor(value, forcedColor) {
|
||||
this.forcedColors[value] = forcedColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
toFunction() {
|
||||
return this.fn;
|
||||
}
|
||||
}
|
||||
86
superset/assets/src/modules/ColorSchemeManager.js
Normal file
86
superset/assets/src/modules/ColorSchemeManager.js
Normal file
@@ -0,0 +1,86 @@
|
||||
class ColorSchemeManager {
|
||||
constructor() {
|
||||
this.schemes = {};
|
||||
this.defaultSchemeName = undefined;
|
||||
}
|
||||
|
||||
clearScheme() {
|
||||
this.schemes = {};
|
||||
return this;
|
||||
}
|
||||
|
||||
getScheme(schemeName) {
|
||||
return this.schemes[schemeName || this.defaultSchemeName];
|
||||
}
|
||||
|
||||
getAllSchemes() {
|
||||
return this.schemes;
|
||||
}
|
||||
|
||||
getDefaultSchemeName() {
|
||||
return this.defaultSchemeName;
|
||||
}
|
||||
|
||||
setDefaultSchemeName(schemeName) {
|
||||
this.defaultSchemeName = schemeName;
|
||||
return this;
|
||||
}
|
||||
|
||||
registerScheme(schemeName, colors) {
|
||||
this.schemes[schemeName] = colors;
|
||||
// If there is no default, set as default
|
||||
if (!this.defaultSchemeName) {
|
||||
this.defaultSchemeName = schemeName;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
registerMultipleSchemes(multipleSchemes) {
|
||||
Object.assign(this.schemes, multipleSchemes);
|
||||
// If there is no default, set the first scheme as default
|
||||
const keys = Object.keys(multipleSchemes);
|
||||
if (!this.defaultSchemeName && keys.length > 0) {
|
||||
this.defaultSchemeName = keys[0];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
let singleton;
|
||||
|
||||
export function getInstance() {
|
||||
if (!singleton) {
|
||||
singleton = new ColorSchemeManager();
|
||||
}
|
||||
return singleton;
|
||||
}
|
||||
|
||||
const staticFunctions = Object.getOwnPropertyNames(ColorSchemeManager.prototype)
|
||||
.filter(fn => fn !== 'constructor')
|
||||
.reduce((all, fn) => {
|
||||
const functions = all;
|
||||
functions[fn] = function (...args) {
|
||||
return getInstance()[fn](...args);
|
||||
};
|
||||
return functions;
|
||||
}, { getInstance });
|
||||
|
||||
const {
|
||||
clearScheme,
|
||||
getScheme,
|
||||
getAllSchemes,
|
||||
getDefaultSchemeName,
|
||||
setDefaultSchemeName,
|
||||
registerScheme,
|
||||
registerMultipleSchemes,
|
||||
} = staticFunctions;
|
||||
|
||||
export {
|
||||
clearScheme,
|
||||
getScheme,
|
||||
getAllSchemes,
|
||||
getDefaultSchemeName,
|
||||
setDefaultSchemeName,
|
||||
registerScheme,
|
||||
registerMultipleSchemes,
|
||||
};
|
||||
25
superset/assets/src/modules/colorSchemes/airbnb.js
Normal file
25
superset/assets/src/modules/colorSchemes/airbnb.js
Normal file
@@ -0,0 +1,25 @@
|
||||
export default {
|
||||
bnbColors: [
|
||||
'#ff5a5f', // rausch
|
||||
'#7b0051', // hackb
|
||||
'#007A87', // kazan
|
||||
'#00d1c1', // babu
|
||||
'#8ce071', // lima
|
||||
'#ffb400', // beach
|
||||
'#b4a76c', // barol
|
||||
'#ff8083',
|
||||
'#cc0086',
|
||||
'#00a1b3',
|
||||
'#00ffeb',
|
||||
'#bbedab',
|
||||
'#ffd266',
|
||||
'#cbc29a',
|
||||
'#ff3339',
|
||||
'#ff1ab1',
|
||||
'#005c66',
|
||||
'#00b3a5',
|
||||
'#55d12e',
|
||||
'#b37e00',
|
||||
'#988b4e',
|
||||
],
|
||||
};
|
||||
42
superset/assets/src/modules/colorSchemes/categorical.js
Normal file
42
superset/assets/src/modules/colorSchemes/categorical.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import d3 from 'd3';
|
||||
|
||||
export default {
|
||||
d3Category10: d3.scale.category10().range(),
|
||||
d3Category20: d3.scale.category20().range(),
|
||||
d3Category20b: d3.scale.category20b().range(),
|
||||
d3Category20c: d3.scale.category20c().range(),
|
||||
googleCategory10c: [
|
||||
'#3366cc',
|
||||
'#dc3912',
|
||||
'#ff9900',
|
||||
'#109618',
|
||||
'#990099',
|
||||
'#0099c6',
|
||||
'#dd4477',
|
||||
'#66aa00',
|
||||
'#b82e2e',
|
||||
'#316395',
|
||||
],
|
||||
googleCategory20c: [
|
||||
'#3366cc',
|
||||
'#dc3912',
|
||||
'#ff9900',
|
||||
'#109618',
|
||||
'#990099',
|
||||
'#0099c6',
|
||||
'#dd4477',
|
||||
'#66aa00',
|
||||
'#b82e2e',
|
||||
'#316395',
|
||||
'#994499',
|
||||
'#22aa99',
|
||||
'#aaaa11',
|
||||
'#6633cc',
|
||||
'#e67300',
|
||||
'#8b0707',
|
||||
'#651067',
|
||||
'#329262',
|
||||
'#5574a6',
|
||||
'#3b3eac',
|
||||
],
|
||||
};
|
||||
14
superset/assets/src/modules/colorSchemes/lyft.js
Normal file
14
superset/assets/src/modules/colorSchemes/lyft.js
Normal file
@@ -0,0 +1,14 @@
|
||||
export default {
|
||||
lyftColors: [
|
||||
'#EA0B8C',
|
||||
'#6C838E',
|
||||
'#29ABE2',
|
||||
'#33D9C1',
|
||||
'#9DACB9',
|
||||
'#7560AA',
|
||||
'#2D5584',
|
||||
'#831C4A',
|
||||
'#333D47',
|
||||
'#AC2077',
|
||||
],
|
||||
};
|
||||
433
superset/assets/src/modules/colorSchemes/sequential.js
Normal file
433
superset/assets/src/modules/colorSchemes/sequential.js
Normal file
@@ -0,0 +1,433 @@
|
||||
export default {
|
||||
blue_white_yellow: [
|
||||
'#00d1c1',
|
||||
'white',
|
||||
'#ffb400',
|
||||
],
|
||||
fire: [
|
||||
'white',
|
||||
'yellow',
|
||||
'red',
|
||||
'black',
|
||||
],
|
||||
white_black: [
|
||||
'white',
|
||||
'black',
|
||||
],
|
||||
black_white: [
|
||||
'black',
|
||||
'white',
|
||||
],
|
||||
dark_blue: [
|
||||
'#EBF5F8',
|
||||
'#6BB1CC',
|
||||
'#357E9B',
|
||||
'#1B4150',
|
||||
'#092935',
|
||||
],
|
||||
pink_grey: [
|
||||
'#E70B81',
|
||||
'#FAFAFA',
|
||||
'#666666',
|
||||
],
|
||||
greens: [
|
||||
'#ffffcc',
|
||||
'#78c679',
|
||||
'#006837',
|
||||
],
|
||||
purples: [
|
||||
'#f2f0f7',
|
||||
'#9e9ac8',
|
||||
'#54278f',
|
||||
],
|
||||
oranges: [
|
||||
'#fef0d9',
|
||||
'#fc8d59',
|
||||
'#b30000',
|
||||
],
|
||||
red_yellow_blue: [
|
||||
'#d7191c',
|
||||
'#fdae61',
|
||||
'#ffffbf',
|
||||
'#abd9e9',
|
||||
'#2c7bb6',
|
||||
],
|
||||
brown_white_green: [
|
||||
'#a6611a',
|
||||
'#dfc27d',
|
||||
'#f5f5f5',
|
||||
'#80cdc1',
|
||||
'#018571',
|
||||
],
|
||||
purple_white_green: [
|
||||
'#7b3294',
|
||||
'#c2a5cf',
|
||||
'#f7f7f7',
|
||||
'#a6dba0',
|
||||
'#008837',
|
||||
],
|
||||
schemeBrBG: [
|
||||
'#543005',
|
||||
'#8c510a',
|
||||
'#bf812d',
|
||||
'#dfc27d',
|
||||
'#f6e8c3',
|
||||
'#c7eae5',
|
||||
'#80cdc1',
|
||||
'#35978f',
|
||||
'#01665e',
|
||||
'#003c30',
|
||||
],
|
||||
schemePRGn: [
|
||||
'#40004b',
|
||||
'#762a83',
|
||||
'#9970ab',
|
||||
'#c2a5cf',
|
||||
'#e7d4e8',
|
||||
'#d9f0d3',
|
||||
'#a6dba0',
|
||||
'#5aae61',
|
||||
'#1b7837',
|
||||
'#00441b',
|
||||
],
|
||||
schemePiYG: [
|
||||
'#8e0152',
|
||||
'#c51b7d',
|
||||
'#de77ae',
|
||||
'#f1b6da',
|
||||
'#fde0ef',
|
||||
'#e6f5d0',
|
||||
'#b8e186',
|
||||
'#7fbc41',
|
||||
'#4d9221',
|
||||
'#276419',
|
||||
],
|
||||
schemePuOr: [
|
||||
'#2d004b',
|
||||
'#542788',
|
||||
'#8073ac',
|
||||
'#b2abd2',
|
||||
'#d8daeb',
|
||||
'#fee0b6',
|
||||
'#fdb863',
|
||||
'#e08214',
|
||||
'#b35806',
|
||||
'#7f3b08',
|
||||
],
|
||||
schemeRdBu: [
|
||||
'#67001f',
|
||||
'#b2182b',
|
||||
'#d6604d',
|
||||
'#f4a582',
|
||||
'#fddbc7',
|
||||
'#d1e5f0',
|
||||
'#92c5de',
|
||||
'#4393c3',
|
||||
'#2166ac',
|
||||
'#053061',
|
||||
],
|
||||
schemeRdGy: [
|
||||
'#67001f',
|
||||
'#b2182b',
|
||||
'#d6604d',
|
||||
'#f4a582',
|
||||
'#fddbc7',
|
||||
'#e0e0e0',
|
||||
'#bababa',
|
||||
'#878787',
|
||||
'#4d4d4d',
|
||||
'#1a1a1a',
|
||||
],
|
||||
schemeRdYlBu: [
|
||||
'#a50026',
|
||||
'#d73027',
|
||||
'#f46d43',
|
||||
'#fdae61',
|
||||
'#fee090',
|
||||
'#e0f3f8',
|
||||
'#abd9e9',
|
||||
'#74add1',
|
||||
'#4575b4',
|
||||
'#313695',
|
||||
],
|
||||
schemeRdYlGn: [
|
||||
'#a50026',
|
||||
'#d73027',
|
||||
'#f46d43',
|
||||
'#fdae61',
|
||||
'#fee08b',
|
||||
'#d9ef8b',
|
||||
'#a6d96a',
|
||||
'#66bd63',
|
||||
'#1a9850',
|
||||
'#006837',
|
||||
],
|
||||
schemeSpectral: [
|
||||
'#9e0142',
|
||||
'#d53e4f',
|
||||
'#f46d43',
|
||||
'#fdae61',
|
||||
'#fee08b',
|
||||
'#e6f598',
|
||||
'#abdda4',
|
||||
'#66c2a5',
|
||||
'#3288bd',
|
||||
'#5e4fa2',
|
||||
],
|
||||
schemeBlues: [
|
||||
'#b5d4e9',
|
||||
'#93c3df',
|
||||
'#6daed5',
|
||||
'#4b97c9',
|
||||
'#2f7ebc',
|
||||
'#1864aa',
|
||||
'#0a4a90',
|
||||
'#08306b',
|
||||
],
|
||||
schemeGreens: [
|
||||
'#b7e2b1',
|
||||
'#97d494',
|
||||
'#73c378',
|
||||
'#4daf62',
|
||||
'#2f984f',
|
||||
'#157f3b',
|
||||
'#036429',
|
||||
'#00441b',
|
||||
],
|
||||
schemeGrays: [
|
||||
'#cecece',
|
||||
'#b4b4b4',
|
||||
'#979797',
|
||||
'#7a7a7a',
|
||||
'#5f5f5f',
|
||||
'#404040',
|
||||
'#1e1e1e',
|
||||
'#000000',
|
||||
],
|
||||
schemeOranges: [
|
||||
'#fdc28c',
|
||||
'#fda762',
|
||||
'#fb8d3d',
|
||||
'#f2701d',
|
||||
'#e25609',
|
||||
'#c44103',
|
||||
'#9f3303',
|
||||
'#7f2704',
|
||||
],
|
||||
schemePurples: [
|
||||
'#cecee5',
|
||||
'#b6b5d8',
|
||||
'#9e9bc9',
|
||||
'#8782bc',
|
||||
'#7363ac',
|
||||
'#61409b',
|
||||
'#501f8c',
|
||||
'#3f007d',
|
||||
],
|
||||
schemeReds: [
|
||||
'#fcaa8e',
|
||||
'#fc8a6b',
|
||||
'#f9694c',
|
||||
'#ef4533',
|
||||
'#d92723',
|
||||
'#bb151a',
|
||||
'#970b13',
|
||||
'#67000d',
|
||||
],
|
||||
schemeViridis: [
|
||||
'#482475',
|
||||
'#414487',
|
||||
'#355f8d',
|
||||
'#2a788e',
|
||||
'#21918c',
|
||||
'#22a884',
|
||||
'#44bf70',
|
||||
'#7ad151',
|
||||
'#bddf26',
|
||||
'#fde725',
|
||||
],
|
||||
schemeInferno: [
|
||||
'#160b39',
|
||||
'#420a68',
|
||||
'#6a176e',
|
||||
'#932667',
|
||||
'#bc3754',
|
||||
'#dd513a',
|
||||
'#f37819',
|
||||
'#fca50a',
|
||||
'#f6d746',
|
||||
'#fcffa4',
|
||||
],
|
||||
schemeMagma: [
|
||||
'#140e36',
|
||||
'#3b0f70',
|
||||
'#641a80',
|
||||
'#8c2981',
|
||||
'#b73779',
|
||||
'#de4968',
|
||||
'#f7705c',
|
||||
'#fe9f6d',
|
||||
'#fecf92',
|
||||
'#fcfdbf',
|
||||
],
|
||||
schemeWarm: [
|
||||
'#963db3',
|
||||
'#bf3caf',
|
||||
'#e4419d',
|
||||
'#fe4b83',
|
||||
'#ff5e63',
|
||||
'#ff7847',
|
||||
'#fb9633',
|
||||
'#e2b72f',
|
||||
'#c6d63c',
|
||||
'#aff05b',
|
||||
],
|
||||
schemeCool: [
|
||||
'#6054c8',
|
||||
'#4c6edb',
|
||||
'#368ce1',
|
||||
'#23abd8',
|
||||
'#1ac7c2',
|
||||
'#1ddfa3',
|
||||
'#30ef82',
|
||||
'#52f667',
|
||||
'#7ff658',
|
||||
'#aff05b',
|
||||
],
|
||||
schemeCubehelixDefault: [
|
||||
'#1a1530',
|
||||
'#163d4e',
|
||||
'#1f6642',
|
||||
'#54792f',
|
||||
'#a07949',
|
||||
'#d07e93',
|
||||
'#cf9cda',
|
||||
'#c1caf3',
|
||||
'#d2eeef',
|
||||
'#ffffff',
|
||||
],
|
||||
schemeBuGn: [
|
||||
'#b7e4da',
|
||||
'#8fd3c1',
|
||||
'#68c2a3',
|
||||
'#49b17f',
|
||||
'#2f9959',
|
||||
'#157f3c',
|
||||
'#036429',
|
||||
'#00441b',
|
||||
],
|
||||
schemeBuPu: [
|
||||
'#b2cae1',
|
||||
'#9cb3d5',
|
||||
'#8f95c6',
|
||||
'#8c74b5',
|
||||
'#8952a5',
|
||||
'#852d8f',
|
||||
'#730f71',
|
||||
'#4d004b',
|
||||
],
|
||||
schemeGnBu: [
|
||||
'#bde5bf',
|
||||
'#9ed9bb',
|
||||
'#7bcbc4',
|
||||
'#58b7cd',
|
||||
'#399cc6',
|
||||
'#1d7eb7',
|
||||
'#0b60a1',
|
||||
'#084081',
|
||||
],
|
||||
schemeOrRd: [
|
||||
'#fdca94',
|
||||
'#fdb07a',
|
||||
'#fa8e5d',
|
||||
'#f16c49',
|
||||
'#e04530',
|
||||
'#c81d13',
|
||||
'#a70403',
|
||||
'#7f0000',
|
||||
],
|
||||
schemePuBuGn: [
|
||||
'#bec9e2',
|
||||
'#98b9d9',
|
||||
'#69a8cf',
|
||||
'#4096c0',
|
||||
'#19879f',
|
||||
'#037877',
|
||||
'#016353',
|
||||
'#014636',
|
||||
],
|
||||
schemePuBu: [
|
||||
'#bfc9e2',
|
||||
'#9bb9d9',
|
||||
'#72a8cf',
|
||||
'#4394c3',
|
||||
'#1a7db6',
|
||||
'#0667a1',
|
||||
'#045281',
|
||||
'#023858',
|
||||
],
|
||||
schemePuRd: [
|
||||
'#d0aad2',
|
||||
'#d08ac2',
|
||||
'#dd63ae',
|
||||
'#e33890',
|
||||
'#d71c6c',
|
||||
'#b70b4f',
|
||||
'#8f023a',
|
||||
'#67001f',
|
||||
],
|
||||
schemeRdPu: [
|
||||
'#fbb5bc',
|
||||
'#f993b0',
|
||||
'#f369a3',
|
||||
'#e03e98',
|
||||
'#c01788',
|
||||
'#99037c',
|
||||
'#700174',
|
||||
'#49006a',
|
||||
],
|
||||
schemeYlGnBu: [
|
||||
'#d5eeb3',
|
||||
'#a9ddb7',
|
||||
'#73c9bd',
|
||||
'#45b4c2',
|
||||
'#2897bf',
|
||||
'#2073b2',
|
||||
'#234ea0',
|
||||
'#1c3185',
|
||||
'#081d58',
|
||||
],
|
||||
schemeYlGn: [
|
||||
'#e4f4ac',
|
||||
'#c7e89b',
|
||||
'#a2d88a',
|
||||
'#78c578',
|
||||
'#4eaf63',
|
||||
'#2f944e',
|
||||
'#15793f',
|
||||
'#036034',
|
||||
'#004529',
|
||||
],
|
||||
schemeYlOrBr: [
|
||||
'#feeaa1',
|
||||
'#fed676',
|
||||
'#feba4a',
|
||||
'#fb992c',
|
||||
'#ee7918',
|
||||
'#d85b0a',
|
||||
'#b74304',
|
||||
'#8f3204',
|
||||
'#662506',
|
||||
],
|
||||
schemeYlOrRd: [
|
||||
'#fee087',
|
||||
'#fec965',
|
||||
'#feab4b',
|
||||
'#fd893c',
|
||||
'#fa5c2e',
|
||||
'#ec3023',
|
||||
'#d31121',
|
||||
'#af0225',
|
||||
'#800026',
|
||||
],
|
||||
};
|
||||
@@ -1,529 +1,13 @@
|
||||
import d3 from 'd3';
|
||||
import { TIME_SHIFT_PATTERN } from '../utils/common';
|
||||
import { getScale } from './CategoricalColorNamespace';
|
||||
import sequentialSchemes from './colorSchemes/sequential';
|
||||
import airbnb from './colorSchemes/airbnb';
|
||||
import lyft from './colorSchemes/lyft';
|
||||
|
||||
export const brandColor = '#00A699';
|
||||
export const colorPrimary = { r: 0, g: 122, b: 135, a: 1 };
|
||||
|
||||
// Color related utility functions go in this object
|
||||
export const bnbColors = [
|
||||
'#ff5a5f', // rausch
|
||||
'#7b0051', // hackb
|
||||
'#007A87', // kazan
|
||||
'#00d1c1', // babu
|
||||
'#8ce071', // lima
|
||||
'#ffb400', // beach
|
||||
'#b4a76c', // barol
|
||||
'#ff8083',
|
||||
'#cc0086',
|
||||
'#00a1b3',
|
||||
'#00ffeb',
|
||||
'#bbedab',
|
||||
'#ffd266',
|
||||
'#cbc29a',
|
||||
'#ff3339',
|
||||
'#ff1ab1',
|
||||
'#005c66',
|
||||
'#00b3a5',
|
||||
'#55d12e',
|
||||
'#b37e00',
|
||||
'#988b4e',
|
||||
];
|
||||
|
||||
export const lyftColors = [
|
||||
'#EA0B8C',
|
||||
'#6C838E',
|
||||
'#29ABE2',
|
||||
'#33D9C1',
|
||||
'#9DACB9',
|
||||
'#7560AA',
|
||||
'#2D5584',
|
||||
'#831C4A',
|
||||
'#333D47',
|
||||
'#AC2077',
|
||||
];
|
||||
|
||||
const d3Category10 = d3.scale.category10().range();
|
||||
const d3Category20 = d3.scale.category20().range();
|
||||
const d3Category20b = d3.scale.category20b().range();
|
||||
const d3Category20c = d3.scale.category20c().range();
|
||||
const googleCategory10c = [
|
||||
'#3366cc',
|
||||
'#dc3912',
|
||||
'#ff9900',
|
||||
'#109618',
|
||||
'#990099',
|
||||
'#0099c6',
|
||||
'#dd4477',
|
||||
'#66aa00',
|
||||
'#b82e2e',
|
||||
'#316395',
|
||||
];
|
||||
const googleCategory20c = [
|
||||
'#3366cc',
|
||||
'#dc3912',
|
||||
'#ff9900',
|
||||
'#109618',
|
||||
'#990099',
|
||||
'#0099c6',
|
||||
'#dd4477',
|
||||
'#66aa00',
|
||||
'#b82e2e',
|
||||
'#316395',
|
||||
'#994499',
|
||||
'#22aa99',
|
||||
'#aaaa11',
|
||||
'#6633cc',
|
||||
'#e67300',
|
||||
'#8b0707',
|
||||
'#651067',
|
||||
'#329262',
|
||||
'#5574a6',
|
||||
'#3b3eac',
|
||||
];
|
||||
export const ALL_COLOR_SCHEMES = {
|
||||
bnbColors,
|
||||
d3Category10,
|
||||
d3Category20,
|
||||
d3Category20b,
|
||||
d3Category20c,
|
||||
googleCategory10c,
|
||||
googleCategory20c,
|
||||
lyftColors,
|
||||
};
|
||||
|
||||
export const spectrums = {
|
||||
blue_white_yellow: [
|
||||
'#00d1c1',
|
||||
'white',
|
||||
'#ffb400',
|
||||
],
|
||||
fire: [
|
||||
'white',
|
||||
'yellow',
|
||||
'red',
|
||||
'black',
|
||||
],
|
||||
white_black: [
|
||||
'white',
|
||||
'black',
|
||||
],
|
||||
black_white: [
|
||||
'black',
|
||||
'white',
|
||||
],
|
||||
dark_blue: [
|
||||
'#EBF5F8',
|
||||
'#6BB1CC',
|
||||
'#357E9B',
|
||||
'#1B4150',
|
||||
'#092935',
|
||||
],
|
||||
pink_grey: [
|
||||
'#E70B81',
|
||||
'#FAFAFA',
|
||||
'#666666',
|
||||
],
|
||||
greens: [
|
||||
'#ffffcc',
|
||||
'#78c679',
|
||||
'#006837',
|
||||
],
|
||||
purples: [
|
||||
'#f2f0f7',
|
||||
'#9e9ac8',
|
||||
'#54278f',
|
||||
],
|
||||
oranges: [
|
||||
'#fef0d9',
|
||||
'#fc8d59',
|
||||
'#b30000',
|
||||
],
|
||||
red_yellow_blue: [
|
||||
'#d7191c',
|
||||
'#fdae61',
|
||||
'#ffffbf',
|
||||
'#abd9e9',
|
||||
'#2c7bb6',
|
||||
],
|
||||
brown_white_green: [
|
||||
'#a6611a',
|
||||
'#dfc27d',
|
||||
'#f5f5f5',
|
||||
'#80cdc1',
|
||||
'#018571',
|
||||
],
|
||||
purple_white_green: [
|
||||
'#7b3294',
|
||||
'#c2a5cf',
|
||||
'#f7f7f7',
|
||||
'#a6dba0',
|
||||
'#008837',
|
||||
],
|
||||
schemeBrBG: [
|
||||
'#543005',
|
||||
'#8c510a',
|
||||
'#bf812d',
|
||||
'#dfc27d',
|
||||
'#f6e8c3',
|
||||
'#c7eae5',
|
||||
'#80cdc1',
|
||||
'#35978f',
|
||||
'#01665e',
|
||||
'#003c30',
|
||||
],
|
||||
schemePRGn: [
|
||||
'#40004b',
|
||||
'#762a83',
|
||||
'#9970ab',
|
||||
'#c2a5cf',
|
||||
'#e7d4e8',
|
||||
'#d9f0d3',
|
||||
'#a6dba0',
|
||||
'#5aae61',
|
||||
'#1b7837',
|
||||
'#00441b',
|
||||
],
|
||||
schemePiYG: [
|
||||
'#8e0152',
|
||||
'#c51b7d',
|
||||
'#de77ae',
|
||||
'#f1b6da',
|
||||
'#fde0ef',
|
||||
'#e6f5d0',
|
||||
'#b8e186',
|
||||
'#7fbc41',
|
||||
'#4d9221',
|
||||
'#276419',
|
||||
],
|
||||
schemePuOr: [
|
||||
'#2d004b',
|
||||
'#542788',
|
||||
'#8073ac',
|
||||
'#b2abd2',
|
||||
'#d8daeb',
|
||||
'#fee0b6',
|
||||
'#fdb863',
|
||||
'#e08214',
|
||||
'#b35806',
|
||||
'#7f3b08',
|
||||
],
|
||||
schemeRdBu: [
|
||||
'#67001f',
|
||||
'#b2182b',
|
||||
'#d6604d',
|
||||
'#f4a582',
|
||||
'#fddbc7',
|
||||
'#d1e5f0',
|
||||
'#92c5de',
|
||||
'#4393c3',
|
||||
'#2166ac',
|
||||
'#053061',
|
||||
],
|
||||
schemeRdGy: [
|
||||
'#67001f',
|
||||
'#b2182b',
|
||||
'#d6604d',
|
||||
'#f4a582',
|
||||
'#fddbc7',
|
||||
'#e0e0e0',
|
||||
'#bababa',
|
||||
'#878787',
|
||||
'#4d4d4d',
|
||||
'#1a1a1a',
|
||||
],
|
||||
schemeRdYlBu: [
|
||||
'#a50026',
|
||||
'#d73027',
|
||||
'#f46d43',
|
||||
'#fdae61',
|
||||
'#fee090',
|
||||
'#e0f3f8',
|
||||
'#abd9e9',
|
||||
'#74add1',
|
||||
'#4575b4',
|
||||
'#313695',
|
||||
],
|
||||
schemeRdYlGn: [
|
||||
'#a50026',
|
||||
'#d73027',
|
||||
'#f46d43',
|
||||
'#fdae61',
|
||||
'#fee08b',
|
||||
'#d9ef8b',
|
||||
'#a6d96a',
|
||||
'#66bd63',
|
||||
'#1a9850',
|
||||
'#006837',
|
||||
],
|
||||
schemeSpectral: [
|
||||
'#9e0142',
|
||||
'#d53e4f',
|
||||
'#f46d43',
|
||||
'#fdae61',
|
||||
'#fee08b',
|
||||
'#e6f598',
|
||||
'#abdda4',
|
||||
'#66c2a5',
|
||||
'#3288bd',
|
||||
'#5e4fa2',
|
||||
],
|
||||
schemeBlues: [
|
||||
'#b5d4e9',
|
||||
'#93c3df',
|
||||
'#6daed5',
|
||||
'#4b97c9',
|
||||
'#2f7ebc',
|
||||
'#1864aa',
|
||||
'#0a4a90',
|
||||
'#08306b',
|
||||
],
|
||||
schemeGreens: [
|
||||
'#b7e2b1',
|
||||
'#97d494',
|
||||
'#73c378',
|
||||
'#4daf62',
|
||||
'#2f984f',
|
||||
'#157f3b',
|
||||
'#036429',
|
||||
'#00441b',
|
||||
],
|
||||
schemeGrays: [
|
||||
'#cecece',
|
||||
'#b4b4b4',
|
||||
'#979797',
|
||||
'#7a7a7a',
|
||||
'#5f5f5f',
|
||||
'#404040',
|
||||
'#1e1e1e',
|
||||
'#000000',
|
||||
],
|
||||
schemeOranges: [
|
||||
'#fdc28c',
|
||||
'#fda762',
|
||||
'#fb8d3d',
|
||||
'#f2701d',
|
||||
'#e25609',
|
||||
'#c44103',
|
||||
'#9f3303',
|
||||
'#7f2704',
|
||||
],
|
||||
schemePurples: [
|
||||
'#cecee5',
|
||||
'#b6b5d8',
|
||||
'#9e9bc9',
|
||||
'#8782bc',
|
||||
'#7363ac',
|
||||
'#61409b',
|
||||
'#501f8c',
|
||||
'#3f007d',
|
||||
],
|
||||
schemeReds: [
|
||||
'#fcaa8e',
|
||||
'#fc8a6b',
|
||||
'#f9694c',
|
||||
'#ef4533',
|
||||
'#d92723',
|
||||
'#bb151a',
|
||||
'#970b13',
|
||||
'#67000d',
|
||||
],
|
||||
schemeViridis: [
|
||||
'#482475',
|
||||
'#414487',
|
||||
'#355f8d',
|
||||
'#2a788e',
|
||||
'#21918c',
|
||||
'#22a884',
|
||||
'#44bf70',
|
||||
'#7ad151',
|
||||
'#bddf26',
|
||||
'#fde725',
|
||||
],
|
||||
schemeInferno: [
|
||||
'#160b39',
|
||||
'#420a68',
|
||||
'#6a176e',
|
||||
'#932667',
|
||||
'#bc3754',
|
||||
'#dd513a',
|
||||
'#f37819',
|
||||
'#fca50a',
|
||||
'#f6d746',
|
||||
'#fcffa4',
|
||||
],
|
||||
schemeMagma: [
|
||||
'#140e36',
|
||||
'#3b0f70',
|
||||
'#641a80',
|
||||
'#8c2981',
|
||||
'#b73779',
|
||||
'#de4968',
|
||||
'#f7705c',
|
||||
'#fe9f6d',
|
||||
'#fecf92',
|
||||
'#fcfdbf',
|
||||
],
|
||||
schemeWarm: [
|
||||
'#963db3',
|
||||
'#bf3caf',
|
||||
'#e4419d',
|
||||
'#fe4b83',
|
||||
'#ff5e63',
|
||||
'#ff7847',
|
||||
'#fb9633',
|
||||
'#e2b72f',
|
||||
'#c6d63c',
|
||||
'#aff05b',
|
||||
],
|
||||
schemeCool: [
|
||||
'#6054c8',
|
||||
'#4c6edb',
|
||||
'#368ce1',
|
||||
'#23abd8',
|
||||
'#1ac7c2',
|
||||
'#1ddfa3',
|
||||
'#30ef82',
|
||||
'#52f667',
|
||||
'#7ff658',
|
||||
'#aff05b',
|
||||
],
|
||||
schemeCubehelixDefault: [
|
||||
'#1a1530',
|
||||
'#163d4e',
|
||||
'#1f6642',
|
||||
'#54792f',
|
||||
'#a07949',
|
||||
'#d07e93',
|
||||
'#cf9cda',
|
||||
'#c1caf3',
|
||||
'#d2eeef',
|
||||
'#ffffff',
|
||||
],
|
||||
schemeBuGn: [
|
||||
'#b7e4da',
|
||||
'#8fd3c1',
|
||||
'#68c2a3',
|
||||
'#49b17f',
|
||||
'#2f9959',
|
||||
'#157f3c',
|
||||
'#036429',
|
||||
'#00441b',
|
||||
],
|
||||
schemeBuPu: [
|
||||
'#b2cae1',
|
||||
'#9cb3d5',
|
||||
'#8f95c6',
|
||||
'#8c74b5',
|
||||
'#8952a5',
|
||||
'#852d8f',
|
||||
'#730f71',
|
||||
'#4d004b',
|
||||
],
|
||||
schemeGnBu: [
|
||||
'#bde5bf',
|
||||
'#9ed9bb',
|
||||
'#7bcbc4',
|
||||
'#58b7cd',
|
||||
'#399cc6',
|
||||
'#1d7eb7',
|
||||
'#0b60a1',
|
||||
'#084081',
|
||||
],
|
||||
schemeOrRd: [
|
||||
'#fdca94',
|
||||
'#fdb07a',
|
||||
'#fa8e5d',
|
||||
'#f16c49',
|
||||
'#e04530',
|
||||
'#c81d13',
|
||||
'#a70403',
|
||||
'#7f0000',
|
||||
],
|
||||
schemePuBuGn: [
|
||||
'#bec9e2',
|
||||
'#98b9d9',
|
||||
'#69a8cf',
|
||||
'#4096c0',
|
||||
'#19879f',
|
||||
'#037877',
|
||||
'#016353',
|
||||
'#014636',
|
||||
],
|
||||
schemePuBu: [
|
||||
'#bfc9e2',
|
||||
'#9bb9d9',
|
||||
'#72a8cf',
|
||||
'#4394c3',
|
||||
'#1a7db6',
|
||||
'#0667a1',
|
||||
'#045281',
|
||||
'#023858',
|
||||
],
|
||||
schemePuRd: [
|
||||
'#d0aad2',
|
||||
'#d08ac2',
|
||||
'#dd63ae',
|
||||
'#e33890',
|
||||
'#d71c6c',
|
||||
'#b70b4f',
|
||||
'#8f023a',
|
||||
'#67001f',
|
||||
],
|
||||
schemeRdPu: [
|
||||
'#fbb5bc',
|
||||
'#f993b0',
|
||||
'#f369a3',
|
||||
'#e03e98',
|
||||
'#c01788',
|
||||
'#99037c',
|
||||
'#700174',
|
||||
'#49006a',
|
||||
],
|
||||
schemeYlGnBu: [
|
||||
'#d5eeb3',
|
||||
'#a9ddb7',
|
||||
'#73c9bd',
|
||||
'#45b4c2',
|
||||
'#2897bf',
|
||||
'#2073b2',
|
||||
'#234ea0',
|
||||
'#1c3185',
|
||||
'#081d58',
|
||||
],
|
||||
schemeYlGn: [
|
||||
'#e4f4ac',
|
||||
'#c7e89b',
|
||||
'#a2d88a',
|
||||
'#78c578',
|
||||
'#4eaf63',
|
||||
'#2f944e',
|
||||
'#15793f',
|
||||
'#036034',
|
||||
'#004529',
|
||||
],
|
||||
schemeYlOrBr: [
|
||||
'#feeaa1',
|
||||
'#fed676',
|
||||
'#feba4a',
|
||||
'#fb992c',
|
||||
'#ee7918',
|
||||
'#d85b0a',
|
||||
'#b74304',
|
||||
'#8f3204',
|
||||
'#662506',
|
||||
],
|
||||
schemeYlOrRd: [
|
||||
'#fee087',
|
||||
'#fec965',
|
||||
'#feab4b',
|
||||
'#fd893c',
|
||||
'#fa5c2e',
|
||||
'#ec3023',
|
||||
'#d31121',
|
||||
'#af0225',
|
||||
'#800026',
|
||||
],
|
||||
};
|
||||
export const bnbColors = airbnb.bnbColors;
|
||||
export const lyftColors = lyft.lyftColors;
|
||||
|
||||
export function hexToRGB(hex, alpha = 255) {
|
||||
if (!hex) {
|
||||
@@ -546,41 +30,20 @@ export function hexToRGB(hex, alpha = 255) {
|
||||
* @param {string} forcedColor - A color that the caller wants to
|
||||
forcibly associate to a label.
|
||||
*/
|
||||
export const getColorFromScheme = (function () {
|
||||
const seen = {};
|
||||
const forcedColors = {};
|
||||
return function (s, scheme, forcedColor) {
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
const selectedScheme = scheme ? ALL_COLOR_SCHEMES[scheme] : ALL_COLOR_SCHEMES.bnbColors;
|
||||
let stringifyS = String(s).toLowerCase();
|
||||
// next line is for superset series that should have the same color
|
||||
stringifyS = stringifyS.split(', ').filter(k => !TIME_SHIFT_PATTERN.test(k)).join(', ');
|
||||
|
||||
if (forcedColor && !forcedColors[stringifyS]) {
|
||||
forcedColors[stringifyS] = forcedColor;
|
||||
}
|
||||
if (forcedColors[stringifyS]) {
|
||||
return forcedColors[stringifyS];
|
||||
}
|
||||
|
||||
if (seen[selectedScheme] === undefined) {
|
||||
seen[selectedScheme] = {};
|
||||
}
|
||||
if (seen[selectedScheme][stringifyS] === undefined) {
|
||||
seen[selectedScheme][stringifyS] = Object.keys(seen[selectedScheme]).length;
|
||||
}
|
||||
/* eslint consistent-return: 0 */
|
||||
return selectedScheme[seen[selectedScheme][stringifyS] % selectedScheme.length];
|
||||
};
|
||||
}());
|
||||
export function getColorFromScheme(value, schemeName, forcedColor) {
|
||||
const scale = getScale(schemeName);
|
||||
if (forcedColor) {
|
||||
scale.setColor(value, forcedColor);
|
||||
return forcedColor;
|
||||
}
|
||||
return scale.getColor(value);
|
||||
}
|
||||
|
||||
export const colorScalerFactory = function (colors, data, accessor, extents, outputRGBA = false) {
|
||||
// Returns a linear scaler our of an array of color
|
||||
if (!Array.isArray(colors)) {
|
||||
/* eslint no-param-reassign: 0 */
|
||||
colors = spectrums[colors];
|
||||
colors = sequentialSchemes[colors];
|
||||
}
|
||||
let ext = [0, 1];
|
||||
if (extents) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import d3 from 'd3';
|
||||
import PropTypes from 'prop-types';
|
||||
import { getColorFromScheme } from '../modules/colors';
|
||||
import { getScale } from '../modules/CategoricalColorNamespace';
|
||||
import './chord.css';
|
||||
|
||||
const propTypes = {
|
||||
@@ -31,6 +31,7 @@ function chordVis(element, props) {
|
||||
const div = d3.select(element);
|
||||
const { nodes, matrix } = data;
|
||||
const f = d3.format(numberFormat);
|
||||
const colorFn = getScale(colorScheme).toFunction();
|
||||
|
||||
const outerRadius = Math.min(width, height) / 2 - 10;
|
||||
const innerRadius = outerRadius - 24;
|
||||
@@ -78,7 +79,7 @@ function chordVis(element, props) {
|
||||
const groupPath = group.append('path')
|
||||
.attr('id', (d, i) => 'group' + i)
|
||||
.attr('d', arc)
|
||||
.style('fill', (d, i) => getColorFromScheme(nodes[i], colorScheme));
|
||||
.style('fill', (d, i) => colorFn(nodes[i]));
|
||||
|
||||
// Add a text label.
|
||||
const groupText = group.append('text')
|
||||
@@ -102,7 +103,7 @@ function chordVis(element, props) {
|
||||
.on('mouseover', (d) => {
|
||||
chord.classed('fade', p => p !== d);
|
||||
})
|
||||
.style('fill', d => getColorFromScheme(nodes[d.source.index], colorScheme))
|
||||
.style('fill', d => colorFn(nodes[d.source.index]))
|
||||
.attr('d', path);
|
||||
|
||||
// Add an elaborate mouseover title for each chord.
|
||||
|
||||
@@ -6,19 +6,21 @@ import PropTypes from 'prop-types';
|
||||
import AnimatableDeckGLContainer from './AnimatableDeckGLContainer';
|
||||
import Legend from '../Legend';
|
||||
|
||||
import { getColorFromScheme, hexToRGB } from '../../modules/colors';
|
||||
import { getScale } from '../../modules/CategoricalColorNamespace';
|
||||
import { hexToRGB } from '../../modules/colors';
|
||||
import { getPlaySliderParams } from '../../modules/time';
|
||||
import sandboxedEval from '../../modules/sandbox';
|
||||
|
||||
function getCategories(fd, data) {
|
||||
const c = fd.color_picker || { r: 0, g: 0, b: 0, a: 1 };
|
||||
const fixedColor = [c.r, c.g, c.b, 255 * c.a];
|
||||
const colorFn = getScale(fd.color_scheme).toFunction();
|
||||
const categories = {};
|
||||
data.forEach((d) => {
|
||||
if (d.cat_color != null && !categories.hasOwnProperty(d.cat_color)) {
|
||||
let color;
|
||||
if (fd.dimension) {
|
||||
color = hexToRGB(getColorFromScheme(d.cat_color, fd.color_scheme), c.a * 255);
|
||||
color = hexToRGB(colorFn(d.cat_color), c.a * 255);
|
||||
} else {
|
||||
color = fixedColor;
|
||||
}
|
||||
@@ -98,10 +100,11 @@ export default class CategoricalDeckGLContainer extends React.PureComponent {
|
||||
}
|
||||
addColor(data, fd) {
|
||||
const c = fd.color_picker || { r: 0, g: 0, b: 0, a: 1 };
|
||||
const colorFn = getScale(fd.color_scheme).toFunction();
|
||||
return data.map((d) => {
|
||||
let color;
|
||||
if (fd.dimension) {
|
||||
color = hexToRGB(getColorFromScheme(d.cat_color, fd.color_scheme), c.a * 255);
|
||||
color = hexToRGB(colorFn(d.cat_color), c.a * 255);
|
||||
return { ...d, color };
|
||||
}
|
||||
return d;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import d3 from 'd3';
|
||||
import PropTypes from 'prop-types';
|
||||
import { hierarchy } from 'd3-hierarchy';
|
||||
import { getScale } from '../modules/CategoricalColorNamespace';
|
||||
import { d3TimeFormatPreset } from '../modules/utils';
|
||||
import { getColorFromScheme } from '../modules/colors';
|
||||
import './partition.css';
|
||||
|
||||
// Compute dx, dy, x, y for each node and
|
||||
@@ -97,6 +97,7 @@ function Icicle(element, props) {
|
||||
const hasTime = ['adv_anal', 'time_series'].indexOf(chartType) >= 0;
|
||||
const format = d3.format(numberFormat);
|
||||
const timeFormat = d3TimeFormatPreset(dateTimeFormat);
|
||||
const colorFn = getScale(colorScheme).toFunction();
|
||||
|
||||
div.selectAll('*').remove();
|
||||
const tooltip = div
|
||||
@@ -363,7 +364,7 @@ function Icicle(element, props) {
|
||||
// Apply color scheme
|
||||
g.selectAll('rect')
|
||||
.style('fill', (d) => {
|
||||
d.color = getColorFromScheme(d.name, colorScheme);
|
||||
d.color = colorFn(d.name);
|
||||
return d.color;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import d3 from 'd3';
|
||||
import PropTypes from 'prop-types';
|
||||
import nv from 'nvd3';
|
||||
import { getScale } from '../modules/CategoricalColorNamespace';
|
||||
import { d3TimeFormatPreset } from '../modules/utils';
|
||||
import { getColorFromScheme } from '../modules/colors';
|
||||
import './rose.css';
|
||||
|
||||
const propTypes = {
|
||||
@@ -62,6 +62,7 @@ function Rose(element, props) {
|
||||
const numGroups = datum[times[0]].length;
|
||||
const format = d3.format(numberFormat);
|
||||
const timeFormat = d3TimeFormatPreset(dateTimeFormat);
|
||||
const colorFn = getScale(colorScheme).toFunction();
|
||||
|
||||
d3.select('.nvtooltip').remove();
|
||||
div.selectAll('*').remove();
|
||||
@@ -70,7 +71,6 @@ function Rose(element, props) {
|
||||
const legend = nv.models.legend();
|
||||
const tooltip = nv.models.tooltip();
|
||||
const state = { disabled: datum[times[0]].map(() => false) };
|
||||
const color = name => getColorFromScheme(name, colorScheme);
|
||||
|
||||
const svg = div
|
||||
.append('svg')
|
||||
@@ -101,9 +101,9 @@ function Rose(element, props) {
|
||||
.map(v => ({
|
||||
key: v.name,
|
||||
value: v.value,
|
||||
color: color(v.name),
|
||||
color: colorFn(v.name),
|
||||
highlight: v.id === d.arcId,
|
||||
})) : [{ key: d.name, value: d.val, color: color(d.name) }];
|
||||
})) : [{ key: d.name, value: d.val, color: colorFn(d.name) }];
|
||||
return {
|
||||
key: 'Date',
|
||||
value: d.time,
|
||||
@@ -113,7 +113,7 @@ function Rose(element, props) {
|
||||
|
||||
legend
|
||||
.width(width)
|
||||
.color(d => getColorFromScheme(d.key, colorScheme));
|
||||
.color(d => colorFn(d.key));
|
||||
legendWrap
|
||||
.datum(legendData(datum))
|
||||
.call(legend);
|
||||
@@ -331,7 +331,7 @@ function Rose(element, props) {
|
||||
const arcs = ae
|
||||
.append('path')
|
||||
.attr('class', 'arc')
|
||||
.attr('fill', d => color(d.name))
|
||||
.attr('fill', d => colorFn(d.name))
|
||||
.attr('d', arc);
|
||||
|
||||
function mousemove() {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import d3 from 'd3';
|
||||
import PropTypes from 'prop-types';
|
||||
import { sankey as d3Sankey } from 'd3-sankey';
|
||||
import { getColorFromScheme } from '../modules/colors';
|
||||
import { getScale } from '../modules/CategoricalColorNamespace';
|
||||
import './sankey.css';
|
||||
|
||||
const propTypes = {
|
||||
@@ -49,6 +49,8 @@ function Sankey(element, props) {
|
||||
.attr('class', 'sankey-tooltip')
|
||||
.style('opacity', 0);
|
||||
|
||||
const colorFn = getScale(colorScheme).toFunction();
|
||||
|
||||
const sankey = d3Sankey()
|
||||
.nodeWidth(15)
|
||||
.nodePadding(10)
|
||||
@@ -153,7 +155,7 @@ function Sankey(element, props) {
|
||||
.attr('width', sankey.nodeWidth())
|
||||
.style('fill', function (d) {
|
||||
const name = d.name || 'N/A';
|
||||
d.color = getColorFromScheme(name.replace(/ .*/, ''), colorScheme);
|
||||
d.color = colorFn(name.replace(/ .*/, ''));
|
||||
return d.color;
|
||||
})
|
||||
.style('stroke', d => d3.rgb(d.color).darker(2))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import d3 from 'd3';
|
||||
import PropTypes from 'prop-types';
|
||||
import { getColorFromScheme } from '../modules/colors';
|
||||
import { getScale } from '../modules/CategoricalColorNamespace';
|
||||
import { wrapSvgText } from '../modules/utils';
|
||||
import './sunburst.css';
|
||||
|
||||
@@ -68,6 +68,8 @@ function Sunburst(element, props) {
|
||||
let arcs;
|
||||
let gMiddleText; // dom handles
|
||||
|
||||
const colorFn = getScale(colorScheme).toFunction();
|
||||
|
||||
// Helper + path gen functions
|
||||
const partition = d3.layout.partition()
|
||||
.size([2 * Math.PI, radius * radius])
|
||||
@@ -132,7 +134,7 @@ function Sunburst(element, props) {
|
||||
.attr('points', breadcrumbPoints)
|
||||
.style('fill', function (d) {
|
||||
return colorByCategory ?
|
||||
getColorFromScheme(d.name, colorScheme) :
|
||||
colorFn(d.name) :
|
||||
colorScale(d.m2 / d.m1);
|
||||
});
|
||||
|
||||
@@ -143,7 +145,7 @@ function Sunburst(element, props) {
|
||||
.style('fill', function (d) {
|
||||
// Make text white or black based on the lightness of the background
|
||||
const col = d3.hsl(colorByCategory ?
|
||||
getColorFromScheme(d.name, colorScheme) :
|
||||
colorFn(d.name) :
|
||||
colorScale(d.m2 / d.m1));
|
||||
return col.l < 0.5 ? 'white' : 'black';
|
||||
})
|
||||
@@ -377,7 +379,7 @@ function Sunburst(element, props) {
|
||||
.attr('d', arc)
|
||||
.attr('fill-rule', 'evenodd')
|
||||
.style('fill', d => colorByCategory
|
||||
? getColorFromScheme(d.name, colorScheme)
|
||||
? colorFn(d.name)
|
||||
: colorScale(d.m2 / d.m1))
|
||||
.style('opacity', 1)
|
||||
.on('mouseenter', mouseenter);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-shadow, no-param-reassign */
|
||||
import d3 from 'd3';
|
||||
import PropTypes from 'prop-types';
|
||||
import { getColorFromScheme } from '../modules/colors';
|
||||
import { getScale } from '../modules/CategoricalColorNamespace';
|
||||
import './treemap.css';
|
||||
|
||||
// Declare PropTypes for recursive data structures
|
||||
@@ -63,6 +63,7 @@ function treemap(element, props) {
|
||||
} = props;
|
||||
const div = d3.select(element);
|
||||
const formatNumber = d3.format(numberFormat);
|
||||
const colorFn = getScale(colorScheme).toFunction();
|
||||
|
||||
function draw(data, eltWidth, eltHeight) {
|
||||
const navBarHeight = 36;
|
||||
@@ -282,7 +283,7 @@ function treemap(element, props) {
|
||||
.text(d => formatNumber(d.value));
|
||||
t.call(text);
|
||||
g.selectAll('rect')
|
||||
.style('fill', d => getColorFromScheme(d.name, colorScheme));
|
||||
.style('fill', d => colorFn(d.name));
|
||||
|
||||
return g;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import d3 from 'd3';
|
||||
import PropTypes from 'prop-types';
|
||||
import cloudLayout from 'd3-cloud';
|
||||
import { getColorFromScheme } from '../../modules/colors';
|
||||
import { getScale } from '../../modules/CategoricalColorNamespace';
|
||||
|
||||
const ROTATION = {
|
||||
square: () => Math.floor((Math.random() * 2)) * 90,
|
||||
@@ -50,6 +50,8 @@ function wordCloud(element, props) {
|
||||
.fontWeight('bold')
|
||||
.fontSize(d => scale(d.size));
|
||||
|
||||
const colorFn = getScale(colorScheme).toFunction();
|
||||
|
||||
function draw(words) {
|
||||
chart.selectAll('*').remove();
|
||||
|
||||
@@ -67,7 +69,7 @@ function wordCloud(element, props) {
|
||||
.style('font-size', d => `${d.size}px`)
|
||||
.style('font-weight', 'bold')
|
||||
.style('font-family', 'Helvetica')
|
||||
.style('fill', d => getColorFromScheme(d.text, colorScheme))
|
||||
.style('fill', d => colorFn(d.text))
|
||||
.attr('text-anchor', 'middle')
|
||||
.attr('transform', d => `translate(${d.x}, ${d.y}) rotate(${d.rotate})`)
|
||||
.text(d => d.text);
|
||||
|
||||
Reference in New Issue
Block a user