npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@yolanda-qn/indicator-library

v0.2.0

Published

## 核心方法

Downloads

2

Readme

@yolanda-qn/indicator-library

核心方法

reportItemBuildFunction

构建单个指标的方法

注意这里目前仅支持protein(蛋白质)与water(体水分)两个指标( 已能满足构建节段指标的需求,详见后面的完整业务代码示例)

参数

| 名称 | 类型 | 必须 | 默认值 | 说明 | | :------------ | :-------------------------------------------- | :--: | :----: | :---------------------- | | key | EightElectrodesIndex | Y | | 需要计算的八电极指标key | | measureDetail | SourceMeasureDetail | Y | | 原始测量数据 | | option | CalculateOptions | Y | | 计算时的目标转换单位 |

返回值

| 类型 | 说明 | | :------------------------ | :----------- | | ReportItem | 指标报告对象 |

示例

import { reportItemBuildFunction } from '@yolanda-qn/indicator-library'

// 目标单位
const targetWeightUnit: WeightUnit = 'lb'

// 模拟数据(仅用作说明)
const mockSourceMeasureDetail: Partial<SourceMeasureDetail> = {
  birthday: '2000-01-01',
  gender: 1,
  height: 170,
  protein: 100,
  water: 35,
  weight: 68,
  // ...
}

// 构建出的报告
const waterMassReport = reportItemBuildFunction('water', mockSourceMeasureDetail, { targetWeightUnit })

subBodyFatIndexCalculator

专门用于构建四肢与躯干体脂指标的函数

参数

| 名称 | 类型 | 必须 | 默认值 | 说明 | | :----- | :---------------------------------------------------------------------------- | :--: | :----: | :------- | | params | subBodyFatIndexCalculatorParams(下方表格) | Y | | 参数对象 |

subBodyFatIndexCalculatorParams

| 名称 | 类型 | 必须 | 默认值 | 说明 | | :------------ | :------------------------------------------ | :--: | :----: | :-------------- | | measureDetail | SourceMeasureDetail | Y | | 原始测量数据 | | subIndexType | BodyFatSubIndex | Y | | 次级体脂指标key |

返回值

| 类型 | 说明 | | :------------------------ | :----------- | | ReportItem | 指标报告对象 |

示例

import {subBodyFatIndexCalculator} from '@yolanda-qn/indicator-library'

// 模拟数据(仅用作说明)
const mockSourceMeasureDetail: Partial<SourceMeasureDetail> = {
    birthday: '2000-01-01',
    gender: 1,
    height: 170,
    protein: 100,
    water: 35,
    weight: 68,
    // ...
}

// 构建出的报告
const bodyFatLeftArmReport = subBodyFatIndexCalculator({
    measureDetail: mockSourceMeasureDetail,
    subIndexType: 'bodyFatLeftArm',
})

subSinewIndexCalculator

专门用于构建四肢与躯干肌肉指标的函数

参数

| 名称 | 类型 | 必须 | 默认值 | 说明 | | :----- | :------------------------------------------------------------------------ | :--: | :----: | :------- | | params | subSinewIndexCalculatorParams(下方表格) | Y | | 参数对象 |

subSinewIndexCalculatorParams

| 名称 | 类型 | 必须 | 默认值 | 说明 | | :--------------- | :------------------------------------------ | :--: | :----: | :-------------- | | measureDetail | SourceMeasureDetail | Y | | 原始测量数据 | | subIndexType | SinewSubIndex | Y | | 次级肌肉指标key | | targetWeightUnit | WeightUnit | Y | | 目标体重单位 |

返回值

| 类型 | 说明 | | :------------------------ | :----------- | | ReportItem | 指标报告对象 |

示例

import { subSinewIndexCalculator } from '@yolanda-qn/indicator-library'

// 目标单位
const targetWeightUnit: WeightUnit = 'lb'

