Controlling font weight dependent on mouse position on the screen - javascript

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!

Related

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

Positioning transformed divs (Trigonometric solution)

I am trying to position some diamond divs using some trigonometry in javascript but it seems my logic fails somewhere.
You can see that I tried this formula: pos + trig * dimension. I hoped it would give me the right coordinates so that I can construct my diamond grid. So my question is, how can I align the diamond borders with trigonometry?
var div = document.getElementsByTagName('div');
var x1 = div[0].offsetTop + Math.cos(45) * div[0].offsetHeight;
var y1 = div[0].offsetLeft + Math.sin(45) * div[0].offsetWidth;
div[1].style.top = y1 + 'px';
div[1].style.left = x1 + 'px';
The entire jsfiddle can be found here: https://jsfiddle.net/hmfxmvvs/
Edit: My intended result is this: https://jsfiddle.net/hmfxmvvs/5/
Try removing .offsetHeight , .offsetWidth from calculations
var x1 = div[0].offsetTop + (Math.cos(45));
var y1 = div[0].offsetLeft + (Math.sin(45));
div[1].style.top = Math.round(y1) + 'px';
div[1].style.left = Math.round(x1) - 9 + 'px';
jsfiddle https://jsfiddle.net/hmfxmvvs/2/

Using OpenLayers ZoomBox in JavaFX WebView

I am using JavaFX WebView included in jdk-8u45 to open a web page which shows a map using OpenLayers 2.13.1. I'm trying to zoom in on the map using a ZoomBox with a BoxHandler. The zooming works like it should, but the problem is how the the rectangle is drawn.
The wanted result is that once I click on the map and start dragging, the rectangle should start drawing as I move the mouse. This works fine in all browsers, except inside my WebView. What happens is that only after I have moved my mouse a few cm in both x- and y-direction (e.g. diagonally), the rectangle starts drawing from this position (not the one where I started dragging). I have looked at the coordinates from the different mouse events, and they all seem to be correct, which is confirmed by the fact that it zooms in on the area I actually dragged over (e.g. not the area that is drawn).
JavaScript console.log stmts output coordinates from the moment I click on the map, but nothing is drawn in the beginning of the drag.
Has anyone had similar problems with WebView? As I said, the code works like a charm in all other browsers I have tried (Safari, Firefox, Chrome, IE). I have looked around on the internet, but I haven't been able to find an answer to my problem.
Code taken from BoxHandler.js:
startBox: function (xy) {
;;;console.log(xy);
;;;console.log("startbox xy=" + xy.x + "," + xy.y);
if(this.zoomBox){
this.removeBox();
}
this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
this.dragHandler.start);
this.zoomBox.className = this.boxDivClassName;
this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
this.map.viewPortDiv.appendChild(this.zoomBox);
OpenLayers.Element.addClass(
this.map.viewPortDiv, "olDrawBox"
);
},
/**
* Method: moveBox
*/
moveBox: function (xy) {
var startX = this.dragHandler.start.x;
var startY = this.dragHandler.start.y;
;;;console.log("dragHandler.start.x=" + this.dragHandler.start.x);
;;;console.log("dragHandler.start.y=" + this.dragHandler.start.y);
var deltaX = Math.abs(startX - xy.x);
var deltaY = Math.abs(startY - xy.y);
this.zoomBox.style.width = Math.max(1, deltaX) + "px";
this.zoomBox.style.height = Math.max(1, deltaY) + "px";
this.zoomBox.style.left = xy.x < startX ? xy.x+"px" : startX+"px";
this.zoomBox.style.top = xy.y < startY ? xy.y+"px" : startY+"px";
console.log("zoombox width=" + this.zoomBox.style.width);
console.log("zoombox height=" + this.zoomBox.style.height);
console.log("zoombox left=" + this.zoomBox.style.left);
console.log("zoombox top=" + this.zoomBox.style.top);
// depending on the box model, modify width and height to take borders
// of the box into account
var box = this.getBoxCharacteristics();
;;;console.log("movebox xOffset=" + box.xOffset);
;;;console.log("movebox yOffset=" + box.yOffset);
if (box.newBoxModel) {
if (xy.x > startX) {
this.zoomBox.style.width =
Math.max(1, deltaX - box.xOffset) + "px";
}
if (xy.y > startY) {
this.zoomBox.style.height =
Math.max(1, deltaY - box.yOffset) + "px";
}
}
},
/**
* Method: endBox
*/
endBox: function(end) {
var result;
console.log(this.map.viewPortDiv.lastElementChild.style);
if (Math.abs(this.dragHandler.start.x - end.x) > 5 ||
Math.abs(this.dragHandler.start.y - end.y) > 5) {
var start = this.dragHandler.start;
var top = Math.min(start.y, end.y);
var bottom = Math.max(start.y, end.y);
var left = Math.min(start.x, end.x);
var right = Math.max(start.x, end.x);
result = new OpenLayers.Bounds(left, bottom, right, top);
} else {
result = this.dragHandler.start.clone(); // i.e. OL.Pixel
}
this.removeBox();
this.callback("done", [result]);
}
Also, I don't know if this is relevant, but when I inspect the HTML div element that holds the map (using Firebug Lite) it looks like the top border of the div is further down than it should be. The map (in correct position on the webpage) is extending beyond the top border. This is different behavior than in the other browsers I mentioned.
Any help would be appreciated.

