Skip to content

Commit

Permalink
#7 DSM-View - Show selected/hovered dependency in DSM panel
Browse files Browse the repository at this point in the history
  • Loading branch information
wuetherich committed Nov 14, 2019
1 parent 2735419 commit bf16e9f
Show file tree
Hide file tree
Showing 14 changed files with 271 additions and 70 deletions.
53 changes: 39 additions & 14 deletions slizaa-web/app/src/components/dsm/DSM.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import * as React from 'react';
import { setupCanvas } from './DpiFixer';
import './DSM.css';
import { DefaultColorScheme, IDsmColorScheme } from './IDsmColorScheme';
import {IDsmProps} from "./IDsmProps";
import {IDsmCell, IDsmProps, IDsmSelection} from "./IDsmProps";

export class DSM extends React.Component<IDsmProps, {}> {

Expand Down Expand Up @@ -50,7 +50,7 @@ export class DSM extends React.Component<IDsmProps, {}> {
private newlySelectedX: number | undefined;
private newlySelectedY: number | undefined;
private sccNodePositions: number[];
private matrixLabels: string[][];
private matrixElements: IDsmCell[][];

constructor(props: IDsmProps) {
super(props);
Expand All @@ -59,6 +59,16 @@ export class DSM extends React.Component<IDsmProps, {}> {
this.verticalSideMarkerWidth = props.verticalSideMarkerWidth;
}

public shouldComponentUpdate(nextProps: Readonly<IDsmProps>, nextState: Readonly<{}>, nextContext: any): boolean {
return nextProps.labels !== this.props.labels ||
nextProps.cells !== this.props.cells ||
nextProps.stronglyConnectedComponents !== this.props.stronglyConnectedComponents ||
nextProps.horizontalBoxSize !== this.props.horizontalBoxSize ||
nextProps.verticalBoxSize !== this.props.verticalBoxSize ||
nextProps.horizontalSideMarkerHeight !== this.props.horizontalSideMarkerHeight ||
nextProps.verticalSideMarkerWidth !== this.props.verticalSideMarkerWidth;
}

public componentWillReceiveProps(nextProps: IDsmProps) {
if (nextProps.horizontalSideMarkerHeight !== this.horizontalSideMarkerHeight ||
nextProps.verticalSideMarkerWidth !== this.verticalSideMarkerWidth) {
Expand Down Expand Up @@ -90,10 +100,15 @@ export class DSM extends React.Component<IDsmProps, {}> {
this.newlySelectedY = position[1];
requestAnimationFrame(this.updateMarkedLayer);
if (this.props.onSelect) {
this.props.onSelect(
this.newlySelectedX !== undefined ? this.props.labels[this.newlySelectedX].id : undefined,
this.newlySelectedY !== undefined ? this.props.labels[this.newlySelectedY].id : undefined,
);
const selection : IDsmSelection | undefined =
this.newlySelectedX !== undefined && this.newlySelectedY !== undefined ?
{
selectedCell: this.matrixElements[this.newlySelectedX][this.newlySelectedY],
sourceLabel: this.props.labels[this.newlySelectedY],
targetLabel: this.props.labels[this.newlySelectedX]
} :
undefined;
this.props.onSelect(selection);
}
}
}).bind(this)
Expand All @@ -109,6 +124,9 @@ export class DSM extends React.Component<IDsmProps, {}> {
this.newlyMarkedX = undefined;
this.newlyMarkedY = undefined;
requestAnimationFrame(this.updateMarkedLayer);
if (this.props.onHover) {
this.props.onHover(undefined);
}
}).bind(this)

this.markedCellLayerrenderingContext.canvas.onmousemove = ((event: MouseEvent) => {
Expand Down Expand Up @@ -169,10 +187,15 @@ export class DSM extends React.Component<IDsmProps, {}> {
this.newlyMarkedY = position[1];

if (this.props.onHover) {
this.props.onHover(
this.newlyMarkedX === undefined ? undefined : this.props.labels[this.newlyMarkedX].id ,
this.newlyMarkedY === undefined ? undefined : this.props.labels[this.newlyMarkedY].id ,
);
const selection : IDsmSelection | undefined =
this.newlyMarkedX !== undefined && this.newlyMarkedY !== undefined ?
{
selectedCell: this.matrixElements[this.newlyMarkedX][this.newlyMarkedY],
sourceLabel: this.props.labels[this.newlyMarkedY],
targetLabel: this.props.labels[this.newlyMarkedX]
} :
undefined;
this.props.onHover(selection);
}
}
}
Expand All @@ -187,6 +210,8 @@ export class DSM extends React.Component<IDsmProps, {}> {
}

public render() {
// tslint:disable-next-line:no-console
console.log("RENDER!!")
return (
<div id="stage">
<canvas id="markedCellLayer" ref={ref => (this.markedCellLayerCanvasRef = ref)} />
Expand Down Expand Up @@ -231,12 +256,12 @@ export class DSM extends React.Component<IDsmProps, {}> {

// create structures
this.sccNodePositions = [].concat.apply([], this.props.stronglyConnectedComponents.map(scc => scc.nodePositions));
this.matrixLabels = new Array(this.props.labels.length);
for (let index = 0; index < this.matrixLabels.length; index++) {
this.matrixLabels[index] = new Array(this.props.labels.length);
this.matrixElements = new Array(this.props.labels.length);
for (let index = 0; index < this.matrixElements.length; index++) {
this.matrixElements[index] = new Array(this.props.labels.length);
}
this.props.cells.forEach(cell => {
this.matrixLabels[cell.column][cell.row] = '' + cell.value;
this.matrixElements[cell.column][cell.row] = cell;
});

// draw the horizontal bar
Expand Down
11 changes: 8 additions & 3 deletions slizaa-web/app/src/components/dsm/IDsmProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ export interface IDsmProps {
horizontalSideMarkerHeight: number;
verticalSideMarkerWidth: number;
onSideMarkerResize?: (horizontalSideMarkerHeight: number | undefined, verticalSideMarkerWidth: number | undefined) => void;
// TODO: Callback-Signature - Generics in TypeScript?
onHover?: (columnElementId: string | undefined, rowElementId: string | undefined) => void;
onSelect?: (columnElementId: string | undefined, rowElementId: string | undefined) => void;
onHover?: (selection: IDsmSelection | undefined) => void;
onSelect?: (selection: IDsmSelection | undefined) => void;
}

export interface IDsmLabel {
Expand All @@ -41,6 +40,12 @@ export interface IDsmCell {
value: number;
}

export interface IDsmSelection {
selectedCell : IDsmCell;
sourceLabel: IDsmLabel;
targetLabel: IDsmLabel;
}

export interface IDsmStronglyConnectedComponent {
nodePositions: number[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export class HierarchicalGraphTree extends React.Component<WithApolloClient<IHie
this.props.onExpand(expandedKeys);
}

public onSelect = (selectedKeys: string[]) => {
this.props.onSelect(selectedKeys);
public onSelect = (selectedNodes: ISlizaaNode[]) => {
this.props.onSelect(selectedNodes);
}

public fetchIcon = (item: ISlizaaNode): React.ReactNode => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import {ISlizaaNode} from "../../model/ISlizaaNode";

export interface IHierarchicalGraphTreeProps {
databaseId: string
hierarchicalGraphId: string
expandedKeys?: string[]
checkedKeys?: string[]
onSelect: (selectedKeys: string[]) => void
onSelect: (selectedNodes: ISlizaaNode[]) => void
onExpand: (expandedKeys: string[]) => void
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ export class SlizaaDependencyTree extends React.Component<ISlizaaDependencyTreeP
return (p: SlizaaNode, c: () => void) => fetchChildrenFilterByDependencySet(client, p, NodeType.TARGET, dependencySourceNodeId, dependencyTargetNodeId, this.props.databaseId, this.props.hierarchicalGraphId, c);
}

private onSourceSelect = (selectedItems: string[]): void => {
private onSourceSelect = (selectedNodes: ISlizaaNode[]): void => {
this.setState({
selectedNodeIds: selectedItems,
selectedNodeIds: selectedNodes.map((node) => node.key),
selectedNodesType: NodeType.SOURCE
})
}
Expand All @@ -157,9 +157,9 @@ export class SlizaaDependencyTree extends React.Component<ISlizaaDependencyTreeP
})
}

private onTargetSelect = (selectedItems: string[]): void => {
private onTargetSelect = (selectedItems: ISlizaaNode[]): void => {
this.setState({
selectedNodeIds: selectedItems,
selectedNodeIds: selectedItems.map((node) => node.key),
selectedNodesType: NodeType.TARGET
})
}
Expand Down
2 changes: 1 addition & 1 deletion slizaa-web/app/src/components/stree/ISTreeProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface ISTreeProps {
expandedKeys?: string[]
selectedKeys?: string[]
markedKeys?: string[]
onSelect?: (selectedKeys: string[]) => void
onSelect?: (selectedKeys: ISlizaaNode[]) => void
onExpand?: (expandedKeys: string[]) => void
loadData?: (node: ISlizaaNode, callback: () => void) => Promise<{}>
fetchIcon?: (node: ISlizaaNode) => React.ReactNode
Expand Down
9 changes: 7 additions & 2 deletions slizaa-web/app/src/components/stree/STree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@ import './STree.css';
export class STree extends React.Component<ISTreeProps, ISTreeState> {

private treeRef: Tree | null;
private nodeCache: Map<string, ISlizaaNode>;
private scrollTop: number;
private scrollLeft: number;

constructor(props: ISTreeProps) {
super(props);

this.nodeCache = new Map();

this.state = {
expandedNodeIds: props.expandedKeys ? props.expandedKeys : [],
rootNodes: [props.rootNode],
Expand All @@ -50,7 +53,7 @@ export class STree extends React.Component<ISTreeProps, ISTreeState> {
}

public componentWillReceiveProps(nextProps: ISTreeProps) {
this.setState( {
this.setState({
expandedNodeIds: nextProps.expandedKeys ? nextProps.expandedKeys : [],
rootNodes: [nextProps.rootNode],
selectedNodeIds: nextProps.selectedKeys ? nextProps.selectedKeys : [],
Expand All @@ -60,6 +63,7 @@ export class STree extends React.Component<ISTreeProps, ISTreeState> {
public renderTreeNodes = (treeNodes: ISlizaaNode[]) => {

return treeNodes.map((item: ISlizaaNode) => {
this.nodeCache.set(item.key, item);

const isSelected = this.state.selectedNodeIds.indexOf(item.key) > -1;
const isExpanded = this.state.expandedNodeIds.indexOf(item.key) > -1;
Expand Down Expand Up @@ -173,7 +177,8 @@ export class STree extends React.Component<ISTreeProps, ISTreeState> {
selectedNodeIds: selectedKeys
});
if (this.props.onSelect) {
this.props.onSelect(selectedKeys);
const nodes: ISlizaaNode[] = selectedKeys.map((v) => this.nodeCache.get(v)).filter((v) => v !== undefined) as ISlizaaNode[];
this.props.onSelect(nodes);
}
}

Expand Down
86 changes: 86 additions & 0 deletions slizaa-web/app/src/views/dependenciesview/dsmPart/DsmPart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* slizaa-web - Slizaa Static Software Analysis Tools
* Copyright © 2019 Code-Kontor GmbH and others ([email protected])
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import * as React from "react";
import {DSM} from "../../../components/dsm";
import {IDsmSelection} from "../../../components/dsm/IDsmProps";
import {IDependencySelection} from "../internal/IDependenciesViewState";
import {IDsmPartProps} from "./IDsmPartProps";
import {IDsmPartState} from "./IDsmPartState";

export class DependencyOverviewPart extends React.Component<IDsmPartProps, IDsmPartState> {

constructor(props: Readonly<IDsmPartProps>) {
super(props);

this.state = {
hoveredDependency: undefined
}
}

public render() {

const selectedDependencyLabel =
// has hoveredMainDependencySelection?
this.state.hoveredDependency ?
this.renderDependencySelection(this.state.hoveredDependency) :
this.renderDependencySelection(this.props.dependencySelection);

return <div className="dsm-container">
<div className="dsm">
<DSM labels={this.props.labels}
cells={this.props.cells}
stronglyConnectedComponents={this.props.stronglyConnectedComponents}
horizontalBoxSize={35}
verticalBoxSize={35}
horizontalSideMarkerHeight={this.props.horizontalSideMarkerHeight}
verticalSideMarkerWidth={this.props.verticalSideMarkerWidth}
onSideMarkerResize={this.props.onSideMarkerResize}
onSelect={this.props.onSelect}
onHover={this.onHoverDependency}
/>
</div>
<div className="dsm-selection">
{selectedDependencyLabel}
</div>
</div>
}

private onHoverDependency = (aSelection: IDsmSelection | undefined): void => {
if (aSelection !== undefined) {
this.setState({
hoveredDependency: {
sourceNodeId: aSelection.sourceLabel.id,
sourceNodeText: aSelection.sourceLabel.text,
targetNodeId: aSelection.targetLabel.id,
targetNodeText: aSelection.targetLabel.text,
weight: aSelection.selectedCell.value
}
});
} else {
this.setState({
hoveredDependency: undefined
});
}
}

private renderDependencySelection = (aSelection: IDependencySelection | undefined): string => {
return aSelection ?
aSelection.sourceNodeText + " ⟹ " + aSelection.targetNodeText /* + "(" + aSelection.weight + ")"*/ :
" "
}
}
23 changes: 23 additions & 0 deletions slizaa-web/app/src/views/dependenciesview/dsmPart/IDsmPartProps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* slizaa-web - Slizaa Static Software Analysis Tools
* Copyright © 2019 Code-Kontor GmbH and others ([email protected])
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import {IDsmProps} from "../../../components/dsm/IDsmProps";
import {IDependencySelection} from "../internal/IDependenciesViewState";

export interface IDsmPartProps extends IDsmProps {
dependencySelection?: IDependencySelection
}
22 changes: 22 additions & 0 deletions slizaa-web/app/src/views/dependenciesview/dsmPart/IDsmPartState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* slizaa-web - Slizaa Static Software Analysis Tools
* Copyright © 2019 Code-Kontor GmbH and others ([email protected])
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import {IDependencySelection} from "../internal/IDependenciesViewState";

export class IDsmPartState {
public hoveredDependency?: IDependencySelection
}
Loading

0 comments on commit bf16e9f

Please sign in to comment.