Support new option getRingColor to determine text and legend color.

Signed-off-by: Aramis Sennyey <sennyeya@amazon.com>
This commit is contained in:
Aramis Sennyey
2023-02-24 12:56:30 -05:00
parent 4e5891524c
commit 1a2fa2f4c7
10 changed files with 67 additions and 18 deletions
@@ -18,9 +18,10 @@ import React from 'react';
import { renderInTestApp } from '@backstage/test-utils';
import GetBBoxPolyfill from '../../utils/polyfills/getBBox';
import Radar, { Props } from './Radar';
import Radar from './Radar';
import type { RadarProps } from './types';
const minProps: Props = {
const minProps: RadarProps = {
width: 500,
height: 200,
quadrants: [{ id: 'languages', name: 'Languages' }],
@@ -15,27 +15,20 @@
*/
import React, { useMemo, useRef, useState } from 'react';
import type { Entry, Quadrant, Ring } from '../../utils/types';
import type { Entry } from '../../utils/types';
import RadarPlot from '../RadarPlot';
import { RadarProps } from './types';
import { adjustEntries, adjustQuadrants, adjustRings } from './utils';
export type Props = {
width: number;
height: number;
quadrants: Quadrant[];
rings: Ring[];
entries: Entry[];
svgProps?: object;
};
const Radar = ({
width,
height,
quadrants,
rings,
entries,
getRingColor,
...props
}: Props): JSX.Element => {
}: RadarProps): JSX.Element => {
const radius = Math.min(width, height) / 2;
// State
@@ -66,6 +59,7 @@ const Radar = ({
return (
<svg ref={node} width={width} height={height} {...props.svgProps}>
<RadarPlot
getRingColor={getRingColor}
width={width}
height={height}
radius={radius}
@@ -0,0 +1,27 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed 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 { Quadrant, Ring, Entry } from '../../utils/types';
import { Color } from 'csstype';
export type RadarProps = {
width: number;
height: number;
quadrants: Quadrant[];
rings: Ring[];
entries: Entry[];
svgProps?: object;
getRingColor?: (ring: Ring) => Color;
};
@@ -20,7 +20,8 @@ import React, { useEffect } from 'react';
import useAsync from 'react-use/lib/useAsync';
import { RadarEntry, techRadarApiRef, TechRadarLoaderResponse } from '../api';
import Radar from '../components/Radar';
import { Entry } from '../utils/types';
import { Entry, Ring } from '../utils/types';
import { RadarProps } from './Radar/types';
const useTechRadarLoader = (id: string | undefined) => {
const errorApi = useApi(errorApiRef);
@@ -89,6 +90,8 @@ export interface TechRadarComponentProps {
* Text to filter {@link RadarEntry} inside Tech Radar
*/
searchText?: string;
getRingColor?: RadarProps['getRingColor'];
}
/**
@@ -102,6 +105,7 @@ export interface TechRadarComponentProps {
*/
export function RadarComponent(props: TechRadarComponentProps) {
const { loading, error, value: data } = useTechRadarLoader(props.id);
const { getRingColor = (ring: Ring) => ring.color } = props;
const mapToEntries = (
loaderResponse: TechRadarLoaderResponse,
@@ -136,6 +140,7 @@ export function RadarComponent(props: TechRadarComponentProps) {
{!loading && !error && data && (
<Radar
{...props}
getRingColor={getRingColor}
rings={data.rings}
quadrants={data.quadrants}
entries={mapToEntries(data)}
@@ -17,10 +17,12 @@
import React from 'react';
import { makeStyles, Theme } from '@material-ui/core';
import type { Ring } from '../../utils/types';
import { RadarProps } from '../Radar/types';
export type Props = {
radius: number;
rings: Ring[];
getRingColor?: RadarProps['getRingColor'];
};
const useStyles = makeStyles<Theme>(theme => ({
@@ -47,7 +49,7 @@ const useStyles = makeStyles<Theme>(theme => ({
// A component for the background grid of the radar, with axes, rings etc. It will render around the origin, i.e.
// assume that (0, 0) is in the middle of the drawing.
const RadarGrid = (props: Props) => {
const { radius, rings } = props;
const { radius, rings, getRingColor } = props;
const classes = useStyles(props);
const makeRingNode = (ringIndex: number, ringRadius?: number) => [
@@ -63,7 +65,9 @@ const RadarGrid = (props: Props) => {
y={ringRadius !== undefined ? -ringRadius + 42 : undefined}
textAnchor="middle"
className={classes.text}
style={{ fill: rings[ringIndex].color }}
style={{
fill: getRingColor ? getRingColor(rings[ringIndex]) : undefined,
}}
>
{rings[ringIndex].name}
</text>,
@@ -88,6 +88,7 @@ const RadarLegend = ({
entries,
onEntryMouseEnter,
onEntryMouseLeave,
getRingColor,
...props
}: RadarLegendProps): JSX.Element => {
const classes = useStyles(props);
@@ -96,6 +97,7 @@ const RadarLegend = ({
<g data-testid="radar-legend">
{quadrants.map(quadrant => (
<RadarLegendQuadrant
getRingColor={getRingColor}
key={quadrant.id}
segments={setupSegments(entries)}
quadrant={quadrant}
@@ -28,6 +28,7 @@ type RadarLegendQuadrantProps = {
classes: ClassNameMap<string>;
onEntryMouseEnter: RadarLegendProps['onEntryMouseEnter'];
onEntryMouseLeave: RadarLegendProps['onEntryMouseLeave'];
getRingColor: RadarLegendProps['getRingColor'];
};
export const RadarLegendQuadrant = ({
@@ -37,6 +38,7 @@ export const RadarLegendQuadrant = ({
classes,
onEntryMouseEnter,
onEntryMouseLeave,
getRingColor,
}: RadarLegendQuadrantProps) => {
return (
<foreignObject
@@ -55,6 +57,7 @@ export const RadarLegendQuadrant = ({
key={ring.id}
ring={ring}
classes={classes}
getRingColor={getRingColor}
entries={getSegment(segments, quadrant, ring)}
onEntryMouseEnter={onEntryMouseEnter}
onEntryMouseLeave={onEntryMouseLeave}
@@ -26,6 +26,7 @@ type RadarLegendRingProps = {
classes: ClassNameMap<string>;
onEntryMouseEnter?: RadarLegendProps['onEntryMouseEnter'];
onEntryMouseLeave?: RadarLegendProps['onEntryMouseEnter'];
getRingColor?: RadarLegendProps['getRingColor'];
};
export const RadarLegendRing = ({
@@ -34,10 +35,14 @@ export const RadarLegendRing = ({
classes,
onEntryMouseEnter,
onEntryMouseLeave,
getRingColor,
}: RadarLegendRingProps) => {
return (
<div data-testid="radar-ring" key={ring.id} className={classes.ring}>
<h3 className={classes.ringHeading} style={{ color: ring.color }}>
<h3
className={classes.ringHeading}
style={{ color: getRingColor ? getRingColor(ring) : undefined }}
>
{ring.name}
</h3>
{entries.length === 0 ? (
@@ -15,6 +15,7 @@
*/
import { Entry, Quadrant, Ring } from '../../utils/types';
import { RadarProps } from '../Radar/types';
export type Segments = {
[k: number]: { [k: number]: Entry[] };
@@ -26,4 +27,6 @@ export type RadarLegendProps = {
entries: Entry[];
onEntryMouseEnter?: (entry: Entry) => void;
onEntryMouseLeave?: (entry: Entry) => void;
getRingColor?: RadarProps['getRingColor'];
};
@@ -22,6 +22,7 @@ import RadarEntry from '../RadarEntry';
import RadarBubble from '../RadarBubble';
import RadarFooter from '../RadarFooter';
import RadarLegend from '../RadarLegend';
import { RadarProps } from '../Radar/types';
export type Props = {
width: number;
@@ -33,6 +34,8 @@ export type Props = {
activeEntry?: Entry;
onEntryMouseEnter?: (entry: Entry) => void;
onEntryMouseLeave?: (entry: Entry) => void;
getRingColor?: RadarProps['getRingColor'];
};
// A component that draws the radar circle.
@@ -47,6 +50,7 @@ const RadarPlot = (props: Props): JSX.Element => {
activeEntry,
onEntryMouseEnter,
onEntryMouseLeave,
getRingColor,
} = props;
return (
@@ -61,9 +65,10 @@ const RadarPlot = (props: Props): JSX.Element => {
onEntryMouseLeave={
onEntryMouseLeave && (entry => onEntryMouseLeave(entry))
}
getRingColor={getRingColor}
/>
<g transform={`translate(${width / 2}, ${height / 2})`}>
<RadarGrid radius={radius} rings={rings} />
<RadarGrid radius={radius} rings={rings} getRingColor={getRingColor} />
<RadarFooter x={-0.5 * width} y={0.5 * height} />
{entries.map(entry => (
<RadarEntry