diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/App.vue | 68 | ||||
| -rw-r--r-- | src/components/Tile.vue | 2 | ||||
| -rw-r--r-- | src/components/TileInfoModal.vue | 2 | ||||
| -rw-r--r-- | src/components/TutorialPane.vue | 76 | ||||
| -rw-r--r-- | src/layout.ts | 2 | ||||
| -rw-r--r-- | src/lib.ts (renamed from src/util.ts) | 21 |
6 files changed, 129 insertions, 42 deletions
diff --git a/src/App.vue b/src/App.vue index 66d9a9c..5fdd279 100644 --- a/src/App.vue +++ b/src/App.vue @@ -18,7 +18,7 @@ import type {TolMap} from './tol'; import {TolNode} from './tol'; import {LayoutNode, initLayoutTree, initLayoutMap, tryLayout} from './layout'; import type {LayoutOptions, LayoutTreeChg} from './layout'; -import {arraySum, randWeightedChoice, getScrollBarWidth} from './util'; +import {EnabledFeatures, arraySum, randWeightedChoice, getScrollBarWidth} from './lib'; // Note: Import paths lack a .ts or .js extension because .ts makes vue-tsc complain, and .js makes vite complain // Type representing auto-mode actions @@ -109,6 +109,7 @@ export default defineComponent({ searchOpen: false, settingsOpen: false, tutorialOpen: true, + enabledFeatures: new EnabledFeatures(), // For search and auto-mode modeRunning: false, lastFocused: null as LayoutNode | null, @@ -176,7 +177,7 @@ export default defineComponent({ return dims; }, ancestryBarPos(): [number, number] { - let pos = [0, 0]; + let pos = [0, 0] as [number, number]; if (this.tutorialOpen){ pos[1] += this.uiOpts.tutorialPaneSz; } @@ -184,7 +185,7 @@ export default defineComponent({ }, ancestryBarDims(): [number, number] { if (this.wideArea){ - let dims = [this.uiOpts.ancestryBarSz, this.height]; + let dims = [this.uiOpts.ancestryBarSz, this.height] as [number, number]; if (this.tutorialOpen){ dims[1] -= this.uiOpts.tutorialPaneSz; } @@ -200,6 +201,9 @@ export default defineComponent({ methods: { // For tile expand/collapse events onLeafClick(layoutNode: LayoutNode){ + if (!this.enabledFeatures.expand){ + return Promise.resolve(false); + } this.setLastFocused(null); // If clicking child of overflowing active-root if (this.overflownRoot){ @@ -249,6 +253,9 @@ export default defineComponent({ } }, onNonleafClick(layoutNode: LayoutNode){ + if (!this.enabledFeatures.collapse){ + return false; + } this.setLastFocused(null); let success = tryLayout(this.activeRoot, this.tileAreaPos, this.tileAreaDims, this.lytOpts, { allowCollapse: false, @@ -278,6 +285,9 @@ export default defineComponent({ }, // For expand-to-view and ancestry-bar events onLeafClickHeld(layoutNode: LayoutNode){ + if (!this.enabledFeatures.expandToView){ + return; + } this.setLastFocused(null); if (layoutNode == this.activeRoot){ this.onLeafClick(layoutNode); @@ -328,6 +338,9 @@ export default defineComponent({ } }, onNonleafClickHeld(layoutNode: LayoutNode){ + if (!this.enabledFeatures.expandToView){ + return; + } this.setLastFocused(null); if (layoutNode == this.activeRoot){ console.log('Ignored expand-to-view on active-root node'); @@ -339,6 +352,9 @@ export default defineComponent({ {allowCollapse: true, layoutMap: this.layoutMap}); }, onDetachedAncestorClick(layoutNode: LayoutNode){ + if (!this.enabledFeatures.unhideAncestor){ + return; + } this.setLastFocused(null); LayoutNode.showDownward(layoutNode); this.activeRoot = layoutNode; @@ -348,18 +364,19 @@ export default defineComponent({ }, // For tile-info events onInfoIconClick(nodeName: string){ + if (!this.enabledFeatures.infoIcon){ + return; + } if (!this.searchOpen){ this.resetMode(); } this.infoModalNodeName = nodeName; }, - // For help events - onHelpIconClick(){ - this.resetMode(); - this.helpOpen = true; - }, // For search events onSearchIconClick(){ + if (!this.enabledFeatures.search){ + return; + } this.resetMode(); this.searchOpen = true; }, @@ -427,6 +444,9 @@ export default defineComponent({ }, // For auto-mode events onPlayIconClick(){ + if (!this.enabledFeatures.autoMode){ + return; + } this.resetMode(); this.modeRunning = true; this.autoAction(); @@ -538,6 +558,9 @@ export default defineComponent({ }, // For settings events onSettingsIconClick(){ + if (!this.enabledFeatures.settings){ + return; + } this.resetMode(); this.settingsOpen = true; }, @@ -554,12 +577,25 @@ export default defineComponent({ // Re-initialise tree this.initTreeFromServer(); }, + // For help events + onHelpIconClick(){ + if (!this.enabledFeatures.help){ + return; + } + this.resetMode(); + this.helpOpen = true; + }, // For tutorial events onTutorialClose(){ this.tutorialOpen = false; + this.enabledFeatures = new EnabledFeatures(); tryLayout(this.activeRoot, this.tileAreaPos, this.tileAreaDims, this.lytOpts, {allowCollapse: true, layoutMap: this.layoutMap}); }, + onSetEnabledFeatures(x: EnabledFeatures){ + this.enabledFeatures = x; + this.resetMode(); + }, // For other events onResize(){ if (this.pendingResizeHdlr == 0){ @@ -654,19 +690,19 @@ export default defineComponent({ :tolMap="tolMap" :lytOpts="lytOpts" :uiOpts="uiOpts" @detached-ancestor-click="onDetachedAncestorClick" @info-icon-click="onInfoIconClick"/> <tutorial-pane v-if="tutorialOpen" :pos="[0,0]" :dims="tutorialPaneDims" :uiOpts="uiOpts" - @tutorial-close="onTutorialClose"/> + @tutorial-close="onTutorialClose" @set-enabled-features="onSetEnabledFeatures"/> <!-- Icons --> - <help-icon @click="onHelpIconClick" - class="absolute bottom-[6px] right-[6px] w-[18px] h-[18px] + <search-icon @click="onSearchIconClick" + class="absolute bottom-[6px] right-[78px] w-[18px] h-[18px] + text-white/40 hover:text-white hover:cursor-pointer"/> + <play-icon @click="onPlayIconClick" + class="absolute bottom-[6px] right-[54px] w-[18px] h-[18px] text-white/40 hover:text-white hover:cursor-pointer"/> <settings-icon @click="onSettingsIconClick" class="absolute bottom-[6px] right-[30px] w-[18px] h-[18px] text-white/40 hover:text-white hover:cursor-pointer"/> - <search-icon @click="onSearchIconClick" - class="absolute bottom-[6px] right-[54px] w-[18px] h-[18px] - text-white/40 hover:text-white hover:cursor-pointer"/> - <play-icon @click="onPlayIconClick" - class="absolute bottom-[6px] right-[78px] w-[18px] h-[18px] + <help-icon @click="onHelpIconClick" + class="absolute bottom-[6px] right-[6px] w-[18px] h-[18px] text-white/40 hover:text-white hover:cursor-pointer"/> <!-- Modals --> <transition name="fade"> diff --git a/src/components/Tile.vue b/src/components/Tile.vue index 7f15f3c..73a5c92 100644 --- a/src/components/Tile.vue +++ b/src/components/Tile.vue @@ -5,7 +5,7 @@ import {LayoutNode} from '../layout'; import type {LayoutOptions} from '../layout'; import type {TolMap} from '../tol'; import {TolNode} from '../tol'; -import {capitalizeWords} from '../util'; +import {capitalizeWords} from '../lib'; // Displays one, or a hierarchy of, tree-of-life nodes, as a 'tile' export default defineComponent({ diff --git a/src/components/TileInfoModal.vue b/src/components/TileInfoModal.vue index 904b2e7..55d95b4 100644 --- a/src/components/TileInfoModal.vue +++ b/src/components/TileInfoModal.vue @@ -6,7 +6,7 @@ import {LayoutNode} from '../layout'; import type {LayoutOptions} from '../layout'; import type {TolMap} from '../tol'; import {TolNode} from '../tol'; -import {capitalizeWords} from '../util'; +import {capitalizeWords} from '../lib'; type DescInfo = {text: string, fromRedirect: boolean, wikiId: number, fromDbp: boolean}; type ImgInfo = {eolId: string, sourceUrl: string, license: string, copyrightOwner: string} diff --git a/src/components/TutorialPane.vue b/src/components/TutorialPane.vue index e027857..37c5832 100644 --- a/src/components/TutorialPane.vue +++ b/src/components/TutorialPane.vue @@ -1,6 +1,7 @@ <script lang="ts"> import {defineComponent, PropType} from 'vue'; import CloseIcon from './icon/CloseIcon.vue'; +import {EnabledFeatures} from '../lib'; export default defineComponent({ props: { @@ -26,7 +27,7 @@ export default defineComponent({ color: this.uiOpts.tutorialPaneTextColor, }; }, - tutContentStyles(): Record<string,string> { + contentStyles(): Record<string,string> { return { padding: '0 0.5cm', maxWidth: '15cm', @@ -45,95 +46,126 @@ export default defineComponent({ }, }, methods: { + onStartTutorial(){ + this.stage = 1; + this.sendEnabledFeatures(); + }, onPrevClick(){ this.stage = Math.max(1, this.stage - 1); + this.sendEnabledFeatures(); }, onNextClick(){ this.stage = Math.min(this.maxStage, this.stage + 1); + this.sendEnabledFeatures(); + }, + onClose(){ + this.$emit('set-enabled-features', new EnabledFeatures()); + this.$emit('tutorial-close'); + }, + sendEnabledFeatures(){ + let x = new EnabledFeatures(); + switch (this.stage){ + case 1: + case 2: x.collapse = false; + case 3: x.expandToView = false; + case 4: x.unhideAncestor = false; + case 5: x.infoIcon = false; + case 6: x.search = false; + case 7: x.autoMode = false; + case 8: x.settings = false; + case 9: x.help = false; + case 10: + } + this.$emit('set-enabled-features', x); }, }, components: {CloseIcon, }, - emits: ['tutorial-close', ], + emits: ['tutorial-close', 'set-enabled-features', ], }); </script> <template> <div :style="styles" class="flex flex-col justify-evenly"> + <close-icon @click.stop="onClose" + class="block absolute top-2 right-2 w-6 h-6 hover:cursor-pointer"/> <template v-if="stage == 0"> - <div :style="tutContentStyles"> + <h2 class="text-center">Welcome</h2> + <div :style="contentStyles"> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco. </div> <div class="w-full flex justify-evenly"> - <button :style="buttonStyles" class="hover:brightness-125" @click="stage = 1"> + <button :style="buttonStyles" class="hover:brightness-125" @click="onStartTutorial"> Start Tutorial </button> - <button :style="buttonStyles" class="hover:brightness-125" @click="$emit('tutorial-close')"> + <button :style="buttonStyles" class="hover:brightness-125" @click="onClose"> Continue </button> </div> </template> - <template v-if="stage > 0"> - <div v-if="stage == 1" :style="tutContentStyles"> + <template v-else> + <h2 class="text-center">Tutorial</h2> + <!-- Text content --> + <div v-if="stage == 1" :style="contentStyles"> Click/touch on the tile to expand it and see it's children. <br/> A green title means the tile has children. Orange and red mean 100+ or 1000+ children. If a clicked tile won't fit on screen, expansion fails. There is a way around this, which we'll describe later. </div> - <div v-else-if="stage == 2" :style="tutContentStyles"> + <div v-else-if="stage == 2" :style="contentStyles"> You can keep expanding tiles, and they are repositioned to try and save space, while still trying to maintain a stable layout, to avoid disorientation. </div> - <div v-else-if="stage == 3" :style="tutContentStyles"> + <div v-else-if="stage == 3" :style="contentStyles"> Click on an expanded tile's header to shrink it, hiding it's children You can keep exploring the tree this way, expanding and collapsing tiles as needed, to better show the groups you're interested in. </div> - <div v-else-if="stage == 4" :style="tutContentStyles"> + <div v-else-if="stage == 4" :style="contentStyles"> Eventually, you might run out of screen space, and be unable to go deeper. Click and hold on a tile to make it fill the view, and move it's ancestors to a sidebar. You can do the same thing on an expanded tile's header. </div> - <div v-else-if="stage == 5" :style="tutContentStyles"> + <div v-else-if="stage == 5" :style="contentStyles"> Click on a tile in the sidebar to bring it back into the main view. In this way, you can explore as deeply as you want, occasionally jumping back upward to explore a different ancestral branch. </div> - <div v-else-if="stage == 6" :style="tutContentStyles"> + <div v-else-if="stage == 6" :style="contentStyles"> Each tile has an info icon on the bottom right. Clicking on this brings up information about the corresponding biological taxon. <br/> A similar icon appears at the right end of each expanded-tile header. </div> - <div v-else-if="stage == 7" :style="tutContentStyles"> + <div v-else-if="stage == 7" :style="contentStyles"> The search icon allows for finding a particular tile, and bringing it into view. To stop the traversal, just click anywhere on screen. </div> - <div v-else-if="stage == 8" :style="tutContentStyles"> + <div v-else-if="stage == 8" :style="contentStyles"> The play icon enables 'auto mode', which continuously expands/collapses random tiles, until you click to make it stop. </div> - <div v-else-if="stage == 9" :style="tutContentStyles"> + <div v-else-if="stage == 9" :style="contentStyles"> The settings icon allows for adjusting the layout, among other things. <ul class="list-disc"> <li>The animation speed can be slowed down if you find the tile-repositioning hard to follow.</li> <li>The 'reduced tree' setting replaces the original tree with a simplified version.</li> </ul> </div> - <div v-else-if="stage == 10" :style="tutContentStyles"> + <div v-else-if="stage == 10" :style="contentStyles"> And finally, the help icon provides summarised usage information. </div> + <!-- Buttons --> <div class="w-full flex justify-evenly"> <button :style="buttonStyles" - :disabled="stage < 2" :class="stage < 2 ? ['brightness-75'] : ['hover:brightness-125']" + :disabled="stage == 1" :class="stage == 1 ? ['brightness-75'] : ['hover:brightness-125']" @click="onPrevClick"> - Previous + Prev </button> - <button :style="buttonStyles" - :disabled="stage == maxStage" :class="stage == maxStage ? ['brightness-75'] : ['hover:brightness-125']" - @click="onNextClick"> - Next + <button :style="buttonStyles" class="hover:brightness-125" + @click="(stage != maxStage) ? onNextClick() : onClose()"> + {{stage != maxStage ? 'Next' : 'Finish'}} </button> </div> </template> diff --git a/src/layout.ts b/src/layout.ts index f5873ca..7cec2a5 100644 --- a/src/layout.ts +++ b/src/layout.ts @@ -7,7 +7,7 @@ */ import type {TolMap} from './tol'; -import {range, arraySum, linspace, limitVals, updateAscSeq} from './util'; +import {range, arraySum, linspace, limitVals, updateAscSeq} from './lib'; // Represents a node/tree that holds layout data for a TolNode node/tree export class LayoutNode { @@ -1,5 +1,24 @@ + +/* + * Types + */ +export class EnabledFeatures { + // Expand/collapse + expand = true; + collapse = true; + // AncestorBar related + expandToView = true; + unhideAncestor = true; + // Other + infoIcon = true; + search = true; + autoMode = true; + settings = true; + help = true; +}; + /* - * Contains utility functions. + * General utility functions */ // Returns [0 ... len] |
