summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-12-02 00:18:58 -0800
committerFuwn <[email protected]>2025-12-02 00:18:58 -0800
commit0d8bf5520876d2dc600cc0a45cf59543c56cd99c (patch)
tree17e8f398e1da3430270a4b3256877e82c907f60b
parentfix(analysis.js): Improve analysis engine (diff)
downloadrysk-0d8bf5520876d2dc600cc0a45cf59543c56cd99c.tar.xz
rysk-0d8bf5520876d2dc600cc0a45cf59543c56cd99c.zip
feat(index.html): Restyle
-rw-r--r--index.html1077
-rw-r--r--js/index.js4
2 files changed, 745 insertions, 336 deletions
diff --git a/index.html b/index.html
index 9445e18..27d817f 100644
--- a/index.html
+++ b/index.html
@@ -1,6 +1,5 @@
<!DOCTYPE html>
-<!-- updated index.html v2024-05-20 -->
-<html>
+<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
@@ -10,389 +9,799 @@
<script src="js/face-landmarks-detection.js"></script>
<script src="js/bootstrap.bundle.min.js"></script>
<link href="css/bootstrap.min.css" rel="stylesheet" />
- <title>Incel Solutions</title>
-
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
+ <link
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap"
+ rel="stylesheet"
+ />
+ <title>Facial Analysis</title>
<style>
- html,
- body,
- body > div {
- height: 100%;
+ *,
+ *::before,
+ *::after {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ }
+
+ :root {
+ --bg: #0a0a0a;
+ --surface: #141414;
+ --surface-elevated: #1a1a1a;
+ --border: rgba(255, 255, 255, 0.08);
+ --text-primary: #ffffff;
+ --text-secondary: rgba(255, 255, 255, 0.7);
+ --text-tertiary: rgba(255, 255, 255, 0.5);
+ --accent: #8b5cf6;
+ --accent-hover: #a78bfa;
+ --success: #22c55e;
+ --warning: #eab308;
+ --error: #ef4444;
+ --radius: 12px;
+ --radius-lg: 16px;
+ --spacing-xs: 0.5rem;
+ --spacing-sm: 0.75rem;
+ --spacing-md: 1rem;
+ --spacing-lg: 1.5rem;
+ --spacing-xl: 2rem;
+ --spacing-2xl: 3rem;
+ }
+
+ html {
+ font-size: 16px;
+ -webkit-text-size-adjust: 100%;
+ }
+
+ body {
+ font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
+ Roboto, "Helvetica Neue", Arial, sans-serif;
+ background: var(--bg);
+ color: var(--text-primary);
+ line-height: 1.5;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ min-height: 100vh;
+ overflow-x: hidden;
}
- .loading {
+ /* Layout */
+ .app {
+ min-height: 100vh;
display: flex;
- align-items: center;
+ flex-direction: column;
}
- .loading > div {
- flex-grow: 1;
+
+ .main-content {
+ flex: 1;
+ max-width: 1200px;
+ width: 100%;
+ margin: 0 auto;
+ padding: var(--spacing-xl) var(--spacing-md);
}
- .loading > .spinner-border {
- height: 8em !important;
- width: 8em !important;
- flex-grow: 0;
+
+ @media (min-width: 768px) {
+ .main-content {
+ padding: var(--spacing-2xl) var(--spacing-xl);
+ }
}
- img {
- height: auto;
- width: 25% !important;
+
+ /* Header */
+ .header {
+ text-align: center;
+ margin-bottom: var(--spacing-2xl);
}
- .perfect {
- color: springgreen;
+ .header h1 {
+ font-size: clamp(1.75rem, 4vw, 2.5rem);
+ font-weight: 700;
+ letter-spacing: -0.02em;
+ margin-bottom: var(--spacing-sm);
+ background: linear-gradient(135deg, #8b5cf6 0%, #ec4899 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
}
- .deviation-0 {
- color: darkkhaki;
+
+ .header p {
+ font-size: clamp(0.875rem, 2vw, 1rem);
+ color: var(--text-secondary);
+ font-weight: 400;
}
- .deviation-1 {
- color: darkorange;
+
+ /* Input Section */
+ .input-container {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-lg);
+ padding: var(--spacing-xl);
+ margin-bottom: var(--spacing-xl);
+ backdrop-filter: blur(10px);
}
- .deviation-2 {
- color: darksalmon;
+
+ .input-grid {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: var(--spacing-lg);
}
- .deviation-3 {
- color: coral;
+
+ @media (min-width: 640px) {
+ .input-grid {
+ grid-template-columns: 1fr 1fr;
+ }
}
- .deviation-4 {
- color: orangered;
+
+ .input-field {
+ display: flex;
+ flex-direction: column;
+ }
+
+ .input-field label {
+ font-size: 0.875rem;
+ font-weight: 500;
+ color: var(--text-secondary);
+ margin-bottom: var(--spacing-xs);
+ letter-spacing: 0.01em;
+ }
+
+ .input-field input {
+ width: 100%;
+ padding: var(--spacing-md) var(--spacing-lg);
+ background: var(--surface-elevated);
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ color: var(--text-primary);
+ font-size: 0.9375rem;
+ font-family: inherit;
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+ }
+
+ .input-field input:hover {
+ border-color: rgba(255, 255, 255, 0.12);
+ }
+
+ .input-field input:focus {
+ outline: none;
+ border-color: var(--accent);
+ box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.1);
+ background: var(--surface);
}
- /* 👉 Paste the following rules here 👇 */
+
+ .input-field input::placeholder {
+ color: var(--text-tertiary);
+ }
+
+ /* Table Container */
+ .table-container {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-lg);
+ overflow: hidden;
+ margin-bottom: var(--spacing-xl);
+ }
+
+ .table-wrapper {
+ overflow-x: auto;
+ -webkit-overflow-scrolling: touch;
+ }
+
table {
- table-layout: auto;
width: 100%;
+ border-collapse: collapse;
+ font-size: 0.875rem;
+ }
+
+ thead {
+ background: var(--surface-elevated);
+ border-bottom: 1px solid var(--border);
+ }
+
+ th {
+ padding: var(--spacing-md) var(--spacing-lg);
+ text-align: left;
+ font-weight: 600;
+ font-size: 0.75rem;
+ color: var(--text-secondary);
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ white-space: nowrap;
+ }
+
+ th:first-child {
+ width: 48px;
+ text-align: center;
+ padding: var(--spacing-md);
+ }
+
+ tbody tr {
+ border-bottom: 1px solid var(--border);
+ transition: background-color 0.15s ease;
+ }
+
+ tbody tr:last-child {
+ border-bottom: none;
+ }
+
+ tbody tr:hover {
+ background: var(--surface-elevated);
}
- th,
td {
- padding: 0.5rem;
+ padding: var(--spacing-md) var(--spacing-lg);
vertical-align: middle;
- white-space: nowrap;
+ color: var(--text-primary);
}
- /* Column 1: checkbox (tightest fit) */
- th:first-child,
td:first-child {
- width: 1%;
+ text-align: center;
+ padding: var(--spacing-md);
}
- /* Column 2: feature (expand just enough for longest label) */
- th:nth-child(2),
- td:nth-child(2) {
- white-space: nowrap;
+ tfoot {
+ background: var(--surface-elevated);
+ border-top: 2px solid var(--border);
}
- /* Column 3: rating (auto resize as needed) */
- th:nth-child(3),
- td:nth-child(3) {
- white-space: nowrap;
+ tfoot td {
+ font-weight: 600;
+ padding: var(--spacing-lg);
}
- /* Columns 4 & 5: measurement and ideal (fixed narrow width) */
- th:nth-child(4),
- td:nth-child(4),
- th:nth-child(5),
- td:nth-child(5) {
- width: 120px;
- text-align: center;
+ /* Checkboxes */
+ .checkbox {
+ width: 18px;
+ height: 18px;
+ border-radius: 4px;
+ border: 2px solid var(--border);
+ background: var(--surface-elevated);
+ cursor: pointer;
+ transition: all 0.2s ease;
+ appearance: none;
+ -webkit-appearance: none;
+ position: relative;
+ flex-shrink: 0;
+ }
+
+ .checkbox:checked {
+ background: var(--accent);
+ border-color: var(--accent);
+ }
+
+ .checkbox:checked::after {
+ content: "";
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%) rotate(45deg);
+ width: 4px;
+ height: 8px;
+ border: solid white;
+ border-width: 0 2px 2px 0;
+ }
+
+ .checkbox:focus {
+ outline: none;
+ box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.2);
+ }
+
+ /* Rating Colors */
+ .perfect {
+ color: var(--success);
+ font-weight: 500;
}
+ .deviation-0 {
+ color: var(--warning);
+ }
+
+ .deviation-1 {
+ color: #f59e0b;
+ }
+
+ .deviation-2 {
+ color: #f97316;
+ }
+
+ .deviation-3 {
+ color: #ef4444;
+ }
+
+ .deviation-4 {
+ color: #dc2626;
+ font-weight: 600;
+ }
+
+ /* Badge */
.badge {
- display: inline-block;
+ display: inline-flex;
+ align-items: center;
+ padding: 0.375rem 0.75rem;
+ border-radius: 6px;
+ font-size: 0.75rem;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ line-height: 1;
+ }
+
+ .badge.bg-success {
+ background: var(--success);
+ color: white;
+ }
+
+ .badge.bg-warning {
+ background: var(--warning);
+ color: #000;
+ }
+
+ .badge.bg-danger {
+ background: var(--error);
+ color: white;
+ }
+
+ /* Loading */
+ .loading-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ min-height: 400px;
+ gap: var(--spacing-lg);
+ }
+
+ .spinner {
+ width: 40px;
+ height: 40px;
+ border: 3px solid var(--border);
+ border-top-color: var(--accent);
+ border-radius: 50%;
+ animation: spin 0.8s linear infinite;
+ }
+
+ @keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+ }
+
+ .loading-text {
+ color: var(--text-secondary);
+ font-size: 0.9375rem;
+ font-weight: 500;
+ }
+
+ /* Canvas */
+ .canvas-container {
+ display: flex;
+ justify-content: center;
+ margin-top: var(--spacing-xl);
+ padding: 0 var(--spacing-md);
+ }
+
+ #canvas {
max-width: 100%;
+ height: auto;
+ border-radius: var(--radius);
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
+ background: var(--surface-elevated);
+ display: block;
+ }
+
+ /* Sections */
+ #introduction {
+ text-align: center;
+ padding: var(--spacing-2xl) var(--spacing-md);
+ color: var(--text-secondary);
+ min-height: 200px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ #introduction:empty {
+ display: none;
+ }
+
+ #analyzing {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ min-height: 300px;
+ padding: var(--spacing-2xl);
+ gap: var(--spacing-lg);
+ }
+
+ #analyzing-status {
+ color: var(--text-secondary);
+ font-size: 0.9375rem;
+ font-weight: 500;
+ }
+
+ #render:empty {
+ display: none;
+ }
+
+ /* Responsive */
+ @media (max-width: 768px) {
+ .main-content {
+ padding: var(--spacing-lg) var(--spacing-md);
+ }
+
+ .input-container {
+ padding: var(--spacing-lg);
+ }
+
+ .table-container {
+ border-radius: var(--radius);
+ }
+
+ table {
+ font-size: 0.8125rem;
+ }
+
+ th,
+ td {
+ padding: var(--spacing-sm) var(--spacing-md);
+ }
+
+ th {
+ font-size: 0.6875rem;
+ }
+ }
+
+ @media (max-width: 480px) {
+ th:nth-child(5),
+ td:nth-child(5) {
+ display: none;
+ }
+
+ .header h1 {
+ font-size: 1.5rem;
+ }
+
+ .input-container {
+ padding: var(--spacing-md);
+ }
+
+ table {
+ font-size: 0.75rem;
+ }
+
+ th,
+ td {
+ padding: var(--spacing-xs) var(--spacing-sm);
+ }
+ }
+
+ /* Scrollbar */
+ ::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+ }
+
+ ::-webkit-scrollbar-track {
+ background: var(--surface);
+ }
+
+ ::-webkit-scrollbar-thumb {
+ background: var(--border);
+ border-radius: 4px;
+ }
+
+ ::-webkit-scrollbar-thumb:hover {
+ background: rgba(255, 255, 255, 0.15);
+ }
+
+ /* Utilities */
+ .d-none {
+ display: none !important;
+ }
+
+ .visually-hidden {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
white-space: nowrap;
- text-overflow: ellipsis;
+ border-width: 0;
+ }
+
+ /* Smooth transitions */
+ * {
+ transition-property: color, background-color, border-color;
+ transition-duration: 0.15s;
+ transition-timing-function: ease;
}
</style>
</head>
<body>
- <div id="loading" class="loading" style="display: none">
- <div></div>
- <div class="spinner-border">
- <span class="visually-hidden">Loading...</span>
- </div>
- <div></div>
- </div>
-
- <div class="container">
- <div class="row">
- <div class="col-md">
- <label for="image-file"> Choose an image to analyze </label>
- <input type="file" id="image-file" class="form-control" />
- </div>
- <div class="col-md">
- <label for="image-url"> or paste an URL </label>
- <input type="text" id="image-url" class="form-control" />
- </div>
- </div>
-
- <div class="row">
- <div class="col">
- <br />
+ <div class="app">
+ <div id="loading" class="loading-container" style="display: none">
+ <div class="spinner">
+ <span class="visually-hidden">Loading...</span>
</div>
</div>
- <div class="container">
- <table class="table table-bordered">
- <thead>
- <tr>
- <th style="width: 50px">
- <input
- type="checkbox"
- id="select-all"
- class="form-check-input"
- />
- </th>
- <th>Feature</th>
- <th>Rating</th>
- <th>Measurement</th>
- <th>Ideal</th>
- </tr>
- </thead>
-
- <tfoot>
- <tr>
- <td>
- <div class="form-check form-switch">
- <input
- class="form-check-input"
- type="checkbox"
- id="grading-toggle"
- checked=""
- />
- </div>
- </td>
- <td><strong>Total</strong></td>
- <td id="total-score"></td>
- <td id="total-breakdown"></td>
- <td id="total-psl"></td>
- </tr>
- </tfoot>
-
- <tbody>
- <tr>
- <td>
- <input
- type="checkbox"
- id="toggle-midface-ratio"
- class="form-check-input"
- checked=""
- />
- </td>
- <td>Midface ratio</td>
- <td id="assessment-midface-ratio"></td>
- <td id="value-midface-ratio"></td>
- <td id="ideal-midface-ratio"></td>
- </tr>
- <tr>
- <td>
- <input
- type="checkbox"
- id="toggle-facial-width-to-height-ratio"
- class="form-check-input"
- checked=""
- />
- </td>
- <td>Facial width to height ratio</td>
- <td id="assessment-facial-width-to-height-ratio"></td>
- <td id="value-facial-width-to-height-ratio"></td>
- <td id="ideal-facial-width-to-height-ratio"></td>
- </tr>
- <tr>
- <td>
- <input
- type="checkbox"
- id="toggle-chin-to-philtrum-ratio"
- class="form-check-input"
- checked=""
- />
- </td>
- <td>Chin to philtrum ratio</td>
- <td id="assessment-chin-to-philtrum-ratio"></td>
- <td id="value-chin-to-philtrum-ratio"></td>
- <td id="ideal-chin-to-philtrum-ratio"></td>
- </tr>
- <tr>
- <td>
- <input
- type="checkbox"
- id="toggle-canthal-tilt"
- class="form-check-input"
- checked=""
- />
- </td>
- <td>Canthal tilt</td>
- <td id="assessment-canthal-tilt"></td>
- <td id="value-canthal-tilt"></td>
- <td id="ideal-canthal-tilt"></td>
- </tr>
- <tr>
- <td>
- <input
- type="checkbox"
- id="toggle-mouth-to-nose-ratio"
- class="form-check-input"
- checked=""
- />
- </td>
- <td>Mouth to nose ratio</td>
- <td id="assessment-mouth-to-nose-ratio"></td>
- <td id="value-mouth-to-nose-ratio"></td>
- <td id="ideal-mouth-to-nose-ratio"></td>
- </tr>
- <tr>
- <td>
- <input
- type="checkbox"
- id="toggle-bigonial-width"
- class="form-check-input"
- checked=""
- />
- </td>
- <td>Bigonial width</td>
- <td id="assessment-bigonial-width"></td>
- <td id="value-bigonial-width"></td>
- <td id="ideal-bigonial-width"></td>
- </tr>
- <tr>
- <td>
- <input
- type="checkbox"
- id="toggle-lip-ratio"
- class="form-check-input"
- checked=""
- />
- </td>
- <td>Lip ratio</td>
- <td id="assessment-lip-ratio"></td>
- <td id="value-lip-ratio"></td>
- <td id="ideal-lip-ratio"></td>
- </tr>
- <tr>
- <td>
- <input
- type="checkbox"
- id="toggle-eye-separation-ratio"
- class="form-check-input"
- checked=""
- />
- </td>
- <td>Eye separation ratio</td>
- <td id="assessment-eye-separation-ratio"></td>
- <td id="value-eye-separation-ratio"></td>
- <td id="ideal-eye-separation-ratio"></td>
- </tr>
- <tr>
- <td>
- <input
- type="checkbox"
- id="toggle-eye-to-mouth-angle"
- class="form-check-input"
- checked=""
- />
- </td>
- <td>Eye to mouth angle</td>
- <td id="assessment-eye-to-mouth-angle"></td>
- <td id="value-eye-to-mouth-angle"></td>
- <td id="ideal-eye-to-mouth-angle"></td>
- </tr>
- <tr>
- <td>
- <input
- type="checkbox"
- id="toggle-lower-third-height"
- class="form-check-input"
- checked=""
- />
- </td>
- <td>Lower third height</td>
- <td id="assessment-lower-third-height"></td>
- <td id="value-lower-third-height"></td>
- <td id="ideal-lower-third-height"></td>
- </tr>
- <tr>
- <td>
- <input
- type="checkbox"
- id="toggle-palpebral-fissure-length"
- class="form-check-input"
- checked=""
- />
- </td>
- <td>Palpebral fissure length</td>
- <td id="assessment-palpebral-fissure-length"></td>
- <td id="value-palpebral-fissure-length"></td>
- <td id="ideal-palpebral-fissure-length"></td>
- </tr>
- <tr>
- <td>
- <input
- type="checkbox"
- id="toggle-eye-color"
- class="form-check-input"
- checked=""
- />
- </td>
- <td>Eye color</td>
- <td id="assessment-eye-color"></td>
- <td id="value-eye-color">
- <canvas height="0" width="0"></canvas>
- <canvas height="0" width="0"></canvas>
- </td>
- <td id="ideal-eye-color"></td>
- </tr>
- </tbody>
- </table>
- </div>
-
- <!-- JavaScript for Select All -->
- <script>
- // Select All Checkbox
- const selectAllCheckbox = document.getElementById("select-all");
-
- // Get all checkboxes in the table body
- const checkboxes = document.querySelectorAll(
- 'tbody input[type="checkbox"]'
- );
-
- // Event Listener for Select All
- selectAllCheckbox.addEventListener("change", function () {
- checkboxes.forEach((checkbox) => {
- checkbox.checked = selectAllCheckbox.checked; // Toggle all checkboxes
- });
- });
+ <main class="main-content">
+ <header class="header">
+ <h1>Facial Analysis</h1>
+ <p>Upload an image or paste a URL to analyse facial features</p>
+ </header>
- // Update "Select All" if any checkbox is unchecked
- checkboxes.forEach((checkbox) => {
- checkbox.addEventListener("change", function () {
- selectAllCheckbox.checked = [...checkboxes].every(
- (cb) => cb.checked
- );
- });
- });
- </script>
+ <section class="input-container">
+ <div class="input-grid">
+ <div class="input-field">
+ <label for="image-file">Upload Image</label>
+ <input
+ type="file"
+ id="image-file"
+ accept="image/*"
+ class="form-control"
+ />
+ </div>
+ <div class="input-field">
+ <label for="image-url">Or Paste URL</label>
+ <input
+ type="text"
+ id="image-url"
+ placeholder="https://example.com/image.jpg"
+ class="form-control"
+ />
+ </div>
+ </div>
+ </section>
- <div id="introduction" class="row mt-3"></div>
+ <section class="table-container">
+ <div class="table-wrapper">
+ <table>
+ <thead>
+ <tr>
+ <th>
+ <input
+ type="checkbox"
+ id="select-all"
+ class="checkbox"
+ title="Select All"
+ />
+ </th>
+ <th>Feature</th>
+ <th>Rating</th>
+ <th>Measurement</th>
+ <th>Ideal</th>
+ </tr>
+ </thead>
- <div class="row d-none mt-5" id="analyzing">
- <div class="col text-center">
- <div>
- <div class="loading">
- <div></div>
+ <tfoot>
+ <tr>
+ <td>
+ <input
+ type="checkbox"
+ id="grading-toggle"
+ class="checkbox"
+ checked
+ />
+ </td>
+ <td><strong>Total</strong></td>
+ <td id="total-score"></td>
+ <td id="total-breakdown"></td>
+ <td id="total-psl"></td>
+ </tr>
+ </tfoot>
- <div class="spinner-border"></div>
+ <tbody>
+ <tr>
+ <td>
+ <input
+ type="checkbox"
+ id="toggle-midface-ratio"
+ class="checkbox"
+ checked
+ />
+ </td>
+ <td>Midface ratio</td>
+ <td id="assessment-midface-ratio"></td>
+ <td id="value-midface-ratio"></td>
+ <td id="ideal-midface-ratio"></td>
+ </tr>
+ <tr>
+ <td>
+ <input
+ type="checkbox"
+ id="toggle-facial-width-to-height-ratio"
+ class="checkbox"
+ checked
+ />
+ </td>
+ <td>Facial width to height ratio</td>
+ <td id="assessment-facial-width-to-height-ratio"></td>
+ <td id="value-facial-width-to-height-ratio"></td>
+ <td id="ideal-facial-width-to-height-ratio"></td>
+ </tr>
+ <tr>
+ <td>
+ <input
+ type="checkbox"
+ id="toggle-chin-to-philtrum-ratio"
+ class="checkbox"
+ checked
+ />
+ </td>
+ <td>Chin to philtrum ratio</td>
+ <td id="assessment-chin-to-philtrum-ratio"></td>
+ <td id="value-chin-to-philtrum-ratio"></td>
+ <td id="ideal-chin-to-philtrum-ratio"></td>
+ </tr>
+ <tr>
+ <td>
+ <input
+ type="checkbox"
+ id="toggle-canthal-tilt"
+ class="checkbox"
+ checked
+ />
+ </td>
+ <td>Canthal tilt</td>
+ <td id="assessment-canthal-tilt"></td>
+ <td id="value-canthal-tilt"></td>
+ <td id="ideal-canthal-tilt"></td>
+ </tr>
+ <tr>
+ <td>
+ <input
+ type="checkbox"
+ id="toggle-mouth-to-nose-ratio"
+ class="checkbox"
+ checked
+ />
+ </td>
+ <td>Mouth to nose ratio</td>
+ <td id="assessment-mouth-to-nose-ratio"></td>
+ <td id="value-mouth-to-nose-ratio"></td>
+ <td id="ideal-mouth-to-nose-ratio"></td>
+ </tr>
+ <tr>
+ <td>
+ <input
+ type="checkbox"
+ id="toggle-bigonial-width"
+ class="checkbox"
+ checked
+ />
+ </td>
+ <td>Bigonial width</td>
+ <td id="assessment-bigonial-width"></td>
+ <td id="value-bigonial-width"></td>
+ <td id="ideal-bigonial-width"></td>
+ </tr>
+ <tr>
+ <td>
+ <input
+ type="checkbox"
+ id="toggle-lip-ratio"
+ class="checkbox"
+ checked
+ />
+ </td>
+ <td>Lip ratio</td>
+ <td id="assessment-lip-ratio"></td>
+ <td id="value-lip-ratio"></td>
+ <td id="ideal-lip-ratio"></td>
+ </tr>
+ <tr>
+ <td>
+ <input
+ type="checkbox"
+ id="toggle-eye-separation-ratio"
+ class="checkbox"
+ checked
+ />
+ </td>
+ <td>Eye separation ratio</td>
+ <td id="assessment-eye-separation-ratio"></td>
+ <td id="value-eye-separation-ratio"></td>
+ <td id="ideal-eye-separation-ratio"></td>
+ </tr>
+ <tr>
+ <td>
+ <input
+ type="checkbox"
+ id="toggle-eye-to-mouth-angle"
+ class="checkbox"
+ checked
+ />
+ </td>
+ <td>Eye to mouth angle</td>
+ <td id="assessment-eye-to-mouth-angle"></td>
+ <td id="value-eye-to-mouth-angle"></td>
+ <td id="ideal-eye-to-mouth-angle"></td>
+ </tr>
+ <tr>
+ <td>
+ <input
+ type="checkbox"
+ id="toggle-lower-third-height"
+ class="checkbox"
+ checked
+ />
+ </td>
+ <td>Lower third height</td>
+ <td id="assessment-lower-third-height"></td>
+ <td id="value-lower-third-height"></td>
+ <td id="ideal-lower-third-height"></td>
+ </tr>
+ <tr>
+ <td>
+ <input
+ type="checkbox"
+ id="toggle-palpebral-fissure-length"
+ class="checkbox"
+ checked
+ />
+ </td>
+ <td>Palpebral fissure length</td>
+ <td id="assessment-palpebral-fissure-length"></td>
+ <td id="value-palpebral-fissure-length"></td>
+ <td id="ideal-palpebral-fissure-length"></td>
+ </tr>
+ <tr>
+ <td>
+ <input
+ type="checkbox"
+ id="toggle-eye-color"
+ class="checkbox"
+ checked
+ />
+ </td>
+ <td>Eye colour</td>
+ <td id="assessment-eye-color"></td>
+ <td id="value-eye-color">
+ <canvas height="0" width="0"></canvas>
+ <canvas height="0" width="0"></canvas>
+ </td>
+ <td id="ideal-eye-color"></td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </section>
- <div></div>
- </div>
+ <div id="introduction"></div>
- <div class="mt-3 fs-5">
- <div id="analyzing-status"></div>
- </div>
- </div>
+ <div class="d-none" id="analyzing">
+ <div class="spinner"></div>
+ <div id="analyzing-status" class="loading-text"></div>
</div>
- </div>
- <div class="row" id="render">
- <div class="col"><canvas id="canvas"></canvas></div>
- </div>
+ <div class="canvas-container" id="render">
+ <canvas id="canvas"></canvas>
+ </div>
+ </main>
</div>
+
+ <script>
+ // Select All Checkbox
+ const selectAllCheckbox = document.getElementById("select-all");
+ const checkboxes = document.querySelectorAll(
+ 'tbody input[type="checkbox"]'
+ );
+
+ selectAllCheckbox.addEventListener("change", function () {
+ checkboxes.forEach((checkbox) => {
+ checkbox.checked = selectAllCheckbox.checked;
+ });
+ });
+
+ checkboxes.forEach((checkbox) => {
+ checkbox.addEventListener("change", function () {
+ selectAllCheckbox.checked = [...checkboxes].every((cb) => cb.checked);
+ });
+ });
+ </script>
+
<script src="js/analysis.js"></script>
<script src="js/index.js"></script>
<script>
diff --git a/js/index.js b/js/index.js
index 3881d38..f1d4210 100644
--- a/js/index.js
+++ b/js/index.js
@@ -205,7 +205,7 @@ if (gradingToggle) {
});
async function onChange(url) {
- setStatus("Analyzing");
+ setStatus("Analysing");
let analysis = await analyze(canvas, ctx, url);
@@ -368,7 +368,7 @@ async function analyze(canvas, ctx, url) {
ctx.lineWidth = Math.sqrt((image.width * image.height) / 100000);
ctx.arcRadius = Math.sqrt((image.width * image.height) / 100000);
- setStatus("Analyzing");
+ setStatus("Analysing");
const model = await faceLandmarksDetection.load(faceLandmarksDetection.SupportedPackages.mediapipeFacemesh, {
maxFaces: 1