@aptpod/data-viz-create-visual-parts-react
Version:
template of npm project with typescript
147 lines (128 loc) • 4.59 kB
text/typescript
import {
FontFamilies,
ViewGrid,
DataSpecification,
Value,
} from '@aptpod/data-viz-visual-parts-sdk'
import { ComponentProps, useMemo } from 'react'
import { BIND_DATA_COUNT_MAX } from './constant'
import { HorizontalBars } from './component'
import { shouldDisplayedSmall, calcRatio } from './utils'
import { canDisplayNumber } from 'src/utils/validator'
import { memoize } from 'src/utils/memoize'
import { buildEmptyArray, selectNonNullables } from 'src/utils/array'
/**
* HorizontalBars Componentの Props型
*/
type HorizontalBarsProps = ComponentProps<typeof HorizontalBars>
type HorizontalBarsPropsValue = HorizontalBarsProps['values'][0]
/**
* DataSpecificationで使用するフィールドの型のみで再定義
*/
type UsedDataSpecification = Pick<
DataSpecification,
'rangeMin' | 'rangeMax' | 'dataName' | 'decimalDigits'
>
/**
* Valueで使用するフィールドの型のみで再定義
*/
type UsedValue = Pick<Value, 'baseIdx' | 'data'>
/**
* HorizontalBars ComponentのPropsに変換します。
* メモ化のため、useMemo、memoize を使用しています。
* memoizeは、可変引数、loop内で使用するfunctionのメモ化で使用しています。
*/
export const useSelectProps = (params: {
fontFamilies: FontFamilies
viewGrid: ViewGrid
dataSpecifications: UsedDataSpecification[]
values: UsedValue[]
}): HorizontalBarsProps => {
const { fontFamilies, viewGrid, dataSpecifications, values } = params
// 小さい表示にするかViewGridを使用して判定します。
// メモ化のため、useMemoを使用します。
const showSmall = useMemo(() => {
return shouldDisplayedSmall(viewGrid.colSpan, viewGrid.rowSpan)
}, [viewGrid.colSpan, viewGrid.rowSpan])
// 使用するFontFamilyを取得します。
// メモ化のため、useMemoを使用します。
const propsFontFamilies = useMemo(() => {
return {
name: fontFamilies.yotsuyaSansJPRegular,
value: fontFamilies.apt7seg,
}
}, [fontFamilies.yotsuyaSansJPRegular, fontFamilies.apt7seg])
// selectNonNullablesのメモ化
const memoizedSelectNonNullables = useMemo(
() => memoize(selectNonNullables),
[],
)
// PropsValueを生成するためのメモ化済みfunctionの初期化
const memoizedPropsValues = useMemo(() => {
return buildEmptyArray(BIND_DATA_COUNT_MAX).map(() => ({
buildPropsValue: memoize(buildPropsValue),
}))
}, [])
// Props Values を取得します。
// メモ化したfunctionを使用します。
const propsValues = memoizedSelectNonNullables(
...buildEmptyArray(BIND_DATA_COUNT_MAX).map((_, i) =>
selectPropsValue(
dataSpecifications[i],
values[i],
memoizedPropsValues[i].buildPropsValue,
),
),
)
return {
showSmall,
fontFamilies: propsFontFamilies,
values: propsValues,
}
}
/**
* HorizontalBarsのValueに変換します。
* dataSpecification, value が未定義の場合はnullを返します。
*/
const selectPropsValue = (
dataSpecification: UsedDataSpecification | undefined,
value: UsedValue | undefined,
funcBuildPropsValue: typeof buildPropsValue,
): HorizontalBarsPropsValue | null => {
// dataSpecification, value のいずれかが無効の場合はnullを返します。
if (!dataSpecification || !value) {
return null
}
// baseIdx に該当するデータポイントの値を取得します。
// 取得できない場合は空文字列とみなします。
const v = value.data[value.baseIdx]?.v ?? ''
// dataSpecification から変換に必要な項目を取得します。
const { dataName, rangeMin, rangeMax, decimalDigits } = dataSpecification
// HorizontalBarsのバー表示するためのratioを計算します。
// データポイントの値が数値として判定できない場合は0とします。
const ratio = canDisplayNumber(v)
? calcRatio({
min: rangeMin,
max: rangeMax,
value: Number(v),
})
: 0
// HorizontalBarsに表示するテキストに変換します。
// データポイントの値が数値として判定できない場合は、小数点の有効桁数を使用せずに文字列に変換します。
const text = canDisplayNumber(v)
? Number(v).toFixed(decimalDigits)
: String(v)
return funcBuildPropsValue(dataName, ratio, text)
}
/**
* HorizontalBarsPropsValueのObjectを作成します。
*/
const buildPropsValue = (
name: string,
ratio: number,
text: string,
): HorizontalBarsPropsValue => ({
name,
ratio,
text,
})