Refactor RangeBar to just a simple styled component
This commit is contained in:
parent
73d7852309
commit
eea49adfee
|
|
@ -1,4 +1,3 @@
|
||||||
import React from "react";
|
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { ZoneType } from "zwiftout";
|
import { ZoneType } from "zwiftout";
|
||||||
|
|
||||||
|
|
@ -33,35 +32,33 @@ export const Bar = styled.div<BarProps>`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export type RangeBarProps = {
|
export type RangeBarProps = {
|
||||||
startZone: ZoneType;
|
|
||||||
endZone: ZoneType;
|
|
||||||
// Percentage of total workout length
|
// Percentage of total workout length
|
||||||
durationPercentage: number;
|
durationPercentage: number;
|
||||||
// Percentage of maximum intensity in workout
|
// Percentage of maximum intensity in workout
|
||||||
intensityStartPercentage: number;
|
maxIntensityPercentage: number;
|
||||||
intensityEndPercentage: number;
|
// Percentage relative to `maxIntensityPercentage`
|
||||||
|
relativeMinIntensityPercentage: number;
|
||||||
|
startZone: ZoneType;
|
||||||
|
endZone: ZoneType;
|
||||||
|
direction: "up" | "down";
|
||||||
};
|
};
|
||||||
|
|
||||||
const createUpPolygon = (middle: number) => `polygon(0% 100%, 100% 100%, 100% 0%, 0% ${middle}%)`;
|
const createUpPolygon = (middle: number) => `polygon(0% 100%, 100% 100%, 100% 0%, 0% ${middle}%)`;
|
||||||
const createDownPolygon = (middle: number) => `polygon(0% 0%, 0% 100%, 100% 100%, 100% ${middle}%)`;
|
const createDownPolygon = (middle: number) => `polygon(0% 0%, 0% 100%, 100% 100%, 100% ${middle}%)`;
|
||||||
|
|
||||||
export const RangeContainer = styled.div<{
|
export const RangeBar = styled.div<RangeBarProps>`
|
||||||
height: number;
|
|
||||||
width: number;
|
|
||||||
startZone: ZoneType;
|
|
||||||
endZone: ZoneType;
|
|
||||||
middle: number;
|
|
||||||
direction: "up" | "down";
|
|
||||||
}>`
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border-bottom-left-radius: 10px;
|
border-bottom-left-radius: 10px;
|
||||||
border-bottom-right-radius: 10px;
|
border-bottom-right-radius: 10px;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
margin-right: 0.1%;
|
margin-right: 0.1%;
|
||||||
/* exclude 0.1% margin from bar width */
|
/* exclude 0.1% margin from bar width */
|
||||||
width: ${(props) => props.width - 0.1}%;
|
width: ${(props) => props.durationPercentage - 0.1}%;
|
||||||
height: ${(props) => props.height}%;
|
height: ${(props) => props.maxIntensityPercentage}%;
|
||||||
clip-path: ${({ direction, middle }) => (direction === "up" ? createUpPolygon(middle) : createDownPolygon(middle))};
|
clip-path: ${({ direction, relativeMinIntensityPercentage }) =>
|
||||||
|
direction === "up"
|
||||||
|
? createUpPolygon(relativeMinIntensityPercentage)
|
||||||
|
: createDownPolygon(relativeMinIntensityPercentage)};
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
to right,
|
to right,
|
||||||
${(props) => zoneColorsMap[props.startZone]},
|
${(props) => zoneColorsMap[props.startZone]},
|
||||||
|
|
@ -69,22 +66,3 @@ export const RangeContainer = styled.div<{
|
||||||
);
|
);
|
||||||
transition: width 0.1s, height 0.1s, background-color 0.1s;
|
transition: width 0.1s, height 0.1s, background-color 0.1s;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const RangeBar: React.FC<RangeBarProps> = (props) => {
|
|
||||||
const minHeightPercentage = Math.min(props.intensityStartPercentage, props.intensityEndPercentage);
|
|
||||||
const maxHeightPercentage = Math.max(props.intensityStartPercentage, props.intensityEndPercentage);
|
|
||||||
const bottomHeight = (minHeightPercentage / maxHeightPercentage) * 100;
|
|
||||||
const topHeight = 100 - bottomHeight;
|
|
||||||
const direction = props.intensityStartPercentage < props.intensityEndPercentage ? "up" : "down";
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RangeContainer
|
|
||||||
height={maxHeightPercentage}
|
|
||||||
width={props.durationPercentage}
|
|
||||||
middle={topHeight}
|
|
||||||
direction={direction}
|
|
||||||
startZone={props.startZone}
|
|
||||||
endZone={props.endZone}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,21 @@ const Plot = styled.div`
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const toRangeBarProps = (interval: Interval, workoutDuration: Duration, maxIntensity: Intensity): RangeBarProps => ({
|
const toRangeBarProps = (interval: Interval, workoutDuration: Duration, maxIntensity: Intensity): RangeBarProps => {
|
||||||
startZone: intensityValueToZoneType(interval.intensity.start),
|
const minIntensityPercentage =
|
||||||
endZone: intensityValueToZoneType(interval.intensity.end),
|
(Math.min(interval.intensity.start, interval.intensity.end) / maxIntensity.value) * 100;
|
||||||
durationPercentage: (interval.duration.seconds / workoutDuration.seconds) * 100,
|
const maxIntensityPercentage =
|
||||||
intensityStartPercentage: (interval.intensity.start / maxIntensity.value) * 100,
|
(Math.max(interval.intensity.start, interval.intensity.end) / maxIntensity.value) * 100;
|
||||||
intensityEndPercentage: (interval.intensity.end / maxIntensity.value) * 100,
|
|
||||||
});
|
return {
|
||||||
|
durationPercentage: (interval.duration.seconds / workoutDuration.seconds) * 100,
|
||||||
|
maxIntensityPercentage: maxIntensityPercentage,
|
||||||
|
relativeMinIntensityPercentage: 100 - (minIntensityPercentage / maxIntensityPercentage) * 100,
|
||||||
|
direction: interval.intensity.start < interval.intensity.end ? "up" : "down",
|
||||||
|
startZone: intensityValueToZoneType(interval.intensity.start),
|
||||||
|
endZone: intensityValueToZoneType(interval.intensity.end),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const WorkoutPlot: React.FC<{ intervals: Interval[] }> = ({ intervals }) => {
|
export const WorkoutPlot: React.FC<{ intervals: Interval[] }> = ({ intervals }) => {
|
||||||
const workoutDuration = totalDuration(intervals);
|
const workoutDuration = totalDuration(intervals);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue