Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GSoC 2023: Abhinav #393

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions modules/code-builder/src/@types/pallete.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type PalleteProps = {
config: {
data: [];
};
reset: boolean;
onBrickDrop: (brick: any) => void;
};

export type Tab = 'flow' | 'music' | 'graphic';
22 changes: 22 additions & 0 deletions modules/code-builder/src/pallete/Canvas.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
interface CanvasProps {
children: React.ReactNode;
}

const Canvas: React.FC<CanvasProps> = ({ children }) => {
return (
<svg
id="Canvas"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
width="100%"
height="100%"
style={{
border: '1px solid black',
}}
>
{children}
</svg>
);
};

export default Canvas;
124 changes: 124 additions & 0 deletions modules/code-builder/src/pallete/DragHoc.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import React, { useEffect, useRef, useState } from 'react';

const getPalletteDimensions = () => {
const pallete = document.getElementById('Pallete');
if (pallete) {
const dimensions = pallete.getBoundingClientRect();
return dimensions;
}
};

const getCanvasDimensions = () => {
const canvas = document.getElementById('Canvas');
if (canvas) {
const dimensions = canvas.getBoundingClientRect();
return dimensions;
}
};

const withDraggable = (Component: React.FC<any>) => (props: any) => {
const threshold = 50;
const [isDragging, setIsDragging] = useState(false);
const [originalPos, setOriginalPos] = useState<{ x: number; y: number }>({ x: 0, y: 0 });
const [dragStartPos, setDragStartPos] = useState<{ x: number; y: number }>({ x: 0, y: 0 });
const [position, setPosition] = useState<{ x: number; y: number }>({ x: 0, y: 0 });
const svgRef = useRef<SVGSVGElement>(null);

const handleMouseDown = (event: React.MouseEvent<SVGSVGElement, MouseEvent>) => {
event.preventDefault();
const svgRect = svgRef.current?.getBoundingClientRect();
if (svgRect) {
const offsetX = event.clientX - svgRect.left;
const offsetY = event.clientY - svgRect.top;
setIsDragging(true);
setDragStartPos({ x: offsetX, y: offsetY });
setOriginalPos({ x: svgRect.x, y: svgRect.y });
}
};

const returnToPallete = () => {
console.log('originalPos', originalPos);
setPosition(originalPos);
console.log('position', position);
};

const resetPositon = () => {
console.log('dragStartPos', dragStartPos);
setPosition(dragStartPos);
console.log('position', position);
};

const handleMouseMove = (event: MouseEvent) => {
if (isDragging && svgRef.current) {
const svgRect = svgRef.current.getBoundingClientRect();
const offsetX = event.clientX - svgRect.left;
const offsetY = event.clientY - svgRect.top;

const deltaX = offsetX - dragStartPos.x;
const deltaY = offsetY - dragStartPos.y;

setPosition((prevPosition) => ({
x: prevPosition.x + deltaX,
y: prevPosition.y + deltaY,
}));
}
};

const handleMouseUp = (event: MouseEvent) => {
if (isDragging) {
const svgRect = svgRef.current?.getBoundingClientRect();
const canvasDimensions = getCanvasDimensions();
const palletteDimensions = getPalletteDimensions();
if (svgRect && canvasDimensions && palletteDimensions) {
if (
svgRect.right > canvasDimensions.right ||
svgRect.top < canvasDimensions.top ||
svgRect.bottom > canvasDimensions.bottom ||
svgRect.left < palletteDimensions.left ||
svgRect.top < palletteDimensions.top ||
svgRect.bottom > palletteDimensions.bottom
) {
returnToPallete();
} else if (svgRect.left < canvasDimensions.left) {
resetPositon();
} else {
props.onCanvasDrop();
svgRef.current?.removeChild(svgRef.current?.children[0]);
}
}
setIsDragging(false);
}
};

useEffect(() => {
if (isDragging) {
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseup', handleMouseUp);
};
}
}, [isDragging]);

return (
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
ref={svgRef}
onMouseDown={handleMouseDown}
transform={`translate(${position.x}, ${position.y})`}
style={{
width: svgRef.current?.children[0].getBoundingClientRect().width,
height: svgRef.current?.children[0].getBoundingClientRect().height,
position: 'absolute',
overflow: 'hidden',
zIndex: 100,
}}
>
<Component {...props} />
</svg>
);
};

