fix: retina canvas support

main
parent cf3f40352a
commit e3a5f83f5b

@ -82,7 +82,7 @@ const PrimalStep = ({
) )
} }
export const Primale = ({ input }: { input: ProblemInput }) => { export const Primal = ({ input }: { input: ProblemInput }) => {
// const steps: Step[] = [{ B: input.B }] // const steps: Step[] = [{ B: input.B }]
const problemOutput = computePrimalSimplexSteps({ const problemOutput = computePrimalSimplexSteps({
@ -141,16 +141,16 @@ const PrimalCanvas = ({
return return
} }
$canvas.width = $canvas.offsetWidth $canvas.width = $canvas.offsetWidth * window.devicePixelRatio
$canvas.height = $canvas.offsetHeight $canvas.height = $canvas.offsetHeight * window.devicePixelRatio
const g = $canvas.getContext('2d') const g = $canvas.getContext('2d')
if (!g) { if (!g) {
throw new Error('Could not get 2d context') throw new Error('Could not get 2d context')
} }
const width = $canvas.width const width = $canvas.offsetWidth
const height = $canvas.height const height = $canvas.offsetHeight
g.clearRect(0, 0, width, height) g.clearRect(0, 0, width, height)
g.strokeStyle = '#333' g.strokeStyle = '#333'
@ -163,6 +163,8 @@ const PrimalCanvas = ({
g.textAlign = 'center' g.textAlign = 'center'
g.textBaseline = 'middle' g.textBaseline = 'middle'
g.scale(window.devicePixelRatio, window.devicePixelRatio)
const [c1, c2] = c.getData() const [c1, c2] = c.getData()
const cLen = Math.sqrt(c1.toNumber() ** 2 + c2.toNumber() ** 2) const cLen = Math.sqrt(c1.toNumber() ** 2 + c2.toNumber() ** 2)
@ -202,87 +204,89 @@ const PrimalCanvas = ({
// g.textBaseline = 'middle' // g.textBaseline = 'middle'
// g.fillText(`A = ${A}`, width / 2, height / 2) // g.fillText(`A = ${A}`, width / 2, height / 2)
g.translate(width / 2, height / 2) g.save()
g.scale(width / 2, -width / 2) {
g.scale(1 / 10, 1 / 10) g.translate(width / 2, height / 2)
g.scale(width / 2, -width / 2)
g.scale(1 / 10, 1 / 10)
// draw grid // draw grid
g.strokeStyle = '#ddd' g.strokeStyle = '#ddd'
g.lineWidth = 20 / g.canvas.width g.lineWidth = 20 / width
for (let i = -10; i <= 10; i++) { for (let i = -10; i <= 10; i++) {
strokeInfiniteLine(g, i, 0, Math.PI / 2) strokeInfiniteLine(g, i, 0, Math.PI / 2)
} }
for (let i = -9; i <= 9; i++) { for (let i = -9; i <= 9; i++) {
strokeInfiniteLine(g, 0, i, 0) strokeInfiniteLine(g, 0, i, 0)
} }
g.strokeStyle = '#333' g.strokeStyle = '#333'
g.lineWidth = 40 / g.canvas.width g.lineWidth = 40 / width
drawSimpleArrow(g, 0, 0, 9.8, 0, 0.35, '#444') drawSimpleArrow(g, 0, 0, 9.8, 0, 0.35, '#444')
drawSimpleArrow(g, 0, 0, 0, 9.8, 0.35, '#444') drawSimpleArrow(g, 0, 0, 0, 9.8, 0.35, '#444')
// draw semiplanes
// draw semiplanes not in B
range(0, A.rows)
.filter(i => !B.includes(i))
.forEach(i => {
const [a1, a2] = A.rowAt(i).getData()
const b_i = b.at(i)
// draw semiplanes drawSemiplane(g, a1.toNumber(), a2.toNumber(), b_i.toNumber())
})
// draw semiplanes not in B // draw semiplanes in B
range(0, A.rows)
.filter(i => !B.includes(i)) B.forEach(i => {
.forEach(i => {
const [a1, a2] = A.rowAt(i).getData() const [a1, a2] = A.rowAt(i).getData()
const b_i = b.at(i) const b_i = b.at(i)
drawSemiplane(g, a1.toNumber(), a2.toNumber(), b_i.toNumber()) drawSemiplane(g, a1.toNumber(), a2.toNumber(), b_i.toNumber(), {
lineColor: '#040',
lineWidth: 3,
})
}) })
// draw semiplanes in B // draw current solution
if (x) {
B.forEach(i => { const [x1, x2] = x.getData()
const [a1, a2] = A.rowAt(i).getData()
const b_i = b.at(i)
drawSemiplane(g, a1.toNumber(), a2.toNumber(), b_i.toNumber(), { g.lineWidth = 50 / width
lineColor: '#040',
lineWidth: 3,
})
})
// draw current solution
if (x) {
const [x1, x2] = x.getData()
g.lineWidth = 50 / g.canvas.width
drawSimpleArrow(
g,
x1.toNumber(),
x2.toNumber(),
x1.toNumber() + c1.toNumber() / cLen,
x2.toNumber() + c2.toNumber() / cLen,
0.25,
'darkgreen'
)
// draw xi
if (xi) {
const [xi1, xi2] = xi.getData()
const xiLen = Math.sqrt(xi1.toNumber() ** 2 + xi2.toNumber() ** 2)
g.lineWidth = 50 / g.canvas.width
drawSimpleArrow( drawSimpleArrow(
g, g,
x1.toNumber(), x1.toNumber(),
x2.toNumber(), x2.toNumber(),
x1.toNumber() + xi1.toNumber() / xiLen, x1.toNumber() + c1.toNumber() / cLen,
x2.toNumber() + xi2.toNumber() / xiLen, x2.toNumber() + c2.toNumber() / cLen,
0.25, 0.25,
'#44d' 'darkgreen'
) )
}
g.fillStyle = '#d44' // draw xi
fillDot(g, x1.toNumber(), x2.toNumber(), 0.2) if (xi) {
} const [xi1, xi2] = xi.getData()
const xiLen = Math.sqrt(xi1.toNumber() ** 2 + xi2.toNumber() ** 2)
g.lineWidth = 50 / width
drawSimpleArrow(
g,
x1.toNumber(),
x2.toNumber(),
x1.toNumber() + xi1.toNumber() / xiLen,
x2.toNumber() + xi2.toNumber() / xiLen,
0.25,
'#44d'
)
}
g.resetTransform() g.fillStyle = '#d44'
fillDot(g, x1.toNumber(), x2.toNumber(), 0.2)
}
}
g.restore()
// draw c vector // draw c vector

@ -69,7 +69,7 @@ export function drawSemiplane(
// Draw the line // Draw the line
g.strokeStyle = lineColor g.strokeStyle = lineColor
g.lineWidth = (lineWidth * 10) / g.canvas.width g.lineWidth = (lineWidth * 10) / (g.canvas.width / window.devicePixelRatio)
g.beginPath() g.beginPath()
if (a2 === 0) { if (a2 === 0) {

@ -2,7 +2,7 @@ import { render } from 'preact'
import { useState } from 'preact/hooks' import { useState } from 'preact/hooks'
import { parseSafeProblemInput } from './parser-problem' import { parseSafeProblemInput } from './parser-problem'
import { DisplayProblemInput } from './DisplayProblemInput' import { DisplayProblemInput } from './DisplayProblemInput'
import { Primale } from './Primale' import { Primal } from './Primal'
import exampleProblems from './example-problems.json' import exampleProblems from './example-problems.json'
@ -43,6 +43,7 @@ const App = () => {
'ricerca-operativa.currentProblemName', 'ricerca-operativa.currentProblemName',
'Pintel' 'Pintel'
) )
const [savedProblems, setSavedProblems] = useLocalStorage<{ name: string; source: string }[]>( const [savedProblems, setSavedProblems] = useLocalStorage<{ name: string; source: string }[]>(
'ricerca-operativa.savedProblems', 'ricerca-operativa.savedProblems',
exampleProblems exampleProblems
@ -137,7 +138,7 @@ const App = () => {
</p> </p>
)} )}
{'result' in problemValuesResult && <Primale input={problemValuesResult.result} />} {'result' in problemValuesResult && <Primal input={problemValuesResult.result} />}
</> </>
) )
} }

Loading…
Cancel
Save