// 模拟数据(仅用作说明)
const mockSourceMeasureDetail: Partial<SourceMeasureDetail> = {
  birthday: '2000-01-01',
  gender: 1,
  height: 170,
  protein: 100,
  water: 35,
  weight: 68,
  // ...
}

// 构建出的报告
const sinewLeftArmReport = subSinewIndexCalculator({
  measureDetail: mockSourceMeasureDetail,
  subIndexType: 'sinewLeftArm',
  targetWeightUnit,
})

NP

一个在js中安全进行小数数学运行的库的导出 详见其官方文档

generateGenerateFormatValueObjectForWeightFn

在本库中承担重量单位转换的函数 采用了柯里化的编写方式 具体使用可以参见下面完整业务代码示例中的构建肌肉平衡相关内容

参数

| 名称 | 类型 | 必须 | 默认值 | 说明 | | :----- | :-------------------------------------------------------------------------------------------- | :--: | :----: | :------- | | params | WeightUnitTransformForSingleValueParams(下方表格) | Y | | 参数对象 |

WeightUnitTransformForSingleValueParams

| 名称 | 类型 | 必须 | 默认值 | 说明 | | :--------------- | :------------------------ | :--: | :----: | :----------- | | targetWeightUnit | WeightUnit | Y | | 目标体重单位 |

返回值

| 类型 | 说明 | | :------------------------------------------------------ | :----------------- | | WeightFormatValueObjectFn | 用于转换单位的函数 |

示例

// 目标单位
const targetWeightUnit: WeightUnit = 'lb'

const formatValueObjectFn = generateGenerateFormatValueObjectForWeightFn({
  targetWeightUnit,
})

const result = formatValueObjectFn(100) // 将100kg转换为目标单位

完整业务代码示例

以使用本库导出的方法与接口组装出构建肌肉平衡节段脂肪方法为示例

import {
  boundariesAverage,
  calcValuesLevelProcess,
  generateGenerateFormatValueObjectForWeightFn,
  NP,
  reportItemBuildFunction,
  SourceMeasureDetail,
  subBodyFatIndexCalculator,
  subSinewIndexCalculator,
  WeightUnit,
} from '@yolanda-qn/indicator-library'

// 目标单位
const targetWeightUnit: WeightUnit = 'lb'
// 模拟数据(仅用作说明)
const mockSourceMeasureDetail: Partial<SourceMeasureDetail> = {
  birthday: '2000-01-01',
  gender: 1,
  height: 170,
  protein: 100,
  water: 35,
  weight: 68,
  // ...
}

