Skip to content

Commit

Permalink
Merge pull request #1 from x-image-privacy/wordcloud-basile
Browse files Browse the repository at this point in the history
Wordcloud working
  • Loading branch information
RoxaneBurri authored Mar 13, 2023
2 parents df340bd + ac9d041 commit 7d925a3
Show file tree
Hide file tree
Showing 13 changed files with 1,870 additions and 402 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ node_modules
dist
dist-ssr
*.local
.yarn
.yarn/*
!.yarn/releases
!.yarn/plugins


# Editor directories and files
.vscode/*
Expand Down
541 changes: 541 additions & 0 deletions .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs

Large diffs are not rendered by default.

873 changes: 873 additions & 0 deletions .yarn/releases/yarn-3.4.1.cjs

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
nodeLinker: node-modules

plugins:
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"

yarnPath: .yarn/releases/yarn-3.4.1.cjs
36 changes: 0 additions & 36 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,3 @@
padding: 2rem;
text-align: center;
}

.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
}

@keyframes logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

@media (prefers-reduced-motion: no-preference) {
a:nth-of-type(2) .logo {
animation: logo-spin infinite 20s linear;
}
}

.card {
padding: 2em;
}

.read-the-docs {
color: #888;
}
168 changes: 109 additions & 59 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,133 @@
import "./App.css";
import {
centerOfObject,
futurPosition,
putWordInRandomPositionOnParent,
setFirstWordInCenterOfParent,
WordArray,
getArea,
getBoundingRect,
placeWordOnOuterCircle,
Word,
} from "./utils";
import * as React from "react";
import {
CENTER_X,
CENTER_Y,
CONTAINER_HEIGHT,
CONTAINER_WIDTH,
DEFAULT_RECT,
} from "./constants";

const defaultWords = [
{ id: "1234", text: "test", x: 10, y: 100 },
{ id: "2345", text: "hello", x: 50, y: 10 },
{ id: "3456", text: "haha", x: 130, y: 40 },
];
const CUT_OFF = 0.5;

const PARENT_ID = "rect";
export const MAX_FONT_SIZE = 20;
export const MIN_FONT_SIZE = 6;

const defaultWords: Word[] = [
{ id: "word-1", text: " Big word ", coef: 0.99 },
{ id: "word-2", text: "hello", coef: 0.8 },
{ id: "word-4", text: "caramba", coef: 0.97 },
{ id: "word-3", text: "all", coef: 0.74 },
{ id: "word-5", text: "Piniata", coef: 0.6 },
{ id: "word-6", text: "Taxi", coef: 0.93 },
{ id: "word-7", text: "papa", coef: 0.94 },
{ id: "word-8", text: "chicita", coef: 0.66 },
{ id: "word-9", text: "hellicopter", coef: 0.92 },
{ id: "word-10", text: "chiold", coef: 0.75 },
{ id: "word-11", text: "text", coef: 0.81 },
{ id: "word-12", text: "document", coef: 0.77 },
{ id: "word-13", text: "text", coef: 0.89 },
{ id: "word-14", text: "finger", coef: 0.91 },
{ id: "word-15", text: "girl", coef: 0.88 },
];

const Wordcloud = () => {
const [words, setWords] = React.useState(defaultWords);

const updateWords = () => {
console.log("start");

setWords((prevWords) => {
let init: WordArray = [];

const newWords = prevWords.reduce((passRect, w) => {
const elem = document.getElementById(w.id);

if (elem) {
if (passRect.length === 0) {
w = setFirstWordInCenterOfParent(w, PARENT_ID);
console.log("first elem");
console.log("w", w);
const wordsToPlace = prevWords
.map((w) => ({ ...w, rect: getBoundingRect(w.id) || DEFAULT_RECT }))
.sort((a, b) => (a.coef > b.coef ? -1 : 1));
const rectsToPlace = wordsToPlace.map((w) => w.rect);
const firstRect = { ...rectsToPlace[0] };
const centeredRect = {
width: firstRect.width,
height: firstRect.height,
x: CENTER_X,
y: CENTER_Y,
};
const newPositions = rectsToPlace.slice(1).reduce(
(placedElements, rect) => {
// move the word
const futureWord = futurPosition(
// put the word in random place around the parent
placeWordOnOuterCircle(rect),
placedElements,
3
);
return [...placedElements, futureWord];
},
[centeredRect]
);
return wordsToPlace.map((word, idx) => ({
...word,
rect: newPositions[idx],
}));

passRect.push(w);
} else {
console.log("w before", w);
// Get the height and width of the word
const heightW = elem.getBoundingClientRect().height;
const widthW = elem.getBoundingClientRect().width;

// put the word in random place arround the parent
w = putWordInRandomPositionOnParent(w, PARENT_ID);

// Get the center of the word
w = centerOfObject(w, heightW, widthW);

// move the word
w = futurPosition(w, passRect, 1, PARENT_ID);

passRect.push(w);
console.log("w after", w);
}
}
return passRect;
// return w;
}, init);
return newWords;
});
console.log("stop");
};

React.useEffect(() => {
updateWords();
}, []);

return (
<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px">
{words.map((word) => (
<text
fill="#000"
id={word.id}
x={word.x.toString()}
y={word.y.toString()}
>
{word.text}
</text>
))}
<rect id="rect" stroke="#000" fill="none" width="200" height="200" />
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
width={CONTAINER_WIDTH}
height={CONTAINER_HEIGHT}
style={{ outline: "1px solid green" }}
>
{words.map((word) => {
const fontSize =
(word.coef - CUT_OFF) *
(1 / (1 - CUT_OFF)) ** 2 *
(MAX_FONT_SIZE - MIN_FONT_SIZE) +
MIN_FONT_SIZE;

return (
<text
key={word.id}
// usefull to have the anchor at the center of the word
textAnchor="middle"
fontSize={fontSize}
style={{ outline: "1px solid rgba(255, 0, 0, 0.1)" }}
id={word.id}
x={(word.rect?.x || CENTER_X).toString()}
// I don't know why I have to add the third of the fontSize to center te word vertically but it works
y={((word.rect?.y || CENTER_Y) + fontSize / 3).toString()}
>
{word.text}
</text>
);
})}
<line
x1={CENTER_X}
x2={CENTER_X}
y1="0"
y2={CONTAINER_HEIGHT}
opacity={0.1}
stroke="orange"
strokeWidth="1"
/>
<line
x1="0"
x2={CONTAINER_WIDTH}
y1={CENTER_Y}
y2={CENTER_Y}
opacity={0.1}
stroke="orange"
strokeWidth="1"
/>
</svg>
);
};
Expand Down
6 changes: 6 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const CONTAINER_WIDTH = 500;
export const CONTAINER_HEIGHT = 300;
export const CENTER_Y = CONTAINER_HEIGHT / 2;
export const CENTER_X = CONTAINER_WIDTH / 2;

export const DEFAULT_RECT = { x: CENTER_X, y: CENTER_Y, width: 10, height: 10 };
9 changes: 9 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}

/* set fill color for svg text element */
text {
fill: rgba(255, 255, 255, 0.87);
}