javascript (making collage from images)

javascript code for making collage through images working in mozilla but chrome
$(document).ready(function() {
var canvaswidth = $('.rc-contentholder').width();
var canvasheight = $('.rc-contentholder').height();
function setleftandtop(noofdivision) {
var elements = document.getElementsByClassName('rc-singlecontentholder');
var noofelements = elements.length;
//place the first row
currentelementid = elements[0].id;
$("#" + currentelementid).css('left', '0px');
$("#" + currentelementid).css('top', '0px');
for (j = 1; j < noofdivision; j++) {
previousleft = parseFloat(elements[j - 1].style.left);
top = 0;
previouswidth = parseFloat(elements[j - 1].style.width);
elements[j].style.left = (previousleft + previouswidth) + "px";
elements[j].style.top = 0;
}
//place the remaining rows
for (i = noofdivision; i < noofelements; i++) {
currentid = elements[i - noofdivision].id;
left = parseFloat(elements[i - noofdivision].style.left);
uppertop = parseFloat(elements[i - noofdivision].style.top);
console.log(uppertop)
height = $("#" + currentid).height();
console.log("id" + "=" + currentid + " " + "height" + "=" + ($("#" + currentid).height()));
elements[i].style.left = left + "px";
elements[i].style.top = (uppertop + height) + "px";
}
}
if (canvaswidth >= 1200) {
noofdivision = 5;
singlecontentholderwidth = canvaswidth / noofdivision;
$('.rc-singlecontentholder').css('width', singlecontentholderwidth);
setleftandtop(noofdivision);
} else if (canvaswidth >= 900) {
noofdivision = 4;
singlecontentholderwidth = canvaswidth / noofdivision;
$('.rc-singlecontentholder').css('width', singlecontentholderwidth);
setleftandtop(noofdivision);
} else if (canvaswidth >= 550) {
noofdivision = 3;
singlecontentholderwidth = canvaswidth / noofdivision;
$('.rc-singlecontentholder').css('width', singlecontentholderwidth);
setleftandtop(noofdivision);
} else if (canvaswidth >= 480) {
noofdivision = 2
singlecontentholderwidth = canvaswidth / noofdivision;
$('.rc-singlecontentholder').css('width', singlecontentholderwidth);
setleftandtop(noofdivision);
} else if (canvaswidth < 480) {
noofdivision = 1;
singlecontentholderwidth = canvaswidth / noofdivision;
$('.rc-singlecontentholder').css('width', singlecontentholderwidth);
setleftandtop(noofdivision);
}
});
in chrome the height of the division rc-singlecontentholder keeps changing dont know what is happening please help me. Help would be appreciated.
As a rule of thumb you should always provide a standalone example/snippet/jsfiddle, so it is easy for others to figure out exactly what your problem is. In your code the markup(HTML) is missing and several of your variables are not defined. However I will try to give you a push in the right direction from the information you have provided.
I deduced that you want to determine the amount of images your canvas can fit from an element with class 'rc-containerwidth'. The first thing I want to address is that if you iterate from
var j = 0
you can just use
elements[j]
but this is just a minor esthetic.
I am assuming that you have classes called 'rc-singlecontentholder' with actual content, that would make the divs have a width and a height. With this in mind the real problem I see with your code is that the first for loop sets the first n=(noofdivision-1) elements with class 'rc-singlecontentholder' to have top=0.
The second for loop starts at element number n=i-noofdivison. Since it starts at
var i = noofdivison;
this effectively starts at n=0, which means you are looping over the same elements as in the first loop. You then calculate the variable upperTop as the elements top position which will be 0.
upperTop = top = 0;
and finally sets the top of this element as top + height
elements[i].style.top = (upperTop + height) + 'px';
Which will cause the different elements to be positioned at the height of their container. This will happen to the first n=(noofdivison-1) elements and the rest will be placed depending on what your original css for these elements are, which are hard to guess from your question. These factors coupled together is likely what is causing the height in chrome to be different from the height of the divs in firefox. Hope this can point you in the right direction to bandage your code.
There are several improvements that can be done to the code apart from this, but this could be a good task to solve if you are in the stages of learning JavaScript.
If learning JavaScript is not of the essence then I suggest trying to reuse some of the libraries that already exists for image collages, which should be more robust and time-saving than creating your own.
You can check out one alternative called H5P Collage or check out how we used JavaScript to make it at github. Disclosure: I am one of the developers on the H5P team.

