React DnD how I cannot allow the draggable cannot overlap - reactjs

Hi Guys I need a guide on this.
I am creating a React DnD. I am creating a Container and I am creating Boxes inside .
How I cannot Drag one over other.
What has more sense, is ask for the position in the callBack and don't allow the drop of the coordinates or modified the ref and "remove the dropable area"?
Anybody with experience in ReactDnD could give me a guide.
import update from 'immutability-helper'
import { useCallback, useState } from 'react'
import { useDrop } from 'react-dnd'
import { Box } from './Box.js'
import { ItemTypes } from './ItemTypes.js'
// This is the size of the area of Drop
const styles = {
width: 500,
height: 500,
border: '1px solid black',
position: 'relative',
}
export const Container = () => {
const [boxes, setBoxes] = useState({
'01': { top: 0, left: 0, title: 'Ship01',width:2,height:1 },
'02': { top: 100, left: 0, title: 'Ship02',width:3,height:1 },
'03': { top: 200, left: 0, title: 'Ship03',width:4,height:1 },
'04': { top: 300, left: 0, title: 'Ship04',width:5,height:1 },
'05': { top: 400, left: 0, title: 'Ship05',width:6,height:1 },
})
const moveBox = useCallback(
(id, left, top) => {
setBoxes(
update(boxes, {
[id]: {
$merge: { left, top },
},
}),
)
},
[boxes, setBoxes],
)
const [, drop] = useDrop(() => ({accept: ItemTypes.BOX, drop(item, monitor) {
const delta = monitor.getDifferenceFromInitialOffset()
const left = Math.round(item.left + delta.x)
const top = Math.round(item.top + delta.y)
moveBox(item.id, left, top)
return undefined}}),[moveBox],)
return (
<div ref={drop} style={styles}>
{Object.keys(boxes).map((key) => {
const { left, top, title,width, height} = boxes[key]
return (
<Box key={key} id={key} left={left} top={top} width={width} height={height} boxes={boxes}> {title} </Box>
)
})}
</div>
)
}

Related

making the position of a popconfirm static

I am using a popconfirm to show up when trying to close a modal, I want the popconfirm position to be below the X button of the modal, I have tried to move its position with the "overlaystyle" property and if I edit the values while the popconfirm is open it works, but if the screen dimensions change or the popconfirm is closed.
it returns to its original position, is there any way to make it stay below the X of the modal?
import { ExclamationCircleFilled } from "#ant-design/icons";
import { Popconfirm } from "antd";
import { useEffect, useState } from "react";
type EditModalCloseType = {
width: number
popupOpen: boolean;
onConfirm: () => void;
onCancel: () => void;
};
export const EditModalClose = ({width, popupOpen, onConfirm, onCancel }: EditModalCloseType) => {
useEffect(() => {
calculateOverlayStyle(width);
}, [width]);
const description = "¿Estás seguro de salir sin actualizar? los cambios se perderan"
const calculateOverlayStyle = (width: number) => {
setOverlayStyle({
...(width < 688 && { marginLeft: '20px', marginTop: '-160px' }),
...(width < 1300 && { position: 'absolute', top: '50%', left: '50%' }),
...(width >= 1300 && { position: 'absolute', top: '50%', left: '50%' })
});
}
const [overlayStyle, setOverlayStyle] = useState({});
return <Popconfirm
title={description}
open={popupOpen}
placement="bottom"
autoAdjustOverflow={true}
overlayStyle={overlayStyle}
icon={<ExclamationCircleFilled style={{ color: 'red' }} />}
okText="Salir"
okButtonProps={{ style: { backgroundColor: 'red', color: 'white' } }}
onConfirm={onConfirm}
cancelText="Regresar"
onCancel={onCancel}
/>
}
const PopupCancel = () => {
setPopupOpen(false);
};
const PopupConfirm = () => {
resetFields();
setPopupOpen(false);
setOpenModal(false);
}
I tried to create a function according to the width of the screen that would adjust it according to that property but the same error I mentioned in the post keeps occurring.

