diff --git a/superset/assets/spec/javascripts/explore/components/ColorPickerControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/ColorPickerControl_spec.jsx index 70f00aa6521..ca814ee7a90 100644 --- a/superset/assets/spec/javascripts/explore/components/ColorPickerControl_spec.jsx +++ b/superset/assets/spec/javascripts/explore/components/ColorPickerControl_spec.jsx @@ -7,7 +7,8 @@ import { SketchPicker } from 'react-color'; import ColorPickerControl from '../../../../src/explore/components/controls/ColorPickerControl'; import ControlHeader from '../../../../src/explore/components/ControlHeader'; -import { registerScheme } from '../../../../src/modules/ColorSchemeManager'; +import getCategoricalSchemeRegistry from '../../../../src/modules/colors/CategoricalSchemeRegistrySingleton'; +import CategoricalScheme from '../../../../src/modules/colors/CategoricalScheme'; const defaultProps = { value: { }, @@ -17,7 +18,11 @@ describe('ColorPickerControl', () => { let wrapper; let inst; beforeEach(() => { - registerScheme('test', ['red', 'green', 'blue']) + getCategoricalSchemeRegistry() + .registerValue('test', new CategoricalScheme({ + name: 'test', + colors: ['red', 'green', 'blue'], + })) .setDefaultSchemeName('test'); wrapper = shallow(); inst = wrapper.instance(); diff --git a/superset/assets/spec/javascripts/explore/components/ColorScheme_spec.jsx b/superset/assets/spec/javascripts/explore/components/ColorScheme_spec.jsx index 5cf2be2e7d8..995bb59dc8d 100644 --- a/superset/assets/spec/javascripts/explore/components/ColorScheme_spec.jsx +++ b/superset/assets/spec/javascripts/explore/components/ColorScheme_spec.jsx @@ -5,10 +5,10 @@ import { Creatable } from 'react-select'; import ColorSchemeControl from '../../../../src/explore/components/controls/ColorSchemeControl'; -import { getAllSchemes } from '../../../../src/modules/ColorSchemeManager'; +import getCategoricalSchemeRegistry from '../../../../src/modules/colors/CategoricalSchemeRegistrySingleton'; const defaultProps = { - options: Object.keys(getAllSchemes()).map(s => ([s, s])), + options: getCategoricalSchemeRegistry().keys().map(s => ([s, s])), }; describe('ColorSchemeControl', () => { diff --git a/superset/assets/spec/javascripts/modules/ColorSchemeManager_spec.js b/superset/assets/spec/javascripts/modules/ColorSchemeManager_spec.js deleted file mode 100644 index 2f3fe33d798..00000000000 --- a/superset/assets/spec/javascripts/modules/ColorSchemeManager_spec.js +++ /dev/null @@ -1,139 +0,0 @@ -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(typeof ColorSchemeManager).not.toBe('Function'); - }); - describe('static getInstance()', () => { - it('returns a singleton instance', () => { - const m1 = getInstance(); - const m2 = getInstance(); - expect(m1).toBeDefined(); - expect(m1).toBe(m2); - }); - }); - describe('.getScheme()', () => { - it('.getScheme() returns default color scheme', () => { - const scheme = getInstance().getScheme(); - expect(scheme).toEqual(['red', 'green', 'blue']); - }); - it('.getScheme(name) returns color scheme with specified name', () => { - const scheme = getInstance().getScheme('test2'); - expect(scheme).toEqual(['orange', 'yellow', 'pink']); - }); - }); - describe('.getAllSchemes()', () => { - it('returns all registered schemes', () => { - const schemes = getInstance().getAllSchemes(); - expect(schemes).toEqual({ - test: ['red', 'green', 'blue'], - test2: ['orange', 'yellow', 'pink'], - }); - }); - }); - describe('.getDefaultSchemeName()', () => { - it('returns default scheme name', () => { - const name = getInstance().getDefaultSchemeName(); - expect(name).toBe('test'); - }); - }); - describe('.setDefaultSchemeName()', () => { - it('set default scheme name', () => { - getInstance().setDefaultSchemeName('test2'); - const name = getInstance().getDefaultSchemeName(); - expect(name).toBe('test2'); - getInstance().setDefaultSchemeName('test'); - }); - it('returns the ColorSchemeManager instance', () => { - const instance = getInstance().setDefaultSchemeName('test'); - expect(instance).toBe(getInstance()); - }); - }); - describe('.registerScheme(name, colors)', () => { - it('sets schemename and color', () => { - getInstance().registerScheme('test3', ['cyan', 'magenta']); - const scheme = getInstance().getScheme('test3'); - expect(scheme).toEqual(['cyan', 'magenta']); - }); - it('returns the ColorSchemeManager instance', () => { - const instance = getInstance().registerScheme('test3', ['cyan', 'magenta']); - expect(instance).toBe(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).toEqual(['cyan', 'magenta']); - const scheme2 = getInstance().getScheme('test5'); - expect(scheme2).toEqual(['brown', 'purple']); - }); - it('returns the ColorSchemeManager instance', () => { - const instance = getInstance().registerMultipleSchemes({ - test4: ['cyan', 'magenta'], - test5: ['brown', 'purple'], - }); - expect(instance).toBe(getInstance()); - }); - }); - describe('static getScheme()', () => { - it('is equivalent to getInstance().getScheme()', () => { - expect(getInstance().getScheme()).toBe(getScheme()); - }); - }); - describe('static getAllSchemes()', () => { - it('is equivalent to getInstance().getAllSchemes()', () => { - expect(getInstance().getAllSchemes()).toBe(getAllSchemes()); - }); - }); - describe('static getDefaultSchemeName()', () => { - it('is equivalent to getInstance().getDefaultSchemeName()', () => { - expect(getInstance().getDefaultSchemeName()).toBe(getDefaultSchemeName()); - }); - }); - describe('static setDefaultSchemeName()', () => { - it('is equivalent to getInstance().setDefaultSchemeName()', () => { - setDefaultSchemeName('test2'); - const name = getInstance().getDefaultSchemeName(); - expect(name).toBe('test2'); - setDefaultSchemeName('test'); - }); - }); - describe('static registerScheme()', () => { - it('is equivalent to getInstance().registerScheme()', () => { - registerScheme('test3', ['cyan', 'magenta']); - const scheme = getInstance().getScheme('test3'); - expect(scheme).toEqual(['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).toEqual(['cyan', 'magenta']); - const scheme2 = getInstance().getScheme('test5'); - expect(scheme2).toEqual(['brown', 'purple']); - }); - }); -}); diff --git a/superset/assets/spec/javascripts/modules/Registry_spec.js b/superset/assets/spec/javascripts/modules/Registry_spec.js index 5eb57916377..111a6145168 100644 --- a/superset/assets/spec/javascripts/modules/Registry_spec.js +++ b/superset/assets/spec/javascripts/modules/Registry_spec.js @@ -17,6 +17,20 @@ describe('Registry', () => { }); }); + describe('.clear()', () => { + it('clears all registered items', () => { + const registry = new Registry(); + registry.registerValue('a', 'testValue'); + registry.clear(); + expect(Object.keys(registry.items)).toHaveLength(0); + expect(Object.keys(registry.promises)).toHaveLength(0); + }); + it('returns the registry itself', () => { + const registry = new Registry(); + expect(registry.clear()).toBe(registry); + }); + }); + describe('.has(key)', () => { it('returns true if an item with the given key exists', () => { const registry = new Registry(); @@ -134,6 +148,34 @@ describe('Registry', () => { ); }); + describe('.getMap()', () => { + it('returns key-value map as plain object', () => { + const registry = new Registry(); + registry.registerValue('a', 'cat'); + registry.registerLoader('b', () => 'dog'); + expect(registry.getMap()).toEqual({ + a: 'cat', + b: 'dog', + }); + }); + }); + + describe('.getMapAsPromise()', () => { + it('returns a promise of key-value map', () => { + const registry = new Registry(); + registry.registerValue('a', 'test1'); + registry.registerLoader('b', () => 'test2'); + registry.registerLoader('c', () => Promise.resolve('test3')); + return registry.getMapAsPromise().then((map) => { + expect(map).toEqual({ + a: 'test1', + b: 'test2', + c: 'test3', + }); + }); + }); + }); + describe('.keys()', () => { it('returns an array of keys', () => { const registry = new Registry(); @@ -143,6 +185,34 @@ describe('Registry', () => { }); }); + describe('.values()', () => { + it('returns an array of values', () => { + const registry = new Registry(); + registry.registerValue('a', 'test1'); + registry.registerLoader('b', () => 'test2'); + expect(registry.values()).toEqual([ + 'test1', + 'test2', + ]); + }); + }); + + describe('.valuesAsPromise()', () => { + it('returns a Promise of an array { key, value }', () => { + const registry = new Registry(); + registry.registerValue('a', 'test1'); + registry.registerLoader('b', () => 'test2'); + registry.registerLoader('c', () => Promise.resolve('test3')); + return registry.valuesAsPromise().then((entries) => { + expect(entries).toEqual([ + 'test1', + 'test2', + 'test3', + ]); + }); + }); + }); + describe('.entries()', () => { it('returns an array of { key, value }', () => { const registry = new Registry(); diff --git a/superset/assets/spec/javascripts/modules/CategoricalColorNameSpace_spec.js b/superset/assets/spec/javascripts/modules/colors/CategoricalColorNameSpace_spec.js similarity index 90% rename from superset/assets/spec/javascripts/modules/CategoricalColorNameSpace_spec.js rename to superset/assets/spec/javascripts/modules/colors/CategoricalColorNameSpace_spec.js index 0be4996f7f2..8ff952ac5c7 100644 --- a/superset/assets/spec/javascripts/modules/CategoricalColorNameSpace_spec.js +++ b/superset/assets/spec/javascripts/modules/colors/CategoricalColorNameSpace_spec.js @@ -3,13 +3,21 @@ import CategoricalColorNamespace, { getScale, getColor, DEFAULT_NAMESPACE, -} from '../../../src/modules/CategoricalColorNamespace'; -import { registerScheme } from '../../../src/modules/ColorSchemeManager'; +} from '../../../../src/modules/colors/CategoricalColorNamespace'; +import getCategoricalSchemeRegistry from '../../../../src/modules/colors/CategoricalSchemeRegistrySingleton'; +import CategoricalScheme from '../../../../src/modules/colors/CategoricalScheme'; describe('CategoricalColorNamespace', () => { beforeAll(() => { - registerScheme('testColors', ['red', 'green', 'blue']); - registerScheme('testColors2', ['red', 'green', 'blue']); + getCategoricalSchemeRegistry() + .registerValue('testColors', new CategoricalScheme({ + name: 'testColors', + colors: ['red', 'green', 'blue'], + })) + .registerValue('testColors2', new CategoricalScheme({ + name: 'testColors2', + colors: ['red', 'green', 'blue'], + })); }); it('The class constructor cannot be accessed directly', () => { expect(typeof CategoricalColorNamespace).not.toBe('Function'); diff --git a/superset/assets/spec/javascripts/modules/CategoricalColorScale_spec.js b/superset/assets/spec/javascripts/modules/colors/CategoricalColorScale_spec.js similarity index 97% rename from superset/assets/spec/javascripts/modules/CategoricalColorScale_spec.js rename to superset/assets/spec/javascripts/modules/colors/CategoricalColorScale_spec.js index 5cbf6e67282..32a455d71bf 100644 --- a/superset/assets/spec/javascripts/modules/CategoricalColorScale_spec.js +++ b/superset/assets/spec/javascripts/modules/colors/CategoricalColorScale_spec.js @@ -1,4 +1,4 @@ -import CategoricalColorScale from '../../../src/modules/CategoricalColorScale'; +import CategoricalColorScale from '../../../../src/modules/colors/CategoricalColorScale'; describe('CategoricalColorScale', () => { it('exists', () => { diff --git a/superset/assets/spec/javascripts/modules/colors/ColorSchemeRegistry_spec.js b/superset/assets/spec/javascripts/modules/colors/ColorSchemeRegistry_spec.js new file mode 100644 index 00000000000..94f6c895170 --- /dev/null +++ b/superset/assets/spec/javascripts/modules/colors/ColorSchemeRegistry_spec.js @@ -0,0 +1,64 @@ +import ColorSchemeRegistry from '../../../../src/modules/colors/ColorSchemeRegistry'; +import CategoricalScheme from '../../../../src/modules/colors/CategoricalScheme'; + +describe('ColorSchemeRegistry', () => { + const registry = new ColorSchemeRegistry(); + const SCHEME1 = new CategoricalScheme({ + name: 'test', + colors: ['red', 'green', 'blue'], + }); + const SCHEME2 = new CategoricalScheme({ + name: 'test2', + colors: ['orange', 'yellow', 'pink'], + }); + const SCHEME3 = new CategoricalScheme({ + name: 'test3', + colors: ['cyan', 'magenta'], + }); + + beforeEach(() => { + registry.clear(); + registry.registerValue('test', SCHEME1); + registry.registerValue('test2', SCHEME2); + registry.setDefaultSchemeName('test'); + }); + describe('.get()', () => { + it('.get() returns default color scheme', () => { + const scheme = registry.get(); + expect(scheme).toEqual(SCHEME1); + }); + it('.get(name) returns color scheme with specified name', () => { + const scheme = registry.get('test2'); + expect(scheme).toEqual(SCHEME2); + }); + }); + describe('.getDefaultSchemeName()', () => { + it('returns default scheme name', () => { + const name = registry.getDefaultSchemeName(); + expect(name).toBe('test'); + }); + }); + describe('.setDefaultSchemeName()', () => { + it('set default scheme name', () => { + registry.setDefaultSchemeName('test2'); + const name = registry.getDefaultSchemeName(); + expect(name).toBe('test2'); + registry.setDefaultSchemeName('test'); + }); + it('returns the ColorSchemeRegistry instance', () => { + const instance = registry.setDefaultSchemeName('test'); + expect(instance).toBe(registry); + }); + }); + describe('.registerValue(name, colors)', () => { + it('sets schemename and color', () => { + registry.registerValue('test3', SCHEME3); + const scheme = registry.get('test3'); + expect(scheme).toEqual(SCHEME3); + }); + it('returns the ColorSchemeRegistry instance', () => { + const instance = registry.registerValue('test3', SCHEME3); + expect(instance).toBe(registry); + }); + }); +}); diff --git a/superset/assets/src/common.js b/superset/assets/src/common.js index f479d229c15..f4f66211580 100644 --- a/superset/assets/src/common.js +++ b/superset/assets/src/common.js @@ -2,12 +2,8 @@ import $ from 'jquery'; import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'; import { SupersetClient } from '@superset-ui/core'; - -import airbnb from './modules/colorSchemes/airbnb'; -import categoricalSchemes from './modules/colorSchemes/categorical'; -import lyft from './modules/colorSchemes/lyft'; -import { getInstance } from './modules/ColorSchemeManager'; import { toggleCheckbox } from './modules/utils'; +import setupColors from './setup/setupColors'; $(document).ready(function () { $(':checkbox[data-checkbox-api-prefix]').change(function () { @@ -28,12 +24,7 @@ $(document).ready(function () { }); }); -// Register color schemes -getInstance() - .registerScheme('bnbColors', airbnb.bnbColors) - .registerMultipleSchemes(categoricalSchemes) - .registerScheme('lyftColors', lyft.lyftColors) - .setDefaultSchemeName('bnbColors'); +setupColors(); export function appSetup() { // A set of hacks to allow apps to run within a FAB template diff --git a/superset/assets/src/dashboard/reducers/getInitialState.js b/superset/assets/src/dashboard/reducers/getInitialState.js index 523db9f251c..c3b9dfdd78c 100644 --- a/superset/assets/src/dashboard/reducers/getInitialState.js +++ b/superset/assets/src/dashboard/reducers/getInitialState.js @@ -18,7 +18,7 @@ import { CHART_TYPE, ROW_TYPE, } from '../util/componentTypes'; -import { getScale } from '../../modules/CategoricalColorNamespace'; +import { getScale } from '../../modules/colors/CategoricalColorNamespace'; export default function(bootstrapData) { const { user_id, datasources, common, editMode } = bootstrapData; diff --git a/superset/assets/src/explore/components/controls/AnnotationLayer.jsx b/superset/assets/src/explore/components/controls/AnnotationLayer.jsx index cbf17a11bfa..5fd580b8057 100644 --- a/superset/assets/src/explore/components/controls/AnnotationLayer.jsx +++ b/superset/assets/src/explore/components/controls/AnnotationLayer.jsx @@ -25,7 +25,7 @@ import { nonEmpty } from '../../validators'; import vizTypes from '../../visTypes'; import { t } from '../../../locales'; -import { getScheme } from '../../../modules/ColorSchemeManager'; +import getCategoricalSchemeRegistry from '../../../modules/colors/CategoricalSchemeRegistrySingleton'; const AUTOMATIC_COLOR = ''; @@ -484,7 +484,10 @@ export default class AnnotationLayer extends React.PureComponent { renderDisplayConfiguration() { const { color, opacity, style, width, showMarkers, hideLine, annotationType } = this.state; - const colorScheme = [...getScheme(this.props.colorScheme)]; + const colorScheme = getCategoricalSchemeRegistry() + .get(this.props.colorScheme) + .colors + .concat(); if ( color && color !== AUTOMATIC_COLOR && diff --git a/superset/assets/src/explore/components/controls/ColorPickerControl.jsx b/superset/assets/src/explore/components/controls/ColorPickerControl.jsx index 55d7ce48838..2c631c11ced 100644 --- a/superset/assets/src/explore/components/controls/ColorPickerControl.jsx +++ b/superset/assets/src/explore/components/controls/ColorPickerControl.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { OverlayTrigger, Popover } from 'react-bootstrap'; import { SketchPicker } from 'react-color'; import ControlHeader from '../ControlHeader'; -import { getScheme } from '../../../modules/ColorSchemeManager'; +import getCategoricalSchemeRegistry from '../../../modules/colors/CategoricalSchemeRegistrySingleton'; const propTypes = { onChange: PropTypes.func, @@ -53,14 +53,19 @@ export default class ColorPickerControl extends React.Component { this.props.onChange(col.rgb); } renderPopover() { + const presetColors = getCategoricalSchemeRegistry() + .get() + .colors + .filter((s, i) => i < 7); return ( i < 7)} + presetColors={presetColors} /> - ); + + ); } render() { const c = this.props.value || { r: 0, g: 0, b: 0, a: 0 }; diff --git a/superset/assets/src/explore/components/controls/ColorSchemeControl.jsx b/superset/assets/src/explore/components/controls/ColorSchemeControl.jsx index f09125d2043..5d9ad4685d1 100644 --- a/superset/assets/src/explore/components/controls/ColorSchemeControl.jsx +++ b/superset/assets/src/explore/components/controls/ColorSchemeControl.jsx @@ -49,7 +49,7 @@ export default class ColorSchemeControl extends React.PureComponent { renderOption(key) { const { schemes } = this.props; const schemeLookup = isFunction(schemes) ? schemes() : schemes; - const currentScheme = schemeLookup[key.value || defaultProps.value]; + const currentScheme = schemeLookup[key.value || defaultProps.value].colors; let colors = currentScheme; if (this.props.isLinear) { diff --git a/superset/assets/src/explore/controls.jsx b/superset/assets/src/explore/controls.jsx index 67f21ac6675..05e4f54eb06 100644 --- a/superset/assets/src/explore/controls.jsx +++ b/superset/assets/src/explore/controls.jsx @@ -50,8 +50,11 @@ 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'; +import getCategoricalSchemeRegistry from '../modules/colors/CategoricalSchemeRegistrySingleton'; +import getSequentialSchemeRegistry from '../modules/colors/SequentialSchemeRegistrySingleton'; + +const categoricalSchemeRegistry = getCategoricalSchemeRegistry(); +const sequentialSchemeRegistry = getSequentialSchemeRegistry(); const D3_FORMAT_DOCS = 'D3 format syntax: https://github.com/d3/d3-format'; @@ -323,58 +326,14 @@ export const controls = { linear_color_scheme: { type: 'ColorSchemeControl', label: t('Linear Color Scheme'), - choices: [ - ['fire', 'fire'], - ['white_black', 'white/black'], - ['black_white', 'black/white'], - ['dark_blue', 'light/dark blue'], - ['pink_grey', 'pink/white/grey'], - ['greens', 'greens'], - ['purples', 'purples'], - ['oranges', 'oranges'], - ['blue_white_yellow', 'blue/white/yellow'], - ['red_yellow_blue', 'red/yellowish/blue'], - ['brown_white_green', 'brown/white/green'], - ['purple_white_green', 'purple/white/green'], - ['schemeBrBG', 'brown/green'], - ['schemePRGn', 'purple/green'], - ['schemePiYG', 'pink/green'], - ['schemePuOr', 'purple/orange'], - ['schemeRdBu', 'red/blue'], - ['schemeRdGy', 'red/gray/black'], - ['schemeRdYlBu', 'red/yellow/blue'], - ['schemeRdYlGn', 'red/yellow/green'], - ['schemeSpectral', 'rainbow'], - ['schemeBlues', 'd3/blues'], - ['schemeGreens', 'd3/greens'], - ['schemeGrays', 'd3/grays'], - ['schemeOranges', 'd3/oranges'], - ['schemePurples', 'd3/purples'], - ['schemeReds', 'd3/reds'], - ['schemeViridis', 'd3/purple/blue/green/yellow'], - ['schemeInferno', 'd3/purple/red/orange/yellow'], - ['schemeMagma', 'd3/purple/pink/peach'], - ['schemeWarm', 'd3/warm/purple/pink/yellow/green'], - ['schemeCool', 'd3/cool/blue/green'], - ['schemeCubehelixDefault', 'd3/black/green/brown/pink/blue'], - ['schemeBuGn', 'd3/blue/green'], - ['schemeBuPu', 'd3/blue/purple'], - ['schemeGnBu', 'd3/green/blue'], - ['schemeOrRd', 'd3/orange/red'], - ['schemePuBuGn', 'd3/purple/blue/green'], - ['schemePuBu', 'd3/purple/blue'], - ['schemePuRd', 'd3/purple/red'], - ['schemeRdPu', 'd3/red/purple'], - ['schemeYlGnBu', 'd3/yellow/green/blue'], - ['schemeYlGn', 'd3/yellow/green'], - ['schemeYlOrBr', 'd3/yellow/brown'], - ['schemeYlOrRd', 'd3/yellow/orange/red'], - ], + choices: () => sequentialSchemeRegistry + .values() + .map(value => [value.name, value.label]), default: 'blue_white_yellow', clearable: false, description: '', renderTrigger: true, - schemes: sequentialSchemes, + schemes: () => sequentialSchemeRegistry.getMap(), isLinear: true, }, @@ -1965,9 +1924,9 @@ export const controls = { label: t('Color Scheme'), default: 'bnbColors', renderTrigger: true, - choices: () => Object.keys(getAllSchemes()).map(s => ([s, s])), + choices: () => categoricalSchemeRegistry.keys().map(s => ([s, s])), description: t('The color scheme for rendering chart'), - schemes: () => getAllSchemes(), + schemes: () => categoricalSchemeRegistry.getMap(), }, significance_level: { diff --git a/superset/assets/src/modules/ColorSchemeManager.js b/superset/assets/src/modules/ColorSchemeManager.js deleted file mode 100644 index 9d21d2628e2..00000000000 --- a/superset/assets/src/modules/ColorSchemeManager.js +++ /dev/null @@ -1,86 +0,0 @@ -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, -}; diff --git a/superset/assets/src/modules/Registry.js b/superset/assets/src/modules/Registry.js index f39a0c5d99b..3b9ef442464 100644 --- a/superset/assets/src/modules/Registry.js +++ b/superset/assets/src/modules/Registry.js @@ -5,6 +5,12 @@ export default class Registry { this.promises = {}; } + clear() { + this.items = {}; + this.promises = {}; + return this; + } + has(key) { const item = this.items[key]; return item !== null && item !== undefined; @@ -44,10 +50,36 @@ export default class Registry { return Promise.reject(`Item with key "${key}" is not registered.`); } + getMap() { + return this.keys().reduce((prev, key) => { + const map = prev; + map[key] = this.get(key); + return map; + }, {}); + } + + getMapAsPromise() { + const keys = this.keys(); + return Promise.all(keys.map(key => this.getAsPromise(key))) + .then(values => values.reduce((prev, value, i) => { + const map = prev; + map[keys[i]] = value; + return map; + }, {})); + } + keys() { return Object.keys(this.items); } + values() { + return this.keys().map(key => this.get(key)); + } + + valuesAsPromise() { + return Promise.all(this.keys().map(key => this.getAsPromise(key))); + } + entries() { return this.keys().map(key => ({ key, diff --git a/superset/assets/src/modules/colorSchemes/airbnb.js b/superset/assets/src/modules/colorSchemes/airbnb.js deleted file mode 100644 index d26a923e4d6..00000000000 --- a/superset/assets/src/modules/colorSchemes/airbnb.js +++ /dev/null @@ -1,25 +0,0 @@ -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', - ], -}; diff --git a/superset/assets/src/modules/colorSchemes/categorical.js b/superset/assets/src/modules/colorSchemes/categorical.js deleted file mode 100644 index 946d14a187b..00000000000 --- a/superset/assets/src/modules/colorSchemes/categorical.js +++ /dev/null @@ -1,42 +0,0 @@ -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', - ], -}; diff --git a/superset/assets/src/modules/colorSchemes/lyft.js b/superset/assets/src/modules/colorSchemes/lyft.js deleted file mode 100644 index cd9412163e9..00000000000 --- a/superset/assets/src/modules/colorSchemes/lyft.js +++ /dev/null @@ -1,14 +0,0 @@ -export default { - lyftColors: [ - '#EA0B8C', - '#6C838E', - '#29ABE2', - '#33D9C1', - '#9DACB9', - '#7560AA', - '#2D5584', - '#831C4A', - '#333D47', - '#AC2077', - ], -}; diff --git a/superset/assets/src/modules/colorSchemes/sequential.js b/superset/assets/src/modules/colorSchemes/sequential.js deleted file mode 100644 index 6970ed411cb..00000000000 --- a/superset/assets/src/modules/colorSchemes/sequential.js +++ /dev/null @@ -1,433 +0,0 @@ -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', - ], -}; diff --git a/superset/assets/src/modules/colors.js b/superset/assets/src/modules/colors.js index 8e86d46eb5c..19cd351da11 100644 --- a/superset/assets/src/modules/colors.js +++ b/superset/assets/src/modules/colors.js @@ -1,5 +1,5 @@ import d3 from 'd3'; -import sequentialSchemes from './colorSchemes/sequential'; +import getSequentialSchemeRegistry from './colors/SequentialSchemeRegistrySingleton'; export const BRAND_COLOR = '#00A699'; export const PRIMARY_COLOR = { r: 0, g: 122, b: 135, a: 1 }; @@ -18,7 +18,7 @@ export const colorScalerFactory = function (colors, data, accessor, extents, out // Returns a linear scaler our of an array of color if (!Array.isArray(colors)) { /* eslint no-param-reassign: 0 */ - colors = sequentialSchemes[colors]; + colors = getSequentialSchemeRegistry().get(colors).colors; } let ext = [0, 1]; if (extents) { diff --git a/superset/assets/src/modules/CategoricalColorNamespace.js b/superset/assets/src/modules/colors/CategoricalColorNamespace.js similarity index 85% rename from superset/assets/src/modules/CategoricalColorNamespace.js rename to superset/assets/src/modules/colors/CategoricalColorNamespace.js index d022bb25fbd..ea5ea935b2b 100644 --- a/superset/assets/src/modules/CategoricalColorNamespace.js +++ b/superset/assets/src/modules/colors/CategoricalColorNamespace.js @@ -1,5 +1,5 @@ import CategoricalColorScale from './CategoricalColorScale'; -import { getScheme, getDefaultSchemeName } from './ColorSchemeManager'; +import getCategoricalSchemeRegistry from './CategoricalSchemeRegistrySingleton'; class CategoricalColorNamespace { constructor(name) { @@ -9,13 +9,13 @@ class CategoricalColorNamespace { } getScale(schemeName) { - const name = schemeName || getDefaultSchemeName(); + const name = schemeName || getCategoricalSchemeRegistry().getDefaultSchemeName(); const scale = this.scales[name]; if (scale) { return scale; } const newScale = new CategoricalColorScale( - getScheme(name), + getCategoricalSchemeRegistry().get(name).colors, this.forcedItems, ); this.scales[name] = newScale; diff --git a/superset/assets/src/modules/CategoricalColorScale.js b/superset/assets/src/modules/colors/CategoricalColorScale.js similarity index 96% rename from superset/assets/src/modules/CategoricalColorScale.js rename to superset/assets/src/modules/colors/CategoricalColorScale.js index eab70d21842..69d8ab2a730 100644 --- a/superset/assets/src/modules/CategoricalColorScale.js +++ b/superset/assets/src/modules/colors/CategoricalColorScale.js @@ -1,4 +1,4 @@ -import { TIME_SHIFT_PATTERN } from '../utils/common'; +import { TIME_SHIFT_PATTERN } from '../../utils/common'; export function cleanValue(value) { // for superset series that should have the same color diff --git a/superset/assets/src/modules/colors/CategoricalScheme.js b/superset/assets/src/modules/colors/CategoricalScheme.js new file mode 100644 index 00000000000..c70ee58415e --- /dev/null +++ b/superset/assets/src/modules/colors/CategoricalScheme.js @@ -0,0 +1,3 @@ +import ColorScheme from './ColorScheme'; + +export default class CategoricalScheme extends ColorScheme {} diff --git a/superset/assets/src/modules/colors/CategoricalSchemeRegistrySingleton.js b/superset/assets/src/modules/colors/CategoricalSchemeRegistrySingleton.js new file mode 100644 index 00000000000..54171802da4 --- /dev/null +++ b/superset/assets/src/modules/colors/CategoricalSchemeRegistrySingleton.js @@ -0,0 +1,8 @@ +import ColorSchemeRegistry from './ColorSchemeRegistry'; +import makeSingleton from '../../utils/makeSingleton'; + +class CategoricalSchemeRegistry extends ColorSchemeRegistry {} + +const getInstance = makeSingleton(CategoricalSchemeRegistry); + +export default getInstance; diff --git a/superset/assets/src/modules/colors/ColorScheme.js b/superset/assets/src/modules/colors/ColorScheme.js new file mode 100644 index 00000000000..91936a077c4 --- /dev/null +++ b/superset/assets/src/modules/colors/ColorScheme.js @@ -0,0 +1,15 @@ +import isRequired from '../../utils/isRequired'; + +export default class ColorScheme { + constructor({ + name = isRequired('name'), + label, + colors = isRequired('colors'), + description = '', + }) { + this.name = name; + this.label = label || name; + this.colors = colors; + this.description = description; + } +} diff --git a/superset/assets/src/modules/colors/ColorSchemeRegistry.js b/superset/assets/src/modules/colors/ColorSchemeRegistry.js new file mode 100644 index 00000000000..59d798de6c4 --- /dev/null +++ b/superset/assets/src/modules/colors/ColorSchemeRegistry.js @@ -0,0 +1,36 @@ +import Registry from '../Registry'; + +class ColorSchemeRegistry extends Registry { + getDefaultSchemeName() { + return this.defaultSchemeName; + } + + setDefaultSchemeName(schemeName) { + this.defaultSchemeName = schemeName; + return this; + } + + get(schemeName) { + return super.get(schemeName || this.defaultSchemeName); + } + + registerValue(schemeName, colors) { + super.registerValue(schemeName, colors); + // If there is no default, set as default + if (!this.defaultSchemeName) { + this.defaultSchemeName = schemeName; + } + return this; + } + + registerLoader(schemeName, loader) { + super.registerLoader(schemeName, loader); + // If there is no default, set as default + if (!this.defaultSchemeName) { + this.defaultSchemeName = schemeName; + } + return this; + } +} + +export default ColorSchemeRegistry; diff --git a/superset/assets/src/modules/colors/SequentialScheme.js b/superset/assets/src/modules/colors/SequentialScheme.js new file mode 100644 index 00000000000..27ad849ec07 --- /dev/null +++ b/superset/assets/src/modules/colors/SequentialScheme.js @@ -0,0 +1,9 @@ +import ColorScheme from './ColorScheme'; + +export default class SequentialScheme extends ColorScheme { + constructor(input) { + super(input); + const { isDiverging = false } = input; + this.isDiverging = isDiverging; + } +} diff --git a/superset/assets/src/modules/colors/SequentialSchemeRegistrySingleton.js b/superset/assets/src/modules/colors/SequentialSchemeRegistrySingleton.js new file mode 100644 index 00000000000..6ba52023060 --- /dev/null +++ b/superset/assets/src/modules/colors/SequentialSchemeRegistrySingleton.js @@ -0,0 +1,8 @@ +import ColorSchemeRegistry from './ColorSchemeRegistry'; +import makeSingleton from '../../utils/makeSingleton'; + +class SequentialSchemeRegistry extends ColorSchemeRegistry {} + +const getInstance = makeSingleton(SequentialSchemeRegistry); + +export default getInstance; diff --git a/superset/assets/src/modules/colors/colorSchemes/categorical/airbnb.js b/superset/assets/src/modules/colors/colorSchemes/categorical/airbnb.js new file mode 100644 index 00000000000..20476244532 --- /dev/null +++ b/superset/assets/src/modules/colors/colorSchemes/categorical/airbnb.js @@ -0,0 +1,32 @@ +import CategoricalScheme from '../../CategoricalScheme'; + +const schemes = [ + { + name: 'bnbColors', + colors: [ + '#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', + ], + }, +].map(s => new CategoricalScheme(s)); + +export default schemes; diff --git a/superset/assets/src/modules/colors/colorSchemes/categorical/d3.js b/superset/assets/src/modules/colors/colorSchemes/categorical/d3.js new file mode 100644 index 00000000000..deac97a1128 --- /dev/null +++ b/superset/assets/src/modules/colors/colorSchemes/categorical/d3.js @@ -0,0 +1,23 @@ +import d3 from 'd3'; +import CategoricalScheme from '../../CategoricalScheme'; + +const schemes = [ + { + name: 'd3Category10', + colors: d3.scale.category10().range(), + }, + { + name: 'd3Category20', + colors: d3.scale.category20().range(), + }, + { + name: 'd3Category20b', + colors: d3.scale.category20b().range(), + }, + { + name: 'd3Category20c', + colors: d3.scale.category20c().range(), + }, +].map(s => new CategoricalScheme(s)); + +export default schemes; diff --git a/superset/assets/src/modules/colors/colorSchemes/categorical/google.js b/superset/assets/src/modules/colors/colorSchemes/categorical/google.js new file mode 100644 index 00000000000..b4195db2b84 --- /dev/null +++ b/superset/assets/src/modules/colors/colorSchemes/categorical/google.js @@ -0,0 +1,46 @@ +import CategoricalScheme from '../../CategoricalScheme'; + +const schemes = [ + { + name: 'googleCategory10c', + colors: [ + '#3366cc', + '#dc3912', + '#ff9900', + '#109618', + '#990099', + '#0099c6', + '#dd4477', + '#66aa00', + '#b82e2e', + '#316395', + ], + }, + { + name: 'googleCategory20c', + colors: [ + '#3366cc', + '#dc3912', + '#ff9900', + '#109618', + '#990099', + '#0099c6', + '#dd4477', + '#66aa00', + '#b82e2e', + '#316395', + '#994499', + '#22aa99', + '#aaaa11', + '#6633cc', + '#e67300', + '#8b0707', + '#651067', + '#329262', + '#5574a6', + '#3b3eac', + ], + }, +].map(s => new CategoricalScheme(s)); + +export default schemes; diff --git a/superset/assets/src/modules/colors/colorSchemes/categorical/lyft.js b/superset/assets/src/modules/colors/colorSchemes/categorical/lyft.js new file mode 100644 index 00000000000..cb81cbb89e0 --- /dev/null +++ b/superset/assets/src/modules/colors/colorSchemes/categorical/lyft.js @@ -0,0 +1,21 @@ +import CategoricalScheme from '../../CategoricalScheme'; + +const schemes = [ + { + name: 'lyftColors', + colors: [ + '#EA0B8C', + '#6C838E', + '#29ABE2', + '#33D9C1', + '#9DACB9', + '#7560AA', + '#2D5584', + '#831C4A', + '#333D47', + '#AC2077', + ], + }, +].map(s => new CategoricalScheme(s)); + +export default schemes; diff --git a/superset/assets/src/modules/colors/colorSchemes/sequential/common.js b/superset/assets/src/modules/colors/colorSchemes/sequential/common.js new file mode 100644 index 00000000000..b5c4a24bf0b --- /dev/null +++ b/superset/assets/src/modules/colors/colorSchemes/sequential/common.js @@ -0,0 +1,121 @@ +import SequentialScheme from '../../SequentialScheme'; + +const schemes = [ + { + name: 'blue_white_yellow', + label: 'blue/white/yellow', + colors: [ + '#00d1c1', + 'white', + '#ffb400', + ], + }, + { + name: 'fire', + colors: [ + 'white', + 'yellow', + 'red', + 'black', + ], + }, + { + name: 'white_black', + label: 'white/black', + colors: [ + 'white', + 'black', + ], + }, + { + name: 'black_white', + label: 'black/white', + colors: [ + 'black', + 'white', + ], + }, + { + name: 'dark_blue', + label: 'dark blues', + colors: [ + '#EBF5F8', + '#6BB1CC', + '#357E9B', + '#1B4150', + '#092935', + ], + }, + { + name: 'pink_grey', + label: 'pink/grey', + colors: [ + '#E70B81', + '#FAFAFA', + '#666666', + ], + isDiverging: true, + }, + { + name: 'greens', + colors: [ + '#ffffcc', + '#78c679', + '#006837', + ], + }, + { + name: 'purples', + colors: [ + '#f2f0f7', + '#9e9ac8', + '#54278f', + ], + }, + { + name: 'oranges', + colors: [ + '#fef0d9', + '#fc8d59', + '#b30000', + ], + }, + { + name: 'red_yellow_blue', + label: 'red/yellow/blue', + colors: [ + '#d7191c', + '#fdae61', + '#ffffbf', + '#abd9e9', + '#2c7bb6', + ], + isDiverging: true, + }, + { + name: 'brown_white_green', + label: 'brown/white/green', + colors: [ + '#a6611a', + '#dfc27d', + '#f5f5f5', + '#80cdc1', + '#018571', + ], + isDiverging: true, + }, + { + name: 'purple_white_green', + label: 'purple/white/green', + colors: [ + '#7b3294', + '#c2a5cf', + '#f7f7f7', + '#a6dba0', + '#008837', + ], + isDiverging: true, + }, +].map(s => new SequentialScheme(s)); + +export default schemes; diff --git a/superset/assets/src/modules/colors/colorSchemes/sequential/d3.js b/superset/assets/src/modules/colors/colorSchemes/sequential/d3.js new file mode 100644 index 00000000000..e811b63330c --- /dev/null +++ b/superset/assets/src/modules/colors/colorSchemes/sequential/d3.js @@ -0,0 +1,510 @@ +import SequentialScheme from '../../SequentialScheme'; + +const schemes = [ + { + name: 'schemeBrBG', + label: 'brown/green', + colors: [ + '#543005', + '#8c510a', + '#bf812d', + '#dfc27d', + '#f6e8c3', + '#c7eae5', + '#80cdc1', + '#35978f', + '#01665e', + '#003c30', + ], + isDiverging: true, + }, + { + name: 'schemePRGn', + label: 'purple/green', + colors: [ + '#40004b', + '#762a83', + '#9970ab', + '#c2a5cf', + '#e7d4e8', + '#d9f0d3', + '#a6dba0', + '#5aae61', + '#1b7837', + '#00441b', + ], + isDiverging: true, + }, + { + name: 'schemePiYG', + label: 'pink/green', + colors: [ + '#8e0152', + '#c51b7d', + '#de77ae', + '#f1b6da', + '#fde0ef', + '#e6f5d0', + '#b8e186', + '#7fbc41', + '#4d9221', + '#276419', + ], + isDiverging: true, + }, + { + name: 'schemePuOr', + label: 'purple/orange', + colors: [ + '#2d004b', + '#542788', + '#8073ac', + '#b2abd2', + '#d8daeb', + '#fee0b6', + '#fdb863', + '#e08214', + '#b35806', + '#7f3b08', + ], + isDiverging: true, + }, + { + name: 'schemeRdBu', + label: 'red/blue', + colors: [ + '#67001f', + '#b2182b', + '#d6604d', + '#f4a582', + '#fddbc7', + '#d1e5f0', + '#92c5de', + '#4393c3', + '#2166ac', + '#053061', + ], + isDiverging: true, + }, + { + name: 'schemeRdGy', + label: 'red/gray/black', + colors: [ + '#67001f', + '#b2182b', + '#d6604d', + '#f4a582', + '#fddbc7', + '#e0e0e0', + '#bababa', + '#878787', + '#4d4d4d', + '#1a1a1a', + ], + isDiverging: true, + }, + { + name: 'schemeRdYlBu', + label: 'red/yellow/blue', + colors: [ + '#a50026', + '#d73027', + '#f46d43', + '#fdae61', + '#fee090', + '#e0f3f8', + '#abd9e9', + '#74add1', + '#4575b4', + '#313695', + ], + isDiverging: true, + }, + { + name: 'schemeRdYlGn', + label: 'red/yellow/green', + colors: [ + '#a50026', + '#d73027', + '#f46d43', + '#fdae61', + '#fee08b', + '#d9ef8b', + '#a6d96a', + '#66bd63', + '#1a9850', + '#006837', + ], + isDiverging: true, + }, + { + name: 'schemeSpectral', + label: 'rainbow', + colors: [ + '#9e0142', + '#d53e4f', + '#f46d43', + '#fdae61', + '#fee08b', + '#e6f598', + '#abdda4', + '#66c2a5', + '#3288bd', + '#5e4fa2', + ], + }, + { + name: 'schemeBlues', + label: 'blues', + colors: [ + '#b5d4e9', + '#93c3df', + '#6daed5', + '#4b97c9', + '#2f7ebc', + '#1864aa', + '#0a4a90', + '#08306b', + ], + }, + { + name: 'schemeGreens', + label: 'greens', + colors: [ + '#b7e2b1', + '#97d494', + '#73c378', + '#4daf62', + '#2f984f', + '#157f3b', + '#036429', + '#00441b', + ], + }, + { + name: 'schemeGrays', + label: 'grays', + colors: [ + '#cecece', + '#b4b4b4', + '#979797', + '#7a7a7a', + '#5f5f5f', + '#404040', + '#1e1e1e', + '#000000', + ], + }, + { + name: 'schemeOranges', + label: 'oranges', + colors: [ + '#fdc28c', + '#fda762', + '#fb8d3d', + '#f2701d', + '#e25609', + '#c44103', + '#9f3303', + '#7f2704', + ], + }, + { + name: 'schemePurples', + label: 'purples', + colors: [ + '#cecee5', + '#b6b5d8', + '#9e9bc9', + '#8782bc', + '#7363ac', + '#61409b', + '#501f8c', + '#3f007d', + ], + }, + { + name: 'schemeReds', + label: 'reds', + colors: [ + '#fcaa8e', + '#fc8a6b', + '#f9694c', + '#ef4533', + '#d92723', + '#bb151a', + '#970b13', + '#67000d', + ], + }, + { + name: 'schemeViridis', + label: 'Viridis', + colors: [ + '#482475', + '#414487', + '#355f8d', + '#2a788e', + '#21918c', + '#22a884', + '#44bf70', + '#7ad151', + '#bddf26', + '#fde725', + ], + }, + { + name: 'schemeInferno', + label: 'Inferno', + colors: [ + '#160b39', + '#420a68', + '#6a176e', + '#932667', + '#bc3754', + '#dd513a', + '#f37819', + '#fca50a', + '#f6d746', + '#fcffa4', + ], + }, + { + name: 'schemeMagma', + label: 'Magma', + colors: [ + '#140e36', + '#3b0f70', + '#641a80', + '#8c2981', + '#b73779', + '#de4968', + '#f7705c', + '#fe9f6d', + '#fecf92', + '#fcfdbf', + ], + }, + { + name: 'schemeWarm', + label: 'Warm', + colors: [ + '#963db3', + '#bf3caf', + '#e4419d', + '#fe4b83', + '#ff5e63', + '#ff7847', + '#fb9633', + '#e2b72f', + '#c6d63c', + '#aff05b', + ], + }, + { + name: 'schemeCool', + label: 'Cool', + colors: [ + '#6054c8', + '#4c6edb', + '#368ce1', + '#23abd8', + '#1ac7c2', + '#1ddfa3', + '#30ef82', + '#52f667', + '#7ff658', + '#aff05b', + ], + }, + { + name: 'schemeCubehelixDefault', + label: 'Cube Helix', + colors: [ + '#1a1530', + '#163d4e', + '#1f6642', + '#54792f', + '#a07949', + '#d07e93', + '#cf9cda', + '#c1caf3', + '#d2eeef', + '#ffffff', + ], + }, + { + name: 'schemeBuGn', + label: 'blue/green', + colors: [ + '#b7e4da', + '#8fd3c1', + '#68c2a3', + '#49b17f', + '#2f9959', + '#157f3c', + '#036429', + '#00441b', + ], + }, + { + name: 'schemeBuPu', + label: 'blue/purple', + colors: [ + '#b2cae1', + '#9cb3d5', + '#8f95c6', + '#8c74b5', + '#8952a5', + '#852d8f', + '#730f71', + '#4d004b', + ], + }, + { + name: 'schemeGnBu', + label: 'green/blue', + colors: [ + '#bde5bf', + '#9ed9bb', + '#7bcbc4', + '#58b7cd', + '#399cc6', + '#1d7eb7', + '#0b60a1', + '#084081', + ], + }, + { + name: 'schemeOrRd', + label: 'orange/red', + colors: [ + '#fdca94', + '#fdb07a', + '#fa8e5d', + '#f16c49', + '#e04530', + '#c81d13', + '#a70403', + '#7f0000', + ], + }, + { + name: 'schemePuBuGn', + label: 'purple/blue/green', + colors: [ + '#bec9e2', + '#98b9d9', + '#69a8cf', + '#4096c0', + '#19879f', + '#037877', + '#016353', + '#014636', + ], + }, + { + name: 'schemePuBu', + label: 'purple/blue', + colors: [ + '#bfc9e2', + '#9bb9d9', + '#72a8cf', + '#4394c3', + '#1a7db6', + '#0667a1', + '#045281', + '#023858', + ], + }, + { + name: 'schemePuRd', + label: 'purple/red', + colors: [ + '#d0aad2', + '#d08ac2', + '#dd63ae', + '#e33890', + '#d71c6c', + '#b70b4f', + '#8f023a', + '#67001f', + ], + }, + { + name: 'schemeRdPu', + label: 'red/purple', + colors: [ + '#fbb5bc', + '#f993b0', + '#f369a3', + '#e03e98', + '#c01788', + '#99037c', + '#700174', + '#49006a', + ], + }, + { + name: 'schemeYlGnBu', + label: 'yellow/green/blue', + colors: [ + '#d5eeb3', + '#a9ddb7', + '#73c9bd', + '#45b4c2', + '#2897bf', + '#2073b2', + '#234ea0', + '#1c3185', + '#081d58', + ], + }, + { + name: 'schemeYlGn', + label: 'yellow/green', + colors: [ + '#e4f4ac', + '#c7e89b', + '#a2d88a', + '#78c578', + '#4eaf63', + '#2f944e', + '#15793f', + '#036034', + '#004529', + ], + }, + { + name: 'schemeYlOrBr', + label: 'yellow/orange/brown', + colors: [ + '#feeaa1', + '#fed676', + '#feba4a', + '#fb992c', + '#ee7918', + '#d85b0a', + '#b74304', + '#8f3204', + '#662506', + ], + }, + { + name: 'schemeYlOrRd', + label: 'yellow/orange/red', + colors: [ + '#fee087', + '#fec965', + '#feab4b', + '#fd893c', + '#fa5c2e', + '#ec3023', + '#d31121', + '#af0225', + '#800026', + ], + }, +].map(s => new SequentialScheme(s)); + +export default schemes; diff --git a/superset/assets/src/setup/setupColors.js b/superset/assets/src/setup/setupColors.js new file mode 100644 index 00000000000..e51ea3db30d --- /dev/null +++ b/superset/assets/src/setup/setupColors.js @@ -0,0 +1,26 @@ +import airbnb from '../modules/colors/colorSchemes/categorical/airbnb'; +import categoricalD3 from '../modules/colors/colorSchemes/categorical/d3'; +import google from '../modules/colors/colorSchemes/categorical/google'; +import lyft from '../modules/colors/colorSchemes/categorical/lyft'; +import sequentialCommon from '../modules/colors/colorSchemes/sequential/common'; +import sequentialD3 from '../modules/colors/colorSchemes/sequential/d3'; +import getCategoricalSchemeRegistry from '../modules/colors/CategoricalSchemeRegistrySingleton'; +import getSequentialSchemeRegistry from '../modules/colors/SequentialSchemeRegistrySingleton'; + +export default function setupColors() { + // Register color schemes + const categoricalSchemeRegistry = getCategoricalSchemeRegistry(); + [airbnb, categoricalD3, google, lyft].forEach((group) => { + group.forEach((scheme) => { + categoricalSchemeRegistry.registerValue(scheme.name, scheme); + }); + }); + categoricalSchemeRegistry.setDefaultSchemeName('bnbColors'); + + const sequentialSchemeRegistry = getSequentialSchemeRegistry(); + [sequentialCommon, sequentialD3].forEach((group) => { + group.forEach((scheme) => { + sequentialSchemeRegistry.registerValue(scheme.name, scheme); + }); + }); +} diff --git a/superset/assets/src/visualizations/Chord/Chord.js b/superset/assets/src/visualizations/Chord/Chord.js index cb5ae6dc2cd..e6502624517 100644 --- a/superset/assets/src/visualizations/Chord/Chord.js +++ b/superset/assets/src/visualizations/Chord/Chord.js @@ -1,7 +1,7 @@ /* eslint-disable no-param-reassign */ import d3 from 'd3'; import PropTypes from 'prop-types'; -import { getScale } from '../../modules/CategoricalColorNamespace'; +import { getScale } from '../../modules/colors/CategoricalColorNamespace'; import './Chord.css'; const propTypes = { diff --git a/superset/assets/src/visualizations/Histogram/Histogram.jsx b/superset/assets/src/visualizations/Histogram/Histogram.jsx index 34540bb9df4..0b896d7946a 100644 --- a/superset/assets/src/visualizations/Histogram/Histogram.jsx +++ b/superset/assets/src/visualizations/Histogram/Histogram.jsx @@ -5,7 +5,7 @@ import { chartTheme } from '@data-ui/theme'; import { LegendOrdinal } from '@vx/legend'; import { scaleOrdinal } from '@vx/scale'; import WithLegend from '../WithLegend'; -import { getScale } from '../../modules/CategoricalColorNamespace'; +import { getScale } from '../../modules/colors/CategoricalColorNamespace'; const propTypes = { className: PropTypes.string, diff --git a/superset/assets/src/visualizations/Partition/Partition.js b/superset/assets/src/visualizations/Partition/Partition.js index 9093d556d3c..03b4df04558 100644 --- a/superset/assets/src/visualizations/Partition/Partition.js +++ b/superset/assets/src/visualizations/Partition/Partition.js @@ -2,7 +2,7 @@ import d3 from 'd3'; import PropTypes from 'prop-types'; import { hierarchy } from 'd3-hierarchy'; -import { getScale } from '../../modules/CategoricalColorNamespace'; +import { getScale } from '../../modules/colors/CategoricalColorNamespace'; import { d3TimeFormatPreset } from '../../modules/utils'; import './Partition.css'; diff --git a/superset/assets/src/visualizations/Rose/Rose.js b/superset/assets/src/visualizations/Rose/Rose.js index 3c76d8fbf9d..2d48c5b5c1e 100644 --- a/superset/assets/src/visualizations/Rose/Rose.js +++ b/superset/assets/src/visualizations/Rose/Rose.js @@ -2,7 +2,7 @@ import d3 from 'd3'; import PropTypes from 'prop-types'; import nv from 'nvd3'; -import { getScale } from '../../modules/CategoricalColorNamespace'; +import { getScale } from '../../modules/colors/CategoricalColorNamespace'; import { d3TimeFormatPreset } from '../../modules/utils'; import './Rose.css'; diff --git a/superset/assets/src/visualizations/Sankey/Sankey.js b/superset/assets/src/visualizations/Sankey/Sankey.js index 0efca777228..405f1b53f31 100644 --- a/superset/assets/src/visualizations/Sankey/Sankey.js +++ b/superset/assets/src/visualizations/Sankey/Sankey.js @@ -2,7 +2,7 @@ import d3 from 'd3'; import PropTypes from 'prop-types'; import { sankey as d3Sankey } from 'd3-sankey'; -import { getScale } from '../../modules/CategoricalColorNamespace'; +import { getScale } from '../../modules/colors/CategoricalColorNamespace'; import './Sankey.css'; const propTypes = { diff --git a/superset/assets/src/visualizations/Sunburst/Sunburst.js b/superset/assets/src/visualizations/Sunburst/Sunburst.js index f557d8d12dd..3cd95128bfd 100644 --- a/superset/assets/src/visualizations/Sunburst/Sunburst.js +++ b/superset/assets/src/visualizations/Sunburst/Sunburst.js @@ -1,7 +1,7 @@ /* eslint-disable no-param-reassign */ import d3 from 'd3'; import PropTypes from 'prop-types'; -import { getScale } from '../../modules/CategoricalColorNamespace'; +import { getScale } from '../../modules/colors/CategoricalColorNamespace'; import { wrapSvgText } from '../../modules/utils'; import './Sunburst.css'; diff --git a/superset/assets/src/visualizations/Treemap/Treemap.js b/superset/assets/src/visualizations/Treemap/Treemap.js index 3596357ee3b..0ceef279b63 100644 --- a/superset/assets/src/visualizations/Treemap/Treemap.js +++ b/superset/assets/src/visualizations/Treemap/Treemap.js @@ -1,7 +1,7 @@ /* eslint-disable no-shadow, no-param-reassign */ import d3 from 'd3'; import PropTypes from 'prop-types'; -import { getScale } from '../../modules/CategoricalColorNamespace'; +import { getScale } from '../../modules/colors/CategoricalColorNamespace'; import './Treemap.css'; // Declare PropTypes for recursive data structures diff --git a/superset/assets/src/visualizations/deckgl/CategoricalDeckGLContainer.jsx b/superset/assets/src/visualizations/deckgl/CategoricalDeckGLContainer.jsx index dd4201769c8..49e37af2d28 100644 --- a/superset/assets/src/visualizations/deckgl/CategoricalDeckGLContainer.jsx +++ b/superset/assets/src/visualizations/deckgl/CategoricalDeckGLContainer.jsx @@ -2,11 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; - import AnimatableDeckGLContainer from './AnimatableDeckGLContainer'; import Legend from '../Legend'; - -import { getScale } from '../../modules/CategoricalColorNamespace'; +import { getScale } from '../../modules/colors/CategoricalColorNamespace'; import { hexToRGB } from '../../modules/colors'; import { getPlaySliderParams } from '../../modules/time'; import sandboxedEval from '../../modules/sandbox'; diff --git a/superset/assets/src/visualizations/nvd3/NVD3Vis.js b/superset/assets/src/visualizations/nvd3/NVD3Vis.js index 5000731c62a..9ffe4687fbe 100644 --- a/superset/assets/src/visualizations/nvd3/NVD3Vis.js +++ b/superset/assets/src/visualizations/nvd3/NVD3Vis.js @@ -8,7 +8,7 @@ import 'nvd3/build/nv.d3.min.css'; import { t } from '../../locales'; import AnnotationTypes, { applyNativeColumns } from '../../modules/AnnotationTypes'; -import { getScale, getColor } from '../../modules/CategoricalColorNamespace'; +import { getScale, getColor } from '../../modules/colors/CategoricalColorNamespace'; import { formatDateVerbose } from '../../modules/dates'; import { d3TimeFormatPreset, d3FormatPreset } from '../../modules/utils'; import { isTruthy } from '../../utils/common'; diff --git a/superset/assets/src/visualizations/wordcloud/WordCloud.js b/superset/assets/src/visualizations/wordcloud/WordCloud.js index 2b91665ee28..a165b016088 100644 --- a/superset/assets/src/visualizations/wordcloud/WordCloud.js +++ b/superset/assets/src/visualizations/wordcloud/WordCloud.js @@ -1,7 +1,7 @@ import d3 from 'd3'; import PropTypes from 'prop-types'; import cloudLayout from 'd3-cloud'; -import { getScale } from '../../modules/CategoricalColorNamespace'; +import { getScale } from '../../modules/colors/CategoricalColorNamespace'; const ROTATION = { square: () => Math.floor((Math.random() * 2)) * 90,