Commit dfb9419f by Torkel Ödegaard

Merge branch 'graph-legend-to-react'

parents baea76c4 36cd7381
import React from 'react';
import { ColorPickerPopover } from './ColorPickerPopover';
import { react2AngularDirective } from 'app/core/utils/react2angular';
import ReactDOM from 'react-dom';
import Drop from 'tether-drop';
import { SeriesColorPickerPopover } from './SeriesColorPickerPopover';
export interface Props {
series: any;
onColorChange: (color: string) => void;
onToggleAxis: () => void;
export interface SeriesColorPickerProps {
color: string;
yaxis?: number;
optionalClass?: string;
onColorChange: (newColor: string) => void;
onToggleAxis?: () => void;
}
export class SeriesColorPicker extends React.Component<Props, any> {
export class SeriesColorPicker extends React.Component<SeriesColorPickerProps> {
pickerElem: any;
colorPickerDrop: any;
static defaultProps = {
optionalClass: '',
yaxis: undefined,
onToggleAxis: () => {},
};
constructor(props) {
super(props);
this.onColorChange = this.onColorChange.bind(this);
this.onToggleAxis = this.onToggleAxis.bind(this);
}
onColorChange(color) {
this.props.onColorChange(color);
componentWillUnmount() {
this.destroyDrop();
}
onToggleAxis() {
this.props.onToggleAxis();
onClickToOpen = () => {
if (this.colorPickerDrop) {
this.destroyDrop();
}
renderAxisSelection() {
const leftButtonClass = this.props.series.yaxis === 1 ? 'btn-success' : 'btn-inverse';
const rightButtonClass = this.props.series.yaxis === 2 ? 'btn-success' : 'btn-inverse';
return (
<div className="p-b-1">
<label className="small p-r-1">Y Axis:</label>
<button onClick={this.onToggleAxis} className={'btn btn-small ' + leftButtonClass}>
Left
</button>
<button onClick={this.onToggleAxis} className={'btn btn-small ' + rightButtonClass}>
Right
</button>
</div>
const { color, yaxis, onColorChange, onToggleAxis } = this.props;
const dropContent = (
<SeriesColorPickerPopover color={color} yaxis={yaxis} onColorChange={onColorChange} onToggleAxis={onToggleAxis} />
);
const dropContentElem = document.createElement('div');
ReactDOM.render(dropContent, dropContentElem);
const drop = new Drop({
target: this.pickerElem,
content: dropContentElem,
position: 'top center',
classes: 'drop-popover',
openOn: 'hover',
hoverCloseDelay: 200,
remove: true,
tetherOptions: {
constraints: [{ to: 'scrollParent', attachment: 'none both' }],
},
});
drop.on('close', this.closeColorPicker.bind(this));
this.colorPickerDrop = drop;
this.colorPickerDrop.open();
};
closeColorPicker() {
setTimeout(() => {
this.destroyDrop();
}, 100);
}
destroyDrop() {
if (this.colorPickerDrop && this.colorPickerDrop.tether) {
this.colorPickerDrop.destroy();
this.colorPickerDrop = null;
}
}
render() {
const { optionalClass, children } = this.props;
return (
<div className="graph-legend-popover">
{this.props.series.yaxis && this.renderAxisSelection()}
<ColorPickerPopover color={this.props.series.color} onColorSelect={this.onColorChange} />
<div className={optionalClass} ref={e => (this.pickerElem = e)} onClick={this.onClickToOpen}>
{children}
</div>
);
}
}
react2AngularDirective('seriesColorPicker', SeriesColorPicker, ['series', 'onColorChange', 'onToggleAxis']);
import React from 'react';
import { ColorPickerPopover } from './ColorPickerPopover';
import { react2AngularDirective } from 'app/core/utils/react2angular';
export interface SeriesColorPickerPopoverProps {
color: string;
yaxis?: number;
onColorChange: (color: string) => void;
onToggleAxis?: () => void;
}
export class SeriesColorPickerPopover extends React.PureComponent<SeriesColorPickerPopoverProps, any> {
render() {
return (
<div className="graph-legend-popover">
{this.props.yaxis && <AxisSelector yaxis={this.props.yaxis} onToggleAxis={this.props.onToggleAxis} />}
<ColorPickerPopover color={this.props.color} onColorSelect={this.props.onColorChange} />
</div>
);
}
}
interface AxisSelectorProps {
yaxis: number;
onToggleAxis: () => void;
}
interface AxisSelectorState {
yaxis: number;
}
export class AxisSelector extends React.PureComponent<AxisSelectorProps, AxisSelectorState> {
constructor(props) {
super(props);
this.state = {
yaxis: this.props.yaxis,
};
this.onToggleAxis = this.onToggleAxis.bind(this);
}
onToggleAxis() {
this.setState({
yaxis: this.state.yaxis === 2 ? 1 : 2,
});
this.props.onToggleAxis();
}
render() {
const leftButtonClass = this.state.yaxis === 1 ? 'btn-success' : 'btn-inverse';
const rightButtonClass = this.state.yaxis === 2 ? 'btn-success' : 'btn-inverse';
return (
<div className="p-b-1">
<label className="small p-r-1">Y Axis:</label>
<button onClick={this.onToggleAxis} className={'btn btn-small ' + leftButtonClass}>
Left
</button>
<button onClick={this.onToggleAxis} className={'btn btn-small ' + rightButtonClass}>
Right
</button>
</div>
);
}
}
react2AngularDirective('seriesColorPickerPopover', SeriesColorPickerPopover, [
'series',
'onColorChange',
'onToggleAxis',
]);
......@@ -14,7 +14,7 @@ import './components/jsontree/jsontree';
import './components/code_editor/code_editor';
import './utils/outline';
import './components/colorpicker/ColorPicker';
import './components/colorpicker/SeriesColorPicker';
import './components/colorpicker/SeriesColorPickerPopover';
import './components/colorpicker/spectrum_picker';
import './services/search_srv';
import './services/ng_react';
......
......@@ -133,6 +133,7 @@ export class PanelModel {
}
destroy() {
this.events.emit('panel-teardown');
this.events.removeAllListeners();
}
}
......@@ -48,11 +48,6 @@ export class PanelCtrl {
}
$scope.$on('component-did-mount', () => this.panelDidMount());
$scope.$on('$destroy', () => {
this.events.emit('panel-teardown');
this.events.removeAllListeners();
});
}
panelDidMount() {
......
import _ from 'lodash';
import React, { PureComponent } from 'react';
import { TimeSeries } from 'app/core/core';
import CustomScrollbar from 'app/core/components/CustomScrollbar/CustomScrollbar';
import { LegendItem, LEGEND_STATS } from './LegendSeriesItem';
interface LegendProps {
seriesList: TimeSeries[];
optionalClass?: string;
}
interface LegendEventHandlers {
onToggleSeries?: (hiddenSeries) => void;
onToggleSort?: (sortBy, sortDesc) => void;
onToggleAxis?: (series: TimeSeries) => void;
onColorChange?: (series: TimeSeries, color: string) => void;
}
interface LegendComponentEventHandlers {
onToggleSeries?: (series, event) => void;
onToggleSort?: (sortBy, sortDesc) => void;
onToggleAxis?: (series: TimeSeries) => void;
onColorChange?: (series: TimeSeries, color: string) => void;
}
interface LegendDisplayProps {
hiddenSeries: any;
hideEmpty?: boolean;
hideZero?: boolean;
alignAsTable?: boolean;
rightSide?: boolean;
sideWidth?: number;
}
interface LegendValuesProps {
values?: boolean;
min?: boolean;
max?: boolean;
avg?: boolean;
current?: boolean;
total?: boolean;
}
interface LegendSortProps {
sort?: 'min' | 'max' | 'avg' | 'current' | 'total';
sortDesc?: boolean;
}
export type GraphLegendProps = LegendProps &
LegendDisplayProps &
LegendValuesProps &
LegendSortProps &
LegendEventHandlers;
export type LegendComponentProps = LegendProps &
LegendDisplayProps &
LegendValuesProps &
LegendSortProps &
LegendComponentEventHandlers;
interface LegendState {
hiddenSeries: { [seriesAlias: string]: boolean };
}
export class GraphLegend extends PureComponent<GraphLegendProps, LegendState> {
static defaultProps: Partial<GraphLegendProps> = {
values: false,
min: false,
max: false,
avg: false,
current: false,
total: false,
alignAsTable: false,
rightSide: false,
sort: undefined,
sortDesc: false,
optionalClass: '',
onToggleSeries: () => {},
onToggleSort: () => {},
onToggleAxis: () => {},
onColorChange: () => {},
};
constructor(props) {
super(props);
this.state = {
hiddenSeries: this.props.hiddenSeries,
};
}
sortLegend() {
let seriesList = [...this.props.seriesList] || [];
if (this.props.sort) {
seriesList = _.sortBy(seriesList, series => {
let sort = series.stats[this.props.sort];
if (sort === null) {
sort = -Infinity;
}
return sort;
});
if (this.props.sortDesc) {
seriesList = seriesList.reverse();
}
}
return seriesList;
}
onToggleSeries = (series, event) => {
let hiddenSeries = { ...this.state.hiddenSeries };
if (event.ctrlKey || event.metaKey || event.shiftKey) {
if (hiddenSeries[series.alias]) {
delete hiddenSeries[series.alias];
} else {
hiddenSeries[series.alias] = true;
}
} else {
hiddenSeries = this.toggleSeriesExclusiveMode(series);
}
this.setState({ hiddenSeries: hiddenSeries });
this.props.onToggleSeries(hiddenSeries);
};
toggleSeriesExclusiveMode(series) {
const hiddenSeries = { ...this.state.hiddenSeries };
if (hiddenSeries[series.alias]) {
delete hiddenSeries[series.alias];
}
// check if every other series is hidden
const alreadyExclusive = this.props.seriesList.every(value => {
if (value.alias === series.alias) {
return true;
}
return hiddenSeries[value.alias];
});
if (alreadyExclusive) {
// remove all hidden series
this.props.seriesList.forEach(value => {
delete hiddenSeries[value.alias];
});
} else {
// hide all but this serie
this.props.seriesList.forEach(value => {
if (value.alias === series.alias) {
return;
}
hiddenSeries[value.alias] = true;
});
}
return hiddenSeries;
}
render() {
const {
optionalClass,
rightSide,
sideWidth,
sort,
sortDesc,
hideEmpty,
hideZero,
values,
min,
max,
avg,
current,
total,
} = this.props;
const seriesValuesProps = { values, min, max, avg, current, total };
const hiddenSeries = this.state.hiddenSeries;
const seriesHideProps = { hideEmpty, hideZero };
const sortProps = { sort, sortDesc };
const seriesList = this.sortLegend().filter(series => !series.hideFromLegend(seriesHideProps));
const legendClass = `${this.props.alignAsTable ? 'graph-legend-table' : ''} ${optionalClass}`;
// Set min-width if side style and there is a value, otherwise remove the CSS property
// Set width so it works with IE11
const width: any = rightSide && sideWidth ? sideWidth : undefined;
const ieWidth: any = rightSide && sideWidth ? sideWidth - 1 : undefined;
const legendStyle: React.CSSProperties = {
minWidth: width,
width: ieWidth,
};
const legendProps: LegendComponentProps = {
seriesList: seriesList,
hiddenSeries: hiddenSeries,
onToggleSeries: this.onToggleSeries,
onToggleAxis: this.props.onToggleAxis,
onToggleSort: this.props.onToggleSort,
onColorChange: this.props.onColorChange,
...seriesValuesProps,
...sortProps,
};
return (
<div className={`graph-legend-content ${legendClass}`} style={legendStyle}>
{this.props.alignAsTable ? <LegendTable {...legendProps} /> : <LegendSeriesList {...legendProps} />}
</div>
);
}
}
class LegendSeriesList extends PureComponent<LegendComponentProps> {
render() {
const { seriesList, hiddenSeries, values, min, max, avg, current, total } = this.props;
const seriesValuesProps = { values, min, max, avg, current, total };
return seriesList.map((series, i) => (
<LegendItem
// This trick required because TimeSeries.id is not unique (it's just TimeSeries.alias).
// In future would be good to make id unique across the series list.
key={`${series.id}-${i}`}
series={series}
hidden={hiddenSeries[series.alias]}
{...seriesValuesProps}
onLabelClick={this.props.onToggleSeries}
onColorChange={this.props.onColorChange}
onToggleAxis={this.props.onToggleAxis}
/>
));
}
}
class LegendTable extends PureComponent<Partial<LegendComponentProps>> {
onToggleSort = stat => {
let sortDesc = this.props.sortDesc;
let sortBy = this.props.sort;
if (stat !== sortBy) {
sortDesc = null;
}
// if already sort ascending, disable sorting
if (sortDesc === false) {
sortBy = null;
sortDesc = null;
} else {
sortDesc = !sortDesc;
sortBy = stat;
}
this.props.onToggleSort(sortBy, sortDesc);
};
render() {
const seriesList = this.props.seriesList;
const { values, min, max, avg, current, total, sort, sortDesc, hiddenSeries } = this.props;
const seriesValuesProps = { values, min, max, avg, current, total };
return (
<table>
<colgroup>
<col style={{ width: '100%' }} />
</colgroup>
<thead>
<tr>
<th style={{ textAlign: 'left' }} />
{LEGEND_STATS.map(
statName =>
seriesValuesProps[statName] && (
<LegendTableHeaderItem
key={statName}
statName={statName}
sort={sort}
sortDesc={sortDesc}
onClick={this.onToggleSort}
/>
)
)}
</tr>
</thead>
<tbody>
{seriesList.map((series, i) => (
<LegendItem
key={`${series.id}-${i}`}
asTable={true}
series={series}
hidden={hiddenSeries[series.alias]}
onLabelClick={this.props.onToggleSeries}
onColorChange={this.props.onColorChange}
onToggleAxis={this.props.onToggleAxis}
{...seriesValuesProps}
/>
))}
</tbody>
</table>
);
}
}
interface LegendTableHeaderProps {
statName: string;
onClick?: (statName: string) => void;
}
class LegendTableHeaderItem extends PureComponent<LegendTableHeaderProps & LegendSortProps> {
onClick = () => this.props.onClick(this.props.statName);
render() {
const { statName, sort, sortDesc } = this.props;
return (
<th className="pointer" onClick={this.onClick}>
{statName}
{sort === statName && <span className={sortDesc ? 'fa fa-caret-down' : 'fa fa-caret-up'} />}
</th>
);
}
}
export class Legend extends PureComponent<GraphLegendProps> {
render() {
return (
<CustomScrollbar>
<GraphLegend {...this.props} />
</CustomScrollbar>
);
}
}
export default Legend;
import React, { PureComponent } from 'react';
import classNames from 'classnames';
import { TimeSeries } from 'app/core/core';
import { SeriesColorPicker } from 'app/core/components/colorpicker/SeriesColorPicker';
export const LEGEND_STATS = ['min', 'max', 'avg', 'current', 'total'];
export interface LegendLabelProps {
series: TimeSeries;
asTable?: boolean;
hidden?: boolean;
onLabelClick?: (series, event) => void;
onColorChange?: (series, color: string) => void;
onToggleAxis?: (series) => void;
}
export interface LegendValuesProps {
values?: boolean;
min?: boolean;
max?: boolean;
avg?: boolean;
current?: boolean;
total?: boolean;
}
type LegendItemProps = LegendLabelProps & LegendValuesProps;
interface LegendItemState {
yaxis: number;
}
export class LegendItem extends PureComponent<LegendItemProps, LegendItemState> {
static defaultProps = {
asTable: false,
hidden: false,
onLabelClick: () => {},
onColorChange: () => {},
onToggleAxis: () => {},
};
constructor(props) {
super(props);
this.state = {
yaxis: this.props.series.yaxis,
};
}
onLabelClick = e => this.props.onLabelClick(this.props.series, e);
onToggleAxis = () => {
const yaxis = this.state.yaxis === 2 ? 1 : 2;
const info = { alias: this.props.series.alias, yaxis: yaxis };
this.setState({ yaxis: yaxis });
this.props.onToggleAxis(info);
};
onColorChange = color => {
this.props.onColorChange(this.props.series, color);
// Because of PureComponent nature it makes only shallow props comparison and changing of series.color doesn't run
// component re-render. In this case we can't rely on color, selected by user, because it may be overwritten
// by series overrides. So we need to use forceUpdate() to make sure we have proper series color.
this.forceUpdate();
};
renderLegendValues() {
const { series, asTable } = this.props;
const legendValueItems = [];
for (const valueName of LEGEND_STATS) {
if (this.props[valueName]) {
const valueFormatted = series.formatValue(series.stats[valueName]);
legendValueItems.push(
<LegendValue key={valueName} valueName={valueName} value={valueFormatted} asTable={asTable} />
);
}
}
return legendValueItems;
}
render() {
const { series, values, asTable, hidden } = this.props;
const seriesOptionClasses = classNames({
'graph-legend-series-hidden': hidden,
'graph-legend-series--right-y': series.yaxis === 2,
});
const valueItems = values ? this.renderLegendValues() : [];
const seriesLabel = (
<LegendSeriesLabel
label={series.alias}
color={series.color}
yaxis={this.state.yaxis}
onLabelClick={this.onLabelClick}
onColorChange={this.onColorChange}
onToggleAxis={this.onToggleAxis}
/>
);
if (asTable) {
return (
<tr className={`graph-legend-series ${seriesOptionClasses}`}>
<td>{seriesLabel}</td>
{valueItems}
</tr>
);
} else {
return (
<div className={`graph-legend-series ${seriesOptionClasses}`}>
{seriesLabel}
{valueItems}
</div>
);
}
}
}
interface LegendSeriesLabelProps {
label: string;
color: string;
yaxis?: number;
onLabelClick?: (event) => void;
}
class LegendSeriesLabel extends PureComponent<LegendSeriesLabelProps & LegendSeriesIconProps> {
static defaultProps = {
yaxis: undefined,
onLabelClick: () => {},
};
render() {
const { label, color, yaxis } = this.props;
const { onColorChange, onToggleAxis } = this.props;
return [
<LegendSeriesIcon
key="icon"
color={color}
yaxis={yaxis}
onColorChange={onColorChange}
onToggleAxis={onToggleAxis}
/>,
<a className="graph-legend-alias pointer" title={label} key="label" onClick={e => this.props.onLabelClick(e)}>
{label}
</a>,
];
}
}
interface LegendSeriesIconProps {
color: string;
yaxis?: number;
onColorChange?: (color: string) => void;
onToggleAxis?: () => void;
}
interface LegendSeriesIconState {
color: string;
}
function SeriesIcon(props) {
return <i className="fa fa-minus pointer" style={{ color: props.color }} />;
}
class LegendSeriesIcon extends PureComponent<LegendSeriesIconProps, LegendSeriesIconState> {
static defaultProps = {
yaxis: undefined,
onColorChange: () => {},
onToggleAxis: () => {},
};
render() {
return (
<SeriesColorPicker
optionalClass="graph-legend-icon"
yaxis={this.props.yaxis}
color={this.props.color}
onColorChange={this.props.onColorChange}
onToggleAxis={this.props.onToggleAxis}
>
<SeriesIcon color={this.props.color} />
</SeriesColorPicker>
);
}
}
interface LegendValueProps {
value: string;
valueName: string;
asTable?: boolean;
}
function LegendValue(props: LegendValueProps) {
const value = props.value;
const valueName = props.valueName;
if (props.asTable) {
return <td className={`graph-legend-value ${valueName}`}>{value}</td>;
}
return <div className={`graph-legend-value ${valueName}`}>{value}</div>;
}
......@@ -20,6 +20,9 @@ import { EventManager } from 'app/features/annotations/all';
import { convertToHistogramData } from './histogram';
import { alignYLevel } from './align_yaxes';
import config from 'app/core/config';
import React from 'react';
import ReactDOM from 'react-dom';
import { Legend, GraphLegendProps } from './Legend/Legend';
import { GraphCtrl } from './module';
......@@ -35,6 +38,7 @@ class GraphElement {
panelWidth: number;
eventManager: EventManager;
thresholdManager: ThresholdManager;
legendElem: HTMLElement;
constructor(private scope, private elem, private timeSrv) {
this.ctrl = scope.ctrl;
......@@ -50,7 +54,7 @@ class GraphElement {
});
// panel events
this.ctrl.events.on('panel-teardown', this.onPanelteardown.bind(this));
this.ctrl.events.on('panel-teardown', this.onPanelTeardown.bind(this));
/**
* Split graph rendering into two parts.
......@@ -63,13 +67,14 @@ class GraphElement {
// global events
appEvents.on('graph-hover', this.onGraphHover.bind(this), scope);
appEvents.on('graph-hover-clear', this.onGraphHoverClear.bind(this), scope);
this.elem.bind('plotselected', this.onPlotSelected.bind(this));
this.elem.bind('plotclick', this.onPlotClick.bind(this));
scope.$on('$destroy', this.onScopeDestroy.bind(this));
// get graph legend element
if (this.elem && this.elem.parent) {
this.legendElem = this.elem.parent().find('.graph-legend')[0];
}
}
onRender(renderData) {
......@@ -82,7 +87,26 @@ class GraphElement {
const graphHeight = this.elem.height();
updateLegendValues(this.data, this.panel, graphHeight);
this.ctrl.events.emit('render-legend');
const { values, min, max, avg, current, total } = this.panel.legend;
const { alignAsTable, rightSide, sideWidth, sort, sortDesc, hideEmpty, hideZero } = this.panel.legend;
const legendOptions = { alignAsTable, rightSide, sideWidth, sort, sortDesc, hideEmpty, hideZero };
const valueOptions = { values, min, max, avg, current, total };
const legendProps: GraphLegendProps = {
seriesList: this.data,
hiddenSeries: this.ctrl.hiddenSeries,
...legendOptions,
...valueOptions,
onToggleSeries: this.ctrl.onToggleSeries,
onToggleSort: this.ctrl.onToggleSort,
onColorChange: this.ctrl.onColorChange,
onToggleAxis: this.ctrl.onToggleAxis,
};
const legendReactElem = React.createElement(Legend, legendProps);
ReactDOM.render(legendReactElem, this.legendElem, () => this.onLegendRenderingComplete());
}
onLegendRenderingComplete() {
this.render_panel();
}
onGraphHover(evt) {
......@@ -99,17 +123,20 @@ class GraphElement {
this.tooltip.show(evt.pos);
}
onPanelteardown() {
onPanelTeardown() {
this.thresholdManager = null;
if (this.plot) {
this.plot.destroy();
this.plot = null;
}
}
onLegendRenderingComplete() {
this.render_panel();
this.tooltip.destroy();
this.elem.off();
this.elem.remove();
console.log('react unmount');
ReactDOM.unmountComponentAtNode(this.legendElem);
}
onGraphHoverClear(event, info) {
......@@ -157,12 +184,6 @@ class GraphElement {
}
}
onScopeDestroy() {
this.tooltip.destroy();
this.elem.off();
this.elem.remove();
}
shouldAbortRender() {
if (!this.data) {
return true;
......
import './graph';
import './legend';
import './series_overrides_ctrl';
import './thresholds_form';
......@@ -244,67 +243,32 @@ class GraphCtrl extends MetricsPanelCtrl {
}
}
changeSeriesColor(series, color) {
onColorChange = (series, color) => {
series.setColor(color);
this.panel.aliasColors[series.alias] = series.color;
this.render();
}
};
toggleSeries(serie, event) {
if (event.ctrlKey || event.metaKey || event.shiftKey) {
if (this.hiddenSeries[serie.alias]) {
delete this.hiddenSeries[serie.alias];
} else {
this.hiddenSeries[serie.alias] = true;
}
} else {
this.toggleSeriesExclusiveMode(serie);
}
onToggleSeries = hiddenSeries => {
this.hiddenSeries = hiddenSeries;
this.render();
}
toggleSeriesExclusiveMode(serie) {
const hidden = this.hiddenSeries;
if (hidden[serie.alias]) {
delete hidden[serie.alias];
}
// check if every other series is hidden
const alreadyExclusive = _.every(this.seriesList, value => {
if (value.alias === serie.alias) {
return true;
}
return hidden[value.alias];
});
if (alreadyExclusive) {
// remove all hidden series
_.each(this.seriesList, value => {
delete this.hiddenSeries[value.alias];
});
} else {
// hide all but this serie
_.each(this.seriesList, value => {
if (value.alias === serie.alias) {
return;
}
};
this.hiddenSeries[value.alias] = true;
});
}
}
onToggleSort = (sortBy, sortDesc) => {
this.panel.legend.sort = sortBy;
this.panel.legend.sortDesc = sortDesc;
this.render();
};
toggleAxis(info) {
onToggleAxis = info => {
let override = _.find(this.panel.seriesOverrides, { alias: info.alias });
if (!override) {
override = { alias: info.alias };
this.panel.seriesOverrides.push(override);
}
info.yaxis = override.yaxis = info.yaxis === 2 ? 1 : 2;
override.yaxis = info.yaxis;
this.render();
}
};
addSeriesOverride(override) {
this.panel.seriesOverrides.push(override || {});
......
......@@ -53,7 +53,7 @@ export function SeriesOverridesCtrl($scope, $element, popoverSrv) {
element: $element.find('.dropdown')[0],
position: 'top center',
openOn: 'click',
template: '<series-color-picker series="series" onColorChange="colorSelected" />',
template: '<series-color-picker-popover series="series" onColorChange="colorSelected" />',
model: {
autoClose: true,
colorSelected: $scope.colorSelected,
......
......@@ -14,7 +14,7 @@
.graph-legend-series {
display: block;
padding-left: 0px;
padding-left: 4px;
}
.graph-legend-table .graph-legend-series {
......@@ -52,9 +52,6 @@
padding-top: 6px;
position: relative;
// fix for Firefox (white stripe on the right of scrollbar)
width: calc(100% - 1px);
.popover-content {
padding: 0;
}
......@@ -62,15 +59,6 @@
.graph-legend-content {
position: relative;
// fix for Firefox (white stripe on the right of scrollbar)
width: calc(100% - 1px);
}
.graph-legend-scroll {
position: relative;
overflow: auto !important;
padding: 1px;
}
.graph-legend-icon {
......@@ -82,8 +70,8 @@
.graph-legend-icon,
.graph-legend-alias,
.graph-legend-value {
display: inline;
cursor: pointer;
float: left;
white-space: nowrap;
font-size: 85%;
text-align: left;
......@@ -120,6 +108,11 @@
}
}
// Don't move series to the right if legend is on the right as well
.graph-panel--legend-right .graph-legend-series--right-y {
float: left;
}
.graph-legend-value {
padding-left: 6px;
}
......@@ -128,7 +121,8 @@
.body--phantomjs {
.graph-panel--legend-right {
.graph-legend {
display: inline-block;
display: block;
max-width: min-content;
}
.graph-panel__chart {
......@@ -138,24 +132,14 @@
.graph-legend-table {
display: table;
width: auto;
.graph-legend-scroll {
display: table;
}
}
}
}
.graph-legend-table {
tbody {
display: block;
position: relative;
overflow-y: auto;
overflow-x: hidden;
padding-bottom: 1px;
padding-right: 5px;
padding-left: 5px;
}
.graph-legend-series {
display: table-row;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment