Skip to content
Snippets Groups Projects
Commit 0ea29f54 authored by Matthias Konitzny's avatar Matthias Konitzny :fire:
Browse files

The FilterOverlay is now a React component.

Renamed the overlays directory to components.
Typescript now compiles to es6 instead of es5 (es6 content gets translated by babel)
parent 4aa701b4
No related branches found
No related tags found
No related merge requests found
Pipeline #56044 failed
import React from "react";
import Graph from "../graph";
import PropTypes, { InferType } from "prop-types";
export { FilterOverlay };
class Link extends React.Component<
InferType<typeof Link.propTypes>,
InferType<typeof Link.stateTypes>
> {
static propTypes = {
type: PropTypes.string.isRequired,
color: PropTypes.string.isRequired,
width: PropTypes.number.isRequired,
toggledCallback: PropTypes.func,
};
static stateTypes = {
visible: PropTypes.bool,
};
constructor(props: InferType<typeof Link.propTypes>) {
super(props);
this.state = { visible: true };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
const callback = this.props.toggledCallback || null;
if (callback) {
callback(this.props.type);
}
this.setState(
(
state: InferType<typeof Link.stateTypes>,
props: InferType<typeof Link.propTypes>
) => ({ visible: !state.visible })
);
}
render() {
const opacity = this.state.visible ? 1.0 : 0.4;
return (
<div
className={"relation"}
style={{ opacity: opacity }}
onClick={this.handleClick}
>
<p>{this.props.type}</p>
<div
className={"rel-container"}
style={{
width: this.props.width + "px",
backgroundColor: this.props.color,
}}
/>
</div>
);
}
}
/**
* Represents an overlay showing the meaning of different link/node colors.
* Offers the ability to toggle certain types.
*/
class FilterOverlay extends React.Component<
InferType<typeof FilterOverlay.propTypes>,
unknown
> {
static propTypes = {
graph: PropTypes.instanceOf(Graph).isRequired,
type: PropTypes.string.isRequired,
};
/**
* Callback which gets called when the visibility of a category has changed.
*/
filterChangedCallback: (type: string) => void;
constructor(props: InferType<typeof FilterOverlay.propTypes>) {
super(props);
this.filterChangedCallback = (type) => void type;
this.toggleVisibility = this.toggleVisibility.bind(this);
}
/**
* Renders an element for each category, which enables the user to toggle
* the corresponding visibility of assigned nodes.
*/
renderLinks() {
const classes =
this.props.type === "link"
? this.props.graph.getLinkClasses()
: this.props.graph.getNodeClasses();
const chars = Math.max(
...classes.map(function (c: string) {
return c.length;
})
);
const links = [];
for (const link of classes) {
links.push(
<Link
type={link}
color={
this.props.type == "link"
? this.props.graph.edgeColors[link]
: this.props.graph.nodeColors[link]
}
width={10 * chars}
toggledCallback={this.toggleVisibility}
key={link}
/>
);
}
return links;
}
render() {
return <div className={"link-overlay"}>{this.renderLinks()}</div>;
}
/**
* Event handler for the click event of the link type divs.
* Toggles the visibility of certain edge types.
*/
toggleVisibility(type: string) {
if (this.props.type === "link") {
this.props.graph.toggleLinkVisibility(type);
} else {
this.props.graph.toggleNodeVisibility(type);
}
this.filterChangedCallback(type);
// TODO: This is really ugly.
this.props.graph.infoOverlay.bottomMenu.toggleCategory(type);
}
}
......@@ -153,6 +153,7 @@
left: 0;
display: block;
background-color: rgba(0, 0, 0, 0.6);
z-index: 1;
}
.relation {
......
import * as Config from "../config";
import { FilterOverlay } from "./overlays/filteroverlay";
import { NodeInfoOverlay } from "./overlays/nodeinfo";
import { FilterOverlay } from "./components/filteroverlay";
import { NodeInfoOverlay } from "./components/nodeinfo";
import Graph from "./graph";
import React from "react";
import screenfull from "screenfull";
class Display extends React.PureComponent {
graph: Graph;
filterOverlay: FilterOverlay;
infoOverlay: NodeInfoOverlay;
sceneNode: HTMLElement;
......@@ -16,16 +15,30 @@ class Display extends React.PureComponent {
Config.SPACE,
this.loadGraphComponents.bind(this)
);
this.filterOverlay = new FilterOverlay(this.graph, "node");
this.infoOverlay = new NodeInfoOverlay(this.graph);
this.graph.infoOverlay = this.infoOverlay;
}
/**
* Callback which is called when the underlying graph has finished loading
* its content
*/
loadGraphComponents() {
this.filterOverlay.create();
this.infoOverlay.create();
this.sceneNode = document.getElementById("kg-display");
/*
* This call is necessary since the graph can only load after the
* component has mounted (the graph requires a fixed <div> element),
* but some components rely on the graph being loaded.
* The fix is to exclude all components from rendering until the graph
* finished loading.
* TODO: Once all components have been transformed to react components
* this call could be substituted by changing the object state (which
* causes a re-render)
*/
this.forceUpdate();
// filterOverlay.filterChangedCallback = (cls) =>
// infoOverlay.bottomMenu.toggleTabVisibility(cls);
// createFullScreenButton();
......@@ -50,6 +63,10 @@ class Display extends React.PureComponent {
>
<p>&#10530;</p>
</div>
{this.graph && (
<FilterOverlay graph={this.graph} type={"node"} />
)}
<div id="3d-graph" />
</div>
);
......
import * as Helpers from "../helpers";
import jQuery from "jquery";
export { FilterOverlay };
/**
* Represents an overlay showing the meaning of different link/node colors.
* Offers the ability to toggle certain types.
*/
class FilterOverlay {
/**
* Creates the overlay for a given graph object.
* @param {Graph} graph The graph object.
* @param {String} type The selection type. Can be "link" or "node".
*/
constructor(graph, type = "link") {
this.graph = graph;
this.type = type;
this.filterChangedCallback = (type) => void type;
}
/**
* Creates the overlay based on the edges and nodes of the graph object.
* Must be called after the graph has been initialized.
*/
create() {
const sceneNode = Helpers.getCanvasDivNode();
const overlayNode = document.createElement("div");
overlayNode.className = "link-overlay";
sceneNode.insertBefore(overlayNode, sceneNode.childNodes[2]);
const classes =
this.type === "link"
? this.graph.getLinkClasses()
: this.graph.getNodeClasses();
const chars = Math.max.apply(
Math,
classes.map(function (c) {
return c.length;
})
);
for (const link of classes) {
const relation = Helpers.createDiv("relation", overlayNode, {
type: link, // Attach the link type to the relation div object
innerHTML: "<p>" + link + "</p>",
});
jQuery(relation).click((event) => this.toggleVisibility(event));
const colorStrip = Helpers.createDiv("rel-container", relation);
colorStrip.style.backgroundColor =
this.type === "link"
? this.graph.edgeColors[link]
: this.graph.nodeColors[link];
colorStrip.style.width = 10 * chars + "px";
}
}
/**
* Event handler for the click event of the link type divs.
* Toggles the visibility of certain edge types.
* @param {MouseEvent} event
*/
toggleVisibility(event) {
const target = event.currentTarget;
if (this.type === "link") {
this.graph.toggleLinkVisibility(target.type);
} else {
this.graph.toggleNodeVisibility(target.type);
}
this.filterChangedCallback(target.type);
if (getComputedStyle(target).opacity == 1.0) {
target.style.opacity = 0.4;
} else {
target.style.opacity = 1.0;
}
this.graph.infoOverlay.bottomMenu.toggleCategory(target.type);
}
}
......@@ -4,7 +4,7 @@
"noImplicitAny": true,
"strictNullChecks": false,
"module": "es6",
"target": "es5",
"target": "es6",
"jsx": "preserve",
"allowJs": true,
"moduleResolution": "node",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment