Harmonyos应用实例237:科学记数法转换器
·
- 科学记数法转换器
- 功能:这是一个基于 HarmonyOS ArkTS 开发的交互式科学记数法转换工具,用户可以输入大数字(如地球到太阳的距离 149600000),系统会实时将其转换为科学记数法格式(1.496 × 10^8),并通过可视化界面展示小数点移动的过程。工具还提供了常见大数字示例和科学记数法规则说明,帮助用户理解指数与小数点移动的关系。

@Entry
@Component
struct ScientificNotationConverter {
// 状态变量
@State inputNumber: string = '149600000'
@State scientificNotation: string = ''
@State mantissa: string = ''
@State exponent: number = 0
@State isValid: boolean = true
@State errorMessage: string = ''
// Canvas 上下文
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
// 生命周期:组件创建时初始化
aboutToAppear() {
this.convertToScientific()
}
build() {
Scroll() {
Column({ space: 20 }) {
// 标题区
Text('科学记数法转换器')
.fontSize(28)
.fontWeight(FontWeight.Bold)
Text('输入大数字,实时转换为科学记数法格式')
.fontSize(14)
.fontColor('#666')
// 输入区域
Column() {
Text('输入大数字:')
.fontSize(16)
.margin({ bottom: 10 })
TextInput({
placeholder: '例如:149600000(地球到太阳的距离)',
text: this.inputNumber
})
.width('100%')
.height(45)
.borderRadius(8)
.border({ width: 1, color: this.isValid ? '#DDDDDD' : '#F44336' })
.onChange((value: string) => {
this.inputNumber = value
this.convertToScientific()
})
if (!this.isValid) {
Text(this.errorMessage)
.fontSize(12)
.fontColor('#F44336')
.margin({ top: 5 })
}
}
.width('100%')
.padding(15)
.backgroundColor('#FFFFFF')
.borderRadius(12)
// 结果显示
if (this.isValid && this.scientificNotation) {
Column({ space: 10 }) {
Text('科学记数法结果:')
.fontSize(16)
Text(this.scientificNotation)
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#2196F3')
Row({ space: 15 }) {
Column() {
Text('尾数:')
.fontSize(14)
.fontColor('#666')
Text(this.mantissa)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#4CAF50')
}
Column() {
Text('指数:')
.fontSize(14)
.fontColor('#666')
Text(`10^${this.exponent}`)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#FF9800')
}
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
}
.width('100%')
.padding(15)
.backgroundColor('#FFFFFF')
.borderRadius(12)
}
// 可视化区域
if (this.isValid && this.scientificNotation) {
Column({ space: 10 }) {
Text('小数点移动可视化:')
.fontSize(16)
.fontWeight(FontWeight.Bold)
Canvas(this.context)
.width('100%')
.height(200)
.backgroundColor('#F8F9FA')
.borderRadius(8)
.onReady(() => {
this.drawVisualization()
})
Text(`小数点移动了 ${Math.abs(this.exponent)} 位 ${this.exponent > 0 ? '向右' : '向左'}`)
.fontSize(14)
.fontColor('#666')
}
.width('100%')
.padding(15)
.backgroundColor('#FFFFFF')
.borderRadius(12)
}
// 示例和说明
Column({ space: 10 }) {
Text('🌍 常见大数字示例:')
.fontSize(16)
.fontWeight(FontWeight.Bold)
Row({ space: 10 }) {
Button('地球到太阳')
.width('45%')
.height(40)
.backgroundColor('#E3F2FD')
.fontColor('#1976D2')
.onClick(() => {
this.inputNumber = '149600000'
this.convertToScientific()
})
Button('光速')
.width('45%')
.height(40)
.backgroundColor('#E8F5E9')
.fontColor('#388E3C')
.onClick(() => {
this.inputNumber = '299792458'
this.convertToScientific()
})
}
Row({ space: 10 }) {
Button('地球半径')
.width('45%')
.height(40)
.backgroundColor('#FFF3E0')
.fontColor('#E65100')
.onClick(() => {
this.inputNumber = '6371000'
this.convertToScientific()
})
Button('阿伏伽德罗常数')
.width('45%')
.height(40)
.backgroundColor('#F3E5F5')
.fontColor('#7B1FA2')
.onClick(() => {
this.inputNumber = '602200000000000000000000'
this.convertToScientific()
})
}
Text('📝 科学记数法规则:')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ top: 10 })
Column({ space: 5 }) {
Text('1. 形式:a × 10^b,其中 1 ≤ a < 10')
.fontSize(13)
.fontColor('#666')
Text('2. 指数 b 是整数,表示小数点移动的位数')
.fontSize(13)
.fontColor('#666')
Text('3. 正数 b:小数点向右移动,数值增大')
.fontSize(13)
.fontColor('#666')
Text('4. 负数 b:小数点向左移动,数值减小')
.fontSize(13)
.fontColor('#666')
}
.width('100%')
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding(15)
.backgroundColor('#F5F5F5')
.borderRadius(12)
}
.width('100%')
.padding(20)
.backgroundColor('#F0F4F8')
}
.width('100%')
.height('100%')
}
// 转换为科学记数法
private convertToScientific() {
const input = this.inputNumber.trim()
// 验证输入
if (!input) {
this.isValid = false
this.errorMessage = '请输入数字'
return
}
if (!/^\d+$/.test(input)) {
this.isValid = false
this.errorMessage = '请输入正整数'
return
}
this.isValid = true
// 处理数字
const num = parseFloat(input)
if (num === 0) {
this.scientificNotation = '0'
this.mantissa = '0'
this.exponent = 0
return
}
// 计算科学记数法
const exponent = input.length - 1
const mantissa = input.charAt(0) + '.' + input.slice(1)
this.mantissa = mantissa
this.exponent = exponent
this.scientificNotation = `${mantissa} × 10^${exponent}`
// 触发重绘
this.drawVisualization()
}
// 绘制可视化效果
private drawVisualization() {
if (!this.isValid) return
const ctx = this.context
const width = 340
const height = 200
const centerY = height / 2
// 清空画布
ctx.clearRect(0, 0, width, height)
// 绘制数字和小数点移动
const originalNumber = this.inputNumber
const mantissa = this.mantissa
const exponent = this.exponent
// 绘制原始数字
ctx.font = '16px sans-serif'
ctx.fillStyle = '#333333'
ctx.textAlign = 'center'
ctx.fillText(`原始数字: ${originalNumber}`, width / 2, 40)
// 绘制箭头
ctx.strokeStyle = '#2196F3'
ctx.lineWidth = 2
ctx.beginPath()
ctx.moveTo(50, centerY)
ctx.lineTo(width - 50, centerY)
ctx.stroke()
// 绘制箭头头部
ctx.beginPath()
ctx.moveTo(width - 50, centerY)
ctx.lineTo(width - 60, centerY - 5)
ctx.lineTo(width - 60, centerY + 5)
ctx.closePath()
ctx.fillStyle = '#2196F3'
ctx.fill()
// 绘制移动后的数字
ctx.font = '18px sans-serif'
ctx.fillStyle = '#4CAF50'
ctx.fillText(`科学记数法: ${this.scientificNotation}`, width / 2, 160)
// 绘制小数点移动过程
if (exponent > 0) {
// 绘制原始数字的小数点位置
const originalText = originalNumber
const textWidth = ctx.measureText(originalText).width
const startX = (width - textWidth) / 2
ctx.font = '20px sans-serif'
ctx.fillStyle = '#333333'
ctx.fillText(originalText, width / 2, centerY + 10)
// 绘制小数点
const dotX = startX + ctx.measureText(originalText.charAt(0)).width
ctx.beginPath()
ctx.arc(dotX, centerY + 5, 3, 0, Math.PI * 2)
ctx.fillStyle = '#F44336'
ctx.fill()
// 绘制移动后的小数点
ctx.beginPath()
ctx.arc(dotX + 15 * exponent, centerY + 5, 3, 0, Math.PI * 2)
ctx.fillStyle = '#4CAF50'
ctx.fill()
// 绘制移动轨迹
ctx.strokeStyle = '#FF9800'
ctx.lineWidth = 1
ctx.setLineDash([5, 5])
ctx.beginPath()
ctx.moveTo(dotX, centerY + 5)
ctx.lineTo(dotX + 15 * exponent, centerY + 5)
ctx.stroke()
ctx.setLineDash([])
}
}
}
更多推荐


所有评论(0)