// 自行组装用于构建肌肉平衡的方法
export const muscleBalanceIndicatorBuildFunction = (measureDetail: Partial<SourceMeasureDetail>) => {
  const sinewLeftArm = measureDetail?.muscle_lh ?? 0
  const sinewLeftLeg = measureDetail?.muscle_lf ?? 0
  const sinewRightArm = measureDetail?.muscle_rh ?? 0
  const sinewRightLeg = measureDetail?.muscle_rf ?? 0
  const sinewTrunk = measureDetail?.muscle_t ?? 0

  const sinewLeftArmReport = subSinewIndexCalculator({
    measureDetail: mockSourceMeasureDetail,
    subIndexType: 'sinewLeftArm',
    targetWeightUnit,
  })
  const sinewRightArmReport = subSinewIndexCalculator({
    measureDetail: mockSourceMeasureDetail,
    subIndexType: 'sinewRightArm',
    targetWeightUnit,
  })
  const sinewLeftLegReport = subSinewIndexCalculator({
    measureDetail: mockSourceMeasureDetail,
    subIndexType: 'sinewLeftLeg',
    targetWeightUnit,
  })
  const sinewRightLegReport = subSinewIndexCalculator({
    measureDetail: mockSourceMeasureDetail,
    subIndexType: 'sinewRightLeg',
    targetWeightUnit,
  })
  const sinewTrunkReport = subSinewIndexCalculator({
    measureDetail: mockSourceMeasureDetail,
    subIndexType: 'sinewTrunk',
    targetWeightUnit,
  })
  const proteinMassReport = reportItemBuildFunction('protein', mockSourceMeasureDetail, { targetWeightUnit })
  const waterMassReport = reportItemBuildFunction('water', mockSourceMeasureDetail, { targetWeightUnit })

  // 上肢均衡百分比差值
  const sinewArmPercent = Math.abs(
    NP.minus(sinewLeftArmReport.formatValueObject.calcValue, sinewRightArmReport.formatValueObject.calcValue),
  )
  // 下肢均衡百分比差值
  const sinewLegPercent = Math.abs(
    NP.minus(sinewLeftLegReport.formatValueObject.calcValue, sinewRightLegReport.formatValueObject.calcValue),
  )
  const boundaries = [6, 9]

  // 计算差值的等级
  const sinewArmValueClc = calcValuesLevelProcess(sinewArmPercent, boundaries)
  const sinewLegValueClc = calcValuesLevelProcess(sinewLegPercent, boundaries)

  // 上肢均衡百分比平均值
  const sinewArmAverage = boundariesAverage([
    sinewLeftArmReport.formatValueObject.calcValue,
    sinewRightArmReport.formatValueObject.calcValue,
  ])
  // 下肢均衡百分比平均值
  const sinewLegAverage = boundariesAverage([
    sinewLeftLegReport.formatValueObject.calcValue,
    sinewRightLegReport.formatValueObject.calcValue,
  ])

  // 计算平均值的等级
  const sinewArmAverageValueClc = calcValuesLevelProcess(sinewArmAverage, sinewLeftArmReport.standardValueArray)
  const sinewLegAverageValueClc = calcValuesLevelProcess(sinewLegAverage, sinewLeftLegReport.standardValueArray)

  // 肌肉总量的标准为:蛋白质的标准 + 水分的标准
  // 肌肉量范围最小值 = 水分范围最小值+蛋白质范围最小值
  // 肌肉量范围最大值 = 水分范围最大值 + 蛋白质范围最大值
  const bodyMuscleBoundaries = [
    NP.plus(
      proteinMassReport.criticalFormatValueObjectArray[0].sourceValue,
      waterMassReport.criticalFormatValueObjectArray[0].sourceValue,
    ),
    NP.plus(
      proteinMassReport.criticalFormatValueObjectArray[1].sourceValue,
      waterMassReport.criticalFormatValueObjectArray[1].sourceValue,
    ),
  ]
  const bodyMuscleValeClc = calcValuesLevelProcess(measureDetail?.sinew ?? 0, bodyMuscleBoundaries)

  // 生成格式化原始值的方法
  const formatValueObjectFn = generateGenerateFormatValueObjectForWeightFn({
    targetWeightUnit,
  })

  /**
   * @note
   * 下面的数据结构根据需求来组装 这里仅作参考
   */
  return {
    swipeItem1: {
      leftArm: {
        levelIndex: sinewLeftArmReport.level,
        percent: {
          value: sinewLeftArmReport.formatValueObject.renderStringArray[0],
          unit: sinewLeftArmReport.formatValueObject.renderStringArray[1],
        },
        mass: {
          value: formatValueObjectFn(sinewLeftArm).renderStringArray.join(''),
        },
      },
      rightArm: {
        levelIndex: sinewRightArmReport.level,
        percent: {
          value: sinewRightArmReport.formatValueObject.renderStringArray[0],
          unit: sinewRightArmReport.formatValueObject.renderStringArray[1],
        },
        mass: {
          value: formatValueObjectFn(sinewRightArm).renderStringArray.join(''),
        },
      },
      leftLeg: {
        levelIndex: sinewLeftLegReport.level,
        percent: {
          value: sinewLeftLegReport.formatValueObject.renderStringArray[0],
          unit: sinewLeftLegReport.formatValueObject.renderStringArray[1],
        },
        mass: {
          value: formatValueObjectFn(sinewLeftLeg).renderStringArray.join(''),
        },
      },
      rightLeg: {
        levelIndex: sinewRightLegReport.level,
        percent: {
          value: sinewRightLegReport.formatValueObject.renderStringArray[0],
          unit: sinewRightLegReport.formatValueObject.renderStringArray[1],
        },
        mass: {
          value: formatValueObjectFn(sinewRightLeg).renderStringArray.join(''),
        },
      },
      trunk: {
        levelIndex: sinewTrunkReport.level,
        percent: {
          value: sinewTrunkReport.formatValueObject.renderStringArray[0],
          unit: sinewTrunkReport.formatValueObject.renderStringArray[1],
        },
        mass: {
          value: formatValueObjectFn(sinewTrunk).renderStringArray.join(''),
        },
      },
    },
    swipeItem2: {
      muscleBalance: [
        {
          level: sinewArmValueClc.level,
          key: 'arm',
          levelList: ['MuscleBalance.1101', 'MuscleBalance.1102', 'MuscleBalance.1103'],
        },
        {
          level: sinewLegValueClc.level,
          key: 'leg',
          levelList: ['MuscleBalance.1101', 'MuscleBalance.1102', 'MuscleBalance.1103'],
        },
        {
          level: sinewLegValueClc.level,
          key: 'armLeg',
          levelList: ['MuscleBalance.1101', 'MuscleBalance.1102', 'MuscleBalance.1103'],
        },
      ],
      bodyStrength: [
        {
          level: sinewArmAverageValueClc.level,
          key: 'arm',
          levelList: ['MuscleBalance.1104', 'MuscleBalance.1105', 'MuscleBalance.1106'],
        },
        {
          level: sinewLegAverageValueClc.level,
          key: 'leg',
          levelList: ['MuscleBalance.1104', 'MuscleBalance.1105', 'MuscleBalance.1106'],
        },
        {
          level: bodyMuscleValeClc.level,
          key: 'muscle',
          levelList: ['MuscleBalance.1104', 'MuscleBalance.1105', 'MuscleBalance.1106'],
        },
      ],
    },
  }
}

