Animating attribute values with JavaScript | Zooming in the SVG viewBox - javascript

We have a SVG grid generated with JavaScript.
The goal is to 2X zoom the SVG grid when the user double clicks on any coordinate on the grid and have a short animation transition between the previous zoom state and current zoom state. This actually works almost 100% fine in my snippet below except one problem:
I can animate the level of zoom but cannot smoothly animate the X and Y coordinate transitions well.
View the snippet below ( preferably in full screen ) and double click on the grid a few times.
'use strict'
function zoom( evt ){
var loc = getCoords( evt ),
newX = loc.x / 0.8 - 12.5,
newY = loc.y / 0.8 - 12.5,
grid = document.getElementById( 'grid' ),
viewBoxAttr = grid.getAttribute( 'viewBox' ),
viewBoxAry = viewBoxAttr.split( ' ' ),
curX = viewBoxAry[ 0 ], curY = viewBoxAry[ 1 ],
curZm = viewBoxAry[ 2 ], dblZm = curZm / 2,
tweenZm = curZm, diffX = 0,
interval = setInterval(
function(){
if( tweenZm >= dblZm ){
tweenZm = tweenZm / 1.015625;
diffX = newX - curX;
}
else {
clearInterval( interval );
}
zmOnPt( newX, newY, tweenZm );
},
10
),
ary = [];
ary.push( curZm );
ary.push( dblZm );
}
var grid = document.getElementById( 'grid' );
grid.addEventListener( 'dblclick', zoom );
createLines( '.h-lns' ); createLines( '.v-lns' );
createLabels( '.h-num' ); createLabels( '.v-num' );
recalibrate();
<head>
<link id="main" rel="stylesheet"
href="https://codepen.io/basement/pen/brJLLZ.css"
>
<link id="animations" rel="stylesheet"
href="https://codepen.io/basement/pen/zdXRWo.css"
>
</head>
<body id="body">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" class="cntr" id="grid">
<script id="injectGrid" xlink:href="https://codepen.io/basement/pen/brJLLZ.js">
</script>
<g id="drawing">
<circle cx="60" cy="40" r="0.5" fill="#0dd" opacity="0.9" />
<circle cx="70" cy="40" r="0.5" fill="#0dd" opacity="0.9" />
<path
fill="none" opacity="0.5" stroke="#0dd" stroke-width="0.5"
d="
M60, 40
A10, 10
0,
0, 1
70, 50
C70, 55
65, 60
60, 60
Q50, 60
50, 50
T55, 35
T70, 40
"
/>
</g>
</svg>
<script id="sidebar" src="https://codepen.io/basement/pen/zdXRWo.js"></script>
<script id="main" src="https://codepen.io/basement/pen/yorjXq.js"></script>
</body>
Notice the smooth zoom animation coupled with the jarring x and y translation? The viewBox just skips to the X and Y coordinate you clicked without animating over to it. Then it zooms in on the now centered coordinates.
The goal is for the x and y to transition smoothly with the zoom.
I've hidden a lot of the code I think is irrelevant in separate files this snippet links to on codepen. If you want to see those without copy and pasting the source code though, here is a list:
MAIN CSS:
https://codepen.io/basement/pen/brJLLZ.css
ANIMATION CSS:
https://codepen.io/basement/pen/zdXRWo.css
GRID CREATION JS:
https://codepen.io/basement/pen/brJLLZ.js
SIDEBAR CODE:
https://codepen.io/basement/pen/zdXRWo.js
MAIN JAVASCRIPT:
https://codepen.io/basement/pen/yorjXq.js

