Video Follow on Mouse Move in React - reactjs

I have this javascript function that autoplays a Vimeo video and attaches to the cursor when hovering over an element. I'm trying to figure out how to do this in React but I'm not having any luck. Originally, I was using Froogaloop and Vimeo player api which seemed to work just fine, but not in react.
Here is the code below
Script
document.getElementById("div").addEventListener("mousemove", function() {
myFunction(event);
});
var mouse;
var cursor = document.getElementById("cursor");
function myFunction(e) {
mouseX = e.clientX;
mouseY = e.clientY;
cursor.style.left = (mouseX - 55) + "px";
cursor.style.top = (mouseY - 55) + "px";
}
// play video on hover
const iframe = document.getElementById('video');
// $f == Froogaloop
const player = $f(iframe);
// bind events
var mouseEntering = document.getElementById("div");
mouseEntering.addEventListener("mouseenter", function() {
player.api("play");
});
var mouseLeaving = document.getElementById("div");
mouseLeaving.addEventListener("mouseleave", function() {
player.api("unload");
});
HTML
<div id="div" class="div">
<div id="cursor" class="cursor">
<iframe id="video" class="video" src="https://player.vimeo.com/video/649593940?api=1&loop=1&muted=1" width="400px"
height="300px" frameborder="0"></iframe>
</div>
</div>
CSS
.wrapper{
display:grid;
grid-template-columns: repeat(auto-fit, minmax(241px,1fr));
gap: 20px;
}
.div:hover{
cursor:pointer;
}
.div:hover .cursor{
visibility:visible;
}
.cursor {
visibility:hidden;
position: absolute;
transform:translate(80px,50px);
background:red;
backface-visibility: hidden;
z-index: 9999999;
pointer-events: none; /* pointer-events: none is needed */
cursor: none;
}
.div {
background: blue;
height:200px;
width:100%;
cursor: none;
}
Here is a full working example on codepen
Any help on how to do this in react would be awesome.

Related

How do I use animation that spreads up and down when I make a drop-down menu?

I'm making a drop-down menu now. When I put my mouse on a specific part, the drop-down menu opens and when the mouse goes out of the browser, I want to make the drop-down menu disappear. I made a state value called isMouseOver to return true when the mouse goes up and to use jquery to return false when the mouse goes out of the browser. When the mouse goes up, I used animation to implement it as I wanted, but I want to implement animation that slowly disappears up when the mouse goes out of the browser, but this part doesn't work well. I put this part in an animation as well, but the animation overlapped and it was executed strangely. To sum up the question, how do I put the animation when isMouseOver becomes false and the display becomes none?
import { useState } from 'react';
import styled, {keyframes} from 'styled-components';
import $ from 'jquery';
// animation when mouseover
const dropdownAnimation = keyframes`
0% {
transform: translateY(-30%);
}
100% {
transform: translateY(0);
}
`
function HeaderRight () {
// Check mouseover
const [isMouseOver, setIsMouseOver] = useState(false)
// return true when mouse over
const ActMouseOver = () => {
setIsMouseOver(true)
}
// return false when mouse over
const ActMouseLeave = () => {
setIsMouseOver(false)
}
// return false when the mouse is out of the browser
$(document).mouseleave(function () {
ActMouseLeave();
});
return (
<HeaderRightWrap isMouseOver={isMouseOver} onMouseEnter={ActMouseOver}>
<ul className='HeaderRightWrapUl'>
<li className='HeaderRightWrapUlLi'>
<ul className='HeaderRightWrapUlLiUl'>
<li className='HeaderRightWrapUlLiUlLi'>
Hello
</li>
</ul>
</li>
</ul>
</HeaderRightWrap>
)
}
export default HeaderRight;
const HeaderRightWrap = styled.div`
position: relative;
box-sizing: border-box;
bottom: 40px;
.HeaderRightWrapUl {
height: 100%;
margin: 0 auto;
padding: 0;
list-style: none;
box-sizing: border-box;
display: block;
margin-inline-end: 0px;
margin-inline-start: 0px;
margin-block-start: 1em;
margin-block-end: 1em;
padding-inline-start: 40px;
}
.HeaderRightWrapUlLi {
z-index: 1000;
position: relative;
float: left;
width: auto;
height: 100%;
padding-right: 80px;
transition: padding .3s;
}
.HeaderRightWrapUlLiUl {
display: ${props=>props.isMouseOver===true?'auto':'none'};
position: absolute;
animation: ${dropdownAnimation} 0.3s ease;
}
.HeaderRightWrapUlLiUlLi {
margin-top: 0;
}
`

