I've created a script that activates on mouseover on a parent container and should move it's child elements away from the mouse. I've currently got it working but there are some parts of the code that seem to contradict what REACT code should look like. Especially two parts.
I'm using a counter in the render function so that each span gets it's correct custom property from
state.customProperties
which is an array that updates the custom properties on mouseover of the parent element.render() { let counter = 0; const returnCustomProp = function(that) { counter++; let x = 0; if (that.state.customProperties[counter - 1]) { x = that.state.customProperties[counter - 1].x; } let y = 0; if (that.state.customProperties[counter - 1]) { y = that.state.customProperties[counter - 1].y; } return "customProperty(" + x + " " + y + ")"; } return ( <div onMouseMove={this._testFunction} id="ParentContainer"> <section custom={returnCustomProp(this)}> <b>Custom content for part 1</b> <i>Could be way different from all the other elements</i> </section> <section custom={returnCustomProp(this)}> 2 </section> <section custom={returnCustomProp(this)}> <div> All content can differ internally so I'm unable to create a generic element and loop trough that </div> </section> <section custom={returnCustomProp(this)}> 4 </section> <section custom={returnCustomProp(this)}> 5 </section> <section custom={returnCustomProp(this)}> <div> <b> This is just test data, the actualy data has no divs nested inside secions </b> <h1> 6 </h1> </div> </section> <section custom={returnCustomProp(this)}> 7 </section> <section custom={returnCustomProp(this)}> 8 </section> </div> ); }
In the mousemove function I'm using
document.getElementById
andquerySelectorAll
to get all the section elements and compare the mouse coordinates from the mouse to the section elements coordinates.var mouseX = e.pageX; var mouseY = e.pageY; var spans = document.getElementById('ParentContainer').querySelectorAll('section'); var theRangeSquared = 10 * 10; var maxOffset = 5; var newCustomProperties = []; for (var i = 0; i < spans.length; i++) { var position = spans[i].getBoundingClientRect(); var widthMod = position.width / 2; var heightMod = position.height / 2; var coordX = position.x + widthMod; var coordY = position.y + heightMod + window.scrollY; // Distance from mouse var dx = coordX - mouseX; var dy = coordY - mouseY; var distanceSquared = (dx * dx + dy * dy); var tx = 0, ty = 0; if (distanceSquared < theRangeSquared && distanceSquared !== 0) { // Calculate shift scale (inverse of distance) var shift = maxOffset * (theRangeSquared - distanceSquared) / theRangeSquared; var distance = Math.sqrt(distanceSquared); tx = shift * dx / distance; ty = shift * dy / distance; } newCustomProperties.push({ x: tx, y: ty }); }
I have a feeling I'm going about this all wrong. I'm not sure how I could avoid the counter while keeping a generic returnCustomProp
function to return the properties for said element (in the live code I've got about 200 of these elements so setting the array item number for them manually is not efficient).
The second part feels hacky to target an element by ID that is inside the actual component. I feel like I should be able to target this without traversing trough the DOM. Referencing the section elements could be a solution, but I believe references should be kept to a minimum and as stated, the actual code consists of hundreds of these sections.
The code does not do much more atm than update the custom="customProperty(0 0)"
property. You can see this happen trough the element inspector on mouseover.
Can I make this functionality work withouth having to count the <section>
elements inside the render function and without having to use document.querySelectorAll
?