re-position react-rnd elements with a css transition

I have a list of two elements scenes rendered as <Rnd /> components from "react-rnd". What I'd like to happen is when I drag one element close to another one they should swap positions, in the list and in the UI. so [first, second] becomes [second, first]. The <Rnd /> position is controlled, this is the code I'm using:
import { useState } from "react";
import "./styles.css";
import { Rnd, Position, DraggableData } from "react-rnd";
interface IScene {
id: string;
name: string;
position: Position;
}
function Scene({
scene,
activeScene,
setActiveScene,
onDrag
}: {
scene: IScene;
activeScene: string;
setActiveScene: (id: string) => void;
onDrag: (d: DraggableData) => void;
}) {
const [dragged, setDragged] = useState(false);
return (
<Rnd
default={{
x: 0,
y: 0,
width: "200px",
height: "100px"
}}
position={scene.position}
onDragStart={() => setDragged(true)}
onDragStop={() => setDragged(false)}
onDrag={(_, d) => onDrag(d)}
onMouseDown={() => setActiveScene(scene.id)}
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: "gray",
transition: dragged ? "" : "transform 0.5s",
border: "1px solid",
borderColor: activeScene === scene.id ? "white" : "gray",
zIndex: activeScene === scene.id ? "1" : "0"
}}
>
{scene.name}
</Rnd>
);
}
const initialScenesState = [
{
id: "1",
name: "first",
position: {
x: 0,
y: 0
}
},
{
id: "2",
name: "second",
position: {
x: 200,
y: 0
}
}
];
export default function App() {
const [scenes, setScenes] = useState<IScene[]>(initialScenesState);
const [activeScene, setActiveScene] = useState<string>("");
const handleStackScenes = () => {
setScenes((scenes) => {
let currentPosition = 0;
return scenes.map((scene) => {
const result = {
...scene,
position: {
x: currentPosition,
y: 0
}
};
currentPosition += 200;
return result;
});
});
};
const swapScenes = (first: IScene, second: IScene) => {
setScenes((scenes) => {
return scenes.map((scene) => {
if (scene.id === first.id) {
return second;
} else if (scene.id === second.id) {
return first;
} else return scene;
});
});
handleStackScenes();
};
const handleDrag = (scene: IScene) => (d: DraggableData) => {
console.log(d.x);
for (let i = 0; i < scenes.length; i++) {
if (
Math.abs(scenes[i].position.x - d.x) < 30 &&
scenes[i].id !== scene.id
) {
swapScenes(scene, scenes[i]);
}
}
};
console.log(scenes);
return (
<div className="App">
{scenes.map((scene) => (
<Scene
key={scene.id}
scene={scene}
activeScene={activeScene}
setActiveScene={setActiveScene}
onDrag={handleDrag(scene)}
/>
))}
</div>
);
}
The problem that I'm facing with my code, is that when I drag the left element to the right one, the swap happens exactly how I wanted, in the other way around the swap happens but I don't see a transition effect, when I checked what happens on the console, it seems that on the second case, the dom elements don't swap, but just the content and it the first case the actual dom elements move. What am I doing wrong?
EDIT: CodeSandBox

How can I send a canvas with a filter through openvidu?

