I have looked through a lot of answers for similar problems but was not able to find any that actually seem to work for me. My problem is very simple, I have two images occupying the exact same spot, however they are at different angles from each other. When I zoom in or out, the images should still occupy the same spot as each other, however, the rotated image always moves.
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<style>
.building {
width:40px;
height:40px;
position:absolute;
left:100px;
top:100px;
}
</style>
<div style="display:flex;justifty-content:space-evenly;width:80%;">
<div id="container" style="position:relative;width:200px;height:200px;border:1px solid red;">
<img src="image1.png" class="building">
<img src="image2.png" class="building" style="transform:rotate(45deg);">
</div>
<div>Scale:<input id="scale" type="text" onChange="changeScale(this.value)"></div>
</div>
<script>
var oldScale = 1;
function changeScale(_scale) {
var zoom = _scale;
var zdelta = (_scale/oldScale);
oldScale=_scale;
var w = $("#container").width();
var h = $("#container").height();
$("#container").width(w*zdelta);
$("#container").height(h*zdelta);
$(".building").each(function() {
var p = $(this).position();
w = $(this).width()*zdelta;
h = $(this).height()*zdelta;
var r = getCurrentRotation(this);
$(this).css({top: (p.top*zdelta), left: (p.left*zdelta)});
$(this).width(w);
$(this).height(h);
});
}
</script>
I have tried to use the following to adjust the rotated image:
$(this).css({top: (p.top*zdelta)+( (h/2)*Math.cos(r) ), left: (p.left*zdelta)+( (w/2)*Math.sin(r) ) });
as well as
function GetArrowLeftShift(w,degrees )
{
var result = (w / 2) * Math.cos( degrees * Math.PI / 180 );
return result;
}
as well as Math.sqrt( Math.pow(w/2,2)+Math.pow(h/2,2) );
Note: I have tried to make the problem easier by using the center position of the square with equal sized images. The real application with have the images in any position, and their sizes will vary but they will need to retain their exact positions in relation to the other images in the square.
So, since I could never find a good mathematical solution to solve this problem, I have ended up doing the following:
var r = getCurrentRotation(this);
$(this).css({transform:"rotate(0deg)"});
var p = $(this).position();
var w = $(this).width()*zdelta;
var h = $(this).height()*zdelta;
$(this).css({top:p.top*zdelta,left:p.left*zdelta,transform:"rotate(+"r+"deg)"});
In essence, I set the rotation to 0, then scale the image and reposition the image and set its rotation back to its original angle.
Related
I've got an image of a basketball court and would like to place either a green or red dot on the court (green if a shot was made from that spot, red if missed).
The basketball shots are recorded by someone clicking the image of the court, and then the coordinates (represented as percentages) are saved to the database. After we are done recording, on a separate view, I am calling all of those coordinates and setting the following parameters for them:
var marker = document.createElement("IMG");
marker.src = image;
marker.style.width = '4%';
marker.style.position = 'absolute';
marker.style.left = offsetLeft + "%";
marker.style.top = offsetTop + "%";
shotChartBox.appendChild(marker);
offetLeft and Top are both just the values from the DB multiplied by 100 and given a % sign.
However, when I do this, the dots always end up just a bit off. If someone clicks in the dead center of the court image, the dot will appear just a bit above and to the right. I know that this is not a data capture problem, because when I went into the browser inspect tool and manually set a dot to have top and left values of exactly 50%, the same thing happened.
I have tried accounting for the 4% width of the dots themselves, but have not been able to find a way to do that and make it work on all browser sizes. As I resize the browser after adding or subtracting 2% here and there, it always throws things off even worse.
Let me know if you have any ideas. I feel as though there is either a positioning or JS thing that I am just not aware of.
//A couple example function calls
displayMarker(0.5, 0.5, "https://i.postimg.cc/8CLJ8Wj6/makeIcon.png");
displayMarker(0.25, 0.25, "https://i.postimg.cc/mDRcTDH6/missIcon.png");
function displayMarker(x, y, image) {
var courtImage = document.getElementById('shotChart');
var shotChartBox = document.getElementById('shotChartBox');
var offsetLeft = x * 100;
var offsetTop = y * 100;
var marker = document.createElement("IMG");
marker.src = image;
marker.style.width = '4%';
marker.style.position = 'absolute';
marker.style.left = offsetLeft + "%";
marker.style.top = offsetTop + "%";
shotChartBox.appendChild(marker);
}
<h2>Shot Chart</h2>
<div id="shotChartBox">
<img id="shotChart" src="https://i.postimg.cc/rswKtPg1/shot-Chart.png" width="100%" />
</div>
JSFiddle demo.
Assuming 0.5, 0.5 is equivalent to the center of the court here is a working solution.
<html>
<style></style>
<body>
<div id="shotChartBox" style="position: relative;">
<img style="position: relative" src="https://i.postimg.cc/rswKtPg1/shot-Chart.png" width="100%" height="auto" />
</div>
<script>
displayMarker(0.5, 0.5, "https://i.postimg.cc/8CLJ8Wj6/makeIcon.png");
displayMarker(0.25, 0.25, "https://i.postimg.cc/mDRcTDH6/missIcon.png");
function displayMarker(x, y, image) {
var shotChartBox = document.getElementById("shotChartBox");
var offsetLeft = x * 100 - 2;
var offsetTop = y * 100 - 1;
var marker = document.createElement("IMG");
marker.src = image;
marker.style.width = "4%";
marker.style.position = "absolute";
marker.style.left = offsetLeft + "%";
marker.style.top = offsetTop + "%";
shotChartBox.appendChild(marker);
}
</script>
</body>
</html>
So I have been trying endlessly to try and do something similar too what this site is doing (http://whois.domaintools.com/). I'm trying to get a webpage, so wherever the mouse moves over the webpage, that kind of effect follows it (I'm sorry I don't know what I would call the effect).
I've read how to ask questions on here, but I don't know what too look for so it's difficult for me to attempt this. So far this link (http://p5js.org/learn/demos/Hello_P5_Drawing.php) I've used the code from this and played around with it but i'm just puzzled as too how I would go about doing this.
Thanks for any help, I've been banging my head against a brick wall for a good couple of days now.
This seems to be some kind of particle system. I would start the following way: First create a class for a particle, it should have a random x and y coordinate, and it should change it's postion periodically to a random new postion. Then create a lot of instances of the particle and distribute them over the page.
http://jsfiddle.net/aggoh0s1/3/
/* each particle will move in a 100px100px square */
var gutterWidth = 100;
/* class definition */
var Particle = function(x, y) {
var t = this;
t.x = x;
t.y = y;
t.elem = $('<div class="particle" />');
t.elem.css({ left: x+"px", top: y+"px"});
$('body').append(t.elem);
/* create a new position every 500-1000 milliseconds */
var milliSecs = 500 + Math.random() * 500;
t.ptinterval = setInterval(function() {
var dx = Math.round(Math.random() * gutterWidth);
var dy = Math.round(Math.random() * gutterWidth);
t.elem.animate({left: (t.x + dx)+"px", top: (t.y + dy) + "px"}, 600);
}, milliSecs);
};
/* create a 1000px1000px area where particles are placed each 100px */
var particles = [];
var newParticle;
for(var x = 0; x < 1000; x = x + gutterWidth) {
for(var y = 0; y < 1000; y = y + gutterWidth) {
newParticle = new Particle(x,y);
particles.push(newParticle);
}
}
CSS:
.particle {
width: 2px;
height: 2px;
background-color: black;
position: absolute;
}
Using this logic, you could also use a canvas to display the particles instead of a html div like it is done on whois.domaintools.com. The next step should be to connect the particles with lines to each other, and after that some code should hide all particles that are some distance away from the mouse position.
I've developed the following solution for the effect which you are referring. This is done using jQuery using the event mousemove(). Bind this event to your body where the content is.
Method :
Create an element with the following css on your body. You can create the element onthefly using jQuery as well.
<div class='hover'></div>
CSS
.hover{
position:absolute;
width:100px;
height:100px;
background-color:#fff;
}
The add the following code to your page.
$('body').mousemove(function(event){
$('.hover').css({
'top' : event.pageY,
'left': event.pageX
})
});
The above code will bind an event to your mouse move and I change the element position according to the mouse coordinates.
This fiddle shows a running example
I've given you the basic idea of the solution! You will have to medle with the css and jquery to add the looks and feels of the effect which you refer to.
See the simple example
<img id="imgMove" src="Images/img1.jpg" height="100" width="100" style="position: absolute;" />
JQuery
$(document).ready(function () {
$(document).mousemove(function (e) {
$("#imgMove").css({ "top": e.pageY - 50, "left": e.pageX - 50 }); // e.pageX - Half of Image height, width
})
})
I've set up a jsfiddle illustrating my situation: http://jsfiddle.net/j5o0w5qc/1/
Basically, I've got three nested HTML elements: a viewport div on the outside, a stage div in the middle, and a canvas on the inside. The stage div provides a perspective setting for 3d transformations applied to the canvas. The viewport has overflow: hidden; so we don't see anything outside of the viewport. It also has a listener attached, listening for mousedown.
In my actual app that I'm building, the canvas might be transformed to any arbitrary 3d transformation, involving translation and rotation in 3d space. What I would like to happen is for the viewport div to intercept a click, and draw a spot on the canvas in the place you clicked. I'm intercepting the event with the viewport div, and I'm using offsetX and offsetY in Chrome. This works great for Chrome, but I know I can't rely on offsetX and offsetY in other browsers, so I'd like to use pageX and pageY, normalized via jQuery, but I'm not sure quite how to do that.
What I've currently got in the jsfiddle works great in Chrome, except when you click in the viewport NOT on the canvas. When you click on the canvas, it draws a dot there, regardless of the canvas's transformation. Chrome is doing all the hard work and giving me exactly what I want with offsetX and offsetY. However, when you click in the viewport NOT on the canvas, I guess it's giving me offsetX and offsetY values relative to the viewport, rather than the canvas, and then interpreting that and drawing a dot on the canvas. For example, if I transform the canvas and then click in the upper right corner of the viewport, a dot appears in the upper right corner of the canvas, regardless of where that corner actually appears on the page.
In Firefox, however, it works great as long as there is no transformation applied to the canvas, but as soon as the canvas is transformed, all of a sudden, the dot being drawn is displaced, and I can't figure out how to take my pageX and pageY values and figure out exactly where in the canvas I am clicking.
Does anyone have any brilliant solutions? I've been bashing my head against this problem for far too long. I'm pretty sure I need to manually calculate some 3d transformation matrices or something, and I've spent hours writing methods to return the inverse of a matrix, and to multiply a matrix by a vector, and all sorts of stuff, but none of it has actually solved the problem for me, and I'm not sure what I'm missing.
Stackoverflow says code is required with jsfiddle links, so here's all my code:
HTML:
<div id="viewport">
<div id="stage">
<canvas id="myCanvas" width="300" height="300"></canvas>
</div>
</div>
<div id="stuff">
<button onclick="transformMe()">Transform</button>
<input id="blah" type="text" size="45"></input>
</div>
CSS:
#viewport, #stage, #myCanvas {
width: 300px;
height: 300px;
position: absolute;
top: 0;
left: 0;
}
#viewport {
border: 1px solid #000;
overflow: hidden;
}
#stage {
perspective: 1000px;
transform-style: preserve-3d;
}
#myCanvas {
background-color: green;
transform-style: preserve-3d;
}
#stuff {
position: absolute;
top: 350px;
}
Javascript:
var counter = 0;
$('#viewport').mousedown(function _drawOnCanvas (e)
{
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var xpos, ypos;
if (typeof e.offsetX=='undefined')
{
xpos = e.pageX - $('#myCanvas').offset().left;
ypos = e.pageY - $('#myCanvas').offset().top;
}
else
{
xpos = e.offsetX;
ypos = e.offsetY;
}
ctx.fillRect(xpos-5, ypos-5, 10, 10);
});
function transformMe()
{
counter++;
var angle = (counter * 30) % 360;
$('#myCanvas').css('transform','perspective(1000px) rotate3d(5,6,7,' + angle + 'deg)');
$('input').val('counter: ' + counter + ', angle: ' + angle);
};
For Firefox, you can use event.layerX and event.layerY. Think of them as Firefox's versions of offsetX & offsetY.
DEMO: http://jsfiddle.net/dirtyd77/j5o0w5qc/3/
JAVASCRIPT:
var counter = 0;
$('#viewport').mousedown(function _drawOnCanvas (e)
{
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var xpos, ypos;
if (typeof e.offsetX=='undefined')
{
xpos = e.originalEvent.layerX;
ypos = e.originalEvent.layerY;
}
else
{
xpos = e.offsetX;
ypos = e.offsetY;
}
ctx.fillRect(xpos-5, ypos-5, 10, 10);
});
function transformMe()
{
counter++;
var angle = (counter * 30) % 360;
$('#myCanvas').css('transform','perspective(1000px) rotate3d(5,6,7,' + angle + 'deg)');
$('input').val('counter: ' + counter + ', angle: ' + angle);
};
If you change viewport to myCanvas in line 3 of the either Kyle S or Dom's jsfiddles:
$('#myCanvas').mousedown(function _drawOnCanvas (e)
it no longer places a dot when you "click in the viewport NOT on the canvas."
It seems there's a new issue with Firefox - if there's a transformation it only lets you paint on half ( the bottom left of diagonal - but depends on transformation ).
I have a div with a variously-sized images in it, which is inside of a parent container.
<div id="parentContainer">
<div id="boxToScale">
<img src="http://placehold.it/350x150" />
<img src="http://placehold.it/150x350" />
<img src="http://placehold.it/200x200" />
<img src="http://placehold.it/50x200" />
</div>
</div>
I need to scale #boxToScale so that it fits inside #parentContainer (both width and height-wise), while all of the images inside of it keep their aspect ratios. All of the images should be scaled at the same factor, and remain on the same line.
Here's a jsfiddle showing the setup: http://jsfiddle.net/32sm4/
I've found lots of stuff for scaling a single image proportionally, but not for scaling a group of images proportionally. I don't know beforehand what the size of the images will be, only the size of #parentContainer.
Javascript/jquery solutions are fine if it can't be done with just css. Thanks!
Edit: Here's (roughly) what I want it to look like after #boxToScale has been scaled:
Updated my answer after I saw your picture how you would your pictures be like.
This is based on this jsfiddle.net/7dpHK/2 (charlietfl commented this on your question). It's almost working like you wanted, but it was bugging because of those 4px borders/paddings around images. There was some confusing CSS too.
So you have to calculate your borders like:
var border = $("#boxToScale img").length * 4;
And then just subtract it from parentW:
parentW = $box.width() - border
Working example.
JS:
var border = $("#boxToScale img").length * 4; // 4px padding around every image
var $box = $('#boxToScale'),
parentW = $box.width() - border,
parentH = $box.height(),
imageTotalW = 0,
imageTotalH = 0,
$imgs = $box.children();
$imgs.each(function () {
var img = $(this),
ht = img.height(),
w = img.outerWidth()
imageTotalW += w;
img.data('w', w);
});
var img_width_ratio = parentW / imageTotalW;
$imgs.each(function (idx) {
var $this = $(this),
$prev = $this.prev();
$this.width($this.outerWidth() * img_width_ratio);
});
DEMO
JS:
function calculateAspectRatioFit(srcWidth, srcHeight, maxWidth, maxHeight) {
var ratio = [maxWidth / srcWidth, maxHeight / srcHeight ];
ratio = Math.min(ratio[0], ratio[1]);
return { width:srcWidth*ratio, height:srcHeight*ratio };
}
imagesInContainer = $("#boxToScale img").length;
var toWidth = $("#parentContainer").width() / imagesInContainer;
var toHeight = $("#parentContainer").height() / imagesInContainer;
$("#boxToScale img").each(function(){
var imageWidth = $(this).width();
var imageHeight = $(this).height();
var getRatio = calculateAspectRatioFit(imageWidth, imageHeight, toWidth, toHeight);
$(this).width(getRatio.width);
$(this).height(getRatio.height);
});
Note: Your 1px border in images may bug this code. See an example here without borders.
#boxToScale {
border: solid blue 1px;
white-space: nowrap;
}
#boxToScale img {
width:20%;
height:auto;
display:inline-block;
}
crazy.. but might work... hope it helps.
have a chess board in TABLE, each square a TD.
how would one use html5 gradients (and javascript for randomness) to create a wood texture background for the dark squares?
I'm grabbing a big wood texture (change to one you like) and grabbing a random piece of it at 50% opacity, then underneath is a random brownish color to add a unique undertone to each square. You can adjust all these to get an effect you want. I messed with some gradients and they looked silly.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js"></script>
<style>
div {
width: 100px; height: 100px; margin: 1px;
}
div.texture {
background: url(http://gallery.hd.org/_exhibits/textures/wood-grain-closeup-1-DHD.jpg);
opacity:0.4; filter:alpha(opacity=100);
}
</style>
<script>
$(function(){
$('div.bg').each(function(){
// make each square a random brown
var browns = new Array('CD853F','8B4513','A0522D');
var col = Math.floor(Math.random()*3);
$(this).css('background-color',browns[col]);
// the dimensions of your texture minus square size
var image_width = 500;
var image_height = 400;
// get a random positions
var x = Math.floor(Math.random()*image_width);
var y = Math.floor(Math.random()*image_height);
// make them negative
x = x - (x * 2);
y = y - (y * 2);
var d = $(this).children('div.texture');
d.css('background-position', x+'px'+' '+y+'px');
});
});
</script>
<div class='bg'><div class='texture'></div>
<div class='bg'><div class='texture'></div>