@media (prefers-color-scheme: light) {
:root {
color: #213547;
Expand All @@ -66,4 +71,8 @@ button:focus-visible {
button {
background-color: #f9f9f9;
}
/* set fill color for svg element */
text {
fill: #213547
}
}
30 changes: 30 additions & 0 deletions src/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { describe, expect, it } from "vitest";
import { areCentersTooClose, Coordinate, Rectangle } from "./utils";

const origin: Coordinate = {
x: 0,
y: 0,
};

describe("areCentersTooClose", () => {
it("No collisions", () => {
expect(areCentersTooClose(origin, { x: 6, y: 0 }, 2, 2)).toBe(false);
expect(areCentersTooClose(origin, { x: 0, y: 6 }, 2, 2)).toBe(false);
expect(areCentersTooClose({ x: 0, y: 6 }, origin, 2, 2)).toBe(false);
});
it("Collisions in X", () => {
expect(areCentersTooClose(origin, { x: 2, y: 0 }, 3, 2)).toBe(true);
expect(areCentersTooClose(origin, { x: 2, y: 0 }, 2.1, 2)).toBe(true);
expect(areCentersTooClose({ x: 2, y: 0 }, origin, 2.1, 2)).toBe(true);
});
it("Collisions in Y", () => {
expect(areCentersTooClose(origin, { x: 0, y: 2 }, 2, 3)).toBe(true);
expect(areCentersTooClose(origin, { x: 0, y: 2 }, 2, 2.1)).toBe(true);
expect(areCentersTooClose({ x: 0, y: 2 }, origin, 2, 2.1)).toBe(true);
});
it("Collisions in X and Y", () => {
expect(areCentersTooClose(origin, { x: 2, y: 2 }, 2.5, 2.5)).toBe(true);
expect(areCentersTooClose(origin, { x: -2, y: -2 }, 2.5, 2.5)).toBe(true);
expect(areCentersTooClose({ x: -2, y: -2 }, origin, 2.5, 2.5)).toBe(true);
});
});
Loading

0 comments on commit 7d925a3

Please sign in to comment.