Skip to content

Commit

Permalink
refactor(mod-math)
Browse files Browse the repository at this point in the history
  • Loading branch information
sheepbox8646 committed Jun 11, 2024
1 parent 027e32f commit 94864fe
Show file tree
Hide file tree
Showing 3 changed files with 237 additions and 252 deletions.
94 changes: 43 additions & 51 deletions mods/mod-math/src/widgets/mathFunction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { WidgetOptions, WidgetRange, WidgetStyle } from '@newcar/core'
import { Widget } from '@newcar/core'
import type { ConvertToProp, Ref, WidgetOptions, WidgetRange, WidgetStyle } from '@newcar/core'
import { Widget, changed, reactive, ref } from '@newcar/core'
import type { Shader } from '@newcar/utils'
import { Color } from '@newcar/utils'
import type { Canvas, CanvasKit, Paint, Path } from 'canvaskit-wasm'
Expand All @@ -21,13 +21,12 @@ export interface MathFunctionStyle extends WidgetStyle {
}

export class MathFunction extends Widget {
declare style: MathFunctionStyle
declare style: ConvertToProp<MathFunctionStyle>
private path: Path
private paint: Paint
numberRange: Range
lineWidth: number
divisionX: number
divisionY: number
numberRange: Ref<Range>
divisionX: Ref<number>
divisionY: Ref<number>

constructor(
public fn: (x: number) => number,
Expand All @@ -36,74 +35,67 @@ export class MathFunction extends Widget {
) {
options ??= {}
super(options)
this.numberRange = options.numberRange ?? [
this.numberRange = ref(options.numberRange ?? [
Number.NEGATIVE_INFINITY,
Number.POSITIVE_INFINITY,
]
this.divisionX = options.divisionX ?? 50
this.divisionY = options.divisionY ?? 50
])
this.divisionX = ref(options.divisionX ?? 50)
this.divisionY = ref(options.divisionY ?? 50)
options.style ??= {}
this.style.width = options.style.width ?? 2
this.style.color = options.style.color ?? Color.WHITE
this.style.shader = options.style.shader
this.style.width = ref(options.style.width ?? 2)
this.style.color = reactive(options.style.color ?? Color.WHITE)
this.style.shader = reactive(options.style.shader)
}

init(ck: CanvasKit) {
this.paint = new ck.Paint()
this.paint.setColor(this.style.color!.toFloat4())
this.paint.setShader(this.style.shader?.toCanvasKitShader(ck) ?? null)
this.paint.setStyle(ck.PaintStyle.Stroke)
this.paint.setStrokeWidth((this.style.width! / this.divisionX) * 2)
this.paint.setStrokeWidth((this.style.width.value! / this.divisionX.value) * 2)
this.path = new ck.Path()
this.path.moveTo(this.domain[0], this.fn(this.domain[0]))
for (
let x = this.domain[0];
x <= this.domain[0] + (this.domain[1] - this.domain[0]) * this.progress;
x += 1 / this.divisionX
x <= this.domain[0] + (this.domain[1] - this.domain[0]) * this.progress.value;
x += 1 / this.divisionX.value
) {
const value = this.fn(x)
this.path.lineTo(x, value)
}
}

predraw(ck: CanvasKit, propertyChanged: string): void {
switch (propertyChanged) {
case 'fn':
case 'divisionX':
case 'divisionY':
case 'lineWidth':
case 'range':
case 'domain': {
this.path.reset()
this.path.moveTo(this.domain[0], this.fn(this.domain[0]))
for (
let x = this.domain[0];
x
<= this.domain[0] + (this.domain[1] - this.domain[0]) * this.progress;
x += 1 / this.divisionX
) {
const value = this.fn(x)
this.path.lineTo(x, value)
}
break
}
case 'style.width': {
this.paint.setStrokeWidth((this.style.width! / this.divisionX) * 2)
break
}
case 'style.color': {
this.paint.setColor(this.style.color!.toFloat4())
break
}
case 'style.shader': {
this.paint.setShader(this.style.shader?.toCanvasKitShader(ck) ?? null)
break
function reset(this: MathFunction) {
this.path.reset()
this.path.moveTo(this.domain[0], this.fn(this.domain[0]))
for (
let x = this.domain[0];
x
<= this.domain[0] + (this.domain[1] - this.domain[0]) * this.progress.value;
x += 1 / this.divisionX.value
) {
const value = this.fn(x)
this.path.lineTo(x, value)
}
}

changed(this.fn, reset.bind(this))
changed(this.domain, reset.bind(this))
changed(this.numberRange, reset.bind(this))
changed(this.divisionX, reset.bind(this))
changed(this.divisionY, reset.bind(this))
changed(this.style.color, () => {
this.paint.setColor(this.style.color!.toFloat4())
})
changed(this.style.shader, () => {
this.paint.setShader(this.style.shader?.toCanvasKitShader(ck) ?? null)
})
changed(this.style.width, () => {
this.paint.setStrokeWidth((this.style.width.value! / this.divisionX.value) * 2)
})
}

draw(canvas: Canvas): void {
canvas.scale(this.divisionX, -this.divisionY)
canvas.scale(this.divisionX.value, -this.divisionY.value)
canvas.drawPath(this.path, this.paint)
}

Expand Down
145 changes: 95 additions & 50 deletions mods/mod-math/src/widgets/numberAxis.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Arrow, Line, Text } from '@newcar/basic'
import type { WidgetOptions, WidgetStyle } from '@newcar/core'
import { Widget } from '@newcar/core'
import type { ConvertToProp, Ref, WidgetOptions, WidgetStyle } from '@newcar/core'
import { Widget, changed, reactive, ref } from '@newcar/core'
import { Color } from '@newcar/utils'
import type { CanvasKit } from 'canvaskit-wasm'

Expand Down Expand Up @@ -28,11 +28,6 @@ export interface NumberAxisStyle extends WidgetStyle {
ticks?: boolean
tickColor?: Color

/**
* If display arrow (the triangle at the end of the axis)
*/
arrow?: boolean

/**
* if display the number or text under the ticks of the axis
*/
Expand All @@ -49,91 +44,141 @@ export interface NumberAxisStyle extends WidgetStyle {
export class NumberAxis extends Widget {
division: number
trend: Trend
declare style: NumberAxisStyle
declare style: ConvertToProp<NumberAxisStyle>
ticks: Line[]
texts: Text[]
main: Arrow
length: Ref<[number, number]>

constructor(
public length: [number, number],
length: [number, number],
options?: NumberAxisOptions,
) {
options ??= {}
super(options)
this.length = ref(length)
this.division = options.division ?? 50
this.trend = options.trend ?? (x => x / 50)
this.style ??= {}
this.style.ticks = options.style.ticks ?? true
this.style.tickColor = options.style.tickColor ?? Color.WHITE
this.style.texts = options.style.texts ?? true
this.style.textSize = options.style.textSize ?? 20
this.style.textColor = options.style.textColor ?? Color.WHITE
this.style.color = options.style.color ?? Color.WHITE
this.style.arrow = options.style.arrow ?? true
this.main = new Arrow([this.length[0], 0], [this.length[1], 0], {
this.style.ticks = ref(options.style.ticks ?? true)
this.style.tickColor = reactive(options.style.tickColor ?? Color.WHITE)
this.style.texts = ref(options.style.texts ?? true)
this.style.textSize = ref(options.style.textSize ?? 20)
this.style.textColor = reactive(options.style.textColor ?? Color.WHITE)
this.style.color = reactive(options.style.color ?? Color.WHITE)
this.main = new Arrow([this.length.value[0], 0], [this.length.value[1], 0], {
style: {
color: this.style.color,
},
progress: this.progress,
progress: this.progress.value,
})
this.ticks = []
this.texts = []
for (let x = this.length[0] + (this.length[1] - this.length[0]) % this.division; x <= this.length[1]; x += this.division) {
for (let x = this.length.value[0] + (this.length.value[1] - this.length.value[0]) % this.division; x <= this.length.value[1]; x += this.division) {
if (this.style.ticks) {
this.ticks.push(
new Line([x, -5], [x, 5], {
style: {
color: this.style.tickColor,
},
progress: this.progress,
progress: this.progress.value,
}),
)
}
if (this.style.texts) {
this.texts.push(new Text(this.trend(x).toString(), {
x: x - (this.style.textSize / 2),
x: x - (this.style.textSize.value / 2),
y: 10,
style: {
fontSize: this.style.textSize,
fontSize: this.style.textSize.value,
fillColor: this.style.textColor,
// Note: the rotation is reversed because the canvas is flipped
rotation: -this.style.rotation,
rotation: -this.style.rotation.value,
},
}))
}
}
this.add(this.main, ...this.ticks, ...this.texts)
}

init(_ck: CanvasKit): void {
super.init(_ck)
}

predraw(ck: CanvasKit, propertyChanged: string): void {
switch (propertyChanged) {
case 'style.color':
this.main.style.color = this.style.color
break
case 'style.tickColor':
changed(this.style.color, (v) => {
this.main.style.color = v
})
changed(this.style.tickColor, (v) => {
for (const tick of this.ticks)
tick.style.color = v
})
changed(this.style.textColor, (v) => {
for (const text of this.texts)
text.style.fillColor = v
})
changed(this.style.textSize, (v) => {
for (const text of this.texts)
text.style.fontSize.value = v.value
})
changed(this.style.rotation, (v) => {
for (const text of this.texts)
text.style.rotation.value = -v.value
})
changed(this.progress, (v) => {
this.main.progress.value = v.value
for (const tick of this.ticks)
tick.progress.value = v.value
})
changed(this.style.ticks, (v) => {
if (v.value) {
for (const tick of this.ticks)
tick.style.color = this.style.tickColor
break
case 'style.textColor':
for (const text of this.texts)
text.style.fillColor = this.style.textColor
break
case 'style.textSize':
for (const text of this.texts)
text.style.fontSize = this.style.textSize
break
case 'progress':
this.main.progress = this.progress
tick.show()
}
else {
for (const tick of this.ticks)
tick.progress = this.progress
break
case 'style.rotation':
tick.hide()
}
})
changed(this.style.texts, (v) => {
if (v.value) {
for (const text of this.texts)
text.show()
}
else {
for (const text of this.texts)
text.style.rotation = -this.style.rotation
text.hide()
}
})

function reset(this: NumberAxis) {
this.texts = []
this.ticks = []
for (let x = this.length.value[0] + (this.length.value[1] - this.length.value[0]) % this.division; x <= this.length.value[1]; x += this.division) {
if (this.style.texts) {
this.texts.push(new Text(this.trend(x).toString(), {
x: x - (this.style.textSize.value / 2),
y: 10,
style: {
fontSize: this.style.textSize.value,
fillColor: this.style.textColor,
// Note: the rotation is reversed because the canvas is flipped
rotation: -this.style.rotation.value,
},
}))
}
if (this.style.ticks) {
this.ticks.push(
new Line([x, -5], [x, 5], {
style: {
color: this.style.tickColor,
},
progress: this.progress.value,
}),
)
}
}
}
changed(this.length.value, reset.bind(this))
changed(this.division, reset.bind(this))
changed(this.trend, reset.bind(this))
}

init(_ck: CanvasKit): void {
super.init(_ck)
}
}
Loading

0 comments on commit 94864fe

Please sign in to comment.