UNPKG

data-clumps-visualizer

Version:
478 lines (477 loc) 24.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataClumpsGraph = void 0; const react_1 = __importStar(require("react")); const react_graph_vis_1 = __importDefault(require("react-graph-vis")); const button_1 = require("primereact/button"); const uuid_1 = require("uuid"); const COLOR_UNI_ROT = "#ac0634"; const COLOR_UNI_GELB = "#fbb900"; const COLOR_UNI_GRAU = "#cfcfcf"; const COLOR_PRIMARY = undefined; const COLOR_PALETTES = generateColorPaletteFromColor(COLOR_PRIMARY); const COLOR_FILE = COLOR_PALETTES.color_file || COLOR_UNI_GRAU; const COLOR_FILE_TEXT = calculateBestTextColor(COLOR_FILE); const COLOR_CLASS = COLOR_PALETTES.color_class || COLOR_UNI_GRAU; const COLOR_CLASS_TEXT = calculateBestTextColor(COLOR_CLASS); const COLOR_METHOD = COLOR_PALETTES.color_method || COLOR_UNI_GELB; const COLOR_METHOD_TEXT = calculateBestTextColor(COLOR_METHOD); const COLOR_PARAMETER = COLOR_PALETTES.color_parameter || COLOR_UNI_ROT; const COLOR_PARAMETER_TEXT = calculateBestTextColor(COLOR_PARAMETER); const COLOR_FIELD = COLOR_PALETTES.color_field || COLOR_UNI_ROT; const COLOR_FIELD_TEXT = calculateBestTextColor(COLOR_FIELD); function generateColorPaletteFromColor(baseColor) { function adjustBrightness(color, percent) { if (!color) { return undefined; } // Convert hex to RGB const num = parseInt(color.replace("#", ""), 16); const r = (num >> 16) + percent; const g = ((num >> 8) & 0x00FF) + percent; const b = (num & 0x0000FF) + percent; // Ensure RGB stays within 0-255 const newR = Math.min(Math.max(0, r), 255); const newG = Math.min(Math.max(0, g), 255); const newB = Math.min(Math.max(0, b), 255); // Convert back to hex return `#${((1 << 24) + (newR << 16) + (newG << 8) + newB) .toString(16) .slice(1)}`; } let isDark = false; const COLOR_BLACK = "#000000"; let bestTextColor = calculateBestTextColor(baseColor); if (bestTextColor === COLOR_BLACK) { isDark = true; } let multiplier = -1; if (isDark) { multiplier = 1; } return { color_file: adjustBrightness(baseColor, multiplier * 160), color_class: adjustBrightness(baseColor, multiplier * 120), color_method: adjustBrightness(baseColor, multiplier * 80), color_parameter: baseColor, color_field: adjustBrightness(baseColor, multiplier * 40), // Lighter than base }; } function calculateBestTextColor(backgroundColor) { const COLOR_BLACK = "#000000"; const COLOR_WHITE = "#FFFFFF"; if (!backgroundColor) { return undefined; } // only black or white for text let color = backgroundColor; if (color.startsWith("#")) { color = color.substring(1); } // calculate highest contrast color let r = parseInt(color.substring(0, 2), 16); let g = parseInt(color.substring(2, 4), 16); let b = parseInt(color.substring(4, 6), 16); let yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000; return (yiq >= 128) ? COLOR_BLACK : COLOR_WHITE; } const DataClumpsGraph = (props) => { var _a, _b; const [a, setA] = (0, react_1.useState)(); const dark_mode = props === null || props === void 0 ? void 0 : props.dark_mode; let dataClumpsDict = props.dataClumpsDict; const from_file_path = props === null || props === void 0 ? void 0 : props.from_file_path; const to_file_path = props === null || props === void 0 ? void 0 : props.to_file_path; const version = (0, react_1.useMemo)(uuid_1.v4, [dataClumpsDict, from_file_path, to_file_path, dark_mode]); //const [dataClumpsDict, setDataClumpsDict] = useSynchedDataClumpsDict(); // we wont use synched variable here, since we want to export our functionality outside // const [showLargeGraph, setShowLargeGraph] = useState(false); const showLargeGraph = true; const setShowLargeGraph = (bool) => { }; function getInitialGraphFromDataClumpsDict(dataClumpsDict) { //console.log("getInitialGraphFromDataClumpsDict"); let from_file_path = props === null || props === void 0 ? void 0 : props.from_file_path; let to_file_path = props === null || props === void 0 ? void 0 : props.to_file_path; let files_dict = {}; let classes_dict = {}; let fields_dict = {}; let methods_dict = {}; let parameters_dict = {}; if (dataClumpsDict) { let dataClumps = (dataClumpsDict === null || dataClumpsDict === void 0 ? void 0 : dataClumpsDict.data_clumps) || {}; let dataClumpsKeys = Object.keys(dataClumps); for (let dataClumpKey of dataClumpsKeys) { let dataClump = dataClumps[dataClumpKey]; let file_path = dataClump.from_file_path; let shouldAnalyzeFile = true; if (from_file_path) { shouldAnalyzeFile = file_path === from_file_path; } if (shouldAnalyzeFile) { let data_clump_data_dict = dataClump.data_clump_data; let dataClumpDataKeys = Object.keys(data_clump_data_dict); for (let dataClumpDataKey of dataClumpDataKeys) { let dataClumpData = data_clump_data_dict[dataClumpDataKey]; initNodesForDataClumpData(dataClump, dataClumpData, files_dict, classes_dict, fields_dict, methods_dict, parameters_dict); } } } } let nodes = []; let edges = []; let graph = { nodes: nodes, edges: edges }; let files_dict_keys = Object.keys(files_dict); for (let file_dict_key of files_dict_keys) { let file_dict_value = files_dict[file_dict_key]; // @ts-ignore graph.nodes.push(file_dict_value); let classes_or_interfaces_ids = file_dict_value.classes_or_interfaces_ids; let classes_or_interfaces_ids_keys = Object.keys(classes_or_interfaces_ids); for (let classes_or_interfaces_ids_key of classes_or_interfaces_ids_keys) { graph.edges.push({ // @ts-ignore from: file_dict_value.id, // @ts-ignore to: classes_or_interfaces_ids_key, }); } } let classes_dict_keys = Object.keys(classes_dict); for (let class_dict_key of classes_dict_keys) { let class_dict_value = classes_dict[class_dict_key]; // @ts-ignore graph.nodes.push(class_dict_value); let field_ids = class_dict_value.field_ids; let field_ids_keys = Object.keys(field_ids); for (let field_ids_key of field_ids_keys) { graph.edges.push({ // @ts-ignore from: class_dict_value.id, // @ts-ignore to: field_ids_key, }); } let method_ids = class_dict_value.method_ids; let method_ids_keys = Object.keys(method_ids); for (let method_ids_key of method_ids_keys) { graph.edges.push({ // @ts-ignore from: class_dict_value.id, // @ts-ignore to: method_ids_key, }); } } let fields_dict_keys = Object.keys(fields_dict); for (let field_dict_key of fields_dict_keys) { let field_dict_value = fields_dict[field_dict_key]; // @ts-ignore graph.nodes.push(field_dict_value); let related_to = field_dict_value.related_to; let related_to_keys = Object.keys(related_to); for (let related_to_key of related_to_keys) { graph.edges.push({ // @ts-ignore from: field_dict_value.id, // @ts-ignore to: related_to_key, }); } } let method_ids = Object.keys(methods_dict); for (let method_id of method_ids) { let method_dict_value = methods_dict[method_id]; // @ts-ignore graph.nodes.push(method_dict_value); let parameter_ids = method_dict_value.parameter_ids; let parameter_ids_keys = Object.keys(parameter_ids); for (let parameter_ids_key of parameter_ids_keys) { graph.edges.push({ // @ts-ignore from: method_dict_value.id, // @ts-ignore to: parameter_ids_key, }); } } let parameters_dict_keys = Object.keys(parameters_dict); for (let parameter_dict_key of parameters_dict_keys) { let parameter_dict_value = parameters_dict[parameter_dict_key]; // @ts-ignore graph.nodes.push(parameter_dict_value); let related_to = parameter_dict_value.related_to; let related_to_keys = Object.keys(related_to); for (let related_to_key of related_to_keys) { graph.edges.push({ // @ts-ignore from: parameter_dict_value.id, // @ts-ignore to: related_to_key, }); } } return graph; } function getRawFileNode(file_path, files_dict) { let file_node = files_dict[file_path]; let file_name = file_path; try { file_name = file_path.split("/").pop(); } catch (e) { // could not split file_path, so just use file_path as file_name } if (!file_node) { file_node = { id: file_path, label: file_name, color: COLOR_FILE, font: { color: COLOR_FILE_TEXT }, classes_or_interfaces_ids: {}, }; files_dict[file_node.id] = file_node; } return file_node; } function getRawClassesOrInterfacesNode(classOrInterface_key, classOrInterface_name, classes_dict) { //console.log("getRawClassesOrInterfacesNode: classOrInterface"); //console.log(classOrInterface) let class_or_interface_node = classes_dict[classOrInterface_key]; if (!class_or_interface_node) { class_or_interface_node = { id: classOrInterface_key, label: classOrInterface_name, color: COLOR_CLASS, font: { color: COLOR_CLASS_TEXT }, field_ids: {}, method_ids: {}, }; classes_dict[class_or_interface_node.id] = class_or_interface_node; } return class_or_interface_node; } function getRawMethodNode(method_key, method_name, methods_dict) { let method_node = methods_dict[method_key]; if (!method_node) { method_node = { id: method_key, label: method_name, color: COLOR_METHOD, font: { color: COLOR_METHOD_TEXT }, parameter_ids: {}, }; methods_dict[method_node.id] = method_node; } return method_node; } function getRawParameterNode(parameter_key, parameter_name, parameters_dict) { let parameter_node = parameters_dict[parameter_key]; if (!parameter_node) { parameter_node = { id: parameter_key, label: parameter_name, color: COLOR_PARAMETER, font: { color: COLOR_PARAMETER_TEXT }, related_to: {}, }; parameters_dict[parameter_node.id] = parameter_node; } return parameter_node; } function createRawLinkBetweenParameterOrFieldNodes(field_node, related_to_field_node) { field_node.related_to[related_to_field_node.id] = related_to_field_node.id; related_to_field_node.related_to[field_node.id] = field_node.id; } function initNodesForDataClumpData(dataClumpHolder, dataClumpData, files_dict, classes_dict, fields_dict, methods_dict, parameters_dict) { let data_clump_type = dataClumpHolder.data_clump_type; if (data_clump_type === "parameters_to_parameters_data_clump") { //console.log("parameter_data_clump") //console.log(dataClumpData); let file_path_from = dataClumpHolder.from_file_path; let file_node_from = getRawFileNode(file_path_from, files_dict); let classOrInterfaceKey_from = dataClumpHolder.from_class_or_interface_key; let classOrInterfaceName_from = dataClumpHolder.from_class_or_interface_name; let class_or_interface_node_from = getRawClassesOrInterfacesNode(classOrInterfaceKey_from, classOrInterfaceName_from, classes_dict); file_node_from.classes_or_interfaces_ids[class_or_interface_node_from.id] = class_or_interface_node_from.id; let file_path_to = dataClumpHolder.to_file_path; let file_node_to = getRawFileNode(file_path_to, files_dict); let classOrInterfaceKey_to = dataClumpHolder.to_class_or_interface_key; let classOrInterfaceName_to = dataClumpHolder.to_class_or_interface_name; let class_or_interface_node_to = getRawClassesOrInterfacesNode(classOrInterfaceKey_to, classOrInterfaceName_to, classes_dict); file_node_to.classes_or_interfaces_ids[class_or_interface_node_to.id] = class_or_interface_node_to.id; let method_key_from = dataClumpHolder.from_method_key + ""; let method_name_from = dataClumpHolder.from_method_name + ""; let method_node_from = getRawMethodNode(method_key_from, method_name_from, methods_dict); class_or_interface_node_from.method_ids[method_node_from.id] = method_node_from.id; let method_key_to = dataClumpHolder.to_method_key + ""; let method_name_to = dataClumpHolder.to_method_name + ""; let method_node_to = getRawMethodNode(method_key_to, method_name_to, methods_dict); class_or_interface_node_to.method_ids[method_node_to.id] = method_node_to.id; let parameter_key_from = dataClumpData.key; let parameter_name_from = dataClumpData.name; let parameter_node_from = getRawParameterNode(parameter_key_from, parameter_name_from, parameters_dict); method_node_from.parameter_ids[parameter_node_from.id] = parameter_node_from.id; let parameter_key_to = dataClumpData.to_variable.key; let parameter_name_to = dataClumpData.to_variable.name; let parameter_node_to = getRawParameterNode(parameter_key_to, parameter_name_to, parameters_dict); method_node_to.parameter_ids[parameter_node_to.id] = parameter_node_to.id; createRawLinkBetweenParameterOrFieldNodes(parameter_node_from, parameter_node_to); } else if (data_clump_type === "fields_to_fields_data_clump") { let file_path_from = dataClumpHolder.from_file_path; let file_node_from = getRawFileNode(file_path_from, files_dict); let classOrInterfaceKey_from = dataClumpHolder.from_class_or_interface_key; let classOrInterfaceName_from = dataClumpHolder.from_class_or_interface_name; let class_or_interface_node_from = getRawClassesOrInterfacesNode(classOrInterfaceKey_from, classOrInterfaceName_from, classes_dict); file_node_from.classes_or_interfaces_ids[class_or_interface_node_from.id] = class_or_interface_node_from.id; let file_path_to = dataClumpHolder.to_file_path; let file_node_to = getRawFileNode(file_path_to, files_dict); let classOrInterfaceKey_to = dataClumpHolder.to_class_or_interface_key; let classOrInterfaceName_to = dataClumpHolder.to_class_or_interface_name; let class_or_interface_node_to = getRawClassesOrInterfacesNode(classOrInterfaceKey_to, classOrInterfaceName_to, classes_dict); file_node_to.classes_or_interfaces_ids[class_or_interface_node_to.id] = class_or_interface_node_to.id; let parameter_key_from = dataClumpData.key; let parameter_name_from = dataClumpData.name; let parameter_node_from = getRawParameterNode(parameter_key_from, parameter_name_from, parameters_dict); class_or_interface_node_from.field_ids[parameter_node_from.id] = parameter_node_from.id; let parameter_key_to = dataClumpData.to_variable.key; let parameter_name_to = dataClumpData.to_variable.name; let parameter_node_to = getRawParameterNode(parameter_key_to, parameter_name_to, parameters_dict); class_or_interface_node_to.field_ids[parameter_node_to.id] = parameter_node_to.id; createRawLinkBetweenParameterOrFieldNodes(parameter_node_from, parameter_node_to); } else if (data_clump_type === "parameters_to_fields_data_clump") { let file_path_from = dataClumpHolder.from_file_path; let file_node_from = getRawFileNode(file_path_from, files_dict); let classOrInterfaceKey_from = dataClumpHolder.from_class_or_interface_key; let classOrInterfaceName_from = dataClumpHolder.from_class_or_interface_name; let class_or_interface_node_from = getRawClassesOrInterfacesNode(classOrInterfaceKey_from, classOrInterfaceName_from, classes_dict); file_node_from.classes_or_interfaces_ids[class_or_interface_node_from.id] = class_or_interface_node_from.id; let file_path_to = dataClumpHolder.to_file_path; let file_node_to = getRawFileNode(file_path_to, files_dict); let classOrInterfaceKey_to = dataClumpHolder.to_class_or_interface_key; let classOrInterfaceName_to = dataClumpHolder.to_class_or_interface_name; let class_or_interface_node_to = getRawClassesOrInterfacesNode(classOrInterfaceKey_to, classOrInterfaceName_to, classes_dict); file_node_to.classes_or_interfaces_ids[class_or_interface_node_to.id] = class_or_interface_node_to.id; let method_key_from = dataClumpHolder.from_method_key + ""; let method_name_from = dataClumpHolder.from_method_name + ""; let method_node_from = getRawMethodNode(method_key_from, method_name_from, methods_dict); class_or_interface_node_from.method_ids[method_node_from.id] = method_node_from.id; let parameter_key_from = dataClumpData.key; let parameter_name_from = dataClumpData.name; let parameter_node_from = getRawParameterNode(parameter_key_from, parameter_name_from, parameters_dict); method_node_from.parameter_ids[parameter_node_from.id] = parameter_node_from.id; let parameter_key_to = dataClumpData.to_variable.key; let parameter_name_to = dataClumpData.to_variable.name; let parameter_node_to = getRawParameterNode(parameter_key_to, parameter_name_to, parameters_dict); class_or_interface_node_to.field_ids[parameter_node_to.id] = parameter_node_to.id; //createRawLinkBetweenParameterOrFieldNodes(parameter_node_from, parameter_node_to); // is uni-directional so only from the parameter to the field parameter_node_from.related_to[parameter_node_to.id] = parameter_node_to.id; } } // const [state, setState] = useState({ let state = { counter: 5, graph: getInitialGraphFromDataClumpsDict(dataClumpsDict), /** graph: { nodes: [ { id: 1, label: "Node 1", color: "#e04141" }, { id: 2, label: "Node 2", color: "#e09c41" }, { id: 3, label: "Node 3", color: "#e0df41" }, { id: 4, label: "Node 4", color: "#7be041" }, { id: 5, label: "Node 5", color: "#41e0c9" } ], edges: [ { from: 1, to: 2 }, { from: 1, to: 3 }, { from: 2, to: 4 }, { from: 2, to: 5 } ] }, */ events: { select: ({ nodes, edges }) => { console.log("Selected nodes:"); console.log(nodes); console.log("Selected edges:"); console.log(edges); } } }; //); const { graph, events } = state; function renderGraph() { const edgesColor = dark_mode ? "#ffffff" : "#000000"; const options = { layout: { hierarchical: false, }, edges: { color: edgesColor }, }; const events = { select: function (event) { var { nodes, edges } = event; } }; return (react_1.default.createElement(react_graph_vis_1.default, { key: version, graph: graph, options: options, events: events, style: { height: "100%", width: "100%" } })); } let amountNodes = ((_a = graph === null || graph === void 0 ? void 0 : graph.nodes) === null || _a === void 0 ? void 0 : _a.length) || 0; let amountEdges = ((_b = graph === null || graph === void 0 ? void 0 : graph.edges) === null || _b === void 0 ? void 0 : _b.length) || 0; function renderSecureGraph() { let largeGraph = amountNodes > 1000; if (largeGraph && !showLargeGraph) { return (react_1.default.createElement("div", { style: { height: "100%", width: "100%", backgroundColor: "transparent" } }, react_1.default.createElement("div", { style: { height: "100%", width: "100%", display: "flex", alignItems: "center", flexDirection: "column" } }, react_1.default.createElement("div", { style: { display: "block" } }, react_1.default.createElement("h1", null, "Graph is very large"), react_1.default.createElement("div", null, "Nodes: ", amountNodes), react_1.default.createElement("div", null, "Edges: ", amountEdges), react_1.default.createElement("h2", null, "Select a specific file")), react_1.default.createElement("div", { style: { paddingTop: "30px", paddingBottom: "30px" } }, "or"), react_1.default.createElement(button_1.Button, { className: "p-button-danger", icon: "pi pi-exclamation-triangle", label: "Show large graph", onClick: () => { setShowLargeGraph(true); } })))); } else { return renderGraph(); } } return (react_1.default.createElement("div", { style: { height: "100%", width: "100%", backgroundColor: "transparent" } }, react_1.default.createElement("div", { style: { height: "100%", width: "100%" } }, renderSecureGraph()))); }; exports.DataClumpsGraph = DataClumpsGraph;