// 自行组装用于构建节段脂肪的方法
export const segmentalFatAnalysisIndicatorBuildFunction = (measureDetail: SourceMeasureDetail) => {
  const weight = measureDetail?.weight ?? 0
  const bodyFatLeftArm = measureDetail?.fat_lh ?? 0
  const bodyFatLeftLeg = measureDetail?.fat_lf ?? 0
  const bodyFatRightArm = measureDetail?.fat_rh ?? 0
  const bodyFatRightLeg = measureDetail?.fat_rf ?? 0
  const bodyFatTrunk = measureDetail?.fat_t ?? 0

  const bodyFatLeftArmReport = subBodyFatIndexCalculator({ measureDetail, subIndexType: 'bodyFatLeftArm' })
  const bodyFatRightArmReport = subBodyFatIndexCalculator({ measureDetail, subIndexType: 'bodyFatRightArm' })
  const bodyFatLeftLegReport = subBodyFatIndexCalculator({ measureDetail, subIndexType: 'bodyFatLeftLeg' })
  const bodyFatRightLegReport = subBodyFatIndexCalculator({ measureDetail, subIndexType: 'bodyFatRightLeg' })
  const bodyFatTrunkReport = subBodyFatIndexCalculator({ measureDetail, subIndexType: 'bodyFatTrunk' })

  const formatValueObjectFn = generateGenerateFormatValueObjectForWeightFn({
    targetWeightUnit,
  })

  /**
   * @note
   * 下面的数据结构根据需求来组装 这里仅作参考
   */
  return {
    segmentalFatAnalysis: {
      leftArm: {
        levelIndex: bodyFatLeftArmReport.level,
        percent: {
          value: bodyFatLeftArmReport.formatValueObject.renderStringArray[0],
          unit: bodyFatLeftArmReport.formatValueObject.renderStringArray[1],
        },
        mass: {
          value: formatValueObjectFn(NP.divide(NP.times(bodyFatLeftArm, weight), 100)).renderStringArray.join(''),
        },
      },
      rightArm: {
        levelIndex: bodyFatRightArmReport.level,
        percent: {
          value: bodyFatRightArmReport.formatValueObject.renderStringArray[0],
          unit: bodyFatRightArmReport.formatValueObject.renderStringArray[1],
        },
        mass: {
          value: formatValueObjectFn(NP.divide(NP.times(bodyFatRightArm, weight), 100)).renderStringArray.join(''),
        },
      },
      leftLeg: {
        levelIndex: bodyFatLeftLegReport.level,
        percent: {
          value: bodyFatLeftLegReport.formatValueObject.renderStringArray[0],
          unit: bodyFatLeftLegReport.formatValueObject.renderStringArray[1],
        },
        mass: {
          value: formatValueObjectFn(NP.divide(NP.times(bodyFatLeftLeg, weight), 100)).renderStringArray.join(''),
        },
      },
      rightLeg: {
        levelIndex: bodyFatRightLegReport.level,
        percent: {
          value: bodyFatRightLegReport.formatValueObject.renderStringArray[0],
          unit: bodyFatRightLegReport.formatValueObject.renderStringArray[1],
        },
        mass: {
          value: formatValueObjectFn(NP.divide(NP.times(bodyFatRightLeg, weight), 100)).renderStringArray.join(''),
        },
      },
      trunk: {
        levelIndex: bodyFatTrunkReport.level,
        percent: {
          value: bodyFatTrunkReport.formatValueObject.renderStringArray[0],
          unit: bodyFatTrunkReport.formatValueObject.renderStringArray[1],
        },
        mass: {
          value: formatValueObjectFn(NP.divide(NP.times(bodyFatTrunk, weight), 100)).renderStringArray.join(''),
        },
      },
    },
  }
}