Your zoom function seems unnecessarily complicated. It has seemingly arbitrary equation constants that I don't understand, and you are manipulating coordinates in a way that I don't see a purpose for.
For the version below, I am just halving the viewBox width and height, then centering that on the coordinates where you click the mouse. Then, for the animation, I just do a linear interpolation from the old viewBox values to the new ones.
function zoom( evt ) {
var loc = getCoords( evt ),
grid = document.getElementById( 'grid' ),
viewBoxAttr = grid.getAttribute( 'viewBox' ),
viewBoxAry = viewBoxAttr.split(' ');
var oldX = parseFloat(viewBoxAry[0]);
var oldY = parseFloat(viewBoxAry[1]);
var oldWidth = parseFloat(viewBoxAry[2]);
var oldHeight = parseFloat(viewBoxAry[3]);
var newWidth = oldWidth / 2; // Halving the view width => zoom X2
var newHeight = oldHeight / 2;
var newX = loc.x - newWidth / 2;
var newY = loc.y - newHeight / 2;
var animProgress = 0; // Goes from 0 to 1
var animStep = 0.02; // Change in animProgress per interval function invocation.
var interval = setInterval( function() {
animProgress += animStep;
if (animProgress > 1)
animProgress = 1;
// Calculate a new viewBox corresponding to our animation progress
var nextViewBox = [
oldX + animProgress * (newX - oldX),
oldY + animProgress * (newY - oldY),
oldWidth + animProgress * (newWidth - oldWidth),
oldHeight + animProgress * (newHeight - oldHeight)
];
grid.setAttribute("viewBox", nextViewBox.join(' '));
if (animProgress >= 1)
clearInterval( interval );
}, 10);
}
'use strict'
function zoom( evt ) {
var loc = getCoords( evt ),
grid = document.getElementById( 'grid' ),
viewBoxAttr = grid.getAttribute( 'viewBox' ),
viewBoxAry = viewBoxAttr.split(' ');
var oldX = parseFloat(viewBoxAry[0]);
var oldY = parseFloat(viewBoxAry[1]);
var oldWidth = parseFloat(viewBoxAry[2]);
var oldHeight = parseFloat(viewBoxAry[3]);
var newWidth = oldWidth / 2;
var newHeight = oldHeight / 2;
var newX = loc.x - newWidth / 2;
var newY = loc.y - newHeight / 2;
var animProgress = 0; // Goes from 0 to 1
var animStep = 0.02; // Change in animProgress per interval function invocation.
var interval = setInterval( function() {
animProgress += animStep;
if (animProgress > 1)
animProgress = 1;
// Calculate a new viewBox corresponding to our animation progress
var nextViewBox = [
oldX + animProgress * (newX - oldX),
oldY + animProgress * (newY - oldY),
oldWidth + animProgress * (newWidth - oldWidth),
oldHeight + animProgress * (newHeight - oldHeight)
];
grid.setAttribute("viewBox", nextViewBox.join(' '));
if (animProgress >= 1)
clearInterval( interval );
}, 10);
}
var grid = document.getElementById( 'grid' );
grid.addEventListener( 'dblclick', zoom );
createLines( '.h-lns' ); createLines( '.v-lns' );
createLabels( '.h-num' ); createLabels( '.v-num' );
recalibrate();
<head>
<link id="main" rel="stylesheet"
href="https://codepen.io/basement/pen/brJLLZ.css"
>
<link id="animations" rel="stylesheet"
href="https://codepen.io/basement/pen/zdXRWo.css"
>
</head>
<body id="body">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" class="cntr" id="grid">
<script id="injectGrid" xlink:href="https://codepen.io/basement/pen/brJLLZ.js">
</script>
<g id="drawing">
<circle cx="60" cy="40" r="0.5" fill="#0dd" opacity="0.9" />
<circle cx="70" cy="40" r="0.5" fill="#0dd" opacity="0.9" />
<path
fill="none" opacity="0.5" stroke="#0dd" stroke-width="0.5"
d="
M60, 40
A10, 10
0,
0, 1
70, 50
C70, 55
65, 60
60, 60
Q50, 60
50, 50
T55, 35
T70, 40
"
/>
</g>
</svg>
<script id="sidebar" src="https://codepen.io/basement/pen/zdXRWo.js"></script>
<script id="main" src="https://codepen.io/basement/pen/yorjXq.js"></script>
</body>

Related

Drag and drop rotated images javascript

