chrono-phylo-tree 1.1.8 → 1.1.10
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/dist/chrono-phylo-tree.es.js +1551 -0
- package/dist/chrono-phylo-tree.umd.js +45 -0
- package/dist/logo.png +0 -0
- package/dist/translate.csv +37 -0
- package/dist/vite.svg +1 -0
- package/package.json +15 -6
- package/src/App.css +0 -131
- package/src/App.tsx +0 -149
- package/src/assets/react.svg +0 -1
- package/src/classes/Species.tsx +0 -267
- package/src/components/HoverDescription.tsx +0 -27
- package/src/components/LanguageSelector.tsx +0 -29
- package/src/components/Menu.tsx +0 -348
- package/src/components/NavBar.tsx +0 -234
- package/src/components/PhTree.tsx +0 -362
- package/src/index.css +0 -68
- package/src/index.ts +0 -4
- package/src/main.tsx +0 -10
- package/src/types.d.ts +0 -9
- package/src/utils/between.tsx +0 -3
- package/src/utils/example.tsx +0 -73
- package/src/utils/hexToRGBA.tsx +0 -12
- package/src/utils/scientificNotation.tsx +0 -20
- package/src/utils/setFromJson.tsx +0 -40
- package/src/utils/translate.tsx +0 -68
- package/src/utils/updateSpecies.tsx +0 -129
- package/src/vite-env.d.ts +0 -1
@@ -1,234 +0,0 @@
|
|
1
|
-
import { Species } from "../classes/Species";
|
2
|
-
import { codeText } from "../utils/translate";
|
3
|
-
import { LanguageSelector } from "./LanguageSelector";
|
4
|
-
|
5
|
-
export const NavBar = ({
|
6
|
-
species,
|
7
|
-
color,
|
8
|
-
lineColor,
|
9
|
-
setLineColor,
|
10
|
-
language,
|
11
|
-
languages,
|
12
|
-
setLanguage,
|
13
|
-
minScale = 1e-12,
|
14
|
-
maxScale,
|
15
|
-
scale,
|
16
|
-
setScale,
|
17
|
-
showScaleNumber,
|
18
|
-
chronoScale,
|
19
|
-
setChronoScale,
|
20
|
-
showHover,
|
21
|
-
setShowHover,
|
22
|
-
showImages,
|
23
|
-
setShowImages,
|
24
|
-
presentTime,
|
25
|
-
presentTimeBoolean,
|
26
|
-
setPresentTimeBoolean,
|
27
|
-
changePresentTime,
|
28
|
-
setFromJson,
|
29
|
-
deleteAllSpecies,
|
30
|
-
createEmptySpecies,
|
31
|
-
showExample
|
32
|
-
}: NavBarProps) => {
|
33
|
-
return (
|
34
|
-
<nav style={{
|
35
|
-
backgroundColor: color,
|
36
|
-
maxWidth: window.screen.width - 64,
|
37
|
-
}}
|
38
|
-
className={`flex flex-col sm:flex-row w-auto ${species ? "fixed" : "static"} p-2.5 box-border ${species ? "transform translate-z-0" : "transform-none"}`}
|
39
|
-
>
|
40
|
-
<table className="flex flex-col justify-start text-start">
|
41
|
-
<tbody>
|
42
|
-
<LanguageSelector
|
43
|
-
className="block sm:hidden"
|
44
|
-
languages={languages}
|
45
|
-
language={language}
|
46
|
-
setLanguage={setLanguage}
|
47
|
-
/>
|
48
|
-
<tr className="block sm:hidden h-2.5"/>
|
49
|
-
<tr>
|
50
|
-
<td>{codeText("nvlbl00", language)}: </td>
|
51
|
-
<td>
|
52
|
-
<input
|
53
|
-
type="range"
|
54
|
-
min={minScale}
|
55
|
-
max={maxScale}
|
56
|
-
step={minScale}
|
57
|
-
value={maxScale - scale + minScale}
|
58
|
-
onChange={(e) => setScale(maxScale - Number(e.target.value) + minScale)}
|
59
|
-
/> {showScaleNumber && <input
|
60
|
-
type="number"
|
61
|
-
min={1}
|
62
|
-
max={maxScale}
|
63
|
-
value={scale}
|
64
|
-
onChange={(e) => setScale(Number(e.target.value))}
|
65
|
-
/>}
|
66
|
-
</td>
|
67
|
-
</tr>
|
68
|
-
<tr className="h-2.5"/>
|
69
|
-
<tr>
|
70
|
-
<td>{codeText("nvlbl06", language)}: </td>
|
71
|
-
<td>
|
72
|
-
<input
|
73
|
-
type="checkbox"
|
74
|
-
checked={chronoScale}
|
75
|
-
onChange={(e) => setChronoScale(e.target.checked)}
|
76
|
-
/>
|
77
|
-
</td>
|
78
|
-
</tr>
|
79
|
-
<tr className="h-2.5"/>
|
80
|
-
<tr>
|
81
|
-
<td>{codeText("nvlbl07", language)}: </td>
|
82
|
-
<td>
|
83
|
-
<input
|
84
|
-
type="checkbox"
|
85
|
-
checked={showHover}
|
86
|
-
onChange={(e) => setShowHover(e.target.checked)}
|
87
|
-
/>
|
88
|
-
</td>
|
89
|
-
</tr>
|
90
|
-
<tr className="h-2.5"/>
|
91
|
-
<tr>
|
92
|
-
<td>{codeText("nvlbl08", language)}</td>
|
93
|
-
<td>
|
94
|
-
<input
|
95
|
-
type="checkbox"
|
96
|
-
checked={showImages}
|
97
|
-
onChange={(e) => setShowImages(e.target.checked)}
|
98
|
-
/>
|
99
|
-
</td>
|
100
|
-
</tr>
|
101
|
-
<tr className="h-2.5"/>
|
102
|
-
<tr>
|
103
|
-
<td>{codeText("nvlbl01", language)}: </td>
|
104
|
-
<td>
|
105
|
-
<input
|
106
|
-
type="range"
|
107
|
-
min={species ? species.apparition : 0}
|
108
|
-
max={species ? species.absoluteExtinction() : 1}
|
109
|
-
value={presentTime}
|
110
|
-
onChange={(e) => changePresentTime(Number(e.target.value))}
|
111
|
-
disabled={!presentTimeBoolean || !chronoScale}
|
112
|
-
/> <input
|
113
|
-
type="number"
|
114
|
-
min={species ? species.apparition : 0}
|
115
|
-
max={species ? species.absoluteExtinction() : 1}
|
116
|
-
value={presentTime}
|
117
|
-
onChange={(e) => changePresentTime(Number(e.target.value))}
|
118
|
-
disabled={!presentTimeBoolean || !chronoScale}
|
119
|
-
/> <input
|
120
|
-
type="checkbox"
|
121
|
-
checked={presentTimeBoolean}
|
122
|
-
onChange={(e) => setPresentTimeBoolean(e.target.checked)}
|
123
|
-
disabled={!chronoScale}
|
124
|
-
/>
|
125
|
-
</td>
|
126
|
-
</tr>
|
127
|
-
</tbody>
|
128
|
-
</table>
|
129
|
-
<div className="h-2.5 sm:w-2.5 sm:h-auto"/>
|
130
|
-
<table className="flex flex-col justify-start text-start">
|
131
|
-
<tbody>
|
132
|
-
<tr>
|
133
|
-
<td>{codeText("nvlbl03", language)}: </td>
|
134
|
-
<td>
|
135
|
-
<a href="https://github.com/LUCHER4321/chrono-phylo-tree" target="_blank" className="ml-1.25 flex items-center">
|
136
|
-
<img style={{maxHeight: 25}} src="https://img.logo.dev/github.com?token=pk_VXzZR_o_QTelazRSvSRkNw&format=png"/>
|
137
|
-
</a>
|
138
|
-
</td>
|
139
|
-
</tr>
|
140
|
-
<tr className="h-2.5"/>
|
141
|
-
<tr>
|
142
|
-
<td>{codeText("nvlbl04", language)}: </td>
|
143
|
-
<td>
|
144
|
-
<input
|
145
|
-
type="file"
|
146
|
-
accept=".json"
|
147
|
-
value={undefined}
|
148
|
-
onChange={async (e) => await setFromJson(e.target.files?.[0])}
|
149
|
-
/>
|
150
|
-
</td>
|
151
|
-
</tr>
|
152
|
-
<tr className="h-2.5"/>
|
153
|
-
<tr className="block sm:hidden">
|
154
|
-
<td>{codeText("nvlbl02", language)}: </td>
|
155
|
-
<td>
|
156
|
-
<input
|
157
|
-
type="color"
|
158
|
-
value={lineColor}
|
159
|
-
onChange={(e) => setLineColor(e.target.value)}
|
160
|
-
/>
|
161
|
-
</td>
|
162
|
-
</tr>
|
163
|
-
</tbody>
|
164
|
-
<tbody>
|
165
|
-
<tr className="h-2.5 sm:h-auto"/>
|
166
|
-
<tr className="flex flex-col sm:flex-row">
|
167
|
-
<button type="button" onClick={async () => species ? deleteAllSpecies() : await createEmptySpecies()}>
|
168
|
-
{codeText("nvbtn00" + (species ? "_0" : ""), language)}
|
169
|
-
</button>
|
170
|
-
<div className="h-2.5 sm:w-2.5 sm:h-auto"/>
|
171
|
-
<button type="button" onClick={showExample}>
|
172
|
-
{codeText("nvbtn01", language)}
|
173
|
-
</button>
|
174
|
-
<div className="h-2.5 sm:w-2.5 sm:h-auto"/>
|
175
|
-
<button onClick={async () => await species?.saveJSON()} disabled={!species}>
|
176
|
-
{codeText("nvbtn02", language)}
|
177
|
-
</button>
|
178
|
-
</tr>
|
179
|
-
</tbody>
|
180
|
-
</table>
|
181
|
-
<div className="h-2.5 sm:w-2.5 sm:h-auto"/>
|
182
|
-
<table className="flex flex-col justify-start text-start hidden sm:block">
|
183
|
-
<tbody>
|
184
|
-
<LanguageSelector
|
185
|
-
languages={languages}
|
186
|
-
language={language}
|
187
|
-
setLanguage={setLanguage}
|
188
|
-
/>
|
189
|
-
<tr className="h-2.5"/>
|
190
|
-
<tr>
|
191
|
-
<td>{codeText("nvlbl02", language)}:</td>
|
192
|
-
<td>
|
193
|
-
<input
|
194
|
-
type="color"
|
195
|
-
value={lineColor}
|
196
|
-
onChange={(e) => setLineColor(e.target.value)}
|
197
|
-
/>
|
198
|
-
</td>
|
199
|
-
</tr>
|
200
|
-
</tbody>
|
201
|
-
</table>
|
202
|
-
</nav>
|
203
|
-
);
|
204
|
-
}
|
205
|
-
|
206
|
-
interface NavBarProps {
|
207
|
-
species?: Species;
|
208
|
-
color: string;
|
209
|
-
lineColor: string;
|
210
|
-
setLineColor: (lineColor: string) => void;
|
211
|
-
language: string;
|
212
|
-
languages: Map<string, string>;
|
213
|
-
setLanguage: (language: string) => void;
|
214
|
-
minScale?: number;
|
215
|
-
maxScale: number;
|
216
|
-
scale: number;
|
217
|
-
setScale: (scale: number) => void;
|
218
|
-
showScaleNumber: boolean;
|
219
|
-
chronoScale: boolean;
|
220
|
-
setChronoScale: (chronoScale: boolean) => void;
|
221
|
-
showHover: boolean;
|
222
|
-
setShowHover: (showHover: boolean) => void;
|
223
|
-
showImages: boolean;
|
224
|
-
setShowImages: (showImages: boolean) => void;
|
225
|
-
presentTime: number;
|
226
|
-
setPresentTime: (presentTime: number) => void;
|
227
|
-
presentTimeBoolean: boolean;
|
228
|
-
setPresentTimeBoolean: (presentTimeBoolean: boolean) => void;
|
229
|
-
changePresentTime: (presentTime: number) => void;
|
230
|
-
setFromJson: (file: File | undefined) => Promise<void>;
|
231
|
-
deleteAllSpecies: () => void;
|
232
|
-
createEmptySpecies: () => Promise<void>;
|
233
|
-
showExample: () => void;
|
234
|
-
}
|
@@ -1,362 +0,0 @@
|
|
1
|
-
import { useEffect, useState } from "react";
|
2
|
-
import { Species } from "../classes/Species";
|
3
|
-
|
4
|
-
interface MultiplePhTreesProps {
|
5
|
-
speciesList: Species[];
|
6
|
-
width?: number;
|
7
|
-
height?: number;
|
8
|
-
padding?: number;
|
9
|
-
stroke?: string;
|
10
|
-
format?: (n: number) => string;
|
11
|
-
chronoScale?: boolean;
|
12
|
-
showImages?: boolean;
|
13
|
-
presentTime?: number;
|
14
|
-
handleMouseMove?: (x: number, y: number) => void;
|
15
|
-
children?: (
|
16
|
-
species: Species | undefined,
|
17
|
-
showMenu: boolean,
|
18
|
-
toggleShowMenu: (species: Species) => void,
|
19
|
-
hoverSpecies: Species | undefined
|
20
|
-
) => any;
|
21
|
-
}
|
22
|
-
|
23
|
-
export const MultiplePhTrees = (
|
24
|
-
{
|
25
|
-
speciesList,
|
26
|
-
width = 1000,
|
27
|
-
height = 50,
|
28
|
-
padding = 0,
|
29
|
-
stroke = "grey",
|
30
|
-
format = (n) => n.toString(),
|
31
|
-
chronoScale = true,
|
32
|
-
showImages = true,
|
33
|
-
presentTime,
|
34
|
-
handleMouseMove,
|
35
|
-
children
|
36
|
-
}: MultiplePhTreesProps
|
37
|
-
) => {
|
38
|
-
const copies = speciesList.map(sp => sp.copy());
|
39
|
-
const lifeApparition = Math.min(...copies.map(sp => sp.apparition));
|
40
|
-
const lifeApparitionDuration = Math.max(...copies.map(sp => sp.apparition - lifeApparition));
|
41
|
-
const life = new Species(
|
42
|
-
"",
|
43
|
-
lifeApparition,
|
44
|
-
lifeApparitionDuration,
|
45
|
-
undefined,
|
46
|
-
[]
|
47
|
-
);
|
48
|
-
life.display = false;
|
49
|
-
life.linkDescendants(copies);
|
50
|
-
return (
|
51
|
-
<PhTree
|
52
|
-
commonAncestor={life}
|
53
|
-
width={width}
|
54
|
-
height={height}
|
55
|
-
padding={padding}
|
56
|
-
stroke={stroke}
|
57
|
-
format={format}
|
58
|
-
chronoScale={chronoScale}
|
59
|
-
showImages={showImages}
|
60
|
-
presentTime={presentTime}
|
61
|
-
handleMouseMove={handleMouseMove}
|
62
|
-
>
|
63
|
-
{(species, showMenu, toggleShowMenu, hoverSpecies) => children?.(species, showMenu, toggleShowMenu, hoverSpecies)}
|
64
|
-
</PhTree>
|
65
|
-
);
|
66
|
-
};
|
67
|
-
|
68
|
-
interface PhTreeProps {
|
69
|
-
commonAncestor: Species;
|
70
|
-
width?: number;
|
71
|
-
height?: number;
|
72
|
-
padding?: number;
|
73
|
-
stroke?: string;
|
74
|
-
format?: (n: number) => string;
|
75
|
-
chronoScale?: boolean;
|
76
|
-
showImages?: boolean;
|
77
|
-
presentTime?: number;
|
78
|
-
handleMouseMove?: (x: number, y: number) => void;
|
79
|
-
children?: (
|
80
|
-
species: Species | undefined,
|
81
|
-
showMenu: boolean,
|
82
|
-
toggleShowMenu: (species: Species) => void,
|
83
|
-
hoverSpecies: Species | undefined
|
84
|
-
) => any;
|
85
|
-
}
|
86
|
-
|
87
|
-
export const PhTree = (
|
88
|
-
{
|
89
|
-
commonAncestor,
|
90
|
-
width = 1000,
|
91
|
-
height = 50,
|
92
|
-
padding = 0,
|
93
|
-
stroke = "grey",
|
94
|
-
format = (n) => n.toString(),
|
95
|
-
chronoScale = true,
|
96
|
-
showImages = true,
|
97
|
-
presentTime,
|
98
|
-
handleMouseMove,
|
99
|
-
children
|
100
|
-
}: PhTreeProps
|
101
|
-
) => {
|
102
|
-
const [showMenu, setShowMenu] = useState(false);
|
103
|
-
const [species, setSpecies] = useState<Species | undefined>(undefined);
|
104
|
-
const [hoverSpecies, setHoverSpecies] = useState<Species | undefined>(undefined);
|
105
|
-
const [showDesc, setShowDesc] = useState<Map<Species, boolean>>(commonAncestor.allDescendants().reduce((acc, desc) => acc.set(desc, true), new Map()));
|
106
|
-
|
107
|
-
useEffect(() => {
|
108
|
-
setShowDesc(commonAncestor.allDescendants().reduce((acc, desc) => acc.set(desc, true), new Map()));
|
109
|
-
}, [commonAncestor]);
|
110
|
-
|
111
|
-
const toggleShowMenu = (sp: Species) => {
|
112
|
-
setSpecies(showMenu ? undefined : sp);
|
113
|
-
setShowMenu(!showMenu);
|
114
|
-
};
|
115
|
-
|
116
|
-
const toggleShowDesc = (sp: Species) => {
|
117
|
-
const newShowDesc = new Map(showDesc);
|
118
|
-
newShowDesc.set(sp, !showDesc.get(sp));
|
119
|
-
setShowDesc(newShowDesc);
|
120
|
-
};
|
121
|
-
|
122
|
-
const hoverShowMenu = (sp: Species | undefined) => {
|
123
|
-
setHoverSpecies(sp);
|
124
|
-
};
|
125
|
-
|
126
|
-
const isPresentTimeDefined = presentTime !== undefined && chronoScale;
|
127
|
-
const heightFactor = (ad: Species[]) => showImages ? ad.map<number>(sp => sp.image ? 2 : 1).reduce((a, b) => a + b) : ad.length;
|
128
|
-
|
129
|
-
return (
|
130
|
-
<>
|
131
|
-
<svg
|
132
|
-
width={width * (isPresentTimeDefined ? (Math.min(presentTime, commonAncestor.absoluteExtinction()) - commonAncestor.apparition) / commonAncestor.absoluteDuration() : 1)}
|
133
|
-
height={height * heightFactor(isPresentTimeDefined ? commonAncestor.allDescendants().filter(desc => desc.apparition < presentTime) : commonAncestor.allDescendants())}
|
134
|
-
onMouseMove={(event) => {handleMouseMove?.(event.clientX, event.clientY)}}
|
135
|
-
>
|
136
|
-
<DrawTree
|
137
|
-
commonAncestor={commonAncestor}
|
138
|
-
species={commonAncestor}
|
139
|
-
y={-1}
|
140
|
-
scaleX={width / (chronoScale ? commonAncestor.absoluteDuration() : (Math.max(0, commonAncestor.stepsUntilLastDescendant()) + 1))}
|
141
|
-
scaleY={height}
|
142
|
-
padding={padding}
|
143
|
-
stroke={stroke}
|
144
|
-
format={format}
|
145
|
-
chronoScale={chronoScale}
|
146
|
-
showImages={showImages}
|
147
|
-
presentTime={presentTime}
|
148
|
-
toggleShowMenu={toggleShowMenu}
|
149
|
-
hoverShowMenu={hoverShowMenu}
|
150
|
-
showDesc={showDesc}
|
151
|
-
changeShowDesc={toggleShowDesc}
|
152
|
-
/>
|
153
|
-
</svg>
|
154
|
-
{children?.(species, showMenu, toggleShowMenu, hoverSpecies)}
|
155
|
-
</>
|
156
|
-
);
|
157
|
-
};
|
158
|
-
|
159
|
-
interface DrawTreeProps {
|
160
|
-
commonAncestor: Species;
|
161
|
-
species: Species;
|
162
|
-
y: number;
|
163
|
-
scaleX: number;
|
164
|
-
scaleY: number;
|
165
|
-
padding?: number;
|
166
|
-
stroke?: string;
|
167
|
-
format?: (n: number) => string;
|
168
|
-
chronoScale?: boolean;
|
169
|
-
showImages?: boolean;
|
170
|
-
presentTime?: number;
|
171
|
-
toggleShowMenu: (s: Species) => void;
|
172
|
-
hoverShowMenu: (s: Species | undefined) => void;
|
173
|
-
showDesc: Map<Species, boolean>;
|
174
|
-
changeShowDesc: (s: Species) => void;
|
175
|
-
}
|
176
|
-
|
177
|
-
const DrawTree = ({
|
178
|
-
commonAncestor,
|
179
|
-
species,
|
180
|
-
y,
|
181
|
-
scaleX,
|
182
|
-
scaleY,
|
183
|
-
padding = 0,
|
184
|
-
stroke = "grey",
|
185
|
-
format = (n: number) => n.toString(),
|
186
|
-
chronoScale = true,
|
187
|
-
showImages = true,
|
188
|
-
presentTime = undefined,
|
189
|
-
toggleShowMenu,
|
190
|
-
hoverShowMenu,
|
191
|
-
showDesc,
|
192
|
-
changeShowDesc
|
193
|
-
}: DrawTreeProps) => {
|
194
|
-
const isPresentTimeDefined = presentTime !== undefined && chronoScale;
|
195
|
-
const all = commonAncestor.allDescendants().filter(desc => isPresentTimeDefined ? desc.apparition < presentTime : true);
|
196
|
-
const spIndex = all.indexOf(species);
|
197
|
-
const startX = (chronoScale ? species.apparition - commonAncestor.apparition : (commonAncestor.stepsUntil(species) ?? 0)) * scaleX;
|
198
|
-
const endX = startX + (chronoScale ? Math.min(showDesc.get(species) ? species.duration : species.absoluteDuration(), isPresentTimeDefined ? presentTime - species.apparition : species.absoluteDuration()) : 1) * scaleX;
|
199
|
-
const endY = (showImages && spIndex > 0) ? [...Array(spIndex).keys()].map(i => all[i]).map(sp => (sp.image ? 2 : 1) * scaleY).reduce((a, b) => a + b) : (spIndex * scaleY);
|
200
|
-
const descendants = species.descendants.filter(desc => isPresentTimeDefined ? desc.apparition < presentTime : true);
|
201
|
-
const branchX = descendants.length > 0 ? startX + (Math.min(...descendants.map(desc => desc.apparition)) - species.apparition) * scaleX : endX;
|
202
|
-
|
203
|
-
return (
|
204
|
-
<g key={spIndex}>
|
205
|
-
{y >= 0 && (
|
206
|
-
<line
|
207
|
-
x1={startX}
|
208
|
-
y1={y}
|
209
|
-
x2={startX}
|
210
|
-
y2={endY}
|
211
|
-
stroke={stroke}
|
212
|
-
/>
|
213
|
-
)}
|
214
|
-
{species.display && <HorizontalLine
|
215
|
-
commonAncestor={commonAncestor}
|
216
|
-
species={species}
|
217
|
-
height={scaleY}
|
218
|
-
x1={startX}
|
219
|
-
x2={endX}
|
220
|
-
x0={branchX}
|
221
|
-
y={endY}
|
222
|
-
stroke={stroke}
|
223
|
-
changeShowDesc={() => changeShowDesc(species)}
|
224
|
-
showDesc={showDesc.get(species)}
|
225
|
-
padding={padding}
|
226
|
-
format={format}
|
227
|
-
chronoScale={chronoScale}
|
228
|
-
showImages={showImages}
|
229
|
-
presentTime={presentTime}
|
230
|
-
toggleShowMenu={toggleShowMenu}
|
231
|
-
hoverShowMenu={hoverShowMenu}
|
232
|
-
/>}
|
233
|
-
{species.descendants.map((desc, index) => (
|
234
|
-
<g className={(showDesc.get(species) && descendants.includes(desc)) ? "block" : "hidden"} key={all.length + index}>
|
235
|
-
<DrawTree
|
236
|
-
commonAncestor={commonAncestor}
|
237
|
-
species={desc}
|
238
|
-
y={desc.display ? endY : -1}
|
239
|
-
scaleX={scaleX}
|
240
|
-
scaleY={scaleY}
|
241
|
-
padding={padding}
|
242
|
-
stroke={stroke}
|
243
|
-
format={format}
|
244
|
-
chronoScale={chronoScale}
|
245
|
-
showImages={showImages}
|
246
|
-
presentTime={presentTime}
|
247
|
-
toggleShowMenu={toggleShowMenu}
|
248
|
-
showDesc={showDesc}
|
249
|
-
changeShowDesc={changeShowDesc}
|
250
|
-
hoverShowMenu={hoverShowMenu}
|
251
|
-
/>
|
252
|
-
</g>
|
253
|
-
))}
|
254
|
-
</g>
|
255
|
-
);
|
256
|
-
};
|
257
|
-
|
258
|
-
interface HorizontalLineProps {
|
259
|
-
commonAncestor: Species;
|
260
|
-
species: Species;
|
261
|
-
height: number;
|
262
|
-
x1: number;
|
263
|
-
x2: number;
|
264
|
-
x0?: number;
|
265
|
-
y: number;
|
266
|
-
stroke: string;
|
267
|
-
showDesc?: boolean;
|
268
|
-
changeShowDesc?: () => void;
|
269
|
-
padding?: number;
|
270
|
-
format?: (n: number) => string;
|
271
|
-
chronoScale?: boolean;
|
272
|
-
showImages?: boolean;
|
273
|
-
presentTime?: number;
|
274
|
-
toggleShowMenu: (s: Species) => void;
|
275
|
-
hoverShowMenu: (s: Species | undefined) => void;
|
276
|
-
className?: string;
|
277
|
-
buttonClassName?: string;
|
278
|
-
}
|
279
|
-
|
280
|
-
const HorizontalLine = ({
|
281
|
-
commonAncestor,
|
282
|
-
species,
|
283
|
-
height,
|
284
|
-
x1, x2, x0, y,
|
285
|
-
stroke,
|
286
|
-
showDesc = true,
|
287
|
-
changeShowDesc = () => {},
|
288
|
-
padding = 0,
|
289
|
-
format = (n) => n.toString(),
|
290
|
-
chronoScale = true,
|
291
|
-
showImages = true,
|
292
|
-
presentTime,
|
293
|
-
toggleShowMenu,
|
294
|
-
hoverShowMenu,
|
295
|
-
className,
|
296
|
-
buttonClassName
|
297
|
-
}: HorizontalLineProps) => {
|
298
|
-
const isPresentTimeDefined = presentTime !== undefined;
|
299
|
-
const all = commonAncestor.allDescendants().filter(desc => isPresentTimeDefined ? desc.apparition < presentTime : true);
|
300
|
-
const index = (s: Species) => all.indexOf(s);
|
301
|
-
const orientation = species.ancestor ? (index(species) > index(species.ancestor) ? -3 : 1) : 1;
|
302
|
-
const descendants = species.descendants.filter(desc => isPresentTimeDefined ? desc.apparition < presentTime : true);
|
303
|
-
const lastOne = descendants.filter(desc => desc.apparition === species.extinction()).length === 0;
|
304
|
-
const extinction = format(Math.min(showDesc ? species.extinction() : species.absoluteExtinction(), isPresentTimeDefined ? presentTime : species.absoluteExtinction()));
|
305
|
-
return (
|
306
|
-
<g>
|
307
|
-
<line
|
308
|
-
x1={x1}
|
309
|
-
y1={y}
|
310
|
-
x2={x2}
|
311
|
-
y2={y}
|
312
|
-
stroke={stroke}
|
313
|
-
/>
|
314
|
-
<foreignObject
|
315
|
-
x={x1 + padding}
|
316
|
-
y={y + (padding) * orientation}
|
317
|
-
width={(chronoScale ? x0 ?? x2 : x2) - x1 - 2 * padding}
|
318
|
-
height={height + (showImages && species.image ? height : 0)}
|
319
|
-
>
|
320
|
-
<div className={`flex flex-row justify-between w-full ${className ?? ""}`}>
|
321
|
-
<div>
|
322
|
-
{chronoScale ? format(species.apparition) : ""}
|
323
|
-
</div>
|
324
|
-
<button
|
325
|
-
className={`p-0.625 justify-center flex flex-col items-center ${buttonClassName ?? ""}`}
|
326
|
-
onClick={() => toggleShowMenu(species)}
|
327
|
-
onMouseEnter={() => hoverShowMenu(species)}
|
328
|
-
onMouseLeave={() => hoverShowMenu(undefined)}
|
329
|
-
>
|
330
|
-
{species.name}
|
331
|
-
{species.image && showImages && (
|
332
|
-
<img
|
333
|
-
src={species.image}
|
334
|
-
alt={species.name}
|
335
|
-
style={{ height: height }}
|
336
|
-
/>
|
337
|
-
)}
|
338
|
-
</button>
|
339
|
-
{descendants.length > 0 ?
|
340
|
-
<button onClick={changeShowDesc} className="h-1" style={{maxWidth: 4}}>
|
341
|
-
{((lastOne || !showDesc) && (!x0 || x0 === x2)) ? extinction : ""}
|
342
|
-
</button> :
|
343
|
-
<div>
|
344
|
-
{chronoScale ? extinction : ""}
|
345
|
-
</div>
|
346
|
-
}
|
347
|
-
</div>
|
348
|
-
</foreignObject>
|
349
|
-
{chronoScale && x0 && x0 < x2 && (
|
350
|
-
<foreignObject
|
351
|
-
x={x0 + padding}
|
352
|
-
y={y + padding * orientation}
|
353
|
-
width={x2 - x0 - 2 * padding}
|
354
|
-
height={height}
|
355
|
-
>
|
356
|
-
<div className="flex flex-row justify-end w-full">
|
357
|
-
{(lastOne || !showDesc) && chronoScale ? extinction : ""}
|
358
|
-
</div>
|
359
|
-
</foreignObject>)}
|
360
|
-
</g>
|
361
|
-
);
|
362
|
-
}
|
package/src/index.css
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
:root {
|
2
|
-
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
3
|
-
line-height: 1.5;
|
4
|
-
font-weight: 400;
|
5
|
-
|
6
|
-
color-scheme: light dark;
|
7
|
-
color: rgba(255, 255, 255, 0.87);
|
8
|
-
background-color: #242424;
|
9
|
-
|
10
|
-
font-synthesis: none;
|
11
|
-
text-rendering: optimizeLegibility;
|
12
|
-
-webkit-font-smoothing: antialiased;
|
13
|
-
-moz-osx-font-smoothing: grayscale;
|
14
|
-
}
|
15
|
-
|
16
|
-
a {
|
17
|
-
font-weight: 500;
|
18
|
-
color: #646cff;
|
19
|
-
text-decoration: inherit;
|
20
|
-
}
|
21
|
-
a:hover {
|
22
|
-
color: #535bf2;
|
23
|
-
}
|
24
|
-
|
25
|
-
body {
|
26
|
-
margin: 0;
|
27
|
-
display: flex;
|
28
|
-
place-items: center;
|
29
|
-
min-width: 320px;
|
30
|
-
min-height: 100vh;
|
31
|
-
}
|
32
|
-
|
33
|
-
h1 {
|
34
|
-
font-size: 3.2em;
|
35
|
-
line-height: 1.1;
|
36
|
-
}
|
37
|
-
|
38
|
-
button {
|
39
|
-
border-radius: 8px;
|
40
|
-
border: 1px solid transparent;
|
41
|
-
padding: 0.6em 1.2em;
|
42
|
-
font-size: 1em;
|
43
|
-
font-weight: 500;
|
44
|
-
font-family: inherit;
|
45
|
-
background-color: #1a1a1a;
|
46
|
-
cursor: pointer;
|
47
|
-
transition: border-color 0.25s;
|
48
|
-
}
|
49
|
-
button:hover {
|
50
|
-
border-color: #646cff;
|
51
|
-
}
|
52
|
-
button:focus,
|
53
|
-
button:focus-visible {
|
54
|
-
outline: 4px auto -webkit-focus-ring-color;
|
55
|
-
}
|
56
|
-
|
57
|
-
@media (prefers-color-scheme: light) {
|
58
|
-
:root {
|
59
|
-
color: #213547;
|
60
|
-
background-color: #ffffff;
|
61
|
-
}
|
62
|
-
a:hover {
|
63
|
-
color: #747bff;
|
64
|
-
}
|
65
|
-
button {
|
66
|
-
background-color: #f9f9f9;
|
67
|
-
}
|
68
|
-
}
|
package/src/index.ts
DELETED
package/src/main.tsx
DELETED
package/src/types.d.ts
DELETED
package/src/utils/between.tsx
DELETED