Positioning transformed divs (Trigonometric solution) - javascript

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/

Related

How to get drawline to work in Internet Explorer?

I have a function that draws a line inside a div (adapted from this solution), used in an e-learning module (explains the weird parts of the code).
My problem is that it doesn't seem to work in IE11.
Here is the code:
var player = GetPlayer();
var progress = player.GetVar("score");
var h = 600; //the height of your slide, as set in Story Size
var w = 1000; //the width of your slide, as set in Story Size
var t = 4; //the desired thickness of the progress bar in px, as based on the size of the styry slide
var c = "#00cc3399"; //the desired color of the progress bar, in hex. The last 2 digits are opacity. See codes below:
var startY = 40; //the desired start coordinate, from the top of the page
var startX = 0; //the desired start coordinate, from the left side of the page. Set to "0" as standard
var aspectRatio = h/w;
var totalW = $('.slide-container').width(); //get the actual width of the slide. only relevant if storyline is set to "Scale to fill browser window"
var totalH = totalW*aspectRatio; //calculate the actual height of the slide. only relevant if storyline is set to "Scale to fill browser window"
console.log("totalW: " + totalW);
var wFactor = totalW/w; //used to calculate the x-position on the slide. only relevant if storyline is set to "Scale to fill browser window"
var hFactor = totalH/h //used to calculate the y-position on the slide. only relevant if storyline is set to "Scale to fill browser window"
var endPointX = totalW*progress/100; //calculate the length of the progress bar
var endPointY = startY*hFactor; //calculate y-position, based on where you want it to be on the slide. The number is the position on the slide, as seen from the top. This is based on a horizontal progress bar
console.log("endPointX: " + endPointX + ", endPointY: " + endPointY)
x1 = startX, y1 = startY, //Start of the bar
x2 = endPointX, y2 = endPointY; //end of the bar
drawline(x1, y1, x2, y2);
//all the technical stuff:
function drawline(ax, ay, bx, by) {
console.log('ax: ' + ax);
console.log('ay: ' + ay);
console.log('bx: ' + bx);
console.log('by: ' + by);
if (ax > bx) {
bx = ax + bx;
ax = bx - ax;
bx = bx - ax;
by = ay + by;
ay = by - ay;
by = by - ay;
}
console.log('by: ' + by);
var angle = Math.atan((ay - by) / (bx - ax));
angle = (angle * 180 / Math.PI);
angle = -angle;
var length = Math.sqrt((ax - bx) * (ax - bx) + (ay - by) * (ay - by));
console.log('length: ' + length);
var style = ""
style += "left:" + (ax) + "px;"
style += "top:" + (ay) + "px;"
style += "width:" + length + "px;"
style += "height:"+t*hFactor+"px;" //set the thickness of the progress bar
style += "background-color:"+c+";"
style += "position:absolute;"
style += "transform:rotate(" + angle + "deg);"
style += "-ms-transform:rotate(" + angle + "deg);"
style += "transform-origin:0% 0%;"
style += "-moz-transform:rotate(" + angle + "deg);"
style += "-moz-transform-origin:0% 0%;"
style += "-webkit-transform:rotate(" + angle + "deg);"
style += "-webkit-transform-origin:0% 0%;"
style += "-o-transform:rotate(" + angle + "deg);"
style += "-o-transform-origin:0% 0%;"
style += "z-index:99;"
$("<div id='progressBar' style='" + style + "'></div>").appendTo('.slide-container');
};
In chrome this function draws a line based on the user's score. In IE nothing happens.
I found the solution myself. It turns out that IE redefined the 8-digit HEX value to RGBa, and turned it white. Replacing the 8-digit HEX value with it's corresponding RGBa value made it work.

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.

Generate numbers in side div at random position without overlapping

I want to display random numbers inside a div at random positions without overlapping.
I am able to display random number at random position but its going outside the box and overlapping each other.
Here is my code:
JS Fiddle
var width = $('.container').innerWidth();
var height = $('.container').innerHeight();
(function generate() { // vary size for fun
for (i = 0; i < 15; i++) {
var divsize = 12;
var color = '#' + Math.round(0xffffff * Math.random()).toString(16);
$newdiv = $('<div/>').css({
'width': divsize + 'px',
'height': divsize + 'px'
});
// make position sensitive to size and document's width
var posx = (Math.random() * (width - divsize)).toFixed();
var posy = (Math.random() * (height - divsize)).toFixed();
$newdiv.css({
'position': 'absolute',
'left': posx + 'px',
'top': posy + 'px',
'float': 'left'
}).appendTo('.container').html(Math.floor(Math.random() * 9));
}
})();
How can I do this?
You've got most of it figured out. You just need to think of the .container div as a grid to avoid any overlap or outlying items.
Just check out this fiddle.
Here's what the code looks like:
var tilesize = 18, tilecount = 15;
var gRows = Math.floor($(".container").innerWidth()/tilesize);
var gCols = Math.floor($('.container').innerHeight()/tilesize);
var vals = _.shuffle(_.range(tilecount));
var xpos = _.shuffle(_.range(gRows));
var ypos = _.shuffle(_.range(gCols));
_.each(vals, function(d,i){
var $newdiv = $('<div/>').addClass("tile");
$newdiv.css({
'position':'absolute',
'left':(xpos[i] * tilesize)+'px',
'top':(ypos[i] * tilesize)+'px'
}).appendTo( '.container' ).html(d);
});
PS:I have used underscore in my fiddle to make things easier for me and because I personally hate writing for loops.
If the number of divs you need to create is small enough (i.e. you're not risking that they won't fit) then a simple algorithm is:
pick a random position (x0, y0)-(x1, y1)
check if any previously selected rect overlaps
if none overlaps then add the rect, otherwise loop back and choose another random position
in code
var selected = [];
for (var i=0; i<num_divs; i++) {
while (true) {
var x0 = Math.floor(Math.random() * (width - sz));
var y0 = Math.floor(Math.random() * (height - sz));
var x1 = x0 + sz;
var y1 = y0 + sz;
var i = 0;
while (i < selected.length &&
(x0 >= selected[i].x1 ||
y0 >= selected[i].y1 ||
x1 <= selected[i].x0 ||
y1 <= selected[i].y0)) {
i++;
}
if (i == selected.length) {
// Spot is safe, add it to the selection
selected.push({x0:x0, y0:y0, x1:x1, y1:y1});
break;
}
// The choice collided with a previously added div
// just remain in the loop so a new attempt is done
}
}
In case the elements are many and it's possible to place n-1 of them so that there's no position where to put n-th element then things are a lot more complex.
For the solution of the 1-dimensional version of this problem see this answer.
You can add to array position of each number. And then when ou generate new position for digit you should check if posx posy in array, if false place number there, if true generate new posx and posy

