Commit 2b907ebd authored by mehdilouraoui's avatar mehdilouraoui
Browse files

refacto(icicles): temp

parent f4404cae
import React, { FC, useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";
import { getFilesAndFoldersFromStore } from "reducers/files-and-folders/files-and-folders-selectors";
import {
getFilesAndFoldersFromStore,
getMaxDepth,
} from "reducers/files-and-folders/files-and-folders-selectors";
import Icicles from "./icicles";
import { getFilesAndFoldersMetadataFromStore } from "reducers/files-and-folders-metadata/files-and-folders-metadata-selectors";
import {
......@@ -8,6 +11,9 @@ import {
setLockedElementId,
} from "reducers/workspace-metadata/workspace-metadata-actions";
import { getWorkspaceMetadataFromStore } from "reducers/workspace-metadata/workspace-metadata-selectors";
import { useDebounceCallback } from "hooks/use-debounce-callback";
const DELAY = 150;
const IciclesContainer: FC = () => {
const filesAndFoldersMap = useSelector(getFilesAndFoldersFromStore);
......@@ -40,15 +46,27 @@ const IciclesContainer: FC = () => {
[dispatch]
);
const debouncedSetHoveredElement = useDebounceCallback(
setHoveredElement,
DELAY
);
const debouncedResetHoveredElement = useDebounceCallback(
resetHoveredElement,
DELAY
);
const treeDepth = getMaxDepth(filesAndFoldersMap);
return (
<Icicles
filesAndFolders={filesAndFoldersMap}
filesAndFoldersMetadata={filesAndFoldersMetadataMap}
setHoveredElement={setHoveredElement}
resetHoveredElement={resetHoveredElement}
setHoveredElement={debouncedSetHoveredElement}
resetHoveredElement={debouncedResetHoveredElement}
setLockedElement={setLockedElement}
resetLockedElement={resetLockedElement}
lockedElementId={lockedElementId}
treeDepth={treeDepth}
/>
);
};
......
import { ROOT_FF_ID } from "reducers/files-and-folders/files-and-folders-selectors";
import { FilesAndFolders } from "reducers/files-and-folders/files-and-folders-types";
import { fromFileName } from "./../../../util/color/color-util";
import { fromFileName } from "util/color/color-util";
import {
getRectangleHeight,
isLabelVisible,
......@@ -43,9 +43,10 @@ export const createCell = (svg, root) => {
export const createRect = (cell, elements) => {
return cell
.append("rect")
.attr("id", (d) => d.data.id)
.attr("width", ({ y0, y1 }) => y1 - y0 - 1)
.attr("height", (d) => getRectangleHeight(d))
.attr("fill-opacity", 0.5)
.attr("opacity", 0.5)
.attr("fill", (d: any) => {
if (!d.depth) {
return "#ccc";
......
import { difference } from "lodash";
import * as d3 from "d3";
export const VIEWBOX_WIDTH = 1000;
export const VIEWBOX_HEIGHT = 300;
......@@ -10,21 +11,75 @@ type Dimensions = {
y1: number;
};
export const OPACITY_05 = 0.5;
export const OPACITY_075 = 0.75;
export const OPACITY_1 = 1;
export const getRectangleHeight = ({ x0, x1 }): number => {
return x1 - x0 - Math.min(1, (x1 - x0) / 2);
};
export const getCurrentRect = (icicles, currentElementId) => {
const rects = getAllRects(icicles);
return rects.filter(({ data: { id } }) => id === currentElementId.data.id);
export const getAllRects = () => d3.selectAll("rect");
export const getCurrentRect = (currentElementId) =>
d3.selectAll("rect").filter(({ data: { id } }) => id === currentElementId);
export const getRectById = (rectId) => d3.select(`rect[id='${rectId}']`);
export const getAncestorsPath = (id, treeDepth) => {
const currentRect = getCurrentRect(id).data()[0];
let temporaryRect = currentRect;
let allAncestorsPath = [];
let numberLoop = 0;
while (temporaryRect.parent && numberLoop <= treeDepth) {
allAncestorsPath.push(temporaryRect.data.virtualPath);
temporaryRect = temporaryRect.parent;
numberLoop++;
}
return allAncestorsPath;
};
export const getAllRects = (icicles) =>
d3.select(icicles.current).selectAll("rect");
export const switchMultipleOpacity = (paths: string[], opacity: number): void =>
paths.forEach((path) => changeRectColor(path, opacity));
export const switchOpacityDifferences = (
oldPaths: string[],
newPaths: string[],
emptyOpacity: number,
fillOpacity: number
) => {
const removeOpacity = difference(oldPaths, newPaths);
const addOpacity = difference(newPaths, oldPaths);
switchMultipleOpacity(removeOpacity, emptyOpacity);
switchMultipleOpacity(addOpacity, fillOpacity);
};
export const getAncestors = (node) => {
if (!node.parent) return [];
return [node.parent, ...getAncestors(node.parent)];
};
export const getPathDifference = (paths1, paths2) =>
paths1.filter((path) => !paths2.includes(path));
export const changeRectColor = (rectId, color) =>
getRectById(rectId).style("opacity", color);
export const resetRectsColor = (paths) =>
paths.map((path) => changeRectColor(path, OPACITY_05));
export const switchRectColor = (
previousRects,
nextRects,
eventType: string
) => {
const TYPE = eventType === "hover" ? OPACITY_075 : OPACITY_1;
export const getRectById = (icicles, rectId) => {
const rects = getAllRects(icicles);
return rects.filter(({ data: { id } }) => id === rectId);
previousRects.map((rectId) => changeRectColor(rectId, OPACITY_05));
nextRects.map((rectId) => changeRectColor(rectId, TYPE));
};
export const format = d3.format(",d");
......
import React, { FC, useEffect, useRef, useState } from "react";
import React, { FC, useEffect, useMemo, useRef, useState } from "react";
import { FilesAndFoldersMap } from "reducers/files-and-folders/files-and-folders-types";
import { FilesAndFoldersMetadataMap } from "reducers/files-and-folders-metadata/files-and-folders-metadata-types";
import { getAllRects, getCurrentRect, getRectById } from "./icicles-utils";
import {
getAncestorsPath,
getAllRects,
switchOpacityDifferences,
switchMultipleOpacity,
} from "./icicles-utils";
import {
createCell,
createRect,
......@@ -10,6 +15,7 @@ import {
createSubtitle,
createPartition,
} from "./icicles-elements";
import { difference } from "lodash";
type IciclesProps = {
filesAndFolders: FilesAndFoldersMap;
......@@ -19,6 +25,7 @@ type IciclesProps = {
setLockedElement: (id: string) => void;
resetLockedElement: () => void;
lockedElementId: string;
treeDepth: number;
};
const Icicles: FC<IciclesProps> = ({
......@@ -27,56 +34,60 @@ const Icicles: FC<IciclesProps> = ({
setLockedElement,
resetLockedElement,
lockedElementId,
treeDepth,
}) => {
const [currentHoveredElementId, setCurrentHoveredElementId] = useState("");
const [currentLockedElementId, setCurrentLockedElementId] = useState("");
const iciclesRef = useRef(null);
const lockedPathRef = useRef<string[]>([]);
const hoveredPathRef = useRef<string[]>([]);
const root = createPartition(filesAndFolders);
const root = useMemo(() => createPartition(filesAndFolders), [
filesAndFolders,
]);
let focus = root;
const handleResetLockedElement = ({ target, currentTarget }) => {
if (target === currentTarget && currentLockedElementId.length) {
if (target === currentTarget) {
resetLockedElement();
setCurrentLockedElementId("");
getAllRects(iciclesRef).style("fill-opacity", 0.5);
switchMultipleOpacity(lockedPathRef.current, 0.5);
lockedPathRef.current = [];
}
};
const handleLockedElement = (_, lockedElement) => {
if (lockedElement.data.id === currentLockedElementId) return;
setLockedElement(lockedElement.data.id);
setCurrentLockedElementId(lockedElement.data.id);
getCurrentRect(iciclesRef, lockedElement).style("fill-opacity", 1);
currentLockedElementId.length
? getRectById(iciclesRef, currentLockedElementId).style(
"fill-opacity",
0.5
)
: null;
const handleLockedElement = (_, { data: { id } }) => {
setLockedElement(id);
};
const handleSetCurrentHoveredElementId = (_, hoveredElement) => {
if (hoveredElement.data.id === currentLockedElementId) return;
const handleSetCurrentHoveredElementId = (_, { data: { id } }) => {
const ancestorsPaths = getAncestorsPath(id, treeDepth);
const removeOpacity = difference(hoveredPathRef.current, [
...ancestorsPaths,
...lockedPathRef.current,
]);
const addOpacity = difference(ancestorsPaths, [
...lockedPathRef.current,
...hoveredPathRef.current,
]);
setCurrentHoveredElementId(hoveredElement.data.id);
getCurrentRect(iciclesRef, hoveredElement).style("fill-opacity", 0.75);
};
switchMultipleOpacity(removeOpacity, 0.5);
switchMultipleOpacity(addOpacity, 0.75);
const handleResetCurrentHoveredElementId = (_, hoveredElement) => {
if (hoveredElement.data.id === currentLockedElementId) return;
hoveredPathRef.current = ancestorsPaths;
setCurrentHoveredElementId("");
getCurrentRect(iciclesRef, hoveredElement).style("fill-opacity", 0.5);
setHoveredElement(id);
};
useEffect(() => {
if (!lockedElementId) {
setHoveredElement(currentHoveredElementId);
const handleResetCurrentHoveredElementId = ({ target, currentTarget }) => {
if (target === currentTarget && hoveredPathRef.current.length > 0) {
const removeOpacity = difference(
hoveredPathRef.current,
lockedPathRef.current
);
switchMultipleOpacity(removeOpacity, 0.5);
hoveredPathRef.current = [];
setHoveredElement("");
}
}, [lockedElementId, setHoveredElement, currentHoveredElementId]);
};
useEffect(() => {
const iciclesElements = {};
......@@ -98,14 +109,24 @@ const Icicles: FC<IciclesProps> = ({
}, []);
useEffect(() => {
getAllRects(iciclesRef)
const ancestorsPaths = getAncestorsPath(lockedElementId, treeDepth);
switchOpacityDifferences(lockedPathRef.current, ancestorsPaths, 0.5, 1);
lockedPathRef.current = ancestorsPaths;
}, [lockedElementId]);
useEffect(() => {
getAllRects()
.on("click", handleLockedElement)
.on("mouseover", handleSetCurrentHoveredElementId)
.on("mouseout", handleResetCurrentHoveredElementId);
}, [currentLockedElementId, iciclesRef]);
.on("mouseover", handleSetCurrentHoveredElementId);
}, []);
return (
<svg ref={iciclesRef} id="icicles" onClick={handleResetLockedElement} />
<svg
ref={iciclesRef}
id="icicles"
onClick={handleResetLockedElement}
onMouseMove={handleResetCurrentHoveredElementId}
/>
);
};
......
import { debounce, DebouncedFunc } from "lodash";
import { useMemo } from "react";
export const useDebounceCallback = <T extends (...args: any[]) => any>(
callback: T,
delay: number
): DebouncedFunc<T> => useMemo(() => debounce(callback, delay), [callback]);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment