Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## [`master`](https://github.com/elastic/eui/tree/master)

- Added `stepNumber` prop and `stepped` as `stopType` option to `EuiColorStops` ([#4613](https://github.com/elastic/eui/pull/4613))
- Expanded `display` prop of `EuiCard` to inherit `color` values from `EuiPanel` ([#4649](https://github.com/elastic/eui/pull/4649))
- Added `element` prop to `EuiPanel` for forcing to `div` or `button` ([#4649](https://github.com/elastic/eui/pull/4649))
- Increased padding on `EuiCheckableCard` with refactor to use `EuiSplitPanel` ([#4649](https://github.com/elastic/eui/pull/4649))
Expand Down
12 changes: 12 additions & 0 deletions src-docs/src/views/color_picker/color_picker_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,17 @@ const colorStopsSnippetFixed = `<EuiColorStops
/>
`;

const colorStopsSnippetStepped = `<EuiColorStops
label="Stepped color segments"
onChange={handleChange}
colorStops={colorStops}
min={0}
max={100}
stopType="stepped"
stepNumber={stepNumber}
/>
`;

import ColorStopsRange from './color_stops_range';
const colorStopsRangeSource = require('!!raw-loader!./color_stops_range');
const colorStopsRangeHtml = renderToHtml(ColorStopsRange);
Expand Down Expand Up @@ -477,6 +488,7 @@ export const ColorPickerExample = {
colorStopsSnippetStandard,
colorStopsSnippetAdd,
colorStopsSnippetFixed,
colorStopsSnippetStepped,
],
demo: <ColorStops />,
},
Expand Down
63 changes: 62 additions & 1 deletion src-docs/src/views/color_picker/color_stops.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import React, { useState } from 'react';

import { EuiColorStops, EuiFormRow } from '../../../../src/components';
import {
EuiColorStops,
EuiFormRow,
EuiRange,
EuiFlexGroup,
EuiFlexItem,
EuiButtonEmpty,
EuiPopover,
} from '../../../../src/components';

import { useColorStopsState } from '../../../../src/services';

Expand All @@ -12,6 +20,9 @@ export default () => {
addRandomColor,
] = useColorStopsState(true);
const [fixedColorStops, setFixedColorStops] = useColorStopsState(true);
const [steppedColorStops, setSteppedColorStops] = useColorStopsState(true);
const [value, setValue] = useState(10);
const [isPopoverOpen, setIsPopoverOpen] = useState(false);

const [extendedColorStops, setExtendedColorStops] = useState([
{
Expand All @@ -38,6 +49,21 @@ export default () => {
setEmptyColorStops(colorStops);
};

const onButtonClick = () =>
setIsPopoverOpen((isPopoverOpen) => !isPopoverOpen);
const closePopover = () => setIsPopoverOpen(false);

const button = (
<EuiButtonEmpty
onClick={onButtonClick}
iconType="controlsVertical"
aria-label="Open settings"
color="text"
size="xs">
Steps
</EuiButtonEmpty>
);

return (
<React.Fragment>
<EuiFormRow label="Empty start">
Expand Down Expand Up @@ -87,6 +113,41 @@ export default () => {
stopType="fixed"
/>
</EuiFormRow>

<EuiFormRow label="Stepped color segments">
<EuiFlexGroup alignItems="center" gutterSize="xs">
<EuiFlexItem>
<EuiColorStops
label="Stepped color segments"
onChange={setSteppedColorStops}
colorStops={steppedColorStops}
stepNumber={value}
min={0}
max={100}
stopType="stepped"
/>
</EuiFlexItem>

<EuiFlexItem grow={false}>
<EuiPopover
panelStyle={{ minWidth: 380 }}
button={button}
isOpen={isPopoverOpen}
closePopover={closePopover}>
<EuiFormRow label="Number of steps" display="columnCompressed">
<EuiRange
value={value}
onChange={(e) => setValue(parseInt(e.target.value))}
showInput
aria-label="Change the number of steps"
min={2}
max={20}
/>
</EuiFormRow>
</EuiPopover>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFormRow>
</React.Fragment>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -812,3 +812,11 @@ exports[`renders readOnly EuiColorStops 1`] = `
</div>
</div>
`;

exports[`renders stepped stop EuiColorStops 1`] = `
Object {
"background": "linear-gradient(to right, currentColor 0%, #ff0000 0% 2.94%, #d72800 2.94% 5.88%, #b04f00 5.880000000000001% 8.82%, #887700 8.82% 11.76%, #609f00 11.76% 14.7%, #39c600 14.700000000000001% 17.64%, #11ee00 17.64% 20.580000000000002%, #00c639 20.580000000000002% 23.520000000000003%, #00639c 23.520000000000003% 26.460000000000004%, #0000ff 26.460000000000004% 29.400000000000006%)",
"marginLeft": "0%",
"width": "100%",
}
`;
18 changes: 18 additions & 0 deletions src/components/color_picker/color_stops/color_stops.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,24 @@ test('renders fixed stop EuiColorStops', () => {
expect(colorStops).toMatchSnapshot();
});

test('renders stepped stop EuiColorStops', () => {
const colorStops = mount(
<EuiColorStops
label="Test"
onChange={onChange}
colorStops={colorStopsArray}
min={0}
max={100}
stopType="stepped"
stepNumber={10}
{...requiredProps}
/>
);
expect(
colorStops.find('.euiRangeHighlight__progress').prop('style')
).toMatchSnapshot();
});

test('renders empty EuiColorStops', () => {
const colorStops = render(
<EuiColorStops
Expand Down
53 changes: 45 additions & 8 deletions src/components/color_picker/color_stops/color_stops.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ import React, {
import classNames from 'classnames';

import { CommonProps } from '../../common';
import { keys, DEFAULT_VISUALIZATION_COLOR } from '../../../services';
import {
keys,
DEFAULT_VISUALIZATION_COLOR,
getSteppedGradient,
} from '../../../services';
import { EuiColorStopThumb, ColorStop } from './color_stop_thumb';
import {
addStop,
Expand Down Expand Up @@ -63,7 +67,17 @@ export interface EuiColorStopsProps extends CommonProps {
max?: number;
min?: number;
label: string;
stopType?: 'fixed' | 'gradient';
/**
* Specify the type of stops:
* `fixed`: individual color blocks.
* `gradient`: each color fades into the next.
* `stepped`: interpolation between colors with a fixed number of steps.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added an explanation for each stopType. Not sure if this is the best explanation for what the stepped option does. A better suggestion is welcome. 😄

*/
stopType?: 'fixed' | 'gradient' | 'stepped';
/**
* Only works when `stopType="stepped"`
*/
stepNumber?: number;
mode?: EuiColorPickerProps['mode'];
swatches?: EuiColorPickerProps['swatches'];
showAlpha?: EuiColorPickerProps['showAlpha'];
Expand Down Expand Up @@ -157,6 +171,7 @@ export const EuiColorStops: FunctionComponent<EuiColorStopsProps> = ({
className,
label,
stopType = 'gradient',
stepNumber = 10,
swatches,
showAlpha = false,
valueInputProps,
Expand Down Expand Up @@ -310,7 +325,6 @@ export const EuiColorStops: FunctionComponent<EuiColorStopsProps> = ({
if (isNotInteractive || isTargetAThumb(e.target) || !wrapperRef) return;
const newStop = getStopFromMouseLocationFn({ x: e.pageX, y: e.pageY });
const newColorStops = addDefinedStop(colorStops, newStop, addColor);

setFocusStopOnUpdate(newStop);
handleOnChange(newColorStops);
};
Expand Down Expand Up @@ -461,10 +475,33 @@ export const EuiColorStops: FunctionComponent<EuiColorStopsProps> = ({
)}`;
}
};
const linearGradient = sortedStops.map(
stopType === 'gradient' ? gradientStop : fixedStop
);
const background = `linear-gradient(to right,${linearGradient})`;

let gradient: string = '';

if (stopType === 'stepped' && positions.length > 0) {
const trailingPercentage = positions[0];
const endingPercentage = positions[positions.length - 1];
const steppedColors = getSteppedGradient(colorStops, stepNumber);
let steppedGradient = '';
const percentage =
(endingPercentage - trailingPercentage) / steppedColors.length;
let percentageSteps =
(endingPercentage - trailingPercentage) / steppedColors.length +
trailingPercentage;
steppedColors.forEach((color) => {
steppedGradient = steppedGradient.concat(
`${color} ${percentageSteps - percentage}% ${percentageSteps}%, `
);
percentageSteps = percentageSteps + percentage;
});
steppedGradient = steppedGradient.substring(0, steppedGradient.length - 2);
gradient = `linear-gradient(to right, currentColor ${trailingPercentage}%, ${steppedGradient})`;
} else {
const linearGradient = sortedStops.map(
stopType === 'gradient' ? gradientStop : fixedStop
);
gradient = `linear-gradient(to right,${linearGradient})`;
}

return (
<EuiRangeWrapper
Expand Down Expand Up @@ -504,7 +541,7 @@ export const EuiColorStops: FunctionComponent<EuiColorStopsProps> = ({
max={max || rangeMax}
lowerValue={min || rangeMin}
upperValue={max || rangeMax}
background={background}
background={gradient}
compressed={compressed}
/>
<div
Expand Down
14 changes: 12 additions & 2 deletions src/components/color_picker/color_stops/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,17 @@ export const addDefinedStop = (
stop,
color,
};
return [...colorStops, newStop];
colorStops = [...colorStops, newStop];
colorStops.sort((a, b) => {
if (a.stop < b.stop) {
return -1;
}
if (a.stop > b.stop) {
return 1;
}
return 0;
});
return colorStops;
};

export const addStop = (
Expand Down Expand Up @@ -125,7 +135,7 @@ export const getPositionFromStop = (
return parseFloat(
(
((stop - min) / (max - min)) *
calculateScale(ref ? ref.clientWidth : 100)
calculateScale(ref && ref.clientWidth > 0 ? ref.clientWidth : 100)
).toFixed(1)
);
};
1 change: 1 addition & 0 deletions src/components/form/range/range_highlight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const EuiRangeHighlight: FunctionComponent<EuiRangeHighlightProps> = ({
// const rangeWidth = (value - min) / (max - min);
const leftPosition = (lowerValue - min) / (max - min);
const rangeWidth = (upperValue - lowerValue) / (max - min);

const rangeWidthStyle = {
background,
marginLeft: `${leftPosition * 100}%`,
Expand Down
1 change: 1 addition & 0 deletions src/services/color/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ export {
euiPaletteGray,
} from './eui_palettes';
export { rgbDef, HSV, RGB } from './color_types';
export { getSteppedGradient } from './stepped_gradient';
32 changes: 32 additions & 0 deletions src/services/color/stepped_gradient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import chroma from 'chroma-js';
import { ColorStop } from '../../components/color_picker/color_stops';

export const getSteppedGradient = function (
colors: ColorStop[],
steps: number
) {
const range = colors[colors.length - 1].stop - colors[0].stop;
const offset = colors[0].stop;
const finalStops = [...colors.map((item) => (item.stop - offset) / range)];
const color = [...colors.map((item) => item.color)];
return chroma.scale(color).domain(finalStops).colors(steps);
};
1 change: 1 addition & 0 deletions src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export {
euiPaletteWarm,
euiPaletteGray,
HSV,
getSteppedGradient,
} from './color';

export { useColorPickerState, useColorStopsState } from './color_picker';
Expand Down