so i have a code that allows me to drag and drop an img tag. The drag and drop works fine but when i added a rotation function, the drag and drop started acting weird (the coordinates changed and when i drag the element the rotation reset). Also when i try dragging again, it goes back to its initial position, do you please have any idea on how i can fix this?
This is my code and thank you in advance:
let rotate=0
function rot_plus() {
rotate=rotate+10
$("#test").css('transform',"rotate("+rotate+"deg)")
}
function rot_minus() {
rotate=rotate-10
$("#test").css('transform',"rotate("+rotate+"deg)")
}
var active = false;
var currentX;
var currentY;
var initialX;
var initialY;
var xOffset = 0;
var yOffset = 0;
let current_elem
var container = document.querySelector("#boite");
container.addEventListener("mousedown", dragStart, false);
container.addEventListener("mouseup", dragEnd, false);
container.addEventListener("mousemove", drag, false);
function dragStart(e) {
if(e.target.id=="test"){
dragItem1=e.target.id
dragItem = document.querySelector("#"+e.target.id);
initialX=e.clientX-xOffset
initialY=e.clientY-yOffset
active = true;
}
}
function drag(e) {
if (active) {
e.preventDefault();
currentX = e.clientX - initialX;
currentY = e.clientY - initialY;
xOffset = currentX;
yOffset = currentY;
setTranslate(currentX, currentY, dragItem);
}
}
function dragEnd(e) {
active = false;
initialX=currentX
initialY=currentY
selectedElement = null;
}
function setTranslate(xPos, yPos, el) {
el.style.transform = "translate3d(" + xPos + "px, " + yPos + "px, 0) rotate("+rotate+"deg)";
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js" integrity="sha512-STof4xm1wgkfm7heWqFJVn58Hm3EtS31XFaagaa8VMReCXAkQnJZ+jEy8PCC/iT18dFy95WcExNHFTqLyp72eQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<div id="boite">
<img src="https://static.vecteezy.com/system/resources/previews/009/342/282/original/cartoon-eyes-clipart-design-illustration-free-png.png" id="test" class="remove" style="position: absolute; width:150px; height:auto" >
<svg xmlns="http://www.w3.org/2000/svg" width="46" height="46" fill="currentColor" class="bi bi-plus-circle" id="rotplus" style="margin-top:120px" onclick="rot_plus()" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"/>
<path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg"width="46" height="46" fill="currentColor" class="bi bi-dash-circle" id="rotminus"
style="margin-top:120px" onclick="rot_minus()" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z"/>
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z"/>
</svg>
</div>
</body>
</html>
You are using $.css to change the transform in the rotation functions. But this removes the positional changes as both are defined in 'transform'. That is, to fix this you need to keep the position information when rotating.
To do this it is better not to use jquery as it will clean the information in transform. So what I did was just replicate the line where you define the position but instead of taking the positions defined in your function I take it directly from the variables where you store the values.
I also used a CSS to prevent items from being selected when dragging:
CSS:
#boite,
#boite * {
user-select: none;
}
JS:
function rot_plus() {
const el = lastItemDragged
rotate = rotate + 10;
el.style.transform = "translate3d(" + xOffset + "px, " + yOffset + "px, 0) rotate(" + rotate + "deg)";
}
function rot_minus() {
const el = lastItemDragged
rotate = rotate - 10;
el.style.transform = "translate3d(" + xOffset + "px, " + yOffset + "px, 0) rotate(" + rotate + "deg)";
}
function setTranslate(el) {
el.style.transform = "translate3d(" + xOffset + "px, " + yOffset + "px, 0) rotate(" + rotate + "deg)";
}
I also added the variable lastItemDragged to store the last item dragged (so that the rotation reaches the same)
full code:
let rotate = 0
function rot_plus() {
const el = lastItemDragged
rotate = rotate + 10;
el.style.transform = "translate3d(" + xOffset + "px, " + yOffset + "px, 0) rotate(" + rotate + "deg)";
}
function rot_minus() {
const el = lastItemDragged
rotate = rotate - 10;
el.style.transform = "translate3d(" + xOffset + "px, " + yOffset + "px, 0) rotate(" + rotate + "deg)";
}
var lastItemDragged = document.querySelector('#test')
var active = false;
var currentX;
var currentY;
var initialX;
var initialY;
var xOffset = 0;
var yOffset = 0;
let current_elem
var container = document.querySelector("#boite");
container.addEventListener("mousedown", dragStart, false);
container.addEventListener("mouseup", dragEnd, false);
container.addEventListener("mousemove", drag, false);
function dragStart(e) {
if (e.target.id == "test") {
dragItem1 = e.target.id
dragItem = document.querySelector("#" + e.target.id);
initialX = e.clientX - xOffset
initialY = e.clientY - yOffset
active = true;
}
}
function drag(e) {
if (active) {
e.preventDefault();
currentX = e.clientX - initialX;
currentY = e.clientY - initialY;
xOffset = currentX;
yOffset = currentY;
setTranslate(dragItem);
}
}
function dragEnd(e) {
active = false;
initialX = currentX
initialY = currentY
selectedElement = null;
}
function setTranslate(el) {
el.style.transform = "translate3d(" + xOffset + "px, " + yOffset + "px, 0) rotate(" + rotate + "deg)";
}
#boite,
#boite * {
user-select: none;
}
<div id="boite">
<img src="https://static.vecteezy.com/system/resources/previews/009/342/282/original/cartoon-eyes-clipart-design-illustration-free-png.png" id="test" class="remove" style="position: absolute; width:150px; height:auto">
<svg xmlns="http://www.w3.org/2000/svg" width="46" height="46" fill="currentColor" class="bi bi-plus-circle" id="rotplus" style="margin-top:120px" onclick="rot_plus()" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z" />
<path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="46" height="46" fill="currentColor" class="bi bi-dash-circle" id="rotminus" style="margin-top:120px" onclick="rot_minus()" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z" />
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z" />
</svg>
</div>

