HARMONYOS应用实例256:变量与函数关系
·
- 变量与函数关系
- 功能:模拟弹簧伸长量与重物质量的关系,记录数据点,绘制图像,引入函数概念。
应用功能:
模拟弹簧伸长量与重物质量的关系
可调节弹簧劲度系数
可调节重物质量,实时计算弹簧伸长量
记录数据点功能,保存实验数据
绘制函数图像,直观展示变量关系
显示/隐藏网格和函数线
显示数据记录表格
展示函数概念和数学表达式
清空数据和重置功能
- 功能:模拟弹簧伸长量与重物质量的关系,记录数据点,绘制图像,引入函数概念。
// 变量与函数关系
// 功能:模拟弹簧伸长量与重物质量的关系,记录数据点,绘制图像,引入函数概念
// 数据点
interface DataPoint {
mass: number;
extension: number;
}
@Entry
@Component
struct VariableFunctionRelation {
@State springConstant: number = 10;
@State currentMass: number = 50;
@State currentExtension: number = 0;
@State dataPoints: Array<DataPoint> = [];
@State showFunction: boolean = true;
@State showGrid: boolean = true;
@State canvasWidth: number = 350;
@State canvasHeight: number = 250;
build() {
Column({ space: 15 }) {
Text('变量与函数关系')
.fontSize(26)
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Center)
Column() {
Text('功能介绍')
.fontSize(18)
.fontWeight(FontWeight.Medium)
Text('模拟弹簧伸长量与重物质量的关系,记录数据点,绘制图像,引入函数概念')
.fontSize(14)
.fontColor('#666666')
.textAlign(TextAlign.Center)
}
.width('100%')
.backgroundColor('#E3F2FD')
.borderRadius(10)
.padding(15)
Column({ space: 10 }) {
Text('弹簧模拟')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.width('100%')
.textAlign(TextAlign.Center)
Column({ space: 8 }) {
Text(`弹簧劲度系数: ${this.springConstant} N/m`)
.fontSize(14)
.fontColor('#666666')
Slider({
value: this.springConstant,
min: 5,
max: 20,
step: 1,
style: SliderStyle.OutSet
})
.width('100%')
.blockColor('#2196F3')
.trackColor('#E0E0E0')
.selectedColor('#2196F3')
.onChange((value: number) => {
this.springConstant = value
this.calculateExtension()
})
}
.width('100%')
.padding(10)
.backgroundColor('#F5F5F5')
.borderRadius(8)
Column({ space: 8 }) {
Text(`当前质量: ${this.currentMass} g`)
.fontSize(14)
.fontColor('#666666')
Slider({
value: this.currentMass,
min: 0,
max: 200,
step: 10,
style: SliderStyle.OutSet
})
.width('100%')
.blockColor('#FF5722')
.trackColor('#E0E0E0')
.selectedColor('#FF5722')
.onChange((value: number) => {
this.currentMass = value
this.calculateExtension()
})
Text(`弹簧伸长量: ${this.currentExtension.toFixed(2)} cm`)
.fontSize(14)
.fontColor('#666666')
}
.width('100%')
.padding(10)
.backgroundColor('#F5F5F5')
.borderRadius(8)
Button('记录数据点')
.width('100%')
.height(45)
.fontSize(16)
.backgroundColor('#4CAF50')
.onClick(() => {
this.recordDataPoint()
})
}
.width('100%')
.padding(10)
.backgroundColor('#FAFAFA')
.borderRadius(10)
Column({ space: 10 }) {
Text('函数图像')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.width('100%')
.textAlign(TextAlign.Center)
Canvas(this.canvasContext)
.width(this.canvasWidth)
.height(this.canvasHeight)
.backgroundColor('#FFFFFF')
.border({ width: 2, color: '#333' })
.borderRadius(10)
.onReady(() => {
this.drawGraph()
})
}
.width('100%')
.padding(10)
.backgroundColor('#FAFAFA')
.borderRadius(10)
Column({ space: 8 }) {
Text('显示选项')
.fontSize(14)
.fontWeight(FontWeight.Medium)
Row({ space: 10 }) {
Row({ space: 5 }) {
Text('显示网格')
.fontSize(14)
Text(this.showGrid ? '✓' : '✗')
.fontSize(14)
.fontColor(this.showGrid ? '#4CAF50' : '#F44336')
}
.onClick(() => {
this.showGrid = !this.showGrid
this.drawGraph()
})
Row({ space: 5 }) {
Text('显示函数')
.fontSize(14)
Text(this.showFunction ? '✓' : '✗')
.fontSize(14)
.fontColor(this.showFunction ? '#4CAF50' : '#F44336')
}
.onClick(() => {
this.showFunction = !this.showFunction
this.drawGraph()
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
}
.width('100%')
.padding(10)
.backgroundColor('#F5F5F5')
.borderRadius(8)
Column({ space: 10 }) {
Text('数据记录')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.width('100%')
.textAlign(TextAlign.Center)
if (this.dataPoints.length > 0) {
Column({ space: 5 }) {
Row({ space: 10 }) {
Text('序号')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.width('20%')
Text('质量(g)')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.width('40%')
Text('伸长量(cm)')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.width('40%')
}
.width('100%')
.padding(8)
.backgroundColor('#E3F2FD')
.borderRadius(5)
ForEach(this.dataPoints, (point: DataPoint, index: number) => {
Row({ space: 10 }) {
Text(`${index + 1}`)
.fontSize(14)
.width('20%')
Text(`${point.mass}`)
.fontSize(14)
.width('40%')
Text(`${point.extension.toFixed(2)}`)
.fontSize(14)
.width('40%')
}
.width('100%')
.padding(8)
.backgroundColor('#FFFFFF')
.borderRadius(5)
})
}
.width('100%')
.padding(10)
.backgroundColor('#FAFAFA')
.borderRadius(8)
} else {
Text('暂无数据,请添加数据点')
.fontSize(14)
.fontColor('#999999')
.textAlign(TextAlign.Center)
.width('100%')
.padding(20)
}
}
.width('100%')
.padding(10)
.backgroundColor('#FAFAFA')
.borderRadius(10)
Column({ space: 8 }) {
Text('函数概念')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.width('100%')
.textAlign(TextAlign.Center)
Text(`函数关系: y = ${(1 / this.springConstant).toFixed(3)}x`)
.fontSize(16)
.fontColor('#2196F3')
.textAlign(TextAlign.Center)
Text('其中:')
.fontSize(14)
.fontColor('#666666')
Text('• x: 重物质量 (g)')
.fontSize(14)
.fontColor('#666666')
Text(`• y: 弹簧伸长量 (cm)`)
.fontSize(14)
.fontColor('#666666')
Text(`• k = ${(1 / this.springConstant).toFixed(3)}: 弹簧常数`)
.fontSize(14)
.fontColor('#666666')
}
.width('100%')
.padding(15)
.backgroundColor('#FFF3E0')
.borderRadius(10)
Row({ space: 10 }) {
Button('清空数据')
.width('48%')
.height(50)
.fontSize(16)
.backgroundColor('#F44336')
.onClick(() => {
this.clearData()
})
Button('重置')
.width('48%')
.height(50)
.fontSize(16)
.backgroundColor('#FF9800')
.onClick(() => {
this.reset()
})
}
.width('100%')
}
.width('100%')
.height('100%')
.padding(10)
.justifyContent(FlexAlign.Start)
}
private canvasContext: CanvasRenderingContext2D = new CanvasRenderingContext2D();
private calculateExtension() {
this.currentExtension = (this.currentMass / this.springConstant)
this.drawGraph()
}
private recordDataPoint() {
if (this.currentMass > 0) {
this.dataPoints.push({
mass: this.currentMass,
extension: this.currentExtension
})
this.drawGraph()
}
}
private drawGraph() {
const ctx = this.canvasContext
ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
if (this.showGrid) {
this.drawGridLines(ctx)
}
this.drawAxes(ctx)
this.drawDataPoints(ctx)
if (this.showFunction) {
this.drawFunctionLine(ctx)
}
}
private drawGridLines(ctx: CanvasRenderingContext2D) {
ctx.strokeStyle = '#E0E0E0'
ctx.lineWidth = 1
const gridSize = 25
for (let i = 0; i <= this.canvasWidth; i += gridSize) {
ctx.beginPath()
ctx.moveTo(i, 0)
ctx.lineTo(i, this.canvasHeight)
ctx.stroke()
}
for (let i = 0; i <= this.canvasHeight; i += gridSize) {
ctx.beginPath()
ctx.moveTo(0, i)
ctx.lineTo(this.canvasWidth, i)
ctx.stroke()
}
}
private drawAxes(ctx: CanvasRenderingContext2D) {
ctx.strokeStyle = '#333'
ctx.lineWidth = 2
const originX = 40
const originY = this.canvasHeight - 30
ctx.beginPath()
ctx.moveTo(originX, 0)
ctx.lineTo(originX, this.canvasHeight)
ctx.stroke()
ctx.beginPath()
ctx.moveTo(0, originY)
ctx.lineTo(this.canvasWidth, originY)
ctx.stroke()
ctx.fillStyle = '#333'
ctx.font = '12px sans-serif'
ctx.fillText('质量(g)', this.canvasWidth - 60, originY + 20)
ctx.fillText('伸长量(cm)', 5, 20)
}
private drawDataPoints(ctx: CanvasRenderingContext2D) {
const originX = 40
const originY = this.canvasHeight - 30
const scaleX = (this.canvasWidth - 60) / 200
const scaleY = (this.canvasHeight - 50) / 20
ctx.fillStyle = '#FF5722'
ctx.strokeStyle = '#FF5722'
for (const point of this.dataPoints) {
const x = originX + point.mass * scaleX
const y = originY - point.extension * scaleY
ctx.beginPath()
ctx.arc(x, y, 5, 0, 2 * Math.PI)
ctx.fill()
ctx.stroke()
}
}
private drawFunctionLine(ctx: CanvasRenderingContext2D) {
const originX = 40
const originY = this.canvasHeight - 30
const scaleX = (this.canvasWidth - 60) / 200
const scaleY = (this.canvasHeight - 50) / 20
ctx.strokeStyle = '#2196F3'
ctx.lineWidth = 2
ctx.beginPath()
for (let mass = 0; mass <= 200; mass += 5) {
const extension = mass / this.springConstant
const x = originX + mass * scaleX
const y = originY - extension * scaleY
if (mass === 0) {
ctx.moveTo(x, y)
} else {
ctx.lineTo(x, y)
}
}
ctx.stroke()
}
private clearData() {
this.dataPoints = []
this.drawGraph()
}
private reset() {
this.springConstant = 10
this.currentMass = 50
this.currentExtension = 0
this.dataPoints = []
this.showFunction = true
this.showGrid = true
this.calculateExtension()
}
}
更多推荐


所有评论(0)