Skip to content

Commit

Permalink
improve pdf generation, now split into pages
Browse files Browse the repository at this point in the history
  • Loading branch information
cnkang committed Aug 19, 2024
1 parent 34be98f commit 1303498
Showing 1 changed file with 165 additions and 145 deletions.
310 changes: 165 additions & 145 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ function App() {
'legal': 'legal',
};

/**
* Calculates the result of an expression with given operands and operators.
*
* @param {Array<number>} operands - The array of operands.
* @param {Array<string>} operators - The array of operators.
* @return {number} The result of the expression.
*/
/**
* Calculates the result of an expression with given operands and operators.
*
* @param {Array<number>} operands - The array of operands.
* @param {Array<string>} operators - The array of operators.
* @return {number} The result of the expression.
*/
const calculateExpression = (operands, operators) => {
let result = operands[0];

Expand Down Expand Up @@ -64,11 +64,11 @@ function App() {
return result;
};

/**
* Generates a math problem with random operands and operations within the specified ranges.
*
* @return {string} The generated math problem, or an empty string if no valid problem was generated in MAX_ATTEMPTS attempts.
*/
/**
* Generates a math problem with random operands and operations within the specified ranges.
*
* @return {string} The generated math problem, or an empty string if no valid problem was generated in MAX_ATTEMPTS attempts.
*/
const generateProblem = () => {
const numOperands = Math.floor(Math.random() * (settings.numOperandsRange[1] - settings.numOperandsRange[0] + 1)) + settings.numOperandsRange[0];

Expand Down Expand Up @@ -106,11 +106,11 @@ function App() {
return ''; // Return an empty string if no valid problem was generated in MAX_ATTEMPTS
};

/**
* Generates a set of problems based on the current settings and updates the state with the generated problems.
*
* @return {void} This function does not return anything.
*/
/**
* Generates a set of problems based on the current settings and updates the state with the generated problems.
*
* @return {void} This function does not return anything.
*/
const generateProblems = () => {
const generatedProblems = Array.from({ length: settings.numProblems }, () =>
generateProblem()
Expand All @@ -119,7 +119,8 @@ function App() {
};

/**
* Downloads a PDF file containing the generated problems.
* Downloads a PDF file
* containing the generated problems.
*
* This function creates a new instance of the jsPDF library and sets the
* paper size and font size based on the settings. It then iterates over
Expand All @@ -134,9 +135,29 @@ function App() {
});

doc.setFontSize(settings.fontSize);
problems.forEach((problem, i) => {
doc.text(problem.text, 10, 10 + i * settings.lineSpacing);
const pageHeight = doc.internal.pageSize.getHeight();
const pageWidth = doc.internal.pageSize.getWidth();

let y = 10; // Initial Y coordinate
let x = 10; // Initial X coordinate
const columnGap = 10; // Gap between columns
const columnWidth = Math.floor(pageWidth / 2 - columnGap); // width of each column

problems.forEach((problem) => {
if (y + settings.lineSpacing > pageHeight) {
if (x + columnWidth + columnGap < pageWidth) {
x += columnWidth + columnGap;
y = 10;
} else {
doc.addPage();
x = 10;
y = 10;
}
}
doc.text(problem.text, x, y);
y += settings.lineSpacing;
});

doc.save('problems.pdf');
};

Expand Down Expand Up @@ -177,130 +198,129 @@ function App() {
type="number"
id="numProblems"
value={settings.numProblems}
onChange={(e) => handleChange('numProblems', parseInt(e.target.value
))}
/>
</div>

<div className="form-group range-container">
<label htmlFor="numRange">Number Range:</label>
<input
type="number"
id="numRangeMin"
value={settings.numRange[0]}
onChange={(e) => handleChange('numRange', [parseInt(e.target.value), settings.numRange[1]])}
placeholder="Min"
/>{' '}
<input
type="number"
id="numRangeMax"
value={settings.numRange[1]}
onChange={(e) => handleChange('numRange', [settings.numRange[0], parseInt(e.target.value)])}
placeholder="Max"
/>
</div>

<div className="form-group result-container">
<label htmlFor="resultRange">Result Range:</label>
<input
type="number"
id="resultRangeMin"
value={settings.resultRange[0]}
onChange={(e) => handleChange('resultRange', [parseInt(e.target.value), settings.resultRange[1]])}
placeholder="Min"
/>{' '}
<input
type="number"
id="resultRangeMax"
value={settings.resultRange[1]}
onChange={(e) => handleChange('resultRange', [settings.resultRange[0], parseInt(e.target.value)])}
placeholder="Max"
/>
</div>

<div className="form-group operands-container">
<label htmlFor="numOperandsRange">Number of Operands Range:</label>
<input
type="number"
id="numOperandsRangeMin"
value={settings.numOperandsRange[0]}
onChange={(e) => handleChange('numOperandsRange', [parseInt(e.target.value), settings.numOperandsRange[1]])}
placeholder="Min"
/>{' '}
<input
type="number"
id="numOperandsRangeMax"
value={settings.numOperandsRange[1]}
onChange={(e) => handleChange('numOperandsRange', [settings.numOperandsRange[0], parseInt(e.target.value)])}
placeholder="Max"
/>
</div>

<div className="form-group">
<label htmlFor="allowNegative">Allow Negative Results:</label>
<input
type="checkbox"
id="allowNegative"
checked={settings.allowNegative}
onChange={(e) => handleChange('allowNegative', e.target.checked)}
/>
</div>

<div className="form-group">
<label htmlFor="showAnswers">Show Answers:</label>
<input
type="checkbox"
id="showAnswers"
checked={settings.showAnswers}
onChange={(e) => handleChange('showAnswers', e.target.checked)}
/>
</div>

<div className="form-group">
<label htmlFor="fontSize">Font Size:</label>
<input
type="number"
id="fontSize"
value={settings.fontSize}
onChange={(e) => handleChange('fontSize', parseInt(e.target.value))}
/>
</div>

<div className="form-group">
<label htmlFor="lineSpacing">Line Spacing (px):</label>
<input
type="number"
id="lineSpacing"
value={settings.lineSpacing}
onChange={(e) => handleChange('lineSpacing', parseInt(e.target.value))}
/>
</div>

<div className="form-group">
<label htmlFor="paperSize">Paper Size:</label>
<select
id="paperSize"
value={settings.paperSize}
onChange={(e) => handleChange('paperSize', e.target.value)}
>
<option value="a4">A4</option>
<option value="letter">Letter</option>
<option value="legal">Legal</option>
</select>
</div>

<button onClick={generateProblems}>Generate Problems</button>{' '}
<button onClick={downloadPdf}>Download PDF</button>

<div className="problems">
{problems.map((problem) => (
<div key={problem.id}>{problem.text}</div>
))}
</div>
onChange={(e) => handleChange('numProblems', parseInt(e.target.value))}
/>
</div>

<div className="form-group range-container">
<label htmlFor="numRange">Number Range:</label>
<input
type="number"
id="numRangeMin"
value={settings.numRange[0]}
onChange={(e) => handleChange('numRange', [parseInt(e.target.value), settings.numRange[1]])}
placeholder="Min"
/>
<input
type="number"
id="numRangeMax"
value={settings.numRange[1]}
onChange={(e) => handleChange('numRange', [settings.numRange[0], parseInt(e.target.value)])}
placeholder="Max"
/>
</div>

<div className="form-group result-container">
<label htmlFor="resultRange">Result Range:</label>
<input
type="number"
id="resultRangeMin"
value={settings.resultRange[0]}
onChange={(e) => handleChange('resultRange', [parseInt(e.target.value), settings.resultRange[1]])}
placeholder="Min"
/>
<input
type="number"
id="resultRangeMax"
value={settings.resultRange[1]}
onChange={(e) => handleChange('resultRange', [settings.resultRange[0], parseInt(e.target.value)])}
placeholder="Max"
/>
</div>

<div className="form-group operands-container">
<label htmlFor="numOperandsRange">Number of Operands Range:</label>
<input
type="number"
id="numOperandsRangeMin"
value={settings.numOperandsRange[0]}
onChange={(e) => handleChange('numOperandsRange', [parseInt(e.target.value), settings.numOperandsRange[1]])}
placeholder="Min"
/>
<input
type="number"
id="numOperandsRangeMax"
value= {settings.numOperandsRange[1]}
onChange={(e) => handleChange('numOperandsRange', [settings.numOperandsRange[0], parseInt(e.target.value)])}
placeholder="Max"
/>
</div>

<div className="form-group">
<label htmlFor="allowNegative">Allow Negative Results:</label>
<input
type="checkbox"
id="allowNegative"
checked={settings.allowNegative}
onChange={(e) => handleChange('allowNegative', e.target.checked)}
/>
</div>

<div className="form-group">
<label htmlFor="showAnswers">Show Answers:</label>
<input
type="checkbox"
id="showAnswers"
checked={settings.showAnswers}
onChange={(e) => handleChange('showAnswers', e.target.checked)}
/>
</div>

<div className="form-group">
<label htmlFor="fontSize">Font Size:</label>
<input
type="number"
id="fontSize"
value={settings.fontSize}
onChange={(e) => handleChange('fontSize', parseInt(e.target.value))}
/>
</div>

<div className="form-group">
<label htmlFor="lineSpacing">Line Spacing (px):</label>
<input
type="number"
id="lineSpacing"
value={settings.lineSpacing}
onChange={(e) => handleChange('lineSpacing', parseInt(e.target.value))}
/>
</div>

<div className="form-group">
<label htmlFor="paperSize">Paper Size:</label>
<select
id="paperSize"
value={settings.paperSize}
onChange={(e) => handleChange('paperSize', e.target.value)}
>
<option value="a4">A4</option>
<option value="letter">Letter</option>
<option value="legal">Legal</option>
</select>
</div>

<button onClick={generateProblems}>Generate Problems</button>{' '}
<button onClick={downloadPdf}>Download PDF</button>

<div className="problems">
{problems.map((problem) => (
<div key={problem.id}>{problem.text}</div>
))}
</div>
</div>
);
}

export default App; // Export the App component for use in other files

</div>
);
}

export default App; // Export the App component for use in other files

0 comments on commit 1303498

Please sign in to comment.