Flickering issue when drawing div in Angular

In this plunk I have a div that needs to be drawn dragging the mouse. I'm using mouse up/move/down events. The problem that I have is that the div "flickers" when I drag down. How to fix this?
HTML
<style>
.frame {
width: 300px;
height: 300px;
background-color: orange;
position: relative;
}
.sel{
border:2px solid black;
background-color: #ffffff;
position:absolute;
}
</style>
<div class="frame" ng-mousedown="mouseDown($event)"
ng-mousemove="mouseMove($event)"
ng-mouseup="mouseUp()">
<div class="sel" ng-show="show"
ng-style="{top:selTop+'px', left:selLeft+'px', width:selWidth+'px', height:selHeight+'px'}"></div>
</div>
Javascript:
var app = angular.module('app', []);
app.controller('ctl', function ($scope) {
$scope.startPoint = {};
$scope.show = false;
$scope.mouseDown = function(event) {
$scope.startPoint = { x: event.offsetX, y: event.offsetY };
$scope.show = true;
};
$scope.mouseMove = function(event) {
if (!$scope.startPoint.x)
return;
$scope.selTop = $scope.startPoint.y;
$scope.selLeft = $scope.startPoint.x;
$scope.selHeight = event.offsetY - $scope.startPoint.y;
$scope.selWidth = event.offsetX - $scope.startPoint.x;
};
$scope.mouseUp = function() {
$scope.startPoint = {};
$scope.show = false;
};
});
just add these css properties
border: none;
color: transparent;
text-shadow: 0 0 0 gray;
text-align: center;
&:focus {
outline: none;
}
see the plunker http://embed.plnkr.co/9WntGyBLQxYSxkFjDAy2/

simple css animation not working on dynamic reactjs element

Check the snippet at codepen http://codepen.io/anon/pen/EZJjNO
Click on Add button, it will add another item but its appearing immediately without any fade effect.
JS:
class App extends React.Component {
constructor(props) {
super(props);
this.addItem = this.addItem.bind(this);
this.state = {
items: [1,2,3]
}
}
addItem() {
var items = this.state.items;
items.push(4);
this.setState({
items: items
})
}
render() {
return (
<div className="App">
{
this.state.items.map(function(i) {
return <div className="item fade">Testing</div>
})
}
<button onClick={this.addItem}>Add</button>
</div>
);
}
}
React.render(<App />, document.body);
CSS:
.App {
background-color: rgba(0,0,0, 0.5);
text-align: center;
height: 100vh;
}
div.item {
border: 1px solid #ccc;
padding: 10px;
background: #123456;
color: #fff;
opacity: 0;
transition: all 0.4s ease-out;
}
.fade {
opacity: 1 !important;
}
Since the fade class is added by default, you don't get the transition effect. If you open your browser's developer tools and remove the class, you'll see it fade away nicely.
There's a few ways to get what you want, but I'd just use a keyframe CSS animation like so:
.fade {
animation: 0.4s ease-out fadeIn 1;
}
#keyframes fadeIn {
0% {
opacity: 0;
visibility: hidden;
}
100% {
opacity: 1;
visibility: visible;
}
}
Here's a fork of your code pen showing how it works :)

How can I make the width of my div expand with it's content within a tooltip?