In progress of a project using WebRTC
I found the code to apply the filter using face_mesh.
The code is as follows
import { FaceMesh } from "#mediapipe/face_mesh";
import React, { useRef, useEffect, createRef } from "react";
import * as Facemesh from "#mediapipe/face_mesh";
import * as cam from "#mediapipe/camera_utils";
import Webcam from "react-webcam";
import "../stream/StreamComponent.css";
function Filter() {
const webcamRef = useRef(null);
const canvasRef = useRef(null);
const connect = window.drawConnectors;
var camera = null;
function onResults(results) {
// const video = webcamRef.current.video;
const videoWidth = webcamRef.current.video.videoWidth;
const videoHeight = webcamRef.current.video.videoHeight;
const videoRef = createRef();
console.log(videoRef);
console.log(connect);
// Set canvas width
canvasRef.current.width = videoWidth;
canvasRef.current.height = videoHeight;
const canvasElement = canvasRef.current;
const canvasCtx = canvasElement.getContext("2d");
canvasCtx.save();
canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
canvasCtx.drawImage(
results.image,
0,
0,
canvasElement.width,
canvasElement.height
);
if (results.multiFaceLandmarks) {
for (const landmarks of results.multiFaceLandmarks) {
connect(canvasCtx, landmarks, Facemesh.FACEMESH_TESSELATION, {
color: "#C0C0C070",
lineWidth: 1,
});
connect(canvasCtx, landmarks, Facemesh.FACEMESH_RIGHT_EYE, {
color: "#FF3030",
});
connect(canvasCtx, landmarks, Facemesh.FACEMESH_RIGHT_EYEBROW, {
color: "#FF3030",
});
connect(canvasCtx, landmarks, Facemesh.FACEMESH_LEFT_EYE, {
color: "#30FF30",
});
connect(canvasCtx, landmarks, Facemesh.FACEMESH_LEFT_EYEBROW, {
color: "#30FF30",
});
connect(canvasCtx, landmarks, Facemesh.FACEMESH_FACE_OVAL, {
color: "#E0E0E0",
});
connect(canvasCtx, landmarks, Facemesh.FACEMESH_LIPS, {
color: "#E0E0E0",
});
}
}
canvasCtx.restore();
}
// }
// setInterval(())
useEffect(() => {
const faceMesh = new FaceMesh({
locateFile: (file) => {
return `https://cdn.jsdelivr.net/npm/#mediapipe/face_mesh/${file}`;
},
});
faceMesh.setOptions({
maxNumFaces: 1,
minDetectionConfidence: 0.5,
minTrackingConfidence: 0.5,
});
faceMesh.onResults(onResults);
if (
typeof webcamRef.current !== "undefined" &&
webcamRef.current !== null
) {
camera = new cam.Camera(webcamRef.current.video, {
onFrame: async () => {
await faceMesh.send({ image: webcamRef.current.video });
},
width: 640,
height: 480,
});
camera.start();
}
}, []);
return (
<center>
<div className="Filter">
<Webcam
ref={webcamRef}
style={{
position: "absolute",
marginLeft: "auto",
marginRight: "auto",
left: 0,
right: 0,
textAlign: "center",
zindex: 9,
width: 640,
height: 480,
}}
/>{" "}
<canvas
ref={canvasRef}
className="output_canvas"
style={{
position: "absolute",
marginLeft: "auto",
marginRight: "auto",
left: 0,
right: 0,
textAlign: "center",
zindex: 9,
width: 640,
height: 480,
}}
></canvas>
</div>
</center>
);
}
export default Filter;
So I'm trying to send a screen with a filter through openvidu
The openvidu code that exports the default camera screen is as follows
import React, { Component } from "react";
import "./StreamComponent.css";
export default class OvVideoComponent extends Component {
constructor(props) {
super(props);
this.videoRef = React.createRef();
}
componentDidMount() {
if (this.props && this.props.user.streamManager && !!this.videoRef) {
console.log("PROPS: ", this.props);
this.props.user.getStreamManager().addVideoElement(this.videoRef.current);
}
}
componentDidUpdate(props) {
if (props && !!this.videoRef) {
this.props.user.getStreamManager().addVideoElement(this.videoRef.current);
}
}
render() {
return (
<video
autoPlay={true}
id={"video-" + this.props.user.getStreamManager().stream.streamId}
ref={this.videoRef}
muted={this.props.mutedSound}
/>
);
}
}
I think apply a canvas object or a canvas.captureStream() to an element**.props.user.getStreamManager().addVideoElement()**
But I don't know how to apply it
It's my first time using openvidu, so I'm facing a lot of difficulties
I'm so sorry if you don't have enough explanation

How to trigger Navigation when an Reanimated 2 Animation is completed? React Native - Reanimated 2 & React-Navigation