How to adjust context menu to always keep it within the table frame

I am struggleing in issue. The issue that i am trying to popup context menu but when i click at the edges of the container div. the context menu getting flow out from this container div.
Example :
This is the menu when i click somewhere away from the edges.
This what happen if i click near to the edges.
HTML:-
<div id="rows-menu-wrapper-container" class="rows-menu-wrapper-container" style="/*display: none;*/" onclick="$(this).remove()">
<div id="rows-menu-wrapper" class="rows-menu-wrapper">
<div id="rows-menu-wrapper-menu-item" class="rows-menu-wrapper-menu-item"><label class="form-label text-truncate rows-menu-wrapper-menu-item-label">Open Menu</label></div>
</div>
</div>
CSS:-
.rows-menu-wrapper-container {
width: 100vw;
height: 100vh;
position: fixed;
top: 0px;
left: 0px;
pointer-events: auto;
background-color: rgba(26,26,26,0.11);
}
Placing the menu using JS:-
// top position
var topY = e.target.getBoundingClientRect().top + document.documentElement.scrollTop
var topX = e.target.getBoundingClientRect().left + document.documentElement.scrollLeft - 250
newPaper.find(".rows-menu-wrapper").css('top' , topY + 'px' )
newPaper.find(".rows-menu-wrapper").css('left' , topX + 'px' )
$('body').append(newPaper)
var paperHeight = newPaper.css('height').replace('px' , '') - 400
var delta = (e.clientY - newPaper.css('height').replace('px' , ''))
delta = parseFloat(delta.toString().replace('-' , '') )
delta = delta * 1.5
if ( paperHeight <= e.clientY ){newPaper.find(".rows-menu-wrapper").css('top' , topY - delta + 'px' )}
I Checked many guides but never understand how it is work.
I would be greatful if someone make it simple for me :(
UPDATE1
I managet to get around of this with below:
// top position
var topY = e.target.getBoundingClientRect().top + document.documentElement.scrollTop
var topX = e.target.getBoundingClientRect().left + document.documentElement.scrollLeft - 250
newPaper.find(".rows-menu-wrapper").css('left' , topX + 'px' )
newPaper.find(".rows-menu-wrapper").css('top' , topY + 'px' )
$('body').append(newPaper)
var totalHeight = newPaper.css('height').replace('px' , '')
var clickY = e.clientY
var elementHight = newPaper.find(".rows-menu-wrapper").css('height').replace('px' , '')
var delta = totalHeight - clickY - elementHight
if (delta <= 0){topY = topY - elementHight + 20 }
newPaper.find(".rows-menu-wrapper").css('top' , topY + 'px' )
IDK if this approach is ok or not clean.

Svg Draw flickering happening in Chrome browser

I need to allow user to draw a shape and I have used svg for same.
In other browser the code is working perfectly fine, but in case of chrome Version 52.0.2743.116 m it is flickering. When I created it it was working fine. But as chrome was updated the issue started happening
Issue is not replicable in chrome Version 49.0.2623.110 m
https://jsfiddle.net/2svxmgwu/1/
Try to drag and drop in yellow area from left top side to right bottom you will see barcode
Refer the attached image
The flickering does not happen if direction of creating shape is other then from top left to lower bottom.
Code
Html
<div class="thisComp">
<div class="svgElementDiv">
</div>
</div>
Js
var svgShape = $('<svg viewBox="0 0 640 480" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg"><g><title>Layer 1</title> <rect stroke="#5B9BD5" id="svg_11" height="473.99998" width="635.99997" y="3" x="3" stroke-linecap="null" stroke-linejoin="null" preserveAspectRatio="none" vector-effect="non-scaling-stroke" stroke-dasharray="null" stroke-width="3" fill="#5B9BD5"/> </g></svg>');
var self = this;
//Added for chrome browser as without this flickering is very high
svgShape.find('[vector-effect="non-scaling-stroke"]').removeAttr('vector-effect');
var $ShapeWrapper = $(".svgElementDiv");
var $thisComp = $(".thisComp");
svgShape.css({
position: "absolute",
left: "0",
top: "0",
width: "100%",
height: "100%",
opacity: "0.5"
});
$ShapeWrapper.css({
position: "fixed"
});
$thisComp.mousedown(function (event) {
if ($ShapeWrapper.length > 0) {
$ShapeWrapper.html(svgShape);
$ShapeWrapper.css("left", event.clientX);
$ShapeWrapper.css("top", event.clientY);
self._selectorLeftPos = event.clientX;
self._selectorTopPos = event.clientY;
$ShapeWrapper.css({
width: "0",
height: "0"
});
self._dragged = false;
event.preventDefault();
}
});
var removeShape = function (event) {
if ($ShapeWrapper.find(svgShape).length > 0 && !(event.type=="mouseleave" && $(event.relatedTarget).closest('.guideWrapper').length>0)) {
var startX = (($ShapeWrapper.offset().left - $thisComp.offset().left) / self._transformRatio) / self._conversionFactor;
var startY = (($ShapeWrapper.offset().top - $thisComp.offset().top) / self._transformRatio) / self._conversionFactor;
var selectWidth = ($ShapeWrapper.width() / self._transformRatio) / self._conversionFactor;
var selectHeight = ($ShapeWrapper.height() / self._transformRatio) / self._conversionFactor;
self._shapeData = '{"left":"' + startX + '","top":"' + startY + '","height":"' + selectHeight + '","width":"' + selectWidth + '"}';
svgShape.remove();
}
}
$thisComp.mousemove(function (event) {
if ($ShapeWrapper.length > 0) {
var width = 0;
var height = 0;
if (event.clientX <= self._selectorLeftPos) {
width = $ShapeWrapper.offset().left - event.clientX + $ShapeWrapper.width();
$ShapeWrapper.css("left", event.clientX);
}
else {
width = event.clientX - $ShapeWrapper.offset().left;
}
if (event.clientY <= self._selectorTopPos) {
height = $ShapeWrapper.offset().top - event.clientY + $ShapeWrapper.height();
$ShapeWrapper.css("top", event.clientY);
}
else {
height = event.clientY - $ShapeWrapper.offset().top;
}
$ShapeWrapper.css("width", width);
$ShapeWrapper.css("height", height);
if (width > 3 || height > 3) {
self._dragged = true;
}
}
});
$thisComp.bind("mouseup", removeShape);
$thisComp.bind("mouseleave", removeShape);
Css
.thisComp{
height:400px;
width:400px;
background-color:yellow;
}

Javascript Circle slider degrees to time

I am looking at this slider http://jsfiddle.net/sCanr/1/.
(function () {
var $container = $('#container');
var $slider = $('#slider');
var sliderW2 = $slider.width()/2;
var sliderH2 = $slider.height()/2;
var radius = 200;
var deg = 0;
var elP = $('#container').offset();
var elPos = { x: elP.left, y: elP.top};
var X = 0, Y = 0;
var mdown = false;
$('#container')
.mousedown(function (e) { mdown = true; })
.mouseup(function (e) { mdown = false; })
.mousemove(function (e) {
if (mdown) {
var mPos = {x: e.clientX-elPos.x, y: e.clientY-elPos.y};
var atan = Math.atan2(mPos.x-radius, mPos.y-radius);
deg = -atan/(Math.PI/180) + 180; // final (0-360 positive) degrees from mouse position
X = Math.round(radius* Math.sin(deg*Math.PI/180));
Y = Math.round(radius* -Math.cos(deg*Math.PI/180));
$slider.css({ left: X+radius-sliderW2, top: Y+radius-sliderH2 });
// AND FINALLY apply exact degrees to ball rotation
$slider.css({ WebkitTransform: 'rotate(' + deg + 'deg)'});
$slider.css({ '-moz-transform': 'rotate(' + deg + 'deg)'});
//
// PRINT DEGREES
$('#test').html('angle deg= '+deg);
}
});
})();
What i want to do it turn this into a time line control for a html5 video. However, i am having some trouble with calculating the math behind this.
Try this:
http://jsfiddle.net/phdphil/Zv4K7/#base
It works by keeping global variables for the current position and last angle (you should change this setup to construct a specific dial with its own state). Each movement then calculates the delta (modulo 360, which requires a proper modulus function) and assumes that movements of < 180 degrees are forward movements, and > 180 degrees (remember -1 modulo 360 is 359) are negative movements. This then updates the cumulative total position:
var current = 0;
var lastAngle = 0;
// ... inside the handler
var delta = 0;
var dir = 0;
var rawDelta = mod(deg-lastAngle,360.0);
if(rawDelta < 180) {
dir = 1;
delta = rawDelta;
} else {
dir = -1;
delta = rawDelta-360.0;
}
current += delta;
lastAngle = deg;
$('#test').html('angle deg= '+current); // current instead of deg
Just for clarity, the dir variable holds the direction of this movement, which could be used to update a >> or << indicator onscreen.
The real modulus function, taken from this SO answer:
function mod(x,n) {
return ((x%n)+n)%n;
}

random position of divs in javascript

I'm trying to make Divs to appear randomly anywhere on a webpage with javascript. So a div appears then disappears, then another div appears somewhere else on the page then disappears, then another div appears again in another random spot on the page then disappears, and so on.
I'm not sure on how to generate random units in pixels or what technique to use to generate random positions.
How do I do that? Here's my code:
var currentDivPosition = myDiv.offset(),
myDivWidth = myDiv.width(),
myDivHeight = myDiv.height(),
var myDiv = $('<div>'),
finalDivPositionTop, finalDivPositionLeft;
myDiv.attr({ id: 'myDivId', class: 'myDivClass' }); // already defined with position: absolute is CSS file.
// Set new position
finalDivPositionTop = currentDivPosition.top + Math.floor( Math.random() * 100 );
finalDivPositionLeft = currentDivPosition.left + Math.floor( Math.random() * 100 );
myDiv.css({ // Set div position
top: finalDivPositionTop,
left: finalDivPositionLeft
});
$('body').append(myDiv);
myDiv.text('My position is: ' + finalDivPositionTop + ', ' + finalDivPositionLeft);
myDiv.fadeIn(500);
setTimeout(function(){
myDiv.fadeOut(500);
myDiv.remove();
}, 3000);
Here's one way to do it. I'm randomly varying the size of the div within a fixed range, then setting the position so the object is always placed within the current window boundaries.
(function makeDiv(){
// vary size for fun
var divsize = ((Math.random()*100) + 50).toFixed();
var color = '#'+ Math.round(0xffffff * Math.random()).toString(16);
$newdiv = $('<div/>').css({
'width':divsize+'px',
'height':divsize+'px',
'background-color': color
});
// make position sensitive to size and document's width
var posx = (Math.random() * ($(document).width() - divsize)).toFixed();
var posy = (Math.random() * ($(document).height() - divsize)).toFixed();
$newdiv.css({
'position':'absolute',
'left':posx+'px',
'top':posy+'px',
'display':'none'
}).appendTo( 'body' ).fadeIn(100).delay(1000).fadeOut(500, function(){
$(this).remove();
makeDiv();
});
})();
Edit: For fun, added a random color.
Edit: Added .remove() so we don't pollute the page with old divs.
Example: http://jsfiddle.net/redler/QcUPk/8/
Let's say you have this HTML:
<div id="test">test div</div>
And this CSS:
#test {
position:absolute;
width:100px;
height:70px;
background-color:#d2fcd9;
}
Using jQuery, if you use this script, whenever you click the div, it will position itself randomly in the document:
$('#test').click(function() {
var docHeight = $(document).height(),
docWidth = $(document).width(),
$div = $('#test'),
divWidth = $div.width(),
divHeight = $div.height(),
heightMax = docHeight - divHeight,
widthMax = docWidth - divWidth;
$div.css({
left: Math.floor( Math.random() * widthMax ),
top: Math.floor( Math.random() * heightMax )
});
});
The way this works is...first you calculate the document width and height, then you calculate the div width and height, and then you subtract the div width from the document width and the div height from the document height and consider that the pixel range you're willing to put the div in (so it doesn't overflow out of the document). If you have padding and border on the div, you'll need to account for those values too. Once you've figured out the range, you can easily multiple that by Math.random() and find the random position of your div.
So once more: first find the dimensions of the container, then find the dimensions of your element, then subtract element dimensions from container dimensions, and THEN use Math.random() on that value.
The basic idea is encapsulated here:
http://jsfiddle.net/5mvKE/
Some bugs:
You missed to position the div absolutely. Otherwise it will not
work.
I think you need to ad 'px' to the numbers.
The map is made of strings
Right in your jQuery css setup:
myDiv.css({
'position' : 'absolute',
'top' : finalDivPositionTop + 'px',
'left' : finalDivPositionLeft + 'px'
});
I changed an existant code by this one for our website, you can see it on tweefox.nc
<script>
function draw() {
$(canvas).attr('width', WIDTH).attr('height',HEIGHT);
con.clearRect(0,0,WIDTH,HEIGHT);
for(var i = 0; i < pxs.length; i++) {
pxs[i].fade();
pxs[i].move();
pxs[i].draw();
}
}
function Circle() {
this.s = {ttl:8000, xmax:10, ymax:4, rmax:10, rt:1, xdef:950, ydef:425, xdrift:4, ydrift: 4, random:true, blink:true};
this.reset = function() {
this.x = (this.s.random ? WIDTH*Math.random() : this.s.xdef);
this.y = (this.s.random ? HEIGHT*Math.random() : this.s.ydef);
this.r = ((this.s.rmax-1)*Math.random()) + 1;
this.dx = (Math.random()*this.s.xmax) * (Math.random() < .5 ? -1 : 1);
this.dy = (Math.random()*this.s.ymax) * (Math.random() < .5 ? -1 : 1);
this.hl = (this.s.ttl/rint)*(this.r/this.s.rmax);
this.rt = Math.random()*this.hl;
this.s.rt = Math.random()+1;
this.stop = Math.random()*.2+.4;
this.s.xdrift *= Math.random() * (Math.random() < .5 ? -1 : 1);
this.s.ydrift *= Math.random() * (Math.random() < .5 ? -1 : 1);
}
this.fade = function() {
this.rt += this.s.rt;
}
this.draw = function() {
if(this.s.blink && (this.rt <= 0 || this.rt >= this.hl)) {
this.s.rt = this.s.rt*-1;
this.dx = (Math.random()*this.s.xmax) * (Math.random() < .5 ? -1 : 1);
this.dy = (Math.random()*this.s.ymax) * (Math.random() < .5 ? -1 : 1);
} else if(this.rt >= this.hl) this.reset();
var newo = 1-(this.rt/this.hl);
con.beginPath();
con.arc(this.x,this.y,this.r,0,Math.PI*2,true);
con.closePath();
var cr = this.r*newo;
g = con.createRadialGradient(this.x,this.y,0,this.x,this.y,(cr <= 0 ? 1 : cr));
g.addColorStop(0.0, 'rgba(255,255,255,'+newo+')');
g.addColorStop(this.stop, 'rgba(255,255,255,'+(newo*.2)+')');
g.addColorStop(1.0, 'rgba(255,255,255,0)');
con.fillStyle = g;
con.fill();
}
this.move = function() {
this.x += (this.rt/this.hl)*this.dx;
this.y += (this.rt/this.hl)*this.dy;
if(this.x > WIDTH || this.x < 0) this.dx *= -1;
if(this.y > HEIGHT || this.y < 0) this.dy *= -1;
}
this.getX = function() { return this.x; }
this.getY = function() { return this.y; }
}
$(document).ready(function(){
// if( /Android|AppleWebKit|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
// } else {
if(document.getElementById('pixie')) {
WIDTH = $(window).width();
HEIGHT = $(window).height();
canvas = document.getElementById('pixie');
$(canvas).attr('width', WIDTH).attr('height',HEIGHT);
con = canvas.getContext('2d');
pxs = new Array();
rint = 60;
for(var i = 0; i < 50; i++) {
pxs[i] = new Circle();
pxs[i].reset();
}
setInterval(draw,rint);
}
// }
});
</script>

Categories