Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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 `stepped color feature` to `EuiColorStops` ([#4613](https://github.com/elastic/eui/pull/4613))
Comment thread
flash1293 marked this conversation as resolved.
Outdated
- Added `panelProps` to `EuiPopover` ([#4573](https://github.com/elastic/eui/pull/4573))
- Updated the default of the `EuiPopover`s `ownFocus` prop from `false` to `true` ([#4551](https://github.com/elastic/eui/pull/4551))

Expand Down
27 changes: 26 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,10 @@
import React, { useState } from 'react';

import { EuiColorStops, EuiFormRow } from '../../../../src/components';
import {
EuiColorStops,
EuiFormRow,
EuiRange,
} from '../../../../src/components';

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

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

const [extendedColorStops, setExtendedColorStops] = useState([
{
Expand Down Expand Up @@ -87,6 +93,25 @@ export default () => {
stopType="fixed"
/>
</EuiFormRow>
<EuiFormRow label="Stepped color segments">
<EuiColorStops
label="Stepped color segments"
onChange={setSteppedColorStops}
colorStops={steppedColorStops}
stepNumber={value}
min={0}
max={100}
stopType="stepped"
/>
</EuiFormRow>
<EuiRange
value={value}
onChange={(e) => setValue(e.target.value)}
showInput
aria-label="An example of EuiRange"
min={2}
max={20}
/>
</React.Fragment>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -812,3 +812,114 @@ exports[`renders readOnly EuiColorStops 1`] = `
</div>
</div>
`;

exports[`renders stepped stop EuiColorStops 1`] = `
<div
class="euiRangeWrapper euiColorStops testClass1 testClass2"
data-test-subj="euiColorStops"
tabindex="0"
>
<p
aria-live="polite"
class="euiScreenReaderOnly"
>
Test: Color stop picker. Each stop consists of a number and corresponding color value. Use the Down and Up arrow keys to select individual stops. Press the Enter key to create a new stop.
</p>
<div
class="euiRangeTrack"
>
<div
class="euiRangeHighlight euiColorStops__highlight"
>
<div
class="euiRangeHighlight__progress"
style="background:linear-gradient(to right, currentColor 0%, #ff0000 0% 10%, #8e7100 10% 20%, #1ce300 20% 30%, #002bd5 30% 40%, #0000ff 40% 50%, #0000ff 50% 60%, #0000ff 60% 70%, #0000ff 70% 80%, #0000ff 80% 90%, #0000ff 90% 100%);margin-left:0%;width:100%"
/>
</div>
<div
class="euiColorStops__addContainer"
data-test-subj="euiColorStopsAdd"
>
<div
class="euiColorStops__addTarget"
style="left:0%"
/>
</div>
<div
class="euiPopover euiPopover--anchorDownCenter euiColorStopPopover"
style="left:0%"
>
<div
class="euiPopover__anchor euiColorStopPopover__anchor"
>
<button
aria-disabled="false"
aria-label="Press the Enter key to modify this stop. Press Escape to focus the group"
aria-valuemax="24"
aria-valuemin="0"
aria-valuenow="0"
aria-valuetext="Stop: 0, Color: #FF0000 (1 of 3)"
class="euiRangeThumb euiColorStopThumb"
data-index="euiColorStop_0"
data-test-subj="euiColorStopThumb"
role="slider"
style="background:rgb(255,0,0)"
tabindex="-1"
title="Click to edit, drag to reposition"
type="button"
/>
</div>
</div>
<div
class="euiPopover euiPopover--anchorDownCenter euiColorStopPopover"
style="left:21%"
>
<div
class="euiPopover__anchor euiColorStopPopover__anchor"
>
<button
aria-disabled="false"
aria-label="Press the Enter key to modify this stop. Press Escape to focus the group"
aria-valuemax="34"
aria-valuemin="1"
aria-valuenow="25"
aria-valuetext="Stop: 25, Color: #00FF00 (2 of 3)"
class="euiRangeThumb euiColorStopThumb"
data-index="euiColorStop_1"
data-test-subj="euiColorStopThumb"
role="slider"
style="background:rgb(0,255,0)"
tabindex="-1"
title="Click to edit, drag to reposition"
type="button"
/>
</div>
</div>
<div
class="euiPopover euiPopover--anchorDownCenter euiColorStopPopover"
style="left:29.4%"
>
<div
class="euiPopover__anchor euiColorStopPopover__anchor"
>
<button
aria-disabled="false"
aria-label="Press the Enter key to modify this stop. Press Escape to focus the group"
aria-valuemax="100"
aria-valuemin="26"
aria-valuenow="35"
aria-valuetext="Stop: 35, Color: #0000FF (3 of 3)"
class="euiRangeThumb euiColorStopThumb"
data-index="euiColorStop_2"
data-test-subj="euiColorStopThumb"
role="slider"
style="background:rgb(0,0,255)"
tabindex="-1"
title="Click to edit, drag to reposition"
type="button"
/>
</div>
</div>
</div>
</div>
`;
16 changes: 16 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 @@ -172,6 +172,22 @@ test('renders fixed stop EuiColorStops', () => {
expect(colorStops).toMatchSnapshot();
});

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

test('renders empty EuiColorStops', () => {
const colorStops = render(
<EuiColorStops
Expand Down
43 changes: 35 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 All @@ -45,6 +49,8 @@ import { EuiScreenReaderOnly } from '../../accessibility';
import { EuiRangeHighlight } from '../../form/range/range_highlight';
import { EuiRangeTrack } from '../../form/range/range_track';
import { EuiRangeWrapper } from '../../form/range/range_wrapper';
// import { colorPalette } from '../../../services/color/color_palette';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

unused imports, please remove

// import { EuiColorPaletteDisplayFixed } from '../color_palette_display/color_palette_display_fixed';

export interface EuiColorStopsProps extends CommonProps {
addColor?: ColorStop['color'];
Expand All @@ -62,7 +68,8 @@ export interface EuiColorStopsProps extends CommonProps {
max?: number;
min?: number;
label: string;
stopType?: 'fixed' | 'gradient';
stopType?: 'fixed' | 'gradient' | 'stepped';
stepNumber?: number;
mode?: EuiColorPickerProps['mode'];
swatches?: EuiColorPickerProps['swatches'];
showAlpha?: EuiColorPickerProps['showAlpha'];
Expand Down Expand Up @@ -139,6 +146,7 @@ export const EuiColorStops: FunctionComponent<EuiColorStopsProps> = ({
className,
label,
stopType = 'gradient',
stepNumber = 10,
swatches,
showAlpha = false,
}) => {
Expand Down Expand Up @@ -291,7 +299,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 @@ -440,10 +447,30 @@ 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') {
const trailingPercentage = colorStops[0].stop;
const steppedColors = getSteppedGradient(colorStops, stepNumber);
let steppedGradient = '';
const percentage = (100 - trailingPercentage) / steppedColors.length;
Comment thread
anuragxxd marked this conversation as resolved.
Outdated
let percentageSteps =
(100 - 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 @@ -483,7 +510,7 @@ export const EuiColorStops: FunctionComponent<EuiColorStopsProps> = ({
max={max || rangeMax}
lowerValue={min || rangeMin}
upperValue={max || rangeMax}
background={background}
background={gradient}
compressed={compressed}
/>
<div
Expand Down
12 changes: 11 additions & 1 deletion 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
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';
34 changes: 34 additions & 0 deletions src/services/color/stepped_gradient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* 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 finalStops = [0, ...colors.map((item) => item.stop / 100), 1];

@flash1293 flash1293 Mar 10, 2021

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@git-anurag-hub This logic always assumes a min of 0 and a max of 100, but that's not the case - the user can configure min and max. This logic needs to be aware. As far as I can tell that's also the reason for the behavior described here: #4613 (review)

The color segments should be done between the first and last stop

const color = [
colors[0].color,
...colors.map((item) => item.color),
colors[colors.length - 1].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