So I'm trying to solve a graphics problem. Basically there's a container, let's say its 600px wide. If there is only one rectangle in that container(with no overlapping rectangles) it takes up the width of it. However, the issue is when these rectangles overlap, the width has to shrink accordingly. We are given the top left and bottom left y-coordinates of this rectangle. (such as it starts 60px down and ends 120 px down the big container)
So I wrote an overlap algorithm that checks if an overlap exists and counts the number of rectangles that the rectangle overlaps with (including itself). Then I divide the container width by the maximum number of elements overlapped to get the width of the smaller rectangles.
for (i = 0; i < events.length; i++) {
var event = events[i];
var numCollisions = 0;
for (j = 0; j < events.length; j++) {
var eventCmp = events[j];
if (event.start <= eventCmp.start && event.end > eventCmp.start ||
event.start < eventCmp.end && event.end >= eventCmp.end) {
numCollisions++;
}
}
However, I've noticed a huge problem with this. If you look at this picture below the rightmost rectangle has two overlapping rectangles. By my algorithm you would get the container width/3 (including the rectangle itself) which is incorrect. The actual answer is the container width/2.
So the issue is (after this long winded explanation) that I need to find if two rectangles are horizontally aligned. I've been busting my head on this for hours. Any hints on how I can do this?
Well, the easiest answer is divide by 2 IF you have a collision (not caring how many collisions you actually have). If you need something more sophisticated, can you show a more sophisticated case?
a less than optimal, but easy to implement algo would be:
foreach y coord in the main container
rects = find all rects which contain this y coord
foreach rects as rect
rect.maxHorizNeighbors = max(rects.length, rect.maxHorizNeighbors)
theres still some other issues you'll need to address, but this should get you started on your homework assignment. in particular, theres a case where you could possibly end up with horizontal gaps. ill let you find that on your own.
Related
Is there a way to find out if an element is obscured by another element that is not a child of the first one? Because I have a menu that I like to hide when you click anywhere on the page, but not when there is currently a lightbox open that obscures the menu.
function isObscured(element) {
// get element at element's position
var elem = document.elementFromPoint(element.offsetLeft, element.offsetTop);
// return whether obscured element has same parent node (will also return false if
// element === elem)
return elem.parentNode !== element.parentNode;
}
http://jsfiddle.net/pimvdb/tKtEV/
You have to evaluate it yourself.
Take into consideration coordinates and size of the frontmost element, then check for "collision" with the elements behind it you need to control.
It's basically a check for overlapping squares.
If you know which element could be obscuring the "target", you can use the method getBoundingClientRect to find the edges of the obscurer and the "target". Then it's a problem of finding if two rectangles overlap.
It could seem daunting to calculate that, but to separate the X and Y axes is the Egg of Columbus here.
Two rectangles do NOT overlap if:
1) their X axis range doesn't overlap
a. rect1's bottom is above rect2's top
b. rect1's top is below rect2's bottom
2) their Y axis range doesn't overlap
a. rect1's right edge is to the left of rect2's left edge
b. rect1's left edge is to the right of rect2's right edge
Otherwise--that is, if their X axis overlaps and their Y axis also overlaps--they definitely DO overlap.
function overlaps(el1, el2){
var rect1 = el1.getBoundingClientRect();
var rect2 = el2.getBoundingClientRect();
if (rect1.bottom < rect2.top // 1a
|| rect2.bottom < rect1.top // 1b
|| rect1.right < rect2.left // 2a
|| rect2.right < rect1.left) { // 2b
return false;
}
return true;
}
Hi I'm looking at the Scroll Drawing examples over on W3Schools and CSS Tricks. Both examples use Javascript and an SVG path to "draw" an element on scroll. They also both base the length of the drawn path according to how much the document body has been scrolled (scroll percentage). Here's how they calculate their scroll percentage:
var scrollpercent = (document.body.scrollTop + document.documentElement.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);
Does anyone know how I can change the scroll percentage so that it calculates based on how far down a div has been scrolled?
Here's a Fiddle where I tried using the y of the div's boundingClientRect() divided by the window.innerHeight. This probably doesn't make sense because it seems to be drawn over and over again, but I'm trying to figure out the math. The SVG in this case is sticky to the div (instead of fixed). This only kind of works in that the SVG path is drawn on scroll, but it's drawn over and over again until you've scrolled past the height of the div.
My desired outcome is for it to be drawn once completely when scrolled 50% down the div and stay drawn for scrolling the remaining 50% of the div.
I hope this makes sense. Thanks for your help in advance! Any references would help too in terms of JS math and logic!
Also, for the SVG itself, do you know which end of the path is the one that starts?
Okay, I figured this out. Here's the complete fiddle
The math for calculating the scroll percentage: get the amount that the window has scrolled and divide by the height of the div (that the SVG is in). You then want to divide this in half so that the drawing completes halfway before div finishes scrolling:
var svgContainer = document.getElementById("svg-container");
var svgContainerRect = svgContainer.getBoundingClientRect();
var svgDivHeight = svgContainerRect.height;
var windowScroll = window.pageYOffset;
var scrollPercent = windowScroll / svgDivHeight *2;
Then, for the drawing to remain "drawn" after scrolling halfway through the div, throw the "drawing function" into an "if". This stops drawing once the scroll percentage reaches 1 (reaching halfway down the page):
if (scrollPercent < 1) {
//draw the length of SVG path according to the scroll
var draw = length * scrollPercent;
// Reverse the drawing (when scrolling upwards)
triangle.style.strokeDashoffset = length - draw;
} else {
var still = length;
}
The only quirk is that when the drawing is reversed (when you scroll up and then scroll back down), it seems to not complete all the way, like there's a bit of length missing. More to figure out, but the main function is there.
I guess it just took me a while to figure out the simple math. Hope this can help someone in the future.
I am referring an svg animation given in below link
https://codepen.io/thinkdesign/pen/JybJOq
I am not able to understand how the recursion works here
var offset = 0;
var animation = function() {
offset -= 100;
pattern.animate({ x: offset }, 500, mina.ease, animation);
};
here we are changing x axis on each function call , so the x axis should go beyond screen at some point. Please help me understanding how this works
Nothing is moving across the page here. The x that is being moved here is the pattern's X offset. An SVG <pattern> is a fill that consists of a "tile" that is repeated infinitely in every direction. The <pattern> has an x and y attribute that tells the browser where to start the tiling from. Animating the pattern's x offset has the effect of making it look like the tile is continuously moving across your object.
Picture a rectangular window lying on a tiled floor. If you slide that window across the floor, it looks to you like the tile pattern moves through the window.
I've been playing with canvas element and discovered that when I attempt to draw NxN uniform solid-colored cells next to each other, in some width/height configurations, there are blurry white-ish lines between them.
For instance, this canvas is supposed to look black but contains some sort of grid which I conjecture to be a result of faulty antialiasing in the browser.
Suffice to say, this bug appears only in some configurations but I would like to get rid of it for good. Is there any way to circumvent this? Have you ever had problems with antialiasing in canvas?
I have made this fiddle which demonstrates the issue and allows you to play with the dimensions of the canvas and number of cells. It also contains the code I use to draw the cells, so that you can inspect it and tell me if I'm doing anything wrong.
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
for (var i = 0; i < numberOfCells; ++i) {
for (var j = 0; j < numberOfCells; ++j) {
ctx.fillStyle = '#000';
ctx.fillRect(j * cellWidth, i * cellHeight, cellWidth, cellHeight);
}
}
Thanks in advance,
Petr.
jsFiddle : https://jsfiddle.net/ngxjnywz/2/
snippet of javascript
var cellWidth = Math.ceil(canvasWidth / numberOfCells);
var cellHeight = Math.ceil(canvasHeight / numberOfCells);
Depending on the width, height and your numberOfCells you are sometimes getting a... lets say 4.2 which is 4, however this would be displayed wrong and will allow a 1 pixel blank line to appear. So all you need to do is use the Math.ceil function and this will cause your cellWidth and cellHeight to always be the higher number and you won't get blank lines anymore
The best solution is to add a 0.5 pixel wide stroke around all the fills, using the same style as the fill and offsetting all drawing so that you render at the center of pixels rather than the top left.
If you add scaling or translation you will have to adjust the coordinates so that you still give the centers for your drawing coordinates.
In the end you can only reduce the artifacts but for many situations you will not be able to completely remove them.
This answer shows you how to remove the artifacts for an untransformed canvas.
How to fill the gaps
After reading through and trying several approaches, I've decided to come up with my own. I've created another (virtual) canvas which had integer dimensions corresponding to the number of cells in the grid.
After drawing all the cells in there, I call context.drawImage() on the main canvas and pass the virtual canvas as an argument along with offset and scale parameters to make it fit rest of my drawing. Assuming that the browser would scale the virtual canvas's image as a whole (and not as individual cells), I was hoping to get rid of the unwanted separator lines.
In spite of my efforts, the lines are still there. Any suggestions?
Here's the fiddle demonstrating my technique: https://jsfiddle.net/ngxjnywz/5/
I generate dynamic SVG graphics on the fly using JavaScript. For this purpose a paragraph of text should be added into a box with a fixed aspect ratio inside the svg image. The text length may differ between short and also very long text length. As the actual font size is not important for my purpose I use the viewBox attribute to show the whole paragraph within the box.
As far as I researched and tested until now, svg does not provide any automatic line breaking functionality, therefore I might use a standard HTML div within a foreignObject to make use of HTML line breaking.
Are there any possibilities to get a div with fixed aspect ratio based on its content length?
I already managed to get such a div by an ittertive decreasing of width until the ratio more or less fits the purpose. But this solution is rather imprecise and needs to add the div to the DOM before actually inserting it into the svg. Are there any CSS solutions?
As unfortunately nobody could help to solve this problem, I implemented the following (more or less working) solution:
for(var i = 0; i < 200; i++){
if($('#wrapper').width()/$('#wrapper').height() <= 5){
console.log($('#wrapper').width()/$('#wrapper').height())
break;
}
$('#wrapper').width($('#wrapper').width()*0.8);
}
for(var y = 0; y < 200; y++){
if($('#wrapper').width()/$('#wrapper').height() >= 4.9){
break;
}
$('#wrapper').width($('#wrapper').width()*1.02);
}
This approach tries to itteratively converge the aspect ratio towards an approximately correct ratio.
This is by far not an optimal solution, but at least a working one.