Passed
Push — master ( 5db84c...83abc2 )
by
unknown
03:00 queued 14s
created

src/utils/helpers/UserEventHelpers.ts   A

Complexity

Total Complexity 15
Complexity/F 3.75

Size

Lines of Code 126
Function Count 4

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 15
eloc 99
mnd 11
bc 11
fnc 4
dl 0
loc 126
rs 10
bpm 2.75
cpm 3.75
noi 0
c 0
b 0
f 0

4 Functions

Rating   Name   Duplication   Size   Complexity  
A UserEventHelpers.ts ➔ subscribeToZoomOnArrowKey 0 15 4
A UserEventHelpers.ts ➔ subscribeToResetHighlight 0 24 3
B UserEventHelpers.ts ➔ subscribeToChangeHighlightRangeOnArrowKey 0 41 6
A UserEventHelpers.ts ➔ subscribeToHighlight 0 9 2
1
import { event, select } from 'd3-selection';
2
import { DependencyNode } from '../../components/types';
3
import {
4
    centerScreenToDimension,
5
    changeZoom,
6
    findGroupBackgroundDimension,
7
    findMaxDependencyLevel,
8
    getHighLightedLabelColor,
9
    hideHighlightBackground,
10
    highlight,
11
    LevelStorage,
12
    selectAllNodes,
13
    selectHighLightedNodes,
14
    zoomToHighLightedNodes,
15
} from './GraphHelpers';
16
import { LabelColors, MAXIMUM_ZOOM_SCALE, MINIMUM_ZOOM_SCALE, Selectors, TextColors } from '../AppConsts';
17
import { zoom, zoomIdentity } from 'd3-zoom';
18
19
enum Subscriptions {
20
    HIGHLIGHT = 'click.highlight',
21
    RESET_HIGHLIGHT = 'click.resetHighlight',
22
    CHANGE_HIGHLIGHT_RANGE = 'keydown.changeHighlightRange',
23
    ZOOM_ON_ARROW_KEY = 'keydown.zoom',
24
}
25
26
export function subscribeToHighlight() {
27
    selectAllNodes().on(Subscriptions.HIGHLIGHT, (node: DependencyNode) => {
28
        LevelStorage.reset();
29
        if (node.links.length) {
30
            highlight(node);
31
            zoomToHighLightedNodes();
32
        }
33
        event.stopPropagation();
34
    });
35
}
36
37
export function subscribeToChangeHighlightRangeOnArrowKey() {
38
    select('body').on(Subscriptions.CHANGE_HIGHLIGHT_RANGE, () => {
39
        const labelNodesGroup = select<SVGGElement, DependencyNode>('g#labels');
40
        LevelStorage.setMaxLevel(findMaxDependencyLevel(labelNodesGroup));
41
42
        if (!isFinite(LevelStorage.getMaxLevel())) {
43
            return;
44
        }
45
46
        if (LevelStorage.isBelowMax() && event.code === 'ArrowRight') {
47
            LevelStorage.increase();
48
        }
49
50
        if (LevelStorage.isAboveMin() && event.code === 'ArrowLeft') {
51
            LevelStorage.decrease();
52
        }
53
54
        // TODO refactor it to share logic with GraphHelpers/highlight function
55
        labelNodesGroup
56
            .selectAll<HTMLElement, DependencyNode>('g')
57
            .filter((node: DependencyNode) => node.level > 0)
58
            .each(function(this: HTMLElement, node: DependencyNode) {
59
                const labelElement = this.firstElementChild;
60
                const textElement = this.lastElementChild;
61
62
                if (!labelElement || !textElement) {
63
                    return;
64
                }
65
66
                let labelColor = LabelColors.DEFAULT;
67
                let textColor = TextColors.DEFAULT;
68
                if (node.level - 1 <= LevelStorage.getLevel()) {
69
                    labelColor = getHighLightedLabelColor(node);
70
                    textColor = TextColors.HIGHLIGHTED;
71
                }
72
73
                select<Element, DependencyNode>(labelElement).attr('fill', labelColor);
74
                select<Element, DependencyNode>(textElement).style('fill', textColor);
75
            });
76
77
        zoomToHighLightedNodes();
78
    });
79
}
80
81
export function subscribeToResetHighlight() {
82
    select(Selectors.CONTAINER).on(Subscriptions.RESET_HIGHLIGHT, () => {
83
        const highlightedNodes = selectHighLightedNodes();
84
        if (highlightedNodes.data().length) {
85
            selectAllNodes().each((node: DependencyNode) => (node.level = 0));
86
87
            const dimension = findGroupBackgroundDimension(highlightedNodes.data());
88
89
            highlightedNodes.each(function(this: SVGGElement) {
90
                const labelElement = this.firstElementChild;
91
                const textElement = this.lastElementChild;
92
93
                if (!labelElement || !textElement) {
94
                    return;
95
                }
96
97
                select<Element, DependencyNode>(labelElement).attr('fill', LabelColors.DEFAULT);
98
                select<Element, DependencyNode>(textElement).style('fill', TextColors.DEFAULT);
99
            });
100
101
            hideHighlightBackground();
102
103
            centerScreenToDimension(dimension, 1);
104
        }
105
    });
106
}
107
108
export function subscribeToZoomOnArrowKey() {
109
    select('body').on(Subscriptions.ZOOM_ON_ARROW_KEY, () => {
110
        if (event.code === 'ArrowUp' || event.code === 'ArrowDown') {
111
            const scaleMultiplier = event.code === 'ArrowUp' ? 1.25 : 0.8;
112
            const zoomLayer = select(Selectors.ZOOM);
113
            const oldScaleValue = Number(zoomLayer.attr('data-scale')) || 1;
114
            const scaleValue = oldScaleValue * scaleMultiplier;
115
            if (scaleValue <= MAXIMUM_ZOOM_SCALE && scaleValue >= MINIMUM_ZOOM_SCALE) {
116
                const container = select(Selectors.CONTAINER);
117
                container.call(() => {
118
                    return zoom<any, any>()
119
                        .on('zoom.key', changeZoom)
120
                        .scaleBy(container, scaleMultiplier);
121
                }, zoomIdentity);
122
            }
123
        }
124
    });
125
}
126