@jjlmoya/utils-forensic-science 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/category/index.ts +3 -1
- package/src/entries.ts +5 -1
- package/src/index.ts +1 -0
- package/src/tests/locale_completeness.test.ts +2 -2
- package/src/tests/tool_validation.test.ts +2 -2
- package/src/tool/fire-pattern-origin-analyzer/bibliography.astro +6 -0
- package/src/tool/fire-pattern-origin-analyzer/bibliography.ts +12 -0
- package/src/tool/fire-pattern-origin-analyzer/component.astro +196 -0
- package/src/tool/fire-pattern-origin-analyzer/entry.ts +32 -0
- package/src/tool/fire-pattern-origin-analyzer/fire-pattern-origin-analyzer.css +681 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/de.ts +250 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/en.ts +250 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/es.ts +250 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/fr.ts +250 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/id.ts +250 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/it.ts +250 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/ja.ts +250 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/ko.ts +250 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/nl.ts +250 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/pl.ts +250 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/pt.ts +250 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/ru.ts +250 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/sv.ts +250 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/tr.ts +250 -0
- package/src/tool/fire-pattern-origin-analyzer/i18n/zh.ts +246 -0
- package/src/tool/fire-pattern-origin-analyzer/index.ts +11 -0
- package/src/tool/fire-pattern-origin-analyzer/logic.ts +123 -0
- package/src/tool/fire-pattern-origin-analyzer/render.ts +159 -0
- package/src/tool/fire-pattern-origin-analyzer/seo.astro +15 -0
- package/src/tool/fire-pattern-origin-analyzer/view-bindings.ts +171 -0
- package/src/tool/fire-pattern-origin-analyzer/view-model.ts +244 -0
- package/src/tool/fire-pattern-origin-analyzer/view.ts +30 -0
- package/src/tools.ts +3 -1
package/package.json
CHANGED
package/src/category/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { forensicGlassBeckeLineSimulator } from '../tool/forensic-glass-becke-li
|
|
|
12
12
|
import { forensicFiberComparisonMicroscope } from '../tool/forensic-fiber-comparison-microscope/index';
|
|
13
13
|
import { bloodstainPatternOriginAnalyzer } from '../tool/bloodstain-pattern-origin-analyzer/index';
|
|
14
14
|
import { forensicFingerprintMinutiaeIdentifier } from '../tool/forensic-fingerprint-minutiae-identifier/index';
|
|
15
|
+
import { firePatternOriginAnalyzer } from '../tool/fire-pattern-origin-analyzer/index';
|
|
15
16
|
|
|
16
17
|
export const forensicCategory: ScienceCategoryEntry = {
|
|
17
18
|
icon: 'mdi:fingerprint',
|
|
@@ -28,7 +29,8 @@ export const forensicCategory: ScienceCategoryEntry = {
|
|
|
28
29
|
forensicGlassBeckeLineSimulator,
|
|
29
30
|
forensicFiberComparisonMicroscope,
|
|
30
31
|
bloodstainPatternOriginAnalyzer,
|
|
31
|
-
forensicFingerprintMinutiaeIdentifier
|
|
32
|
+
forensicFingerprintMinutiaeIdentifier,
|
|
33
|
+
firePatternOriginAnalyzer
|
|
32
34
|
],
|
|
33
35
|
i18n: {
|
|
34
36
|
de: () => import('./i18n/de').then((m) => m.content),
|
package/src/entries.ts
CHANGED
|
@@ -24,6 +24,8 @@ export { bloodstainPatternOriginAnalyzer } from './tool/bloodstain-pattern-origi
|
|
|
24
24
|
export type { BloodstainPatternUI, BloodstainPatternLocaleContent } from './tool/bloodstain-pattern-origin-analyzer/entry';
|
|
25
25
|
export { forensicFingerprintMinutiaeIdentifier } from './tool/forensic-fingerprint-minutiae-identifier/entry';
|
|
26
26
|
export type { FingerprintMinutiaeUI, FingerprintMinutiaeLocaleContent } from './tool/forensic-fingerprint-minutiae-identifier/entry';
|
|
27
|
+
export { firePatternOriginAnalyzer } from './tool/fire-pattern-origin-analyzer/entry';
|
|
28
|
+
export type { FirePatternOriginAnalyzerUI, FirePatternOriginAnalyzerLocaleContent } from './tool/fire-pattern-origin-analyzer/entry';
|
|
27
29
|
|
|
28
30
|
import { forensicAgeEstimator } from './tool/forensic-age-estimator/entry';
|
|
29
31
|
import { widmarkAlcoholSimulator } from './tool/widmark-alcohol-simulator/entry';
|
|
@@ -38,6 +40,7 @@ import { forensicGlassBeckeLineSimulator } from './tool/forensic-glass-becke-lin
|
|
|
38
40
|
import { forensicFiberComparisonMicroscope } from './tool/forensic-fiber-comparison-microscope/entry';
|
|
39
41
|
import { bloodstainPatternOriginAnalyzer } from './tool/bloodstain-pattern-origin-analyzer/entry';
|
|
40
42
|
import { forensicFingerprintMinutiaeIdentifier } from './tool/forensic-fingerprint-minutiae-identifier/entry';
|
|
43
|
+
import { firePatternOriginAnalyzer } from './tool/fire-pattern-origin-analyzer/entry';
|
|
41
44
|
|
|
42
45
|
export const ALL_ENTRIES = [
|
|
43
46
|
forensicAgeEstimator,
|
|
@@ -52,5 +55,6 @@ export const ALL_ENTRIES = [
|
|
|
52
55
|
forensicGlassBeckeLineSimulator,
|
|
53
56
|
forensicFiberComparisonMicroscope,
|
|
54
57
|
bloodstainPatternOriginAnalyzer,
|
|
55
|
-
forensicFingerprintMinutiaeIdentifier
|
|
58
|
+
forensicFingerprintMinutiaeIdentifier,
|
|
59
|
+
firePatternOriginAnalyzer
|
|
56
60
|
];
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ export { FORENSIC_GLASS_BECKE_LINE_SIMULATOR_TOOL } from './tool/forensic-glass-
|
|
|
13
13
|
export { FORENSIC_FIBER_COMPARISON_MICROSCOPE_TOOL } from './tool/forensic-fiber-comparison-microscope/index';
|
|
14
14
|
export { BLOODSTAIN_PATTERN_ORIGIN_ANALYZER_TOOL } from './tool/bloodstain-pattern-origin-analyzer/index';
|
|
15
15
|
export { FORENSIC_FINGERPRINT_MINUTIAE_IDENTIFIER_TOOL } from './tool/forensic-fingerprint-minutiae-identifier/index';
|
|
16
|
+
export { FIRE_PATTERN_ORIGIN_ANALYZER_TOOL } from './tool/fire-pattern-origin-analyzer/index';
|
|
16
17
|
|
|
17
18
|
export type {
|
|
18
19
|
KnownLocale,
|
|
@@ -4,8 +4,8 @@ import { scienceCategory } from '../data';
|
|
|
4
4
|
|
|
5
5
|
describe('Tool Validation Suite', () => {
|
|
6
6
|
describe('Library Registration', () => {
|
|
7
|
-
it('should have
|
|
8
|
-
expect(ALL_TOOLS.length).toBe(
|
|
7
|
+
it('should have 14 tools in ALL_TOOLS', () => {
|
|
8
|
+
expect(ALL_TOOLS.length).toBe(14);
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
it('scienceCategory should be defined', () => {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { BibliographyEntry } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const bibliography: BibliographyEntry[] = [
|
|
4
|
+
{
|
|
5
|
+
name: 'NFPA 921: Guide for Fire and Explosion Investigations.',
|
|
6
|
+
url: 'https://www.nfpa.org/codes-and-standards/nfpa-921-standard-development/921',
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
name: 'NIJ: Fire and Arson Scene Evidence, A Guide for Public Safety Personnel.',
|
|
10
|
+
url: 'https://www.ojp.gov/pdffiles1/nij/181584.pdf',
|
|
11
|
+
}
|
|
12
|
+
];
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
import './fire-pattern-origin-analyzer.css';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
ui: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { ui } = Astro.props;
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<section class="fire-origin" data-fire-origin-tool data-has-plan="false">
|
|
12
|
+
<div class="fire-workspace">
|
|
13
|
+
<div class="fire-topbar">
|
|
14
|
+
<label class="fire-command fire-command-load">
|
|
15
|
+
<input id="fire-plan-upload" type="file" accept="image/*" />
|
|
16
|
+
<span>{ui.loadPlan}</span>
|
|
17
|
+
</label>
|
|
18
|
+
<button type="button" class="fire-command" id="fire-reset" disabled>{ui.resetVectors}</button>
|
|
19
|
+
<button type="button" class="fire-command fire-command-export" id="fire-export" disabled>{ui.generateReport}</button>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div class="fire-plan-shell">
|
|
23
|
+
<div class="fire-layer-dots" role="group" aria-label={ui.visibleLayers}>
|
|
24
|
+
<button type="button" class="fire-layer-dot" data-fire-layer-toggle="vPattern" data-active="true" aria-label={ui.vPattern} disabled></button>
|
|
25
|
+
<button type="button" class="fire-layer-dot" data-fire-layer-toggle="deepChar" data-active="true" aria-label={ui.deepChar} disabled></button>
|
|
26
|
+
<button type="button" class="fire-layer-dot" data-fire-layer-toggle="sootShadow" data-active="true" aria-label={ui.sootShadow} disabled></button>
|
|
27
|
+
<button type="button" class="fire-layer-dot" data-fire-layer-toggle="cleanBurn" data-active="true" aria-label={ui.cleanBurn} disabled></button>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div class="fire-pointer-overlay" id="fire-pointer-overlay">
|
|
31
|
+
<span>{ui.pointerLabel}</span>
|
|
32
|
+
<strong id="fire-pointer-coordinate">--, --</strong>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div class="fire-origin-overlay" id="fire-origin-overlay">
|
|
36
|
+
<span>{ui.estimatedOrigin}</span>
|
|
37
|
+
<strong id="fire-origin-coordinate">--, --</strong>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<button type="button" class="fire-dropzone" id="fire-dropzone">{ui.dropPlan}</button>
|
|
41
|
+
|
|
42
|
+
<div class="fire-radial-menu" id="fire-radial-menu" hidden>
|
|
43
|
+
<button type="button" data-fire-pattern="vPattern">{ui.vPattern}</button>
|
|
44
|
+
<button type="button" data-fire-pattern="deepChar">{ui.deepChar}</button>
|
|
45
|
+
<button type="button" data-fire-pattern="cleanBurn">{ui.cleanBurn}</button>
|
|
46
|
+
<button type="button" data-fire-pattern="sootShadow">{ui.sootShadow}</button>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<svg id="fire-plan-svg" viewBox="0 0 1000 680" role="img" aria-label={ui.planAria}>
|
|
50
|
+
<defs>
|
|
51
|
+
<pattern id="fire-grid" width="50" height="50" patternUnits="userSpaceOnUse">
|
|
52
|
+
<path d="M 50 0 L 0 0 0 50" fill="none" stroke="currentColor" stroke-width="1" opacity="0.14"></path>
|
|
53
|
+
</pattern>
|
|
54
|
+
</defs>
|
|
55
|
+
<image id="fire-plan-image" x="0" y="0" width="1000" height="680" preserveAspectRatio="xMidYMid slice"></image>
|
|
56
|
+
<rect class="fire-grid-fill" x="0" y="0" width="1000" height="680" fill="url(#fire-grid)"></rect>
|
|
57
|
+
</svg>
|
|
58
|
+
<canvas id="fire-overlay-canvas" width="1000" height="680"></canvas>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<footer class="fire-statusbar">
|
|
62
|
+
<span>{ui.vectorsLabel}: <strong id="fire-vector-count">0</strong></span>
|
|
63
|
+
<span>{ui.confidenceLabel}: <strong id="fire-confidence-score">0.0%</strong></span>
|
|
64
|
+
<span>{ui.varianceLabel}: <strong id="fire-origin-variance">+-0.0 m</strong></span>
|
|
65
|
+
<span>{ui.modeLabel}: <strong id="fire-mode-label">{ui.awaitingVector}</strong></span>
|
|
66
|
+
</footer>
|
|
67
|
+
|
|
68
|
+
<details class="fire-guide" open>
|
|
69
|
+
<summary>{ui.guideSummary}</summary>
|
|
70
|
+
<div class="fire-guide-body" aria-label={ui.guideTitle}>
|
|
71
|
+
<div class="fire-guide-panels">
|
|
72
|
+
<details open>
|
|
73
|
+
<summary>{ui.flowPanelTitle}</summary>
|
|
74
|
+
<div class="fire-guide-flow">
|
|
75
|
+
<article>
|
|
76
|
+
<strong>{ui.flow1Kicker}</strong>
|
|
77
|
+
<span>{ui.flow1Icon}</span>
|
|
78
|
+
<h3>{ui.flow1Title}</h3>
|
|
79
|
+
<p>{ui.flow1Text}</p>
|
|
80
|
+
</article>
|
|
81
|
+
<article>
|
|
82
|
+
<strong>{ui.flow2Kicker}</strong>
|
|
83
|
+
<span>{ui.flow2Icon}</span>
|
|
84
|
+
<h3>{ui.flow2Title}</h3>
|
|
85
|
+
<p>{ui.flow2Text}</p>
|
|
86
|
+
</article>
|
|
87
|
+
<article>
|
|
88
|
+
<strong>{ui.flow3Kicker}</strong>
|
|
89
|
+
<span>{ui.flow3Icon}</span>
|
|
90
|
+
<h3>{ui.flow3Title}</h3>
|
|
91
|
+
<p>{ui.flow3Text}</p>
|
|
92
|
+
</article>
|
|
93
|
+
<article>
|
|
94
|
+
<strong>{ui.flow4Kicker}</strong>
|
|
95
|
+
<span>{ui.flow4Icon}</span>
|
|
96
|
+
<h3>{ui.flow4Title}</h3>
|
|
97
|
+
<p>{ui.flow4Text}</p>
|
|
98
|
+
</article>
|
|
99
|
+
</div>
|
|
100
|
+
</details>
|
|
101
|
+
|
|
102
|
+
<details open>
|
|
103
|
+
<summary>{ui.legendPanelTitle}</summary>
|
|
104
|
+
<div class="fire-guide-legend" aria-label={ui.indicatorsTitle}>
|
|
105
|
+
<article class="fire-guide-chip fire-guide-chip-v">
|
|
106
|
+
<span></span>
|
|
107
|
+
<strong>{ui.vPattern}</strong>
|
|
108
|
+
<small>{ui.vPatternShort}</small>
|
|
109
|
+
</article>
|
|
110
|
+
<article class="fire-guide-chip fire-guide-chip-char">
|
|
111
|
+
<span></span>
|
|
112
|
+
<strong>{ui.deepChar}</strong>
|
|
113
|
+
<small>{ui.deepCharShort}</small>
|
|
114
|
+
</article>
|
|
115
|
+
<article class="fire-guide-chip fire-guide-chip-soot">
|
|
116
|
+
<span></span>
|
|
117
|
+
<strong>{ui.sootShadow}</strong>
|
|
118
|
+
<small>{ui.sootShadowShort}</small>
|
|
119
|
+
</article>
|
|
120
|
+
<article class="fire-guide-chip fire-guide-chip-clean">
|
|
121
|
+
<span></span>
|
|
122
|
+
<strong>{ui.cleanBurn}</strong>
|
|
123
|
+
<small>{ui.cleanBurnShort}</small>
|
|
124
|
+
</article>
|
|
125
|
+
</div>
|
|
126
|
+
</details>
|
|
127
|
+
|
|
128
|
+
<details open>
|
|
129
|
+
<summary>{ui.readoutPanelTitle}</summary>
|
|
130
|
+
<div class="fire-guide-readouts">
|
|
131
|
+
<article>
|
|
132
|
+
<strong>{ui.vectorsLabel}</strong>
|
|
133
|
+
<p>{ui.resultsPoint1}</p>
|
|
134
|
+
</article>
|
|
135
|
+
<article>
|
|
136
|
+
<strong>{ui.confidenceLabel}</strong>
|
|
137
|
+
<p>{ui.resultsPoint2}</p>
|
|
138
|
+
</article>
|
|
139
|
+
<article>
|
|
140
|
+
<strong>{ui.varianceLabel}</strong>
|
|
141
|
+
<p>{ui.resultsPoint3}</p>
|
|
142
|
+
</article>
|
|
143
|
+
<article>
|
|
144
|
+
<strong>{ui.modeLabel}</strong>
|
|
145
|
+
<p>{ui.resultsPoint4}</p>
|
|
146
|
+
</article>
|
|
147
|
+
</div>
|
|
148
|
+
</details>
|
|
149
|
+
|
|
150
|
+
<details open>
|
|
151
|
+
<summary>{ui.basicsTitle}</summary>
|
|
152
|
+
<div class="fire-guide-panel-copy">
|
|
153
|
+
<p>{ui.basicsIntro}</p>
|
|
154
|
+
</div>
|
|
155
|
+
</details>
|
|
156
|
+
|
|
157
|
+
<details>
|
|
158
|
+
<summary>{ui.indicatorsTitle}</summary>
|
|
159
|
+
<div class="fire-guide-definitions">
|
|
160
|
+
<article>
|
|
161
|
+
<h3>{ui.vPattern}</h3>
|
|
162
|
+
<p>{ui.vPatternExplain}</p>
|
|
163
|
+
</article>
|
|
164
|
+
<article>
|
|
165
|
+
<h3>{ui.deepChar}</h3>
|
|
166
|
+
<p>{ui.deepCharExplain}</p>
|
|
167
|
+
</article>
|
|
168
|
+
<article>
|
|
169
|
+
<h3>{ui.sootShadow}</h3>
|
|
170
|
+
<p>{ui.sootShadowExplain}</p>
|
|
171
|
+
</article>
|
|
172
|
+
<article>
|
|
173
|
+
<h3>{ui.cleanBurn}</h3>
|
|
174
|
+
<p>{ui.cleanBurnExplain}</p>
|
|
175
|
+
</article>
|
|
176
|
+
</div>
|
|
177
|
+
</details>
|
|
178
|
+
|
|
179
|
+
<details>
|
|
180
|
+
<summary>{ui.resultsTitle}</summary>
|
|
181
|
+
<div class="fire-guide-panel-copy">
|
|
182
|
+
<p>{ui.resultsIntro}</p>
|
|
183
|
+
</div>
|
|
184
|
+
</details>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
</details>
|
|
188
|
+
</div>
|
|
189
|
+
</section>
|
|
190
|
+
|
|
191
|
+
<script id="fire-origin-ui" type="application/json" set:html={JSON.stringify(ui)}></script>
|
|
192
|
+
<script>
|
|
193
|
+
import { initFirePatternOriginAnalyzer } from './view';
|
|
194
|
+
|
|
195
|
+
initFirePatternOriginAnalyzer(JSON.parse(document.getElementById('fire-origin-ui')?.textContent || '{}'));
|
|
196
|
+
</script>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ScienceToolEntry, ToolLocaleContent } from '../../types';
|
|
2
|
+
|
|
3
|
+
export interface FirePatternOriginAnalyzerUI {
|
|
4
|
+
[key: string]: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type FirePatternOriginAnalyzerLocaleContent = ToolLocaleContent<FirePatternOriginAnalyzerUI>;
|
|
8
|
+
|
|
9
|
+
export const firePatternOriginAnalyzer: ScienceToolEntry<FirePatternOriginAnalyzerUI> = {
|
|
10
|
+
id: 'fire-pattern-origin-analyzer',
|
|
11
|
+
icons: {
|
|
12
|
+
bg: 'mdi:fire-alert',
|
|
13
|
+
fg: 'mdi:vector-polyline',
|
|
14
|
+
},
|
|
15
|
+
i18n: {
|
|
16
|
+
de: () => import('./i18n/de').then((m) => m.content),
|
|
17
|
+
en: () => import('./i18n/en').then((m) => m.content),
|
|
18
|
+
es: () => import('./i18n/es').then((m) => m.content),
|
|
19
|
+
fr: () => import('./i18n/fr').then((m) => m.content),
|
|
20
|
+
id: () => import('./i18n/id').then((m) => m.content),
|
|
21
|
+
it: () => import('./i18n/it').then((m) => m.content),
|
|
22
|
+
ja: () => import('./i18n/ja').then((m) => m.content),
|
|
23
|
+
ko: () => import('./i18n/ko').then((m) => m.content),
|
|
24
|
+
nl: () => import('./i18n/nl').then((m) => m.content),
|
|
25
|
+
pl: () => import('./i18n/pl').then((m) => m.content),
|
|
26
|
+
pt: () => import('./i18n/pt').then((m) => m.content),
|
|
27
|
+
ru: () => import('./i18n/ru').then((m) => m.content),
|
|
28
|
+
sv: () => import('./i18n/sv').then((m) => m.content),
|
|
29
|
+
tr: () => import('./i18n/tr').then((m) => m.content),
|
|
30
|
+
zh: () => import('./i18n/zh').then((m) => m.content),
|
|
31
|
+
},
|
|
32
|
+
};
|