类型声明

SourceMeasureDetail

原始测量数据定义接口

这里与小程序插件中onGetScaleData方法回调对象中response字段的内容保持一致命名 因此直接将其用于后续方法的调用

interface SourceMeasureDetail {
  /**
   * 体重
   */
  weight: number
  /**
   * 身高
   */
  stature: number
  /**
   * 体脂率
   */
  bodyfat: number
  /**
   * 皮下脂肪
   */
  subfat: number
  /**
   *  内脏脂肪等级
   */
  visfat: number
  /**
   *  体水分
   */
  water: number
  /**
   *  基础代谢量
   */
  bmr: number
  /**
   *  骨骼肌率
   */
  muscle: number
  /**
   * 骨量(无机盐)
   */
  bone: number
  /**
   * 去脂体重
   */
  fat_free_weight: number
  /**
   * 蛋白质
   */
  protein: number
  /**
   * 肌肉率
   */
  sinew: number
  /**
   * 得分
   */
  score: number
  /**
   * 体年龄
   */
  bodyage: number
  /**
   * bmi
   */
  bmi: number
  /**
   * 体型
   */
  body_shape: number
  /**
   * 心脏指数
   */
  cardiac_index: number
  /**
   * 心率
   */
  heart_rate: number
  /**
   * 肌肉量 右手
   */
  muscle_rh: number
  /**
   * 肌肉量 左手
   */
  muscle_lh: number
  /**
   * 肌肉量 躯干
   */
  muscle_t: number
  /**
   * 肌肉量 右腿
   */
  muscle_rf: number
  /**
   * 肌肉量 左腿
   */
  muscle_lf: number
  /**
   * 脂肪率 右手
   */
  fat_rh: number
  /**
   * 脂肪率 左手
   */
  fat_lh: number
  /**
   * 脂肪率 躯干
   */
  fat_t: number
  /**
   * 脂肪率 右腿
   */
  fat_rf: number
  /**
   * 脂肪率 左腿
   */
  fat_lf: number
  /**
   * 测量时间
   */
  time: Date
  /**
   * 性别
   */
  gender: number
  /**
   * 身高
   */
  height: number
  /**
   * 生日(YYYY-MM-DD)
   */
  birthday: string
  /**
   * 年龄
   */
  age: number
}

