Merge branch 'main' into simulation

This commit is contained in:
2025-03-26 11:24:00 +05:30
206 changed files with 17562 additions and 17397 deletions

View File

@@ -1,25 +1,25 @@
#!/usr/bin/env bash #!/usr/bin/env bash
echo "Running pre-commit hook..." echo "Running pre-commit hook..."
# Compile TypeScript # Compile TypeScript
echo "Compiling TypeScript..." echo "Compiling TypeScript..."
npx tsc scripts/validate-filenames.ts npx tsc scripts/validate-filenames.ts
# if [ $? -ne 0 ]; then # if [ $? -ne 0 ]; then
# echo "TypeScript compilation failed. Aborting commit." # echo "TypeScript compilation failed. Aborting commit."
# exit 1 # exit 1
# fi # fi
echo "TypeScript compilation successful." echo "TypeScript compilation successful."
# Run Node.js script # Run Node.js script
echo "Running Node.js script..." echo "Running Node.js script..."
node scripts/validate-filenames.js --no-prompt node scripts/validate-filenames.js --no-prompt
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Node.js script failed. Aborting commit." echo "Node.js script failed. Aborting commit."
exit 1 exit 1
fi fi
echo "Pre-commit hook completed successfully." echo "Pre-commit hook completed successfully."

View File

@@ -1,25 +1,25 @@
#!/usr/bin/env bash #!/usr/bin/env bash
echo "Running pre-commit hook..." echo "Running pre-commit hook..."
# Compile TypeScript # Compile TypeScript
echo "Compiling TypeScript..." echo "Compiling TypeScript..."
npx tsc scripts/validate-filenames.ts npx tsc scripts/validate-filenames.ts
# if [ $? -ne 0 ]; then # if [ $? -ne 0 ]; then
# echo "TypeScript compilation failed. Aborting commit." # echo "TypeScript compilation failed. Aborting commit."
# exit 1 # exit 1
# fi # fi
echo "TypeScript compilation successful." echo "TypeScript compilation successful."
# Run Node.js script # Run Node.js script
echo "Running Node.js script..." echo "Running Node.js script..."
node scripts/validate-filenames.js --no-prompt node scripts/validate-filenames.js --no-prompt
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Node.js script failed. Aborting commit." echo "Node.js script failed. Aborting commit."
exit 1 exit 1
fi fi
echo "Pre-commit hook completed successfully." echo "Pre-commit hook completed successfully."

View File

@@ -1,51 +1,51 @@
# Use the argument for node version (defaults to 'lts' if not provided) # Use the argument for node version (defaults to 'lts' if not provided)
ARG NODE_VERSION=lts ARG NODE_VERSION=lts
# Stage 1: Build React App # Stage 1: Build React App
FROM node:${NODE_VERSION}-alpine AS development FROM node:${NODE_VERSION}-alpine AS development
# Set the Node.js environment to development # Set the Node.js environment to development
ENV NODE_ENV=development ENV NODE_ENV=development
# Define build arguments for the API base URLs # Define build arguments for the API base URLs
ARG REACT_APP_SERVER_SOCKET_API_BASE_URL ARG REACT_APP_SERVER_SOCKET_API_BASE_URL
ARG REACT_APP_SERVER_REST_API_BASE_URL ARG REACT_APP_SERVER_REST_API_BASE_URL
ARG REACT_APP_SERVER_MARKETPLACE_URL ARG REACT_APP_SERVER_MARKETPLACE_URL
# Set environment variables for the API base URLs using the build arguments # Set environment variables for the API base URLs using the build arguments
ENV REACT_APP_SERVER_SOCKET_API_BASE_URL=${REACT_APP_SERVER_SOCKET_API_BASE_URL} ENV REACT_APP_SERVER_SOCKET_API_BASE_URL=${REACT_APP_SERVER_SOCKET_API_BASE_URL}
ENV REACT_APP_SERVER_REST_API_BASE_URL=${REACT_APP_SERVER_REST_API_BASE_URL} ENV REACT_APP_SERVER_REST_API_BASE_URL=${REACT_APP_SERVER_REST_API_BASE_URL}
ENV REACT_APP_SERVER_MARKETPLACE_URL=${REACT_APP_SERVER_MARKETPLACE_URL} ENV REACT_APP_SERVER_MARKETPLACE_URL=${REACT_APP_SERVER_MARKETPLACE_URL}
# Set working directory for frontend code # Set working directory for frontend code
WORKDIR /frontend WORKDIR /frontend
# Copy package.json and package-lock.json for npm install # Copy package.json and package-lock.json for npm install
COPY package*.json ./ COPY package*.json ./
# Install the latest npm version # Install the latest npm version
RUN npm install -g npm RUN npm install -g npm
# Install dependencies (this includes react-scripts) # Install dependencies (this includes react-scripts)
RUN npm install --legacy-peer-deps RUN npm install --legacy-peer-deps
# Copy the rest of the application code # Copy the rest of the application code
COPY . . COPY . .
# Run the build command (build the React app) # Run the build command (build the React app)
RUN npm run build RUN npm run build
# Stage 2: Serve with Nginx # Stage 2: Serve with Nginx
FROM nginx:alpine FROM nginx:alpine
# Copy the built React files from the build stage into Nginx's default HTML folder # Copy the built React files from the build stage into Nginx's default HTML folder
COPY --from=development /frontend/build /usr/share/nginx/html COPY --from=development /frontend/build /usr/share/nginx/html
# Optionally copy a custom Nginx config (if needed) # Optionally copy a custom Nginx config (if needed)
COPY nginx.conf /etc/nginx/conf.d/default.conf COPY nginx.conf /etc/nginx/conf.d/default.conf
# Expose port 80 for Nginx (default HTTP port) # Expose port 80 for Nginx (default HTTP port)
EXPOSE 80 EXPOSE 80
# Start Nginx in the foreground (this is required to keep the container running) # Start Nginx in the foreground (this is required to keep the container running)
CMD ["nginx", "-g", "daemon off;"] CMD ["nginx", "-g", "daemon off;"]

View File

@@ -1,99 +1,99 @@
## Getting Started ## Getting Started
Follow these steps to set up and run the project locally. Follow these steps to set up and run the project locally.
### Prerequisites ### Prerequisites
Ensure you have the following installed on your system: Ensure you have the following installed on your system:
- **Node.js**: [Download and install Node.js](https://nodejs.org/) - **Node.js**: [Download and install Node.js](https://nodejs.org/)
- **npm**: Comes with Node.js, but you can also install [npm separately](https://www.npmjs.com/get-npm) - **npm**: Comes with Node.js, but you can also install [npm separately](https://www.npmjs.com/get-npm)
- **yarn (optional)**: If you prefer to use Yarn, [install it here](https://yarnpkg.com/) - **yarn (optional)**: If you prefer to use Yarn, [install it here](https://yarnpkg.com/)
- **TypeScript**: This project uses TypeScript, and the necessary dependencies will be installed automatically. - **TypeScript**: This project uses TypeScript, and the necessary dependencies will be installed automatically.
### Installation ### Installation
1. Clone the repository: 1. Clone the repository:
```bash ```bash
git clone https://github.com/S0Vishnu/react-production-project-boilerplate.git git clone https://github.com/S0Vishnu/react-production-project-boilerplate.git
cd react-production-project-boilerplate cd react-production-project-boilerplate
``` ```
2. Cloning repository with User Credentials: 2. Cloning repository with User Credentials:
```bash ```bash
git clone https://your_username:password@github.com/S0Vishnu/react-production-project-boilerplate.git git clone https://your_username:password@github.com/S0Vishnu/react-production-project-boilerplate.git
cd react-production-project-boilerplate cd react-production-project-boilerplate
``` ```
note: if password contains special charecters use: note: if password contains special charecters use:
- @ → %40 - @ → %40
- : → %3A - : → %3A
- / → %2F - / → %2F
- ? → %3F - ? → %3F
- & → %26 - & → %26
- = → %3D - = → %3D
- ! → %21 - ! → %21
2. Install the dependencies: 2. Install the dependencies:
```bash ```bash
npm install npm install
``` ```
3. Start server: 3. Start server:
```bash ```bash
npm start npm start
``` ```
4. Build the app for production: 4. Build the app for production:
```bash ```bash
npm run build npm run build
``` ```
5. Tests 5. Tests
This project includes both **unit tests** using **Jest** and **end-to-end (E2E) tests** using **Cypress**. Heres how you can run and manage these tests. This project includes both **unit tests** using **Jest** and **end-to-end (E2E) tests** using **Cypress**. Heres how you can run and manage these tests.
**Unit Tests (Jest)** **Unit Tests (Jest)**
Unit tests are located in the `src/tests/unit/` directory. They test individual components and functions to ensure they work as expected. **Jest** is used for running these tests. Unit tests are located in the `src/tests/unit/` directory. They test individual components and functions to ensure they work as expected. **Jest** is used for running these tests.
**Running Unit Tests** **Running Unit Tests**
To run the unit tests, use the following command: To run the unit tests, use the following command:
```bash ```bash
npm run test npm run test
``` ```
**End-to-End (E2E) Tests (Cypress)** **End-to-End (E2E) Tests (Cypress)**
Cypress can be run in two modes Cypress can be run in two modes
1. Interactive Mode: 1. Interactive Mode:
```bash ```bash
npm run cypress:open npm run cypress:open
``` ```
2. Headless Mode: 2. Headless Mode:
```bash ```bash
npm run cypress:run npm run cypress:run
``` ```
### Run Documentation(Docsify) ### Run Documentation(Docsify)
1. Installation (if needed): 1. Installation (if needed):
```bash ```bash
npm i docsify-cli -g npm i docsify-cli -g
``` ```
2. Run Command: 2. Run Command:
```bash ```bash
docsify serve docs docsify serve docs
``` ```

View File

@@ -1,18 +1,18 @@
# Boilerplate Project # Boilerplate Project
A **Boilerplate Project** designed to jumpstart your development process with a clean, organized, and scalable structure. A **Boilerplate Project** designed to jumpstart your development process with a clean, organized, and scalable structure.
## Features ## Features
- **Pre-configured Tooling**: Includes [Tool1], [Tool2], and [Tool3] for seamless development. - **Pre-configured Tooling**: Includes [Tool1], [Tool2], and [Tool3] for seamless development.
- **Modular Structure**: Organized folder structure for scalability and maintainability. - **Modular Structure**: Organized folder structure for scalability and maintainability.
- **Best Practices**: Follows industry standards for coding, linting, and testing. - **Best Practices**: Follows industry standards for coding, linting, and testing.
- **Cross-Environment Compatibility**: Ready for local, staging, and production environments. - **Cross-Environment Compatibility**: Ready for local, staging, and production environments.
## Technologies Used ## Technologies Used
- **Frontend**: React - **Frontend**: React
- **Backend**: Node.js - **Backend**: Node.js
- **Database**: [MongoDB, PostgreSQL, MySQL, etc.] - **Database**: [MongoDB, PostgreSQL, MySQL, etc.]
- **Build Tools**: Webpack - **Build Tools**: Webpack
- **Testing**: Jest - **Testing**: Jest

View File

@@ -1,12 +1,12 @@
- [Get Started](/README.md) - [Get Started](/README.md)
<!-- Documetations Section (start)--> <!-- Documetations Section (start)-->
<!-- Documetations Section (end)--> <!-- Documetations Section (end)-->
- [Git Commands](./documents/gitNotes.md) - [Git Commands](./documents/gitNotes.md)
- [Notes and Guidlines](./documents/notes.md) - [Notes and Guidlines](./documents/notes.md)
- [Project Structure](./documents/projectStructure.md) - [Project Structure](./documents/projectStructure.md)
- [How to Document](./documents/documentationGuide.md) - [How to Document](./documents/documentationGuide.md)
- [How to Write a Markdown (.md)](./documents/markdownGuide.md) - [How to Write a Markdown (.md)](./documents/markdownGuide.md)
- [Docsify Overview](./documents/docsifyGuide.md) - [Docsify Overview](./documents/docsifyGuide.md)

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,35 +1,35 @@
# Quick start # Quick start
It is recommended to install `docsify-cli` globally, which helps initializing and previewing the website locally. It is recommended to install `docsify-cli` globally, which helps initializing and previewing the website locally.
```bash ```bash
npm i docsify-cli -g npm i docsify-cli -g
``` ```
### Initialize ### Initialize
If you want to write the documentation in the `./docs` subdirectory, you can use the `init` command. If you want to write the documentation in the `./docs` subdirectory, you can use the `init` command.
```bash ```bash
docsify init ./docs docsify init ./docs
``` ```
### Writing content ### Writing content
After the `init` is complete, you can see the file list in the `./docs` subdirectory. After the `init` is complete, you can see the file list in the `./docs` subdirectory.
- `index.html` as the entry file - `index.html` as the entry file
- `README.md` as the home page - `README.md` as the home page
- `.nojekyll` prevents GitHub Pages from ignoring files that begin with an underscore - `.nojekyll` prevents GitHub Pages from ignoring files that begin with an underscore
You can easily update the documentation in `./docs/README.md`, of course you can add more pages. You can easily update the documentation in `./docs/README.md`, of course you can add more pages.
### Preview your site ### Preview your site
Run the local server with `docsify serve`. You can preview your site in your browser on `http://localhost:3000`. Run the local server with `docsify serve`. You can preview your site in your browser on `http://localhost:3000`.
```bash ```bash
docsify serve docs docsify serve docs
``` ```
?> For more use cases of `docsify-cli`, head over to the [docsify-cli documentation](https://github.com/docsifyjs/docsify-cli). ?> For more use cases of `docsify-cli`, head over to the [docsify-cli documentation](https://github.com/docsifyjs/docsify-cli).

View File

@@ -1,380 +1,380 @@
# Why Documentation is Important for Developers # Why Documentation is Important for Developers
Documentation helps developers work efficiently and ensures projects run smoothly. Heres why its crucial: Documentation helps developers work efficiently and ensures projects run smoothly. Heres why its crucial:
1. **Knowledge Sharing**: It helps team members understand the system and communicate effectively, especially when new people join the project. 1. **Knowledge Sharing**: It helps team members understand the system and communicate effectively, especially when new people join the project.
2. **Code Maintenance**: Good documentation makes it easier to fix bugs, make updates, and keep the code consistent. 2. **Code Maintenance**: Good documentation makes it easier to fix bugs, make updates, and keep the code consistent.
3. **Project Longevity**: It ensures that project knowledge is preserved, so future developers can maintain or improve the code without confusion. 3. **Project Longevity**: It ensures that project knowledge is preserved, so future developers can maintain or improve the code without confusion.
4. **Troubleshooting**: Developers can quickly find solutions to problems or understand past decisions, saving time and reducing errors. 4. **Troubleshooting**: Developers can quickly find solutions to problems or understand past decisions, saving time and reducing errors.
5. **Testing and Quality**: Documentation helps ensure the right testing processes are followed, leading to better-quality code. 5. **Testing and Quality**: Documentation helps ensure the right testing processes are followed, leading to better-quality code.
6. **Efficiency**: It saves time by reducing the need to explain things repeatedly or search for answers. 6. **Efficiency**: It saves time by reducing the need to explain things repeatedly or search for answers.
In short, internal documentation keeps projects organized, helps teams collaborate, and ensures the software can be maintained and improved over time. In short, internal documentation keeps projects organized, helps teams collaborate, and ensures the software can be maintained and improved over time.
--- ---
## Guide to Writing Modular Documentation for React Projects ## Guide to Writing Modular Documentation for React Projects
Modular documentation refers to organizing your documentation into independent, reusable sections or modules. Each module typically covers a specific part of your project, making it easier to update and navigate. Modular documentation refers to organizing your documentation into independent, reusable sections or modules. Each module typically covers a specific part of your project, making it easier to update and navigate.
In the context of React, modular documentation should cover both React components and the overall architecture of the app. In the context of React, modular documentation should cover both React components and the overall architecture of the app.
### Split Documentation into Smaller Sections ### Split Documentation into Smaller Sections
When documenting, break down each part of your codebase into its smallest logical unit: When documenting, break down each part of your codebase into its smallest logical unit:
1. **Functions**: Explain its purpose, inputs (arguments), and outputs (returns). 1. **Functions**: Explain its purpose, inputs (arguments), and outputs (returns).
2. **Components**: Detail props, their types, default values, and the UI they render. 2. **Components**: Detail props, their types, default values, and the UI they render.
3. **Utilities/Helpers**: Document what a utility does, its inputs, and outputs. 3. **Utilities/Helpers**: Document what a utility does, its inputs, and outputs.
4. **APIs**: Cover the endpoint, request format, and expected response. 4. **APIs**: Cover the endpoint, request format, and expected response.
Each section should have a consistent structure for easy understanding and reference. Each section should have a consistent structure for easy understanding and reference.
## Documenting Functions ## Documenting Functions
#### Structure for Documenting Functions #### Structure for Documenting Functions
1. **Function Name**: A short and descriptive name. 1. **Function Name**: A short and descriptive name.
2. **Purpose**: Briefly explain what the function does. 2. **Purpose**: Briefly explain what the function does.
3. **Inputs**: 3. **Inputs**:
- List each parameter. - List each parameter.
- Include types and default values if applicable. - Include types and default values if applicable.
4. **Output**: Describe the return value and its type. 4. **Output**: Describe the return value and its type.
5. **Code Examples**: Provide a usage example. 5. **Code Examples**: Provide a usage example.
#### Example: Utility Function Documentation #### Example: Utility Function Documentation
````markdown ````markdown
## `formatDate` ## `formatDate`
### Purpose ### Purpose
The `formatDate` function converts a `Date` object into a human-readable string format. The `formatDate` function converts a `Date` object into a human-readable string format.
### Inputs ### Inputs
| Parameter | Type | Default Value | Description | | Parameter | Type | Default Value | Description |
| --------- | -------- | ------------- | -------------------------- | | --------- | -------- | ------------- | -------------------------- |
| `date` | `Date` | - | The date object to format. | | `date` | `Date` | - | The date object to format. |
| `locale` | `string` | `"en-US"` | The locale for formatting. | | `locale` | `string` | `"en-US"` | The locale for formatting. |
### Output ### Output
Returns a `string` representing the formatted date. Returns a `string` representing the formatted date.
### Example ### Example
```javascript ```javascript
import { formatDate } from "./utils"; import { formatDate } from "./utils";
const date = new Date("2024-11-21"); const date = new Date("2024-11-21");
console.log(formatDate(date)); // Output: "November 21, 2024" console.log(formatDate(date)); // Output: "November 21, 2024"
``` ```
```` ````
## Documenting Components ## Documenting Components
#### Structure for Documenting Components #### Structure for Documenting Components
1. **Component Name**: Name of the React component. 1. **Component Name**: Name of the React component.
2. **Purpose**: Explain what the component is for and its use case. 2. **Purpose**: Explain what the component is for and its use case.
3. **Props**: 3. **Props**:
- List each prop. - List each prop.
- Include type, whether its required, and default value. - Include type, whether its required, and default value.
4. **Behavior**: Describe what the component does and any side effects. 4. **Behavior**: Describe what the component does and any side effects.
5. **Output**: Explain what the component renders or returns. 5. **Output**: Explain what the component renders or returns.
6. **Code Examples**: Show how to use the component. 6. **Code Examples**: Show how to use the component.
#### Example: Component Documentation #### Example: Component Documentation
`````markdown `````markdown
## `Button` ## `Button`
### Purpose ### Purpose
The `Button` component renders a clickable button with customizable styles and behavior. The `Button` component renders a clickable button with customizable styles and behavior.
### Props ### Props
| Prop Name | Type | Required | Default Value | Description | | Prop Name | Type | Required | Default Value | Description |
| ---------- | ---------- | -------- | ------------- | ---------------------------------- | | ---------- | ---------- | -------- | ------------- | ---------------------------------- |
| `label` | `string` | Yes | - | The text displayed on the button. | | `label` | `string` | Yes | - | The text displayed on the button. |
| `onClick` | `function` | No | `() => {}` | The function to call when clicked. | | `onClick` | `function` | No | `() => {}` | The function to call when clicked. |
| `disabled` | `boolean` | No | `false` | Disables the button if true. | | `disabled` | `boolean` | No | `false` | Disables the button if true. |
| `style` | `object` | No | `{}` | Inline styles for the button. | | `style` | `object` | No | `{}` | Inline styles for the button. |
### Behavior ### Behavior
- If `disabled` is true, the button cannot be clicked. - If `disabled` is true, the button cannot be clicked.
- The `onClick` function will only be called when the button is enabled. - The `onClick` function will only be called when the button is enabled.
### Output ### Output
Renders a `<button>` element styled based on the passed props. Renders a `<button>` element styled based on the passed props.
### Example ### Example
```jsx ```jsx
import Button from "./components/Button"; import Button from "./components/Button";
<Button <Button
label="Submit" label="Submit"
onClick={() => console.log("Clicked")} onClick={() => console.log("Clicked")}
disabled={false} disabled={false}
style={{ color: "white", backgroundColor: "blue" }} style={{ color: "white", backgroundColor: "blue" }}
/>; />;
``` ```
## Documenting Advanced Components ## Documenting Advanced Components
For components with complex functionality (e.g., controlled components, form components, or components interacting with APIs), follow these additional guidelines: For components with complex functionality (e.g., controlled components, form components, or components interacting with APIs), follow these additional guidelines:
1. **State Management**: Document the state it manages and how to interact with it. 1. **State Management**: Document the state it manages and how to interact with it.
2. **Lifecycle**: If it uses React lifecycle methods or hooks, explain their purpose. 2. **Lifecycle**: If it uses React lifecycle methods or hooks, explain their purpose.
3. **Events**: Document events (e.g., `onChange`, `onBlur`) and their payloads. 3. **Events**: Document events (e.g., `onChange`, `onBlur`) and their payloads.
#### Example: Complex Component Documentation #### Example: Complex Component Documentation
````markdown ````markdown
## `SearchBar` ## `SearchBar`
### Purpose ### Purpose
The `SearchBar` component provides a text input for users to search and emits search queries through the `onSearch` event. The `SearchBar` component provides a text input for users to search and emits search queries through the `onSearch` event.
### Props ### Props
| Prop Name | Type | Required | Default Value | Description | | Prop Name | Type | Required | Default Value | Description |
| ------------- | ---------- | -------- | ------------- | -------------------------------------------- | | ------------- | ---------- | -------- | ------------- | -------------------------------------------- |
| `placeholder` | `string` | No | `"Search..."` | The placeholder text for the input. | | `placeholder` | `string` | No | `"Search..."` | The placeholder text for the input. |
| `onSearch` | `function` | Yes | - | Callback fired when the search is submitted. | | `onSearch` | `function` | Yes | - | Callback fired when the search is submitted. |
| `debounce` | `number` | No | `300` | Time in milliseconds to debounce user input. | | `debounce` | `number` | No | `300` | Time in milliseconds to debounce user input. |
### Behavior ### Behavior
1. The component manages the `inputValue` state. 1. The component manages the `inputValue` state.
2. After the user stops typing for the `debounce` duration, it triggers the `onSearch` callback with the input value. 2. After the user stops typing for the `debounce` duration, it triggers the `onSearch` callback with the input value.
### Output ### Output
Renders: Renders:
- A `<div>` wrapper. - A `<div>` wrapper.
- An `<input>` field styled with default or custom styles. - An `<input>` field styled with default or custom styles.
### Example ### Example
```jsx ```jsx
import SearchBar from "./components/SearchBar"; import SearchBar from "./components/SearchBar";
<SearchBar <SearchBar
placeholder="Search items..." placeholder="Search items..."
onSearch={(query) => console.log(query)} onSearch={(query) => console.log(query)}
debounce={500} debounce={500}
/>; />;
``` ```
```` ````
````` `````
## Documenting Custom Hooks ## Documenting Custom Hooks
#### Structure for Documenting Hooks #### Structure for Documenting Hooks
1. **Hook Name**: Name of the hook. 1. **Hook Name**: Name of the hook.
2. **Purpose**: Why its used and what it does. 2. **Purpose**: Why its used and what it does.
3. **Inputs**: Parameters passed to the hook. 3. **Inputs**: Parameters passed to the hook.
4. **State/Outputs**: State or values returned by the hook. 4. **State/Outputs**: State or values returned by the hook.
5. **Usage**: Show an example. 5. **Usage**: Show an example.
#### Example: Hook Documentation #### Example: Hook Documentation
````markdown ````markdown
## `useFetch` ## `useFetch`
### Purpose ### Purpose
The `useFetch` hook manages data fetching and provides loading, error, and response states. The `useFetch` hook manages data fetching and provides loading, error, and response states.
### Inputs ### Inputs
| Parameter | Type | Required | Default Value | Description | | Parameter | Type | Required | Default Value | Description |
| --------- | -------- | -------- | ------------- | ------------------------------------- | | --------- | -------- | -------- | ------------- | ------------------------------------- |
| `url` | `string` | Yes | - | The endpoint to fetch data from. | | `url` | `string` | Yes | - | The endpoint to fetch data from. |
| `options` | `object` | No | `{}` | Fetch options like headers or method. | | `options` | `object` | No | `{}` | Fetch options like headers or method. |
### State/Outputs ### State/Outputs
| State Name | Type | Description | | State Name | Type | Description |
| ---------- | --------- | ---------------------------------------- | | ---------- | --------- | ---------------------------------------- |
| `data` | `any` | The response data from the API. | | `data` | `any` | The response data from the API. |
| `loading` | `boolean` | Indicates if the request is in progress. | | `loading` | `boolean` | Indicates if the request is in progress. |
| `error` | `object` | The error object if the request fails. | | `error` | `object` | The error object if the request fails. |
### Example ### Example
```javascript ```javascript
import { useFetch } from "./hooks/useFetch"; import { useFetch } from "./hooks/useFetch";
const MyComponent = () => { const MyComponent = () => {
const { data, loading, error } = useFetch("/api/data"); const { data, loading, error } = useFetch("/api/data");
if (loading) return <p>Loading...</p>; if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>; if (error) return <p>Error: {error.message}</p>;
return <div>{JSON.stringify(data)}</div>; return <div>{JSON.stringify(data)}</div>;
}; };
``` ```
```` ````
#### General Best Practices for Modular Documentation #### General Best Practices for Modular Documentation
1. **Be Consistent**: Use the same format for all functions, components, and hooks. 1. **Be Consistent**: Use the same format for all functions, components, and hooks.
2. **Focus on Inputs and Outputs**: Developers care about what they give and what they get. 2. **Focus on Inputs and Outputs**: Developers care about what they give and what they get.
3. **Use Examples**: Code examples make documentation actionable. 3. **Use Examples**: Code examples make documentation actionable.
4. **Avoid Overloading**: Document each function/component in its own file if its complex. 4. **Avoid Overloading**: Document each function/component in its own file if its complex.
5. **Explain Behavior**: Describe any side effects, state changes, or interactions. 5. **Explain Behavior**: Describe any side effects, state changes, or interactions.
--- ---
## Guide to Managing Files and Folders for Documentation in Docsify ## Guide to Managing Files and Folders for Documentation in Docsify
Docsify is a flexible tool for generating documentation from markdown files. To keep your Docsify-based project well-organized, heres a guide on how to manage files and folders effectively. Docsify is a flexible tool for generating documentation from markdown files. To keep your Docsify-based project well-organized, heres a guide on how to manage files and folders effectively.
#### 1. Project Structure Overview #### 1. Project Structure Overview
A clean folder structure is crucial for scalability, readability, and ease of maintenance. Below is a suggested structure: A clean folder structure is crucial for scalability, readability, and ease of maintenance. Below is a suggested structure:
``` ```
/docs # Root folder for your Docsify project /docs # Root folder for your Docsify project
├── /assets/ # Static resources (images, videos, files, etc.) ├── /assets/ # Static resources (images, videos, files, etc.)
│ └── /images/ # Folder for images used in your docs │ └── /images/ # Folder for images used in your docs
│ └── gitWorkFlow.svg # Example image used in documentation │ └── gitWorkFlow.svg # Example image used in documentation
│ └── /videos/ # Folder for tutorial videos or related media │ └── /videos/ # Folder for tutorial videos or related media
│ └── walkthrough.mp4 # old walkthrough presentation │ └── walkthrough.mp4 # old walkthrough presentation
├── /documents/ # Folder for the main documentation content ├── /documents/ # Folder for the main documentation content
│ └── docsifyGuide.md # Documentation for setting up and using Docsify │ └── docsifyGuide.md # Documentation for setting up and using Docsify
│ └── projectStructure.md # Explanation of the project structure and organization │ └── projectStructure.md # Explanation of the project structure and organization
│ └── /components/ # Folder for documentation on different components │ └── /components/ # Folder for documentation on different components
│ └── input.md # Input component documentation │ └── input.md # Input component documentation
│ └── others.md # Other components documentation │ └── others.md # Other components documentation
│ └── etc.md # Any additional miscellaneous documentation │ └── etc.md # Any additional miscellaneous documentation
├── /style/ # Folder for custom styles ├── /style/ # Folder for custom styles
│ └── style.css # Custom CSS file for styling the documentation │ └── style.css # Custom CSS file for styling the documentation
└── index.html # Main entry point for Docsify (loads the documentation) └── index.html # Main entry point for Docsify (loads the documentation)
``` ```
--- ---
#### 2. Folder Breakdown #### 2. Folder Breakdown
- **/docs**: This is the core folder that contains all of your Markdown (`.md`) files. You can organize these files by sections or topics such as guides, API references, and tutorials. Subfolders like `/guide`, `/reference`, or `/tutorials` help keep related files together. - **/docs**: This is the core folder that contains all of your Markdown (`.md`) files. You can organize these files by sections or topics such as guides, API references, and tutorials. Subfolders like `/guide`, `/reference`, or `/tutorials` help keep related files together.
- **/assets**: This folder is for any images, diagrams, videos, or other static files referenced in your documentation. It's best to organize your media into subfolders based on the section they belong to. - **/assets**: This folder is for any images, diagrams, videos, or other static files referenced in your documentation. It's best to organize your media into subfolders based on the section they belong to.
Example: Example:
``` ```
/assets /assets
├── /images/ ├── /images/
│ ├── diagram1.png │ ├── diagram1.png
│ └── screenshot.png │ └── screenshot.png
└── /videos/ └── /videos/
└── tutorial.mp4 └── tutorial.mp4
``` ```
- **/lib**: If you want to add custom JavaScript or other scripts to enhance Docsifys functionality, place them in the `/lib` folder. This can include themes, custom navigation, or interactive features. - **/lib**: If you want to add custom JavaScript or other scripts to enhance Docsifys functionality, place them in the `/lib` folder. This can include themes, custom navigation, or interactive features.
--- ---
#### 3. Naming Conventions #### 3. Naming Conventions
Use simple, descriptive names for your files and folders. Avoid spaces in filenames—use hyphens (`-`) instead. For example: Use simple, descriptive names for your files and folders. Avoid spaces in filenames—use hyphens (`-`) instead. For example:
- **Correct**: `installation-guide.md`, `api-reference.md` - **Correct**: `installation-guide.md`, `api-reference.md`
- **Incorrect**: `installation guide.md`, `api reference.md` - **Incorrect**: `installation guide.md`, `api reference.md`
This keeps URLs and links consistent and easier to handle. This keeps URLs and links consistent and easier to handle.
--- ---
#### 4. Organizing Documentation Files #### 4. Organizing Documentation Files
1. **Homepage (index.md)**: 1. **Homepage (index.md)**:
The `index.md` file serves as the homepage for your documentation. It should provide an introduction to the project and link to other sections of your documentation. The `index.md` file serves as the homepage for your documentation. It should provide an introduction to the project and link to other sections of your documentation.
2. **Guide Section**: 2. **Guide Section**:
Place introductory content, installation instructions, and tutorials in the `/guide` folder. Each file should be named based on its content (e.g., `installation.md`, `getting-started.md`). Place introductory content, installation instructions, and tutorials in the `/guide` folder. Each file should be named based on its content (e.g., `installation.md`, `getting-started.md`).
3. **Reference Section**: 3. **Reference Section**:
For API documentation or technical references, create a `/reference` folder. You might have files like `api-reference.md`, `config.md`, or `troubleshooting.md`. For API documentation or technical references, create a `/reference` folder. You might have files like `api-reference.md`, `config.md`, or `troubleshooting.md`.
4. **Assets**: 4. **Assets**:
Organize images, videos, or diagrams in the `/assets` folder. Keep this structure consistent across sections (e.g., `/assets/images/`, `/assets/videos/`). Organize images, videos, or diagrams in the `/assets` folder. Keep this structure consistent across sections (e.g., `/assets/images/`, `/assets/videos/`).
--- ---
#### 5. Writing the \_sidebar.md File #### 5. Writing the \_sidebar.md File
The `_sidebar.md` file controls the sidebar navigation in Docsify. It defines the links that appear on the sidebar, which can point to sections of the documentation or external URLs. The `_sidebar.md` file controls the sidebar navigation in Docsify. It defines the links that appear on the sidebar, which can point to sections of the documentation or external URLs.
Heres how to structure the `_sidebar.md` file: Heres how to structure the `_sidebar.md` file:
- **Basic Structure**: - **Basic Structure**:
You can list the sections of your documentation as clickable links. Use Markdown syntax to link to the different `.md` files within your `/docs` folder. You can list the sections of your documentation as clickable links. Use Markdown syntax to link to the different `.md` files within your `/docs` folder.
Example: Example:
```markdown ```markdown
- [Home](/) # Link to the homepage - [Home](/) # Link to the homepage
- [Getting Started](/guide/intro.md) # Link to the "Getting Started" guide - [Getting Started](/guide/intro.md) # Link to the "Getting Started" guide
- [API Reference](/reference/api.md) # Link to the API documentation - [API Reference](/reference/api.md) # Link to the API documentation
- [Installation](/guide/installation.md) # Link to the installation guide - [Installation](/guide/installation.md) # Link to the installation guide
``` ```
- **Nested Links**: - **Nested Links**:
To organize sections into subcategories, you can nest links under headings. This helps create a hierarchical structure in the sidebar. To organize sections into subcategories, you can nest links under headings. This helps create a hierarchical structure in the sidebar.
Example: Example:
```markdown ```markdown
- [Home](/) - [Home](/)
- [Guide](/guide/intro.md) - [Guide](/guide/intro.md)
- [Introduction](/guide/intro.md) - [Introduction](/guide/intro.md)
- [Usage](/guide/usage.md) - [Usage](/guide/usage.md)
- [API Reference](/reference/api.md) - [API Reference](/reference/api.md)
- [Authentication](/reference/authentication.md) - [Authentication](/reference/authentication.md)
- [Endpoints](/reference/endpoints.md) - [Endpoints](/reference/endpoints.md)
``` ```
- **External Links**: - **External Links**:
You can also add external links to resources outside of your Docsify project. You can also add external links to resources outside of your Docsify project.
Example: Example:
```markdown ```markdown
- [External Resource](https://example.com) - [External Resource](https://example.com)
``` ```
--- ---
#### 6. Managing Large Projects #### 6. Managing Large Projects
For large documentation projects, its best to break content into smaller, manageable sections. This will help keep the documentation organized and make it easier for team members to collaborate. For large documentation projects, its best to break content into smaller, manageable sections. This will help keep the documentation organized and make it easier for team members to collaborate.
- **Modular Sections**: - **Modular Sections**:
Use subfolders like `/getting-started/`, `/setup/`, and `/troubleshooting/` to logically divide your content. Each section should have its own introduction, details, and examples. Use subfolders like `/getting-started/`, `/setup/`, and `/troubleshooting/` to logically divide your content. Each section should have its own introduction, details, and examples.
- **Indexing**: - **Indexing**:
Consider creating an `index.md` in each major folder (e.g., `/guide/index.md`, `/reference/index.md`) for clarity and easy navigation. Consider creating an `index.md` in each major folder (e.g., `/guide/index.md`, `/reference/index.md`) for clarity and easy navigation.
--- ---

View File

@@ -1,338 +1,338 @@
## Git basic Workflow ## Git basic Workflow
<p align="center"> <p align="center">
<img src="../assets/images/gitWorkFlow.svg" alt="Git basic Workflow"> <img src="../assets/images/gitWorkFlow.svg" alt="Git basic Workflow">
<p align="center">Fig.1 - Git basic Workflow</p> <p align="center">Fig.1 - Git basic Workflow</p>
</p> </p>
--- ---
## Git Commands ## Git Commands
1. Initialize git: 1. Initialize git:
```bash ```bash
git init git init
``` ```
2. Check remote repository: 2. Check remote repository:
```bash ```bash
git remote git remote
git remote -v git remote -v
``` ```
3. Connect to remote repository (optional): 3. Connect to remote repository (optional):
If remote repository is not connected use, If remote repository is not connected use,
```bash ```bash
git remote add origin http://185.100.212.76:7776/Vishnu/modeling_app.git git remote add origin http://185.100.212.76:7776/Vishnu/modeling_app.git
``` ```
To change url use, To change url use,
```bash ```bash
git remote set-url origin http://185.100.212.76:7776/Vishnu/modeling_app.git git remote set-url origin http://185.100.212.76:7776/Vishnu/modeling_app.git
``` ```
4. Fetch from origin: 4. Fetch from origin:
On fetch mention --all to pull all branches or mention remote_name and branch_name to fetch a particular branch. On fetch mention --all to pull all branches or mention remote_name and branch_name to fetch a particular branch.
Use --force to perform force Pull. Use --force to perform force Pull.
```bash ```bash
git fetch git fetch
git pull git pull
``` ```
5. Staging and Commit changes: 5. Staging and Commit changes:
- "." indicated all changed files will be staged. - "." indicated all changed files will be staged.
- For, specific file replace "." with the path to the specific file or directory(folder). - For, specific file replace "." with the path to the specific file or directory(folder).
- "commit message" - replace text in this phrase to your commit discription. - "commit message" - replace text in this phrase to your commit discription.
**Staging** **Staging**
```bash ```bash
git add . git add .
git add path/to/directory_or_file git add path/to/directory_or_file
``` ```
To Unstage all files that were added to the staging area but does not affect the working directory: To Unstage all files that were added to the staging area but does not affect the working directory:
```bash ```bash
git reset git reset
``` ```
**Commit** **Commit**
```bash ```bash
git commit -m "commit message" git commit -m "commit message"
``` ```
Creates a new commit that undoes the changes introduced by the specified commit, use --hard for discarding all changes since that commit (Warning: This command can permanently delete data.): Creates a new commit that undoes the changes introduced by the specified commit, use --hard for discarding all changes since that commit (Warning: This command can permanently delete data.):
```bash ```bash
git revert commit_hash git revert commit_hash
``` ```
6. Inspecting Commits: 6. Inspecting Commits:
- View the commit history: - View the commit history:
```bash ```bash
git log git log
``` ```
- View a graph of commits: - View a graph of commits:
```bash ```bash
git log --graph --oneline --all git log --graph --oneline --all
``` ```
7. Push to remote repository: 7. Push to remote repository:
- If the branch is creted for the first time and dose not located in the remote repsitory. Use, - If the branch is creted for the first time and dose not located in the remote repsitory. Use,
```bash ```bash
git push --set-upstream origin new_branch_name git push --set-upstream origin new_branch_name
``` ```
- Normal push - Normal push
```bash ```bash
git push origin new_branch_name git push origin new_branch_name
``` ```
- Force push and Safer force push - Force push and Safer force push
```bash ```bash
git push --force git push --force
git push --force-with-lease git push --force-with-lease
``` ```
- Delete branch in remote repository - Delete branch in remote repository
```bash ```bash
git push origin --delete branch_name git push origin --delete branch_name
``` ```
8. Creating and Switching Branches: 8. Creating and Switching Branches:
- To check current branch name. Use, - To check current branch name. Use,
```bash ```bash
git remote git remote
``` ```
- To checkout from current branch and move to another branch. Use, - To checkout from current branch and move to another branch. Use,
```bash ```bash
git checkout branch_name git checkout branch_name
``` ```
- To checkout from current branch and create new branch. Use, - To checkout from current branch and create new branch. Use,
```bash ```bash
git checkout -b new_branch_name git checkout -b new_branch_name
``` ```
9. Merging branches: 9. Merging branches:
- Merges the specified branch to the current active branch: - Merges the specified branch to the current active branch:
```bash ```bash
git merge branch_name git merge branch_name
``` ```
- This will only perform the merge if it can be fast-forwarded. If a fast-forward isn't possible, Git will abort the merge: - This will only perform the merge if it can be fast-forwarded. If a fast-forward isn't possible, Git will abort the merge:
```bash ```bash
git merge --ff-only branch_name git merge --ff-only branch_name
``` ```
- Provide a custom merge commit message: - Provide a custom merge commit message:
```bash ```bash
git merge -m "Custom merge message" branch_name git merge -m "Custom merge message" branch_name
``` ```
- Merge without committing automatically: - Merge without committing automatically:
```bash ```bash
git merge --no-commit branch_name git merge --no-commit branch_name
``` ```
- Continue the merge after resolving conflicts: - Continue the merge after resolving conflicts:
```bash ```bash
git merge --continue git merge --continue
``` ```
- Abort a merge in progress: - Abort a merge in progress:
```bash ```bash
git merge --abort git merge --abort
``` ```
10. Stash changes: 10. Stash changes:
- Stashes changes made in current branch: - Stashes changes made in current branch:
```bash ```bash
git stash git stash
``` ```
- Stashes changes made in current branch with message: - Stashes changes made in current branch with message:
```bash ```bash
git stash save "message" git stash save "message"
``` ```
- Apply Latest stash and apply and remove form stash list: - Apply Latest stash and apply and remove form stash list:
```bash ```bash
git stash apply git stash apply
git stash pop git stash pop
``` ```
- View Stash: - View Stash:
```bash ```bash
git stash list git stash list
``` ```
- Clear all stashes: - Clear all stashes:
```bash ```bash
git stash clear git stash clear
``` ```
- Remove the latest stash: - Remove the latest stash:
```bash ```bash
git stash drop git stash drop
``` ```
11. Branch commands: 11. Branch commands:
- To View all local and remote branches - To View all local and remote branches
```bash ```bash
git branch git branch
git branch -a git branch -a
``` ```
- To Create branch - To Create branch
```bash ```bash
git branch branch_name git branch branch_name
``` ```
- To switch between branch - To switch between branch
```bash ```bash
git checkout branch_name git checkout branch_name
``` ```
Alternatively if you want to bring the changes to the new branch, Alternatively if you want to bring the changes to the new branch,
```bash ```bash
git switch branch_name git switch branch_name
``` ```
- To switch between branch - To switch between branch
```bash ```bash
git checkout -b branch_name git checkout -b branch_name
``` ```
Alternatively, Alternatively,
```bash ```bash
git switch -c branch_name git switch -c branch_name
``` ```
- To rename branch - To rename branch
```bash ```bash
git branch -m old_branch_name new_branch_name git branch -m old_branch_name new_branch_name
``` ```
- To Delete branch (use -D to force delete) - To Delete branch (use -D to force delete)
```bash ```bash
git branch -d branch_name git branch -d branch_name
``` ```
12. Other git comments consiered usefull in previous encounters: 12. Other git comments consiered usefull in previous encounters:
- press q to exit git response - press q to exit git response
- Prevent git from creating **zoneIdentifier** files - Prevent git from creating **zoneIdentifier** files
```bash ```bash
git config core.protectNTFS false git config core.protectNTFS false
``` ```
--- ---
## Git Branching ## Git Branching
<p align="center"> <p align="center">
<img src="../assets/images/gitBranching.svg" alt="Git Branching"> <img src="../assets/images/gitBranching.svg" alt="Git Branching">
<p align="center">Fig.2 - Git Branching</p> <p align="center">Fig.2 - Git Branching</p>
</p> </p>
This diagram represents a branching model for managing the development of a software project. It uses different branches to organize and control how code changes are developed, tested, and released. Heres a breakdown of the key concepts, simplified for someone new: This diagram represents a branching model for managing the development of a software project. It uses different branches to organize and control how code changes are developed, tested, and released. Heres a breakdown of the key concepts, simplified for someone new:
### **Main Components** ### **Main Components**
1. **Main Branch** (blue line): 1. **Main Branch** (blue line):
- This branch represents the "production" or "live" version of the project. - This branch represents the "production" or "live" version of the project.
- Only stable and tested versions of the code are added here. - Only stable and tested versions of the code are added here.
- Releases like `v0.1`, `v0.2`, and `v1.0` are tagged here. - Releases like `v0.1`, `v0.2`, and `v1.0` are tagged here.
2. **Develop Branch** (purple line): 2. **Develop Branch** (purple line):
- This is where active development happens. - This is where active development happens.
- Features or fixes are integrated here before they are prepared for a release. - Features or fixes are integrated here before they are prepared for a release.
- It acts as a staging area for new work to ensure its functional and complete. - It acts as a staging area for new work to ensure its functional and complete.
3. **Feature Branches** (green lines): 3. **Feature Branches** (green lines):
- These branches are used to develop specific features or tasks. - These branches are used to develop specific features or tasks.
- Developers create a new branch for each feature and work on it independently. - Developers create a new branch for each feature and work on it independently.
- Once complete, they are merged into the **Develop Branch**. - Once complete, they are merged into the **Develop Branch**.
4. **Release Branch** (teal line): 4. **Release Branch** (teal line):
- Before a release is finalized, a release branch is created. - Before a release is finalized, a release branch is created.
- Final fixes and testing are done here to ensure stability. - Final fixes and testing are done here to ensure stability.
- Once complete, it is merged into both **Main** and **Develop** branches to mark the release. - Once complete, it is merged into both **Main** and **Develop** branches to mark the release.
5. **Hotfix Branch** (red line): 5. **Hotfix Branch** (red line):
- This branch is for urgent fixes to the live code. - This branch is for urgent fixes to the live code.
- If an issue is found in the **Main Branch** (e.g., a bug in `v0.1`), a **Hotfix Branch** is created. - If an issue is found in the **Main Branch** (e.g., a bug in `v0.1`), a **Hotfix Branch** is created.
- After fixing, it is merged into both **Main** and **Develop** to ensure the fix is applied everywhere. - After fixing, it is merged into both **Main** and **Develop** to ensure the fix is applied everywhere.
### **Workflow Summary** ### **Workflow Summary**
1. **Start a Feature:** 1. **Start a Feature:**
- Create a feature branch from the **Develop Branch**. - Create a feature branch from the **Develop Branch**.
- Work on your task and complete it. - Work on your task and complete it.
2. **Integrate Your Work:** 2. **Integrate Your Work:**
- When your feature is ready, merge it back into the **Develop Branch**. - When your feature is ready, merge it back into the **Develop Branch**.
3. **Prepare a Release:** 3. **Prepare a Release:**
- When the team decides to release a version, a **Release Branch** is created from **Develop**. - When the team decides to release a version, a **Release Branch** is created from **Develop**.
- Final adjustments are made before merging it into **Main**. - Final adjustments are made before merging it into **Main**.
4. **Fix Urgent Problems:** 4. **Fix Urgent Problems:**
- If a critical issue is found in production, create a **Hotfix Branch** from **Main**, fix it, and merge it into both **Main** and **Develop**. - If a critical issue is found in production, create a **Hotfix Branch** from **Main**, fix it, and merge it into both **Main** and **Develop**.
This system helps keep work organized, ensures stability for the live version, and allows teams to work on different features or fixes simultaneously. Its designed to make collaboration and code integration smoother. This system helps keep work organized, ensures stability for the live version, and allows teams to work on different features or fixes simultaneously. Its designed to make collaboration and code integration smoother.
--- ---
## Aditional notes ## Aditional notes
**On start the app asks wheather to pull from git or not.** **On start the app asks wheather to pull from git or not.**
- If you are connected to the remote repository, type "y" or "yes" to perform the pull action. The app will automatically abort the start process if the pull operation encounters any issues to prevent abnormalities. - If you are connected to the remote repository, type "y" or "yes" to perform the pull action. The app will automatically abort the start process if the pull operation encounters any issues to prevent abnormalities.
- If you are not connected to the remote repository, type "n" or "no" to skip the pull action and proceed with starting the app. - If you are not connected to the remote repository, type "n" or "no" to skip the pull action and proceed with starting the app.

View File

@@ -1,197 +1,197 @@
# How to Write a Markdown (.md) File for Large-Scale Projects # How to Write a Markdown (.md) File for Large-Scale Projects
## Introduction ## Introduction
Markdown (MD) is a lightweight markup language widely used in software development for documentation purposes. It is simple, easy to read, and can be converted to HTML, making it ideal for collaborative and large-scale projects. This guide will help you create well-structured, clear, and professional Markdown files tailored for use in large-scale projects. Markdown (MD) is a lightweight markup language widely used in software development for documentation purposes. It is simple, easy to read, and can be converted to HTML, making it ideal for collaborative and large-scale projects. This guide will help you create well-structured, clear, and professional Markdown files tailored for use in large-scale projects.
--- ---
## Obsidian ## Obsidian
#### What is Obsidian #### What is Obsidian
Obsidian is a powerful, feature-rich note-taking and knowledge management application designed for individuals and teams. It is highly customizable and based on plain text Markdown files, making it a versatile tool for creating, organizing, and connecting ideas. Its particularly popular among professionals, students, and researchers who use it for personal knowledge management (PKM), journaling, writing, and task management. Obsidian is a powerful, feature-rich note-taking and knowledge management application designed for individuals and teams. It is highly customizable and based on plain text Markdown files, making it a versatile tool for creating, organizing, and connecting ideas. Its particularly popular among professionals, students, and researchers who use it for personal knowledge management (PKM), journaling, writing, and task management.
All notes in Obsidian are plain text Markdown files stored locally on your computer. This ensures that your notes are portable, future-proof, and easy to access outside the application. All notes in Obsidian are plain text Markdown files stored locally on your computer. This ensures that your notes are portable, future-proof, and easy to access outside the application.
#### How to Get Started #### How to Get Started
1. Download and Install: 1. Download and Install:
- [Obsidians website](https://obsidian.md/) provides downloads for all major platforms. - [Obsidians website](https://obsidian.md/) provides downloads for all major platforms.
2. Create a Vault: 2. Create a Vault:
- A "vault" is a folder where all your Markdown notes are stored. You can have multiple vaults for different purposes. - A "vault" is a folder where all your Markdown notes are stored. You can have multiple vaults for different purposes.
3. Start Taking Notes: 3. Start Taking Notes:
- Create new notes using Markdown syntax and link them using Note Name. - Create new notes using Markdown syntax and link them using Note Name.
4. For more: 4. For more:
- [Read official Obsidian documentation](https://help.obsidian.md/Home) - [Read official Obsidian documentation](https://help.obsidian.md/Home)
--- ---
## Understanding Markdown Syntax ## Understanding Markdown Syntax
Markdown provides a straightforward syntax for formatting text. Below are the essential elements you'll need to master: Markdown provides a straightforward syntax for formatting text. Below are the essential elements you'll need to master:
#### **1. Headers** #### **1. Headers**
Headers define the structure of your document. Use `#` to denote headings, with more `#` symbols indicating smaller headings. Headers define the structure of your document. Use `#` to denote headings, with more `#` symbols indicating smaller headings.
- Example: - Example:
```markdown ```markdown
# Main Header # Main Header
## Subheader ## Subheader
### Sub-Subheader ### Sub-Subheader
``` ```
#### **2. Lists** #### **2. Lists**
Markdown supports ordered and unordered lists for organizing information. Markdown supports ordered and unordered lists for organizing information.
- Unordered list: - Unordered list:
```markdown ```markdown
- Item 1 - Item 1
- Item 2 - Item 2
``` ```
- Ordered list: - Ordered list:
```markdown ```markdown
1. Step 1 1. Step 1
2. Step 2 2. Step 2
``` ```
#### **3. Text Formatting** #### **3. Text Formatting**
- Bold: `**bold text**` - Bold: `**bold text**`
- Italic: `*italic text*` - Italic: `*italic text*`
- Inline Code: `` `inline code` `` - Inline Code: `` `inline code` ``
- Strikethrough: `~~strikethrough~~` - Strikethrough: `~~strikethrough~~`
#### **4. Links and Images** #### **4. Links and Images**
- Link: `[Link Text](URL)` - Link: `[Link Text](URL)`
- Image: `![Alt Text](Image URL)` - Image: `![Alt Text](Image URL)`
#### **5. Tables** #### **5. Tables**
Tables are useful for presenting structured data. Tables are useful for presenting structured data.
- Example: - Example:
```markdown ```markdown
| Header 1 | Header 2 | | Header 1 | Header 2 |
| -------- | -------- | | -------- | -------- |
| Row 1 | Data | | Row 1 | Data |
| Row 2 | Data | | Row 2 | Data |
``` ```
#### **6. Code Blocks** #### **6. Code Blocks**
Use triple backticks to include code blocks. Specify the programming language for syntax highlighting. Use triple backticks to include code blocks. Specify the programming language for syntax highlighting.
- Example: - Example:
````markdown ````markdown
```jsx ```jsx
console.log("Hello world"); console.log("Hello world");
``` ```
```` ````
--- ---
## Key Guidelines for Large-Scale Projects ## Key Guidelines for Large-Scale Projects
#### **1. Understand the Project Structure** #### **1. Understand the Project Structure**
Before you start writing, familiarize yourself with the project's directory and the purpose of the documentation. In large projects, MD files often serve specific roles, such as: Before you start writing, familiarize yourself with the project's directory and the purpose of the documentation. In large projects, MD files often serve specific roles, such as:
- **README.md**: A high-level overview of the project. - **README.md**: A high-level overview of the project.
- **CONTRIBUTING.md**: Guidelines for contributing to the project. - **CONTRIBUTING.md**: Guidelines for contributing to the project.
- **CHANGELOG.md**: Records of changes made over time. - **CHANGELOG.md**: Records of changes made over time.
- **API.md**: Detailed documentation of APIs. - **API.md**: Detailed documentation of APIs.
#### **2. Write for Your Audience** #### **2. Write for Your Audience**
- Identify the primary readers of the document (e.g., developers, testers, stakeholders). - Identify the primary readers of the document (e.g., developers, testers, stakeholders).
- Use technical terms appropriately and explain jargon when necessary. - Use technical terms appropriately and explain jargon when necessary.
#### **3. Maintain Consistency** #### **3. Maintain Consistency**
- Follow a consistent style, tone, and structure across all Markdown files. - Follow a consistent style, tone, and structure across all Markdown files.
- Adhere to any project-specific conventions or style guides. - Adhere to any project-specific conventions or style guides.
#### **4. Use Comments Wisely** #### **4. Use Comments Wisely**
Markdown does not support native comments, but you can use HTML-style comments for notes that should not appear in the rendered file. Markdown does not support native comments, but you can use HTML-style comments for notes that should not appear in the rendered file.
- Example: - Example:
```markdown ```markdown
<!-- This is a comment --> <!-- This is a comment -->
``` ```
--- ---
## Checklist for Writing a Quality Markdown File ## Checklist for Writing a Quality Markdown File
1. **Start with a Purpose** 1. **Start with a Purpose**
Begin your document with a clear purpose or summary of what it covers. Begin your document with a clear purpose or summary of what it covers.
2. **Follow a Logical Flow** 2. **Follow a Logical Flow**
Organize information hierarchically using headings and subheadings. Organize information hierarchically using headings and subheadings.
3. **Be Concise and Clear** 3. **Be Concise and Clear**
Avoid redundant information. Use simple language where possible. Avoid redundant information. Use simple language where possible.
4. **Incorporate Visual Aids** 4. **Incorporate Visual Aids**
Use tables, images, or diagrams to explain complex topics. Use tables, images, or diagrams to explain complex topics.
5. **Test and Validate** 5. **Test and Validate**
- Render your Markdown file locally or in the projects preferred Markdown viewer to ensure formatting works as expected. - Render your Markdown file locally or in the projects preferred Markdown viewer to ensure formatting works as expected.
- Use tools like **MarkdownLint** to check for common syntax errors. - Use tools like **MarkdownLint** to check for common syntax errors.
6. **Link to Other Resources** 6. **Link to Other Resources**
Provide hyperlinks to related MD files or external resources. Provide hyperlinks to related MD files or external resources.
7. **Version Control** 7. **Version Control**
Use version control (e.g., Git) to track changes and maintain a clear history of updates. Use version control (e.g., Git) to track changes and maintain a clear history of updates.
--- ---
## Example: Simple README.md Template ## Example: Simple README.md Template
````markdown ````markdown
# Project Title # Project Title
## Description ## Description
Provide a brief overview of the project, its purpose, and key features. Provide a brief overview of the project, its purpose, and key features.
## Installation ## Installation
Explain how to set up the project. Explain how to set up the project.
```bash ```bash
# Example installation command # Example installation command
pip install project-name pip install project-name
``` ```
```` ````
## Usage ## Usage
Provide examples of how to use the project. Provide examples of how to use the project.
```python ```python
# Example usage # Example usage
from project import feature from project import feature
feature.run() feature.run()
``` ```
--- ---
## External Resources ## External Resources
1. ▶️ [The Only Markdown Crash Course You Will Ever Need](https://www.youtube.com/watch?v=_PPWWRV6gbA&ab_channel=WebDevSimplified) 1. ▶️ [The Only Markdown Crash Course You Will Ever Need](https://www.youtube.com/watch?v=_PPWWRV6gbA&ab_channel=WebDevSimplified)
2. 📄 [Basic writing and formatting syntax](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) 2. 📄 [Basic writing and formatting syntax](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax)
--- ---

View File

@@ -1,176 +1,176 @@
## /temp/ files ## /temp/ files
Ive set up the repository to ignore all folders named `temp`. This is a space you can use for temporary or experimental files without worrying about affecting the application or pushing these files to Gitea. Ive set up the repository to ignore all folders named `temp`. This is a space you can use for temporary or experimental files without worrying about affecting the application or pushing these files to Gitea.
- **Purpose**: Use the `temp` folder to store temporary files, logs, or scripts for testing purposes. - **Purpose**: Use the `temp` folder to store temporary files, logs, or scripts for testing purposes.
- **Ignored by Git**: All `temp` folders are excluded from version control using the `.gitignore` rule `**/temp/`. These files will not be committed or pushed to the repository. - **Ignored by Git**: All `temp` folders are excluded from version control using the `.gitignore` rule `**/temp/`. These files will not be committed or pushed to the repository.
- **Best Practices**: Please avoid storing critical or shared files here. Use it for temporary work only, and clean up files when no longer needed. - **Best Practices**: Please avoid storing critical or shared files here. Use it for temporary work only, and clean up files when no longer needed.
This should help us maintain a clean repository while giving everyone the freedom to experiment. This should help us maintain a clean repository while giving everyone the freedom to experiment.
--- ---
## Standardized File Structure and Coding Guidelines ## Standardized File Structure and Coding Guidelines
To improve our codebase's readability, maintainability, and scalability, were adopting a standardized file structure and coding practices. Heres a summary: To improve our codebase's readability, maintainability, and scalability, were adopting a standardized file structure and coding practices. Heres a summary:
1. **File Structure**: 1. **File Structure**:
- **Components (`.tsx`)**: All files that return HTML/JSX will be React components with a `.tsx` extension. They should focus on UI logic and presentation. - **Components (`.tsx`)**: All files that return HTML/JSX will be React components with a `.tsx` extension. They should focus on UI logic and presentation.
- **Purpose**: Files with the `.tsx` extension are reserved for React components that return JSX/HTML. - **Purpose**: Files with the `.tsx` extension are reserved for React components that return JSX/HTML.
- **Location**: Components should be organized based on their purpose or scope within the application. Example: - **Location**: Components should be organized based on their purpose or scope within the application. Example:
``` ```
src/ src/
components/ components/
Header.tsx Header.tsx
Footer.tsx Footer.tsx
pages/ pages/
Home.tsx Home.tsx
About.tsx About.tsx
``` ```
- **Naming Convention**: Component filenames should use PascalCase, matching the component name (e.g., `Header.tsx` for a `Header` component). - **Naming Convention**: Component filenames should use PascalCase, matching the component name (e.g., `Header.tsx` for a `Header` component).
- **Example**: - **Example**:
```tsx ```tsx
/** /**
* Header component that displays the application's navigation bar. * Header component that displays the application's navigation bar.
* *
* @returns {JSX.Element} A navigation bar with links. * @returns {JSX.Element} A navigation bar with links.
*/ */
const Header: React.FC = () => { const Header: React.FC = () => {
return ( return (
<header> <header>
<nav> <nav>
<a href="/">Home</a> <a href="/">Home</a>
<a href="/about">About</a> <a href="/about">About</a>
</nav> </nav>
</header> </header>
); );
}; };
export default Header; export default Header;
``` ```
- **Functions (`.ts`)**: All helper functions or business logic will go into `.ts` files, separate from the components. - **Functions (`.ts`)**: All helper functions or business logic will go into `.ts` files, separate from the components.
- **Purpose**: Files with the `.ts` extension are for helper functions, utility logic, or other non-React code that does not return JSX/HTML. - **Purpose**: Files with the `.ts` extension are for helper functions, utility logic, or other non-React code that does not return JSX/HTML.
- **Location**: Place utility files in a `utils` directory or within a directory relevant to their context. Example: - **Location**: Place utility files in a `utils` directory or within a directory relevant to their context. Example:
``` ```
src/ src/
utils/ utils/
calculateTotal.ts calculateTotal.ts
formatDate.ts formatDate.ts
hooks/ hooks/
useFetch.ts useFetch.ts
``` ```
- **Naming Convention**: Use camelCase for filenames that describe the primary function (e.g., `calculateTotal.ts` for a `calculateTotal` function). - **Naming Convention**: Use camelCase for filenames that describe the primary function (e.g., `calculateTotal.ts` for a `calculateTotal` function).
- **Example**: - **Example**:
```ts ```ts
/** /**
* Calculates the total price based on items and tax rate. * Calculates the total price based on items and tax rate.
* *
* @param {number[]} prices - Array of item prices. * @param {number[]} prices - Array of item prices.
* @param {number} taxRate - Tax rate as a decimal. * @param {number} taxRate - Tax rate as a decimal.
* @returns {number} Total price including tax. * @returns {number} Total price including tax.
*/ */
export const calculateTotal = ( export const calculateTotal = (
prices: number[], prices: number[],
taxRate: number taxRate: number
): number => { ): number => {
const subtotal = prices.reduce((sum, price) => sum + price, 0); const subtotal = prices.reduce((sum, price) => sum + price, 0);
return subtotal + subtotal * taxRate; return subtotal + subtotal * taxRate;
}; };
``` ```
--- ---
## Commenting Standards ## Commenting Standards
To improve code readability and understanding, every function and component should include comments explaining its purpose, inputs, and outputs. Heres how well approach this: To improve code readability and understanding, every function and component should include comments explaining its purpose, inputs, and outputs. Heres how well approach this:
1. **React Components**: 1. **React Components**:
- Include a **high-level description** of what the component does. - Include a **high-level description** of what the component does.
- Specify the **props** it accepts, along with their types. - Specify the **props** it accepts, along with their types.
- Specify the **return type** (`JSX.Element` for React components). - Specify the **return type** (`JSX.Element` for React components).
**Example**: **Example**:
```tsx ```tsx
/** /**
* Button component that triggers an action when clicked. * Button component that triggers an action when clicked.
* *
* @param {object} props - The props object. * @param {object} props - The props object.
* @param {string} props.label - The text to display on the button. * @param {string} props.label - The text to display on the button.
* @param {() => void} props.onClick - The callback function triggered when the button is clicked. * @param {() => void} props.onClick - The callback function triggered when the button is clicked.
* @returns {JSX.Element} A styled button element. * @returns {JSX.Element} A styled button element.
*/ */
const Button: React.FC<{ label: string; onClick: () => void }> = ({ const Button: React.FC<{ label: string; onClick: () => void }> = ({
label, label,
onClick, onClick,
}) => { }) => {
return <button onClick={onClick}>{label}</button>; return <button onClick={onClick}>{label}</button>;
}; };
export default Button; export default Button;
``` ```
2. **Functions**: 2. **Functions**:
- Include a **detailed description** of what the function does. - Include a **detailed description** of what the function does.
- Specify the **parameters**, their types, and what they represent. - Specify the **parameters**, their types, and what they represent.
- Specify the **return type** and what it represents. - Specify the **return type** and what it represents.
**Example**: **Example**:
```ts ```ts
/** /**
* Converts a date string to a readable format. * Converts a date string to a readable format.
* *
* @param {string} date - A date string in ISO format (e.g., "2024-11-21"). * @param {string} date - A date string in ISO format (e.g., "2024-11-21").
* @returns {string} The formatted date (e.g., "November 21, 2024"). * @returns {string} The formatted date (e.g., "November 21, 2024").
*/ */
export const formatDate = (date: string): string => { export const formatDate = (date: string): string => {
const options: Intl.DateTimeFormatOptions = { const options: Intl.DateTimeFormatOptions = {
year: "numeric", year: "numeric",
month: "long", month: "long",
day: "numeric", day: "numeric",
}; };
return new Date(date).toLocaleDateString(undefined, options); return new Date(date).toLocaleDateString(undefined, options);
}; };
``` ```
3. **Commenting Standards**: 3. **Commenting Standards**:
- Each function and component should have a comment explaining: - Each function and component should have a comment explaining:
- What it does. - What it does.
- The props or parameters it accepts (including types). - The props or parameters it accepts (including types).
- What it returns and why. - What it returns and why.
4. **Why This Matters**: 4. **Why This Matters**:
- This structure helps us maintain a clean, modular codebase. It also makes the project easier to navigate for new and existing team members. - This structure helps us maintain a clean, modular codebase. It also makes the project easier to navigate for new and existing team members.
--- ---
## File Naming Guidelines ## File Naming Guidelines
To maintain consistency and professionalism in our codebase, we are standardizing the way we name files. This is crucial for readability, collaboration, and avoiding potential issues across different operating systems. To maintain consistency and professionalism in our codebase, we are standardizing the way we name files. This is crucial for readability, collaboration, and avoiding potential issues across different operating systems.
We are introducing a standardized **file naming convention** to maintain consistency across the codebase. Here are the key points: We are introducing a standardized **file naming convention** to maintain consistency across the codebase. Here are the key points:
1. **File Naming**: 1. **File Naming**:
- All file names must follow the **camelCase** convention (e.g., `headerComponent.tsx`, `calculateTotal.ts`). - All file names must follow the **camelCase** convention (e.g., `headerComponent.tsx`, `calculateTotal.ts`).
- This ensures uniformity and avoids case sensitivity issues. - This ensures uniformity and avoids case sensitivity issues.
2. **Pre-Commit Hook**: 2. **Pre-Commit Hook**:
- A pre-commit hook will automatically rename files to camelCase if they dont comply. - A pre-commit hook will automatically rename files to camelCase if they dont comply.
- Please double-check that your imports match the updated file names to avoid runtime errors. - Please double-check that your imports match the updated file names to avoid runtime errors.
3. **What You Need to Do**: 3. **What You Need to Do**:
- Name files correctly in camelCase from the start. - Name files correctly in camelCase from the start.
- If a file is renamed during a commit, ensure all imports are updated to reflect the new name. - If a file is renamed during a commit, ensure all imports are updated to reflect the new name.
4. **Why This Matters**: 4. **Why This Matters**:
- Consistent file naming improves readability and reduces issues when working in teams or across different operating systems. - Consistent file naming improves readability and reduces issues when working in teams or across different operating systems.

View File

@@ -1,107 +1,107 @@
# Project Folder Structure # Project Folder Structure
This document provides a detailed description of the purpose of each folder in the project by root level, along with the folder hierarchy. This document provides a detailed description of the purpose of each folder in the project by root level, along with the folder hierarchy.
## Folder Hierarchy ## Folder Hierarchy
``` ```
📁 src 📁 src
├── 📁 assets ├── 📁 assets
├── 📁 components ├── 📁 components
├── 📁 functions ├── 📁 functions
├── 📁 hooks ├── 📁 hooks
├── 📁 modules ├── 📁 modules
│ ├── 📁 builder │ ├── 📁 builder
│ ├── 📁 simulation │ ├── 📁 simulation
│ └── 📁 visualization │ └── 📁 visualization
├── 📁 services ├── 📁 services
├── 📁 store ├── 📁 store
├── 📁 styles ├── 📁 styles
├── 📁 tests ├── 📁 tests
├── 📁 types ├── 📁 types
├── 📁 utils ├── 📁 utils
├── App.css ├── App.css
├── App.tsx ├── App.tsx
├── index.css ├── index.css
├── main.tsx ├── main.tsx
└── vite-env.d.ts └── vite-env.d.ts
``` ```
--- ---
## Description of Each Folder ## Description of Each Folder
### 📁 `src` ### 📁 `src`
The root directory for all source code related to the application. The root directory for all source code related to the application.
#### 📁 `assets` #### 📁 `assets`
- **Purpose:** Contains static assets such as images, icons, fonts, or other resources. - **Purpose:** Contains static assets such as images, icons, fonts, or other resources.
- **Example:** - **Example:**
- `react.svg`: A static SVG file used in the project. - `react.svg`: A static SVG file used in the project.
#### 📁 `components` #### 📁 `components`
- **Purpose:** Contains reusable React components, serving as building blocks for the user interface. - **Purpose:** Contains reusable React components, serving as building blocks for the user interface.
- **Example:** - **Example:**
- Buttons, modals, headers, and forms. - Buttons, modals, headers, and forms.
#### 📁 `functions` #### 📁 `functions`
- **Purpose:** Stores pure functions or logic that can be reused across the application. - **Purpose:** Stores pure functions or logic that can be reused across the application.
- **Example:** - **Example:**
- Utility functions for data transformation or computation. - Utility functions for data transformation or computation.
#### 📁 `hooks` #### 📁 `hooks`
- **Purpose:** Holds custom React hooks for managing specific logic or behaviors. - **Purpose:** Holds custom React hooks for managing specific logic or behaviors.
- **Example:** - **Example:**
- Hooks for state management, API calls, or reusable effects. - Hooks for state management, API calls, or reusable effects.
#### 📁 `modules` #### 📁 `modules`
- **Purpose:** Organizes high-level, feature-specific code into subdirectories. - **Purpose:** Organizes high-level, feature-specific code into subdirectories.
- **📁 builder:** Manages functionalities and components related to building or configuring features. - **📁 builder:** Manages functionalities and components related to building or configuring features.
- **📁 simulation:** Handles processes or logic related to simulations or dynamic scenarios. - **📁 simulation:** Handles processes or logic related to simulations or dynamic scenarios.
- **📁 visualization:** Focuses on displaying data visually, such as charts, graphs, or interactive UI elements. - **📁 visualization:** Focuses on displaying data visually, such as charts, graphs, or interactive UI elements.
#### 📁 `services` #### 📁 `services`
- **Purpose:** Encapsulates external service interactions, such as API calls or library integrations. - **Purpose:** Encapsulates external service interactions, such as API calls or library integrations.
- **Example:** - **Example:**
- REST API clients or authentication handlers. - REST API clients or authentication handlers.
#### 📁 `store` #### 📁 `store`
- **Purpose:** Contains state management logic and configurations for tools like Redux or Zustand. - **Purpose:** Contains state management logic and configurations for tools like Redux or Zustand.
- **Example:** - **Example:**
- Redux slices, context providers, or global state stores. - Redux slices, context providers, or global state stores.
#### 📁 `styles` #### 📁 `styles`
- **Purpose:** Includes global CSS, SCSS, or theming resources. - **Purpose:** Includes global CSS, SCSS, or theming resources.
- **Example:** - **Example:**
- Global styles, theme variables, or resets. - Global styles, theme variables, or resets.
#### 📁 `tests` #### 📁 `tests`
- **Purpose:** Stores test files for unit testing, integration testing, and mock data. - **Purpose:** Stores test files for unit testing, integration testing, and mock data.
- **Example:** - **Example:**
- Test files (`*.test.tsx`, `*.spec.ts`) or mock utilities. - Test files (`*.test.tsx`, `*.spec.ts`) or mock utilities.
#### 📁 `types` #### 📁 `types`
- **Purpose:** Contains shared TypeScript type definitions and interfaces. - **Purpose:** Contains shared TypeScript type definitions and interfaces.
- **Example:** - **Example:**
- Type declarations for props, data models, or API responses. - Type declarations for props, data models, or API responses.
#### 📁 `utils` #### 📁 `utils`
- **Purpose:** Includes general-purpose utility files that dont fit into other specific folders. - **Purpose:** Includes general-purpose utility files that dont fit into other specific folders.
- **Example:** - **Example:**
- Helper functions like debouncers or date formatters. - Helper functions like debouncers or date formatters.
--- ---
## Root-Level Files ## Root-Level Files
### `App.tsx` ### `App.tsx`
- **Purpose:** The root React component, initializing the main application layout and logic. - **Purpose:** The root React component, initializing the main application layout and logic.
### `index.css` ### `index.css`
- **Purpose:** Contains global styles applied throughout the application. - **Purpose:** Contains global styles applied throughout the application.
### `main.tsx` ### `main.tsx`
- **Purpose:** The entry point of the app, rendering the React application and setting up the React DOM. - **Purpose:** The entry point of the app, rendering the React application and setting up the React DOM.
### `vite-env.d.ts` ### `vite-env.d.ts`
- **Purpose:** TypeScript environment configuration file for Vite. - **Purpose:** TypeScript environment configuration file for Vite.

View File

@@ -1,97 +1,97 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documentation</title> <title>Documentation</title>
<!-- Docsify Vue Theme --> <!-- Docsify Vue Theme -->
<link <link
rel="stylesheet" rel="stylesheet"
href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css"
/> />
<!-- Link to your custom styles --> <!-- Link to your custom styles -->
<link rel="stylesheet" href="./styles/style.css" /> <link rel="stylesheet" href="./styles/style.css" />
<!-- Docsify Search Plugin (Make sure it's the correct version) --> <!-- Docsify Search Plugin (Make sure it's the correct version) -->
<link <link
rel="stylesheet" rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/docsify-search@1.7.0/dist/docsify-search.min.css" href="https://cdn.jsdelivr.net/npm/docsify-search@1.7.0/dist/docsify-search.min.css"
/> />
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>
<!-- Docsify Script --> <!-- Docsify Script -->
<script src="https://cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/docsify/lib/docsify.min.js"></script>
<!-- Docsify Search Plugin Script --> <!-- Docsify Search Plugin Script -->
<script src="https://cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
<!-- Docsify Image Preview Plugin --> <!-- Docsify Image Preview Plugin -->
<script src="https://cdn.jsdelivr.net/npm/docsify/lib/plugins/zoom-image.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/docsify/lib/plugins/zoom-image.min.js"></script>
<!-- Docsify Theme Toggle Button and Search Integration --> <!-- Docsify Theme Toggle Button and Search Integration -->
<script> <script>
window.$docsify = { window.$docsify = {
loadSidebar: true, loadSidebar: true,
loadNavbar: true, loadNavbar: true,
subMaxLevel: 2, subMaxLevel: 2,
auto2top: true, auto2top: true,
search: { search: {
insertBefore: ".sidebar-nav", // Ensure the search bar is placed before the sidebar-nav element insertBefore: ".sidebar-nav", // Ensure the search bar is placed before the sidebar-nav element
paths: "auto", // Automatically index all markdown files paths: "auto", // Automatically index all markdown files
placeholder: "Search documentation...", // Placeholder text placeholder: "Search documentation...", // Placeholder text
noData: "No results!", // Message when no results are found noData: "No results!", // Message when no results are found
}, },
plugins: [ plugins: [
function (hook, vm) { function (hook, vm) {
// Function to add the theme toggle button // Function to add the theme toggle button
function addThemeToggle() { function addThemeToggle() {
const themeButtonHtml = ` const themeButtonHtml = `
<div class="theme-toggle-container"> <div class="theme-toggle-container">
Theme : Theme :
<button id="theme-toggle">🌙</button> <button id="theme-toggle">🌙</button>
</div> </div>
`; `;
// Append the theme button inside the sidebar or navbar // Append the theme button inside the sidebar or navbar
const sidebar = document.querySelector(".sidebar"); const sidebar = document.querySelector(".sidebar");
if (sidebar) { if (sidebar) {
sidebar.insertAdjacentHTML("beforebegin", themeButtonHtml); sidebar.insertAdjacentHTML("beforebegin", themeButtonHtml);
} }
// Handle the theme toggle functionality // Handle the theme toggle functionality
const themeToggleBtn = document.getElementById("theme-toggle"); const themeToggleBtn = document.getElementById("theme-toggle");
themeToggleBtn.addEventListener("click", () => { themeToggleBtn.addEventListener("click", () => {
// Toggle the dark-theme class // Toggle the dark-theme class
const isDark = document.body.classList.toggle("dark-theme"); const isDark = document.body.classList.toggle("dark-theme");
themeToggleBtn.textContent = isDark ? "🌞" : "🌙"; themeToggleBtn.textContent = isDark ? "🌞" : "🌙";
// Optionally save the user's theme preference to localStorage // Optionally save the user's theme preference to localStorage
localStorage.setItem("theme", isDark ? "dark" : "light"); localStorage.setItem("theme", isDark ? "dark" : "light");
}); });
// Check if there's a saved theme in localStorage // Check if there's a saved theme in localStorage
const savedTheme = localStorage.getItem("theme"); const savedTheme = localStorage.getItem("theme");
if (savedTheme === "dark") { if (savedTheme === "dark") {
document.body.classList.add("dark-theme"); document.body.classList.add("dark-theme");
themeToggleBtn.textContent = "🌞"; // Set the button to indicate light theme themeToggleBtn.textContent = "🌞"; // Set the button to indicate light theme
} }
} }
// Run the theme toggle setup after each page load // Run the theme toggle setup after each page load
hook.afterEach(function (html) { hook.afterEach(function (html) {
// Make sure the theme toggle button is added after the page content changes // Make sure the theme toggle button is added after the page content changes
if (!document.getElementById("theme-toggle")) { if (!document.getElementById("theme-toggle")) {
addThemeToggle(); addThemeToggle();
} }
}); });
}, },
], ],
}; };
</script> </script>
</body> </body>
</html> </html>

View File

@@ -1,14 +1,14 @@
server { server {
listen 3000; listen 3000;
server_name localhost; server_name localhost;
root /usr/share/nginx/html; root /usr/share/nginx/html;
index index.html; index index.html;
location / { location / {
try_files $uri /index.html; try_files $uri /index.html;
} }
# Redirect 404 errors to index.html (for React Router) # Redirect 404 errors to index.html (for React Router)
error_page 404 /index.html; error_page 404 /index.html;
} }

View File

@@ -1,73 +1,73 @@
{ {
"name": "dwinzo-beta", "name": "dwinzo-beta",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@react-three/csg": "^3.2.0", "@react-three/csg": "^3.2.0",
"@react-three/drei": "^9.113.0", "@react-three/drei": "^9.113.0",
"@react-three/fiber": "^8.17.7", "@react-three/fiber": "^8.17.7",
"@react-three/postprocessing": "^2.16.3", "@react-three/postprocessing": "^2.16.3",
"@testing-library/jest-dom": "^5.17.0", "@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"@turf/turf": "^7.1.0", "@turf/turf": "^7.1.0",
"@types/jest": "^27.5.2", "@types/jest": "^27.5.2",
"@types/react": "^18.3.5", "@types/react": "^18.3.5",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
"@use-gesture/react": "^10.3.1", "@use-gesture/react": "^10.3.1",
"chart.js": "^4.4.8", "chart.js": "^4.4.8",
"glob": "^11.0.0", "glob": "^11.0.0",
"gsap": "^3.12.5", "gsap": "^3.12.5",
"leva": "^0.10.0", "leva": "^0.10.0",
"mqtt": "^5.10.4", "mqtt": "^5.10.4",
"postprocessing": "^6.36.4", "postprocessing": "^6.36.4",
"prompt-sync": "^4.2.0", "prompt-sync": "^4.2.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-chartjs-2": "^5.3.0", "react-chartjs-2": "^5.3.0",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-router-dom": "^7.4.0", "react-router-dom": "^7.4.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-toastify": "^10.0.5", "react-toastify": "^10.0.5",
"sass": "^1.78.0", "sass": "^1.78.0",
"socket.io-client": "^4.8.1", "socket.io-client": "^4.8.1",
"three": "^0.168.0", "three": "^0.168.0",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"web-vitals": "^2.1.4", "web-vitals": "^2.1.4",
"zustand": "^5.0.0-rc.2" "zustand": "^5.0.0-rc.2"
}, },
"scripts": { "scripts": {
"prepare": "husky", "prepare": "husky",
"prestart": "tsc scripts/git-prompt.ts && node scripts/git-prompt.js", "prestart": "tsc scripts/git-prompt.ts && node scripts/git-prompt.js",
"start": "react-scripts start", "start": "react-scripts start",
"build": "react-scripts build", "build": "GENERATE_SOURCEMAP=false react-scripts build",
"test": "jest", "test": "jest",
"cypress:open": "cypress open", "cypress:open": "cypress open",
"cypress:run": "cypress run" "cypress:run": "cypress run"
}, },
"eslintConfig": { "eslintConfig": {
"extends": [ "extends": [
"react-app", "react-app",
"react-app/jest" "react-app/jest"
] ]
}, },
"browserslist": { "browserslist": {
"production": [ "production": [
">0.2%", ">0.2%",
"not dead", "not dead",
"not op_mini all" "not op_mini all"
], ],
"development": [ "development": [
"last 1 chrome version", "last 1 chrome version",
"last 1 firefox version", "last 1 firefox version",
"last 1 safari version" "last 1 safari version"
] ]
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.1", "@types/node": "^22.9.1",
"@types/three": "^0.169.0", "@types/three": "^0.169.0",
"cypress": "^13.14.2", "cypress": "^13.14.2",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"husky": "^9.1.6", "husky": "^9.1.6",
"ts-node": "^10.9.2" "ts-node": "^10.9.2"
} }
} }

View File

@@ -1,44 +1,44 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1", user-scalable=no" /> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
name="description" name="description"
content="Web site created using create-react-app" content="Web site created using create-react-app"
/> />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML. Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>Dwinzo (beta)</title> <title>Dwinzo (beta)</title>
</head> </head>
<body data-theme="light"> <body data-theme="light">
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<div id="root-over"></div> <div id="root-over"></div>
<!-- <!--
This HTML file is a template. This HTML file is a template.
If you open it directly in the browser, you will see an empty page. If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file. You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag. The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`. To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`. To create a production bundle, use `npm run build` or `yarn build`.
--> -->
</body> </body>
</html> </html>

View File

@@ -1,25 +1,25 @@
{ {
"short_name": "React App", "short_name": "React App",
"name": "Create React App Sample", "name": "Create React App Sample",
"icons": [ "icons": [
{ {
"src": "favicon.ico", "src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16", "sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon" "type": "image/x-icon"
}, },
{ {
"src": "logo192.png", "src": "logo192.png",
"type": "image/png", "type": "image/png",
"sizes": "192x192" "sizes": "192x192"
}, },
{ {
"src": "logo512.png", "src": "logo512.png",
"type": "image/png", "type": "image/png",
"sizes": "512x512" "sizes": "512x512"
} }
], ],
"start_url": ".", "start_url": ".",
"display": "standalone", "display": "standalone",
"theme_color": "#000000", "theme_color": "#000000",
"background_color": "#ffffff" "background_color": "#ffffff"
} }

View File

@@ -1,3 +1,3 @@
# https://www.robotstxt.org/robotstxt.html # https://www.robotstxt.org/robotstxt.html
User-agent: * User-agent: *
Disallow: Disallow:

View File

@@ -1,9 +1,9 @@
import React from "react"; import React from "react";
import { render, screen } from "@testing-library/react"; import { render, screen } from "@testing-library/react";
import App from "./app"; import App from "./app";
test("renders learn react link", () => { test("renders learn react link", () => {
render(<App />); render(<App />);
const linkElement = screen.getByText(/learn react/i); const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument(); expect(linkElement).toBeInTheDocument();
}); });

View File

@@ -1,26 +1,26 @@
import React from "react"; import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Dashboard from "./pages/Dashboard"; import Dashboard from "./pages/Dashboard";
import Project from "./pages/Project"; import Project from "./pages/Project";
import UserAuth from "./pages/UserAuth"; import UserAuth from "./pages/UserAuth";
import ToastProvider from "./components/templates/ToastProvider"; import ToastProvider from "./components/templates/ToastProvider";
import "./styles/main.scss" import "./styles/main.scss"
const App: React.FC = () => { const App: React.FC = () => {
return ( return (
<ToastProvider> <ToastProvider>
<Router> <Router>
<Routes> <Routes>
<Route <Route
path="/" path="/"
element={<UserAuth />} element={<UserAuth />}
/> />
<Route path="/dashboard" element={<Dashboard />} /> <Route path="/dashboard" element={<Dashboard />} />
<Route path="/project" element={<Project />} /> <Route path="/project" element={<Project />} />
</Routes> </Routes>
</Router> </Router>
</ToastProvider> </ToastProvider>
); );
}; };
export default App; export default App;

File diff suppressed because one or more lines are too long

View File

@@ -1,160 +1,160 @@
export function CleanPannel() { export function CleanPannel() {
return ( return (
<svg <svg
width="12" width="12"
height="12" height="12"
viewBox="0 0 12 12" viewBox="0 0 12 12"
fill="none" fill="none"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
> >
<g clipPath="url(#clip0_1782_1158)"> <g clipPath="url(#clip0_1782_1158)">
<path d="M12 0H0V12H12V0Z" fill="white" fillOpacity="0.01" /> <path d="M12 0H0V12H12V0Z" fill="white" fillOpacity="0.01" />
<path <path
fillRule="evenodd" fillRule="evenodd"
clipRule="evenodd" clipRule="evenodd"
d="M5 1.47852H7V3.47853H10.75V5.47853H1.25V3.47853H5V1.47852Z" d="M5 1.47852H7V3.47853H10.75V5.47853H1.25V3.47853H5V1.47852Z"
stroke="#2B3344" stroke="#2B3344"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
/> />
<path d="M2 10H10V5.5H2V10Z" stroke="#2B3344" strokeLinejoin="round" /> <path d="M2 10H10V5.5H2V10Z" stroke="#2B3344" strokeLinejoin="round" />
<path <path
d="M4 9.97439V8.47852" d="M4 9.97439V8.47852"
stroke="#2B3344" stroke="#2B3344"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
/> />
<path <path
d="M6 9.97461V8.47461" d="M6 9.97461V8.47461"
stroke="#2B3344" stroke="#2B3344"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
/> />
<path <path
d="M8 9.97439V8.47852" d="M8 9.97439V8.47852"
stroke="#2B3344" stroke="#2B3344"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
/> />
<path <path
d="M3 10H9" d="M3 10H9"
stroke="#2B3344" stroke="#2B3344"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
/> />
</g> </g>
<defs> <defs>
<clipPath id="clip0_1782_1158"> <clipPath id="clip0_1782_1158">
<rect width="12" height="12" fill="white" /> <rect width="12" height="12" fill="white" />
</clipPath> </clipPath>
</defs> </defs>
</svg> </svg>
); );
} }
export function EyeIcon({ fill }: { fill?: string }) { export function EyeIcon({ fill }: { fill?: string }) {
return ( return (
<svg <svg
width="14" width="14"
height="15" height="15"
viewBox="0 0 14 15" viewBox="0 0 14 15"
fill="none" fill="none"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
> >
<path <path
d="M8.75047 7.4375C8.75047 8.40402 7.967 9.1875 7.00047 9.1875C6.034 9.1875 5.25049 8.40402 5.25049 7.4375C5.25049 6.47097 6.034 5.6875 7.00047 5.6875C7.967 5.6875 8.75047 6.47097 8.75047 7.4375Z" d="M8.75047 7.4375C8.75047 8.40402 7.967 9.1875 7.00047 9.1875C6.034 9.1875 5.25049 8.40402 5.25049 7.4375C5.25049 6.47097 6.034 5.6875 7.00047 5.6875C7.967 5.6875 8.75047 6.47097 8.75047 7.4375Z"
stroke={fill} stroke={fill}
strokeOpacity="1" strokeOpacity="1"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
/> />
<path <path
d="M7.00086 3.35419C4.3889 3.35419 2.1779 5.07087 1.43457 7.43752C2.17789 9.80416 4.3889 11.5209 7.00086 11.5209C9.6128 11.5209 11.8238 9.80416 12.5671 7.43752C11.8238 5.07088 9.6128 3.35419 7.00086 3.35419Z" d="M7.00086 3.35419C4.3889 3.35419 2.1779 5.07087 1.43457 7.43752C2.17789 9.80416 4.3889 11.5209 7.00086 11.5209C9.6128 11.5209 11.8238 9.80416 12.5671 7.43752C11.8238 5.07088 9.6128 3.35419 7.00086 3.35419Z"
stroke={fill} stroke={fill}
strokeOpacity="1" strokeOpacity="1"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
/> />
</svg> </svg>
); );
} }
export function LockIcon({ fill }: { fill?: string }) { export function LockIcon({ fill }: { fill?: string }) {
return ( return (
<svg <svg
width="14" width="14"
height="15" height="15"
viewBox="0 0 14 15" viewBox="0 0 14 15"
fill="none" fill="none"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
> >
<path <path
d="M4.0835 6.28763C4.35849 6.27083 4.69751 6.27083 5.1335 6.27083H8.86683C9.30281 6.27083 9.64185 6.27083 9.91683 6.28763M4.0835 6.28763C3.74031 6.30857 3.49683 6.35571 3.28901 6.46158C2.95973 6.62935 2.69201 6.89704 2.52423 7.22633C2.3335 7.60072 2.3335 8.09072 2.3335 9.07083V9.8875C2.3335 10.8676 2.3335 11.3576 2.52423 11.732C2.69201 12.0613 2.95973 12.329 3.28901 12.4967C3.66336 12.6875 4.1534 12.6875 5.1335 12.6875H8.86683C9.84695 12.6875 10.3369 12.6875 10.7113 12.4967C11.0406 12.329 11.3083 12.0613 11.4761 11.732C11.6668 11.3576 11.6668 10.8676 11.6668 9.8875V9.07083C11.6668 8.09072 11.6668 7.60072 11.4761 7.22633C11.3083 6.89704 11.0406 6.62935 10.7113 6.46158C10.5035 6.35571 10.26 6.30857 9.91683 6.28763M4.0835 6.28763V5.10417C4.0835 3.49334 5.38933 2.1875 7.00016 2.1875C8.61098 2.1875 9.91683 3.49334 9.91683 5.10417V6.28763" d="M4.0835 6.28763C4.35849 6.27083 4.69751 6.27083 5.1335 6.27083H8.86683C9.30281 6.27083 9.64185 6.27083 9.91683 6.28763M4.0835 6.28763C3.74031 6.30857 3.49683 6.35571 3.28901 6.46158C2.95973 6.62935 2.69201 6.89704 2.52423 7.22633C2.3335 7.60072 2.3335 8.09072 2.3335 9.07083V9.8875C2.3335 10.8676 2.3335 11.3576 2.52423 11.732C2.69201 12.0613 2.95973 12.329 3.28901 12.4967C3.66336 12.6875 4.1534 12.6875 5.1335 12.6875H8.86683C9.84695 12.6875 10.3369 12.6875 10.7113 12.4967C11.0406 12.329 11.3083 12.0613 11.4761 11.732C11.6668 11.3576 11.6668 10.8676 11.6668 9.8875V9.07083C11.6668 8.09072 11.6668 7.60072 11.4761 7.22633C11.3083 6.89704 11.0406 6.62935 10.7113 6.46158C10.5035 6.35571 10.26 6.30857 9.91683 6.28763M4.0835 6.28763V5.10417C4.0835 3.49334 5.38933 2.1875 7.00016 2.1875C8.61098 2.1875 9.91683 3.49334 9.91683 5.10417V6.28763"
stroke={fill} stroke={fill}
strokeOpacity="1" strokeOpacity="1"
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
/> />
</svg> </svg>
); );
} }
export function StockIncreseIcon() { export function StockIncreseIcon() {
return ( return (
<svg <svg
width="9" width="9"
height="9" height="9"
viewBox="0 0 9 9" viewBox="0 0 9 9"
fill="none" fill="none"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
> >
<g clip-path="url(#clip0_3050_69519)"> <g clipPath="url(#clip0_3050_69519)">
<path <path
d="M7.80766 6.99219H1.17811C0.752382 6.99219 0.407227 7.33734 0.407227 7.76307C0.407227 8.18879 0.752382 8.53395 1.17811 8.53395H7.80766C8.23339 8.53395 8.57854 8.18879 8.57854 7.76307C8.57854 7.33733 8.23339 6.99219 7.80766 6.99219Z" d="M7.80766 6.99219H1.17811C0.752382 6.99219 0.407227 7.33734 0.407227 7.76307C0.407227 8.18879 0.752382 8.53395 1.17811 8.53395H7.80766C8.23339 8.53395 8.57854 8.18879 8.57854 7.76307C8.57854 7.33733 8.23339 6.99219 7.80766 6.99219Z"
fill="white" fill="white"
/> />
<path <path
d="M2.05066 6.50215C2.47639 6.50215 2.82154 6.15699 2.82154 5.73127V2.7865C2.82154 2.36078 2.47639 2.01562 2.05066 2.01562C1.62494 2.01562 1.27979 2.36078 1.27979 2.7865V5.73127C1.27977 6.15699 1.62494 6.50215 2.05066 6.50215Z" d="M2.05066 6.50215C2.47639 6.50215 2.82154 6.15699 2.82154 5.73127V2.7865C2.82154 2.36078 2.47639 2.01562 2.05066 2.01562C1.62494 2.01562 1.27979 2.36078 1.27979 2.7865V5.73127C1.27977 6.15699 1.62494 6.50215 2.05066 6.50215Z"
fill="white" fill="white"
/> />
<path <path
d="M4.49598 6.49421C4.9217 6.49421 5.26686 6.14905 5.26686 5.72333V1.80213C5.26686 1.37641 4.9217 1.03125 4.49598 1.03125C4.07025 1.03125 3.7251 1.37641 3.7251 1.80213V5.72333C3.7251 6.14905 4.07023 6.49421 4.49598 6.49421Z" d="M4.49598 6.49421C4.9217 6.49421 5.26686 6.14905 5.26686 5.72333V1.80213C5.26686 1.37641 4.9217 1.03125 4.49598 1.03125C4.07025 1.03125 3.7251 1.37641 3.7251 1.80213V5.72333C3.7251 6.14905 4.07023 6.49421 4.49598 6.49421Z"
fill="white" fill="white"
/> />
<path <path
d="M6.92957 6.50192C7.35529 6.50192 7.70042 6.15677 7.70042 5.73104V0.83338C7.70046 0.407655 7.35532 0.0625 6.92957 0.0625C6.50385 0.0625 6.15869 0.407655 6.15869 0.83338V5.73103C6.15869 6.15677 6.50385 6.50192 6.92957 6.50192Z" d="M6.92957 6.50192C7.35529 6.50192 7.70042 6.15677 7.70042 5.73104V0.83338C7.70046 0.407655 7.35532 0.0625 6.92957 0.0625C6.50385 0.0625 6.15869 0.407655 6.15869 0.83338V5.73103C6.15869 6.15677 6.50385 6.50192 6.92957 6.50192Z"
fill="white" fill="white"
/> />
</g> </g>
<rect <rect
x="0.27293" x="0.27293"
y="0.066387" y="0.066387"
width="8.45313" width="8.45313"
height="8.45313" height="8.45313"
stroke="url(#paint0_linear_3050_69519)" stroke="url(#paint0_linear_3050_69519)"
strokeWidth="0.0233989" strokeWidth="0.0233989"
/> />
<defs> <defs>
<linearGradient <linearGradient
id="paint0_linear_3050_69519" id="paint0_linear_3050_69519"
x1="4.4995" x1="4.4995"
y1="0.0546875" y1="0.0546875"
x2="4.4995" x2="4.4995"
y2="8.53122" y2="8.53122"
gradientUnits="userSpaceOnUse" gradientUnits="userSpaceOnUse"
> >
<stop stop-color="#31B2B9" /> <stop stopColor="#31B2B9" />
<stop offset="1" stop-color="#FBD8B8" /> <stop offset="1" stopColor="#FBD8B8" />
</linearGradient> </linearGradient>
<clipPath id="clip0_3050_69519"> <clipPath id="clip0_3050_69519">
<rect <rect
x="0.26123" x="0.26123"
y="0.0546875" y="0.0546875"
width="8.47653" width="8.47653"
height="8.47653" height="8.47653"
fill="white" fill="white"
/> />
</clipPath> </clipPath>
</defs> </defs>
</svg> </svg>
); );
} }

View File

@@ -3,9 +3,12 @@ import { ToggleSidebarIcon } from "../../icons/HeaderIcons";
import { LogoIcon } from "../../icons/Logo"; import { LogoIcon } from "../../icons/Logo";
import FileMenu from "../../ui/FileMenu"; import FileMenu from "../../ui/FileMenu";
import useToggleStore from "../../../store/useUIToggleStore"; import useToggleStore from "../../../store/useUIToggleStore";
import useModuleStore from "../../../store/useModuleStore";
const Header: React.FC = () => { const Header: React.FC = () => {
const { toggleUI, setToggleUI } = useToggleStore(); const { toggleUI, setToggleUI } = useToggleStore();
const { activeModule } = useModuleStore();
return ( return (
<div className="header-container"> <div className="header-container">
<div className="header-content"> <div className="header-content">
@@ -19,7 +22,7 @@ const Header: React.FC = () => {
<div <div
className={`toggle-sidebar-ui-button ${!toggleUI ? "active" : ""}`} className={`toggle-sidebar-ui-button ${!toggleUI ? "active" : ""}`}
onClick={() => { onClick={() => {
setToggleUI(!toggleUI); if (activeModule !== "market") setToggleUI(!toggleUI);
}} }}
> >
<ToggleSidebarIcon /> <ToggleSidebarIcon />

View File

@@ -1,6 +1,8 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Header from "./Header"; import Header from "./Header";
import useModuleStore, { useSubModuleStore } from "../../../store/useModuleStore"; import useModuleStore, {
useSubModuleStore,
} from "../../../store/useModuleStore";
import { import {
AnalysisIcon, AnalysisIcon,
MechanicsIcon, MechanicsIcon,
@@ -15,6 +17,7 @@ import AsstePropertiies from "./properties/AssetProperties";
import Analysis from "./analysis/Analysis"; import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations"; import Simulations from "./simulation/Simulations";
import { useSelectedActionSphere } from "../../../store/store"; import { useSelectedActionSphere } from "../../../store/store";
import ZoneProperties from "./properties/ZoneProperties";
const SideBarRight: React.FC = () => { const SideBarRight: React.FC = () => {
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
@@ -24,7 +27,8 @@ const SideBarRight: React.FC = () => {
// Reset subModule whenever activeModule changes // Reset subModule whenever activeModule changes
useEffect(() => { useEffect(() => {
setSubModule("properties"); if (activeModule !== "simulation") setSubModule("properties");
if (activeModule === "simulation") setSubModule("mechanics");
}, [activeModule]); }, [activeModule]);
return ( return (
@@ -32,32 +36,38 @@ const SideBarRight: React.FC = () => {
<Header /> <Header />
{toggleUI && ( {toggleUI && (
<div className="sidebar-actions-container"> <div className="sidebar-actions-container">
<div {/* {activeModule === "builder" && ( */}
className={`sidebar-action-list ${subModule === "properties" ? "active" : "" <div
className={`sidebar-action-list ${
subModule === "properties" ? "active" : ""
}`} }`}
onClick={() => setSubModule("properties")} onClick={() => setSubModule("properties")}
> >
<PropertiesIcon isActive={subModule === "properties"} /> <PropertiesIcon isActive={subModule === "properties"} />
</div> </div>
{/* )} */}
{activeModule === "simulation" && ( {activeModule === "simulation" && (
<> <>
<div <div
className={`sidebar-action-list ${subModule === "mechanics" ? "active" : "" className={`sidebar-action-list ${
}`} subModule === "mechanics" ? "active" : ""
}`}
onClick={() => setSubModule("mechanics")} onClick={() => setSubModule("mechanics")}
> >
<MechanicsIcon isActive={subModule === "mechanics"} /> <MechanicsIcon isActive={subModule === "mechanics"} />
</div> </div>
<div <div
className={`sidebar-action-list ${subModule === "simulations" ? "active" : "" className={`sidebar-action-list ${
}`} subModule === "simulations" ? "active" : ""
}`}
onClick={() => setSubModule("simulations")} onClick={() => setSubModule("simulations")}
> >
<SimulationIcon isActive={subModule === "simulations"} /> <SimulationIcon isActive={subModule === "simulations"} />
</div> </div>
<div <div
className={`sidebar-action-list ${subModule === "analysis" ? "active" : "" className={`sidebar-action-list ${
}`} subModule === "analysis" ? "active" : ""
}`}
onClick={() => setSubModule("analysis")} onClick={() => setSubModule("analysis")}
> >
<AnalysisIcon isActive={subModule === "analysis"} /> <AnalysisIcon isActive={subModule === "analysis"} />
@@ -73,6 +83,7 @@ const SideBarRight: React.FC = () => {
<div className="sidebar-right-container"> <div className="sidebar-right-container">
<div className="sidebar-right-content-container"> <div className="sidebar-right-content-container">
<GlobalProperties /> <GlobalProperties />
{/* <ZoneProperties /> */}
{/* <AsstePropertiies /> */} {/* <AsstePropertiies /> */}
</div> </div>
</div> </div>
@@ -82,17 +93,17 @@ const SideBarRight: React.FC = () => {
{toggleUI && activeModule === "simulation" && ( {toggleUI && activeModule === "simulation" && (
<> <>
{(subModule === "mechanics" && selectedActionSphere) && ( {subModule === "mechanics" && selectedActionSphere && (
<div className="sidebar-right-container"> <div className="sidebar-right-container">
<div className="sidebar-right-content-container"> <div className="sidebar-right-content-container">
<MachineMechanics /> <MachineMechanics />
</div> </div>
</div> </div>
)} )}
{(subModule === "mechanics" && !selectedActionSphere) && ( {subModule === "mechanics" && !selectedActionSphere && (
<div className="sidebar-right-container"> <div className="sidebar-right-container">
<div className="sidebar-right-content-container"> <div className="sidebar-right-content-container">
{/* <MachineMechanics /> */} <MachineMechanics />
</div> </div>
</div> </div>
)} )}

View File

@@ -0,0 +1,59 @@
import React from "react";
import { EyeDroperIcon } from "../../../icons/ExportCommonIcons";
interface PositionInputProps {
onChange: (value: string) => void; // Callback for value change
header: string;
placeholder?: string; // Optional placeholder
type?: string; // Input type (e.g., text, number, email)
}
const Vector3Input: React.FC<PositionInputProps> = ({
onChange,
header,
placeholder = "Enter value", // Default placeholder
type = "number", // Default type
}) => {
return (
<div className="custom-input-container">
<div className="header">
{header}{" "}
<div className="eyedrop-button">
<EyeDroperIcon isActive={false} />
</div>
</div>
<div className="inputs-container">
<div className="input-container">
<div className="custom-input-label">X : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
/>
</div>
<div className="input-container">
<div className="custom-input-label">Y : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
min={0}
/>
</div>
<div className="input-container">
<div className="custom-input-label">Z : </div>
<input
className="custom-input-field"
type={type}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
/>
</div>
</div>
</div>
);
};
export default Vector3Input;

View File

@@ -14,8 +14,8 @@ import EyeDropInput from "../../../ui/inputs/EyeDropInput";
import { useSelectedActionSphere } from "../../../../store/store"; import { useSelectedActionSphere } from "../../../../store/store";
const MachineMechanics: React.FC = () => { const MachineMechanics: React.FC = () => {
const { selectedActionSphere, setSelectedActionSphere } = useSelectedActionSphere(); const { selectedActionSphere } = useSelectedActionSphere();
console.log('selectedActionSphere: ', selectedActionSphere); console.log("selectedActionSphere: ", selectedActionSphere);
const [actionList, setActionList] = useState<string[]>([]); const [actionList, setActionList] = useState<string[]>([]);
const [triggerList, setTriggerList] = useState<string[]>([]); const [triggerList, setTriggerList] = useState<string[]>([]);
const [selectedItem, setSelectedItem] = useState<{ const [selectedItem, setSelectedItem] = useState<{
@@ -71,7 +71,9 @@ const MachineMechanics: React.FC = () => {
return ( return (
<div className="machine-mechanics-container"> <div className="machine-mechanics-container">
<div className="machine-mechanics-header">{selectedActionSphere.path.modelName}</div> <div className="machine-mechanics-header">
{selectedActionSphere?.path?.modelName || "path name not found"}
</div>
{/* <div className="process-list-container"> {/* <div className="process-list-container">
<div className="label">Process:</div> <div className="label">Process:</div>
<RegularDropDown <RegularDropDown
@@ -100,11 +102,12 @@ const MachineMechanics: React.FC = () => {
{actionList.map((action, index) => ( {actionList.map((action, index) => (
<div <div
key={index} key={index}
className={`list-item ${selectedItem?.type === "action" && className={`list-item ${
selectedItem?.type === "action" &&
selectedItem.name === action selectedItem.name === action
? "active" ? "active"
: "" : ""
}`} }`}
> >
<div <div
className="value" className="value"
@@ -146,11 +149,12 @@ const MachineMechanics: React.FC = () => {
{triggerList.map((trigger, index) => ( {triggerList.map((trigger, index) => (
<div <div
key={index} key={index}
className={`list-item ${selectedItem?.type === "trigger" && className={`list-item ${
selectedItem?.type === "trigger" &&
selectedItem.name === trigger selectedItem.name === trigger
? "active" ? "active"
: "" : ""
}`} }`}
> >
<div <div
className="value" className="value"
@@ -188,7 +192,7 @@ const MachineMechanics: React.FC = () => {
label="Speed" label="Speed"
value="" value=""
activeOption=".mm" activeOption=".mm"
onChange={() => { }} onChange={() => {}}
/> />
<EyeDropInput /> <EyeDropInput />
</> </>

View File

@@ -0,0 +1,17 @@
import React from "react";
import RenameInput from "../../../ui/inputs/RenameInput";
import Vector3Input from "../customInput/Vector3Input";
const ZoneProperties = () => {
return (
<div className="zone-properties-container">
<div className="header">
<RenameInput value="Selected Zone Name" />
</div>
<Vector3Input onChange={()=>{}} header="Target"/>
<Vector3Input onChange={()=>{}} header="Position"/>
</div>
);
};
export default ZoneProperties;

View File

@@ -28,7 +28,7 @@ const DropList: React.FC<DropListProps> = ({ val }) => {
}} }}
> >
{val.pathName} {val.pathName}
<div className="arrow-container"> <div className={`arrow-container${openDrop ? " active" : ""}`}>
<ArrowIcon /> <ArrowIcon />
</div> </div>
</div> </div>
@@ -87,8 +87,9 @@ const Simulations: React.FC = () => {
{productsList.map((action, index) => ( {productsList.map((action, index) => (
<div <div
key={index} key={index}
className={`list-item ${selectedItem === action ? "active" : "" className={`list-item ${
}`} selectedItem === action ? "active" : ""
}`}
> >
<div <div
className="value" className="value"

View File

@@ -6,15 +6,20 @@ import {
SimulationIcon, SimulationIcon,
VisualizationIcon, VisualizationIcon,
} from "../icons/ExportModuleIcons"; } from "../icons/ExportModuleIcons";
import useToggleStore from "../../store/useUIToggleStore";
const ModuleToggle: React.FC = () => { const ModuleToggle: React.FC = () => {
const { activeModule, setActiveModule } = useModuleStore(); const { activeModule, setActiveModule } = useModuleStore();
const { setToggleUI } = useToggleStore();
return ( return (
<div className="module-toggle-container"> <div className="module-toggle-container">
<div <div
className={`module-list ${activeModule === "builder" && "active"}`} className={`module-list ${activeModule === "builder" && "active"}`}
onClick={() => setActiveModule("builder")} onClick={() => {
setActiveModule("builder");
setToggleUI(true);
}}
> >
<div className="icon"> <div className="icon">
<BuilderIcon isActive={activeModule === "builder"} /> <BuilderIcon isActive={activeModule === "builder"} />
@@ -23,7 +28,10 @@ const ModuleToggle: React.FC = () => {
</div> </div>
<div <div
className={`module-list ${activeModule === "simulation" && "active"}`} className={`module-list ${activeModule === "simulation" && "active"}`}
onClick={() => setActiveModule("simulation")} onClick={() => {
setActiveModule("simulation");
setToggleUI(true);
}}
> >
<div className="icon"> <div className="icon">
<SimulationIcon isActive={activeModule === "simulation"} /> <SimulationIcon isActive={activeModule === "simulation"} />
@@ -34,7 +42,10 @@ const ModuleToggle: React.FC = () => {
className={`module-list ${ className={`module-list ${
activeModule === "visualization" && "active" activeModule === "visualization" && "active"
}`} }`}
onClick={() => setActiveModule("visualization")} onClick={() => {
setActiveModule("visualization");
setToggleUI(true);
}}
> >
<div className="icon"> <div className="icon">
<VisualizationIcon isActive={activeModule === "visualization"} /> <VisualizationIcon isActive={activeModule === "visualization"} />
@@ -42,10 +53,11 @@ const ModuleToggle: React.FC = () => {
<div className="module">Visualization</div> <div className="module">Visualization</div>
</div> </div>
<div <div
className={`module-list ${ className={`module-list ${activeModule === "market" && "active"}`}
activeModule === "market" && "active" onClick={() => {
}`} setActiveModule("market");
onClick={() => setActiveModule("market")} setToggleUI(false);
}}
> >
<div className="icon"> <div className="icon">
<CartIcon isActive={activeModule === "market"} /> <CartIcon isActive={activeModule === "market"} />

View File

@@ -1,94 +1,94 @@
import { useMemo } from "react"; import { useMemo } from "react";
import { Bar } from "react-chartjs-2"; import { Bar } from "react-chartjs-2";
interface ChartComponentProps { interface ChartComponentProps {
type: any; type: any;
title: string; title: string;
fontFamily?: string; fontFamily?: string;
fontSize?: string; fontSize?: string;
fontWeight?: "Light" | "Regular" | "Bold"; fontWeight?: "Light" | "Regular" | "Bold";
data: any; data: any;
} }
const LineGraphComponent = ({ const LineGraphComponent = ({
title, title,
fontFamily, fontFamily,
fontSize, fontSize,
fontWeight = "Regular", fontWeight = "Regular",
}: ChartComponentProps) => { }: ChartComponentProps) => {
// Memoize Font Weight Mapping // Memoize Font Weight Mapping
const chartFontWeightMap = useMemo( const chartFontWeightMap = useMemo(
() => ({ () => ({
Light: "lighter" as const, Light: "lighter" as const,
Regular: "normal" as const, Regular: "normal" as const,
Bold: "bold" as const, Bold: "bold" as const,
}), }),
[] []
); );
// Parse and Memoize Font Size // Parse and Memoize Font Size
const fontSizeValue = useMemo( const fontSizeValue = useMemo(
() => (fontSize ? parseInt(fontSize) : 12), () => (fontSize ? parseInt(fontSize) : 12),
[fontSize] [fontSize]
); );
// Determine and Memoize Font Weight // Determine and Memoize Font Weight
const fontWeightValue = useMemo( const fontWeightValue = useMemo(
() => chartFontWeightMap[fontWeight], () => chartFontWeightMap[fontWeight],
[fontWeight, chartFontWeightMap] [fontWeight, chartFontWeightMap]
); );
// Memoize Chart Font Style // Memoize Chart Font Style
const chartFontStyle = useMemo( const chartFontStyle = useMemo(
() => ({ () => ({
family: fontFamily || "Arial", family: fontFamily || "Arial",
size: fontSizeValue, size: fontSizeValue,
weight: fontWeightValue, weight: fontWeightValue,
}), }),
[fontFamily, fontSizeValue, fontWeightValue] [fontFamily, fontSizeValue, fontWeightValue]
); );
const options = useMemo( const options = useMemo(
() => ({ () => ({
responsive: true, responsive: true,
maintainAspectRatio: false, maintainAspectRatio: false,
plugins: { plugins: {
title: { title: {
display: true, display: true,
text: title, text: title,
font: chartFontStyle, font: chartFontStyle,
}, },
legend: { legend: {
display: false, display: false,
}, },
}, },
scales: { scales: {
x: { x: {
ticks: { ticks: {
display: false, // This hides the x-axis labels display: false, // This hides the x-axis labels
}, },
}, },
}, },
}), }),
[title, chartFontStyle] [title, chartFontStyle]
); );
const chartData = { const chartData = {
labels: ["January", "February", "March", "April", "May", "June", "July"], labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [ datasets: [
{ {
label: "My First Dataset", label: "My First Dataset",
data: [65, 59, 80, 81, 56, 55, 40], data: [65, 59, 80, 81, 56, 55, 40],
backgroundColor: "#6f42c1", backgroundColor: "#6f42c1",
borderColor: "#ffffff", borderColor: "#ffffff",
borderWidth: 2, borderWidth: 2,
fill: false, fill: false,
}, },
], ],
}; };
return <Bar data={chartData} options={options} />; return <Bar data={chartData} options={options} />;
}; };
export default LineGraphComponent; export default LineGraphComponent;

View File

@@ -1,93 +1,93 @@
import { useMemo } from "react"; import { useMemo } from "react";
import { Line } from "react-chartjs-2"; import { Line } from "react-chartjs-2";
interface ChartComponentProps { interface ChartComponentProps {
type: any; type: any;
title: string; title: string;
fontFamily?: string; fontFamily?: string;
fontSize?: string; fontSize?: string;
fontWeight?: "Light" | "Regular" | "Bold"; fontWeight?: "Light" | "Regular" | "Bold";
data: any; data: any;
} }
const LineGraphComponent = ({ const LineGraphComponent = ({
title, title,
fontFamily, fontFamily,
fontSize, fontSize,
fontWeight = "Regular", fontWeight = "Regular",
}: ChartComponentProps) => { }: ChartComponentProps) => {
// Memoize Font Weight Mapping // Memoize Font Weight Mapping
const chartFontWeightMap = useMemo( const chartFontWeightMap = useMemo(
() => ({ () => ({
Light: "lighter" as const, Light: "lighter" as const,
Regular: "normal" as const, Regular: "normal" as const,
Bold: "bold" as const, Bold: "bold" as const,
}), }),
[] []
); );
// Parse and Memoize Font Size // Parse and Memoize Font Size
const fontSizeValue = useMemo( const fontSizeValue = useMemo(
() => (fontSize ? parseInt(fontSize) : 12), () => (fontSize ? parseInt(fontSize) : 12),
[fontSize] [fontSize]
); );
// Determine and Memoize Font Weight // Determine and Memoize Font Weight
const fontWeightValue = useMemo( const fontWeightValue = useMemo(
() => chartFontWeightMap[fontWeight], () => chartFontWeightMap[fontWeight],
[fontWeight, chartFontWeightMap] [fontWeight, chartFontWeightMap]
); );
// Memoize Chart Font Style // Memoize Chart Font Style
const chartFontStyle = useMemo( const chartFontStyle = useMemo(
() => ({ () => ({
family: fontFamily || "Arial", family: fontFamily || "Arial",
size: fontSizeValue, size: fontSizeValue,
weight: fontWeightValue, weight: fontWeightValue,
}), }),
[fontFamily, fontSizeValue, fontWeightValue] [fontFamily, fontSizeValue, fontWeightValue]
); );
const options = useMemo( const options = useMemo(
() => ({ () => ({
responsive: true, responsive: true,
maintainAspectRatio: false, maintainAspectRatio: false,
plugins: { plugins: {
title: { title: {
display: true, display: true,
text: title, text: title,
font: chartFontStyle, font: chartFontStyle,
}, },
legend: { legend: {
display: false, display: false,
}, },
}, },
scales: { scales: {
x: { x: {
ticks: { ticks: {
display: false, // This hides the x-axis labels display: false, // This hides the x-axis labels
}, },
}, },
}, },
}), }),
[title, chartFontStyle] [title, chartFontStyle]
); );
const chartData = { const chartData = {
labels: ["January", "February", "March", "April", "May", "June", "July"], labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [ datasets: [
{ {
label: "My First Dataset", label: "My First Dataset",
data: [65, 59, 80, 81, 56, 55, 40], data: [65, 59, 80, 81, 56, 55, 40],
backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple) backgroundColor: "#6f42c1", // Updated to #6f42c1 (Purple)
borderColor: "#ffffff", // Keeping border color white borderColor: "#ffffff", // Keeping border color white
borderWidth: 2, borderWidth: 2,
fill: false, fill: false,
}, },
], ],
}; };
return <Line data={chartData} options={options} />; return <Line data={chartData} options={options} />;
}; };
export default LineGraphComponent; export default LineGraphComponent;

View File

@@ -1,91 +1,91 @@
import { useMemo } from "react"; import { useMemo } from "react";
import { Pie } from "react-chartjs-2"; import { Pie } from "react-chartjs-2";
interface ChartComponentProps { interface ChartComponentProps {
type: any; type: any;
title: string; title: string;
fontFamily?: string; fontFamily?: string;
fontSize?: string; fontSize?: string;
fontWeight?: "Light" | "Regular" | "Bold"; fontWeight?: "Light" | "Regular" | "Bold";
data: any; data: any;
} }
const PieChartComponent = ({ const PieChartComponent = ({
title, title,
fontFamily, fontFamily,
fontSize, fontSize,
fontWeight = "Regular", fontWeight = "Regular",
}: ChartComponentProps) => { }: ChartComponentProps) => {
// Memoize Font Weight Mapping // Memoize Font Weight Mapping
const chartFontWeightMap = useMemo( const chartFontWeightMap = useMemo(
() => ({ () => ({
Light: "lighter" as const, Light: "lighter" as const,
Regular: "normal" as const, Regular: "normal" as const,
Bold: "bold" as const, Bold: "bold" as const,
}), }),
[] []
); );
// Parse and Memoize Font Size // Parse and Memoize Font Size
const fontSizeValue = useMemo( const fontSizeValue = useMemo(
() => (fontSize ? parseInt(fontSize) : 12), () => (fontSize ? parseInt(fontSize) : 12),
[fontSize] [fontSize]
); );
// Determine and Memoize Font Weight // Determine and Memoize Font Weight
const fontWeightValue = useMemo( const fontWeightValue = useMemo(
() => chartFontWeightMap[fontWeight], () => chartFontWeightMap[fontWeight],
[fontWeight, chartFontWeightMap] [fontWeight, chartFontWeightMap]
); );
// Memoize Chart Font Style // Memoize Chart Font Style
const chartFontStyle = useMemo( const chartFontStyle = useMemo(
() => ({ () => ({
family: fontFamily || "Arial", family: fontFamily || "Arial",
size: fontSizeValue, size: fontSizeValue,
weight: fontWeightValue, weight: fontWeightValue,
}), }),
[fontFamily, fontSizeValue, fontWeightValue] [fontFamily, fontSizeValue, fontWeightValue]
); );
// Access the CSS variable for the primary accent color // Access the CSS variable for the primary accent color
const accentColor = getComputedStyle(document.documentElement) const accentColor = getComputedStyle(document.documentElement)
.getPropertyValue("--accent-color") .getPropertyValue("--accent-color")
.trim(); .trim();
console.log("accentColor: ", accentColor); console.log("accentColor: ", accentColor);
const options = useMemo( const options = useMemo(
() => ({ () => ({
responsive: true, responsive: true,
maintainAspectRatio: false, maintainAspectRatio: false,
plugins: { plugins: {
title: { title: {
display: true, display: true,
text: title, text: title,
font: chartFontStyle, font: chartFontStyle,
}, },
legend: { legend: {
display: false, display: false,
}, },
}, },
}), }),
[title, chartFontStyle] [title, chartFontStyle]
); );
const chartData = { const chartData = {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"], labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [ datasets: [
{ {
label: "Dataset", label: "Dataset",
data: [12, 19, 3, 5, 2, 3], data: [12, 19, 3, 5, 2, 3],
backgroundColor: ["#6f42c1"], backgroundColor: ["#6f42c1"],
borderColor: "#ffffff", borderColor: "#ffffff",
borderWidth: 2, borderWidth: 2,
}, },
], ],
}; };
return <Pie data={chartData} options={options} />; return <Pie data={chartData} options={options} />;
}; };
export default PieChartComponent; export default PieChartComponent;

View File

@@ -1,192 +1,192 @@
import React from "react"; import React from "react";
import { import {
CleanPannel, CleanPannel,
EyeIcon, EyeIcon,
LockIcon, LockIcon,
} from "../../icons/RealTimeVisulationIcons"; } from "../../icons/RealTimeVisulationIcons";
// Define the type for `Side` // Define the type for `Side`
type Side = "top" | "bottom" | "left" | "right"; type Side = "top" | "bottom" | "left" | "right";
// Define the type for the props passed to the Buttons component // Define the type for the props passed to the Buttons component
interface ButtonsProps { interface ButtonsProps {
selectedZone: { selectedZone: {
zoneName: string; zoneName: string;
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
widgets: { widgets: {
id: string; id: string;
type: string; type: string;
title: string; title: string;
panel: Side; panel: Side;
data: any; data: any;
}[]; }[];
}; };
setSelectedZone: React.Dispatch< setSelectedZone: React.Dispatch<
React.SetStateAction<{ React.SetStateAction<{
zoneName: string; zoneName: string;
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
widgets: { widgets: {
id: string; id: string;
type: string; type: string;
title: string; title: string;
panel: Side; panel: Side;
data: any; data: any;
}[]; }[];
}> }>
>; >;
hiddenPanels: Side[]; // Add this prop for hidden panels hiddenPanels: Side[]; // Add this prop for hidden panels
setHiddenPanels: React.Dispatch<React.SetStateAction<Side[]>>; // Add this prop for updating hidden panels setHiddenPanels: React.Dispatch<React.SetStateAction<Side[]>>; // Add this prop for updating hidden panels
} }
const AddButtons: React.FC<ButtonsProps> = ({ const AddButtons: React.FC<ButtonsProps> = ({
selectedZone, selectedZone,
setSelectedZone, setSelectedZone,
setHiddenPanels, setHiddenPanels,
hiddenPanels, hiddenPanels,
}) => { }) => {
// Local state to track hidden panels // Local state to track hidden panels
// Function to toggle lock/unlock a panel // Function to toggle lock/unlock a panel
const toggleLockPanel = (side: Side) => { const toggleLockPanel = (side: Side) => {
const newLockedPanels = selectedZone.lockedPanels.includes(side) const newLockedPanels = selectedZone.lockedPanels.includes(side)
? selectedZone.lockedPanels.filter((panel) => panel !== side) ? selectedZone.lockedPanels.filter((panel) => panel !== side)
: [...selectedZone.lockedPanels, side]; : [...selectedZone.lockedPanels, side];
const updatedZone = { const updatedZone = {
...selectedZone, ...selectedZone,
lockedPanels: newLockedPanels, lockedPanels: newLockedPanels,
}; };
// Update the selectedZone state // Update the selectedZone state
setSelectedZone(updatedZone); setSelectedZone(updatedZone);
}; };
// Function to toggle visibility of a panel // Function to toggle visibility of a panel
const toggleVisibility = (side: Side) => { const toggleVisibility = (side: Side) => {
const isHidden = hiddenPanels.includes(side); const isHidden = hiddenPanels.includes(side);
if (isHidden) { if (isHidden) {
// If the panel is already hidden, remove it from the hiddenPanels array // If the panel is already hidden, remove it from the hiddenPanels array
setHiddenPanels(hiddenPanels.filter((panel) => panel !== side)); setHiddenPanels(hiddenPanels.filter((panel) => panel !== side));
} else { } else {
// If the panel is visible, add it to the hiddenPanels array // If the panel is visible, add it to the hiddenPanels array
setHiddenPanels([...hiddenPanels, side]); setHiddenPanels([...hiddenPanels, side]);
} }
}; };
// Function to clean all widgets from a panel // Function to clean all widgets from a panel
const cleanPanel = (side: Side) => { const cleanPanel = (side: Side) => {
const cleanedWidgets = selectedZone.widgets.filter( const cleanedWidgets = selectedZone.widgets.filter(
(widget) => widget.panel !== side (widget) => widget.panel !== side
); );
const updatedZone = { const updatedZone = {
...selectedZone, ...selectedZone,
widgets: cleanedWidgets, widgets: cleanedWidgets,
}; };
// Update the selectedZone state // Update the selectedZone state
setSelectedZone(updatedZone); setSelectedZone(updatedZone);
}; };
// Function to handle "+" button click // Function to handle "+" button click
const handlePlusButtonClick = (side: Side) => { const handlePlusButtonClick = (side: Side) => {
if (selectedZone.activeSides.includes(side)) { if (selectedZone.activeSides.includes(side)) {
// If the panel is already active, remove all widgets and close the panel // If the panel is already active, remove all widgets and close the panel
const cleanedWidgets = selectedZone.widgets.filter( const cleanedWidgets = selectedZone.widgets.filter(
(widget) => widget.panel !== side (widget) => widget.panel !== side
); );
const newActiveSides = selectedZone.activeSides.filter((s) => s !== side); const newActiveSides = selectedZone.activeSides.filter((s) => s !== side);
const updatedZone = { const updatedZone = {
...selectedZone, ...selectedZone,
widgets: cleanedWidgets, widgets: cleanedWidgets,
activeSides: newActiveSides, activeSides: newActiveSides,
panelOrder: newActiveSides, panelOrder: newActiveSides,
}; };
// Update the selectedZone state // Update the selectedZone state
setSelectedZone(updatedZone); setSelectedZone(updatedZone);
} else { } else {
// If the panel is not active, activate it // If the panel is not active, activate it
const newActiveSides = [...selectedZone.activeSides, side]; const newActiveSides = [...selectedZone.activeSides, side];
const updatedZone = { const updatedZone = {
...selectedZone, ...selectedZone,
activeSides: newActiveSides, activeSides: newActiveSides,
panelOrder: newActiveSides, panelOrder: newActiveSides,
}; };
// Update the selectedZone state // Update the selectedZone state
setSelectedZone(updatedZone); setSelectedZone(updatedZone);
} }
}; };
return ( return (
<div> <div>
{(["top", "right", "bottom", "left"] as Side[]).map((side) => ( {(["top", "right", "bottom", "left"] as Side[]).map((side) => (
<div key={side} className={`side-button-container ${side}`}> <div key={side} className={`side-button-container ${side}`}>
{/* "+" Button */} {/* "+" Button */}
<button <button
className={`side-button ${side}`} className={`side-button ${side}`}
onClick={() => handlePlusButtonClick(side)} onClick={() => handlePlusButtonClick(side)}
title={ title={
selectedZone.activeSides.includes(side) selectedZone.activeSides.includes(side)
? `Remove all items and close ${side} panel` ? `Remove all items and close ${side} panel`
: `Activate ${side} panel` : `Activate ${side} panel`
} }
> >
+ +
</button> </button>
{/* Extra Buttons */} {/* Extra Buttons */}
{selectedZone.activeSides.includes(side) && ( {selectedZone.activeSides.includes(side) && (
<div className="extra-Bs"> <div className="extra-Bs">
{/* Hide Panel */} {/* Hide Panel */}
<div <div
className={`icon ${ className={`icon ${
hiddenPanels.includes(side) ? "active" : "" hiddenPanels.includes(side) ? "active" : ""
}`} }`}
title={ title={
hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel" hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel"
} }
onClick={() => toggleVisibility(side)} onClick={() => toggleVisibility(side)}
> >
<EyeIcon /> <EyeIcon />
</div> </div>
{/* Clean Panel */} {/* Clean Panel */}
<div <div
className="icon" className="icon"
title="Clean Panel" title="Clean Panel"
onClick={() => cleanPanel(side)} onClick={() => cleanPanel(side)}
> >
<CleanPannel /> <CleanPannel />
</div> </div>
{/* Lock/Unlock Panel */} {/* Lock/Unlock Panel */}
<div <div
className={`icon ${ className={`icon ${
selectedZone.lockedPanels.includes(side) ? "active" : "" selectedZone.lockedPanels.includes(side) ? "active" : ""
}`} }`}
title={ title={
selectedZone.lockedPanels.includes(side) selectedZone.lockedPanels.includes(side)
? "Unlock Panel" ? "Unlock Panel"
: "Lock Panel" : "Lock Panel"
} }
onClick={() => toggleLockPanel(side)} onClick={() => toggleLockPanel(side)}
> >
<LockIcon /> <LockIcon />
</div> </div>
</div> </div>
)} )}
</div> </div>
))} ))}
</div> </div>
); );
}; };
export default AddButtons; export default AddButtons;

View File

@@ -1,179 +1,179 @@
import React, { useEffect, useRef } from "react"; import React, { useEffect, useRef } from "react";
import { Widget } from "../../../store/useWidgetStore"; import { Widget } from "../../../store/useWidgetStore";
// Define the type for `Side` // Define the type for `Side`
type Side = "top" | "bottom" | "left" | "right"; type Side = "top" | "bottom" | "left" | "right";
interface DisplayZoneProps { interface DisplayZoneProps {
zonesData: { zonesData: {
[key: string]: { [key: string]: {
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
widgets: Widget[]; widgets: Widget[];
}; };
}; };
selectedZone: { selectedZone: {
zoneName: string; zoneName: string;
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
widgets: { widgets: {
id: string; id: string;
type: string; type: string;
title: string; title: string;
panel: Side; panel: Side;
data: any; data: any;
}[]; }[];
}; };
setSelectedZone: React.Dispatch< setSelectedZone: React.Dispatch<
React.SetStateAction<{ React.SetStateAction<{
zoneName: string; zoneName: string;
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
widgets: { widgets: {
id: string; id: string;
type: string; type: string;
title: string; title: string;
panel: Side; panel: Side;
data: any; data: any;
}[]; }[];
}> }>
>; >;
} }
const DisplayZone: React.FC<DisplayZoneProps> = ({ const DisplayZone: React.FC<DisplayZoneProps> = ({
zonesData, zonesData,
selectedZone, selectedZone,
setSelectedZone, setSelectedZone,
}) => { }) => {
// Ref for the container element // Ref for the container element
const containerRef = useRef<HTMLDivElement | null>(null); const containerRef = useRef<HTMLDivElement | null>(null);
// Example state for selectedOption and options (adjust based on your actual use case) // Example state for selectedOption and options (adjust based on your actual use case)
const [selectedOption, setSelectedOption] = React.useState<string | null>( const [selectedOption, setSelectedOption] = React.useState<string | null>(
null null
); );
// console.log('setSelectedOption: ', setSelectedOption); // console.log('setSelectedOption: ', setSelectedOption);
const [options, setOptions] = React.useState<string[]>([]); const [options, setOptions] = React.useState<string[]>([]);
// console.log('setOptions: ', setOptions); // console.log('setOptions: ', setOptions);
// Scroll to the selected option when it changes // Scroll to the selected option when it changes
useEffect(() => { useEffect(() => {
const container = containerRef.current; const container = containerRef.current;
if (container && selectedOption) { if (container && selectedOption) {
// Handle scrolling to the selected option // Handle scrolling to the selected option
const index = options.findIndex((option) => { const index = options.findIndex((option) => {
const formattedOption = formatOptionName(option); const formattedOption = formatOptionName(option);
const selectedFormattedOption = const selectedFormattedOption =
selectedOption?.split("_")[1] || selectedOption; selectedOption?.split("_")[1] || selectedOption;
return formattedOption === selectedFormattedOption; return formattedOption === selectedFormattedOption;
}); });
if (index !== -1) { if (index !== -1) {
const optionElement = container.children[index] as HTMLElement; const optionElement = container.children[index] as HTMLElement;
if (optionElement) { if (optionElement) {
optionElement.scrollIntoView({ optionElement.scrollIntoView({
behavior: "smooth", behavior: "smooth",
block: "nearest", block: "nearest",
inline: "center", inline: "center",
}); });
} }
} }
} }
}, [selectedOption, options]); }, [selectedOption, options]);
useEffect(() => { useEffect(() => {
const container = containerRef.current; const container = containerRef.current;
const handleWheel = (event: WheelEvent) => { const handleWheel = (event: WheelEvent) => {
event.preventDefault(); event.preventDefault();
if (container) { if (container) {
container.scrollBy({ container.scrollBy({
left: event.deltaY * 2, // Adjust the multiplier for faster scrolling left: event.deltaY * 2, // Adjust the multiplier for faster scrolling
behavior: "smooth", behavior: "smooth",
}); });
} }
}; };
let isDragging = false; let isDragging = false;
let startX: number; let startX: number;
let scrollLeft: number; let scrollLeft: number;
const handleMouseDown = (event: MouseEvent) => { const handleMouseDown = (event: MouseEvent) => {
isDragging = true; isDragging = true;
startX = event.pageX - (container?.offsetLeft || 0); startX = event.pageX - (container?.offsetLeft || 0);
scrollLeft = container?.scrollLeft || 0; scrollLeft = container?.scrollLeft || 0;
}; };
const handleMouseMove = (event: MouseEvent) => { const handleMouseMove = (event: MouseEvent) => {
if (!isDragging || !container) return; if (!isDragging || !container) return;
event.preventDefault(); event.preventDefault();
const x = event.pageX - (container.offsetLeft || 0); const x = event.pageX - (container.offsetLeft || 0);
const walk = (x - startX) * 2; // Adjust the multiplier for faster dragging const walk = (x - startX) * 2; // Adjust the multiplier for faster dragging
container.scrollLeft = scrollLeft - walk; container.scrollLeft = scrollLeft - walk;
}; };
const handleMouseUp = () => { const handleMouseUp = () => {
isDragging = false; isDragging = false;
}; };
const handleMouseLeave = () => { const handleMouseLeave = () => {
isDragging = false; isDragging = false;
}; };
if (container) { if (container) {
container.addEventListener("wheel", handleWheel, { passive: false }); container.addEventListener("wheel", handleWheel, { passive: false });
container.addEventListener("mousedown", handleMouseDown); container.addEventListener("mousedown", handleMouseDown);
container.addEventListener("mousemove", handleMouseMove); container.addEventListener("mousemove", handleMouseMove);
container.addEventListener("mouseup", handleMouseUp); container.addEventListener("mouseup", handleMouseUp);
container.addEventListener("mouseleave", handleMouseLeave); container.addEventListener("mouseleave", handleMouseLeave);
} }
return () => { return () => {
if (container) { if (container) {
container.removeEventListener("wheel", handleWheel); container.removeEventListener("wheel", handleWheel);
container.removeEventListener("mousedown", handleMouseDown); container.removeEventListener("mousedown", handleMouseDown);
container.removeEventListener("mousemove", handleMouseMove); container.removeEventListener("mousemove", handleMouseMove);
container.removeEventListener("mouseup", handleMouseUp); container.removeEventListener("mouseup", handleMouseUp);
container.removeEventListener("mouseleave", handleMouseLeave); container.removeEventListener("mouseleave", handleMouseLeave);
} }
}; };
}, []); }, []);
// Helper function to format option names (customize as needed) // Helper function to format option names (customize as needed)
const formatOptionName = (option: string): string => { const formatOptionName = (option: string): string => {
// Replace underscores with spaces and capitalize the first letter // Replace underscores with spaces and capitalize the first letter
return option.replace(/_/g, " ").replace(/^\w/, (c) => c.toUpperCase()); return option.replace(/_/g, " ").replace(/^\w/, (c) => c.toUpperCase());
}; };
return ( return (
<div <div
ref={containerRef} ref={containerRef}
className={`zoon-wrapper ${ className={`zoon-wrapper ${
selectedZone.activeSides.includes("bottom") && "bottom" selectedZone.activeSides.includes("bottom") && "bottom"
}`} }`}
> >
{Object.keys(zonesData).map((zoneName, index) => ( {Object.keys(zonesData).map((zoneName, index) => (
<div <div
key={index} key={index}
className={`zone ${ className={`zone ${
selectedZone.zoneName === zoneName ? "active" : "" selectedZone.zoneName === zoneName ? "active" : ""
}`} }`}
onClick={() => { onClick={() => {
setSelectedZone({ setSelectedZone({
zoneName, zoneName,
...zonesData[zoneName], ...zonesData[zoneName],
}); });
}} }}
> >
{zoneName} {zoneName}
</div> </div>
))} ))}
</div> </div>
); );
}; };
export default DisplayZone; export default DisplayZone;

View File

@@ -1,82 +1,82 @@
import { useWidgetStore } from "../../../store/useWidgetStore"; import { useWidgetStore } from "../../../store/useWidgetStore";
import PieGraphComponent from "../charts/PieGraphComponent"; import PieGraphComponent from "../charts/PieGraphComponent";
import BarGraphComponent from "../charts/BarGraphComponent"; import BarGraphComponent from "../charts/BarGraphComponent";
import LineGraphComponent from "../charts/LineGraphComponent"; import LineGraphComponent from "../charts/LineGraphComponent";
export const DraggableWidget = ({ widget }: { widget: any }) => { export const DraggableWidget = ({ widget }: { widget: any }) => {
const { selectedChartId, setSelectedChartId } = useWidgetStore(); const { selectedChartId, setSelectedChartId } = useWidgetStore();
const handlePointerDown = () => { const handlePointerDown = () => {
if (selectedChartId?.id !== widget.id) { if (selectedChartId?.id !== widget.id) {
setSelectedChartId(widget); setSelectedChartId(widget);
} }
}; };
return ( return (
<> <>
<div <div
key={widget.id} key={widget.id}
className={`chart-container ${ className={`chart-container ${
selectedChartId?.id === widget.id && "activeChart" selectedChartId?.id === widget.id && "activeChart"
}`} }`}
onPointerDown={handlePointerDown} onPointerDown={handlePointerDown}
> >
{widget.type === "progress" ? ( {widget.type === "progress" ? (
// <ProgressCard title={widget.title} data={widget.data} /> // <ProgressCard title={widget.title} data={widget.data} />
<></> <></>
) : ( ) : (
<> <>
{widget.type === "line" && ( {widget.type === "line" && (
<LineGraphComponent <LineGraphComponent
type={widget.type} type={widget.type}
title={widget.title} title={widget.title}
fontSize={widget.fontSize} fontSize={widget.fontSize}
fontWeight={widget.fontWeight} fontWeight={widget.fontWeight}
data={{ data={{
measurements: [ measurements: [
{ name: "testDevice", fields: "powerConsumption" }, { name: "testDevice", fields: "powerConsumption" },
{ name: "furnace", fields: "powerConsumption" }, { name: "furnace", fields: "powerConsumption" },
], ],
interval: 1000, interval: 1000,
duration: "1h", duration: "1h",
}} }}
/> />
)} )}
{widget.type === "bar" && ( {widget.type === "bar" && (
<BarGraphComponent <BarGraphComponent
type={widget.type} type={widget.type}
title={widget.title} title={widget.title}
fontSize={widget.fontSize} fontSize={widget.fontSize}
fontWeight={widget.fontWeight} fontWeight={widget.fontWeight}
data={{ data={{
measurements: [ measurements: [
{ name: "testDevice", fields: "powerConsumption" }, { name: "testDevice", fields: "powerConsumption" },
{ name: "furnace", fields: "powerConsumption" }, { name: "furnace", fields: "powerConsumption" },
], ],
interval: 1000, interval: 1000,
duration: "1h", duration: "1h",
}} }}
/> />
)} )}
{widget.type === "pie" && ( {widget.type === "pie" && (
<PieGraphComponent <PieGraphComponent
type={widget.type} type={widget.type}
title={widget.title} title={widget.title}
fontSize={widget.fontSize} fontSize={widget.fontSize}
fontWeight={widget.fontWeight} fontWeight={widget.fontWeight}
data={{ data={{
measurements: [ measurements: [
{ name: "testDevice", fields: "powerConsumption" }, { name: "testDevice", fields: "powerConsumption" },
{ name: "furnace", fields: "powerConsumption" }, { name: "furnace", fields: "powerConsumption" },
], ],
interval: 1000, interval: 1000,
duration: "1h", duration: "1h",
}} }}
/> />
)} )}
</> </>
)} )}
</div> </div>
</> </>
); );
}; };

View File

@@ -1,203 +1,203 @@
import React, { useEffect, useMemo, useRef, useState } from "react"; import React, { useEffect, useMemo, useRef, useState } from "react";
import { useWidgetStore } from "../../../store/useWidgetStore"; import { useWidgetStore } from "../../../store/useWidgetStore";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
import { DraggableWidget } from "./DraggableWidget"; import { DraggableWidget } from "./DraggableWidget";
type Side = "top" | "bottom" | "left" | "right"; type Side = "top" | "bottom" | "left" | "right";
interface Widget { interface Widget {
id: string; id: string;
type: string; type: string;
title: string; title: string;
panel: Side; panel: Side;
data: any; data: any;
} }
interface PanelProps { interface PanelProps {
selectedZone: { selectedZone: {
zoneName: string; zoneName: string;
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
widgets: Widget[]; widgets: Widget[];
}; };
setSelectedZone: React.Dispatch< setSelectedZone: React.Dispatch<
React.SetStateAction<{ React.SetStateAction<{
zoneName: string; zoneName: string;
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
widgets: Widget[]; widgets: Widget[];
}> }>
>; >;
} }
const generateUniqueId = () => const generateUniqueId = () =>
`${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const Panel: React.FC<PanelProps> = ({ selectedZone, setSelectedZone }) => { const Panel: React.FC<PanelProps> = ({ selectedZone, setSelectedZone }) => {
const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({}); const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({});
const [panelDimensions, setPanelDimensions] = useState<{ const [panelDimensions, setPanelDimensions] = useState<{
[side in Side]?: { width: number; height: number }; [side in Side]?: { width: number; height: number };
}>({}); }>({});
const getPanelStyle = useMemo( const getPanelStyle = useMemo(
() => (side: Side) => { () => (side: Side) => {
const currentIndex = selectedZone.panelOrder.indexOf(side); const currentIndex = selectedZone.panelOrder.indexOf(side);
const previousPanels = selectedZone.panelOrder.slice(0, currentIndex); const previousPanels = selectedZone.panelOrder.slice(0, currentIndex);
const leftActive = previousPanels.includes("left"); const leftActive = previousPanels.includes("left");
const rightActive = previousPanels.includes("right"); const rightActive = previousPanels.includes("right");
const topActive = previousPanels.includes("top"); const topActive = previousPanels.includes("top");
const bottomActive = previousPanels.includes("bottom"); const bottomActive = previousPanels.includes("bottom");
switch (side) { switch (side) {
case "top": case "top":
case "bottom": case "bottom":
return { return {
width: `calc(100% - ${ width: `calc(100% - ${
(leftActive ? 204 : 0) + (rightActive ? 204 : 0) (leftActive ? 204 : 0) + (rightActive ? 204 : 0)
}px)`, }px)`,
left: leftActive ? "204px" : "0", left: leftActive ? "204px" : "0",
right: rightActive ? "204px" : "0", right: rightActive ? "204px" : "0",
[side]: "0", [side]: "0",
height: "200px", height: "200px",
}; };
case "left": case "left":
case "right": case "right":
return { return {
height: `calc(100% - ${ height: `calc(100% - ${
(topActive ? 204 : 0) + (bottomActive ? 204 : 0) (topActive ? 204 : 0) + (bottomActive ? 204 : 0)
}px)`, }px)`,
top: topActive ? "204px" : "0", top: topActive ? "204px" : "0",
bottom: bottomActive ? "204px" : "0", bottom: bottomActive ? "204px" : "0",
[side]: "0", [side]: "0",
width: "200px", width: "200px",
}; };
default: default:
return {}; return {};
} }
}, },
[selectedZone.panelOrder] [selectedZone.panelOrder]
); );
const handleDrop = (e: React.DragEvent, panel: Side) => { const handleDrop = (e: React.DragEvent, panel: Side) => {
e.preventDefault(); e.preventDefault();
const { draggedAsset } = useWidgetStore.getState(); const { draggedAsset } = useWidgetStore.getState();
if (!draggedAsset) return; if (!draggedAsset) return;
if (isPanelLocked(panel)) return; if (isPanelLocked(panel)) return;
const currentWidgetsCount = getCurrentWidgetCount(panel); const currentWidgetsCount = getCurrentWidgetCount(panel);
const maxCapacity = calculatePanelCapacity(panel); const maxCapacity = calculatePanelCapacity(panel);
if (currentWidgetsCount >= maxCapacity) return; if (currentWidgetsCount >= maxCapacity) return;
addWidgetToPanel(draggedAsset, panel); addWidgetToPanel(draggedAsset, panel);
}; };
// Helper functions // Helper functions
const isPanelLocked = (panel: Side) => const isPanelLocked = (panel: Side) =>
selectedZone.lockedPanels.includes(panel); selectedZone.lockedPanels.includes(panel);
const getCurrentWidgetCount = (panel: Side) => const getCurrentWidgetCount = (panel: Side) =>
selectedZone.widgets.filter(w => w.panel === panel).length; selectedZone.widgets.filter(w => w.panel === panel).length;
const calculatePanelCapacity = (panel: Side) => { const calculatePanelCapacity = (panel: Side) => {
const CHART_WIDTH = 200; const CHART_WIDTH = 200;
const CHART_HEIGHT = 200; const CHART_HEIGHT = 200;
const FALLBACK_HORIZONTAL_CAPACITY = 5; const FALLBACK_HORIZONTAL_CAPACITY = 5;
const FALLBACK_VERTICAL_CAPACITY = 3; const FALLBACK_VERTICAL_CAPACITY = 3;
const dimensions = panelDimensions[panel]; const dimensions = panelDimensions[panel];
if (!dimensions) { if (!dimensions) {
return panel === "top" || panel === "bottom" return panel === "top" || panel === "bottom"
? FALLBACK_HORIZONTAL_CAPACITY ? FALLBACK_HORIZONTAL_CAPACITY
: FALLBACK_VERTICAL_CAPACITY; : FALLBACK_VERTICAL_CAPACITY;
} }
return panel === "top" || panel === "bottom" return panel === "top" || panel === "bottom"
? Math.floor(dimensions.width / CHART_WIDTH) ? Math.floor(dimensions.width / CHART_WIDTH)
: Math.floor(dimensions.height / CHART_HEIGHT); : Math.floor(dimensions.height / CHART_HEIGHT);
}; };
const addWidgetToPanel = (asset: any, panel: Side) => { const addWidgetToPanel = (asset: any, panel: Side) => {
const newWidget = { const newWidget = {
...asset, ...asset,
id: generateUniqueId(), id: generateUniqueId(),
panel, panel,
}; };
setSelectedZone(prev => ({ setSelectedZone(prev => ({
...prev, ...prev,
widgets: [...prev.widgets, newWidget] widgets: [...prev.widgets, newWidget]
})); }));
}; };
useEffect(() => { useEffect(() => {
const observers: ResizeObserver[] = []; const observers: ResizeObserver[] = [];
const currentPanelRefs = panelRefs.current; const currentPanelRefs = panelRefs.current;
selectedZone.activeSides.forEach((side) => { selectedZone.activeSides.forEach((side) => {
const element = currentPanelRefs[side]; const element = currentPanelRefs[side];
if (element) { if (element) {
const observer = new ResizeObserver((entries) => { const observer = new ResizeObserver((entries) => {
for (const entry of entries) { for (const entry of entries) {
const { width, height } = entry.contentRect; const { width, height } = entry.contentRect;
setPanelDimensions((prev) => ({ setPanelDimensions((prev) => ({
...prev, ...prev,
[side]: { width, height }, [side]: { width, height },
})); }));
} }
}); });
observer.observe(element); observer.observe(element);
observers.push(observer); observers.push(observer);
} }
}); });
return () => { return () => {
observers.forEach((observer) => observer.disconnect()); observers.forEach((observer) => observer.disconnect());
}; };
}, [selectedZone.activeSides]); }, [selectedZone.activeSides]);
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
return ( return (
<> <>
{selectedZone.activeSides.map((side) => ( {selectedZone.activeSides.map((side) => (
<div <div
key={side} key={side}
className={`panel ${side}-panel absolute ${isPlaying && ""}`} className={`panel ${side}-panel absolute ${isPlaying && ""}`}
style={getPanelStyle(side)} style={getPanelStyle(side)}
onDrop={(e) => handleDrop(e, side)} onDrop={(e) => handleDrop(e, side)}
onDragOver={(e) => e.preventDefault()} onDragOver={(e) => e.preventDefault()}
ref={(el) => { ref={(el) => {
if (el) { if (el) {
panelRefs.current[side] = el; panelRefs.current[side] = el;
} else { } else {
delete panelRefs.current[side]; delete panelRefs.current[side];
} }
}} }}
> >
<div <div
className={`panel-content ${isPlaying && "fullScreen"}`} className={`panel-content ${isPlaying && "fullScreen"}`}
style={{ style={{
pointerEvents: selectedZone.lockedPanels.includes(side) pointerEvents: selectedZone.lockedPanels.includes(side)
? "none" ? "none"
: "auto", : "auto",
opacity: selectedZone.lockedPanels.includes(side) ? "0.8" : "1", opacity: selectedZone.lockedPanels.includes(side) ? "0.8" : "1",
}} }}
> >
<>{}</> <>{}</>
{selectedZone.widgets {selectedZone.widgets
.filter((w) => w.panel === side) .filter((w) => w.panel === side)
.map((widget) => ( .map((widget) => (
<DraggableWidget widget={widget} key={widget.id} /> <DraggableWidget widget={widget} key={widget.id} />
))} ))}
</div> </div>
</div> </div>
))} ))}
</> </>
); );
}; };
export default Panel; export default Panel;

View File

@@ -1,103 +1,122 @@
import React, { useEffect, useState, useRef } from "react"; import React, { useEffect, useState, useRef } from "react";
import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
import Panel from "./Panel"; import Panel from "./Panel";
import AddButtons from "./AddButtons"; import AddButtons from "./AddButtons";
import { useSelectedZoneStore } from "../../../store/useZoneStore"; import { useSelectedZoneStore } from "../../../store/useZoneStore";
import DisplayZone from "./DisplayZone"; import DisplayZone from "./DisplayZone";
import Scene from "../../../modules/scene/scene";
type Side = "top" | "bottom" | "left" | "right"; import useModuleStore from "../../../store/useModuleStore";
interface Widget { type Side = "top" | "bottom" | "left" | "right";
id: string;
type: string; interface Widget {
title: string; id: string;
panel: Side; type: string;
data: any; title: string;
} panel: Side;
data: any;
const RealTimeVisulization: React.FC = () => { }
const [hiddenPanels, setHiddenPanels] = React.useState<Side[]>([]);
const containerRef = useRef<HTMLDivElement>(null); const RealTimeVisulization: React.FC = () => {
const [zonesData, setZonesData] = useState<{ const [hiddenPanels, setHiddenPanels] = React.useState<Side[]>([]);
[key: string]: { const containerRef = useRef<HTMLDivElement>(null);
activeSides: Side[]; const [zonesData, setZonesData] = useState<{
panelOrder: Side[]; [key: string]: {
lockedPanels: Side[]; activeSides: Side[];
widgets: Widget[]; panelOrder: Side[];
}; lockedPanels: Side[];
}>({ widgets: Widget[];
"Manufacturing unit": { };
activeSides: [], }>({
panelOrder: [], "Manufacturing unit": {
lockedPanels: [], activeSides: [],
widgets: [], panelOrder: [],
}, lockedPanels: [],
"Assembly unit": { widgets: [],
activeSides: [], },
panelOrder: [], "Assembly unit": {
lockedPanels: [], activeSides: [],
widgets: [], panelOrder: [],
}, lockedPanels: [],
"Packing unit": { widgets: [],
activeSides: [], },
panelOrder: [], "Packing unit": {
lockedPanels: [], activeSides: [],
widgets: [], panelOrder: [],
}, lockedPanels: [],
Warehouse: { widgets: [],
activeSides: [], },
panelOrder: [], Warehouse: {
lockedPanels: [], activeSides: [],
widgets: [], panelOrder: [],
}, lockedPanels: [],
Inventory: { widgets: [],
activeSides: [], },
panelOrder: [], Inventory: {
lockedPanels: [], activeSides: [],
widgets: [], panelOrder: [],
}, lockedPanels: [],
}); widgets: [],
},
const { isPlaying } = usePlayButtonStore(); });
const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { isPlaying } = usePlayButtonStore();
useEffect(() => { const { activeModule } = useModuleStore();
setZonesData((prev) => ({
...prev, const { selectedZone, setSelectedZone } = useSelectedZoneStore();
[selectedZone.zoneName]: selectedZone, useEffect(() => {
})); setZonesData((prev) => ({
}, [selectedZone]); ...prev,
[selectedZone.zoneName]: selectedZone,
return ( }));
<div }, [selectedZone]);
ref={containerRef}
id="real-time-vis-canvas" return (
className="realTime-viz canvas" <div
style={{ ref={containerRef}
height: isPlaying ? "100vh" : "", id="real-time-vis-canvas"
width: isPlaying ? "100%" : "", className="realTime-viz canvas"
left: isPlaying ? "0%" : "", style={{
}} height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
> width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
<DisplayZone left: isPlaying || activeModule !== "visualization" ? "0%" : "",
zonesData={zonesData} }}
selectedZone={selectedZone} >
setSelectedZone={setSelectedZone} <div
/> className="scene-container"
style={{
{!isPlaying && ( height: "100%",
<AddButtons width: "100%",
hiddenPanels={hiddenPanels} borderRadius: isPlaying || activeModule !== "visualization" ? "" : "6px",
setHiddenPanels={setHiddenPanels} }}
selectedZone={selectedZone} >
setSelectedZone={setSelectedZone} <Scene />
/> </div>
)} {activeModule === "visualization" && (
<>
<Panel selectedZone={selectedZone} setSelectedZone={setSelectedZone} /> <DisplayZone
</div> zonesData={zonesData}
); selectedZone={selectedZone}
}; setSelectedZone={setSelectedZone}
/>
export default RealTimeVisulization;
{!isPlaying && (
<AddButtons
hiddenPanels={hiddenPanels}
setHiddenPanels={setHiddenPanels}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
)}
<Panel
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
</>
)}
</div>
);
};
export default RealTimeVisulization;

View File

@@ -1,76 +1,76 @@
import React, { useState } from "react"; import React, { useState } from "react";
import RenameInput from "./RenameInput"; import RenameInput from "./RenameInput";
type InputWithDropDownProps = { type InputWithDropDownProps = {
label: string; label: string;
value: string; value: string;
options?: string[]; // Array of dropdown options options?: string[]; // Array of dropdown options
activeOption?: string; // The currently active dropdown option activeOption?: string; // The currently active dropdown option
onClick?: () => void; onClick?: () => void;
onChange: (newValue: string) => void; onChange: (newValue: string) => void;
editableLabel?: boolean; editableLabel?: boolean;
}; };
const InputWithDropDown: React.FC<InputWithDropDownProps> = ({ const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
label, label,
value, value,
options, options,
activeOption, activeOption,
onClick, onClick,
onChange, onChange,
editableLabel = false, editableLabel = false,
}) => { }) => {
const separatedWords = label const separatedWords = label
.split(/(?=[A-Z])/) .split(/(?=[A-Z])/)
.map((word) => word.trim()) .map((word) => word.trim())
.toString(); .toString();
const [openDropdown, setOpenDropdown] = useState(false); const [openDropdown, setOpenDropdown] = useState(false);
return ( return (
<div className="value-field-container"> <div className="value-field-container">
{editableLabel ? ( {editableLabel ? (
<RenameInput value={label} /> <RenameInput value={label} />
) : ( ) : (
<label htmlFor={separatedWords} className="label"> <label htmlFor={separatedWords} className="label">
{label} {label}
</label> </label>
)} )}
<div className="input default" id={separatedWords}> <div className="input default" id={separatedWords}>
<input <input
type="text" type="text"
defaultValue={value} defaultValue={value}
onChange={(e) => { onChange={(e) => {
onChange(e.target.value); onChange(e.target.value);
}} }}
/> />
{activeOption && ( {activeOption && (
<div <div
className="dropdown" className="dropdown"
onClick={() => { onClick={() => {
setOpenDropdown(true); setOpenDropdown(true);
}} }}
> >
<div className="active-option">{activeOption}</div> <div className="active-option">{activeOption}</div>
{options && openDropdown && ( {options && openDropdown && (
<div className="dropdown-options-list"> <div className="dropdown-options-list">
{options.map((option, index) => ( {options.map((option, index) => (
<div <div
key={index} key={index}
className={"dropdown-option"} className={"dropdown-option"}
onClick={onClick} onClick={onClick}
> >
{option} {option}
</div> </div>
))} ))}
</div> </div>
)} )}
</div> </div>
)} )}
</div> </div>
</div> </div>
); );
}; };
export default InputWithDropDown; export default InputWithDropDown;

View File

@@ -1,29 +1,29 @@
import React, { useState } from "react"; import React, { useState } from "react";
import RegularDropDown from "./RegularDropDown"; import RegularDropDown from "./RegularDropDown";
type LabledDropdownProps = { type LabledDropdownProps = {
defaultOption: string; // Initial active option defaultOption: string; // Initial active option
options: string[]; // Array of dropdown options options: string[]; // Array of dropdown options
}; };
const LabledDropdown: React.FC<LabledDropdownProps> = ({ defaultOption, options }) => { const LabledDropdown: React.FC<LabledDropdownProps> = ({ defaultOption, options }) => {
const [activeOption, setActiveOption] = useState(defaultOption); // State for active option const [activeOption, setActiveOption] = useState(defaultOption); // State for active option
const handleSelect = (option: string) => { const handleSelect = (option: string) => {
setActiveOption(option); // Update the active option state setActiveOption(option); // Update the active option state
}; };
return ( return (
<div className="value-field-container"> <div className="value-field-container">
<div className="label">Type</div> <div className="label">Type</div>
<RegularDropDown <RegularDropDown
header={activeOption} // Display the current active option header={activeOption} // Display the current active option
options={options} // Use the options from props options={options} // Use the options from props
onSelect={handleSelect} // Handle option selection onSelect={handleSelect} // Handle option selection
search = {false} search = {false}
/> />
</div> </div>
); );
}; };
export default LabledDropdown; export default LabledDropdown;

View File

@@ -1,141 +1,141 @@
import React, { useState, useRef, useEffect } from "react"; import React, { useState, useRef, useEffect } from "react";
// Dropdown Item Component // Dropdown Item Component
const DropdownItem = ({ const DropdownItem = ({
label, label,
href, href,
onClick, onClick,
}: { }: {
label: string; label: string;
href?: string; href?: string;
onClick?: () => void; onClick?: () => void;
}) => ( }) => (
<a <a
href={href || "#"} href={href || "#"}
className="dropdown-item" className="dropdown-item"
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
onClick?.(); onClick?.();
}} }}
> >
{label} {label}
</a> </a>
); );
// Nested Dropdown Component // Nested Dropdown Component
const NestedDropdown = ({ const NestedDropdown = ({
label, label,
children, children,
onSelect, onSelect,
}: { }: {
label: string; label: string;
children: React.ReactNode; children: React.ReactNode;
onSelect: (selectedLabel: string) => void; onSelect: (selectedLabel: string) => void;
}) => { }) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
return ( return (
<div className="nested-dropdown"> <div className="nested-dropdown">
{/* Dropdown Trigger */} {/* Dropdown Trigger */}
<div <div
className={`dropdown-trigger ${open ? "open" : ""}`} className={`dropdown-trigger ${open ? "open" : ""}`}
onClick={() => setOpen(!open)} // Toggle submenu on click onClick={() => setOpen(!open)} // Toggle submenu on click
> >
{label} <span className="icon">{open ? "▼" : "▶"}</span> {label} <span className="icon">{open ? "▼" : "▶"}</span>
</div> </div>
{/* Submenu */} {/* Submenu */}
{open && ( {open && (
<div className="submenu"> <div className="submenu">
{React.Children.map(children, (child) => { {React.Children.map(children, (child) => {
if (React.isValidElement(child)) { if (React.isValidElement(child)) {
// Clone the element and pass the `onSelect` prop only if it's expected // Clone the element and pass the `onSelect` prop only if it's expected
return React.cloneElement(child as React.ReactElement<any>, { onSelect }); return React.cloneElement(child as React.ReactElement<any>, { onSelect });
} }
return child; // Return non-element children as-is return child; // Return non-element children as-is
})} })}
</div> </div>
)} )}
</div> </div>
); );
}; };
// Recursive Function to Render Nested Data // Recursive Function to Render Nested Data
const renderNestedData = ( const renderNestedData = (
data: Record<string, any>, data: Record<string, any>,
onSelect: (selectedLabel: string) => void onSelect: (selectedLabel: string) => void
) => { ) => {
return Object.entries(data).map(([key, value]) => { return Object.entries(data).map(([key, value]) => {
if (typeof value === "object" && !Array.isArray(value)) { if (typeof value === "object" && !Array.isArray(value)) {
// If the value is an object, render it as a nested dropdown // If the value is an object, render it as a nested dropdown
return ( return (
<NestedDropdown key={key} label={key} onSelect={onSelect}> <NestedDropdown key={key} label={key} onSelect={onSelect}>
{renderNestedData(value, onSelect)} {renderNestedData(value, onSelect)}
</NestedDropdown> </NestedDropdown>
); );
} else if (Array.isArray(value)) { } else if (Array.isArray(value)) {
// If the value is an array, render each item as a dropdown item // If the value is an array, render each item as a dropdown item
return value.map((item, index) => ( return value.map((item, index) => (
<DropdownItem key={index} label={item} onClick={() => onSelect(item)} /> <DropdownItem key={index} label={item} onClick={() => onSelect(item)} />
)); ));
} else { } else {
// If the value is a simple string, render it as a dropdown item // If the value is a simple string, render it as a dropdown item
return ( return (
<DropdownItem key={key} label={value} onClick={() => onSelect(value)} /> <DropdownItem key={key} label={value} onClick={() => onSelect(value)} />
); );
} }
}); });
}; };
// Main Multi-Level Dropdown Component // Main Multi-Level Dropdown Component
const MultiLevelDropdown = ({ data }: { data: Record<string, any> }) => { const MultiLevelDropdown = ({ data }: { data: Record<string, any> }) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [selectedLabel, setSelectedLabel] = useState("Dropdown trigger"); const [selectedLabel, setSelectedLabel] = useState("Dropdown trigger");
const dropdownRef = useRef<HTMLDivElement>(null); const dropdownRef = useRef<HTMLDivElement>(null);
// Handle outer click to close the dropdown // Handle outer click to close the dropdown
useEffect(() => { useEffect(() => {
const handleClickOutside = (event: MouseEvent) => { const handleClickOutside = (event: MouseEvent) => {
if ( if (
dropdownRef.current && dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node) !dropdownRef.current.contains(event.target as Node)
) { ) {
setOpen(false); setOpen(false);
} }
}; };
document.addEventListener("mousedown", handleClickOutside); document.addEventListener("mousedown", handleClickOutside);
return () => { return () => {
document.removeEventListener("mousedown", handleClickOutside); document.removeEventListener("mousedown", handleClickOutside);
}; };
}, []); }, []);
// Handle selection of an item // Handle selection of an item
const handleSelect = (selectedLabel: string) => { const handleSelect = (selectedLabel: string) => {
setSelectedLabel(selectedLabel); // Update the dropdown trigger text setSelectedLabel(selectedLabel); // Update the dropdown trigger text
setOpen(false); // Close the dropdown setOpen(false); // Close the dropdown
}; };
return ( return (
<div className="multi-level-dropdown" ref={dropdownRef}> <div className="multi-level-dropdown" ref={dropdownRef}>
{/* Dropdown Trigger Button */} {/* Dropdown Trigger Button */}
<button <button
className={`dropdown-button ${open ? "open" : ""}`} className={`dropdown-button ${open ? "open" : ""}`}
onClick={() => setOpen(!open)} // Toggle main menu on click onClick={() => setOpen(!open)} // Toggle main menu on click
> >
{selectedLabel} <span className="icon"></span> {selectedLabel} <span className="icon"></span>
</button> </button>
{/* Dropdown Menu */} {/* Dropdown Menu */}
{open && ( {open && (
<div className="dropdown-menu"> <div className="dropdown-menu">
<div className="dropdown-content"> <div className="dropdown-content">
{renderNestedData(data, handleSelect)} {renderNestedData(data, handleSelect)}
</div> </div>
</div> </div>
)} )}
</div> </div>
); );
}; };
export default MultiLevelDropdown; export default MultiLevelDropdown;

View File

@@ -1,127 +1,127 @@
import React, { useState, useEffect, useRef } from "react"; import React, { useState, useEffect, useRef } from "react";
interface DropdownProps { interface DropdownProps {
header: string; header: string;
options: string[]; options: string[];
onSelect: (option: string) => void; onSelect: (option: string) => void;
search?: boolean; search?: boolean;
onClick?: () => void; onClick?: () => void;
onChange?: () => void; onChange?: () => void;
} }
const RegularDropDown: React.FC<DropdownProps> = ({ const RegularDropDown: React.FC<DropdownProps> = ({
header, header,
options, options,
onSelect, onSelect,
search = true, search = true,
onClick, onClick,
onChange, onChange,
}) => { }) => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [selectedOption, setSelectedOption] = useState<string | null>(null); const [selectedOption, setSelectedOption] = useState<string | null>(null);
const [searchTerm, setSearchTerm] = useState(""); // State to store search term const [searchTerm, setSearchTerm] = useState(""); // State to store search term
const [filteredOptions, setFilteredOptions] = useState<string[]>(options); // State for filtered options const [filteredOptions, setFilteredOptions] = useState<string[]>(options); // State for filtered options
const dropdownRef = useRef<HTMLDivElement>(null); // Ref for the dropdown container const dropdownRef = useRef<HTMLDivElement>(null); // Ref for the dropdown container
// Reset selectedOption when the dropdown closes // Reset selectedOption when the dropdown closes
useEffect(() => { useEffect(() => {
if (!isOpen) { if (!isOpen) {
setSelectedOption(null); setSelectedOption(null);
setSearchTerm(""); // Clear the search term when the dropdown closes setSearchTerm(""); // Clear the search term when the dropdown closes
setFilteredOptions(options); // Reset filtered options when the dropdown closes setFilteredOptions(options); // Reset filtered options when the dropdown closes
} }
}, [isOpen, options]); }, [isOpen, options]);
// Reset selectedOption when the header prop changes // Reset selectedOption when the header prop changes
useEffect(() => { useEffect(() => {
setSelectedOption(null); setSelectedOption(null);
setSearchTerm(""); // Reset search term if header changes setSearchTerm(""); // Reset search term if header changes
setFilteredOptions(options); // Reset options if header changes setFilteredOptions(options); // Reset options if header changes
}, [header, options]); }, [header, options]);
// Close dropdown if clicked outside // Close dropdown if clicked outside
useEffect(() => { useEffect(() => {
const handleClickOutside = (event: MouseEvent) => { const handleClickOutside = (event: MouseEvent) => {
if ( if (
dropdownRef.current && dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node) !dropdownRef.current.contains(event.target as Node)
) { ) {
setIsOpen(false); setIsOpen(false);
} }
}; };
document.addEventListener("click", handleClickOutside); document.addEventListener("click", handleClickOutside);
return () => { return () => {
document.removeEventListener("click", handleClickOutside); document.removeEventListener("click", handleClickOutside);
}; };
}, []); }, []);
// Toggle the dropdown // Toggle the dropdown
const toggleDropdown = () => { const toggleDropdown = () => {
setIsOpen((prev) => !prev); setIsOpen((prev) => !prev);
}; };
// Handle option selection // Handle option selection
const handleOptionClick = (option: string) => { const handleOptionClick = (option: string) => {
setSelectedOption(option); setSelectedOption(option);
onSelect(option); onSelect(option);
setIsOpen(false); setIsOpen(false);
}; };
// Handle search input change // Handle search input change
const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => { const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const term = event.target.value; const term = event.target.value;
setSearchTerm(term); setSearchTerm(term);
// Filter options based on the search term // Filter options based on the search term
const filtered = options.filter((option) => const filtered = options.filter((option) =>
option.toLowerCase().includes(term.toLowerCase()) option.toLowerCase().includes(term.toLowerCase())
); );
setFilteredOptions(filtered); setFilteredOptions(filtered);
}; };
return ( return (
<div className="regularDropdown-container" ref={dropdownRef}> <div className="regularDropdown-container" ref={dropdownRef}>
{/* Dropdown Header */} {/* Dropdown Header */}
<div className="dropdown-header flex-sb" onClick={toggleDropdown}> <div className="dropdown-header flex-sb" onClick={toggleDropdown}>
<div className="key">{selectedOption || header}</div> <div className="key">{selectedOption || header}</div>
<div className="icon"></div> <div className="icon"></div>
</div> </div>
{/* Dropdown Options */} {/* Dropdown Options */}
{isOpen && ( {isOpen && (
<div className="dropdown-options"> <div className="dropdown-options">
{/* Search Bar */} {/* Search Bar */}
{search && ( {search && (
<div className="dropdown-search"> <div className="dropdown-search">
<input <input
type="text" type="text"
placeholder="Search..." placeholder="Search..."
value={searchTerm} value={searchTerm}
onChange={handleSearchChange} onChange={handleSearchChange}
/> />
</div> </div>
)} )}
{/* Filtered Options */} {/* Filtered Options */}
{filteredOptions.length > 0 ? ( {filteredOptions.length > 0 ? (
filteredOptions.map((option, index) => ( filteredOptions.map((option, index) => (
<div <div
className="option" className="option"
key={index} key={index}
onClick={() => handleOptionClick(option)} onClick={() => handleOptionClick(option)}
> >
{option} {option}
</div> </div>
)) ))
) : ( ) : (
<div className="no-options">No options found</div> <div className="no-options">No options found</div>
)} )}
</div> </div>
)} )}
</div> </div>
); );
}; };
export default RegularDropDown; export default RegularDropDown;

View File

@@ -1,24 +1,24 @@
export const handleResize = ( export const handleResize = (
e: React.MouseEvent<HTMLDivElement>, e: React.MouseEvent<HTMLDivElement>,
containerRef: React.RefObject<HTMLDivElement | null> containerRef: React.RefObject<HTMLDivElement | null>
) => { ) => {
if (!containerRef.current) return; // Ensure containerRef is not null if (!containerRef.current) return; // Ensure containerRef is not null
const startY = e.clientY; const startY = e.clientY;
const startHeight = containerRef.current.offsetHeight; const startHeight = containerRef.current.offsetHeight;
const onMouseMove = (moveEvent: MouseEvent) => { const onMouseMove = (moveEvent: MouseEvent) => {
const newHeight = Math.max( const newHeight = Math.max(
120, 120,
Math.min(400, startHeight + moveEvent.clientY - startY) Math.min(400, startHeight + moveEvent.clientY - startY)
); );
containerRef.current!.style.height = `${newHeight}px`; containerRef.current!.style.height = `${newHeight}px`;
}; };
const onMouseUp = () => { const onMouseUp = () => {
document.removeEventListener("mousemove", onMouseMove); document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp); document.removeEventListener("mouseup", onMouseUp);
}; };
document.addEventListener("mousemove", onMouseMove); document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp); document.addEventListener("mouseup", onMouseUp);
}; };

View File

@@ -1,13 +1,13 @@
body { body {
margin: 0; margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif; sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
code { code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace; monospace;
} }

View File

@@ -1,19 +1,19 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';
import './index.css'; import './index.css';
import App from './app'; import App from './app';
import reportWebVitals from './reportWebVitals'; import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot( const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement document.getElementById('root') as HTMLElement
); );
root.render( root.render(
<React.StrictMode> <React.StrictMode>
<App /> <App />
</React.StrictMode> </React.StrictMode>
); );
// If you want to start measuring performance in your app, pass a function // If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log)) // to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals(); reportWebVitals();

View File

@@ -1,54 +1,54 @@
import * as THREE from "three"; import * as THREE from "three";
import { Geometry, Base, Subtraction } from "@react-three/csg"; import { Geometry, Base, Subtraction } from "@react-three/csg";
import { useDeleteModels } from "../../../store/store"; import { useDeleteModels } from "../../../store/store";
import { useRef } from "react"; import { useRef } from "react";
export interface CsgProps { export interface CsgProps {
position: THREE.Vector3 | [number, number, number]; position: THREE.Vector3 | [number, number, number];
scale: THREE.Vector3 | [number, number, number]; scale: THREE.Vector3 | [number, number, number];
model: THREE.Object3D; model: THREE.Object3D;
hoveredDeletableWallItem: { current: THREE.Mesh | null }; hoveredDeletableWallItem: { current: THREE.Mesh | null };
} }
export const Csg: React.FC<CsgProps> = (props) => { export const Csg: React.FC<CsgProps> = (props) => {
const { deleteModels } = useDeleteModels(); const { deleteModels } = useDeleteModels();
const modelRef = useRef<THREE.Object3D>(); const modelRef = useRef<THREE.Object3D>();
const originalMaterials = useRef<Map<THREE.Mesh, THREE.Material>>(new Map()); const originalMaterials = useRef<Map<THREE.Mesh, THREE.Material>>(new Map());
const handleHover = (hovered: boolean, object: THREE.Mesh | null) => { const handleHover = (hovered: boolean, object: THREE.Mesh | null) => {
if (modelRef.current && deleteModels) { if (modelRef.current && deleteModels) {
modelRef.current.traverse((child) => { modelRef.current.traverse((child) => {
if (child instanceof THREE.Mesh) { if (child instanceof THREE.Mesh) {
if (!originalMaterials.current.has(child)) { if (!originalMaterials.current.has(child)) {
originalMaterials.current.set(child, child.material); originalMaterials.current.set(child, child.material);
} }
child.material = child.material.clone(); child.material = child.material.clone();
child.material.color.set(hovered && deleteModels ? 0xff0000 : (originalMaterials.current.get(child) as any).color); child.material.color.set(hovered && deleteModels ? 0xff0000 : (originalMaterials.current.get(child) as any).color);
} }
}); });
} }
props.hoveredDeletableWallItem.current = hovered ? object : null; props.hoveredDeletableWallItem.current = hovered ? object : null;
}; };
return ( return (
<Geometry> <Geometry>
<Subtraction {...props}> <Subtraction {...props}>
<Geometry> <Geometry>
<Base geometry={new THREE.BoxGeometry()} /> <Base geometry={new THREE.BoxGeometry()} />
</Geometry> </Geometry>
</Subtraction> </Subtraction>
<primitive <primitive
object={props.model} object={props.model}
ref={modelRef} ref={modelRef}
onPointerOver={(e: any) => { onPointerOver={(e: any) => {
e.stopPropagation(); e.stopPropagation();
handleHover(true, e.object.parent); handleHover(true, e.object.parent);
}} }}
onPointerOut={(e: any) => { onPointerOut={(e: any) => {
e.stopPropagation(); e.stopPropagation();
handleHover(false, null); handleHover(false, null);
}} }}
/> />
</Geometry> </Geometry>
); );
}; };

View File

@@ -1,80 +1,80 @@
import * as THREE from 'three'; import * as THREE from 'three';
import { DragControls } from 'three/examples/jsm/controls/DragControls'; import { DragControls } from 'three/examples/jsm/controls/DragControls';
import * as CONSTANTS from '../../../types/world/worldConstants'; import * as CONSTANTS from '../../../types/world/worldConstants';
import DragPoint from '../geomentries/points/dragPoint'; import DragPoint from '../geomentries/points/dragPoint';
import * as Types from "../../../types/world/worldTypes"; import * as Types from "../../../types/world/worldTypes";
// import { updatePoint } from '../../../services/factoryBuilder/lines/updatePointApi'; // import { updatePoint } from '../../../services/factoryBuilder/lines/updatePointApi';
import { Socket } from 'socket.io-client'; import { Socket } from 'socket.io-client';
export default async function addDragControl( export default async function addDragControl(
dragPointControls: Types.RefDragControl, dragPointControls: Types.RefDragControl,
currentLayerPoint: Types.RefMeshArray, currentLayerPoint: Types.RefMeshArray,
state: Types.ThreeState, state: Types.ThreeState,
floorPlanGroupPoint: Types.RefGroup, floorPlanGroupPoint: Types.RefGroup,
floorPlanGroupLine: Types.RefGroup, floorPlanGroupLine: Types.RefGroup,
lines: Types.RefLines, lines: Types.RefLines,
onlyFloorlines: Types.RefOnlyFloorLines, onlyFloorlines: Types.RefOnlyFloorLines,
socket: Socket<any> socket: Socket<any>
) { ) {
////////// Dragging Point and also change the size to indicate during hover ////////// ////////// Dragging Point and also change the size to indicate during hover //////////
dragPointControls.current = new DragControls(currentLayerPoint.current, state.camera, state.gl.domElement); dragPointControls.current = new DragControls(currentLayerPoint.current, state.camera, state.gl.domElement);
dragPointControls.current.enabled = false; dragPointControls.current.enabled = false;
dragPointControls.current.addEventListener('drag', function (event) { dragPointControls.current.addEventListener('drag', function (event) {
const object = event.object; const object = event.object;
if (object.visible) { if (object.visible) {
(state.controls as any).enabled = false; (state.controls as any).enabled = false;
DragPoint(event as any, floorPlanGroupPoint, floorPlanGroupLine, state.scene, lines, onlyFloorlines) DragPoint(event as any, floorPlanGroupPoint, floorPlanGroupLine, state.scene, lines, onlyFloorlines)
} else { } else {
(state.controls as any).enabled = true; (state.controls as any).enabled = true;
} }
}); });
dragPointControls.current.addEventListener('dragstart', function (event) { dragPointControls.current.addEventListener('dragstart', function (event) {
}); });
dragPointControls.current.addEventListener('dragend', async function (event) { dragPointControls.current.addEventListener('dragend', async function (event) {
if (!dragPointControls.current) return; if (!dragPointControls.current) return;
const email = localStorage.getItem('email') const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0]; const organization = (email!.split("@")[1]).split(".")[0];
//REST //REST
// await updatePoint( // await updatePoint(
// organization, // organization,
// { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z }, // { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z },
// event.object.uuid, // event.object.uuid,
// ) // )
//SOCKET //SOCKET
const data = { const data = {
organization: organization, organization: organization,
position: { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z }, position: { "x": event.object.position.x, "y": 0.01, "z": event.object.position.z },
uuid: event.object.uuid, uuid: event.object.uuid,
socketId: socket.id socketId: socket.id
} }
socket.emit('v1:Line:update', data); socket.emit('v1:Line:update', data);
if (state.controls) { if (state.controls) {
(state.controls as any).enabled = true; (state.controls as any).enabled = true;
} }
}); });
dragPointControls.current.addEventListener('hoveron', function (event: any) { dragPointControls.current.addEventListener('hoveron', function (event: any) {
if ((event.object as Types.Mesh).name === "point") { if ((event.object as Types.Mesh).name === "point") {
event.object.material.uniforms.uInnerColor.value.set(event.object.userData.color) event.object.material.uniforms.uInnerColor.value.set(event.object.userData.color)
} }
}); });
dragPointControls.current.addEventListener('hoveroff', function (event: any) { dragPointControls.current.addEventListener('hoveroff', function (event: any) {
if ((event.object as Types.Mesh).name === "point") { if ((event.object as Types.Mesh).name === "point") {
event.object.material.uniforms.uInnerColor.value.set(new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor)) event.object.material.uniforms.uInnerColor.value.set(new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor))
} }
}); });
} }

View File

@@ -1,8 +1,8 @@
import * as Types from "../../../types/world/worldTypes"; import * as Types from "../../../types/world/worldTypes";
export default function handleContextMenu( export default function handleContextMenu(
menuVisible: Types.Boolean, menuVisible: Types.Boolean,
setMenuVisible: Types.BooleanState setMenuVisible: Types.BooleanState
): void { ): void {
// setMenuVisible(true) // setMenuVisible(true)
} }

View File

@@ -1,64 +1,64 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../types/world/worldTypes"; import * as Types from "../../../types/world/worldTypes";
function handleMeshDown( function handleMeshDown(
event: Types.MeshEvent, event: Types.MeshEvent,
currentWallItem: Types.RefMesh, currentWallItem: Types.RefMesh,
setSelectedWallItem: Types.setSelectedWallItemSetState, setSelectedWallItem: Types.setSelectedWallItemSetState,
setSelectedItemsIndex: Types.setSelectedItemsIndexSetState, setSelectedItemsIndex: Types.setSelectedItemsIndexSetState,
wallItems: Types.wallItems, wallItems: Types.wallItems,
toggleView: Types.Boolean toggleView: Types.Boolean
): void { ): void {
////////// To select which of the Wall item and CSG is selected to be dragged ////////// ////////// To select which of the Wall item and CSG is selected to be dragged //////////
if (!toggleView) { if (!toggleView) {
if (currentWallItem.current) { if (currentWallItem.current) {
currentWallItem.current.children.forEach((child) => { currentWallItem.current.children.forEach((child) => {
if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") { if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") {
const material = (child as THREE.Mesh).material; const material = (child as THREE.Mesh).material;
if (Array.isArray(material)) { if (Array.isArray(material)) {
material.forEach(mat => { material.forEach(mat => {
if (mat instanceof THREE.MeshStandardMaterial) { if (mat instanceof THREE.MeshStandardMaterial) {
mat.emissive = new THREE.Color("black"); mat.emissive = new THREE.Color("black");
} }
}); });
} else if (material instanceof THREE.MeshStandardMaterial) { } else if (material instanceof THREE.MeshStandardMaterial) {
material.emissive = new THREE.Color("black"); material.emissive = new THREE.Color("black");
} }
} }
}); });
currentWallItem.current = null; currentWallItem.current = null;
setSelectedWallItem(null); setSelectedWallItem(null);
setSelectedItemsIndex(null); setSelectedItemsIndex(null);
} }
if (event.intersections.length > 0) { if (event.intersections.length > 0) {
const clickedIndex = wallItems.findIndex((item) => item.model === event.intersections[0]?.object?.parent?.parent); const clickedIndex = wallItems.findIndex((item) => item.model === event.intersections[0]?.object?.parent?.parent);
if (clickedIndex !== -1) { if (clickedIndex !== -1) {
setSelectedItemsIndex(clickedIndex); setSelectedItemsIndex(clickedIndex);
const wallItemModel = wallItems[clickedIndex]?.model; const wallItemModel = wallItems[clickedIndex]?.model;
if (wallItemModel && wallItemModel.parent && wallItemModel.parent.parent) { if (wallItemModel && wallItemModel.parent && wallItemModel.parent.parent) {
currentWallItem.current = (wallItemModel.parent.parent.children[0]?.children[1]?.children[0] as Types.Mesh) || null; currentWallItem.current = (wallItemModel.parent.parent.children[0]?.children[1]?.children[0] as Types.Mesh) || null;
setSelectedWallItem(wallItemModel.parent); setSelectedWallItem(wallItemModel.parent);
// currentWallItem.current?.children.forEach((child) => { // currentWallItem.current?.children.forEach((child) => {
// if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") { // if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") {
// const material = (child as THREE.Mesh).material; // const material = (child as THREE.Mesh).material;
// if (Array.isArray(material)) { // if (Array.isArray(material)) {
// material.forEach(mat => { // material.forEach(mat => {
// if (mat instanceof THREE.MeshStandardMaterial) { // if (mat instanceof THREE.MeshStandardMaterial) {
// mat.emissive = new THREE.Color("green"); // mat.emissive = new THREE.Color("green");
// } // }
// }); // });
// } else if (material instanceof THREE.MeshStandardMaterial) { // } else if (material instanceof THREE.MeshStandardMaterial) {
// material.emissive = new THREE.Color("green"); // material.emissive = new THREE.Color("green");
// } // }
// } // }
// }); // });
} }
} }
} }
} }
} }
export default handleMeshDown; export default handleMeshDown;

View File

@@ -1,34 +1,34 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../types/world/worldTypes"; import * as Types from "../../../types/world/worldTypes";
function handleMeshMissed( function handleMeshMissed(
currentWallItem: Types.RefMesh, currentWallItem: Types.RefMesh,
setSelectedWallItem: Types.setSelectedWallItemSetState, setSelectedWallItem: Types.setSelectedWallItemSetState,
setSelectedItemsIndex: Types.setSelectedItemsIndexSetState setSelectedItemsIndex: Types.setSelectedItemsIndexSetState
): void { ): void {
////////// If an item is selected and then clicked outside other than the selected object, this runs and removes the color of the selected object and sets setSelectedWallItem and setSelectedItemsIndex as null ////////// ////////// If an item is selected and then clicked outside other than the selected object, this runs and removes the color of the selected object and sets setSelectedWallItem and setSelectedItemsIndex as null //////////
if (currentWallItem.current) { if (currentWallItem.current) {
currentWallItem.current.children.forEach((child) => { currentWallItem.current.children.forEach((child) => {
if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") { if ((child as THREE.Mesh).isMesh && child.name !== "CSG_REF") {
const material = (child as THREE.Mesh).material; const material = (child as THREE.Mesh).material;
if (Array.isArray(material)) { if (Array.isArray(material)) {
material.forEach(mat => { material.forEach(mat => {
if (mat instanceof THREE.MeshStandardMaterial) { if (mat instanceof THREE.MeshStandardMaterial) {
mat.emissive = new THREE.Color("black"); mat.emissive = new THREE.Color("black");
} }
}); });
} else if (material instanceof THREE.MeshStandardMaterial) { } else if (material instanceof THREE.MeshStandardMaterial) {
material.emissive = new THREE.Color("black"); material.emissive = new THREE.Color("black");
} }
} }
}); });
currentWallItem.current = null; currentWallItem.current = null;
setSelectedWallItem(null); setSelectedWallItem(null);
setSelectedItemsIndex(null); setSelectedItemsIndex(null);
} }
} }
export default handleMeshMissed; export default handleMeshMissed;

View File

@@ -1,87 +1,87 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as CONSTANTS from '../../../types/world/worldConstants'; import * as CONSTANTS from '../../../types/world/worldConstants';
import * as Types from "../../../types/world/worldTypes"; import * as Types from "../../../types/world/worldTypes";
function DeletableLineorPoint( function DeletableLineorPoint(
state: Types.ThreeState, state: Types.ThreeState,
plane: Types.RefMesh, plane: Types.RefMesh,
floorPlanGroupLine: Types.RefGroup, floorPlanGroupLine: Types.RefGroup,
floorPlanGroupPoint: Types.RefGroup, floorPlanGroupPoint: Types.RefGroup,
hoveredDeletableLine: Types.RefMesh, hoveredDeletableLine: Types.RefMesh,
hoveredDeletablePoint: Types.RefMesh hoveredDeletablePoint: Types.RefMesh
): void { ): void {
////////// Altering the color of the hovered line or point during the deletion time ////////// ////////// Altering the color of the hovered line or point during the deletion time //////////
if (!plane.current) return; if (!plane.current) return;
let intersects = state.raycaster.intersectObject(plane.current, true); let intersects = state.raycaster.intersectObject(plane.current, true);
let visibleIntersectLines; let visibleIntersectLines;
if (floorPlanGroupLine.current) { visibleIntersectLines = state.raycaster?.intersectObjects(floorPlanGroupLine.current.children, true); } if (floorPlanGroupLine.current) { visibleIntersectLines = state.raycaster?.intersectObjects(floorPlanGroupLine.current.children, true); }
const visibleIntersectLine = visibleIntersectLines?.find(intersect => intersect.object.visible) as THREE.Line | undefined || null; const visibleIntersectLine = visibleIntersectLines?.find(intersect => intersect.object.visible) as THREE.Line | undefined || null;
let visibleIntersectPoints; let visibleIntersectPoints;
if (floorPlanGroupPoint.current) { if (floorPlanGroupPoint.current) {
visibleIntersectPoints = state.raycaster?.intersectObjects(floorPlanGroupPoint.current.children, true); visibleIntersectPoints = state.raycaster?.intersectObjects(floorPlanGroupPoint.current.children, true);
} }
const visibleIntersectPoint = visibleIntersectPoints?.find(intersect => intersect.object.visible) as THREE.Mesh | undefined; const visibleIntersectPoint = visibleIntersectPoints?.find(intersect => intersect.object.visible) as THREE.Mesh | undefined;
function getLineColor(lineType: string | undefined): string { function getLineColor(lineType: string | undefined): string {
switch (lineType) { switch (lineType) {
case CONSTANTS.lineConfig.wallName: return CONSTANTS.lineConfig.wallColor; case CONSTANTS.lineConfig.wallName: return CONSTANTS.lineConfig.wallColor;
case CONSTANTS.lineConfig.floorName: return CONSTANTS.lineConfig.floorColor; case CONSTANTS.lineConfig.floorName: return CONSTANTS.lineConfig.floorColor;
case CONSTANTS.lineConfig.aisleName: return CONSTANTS.lineConfig.aisleColor; case CONSTANTS.lineConfig.aisleName: return CONSTANTS.lineConfig.aisleColor;
default: return CONSTANTS.lineConfig.defaultColor; default: return CONSTANTS.lineConfig.defaultColor;
} }
} }
if (intersects.length > 0) { if (intersects.length > 0) {
if (visibleIntersectPoint) { if (visibleIntersectPoint) {
if (hoveredDeletableLine.current) { if (hoveredDeletableLine.current) {
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3]; const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
const color = getLineColor(lineType); const color = getLineColor(lineType);
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color); (hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
hoveredDeletableLine.current = null; hoveredDeletableLine.current = null;
} }
hoveredDeletablePoint.current = (visibleIntersectPoint as any).object; hoveredDeletablePoint.current = (visibleIntersectPoint as any).object;
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(new THREE.Color("red")); (hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(new THREE.Color("red"));
(hoveredDeletablePoint.current as any).material.uniforms.uColor.value.set(new THREE.Color("red")); (hoveredDeletablePoint.current as any).material.uniforms.uColor.value.set(new THREE.Color("red"));
// (hoveredDeletablePoint.current as THREE.Mesh).scale.set(1.5, 1.5, 1.5); // (hoveredDeletablePoint.current as THREE.Mesh).scale.set(1.5, 1.5, 1.5);
} else if (hoveredDeletablePoint.current) { } else if (hoveredDeletablePoint.current) {
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(CONSTANTS.pointConfig.defaultInnerColor); (hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(CONSTANTS.pointConfig.defaultInnerColor);
(hoveredDeletablePoint.current as any).material.uniforms.uColor.value.set((hoveredDeletablePoint.current as any).userData.color); (hoveredDeletablePoint.current as any).material.uniforms.uColor.value.set((hoveredDeletablePoint.current as any).userData.color);
// hoveredDeletablePoint.current.scale.set(1, 1, 1); // hoveredDeletablePoint.current.scale.set(1, 1, 1);
hoveredDeletablePoint.current = null; hoveredDeletablePoint.current = null;
} }
if (visibleIntersectLine && !visibleIntersectPoint) { if (visibleIntersectLine && !visibleIntersectPoint) {
if (hoveredDeletableLine.current) { if (hoveredDeletableLine.current) {
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3]; const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
const color = getLineColor(lineType); const color = getLineColor(lineType);
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color); (hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
hoveredDeletableLine.current = null; hoveredDeletableLine.current = null;
} }
if (hoveredDeletablePoint.current) { if (hoveredDeletablePoint.current) {
(hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(CONSTANTS.pointConfig.defaultInnerColor); (hoveredDeletablePoint.current as any).material.uniforms.uInnerColor.value.set(CONSTANTS.pointConfig.defaultInnerColor);
(hoveredDeletablePoint.current as any).material.uniforms.uColor.value.set((hoveredDeletablePoint.current as any).userData.color); (hoveredDeletablePoint.current as any).material.uniforms.uColor.value.set((hoveredDeletablePoint.current as any).userData.color);
// hoveredDeletablePoint.current.scale.set(1, 1, 1); // hoveredDeletablePoint.current.scale.set(1, 1, 1);
hoveredDeletablePoint.current = null; hoveredDeletablePoint.current = null;
} }
hoveredDeletableLine.current = (visibleIntersectLine as any).object; hoveredDeletableLine.current = (visibleIntersectLine as any).object;
if (hoveredDeletableLine.current) { if (hoveredDeletableLine.current) {
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color("red"); (hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color("red");
} }
} else if (hoveredDeletableLine.current) { } else if (hoveredDeletableLine.current) {
const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3]; const lineType = hoveredDeletableLine.current.userData.linePoints[1]?.[3];
const color = getLineColor(lineType); const color = getLineColor(lineType);
(hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color); (hoveredDeletableLine.current.material as THREE.MeshBasicMaterial).color = new THREE.Color(color);
hoveredDeletableLine.current = null; hoveredDeletableLine.current = null;
} }
} }
} }
export default DeletableLineorPoint; export default DeletableLineorPoint;

View File

@@ -1,97 +1,97 @@
import * as Types from "../../../types/world/worldTypes"; import * as Types from "../../../types/world/worldTypes";
import * as CONSTANTS from '../../../types/world/worldConstants'; import * as CONSTANTS from '../../../types/world/worldConstants';
import createAndMoveReferenceLine from "../geomentries/lines/createAndMoveReferenceLine"; import createAndMoveReferenceLine from "../geomentries/lines/createAndMoveReferenceLine";
async function Draw( async function Draw(
state: Types.ThreeState, state: Types.ThreeState,
plane: Types.RefMesh, plane: Types.RefMesh,
cursorPosition: Types.Vector3, cursorPosition: Types.Vector3,
floorPlanGroupPoint: Types.RefGroup, floorPlanGroupPoint: Types.RefGroup,
floorPlanGroupLine: Types.RefGroup, floorPlanGroupLine: Types.RefGroup,
snappedPoint: Types.RefVector3, snappedPoint: Types.RefVector3,
isSnapped: Types.RefBoolean, isSnapped: Types.RefBoolean,
isSnappedUUID: Types.RefString, isSnappedUUID: Types.RefString,
line: Types.RefLine, line: Types.RefLine,
lines: Types.RefLines, lines: Types.RefLines,
ispreSnapped: Types.RefBoolean, ispreSnapped: Types.RefBoolean,
floorPlanGroup: Types.RefGroup, floorPlanGroup: Types.RefGroup,
ReferenceLineMesh: Types.RefMesh, ReferenceLineMesh: Types.RefMesh,
LineCreated: Types.RefBoolean, LineCreated: Types.RefBoolean,
setRefTextUpdate: Types.NumberIncrementState, setRefTextUpdate: Types.NumberIncrementState,
Tube: Types.RefTubeGeometry, Tube: Types.RefTubeGeometry,
anglesnappedPoint: Types.RefVector3, anglesnappedPoint: Types.RefVector3,
isAngleSnapped: Types.RefBoolean, isAngleSnapped: Types.RefBoolean,
toolMode: Types.String, toolMode: Types.String,
): Promise<void> { ): Promise<void> {
////////// Snapping the cursor during the drawing time and also changing the color of the intersected lines ////////// ////////// Snapping the cursor during the drawing time and also changing the color of the intersected lines //////////
if (!plane.current) return; if (!plane.current) return;
const intersects = state.raycaster.intersectObject(plane.current, true); const intersects = state.raycaster.intersectObject(plane.current, true);
if (intersects.length > 0 && (toolMode === "Wall" || toolMode === "Aisle" || toolMode === "Floor")) { if (intersects.length > 0 && (toolMode === "Wall" || toolMode === "Aisle" || toolMode === "Floor")) {
const intersectionPoint = intersects[0].point; const intersectionPoint = intersects[0].point;
cursorPosition.copy(intersectionPoint); cursorPosition.copy(intersectionPoint);
const snapThreshold = 1; const snapThreshold = 1;
if (line.current.length === 0) { if (line.current.length === 0) {
for (const point of floorPlanGroupPoint.current.children) { for (const point of floorPlanGroupPoint.current.children) {
const pointType = point.userData.type; const pointType = point.userData.type;
const canSnap = const canSnap =
((toolMode === "Wall") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) || ((toolMode === "Wall") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
((toolMode === "Floor") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) || ((toolMode === "Floor") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
((toolMode === "Aisle") && pointType === CONSTANTS.lineConfig.aisleName);; ((toolMode === "Aisle") && pointType === CONSTANTS.lineConfig.aisleName);;
if (canSnap && cursorPosition.distanceTo(point.position) < snapThreshold + 0.5 && point.visible) { if (canSnap && cursorPosition.distanceTo(point.position) < snapThreshold + 0.5 && point.visible) {
cursorPosition.copy(point.position); cursorPosition.copy(point.position);
snappedPoint.current = point.position; snappedPoint.current = point.position;
ispreSnapped.current = true; ispreSnapped.current = true;
isSnapped.current = false; isSnapped.current = false;
isSnappedUUID.current = point.uuid; isSnappedUUID.current = point.uuid;
break; break;
} else { } else {
ispreSnapped.current = false; ispreSnapped.current = false;
} }
} }
} else if (line.current.length > 0 && line.current[0]) { } else if (line.current.length > 0 && line.current[0]) {
for (const point of floorPlanGroupPoint.current.children) { for (const point of floorPlanGroupPoint.current.children) {
const pointType = point.userData.type; const pointType = point.userData.type;
let canSnap = let canSnap =
((toolMode === "Wall") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) || ((toolMode === "Wall") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
((toolMode === "Floor") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) || ((toolMode === "Floor") && (pointType === CONSTANTS.lineConfig.wallName || pointType === CONSTANTS.lineConfig.floorName)) ||
((toolMode === "Aisle") && pointType === CONSTANTS.lineConfig.aisleName); ((toolMode === "Aisle") && pointType === CONSTANTS.lineConfig.aisleName);
if (canSnap && cursorPosition.distanceTo(point.position) < snapThreshold && point.visible) { if (canSnap && cursorPosition.distanceTo(point.position) < snapThreshold && point.visible) {
cursorPosition.copy(point.position); cursorPosition.copy(point.position);
snappedPoint.current = point.position; snappedPoint.current = point.position;
isSnapped.current = true; isSnapped.current = true;
ispreSnapped.current = false; ispreSnapped.current = false;
isSnappedUUID.current = point.uuid; isSnappedUUID.current = point.uuid;
break; break;
} else { } else {
isSnapped.current = false; isSnapped.current = false;
} }
} }
createAndMoveReferenceLine( createAndMoveReferenceLine(
line.current[0][0], line.current[0][0],
cursorPosition, cursorPosition,
isSnapped, isSnapped,
ispreSnapped, ispreSnapped,
line, line,
setRefTextUpdate, setRefTextUpdate,
floorPlanGroup, floorPlanGroup,
ReferenceLineMesh, ReferenceLineMesh,
LineCreated, LineCreated,
Tube, Tube,
anglesnappedPoint, anglesnappedPoint,
isAngleSnapped isAngleSnapped
); );
} }
} }
} }
export default Draw; export default Draw;

View File

@@ -1,56 +1,56 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from '../../../../types/world/worldTypes'; import * as Types from '../../../../types/world/worldTypes';
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
export default async function addAisleToScene( export default async function addAisleToScene(
aisle: Types.Line, aisle: Types.Line,
floorGroupAisle: Types.RefGroup, floorGroupAisle: Types.RefGroup,
): Promise<void> { ): Promise<void> {
if (aisle.length >= 2 && aisle[0] && aisle[1]) { if (aisle.length >= 2 && aisle[0] && aisle[1]) {
const start: Types.Vector3 = aisle[0][0]; const start: Types.Vector3 = aisle[0][0];
const end: Types.Vector3 = aisle[1][0]; const end: Types.Vector3 = aisle[1][0];
const direction = new THREE.Vector3( const direction = new THREE.Vector3(
end.x - start.x, end.x - start.x,
end.y - start.y, end.y - start.y,
end.z - start.z end.z - start.z
).normalize(); ).normalize();
const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize(); const perp = new THREE.Vector3(-direction.z, 0, direction.x).normalize();
const offsetDistance = CONSTANTS.aisleConfig.width; const offsetDistance = CONSTANTS.aisleConfig.width;
const leftStart = new THREE.Vector3().copy(start).addScaledVector(perp, offsetDistance); const leftStart = new THREE.Vector3().copy(start).addScaledVector(perp, offsetDistance);
const rightStart = new THREE.Vector3().copy(start).addScaledVector(perp, -offsetDistance); const rightStart = new THREE.Vector3().copy(start).addScaledVector(perp, -offsetDistance);
const leftEnd = new THREE.Vector3().copy(end).addScaledVector(perp, offsetDistance); const leftEnd = new THREE.Vector3().copy(end).addScaledVector(perp, offsetDistance);
const rightEnd = new THREE.Vector3().copy(end).addScaledVector(perp, -offsetDistance); const rightEnd = new THREE.Vector3().copy(end).addScaledVector(perp, -offsetDistance);
const stripShape = new THREE.Shape(); const stripShape = new THREE.Shape();
stripShape.moveTo(leftStart.x, leftStart.z); stripShape.moveTo(leftStart.x, leftStart.z);
stripShape.lineTo(leftEnd.x, leftEnd.z); stripShape.lineTo(leftEnd.x, leftEnd.z);
stripShape.lineTo(rightEnd.x, rightEnd.z); stripShape.lineTo(rightEnd.x, rightEnd.z);
stripShape.lineTo(rightStart.x, rightStart.z); stripShape.lineTo(rightStart.x, rightStart.z);
stripShape.lineTo(leftStart.x, leftStart.z); stripShape.lineTo(leftStart.x, leftStart.z);
const extrudeSettings = { const extrudeSettings = {
depth: CONSTANTS.aisleConfig.height, depth: CONSTANTS.aisleConfig.height,
bevelEnabled: false, bevelEnabled: false,
}; };
const stripGeometry = new THREE.ExtrudeGeometry(stripShape, extrudeSettings); const stripGeometry = new THREE.ExtrudeGeometry(stripShape, extrudeSettings);
const stripMaterial = new THREE.MeshStandardMaterial({ const stripMaterial = new THREE.MeshStandardMaterial({
color: CONSTANTS.aisleConfig.defaultColor, color: CONSTANTS.aisleConfig.defaultColor,
polygonOffset: true, polygonOffset: true,
polygonOffsetFactor: -1, polygonOffsetFactor: -1,
polygonOffsetUnits: -1, polygonOffsetUnits: -1,
}); });
const stripMesh = new THREE.Mesh(stripGeometry, stripMaterial); const stripMesh = new THREE.Mesh(stripGeometry, stripMaterial);
stripMesh.receiveShadow = true; stripMesh.receiveShadow = true;
stripMesh.castShadow = true; stripMesh.castShadow = true;
stripMesh.position.y = (aisle[0][2] - 1) * CONSTANTS.wallConfig.height + 0.01; stripMesh.position.y = (aisle[0][2] - 1) * CONSTANTS.wallConfig.height + 0.01;
stripMesh.rotateX(Math.PI / 2); stripMesh.rotateX(Math.PI / 2);
floorGroupAisle.current.add(stripMesh); floorGroupAisle.current.add(stripMesh);
} }
} }

View File

@@ -1,19 +1,19 @@
import * as Types from '../../../../types/world/worldTypes'; import * as Types from '../../../../types/world/worldTypes';
import addAisleToScene from './addAilseToScene'; import addAisleToScene from './addAilseToScene';
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
export default async function loadAisles( export default async function loadAisles(
lines: Types.RefLines, lines: Types.RefLines,
floorGroupAisle: Types.RefGroup floorGroupAisle: Types.RefGroup
) { ) {
// console.log('lines: ', lines.current[0][0][0]); // console.log('lines: ', lines.current[0][0][0]);
if (!floorGroupAisle.current) return if (!floorGroupAisle.current) return
floorGroupAisle.current.children = []; floorGroupAisle.current.children = [];
const aisles = lines.current.filter((line) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName); const aisles = lines.current.filter((line) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.aisleName);
if (aisles.length > 0) { if (aisles.length > 0) {
aisles.forEach((aisle: Types.Line) => { aisles.forEach((aisle: Types.Line) => {
addAisleToScene(aisle, floorGroupAisle) addAisleToScene(aisle, floorGroupAisle)
}) })
} }
} }

View File

@@ -1,186 +1,186 @@
import * as THREE from 'three'; import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import gsap from 'gsap'; import gsap from 'gsap';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import TempLoader from './tempLoader'; import TempLoader from './tempLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils'; import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils';
// import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
import { Socket } from 'socket.io-client'; import { Socket } from 'socket.io-client';
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
async function addAssetModel( async function addAssetModel(
raycaster: THREE.Raycaster, raycaster: THREE.Raycaster,
camera: THREE.Camera, camera: THREE.Camera,
pointer: THREE.Vector2, pointer: THREE.Vector2,
floorGroup: Types.RefGroup, floorGroup: Types.RefGroup,
setFloorItems: Types.setFloorItemSetState, setFloorItems: Types.setFloorItemSetState,
itemsGroup: Types.RefGroup, itemsGroup: Types.RefGroup,
isTempLoader: Types.RefBoolean, isTempLoader: Types.RefBoolean,
tempLoader: Types.RefMesh, tempLoader: Types.RefMesh,
socket: Socket<any>, socket: Socket<any>,
selectedItem: any, selectedItem: any,
setSelectedItem: any, setSelectedItem: any,
plane: Types.RefMesh, plane: Types.RefMesh,
): Promise<void> { ): Promise<void> {
////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage ////////// ////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
try { try {
isTempLoader.current = true; isTempLoader.current = true;
const loader = new GLTFLoader(); const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader(); const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/'); dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
loader.setDRACOLoader(dracoLoader); loader.setDRACOLoader(dracoLoader);
raycaster.setFromCamera(pointer, camera); raycaster.setFromCamera(pointer, camera);
const floorIntersections = raycaster.intersectObjects(floorGroup.current.children, true); const floorIntersections = raycaster.intersectObjects(floorGroup.current.children, true);
const intersectedFloor = floorIntersections.find(intersect => intersect.object.name.includes("Floor")); const intersectedFloor = floorIntersections.find(intersect => intersect.object.name.includes("Floor"));
const planeIntersections = raycaster.intersectObject(plane.current!, true); const planeIntersections = raycaster.intersectObject(plane.current!, true);
const intersectedPlane = planeIntersections[0]; const intersectedPlane = planeIntersections[0];
let intersectPoint: THREE.Vector3 | null = null; let intersectPoint: THREE.Vector3 | null = null;
if (intersectedFloor && intersectedPlane) { if (intersectedFloor && intersectedPlane) {
intersectPoint = intersectedFloor.distance < intersectedPlane.distance ? (new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z)) : (new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z)); intersectPoint = intersectedFloor.distance < intersectedPlane.distance ? (new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z)) : (new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z));
} else if (intersectedFloor) { } else if (intersectedFloor) {
intersectPoint = new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z); intersectPoint = new THREE.Vector3(intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z);
} else if (intersectedPlane) { } else if (intersectedPlane) {
intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z); intersectPoint = new THREE.Vector3(intersectedPlane.point.x, 0, intersectedPlane.point.z);
} }
if (intersectPoint) { if (intersectPoint) {
if (intersectPoint.y < 0) { if (intersectPoint.y < 0) {
intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z); intersectPoint = new THREE.Vector3(intersectPoint.x, 0, intersectPoint.z);
} }
const cachedModel = THREE.Cache.get(selectedItem.id); const cachedModel = THREE.Cache.get(selectedItem.id);
if (cachedModel) { if (cachedModel) {
// console.log(`[Cache] Fetching ${selectedItem.name}`); // console.log(`[Cache] Fetching ${selectedItem.name}`);
handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket); handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
return; return;
} else { } else {
const cachedModelBlob = await retrieveGLTF(selectedItem.id); const cachedModelBlob = await retrieveGLTF(selectedItem.id);
if (cachedModelBlob) { if (cachedModelBlob) {
// console.log(`Added ${selectedItem.name} from indexDB`); // console.log(`Added ${selectedItem.name} from indexDB`);
const blobUrl = URL.createObjectURL(cachedModelBlob); const blobUrl = URL.createObjectURL(cachedModelBlob);
loader.load(blobUrl, (gltf) => { loader.load(blobUrl, (gltf) => {
URL.revokeObjectURL(blobUrl); URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl); THREE.Cache.remove(blobUrl);
THREE.Cache.add(selectedItem.id, gltf); THREE.Cache.add(selectedItem.id, gltf);
handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket); handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
}, },
() => { () => {
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup); TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
}); });
} else { } else {
// console.log(`Added ${selectedItem.name} from Backend`); // console.log(`Added ${selectedItem.name} from Backend`);
loader.load(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`, async (gltf) => { loader.load(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`, async (gltf) => {
const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob()); const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob());
await storeGLTF(selectedItem.id, modelBlob); await storeGLTF(selectedItem.id, modelBlob);
THREE.Cache.add(selectedItem.id, gltf); THREE.Cache.add(selectedItem.id, gltf);
await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket); await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket);
}, },
() => { () => {
TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup); TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup);
}); });
} }
} }
} }
} catch (error) { } catch (error) {
console.error('Error fetching asset model:', error); console.error('Error fetching asset model:', error);
} finally { } finally {
setSelectedItem({}); setSelectedItem({});
} }
} }
async function handleModelLoad( async function handleModelLoad(
gltf: any, gltf: any,
intersectPoint: THREE.Vector3, intersectPoint: THREE.Vector3,
selectedItem: any, selectedItem: any,
itemsGroup: Types.RefGroup, itemsGroup: Types.RefGroup,
tempLoader: Types.RefMesh, tempLoader: Types.RefMesh,
isTempLoader: Types.RefBoolean, isTempLoader: Types.RefBoolean,
setFloorItems: Types.setFloorItemSetState, setFloorItems: Types.setFloorItemSetState,
socket: Socket<any> socket: Socket<any>
) { ) {
const model = gltf.scene.clone(); const model = gltf.scene.clone();
model.userData = { name: selectedItem.name, modelId: selectedItem.id }; model.userData = { name: selectedItem.name, modelId: selectedItem.id };
model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z); model.position.set(intersectPoint!.x, 3 + intersectPoint!.y, intersectPoint!.z);
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
model.traverse((child: any) => { model.traverse((child: any) => {
if (child) { if (child) {
child.castShadow = true; child.castShadow = true;
child.receiveShadow = true; child.receiveShadow = true;
} }
}); });
itemsGroup.current.add(model); itemsGroup.current.add(model);
if (tempLoader.current) { if (tempLoader.current) {
(<any>tempLoader.current.material).dispose(); (<any>tempLoader.current.material).dispose();
(<any>tempLoader.current.geometry).dispose(); (<any>tempLoader.current.geometry).dispose();
itemsGroup.current.remove(tempLoader.current); itemsGroup.current.remove(tempLoader.current);
tempLoader.current = undefined; tempLoader.current = undefined;
} }
const newFloorItem: Types.FloorItemType = { const newFloorItem: Types.FloorItemType = {
modeluuid: model.uuid, modeluuid: model.uuid,
modelname: selectedItem.name, modelname: selectedItem.name,
modelfileID: selectedItem.id, modelfileID: selectedItem.id,
position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z], position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z],
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, }, rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, },
isLocked: false, isLocked: false,
isVisible: true isVisible: true
}; };
setFloorItems((prevItems) => { setFloorItems((prevItems) => {
const updatedItems = [...(prevItems || []), newFloorItem]; const updatedItems = [...(prevItems || []), newFloorItem];
localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
return updatedItems; return updatedItems;
}); });
const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
const organization = email ? email.split("@")[1].split(".")[0] : "default"; const organization = email ? email.split("@")[1].split(".")[0] : "default";
//REST //REST
// await setFloorItemApi( // await setFloorItemApi(
// organization, // organization,
// newFloorItem.modeluuid, // newFloorItem.modeluuid,
// newFloorItem.modelname, // newFloorItem.modelname,
// newFloorItem.position, // newFloorItem.position,
// { "x": model.rotation.x, "y": model.rotation.y, "z": model.rotation.z }, // { "x": model.rotation.x, "y": model.rotation.y, "z": model.rotation.z },
// newFloorItem.modelfileID!, // newFloorItem.modelfileID!,
// false, // false,
// true, // true,
// ); // );
//SOCKET //SOCKET
const data = { const data = {
organization, organization,
modeluuid: newFloorItem.modeluuid, modeluuid: newFloorItem.modeluuid,
modelname: newFloorItem.modelname, modelname: newFloorItem.modelname,
modelfileID: newFloorItem.modelfileID, modelfileID: newFloorItem.modelfileID,
position: newFloorItem.position, position: newFloorItem.position,
rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z }, rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z },
isLocked: false, isLocked: false,
isVisible: true, isVisible: true,
socketId: socket.id, socketId: socket.id,
}; };
socket.emit("v1:FloorItems:set", data); socket.emit("v1:FloorItems:set", data);
gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" }); gsap.to(model.position, { y: newFloorItem.position[1], duration: 1.5, ease: "power2.out" });
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } }); gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: "power2.out", onComplete: () => { toast.success("Model Added!"); } });
} }
export default addAssetModel; export default addAssetModel;

View File

@@ -1,153 +1,153 @@
import * as THREE from "three"; import * as THREE from "three";
import gsap from "gsap"; import gsap from "gsap";
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { initializeDB, retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils"; import { initializeDB, retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils";
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
let currentTaskId = 0; // Track the active task let currentTaskId = 0; // Track the active task
let activePromises = new Map<number, boolean>(); // Map to track task progress let activePromises = new Map<number, boolean>(); // Map to track task progress
export default async function assetManager( export default async function assetManager(
data: any, data: any,
itemsGroup: Types.RefGroup, itemsGroup: Types.RefGroup,
loader: GLTFLoader, loader: GLTFLoader,
) { ) {
const taskId = ++currentTaskId; // Increment taskId for each call const taskId = ++currentTaskId; // Increment taskId for each call
activePromises.set(taskId, true); // Mark task as active activePromises.set(taskId, true); // Mark task as active
// console.log("Received message from worker:", data); // console.log("Received message from worker:", data);
if (data.toRemove.length > 0) { if (data.toRemove.length > 0) {
data.toRemove.forEach((uuid: string) => { data.toRemove.forEach((uuid: string) => {
const item = itemsGroup.current.getObjectByProperty("uuid", uuid); const item = itemsGroup.current.getObjectByProperty("uuid", uuid);
if (item) { if (item) {
// Traverse and dispose of resources // Traverse and dispose of resources
// item.traverse((child: THREE.Object3D) => { // item.traverse((child: THREE.Object3D) => {
// if (child instanceof THREE.Mesh) { // if (child instanceof THREE.Mesh) {
// if (child.geometry) child.geometry.dispose(); // if (child.geometry) child.geometry.dispose();
// if (Array.isArray(child.material)) { // if (Array.isArray(child.material)) {
// child.material.forEach((material) => { // child.material.forEach((material) => {
// if (material.map) material.map.dispose(); // if (material.map) material.map.dispose();
// material.dispose(); // material.dispose();
// }); // });
// } else if (child.material) { // } else if (child.material) {
// if (child.material.map) child.material.map.dispose(); // if (child.material.map) child.material.map.dispose();
// child.material.dispose(); // child.material.dispose();
// } // }
// } // }
// }); // });
// Remove the object from the scene // Remove the object from the scene
itemsGroup.current.remove(item); itemsGroup.current.remove(item);
} }
}); });
} }
if (data.toAdd.length > 0) { if (data.toAdd.length > 0) {
await initializeDB(); await initializeDB();
for (const item of data.toAdd) { for (const item of data.toAdd) {
if (!activePromises.get(taskId)) return; // Stop processing if task is canceled if (!activePromises.get(taskId)) return; // Stop processing if task is canceled
await new Promise<void>(async (resolve) => { await new Promise<void>(async (resolve) => {
const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${item.modelfileID!}`; const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${item.modelfileID!}`;
// Check Three.js Cache // Check Three.js Cache
const cachedModel = THREE.Cache.get(item.modelfileID!); const cachedModel = THREE.Cache.get(item.modelfileID!);
if (cachedModel) { if (cachedModel) {
// console.log(`[Cache] Fetching ${item.modelname}`); // console.log(`[Cache] Fetching ${item.modelname}`);
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, resolve); processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, resolve);
return; return;
} }
// Check IndexedDB // Check IndexedDB
const indexedDBModel = await retrieveGLTF(item.modelfileID!); const indexedDBModel = await retrieveGLTF(item.modelfileID!);
if (indexedDBModel) { if (indexedDBModel) {
// console.log(`[IndexedDB] Fetching ${item.modelname}`); // console.log(`[IndexedDB] Fetching ${item.modelname}`);
const blobUrl = URL.createObjectURL(indexedDBModel); const blobUrl = URL.createObjectURL(indexedDBModel);
loader.load( loader.load(
blobUrl, blobUrl,
(gltf) => { (gltf) => {
URL.revokeObjectURL(blobUrl); URL.revokeObjectURL(blobUrl);
THREE.Cache.remove(blobUrl); THREE.Cache.remove(blobUrl);
THREE.Cache.add(item.modelfileID!, gltf); // Add to cache THREE.Cache.add(item.modelfileID!, gltf); // Add to cache
processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve); processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve);
}, },
undefined, undefined,
(error) => { (error) => {
toast.error(`[IndexedDB] Error loading ${item.modelname}:`); toast.error(`[IndexedDB] Error loading ${item.modelname}:`);
resolve(); resolve();
} }
); );
return; return;
} }
// Fetch from Backend // Fetch from Backend
// console.log(`[Backend] Fetching ${item.modelname}`); // console.log(`[Backend] Fetching ${item.modelname}`);
loader.load( loader.load(
modelUrl, modelUrl,
async (gltf) => { async (gltf) => {
const modelBlob = await fetch(modelUrl).then((res) => res.blob()); const modelBlob = await fetch(modelUrl).then((res) => res.blob());
await storeGLTF(item.modelfileID!, modelBlob); // Store in IndexedDB await storeGLTF(item.modelfileID!, modelBlob); // Store in IndexedDB
THREE.Cache.add(item.modelfileID!, gltf); // Add to cache THREE.Cache.add(item.modelfileID!, gltf); // Add to cache
processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve); processLoadedModel(gltf.scene.clone(), item, itemsGroup, resolve);
}, },
undefined, undefined,
(error) => { (error) => {
toast.error(`[Backend] Error loading ${item.modelname}:`); toast.error(`[Backend] Error loading ${item.modelname}:`);
resolve(); resolve();
} }
); );
}); });
} }
function processLoadedModel( function processLoadedModel(
gltf: any, gltf: any,
item: Types.FloorItemType, item: Types.FloorItemType,
itemsGroup: Types.RefGroup, itemsGroup: Types.RefGroup,
resolve: () => void resolve: () => void
) { ) {
if (!activePromises.get(taskId)) return; // Stop processing if task is canceled if (!activePromises.get(taskId)) return; // Stop processing if task is canceled
const existingModel = itemsGroup.current.getObjectByProperty("uuid", item.modeluuid); const existingModel = itemsGroup.current.getObjectByProperty("uuid", item.modeluuid);
if (existingModel) { if (existingModel) {
// console.log(`Model ${item.modelname} already exists in the scene.`); // console.log(`Model ${item.modelname} already exists in the scene.`);
resolve(); resolve();
return; return;
} }
const model = gltf; const model = gltf;
model.uuid = item.modeluuid; model.uuid = item.modeluuid;
model.userData = { name: item.modelname, modelId: item.modelfileID }; model.userData = { name: item.modelname, modelId: item.modelfileID };
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
model.position.set(...item.position); model.position.set(...item.position);
model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z); model.rotation.set(item.rotation.x, item.rotation.y, item.rotation.z);
model.traverse((child: any) => { model.traverse((child: any) => {
if (child.isMesh) { if (child.isMesh) {
// Clone the material to ensure changes are independent // Clone the material to ensure changes are independent
// child.material = child.material.clone(); // child.material = child.material.clone();
child.castShadow = true; child.castShadow = true;
child.receiveShadow = true; child.receiveShadow = true;
} }
}); });
itemsGroup?.current?.add(model); itemsGroup?.current?.add(model);
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: "power2.out" }); gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: "power2.out" });
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 0.5, ease: "power2.out", onStart: resolve, }); gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 0.5, ease: "power2.out", onStart: resolve, });
} }
} }
activePromises.delete(taskId); // Mark task as complete activePromises.delete(taskId); // Mark task as complete
} }
// Cancel ongoing task when new call arrives // Cancel ongoing task when new call arrives
export function cancelOngoingTasks() { export function cancelOngoingTasks() {
activePromises.clear(); // Clear all ongoing tasks activePromises.clear(); // Clear all ongoing tasks
} }

View File

@@ -1,25 +1,25 @@
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
let lastUpdateTime = 0; let lastUpdateTime = 0;
export default function assetVisibility( export default function assetVisibility(
itemsGroup: Types.RefGroup, itemsGroup: Types.RefGroup,
cameraPosition: Types.Vector3, cameraPosition: Types.Vector3,
renderDistance: Types.Number, renderDistance: Types.Number,
throttleTime = 100 throttleTime = 100
): void { ): void {
const now = performance.now(); const now = performance.now();
if (now - lastUpdateTime < throttleTime) return; if (now - lastUpdateTime < throttleTime) return;
lastUpdateTime = now; lastUpdateTime = now;
if (!itemsGroup?.current || !cameraPosition) return; if (!itemsGroup?.current || !cameraPosition) return;
itemsGroup.current.children.forEach((child) => { itemsGroup.current.children.forEach((child) => {
const Distance = cameraPosition.distanceTo(child.position); const Distance = cameraPosition.distanceTo(child.position);
if (Distance <= renderDistance) { if (Distance <= renderDistance) {
child.visible = true; child.visible = true;
} else { } else {
child.visible = false; child.visible = false;
} }
}); });
} }

View File

@@ -1,43 +1,43 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function DeletableHoveredFloorItems( function DeletableHoveredFloorItems(
state: Types.ThreeState, state: Types.ThreeState,
itemsGroup: Types.RefGroup, itemsGroup: Types.RefGroup,
hoveredDeletableFloorItem: Types.RefMesh, hoveredDeletableFloorItem: Types.RefMesh,
setDeletableFloorItem: any setDeletableFloorItem: any
): void { ): void {
////////// Altering the color of the hovered GLTF item during the Deletion time ////////// ////////// Altering the color of the hovered GLTF item during the Deletion time //////////
state.raycaster.setFromCamera(state.pointer, state.camera); state.raycaster.setFromCamera(state.pointer, state.camera);
const intersects = state.raycaster.intersectObjects(itemsGroup.current.children, true); const intersects = state.raycaster.intersectObjects(itemsGroup.current.children, true);
if (intersects.length > 0) { if (intersects.length > 0) {
if (intersects[0].object.name === "Pole") { if (intersects[0].object.name === "Pole") {
return; return;
} }
if (hoveredDeletableFloorItem.current) { if (hoveredDeletableFloorItem.current) {
hoveredDeletableFloorItem.current = undefined; hoveredDeletableFloorItem.current = undefined;
setDeletableFloorItem(null); setDeletableFloorItem(null);
} }
let currentObject = intersects[0].object; let currentObject = intersects[0].object;
while (currentObject) { while (currentObject) {
if (currentObject.name === "Scene") { if (currentObject.name === "Scene") {
hoveredDeletableFloorItem.current = currentObject as THREE.Mesh; hoveredDeletableFloorItem.current = currentObject as THREE.Mesh;
setDeletableFloorItem(currentObject); setDeletableFloorItem(currentObject);
break; break;
} }
currentObject = currentObject.parent as THREE.Object3D; currentObject = currentObject.parent as THREE.Object3D;
} }
} else { } else {
if (hoveredDeletableFloorItem.current) { if (hoveredDeletableFloorItem.current) {
hoveredDeletableFloorItem.current = undefined; hoveredDeletableFloorItem.current = undefined;
setDeletableFloorItem(null); setDeletableFloorItem(null);
} }
} }
} }
export default DeletableHoveredFloorItems; export default DeletableHoveredFloorItems;

View File

@@ -1,82 +1,82 @@
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import { getFloorItems } from '../../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi'; import { getFloorItems } from '../../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
// import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi'; // import { deleteFloorItem } from '../../../../services/factoryBuilder/assest/floorAsset/deleteFloorItemApi';
import { Socket } from 'socket.io-client'; import { Socket } from 'socket.io-client';
async function DeleteFloorItems( async function DeleteFloorItems(
itemsGroup: Types.RefGroup, itemsGroup: Types.RefGroup,
hoveredDeletableFloorItem: Types.RefMesh, hoveredDeletableFloorItem: Types.RefMesh,
setFloorItems: Types.setFloorItemSetState, setFloorItems: Types.setFloorItemSetState,
socket: Socket<any> socket: Socket<any>
): Promise<void> { ): Promise<void> {
////////// Deleting the hovered Floor GLTF from the scene (itemsGroup.current) and from the floorItems and also update it in the localstorage ////////// ////////// Deleting the hovered Floor GLTF from the scene (itemsGroup.current) and from the floorItems and also update it in the localstorage //////////
if (hoveredDeletableFloorItem.current) { if (hoveredDeletableFloorItem.current) {
const email = localStorage.getItem('email') const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0]; const organization = (email!.split("@")[1]).split(".")[0];
const items = await getFloorItems(organization); const items = await getFloorItems(organization);
const removedItem = items.find( const removedItem = items.find(
(item: { modeluuid: string }) => item.modeluuid === hoveredDeletableFloorItem.current?.uuid (item: { modeluuid: string }) => item.modeluuid === hoveredDeletableFloorItem.current?.uuid
); );
if (!removedItem) { if (!removedItem) {
return return
} }
//REST //REST
// const response = await deleteFloorItem(organization, removedItem.modeluuid, removedItem.modelname); // const response = await deleteFloorItem(organization, removedItem.modeluuid, removedItem.modelname);
//SOCKET //SOCKET
const data = { const data = {
organization: organization, organization: organization,
modeluuid: removedItem.modeluuid, modeluuid: removedItem.modeluuid,
modelname: removedItem.modelname, modelname: removedItem.modelname,
socketId: socket.id socketId: socket.id
} }
const response = socket.emit('v1:FloorItems:delete', data) const response = socket.emit('v1:FloorItems:delete', data)
if (response) { if (response) {
const updatedItems = items.filter( const updatedItems = items.filter(
(item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid (item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid
); );
const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]'); const storedItems = JSON.parse(localStorage.getItem("FloorItems") || '[]');
const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid); const updatedStoredItems = storedItems.filter((item: { modeluuid: string }) => item.modeluuid !== hoveredDeletableFloorItem.current?.uuid);
localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems)); localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems));
if (hoveredDeletableFloorItem.current) { if (hoveredDeletableFloorItem.current) {
// Traverse and dispose of resources // Traverse and dispose of resources
hoveredDeletableFloorItem.current.traverse((child: THREE.Object3D) => { hoveredDeletableFloorItem.current.traverse((child: THREE.Object3D) => {
if (child instanceof THREE.Mesh) { if (child instanceof THREE.Mesh) {
if (child.geometry) child.geometry.dispose(); if (child.geometry) child.geometry.dispose();
if (Array.isArray(child.material)) { if (Array.isArray(child.material)) {
child.material.forEach((material) => { child.material.forEach((material) => {
if (material.map) material.map.dispose(); if (material.map) material.map.dispose();
material.dispose(); material.dispose();
}); });
} else if (child.material) { } else if (child.material) {
if (child.material.map) child.material.map.dispose(); if (child.material.map) child.material.map.dispose();
child.material.dispose(); child.material.dispose();
} }
} }
}); });
// Remove the object from the scene // Remove the object from the scene
itemsGroup.current.remove(hoveredDeletableFloorItem.current); itemsGroup.current.remove(hoveredDeletableFloorItem.current);
} }
setFloorItems(updatedItems); setFloorItems(updatedItems);
toast.success("Model Removed!"); toast.success("Model Removed!");
} }
} }
} }
export default DeleteFloorItems; export default DeleteFloorItems;

View File

@@ -1,29 +1,29 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function TempLoader( function TempLoader(
intersectPoint: Types.Vector3, intersectPoint: Types.Vector3,
isTempLoader: Types.RefBoolean, isTempLoader: Types.RefBoolean,
tempLoader: Types.RefMesh, tempLoader: Types.RefMesh,
itemsGroup: Types.RefGroup itemsGroup: Types.RefGroup
): void { ): void {
////////// Temporary Loader that indicates the gltf is being loaded ////////// ////////// Temporary Loader that indicates the gltf is being loaded //////////
////////// Bug: Can't Load More than one TempLoader if done, it won't leave the scene ////////// ////////// Bug: Can't Load More than one TempLoader if done, it won't leave the scene //////////
if (tempLoader.current) { if (tempLoader.current) {
itemsGroup.current.remove(tempLoader.current); itemsGroup.current.remove(tempLoader.current);
} }
if (isTempLoader.current) { if (isTempLoader.current) {
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1); const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
const cubeMaterial = new THREE.MeshBasicMaterial({ color: "white" }); const cubeMaterial = new THREE.MeshBasicMaterial({ color: "white" });
tempLoader.current = new THREE.Mesh(cubeGeometry, cubeMaterial); tempLoader.current = new THREE.Mesh(cubeGeometry, cubeMaterial);
tempLoader.current.position.set(intersectPoint.x, 0.5 + intersectPoint.y, intersectPoint.z); tempLoader.current.position.set(intersectPoint.x, 0.5 + intersectPoint.y, intersectPoint.z);
itemsGroup.current.add(tempLoader.current); itemsGroup.current.add(tempLoader.current);
isTempLoader.current = false; isTempLoader.current = false;
} }
} }
export default TempLoader; export default TempLoader;

View File

@@ -1,64 +1,64 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import * as CONSTANTS from "../../../../types/world/worldConstants"; import * as CONSTANTS from "../../../../types/world/worldConstants";
import texturePath from "../../../../assets/textures/floor/concreteFloorWorn001Diff2k.jpg"; import texturePath from "../../../../assets/textures/floor/concreteFloorWorn001Diff2k.jpg";
import normalPath from "../../../../assets/textures/floor/concreteFloorWorn001NorGl2k.jpg"; import normalPath from "../../../../assets/textures/floor/concreteFloorWorn001NorGl2k.jpg";
// Cache for materials // Cache for materials
const materialCache = new Map<string, THREE.Material>(); const materialCache = new Map<string, THREE.Material>();
export default function addFloorToScene( export default function addFloorToScene(
shape: THREE.Shape, shape: THREE.Shape,
layer: number, layer: number,
floorGroup: Types.RefGroup, floorGroup: Types.RefGroup,
userData: any, userData: any,
) { ) {
const textureLoader = new THREE.TextureLoader(); const textureLoader = new THREE.TextureLoader();
const textureScale = CONSTANTS.floorConfig.textureScale; const textureScale = CONSTANTS.floorConfig.textureScale;
const materialKey = `floorMaterial_${textureScale}`; const materialKey = `floorMaterial_${textureScale}`;
let material: THREE.Material; let material: THREE.Material;
if (materialCache.has(materialKey)) { if (materialCache.has(materialKey)) {
material = materialCache.get(materialKey) as THREE.Material; material = materialCache.get(materialKey) as THREE.Material;
} else { } else {
const floorTexture = textureLoader.load(texturePath); const floorTexture = textureLoader.load(texturePath);
const normalMap = textureLoader.load(normalPath); const normalMap = textureLoader.load(normalPath);
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping; floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set(textureScale, textureScale); floorTexture.repeat.set(textureScale, textureScale);
floorTexture.colorSpace = THREE.SRGBColorSpace; floorTexture.colorSpace = THREE.SRGBColorSpace;
normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping; normalMap.wrapS = normalMap.wrapT = THREE.RepeatWrapping;
normalMap.repeat.set(textureScale, textureScale); normalMap.repeat.set(textureScale, textureScale);
material = new THREE.MeshStandardMaterial({ material = new THREE.MeshStandardMaterial({
map: floorTexture, map: floorTexture,
normalMap: normalMap, normalMap: normalMap,
side: THREE.DoubleSide, side: THREE.DoubleSide,
}); });
materialCache.set(materialKey, material); materialCache.set(materialKey, material);
} }
const extrudeSettings = { const extrudeSettings = {
depth: CONSTANTS.floorConfig.height, depth: CONSTANTS.floorConfig.height,
bevelEnabled: false, bevelEnabled: false,
}; };
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const mesh = new THREE.Mesh(geometry, material); const mesh = new THREE.Mesh(geometry, material);
mesh.receiveShadow = true; mesh.receiveShadow = true;
mesh.position.y = layer; mesh.position.y = layer;
mesh.rotateX(Math.PI / 2); mesh.rotateX(Math.PI / 2);
mesh.name = `Floor_Layer_${layer}`; mesh.name = `Floor_Layer_${layer}`;
// Store UUIDs for debugging or future processing // Store UUIDs for debugging or future processing
mesh.userData.uuids = userData; mesh.userData.uuids = userData;
floorGroup.current.add(mesh); floorGroup.current.add(mesh);
} }

View File

@@ -1,179 +1,179 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
import addPointToScene from '../points/addPointToScene'; import addPointToScene from '../points/addPointToScene';
import addLineToScene from '../lines/addLineToScene'; import addLineToScene from '../lines/addLineToScene';
import splitLine from '../lines/splitLine'; import splitLine from '../lines/splitLine';
import removeReferenceLine from '../lines/removeReferenceLine'; import removeReferenceLine from '../lines/removeReferenceLine';
import getClosestIntersection from '../lines/getClosestIntersection'; import getClosestIntersection from '../lines/getClosestIntersection';
import arrayLineToObject from '../lines/lineConvertions/arrayLineToObject'; import arrayLineToObject from '../lines/lineConvertions/arrayLineToObject';
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi'; // import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
import { Socket } from 'socket.io-client'; import { Socket } from 'socket.io-client';
async function drawOnlyFloor( async function drawOnlyFloor(
raycaster: THREE.Raycaster, raycaster: THREE.Raycaster,
state: Types.ThreeState, state: Types.ThreeState,
camera: THREE.Camera, camera: THREE.Camera,
plane: Types.RefMesh, plane: Types.RefMesh,
floorPlanGroupPoint: Types.RefGroup, floorPlanGroupPoint: Types.RefGroup,
snappedPoint: Types.RefVector3, snappedPoint: Types.RefVector3,
isSnapped: Types.RefBoolean, isSnapped: Types.RefBoolean,
isSnappedUUID: Types.RefString, isSnappedUUID: Types.RefString,
line: Types.RefLine, line: Types.RefLine,
ispreSnapped: Types.RefBoolean, ispreSnapped: Types.RefBoolean,
anglesnappedPoint: Types.RefVector3, anglesnappedPoint: Types.RefVector3,
isAngleSnapped: Types.RefBoolean, isAngleSnapped: Types.RefBoolean,
onlyFloorline: Types.RefOnlyFloorLine, onlyFloorline: Types.RefOnlyFloorLine,
onlyFloorlines: Types.RefOnlyFloorLines, onlyFloorlines: Types.RefOnlyFloorLines,
lines: Types.RefLines, lines: Types.RefLines,
floorPlanGroupLine: Types.RefGroup, floorPlanGroupLine: Types.RefGroup,
floorPlanGroup: Types.RefGroup, floorPlanGroup: Types.RefGroup,
ReferenceLineMesh: Types.RefMesh, ReferenceLineMesh: Types.RefMesh,
LineCreated: Types.RefBoolean, LineCreated: Types.RefBoolean,
currentLayerPoint: Types.RefMeshArray, currentLayerPoint: Types.RefMeshArray,
dragPointControls: Types.RefDragControl, dragPointControls: Types.RefDragControl,
setNewLines: any, setNewLines: any,
setDeletedLines: any, setDeletedLines: any,
activeLayer: Types.Number, activeLayer: Types.Number,
socket: Socket<any> socket: Socket<any>
): Promise<void> { ): Promise<void> {
////////// Creating lines Based on the positions clicked ////////// ////////// Creating lines Based on the positions clicked //////////
if (!plane.current) return if (!plane.current) return
const intersects = raycaster.intersectObject(plane.current, true); const intersects = raycaster.intersectObject(plane.current, true);
const intersectsLines = raycaster.intersectObjects(floorPlanGroupLine.current.children, true); const intersectsLines = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
const intersectsPoint = raycaster.intersectObjects(floorPlanGroupPoint.current.children, true); const intersectsPoint = raycaster.intersectObjects(floorPlanGroupPoint.current.children, true);
const VisibleintersectsPoint = intersectsPoint.find(intersect => intersect.object.visible); const VisibleintersectsPoint = intersectsPoint.find(intersect => intersect.object.visible);
const visibleIntersect = intersectsLines.find(intersect => intersect.object.visible && intersect.object.name !== CONSTANTS.lineConfig.referenceName); const visibleIntersect = intersectsLines.find(intersect => intersect.object.visible && intersect.object.name !== CONSTANTS.lineConfig.referenceName);
if ((intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && intersectsLines.length > 0 && !isSnapped.current && !ispreSnapped.current) { if ((intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && intersectsLines.length > 0 && !isSnapped.current && !ispreSnapped.current) {
////////// Clicked on a preexisting Line ////////// ////////// Clicked on a preexisting Line //////////
if (visibleIntersect && (intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.floorName || intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName)) { if (visibleIntersect && (intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.floorName || intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName)) {
let pointColor, lineColor; let pointColor, lineColor;
if (intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName) { if (intersectsLines[0].object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName) {
pointColor = CONSTANTS.pointConfig.wallOuterColor; pointColor = CONSTANTS.pointConfig.wallOuterColor;
lineColor = CONSTANTS.lineConfig.wallColor; lineColor = CONSTANTS.lineConfig.wallColor;
} else { } else {
pointColor = CONSTANTS.pointConfig.floorOuterColor; pointColor = CONSTANTS.pointConfig.floorOuterColor;
lineColor = CONSTANTS.lineConfig.floorColor; lineColor = CONSTANTS.lineConfig.floorColor;
} }
let IntersectsPoint = new THREE.Vector3(intersects[0].point.x, 0.01, intersects[0].point.z); let IntersectsPoint = new THREE.Vector3(intersects[0].point.x, 0.01, intersects[0].point.z);
if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) { if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) {
IntersectsPoint = anglesnappedPoint.current; IntersectsPoint = anglesnappedPoint.current;
} }
if (visibleIntersect.object instanceof THREE.Mesh) { if (visibleIntersect.object instanceof THREE.Mesh) {
const ThroughPoint = (visibleIntersect.object.geometry.parameters.path).getPoints(CONSTANTS.lineConfig.lineIntersectionPoints); const ThroughPoint = (visibleIntersect.object.geometry.parameters.path).getPoints(CONSTANTS.lineConfig.lineIntersectionPoints);
let intersectionPoint = getClosestIntersection(ThroughPoint, IntersectsPoint); let intersectionPoint = getClosestIntersection(ThroughPoint, IntersectsPoint);
if (intersectionPoint) { if (intersectionPoint) {
const newLines = splitLine(visibleIntersect, intersectionPoint, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, lines, setDeletedLines, floorPlanGroupLine, socket, pointColor, lineColor, intersectsLines[0].object.userData.linePoints[0][3]); const newLines = splitLine(visibleIntersect, intersectionPoint, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, lines, setDeletedLines, floorPlanGroupLine, socket, pointColor, lineColor, intersectsLines[0].object.userData.linePoints[0][3]);
setNewLines([newLines[0], newLines[1]]); setNewLines([newLines[0], newLines[1]]);
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), isSnappedUUID.current!, activeLayer, CONSTANTS.lineConfig.floorName]); (line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), isSnappedUUID.current!, activeLayer, CONSTANTS.lineConfig.floorName]);
if (line.current.length >= 2 && line.current[0] && line.current[1]) { if (line.current.length >= 2 && line.current[0] && line.current[1]) {
lines.current.push(line.current as Types.Line); lines.current.push(line.current as Types.Line);
const data = arrayLineToObject(line.current as Types.Line); const data = arrayLineToObject(line.current as Types.Line);
const email = localStorage.getItem('email') const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0]; const organization = (email!.split("@")[1]).split(".")[0];
//REST //REST
// setLine(organization, data.layer!, data.line!, data.type!); // setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET //SOCKET
const input = { const input = {
organization: organization, organization: organization,
layer: data.layer, layer: data.layer,
line: data.line, line: data.line,
type: data.type, type: data.type,
socketId: socket.id socketId: socket.id
} }
socket.emit('v1:Line:create', input); socket.emit('v1:Line:create', input);
setNewLines([newLines[0], newLines[1], line.current]); setNewLines([newLines[0], newLines[1], line.current]);
onlyFloorline.current.push(line.current as Types.Line); onlyFloorline.current.push(line.current as Types.Line);
onlyFloorlines.current.push(onlyFloorline.current); onlyFloorlines.current.push(onlyFloorline.current);
onlyFloorline.current = []; onlyFloorline.current = [];
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.floorColor, line.current, floorPlanGroupLine); addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.floorColor, line.current, floorPlanGroupLine);
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
} }
return; return;
} }
} }
} }
} }
if (intersects.length > 0 && intersectsLines.length === 0) { if (intersects.length > 0 && intersectsLines.length === 0) {
////////// Clicked on an empty place or a point ////////// ////////// Clicked on an empty place or a point //////////
let intersectionPoint = intersects[0].point; let intersectionPoint = intersects[0].point;
if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) { if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) {
intersectionPoint = anglesnappedPoint.current; intersectionPoint = anglesnappedPoint.current;
} }
if (isSnapped.current && line.current.length > 0 && snappedPoint.current) { if (isSnapped.current && line.current.length > 0 && snappedPoint.current) {
intersectionPoint = snappedPoint.current; intersectionPoint = snappedPoint.current;
} }
if (ispreSnapped.current && snappedPoint.current) { if (ispreSnapped.current && snappedPoint.current) {
intersectionPoint = snappedPoint.current; intersectionPoint = snappedPoint.current;
} }
if (!isSnapped.current && !ispreSnapped.current) { if (!isSnapped.current && !ispreSnapped.current) {
addPointToScene(intersectionPoint, CONSTANTS.pointConfig.floorOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, CONSTANTS.lineConfig.floorName); addPointToScene(intersectionPoint, CONSTANTS.pointConfig.floorOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, CONSTANTS.lineConfig.floorName);
} else { } else {
ispreSnapped.current = false; ispreSnapped.current = false;
isSnapped.current = false; isSnapped.current = false;
} }
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), isSnappedUUID.current!, activeLayer, CONSTANTS.lineConfig.floorName]); (line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), isSnappedUUID.current!, activeLayer, CONSTANTS.lineConfig.floorName]);
if (line.current.length >= 2 && line.current[0] && line.current[1]) { if (line.current.length >= 2 && line.current[0] && line.current[1]) {
onlyFloorline.current.push(line.current as Types.Line); onlyFloorline.current.push(line.current as Types.Line);
lines.current.push(line.current as Types.Line); lines.current.push(line.current as Types.Line);
const data = arrayLineToObject(line.current as Types.Line); const data = arrayLineToObject(line.current as Types.Line);
const email = localStorage.getItem('email') const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0]; const organization = (email!.split("@")[1]).split(".")[0];
//REST //REST
// setLine(organization, data.layer!, data.line!, data.type!); // setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET //SOCKET
const input = { const input = {
organization: organization, organization: organization,
layer: data.layer, layer: data.layer,
line: data.line, line: data.line,
type: data.type, type: data.type,
socketId: socket.id socketId: socket.id
} }
socket.emit('v1:Line:create', input); socket.emit('v1:Line:create', input);
setNewLines([line.current]); setNewLines([line.current]);
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.floorColor, line.current, floorPlanGroupLine); addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.floorColor, line.current, floorPlanGroupLine);
const lastPoint = line.current[line.current.length - 1]; const lastPoint = line.current[line.current.length - 1];
line.current = [lastPoint]; line.current = [lastPoint];
} }
if (isSnapped.current) { ////////// Add this to stop the drawing mode after snapping ////////// if (isSnapped.current) { ////////// Add this to stop the drawing mode after snapping //////////
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
onlyFloorlines.current.push(onlyFloorline.current); onlyFloorlines.current.push(onlyFloorline.current);
onlyFloorline.current = []; onlyFloorline.current = [];
} }
} }
} }
export default drawOnlyFloor; export default drawOnlyFloor;

View File

@@ -1,50 +1,50 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
import addRoofToScene from '../roofs/addRoofToScene'; import addRoofToScene from '../roofs/addRoofToScene';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import loadOnlyFloors from './loadOnlyFloors'; import loadOnlyFloors from './loadOnlyFloors';
import addFloorToScene from './addFloorToScene'; import addFloorToScene from './addFloorToScene';
import getRoomsFromLines from '../lines/getRoomsFromLines'; import getRoomsFromLines from '../lines/getRoomsFromLines';
async function loadFloor( async function loadFloor(
lines: Types.RefLines, lines: Types.RefLines,
floorGroup: Types.RefGroup, floorGroup: Types.RefGroup,
): Promise<void> { ): Promise<void> {
if (!floorGroup.current) return; if (!floorGroup.current) return;
floorGroup.current.children = []; floorGroup.current.children = [];
if (lines.current.length > 2) { if (lines.current.length > 2) {
const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => { const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => {
const layer = pair[0][2]; const layer = pair[0][2];
if (!acc[layer]) acc[layer] = []; if (!acc[layer]) acc[layer] = [];
acc[layer].push(pair); acc[layer].push(pair);
return acc; return acc;
}, {}); }, {});
for (const layer in linesByLayer) { for (const layer in linesByLayer) {
// Only Floor Polygons // Only Floor Polygons
loadOnlyFloors(floorGroup, linesByLayer, layer); loadOnlyFloors(floorGroup, linesByLayer, layer);
const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] }); const rooms: Types.Rooms = await getRoomsFromLines({ current: linesByLayer[layer] });
rooms.forEach(({ coordinates: room, layer }) => { rooms.forEach(({ coordinates: room, layer }) => {
const userData = room.map(point => point.uuid); const userData = room.map(point => point.uuid);
const shape = new THREE.Shape(); const shape = new THREE.Shape();
shape.moveTo(room[0].position.x, room[0].position.z); shape.moveTo(room[0].position.x, room[0].position.z);
room.forEach(point => shape.lineTo(point.position.x, point.position.z)); room.forEach(point => shape.lineTo(point.position.x, point.position.z));
shape.closePath(); shape.closePath();
// Floor Polygons // Floor Polygons
addFloorToScene(shape, (layer - 1) * CONSTANTS.wallConfig.height, floorGroup, userData); addFloorToScene(shape, (layer - 1) * CONSTANTS.wallConfig.height, floorGroup, userData);
// Roof Polygons // Roof Polygons
addRoofToScene(shape, (layer - 1) * CONSTANTS.wallConfig.height, userData, floorGroup); addRoofToScene(shape, (layer - 1) * CONSTANTS.wallConfig.height, userData, floorGroup);
}); });
} }
} }
} }
export default loadFloor; export default loadFloor;

View File

@@ -1,183 +1,183 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as turf from '@turf/turf'; import * as turf from '@turf/turf';
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function loadOnlyFloors( function loadOnlyFloors(
floorGroup: Types.RefGroup, floorGroup: Types.RefGroup,
linesByLayer: any, linesByLayer: any,
layer: any, layer: any,
): void { ): void {
////////// Creating polygon floor based on the onlyFloorlines.current which does not add roof to it, The lines are still stored in Lines.current as well ////////// ////////// Creating polygon floor based on the onlyFloorlines.current which does not add roof to it, The lines are still stored in Lines.current as well //////////
let floorsInLayer = linesByLayer[layer]; let floorsInLayer = linesByLayer[layer];
floorsInLayer = floorsInLayer.filter((line: any) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName); floorsInLayer = floorsInLayer.filter((line: any) => line[0][3] && line[1][3] === CONSTANTS.lineConfig.floorName);
const floorResult = floorsInLayer.map((pair: [THREE.Vector3, string, number, string][]) => const floorResult = floorsInLayer.map((pair: [THREE.Vector3, string, number, string][]) =>
pair.map((point) => ({ pair.map((point) => ({
position: [point[0].x, point[0].z], position: [point[0].x, point[0].z],
uuid: point[1] uuid: point[1]
})) }))
); );
const FloorLineFeatures = floorResult.map((line: any) => turf.lineString(line.map((p: any) => p.position))); const FloorLineFeatures = floorResult.map((line: any) => turf.lineString(line.map((p: any) => p.position)));
function identifyPolygonsAndConnectedLines(FloorLineFeatures: any) { function identifyPolygonsAndConnectedLines(FloorLineFeatures: any) {
const floorpolygons = []; const floorpolygons = [];
const connectedLines = []; const connectedLines = [];
const unprocessedLines = [...FloorLineFeatures]; // Copy the features const unprocessedLines = [...FloorLineFeatures]; // Copy the features
while (unprocessedLines.length > 0) { while (unprocessedLines.length > 0) {
const currentLine = unprocessedLines.pop(); const currentLine = unprocessedLines.pop();
const coordinates = currentLine.geometry.coordinates; const coordinates = currentLine.geometry.coordinates;
// Check if the line is closed (forms a polygon) // Check if the line is closed (forms a polygon)
if ( if (
coordinates[0][0] === coordinates[coordinates.length - 1][0] && coordinates[0][0] === coordinates[coordinates.length - 1][0] &&
coordinates[0][1] === coordinates[coordinates.length - 1][1] coordinates[0][1] === coordinates[coordinates.length - 1][1]
) { ) {
floorpolygons.push(turf.polygon([coordinates])); // Add as a polygon floorpolygons.push(turf.polygon([coordinates])); // Add as a polygon
continue; continue;
} }
// Check if the line connects to another line // Check if the line connects to another line
let connected = false; let connected = false;
for (let i = unprocessedLines.length - 1; i >= 0; i--) { for (let i = unprocessedLines.length - 1; i >= 0; i--) {
const otherCoordinates = unprocessedLines[i].geometry.coordinates; const otherCoordinates = unprocessedLines[i].geometry.coordinates;
// Check if lines share a start or end point // Check if lines share a start or end point
if ( if (
coordinates[0][0] === otherCoordinates[otherCoordinates.length - 1][0] && coordinates[0][0] === otherCoordinates[otherCoordinates.length - 1][0] &&
coordinates[0][1] === otherCoordinates[otherCoordinates.length - 1][1] coordinates[0][1] === otherCoordinates[otherCoordinates.length - 1][1]
) { ) {
// Merge lines // Merge lines
const mergedCoordinates = [...otherCoordinates, ...coordinates.slice(1)]; const mergedCoordinates = [...otherCoordinates, ...coordinates.slice(1)];
unprocessedLines[i] = turf.lineString(mergedCoordinates); unprocessedLines[i] = turf.lineString(mergedCoordinates);
connected = true; connected = true;
break; break;
} else if ( } else if (
coordinates[coordinates.length - 1][0] === otherCoordinates[0][0] && coordinates[coordinates.length - 1][0] === otherCoordinates[0][0] &&
coordinates[coordinates.length - 1][1] === otherCoordinates[0][1] coordinates[coordinates.length - 1][1] === otherCoordinates[0][1]
) { ) {
// Merge lines // Merge lines
const mergedCoordinates = [...coordinates, ...otherCoordinates.slice(1)]; const mergedCoordinates = [...coordinates, ...otherCoordinates.slice(1)];
unprocessedLines[i] = turf.lineString(mergedCoordinates); unprocessedLines[i] = turf.lineString(mergedCoordinates);
connected = true; connected = true;
break; break;
} }
} }
if (!connected) { if (!connected) {
connectedLines.push(currentLine); // Add unconnected line as-is connectedLines.push(currentLine); // Add unconnected line as-is
} }
} }
return { floorpolygons, connectedLines }; return { floorpolygons, connectedLines };
} }
const { floorpolygons, connectedLines } = identifyPolygonsAndConnectedLines(FloorLineFeatures); const { floorpolygons, connectedLines } = identifyPolygonsAndConnectedLines(FloorLineFeatures);
function convertConnectedLinesToPolygons(connectedLines: any) { function convertConnectedLinesToPolygons(connectedLines: any) {
return connectedLines.map((line: any) => { return connectedLines.map((line: any) => {
const coordinates = line.geometry.coordinates; const coordinates = line.geometry.coordinates;
// If the line has more than two points, close the polygon // If the line has more than two points, close the polygon
if (coordinates.length > 2) { if (coordinates.length > 2) {
const firstPoint = coordinates[0]; const firstPoint = coordinates[0];
const lastPoint = coordinates[coordinates.length - 1]; const lastPoint = coordinates[coordinates.length - 1];
// Check if already closed; if not, close it // Check if already closed; if not, close it
if (firstPoint[0] !== lastPoint[0] || firstPoint[1] !== lastPoint[1]) { if (firstPoint[0] !== lastPoint[0] || firstPoint[1] !== lastPoint[1]) {
coordinates.push(firstPoint); coordinates.push(firstPoint);
} }
// Convert the closed line into a polygon // Convert the closed line into a polygon
return turf.polygon([coordinates]); return turf.polygon([coordinates]);
} }
// If not enough points for a polygon, return the line unchanged // If not enough points for a polygon, return the line unchanged
return line; return line;
}); });
} }
const convertedConnectedPolygons = convertConnectedLinesToPolygons(connectedLines); const convertedConnectedPolygons = convertConnectedLinesToPolygons(connectedLines);
if (convertedConnectedPolygons.length > 0) { if (convertedConnectedPolygons.length > 0) {
const validPolygons = convertedConnectedPolygons.filter( const validPolygons = convertedConnectedPolygons.filter(
(polygon: any) => polygon.geometry?.type === "Polygon" (polygon: any) => polygon.geometry?.type === "Polygon"
); );
if (validPolygons.length > 0) { if (validPolygons.length > 0) {
floorpolygons.push(...validPolygons); floorpolygons.push(...validPolygons);
} }
} }
function convertPolygonsToOriginalFormat(floorpolygons: any, originalLines: [THREE.Vector3, string, number, string][][]) { function convertPolygonsToOriginalFormat(floorpolygons: any, originalLines: [THREE.Vector3, string, number, string][][]) {
return floorpolygons.map((polygon: any) => { return floorpolygons.map((polygon: any) => {
const coordinates = polygon.geometry.coordinates[0]; // Extract the coordinates array (assume it's a single polygon) const coordinates = polygon.geometry.coordinates[0]; // Extract the coordinates array (assume it's a single polygon)
// Map each coordinate back to its original structure // Map each coordinate back to its original structure
const mappedPoints = coordinates.map((coord: [number, number]) => { const mappedPoints = coordinates.map((coord: [number, number]) => {
const [x, z] = coord; const [x, z] = coord;
// Find the original point matching this coordinate // Find the original point matching this coordinate
const originalPoint = originalLines.flat().find(([point]) => point.x === x && point.z === z); const originalPoint = originalLines.flat().find(([point]) => point.x === x && point.z === z);
if (!originalPoint) { if (!originalPoint) {
throw new Error(`Original point for coordinate [${x}, ${z}] not found.`); throw new Error(`Original point for coordinate [${x}, ${z}] not found.`);
} }
return originalPoint; return originalPoint;
}); });
// Create pairs of consecutive points // Create pairs of consecutive points
const pairs: typeof originalLines = []; const pairs: typeof originalLines = [];
for (let i = 0; i < mappedPoints.length - 1; i++) { for (let i = 0; i < mappedPoints.length - 1; i++) {
pairs.push([mappedPoints[i], mappedPoints[i + 1]]); pairs.push([mappedPoints[i], mappedPoints[i + 1]]);
} }
return pairs; return pairs;
}); });
} }
const convertedFloorPolygons: Types.OnlyFloorLines = convertPolygonsToOriginalFormat(floorpolygons, floorsInLayer); const convertedFloorPolygons: Types.OnlyFloorLines = convertPolygonsToOriginalFormat(floorpolygons, floorsInLayer);
convertedFloorPolygons.forEach((floor) => { convertedFloorPolygons.forEach((floor) => {
const points: THREE.Vector3[] = []; const points: THREE.Vector3[] = [];
floor.forEach((lineSegment) => { floor.forEach((lineSegment) => {
const startPoint = lineSegment[0][0]; const startPoint = lineSegment[0][0];
points.push(new THREE.Vector3(startPoint.x, startPoint.y, startPoint.z)); points.push(new THREE.Vector3(startPoint.x, startPoint.y, startPoint.z));
}); });
const lastLine = floor[floor.length - 1]; const lastLine = floor[floor.length - 1];
const endPoint = lastLine[1][0]; const endPoint = lastLine[1][0];
points.push(new THREE.Vector3(endPoint.x, endPoint.y, endPoint.z)); points.push(new THREE.Vector3(endPoint.x, endPoint.y, endPoint.z));
const shape = new THREE.Shape(); const shape = new THREE.Shape();
shape.moveTo(points[0].x, points[0].z); shape.moveTo(points[0].x, points[0].z);
points.forEach(point => shape.lineTo(point.x, point.z)); points.forEach(point => shape.lineTo(point.x, point.z));
shape.closePath(); shape.closePath();
const extrudeSettings = { const extrudeSettings = {
depth: CONSTANTS.floorConfig.height, depth: CONSTANTS.floorConfig.height,
bevelEnabled: false bevelEnabled: false
}; };
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.floorConfig.defaultColor, side: THREE.DoubleSide }); const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.floorConfig.defaultColor, side: THREE.DoubleSide });
const mesh = new THREE.Mesh(geometry, material); const mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true; mesh.castShadow = true;
mesh.receiveShadow = true; mesh.receiveShadow = true;
mesh.position.y = (floor[0][0][2] - 1) * CONSTANTS.wallConfig.height + 0.03; mesh.position.y = (floor[0][0][2] - 1) * CONSTANTS.wallConfig.height + 0.03;
mesh.rotateX(Math.PI / 2); mesh.rotateX(Math.PI / 2);
mesh.name = `Only_Floor_Line_${floor[0][0][2]}`; mesh.name = `Only_Floor_Line_${floor[0][0][2]}`;
mesh.userData = floor; mesh.userData = floor;
floorGroup?.current?.add(mesh); floorGroup?.current?.add(mesh);
}); });
} }
export default loadOnlyFloors; export default loadOnlyFloors;

View File

@@ -1,24 +1,24 @@
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function updateFloorLines( function updateFloorLines(
onlyFloorlines: Types.RefOnlyFloorLines, onlyFloorlines: Types.RefOnlyFloorLines,
DragedPoint: Types.Mesh | { uuid: string, position: Types.Vector3 } DragedPoint: Types.Mesh | { uuid: string, position: Types.Vector3 }
): void { ): void {
////////// Update onlyFloorlines.current if it contains the dragged point ////////// ////////// Update onlyFloorlines.current if it contains the dragged point //////////
onlyFloorlines.current.forEach((floorline) => { onlyFloorlines.current.forEach((floorline) => {
floorline.forEach((line) => { floorline.forEach((line) => {
line.forEach((point) => { line.forEach((point) => {
const [position, uuid] = point; const [position, uuid] = point;
if (uuid === DragedPoint.uuid) { if (uuid === DragedPoint.uuid) {
position.x = DragedPoint.position.x; position.x = DragedPoint.position.x;
position.y = 0.01; position.y = 0.01;
position.z = DragedPoint.position.z; position.z = DragedPoint.position.z;
} }
}); });
}); });
}); });
} }
export default updateFloorLines; export default updateFloorLines;

View File

@@ -1,89 +1,89 @@
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import RemoveConnectedLines from '../lines/removeConnectedLines'; import RemoveConnectedLines from '../lines/removeConnectedLines';
import * as Types from '../../../../types/world/worldTypes'; import * as Types from '../../../../types/world/worldTypes';
import { Socket } from 'socket.io-client'; import { Socket } from 'socket.io-client';
// import { deleteLayer } from '../../../../services/factoryBuilder/lines/deleteLayerApi'; // import { deleteLayer } from '../../../../services/factoryBuilder/lines/deleteLayerApi';
async function DeleteLayer( async function DeleteLayer(
removedLayer: Types.Number, removedLayer: Types.Number,
lines: Types.RefLines, lines: Types.RefLines,
floorPlanGroupLine: Types.RefGroup, floorPlanGroupLine: Types.RefGroup,
floorPlanGroupPoint: Types.RefGroup, floorPlanGroupPoint: Types.RefGroup,
onlyFloorlines: Types.RefOnlyFloorLines, onlyFloorlines: Types.RefOnlyFloorLines,
floorGroup: Types.RefGroup, floorGroup: Types.RefGroup,
setDeletedLines: any, setDeletedLines: any,
setRemovedLayer: Types.setRemoveLayerSetState, setRemovedLayer: Types.setRemoveLayerSetState,
socket: Socket<any> socket: Socket<any>
): Promise<void> { ): Promise<void> {
////////// Remove the Lines from the lines.current based on the removed layer and rearrange the layer number that are higher than the removed layer ////////// ////////// Remove the Lines from the lines.current based on the removed layer and rearrange the layer number that are higher than the removed layer //////////
const removedLines: Types.Lines = lines.current.filter(line => line[0][2] === removedLayer); const removedLines: Types.Lines = lines.current.filter(line => line[0][2] === removedLayer);
const email = localStorage.getItem('email') const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0]; const organization = (email!.split("@")[1]).split(".")[0];
//REST //REST
// await deleteLayer(organization, removedLayer); // await deleteLayer(organization, removedLayer);
//SOCKET //SOCKET
const data = { const data = {
organization: organization, organization: organization,
layer: removedLayer, layer: removedLayer,
socketId: socket.id socketId: socket.id
} }
socket.emit('v1:Line:delete:layer', data); socket.emit('v1:Line:delete:layer', data);
////////// Remove Points and lines from the removed layer ////////// ////////// Remove Points and lines from the removed layer //////////
removedLines.forEach((line) => { removedLines.forEach((line) => {
line.forEach((removedPoint) => { line.forEach((removedPoint) => {
RemoveConnectedLines(removedPoint[1], floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, lines); RemoveConnectedLines(removedPoint[1], floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, lines);
}); });
}); });
////////// Update the remaining lines layer values in the userData and in lines.current ////////// ////////// Update the remaining lines layer values in the userData and in lines.current //////////
let remaining = lines.current.filter(line => line[0][2] !== removedLayer); let remaining = lines.current.filter(line => line[0][2] !== removedLayer);
let updatedLines: Types.Lines = []; let updatedLines: Types.Lines = [];
remaining.forEach(line => { remaining.forEach(line => {
let newLines: Types.Line = [...line]; let newLines: Types.Line = [...line];
if (newLines[0][2] > removedLayer) { if (newLines[0][2] > removedLayer) {
newLines[0][2] -= 1; newLines[0][2] -= 1;
newLines[1][2] -= 1; newLines[1][2] -= 1;
} }
const matchingLine = floorPlanGroupLine.current.children.find(l => l.userData.linePoints[0][1] === line[0][1] && l.userData.linePoints[1][1] === line[1][1]); const matchingLine = floorPlanGroupLine.current.children.find(l => l.userData.linePoints[0][1] === line[0][1] && l.userData.linePoints[1][1] === line[1][1]);
if (matchingLine) { if (matchingLine) {
const updatedUserData = matchingLine.userData; const updatedUserData = matchingLine.userData;
updatedUserData.linePoints[0][2] = newLines[0][2]; updatedUserData.linePoints[0][2] = newLines[0][2];
updatedUserData.linePoints[1][2] = newLines[1][2]; updatedUserData.linePoints[1][2] = newLines[1][2];
} }
updatedLines.push(newLines); updatedLines.push(newLines);
}); });
lines.current = updatedLines; lines.current = updatedLines;
localStorage.setItem("Lines", JSON.stringify(lines.current)); localStorage.setItem("Lines", JSON.stringify(lines.current));
////////// Also remove OnlyFloorLines and update it in localstorage ////////// ////////// Also remove OnlyFloorLines and update it in localstorage //////////
onlyFloorlines.current = onlyFloorlines.current.filter((floor) => { onlyFloorlines.current = onlyFloorlines.current.filter((floor) => {
return floor[0][0][2] !== removedLayer; return floor[0][0][2] !== removedLayer;
}); });
const meshToRemove: any = floorGroup.current?.children.find((mesh) => const meshToRemove: any = floorGroup.current?.children.find((mesh) =>
mesh.name === `Only_Floor_Line_${removedLayer}` mesh.name === `Only_Floor_Line_${removedLayer}`
); );
if (meshToRemove) { if (meshToRemove) {
(<any>meshToRemove.material).dispose(); (<any>meshToRemove.material).dispose();
(<any>meshToRemove.geometry).dispose(); (<any>meshToRemove.geometry).dispose();
floorGroup.current?.remove(meshToRemove); floorGroup.current?.remove(meshToRemove);
} }
toast.success("Layer Removed!"); toast.success("Layer Removed!");
setRemovedLayer(null); setRemovedLayer(null);
} }
export default DeleteLayer; export default DeleteLayer;

View File

@@ -1,35 +1,35 @@
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function Layer2DVisibility( function Layer2DVisibility(
activeLayer: Types.Number, activeLayer: Types.Number,
floorPlanGroup: Types.RefGroup, floorPlanGroup: Types.RefGroup,
floorPlanGroupLine: Types.RefGroup, floorPlanGroupLine: Types.RefGroup,
floorPlanGroupPoint: Types.RefGroup, floorPlanGroupPoint: Types.RefGroup,
currentLayerPoint: Types.RefMeshArray, currentLayerPoint: Types.RefMeshArray,
dragPointControls: Types.RefDragControl dragPointControls: Types.RefDragControl
): void { ): void {
if (floorPlanGroup.current && dragPointControls.current) { if (floorPlanGroup.current && dragPointControls.current) {
currentLayerPoint.current = []; currentLayerPoint.current = [];
floorPlanGroupLine.current.children.forEach((line) => { floorPlanGroupLine.current.children.forEach((line) => {
const linePoints = line.userData.linePoints; const linePoints = line.userData.linePoints;
const point1 = floorPlanGroupPoint.current.getObjectByProperty('uuid', linePoints[0][1]) as Types.Mesh; const point1 = floorPlanGroupPoint.current.getObjectByProperty('uuid', linePoints[0][1]) as Types.Mesh;
const point2 = floorPlanGroupPoint.current.getObjectByProperty('uuid', linePoints[1][1]) as Types.Mesh; const point2 = floorPlanGroupPoint.current.getObjectByProperty('uuid', linePoints[1][1]) as Types.Mesh;
if (linePoints[0][2] !== activeLayer && linePoints[1][2] !== activeLayer) { if (linePoints[0][2] !== activeLayer && linePoints[1][2] !== activeLayer) {
point1.visible = false; point1.visible = false;
point2.visible = false; point2.visible = false;
line.visible = false; line.visible = false;
} else { } else {
point1.visible = true; point1.visible = true;
point2.visible = true; point2.visible = true;
line.visible = true; line.visible = true;
currentLayerPoint.current.push(point1, point2); currentLayerPoint.current.push(point1, point2);
} }
}); });
dragPointControls.current!.objects = currentLayerPoint.current; dragPointControls.current!.objects = currentLayerPoint.current;
} }
} }
export default Layer2DVisibility; export default Layer2DVisibility;

View File

@@ -1,24 +1,24 @@
import * as THREE from "three"; import * as THREE from "three";
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function addLineToScene( function addLineToScene(
start: Types.Vector3, start: Types.Vector3,
end: Types.Vector3, end: Types.Vector3,
colour: Types.Color, colour: Types.Color,
userData: Types.UserData, userData: Types.UserData,
floorPlanGroupLine: Types.RefGroup floorPlanGroupLine: Types.RefGroup
): void { ): void {
////////// A function that creates and adds lines based on the start, end, and colour from the params, Also adds the userData in the mesh userData ////////// ////////// A function that creates and adds lines based on the start, end, and colour from the params, Also adds the userData in the mesh userData //////////
const path = new THREE.CatmullRomCurve3([start, end]); const path = new THREE.CatmullRomCurve3([start, end]);
const geometry = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false); const geometry = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
const material = new THREE.MeshBasicMaterial({ color: colour }); const material = new THREE.MeshBasicMaterial({ color: colour });
const mesh = new THREE.Mesh(geometry, material); const mesh = new THREE.Mesh(geometry, material);
floorPlanGroupLine.current.add(mesh); floorPlanGroupLine.current.add(mesh);
mesh.userData.linePoints = userData; mesh.userData.linePoints = userData;
} }
export default addLineToScene; export default addLineToScene;

View File

@@ -1,98 +1,98 @@
import * as THREE from "three"; import * as THREE from "three";
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function createAndMoveReferenceLine( function createAndMoveReferenceLine(
point: Types.Vector3, point: Types.Vector3,
cursorPosition: Types.Vector3, cursorPosition: Types.Vector3,
isSnapped: Types.RefBoolean, isSnapped: Types.RefBoolean,
ispreSnapped: Types.RefBoolean, ispreSnapped: Types.RefBoolean,
line: Types.RefLine, line: Types.RefLine,
setRefTextUpdate: Types.NumberIncrementState, setRefTextUpdate: Types.NumberIncrementState,
floorPlanGroup: Types.RefGroup, floorPlanGroup: Types.RefGroup,
ReferenceLineMesh: Types.RefMesh, ReferenceLineMesh: Types.RefMesh,
LineCreated: Types.RefBoolean, LineCreated: Types.RefBoolean,
Tube: Types.RefTubeGeometry, Tube: Types.RefTubeGeometry,
anglesnappedPoint: Types.RefVector3, anglesnappedPoint: Types.RefVector3,
isAngleSnapped: Types.RefBoolean isAngleSnapped: Types.RefBoolean
): void { ): void {
////////// Creating new and maintaining the old reference line and also snap the reference line based on its angle ////////// ////////// Creating new and maintaining the old reference line and also snap the reference line based on its angle //////////
const startPoint = point; const startPoint = point;
const dx = cursorPosition.x - startPoint.x; const dx = cursorPosition.x - startPoint.x;
const dz = cursorPosition.z - startPoint.z; const dz = cursorPosition.z - startPoint.z;
let angle = Math.atan2(dz, dx); let angle = Math.atan2(dz, dx);
angle = (angle * 180) / Math.PI; angle = (angle * 180) / Math.PI;
angle = (angle + 360) % 360; angle = (angle + 360) % 360;
const snapAngles = [0, 90, 180, 270, 360]; const snapAngles = [0, 90, 180, 270, 360];
const snapThreshold = 2.5; const snapThreshold = 2.5;
const closestSnapAngle = snapAngles.reduce((prev, curr) => const closestSnapAngle = snapAngles.reduce((prev, curr) =>
Math.abs(curr - angle) < Math.abs(prev - angle) ? curr : prev Math.abs(curr - angle) < Math.abs(prev - angle) ? curr : prev
); );
if (!isSnapped.current && !ispreSnapped.current && line.current.length > 0) { if (!isSnapped.current && !ispreSnapped.current && line.current.length > 0) {
if (Math.abs(closestSnapAngle - angle) <= snapThreshold) { if (Math.abs(closestSnapAngle - angle) <= snapThreshold) {
const snappedAngleRad = (closestSnapAngle * Math.PI) / 180; const snappedAngleRad = (closestSnapAngle * Math.PI) / 180;
const distance = Math.sqrt(dx * dx + dz * dz); const distance = Math.sqrt(dx * dx + dz * dz);
const snappedX = startPoint.x + distance * Math.cos(snappedAngleRad); const snappedX = startPoint.x + distance * Math.cos(snappedAngleRad);
const snappedZ = startPoint.z + distance * Math.sin(snappedAngleRad); const snappedZ = startPoint.z + distance * Math.sin(snappedAngleRad);
if ( if (
cursorPosition.distanceTo( cursorPosition.distanceTo(
new THREE.Vector3(snappedX, 0.01, snappedZ) new THREE.Vector3(snappedX, 0.01, snappedZ)
) < 2 ) < 2
) { ) {
cursorPosition.set(snappedX, 0.01, snappedZ); cursorPosition.set(snappedX, 0.01, snappedZ);
isAngleSnapped.current = true; isAngleSnapped.current = true;
anglesnappedPoint.current = new THREE.Vector3( anglesnappedPoint.current = new THREE.Vector3(
snappedX, snappedX,
0.01, 0.01,
snappedZ snappedZ
); );
} else { } else {
isAngleSnapped.current = false; isAngleSnapped.current = false;
anglesnappedPoint.current = null; anglesnappedPoint.current = null;
} }
} else { } else {
isAngleSnapped.current = false; isAngleSnapped.current = false;
anglesnappedPoint.current = null; anglesnappedPoint.current = null;
} }
} else { } else {
isAngleSnapped.current = false; isAngleSnapped.current = false;
anglesnappedPoint.current = null; anglesnappedPoint.current = null;
} }
if (!LineCreated.current) { if (!LineCreated.current) {
setRefTextUpdate((prevUpdate) => prevUpdate - 1); setRefTextUpdate((prevUpdate) => prevUpdate - 1);
const path = new THREE.LineCurve3(startPoint, cursorPosition); const path = new THREE.LineCurve3(startPoint, cursorPosition);
Tube.current = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false); Tube.current = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
const material = new THREE.MeshBasicMaterial({ color: CONSTANTS.lineConfig.helperColor }); const material = new THREE.MeshBasicMaterial({ color: CONSTANTS.lineConfig.helperColor });
ReferenceLineMesh.current = new THREE.Mesh(Tube.current, material); ReferenceLineMesh.current = new THREE.Mesh(Tube.current, material);
ReferenceLineMesh.current.name = CONSTANTS.lineConfig.referenceName; ReferenceLineMesh.current.name = CONSTANTS.lineConfig.referenceName;
ReferenceLineMesh.current.userData = { ReferenceLineMesh.current.userData = {
linePoints: { startPoint, cursorPosition }, linePoints: { startPoint, cursorPosition },
}; };
floorPlanGroup.current?.add(ReferenceLineMesh.current); floorPlanGroup.current?.add(ReferenceLineMesh.current);
LineCreated.current = true; LineCreated.current = true;
} else { } else {
if (ReferenceLineMesh.current) { if (ReferenceLineMesh.current) {
const path = new THREE.LineCurve3(startPoint, new THREE.Vector3(cursorPosition.x, 0.01, cursorPosition.z)); const path = new THREE.LineCurve3(startPoint, new THREE.Vector3(cursorPosition.x, 0.01, cursorPosition.z));
Tube.current = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false); Tube.current = new THREE.TubeGeometry(path, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
if (ReferenceLineMesh.current) { if (ReferenceLineMesh.current) {
ReferenceLineMesh.current.userData = { ReferenceLineMesh.current.userData = {
linePoints: { startPoint, cursorPosition }, linePoints: { startPoint, cursorPosition },
}; };
ReferenceLineMesh.current.geometry.dispose(); ReferenceLineMesh.current.geometry.dispose();
ReferenceLineMesh.current.geometry = Tube.current; ReferenceLineMesh.current.geometry = Tube.current;
} }
} }
} }
} }
export default createAndMoveReferenceLine; export default createAndMoveReferenceLine;

View File

@@ -1,88 +1,88 @@
import { Socket } from "socket.io-client"; import { Socket } from "socket.io-client";
// import { deleteLineApi } from "../../../../services/factoryBuilder/lines/deleteLineApi"; // import { deleteLineApi } from "../../../../services/factoryBuilder/lines/deleteLineApi";
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
function deleteLine( function deleteLine(
hoveredDeletableLine: Types.RefMesh, hoveredDeletableLine: Types.RefMesh,
onlyFloorlines: Types.RefOnlyFloorLines, onlyFloorlines: Types.RefOnlyFloorLines,
lines: Types.RefLines, lines: Types.RefLines,
floorPlanGroupLine: Types.RefGroup, floorPlanGroupLine: Types.RefGroup,
floorPlanGroupPoint: Types.RefGroup, floorPlanGroupPoint: Types.RefGroup,
setDeletedLines: any, setDeletedLines: any,
socket: Socket<any> socket: Socket<any>
): void { ): void {
////////// Deleting a line and the points if they are not connected to any other line ////////// ////////// Deleting a line and the points if they are not connected to any other line //////////
if (!hoveredDeletableLine.current) { if (!hoveredDeletableLine.current) {
return; return;
} }
const linePoints = hoveredDeletableLine.current.userData.linePoints; const linePoints = hoveredDeletableLine.current.userData.linePoints;
const connectedpoints = [linePoints[0][1], linePoints[1][1]]; const connectedpoints = [linePoints[0][1], linePoints[1][1]];
const email = localStorage.getItem('email') const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0]; const organization = (email!.split("@")[1]).split(".")[0];
//REST //REST
// deleteLineApi( // deleteLineApi(
// organization, // organization,
// [ // [
// { "uuid": linePoints[0][1] }, // { "uuid": linePoints[0][1] },
// { "uuid": linePoints[1][1] } // { "uuid": linePoints[1][1] }
// ] // ]
// ) // )
//SOCKET //SOCKET
const data = { const data = {
organization: organization, organization: organization,
line: [ line: [
{ "uuid": linePoints[0][1] }, { "uuid": linePoints[0][1] },
{ "uuid": linePoints[1][1] } { "uuid": linePoints[1][1] }
], ],
socketId: socket.id socketId: socket.id
} }
socket.emit('v1:Line:delete', data); socket.emit('v1:Line:delete', data);
onlyFloorlines.current = onlyFloorlines.current.map(floorline => onlyFloorlines.current = onlyFloorlines.current.map(floorline =>
floorline.filter(line => line[0][1] !== connectedpoints[0] && line[1][1] !== connectedpoints[1]) floorline.filter(line => line[0][1] !== connectedpoints[0] && line[1][1] !== connectedpoints[1])
).filter(floorline => floorline.length > 0); ).filter(floorline => floorline.length > 0);
lines.current = lines.current.filter(item => item !== linePoints); lines.current = lines.current.filter(item => item !== linePoints);
(<any>hoveredDeletableLine.current.material).dispose(); (<any>hoveredDeletableLine.current.material).dispose();
(<any>hoveredDeletableLine.current.geometry).dispose(); (<any>hoveredDeletableLine.current.geometry).dispose();
floorPlanGroupLine.current.remove(hoveredDeletableLine.current); floorPlanGroupLine.current.remove(hoveredDeletableLine.current);
setDeletedLines([linePoints]); setDeletedLines([linePoints]);
connectedpoints.forEach((pointUUID) => { connectedpoints.forEach((pointUUID) => {
let isConnected = false; let isConnected = false;
floorPlanGroupLine.current.children.forEach((line) => { floorPlanGroupLine.current.children.forEach((line) => {
const linePoints = line.userData.linePoints; const linePoints = line.userData.linePoints;
const uuid1 = linePoints[0][1]; const uuid1 = linePoints[0][1];
const uuid2 = linePoints[1][1]; const uuid2 = linePoints[1][1];
if (uuid1 === pointUUID || uuid2 === pointUUID) { if (uuid1 === pointUUID || uuid2 === pointUUID) {
isConnected = true; isConnected = true;
} }
}); });
if (!isConnected) { if (!isConnected) {
floorPlanGroupPoint.current.children.forEach((point: any) => { floorPlanGroupPoint.current.children.forEach((point: any) => {
if (point.uuid === pointUUID) { if (point.uuid === pointUUID) {
(<any>point.material).dispose(); (<any>point.material).dispose();
(<any>point.geometry).dispose(); (<any>point.geometry).dispose();
floorPlanGroupPoint.current.remove(point); floorPlanGroupPoint.current.remove(point);
} }
}); });
} }
}); });
toast.success("Line Removed!"); toast.success("Line Removed!");
} }
export default deleteLine; export default deleteLine;

View File

@@ -1,90 +1,90 @@
import { useEffect, useState } from "react" import { useEffect, useState } from "react"
import { getLines } from "../../../../services/factoryBuilder/lines/getLinesApi"; import { getLines } from "../../../../services/factoryBuilder/lines/getLinesApi";
import * as THREE from "three"; import * as THREE from "three";
import { useActiveLayer, useDeletedLines, useNewLines, useToggleView } from "../../../../store/store"; import { useActiveLayer, useDeletedLines, useNewLines, useToggleView } from "../../../../store/store";
import objectLinesToArray from "./lineConvertions/objectLinesToArray"; import objectLinesToArray from "./lineConvertions/objectLinesToArray";
import { Html } from "@react-three/drei"; import { Html } from "@react-three/drei";
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
const DistanceText = () => { const DistanceText = () => {
const [lines, setLines] = useState<{ distance: string; position: THREE.Vector3; userData: Types.Line; layer: string }[]>([]); const [lines, setLines] = useState<{ distance: string; position: THREE.Vector3; userData: Types.Line; layer: string }[]>([]);
const { activeLayer } = useActiveLayer(); const { activeLayer } = useActiveLayer();
const { toggleView } = useToggleView(); const { toggleView } = useToggleView();
const { newLines, setNewLines } = useNewLines(); const { newLines, setNewLines } = useNewLines();
const { deletedLines, setDeletedLines } = useDeletedLines(); const { deletedLines, setDeletedLines } = useDeletedLines();
useEffect(() => { useEffect(() => {
const email = localStorage.getItem('email') const email = localStorage.getItem('email')
if (!email) return; if (!email) return;
const organization = (email.split("@")[1]).split(".")[0]; const organization = (email.split("@")[1]).split(".")[0];
getLines(organization).then((data) => { getLines(organization).then((data) => {
data = objectLinesToArray(data); data = objectLinesToArray(data);
const lines = data.filter((line: Types.Line) => line[0][2] === activeLayer) const lines = data.filter((line: Types.Line) => line[0][2] === activeLayer)
.map((line: Types.Line) => { .map((line: Types.Line) => {
const point1 = new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z); const point1 = new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z);
const point2 = new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z); const point2 = new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z);
const distance = point1.distanceTo(point2); const distance = point1.distanceTo(point2);
const midpoint = new THREE.Vector3().addVectors(point1, point2).divideScalar(2); const midpoint = new THREE.Vector3().addVectors(point1, point2).divideScalar(2);
return { return {
distance: distance.toFixed(1), distance: distance.toFixed(1),
position: midpoint, position: midpoint,
userData: line, userData: line,
layer: activeLayer, layer: activeLayer,
}; };
}); });
setLines(lines) setLines(lines)
}) })
}, [activeLayer]) }, [activeLayer])
useEffect(() => { useEffect(() => {
if (newLines.length > 0) { if (newLines.length > 0) {
if (newLines[0][0][2] !== activeLayer) return; if (newLines[0][0][2] !== activeLayer) return;
const newLinesData = newLines.map((line: Types.Line) => { const newLinesData = newLines.map((line: Types.Line) => {
const point1 = new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z); const point1 = new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z);
const point2 = new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z); const point2 = new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z);
const distance = point1.distanceTo(point2); const distance = point1.distanceTo(point2);
const midpoint = new THREE.Vector3().addVectors(point1, point2).divideScalar(2); const midpoint = new THREE.Vector3().addVectors(point1, point2).divideScalar(2);
return { return {
distance: distance.toFixed(1), distance: distance.toFixed(1),
position: midpoint, position: midpoint,
userData: line, userData: line,
layer: activeLayer, layer: activeLayer,
}; };
}); });
setLines((prevLines) => [...prevLines, ...newLinesData]); setLines((prevLines) => [...prevLines, ...newLinesData]);
setNewLines([]); setNewLines([]);
} }
}, [newLines, activeLayer]); }, [newLines, activeLayer]);
useEffect(() => { useEffect(() => {
if ((deletedLines as Types.Lines).length > 0) { if ((deletedLines as Types.Lines).length > 0) {
setLines((prevLines) => setLines((prevLines) =>
prevLines.filter( prevLines.filter(
(line) => !deletedLines.some((deletedLine: any) => deletedLine[0][1] === line.userData[0][1] && deletedLine[1][1] === line.userData[1][1]) (line) => !deletedLines.some((deletedLine: any) => deletedLine[0][1] === line.userData[0][1] && deletedLine[1][1] === line.userData[1][1])
) )
); );
setDeletedLines([]); setDeletedLines([]);
} }
}, [deletedLines]); }, [deletedLines]);
return ( return (
<> <>
{toggleView && ( {toggleView && (
<group name='Distance_Text'> <group name='Distance_Text'>
{lines.map((text) => ( {lines.map((text) => (
<Html key={`${text.userData[0][1]}_${text.userData[1][1]}`} transform sprite userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }} > <Html key={`${text.userData[0][1]}_${text.userData[1][1]}`} transform sprite userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }} >
<div key={`${text.userData[0][1]}_${text.userData[1][1]}`} className={`Distance line-${text.userData[0][1]}_${text.userData[1][1]}_${text.layer}`} >{text.distance} m</div> <div key={`${text.userData[0][1]}_${text.userData[1][1]}`} className={`Distance line-${text.userData[0][1]}_${text.userData[1][1]}_${text.layer}`} >{text.distance} m</div>
</Html> </Html>
))} ))}
</group> </group>
)} )}
</> </>
) )
} }
export default DistanceText; export default DistanceText;

View File

@@ -1,167 +1,167 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
import addPointToScene from '../points/addPointToScene'; import addPointToScene from '../points/addPointToScene';
import addLineToScene from './addLineToScene'; import addLineToScene from './addLineToScene';
import splitLine from './splitLine'; import splitLine from './splitLine';
import removeReferenceLine from './removeReferenceLine'; import removeReferenceLine from './removeReferenceLine';
import getClosestIntersection from './getClosestIntersection'; import getClosestIntersection from './getClosestIntersection';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import arrayLineToObject from './lineConvertions/arrayLineToObject'; import arrayLineToObject from './lineConvertions/arrayLineToObject';
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi'; // import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
import { Socket } from 'socket.io-client'; import { Socket } from 'socket.io-client';
async function drawWall( async function drawWall(
raycaster: THREE.Raycaster, raycaster: THREE.Raycaster,
plane: Types.RefMesh, plane: Types.RefMesh,
floorPlanGroupPoint: Types.RefGroup, floorPlanGroupPoint: Types.RefGroup,
snappedPoint: Types.RefVector3, snappedPoint: Types.RefVector3,
isSnapped: Types.RefBoolean, isSnapped: Types.RefBoolean,
isSnappedUUID: Types.RefString, isSnappedUUID: Types.RefString,
line: Types.RefLine, line: Types.RefLine,
ispreSnapped: Types.RefBoolean, ispreSnapped: Types.RefBoolean,
anglesnappedPoint: Types.RefVector3, anglesnappedPoint: Types.RefVector3,
isAngleSnapped: Types.RefBoolean, isAngleSnapped: Types.RefBoolean,
lines: Types.RefLines, lines: Types.RefLines,
floorPlanGroupLine: Types.RefGroup, floorPlanGroupLine: Types.RefGroup,
floorPlanGroup: Types.RefGroup, floorPlanGroup: Types.RefGroup,
ReferenceLineMesh: Types.RefMesh, ReferenceLineMesh: Types.RefMesh,
LineCreated: Types.RefBoolean, LineCreated: Types.RefBoolean,
currentLayerPoint: Types.RefMeshArray, currentLayerPoint: Types.RefMeshArray,
dragPointControls: Types.RefDragControl, dragPointControls: Types.RefDragControl,
setNewLines: any, setNewLines: any,
setDeletedLines: any, setDeletedLines: any,
activeLayer: Types.Number, activeLayer: Types.Number,
socket: Socket<any> socket: Socket<any>
): Promise<void> { ): Promise<void> {
////////// Creating lines Based on the positions clicked ////////// ////////// Creating lines Based on the positions clicked //////////
////////// Allows the user lines that represents walls and roof, floor if forms a polygon ////////// ////////// Allows the user lines that represents walls and roof, floor if forms a polygon //////////
if (!plane.current) return if (!plane.current) return
let intersects = raycaster.intersectObject(plane.current, true); let intersects = raycaster.intersectObject(plane.current, true);
let intersectsLines = raycaster.intersectObjects(floorPlanGroupLine.current.children, true); let intersectsLines = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
let intersectsPoint = raycaster.intersectObjects(floorPlanGroupPoint.current.children, true); let intersectsPoint = raycaster.intersectObjects(floorPlanGroupPoint.current.children, true);
const VisibleintersectsPoint = intersectsPoint.find(intersect => intersect.object.visible); const VisibleintersectsPoint = intersectsPoint.find(intersect => intersect.object.visible);
const visibleIntersect = intersectsLines.find(intersect => intersect.object.visible && intersect.object.name !== CONSTANTS.lineConfig.referenceName && intersect.object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName); const visibleIntersect = intersectsLines.find(intersect => intersect.object.visible && intersect.object.name !== CONSTANTS.lineConfig.referenceName && intersect.object.userData.linePoints[0][3] === CONSTANTS.lineConfig.wallName);
if ((intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && intersectsLines.length > 0 && !isSnapped.current && !ispreSnapped.current) { if ((intersectsPoint.length === 0 || VisibleintersectsPoint === undefined) && intersectsLines.length > 0 && !isSnapped.current && !ispreSnapped.current) {
////////// Clicked on a preexisting Line ////////// ////////// Clicked on a preexisting Line //////////
if (visibleIntersect && intersects) { if (visibleIntersect && intersects) {
let IntersectsPoint = new THREE.Vector3(intersects[0].point.x, 0.01, intersects[0].point.z); let IntersectsPoint = new THREE.Vector3(intersects[0].point.x, 0.01, intersects[0].point.z);
if (isAngleSnapped.current && anglesnappedPoint.current) { if (isAngleSnapped.current && anglesnappedPoint.current) {
IntersectsPoint = anglesnappedPoint.current; IntersectsPoint = anglesnappedPoint.current;
} }
if (visibleIntersect.object instanceof THREE.Mesh) { if (visibleIntersect.object instanceof THREE.Mesh) {
const ThroughPoint = (visibleIntersect.object.geometry.parameters.path).getPoints(CONSTANTS.lineConfig.lineIntersectionPoints); const ThroughPoint = (visibleIntersect.object.geometry.parameters.path).getPoints(CONSTANTS.lineConfig.lineIntersectionPoints);
let intersectionPoint = getClosestIntersection(ThroughPoint, IntersectsPoint); let intersectionPoint = getClosestIntersection(ThroughPoint, IntersectsPoint);
if (intersectionPoint) { if (intersectionPoint) {
const newLines = splitLine(visibleIntersect, intersectionPoint, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, lines, setDeletedLines, floorPlanGroupLine, socket, CONSTANTS.pointConfig.wallOuterColor, CONSTANTS.lineConfig.wallColor, CONSTANTS.lineConfig.wallName); const newLines = splitLine(visibleIntersect, intersectionPoint, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, lines, setDeletedLines, floorPlanGroupLine, socket, CONSTANTS.pointConfig.wallOuterColor, CONSTANTS.lineConfig.wallColor, CONSTANTS.lineConfig.wallName);
setNewLines([newLines[0], newLines[1]]); setNewLines([newLines[0], newLines[1]]);
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), isSnappedUUID.current!, activeLayer, CONSTANTS.lineConfig.wallName,]); (line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), isSnappedUUID.current!, activeLayer, CONSTANTS.lineConfig.wallName,]);
if (line.current.length >= 2 && line.current[0] && line.current[1]) { if (line.current.length >= 2 && line.current[0] && line.current[1]) {
const data = arrayLineToObject(line.current as Types.Line); const data = arrayLineToObject(line.current as Types.Line);
const email = localStorage.getItem('email') const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0]; const organization = (email!.split("@")[1]).split(".")[0];
//REST //REST
// setLine(organization, data.layer!, data.line!, data.type!); // setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET //SOCKET
const input = { const input = {
organization: organization, organization: organization,
layer: data.layer, layer: data.layer,
line: data.line, line: data.line,
type: data.type, type: data.type,
socketId: socket.id socketId: socket.id
} }
socket.emit('v1:Line:create', input); socket.emit('v1:Line:create', input);
setNewLines([newLines[0], newLines[1], line.current]); setNewLines([newLines[0], newLines[1], line.current]);
lines.current.push(line.current as Types.Line); lines.current.push(line.current as Types.Line);
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.wallColor, line.current, floorPlanGroupLine); addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.wallColor, line.current, floorPlanGroupLine);
let lastPoint = line.current[line.current.length - 1]; let lastPoint = line.current[line.current.length - 1];
line.current = [lastPoint]; line.current = [lastPoint];
} }
return; return;
} }
} }
} }
} }
if (intersects && intersects.length > 0) { if (intersects && intersects.length > 0) {
////////// Clicked on a emply place or a point ////////// ////////// Clicked on a emply place or a point //////////
let intersectionPoint = intersects[0].point; let intersectionPoint = intersects[0].point;
if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) { if (isAngleSnapped.current && line.current.length > 0 && anglesnappedPoint.current) {
intersectionPoint = anglesnappedPoint.current; intersectionPoint = anglesnappedPoint.current;
} }
if (isSnapped.current && line.current.length > 0 && snappedPoint.current) { if (isSnapped.current && line.current.length > 0 && snappedPoint.current) {
intersectionPoint = snappedPoint.current; intersectionPoint = snappedPoint.current;
} }
if (ispreSnapped.current && snappedPoint.current) { if (ispreSnapped.current && snappedPoint.current) {
intersectionPoint = snappedPoint.current; intersectionPoint = snappedPoint.current;
} }
if (!isSnapped.current && !ispreSnapped.current) { if (!isSnapped.current && !ispreSnapped.current) {
addPointToScene(intersectionPoint, CONSTANTS.pointConfig.wallOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, CONSTANTS.lineConfig.wallName); addPointToScene(intersectionPoint, CONSTANTS.pointConfig.wallOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, CONSTANTS.lineConfig.wallName);
} else { } else {
ispreSnapped.current = false; ispreSnapped.current = false;
isSnapped.current = false; isSnapped.current = false;
} }
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), isSnappedUUID.current!, activeLayer, CONSTANTS.lineConfig.wallName,]); (line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), isSnappedUUID.current!, activeLayer, CONSTANTS.lineConfig.wallName,]);
if (line.current.length >= 2 && line.current[0] && line.current[1]) { if (line.current.length >= 2 && line.current[0] && line.current[1]) {
const data = arrayLineToObject(line.current as Types.Line); const data = arrayLineToObject(line.current as Types.Line);
const email = localStorage.getItem('email') const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0]; const organization = (email!.split("@")[1]).split(".")[0];
//REST //REST
// setLine(organization, data.layer!, data.line!, data.type!); // setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET //SOCKET
const input = { const input = {
organization: organization, organization: organization,
layer: data.layer, layer: data.layer,
line: data.line, line: data.line,
type: data.type, type: data.type,
socketId: socket.id socketId: socket.id
} }
socket.emit('v1:Line:create', input); socket.emit('v1:Line:create', input);
setNewLines([line.current]) setNewLines([line.current])
lines.current.push(line.current as Types.Line); lines.current.push(line.current as Types.Line);
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.wallColor, line.current, floorPlanGroupLine); addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.wallColor, line.current, floorPlanGroupLine);
let lastPoint = line.current[line.current.length - 1]; let lastPoint = line.current[line.current.length - 1];
line.current = [lastPoint]; line.current = [lastPoint];
} }
if (isSnapped.current) { if (isSnapped.current) {
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line); removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
} }
} }
} }
export default drawWall; export default drawWall;

View File

@@ -1,26 +1,26 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function getClosestIntersection( function getClosestIntersection(
intersects: Types.Vector3Array, intersects: Types.Vector3Array,
point: Types.Vector3 point: Types.Vector3
): Types.Vector3 | null { ): Types.Vector3 | null {
////////// A function that finds which point is closest from the intersects points that is given, Used in finding which point in a line is closest when clicked on a line during drawing ////////// ////////// A function that finds which point is closest from the intersects points that is given, Used in finding which point in a line is closest when clicked on a line during drawing //////////
let closestNewPoint: THREE.Vector3 | null = null; let closestNewPoint: THREE.Vector3 | null = null;
let minDistance = Infinity; let minDistance = Infinity;
for (const intersect of intersects) { for (const intersect of intersects) {
const distance = point.distanceTo(intersect); const distance = point.distanceTo(intersect);
if (distance < minDistance) { if (distance < minDistance) {
minDistance = distance; minDistance = distance;
closestNewPoint = intersect; closestNewPoint = intersect;
} }
} }
return closestNewPoint; return closestNewPoint;
} }
export default getClosestIntersection; export default getClosestIntersection;

View File

@@ -1,86 +1,86 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as turf from '@turf/turf'; import * as turf from '@turf/turf';
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
async function getRoomsFromLines(lines: Types.RefLines) { async function getRoomsFromLines(lines: Types.RefLines) {
const rooms: Types.Rooms = []; const rooms: Types.Rooms = [];
if (lines.current.length > 2) { if (lines.current.length > 2) {
const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => { const linesByLayer = lines.current.reduce((acc: { [key: number]: any[] }, pair) => {
const layer = pair[0][2]; const layer = pair[0][2];
if (!acc[layer]) acc[layer] = []; if (!acc[layer]) acc[layer] = [];
acc[layer].push(pair); acc[layer].push(pair);
return acc; return acc;
}, {}); }, {});
////////// Use turf.polygonize to create polygons from the line points ////////// ////////// Use turf.polygonize to create polygons from the line points //////////
for (const layer in linesByLayer) { for (const layer in linesByLayer) {
let linesInLayer = linesByLayer[layer]; let linesInLayer = linesByLayer[layer];
linesInLayer = linesInLayer.filter(line => line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName); linesInLayer = linesInLayer.filter(line => line[0][3] && line[1][3] === CONSTANTS.lineConfig.wallName);
const result = linesInLayer.map((pair: [THREE.Vector3, string, number, string][]) => const result = linesInLayer.map((pair: [THREE.Vector3, string, number, string][]) =>
pair.map((point) => ({ pair.map((point) => ({
position: [point[0].x, point[0].z], position: [point[0].x, point[0].z],
uuid: point[1] uuid: point[1]
})) }))
); );
const lineFeatures = result.map(line => turf.lineString(line.map(p => p.position))); const lineFeatures = result.map(line => turf.lineString(line.map(p => p.position)));
const polygons = turf.polygonize(turf.featureCollection(lineFeatures)); const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
let union: any[] = []; let union: any[] = [];
polygons.features.forEach((feature) => { polygons.features.forEach((feature) => {
union.push(feature); union.push(feature);
}); });
if (union.length > 1) { if (union.length > 1) {
const unionResult = turf.union(turf.featureCollection(union)); const unionResult = turf.union(turf.featureCollection(union));
if (unionResult?.geometry.type === "MultiPolygon") { if (unionResult?.geometry.type === "MultiPolygon") {
unionResult?.geometry.coordinates.forEach((poly) => { unionResult?.geometry.coordinates.forEach((poly) => {
const Coordinates = poly[0].map(([x, z]) => { const Coordinates = poly[0].map(([x, z]) => {
const matchingPoint = result.flat().find(r => const matchingPoint = result.flat().find(r =>
r.position[0].toFixed(10) === x.toFixed(10) && r.position[0].toFixed(10) === x.toFixed(10) &&
r.position[1].toFixed(10) === z.toFixed(10) r.position[1].toFixed(10) === z.toFixed(10)
); );
return { return {
position: new THREE.Vector3(x, 0, z), position: new THREE.Vector3(x, 0, z),
uuid: matchingPoint ? matchingPoint.uuid : '' uuid: matchingPoint ? matchingPoint.uuid : ''
}; };
}); });
rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) }); rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) });
}); });
} else if (unionResult?.geometry.type === "Polygon") { } else if (unionResult?.geometry.type === "Polygon") {
const Coordinates = unionResult?.geometry.coordinates[0].map(([x, z]) => { const Coordinates = unionResult?.geometry.coordinates[0].map(([x, z]) => {
const matchingPoint = result.flat().find(r => const matchingPoint = result.flat().find(r =>
r.position[0].toFixed(10) === x.toFixed(10) && r.position[0].toFixed(10) === x.toFixed(10) &&
r.position[1].toFixed(10) === z.toFixed(10) r.position[1].toFixed(10) === z.toFixed(10)
); );
return { return {
position: new THREE.Vector3(x, 0, z), position: new THREE.Vector3(x, 0, z),
uuid: matchingPoint ? matchingPoint.uuid : '' uuid: matchingPoint ? matchingPoint.uuid : ''
}; };
}); });
rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) }); rooms.push({ coordinates: Coordinates.reverse(), layer: parseInt(layer) });
} }
} else if (union.length === 1) { } else if (union.length === 1) {
const Coordinates = union[0].geometry.coordinates[0].map(([x, z]: [number, number]) => { const Coordinates = union[0].geometry.coordinates[0].map(([x, z]: [number, number]) => {
const matchingPoint = result.flat().find(r => const matchingPoint = result.flat().find(r =>
r.position[0].toFixed(10) === x.toFixed(10) && r.position[0].toFixed(10) === x.toFixed(10) &&
r.position[1].toFixed(10) === z.toFixed(10) r.position[1].toFixed(10) === z.toFixed(10)
); );
return { return {
position: new THREE.Vector3(x, 0, z), position: new THREE.Vector3(x, 0, z),
uuid: matchingPoint ? matchingPoint.uuid : '' uuid: matchingPoint ? matchingPoint.uuid : ''
}; };
}); });
rooms.push({ coordinates: Coordinates, layer: parseInt(layer) }); rooms.push({ coordinates: Coordinates, layer: parseInt(layer) });
} }
} }
} }
return rooms; return rooms;
} }
export default getRoomsFromLines; export default getRoomsFromLines;

View File

@@ -1,24 +1,24 @@
import * as Types from "../../../../../types/world/worldTypes"; import * as Types from "../../../../../types/world/worldTypes";
export default function arrayLineToObject(array: Types.Line) { export default function arrayLineToObject(array: Types.Line) {
if (!Array.isArray(array)) { if (!Array.isArray(array)) {
return {}; return {};
} }
// Extract common properties from the first point // Extract common properties from the first point
const commonLayer = array[0][2]; const commonLayer = array[0][2];
const commonType = array[0][3]; const commonType = array[0][3];
// Map points into a structured format // Map points into a structured format
const line = array.map(([position, uuid]) => ({ const line = array.map(([position, uuid]) => ({
position, position,
uuid, uuid,
})); }));
// Create the final structured object // Create the final structured object
return { return {
layer: commonLayer, layer: commonLayer,
type: commonType, type: commonType,
line, line,
}; };
} }

View File

@@ -1,30 +1,30 @@
import * as Types from "../../../../../types/world/worldTypes"; import * as Types from "../../../../../types/world/worldTypes";
export default function arrayLinesToObject(array: Array<Types.Line>) { export default function arrayLinesToObject(array: Array<Types.Line>) {
if (!Array.isArray(array)) { if (!Array.isArray(array)) {
return []; return [];
} }
return array.map((lineArray) => { return array.map((lineArray) => {
if (!Array.isArray(lineArray)) { if (!Array.isArray(lineArray)) {
return null; return null;
} }
// Extract common properties from the first point // Extract common properties from the first point
const commonLayer = lineArray[0][2]; const commonLayer = lineArray[0][2];
const commonType = lineArray[0][3]; const commonType = lineArray[0][3];
// Map points into a structured format // Map points into a structured format
const line = lineArray.map(([position, uuid]) => ({ const line = lineArray.map(([position, uuid]) => ({
position, position,
uuid, uuid,
})); }));
// Create the final structured object // Create the final structured object
return { return {
layer: commonLayer, layer: commonLayer,
type: commonType, type: commonType,
line, line,
}; };
}).filter((item) => item !== null); // Filter out invalid entries }).filter((item) => item !== null); // Filter out invalid entries
} }

View File

@@ -1,13 +1,13 @@
import * as THREE from 'three'; import * as THREE from 'three';
export default function objectLineToArray(structuredObject: any) { export default function objectLineToArray(structuredObject: any) {
if (!structuredObject || !structuredObject.line) { if (!structuredObject || !structuredObject.line) {
return []; return [];
} }
// Destructure common properties // Destructure common properties
const { layer, type, line } = structuredObject; const { layer, type, line } = structuredObject;
// Map points back to the original array format // Map points back to the original array format
return line.map(({ position, uuid }: any) => [new THREE.Vector3(position.x, position.y, position.z), uuid, layer, type]); return line.map(({ position, uuid }: any) => [new THREE.Vector3(position.x, position.y, position.z), uuid, layer, type]);
} }

View File

@@ -1,20 +1,20 @@
import * as THREE from 'three'; import * as THREE from 'three';
export default function objectLinesToArray(structuredObjects: any): any { export default function objectLinesToArray(structuredObjects: any): any {
if (!Array.isArray(structuredObjects)) { if (!Array.isArray(structuredObjects)) {
return []; return [];
} }
return structuredObjects.map((structuredObject) => { return structuredObjects.map((structuredObject) => {
if (!structuredObject || !structuredObject.line) { if (!structuredObject || !structuredObject.line) {
return []; return [];
} }
const { layer, type, line } = structuredObject; const { layer, type, line } = structuredObject;
return line.map(({ position, uuid }: any) => { return line.map(({ position, uuid }: any) => {
const vector = new THREE.Vector3(position.x, position.y, position.z); const vector = new THREE.Vector3(position.x, position.y, position.z);
return [vector, uuid, layer, type]; return [vector, uuid, layer, type];
}); });
}); });
} }

View File

@@ -1,48 +1,48 @@
import * as THREE from 'three'; import * as THREE from 'three';
import { Html } from '@react-three/drei'; import { Html } from '@react-three/drei';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { useActiveLayer } from '../../../../store/store'; import { useActiveLayer } from '../../../../store/store';
const ReferenceDistanceText = ({ line }: { line: any }) => { const ReferenceDistanceText = ({ line }: { line: any }) => {
interface TextState { interface TextState {
distance: string; distance: string;
position: THREE.Vector3; position: THREE.Vector3;
userData: any; userData: any;
layer: any; layer: any;
} }
const [text, setTexts] = useState<TextState | null>(null); const [text, setTexts] = useState<TextState | null>(null);
const { activeLayer } = useActiveLayer(); const { activeLayer } = useActiveLayer();
useEffect(() => { useEffect(() => {
if (line) { if (line) {
if (line.parent === null) { if (line.parent === null) {
setTexts(null); setTexts(null);
return; return;
} }
const distance = line.userData.linePoints.cursorPosition.distanceTo(line.userData.linePoints.startPoint); const distance = line.userData.linePoints.cursorPosition.distanceTo(line.userData.linePoints.startPoint);
const midpoint = new THREE.Vector3().addVectors(line.userData.linePoints.cursorPosition, line.userData.linePoints.startPoint).divideScalar(2); const midpoint = new THREE.Vector3().addVectors(line.userData.linePoints.cursorPosition, line.userData.linePoints.startPoint).divideScalar(2);
const newTexts = { const newTexts = {
distance: distance.toFixed(1), distance: distance.toFixed(1),
position: midpoint, position: midpoint,
userData: line, userData: line,
layer: activeLayer layer: activeLayer
}; };
setTexts(newTexts); setTexts(newTexts);
} }
}); });
return ( return (
<group name='Reference_Distance_Text'> <group name='Reference_Distance_Text'>
<mesh> <mesh>
{text !== null && {text !== null &&
< Html transform sprite key={text.distance} userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }}> < Html transform sprite key={text.distance} userData={text.userData} scale={5} position={[text.position.x, 1, text.position.z]} style={{ pointerEvents: 'none' }}>
<div className={`Reference_Distance line-${text.userData.userData}`}>{text.distance} m</div> <div className={`Reference_Distance line-${text.userData.userData}`}>{text.distance} m</div>
</Html> </Html>
} }
</mesh> </mesh>
</group > </group >
); );
}; };
export default ReferenceDistanceText; export default ReferenceDistanceText;

View File

@@ -1,66 +1,66 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function RemoveConnectedLines( function RemoveConnectedLines(
DeletedPointUUID: Types.String, DeletedPointUUID: Types.String,
floorPlanGroupLine: Types.RefGroup, floorPlanGroupLine: Types.RefGroup,
floorPlanGroupPoint: Types.RefGroup, floorPlanGroupPoint: Types.RefGroup,
setDeletedLines: any, setDeletedLines: any,
lines: Types.RefLines, lines: Types.RefLines,
): void { ): void {
////////// Check if any and how many lines are connected to the deleted point ////////// ////////// Check if any and how many lines are connected to the deleted point //////////
const removableLines: THREE.Mesh[] = []; const removableLines: THREE.Mesh[] = [];
const connectedpoints: string[] = []; const connectedpoints: string[] = [];
const removedLinePoints: [number, string, number][][] = []; // Array to hold linePoints of removed lines const removedLinePoints: [number, string, number][][] = []; // Array to hold linePoints of removed lines
floorPlanGroupLine.current.children.forEach((line) => { floorPlanGroupLine.current.children.forEach((line) => {
const linePoints = line.userData.linePoints as [number, string, number][]; const linePoints = line.userData.linePoints as [number, string, number][];
const uuid1 = linePoints[0][1]; const uuid1 = linePoints[0][1];
const uuid2 = linePoints[1][1]; const uuid2 = linePoints[1][1];
if (uuid1 === DeletedPointUUID || uuid2 === DeletedPointUUID) { if (uuid1 === DeletedPointUUID || uuid2 === DeletedPointUUID) {
connectedpoints.push(uuid1 === DeletedPointUUID ? uuid2 : uuid1); connectedpoints.push(uuid1 === DeletedPointUUID ? uuid2 : uuid1);
removableLines.push(line as THREE.Mesh); removableLines.push(line as THREE.Mesh);
removedLinePoints.push(linePoints); removedLinePoints.push(linePoints);
} }
}); });
if (removableLines.length > 0) { if (removableLines.length > 0) {
removableLines.forEach((line) => { removableLines.forEach((line) => {
lines.current = lines.current.filter(item => item !== line.userData.linePoints); lines.current = lines.current.filter(item => item !== line.userData.linePoints);
(<any>line.material).dispose(); (<any>line.material).dispose();
(<any>line.geometry).dispose(); (<any>line.geometry).dispose();
floorPlanGroupLine.current.remove(line); floorPlanGroupLine.current.remove(line);
}); });
} }
setDeletedLines(removedLinePoints) setDeletedLines(removedLinePoints)
////////// Check and Remove point that are no longer connected to any lines ////////// ////////// Check and Remove point that are no longer connected to any lines //////////
connectedpoints.forEach((pointUUID) => { connectedpoints.forEach((pointUUID) => {
let isConnected = false; let isConnected = false;
floorPlanGroupLine.current.children.forEach((line) => { floorPlanGroupLine.current.children.forEach((line) => {
const linePoints = line.userData.linePoints as [number, string, number][]; const linePoints = line.userData.linePoints as [number, string, number][];
const uuid1 = linePoints[0][1]; const uuid1 = linePoints[0][1];
const uuid2 = linePoints[1][1]; const uuid2 = linePoints[1][1];
if (uuid1 === pointUUID || uuid2 === pointUUID) { if (uuid1 === pointUUID || uuid2 === pointUUID) {
isConnected = true; isConnected = true;
} }
}); });
if (!isConnected) { if (!isConnected) {
floorPlanGroupPoint.current.children.forEach((point: any) => { floorPlanGroupPoint.current.children.forEach((point: any) => {
if (point.uuid === pointUUID) { if (point.uuid === pointUUID) {
(<any>point.material).dispose(); (<any>point.material).dispose();
(<any>point.geometry).dispose(); (<any>point.geometry).dispose();
floorPlanGroupPoint.current.remove(point); floorPlanGroupPoint.current.remove(point);
} }
}); });
} }
}); });
} }
export default RemoveConnectedLines; export default RemoveConnectedLines;

View File

@@ -1,22 +1,22 @@
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function removeReferenceLine( function removeReferenceLine(
floorPlanGroup: Types.RefGroup, floorPlanGroup: Types.RefGroup,
ReferenceLineMesh: Types.RefMesh, ReferenceLineMesh: Types.RefMesh,
LineCreated: Types.RefBoolean, LineCreated: Types.RefBoolean,
line: Types.RefLine line: Types.RefLine
): void { ): void {
////////// Removes Dangling reference line if the draw mode is ended or any other case ////////// ////////// Removes Dangling reference line if the draw mode is ended or any other case //////////
line.current = []; line.current = [];
if (ReferenceLineMesh.current) { if (ReferenceLineMesh.current) {
(<any>ReferenceLineMesh.current.material).dispose(); (<any>ReferenceLineMesh.current.material).dispose();
(<any>ReferenceLineMesh.current.geometry).dispose(); (<any>ReferenceLineMesh.current.geometry).dispose();
floorPlanGroup.current.remove(ReferenceLineMesh.current); floorPlanGroup.current.remove(ReferenceLineMesh.current);
LineCreated.current = false; LineCreated.current = false;
ReferenceLineMesh.current = undefined; ReferenceLineMesh.current = undefined;
} }
} }
export default removeReferenceLine; export default removeReferenceLine;

View File

@@ -1,124 +1,124 @@
import * as THREE from 'three'; import * as THREE from 'three';
import addLineToScene from './addLineToScene'; import addLineToScene from './addLineToScene';
import addPointToScene from '../points/addPointToScene'; import addPointToScene from '../points/addPointToScene';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import arrayLineToObject from '../lines/lineConvertions/arrayLineToObject'; import arrayLineToObject from '../lines/lineConvertions/arrayLineToObject';
import { Socket } from 'socket.io-client'; import { Socket } from 'socket.io-client';
// import { deleteLineApi } from '../../../../services/factoryBuilder/lines/deleteLineApi'; // import { deleteLineApi } from '../../../../services/factoryBuilder/lines/deleteLineApi';
// import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi'; // import { setLine } from '../../../../services/factoryBuilder/lines/setLineApi';
function splitLine( function splitLine(
visibleIntersect: Types.IntersectionEvent, visibleIntersect: Types.IntersectionEvent,
intersectionPoint: Types.Vector3, intersectionPoint: Types.Vector3,
currentLayerPoint: Types.RefMeshArray, currentLayerPoint: Types.RefMeshArray,
floorPlanGroupPoint: Types.RefGroup, floorPlanGroupPoint: Types.RefGroup,
dragPointControls: Types.RefDragControl, dragPointControls: Types.RefDragControl,
isSnappedUUID: Types.RefString, isSnappedUUID: Types.RefString,
lines: Types.RefLines, lines: Types.RefLines,
setDeletedLines: any, setDeletedLines: any,
floorPlanGroupLine: { current: THREE.Group }, floorPlanGroupLine: { current: THREE.Group },
socket: Socket<any>, socket: Socket<any>,
pointColor: Types.String, pointColor: Types.String,
lineColor: Types.String, lineColor: Types.String,
lineType: Types.String, lineType: Types.String,
): [Types.Line, Types.Line] { ): [Types.Line, Types.Line] {
////////// Removing the clicked line and splitting it with the clicked position adding a new point and two new lines ////////// ////////// Removing the clicked line and splitting it with the clicked position adding a new point and two new lines //////////
((visibleIntersect.object as any).material).dispose(); ((visibleIntersect.object as any).material).dispose();
((visibleIntersect.object as any).geometry).dispose(); ((visibleIntersect.object as any).geometry).dispose();
floorPlanGroupLine.current.remove(visibleIntersect.object); floorPlanGroupLine.current.remove(visibleIntersect.object);
setDeletedLines([visibleIntersect.object.userData.linePoints]); setDeletedLines([visibleIntersect.object.userData.linePoints]);
const email = localStorage.getItem('email') const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0]; const organization = (email!.split("@")[1]).split(".")[0];
//REST //REST
// deleteLineApi( // deleteLineApi(
// organization, // organization,
// [ // [
// { "uuid": visibleIntersect.object.userData.linePoints[0][1] }, // { "uuid": visibleIntersect.object.userData.linePoints[0][1] },
// { "uuid": visibleIntersect.object.userData.linePoints[1][1] } // { "uuid": visibleIntersect.object.userData.linePoints[1][1] }
// ] // ]
// ) // )
//SOCKET //SOCKET
const data = { const data = {
organization: organization, organization: organization,
line: [ line: [
{ "uuid": visibleIntersect.object.userData.linePoints[0][1] }, { "uuid": visibleIntersect.object.userData.linePoints[0][1] },
{ "uuid": visibleIntersect.object.userData.linePoints[1][1] } { "uuid": visibleIntersect.object.userData.linePoints[1][1] }
], ],
socketId: socket.id socketId: socket.id
} }
socket.emit('v1:Line:delete', data); socket.emit('v1:Line:delete', data);
const point = addPointToScene(intersectionPoint, pointColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, lineType); const point = addPointToScene(intersectionPoint, pointColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, isSnappedUUID, lineType);
const oldLinePoints = visibleIntersect.object.userData.linePoints; const oldLinePoints = visibleIntersect.object.userData.linePoints;
lines.current = lines.current.filter(item => item !== oldLinePoints); lines.current = lines.current.filter(item => item !== oldLinePoints);
const clickedPoint: Types.Point = [ const clickedPoint: Types.Point = [
new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z),
point.uuid, point.uuid,
oldLinePoints[0][2], oldLinePoints[0][2],
lineType lineType
]; ];
const start = oldLinePoints[0]; const start = oldLinePoints[0];
const end = oldLinePoints[1]; const end = oldLinePoints[1];
const newLine1: Types.Line = [start, clickedPoint]; const newLine1: Types.Line = [start, clickedPoint];
const newLine2: Types.Line = [clickedPoint, end]; const newLine2: Types.Line = [clickedPoint, end];
const line1 = arrayLineToObject(newLine1); const line1 = arrayLineToObject(newLine1);
const line2 = arrayLineToObject(newLine2); const line2 = arrayLineToObject(newLine2);
//REST //REST
// setLine(organization, line1.layer!, line1.line!, line1.type!); // setLine(organization, line1.layer!, line1.line!, line1.type!);
//SOCKET //SOCKET
const input1 = { const input1 = {
organization: organization, organization: organization,
layer: line1.layer, layer: line1.layer,
line: line1.line, line: line1.line,
type: line1.type, type: line1.type,
socketId: socket.id socketId: socket.id
} }
socket.emit('v1:Line:create', input1); socket.emit('v1:Line:create', input1);
//REST //REST
// setLine(organization, line2.layer!, line2.line!, line2.type!); // setLine(organization, line2.layer!, line2.line!, line2.type!);
//SOCKET //SOCKET
const input2 = { const input2 = {
organization: organization, organization: organization,
layer: line2.layer, layer: line2.layer,
line: line2.line, line: line2.line,
type: line2.type, type: line2.type,
socketId: socket.id socketId: socket.id
} }
socket.emit('v1:Line:create', input2); socket.emit('v1:Line:create', input2);
lines.current.push(newLine1, newLine2); lines.current.push(newLine1, newLine2);
addLineToScene(newLine1[0][0], newLine1[1][0], lineColor, newLine1, floorPlanGroupLine); addLineToScene(newLine1[0][0], newLine1[1][0], lineColor, newLine1, floorPlanGroupLine);
addLineToScene(newLine2[0][0], newLine2[1][0], lineColor, newLine2, floorPlanGroupLine); addLineToScene(newLine2[0][0], newLine2[1][0], lineColor, newLine2, floorPlanGroupLine);
return [newLine1, newLine2]; return [newLine1, newLine2];
} }
export default splitLine; export default splitLine;

View File

@@ -1,42 +1,42 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function updateDistanceText( function updateDistanceText(
scene: THREE.Scene, scene: THREE.Scene,
floorPlanGroupLine: Types.RefGroup, floorPlanGroupLine: Types.RefGroup,
affectedLines: Types.NumberArray affectedLines: Types.NumberArray
): void { ): void {
////////// Updating the Distance Texts of the lines that are affected during drag ////////// ////////// Updating the Distance Texts of the lines that are affected during drag //////////
const DistanceGroup = scene.children.find((child) => child.name === "Distance_Text") as THREE.Group; const DistanceGroup = scene.children.find((child) => child.name === "Distance_Text") as THREE.Group;
affectedLines.forEach((lineIndex) => { affectedLines.forEach((lineIndex) => {
const mesh = floorPlanGroupLine.current.children[lineIndex] as THREE.Mesh; const mesh = floorPlanGroupLine.current.children[lineIndex] as THREE.Mesh;
const linePoints = mesh.userData.linePoints; const linePoints = mesh.userData.linePoints;
if (linePoints) { if (linePoints) {
const distance = linePoints[0][0].distanceTo(linePoints[1][0]).toFixed(1); const distance = linePoints[0][0].distanceTo(linePoints[1][0]).toFixed(1);
const position = new THREE.Vector3().addVectors(linePoints[0][0], linePoints[1][0]).divideScalar(2); const position = new THREE.Vector3().addVectors(linePoints[0][0], linePoints[1][0]).divideScalar(2);
if (!DistanceGroup || !linePoints) { if (!DistanceGroup || !linePoints) {
return return
} }
DistanceGroup.children.forEach((text) => { DistanceGroup.children.forEach((text) => {
const textMesh = text as THREE.Mesh; const textMesh = text as THREE.Mesh;
if (textMesh.userData[0][1] === linePoints[0][1] && textMesh.userData[1][1] === linePoints[1][1]) { if (textMesh.userData[0][1] === linePoints[0][1] && textMesh.userData[1][1] === linePoints[1][1]) {
textMesh.position.set(position.x, 1, position.z); textMesh.position.set(position.x, 1, position.z);
const className = `Distance line-${textMesh.userData[0][1]}_${textMesh.userData[1][1]}_${linePoints[0][2]}`; const className = `Distance line-${textMesh.userData[0][1]}_${textMesh.userData[1][1]}_${linePoints[0][2]}`;
const element = document.getElementsByClassName(className)[0] as HTMLElement; const element = document.getElementsByClassName(className)[0] as HTMLElement;
if (element) { if (element) {
element.innerHTML = `${distance} m`; element.innerHTML = `${distance} m`;
} }
} }
}); });
} }
}); });
} }
export default updateDistanceText; export default updateDistanceText;

View File

@@ -1,24 +1,24 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
function updateLines( function updateLines(
floorPlanGroupLine: Types.RefGroup, floorPlanGroupLine: Types.RefGroup,
affectedLines: Types.NumberArray affectedLines: Types.NumberArray
): void { ): void {
////////// Updating the positions for the affected lines only based on the updated positions ////////// ////////// Updating the positions for the affected lines only based on the updated positions //////////
affectedLines.forEach((lineIndex) => { affectedLines.forEach((lineIndex) => {
const mesh = floorPlanGroupLine.current.children[lineIndex] as Types.Mesh; const mesh = floorPlanGroupLine.current.children[lineIndex] as Types.Mesh;
const linePoints = mesh.userData.linePoints as Types.Line; const linePoints = mesh.userData.linePoints as Types.Line;
if (linePoints) { if (linePoints) {
const newPositions = linePoints.map(([pos]) => pos); const newPositions = linePoints.map(([pos]) => pos);
const newPath = new THREE.CatmullRomCurve3(newPositions); const newPath = new THREE.CatmullRomCurve3(newPositions);
mesh.geometry.dispose(); mesh.geometry.dispose();
mesh.geometry = new THREE.TubeGeometry(newPath, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false); mesh.geometry = new THREE.TubeGeometry(newPath, CONSTANTS.lineConfig.tubularSegments, CONSTANTS.lineConfig.radius, CONSTANTS.lineConfig.radialSegments, false);
} }
}); });
} }
export default updateLines; export default updateLines;

View File

@@ -1,32 +1,32 @@
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function updateLinesPositions( function updateLinesPositions(
DragedPoint: Types.Mesh | { uuid: string, position: Types.Vector3 }, DragedPoint: Types.Mesh | { uuid: string, position: Types.Vector3 },
lines: Types.RefLines lines: Types.RefLines
): Types.NumberArray { ): Types.NumberArray {
////////// Updating the lines position based on the dragged point's position ////////// ////////// Updating the lines position based on the dragged point's position //////////
const objectUUID = DragedPoint.uuid; const objectUUID = DragedPoint.uuid;
const affectedLines: Types.NumberArray = []; const affectedLines: Types.NumberArray = [];
lines.current.forEach((line, index) => { lines.current.forEach((line, index) => {
let lineUpdated = false; let lineUpdated = false;
line.forEach((point) => { line.forEach((point) => {
const [position, uuid] = point; const [position, uuid] = point;
if (uuid === objectUUID) { if (uuid === objectUUID) {
position.x = DragedPoint.position.x; position.x = DragedPoint.position.x;
position.y = 0.01; position.y = 0.01;
position.z = DragedPoint.position.z; position.z = DragedPoint.position.z;
lineUpdated = true; lineUpdated = true;
} }
}); });
if (lineUpdated) { if (lineUpdated) {
affectedLines.push(index); affectedLines.push(index);
} }
}); });
return affectedLines; return affectedLines;
} }
export default updateLinesPositions; export default updateLinesPositions;

View File

@@ -1,18 +1,18 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function vectorizeLinesCurrent( function vectorizeLinesCurrent(
lines: Types.Lines lines: Types.Lines
): Types.Lines { ): Types.Lines {
////////// Storing a vector3 array in localstorage makes the prototype functions go puff. This function brings back the prototype functions by creating it again ////////// ////////// Storing a vector3 array in localstorage makes the prototype functions go puff. This function brings back the prototype functions by creating it again //////////
return lines.map((line) => { return lines.map((line) => {
const p1: Types.Point = [new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z), line[0][1], line[0][2], line[0][3],]; const p1: Types.Point = [new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z), line[0][1], line[0][2], line[0][3],];
const p2: Types.Point = [new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z), line[1][1], line[0][2], line[1][3],]; const p2: Types.Point = [new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z), line[1][1], line[0][2], line[1][3],];
return [p1, p2]; return [p1, p2];
}); });
} }
export default vectorizeLinesCurrent; export default vectorizeLinesCurrent;

View File

@@ -1,54 +1,54 @@
import * as THREE from 'three'; import * as THREE from 'three';
import updateReferencePolesheight from './updateReferencePolesheight'; import updateReferencePolesheight from './updateReferencePolesheight';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function addAndUpdateReferencePillar( function addAndUpdateReferencePillar(
raycaster: THREE.Raycaster, raycaster: THREE.Raycaster,
floorGroup: Types.RefGroup, floorGroup: Types.RefGroup,
referencePole: Types.RefMesh referencePole: Types.RefMesh
): void { ): void {
////////// Find Pillars position and scale based on the pointer interaction ////////// ////////// Find Pillars position and scale based on the pointer interaction //////////
let Roofs = raycaster.intersectObjects(floorGroup.current.children, true); let Roofs = raycaster.intersectObjects(floorGroup.current.children, true);
const intersected = Roofs.find(intersect => intersect.object.name.includes("Roof") || intersect.object.name.includes("Floor")); const intersected = Roofs.find(intersect => intersect.object.name.includes("Roof") || intersect.object.name.includes("Floor"));
if (intersected) { if (intersected) {
const intersectionPoint = intersected.point; const intersectionPoint = intersected.point;
raycaster.ray.origin.copy(intersectionPoint); raycaster.ray.origin.copy(intersectionPoint);
raycaster.ray.direction.set(0, -1, 0); raycaster.ray.direction.set(0, -1, 0);
const belowIntersections = raycaster.intersectObjects(floorGroup.current.children, true); const belowIntersections = raycaster.intersectObjects(floorGroup.current.children, true);
const validIntersections = belowIntersections.filter(intersect => intersect.object.name.includes("Floor")); const validIntersections = belowIntersections.filter(intersect => intersect.object.name.includes("Floor"));
let distance: Types.Number; let distance: Types.Number;
if (validIntersections.length > 1) { if (validIntersections.length > 1) {
let valid = validIntersections.find(intersectedBelow => intersected.point.distanceTo(intersectedBelow.point) > 3); let valid = validIntersections.find(intersectedBelow => intersected.point.distanceTo(intersectedBelow.point) > 3);
if (valid) { if (valid) {
updateReferencePolesheight(intersectionPoint, valid.distance, referencePole, floorGroup); updateReferencePolesheight(intersectionPoint, valid.distance, referencePole, floorGroup);
} else { } else {
const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z); const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z);
distance = intersected.point.distanceTo(belowPoint); distance = intersected.point.distanceTo(belowPoint);
if (distance > 3) { if (distance > 3) {
updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup); updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup);
} }
} }
} else { } else {
const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z); const belowPoint = new THREE.Vector3(intersectionPoint.x, 0, intersectionPoint.z);
distance = intersected.point.distanceTo(belowPoint); distance = intersected.point.distanceTo(belowPoint);
if (distance > 3) { if (distance > 3) {
updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup); updateReferencePolesheight(intersectionPoint, distance, referencePole, floorGroup);
} }
} }
} else { } else {
if (referencePole.current) { if (referencePole.current) {
(<any>referencePole.current.material).dispose(); (<any>referencePole.current.material).dispose();
(<any>referencePole.current.geometry).dispose(); (<any>referencePole.current.geometry).dispose();
floorGroup.current.remove(referencePole.current); floorGroup.current.remove(referencePole.current);
referencePole.current = null; referencePole.current = null;
} }
} }
} }
export default addAndUpdateReferencePillar; export default addAndUpdateReferencePillar;

View File

@@ -1,24 +1,24 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function addPillar( function addPillar(
referencePole: Types.RefMesh, referencePole: Types.RefMesh,
floorGroup: Types.RefGroup floorGroup: Types.RefGroup
): void { ): void {
////////// Add Pillars to the scene based on the reference. current poles position and scale ////////// ////////// Add Pillars to the scene based on the reference. current poles position and scale //////////
if (referencePole.current) { if (referencePole.current) {
let pole: THREE.Mesh; let pole: THREE.Mesh;
const geometry = referencePole.current.userData.geometry.clone(); const geometry = referencePole.current.userData.geometry.clone();
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.columnConfig.defaultColor }); const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.columnConfig.defaultColor });
pole = new THREE.Mesh(geometry, material); pole = new THREE.Mesh(geometry, material);
pole.rotateX(Math.PI / 2); pole.rotateX(Math.PI / 2);
pole.name = "Pole"; pole.name = "Pole";
pole.position.set(referencePole.current.userData.position.x, referencePole.current.userData.position.y, referencePole.current.userData.position.z); pole.position.set(referencePole.current.userData.position.x, referencePole.current.userData.position.y, referencePole.current.userData.position.z);
floorGroup.current.add(pole); floorGroup.current.add(pole);
} }
} }
export default addPillar; export default addPillar;

View File

@@ -1,34 +1,34 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function DeletableHoveredPillar( function DeletableHoveredPillar(
state: Types.ThreeState, state: Types.ThreeState,
floorGroup: Types.RefGroup, floorGroup: Types.RefGroup,
hoveredDeletablePillar: Types.RefMesh hoveredDeletablePillar: Types.RefMesh
): void { ): void {
////////// Altering the color of the hovered Pillar during the Deletion time ////////// ////////// Altering the color of the hovered Pillar during the Deletion time //////////
const intersects = state.raycaster.intersectObjects(floorGroup.current.children, true); const intersects = state.raycaster.intersectObjects(floorGroup.current.children, true);
const poleIntersect = intersects.find(intersect => intersect.object.name === "Pole"); const poleIntersect = intersects.find(intersect => intersect.object.name === "Pole");
if (poleIntersect) { if (poleIntersect) {
if (poleIntersect.object.name !== "Pole") { if (poleIntersect.object.name !== "Pole") {
return; return;
} }
if (hoveredDeletablePillar.current) { if (hoveredDeletablePillar.current) {
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black"); (hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black");
hoveredDeletablePillar.current = undefined; hoveredDeletablePillar.current = undefined;
} }
hoveredDeletablePillar.current = poleIntersect.object as THREE.Mesh; // Type assertion hoveredDeletablePillar.current = poleIntersect.object as THREE.Mesh; // Type assertion
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("red"); (hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("red");
} else { } else {
if (hoveredDeletablePillar.current) { if (hoveredDeletablePillar.current) {
(hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black"); (hoveredDeletablePillar.current.material as THREE.MeshStandardMaterial).emissive = new THREE.Color("black");
hoveredDeletablePillar.current = undefined; hoveredDeletablePillar.current = undefined;
} }
} }
} }
export default DeletableHoveredPillar; export default DeletableHoveredPillar;

View File

@@ -1,21 +1,21 @@
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function DeletePillar( function DeletePillar(
hoveredDeletablePillar: Types.RefMesh, hoveredDeletablePillar: Types.RefMesh,
floorGroup: Types.RefGroup floorGroup: Types.RefGroup
): void { ): void {
////////// Deleting the hovered Pillar from the itemsGroup ////////// ////////// Deleting the hovered Pillar from the itemsGroup //////////
if (hoveredDeletablePillar.current) { if (hoveredDeletablePillar.current) {
(<any>hoveredDeletablePillar.current.material).dispose(); (<any>hoveredDeletablePillar.current.material).dispose();
(<any>hoveredDeletablePillar.current.geometry).dispose(); (<any>hoveredDeletablePillar.current.geometry).dispose();
floorGroup.current.remove(hoveredDeletablePillar.current); floorGroup.current.remove(hoveredDeletablePillar.current);
toast.success("Pillar Removed!"); toast.success("Pillar Removed!");
hoveredDeletablePillar.current = undefined; hoveredDeletablePillar.current = undefined;
} }
} }
export default DeletePillar; export default DeletePillar;

View File

@@ -1,40 +1,40 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function updateReferencePolesheight( function updateReferencePolesheight(
intersectionPoint: Types.Vector3, intersectionPoint: Types.Vector3,
distance: Types.Number, distance: Types.Number,
referencePole: Types.RefMesh, referencePole: Types.RefMesh,
floorGroup: Types.RefGroup floorGroup: Types.RefGroup
): void { ): void {
////////// Add a Reference Pillar and update its position and scale based on the pointer interaction ////////// ////////// Add a Reference Pillar and update its position and scale based on the pointer interaction //////////
if (referencePole.current) { if (referencePole.current) {
(<any>referencePole.current.material).dispose(); (<any>referencePole.current.material).dispose();
(<any>referencePole.current.geometry).dispose(); (<any>referencePole.current.geometry).dispose();
floorGroup.current.remove(referencePole.current); floorGroup.current.remove(referencePole.current);
referencePole.current.geometry.dispose(); referencePole.current.geometry.dispose();
} }
const shape = new THREE.Shape(); const shape = new THREE.Shape();
shape.moveTo(0.5, 0); shape.moveTo(0.5, 0);
shape.absarc(0, 0, 0.5, 0, 2 * Math.PI, false); shape.absarc(0, 0, 0.5, 0, 2 * Math.PI, false);
const extrudeSettings = { const extrudeSettings = {
depth: distance, depth: distance,
bevelEnabled: false, bevelEnabled: false,
}; };
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const material = new THREE.MeshBasicMaterial({ color: "green", transparent: true, opacity: 0.5 }); const material = new THREE.MeshBasicMaterial({ color: "green", transparent: true, opacity: 0.5 });
referencePole.current = new THREE.Mesh(geometry, material); referencePole.current = new THREE.Mesh(geometry, material);
referencePole.current.rotateX(Math.PI / 2); referencePole.current.rotateX(Math.PI / 2);
referencePole.current.position.set(intersectionPoint.x, intersectionPoint.y - 0.01, intersectionPoint.z); referencePole.current.position.set(intersectionPoint.x, intersectionPoint.y - 0.01, intersectionPoint.z);
referencePole.current.userData = { geometry: geometry, distance: distance, position: { x: intersectionPoint.x, y: intersectionPoint.y - 0.01, z: intersectionPoint.z } }; referencePole.current.userData = { geometry: geometry, distance: distance, position: { x: intersectionPoint.x, y: intersectionPoint.y - 0.01, z: intersectionPoint.z } };
floorGroup.current.add(referencePole.current); floorGroup.current.add(referencePole.current);
} }
export default updateReferencePolesheight; export default updateReferencePolesheight;

View File

@@ -1,65 +1,65 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function addPointToScene( function addPointToScene(
position: Types.Vector3, position: Types.Vector3,
colour: Types.Color, colour: Types.Color,
currentLayerPoint: Types.RefMeshArray, currentLayerPoint: Types.RefMeshArray,
floorPlanGroupPoint: Types.RefGroup, floorPlanGroupPoint: Types.RefGroup,
dragPointControls: Types.RefDragControl | undefined, dragPointControls: Types.RefDragControl | undefined,
uuid: Types.RefString | undefined, uuid: Types.RefString | undefined,
Type: Types.String Type: Types.String
): Types.Mesh { ): Types.Mesh {
////////// A function that creates and adds a cube (point) with an outline based on the position and colour given as params, It also updates the drag controls objects and sets the box uuid in uuid.current ////////// ////////// A function that creates and adds a cube (point) with an outline based on the position and colour given as params, It also updates the drag controls objects and sets the box uuid in uuid.current //////////
const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale); const geometry = new THREE.BoxGeometry(...CONSTANTS.pointConfig.boxScale);
const material = new THREE.ShaderMaterial({ const material = new THREE.ShaderMaterial({
uniforms: { uniforms: {
uColor: { value: new THREE.Color(colour) }, // Blue color for the border uColor: { value: new THREE.Color(colour) }, // Blue color for the border
uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square uInnerColor: { value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor) }, // White color for the inner square
}, },
vertexShader: ` vertexShader: `
varying vec2 vUv; varying vec2 vUv;
void main() { void main() {
vUv = uv; vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
} }
`, `,
fragmentShader: ` fragmentShader: `
varying vec2 vUv; varying vec2 vUv;
uniform vec3 uColor; uniform vec3 uColor;
uniform vec3 uInnerColor; uniform vec3 uInnerColor;
void main() { void main() {
// Define the size of the white square as a proportion of the face // Define the size of the white square as a proportion of the face
float borderThickness = 0.2; // Adjust this value for border thickness float borderThickness = 0.2; // Adjust this value for border thickness
if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness && if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness &&
vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) { vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) {
gl_FragColor = vec4(uInnerColor, 1.0); // White inner square gl_FragColor = vec4(uInnerColor, 1.0); // White inner square
} else { } else {
gl_FragColor = vec4(uColor, 1.0); // Blue border gl_FragColor = vec4(uColor, 1.0); // Blue border
} }
} }
`, `,
}); });
const point = new THREE.Mesh(geometry, material); const point = new THREE.Mesh(geometry, material);
point.name = "point"; point.name = "point";
point.userData = { type: Type, color: colour }; point.userData = { type: Type, color: colour };
point.position.set(position.x, 0.01, position.z); point.position.set(position.x, 0.01, position.z);
currentLayerPoint.current.push(point); currentLayerPoint.current.push(point);
floorPlanGroupPoint.current.add(point); floorPlanGroupPoint.current.add(point);
if (uuid) { if (uuid) {
uuid.current = point.uuid; uuid.current = point.uuid;
} }
if (dragPointControls) { if (dragPointControls) {
dragPointControls.current!.objects = currentLayerPoint.current; dragPointControls.current!.objects = currentLayerPoint.current;
} }
return point; return point;
} }
export default addPointToScene; export default addPointToScene;

View File

@@ -1,57 +1,57 @@
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import RemoveConnectedLines from "../lines/removeConnectedLines"; import RemoveConnectedLines from "../lines/removeConnectedLines";
// import { deletePointApi } from "../../../../services/factoryBuilder/lines/deletePointApi"; // import { deletePointApi } from "../../../../services/factoryBuilder/lines/deletePointApi";
import { Socket } from "socket.io-client"; import { Socket } from "socket.io-client";
function deletePoint( function deletePoint(
hoveredDeletablePoint: Types.RefMesh, hoveredDeletablePoint: Types.RefMesh,
onlyFloorlines: Types.RefOnlyFloorLines, onlyFloorlines: Types.RefOnlyFloorLines,
floorPlanGroupPoint: Types.RefGroup, floorPlanGroupPoint: Types.RefGroup,
floorPlanGroupLine: Types.RefGroup, floorPlanGroupLine: Types.RefGroup,
lines: Types.RefLines, lines: Types.RefLines,
setDeletedLines: any, setDeletedLines: any,
socket: Socket<any> socket: Socket<any>
): void { ): void {
////////// Deleting a Point and the lines that are connected to it ////////// ////////// Deleting a Point and the lines that are connected to it //////////
if (!hoveredDeletablePoint.current) { if (!hoveredDeletablePoint.current) {
return; return;
} }
(<any>hoveredDeletablePoint.current.material).dispose(); (<any>hoveredDeletablePoint.current.material).dispose();
(<any>hoveredDeletablePoint.current.geometry).dispose(); (<any>hoveredDeletablePoint.current.geometry).dispose();
floorPlanGroupPoint.current.remove(hoveredDeletablePoint.current); floorPlanGroupPoint.current.remove(hoveredDeletablePoint.current);
const DeletedPointUUID = hoveredDeletablePoint.current.uuid; const DeletedPointUUID = hoveredDeletablePoint.current.uuid;
const email = localStorage.getItem('email') const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0]; const organization = (email!.split("@")[1]).split(".")[0];
//REST //REST
// deletePointApi(organization, DeletedPointUUID); // deletePointApi(organization, DeletedPointUUID);
//SOCKET //SOCKET
const data = { const data = {
organization: organization, organization: organization,
uuid: DeletedPointUUID, uuid: DeletedPointUUID,
socketId: socket.id socketId: socket.id
} }
socket.emit('v1:Line:delete:point', data); socket.emit('v1:Line:delete:point', data);
////////// Update onlyFloorlines.current to remove references to the deleted point ////////// ////////// Update onlyFloorlines.current to remove references to the deleted point //////////
onlyFloorlines.current = onlyFloorlines.current.map(floorline => onlyFloorlines.current = onlyFloorlines.current.map(floorline =>
floorline.filter(line => line[0][1] !== DeletedPointUUID && line[1][1] !== DeletedPointUUID) floorline.filter(line => line[0][1] !== DeletedPointUUID && line[1][1] !== DeletedPointUUID)
).filter(floorline => floorline.length > 0); ).filter(floorline => floorline.length > 0);
RemoveConnectedLines(DeletedPointUUID, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, lines); RemoveConnectedLines(DeletedPointUUID, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, lines);
toast.success("Point Removed!"); toast.success("Point Removed!");
} }
export default deletePoint; export default deletePoint;

View File

@@ -1,44 +1,44 @@
import * as THREE from "three"; import * as THREE from "three";
import * as Types from "../../../../types/world/worldTypes" import * as Types from "../../../../types/world/worldTypes"
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
import updateLinesPositions from "../lines/updateLinesPositions"; import updateLinesPositions from "../lines/updateLinesPositions";
import updateLines from "../lines/updateLines"; import updateLines from "../lines/updateLines";
import updateDistanceText from "../lines/updateDistanceText"; import updateDistanceText from "../lines/updateDistanceText";
import updateFloorLines from "../floors/updateFloorLines"; import updateFloorLines from "../floors/updateFloorLines";
function DragPoint( function DragPoint(
event: Types.IntersectionEvent, event: Types.IntersectionEvent,
floorPlanGroupPoint: Types.RefGroup, floorPlanGroupPoint: Types.RefGroup,
floorPlanGroupLine: Types.RefGroup, floorPlanGroupLine: Types.RefGroup,
scene: THREE.Scene, scene: THREE.Scene,
lines: Types.RefLines, lines: Types.RefLines,
onlyFloorlines: Types.RefOnlyFloorLines onlyFloorlines: Types.RefOnlyFloorLines
): void { ): void {
////////// Calling the line updation of the affected lines and Snapping of the point during the drag ////////// ////////// Calling the line updation of the affected lines and Snapping of the point during the drag //////////
const snapThreshold = CONSTANTS.pointConfig.snappingThreshold; const snapThreshold = CONSTANTS.pointConfig.snappingThreshold;
const DragedPoint = event.object as Types.Mesh; const DragedPoint = event.object as Types.Mesh;
floorPlanGroupPoint.current.children.forEach((point) => { floorPlanGroupPoint.current.children.forEach((point) => {
let canSnap = let canSnap =
((DragedPoint.userData.type === CONSTANTS.lineConfig.wallName) && (point.userData.type === CONSTANTS.lineConfig.wallName || point.userData.type === CONSTANTS.lineConfig.floorName)) || ((DragedPoint.userData.type === CONSTANTS.lineConfig.wallName) && (point.userData.type === CONSTANTS.lineConfig.wallName || point.userData.type === CONSTANTS.lineConfig.floorName)) ||
((DragedPoint.userData.type === CONSTANTS.lineConfig.floorName) && (point.userData.type === CONSTANTS.lineConfig.wallName || point.userData.type === CONSTANTS.lineConfig.floorName)) || ((DragedPoint.userData.type === CONSTANTS.lineConfig.floorName) && (point.userData.type === CONSTANTS.lineConfig.wallName || point.userData.type === CONSTANTS.lineConfig.floorName)) ||
((DragedPoint.userData.type === CONSTANTS.lineConfig.aisleName) && point.userData.type === CONSTANTS.lineConfig.aisleName); ((DragedPoint.userData.type === CONSTANTS.lineConfig.aisleName) && point.userData.type === CONSTANTS.lineConfig.aisleName);
if (canSnap && point.uuid !== DragedPoint.uuid && point.visible) { if (canSnap && point.uuid !== DragedPoint.uuid && point.visible) {
const distance = DragedPoint.position.distanceTo(point.position); const distance = DragedPoint.position.distanceTo(point.position);
if (distance < snapThreshold) { if (distance < snapThreshold) {
DragedPoint.position.copy(point.position); DragedPoint.position.copy(point.position);
} }
} }
}); });
const affectedLines = updateLinesPositions(DragedPoint, lines); const affectedLines = updateLinesPositions(DragedPoint, lines);
updateLines(floorPlanGroupLine, affectedLines); updateLines(floorPlanGroupLine, affectedLines);
updateDistanceText(scene, floorPlanGroupLine, affectedLines); updateDistanceText(scene, floorPlanGroupLine, affectedLines);
updateFloorLines(onlyFloorlines, DragedPoint); updateFloorLines(onlyFloorlines, DragedPoint);
} }
export default DragPoint; export default DragPoint;

View File

@@ -1,37 +1,37 @@
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function removeSoloPoint( function removeSoloPoint(
line: Types.RefLine, line: Types.RefLine,
floorPlanGroupLine: Types.RefGroup, floorPlanGroupLine: Types.RefGroup,
floorPlanGroupPoint: Types.RefGroup floorPlanGroupPoint: Types.RefGroup
): void { ): void {
////////// Remove the point if there is only one point and if it is not connected to any other line and also the reference line ////////// ////////// Remove the point if there is only one point and if it is not connected to any other line and also the reference line //////////
if (line.current[0]) { if (line.current[0]) {
const pointUUID = line.current[0][1]; const pointUUID = line.current[0][1];
let isConnected = false; let isConnected = false;
floorPlanGroupLine.current.children.forEach((line) => { floorPlanGroupLine.current.children.forEach((line) => {
const linePoints = line.userData.linePoints; const linePoints = line.userData.linePoints;
const uuid1 = linePoints[0][1]; const uuid1 = linePoints[0][1];
const uuid2 = linePoints[1][1]; const uuid2 = linePoints[1][1];
if (uuid1 === pointUUID || uuid2 === pointUUID) { if (uuid1 === pointUUID || uuid2 === pointUUID) {
isConnected = true; isConnected = true;
} }
}); });
if (!isConnected) { if (!isConnected) {
floorPlanGroupPoint.current.children.forEach((point: any) => { floorPlanGroupPoint.current.children.forEach((point: any) => {
if (point.uuid === pointUUID) { if (point.uuid === pointUUID) {
(<any>point.material).dispose(); (<any>point.material).dispose();
(<any>point.geometry).dispose(); (<any>point.geometry).dispose();
floorPlanGroupPoint.current.remove(point); floorPlanGroupPoint.current.remove(point);
} }
}); });
} }
line.current = []; line.current = [];
} }
} }
export default removeSoloPoint; export default removeSoloPoint;

View File

@@ -1,32 +1,32 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function addRoofToScene( function addRoofToScene(
shape: Types.Shape, shape: Types.Shape,
floor: Types.Number, floor: Types.Number,
userData: Types.UserData, userData: Types.UserData,
floorGroup: Types.RefGroup floorGroup: Types.RefGroup
): void { ): void {
////////// Creating a Polygon roof from the shape of the Polygon floor ////////// ////////// Creating a Polygon roof from the shape of the Polygon floor //////////
const extrudeSettings: THREE.ExtrudeGeometryOptions = { const extrudeSettings: THREE.ExtrudeGeometryOptions = {
depth: CONSTANTS.roofConfig.height, depth: CONSTANTS.roofConfig.height,
bevelEnabled: false bevelEnabled: false
}; };
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.roofConfig.defaultColor, side: THREE.DoubleSide, transparent: true, depthWrite: false }); const material = new THREE.MeshStandardMaterial({ color: CONSTANTS.roofConfig.defaultColor, side: THREE.DoubleSide, transparent: true, depthWrite: false });
const mesh = new THREE.Mesh(geometry, material); const mesh = new THREE.Mesh(geometry, material);
mesh.position.y = CONSTANTS.wallConfig.height + floor; mesh.position.y = CONSTANTS.wallConfig.height + floor;
mesh.castShadow = true; mesh.castShadow = true;
mesh.receiveShadow = true; mesh.receiveShadow = true;
mesh.rotateX(Math.PI / 2); mesh.rotateX(Math.PI / 2);
mesh.userData.uuids = userData; mesh.userData.uuids = userData;
mesh.name = `Roof_Layer_${(floor / CONSTANTS.wallConfig.height) + 1}`; mesh.name = `Roof_Layer_${(floor / CONSTANTS.wallConfig.height) + 1}`;
floorGroup.current.add(mesh); floorGroup.current.add(mesh);
} }
export default addRoofToScene; export default addRoofToScene;

View File

@@ -1,47 +1,47 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function hideRoof( function hideRoof(
visibility: Types.Boolean, visibility: Types.Boolean,
floorGroup: Types.RefGroup, floorGroup: Types.RefGroup,
camera: THREE.Camera camera: THREE.Camera
): void { ): void {
////////// Toggles the visibility of the roof based on the camera position and the Roof visibility button on UI ////////// ////////// Toggles the visibility of the roof based on the camera position and the Roof visibility button on UI //////////
const v = new THREE.Vector3(); const v = new THREE.Vector3();
const u = new THREE.Vector3(); const u = new THREE.Vector3();
if (visibility === true && floorGroup.current) { if (visibility === true && floorGroup.current) {
for (const child of floorGroup.current.children) { for (const child of floorGroup.current.children) {
if (child.name.includes("Roof")) { if (child.name.includes("Roof")) {
const roofChild = child as Types.Mesh; const roofChild = child as Types.Mesh;
roofChild.getWorldDirection(v); roofChild.getWorldDirection(v);
camera?.getWorldDirection(u); camera?.getWorldDirection(u);
if (roofChild.material) { if (roofChild.material) {
const materials = Array.isArray(roofChild.material) ? roofChild.material : [roofChild.material]; const materials = Array.isArray(roofChild.material) ? roofChild.material : [roofChild.material];
materials.forEach(material => { materials.forEach(material => {
material.visible = v.dot(u) < 0.25; material.visible = v.dot(u) < 0.25;
}); });
} }
} }
} }
} else { } else {
if (floorGroup.current) { if (floorGroup.current) {
for (const child of floorGroup.current.children) { for (const child of floorGroup.current.children) {
if (child.name.includes("Roof")) { if (child.name.includes("Roof")) {
const roofChild = child as Types.Mesh; const roofChild = child as Types.Mesh;
if (roofChild.material) { if (roofChild.material) {
const materials = Array.isArray(roofChild.material) ? roofChild.material : [roofChild.material]; const materials = Array.isArray(roofChild.material) ? roofChild.material : [roofChild.material];
materials.forEach(material => { materials.forEach(material => {
material.visible = false; material.visible = false;
}); });
} }
} }
} }
} }
} }
} }
export default hideRoof; export default hideRoof;

View File

@@ -1,108 +1,108 @@
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
import * as CONSTANTS from '../../../../types/world/worldConstants'; import * as CONSTANTS from '../../../../types/world/worldConstants';
// import { setWallItem } from '../../../../services/factoryBuilder/assest/wallAsset/setWallItemApi'; // import { setWallItem } from '../../../../services/factoryBuilder/assest/wallAsset/setWallItemApi';
import { Socket } from 'socket.io-client'; import { Socket } from 'socket.io-client';
async function AddWallItems( async function AddWallItems(
selected: Types.String, selected: Types.String,
raycaster: THREE.Raycaster, raycaster: THREE.Raycaster,
CSGGroup: Types.RefMesh, CSGGroup: Types.RefMesh,
AssetConfigurations: Types.AssetConfigurations, AssetConfigurations: Types.AssetConfigurations,
setWallItems: Types.setWallItemSetState, setWallItems: Types.setWallItemSetState,
socket: Socket<any> socket: Socket<any>
): Promise<void> { ): Promise<void> {
////////// Load Wall GLtf's and set the positions, rotation, type etc. in state and store in localstorage ////////// ////////// Load Wall GLtf's and set the positions, rotation, type etc. in state and store in localstorage //////////
let intersects = raycaster?.intersectObject(CSGGroup.current!, true); let intersects = raycaster?.intersectObject(CSGGroup.current!, true);
const wallRaycastIntersection = intersects?.find((child) => child.object.name.includes("WallRaycastReference")); const wallRaycastIntersection = intersects?.find((child) => child.object.name.includes("WallRaycastReference"));
if (wallRaycastIntersection) { if (wallRaycastIntersection) {
const intersectionPoint = wallRaycastIntersection; const intersectionPoint = wallRaycastIntersection;
const loader = new GLTFLoader(); const loader = new GLTFLoader();
loader.load(AssetConfigurations[selected].modelUrl, async (gltf) => { loader.load(AssetConfigurations[selected].modelUrl, async (gltf) => {
const model = gltf.scene; const model = gltf.scene;
model.userData = { wall: intersectionPoint.object.parent }; model.userData = { wall: intersectionPoint.object.parent };
model.children[0].children.forEach((child) => { model.children[0].children.forEach((child) => {
if (child.name !== "CSG_REF") { if (child.name !== "CSG_REF") {
child.castShadow = true; child.castShadow = true;
child.receiveShadow = true; child.receiveShadow = true;
} }
}); });
const config = AssetConfigurations[selected]; const config = AssetConfigurations[selected];
let positionY = typeof config.positionY === 'function' ? config.positionY(intersectionPoint) : config.positionY; let positionY = typeof config.positionY === 'function' ? config.positionY(intersectionPoint) : config.positionY;
if (positionY === 0) { if (positionY === 0) {
positionY = Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height; positionY = Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height;
} }
const newWallItem = { const newWallItem = {
type: config.type, type: config.type,
model: model, model: model,
modelname: selected, modelname: selected,
scale: config.scale, scale: config.scale,
csgscale: config.csgscale, csgscale: config.csgscale,
csgposition: config.csgposition, csgposition: config.csgposition,
position: [intersectionPoint.point.x, positionY, intersectionPoint.point.z] as [number, number, number], position: [intersectionPoint.point.x, positionY, intersectionPoint.point.z] as [number, number, number],
quaternion: intersectionPoint.object.quaternion.clone() as Types.QuaternionType quaternion: intersectionPoint.object.quaternion.clone() as Types.QuaternionType
}; };
const email = localStorage.getItem('email') const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0]; const organization = (email!.split("@")[1]).split(".")[0];
//REST //REST
// await setWallItem( // await setWallItem(
// organization, // organization,
// model.uuid, // model.uuid,
// newWallItem.modelname, // newWallItem.modelname,
// newWallItem.type!, // newWallItem.type!,
// newWallItem.csgposition!, // newWallItem.csgposition!,
// newWallItem.csgscale!, // newWallItem.csgscale!,
// newWallItem.position, // newWallItem.position,
// newWallItem.quaternion, // newWallItem.quaternion,
// newWallItem.scale!, // newWallItem.scale!,
// ) // )
//SOCKET //SOCKET
const data = { const data = {
organization: organization, organization: organization,
modeluuid: model.uuid, modeluuid: model.uuid,
modelname: newWallItem.modelname, modelname: newWallItem.modelname,
type: newWallItem.type!, type: newWallItem.type!,
csgposition: newWallItem.csgposition!, csgposition: newWallItem.csgposition!,
csgscale: newWallItem.csgscale!, csgscale: newWallItem.csgscale!,
position: newWallItem.position, position: newWallItem.position,
quaternion: newWallItem.quaternion, quaternion: newWallItem.quaternion,
scale: newWallItem.scale!, scale: newWallItem.scale!,
socketId: socket.id socketId: socket.id
} }
socket.emit('v1:wallItems:set', data); socket.emit('v1:wallItems:set', data);
setWallItems((prevItems) => { setWallItems((prevItems) => {
const updatedItems = [...prevItems, newWallItem]; const updatedItems = [...prevItems, newWallItem];
const WallItemsForStorage = updatedItems.map(item => { const WallItemsForStorage = updatedItems.map(item => {
const { model, ...rest } = item; const { model, ...rest } = item;
return { return {
...rest, ...rest,
modeluuid: model?.uuid, modeluuid: model?.uuid,
}; };
}); });
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage)); localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
toast.success("Model Added!"); toast.success("Model Added!");
return updatedItems; return updatedItems;
}); });
}); });
} }
} }
export default AddWallItems; export default AddWallItems;

View File

@@ -1,59 +1,59 @@
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
// import { deleteWallItem } from '../../../../services/factoryBuilder/assest/wallAsset/deleteWallItemApi'; // import { deleteWallItem } from '../../../../services/factoryBuilder/assest/wallAsset/deleteWallItemApi';
import { Socket } from 'socket.io-client'; import { Socket } from 'socket.io-client';
function DeleteWallItems( function DeleteWallItems(
hoveredDeletableWallItem: Types.RefMesh, hoveredDeletableWallItem: Types.RefMesh,
setWallItems: Types.setWallItemSetState, setWallItems: Types.setWallItemSetState,
wallItems: Types.wallItems, wallItems: Types.wallItems,
socket: Socket<any> socket: Socket<any>
): void { ): void {
////////// Deleting the hovered Wall GLTF from thewallItems and also update it in the localstorage ////////// ////////// Deleting the hovered Wall GLTF from thewallItems and also update it in the localstorage //////////
if (hoveredDeletableWallItem.current && hoveredDeletableWallItem.current.parent) { if (hoveredDeletableWallItem.current && hoveredDeletableWallItem.current.parent) {
setWallItems([]); setWallItems([]);
let WallItemsRef = wallItems; let WallItemsRef = wallItems;
const removedItem = WallItemsRef.find((item) => item.model?.uuid === hoveredDeletableWallItem.current?.parent?.uuid); const removedItem = WallItemsRef.find((item) => item.model?.uuid === hoveredDeletableWallItem.current?.parent?.uuid);
const Items = WallItemsRef.filter((item) => item.model?.uuid !== hoveredDeletableWallItem.current?.parent?.uuid); const Items = WallItemsRef.filter((item) => item.model?.uuid !== hoveredDeletableWallItem.current?.parent?.uuid);
setTimeout(async () => { setTimeout(async () => {
WallItemsRef = Items; WallItemsRef = Items;
setWallItems(WallItemsRef); setWallItems(WallItemsRef);
const email = localStorage.getItem('email') const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0]; const organization = (email!.split("@")[1]).split(".")[0];
//REST //REST
// await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelname!) // await deleteWallItem(organization, removedItem?.model?.uuid!, removedItem?.modelname!)
//SOCKET //SOCKET
const data = { const data = {
organization: organization, organization: organization,
modeluuid: removedItem?.model?.uuid!, modeluuid: removedItem?.model?.uuid!,
modelname: removedItem?.modelname!, modelname: removedItem?.modelname!,
socketId: socket.id socketId: socket.id
} }
socket.emit('v1:wallItems:delete', data); socket.emit('v1:wallItems:delete', data);
const WallItemsForStorage = WallItemsRef.map(item => { const WallItemsForStorage = WallItemsRef.map(item => {
const { model, ...rest } = item; const { model, ...rest } = item;
return { return {
...rest, ...rest,
modeluuid: model?.uuid, modeluuid: model?.uuid,
}; };
}); });
localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage)); localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
toast.success("Model Removed!"); toast.success("Model Removed!");
hoveredDeletableWallItem.current = null; hoveredDeletableWallItem.current = null;
}, 50); }, 50);
} }
} }
export default DeleteWallItems; export default DeleteWallItems;

View File

@@ -1,45 +1,45 @@
import * as THREE from 'three'; import * as THREE from 'three';
import * as Types from "../../../../types/world/worldTypes"; import * as Types from "../../../../types/world/worldTypes";
function hideWalls( function hideWalls(
visibility: Types.Boolean, visibility: Types.Boolean,
scene: THREE.Scene, scene: THREE.Scene,
camera: THREE.Camera camera: THREE.Camera
): void { ): void {
////////// Altering the visibility of the Walls when the world direction of the wall is facing the camera ////////// ////////// Altering the visibility of the Walls when the world direction of the wall is facing the camera //////////
const v = new THREE.Vector3(); const v = new THREE.Vector3();
const u = new THREE.Vector3(); const u = new THREE.Vector3();
if (visibility === true) { if (visibility === true) {
for (const children of scene.children) { for (const children of scene.children) {
if (children.name === "Walls" && children.children[0]?.children.length > 0) { if (children.name === "Walls" && children.children[0]?.children.length > 0) {
children.children[0].children.forEach((child: any) => { children.children[0].children.forEach((child: any) => {
if (child.children[0]?.userData.WallType === "RoomWall") { if (child.children[0]?.userData.WallType === "RoomWall") {
child.children[0].getWorldDirection(v); child.children[0].getWorldDirection(v);
camera.getWorldDirection(u); camera.getWorldDirection(u);
if (child.children[0].material) { if (child.children[0].material) {
child.children[0].material.visible = (2 * v.dot(u)) >= -0.5; child.children[0].material.visible = (2 * v.dot(u)) >= -0.5;
} }
} }
}); });
} }
} }
} else { } else {
for (const children of scene.children) { for (const children of scene.children) {
if (children.name === "Walls" && children.children[0]?.children.length > 0) { if (children.name === "Walls" && children.children[0]?.children.length > 0) {
children.children[0].children.forEach((child: any) => { children.children[0].children.forEach((child: any) => {
if (child.children[0]?.userData.WallType === "RoomWall") { if (child.children[0]?.userData.WallType === "RoomWall") {
if (child.children[0].material) { if (child.children[0].material) {
child.children[0].material.visible = true; child.children[0].material.visible = true;
} }
} }
}); });
} }
} }
} }
} }
export default hideWalls; export default hideWalls;

Some files were not shown because too many files have changed in this diff Show More