move water based on the user inputted value - javascript

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

Related

pts.js: Speed up animation of grid cells?

I'm using Pts.js to create a grid of cells and then color these cells depending on their distance to the mouse pointer. My code is largely based on a demo from the official Pts.js Website.
Pts.quickStart("#pt", "#123");
//
let pts = [];
var follower = new Pt();
space.add({
start: (bound) => {
pts = Create.gridCells(space.innerBound, 40, 20);
follower = space.center;
},
//
animate: (time, ftime) => {
follower = follower.add(space.pointer.$subtract(follower).divide(20));
form.stroke("#123");
//
let rects = pts.map((p) => {
let color;
let mag = follower.$subtract(Rectangle.center(p)).magnitude();
let r = Rectangle.fromCenter(Rectangle.center(p), Rectangle.size(p));
//
if (mag >= 100) {
color = "#000"
} else {
color = "#f00"
}
//
form.fill(color).rect(r);
})
//
form.fillOnly("#fff").point(space.pointer, 10, "circle");
}
})
//
space.bindMouse().bindTouch().play();
#pt {
width: 800px;
height: 600px;
margin: 30px auto 0;
}
<script src="https://unpkg.com/pts#0.9.4/dist/pts.min.js"></script>
<div id="pt"></div>
The implementation works absolutely fine. But I'd like to increase the speed with which the »coloring« of the cells »follows« the cursor, i.e. reduce the delay with which the red space around the cursor is animated. Ideally, I'd like to have no delay.
I'm new to Pts.js, so still wrapping my head around the docs, and I can't find an option or explanation for how to control the animation's speed. If anyone could point me to what I need to do here, that'd be great.
It seems that this line is what controls the behavior of the red grid area:
follower = follower.add(space.pointer.$subtract(follower).divide(20));
The value supplied to .divide() controls the speed at which the red area follows the cursor. Changing its argument from 20 to 1 (or even removing .divide(20) entirely) causes the "following" behavior to be immediate.
(Though, if you intend to remove the capability for that behavior, I suspect that entire line could be simplified.)

SVG rotation with support for all Browsers

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 + ')');
}

amcharts customized label position

Right now my graph's label is placed in a default position, but my label texts are rather long and its sticking out from the graph.
If possible, I want to place it so that the labels don't stick out from the graph.
Pic of Current situation & Ideal graph
Or if the above is not possible, I want to fix the visible labels. Is this possible?
right now, the "best" label gets lost/hidden when the graph width is reduced. The "too much" label also gets lost when the width is largely reduced.
I have been searching all over stackoverflow and amcharts website but I can't seem to find a good solution.
Is there any way to solve either of the problems...?
// tried these but doesnt work for what I want to do
va.labelOffset = -5;
va.position = "bottom";
va.inside = false;
full code in JSfiddle
In order to keep the chart from hiding the labels on resize, you need to disable the valueAxis' autoGridCount and set the gridCount to the number of tick marks you want to see. You'll also need to remove the labelFrequency setting.
va.autoGridCount = false;
va.gridCount = 3;
//va.labelFrequency = 5;
As for label positioning, you are limted to rotating and vertical offsets out of the box. As a workaround, you can position the labels by modifying the SVG nodes directly through the drawn event, for example:
// prior to chart.write
chart.addListener("drawn", function(e) {
var textNodes = e.chart.valueAxes[0].labelsSet.node.childNodes;
var transform;
//Position "too little"
transform = parseTransform(textNodes[0].getAttribute('transform'));
transform.translate[0] = parseFloat(transform.translate[0]) + 25;
textNodes[0].setAttribute('transform', serializeTransform(transform));
// Position "too much"
transform = parseTransform(textNodes[2].getAttribute('transform'));
transform.translate[0] = parseFloat(transform.translate[0]) - 25;
textNodes[2].setAttribute('transform', serializeTransform(transform));
});
// ...
// from http://stackoverflow.com/questions/17824145/parse-svg-transform-attribute-with-javascript
function parseTransform(a) {
var b = {};
for (var i in a = a.match(/(\w+\((\-?\d+\.?\d*e?\-?\d*,?)+\))+/g)) {
var c = a[i].match(/[\w\.\-]+/g);
b[c.shift()] = c;
}
return b;
}
//serialize transform object back to an attribute string
function serializeTransform(transformObj) {
var transformStrings = [];
for (var attr in transformObj) {
transformStrings.push(attr + '(' + transformObj[attr].join(',') + ')');
}
return transformStrings.join(',');
}
Updated fiddle

Adding a scale to canvas image zoom

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

SVG: Scale one element of group from specified anchor point

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).

Categories