Pinch to zoom with CSS3

I'm trying to implement pinch-to-zoom gestures exactly as in Google Maps. I watched a talk by Stephen Woods - "Creating Responsive HTML5 Touch Interfaces” - about the issue and used the technique mentioned. The idea is to set the transform origin of the target element at (0, 0) and scale at the point of the transform. Then translate the image to keep it centered at the point of transform.
In my test code scaling works fine. The image zooms in and out fine between subsequent translations. The problem is I am not calculating the translation values properly. I am using jQuery and Hammer.js for touch events. How can I adjust my calculation in the transform callback so that the image stays centered at the point of transform?
The CoffeeScript (#test-resize is a div with a background image)
image = $('#test-resize')
hammer = image.hammer ->
prevent_default: true
scale_treshold: 0
width = image.width()
height = image.height()
toX = 0
toY = 0
translateX = 0
translateY = 0
prevScale = 1
scale = 1
hammer.bind 'transformstart', (event) ->
toX = (event.touches[0].x + event.touches[0].x) / 2
toY = (event.touches[1].y + event.touches[1].y) / 2
hammer.bind 'transform', (event) ->
scale = prevScale * event.scale
shiftX = toX * ((image.width() * scale) - width) / (image.width() * scale)
shiftY = toY * ((image.height() * scale) - height) / (image.height() * scale)
width = image.width() * scale
height = image.height() * scale
translateX -= shiftX
translateY -= shiftY
css = 'translateX(' + #translateX + 'px) translateY(' + #translateY + 'px) scale(' + scale + ')'
image.css '-webkit-transform', css
image.css '-webkit-transform-origin', '0 0'
hammer.bind 'transformend', () ->
prevScale = scale
I managed to get it working.
jsFiddle demo
In the jsFiddle demo, clicking on the image represents a pinch gesture centred at the click point. Subsequent clicks increase the scale factor by a constant amount. To make this useful, you would want to make the scale and translate computations much more often on a transform event (hammer.js provides one).
The key to getting it to work was to correctly compute the point of scale coordinates relative to the image. I used event.clientX/Y to get the screen coordinates. The following lines convert from screen to image coordinates:
x -= offset.left + newX
y -= offset.top + newY
Then we compute a new size for the image and find the distances to translate by. The translation equation is taken from Stephen Woods' talk.
newWidth = image.width() * scale
newHeight = image.height() * scale
newX += -x * (newWidth - image.width) / newWidth
newY += -y * (newHeight - image.height) / newHeight
Finally, we scale and translate
image.css '-webkit-transform', "scale3d(#{scale}, #{scale}, 1)"
wrap.css '-webkit-transform', "translate3d(#{newX}px, #{newY}px, 0)"
We do all our translations on a wrapper element to ensure that the translate-origin stays at the top left of our image.
I successfully used that snippet to resize images on phonegap, using hammer and jquery.
If it interests someone, i translated this to JS.
function attachPinch(wrapperID,imgID)
{
var image = $(imgID);
var wrap = $(wrapperID);
var width = image.width();
var height = image.height();
var newX = 0;
var newY = 0;
var offset = wrap.offset();
$(imgID).hammer().on("pinch", function(event) {
var photo = $(this);
newWidth = photo.width() * event.gesture.scale;
newHeight = photo.height() * event.gesture.scale;
// Convert from screen to image coordinates
var x;
var y;
x -= offset.left + newX;
y -= offset.top + newY;
newX += -x * (newWidth - width) / newWidth;
newY += -y * (newHeight - height) / newHeight;
photo.css('-webkit-transform', "scale3d("+event.gesture.scale+", "+event.gesture.scale+", 1)");
wrap.css('-webkit-transform', "translate3d("+newX+"px, "+newY+"px, 0)");
width = newWidth;
height = newHeight;
});
}
I looked all over the internet, and outernet whatever, until I came across the only working plugin/library - http://cubiq.org/iscroll-4
var myScroll;
myScroll = new iScroll('wrapper');
where wrapper is your id as in id="wrapper"
<div id="wrapper">
<img src="smth.jpg" />
</div>
Not a real answer, but a link to a plug=in that does it all for you. Great work!
https://github.com/timmywil/jquery.panzoom
(Thanks 'Timmywil', who-ever you are)
This is something I wrote a few years back in Java and recently converted to JavaScript
function View()
{
this.pos = {x:0,y:0};
this.Z = 0;
this.zoom = 1;
this.scale = 1.1;
this.Zoom = function(delta,x,y)
{
var X = x-this.pos.x;
var Y = y-this.pos.y;
var scale = this.scale;
if(delta>0) this.Z++;
else
{
this.Z--;
scale = 1/scale;
}
this.zoom = Math.pow(this.scale, this.Z);
this.pos.x+=X-scale*X;
this.pos.y+=Y-scale*Y;
}
}
The this.Zoom = function(delta,x,y) takes:
delta = zoom in or out
x = x position of the zoom origin
y = y position of the zoom origin
A small example:
<script>
var view = new View();
var DivStyle = {x:-123,y:-423,w:300,h:200};
function OnMouseWheel(event)
{
event.preventDefault();
view.Zoom(event.wheelDelta,event.clientX,event.clientY);
div.style.left = (DivStyle.x*view.zoom+view.pos.x)+"px";
div.style.top = (DivStyle.y*view.zoom+view.pos.y)+"px";
div.style.width = (DivStyle.w*view.zoom)+"px";
div.style.height = (DivStyle.h*view.zoom)+"px";
}
function OnMouseMove(event)
{
view.pos = {x:event.clientX,y:event.clientY};
div.style.left = (DivStyle.x*view.zoom+view.pos.x)+"px";
div.style.top = (DivStyle.y*view.zoom+view.pos.y)+"px";
div.style.width = (DivStyle.w*view.zoom)+"px";
div.style.height = (DivStyle.h*view.zoom)+"px";
}
</script>
<body onmousewheel="OnMouseWheel(event)" onmousemove="OnMouseMove(event)">
<div id="div" style="position:absolute;left:-123px;top:-423px;width:300px;height:200px;border:1px solid;"></div>
</body>
This was made with the intention of being used with a canvas and graphics, but it should work perfectly for normal HTML layout

Categories

Resources