mirror of
https://github.com/getredash/redash.git
synced 2026-05-13 16:01:20 -04:00
Pie chart: sectors colors
This commit is contained in:
@@ -12,6 +12,9 @@
|
||||
<li ng-class="{active: currentTab == 'series'}" ng-if="options.globalSeriesType != 'custom'">
|
||||
<a ng-click="changeTab('series')">Series</a>
|
||||
</li>
|
||||
<li ng-class="{active: currentTab == 'colors'}" ng-if="options.globalSeriesType != 'custom'">
|
||||
<a ng-click="changeTab('colors')">Colors</a>
|
||||
</li>
|
||||
<li ng-class="{active: currentTab == 'dataLabels'}" ng-if="options.globalSeriesType != 'custom'">
|
||||
<a ng-click="changeTab('dataLabels')">Data Labels</a>
|
||||
</li>
|
||||
@@ -210,15 +213,15 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">Name</label>
|
||||
<input ng-model="yAxis.title.text" type="text" class="form-control"></input>
|
||||
<input ng-model="yAxis.title.text" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">Min Value</label>
|
||||
<input ng-model="yAxis.rangeMin" type="number" step="any" placeholder="Auto" class="form-control"></input>
|
||||
<input ng-model="yAxis.rangeMin" type="number" step="any" placeholder="Auto" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">Max Value</label>
|
||||
<input ng-model="yAxis.rangeMax" type="number" step="any" placeholder="Auto" class="form-control"></input>
|
||||
<input ng-model="yAxis.rangeMax" type="number" step="any" placeholder="Auto" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -226,40 +229,28 @@
|
||||
<div ng-if="currentTab == 'series'" class="m-t-10 m-b-10">
|
||||
<table class="table table-condensed col-table">
|
||||
<thead>
|
||||
<th>zIndex</th>
|
||||
<th>Left Y Axis</th>
|
||||
<th>Right Y Axis</th>
|
||||
<th style="width: 1%;">zIndex</th>
|
||||
<th ng-if="options.globalSeriesType != 'pie'">Left Y Axis</th>
|
||||
<th ng-if="options.globalSeriesType != 'pie'">Right Y Axis</th>
|
||||
<th>Label</th>
|
||||
<th>Color</th>
|
||||
<th>Type</th>
|
||||
<th ng-if="options.globalSeriesType != 'pie'">Type</th>
|
||||
</thead>
|
||||
<tbody ui-sortable ng-model="form.seriesList">
|
||||
<tr ng-repeat="name in form.seriesList">
|
||||
<td style="cursor: move;">
|
||||
<td style="width: 1%; cursor: move;">
|
||||
<i class="fa fa-arrows-v"></i>
|
||||
<span ng-bind="options.seriesOptions[name].zIndex + 1"></span>
|
||||
</td>
|
||||
<td>
|
||||
<td ng-if="options.globalSeriesType != 'pie'">
|
||||
<input type="radio" ng-value="0" ng-model="options.seriesOptions[name].yAxis">
|
||||
</td>
|
||||
<td>
|
||||
<td ng-if="options.globalSeriesType != 'pie'">
|
||||
<input type="radio" ng-value="1" ng-model="options.seriesOptions[name].yAxis">
|
||||
</td>
|
||||
<td style="padding: 3px; width: 140px;">
|
||||
<input placeholder="{{name}}" class="form-control input-sm super-small-input" type="text" ng-model="options.seriesOptions[name].name">
|
||||
</td>
|
||||
<td style="padding: 3px; width: 35px;">
|
||||
<ui-select ng-model="options.seriesOptions[name].color">
|
||||
<ui-select-match>
|
||||
<color-box color="$select.selected.value"></color-box>
|
||||
</ui-select-match>
|
||||
<ui-select-choices repeat="color.value as (key, color) in colors">
|
||||
<color-box color="color.value"></color-box>
|
||||
<span ng-bind-html="color.key | capitalize | highlight: $select.search"></span>
|
||||
</ui-select-choices>
|
||||
</ui-select>
|
||||
</td>
|
||||
<td style="padding: 3px; width: 105px;">
|
||||
<td ng-if="options.globalSeriesType != 'pie'" style="padding: 3px; width: 105px;">
|
||||
<ui-select ng-model="options.seriesOptions[name].type">
|
||||
<ui-select-match placeholder="Chart Type">
|
||||
<div>
|
||||
@@ -281,6 +272,52 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div ng-if="(currentTab == 'colors') && (options.globalSeriesType != 'pie')" class="m-t-10 m-b-10">
|
||||
<table class="table table-condensed col-table">
|
||||
<tbody>
|
||||
<tr ng-repeat="name in form.seriesList">
|
||||
<td style="padding: 3px; width: 140px;">
|
||||
<div>{{ name }}</div>
|
||||
</td>
|
||||
<td style="padding: 3px; width: 35px;">
|
||||
<ui-select ng-model="options.seriesOptions[name].color">
|
||||
<ui-select-match>
|
||||
<color-box color="$select.selected.value"></color-box>
|
||||
</ui-select-match>
|
||||
<ui-select-choices repeat="color.value as (key, color) in colors">
|
||||
<color-box color="color.value"></color-box>
|
||||
<span ng-bind-html="color.key | capitalize | highlight: $select.search"></span>
|
||||
</ui-select-choices>
|
||||
</ui-select>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div ng-if="(currentTab == 'colors') && (options.globalSeriesType == 'pie')" class="m-t-10 m-b-10">
|
||||
<table class="table table-condensed col-table">
|
||||
<tbody>
|
||||
<tr ng-repeat="name in form.valuesList">
|
||||
<td style="padding: 3px; width: 140px;">
|
||||
<div>{{ name }}</div>
|
||||
</td>
|
||||
<td style="padding: 3px; width: 35px;">
|
||||
<ui-select ng-model="options.valuesOptions[name].color">
|
||||
<ui-select-match>
|
||||
<color-box color="$select.selected.value"></color-box>
|
||||
</ui-select-match>
|
||||
<ui-select-choices repeat="color.value as (key, color) in colors">
|
||||
<color-box color="color.value"></color-box>
|
||||
<span ng-bind-html="color.key | capitalize | highlight: $select.search"></span>
|
||||
</ui-select-choices>
|
||||
</ui-select>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div ng-if="currentTab == 'dataLabels'" class="m-t-10 m-b-10">
|
||||
<div ng-if="['line', 'area', 'column', 'scatter', 'pie'].indexOf(options.globalSeriesType) >= 0" class="checkbox">
|
||||
<label>
|
||||
@@ -329,4 +366,4 @@
|
||||
placeholder="(auto)">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,6 +14,7 @@ const DEFAULT_OPTIONS = {
|
||||
error_y: { type: 'data', visible: true },
|
||||
series: { stacking: null, error_y: { type: 'data', visible: true } },
|
||||
seriesOptions: {},
|
||||
valuesOptions: {},
|
||||
columnMapping: {},
|
||||
|
||||
// showDataLabels: false, // depends on chart type
|
||||
@@ -156,7 +157,8 @@ function ChartEditor(ColorPalette, clientConfig) {
|
||||
}
|
||||
|
||||
function refreshSeries() {
|
||||
const seriesNames = map(scope.queryResult.getChartData(scope.options.columnMapping), i => i.name);
|
||||
const chartData = scope.queryResult.getChartData(scope.options.columnMapping);
|
||||
const seriesNames = map(chartData, i => i.name);
|
||||
const existing = keys(scope.options.seriesOptions);
|
||||
each(difference(seriesNames, existing), (name) => {
|
||||
scope.options.seriesOptions[name] = {
|
||||
@@ -169,6 +171,31 @@ function ChartEditor(ColorPalette, clientConfig) {
|
||||
scope.form.seriesList = without(scope.form.seriesList, name);
|
||||
delete scope.options.seriesOptions[name];
|
||||
});
|
||||
|
||||
if (scope.options.globalSeriesType === 'pie') {
|
||||
const uniqueValuesNames = new Set();
|
||||
each(chartData, (series) => {
|
||||
each(series.data, (row) => {
|
||||
uniqueValuesNames.add(row.x);
|
||||
});
|
||||
});
|
||||
const valuesNames = [];
|
||||
uniqueValuesNames.forEach(v => valuesNames.push(v));
|
||||
|
||||
// initialize newly added values
|
||||
const newValues = difference(valuesNames, keys(scope.options.valuesOptions));
|
||||
each(newValues, (name) => {
|
||||
scope.options.valuesOptions[name] = {};
|
||||
scope.form.valuesList.push(name);
|
||||
});
|
||||
// remove settings for values that are no longer available
|
||||
each(keys(scope.options.valuesOptions), (name) => {
|
||||
if (valuesNames.indexOf(name) === -1) {
|
||||
delete scope.options.valuesOptions[name];
|
||||
}
|
||||
});
|
||||
scope.form.valuesList = intersection(scope.form.valuesList, valuesNames);
|
||||
}
|
||||
}
|
||||
|
||||
function setColumnRole(role, column) {
|
||||
@@ -200,6 +227,7 @@ function ChartEditor(ColorPalette, clientConfig) {
|
||||
yAxisColumns: [],
|
||||
seriesList: sortBy(keys(scope.options.seriesOptions), name =>
|
||||
scope.options.seriesOptions[name].zIndex),
|
||||
valuesList: keys(scope.options.valuesOptions),
|
||||
};
|
||||
|
||||
scope.$watchCollection('form.seriesList', (value) => {
|
||||
@@ -273,7 +301,7 @@ function ChartEditor(ColorPalette, clientConfig) {
|
||||
});
|
||||
}
|
||||
|
||||
scope.$watch('options', () => {
|
||||
function setOptionsDefaults() {
|
||||
if (scope.options) {
|
||||
// For existing visualization - set default options
|
||||
defaults(scope.options, extend({}, DEFAULT_OPTIONS, {
|
||||
@@ -281,7 +309,9 @@ function ChartEditor(ColorPalette, clientConfig) {
|
||||
dateTimeFormat: clientConfig.dateTimeFormat,
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
setOptionsDefaults();
|
||||
scope.$watch('options', setOptionsDefaults);
|
||||
|
||||
scope.templateHint = `
|
||||
<div class="p-b-5">Use special names to access additional properties:</div>
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
each, values, sortBy, identity, filter, map, extend, reduce,
|
||||
} from 'lodash';
|
||||
import moment from 'moment';
|
||||
import d3 from 'd3';
|
||||
import { createFormatter, formatSimpleTemplate } from '@/lib/value-format';
|
||||
|
||||
// The following colors will be used if you pick "Automatic" color.
|
||||
@@ -227,6 +228,15 @@ function preparePieData(seriesList, options) {
|
||||
|
||||
const hoverinfo = getPieHoverInfoPattern(options);
|
||||
|
||||
// we will use this to assign colors for values that have not explicitly set color
|
||||
const getDefaultColor = d3.scale.ordinal().domain([]).range(ColorPaletteArray);
|
||||
const valuesColors = {};
|
||||
each(options.valuesOptions, (item, key) => {
|
||||
if (isString(item.color) && (item.color !== '')) {
|
||||
valuesColors[key] = item.color;
|
||||
}
|
||||
});
|
||||
|
||||
return map(seriesList, (serie, index) => {
|
||||
const xPosition = (index % cellsInRow) * cellWidth;
|
||||
const yPosition = Math.floor(index / cellsInRow) * cellHeight;
|
||||
@@ -255,7 +265,9 @@ function preparePieData(seriesList, options) {
|
||||
labels: map(serie.data, row => (hasX ? normalizeValue(row.x) : `Slice ${index}`)),
|
||||
type: 'pie',
|
||||
hole: 0.4,
|
||||
marker: { colors: ColorPaletteArray },
|
||||
marker: {
|
||||
colors: map(serie.data, row => valuesColors[row.x] || getDefaultColor(row.x)),
|
||||
},
|
||||
hoverinfo,
|
||||
text: [],
|
||||
textinfo: options.showDataLabels ? 'percent' : 'none',
|
||||
|
||||
Reference in New Issue
Block a user