Cropping an image with a preview using jcrop

I'm using jcrop and trying to make a "live" preview of the cropped area on an image.
The movement of the selected area works perfectly if the "Crop Selection" area is the same height and width as the destination preview div.
Check out the issue here: http://jsfiddle.net/fbaAW/
function showCoords(c)
{
var $this = this.ui.holder;
var original = $this.prev();
var preview = original.parent().find(".image");
var oH = original.height();
var oW = original.width();
var pH = preview.height();
var pW = preview.width();
var sH = c.h;
var sW = c.w;
var differenceH = pH - sH;
var differenceW = pW - sW;
//preview.css('width', c.w);
//preview.css('height', c.h);
//preview.css("background-size", Math.round(oW + differenceW) + "px" + " " + Math.round(oH + differenceH) + "px");
preview.css("background-position", Math.round(c.x) * -1 + "px" + " " + Math.round(c.y) * -1 + "px");
}
As you can see, I've commented out a few of my tests and attempts at getting this code to work properly but I just can't wrap my head around the relationship between the position and the size background properties in order to get this effect to work correctly.
Calculate the horizontal and vertical ratios between the selection size and the preview area size:
var rW = pW / c.w;
var rH = pH / c.h;
Then apply them to the background-size and background-position:
preview.css("background-size", (oW*rW) + "px" + " " + (oH*rH) + "px");
preview.css("background-position", rW * Math.round(c.x) * -1 + "px" + " " + rH * Math.round(c.y) * -1 + "px");
http://jsfiddle.net/fbaAW/1/
So, if the preview size is, say, 3 times the size of your jCrop selection area, it means you have scale the original image by 3, and compensate for the scaling when defining the background position.

How to draw a line between two divs?

I'm currently trying to draw a diagonal line between the bottom right corner of one div to the top right corner of another. If possible, I would like to do it without jQuery. Is this possible?
http://jsfiddle.net/cnmsc1tm/
This won't work with IE8 or below because of CSS limitations.
function getOffset( el ) {
var rect = el.getBoundingClientRect();
return {
left: rect.left + window.pageXOffset,
top: rect.top + window.pageYOffset,
width: rect.width || el.offsetWidth,
height: rect.height || el.offsetHeight
};
}
function connect(div1, div2, color, thickness) { // draw a line connecting elements
var off1 = getOffset(div1);
var off2 = getOffset(div2);
// bottom right
var x1 = off1.left + off1.width;
var y1 = off1.top + off1.height;
// top right
var x2 = off2.left + off2.width;
var y2 = off2.top;
// distance
var length = Math.sqrt(((x2-x1) * (x2-x1)) + ((y2-y1) * (y2-y1)));
// center
var cx = ((x1 + x2) / 2) - (length / 2);
var cy = ((y1 + y2) / 2) - (thickness / 2);
// angle
var angle = Math.atan2((y1-y2),(x1-x2))*(180/Math.PI);
// make hr
var htmlLine = "<div style='padding:0px; margin:0px; height:" + thickness + "px; background-color:" + color + "; line-height:1px; position:absolute; left:" + cx + "px; top:" + cy + "px; width:" + length + "px; -moz-transform:rotate(" + angle + "deg); -webkit-transform:rotate(" + angle + "deg); -o-transform:rotate(" + angle + "deg); -ms-transform:rotate(" + angle + "deg); transform:rotate(" + angle + "deg);' />";
//
// alert(htmlLine);
document.body.innerHTML += htmlLine;
}
The Distance Formula
Finding the Center Of Two Points
Finding the Angle Between Two Points
CSS Transform:Rotate
HTML Element offset[Width|Height|Top|Left] properties
Edit (for others with the same problem):
If you need to, for example, create a line from two corners that are not the top right and bottom right divs, go to this section of the code:
// bottom right
var x1 = off1.left + off1.width;
var y1 = off1.top + off1.height;
// top right
var x2 = off2.left + off2.width;
var y2 = off2.top;
where you see + off1.width and + off1.height, that means that the code is calculating the position of the bottom or the right of the div. Remove the + off1.width or the + off1.height to get the left or the top of the div.
EDIT updated to a more standard getOffset function. If you want to get really anal you'd probably also have to add document.documentElement.client[Left/Top] and walk the offsetParent tree, but I think getBoundingClientRect() and window.page[X/Y]Offset are sufficient for an example like this.
There is a way to do it without jQ.
Find the position of your divs using offset.
Find the slope
draw 1x1px points from start to end position using the slope in your loop.

Categories

Resources