From 0199371f51cb52dac036cedbf275d0f1e765e87f Mon Sep 17 00:00:00 2001 From: kitsuyui Date: Sat, 20 May 2023 20:02:15 +0900 Subject: [PATCH 01/12] Add UI Currently, there is only a minimal UI, so add UI. However, I don't want to use CSS frameworks such as Tailwind, Bulma, and UI Kit. I want to keep it within the range of bare functions supported by the browser. Or, take one of the following options 1. Do not directly depend on parts that depend on CSS frameworks, but keep them as indirect dependencies (optionalDependencies) 2. If you use a CSS framework, separate the parts that depend on the CSS framework into a separate package. From b3c2c0e05e5dc434f5f04315a216ef7fcde82fdb Mon Sep 17 00:00:00 2001 From: kitsuyui Date: Sat, 20 May 2023 20:06:59 +0900 Subject: [PATCH 02/12] Update Minimal UIs - Use monospace fonts. - remove borders. --- .../clock/src/__snapshots__/test.tsx.snap | 102 ++++++++-------- packages/clock/src/analog.tsx | 109 ++++++++++-------- packages/clock/src/digital.tsx | 7 +- .../stopwatch/src/__snapshots__/test.tsx.snap | 2 +- packages/stopwatch/src/minimal.tsx | 2 +- .../timer/src/__snapshots__/test.tsx.snap | 2 +- packages/timer/src/minimal.tsx | 2 +- 7 files changed, 126 insertions(+), 100 deletions(-) diff --git a/packages/clock/src/__snapshots__/test.tsx.snap b/packages/clock/src/__snapshots__/test.tsx.snap index e2b7de16..3d8f1717 100644 --- a/packages/clock/src/__snapshots__/test.tsx.snap +++ b/packages/clock/src/__snapshots__/test.tsx.snap @@ -2,60 +2,66 @@ exports[`render AnalogClock 1`] = ` - - - - - - - + + + + + + + + `; exports[`render DigitalClock 1`] = ` -
+
09:00:00 AM (Asia/Tokyo)
diff --git a/packages/clock/src/analog.tsx b/packages/clock/src/analog.tsx index 2f547193..7386a235 100644 --- a/packages/clock/src/analog.tsx +++ b/packages/clock/src/analog.tsx @@ -24,53 +24,68 @@ export const AnalogClock: React.FunctionComponent = ( const centerX = 50 const centerY = 50 return ( - - - - - - - + + + + + + + +
) } diff --git a/packages/clock/src/digital.tsx b/packages/clock/src/digital.tsx index 32cffc61..31401cf8 100644 --- a/packages/clock/src/digital.tsx +++ b/packages/clock/src/digital.tsx @@ -15,7 +15,12 @@ export const DigitalClock: React.FunctionComponent = ( const secondStr = dt.second < 10 ? `0${dt.second}` : dt.second const ampm = dt.hour < 12 ? 'AM' : 'PM' return ( -
+
{hourStr}:{minuteStr}:{secondStr} {ampm} ({timezone})
) diff --git a/packages/stopwatch/src/__snapshots__/test.tsx.snap b/packages/stopwatch/src/__snapshots__/test.tsx.snap index f9cbdcfe..c8f50a32 100644 --- a/packages/stopwatch/src/__snapshots__/test.tsx.snap +++ b/packages/stopwatch/src/__snapshots__/test.tsx.snap @@ -3,7 +3,7 @@ exports[`render MinimalStopwatch 1`] = `
diff --git a/packages/stopwatch/src/minimal.tsx b/packages/stopwatch/src/minimal.tsx index 269487ee..c8ac2eb2 100644 --- a/packages/stopwatch/src/minimal.tsx +++ b/packages/stopwatch/src/minimal.tsx @@ -28,8 +28,8 @@ export const MinimalStopwatch: React.FunctionComponent = ( return (
diff --git a/packages/timer/src/__snapshots__/test.tsx.snap b/packages/timer/src/__snapshots__/test.tsx.snap index 3994b6a2..55706662 100644 --- a/packages/timer/src/__snapshots__/test.tsx.snap +++ b/packages/timer/src/__snapshots__/test.tsx.snap @@ -3,7 +3,7 @@ exports[`render MinimalTimer 1`] = `
diff --git a/packages/timer/src/minimal.tsx b/packages/timer/src/minimal.tsx index 58a2d6bd..ef1226a7 100644 --- a/packages/timer/src/minimal.tsx +++ b/packages/timer/src/minimal.tsx @@ -28,8 +28,8 @@ export const MinimalTimer: React.FunctionComponent = ( return (
From 7560e0388e06df4e7b3018053bd08639144f5609 Mon Sep 17 00:00:00 2001 From: kitsuyui Date: Wed, 24 May 2023 02:07:10 +0900 Subject: [PATCH 03/12] Abstraction: analog clock parameters --- packages/clock/src/analog.tsx | 160 ++++++++++++++++++++++++++-------- 1 file changed, 122 insertions(+), 38 deletions(-) diff --git a/packages/clock/src/analog.tsx b/packages/clock/src/analog.tsx index 7386a235..a04de912 100644 --- a/packages/clock/src/analog.tsx +++ b/packages/clock/src/analog.tsx @@ -3,6 +3,46 @@ import React from 'react' import { ClockProps } from './types' +export interface AnalogClockDesign { + bigHandColor: string + smallHandColor: string + secondHandColor: string + bigHandWidth: number + smallHandWidth: number + secondHandWidth: number + bigHandLength: number + secondHandLength: number + minuteHandLength: number + width: number + height: number + frameSize: number + frameWidth: number + frameColor: string + frameBackgroundColor: string + centerPointSize: number + centerPointColor: string +} + +export const defaultAnalogClockDesign: AnalogClockDesign = { + bigHandColor: 'black', + smallHandColor: 'black', + secondHandColor: 'red', + bigHandWidth: 2, + smallHandWidth: 2, + secondHandWidth: 2, + bigHandLength: 30, + secondHandLength: 40, + minuteHandLength: 40, + width: 100, + height: 100, + frameSize: 45, + frameWidth: 2, + frameColor: 'black', + frameBackgroundColor: 'white', + centerPointSize: 2, + centerPointColor: 'black', +} + export const AnalogClock: React.FunctionComponent = ( props ): JSX.Element => { @@ -12,76 +52,80 @@ export const AnalogClock: React.FunctionComponent = ( const hour = dt.hour const minute = dt.minute const second = dt.second - const bigHandColor = 'black' - const smallHandColor = 'black' - const secondHandColor = 'red' - const bigHandWidth = 2 - const smallHandWidth = 2 - const secondHandWidth = 2 - const bigHandLength = 30 - const secondHandLength = 40 - const minuteHandLength = 40 - const centerX = 50 - const centerY = 50 + const { + bigHandColor, + smallHandColor, + secondHandColor, + bigHandWidth, + smallHandWidth, + secondHandWidth, + bigHandLength, + secondHandLength, + minuteHandLength, + width, + height, + frameSize, + frameWidth, + frameColor, + centerPointSize, + centerPointColor, + frameBackgroundColor, + } = defaultAnalogClockDesign + + const centerX = width / 2 + const centerY = height / 2 + return (
@@ -89,3 +133,43 @@ export const AnalogClock: React.FunctionComponent = (
) } + +function hourToDegree(hour: number) { + return hour * 30 +} + +function secondToDegree(second: number) { + return second * 6 +} + +function minuteToDegree(minute: number) { + return minute * 6 +} + +function degreeToRadian(degree: number) { + return degree * (Math.PI / 180) +} + +function hourToSin(hour: number) { + return Math.sin(degreeToRadian(hourToDegree(hour))) +} + +function hourToCos(hour: number) { + return Math.cos(degreeToRadian(hourToDegree(hour))) +} + +function minuteToSin(minute: number) { + return Math.sin(degreeToRadian(minuteToDegree(minute))) +} + +function minuteToCos(minute: number) { + return Math.cos(degreeToRadian(minuteToDegree(minute))) +} + +function secondToSin(second: number) { + return Math.sin(degreeToRadian(secondToDegree(second))) +} + +function secondToCos(second: number) { + return Math.cos(degreeToRadian(secondToDegree(second))) +} From 966ab9aa52e85686ca85b7c82ec623d7a1c4016e Mon Sep 17 00:00:00 2001 From: kitsuyui Date: Wed, 24 May 2023 03:03:38 +0900 Subject: [PATCH 04/12] Add sweep (non-tick) style analog clock --- examples/simple/src/App.tsx | 4 +- packages/clock/src/analog.tsx | 312 ++++++++++++++++++++++------------ 2 files changed, 205 insertions(+), 111 deletions(-) diff --git a/examples/simple/src/App.tsx b/examples/simple/src/App.tsx index 0c6b61ad..98416864 100644 --- a/examples/simple/src/App.tsx +++ b/examples/simple/src/App.tsx @@ -24,13 +24,13 @@ import './App.css' const Clock = () => { return ( - + {(date: Date) => ( <> - + )} diff --git a/packages/clock/src/analog.tsx b/packages/clock/src/analog.tsx index a04de912..ded41fe0 100644 --- a/packages/clock/src/analog.tsx +++ b/packages/clock/src/analog.tsx @@ -3,78 +3,96 @@ import React from 'react' import { ClockProps } from './types' -export interface AnalogClockDesign { - bigHandColor: string - smallHandColor: string - secondHandColor: string - bigHandWidth: number - smallHandWidth: number - secondHandWidth: number - bigHandLength: number - secondHandLength: number - minuteHandLength: number +export interface AnalogClockStyle { width: number height: number - frameSize: number - frameWidth: number - frameColor: string - frameBackgroundColor: string - centerPointSize: number - centerPointColor: string -} - -export const defaultAnalogClockDesign: AnalogClockDesign = { - bigHandColor: 'black', - smallHandColor: 'black', - secondHandColor: 'red', - bigHandWidth: 2, - smallHandWidth: 2, - secondHandWidth: 2, - bigHandLength: 30, - secondHandLength: 40, - minuteHandLength: 40, + step: StepStyle + bigHand: HandStyle + smallHand: HandStyle + secondHand: HandStyle + frame: FrameStyle + centerPoint: CenterPointStyle +} + +export interface HandStyle { + width: number + length: number + color: string +} + +export interface FrameStyle { + size: number + width: number + color: string + backgroundColor: string +} + +export interface CenterPointStyle { + size: number + color: string +} + +export const defaultAnalogClockStyle: AnalogClockStyle = { width: 100, height: 100, - frameSize: 45, - frameWidth: 2, - frameColor: 'black', - frameBackgroundColor: 'white', - centerPointSize: 2, - centerPointColor: 'black', + step: 'tick', + bigHand: { + width: 2, + length: 30, + color: 'black', + }, + smallHand: { + width: 2, + length: 40, + color: 'black', + }, + secondHand: { + width: 2, + length: 40, + color: 'red', + }, + frame: { + size: 45, + width: 2, + color: 'black', + backgroundColor: 'white', + }, + centerPoint: { + size: 2, + color: 'black', + }, +} + +export type StepStyle = 'tick' | 'sweep' + +interface AnalogClockCustomize { + step?: StepStyle + width?: number + height?: number + bigHand?: Partial + smallHand?: Partial + secondHand?: Partial + frame?: Partial + centerPoint?: Partial } -export const AnalogClock: React.FunctionComponent = ( - props -): JSX.Element => { +type AnalogClockProps = ClockProps & AnalogClockCustomize + +export const AnalogClock: React.FC = (props): JSX.Element => { const { timezone, date } = props - const datetime = DateTime.fromJSDate(date) - const dt = datetime.setZone(timezone) - const hour = dt.hour - const minute = dt.minute - const second = dt.second const { - bigHandColor, - smallHandColor, - secondHandColor, - bigHandWidth, - smallHandWidth, - secondHandWidth, - bigHandLength, - secondHandLength, - minuteHandLength, width, height, - frameSize, - frameWidth, - frameColor, - centerPointSize, - centerPointColor, - frameBackgroundColor, - } = defaultAnalogClockDesign - + bigHand: bigHandStyle, + smallHand: smallHandStyle, + secondHand: secondHandStyle, + frame: frameStyle, + step: stepStyle, + centerPoint: centerPointStyle, + } = customizeClockProps(props) + const { hour, minute, second } = calcHMS(date, timezone, stepStyle) const centerX = width / 2 const centerY = height / 2 - return (
= ( - - -
) } -function hourToDegree(hour: number) { - return hour * 30 +export const Hand: React.FC< + { + centerX: number + centerY: number + degree: number + } & HandStyle +> = (props) => { + const { centerX, centerY, degree, length, width, color } = props + const x = centerX + length * degreeToSin(degree) + const y = centerY - length * degreeToCos(degree) + return ( + + ) } -function secondToDegree(second: number) { - return second * 6 +function customizeClockProps( + customize: AnalogClockCustomize +): AnalogClockStyle { + const { + width, + height, + step, + bigHand, + smallHand, + secondHand, + frame: frameStyle, + centerPoint: centerPointStyle, + } = { + ...defaultAnalogClockStyle, + ...customize, + } + return { + width, + height, + step, + bigHand: { + ...defaultAnalogClockStyle.bigHand, + ...bigHand, + }, + smallHand: { + ...defaultAnalogClockStyle.smallHand, + ...smallHand, + }, + secondHand: { + ...defaultAnalogClockStyle.secondHand, + ...secondHand, + }, + frame: { + ...defaultAnalogClockStyle.frame, + ...frameStyle, + }, + centerPoint: { + ...defaultAnalogClockStyle.centerPoint, + ...centerPointStyle, + }, + } } -function minuteToDegree(minute: number) { - return minute * 6 +type hms = { + hour: number + minute: number + second: number } -function degreeToRadian(degree: number) { - return degree * (Math.PI / 180) +function calcHMS(date: Date, timezone: string, stepStyle: StepStyle): hms { + switch (stepStyle) { + case 'tick': + return TickHMS(date, timezone) + case 'sweep': + return SweepHMS(date, timezone) + } } -function hourToSin(hour: number) { - return Math.sin(degreeToRadian(hourToDegree(hour))) +function TickHMS(date: Date, timezone: string): hms { + const datetime = DateTime.fromJSDate(date) + const dt = datetime.setZone(timezone) + const hour = dt.hour + const minute = dt.minute + const second = dt.second + return { hour, minute, second } } -function hourToCos(hour: number) { - return Math.cos(degreeToRadian(hourToDegree(hour))) +function SweepHMS(date: Date, timezone: string): hms { + const datetime = DateTime.fromJSDate(date) + const dt = datetime.setZone(timezone) + const hour = dt.hour + dt.minute / 60 + dt.second / 3600 + const minute = dt.minute + dt.second / 60 + const second = dt.second + dt.millisecond / 1000 + return { hour, minute, second } } -function minuteToSin(minute: number) { - return Math.sin(degreeToRadian(minuteToDegree(minute))) +function hourToDegree(hour: number): number { + return hour * 30 } -function minuteToCos(minute: number) { - return Math.cos(degreeToRadian(minuteToDegree(minute))) +function secondToDegree(second: number): number { + return second * 6 } -function secondToSin(second: number) { - return Math.sin(degreeToRadian(secondToDegree(second))) +function minuteToDegree(minute: number): number { + return minute * 6 } -function secondToCos(second: number) { - return Math.cos(degreeToRadian(secondToDegree(second))) +function degreeToSin(degree: number): number { + return Math.sin(degreeToRadian(degree)) +} + +function degreeToCos(degree: number): number { + return Math.cos(degreeToRadian(degree)) +} + +function degreeToRadian(degree: number): number { + return degree * (Math.PI / 180) } From 07c813f76eaddc83be3291c4ad44541c52151f16 Mon Sep 17 00:00:00 2001 From: kitsuyui Date: Wed, 24 May 2023 03:13:32 +0900 Subject: [PATCH 05/12] refactor Analog Clock --- packages/clock/src/analog.tsx | 70 +++++------------------------------ packages/clock/src/math.tsx | 58 +++++++++++++++++++++++++++++ packages/clock/src/types.ts | 8 ++++ 3 files changed, 75 insertions(+), 61 deletions(-) create mode 100644 packages/clock/src/math.tsx diff --git a/packages/clock/src/analog.tsx b/packages/clock/src/analog.tsx index ded41fe0..d4c39cc4 100644 --- a/packages/clock/src/analog.tsx +++ b/packages/clock/src/analog.tsx @@ -1,7 +1,14 @@ -import { DateTime } from 'luxon' import React from 'react' -import { ClockProps } from './types' +import { + degreeToCos, + degreeToSin, + hourToDegree, + minuteToDegree, + secondToDegree, + calcHMS, +} from './math' +import { ClockProps, StepStyle } from './types' export interface AnalogClockStyle { width: number @@ -63,8 +70,6 @@ export const defaultAnalogClockStyle: AnalogClockStyle = { }, } -export type StepStyle = 'tick' | 'sweep' - interface AnalogClockCustomize { step?: StepStyle width?: number @@ -210,60 +215,3 @@ function customizeClockProps( }, } } - -type hms = { - hour: number - minute: number - second: number -} - -function calcHMS(date: Date, timezone: string, stepStyle: StepStyle): hms { - switch (stepStyle) { - case 'tick': - return TickHMS(date, timezone) - case 'sweep': - return SweepHMS(date, timezone) - } -} - -function TickHMS(date: Date, timezone: string): hms { - const datetime = DateTime.fromJSDate(date) - const dt = datetime.setZone(timezone) - const hour = dt.hour - const minute = dt.minute - const second = dt.second - return { hour, minute, second } -} - -function SweepHMS(date: Date, timezone: string): hms { - const datetime = DateTime.fromJSDate(date) - const dt = datetime.setZone(timezone) - const hour = dt.hour + dt.minute / 60 + dt.second / 3600 - const minute = dt.minute + dt.second / 60 - const second = dt.second + dt.millisecond / 1000 - return { hour, minute, second } -} - -function hourToDegree(hour: number): number { - return hour * 30 -} - -function secondToDegree(second: number): number { - return second * 6 -} - -function minuteToDegree(minute: number): number { - return minute * 6 -} - -function degreeToSin(degree: number): number { - return Math.sin(degreeToRadian(degree)) -} - -function degreeToCos(degree: number): number { - return Math.cos(degreeToRadian(degree)) -} - -function degreeToRadian(degree: number): number { - return degree * (Math.PI / 180) -} diff --git a/packages/clock/src/math.tsx b/packages/clock/src/math.tsx new file mode 100644 index 00000000..fd69fde9 --- /dev/null +++ b/packages/clock/src/math.tsx @@ -0,0 +1,58 @@ +import { DateTime } from 'luxon' + +import type { StepStyle, HMS } from './types' + +export function hourToDegree(hour: number): number { + return hour * 30 +} + +export function secondToDegree(second: number): number { + return second * 6 +} + +export function minuteToDegree(minute: number): number { + return minute * 6 +} + +export function degreeToSin(degree: number): number { + return Math.sin(degreeToRadian(degree)) +} + +export function degreeToCos(degree: number): number { + return Math.cos(degreeToRadian(degree)) +} + +export function degreeToRadian(degree: number): number { + return degree * (Math.PI / 180) +} + +export function calcHMS( + date: Date, + timezone: string, + stepStyle: StepStyle +): HMS { + switch (stepStyle) { + case 'tick': + return tickHMS(date, timezone) + case 'sweep': + return sweepHMS(date, timezone) + } +} + +export function tickHMS(date: Date, timezone: string): HMS { + const datetime = DateTime.fromJSDate(date) + const dt = datetime.setZone(timezone) + const hour = dt.hour + const minute = dt.minute + const second = dt.second + return { hour, minute, second } +} + +export function sweepHMS(date: Date, timezone: string): HMS { + const datetime = DateTime.fromJSDate(date) + const dt = datetime.setZone(timezone) + const hour = dt.hour + dt.minute / 60 + dt.second / 3600 + const minute = dt.minute + dt.second / 60 + const second = dt.second + dt.millisecond / 1000 + return { hour, minute, second } +} diff --git a/packages/clock/src/types.ts b/packages/clock/src/types.ts index ed34f7c4..07678102 100644 --- a/packages/clock/src/types.ts +++ b/packages/clock/src/types.ts @@ -7,3 +7,11 @@ export interface ClockContainerProps { children: React.ReactElement | React.ReactElement[] refreshInterval?: number } + +export type StepStyle = 'tick' | 'sweep' + +export type HMS = { + hour: number + minute: number + second: number +} From 90efd0c65677c405c8f2d1a96971614d927f58af Mon Sep 17 00:00:00 2001 From: kitsuyui Date: Wed, 24 May 2023 03:43:22 +0900 Subject: [PATCH 06/12] Add hour lines and minute lines --- packages/clock/src/analog.tsx | 170 +++++++++++++++++++++++++++++----- 1 file changed, 147 insertions(+), 23 deletions(-) diff --git a/packages/clock/src/analog.tsx b/packages/clock/src/analog.tsx index d4c39cc4..3ba538e2 100644 --- a/packages/clock/src/analog.tsx +++ b/packages/clock/src/analog.tsx @@ -19,6 +19,8 @@ export interface AnalogClockStyle { secondHand: HandStyle frame: FrameStyle centerPoint: CenterPointStyle + hourLines: LinesStyle + minuteLines: LinesStyle } export interface HandStyle { @@ -39,6 +41,12 @@ export interface CenterPointStyle { color: string } +export interface LinesStyle { + width: number + length: number + color: string +} + export const defaultAnalogClockStyle: AnalogClockStyle = { width: 100, height: 100, @@ -60,7 +68,7 @@ export const defaultAnalogClockStyle: AnalogClockStyle = { }, frame: { size: 45, - width: 2, + width: 1, color: 'black', backgroundColor: 'white', }, @@ -68,6 +76,16 @@ export const defaultAnalogClockStyle: AnalogClockStyle = { size: 2, color: 'black', }, + hourLines: { + width: 1, + length: 4, + color: 'black', + }, + minuteLines: { + width: 1, + length: 2, + color: 'black', + }, } interface AnalogClockCustomize { @@ -79,6 +97,8 @@ interface AnalogClockCustomize { secondHand?: Partial frame?: Partial centerPoint?: Partial + hourLines?: Partial + minuteLines?: Partial } type AnalogClockProps = ClockProps & AnalogClockCustomize @@ -88,14 +108,16 @@ export const AnalogClock: React.FC = (props): JSX.Element => { const { width, height, - bigHand: bigHandStyle, - smallHand: smallHandStyle, - secondHand: secondHandStyle, - frame: frameStyle, - step: stepStyle, - centerPoint: centerPointStyle, + bigHand, + smallHand, + secondHand, + frame, + step, + centerPoint, + hourLines, + minuteLines, } = customizeClockProps(props) - const { hour, minute, second } = calcHMS(date, timezone, stepStyle) + const { hour, minute, second } = calcHMS(date, timezone, step) const centerX = width / 2 const centerY = height / 2 return ( @@ -115,36 +137,52 @@ export const AnalogClock: React.FC = (props): JSX.Element => { + +
@@ -173,6 +211,82 @@ export const Hand: React.FC< ) } +const HourLines = (props: { + centerX: number + centerY: number + radius: number + length: number + width: number + color: string +}) => { + const { centerX, centerY, radius, width, color, length } = props + return ( + + ) +} + +const MinutesLines = (props: { + centerX: number + centerY: number + radius: number + length: number + width: number + color: string +}) => { + const { centerX, centerY, radius, width, color, length } = props + return ( + + ) +} + +const Lines = (props: { + centerX: number + centerY: number + radius: number + length: number + count: number + width: number + color: string +}) => { + const { centerX, centerY, radius, length, count, width, color } = props + const lines = [] + for (let i = 0; i < count; i++) { + const degree = (360 / count) * i + const x1 = centerX + radius * degreeToSin(degree) + const y1 = centerY + radius * degreeToCos(degree) + const x2 = x1 + length * degreeToSin(degree) + const y2 = y1 + length * degreeToCos(degree) + lines.push( + + ) + } + return <>{lines} +} + function customizeClockProps( customize: AnalogClockCustomize ): AnalogClockStyle { @@ -183,8 +297,10 @@ function customizeClockProps( bigHand, smallHand, secondHand, - frame: frameStyle, - centerPoint: centerPointStyle, + frame, + centerPoint, + hourLines, + minuteLines, } = { ...defaultAnalogClockStyle, ...customize, @@ -207,11 +323,19 @@ function customizeClockProps( }, frame: { ...defaultAnalogClockStyle.frame, - ...frameStyle, + ...frame, }, centerPoint: { ...defaultAnalogClockStyle.centerPoint, - ...centerPointStyle, + ...centerPoint, + }, + hourLines: { + ...defaultAnalogClockStyle.hourLines, + ...hourLines, + }, + minuteLines: { + ...defaultAnalogClockStyle.minuteLines, + ...minuteLines, }, } } From 52541c387317e1ba93d50b8ac7e6cac29c4bcabb Mon Sep 17 00:00:00 2001 From: kitsuyui Date: Wed, 24 May 2023 04:20:05 +0900 Subject: [PATCH 07/12] Add faces to Analog Clock --- examples/simple/src/App.tsx | 7 +- .../clock-image-chromium-darwin.png | Bin 7780 -> 10592 bytes .../clock/src/__snapshots__/test.tsx.snap | 718 +++++++++++++++++- packages/clock/src/analog.tsx | 91 ++- packages/clock/src/types.ts | 2 + 5 files changed, 807 insertions(+), 11 deletions(-) diff --git a/examples/simple/src/App.tsx b/examples/simple/src/App.tsx index 98416864..3302bf6f 100644 --- a/examples/simple/src/App.tsx +++ b/examples/simple/src/App.tsx @@ -30,7 +30,12 @@ const Clock = () => { <> - + )} diff --git a/examples/storybook/tests/example.spec.ts-snapshots/clock-image-chromium-darwin.png b/examples/storybook/tests/example.spec.ts-snapshots/clock-image-chromium-darwin.png index d1615d1650f9956fe0c5a2c2f1f2cfa04f5067d6..1e446db8572d8b981f426e08ed06e49f6650ea02 100644 GIT binary patch literal 10592 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 OVosT#%sz4H_CEpW+x4&j diff --git a/packages/clock/src/__snapshots__/test.tsx.snap b/packages/clock/src/__snapshots__/test.tsx.snap index 3d8f1717..881e8a80 100644 --- a/packages/clock/src/__snapshots__/test.tsx.snap +++ b/packages/clock/src/__snapshots__/test.tsx.snap @@ -16,9 +16,9 @@ exports[`render AnalogClock 1`] = ` cx="50" cy="50" fill="white" - r="45" + r="49" stroke="black" - stroke-width="2" + stroke-width="1" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 12 + + + 1 + + + 2 + + + 3 + + + 4 + + + 5 + + + 6 + + + 7 + + + 8 + + + 9 + + + 10 + + + 11 + +
diff --git a/packages/clock/src/analog.tsx b/packages/clock/src/analog.tsx index 3ba538e2..b1fcd6e9 100644 --- a/packages/clock/src/analog.tsx +++ b/packages/clock/src/analog.tsx @@ -8,12 +8,13 @@ import { secondToDegree, calcHMS, } from './math' -import { ClockProps, StepStyle } from './types' +import { ClockProps, StepStyle, AnalogClockFaceType as FaceType } from './types' export interface AnalogClockStyle { width: number height: number step: StepStyle + face: FaceType bigHand: HandStyle smallHand: HandStyle secondHand: HandStyle @@ -51,8 +52,9 @@ export const defaultAnalogClockStyle: AnalogClockStyle = { width: 100, height: 100, step: 'tick', + face: 'arabic', bigHand: { - width: 2, + width: 3, length: 30, color: 'black', }, @@ -62,12 +64,12 @@ export const defaultAnalogClockStyle: AnalogClockStyle = { color: 'black', }, secondHand: { - width: 2, - length: 40, + width: 1, + length: 45, color: 'red', }, frame: { - size: 45, + size: 49, width: 1, color: 'black', backgroundColor: 'white', @@ -90,6 +92,7 @@ export const defaultAnalogClockStyle: AnalogClockStyle = { interface AnalogClockCustomize { step?: StepStyle + face?: FaceType width?: number height?: number bigHand?: Partial @@ -113,6 +116,7 @@ export const AnalogClock: React.FC = (props): JSX.Element => { secondHand, frame, step, + face, centerPoint, hourLines, minuteLines, @@ -166,6 +170,12 @@ export const AnalogClock: React.FC = (props): JSX.Element => { width={minuteLines.width} color={minuteLines.color} /> + {lines} } +const Faces = (props: { + centerX: number + centerY: number + radius: number + faceType: FaceType +}) => { + const { centerX, centerY, radius } = props + const faces = [] + for (let i = 0; i < 12; i++) { + const degree = (360 / 12) * i + 180 + const textSize = radius / 5 + const x = centerX + (radius - textSize) * degreeToSin(-degree) + const y = centerY + (radius - textSize) * degreeToCos(-degree) + faces.push( + + {getFace(i, props.faceType)} + + ) + } + return <>{faces} +} + +function getFace(num: number, faceType: FaceType): string { + switch (faceType) { + case 'arabic': + if (num === 0) { + return '12' + } + return `${num}` + case 'roman': + switch (num) { + case 0: + return 'Ⅻ' + case 1: + return 'Ⅰ' + case 2: + return 'Ⅱ' + case 3: + return 'Ⅲ' + case 4: + return 'Ⅳ' + case 5: + return `Ⅴ` + case 6: + return 'Ⅵ' + case 7: + return 'Ⅶ' + case 8: + return 'Ⅷ' + case 9: + return 'Ⅸ' + case 10: + return 'Ⅹ' + case 11: + return 'Ⅺ' + } + return `${num}` // unreachable + } +} + function customizeClockProps( customize: AnalogClockCustomize ): AnalogClockStyle { @@ -294,6 +373,7 @@ function customizeClockProps( width, height, step, + face, bigHand, smallHand, secondHand, @@ -309,6 +389,7 @@ function customizeClockProps( width, height, step, + face, bigHand: { ...defaultAnalogClockStyle.bigHand, ...bigHand, diff --git a/packages/clock/src/types.ts b/packages/clock/src/types.ts index 07678102..34f39dc0 100644 --- a/packages/clock/src/types.ts +++ b/packages/clock/src/types.ts @@ -10,6 +10,8 @@ export interface ClockContainerProps { export type StepStyle = 'tick' | 'sweep' +export type AnalogClockFaceType = 'roman' | 'arabic' + export type HMS = { hour: number minute: number From 76a4fec5789c8575faa7154d50b6f9faa93c01fa Mon Sep 17 00:00:00 2001 From: kitsuyui Date: Wed, 24 May 2023 07:47:16 +0900 Subject: [PATCH 08/12] Relax the threshold of VRT The threshold for snapshot testing is currently a perfect match. Relax it. --- examples/storybook/playwright.config.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/storybook/playwright.config.ts b/examples/storybook/playwright.config.ts index e49e1f05..9fa17043 100644 --- a/examples/storybook/playwright.config.ts +++ b/examples/storybook/playwright.config.ts @@ -29,10 +29,10 @@ export default defineConfig({ // maxDiffPixels: 1, // }, - // toMatchSnapshot: { - // // An acceptable ratio of pixels that are different to the total amount of pixels, between 0 and 1. - // maxDiffPixelRatio: 0.0125, - // }, + toMatchSnapshot: { + // An acceptable ratio of pixels that are different to the total amount of pixels, between 0 and 1. + maxDiffPixelRatio: 0.001, + }, }, use: { From a677ce942c59b7dd5fc1b91762dada735db63b77 Mon Sep 17 00:00:00 2001 From: kitsuyui Date: Wed, 24 May 2023 08:07:39 +0900 Subject: [PATCH 09/12] Test faces and step types --- packages/clock/src/analog.tsx | 74 +++++++++++++++++++--------------- packages/clock/src/test.tsx | 76 ++++++++++++++++++++++++++++++++++- 2 files changed, 116 insertions(+), 34 deletions(-) diff --git a/packages/clock/src/analog.tsx b/packages/clock/src/analog.tsx index b1fcd6e9..82c2c928 100644 --- a/packages/clock/src/analog.tsx +++ b/packages/clock/src/analog.tsx @@ -321,51 +321,59 @@ const Faces = (props: { fontFamily="monospace" fill="black" > - {getFace(i, props.faceType)} + {computeFace(i, props.faceType)} ) } return <>{faces} } -function getFace(num: number, faceType: FaceType): string { +export function computeFace(num: number, faceType: FaceType): string { switch (faceType) { case 'arabic': - if (num === 0) { - return '12' - } - return `${num}` + return arabicFace(num) case 'roman': - switch (num) { - case 0: - return 'Ⅻ' - case 1: - return 'Ⅰ' - case 2: - return 'Ⅱ' - case 3: - return 'Ⅲ' - case 4: - return 'Ⅳ' - case 5: - return `Ⅴ` - case 6: - return 'Ⅵ' - case 7: - return 'Ⅶ' - case 8: - return 'Ⅷ' - case 9: - return 'Ⅸ' - case 10: - return 'Ⅹ' - case 11: - return 'Ⅺ' - } - return `${num}` // unreachable + return romanFace(num) } } +export function arabicFace(num: number): string { + if (num === 0) { + return '12' + } + return `${num}` +} + +export function romanFace(num: number): string { + switch (num) { + case 0: + return 'Ⅻ' + case 1: + return 'Ⅰ' + case 2: + return 'Ⅱ' + case 3: + return 'Ⅲ' + case 4: + return 'Ⅳ' + case 5: + return `Ⅴ` + case 6: + return 'Ⅵ' + case 7: + return 'Ⅶ' + case 8: + return 'Ⅷ' + case 9: + return 'Ⅸ' + case 10: + return 'Ⅹ' + case 11: + return 'Ⅺ' + } + return `${num}` // unreachable +} + function customizeClockProps( customize: AnalogClockCustomize ): AnalogClockStyle { diff --git a/packages/clock/src/test.tsx b/packages/clock/src/test.tsx index 1ec2eb51..9a681bc4 100644 --- a/packages/clock/src/test.tsx +++ b/packages/clock/src/test.tsx @@ -1,7 +1,15 @@ import { render } from '@testing-library/react' import React from 'react' -import { AnalogClock, DigitalClock } from '.' +import { tickHMS, sweepHMS, calcHMS } from './math' + +import { + AnalogClock, + DigitalClock, + computeFace, + romanFace, + arabicFace, +} from '.' test('render AnalogClock', () => { const dt = new Date('2021-01-01T00:00:00Z') @@ -16,3 +24,69 @@ test('render DigitalClock', () => { ) expect(asFragment()).toMatchSnapshot() }) + +test('tickHMS returns HMS', () => { + const dt = new Date('2021-01-01T00:00:00Z') + expect(tickHMS(dt, 'Asia/Tokyo')).toEqual({ + hour: 9, + minute: 0, + second: 0, + }) + + const dt2 = new Date('2021-01-01T10:08:14Z') + expect(tickHMS(dt2, 'Asia/Tokyo')).toEqual({ + hour: 19, + minute: 8, + second: 14, + }) +}) + +test('sweepHMS returns HMS', () => { + const dt2 = new Date('2021-01-01T10:08:14.2000Z') + expect(sweepHMS(dt2, 'Asia/Tokyo')).toEqual({ + hour: 19.13722222222222, + minute: 8.233333333333333, + second: 14.2, + }) +}) + +test('calcHMS returns HMS', () => { + const dt = new Date('2021-01-01T10:08:14.2000Z') + expect(calcHMS(dt, 'Asia/Tokyo', 'tick')).toEqual(tickHMS(dt, 'Asia/Tokyo')) + expect(calcHMS(dt, 'Asia/Tokyo', 'sweep')).toEqual(sweepHMS(dt, 'Asia/Tokyo')) +}) + +test('arabicFace returns arabicFace', () => { + expect(arabicFace(0)).toBe('12') + expect(arabicFace(1)).toBe('1') + expect(arabicFace(2)).toBe('2') + expect(arabicFace(3)).toBe('3') + expect(arabicFace(4)).toBe('4') + expect(arabicFace(5)).toBe('5') + expect(arabicFace(6)).toBe('6') + expect(arabicFace(7)).toBe('7') + expect(arabicFace(8)).toBe('8') + expect(arabicFace(9)).toBe('9') + expect(arabicFace(10)).toBe('10') + expect(arabicFace(11)).toBe('11') +}) + +test('romanFace returns romanFace', () => { + expect(romanFace(0)).toBe('Ⅻ') + expect(romanFace(1)).toBe('Ⅰ') + expect(romanFace(2)).toBe('Ⅱ') + expect(romanFace(3)).toBe('Ⅲ') + expect(romanFace(4)).toBe('Ⅳ') + expect(romanFace(5)).toBe('Ⅴ') + expect(romanFace(6)).toBe('Ⅵ') + expect(romanFace(7)).toBe('Ⅶ') + expect(romanFace(8)).toBe('Ⅷ') + expect(romanFace(9)).toBe('Ⅸ') + expect(romanFace(10)).toBe('Ⅹ') + expect(romanFace(11)).toBe('Ⅺ') +}) + +test('computeFace returns face', () => { + expect(computeFace(0, 'roman')).toBe(romanFace(0)) + expect(computeFace(0, 'arabic')).toBe(arabicFace(0)) +}) From 4e8c3eab13964eee032d1f025926ae5787efc151 Mon Sep 17 00:00:00 2001 From: kitsuyui Date: Wed, 24 May 2023 08:24:50 +0900 Subject: [PATCH 10/12] Cleanup faces directory structure --- packages/clock/src/analog.tsx | 49 +----------------------- packages/clock/src/faces/arabic/index.ts | 6 +++ packages/clock/src/faces/arabic/test.ts | 16 ++++++++ packages/clock/src/faces/index.ts | 12 ++++++ packages/clock/src/faces/roman/index.ts | 29 ++++++++++++++ packages/clock/src/faces/roman/test.ts | 17 ++++++++ packages/clock/src/faces/test.ts | 9 +++++ packages/clock/src/test.tsx | 43 +-------------------- packages/clock/src/types.ts | 2 - 9 files changed, 92 insertions(+), 91 deletions(-) create mode 100644 packages/clock/src/faces/arabic/index.ts create mode 100644 packages/clock/src/faces/arabic/test.ts create mode 100644 packages/clock/src/faces/index.ts create mode 100644 packages/clock/src/faces/roman/index.ts create mode 100644 packages/clock/src/faces/roman/test.ts create mode 100644 packages/clock/src/faces/test.ts diff --git a/packages/clock/src/analog.tsx b/packages/clock/src/analog.tsx index 82c2c928..c6c50fb2 100644 --- a/packages/clock/src/analog.tsx +++ b/packages/clock/src/analog.tsx @@ -1,5 +1,6 @@ import React from 'react' +import { computeFace, FaceType } from './faces' import { degreeToCos, degreeToSin, @@ -8,7 +9,7 @@ import { secondToDegree, calcHMS, } from './math' -import { ClockProps, StepStyle, AnalogClockFaceType as FaceType } from './types' +import { ClockProps, StepStyle } from './types' export interface AnalogClockStyle { width: number @@ -328,52 +329,6 @@ const Faces = (props: { return <>{faces} } -export function computeFace(num: number, faceType: FaceType): string { - switch (faceType) { - case 'arabic': - return arabicFace(num) - case 'roman': - return romanFace(num) - } -} - -export function arabicFace(num: number): string { - if (num === 0) { - return '12' - } - return `${num}` -} - -export function romanFace(num: number): string { - switch (num) { - case 0: - return 'Ⅻ' - case 1: - return 'Ⅰ' - case 2: - return 'Ⅱ' - case 3: - return 'Ⅲ' - case 4: - return 'Ⅳ' - case 5: - return `Ⅴ` - case 6: - return 'Ⅵ' - case 7: - return 'Ⅶ' - case 8: - return 'Ⅷ' - case 9: - return 'Ⅸ' - case 10: - return 'Ⅹ' - case 11: - return 'Ⅺ' - } - return `${num}` // unreachable -} - function customizeClockProps( customize: AnalogClockCustomize ): AnalogClockStyle { diff --git a/packages/clock/src/faces/arabic/index.ts b/packages/clock/src/faces/arabic/index.ts new file mode 100644 index 00000000..d72ad332 --- /dev/null +++ b/packages/clock/src/faces/arabic/index.ts @@ -0,0 +1,6 @@ +export function face(num: number): string { + if (num === 0) { + return '12' + } + return `${num}` +} diff --git a/packages/clock/src/faces/arabic/test.ts b/packages/clock/src/faces/arabic/test.ts new file mode 100644 index 00000000..10456d4c --- /dev/null +++ b/packages/clock/src/faces/arabic/test.ts @@ -0,0 +1,16 @@ +import { face } from '.' + +test('arabic/face returns face', () => { + expect(face(0)).toBe('12') // clock starts at 12 + expect(face(1)).toBe('1') + expect(face(2)).toBe('2') + expect(face(3)).toBe('3') + expect(face(4)).toBe('4') + expect(face(5)).toBe('5') + expect(face(6)).toBe('6') + expect(face(7)).toBe('7') + expect(face(8)).toBe('8') + expect(face(9)).toBe('9') + expect(face(10)).toBe('10') + expect(face(11)).toBe('11') +}) diff --git a/packages/clock/src/faces/index.ts b/packages/clock/src/faces/index.ts new file mode 100644 index 00000000..4d6dc123 --- /dev/null +++ b/packages/clock/src/faces/index.ts @@ -0,0 +1,12 @@ +import { face as arabicFace } from './arabic' +import { face as romanFace } from './roman' +export type FaceType = 'roman' | 'arabic' + +export function computeFace(num: number, faceType: FaceType): string { + switch (faceType) { + case 'arabic': + return arabicFace(num) + case 'roman': + return romanFace(num) + } +} diff --git a/packages/clock/src/faces/roman/index.ts b/packages/clock/src/faces/roman/index.ts new file mode 100644 index 00000000..6254f48a --- /dev/null +++ b/packages/clock/src/faces/roman/index.ts @@ -0,0 +1,29 @@ +export function face(num: number): string { + switch (num) { + case 0: + return 'Ⅻ' + case 1: + return 'Ⅰ' + case 2: + return 'Ⅱ' + case 3: + return 'Ⅲ' + case 4: + return 'Ⅳ' + case 5: + return `Ⅴ` + case 6: + return 'Ⅵ' + case 7: + return 'Ⅶ' + case 8: + return 'Ⅷ' + case 9: + return 'Ⅸ' + case 10: + return 'Ⅹ' + case 11: + return 'Ⅺ' + } + return `${num}` // unreachable +} diff --git a/packages/clock/src/faces/roman/test.ts b/packages/clock/src/faces/roman/test.ts new file mode 100644 index 00000000..c5846740 --- /dev/null +++ b/packages/clock/src/faces/roman/test.ts @@ -0,0 +1,17 @@ +import { face } from '.' + +test('roman/face returns face', () => { + expect(face(0)).toBe('Ⅻ') + expect(face(1)).toBe('Ⅰ') + expect(face(2)).toBe('Ⅱ') + expect(face(3)).toBe('Ⅲ') + expect(face(4)).toBe('Ⅳ') + expect(face(5)).toBe('Ⅴ') + expect(face(6)).toBe('Ⅵ') + expect(face(7)).toBe('Ⅶ') + expect(face(8)).toBe('Ⅷ') + expect(face(9)).toBe('Ⅸ') + expect(face(10)).toBe('Ⅹ') + expect(face(11)).toBe('Ⅺ') + expect(face(12)).toBe('12') // invalid +}) diff --git a/packages/clock/src/faces/test.ts b/packages/clock/src/faces/test.ts new file mode 100644 index 00000000..76756ef9 --- /dev/null +++ b/packages/clock/src/faces/test.ts @@ -0,0 +1,9 @@ +import { face as arabicFace } from './arabic' +import { face as romanFace } from './roman' + +import { computeFace } from '.' + +test('computeFace returns face', () => { + expect(computeFace(0, 'roman')).toBe(romanFace(0)) + expect(computeFace(0, 'arabic')).toBe(arabicFace(0)) +}) diff --git a/packages/clock/src/test.tsx b/packages/clock/src/test.tsx index 9a681bc4..fbad5115 100644 --- a/packages/clock/src/test.tsx +++ b/packages/clock/src/test.tsx @@ -3,13 +3,7 @@ import React from 'react' import { tickHMS, sweepHMS, calcHMS } from './math' -import { - AnalogClock, - DigitalClock, - computeFace, - romanFace, - arabicFace, -} from '.' +import { AnalogClock, DigitalClock } from '.' test('render AnalogClock', () => { const dt = new Date('2021-01-01T00:00:00Z') @@ -55,38 +49,3 @@ test('calcHMS returns HMS', () => { expect(calcHMS(dt, 'Asia/Tokyo', 'tick')).toEqual(tickHMS(dt, 'Asia/Tokyo')) expect(calcHMS(dt, 'Asia/Tokyo', 'sweep')).toEqual(sweepHMS(dt, 'Asia/Tokyo')) }) - -test('arabicFace returns arabicFace', () => { - expect(arabicFace(0)).toBe('12') - expect(arabicFace(1)).toBe('1') - expect(arabicFace(2)).toBe('2') - expect(arabicFace(3)).toBe('3') - expect(arabicFace(4)).toBe('4') - expect(arabicFace(5)).toBe('5') - expect(arabicFace(6)).toBe('6') - expect(arabicFace(7)).toBe('7') - expect(arabicFace(8)).toBe('8') - expect(arabicFace(9)).toBe('9') - expect(arabicFace(10)).toBe('10') - expect(arabicFace(11)).toBe('11') -}) - -test('romanFace returns romanFace', () => { - expect(romanFace(0)).toBe('Ⅻ') - expect(romanFace(1)).toBe('Ⅰ') - expect(romanFace(2)).toBe('Ⅱ') - expect(romanFace(3)).toBe('Ⅲ') - expect(romanFace(4)).toBe('Ⅳ') - expect(romanFace(5)).toBe('Ⅴ') - expect(romanFace(6)).toBe('Ⅵ') - expect(romanFace(7)).toBe('Ⅶ') - expect(romanFace(8)).toBe('Ⅷ') - expect(romanFace(9)).toBe('Ⅸ') - expect(romanFace(10)).toBe('Ⅹ') - expect(romanFace(11)).toBe('Ⅺ') -}) - -test('computeFace returns face', () => { - expect(computeFace(0, 'roman')).toBe(romanFace(0)) - expect(computeFace(0, 'arabic')).toBe(arabicFace(0)) -}) diff --git a/packages/clock/src/types.ts b/packages/clock/src/types.ts index 34f39dc0..07678102 100644 --- a/packages/clock/src/types.ts +++ b/packages/clock/src/types.ts @@ -10,8 +10,6 @@ export interface ClockContainerProps { export type StepStyle = 'tick' | 'sweep' -export type AnalogClockFaceType = 'roman' | 'arabic' - export type HMS = { hour: number minute: number From 6fef0b4ad13c708f06f11bfe760b60f0389de2d1 Mon Sep 17 00:00:00 2001 From: kitsuyui Date: Wed, 24 May 2023 08:33:58 +0900 Subject: [PATCH 11/12] Cleanup step (sweep/tick) directory structure --- packages/clock/src/analog.tsx | 4 +-- packages/clock/src/math.tsx | 35 ------------------------ packages/clock/src/step/index.ts | 46 ++++++++++++++++++++++++++++++++ packages/clock/src/step/test.ts | 32 ++++++++++++++++++++++ packages/clock/src/test.tsx | 33 ----------------------- packages/clock/src/types.ts | 8 ------ 6 files changed, 80 insertions(+), 78 deletions(-) create mode 100644 packages/clock/src/step/index.ts create mode 100644 packages/clock/src/step/test.ts diff --git a/packages/clock/src/analog.tsx b/packages/clock/src/analog.tsx index c6c50fb2..0e2e01a5 100644 --- a/packages/clock/src/analog.tsx +++ b/packages/clock/src/analog.tsx @@ -7,9 +7,9 @@ import { hourToDegree, minuteToDegree, secondToDegree, - calcHMS, } from './math' -import { ClockProps, StepStyle } from './types' +import { calcHMS, StepStyle } from './step' +import { ClockProps } from './types' export interface AnalogClockStyle { width: number diff --git a/packages/clock/src/math.tsx b/packages/clock/src/math.tsx index fd69fde9..68e41230 100644 --- a/packages/clock/src/math.tsx +++ b/packages/clock/src/math.tsx @@ -1,7 +1,3 @@ -import { DateTime } from 'luxon' - -import type { StepStyle, HMS } from './types' - export function hourToDegree(hour: number): number { return hour * 30 } @@ -25,34 +21,3 @@ export function degreeToCos(degree: number): number { export function degreeToRadian(degree: number): number { return degree * (Math.PI / 180) } - -export function calcHMS( - date: Date, - timezone: string, - stepStyle: StepStyle -): HMS { - switch (stepStyle) { - case 'tick': - return tickHMS(date, timezone) - case 'sweep': - return sweepHMS(date, timezone) - } -} - -export function tickHMS(date: Date, timezone: string): HMS { - const datetime = DateTime.fromJSDate(date) - const dt = datetime.setZone(timezone) - const hour = dt.hour - const minute = dt.minute - const second = dt.second - return { hour, minute, second } -} - -export function sweepHMS(date: Date, timezone: string): HMS { - const datetime = DateTime.fromJSDate(date) - const dt = datetime.setZone(timezone) - const hour = dt.hour + dt.minute / 60 + dt.second / 3600 - const minute = dt.minute + dt.second / 60 - const second = dt.second + dt.millisecond / 1000 - return { hour, minute, second } -} diff --git a/packages/clock/src/step/index.ts b/packages/clock/src/step/index.ts new file mode 100644 index 00000000..7b73656d --- /dev/null +++ b/packages/clock/src/step/index.ts @@ -0,0 +1,46 @@ +import { DateTime } from 'luxon' + +export type StepStyle = 'tick' | 'sweep' + +interface HMS { + hour: number + minute: number + second: number +} + +export function calcHMS( + date: Date, + timezone: string, + stepStyle: StepStyle +): HMS { + switch (stepStyle) { + case 'tick': + return tickHMS(date, timezone) + case 'sweep': + return sweepHMS(date, timezone) + } +} + +/** + * tick represents a clock hand that moves in discrete steps + */ +export function tickHMS(date: Date, timezone: string): HMS { + const datetime = DateTime.fromJSDate(date) + const dt = datetime.setZone(timezone) + const hour = dt.hour + const minute = dt.minute + const second = dt.second + return { hour, minute, second } +} + +/** + * sweep represents a clock hand that moves smoothly + */ +export function sweepHMS(date: Date, timezone: string): HMS { + const datetime = DateTime.fromJSDate(date) + const dt = datetime.setZone(timezone) + const hour = dt.hour + dt.minute / 60 + dt.second / 3600 + const minute = dt.minute + dt.second / 60 + const second = dt.second + dt.millisecond / 1000 + return { hour, minute, second } +} diff --git a/packages/clock/src/step/test.ts b/packages/clock/src/step/test.ts new file mode 100644 index 00000000..5c3b85ab --- /dev/null +++ b/packages/clock/src/step/test.ts @@ -0,0 +1,32 @@ +import { calcHMS, tickHMS, sweepHMS } from '.' + +test('tickHMS returns HMS', () => { + const dt = new Date('2021-01-01T00:00:00Z') + expect(tickHMS(dt, 'Asia/Tokyo')).toEqual({ + hour: 9, + minute: 0, + second: 0, + }) + + const dt2 = new Date('2021-01-01T10:08:14Z') + expect(tickHMS(dt2, 'Asia/Tokyo')).toEqual({ + hour: 19, + minute: 8, + second: 14, + }) +}) + +test('sweepHMS returns HMS', () => { + const dt2 = new Date('2021-01-01T10:08:14.2000Z') + expect(sweepHMS(dt2, 'Asia/Tokyo')).toEqual({ + hour: 19.13722222222222, + minute: 8.233333333333333, + second: 14.2, + }) +}) + +test('calcHMS returns HMS', () => { + const dt = new Date('2021-01-01T10:08:14.2000Z') + expect(calcHMS(dt, 'Asia/Tokyo', 'tick')).toEqual(tickHMS(dt, 'Asia/Tokyo')) + expect(calcHMS(dt, 'Asia/Tokyo', 'sweep')).toEqual(sweepHMS(dt, 'Asia/Tokyo')) +}) diff --git a/packages/clock/src/test.tsx b/packages/clock/src/test.tsx index fbad5115..1ec2eb51 100644 --- a/packages/clock/src/test.tsx +++ b/packages/clock/src/test.tsx @@ -1,8 +1,6 @@ import { render } from '@testing-library/react' import React from 'react' -import { tickHMS, sweepHMS, calcHMS } from './math' - import { AnalogClock, DigitalClock } from '.' test('render AnalogClock', () => { @@ -18,34 +16,3 @@ test('render DigitalClock', () => { ) expect(asFragment()).toMatchSnapshot() }) - -test('tickHMS returns HMS', () => { - const dt = new Date('2021-01-01T00:00:00Z') - expect(tickHMS(dt, 'Asia/Tokyo')).toEqual({ - hour: 9, - minute: 0, - second: 0, - }) - - const dt2 = new Date('2021-01-01T10:08:14Z') - expect(tickHMS(dt2, 'Asia/Tokyo')).toEqual({ - hour: 19, - minute: 8, - second: 14, - }) -}) - -test('sweepHMS returns HMS', () => { - const dt2 = new Date('2021-01-01T10:08:14.2000Z') - expect(sweepHMS(dt2, 'Asia/Tokyo')).toEqual({ - hour: 19.13722222222222, - minute: 8.233333333333333, - second: 14.2, - }) -}) - -test('calcHMS returns HMS', () => { - const dt = new Date('2021-01-01T10:08:14.2000Z') - expect(calcHMS(dt, 'Asia/Tokyo', 'tick')).toEqual(tickHMS(dt, 'Asia/Tokyo')) - expect(calcHMS(dt, 'Asia/Tokyo', 'sweep')).toEqual(sweepHMS(dt, 'Asia/Tokyo')) -}) diff --git a/packages/clock/src/types.ts b/packages/clock/src/types.ts index 07678102..ed34f7c4 100644 --- a/packages/clock/src/types.ts +++ b/packages/clock/src/types.ts @@ -7,11 +7,3 @@ export interface ClockContainerProps { children: React.ReactElement | React.ReactElement[] refreshInterval?: number } - -export type StepStyle = 'tick' | 'sweep' - -export type HMS = { - hour: number - minute: number - second: number -} From c20ca2010ca3c68f22aef1f035329fbf0d18c7b6 Mon Sep 17 00:00:00 2001 From: kitsuyui Date: Wed, 24 May 2023 09:09:24 +0900 Subject: [PATCH 12/12] Clean up --- .../clock/src/__snapshots__/test.tsx.snap | 104 +++++++++--------- packages/clock/src/analog.tsx | 67 ++++++----- packages/clock/src/math.tsx | 23 ---- 3 files changed, 83 insertions(+), 111 deletions(-) delete mode 100644 packages/clock/src/math.tsx diff --git a/packages/clock/src/__snapshots__/test.tsx.snap b/packages/clock/src/__snapshots__/test.tsx.snap index 881e8a80..e74d210f 100644 --- a/packages/clock/src/__snapshots__/test.tsx.snap +++ b/packages/clock/src/__snapshots__/test.tsx.snap @@ -255,18 +255,18 @@ exports[`render AnalogClock 1`] = ` 12 @@ -621,7 +621,7 @@ exports[`render AnalogClock 1`] = ` font-family="monospace" font-size="9.4" text-anchor="middle" - x="68.80000000000001" + x="68.8" y="17.437444817705106" > 1 @@ -633,7 +633,7 @@ exports[`render AnalogClock 1`] = ` font-size="9.4" text-anchor="middle" x="82.56255518229489" - y="31.19999999999998" + y="31.199999999999996" > 2 @@ -644,7 +644,7 @@ exports[`render AnalogClock 1`] = ` font-size="9.4" text-anchor="middle" x="87.6" - y="49.99999999999999" + y="50" > 3 @@ -655,7 +655,7 @@ exports[`render AnalogClock 1`] = ` font-size="9.4" text-anchor="middle" x="82.56255518229489" - y="68.80000000000001" + y="68.8" > 4 @@ -665,7 +665,7 @@ exports[`render AnalogClock 1`] = ` font-family="monospace" font-size="9.4" text-anchor="middle" - x="68.80000000000001" + x="68.8" y="82.56255518229489" > 5 @@ -687,7 +687,7 @@ exports[`render AnalogClock 1`] = ` font-family="monospace" font-size="9.4" text-anchor="middle" - x="31.2" + x="31.199999999999996" y="82.56255518229489" > 7 @@ -698,8 +698,8 @@ exports[`render AnalogClock 1`] = ` font-family="monospace" font-size="9.4" text-anchor="middle" - x="17.4374448177051" - y="68.79999999999998" + x="17.437444817705114" + y="68.80000000000001" > 8 @@ -710,7 +710,7 @@ exports[`render AnalogClock 1`] = ` font-size="9.4" text-anchor="middle" x="12.399999999999999" - y="50.000000000000014" + y="50.00000000000001" > 9 @@ -720,8 +720,8 @@ exports[`render AnalogClock 1`] = ` font-family="monospace" font-size="9.4" text-anchor="middle" - x="17.437444817705085" - y="31.200000000000028" + x="17.437444817705106" + y="31.199999999999996" > 10 @@ -731,8 +731,8 @@ exports[`render AnalogClock 1`] = ` font-family="monospace" font-size="9.4" text-anchor="middle" - x="31.200000000000006" - y="17.4374448177051" + x="31.19999999999998" + y="17.437444817705114" > 11 diff --git a/packages/clock/src/analog.tsx b/packages/clock/src/analog.tsx index 0e2e01a5..5bf25010 100644 --- a/packages/clock/src/analog.tsx +++ b/packages/clock/src/analog.tsx @@ -1,13 +1,6 @@ import React from 'react' import { computeFace, FaceType } from './faces' -import { - degreeToCos, - degreeToSin, - hourToDegree, - minuteToDegree, - secondToDegree, -} from './math' import { calcHMS, StepStyle } from './step' import { ClockProps } from './types' @@ -159,17 +152,13 @@ export const AnalogClock: React.FC = (props): JSX.Element => { centerX={centerX} centerY={centerY} radius={frame.size - hourLines.length} - length={hourLines.length} - width={hourLines.width} - color={hourLines.color} + {...hourLines} /> = (props): JSX.Element => { @@ -208,8 +197,9 @@ export const Hand: React.FC< } & HandStyle > = (props) => { const { centerX, centerY, degree, length, width, color } = props - const x = centerX + length * degreeToSin(degree) - const y = centerY - length * degreeToCos(degree) + const radDegree = degreeToRadian(degree) + const x = centerX + length * Math.sin(radDegree) + const y = centerY - length * Math.cos(radDegree) // clock coordinate return ( { const { centerX, centerY, radius } = props const faces = [] + const textSize = radius / 5 + const radius2 = radius - textSize + const textStyle = { + textAnchor: 'middle', + dominantBaseline: 'central', + fontSize: textSize, + fontFamily: 'monospace', + fill: 'black', + } for (let i = 0; i < 12; i++) { - const degree = (360 / 12) * i + 180 - const textSize = radius / 5 - const x = centerX + (radius - textSize) * degreeToSin(-degree) - const y = centerY + (radius - textSize) * degreeToCos(-degree) + const degree = (360 / 12) * i + const rad = degreeToRadian(degree) + const x = centerX + radius2 * Math.sin(rad) + const y = centerY - radius2 * Math.cos(rad) // clock coordinate faces.push( - + {computeFace(i, props.faceType)} ) @@ -383,3 +374,7 @@ function customizeClockProps( }, } } + +function degreeToRadian(degree: number): number { + return (degree * Math.PI) / 180 +} diff --git a/packages/clock/src/math.tsx b/packages/clock/src/math.tsx deleted file mode 100644 index 68e41230..00000000 --- a/packages/clock/src/math.tsx +++ /dev/null @@ -1,23 +0,0 @@ -export function hourToDegree(hour: number): number { - return hour * 30 -} - -export function secondToDegree(second: number): number { - return second * 6 -} - -export function minuteToDegree(minute: number): number { - return minute * 6 -} - -export function degreeToSin(degree: number): number { - return Math.sin(degreeToRadian(degree)) -} - -export function degreeToCos(degree: number): number { - return Math.cos(degreeToRadian(degree)) -} - -export function degreeToRadian(degree: number): number { - return degree * (Math.PI / 180) -}