I have made a post on Friday already about how starting off to use an SVG animation to show the state of IO hardware.
I've read a bit now because im using CSS like so
svg {
transform: rotate(45deg);
transform-origin: 50% 50%;
}
where sadly the support for IE is by giving the attribute directly to the svg:
<rect x='65' y='65' width='150' height='80'
transform='rotate(45 140 105) rotate(-45)' />
Now I've used a rect as an example but I'm actually using a shape because I need to animate a needle for a Voltmeter.
I could use stroke maybe but it would look better with a real needle like thingy.
Now the problem I have with this is that after designing, there must be a function made in Javascript to get to the different states.
So I wanna rotate the needle for example 2 degrees for every value I get from the IO.
21 states are needed and it would be a hell of work to calculate all the positions for transform rotate when the attribute is set directly onto it.
Is there another way?
Thanks in advance.
Set an id attribute for your needle, so you can target it.
Find the center point to rotate about.
Set the minimum and maximum angle the needle can rotate to.
Set the minimum and maximum value you can receive.
Now, if your SVG content is part of the same document that runs the script, no matter if that is a HTML or SVG file:
var needle = document.getElementById('voltmeterNeedle'); // use your id
If you link the SVG content with a <object> or <iframe> tag from document that runs the script (<img> won't work):
var needle, svg = document.getElementById('embedingTag'); // use your id
svg.addEventListener('load', function () { // wait for load event
needle = svg.contentCocument.getElementById('voltmeterNeedle'); // use your id
});
...continuing for both:
var needleCenterX = 140, needleCenterY = 105;
var minAngle = -45, maxAngle = 45;
var minValue = 0, maxValue = 21;
function setNeedle (value) {
var valueRatio = (value - minValue) / (maxValue - minValue);
var angle = (maxAngle - minAngle) * valueRatio + minAngle;
var rotation = [angle, needleCenterX, needleCenterY].join(' ');
needle.setAttribute('transform', 'rotate(' + rotation + ')');
}
Related
I have a svg of water vessel. The concept is the user will provide min and max range for the water vessel. If it reaches to min level, the color of water level should be shown red which i could do but how can i change the value as per the user given value. The upper level is the max part and lower level is the min part.
The path element made me difficult to change the water level. I know the d attribute of path should be change but how to adapt the d attribute with the user value.
<script>
const MIN = 0;
const MAX = 100;
// if it is near to minimum, color should be change to Red
var svg = Snap('#svg');
const s = Snap('#waterLevel');
const path = Snap('#path-3');
document.getElementById('inputValue').addEventListener('change', function(event){
path.attr({
d: `M140.79,105 L${event.target.value}`
});
if (event.target.value === "50") {
console.log('yes');
s.attr({
fill: 'red'
});
}
})
</script>
Here is the updated jsbin example with translate(0,0) used
http://jsbin.com/pocicozini/1/edit?html,output
Rather than change the shape of the path, I would be tempted to take an alternate approach. You could use a clipPath which clips the liquid, and change how high the clip is.
The core of the code would look like this..
document.getElementById('inputValue').addEventListener('change', function(event){
Snap.animate(200-Snap.select("#rectclip").attr('y'),event.target.value,
function( val ) {
Snap.select("#rectclip").attr({ y: 200 - val });
}, 50 );
});
So we place a rect over the liquid, and adjust the y value so it changes how much of the liquid path is clipped.
jsbin
I'm using a some code from https://github.com/dimxasnewfrozen/Panning-Zooming-Canvas-Demos/blob/master/demo12/main.js (demo at http://dayobject.me/canvas/demo12/) to zoom in on an image using the Canvas element.
However, when zooming the jump between one zoom level and the next is too large, so I need to add a scale parameter.
How would I got about doing this?
In your main.js, you can change your zoomLevel here,
mouseWheel: function (e) {
e.preventDefault() // Please add this, coz the scroll event bubbles up to document.
var zoomLevel = 2;
...
if (delta > 0)
{
// ZOOMING IN
var zoomedX = canvasPos.deltaX - (canvasZoomX - canvasPos.deltaX);
var zoomedY = canvasPos.deltaY - (canvasZoomY - canvasPos.deltaY);
// scale the image up by 2
initialImageWidth = initialImageWidth * zoomLevel;
}
else
{
// ZOOMING OUT
var zoomedX = (canvasPos.deltaX + canvasZoomX);
var zoomedY = (canvasPos.deltaY + canvasZoomY);
// scale the image down by 2
initialImageWidth = initialImageWidth / zoomLevel;
}
}
Disclaimer: this ruins the zoomedX and zoomedY values. You gotta fix them :)
It seams to me as if the algorithm always takes half of the dimension befor the zoom. At the end of you code you see it in main.js the mouseWheel function:
initialImageWidth = initialImageWidth * 2;
the width is divided by 2 so just change the used value.
You said the step used to zoom in and out is too big.
So I suggest that you generate the new value by using the dimensions of the image you want to zoom. For example you take a percentage of the biggest dimension of the current image.
That's how you can implement a zoom function that zooms according to the dimensions of the image
I have a javascript code that works perfectly for dragging object...but when I scaled the body down to 0.5...
transform:scale(0.5);
the position of mouse and the object dragged is not the same. How can I fix this? or is this possible?... thank you.
Heres a fiddle : http://jsfiddle.net/Xcb8d/65/
This was pretty interesting and makes me rethink all the locations I simply used offsetHeight and offsetWidth without knowing that if a transformation was applied to the element, these readonly properties in JavaScript would return incorrect.
The "trick" to this is the clientHeight/offsetHeight will not report their transformed properties correctly. In order to get the correct sizing information from the element you need to call getBoundingClientRect(). You then can calculate the correct pixel information of the scaled element, allowing you then to perform the correct positioning.
Retrieving the bounding rectangle allows you to get the pixel information off the viewport, you then can compare this information to the clientHeight within the browser to determine the scaled offset height, and position.
I modified some of the event wire ups just for testing. Also I added another class to produce a quarter sized object just to prove it works regardless of scale.
CSS:
html,
body {
width:100%;
height:100%;
}
.half-size
{
transform:scale(0.5);
-moz-transform:scale(0.5);
-webkit-transform:scale(0.5);
}
.quarter-size
{
transform:scale(0.25);
-moz-transform:scale(0.25);
-webkit-transform:scale(0.25);
}
#draggable-element {
width:100px;
height:100px;
background-color:#666;
color:white;
padding:10px 12px;
cursor:move;
position:relative; /* important (all position that's not `static`) */
display:block;
}
JavaScript:
var selected = null, // Object of the element to be moved
x_pos = 0, y_pos = 0, // Stores x & y coordinates of the mouse pointer
x_elem = 0, y_elem = 0; // Stores top, left values (edge) of the element
var elem_height = 0;
var elem_width = 0;
// Will be called when user starts dragging an element
function _drag_init(elem) {
// Store the object of the element which needs to be moved
selected = elem;
var boundingRectangle = selected.getBoundingClientRect();
y_elem = (selected.offsetHeight - (boundingRectangle.bottom - boundingRectangle.top)) / 2;
x_elem = (selected.offsetWidth - (boundingRectangle.right - boundingRectangle.left)) / 2
half_elem_height = (boundingRectangle.bottom - boundingRectangle.top) / 2;
half_elem_width = (boundingRectangle.right - boundingRectangle.left) /2;
document.addEventListener('mousemove', _move_elem, false);
document.addEventListener('mouseup', _destroy, false);
};
// Will be called when user dragging an element
function _move_elem(e)
{
x_pos = e.clientX;
y_pos = e.clientY;
selected.style.left = ((x_pos - x_elem) - half_elem_width) + 'px';
selected.style.top = ((y_pos - y_elem) - half_elem_height) + 'px';
}
// Destroy the object when we are done and remove event binds
function _destroy() {
selected = null;
document.removeEventListener('mousemove', _move_elem);
document.removeEventListener('mouseup', _destroy);
}
// Bind the functions...
document.getElementById('draggable-element').onmousedown = function () {
_drag_init(this);
};
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id="draggable-element" class='half-size'>Drag me!</div>
</body>
</html>
Click below for a live preview
http://jsbin.com/moyadici/1/edit
(I prefer jsBin over jsFiddle for its live updates)
I did modify some of the event wire ups just for my initial testing. Also I broke the transform into a style so I could try other transforms. Tests look correct when rendering the 'quarter-size'. This just proves out it works regardless of scale and you don't need a magic number for your position calculations.
Not a real answer , but too long for a comment and because it is still jumpy, maybe not on first try ...
In Firefox, using pointer-events, you could try to restrain the area that will catch the mouse.
create an inside element right in center wich has the size of the element itself once scaled.
Your fiddle says scale(0.5) a square of 100px, so lets draw a square of 50px right in the middle with a pseudo element.
Set pointer-events to none to the element and reset it back to normal for the pseudo element. Now we have a square of 50px that will accept the mouse. once the element scaled down to 50px , we still have this area reacting. (the square only looks smaller, but keeping using same space.
To finalize your fiddle test, let's add to body : transform-origin:top left;, now we should be abble to drag this square.
Firefox test :http://jsfiddle.net/Xcb8d/78/
Chrome test : http://jsfiddle.net/Xcb8d/79/ (negative margins added )
after a few clicks, it really gets jumpy of limits :)
hope it gives some hints.
reading this : http://css-tricks.com/get-value-of-css-rotation-through-javascript/
I thought , we could get the transform value from body and update calculation within the function , so we can modify scale value without touching script
. rookie test : http://jsfiddle.net/Xcb8d/82/
ex: function updated from original fiddle
// Will be called when user dragging an element
function _move_elem(e) {
var el = window.document.body;
var st = window.getComputedStyle(el, null);
var tr = st.getPropertyValue("transform") ;
var values = tr.split('(')[1];
values = values.split(')')[0];
values = values.split(',');
var a = values[0];
var b = values[1];
var c = values[2];
var d = values[3];
x_pos = document.all ? window.event.clientX : e.pageX;
y_pos = document.all ? window.event.clientY : e.pageY;
if (selected !== null) {
selected.style.left = ((x_pos / a) - x_elem) + 'px';
selected.style.top = ((y_pos / d) - y_elem) + 'px';
}
}
OK, so I have a group of four elements rotating 90 degrees as I want them to, around an origin point in the middle of the four elements.
I would like to scale the top left block before and after spinning as well, outward from said origin point, but I'm having much difficulty doing so.
Here is a fiddle for my sample (read: overly simplified) progress so far:
http://jsfiddle.net/Vac2Q/2843/
The fiddle's javascript:
/* create an svg drawing */
var draw = SVG('drawing')
/* draw rectangle */
var dial = draw.circle(60)
.move(125,125)
.fill('#0099ff')
var rect_yellow = draw.rect(50,50)
.move(100,100)
.fill('gold')
var rect_blue = draw.rect(50,50)
.move(160,100)
.fill('navy')
var rect_black = draw.rect(50,50)
.move(160,160)
.fill('black')
var rect_green = draw.rect(50,50)
.move(100,160)
.fill('green')
var blades = draw.group()
.add(rect_yellow)
.add(rect_blue)
.add(rect_black)
.add(rect_green)
.back()
var angle = 0
var rotation = 90
var spin = document.getElementById('spin')
var spun = 0
/* make rectangle jump and change color on mouse over */
spin.addEventListener('click', function() {
/* calculate new ending orientation for blades */
angle += rotation
var new_rotate = angle
/* rotate the blade group */
blades.animate(1000, '>')
.rotate(new_rotate, 155, 155)
++spun
})
And here is a slightly more glamorous example of what I'm trying to do re: scaling:
The first issue is being able to determine which blade is in the top left position after a given rotation. The second issue is scaling itself; I've gotten the blade to scale, but then it goes crazy and moves off the screen at the same time. I'm not sure how to get it to scale properly from the specified origin point (the middle of the center circle).
You can use the .after() function to chain animations.
I'm not sure if I am using svg.js correctly, but here's what I did:
var rects = [rect_yellow, rect_green, rect_black, rect_blue];
// define the animations
var enlarge_blade = function() {
rects[spun % 4].animate(250, '<')
.scale(1.25, 1.25)
.translate(-38,-38);
};
function spin_anim() {
rects[spun % 4].animate(250, '>')
.scale(1, 1)
.translate(0,0)
.after(rotate_blades);
};
var rotate_blades = function() {
blades.animate(1000, '>')
.rotate(angle, 155, 155)
.after(function() {
++spun;
enlarge_blade();
title.text('spun ' + spun + ' times');
});
};
// Pre-enlarge the first (yellow) rect
enlarge_blade();
/* make rectangle jump and change color on mouse over */
spin.addEventListener('click', function() {
angle += rotation
spin_anim();
})
Demo here
I see you're using svg.js. I don't know how it treats transforms internally. But in any case. To scale an element, you typically use its center point as a reference. Therefore you should find the center point of each rect and scale it using that point. (I assume svg.js performs the required translation internally).
I'm trying to create a rollercoaster ride for a project and need the rollercoaster to follow a path.
You can see my illustration on rollercoaster
I need the red box to follow the rollercoaster road in the background? The red box illustreres the image I'm going to use. Is this possible? I'm trying using this code...
<script type="text/javascript">
$(window).on('scroll', function(e) {
var scrollTop = $(window).scrollTop();
//var windowHeight = $(window).height();
var windowHeight = $('.road2').height();
//var S = scrollTop + Math.floor(windowHeight / 2);
var S = $(this).scrollTop(); // scrolled distance
var t = 0 + (S/windowHeight);
//var T = 0 + (S/36); // value for Top
//var L = 300 + Math.abs(Math.sin(S/400)*460); // value for Left
//
//$(".rollerImage").css({top: T+'%', left: L+'px'}); //set CSS
var canvas_X=400;
var canvas_Y=400;
// Increment Parameterization
t += 0.05;
// Width of Car
var car_X=150;
// Hieght of Car
var car_Y=50;
// Point A
var a_X=0;
var a_Y=0;
// Point B
var b_X=canvas_X-car_X; //Place point B at the end
var b_Y=0;
// Center of Semi Circle
var c_X=(b_X-a_X)/2;
var c_Y=(a_Y-a_Y)/2;
// Calculate X and Y point on trajectory
var x = a_X + t * (b_X- a_X);
var y = Math.sqrt(Math.pow((b_X - a_X),2)/4 + Math.pow((x-c_X),2));
$(".rollerImage").css({top: x+'px', left: y+'px'}); //set CSS
});
</script>
Hope someone can help with this type of path animation. Maybe it is possible to define the path in a array of coordinates?
I've tried using joel scrollpath, but can't "bind" an image to the path :(
//Graahf
I've tried to get it working with the jQuery Scrollpath using your html and css files plus the code from the demo site.
Check if this is OK for you: http://jsfiddle.net/Skr4R/6/embedded/result/
You can also check the sources of the fiddle: http://jsfiddle.net/Skr4R/6/
Important for this, is that the entire wrapper moves and rotates, that is why in my solution the train-image is outside of the wrapper, like this:
<div class="rollerCoasters">
<img src="" style="background:red; height:100px; width:50px; position:absolute; top:380px; left:50%; z-index:200; margin-left:-25px">
</div>
<div class="wrapper">
<div class="road1"><img src="base64-encoded-img" width="1434" height="539"/></div>
</div>
Hope this gets you started. It might not be the best solution, if you want the train to move, and not it's surroundings.
i am trying to achieve the same process and this has helped me along, the way forward about roating the train/object with the track could you not rotate the background(track to make the train look like it is following the track)