From ec791958bc100f54bc093cfbc082e4d832e62450 Mon Sep 17 00:00:00 2001 From: David Baetge Date: Fri, 10 Jun 2022 02:04:12 +0200 Subject: [PATCH 1/2] Added react-fullscreen and fullscreen button to line diagrams. [GH-6] --- package.json | 1 + skins/weewx-wdc/src/js/assets/maximize.tsx | 25 ++++ skins/weewx-wdc/src/js/diagrams/line.tsx | 131 +++++++++++---------- skins/weewx-wdc/src/scss/index.scss | 30 +++++ yarn.lock | 12 ++ 5 files changed, 137 insertions(+), 62 deletions(-) create mode 100644 skins/weewx-wdc/src/js/assets/maximize.tsx diff --git a/package.json b/package.json index df0a9a58..5ae71809 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "prop-types": "^15.8.1", "react": "^18.1.0", "react-dom": "^18.1.0", + "react-full-screen": "^1.1.1", "use-debounce": "^8.0.1", "workbox-cacheable-response": "^6.5.3", "workbox-expiration": "^6.5.3", diff --git a/skins/weewx-wdc/src/js/assets/maximize.tsx b/skins/weewx-wdc/src/js/assets/maximize.tsx new file mode 100644 index 00000000..153a1a1a --- /dev/null +++ b/skins/weewx-wdc/src/js/assets/maximize.tsx @@ -0,0 +1,25 @@ +import React, { MouseEventHandler } from "react"; + +export const Maximize = ({ onClick }: { onClick: MouseEventHandler }) => { + return ( + + + + + + ); +}; diff --git a/skins/weewx-wdc/src/js/diagrams/line.tsx b/skins/weewx-wdc/src/js/diagrams/line.tsx index ece6b5f0..acbf11f1 100644 --- a/skins/weewx-wdc/src/js/diagrams/line.tsx +++ b/skins/weewx-wdc/src/js/diagrams/line.tsx @@ -1,5 +1,6 @@ import React, { FunctionComponent } from "react"; import { ResponsiveLine } from "@nivo/line"; +import { FullScreen, useFullScreenHandle } from "react-full-screen"; import { DiagramBaseProps } from "./types"; import { TooltipLine } from "../components/tooltip-line"; @@ -15,14 +16,14 @@ import { } from "../util/util"; import { sliceTooltip } from "../components/tooltip-slice"; import { useMediaQuery } from "@react-hook/media-query"; +import { Maximize } from "../assets/maximize"; export const LineDiagram: FunctionComponent = ( props: DiagramBaseProps ): React.ReactElement => { const small = useMediaQuery("(max-width: 672px)"); const timeDifferenceInMonths = getTimeDifferenceInMonths(props.data[0].data); - - console.log(timeDifferenceInMonths); + const handle = useFullScreenHandle(); let format = "%H:%M"; let tickValues = "every 3 hours"; @@ -81,66 +82,72 @@ export const LineDiagram: FunctionComponent = ( ]; } + const lineDiagram = ( + item.y)) - + getyScaleOffset(props.observation) + } + enableCrosshair={true} + enablePoints={true} + enableSlices={props.data.length > 1 ? "x" : false} + sliceTooltip={(slice) => sliceTooltip(slice)} + isInteractive={true} + legends={ + props.data.length > 1 + ? [ + { + anchor: "top-right", + direction: "row", + itemWidth: 120, + itemHeight: 20, + itemsSpacing: 10, + }, + ] + : undefined + } + lineWidth={2} + margin={getMargins(props.observation)} + markers={markers} + pointSize={5} + tooltip={(point) => } + useMesh={true} + xScale={{ + precision: "minute", + type: "time", + format: "%s", + }} + yScale={getyScale(props.observation, combinedData)} + xFormat="time:%Y/%m/%d %H:%M" + yFormat={(value) => `${value} ${props.unit}`} + /> + ); + return ( -
- item.y)) - - getyScaleOffset(props.observation) - } - enableCrosshair={true} - enablePoints={true} - enableSlices={props.data.length > 1 ? "x" : false} - sliceTooltip={(slice) => sliceTooltip(slice)} - isInteractive={true} - legends={ - props.data.length > 1 - ? [ - { - anchor: "top-right", - direction: "row", - itemWidth: 120, - itemHeight: 20, - itemsSpacing: 10, - }, - ] - : undefined - } - lineWidth={2} - margin={getMargins(props.observation)} - markers={markers} - pointSize={5} - tooltip={(point) => } - useMesh={true} - xScale={{ - precision: "minute", - type: "time", - format: "%s", - }} - yScale={getyScale(props.observation, combinedData)} - xFormat="time:%Y/%m/%d %H:%M" - yFormat={(value) => `${value} ${props.unit}`} - /> -
+ <> + +
{lineDiagram}
+ {lineDiagram} + ); }; diff --git a/skins/weewx-wdc/src/scss/index.scss b/skins/weewx-wdc/src/scss/index.scss index 56ce569a..894755c8 100644 --- a/skins/weewx-wdc/src/scss/index.scss +++ b/skins/weewx-wdc/src/scss/index.scss @@ -256,6 +256,36 @@ bx-tabs { } } } + .diagram { + position: relative; + .maximize { + transition: opacity 250ms ease; + opacity: 0; + cursor: pointer; + position: absolute; + right: 0; + top: -#{$spacing-06}; + @include carbon--breakpoint-down(lg) { + opacity: 1; + } + } + .fullscreen { + display: none; + &.fullscreen-enabled { + display: block; + padding: $spacing-08 !important; + background: white; + @include carbon--breakpoint-down(lg) { + padding: $spacing-04 !important; + } + } + } + } + &:hover { + .maximize { + opacity: 1; + } + } } .diagram-tile, diff --git a/yarn.lock b/yarn.lock index 603975bb..3df547e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2249,6 +2249,11 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= +fscreen@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fscreen/-/fscreen-1.2.0.tgz#1a8c88e06bc16a07b473ad96196fb06d6657f59e" + integrity sha512-hlq4+BU0hlPmwsFjwGGzZ+OZ9N/wq9Ljg/sq3pX+2CD7hrJsX9tJgWWK/wiNTFM212CLHWhicOoqwXyZGGetJg== + fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" @@ -3022,6 +3027,13 @@ react-dom@^18.1.0: loose-envify "^1.1.0" scheduler "^0.22.0" +react-full-screen@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/react-full-screen/-/react-full-screen-1.1.1.tgz#b707d56891015a71c503a65dbab3086d75be97d7" + integrity sha512-xoEgkoTiN0dw9cjYYGViiMCBYbkS97BYb4bHPhQVWXj1UnOs8PZ1rPzpX+2HMhuvQV1jA5AF9GaRbO3fA5aZtg== + dependencies: + fscreen "^1.0.2" + react-is@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" From 2b51af90935153eab7d93fc03bc66936354842a5 Mon Sep 17 00:00:00 2001 From: David Baetge Date: Sat, 11 Jun 2022 02:07:53 +0200 Subject: [PATCH 2/2] Added fullscreen handle to bar and calendar diagrams. [GH-6] --- .../includes/climatological-days.inc | 4 +- skins/weewx-wdc/src/js/diagrams/bar.tsx | 122 ++++++++++-------- skins/weewx-wdc/src/js/diagrams/calendar.tsx | 101 ++++++++------- skins/weewx-wdc/src/js/diagrams/line.tsx | 6 +- skins/weewx-wdc/src/js/index.tsx | 4 +- skins/weewx-wdc/src/scss/index.scss | 75 +++++++---- 6 files changed, 186 insertions(+), 126 deletions(-) diff --git a/skins/weewx-wdc/includes/climatological-days.inc b/skins/weewx-wdc/includes/climatological-days.inc index 6c5459fd..63c0a475 100644 --- a/skins/weewx-wdc/includes/climatological-days.inc +++ b/skins/weewx-wdc/includes/climatological-days.inc @@ -105,7 +105,7 @@ var calendarDataRain = $get_calendar_data('rain', 'sum', $get_time_span_from_attr($precision, $day, $week, $month, $year, $alltime));
= ( props: DiagramBaseProps ): React.ReactElement => { const small = useMediaQuery("(max-width: 672px)"); + const handle = useFullScreenHandle(); let dateFormat = "HH:mm"; switch (props.precision) { @@ -26,62 +29,69 @@ export const BarDiagram: FunctionComponent = ( break; } + const barDiagram = ( + moment.unix(value).format(dateFormat), + tickSize: props.precision === "day" ? 2 : 0, + tickPadding: 5, + tickRotation: -65, + }} + axisLeft={{ + legend: props.unit, + legendOffset: -50, + legendPosition: "middle", + tickSize: 0, + tickPadding: 10, + }} + colors={props.color} + data={props.data[0].data} + enableLabel={false} + enableGridX={false} + enableGridY={true} + indexBy="x" + indexScale={{ type: "band", round: false }} + isInteractive={true} + labelSkipHeight={50} + margin={{ + top: 20, + right: 10, + bottom: 40, + left: 55, + }} + maxValue={ + Math.max( + ...props.data[0].data.map((item): number => (item as { y: number }).y) + ) + getyScaleOffset(props.observation) + } + minValue={0} + keys={["y"]} + tooltip={(point) => ( + + )} + valueFormat={(value) => `${value} ${props.unit}`} + valueScale={{ type: "linear" }} + theme={{ + fontSize: small ? 9 : 11, + }} + /> + ); + return ( -
- moment.unix(value).format(dateFormat), - tickSize: props.precision === "day" ? 2 : 0, - tickPadding: 5, - tickRotation: -65, - }} - axisLeft={{ - legend: props.unit, - legendOffset: -50, - legendPosition: "middle", - tickSize: 0, - tickPadding: 10, - }} - colors={props.color} - data={props.data[0].data} - enableLabel={false} - enableGridX={false} - enableGridY={true} - indexBy="x" - indexScale={{ type: "band", round: false }} - isInteractive={true} - labelSkipHeight={50} - margin={{ - top: 20, - right: 10, - bottom: 40, - left: 55, - }} - maxValue={ - Math.max( - ...props.data[0].data.map( - (item): number => (item as { y: number }).y - ) - ) + getyScaleOffset(props.observation) - } - minValue={0} - keys={["y"]} - tooltip={(point) => ( - - )} - valueFormat={(value) => `${value} ${props.unit}`} - valueScale={{ type: "linear" }} - theme={{ - fontSize: small ? 9 : 11, - }} - /> -
+ <> + +
{barDiagram}
+ + + {barDiagram} + + ); }; diff --git a/skins/weewx-wdc/src/js/diagrams/calendar.tsx b/skins/weewx-wdc/src/js/diagrams/calendar.tsx index 632b761c..a0cbc826 100644 --- a/skins/weewx-wdc/src/js/diagrams/calendar.tsx +++ b/skins/weewx-wdc/src/js/diagrams/calendar.tsx @@ -3,19 +3,24 @@ import { ResponsiveCalendar } from "@nivo/calendar"; import moment from "moment"; import { NumberValue, scaleQuantize } from "d3-scale"; import { useMediaQuery } from "@react-hook/media-query"; +import { FullScreen, useFullScreenHandle } from "react-full-screen"; import { ColorScale } from "@nivo/calendar"; import { CalendarDiagramBaseProps } from "./types"; import { TooltipCalendar } from "../components/tooltip-calendar"; +import { Maximize } from "../assets/maximize"; export const CalendarDiagram: FunctionComponent = ( props: CalendarDiagramBaseProps ): React.ReactElement => { const small = useMediaQuery("(max-width: 672px)"); + const handle = useFullScreenHandle(); const start = props.data[0].day; const end = props.data[props.data.length - 1].day; - const yearDiff = moment(end).diff(start, "years"); + const yearDiff = + parseInt(moment(end, "YYYY-MM-DD").format("YYYY")) - + parseInt(moment(start, "YYYY-MM-DD").format("YYYY")); // @see https://nivo.rocks/storybook/?path=/story/calendarcanvas--custom-color-space-function // @see https://github.com/plouc/nivo/issues/744#issuecomment-573340879 @@ -31,7 +36,6 @@ export const CalendarDiagram: FunctionComponent = ( }; colorScale.ticks = (count: number | undefined) => { return defaultColorScale.ticks(count).map((e) => { - console.log("e", e); return `${e}${props.unit}`; }); }; @@ -40,6 +44,51 @@ export const CalendarDiagram: FunctionComponent = ( return colorScale; }; + const calendarDiagram = ( + ( + + )} + legends={[ + { + anchor: small ? "bottom-left" : "right", + direction: small ? "row" : "column", + translateY: small ? -20 : 0, + translateX: small ? 0 : -20, + itemCount: 4, + itemWidth: small ? 50 : 80, + itemHeight: 20, + itemsSpacing: small ? 2 : 5, + itemDirection: "left-to-right", + }, + ]} + /> + ); + return ( <>

{props.heading}

@@ -48,49 +97,13 @@ export const CalendarDiagram: FunctionComponent = ( // @todo Add responsive style. style={{ height: `${(yearDiff + 1) * (small ? 25 : 14)}vw` }} > - ( - - )} - legends={[ - { - anchor: small ? "bottom-left" : "right", - direction: small ? "row" : "column", - translateY: small ? -20 : 0, - translateX: small ? 0 : -20, - itemCount: 4, - itemWidth: small ? 50 : 80, - itemHeight: 20, - itemsSpacing: small ? 2 : 5, - itemDirection: "left-to-right", - }, - ]} - /> + + {calendarDiagram}
+ + + {calendarDiagram} + ); }; diff --git a/skins/weewx-wdc/src/js/diagrams/line.tsx b/skins/weewx-wdc/src/js/diagrams/line.tsx index acbf11f1..da7c1968 100644 --- a/skins/weewx-wdc/src/js/diagrams/line.tsx +++ b/skins/weewx-wdc/src/js/diagrams/line.tsx @@ -143,11 +143,15 @@ export const LineDiagram: FunctionComponent = ( /> ); + // @todo Fullscreen close button. return ( <>
{lineDiagram}
- {lineDiagram} + + + {lineDiagram} + ); }; diff --git a/skins/weewx-wdc/src/js/index.tsx b/skins/weewx-wdc/src/js/index.tsx index 0efdee00..ca2b9f43 100644 --- a/skins/weewx-wdc/src/js/index.tsx +++ b/skins/weewx-wdc/src/js/index.tsx @@ -8,7 +8,9 @@ import { LineDiagram } from "./diagrams/line"; import { precision, Series } from "./diagrams/types"; import { CalendarDiagram } from "./diagrams/calendar"; -const calendarDiagrams = document.querySelectorAll("div.calendar-diagram"); +const calendarDiagrams = document.querySelectorAll( + "div.calendar-diagram-clim-wrap" +); calendarDiagrams.forEach((diagram) => { if ( diagram instanceof HTMLElement && diff --git a/skins/weewx-wdc/src/scss/index.scss b/skins/weewx-wdc/src/scss/index.scss index 894755c8..a249f5b6 100644 --- a/skins/weewx-wdc/src/scss/index.scss +++ b/skins/weewx-wdc/src/scss/index.scss @@ -246,6 +246,45 @@ bx-tabs { } } +@mixin fullscreen { + .maximize { + transition: all 250ms ease; + opacity: 0; + cursor: pointer; + position: absolute; + right: 0; + top: -#{$spacing-07}; + padding: $spacing-02; + box-sizing: content-box; + &:hover { + background: $background-active; + } + @include carbon--breakpoint-down(lg) { + opacity: 1; + } + } + .fullscreen { + display: none; + &.fullscreen-enabled { + display: block; + padding: $spacing-08 !important; + background: white; + .maximize { + position: absolute; + top: $spacing-04; + right: $spacing-08; + z-index: 10; + @include carbon--breakpoint-down(lg) { + right: $spacing-04; + } + } + @include carbon--breakpoint-down(lg) { + padding: $spacing-04 !important; + } + } + } +} + .diagram-tile { margin-bottom: $spacing-05; &.combined { @@ -258,28 +297,7 @@ bx-tabs { } .diagram { position: relative; - .maximize { - transition: opacity 250ms ease; - opacity: 0; - cursor: pointer; - position: absolute; - right: 0; - top: -#{$spacing-06}; - @include carbon--breakpoint-down(lg) { - opacity: 1; - } - } - .fullscreen { - display: none; - &.fullscreen-enabled { - display: block; - padding: $spacing-08 !important; - background: white; - @include carbon--breakpoint-down(lg) { - padding: $spacing-04 !important; - } - } - } + @include fullscreen(); } &:hover { .maximize { @@ -300,6 +318,19 @@ bx-tabs { } } +.calendar-diagram-clim-wrap { + position: relative; + @include fullscreen(); + .maximize { + top: 0; + } + &:hover { + .maximize { + opacity: 1; + } + } +} + .tile-radar-forecast { img { width: 100%;