I have functioning tooltip that I would like to make responsive based on it's content. According to the inspector it is inheriting a width of 75px (I do not know from where) and then all the content is wrapping to the next line. I noticed if I change the positioning to relative all the text will go on one line, however I need to keep it's positioning absolute in order to make it appear above the svg. How can I achieve this?
I've already tried "display: inline-block" and using"float". Neither works.
<div class="tooltip-wrapper">
<div class='tooltip'>
{{content}}
</div>
<svg>
<use xlink:href={{icon}}>
</svg>
</div>
.tooltip-wrapper {
position: relative;
cursor: pointer;
svg {
height: 0.75rem;
width: 0.75rem;
}
&:hover {
.tooltip {
opacity: 1;
}
}
}
.tooltip {
position: absolute;
bottom: calc(100% + 1rem);
background-color: rgba($black, 0.7);
border-radius: 2px;
color: $white;
padding: 0.5rem;
opacity: 0;
transition: opacity $transition-timing ease;
&:before {
content: '';
position: absolute;
bottom: -0.3rem;
left: 50%;
margin-left: -0.3rem;
#include triangle(0.7rem, rgba($black, 0.7), down);
}
}
controller: ($element, $scope) ->
$scope.content = "Content stuff and stuff"
$scope.icon = "#icon-history"
link: (scope, element, attrs, ctrl) ->
#tooltipWrapper = element[0].children[0]
#tooltipIcon = #tooltipWrapper.children[1]
#tooltipContent = #tooltipWrapper.children[0]
console.log #tooltipWrapper
element.on 'mouseenter', =>
#_dropdown()
#_dropdown = (offset) =>
Lcontent = #tooltipContent.innerHTML
Lsplit = Lcontent.split(' ')
leng = 0
for i of Lsplit
leng += Lsplit[i].length
# console.log leng
if leng > 10
$(tooltipContent).css('width', #tooltipContent.width)
console.log #tooltipContent.width //this returns undefined
#left = -(#tooltipContent.offsetWidth - #tooltipIcon.offsetWidth) / 2
$(tooltipContent).css('left', #left)
This is what I was missing.
'white-space: nowrap;' inside of my 'tooltip' class. I then added the code below inside of my '#_dropdown function so it would eventually go on multiple lines if I had tons of content.
if leng > 50
$(tooltipContent).css({"width": '360px', 'white-space': 'initial'})

Why doesn't ng-style work initially with a css transition?

I'm trying to create a zoom effect, by adding a class and a width or height style to a span.
<span ng-class="fat_or_tall(this)"><figure><img ng-style="set_ratio(this)" draggable="true" class="thumb" id="{{tablet.created}}" title="{{ tablet.title }}" data-ng-src="{{ tablet.src }}" /></figure></span>
It works on the first page i'm on after the refresh, but when I click on the other tabs it just hops between sizes as if the css transition doesn't exist. If I inspect I see that sometime the styles have rendered, but sometimes they have not. After I click around the tabs and visit each one, then the zoom works properly. Why doesn't it work on the first try, and how can I fix that?
First image above notice there is no style, and the transition does not work, but after I click the tab a second time (second pic) the style does show and the transition works well.
HERE: http://jsfiddle.net/U3pVM/23506/ (If you click refresh it won't wont, but if you click run it will. The style won't render. WHY?)
function TodoCtrl($scope) {
$scope.tablet = {}
$scope.tablet.title = 'help'
$scope.tablet.created = Date.now()
$scope.tablet.src = 'http://tallclub.co.uk/wp-content/uploads/2011/04/Tall-Person-1.png'
$scope.set_ratio = function (it) { //Find ratio and return style so that it can be used for zoom effect.
console.log(it)
var img = new Image();
img.src = it.tablet.src;
console.log(it.tablet)
if(img.height>img.width){
var h = 300*(img.height/img.width)+'px'
return {
"height": h
}
}else{
var w = 300*(img.width/img.height)+'px'
return {
"width":w
}
}
}
}
function TodoCtrlTwo($scope) {
$scope.tablet = {}
$scope.tablet.title = 'help'
$scope.tablet.created = Date.now()
$scope.tablet.src = 'http://tallclub.co.uk/wp-content/uploads/2011/04/Tall-Person-1.png'
$scope.set_ratio = function (it) { //Find ratio and return style so that it can be used for zoom effect.
console.log(it)
var img = new Image();
img.src = it.tablet.src;
console.log(it.tablet)
if(img.height>img.width){
var h = 300*(img.height/img.width)+'px'
return {
"height": h
}
}else{
var w = 300*(img.width/img.height)+'px'
return {
"width":w
}
}
}
}
.taller img {
-webkit-transition: .3s ease-in-out;
transition: .3s ease-in-out;
}
.taller img:hover {
-webkit-transition: .3s ease-in-out;
transition: .3s ease-in-out;
height: 300px !important;
}
figure {
width: 300px;
height: 300px;
//height: 200px;
margin: 1em;
padding: 0;
background: #fff;
overflow: hidden;
border: 1px solid #222;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app>
<h2>ARGH</h2>
<div ng-controller="TodoCtrl">
<span class="taller"><figure><img ng-style="set_ratio(this)" draggable="true" class="thumb" id="{{tablet.created}}" title="{{ tablet.title }}" data-ng-src={{tablet.src}} /></figure></span>
</div>
<div ng-controller="TodoCtrlTwo">
<span class="taller"><figure><img ng-style="set_ratio(this)" draggable="true" class="thumb" id="{{tablet.created}}" title="{{ tablet.title }}" data-ng-src={{tablet.src}} /></figure></span>
</div>
</div>
Refresh page and click run code snippet, and mouse over. The images will jump. Then click run code snippet again and mouse over. There will be a smooth transition. Why is that?
Solution 1:
Working Demo
On first load of image, both width and height of the image are 0. So code of else block get executed which returns NaNpx.
In detail:
var w = 300*(img.width/img.height)+'px'
var w = 300*(0/0)+'px' // As img.width = 0, img.height = 0
var w = 300*(NaN)+'px'
var w = NaNpx
To resolve this, set initial height of the image:
.taller img {
-webkit-transition: .3s ease-in-out;
transition: .3s ease-in-out;
height: 500px;
}
Solution 2:
You can add following if block in both controller.
if(img.height===0 && img.width ===0){
var h = '500px';
return {
"height": h
}
}
Working Demo
Hope that solve your problem.
try this. create $scope.tablet ={}; object first.and change ng-class to class for span tag.
var app = angular.module("app",[])
app.controller('ctrl',['$scope', function($scope){
$scope.tablet ={};
$scope.tablet.title = 'help';
$scope.tablet.created = Date.now();;
$scope.tablet.src = 'http://tallclub.co.uk/wp-content/uploads/2011/04/Tall-Person-1.png'
$scope.set_ratio = function (it) { //Find ratio and return style so that it can be used for zoom effect.
console.log(it);
var img = new Image();
img.src = it.tablet.src;
console.log(it.tablet)
if(img.height>img.width){
var h = 300*(img.height/img.width)+'px'
return {'height':h};
}else{
var w = 300*(img.width/img.height)+'px'
return {
'width':w
}
}
}
}]);
.taller img {
-webkit-transition: .3s ease-in-out;
transition: .3s ease-in-out;
}
.taller img:hover {
-webkit-transition: .3s ease-in-out;
transition: .3s ease-in-out;
height: 300px !important;
}
figure {
width: 300px;
height: 300px;
//height: 200px;
margin: 1em;
padding: 0;
background: #fff;
overflow: hidden;
border: 1px solid #222;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div >
<h2>ARGH</h2>
<div>
<span class="taller">
<figure>
<img ng-mouseenter="set_ratio(this)" draggable="true" class="thumb" id="{{tablet.created}}" title="{{ tablet.title }}" data-ng- src={{tablet.src}} />
</figure>
</span>
</div>
</div>
</div>
The answer can be found here.
is there a post render callback for Angular JS directive?
I simply wrapped it in a $timeout
$timeout(function(){
$scope.set_ratio = function (it) { //Find ratio and return style so that it can be used for zoom effect.
var img = new Image();
img.src = it.tablet.src;
console.log(it.tablet)
if(img.height>img.width){
var h = 300*(img.height/img.width)+'px'
return {
"height": h
}
}else{
var w = 300*(img.width/img.height)+'px'
return {
"width":w
}
}
}
}, 50)

Resources