export default withDraggable;
112 changes: 112 additions & 0 deletions modules/code-builder/src/pallete/Pallete.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { TBrickArgDataType } from '@/@types/brick';
import { PalleteProps, Tab } from '@/@types/pallete';
import { BrickStatement, ModelBrickStatement } from '@/brick';
import { useEffect, useState } from 'react';
import withDraggable from './DragHoc';
import './pallete.scss';

const Pallete = (PalleteProps: PalleteProps) => {
const { config, reset, onBrickDrop } = PalleteProps;
const [search, setSearch] = useState('');
const [selectedTab, setSelectedTab] = useState<Tab>('flow');
const [data, setData] = useState(config.data);
const instance = new ModelBrickStatement({
label: 'Statement',
args: Object.fromEntries(
[].map<
[
string,
{
label: string;
dataType: TBrickArgDataType;
meta: unknown;
},
]
>((name) => [name, { label: name, dataType: 'any', meta: undefined }]),
),
colorBg: 'lightgreen',
colorFg: 'black',
outline: 'green',
scale: 2,
glyph: '',
connectAbove: true,
connectBelow: true,
name: '',
});

const DragBrick = withDraggable(BrickStatement);

const searchBlocks = (search: string) => {
if (search === '') {
setSearch('');
setSelectedTab('flow');
setData(config.data);
return;
}
const newData = data.filter((block) => {
return block;
});
setData([]);
};

useEffect(() => {
if (reset) {
setSearch('');
setSelectedTab('flow');
setData(config.data);
}
}, [reset]);

return (
<div className="palleteContainer" id="Pallete">
<span>Pallete</span>
<div className="tabContainer">
<button
className="tab"
onClick={() => setSelectedTab('flow')}
style={{
backgroundColor: selectedTab === 'flow' ? '#0096FF' : 'white',
color: selectedTab === 'flow' ? 'white' : 'black',
}}
>
Flow
</button>
<button
className="tab"
onClick={() => setSelectedTab('music')}
style={{
backgroundColor: selectedTab === 'music' ? '#0096FF' : 'white',
color: selectedTab === 'music' ? 'white' : 'black',
}}
>
Music
</button>
<button
className="tab"
onClick={() => setSelectedTab('graphic')}
style={{
backgroundColor: selectedTab === 'graphic' ? '#0096FF' : 'white',
color: selectedTab === 'graphic' ? 'white' : 'black',
}}
>
Graphic
</button>
</div>
<div className="searchContainer">
<input
type="text"
placeholder="Search"
value={search}
onChange={(e) => setSearch(e.target.value)}
className="search"
onSubmit={() => searchBlocks(search)}
/>
</div>
<div className="blocksContainer">
<DragBrick instance={instance} onCanvasDrop={onBrickDrop} />
</div>
</div>
);
};

export default Pallete;
83 changes: 83 additions & 0 deletions modules/code-builder/src/pallete/Playground.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { TBrickArgDataType } from '@/@types/brick';
import { BrickStatement, ModelBrickStatement } from '@/brick';
import { useState } from 'react';
import Canvas from './Canvas';
import withDraggable from './DragHoc';
import Pallete from './Pallete';

const Playground = () => {
const [reset, setReset] = useState(false);

const [elements, setElements] = useState<JSX.Element[]>([]);
const instance = new ModelBrickStatement({
label: 'Statement',
args: Object.fromEntries(
[].map<
[
string,
{
label: string;
dataType: TBrickArgDataType;
meta: unknown;
},
]
>((name) => [name, { label: name, dataType: 'any', meta: undefined }]),
),
colorBg: 'lightgreen',
colorFg: 'black',
outline: 'green',
scale: 2,
glyph: '',
connectAbove: true,
connectBelow: true,
name: '',
});

const handleBrickDrop = () => {
console.log('handleBrickDrop');
const DragBrick = withDraggable(BrickStatement);
const newElement = <DragBrick instance={instance} />;
setElements([...elements, newElement]);
setReset(true);
};

return (
<div
style={{
display: 'flex',
flexDirection: 'row',
width: '85vw',
minHeight: '95vh',
border: '1px solid black',
}}
>
<div
style={{
display: 'flex',
flexDirection: 'column',
width: '35%',
height: '95vh',
}}
>
<Pallete
config={{
data: [],
}}
onBrickDrop={handleBrickDrop}
reset={reset}
/>
</div>
<div
style={{
display: 'flex',
flexDirection: 'column',
width: '65%',
}}
>
<Canvas>{elements}</Canvas>
</div>
</div>
);
};

export default Playground;
Loading
Loading