Problem with the '.style.transform=' in JS - javascript

I have this SVG header that, on screen scroll, its parts move differently. For this, I am using a script like the following:
let menu = document.getElementById('main-menu');
let lua = document.getElementById('lua');
window.addEventListener('scroll', function(){
let value = window.scrollY;
menu.style.marginTop = value * 0.45 + 'px'; // working just fine
lua.style.transform = "translateY(" + value * 0.25 + ")"; // don't know how to make this work
OBS: I need to use the transform: translate because this SVG element, for some reason, can't be moved with margin or top/left, only translate.
The menu.style work just fine, but on the lua.style case I'm struggling cause I don't know how to write on the JS a CSS such as transform: translateY that merges a child property (translate) inside another property (transform).
I've tried to write the lua.style.transform = "translateY(" + value * 0.25 + ")"; in many different ways, like:
lua.style.transform = value + "translateY(" * 0.25 + ")";
// or
lua.style.translate = value * 0.45 + 'px';
// or
lua.style.translate = value * 0.45;
// or
lua.style.translate = (0,value * 0.45);
but still can't make it work. How can I write it correctly?

DONE! I used the template literal that Dane Landry explained in the comments. Thanks man.
The code:
lua.style.transform = ` translateY(${value * 0.25}px ) `;
And also thanks kmoser for reminding me translate demans a unit of measurement. It does.

Related

Controlling font weight dependent on mouse position on the screen

I'm using ABC Dinamo's resource on variable fonts but am getting a bit stuck. I'm trying to control font weight in relation to the user's mouse movements, for which they provide this script:
function updateText(e) {
multiplierWidth = e.offsetX / window.innerWidth;
multiplierHeight = e.offsetY / window.innerHeight;
randomWeight = multiplierWidth * (200 - 35) + 35;
randomWidth = multiplierHeight * (200 - 100) + 100;
myText.style.fontVariationSettings = "\"wght\" " + randomWeight + ", \"wdth\" " + randomWidth;
}
window.addEventListener("mousemove", updateText)
However, the font I'm using only has one variable axis, weight, from 200 to 800. The code they provide is for a font that has two, weight and width.
I've tried to use the code as is (but with 'myText.style' replaced with the h7 tag I need to use), but that doesn't work. I've tried using this edited version, but it doesn't work either:
function updateText(e) {
multiplierWidth = e.offsetX / window.innerWidth;
multiplierHeight = e.offsetY / window.innerHeight;
randomWeight = multiplierWidth * (200 - 35) + 35;
h7.fontVariationSettings = "\"wght\" " + randomWeight;
}
window.addEventListener("mousemove", updateText)
Can anyone tell me where I'm going wrong please? Am I missing parts of the script? The guide is useful to a point but I think it's not quite clear enough for script novices like me!

Prevent subpixel rendering with svg

I'm working with SVGs currently and came to a dead end.
The SVG has lines, which should scale together with zooming (so that they stay in balance: 100% width 10px --> 10% width 1px for example)
i scale all stroke-widths with this code:
var svgPath = this._svgContainer.find('svg [class*="style"]');
for (var i = 0; i < svgPath.length; ++i) {
var newStrokeWidth = this._oldStrokeWidth[i] * (1 / (width / imgData.w));
$(svgPath[i]).css(
'stroke-width', newStrokeWidth
);
}
Where width is the new width after zoom and imgData.w is the original unscaled width.
The problem with this is, if i zoom in to far. The stroke with becomes to small and leads to sub-pixel rendering. And supposedly black lines get grey-ish.
My Idea was to clip the value at a certain point to prevent it.
But as far as I know, I have to consider the Device Pixel ratio too, because of different screens (desktop, mobile, 4K)
Would be nice If someone can help me with an idea to fix my problem
We finally found a solution for this, in case anyone has the same problems:
1) Because of the panning of this._$svgElement and the calculation of vpx in a completely different section of the code the element is 'between' pixels. ( 100.88945px for x for example). This causes lines to blur.
I fixed this part with a simple Math.round().
this._hammerCanvas.on('panmove', (event: any) => {
const translate3d = 'translate3d(' + Math.round(this._oldDeltaX + ((vpx === imgData.x) ? 0 : vpx) + event.deltaX) + 'px, ' + Math.round(this._oldDeltaY + ((vpy === imgData.y) ? 0 : vpy) + event.deltaY) + 'px, 0)';
this._$svgElement.css({
transform: translate3d
});
}
2) To fix the problem between the SVG viewport and the line strength, I had to implement a method to calculate the strokewidth equal to 1 'real' pixel regarding the svgs dimension.
the updated code looks like this: (This is the inital code, after the SVG was loaded from the server. Inside the zooming, the old code from above is still the same)
const pixelRatio = devicePixelRatio || 1;
const widthRatio = this._initSVGWidth / svgContainerWidth;
const heightRatio = this._initSVGHeight / svgContainerHeight;
this._svgZoomFactor = Math.max(widthRatio, heightRatio);
const strokeWidth1px = this.computeStrokeWidth1px(widthRatio, heightRatio);
for (let i = 0; i < svgPaths.length; ++i) {
this._initalStrokeWidth[i] = parseFloat($(svgPaths[i]).css('stroke-width'));
const newStrokeWidth = Math.max(strokeWidth1px / pixelRatio, this._svgZoomFactor * this._initalStrokeWidth[i]);
$(svgPaths[i])[0].setAttribute('style', 'stroke-width:' + newStrokeWidth);
this._oldStrokeWidth[i] = newStrokeWidth;
}
and the compute:
protected computeStrokeWidth1px (widthRatio: number, heightRatio: number): number {
const viewBox = this._$svgElement[0].getAttribute('viewBox').split(' ');
const viewBoxWidthRatio = parseFloat(viewBox[2]) / this._$svgElement.width();
const viewBoxHeightRatio = parseFloat(viewBox[3]) / this._$svgElement.height();
return widthRatio > heightRatio ? viewBoxWidthRatio : viewBoxHeightRatio;
}
var newStrokeWidth = this._oldStrokeWidth[i] * (1 / (width / imgData.w));
newStrokeWidth = (newStrokeWidth < 1) ? 1 : newStrokeWidth;
newStrokeWidth will always be 1 or greater

Addition operators not working

I'm trying to make one-page scrolling but I have a small problem. I have
var main = document.getElementById('main');
window.addEventListener('scroll', function(){
window.scrollTo(0, 0);
var top = -main.offsetTop;
main.style.top = -100 + '%';
});
Now this only works once obviously, so I'm trying to put an addition operator so it deducts a 100% every time you scroll.
main.style.top -= 100 + '%';
but that doesn't work for some reason..
Addition works if I do this instead...
var top = main.offsetTop;
main.style.top = top - 100 + '%';
but this fucks things up since top is technically in px not %. So any ideas how to make main.style.top -= 100 + '%'; work or a good alternative instead?
Let me write the expression main.style.top -= 100 + '%'; in another way that means the same thing:
main.style.top -= (100 + '%' /* this is a string now */)
What happens if you -= a string from anything? The first expression that you put (main.style.top = top - 100 + '%';) was closer to what you want but still not right. If you want to subtract 100% of the top value every time, like you said you need to do it in terms of pixels, not percent. So first you need to find how many pixels is 100 percent, which looking at your code might just be the value of main.offsetTop for you. Then you need to subtract that value from the top value. So what you have first is close but I think you need:
var main = document.getElementById('main');
window.addEventListener('scroll', function(){
window.scrollTo(0, 0);
var top = main.offsetTop;
main.style.top -= top;
});

Image slider is choppy

I have put together a plain javascript/css image slider, started out as just a learning exercise but am now looking to apply it in the real world. The problem is that the animation is choppy on my desktop (which is a v. high spec gaming rig) - and even worse on a mobile (to the degree it's not really an animation anymore)
You can see it in action here:
www.chrishowie.co.uk/sands/
jsfiddle isolates much of the pertinent code - it's not a "this doesn't work" issue, so hopefully the fiddle gives enough to help optimize it.
http://jsfiddle.net/9aozrxy8/5/
In summary: I have a DIV with 4 images in a row, each image is 100% the width of the page. I use javascript to translateX (I have tried translate3d as heard this uses GPU, but didnt make much diff) and I set CSS transitions to ease-in the transform.
I also thought that potentially I am just trying to do too much on this site - but then I look at some other sites doing a heck of a lot more and it's smooth as silk. So I guess I'm missing something.
function slideRight() {
if (sliding) {
return false
};
window.sliding = true;
el = document.getElementById("slider");
cst = getComputedStyle(el);
transformst = cst.transform || cst.webkitTransform || cst.mozTransform;
widthst = cst.width;
widthst = widthst.replace("px", ""); // computed width of slider (7680px)
slidewidth = widthst / 4;
transformst = transformst.replace("matrix(", "");
transformst = transformst.replace(")", "");
transformst = transformst.split(",");
transformst = transformst[4]; // returns current transform in px without unit (px)
if (!transformst) {
transformst = 0;
}
var activebtn = "sldr" + Math.round((Number(transformst) / (-1 * slidewidth)));
document.getElementById(activebtn).classList.remove("sliderbuttonactive");
if (activebtn != "sldr3") {
document.getElementById("slider" + Math.round((2 + Number(transformst) / (-1 * slidewidth)))).style.visibility = "visible";
document.getElementById("slider" + Math.round((2 + Number(transformst) / (-1 * slidewidth)))).style.display = "initial";
document.getElementById("slider").style.transform = "translate3d(" + 25 * ((Number(transformst) / (slidewidth)) - 1) + "%, 0, 0)";
document.getElementById("slider").style.transform = "-webkit-translate3d(" + 25 * ((Number(transformst) / (slidewidth)) - 1) + "%, 0, 0)";
document.getElementById("slider").style.transform = "-moz-translate3d(" + 25 * ((Number(transformst) / (slidewidth)) - 1) + "%, 0, 0)";
document.getElementById("slider").style.transform = "-ms-translate3d(" + 25 * ((Number(transformst) / (slidewidth)) - 1) + "%, 0, 0)";
document.getElementById("leftslidebtn").style.visibility = "visible";
document.getElementById("leftslidebtn").style.display = "block";
}
activebtn = activebtn.replace("sldr", "");
activebtn = "sldr" + (1 + Number(activebtn));
document.getElementById(activebtn).classList.add("sliderbuttonactive");
if (Number(activebtn.replace("sldr", "")) == 3) {
document.getElementById("rightslidebtn").style.visibility = "hidden";
document.getElementById("rightslidebtn").style.display = "none";
}
setTimeout(function () {
window.sliding = false
}, 2000);
}
update: still not resolved but on mobile I have made it usable by reducing the image size for small screens and also not displaying images that are off-screen. Not perfectly smooth but getting there.
Thanks a lot,
C
Like Jeremy mentioned, that the "transition" in your JSFiddle caused the problem, it's also causing it on your website.
In your "Main.css" in line 221. Remove the "transition: top ease 2s;" from class .slide
Everything works fine then on Win8.1/Google Chrome/i7

Off target absolutely positioned elements in IE

I have a bunch of absolutely positioned elements being generated into a div through javascript.
The positioning of each element differs 2px vertically. IE however adds an extra vertical pixel every 3 elements, then one every 2 elements and then back every 3 elements.
Wait, A pic explains it:
I have coloured the back behaving blocks in red, the correct ones in green.
Chrome renders it correctly (and so does Firefox):
When I use the IE developer tools, I can see that the CSS is set correctly:
I've tried adding zoom:1 to the elements, but that doesn't seem to make a difference.
The code to add the elements is this:
var element = document.createElement("a");
element.style.fontSize = "6pt";
element.style.width = "20px";
element.style.height = "20px";
element.style.position = "absolute";
element.style.backgroundColor = "red";
element.style.zoom = "1";
element.style.display = "block";
var tofs = (columns * 2 + r * 20 - (c * 2));
var lofs = (c * 14 + (r + offset) * 9);
trace(c + "," + r + ": " + lofs + "," + tofs);
element.style.top = tofs + "px";
element.style.left = lofs + "px";
element.style.textIndent = "-10000px";
element.style.overflow = "hidden";
element.innerText = t;
element.selectable = "no";
setBackgroundForSeat(t, element);
target.append(element);
I have tried adjusting the offset every 3 then 2 elements when IE is detected, but that doesn't work: the actual visual difference to the next element becomes 1px instead of the desired 2px (where without the hack it's 3px).
I have run out of ideas. Anybody?
Update: Here's a JS fiddle with the behaviour described. http://jsfiddle.net/uGHDh/5/
I know the IE toolbar is telling you it's setting the CSS correctly, but it might be lying about the actual values. From your code it looks like you will be getting floating point values, and it seems like IE is producing rounding errors when it draws out the objects.
You could try casting the pixel values to an integar before using them, but that might product unwanted results in all the browsers.

Categories

Resources