WeightUnit

体重单位类型

type WeightUnit = 'kg' | 'lb' | 'st' | 'st+lb'

HeightUnit

身高单位类型

type HeightUnit = 'cm' | 'inch' | 'ft+in'

CalculateOptions

interface CalculateOptions {
  /**
   * 目标体重单位(默认为kg 即不发生转换)
   */
  targetWeightUnit?: WeightUnit
  /**
   * 目标身高单位(默认为cm 即不发生转换)
   */
  targetHeightUnit?: HeightUnit
}

FormatValueObject

/**
 * 🌟该对象的含义需要重点理解一下
 * 该设计中是使用了一个对象去替代了一个数值 这样可以把`原始值` `转换后的用于计算的值` `转换后用于展示的值`集成在一个对象中
 * 对于大多数单位来说`转换后的用于计算的值`与`转换后用于展示的值`是没有什么分别的
 * 但对于一些特殊的单位 例如`st:lb`单位 它在展示时是`1st1lb`的形式 但参与计算时需要以`lb`的形式参与 故这里做了区分
 */
interface FormatValueObject<SourceUnit extends string = string, CalcUnit extends string = string> {
  /**
   * **未经任何处理**的原始值
   */
  sourceValue: number
  /**
   * 原始值的单位
   */
  sourceUnit: SourceUnit
  /**
   * 用于计算的值
   */
  calcValue: number
  /**
   * 用于计算的值的单位
   */
  calcUnit: CalcUnit
  /**
   * 用于渲染的数组
   */
  renderStringArray: string[]
}

ReportItem

/**
 * 最终返回的单个指标的报告格式
 * @note 注意到下面会出现`次级`相关的内容 目前`构建节段指标`中不会涉及到可以直接忽略
 */
interface ReportItem<Key extends string = string> {
  key: Key
  /**
   * 标准值对象
   */
  standardValueFormatValueObject?: FormatValueObject
  /**
   * 边界值数组
   */
  standardValueArray: number[]
  /**
   * 次级边界值数组
   */
  subStandardValueArray?: number[]
  /**
   * 最值
   */
  minValue: number
  subMixValue?: number
  maxValue: number
  subMaxValue?: number
  /**
   * 等级数值
   */
  level: number
  /**
   * 次级等级数值
   */
  subLevel?: number
  /**
   * 等级偏移百分比
   */
  relativeProportion: number
  /**
   * 次级等级偏移百分比
   */
  subRelativeProportion?: number
  /**
   * 展示值对象
   */
  formatValueObject: FormatValueObject
  /**
   * 边界对象数组(基于standardValueArray运算)
   */
  criticalFormatValueObjectArray: FormatValueObject[]
  /**
   * 次级对象数组(基于subStandardValueArray运算)
   */
  subCriticalFormatValueObjectArray?: FormatValueObject[]
  /**
   * 是否为多单位(例如: 1st1lb 与 1lb 分别被认为是多单位与单单位)
   */
  isMultiUnit: boolean
}

EightElectrodesIndex

// 八电极指标 目前仅支持蛋白质与体水分
type EightElectrodesIndex = 'protein' | 'water'

BodyFatSubIndex

// 四肢与躯干体脂指标(左上 右上 躯干 左下 右下)
type BodyFatSubIndex = 'bodyFatLeftArm' | 'bodyFatRightArm' | 'bodyFatTrunk' | 'bodyFatLeftLeg' | 'bodyFatRightLeg'

SinewSubIndex

// 四肢与躯干肌肉指标(左上 右上 躯干 左下 右下)
type SinewSubIndex = 'sinewLeftArm' | 'sinewRightArm' | 'sinewTrunk' | 'sinewLeftLeg' | 'sinewRightLeg'

WeightFormatValueObjectFn

type WeightFormatValueObjectFn = (sourceValue: number) => FormatValueObject