I'm trying to create a Tinder clone where there is a left and right swiping mechanism for liking and disliking a profile. However, I want the user to swipe the profile downwards to open the profile details screen. I have tried creating the function directly in ".onEnd" but every time I perform the swipe action, it completely crashes the app. Every other swipe direction works perfectly as expected. I have tried resetting the cache, uninstalling the app on the emulator and that hasn't fixed it. I couldn't find a solution on the documentation or anywhere on Google.
Thanks for the help in advance! This is my first programming project! :D
Here's my current code:
import React from "react";
import { View, Text, Image, StyleSheet } from 'react-native'
import LinearGradient from "react-native-linear-gradient";
import ListingDetails from "../ListingDetails";
import { listingsArr } from "../Listings";
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from "react-native-reanimated";
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
import { useWindowDimensions } from 'react-native';
import { useNavigation } from '#react-navigation/native';
import ListingDetailScreen from "../../Screens/ListingDetailScreen";
import {MainStackNavigator } from '../../Navigation/MainStackNavigator';
const SingleCard = (props) => {
const navigation = useNavigation();
const navigateToHome = () => {navigation.navigate('Home')}
console.log(useWindowDimensions().height)
const windowWidth = useWindowDimensions().width
const windowHeight = useWindowDimensions().height
const startPosition = 0;
const x = useSharedValue(startPosition)
const y = useSharedValue(startPosition)
const isPressed = useSharedValue(false);
const offset = useSharedValue({ x: 0, y: 0 });
const animatedStyles = useAnimatedStyle(() => {
return {
transform: [
{ translateX: withSpring(x.value) },
{ translateY: withSpring(y.value) },
],
backgroundColor: isPressed.value ? 'yellow' : 'blue',
};
});
const start = useSharedValue({ x: 0, y: 0 });
const gesture = Gesture.Pan()
.onBegin(() => {
isPressed.value = true
})
.onUpdate((e) => {
x.value = startPosition + e.translationX;
y.value = startPosition + e.translationY;
})
.onEnd((e) => {
const verticalSwipe = Math.abs(y.value) - Math.abs(x.value);
const horizontalSwipe = Math.abs(x.value) - Math.abs(y.value);
console.log(verticalSwipe)
console.log(y.value)
if (verticalSwipe >= 0) {
if (y.value > windowHeight / 4) {
navigateToHome();
console.log('swiped up')
} else {
x.value = withSpring(startPosition);
y.value = withSpring(startPosition);
}
} else {
if (x.value > windowWidth / 4) {
x.value = withSpring(windowWidth * 2);
y.value = withSpring(startPosition)
} else if (x.value < windowWidth / -4) {
x.value = withSpring(windowWidth * -2);
y.value = withSpring(startPosition);
console.log('swiped left')
} else {
x.value = withSpring(startPosition);
y.value = withSpring(startPosition);
}
}
})
.onFinalize(() => {
isPressed.value = false;
});
return (
<GestureDetector gesture={gesture}>
<Animated.View style={[styles.masterContainer, animatedStyles]} >
<View style={styles.spacerContainer}>
</View>
<Text> This is single card component </Text>
<Image style={styles.imageStyle} source={props.cardListing.Photo} />
<LinearGradient colors={['rgba(255,255,255,0)', 'rgba(0,0,0,0.4 )']} style={styles.backgroundOverlay} />
<ListingDetails myListing={props.cardListing} />
</Animated.View>
</GestureDetector>
)
}
const styles = StyleSheet.create({
spacerContainer: {
flex: 2,
},
containerStyle: {
flex: 1,
},
imageStyle: {
position: 'absolute',
resizeMode: 'cover',
width: '100%',
height: '100%',
flex: 1,
},
imageContainer1: {
position: 'absolute',
width: '100%',
height: '100%',
zIndex: 0,
flex: 1
},
imageContainer2: {
position: 'absolute',
width: '100%',
height: '100%',
flex: 1,
zIndex: 0,
},
backgroundOverlay: {
flex: 1,
width: '100%',
height: '100%',
resizeMode: 'cover',
position: 'absolute',
zIndex: 0,
},
masterContainer: {
width: '100%',
height: '100%',
}
})
export default SingleCard;
You must use RunOnJS from reanimated lib like example below:
Explaining, animated is running in UI Thread and navigation.navigate function run in another thread (JS Thread), then animated can't call navigate function.
More in reanimated documentation.
import Animated, { runOnJS, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
// ...other codes
const settingsIconRotation = useSharedValue(0);
const onPressFn = () => {
// function from other thread (different of reanimated thread)
navigation.navigate('Modal');
};
const onPressSettings = () => {
settingsIconRotation.value = withSpring(180, {}, (finished) => {
if (finished) {
settingsIconRotation.value = 0;
runOnJS(onPressFn)(); // execute on JS thread
} else {
}
});
};
// ...other codes

Dropping Over a Component inside nested Drop Targets giving error

Here is my Container Class
Code on Sandbox
`import React, { Component } from "react";
import { DropTarget } from "react-dnd";
import Box from "./Box";
class Container extends Component {
state = {
Boxes: [
{ left: 60, top: 30, text: "ITEM_1" },
{ left: 100, top: 70, text: "ITEM_2" }
]
};
render() {
const { connectDropTarget } = this.props;
return connectDropTarget(
<div
className="container"
style={{ width: "100%", height: "100vh", background: "yellow" }}
>
{this.state.Boxes.map((box, index) => {
return (
<Box
id={index}
key={index}
left={box.left}
top={box.top}
text={box.text}
moveBox={this.moveBox}
/>
);
})}
</div>
);
}
moveBox(id, left, top) {
const allBoxes = this.state.Boxes;
const singleBox = this.state.Boxes[id];
singleBox.left = left;
singleBox.top = top;
const newBox = allBoxes.filter((box, index) => index !== id);
newBox.push(singleBox);
this.setState({ Boxes: newBox });
}
}
export default DropTarget(
"items",
{
// Spec Object Started
drop(props, monitor, component) {
const item = monitor.getItem();
const delta = monitor.getDifferenceFromInitialOffset();
const left = Math.round(item.left + delta.x);
const top = Math.round(item.top + delta.y);
component.moveBox(item.id, left, top);
}
}, //Spec Oject Ended Here
(connect, monitor) => ({
connectDropTarget: connect.dropTarget()
})
)(Container);
`
And Here is my Box Class
import React, { Component } from "react";
import { DragSource, DropTarget } from "react-dnd";
import flow from "lodash/flow";
let whichDragging = "items";
class Box extends Component {
state = {};
render() {
const { left, top, text, connectDragSouce, connectDropTarget } = this.props;
return connectDragSouce(
connectDropTarget(
<div
style={{
width: "20%",
border: "2px dotted black",
margin: "auto",
position: "relative",
top: top,
left: left
}}
>
{text}
</div>
)
);
}
}
export default flow(
DragSource(
whichDragging,
{
beginDrag(props, monitor, component) {
console.log(component);
const { left, top, text, id } = props;
return {
left,
top,
text,
id
};
}
},
(connect, monitor) => ({
connectDragSouce: connect.dragSource()
})
),
DropTarget(
whichDragging,
{
drop(props, monitor, component) {
whichDragging = "nested";
const item = monitor.getItem();
const delta = monitor.getDifferenceFromInitialOffset();
const left = Math.round(item.left + delta.x);
const top = Math.round(item.top + delta.y);
console.log("Logging");
console.log(component);
// whichDragging = "items";
}
},
(connect, monitor) => ({
connectDropTarget: connect.dropTarget()
})
)
)(Box);
Simple Dragging Dropping Working fine but when i drop item_1 over item_2 or vice versa i got error and my Component in drop shows DragDropContainer in console.log i want to get the id|key of component over which one component is dropped and not able to find any solution since 2 days any help will be appriciated.

Resources