Ok, I feel incredibly stupid, but after trying for half an hour or so, I give up.
How do I resize a rectangle via the onResize() event in paper.js?
I am trying with this example, which comes with a onResize() function already, but I am having no success (you can edit the sample by clicking on the Source button on the top right).
The current resize function looks like this:
function onResize() {
text.position = view.center + [0, 200];
square.position = view.center;
}
Now, I tried to make the square 80 % of the viewport height on resize by adding:
square.size = [view.size.height / 100 * 80, view.size.height / 100 * 80];
(I tried the same with static numbers, just to be sure).
I tried
square.size = new Size(width, height);
square.set(new Point(view.center), new Size(width, height)
square.height = height;
square.width = width;
and probably 20 more version that I cannot remember now.
When I console.logged the square.size it did show me the newly assigned values (sometimes?), but it still left the size of the rectangle unchanged.
What can I do to actually change the size of rectangle?
Just to make sure, the onResize() function gets called whenever the window's dimensions change. That's not the only place you can change the rectangle's size / it has nothing to do with the rectangle per se.
To change the rectangle's sizes, you have to check the documentation. There's a scale(amount) and an expand(amount) method attached to the Rectangle object. size is just a property, and it doesn't seem to come with a setter.
Hence, if you want to keep a ratio in between the square and the view, I guess you could save the previous view width, see what the difference is and scale the rectangle accordingly – see how in this this answer to a previous question.
Alternatively, you could just reinitialise the square and set the size property to 80% of the view's width on each view resize:
square = new Path.Rectangle({
position: view.center,
size: view.bounds.width * 0.8,
parent: originals,
fillColor: 'white'
});
Related
I'm have a heat map application and store I store the x,y coordinates of a click and also the viewport width and height. Real data for 2 clicks:
x, y, width, height
433, 343, 1257, 959
331, 823, 1257, 959
The issue is when I resize the screen on the responsive site, the displayed clicks are now all off. I'm coming up empty on my searches but is there a formula or algorithm to recalculate the x and y coordinates for different resolutions. For example, the first click, if the width goes from 1257 to 990 and the height goes from 959 to 400, how to I recalculate the x and y so they line up in the same spot?
EDIT:
I added 2 fields to the database, width_percentage and height percentage
to store the x percentage of the width and the y percentage of the height. So if x was 433 and the width of the screen was 1257 then x was 35% from the left edge of the screen. I then used the same theory for the height and ran the calculations but it did not scale the click dot to the same spot as I though the percentages would do for scaling resolutions. I testing this by clicking on full resolution 1257 width then reopening at 900 width. See below for code to display click dots at lower resolution.
Ajax PHP
while ($row = mysql_fetch_array($results)) {
if( $_GET['w'] < $row['width'] ) {
$xcorr = $row['width_percentage'] * $_GET['w'];
$ycorr = $row['y'];
}
}
This uses the $_GET variable, passing the width and height of the screen resolution on page load. Then it gets the click dots from the database as $results. Since I only scale the resolution width from 1257 to 900 I did not put in calculation for height and its the same pixel as the initial click. The new width I multiplied by the percentage and set the dot that percentage margin from the left of the screen. Since the percentage is 35%
the new x coordinate becomes 900 *.35 = 315px from the left edge. It did not work and I'm still scratching my head on head to keep click in the same spot for responsive sites.
Have you tried this mathematical formula to change the range of a number?
And also instead of storing this:
x, y, width, height
433, 343, 1257, 959
331, 823, 1257, 959
You could store it normalized between 0 and 1 so it works for any width/height (calculated by dividing each x by its width and each y by its height):
x, y
0.344, 0.357
0.263, 0.858
Then you don't need to know the width/height you used when you stored them, and when you want to translate them to the size of the current screen you just multiply each one by the current width/height
You can acheive this by jquery:
$( window ).resize(function() {
//ur code
});
javascript
window.onresize = resize;
function resize()
{
alert("resize event detected!");
}
if you are working on mobile devices use this one also
$(window).on("orientationchange",function(event){
alert("Orientation is: " + event.orientation);
});
I think you are on the right track with the percentages. Are you including the offset of the map image. I wonder if your algo is working but the visual representation appears wrong because the offset is changing in the viewport.
$(window).resize(function() {
var offset = yourMap.offset();
myLeft = offset.left();
myTop = offset.top();
});
You need to add the offsets every time to get the proper placement.
This is what you should do. Sometimes the resize event fires when the document is being parsed. It is a good idea to put the code inside an onload event function. The orientation change function is taken from #Arun answer.
window.onload = function() {
$(window).on("orientationchange", function(event) {
alert("Orientation is: " + event.orientation);
});
window.onresize = function() {
alert('window resized; recalculate');
};
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
for this you need to do some calculation. Here is the function which will return new x and y potion based on the height and width
function getNewX(xVlaue, oldWidth, newWidth){
return xVlaue * newWidth / oldWidth;
}
newX = getNewX(10, 150, 100); // Use
You can use the common function for height and width calc.
DEMO
The whole question highly depends on the page you want to use this on.
Most pages have a centered block and/or some self-resizing (read "responsive") elements. If the page is not very responsive, e.g. having a fixed width, you have an easier job. If the page is centered, you might want to save the cursor's X-position relative to the center of the page. this way the window width doesn't matter. The same also applies to left- and right aligned pages of course - in this case you would save the X-pos relative to the left or right edge of the window respectively.
The following image shows a center-oriented click position. Note that the x- and y properties of the click don't change here if you resize the window.
Now to the more generic methods
If you save the window dimensions, the cursor position AND the scroll offsets on every click, you will most probably be able to reproduce it alongside the layout, but you'll need to reproduce it for every unique dimensions set. If you used the trick from above you might be able to overlay all layouts and find a common denominator. For example, if your page is centered in the window, has a max-width, and you saved the X-pos relative to the center of the window, you can overlay all clicks that happened in windows that were at least that width.
You could do some trickery however, and save the clicked elements alongside the informations you already do save. If you also save the click position relative to the element, you can evaluate this data to something like "the submit button is rather pressed on the bottom right side" or "people often click on the far end of that drop-down and sometimes mis-click by a few pixels".
Try both of the following:
1. Padding and margins might not scale. Use "* {padding:0;margin:0}" at the end of your stylesheet and check if that fixes it.
2. Ensure outer and inner (that means all) elements scale. Any single element failing to scale will make many other elements fall out of place. This generally happens with text inputs. Use "*{border:solid 2}" at the end of your stylesheet to visually observe the effect of scaling on each element.
I'm sure your problem will be resolved.
I'm using jointjs to make diagrams which will be user-editable. The user may drag them around and relocate each cell. However, when a cell is dragged to the edge, it overflows and becomes cut off. I want to prevent this from happening, instead the cell to stop before it gets to the edge of the paper and not be allowed to cross the edge, thus always staying completely within the paper. The behavior can be seen in jointjs' very own demos here:
http://www.jointjs.com/tutorial/ports
Try dragging the cell to the edge and you'll see that it eventually becomes hidden as it crosses the edge of the paper element.
Secondly, I'm using the plugin for directed graph layout, found here:
http://jointjs.com/rappid/docs/layout/directedGraph
As you can see, the tree position automatically moves to the upper left of the paper element whenever your click layout. How can I modify these default positions? The only options I see for the provided function are space between ranks and space between nodes, no initial position. Say I wanted the tree to appear in the middle of the paper upon clicking 'layout', where would I have to make changes? Thanks in advance for any help.
As an addition to Roman's answer, restrictTranslate can also be configured as true to restrict movement of elements to the boundary of the paper area.
Example:
var paper = new joint.dia.Paper({
el: $('#paper'),
width: 600,
height: 400,
model: graph,
restrictTranslate: true
})
I. To prevent elements from overflowing the paper you might use restrictTranslate paper option (JointJS v0.9.7+).
paper.options.restrictTranslate = function(cellView) {
// move element inside the bounding box of the paper element only
return cellView.paper.getArea();
}
http://jointjs.com/api#joint.dia.Paper:options
II. Use marginX and marginY DirectedGraph layout options to move the left-top corner of the resulting graph i.e. add margin to the left and top.
http://jointjs.com/rappid/docs/layout/directedGraph#configuration
I think my previous answer is still feasible, but this is how I implemented it in my project. It has an advantage over the other answer in that it doesn't require you to use a custom elementView and seems simpler (to me).
(Working jsfiddle: http://jsfiddle.net/pL68gs2m/2/)
On the paper, handle the cell:pointermove event. In the event handler, work out the bounding box of the cellView on which the event was triggered and use that to constrain the movement.
var graph = new joint.dia.Graph;
var width = 400;
var height = 400;
var gridSize = 1;
var paper = new joint.dia.Paper({
el: $('#paper'),
width: width,
height: height,
model: graph,
gridSize: gridSize
});
paper.on('cell:pointermove', function (cellView, evt, x, y) {
var bbox = cellView.getBBox();
var constrained = false;
var constrainedX = x;
if (bbox.x <= 0) { constrainedX = x + gridSize; constrained = true }
if (bbox.x + bbox.width >= width) { constrainedX = x - gridSize; constrained = true }
var constrainedY = y;
if (bbox.y <= 0) { constrainedY = y + gridSize; constrained = true }
if (bbox.y + bbox.height >= height) { constrainedY = y - gridSize; constrained = true }
//if you fire the event all the time you get a stack overflow
if (constrained) { cellView.pointermove(evt, constrainedX, constrainedY) }
});
Edit: I think this approach is still feasible,but I now think my other answer is simpler/better.
The JointJS docs provide a sample where the movement of a shape is contrained to lie on an ellipse:
http://www.jointjs.com/tutorial/constraint-move-to-circle
It works by
Defining a new view for your element, extending joint.dia.ElementView
Overiding the pointerdown and pointermove event in the view to implement the constraint. This is done by calculating a new position, based on the mouse position and the constraint, and then passing this to the base ElementView event handler
Forcing the paper to use your custom element view
This approach can be easily adapted to prevent a shape being dragged off the edge of your paper. In step 2, instead of calculating the intersection with the ellipse as in the tutorial, you would use Math.min() or Math.max() to calculate a new position.
I have checked this question which provides the perfect answer. But my problem is slightly different. I have a canvas of 300 x 300 and i am re-sizing the canvas using css to 200 x 60. If i re-size the canvas using css i am not able to get the color value onmouseover.
In the re-sized fiddle if you mouse over right below the red or blue rectangles you will notice it still says #FF0000 & #0000FF respectively while it should be #000000. So how to make it work even with re-sized canvas?
Fiddle: Re-sized with css.
Fiddle: Non re-sized.
You need to apply a scale factor inside the mouse handler method. The scale factor is the relationship between your canvas's bitmap (actual size) and the element size (CSS size).
For example:
// find scale:
var sx = example.width / parseInt(example.style.width, 10);
var sy = example.height / parseInt(example.style.height, 10);
// apply to x/y
x = (x * sx)|0; // scale and cut any fraction to get integer value
y = (y * sy)|0;
Updated fiddle
In addition the code need to have some boundary check of the coordinates so getImageData() won't fail (not shown here).
I've been working on an application that allows users to add images to a viewport, then resize them, crop them and rotate them. For the rotation to work, the images are added as SVG's, using the Raphael.js library.
All images have an outline (called wrapper). When an image is resized, so is its wrapper. When the image is rotated, the wrapper expands too, so that it will contain the rotated image (see image bellow).
So far, so good. Except that when I attempt to resize an image object AFTER it has been rotated, it won't be contained within its outline anymore (see image bellow).
When resizing an image, the svg oject's "x" and "y" attributes also need to be adjusted. Both the new size (width + height) of the image and the "x" and "y" attributes are computed as seen bellow:
var ratio_width = w / init.wrapper.width, // w = the new width of the wrapper (computed at each resize step)
ratio_height = h / init.wrapper.height, // h = the new height of the wrapper
svg_width = init.svg.width * ratio_width, // svg_width = the new width of the image
svg_height = init.svg.height * ratio_height, // svg_height = the new height of the image
x = init.svg.x*ratio_width,
y = init.svg.y*ratio_height;
this.svg.attr({
"x": x,
"y": y,
"width": svg_width,
"height": svg_height
});
The "init" JavaScript object contains the size (width & height) of the wrapper AND the size of the image (after the image is rotated, their dimensions will differ), but also the values of the x and y attributes BEFORE the resize operation.
The thing is that all the values computed above are correct. I know because I've also tried destroying the svg at each resize step and re-appending it (but it's not an option, there's too much of a flicker), with those same values for size, x and y, like so:
// "this.angle" on the second line is the current rotation angle
this.svg.remove();
this.svg = this.canvas.image(this.src,x,y,svg_width,svg_height).transform("r"+this.angle);
So if I simply remove the object and then create it again with the values above, why won't simply changing its attributes do the job as it should? I've been pulling my hair out for 3 days now, so I'd appreciate some help!
I'm using context-blender to apply a multiply effect on the first 192 pixels of the html background-image with a fixed color to achieve a transparency effect on the header of the page.
On the html I have 2 canvas. One for the part of the image to apply the multiply effect and one for the color.
On the javascript, after setting the color of the color-canvas and the width of both canvas to the window.innerWidth I'm getting the background image with:
imageObj.src = $('html').css('background-image').replace(/^url|[\(\)]/g, '');
Now comes the problem. I want to draw a cropped image to the image to the image-canvas so I can apply the multiply effect. I'm trying to do the following:
imageObj.onload = function(){
// getting the background-image height
var imageHeight = window.innerWidth * imageObj.height / imageObj.width;
// get the corresponding pixels of the source image that correspond to the first 192 pixels of the background-image
var croppedHeight = 192 * imageObj.height / imageHeight;
// draw the image to the canvas
imageCanvas.drawImage(imageObj, 0, 0, imageObj.width, croppedHeight, 0, 0, window.innerWidth, 192);
// apply the multiply effect
colorCanvas.blendOnto( imageCanvas, 'multiply');
}
But I'm doing something wrong getting the cropped height.
Ex: For an 1536x1152 image and a 1293x679 browser container, the value I'm getting for the source cropped height is 230 but to get the correct crop I need to use something around 296.
Edit:
I'm using background-size: cover on the css to create the background-image
Edit2:
I created a fiddle to illustrate the problem. If you uncomment the line //cHeight *= magicConstant; the cropped image looks a lot better but things stop making sense. I removed the multiply effect on the fiddler but that's not required to reproduce the problem. I also noticed that the behavior changed if I remove the second canvas from the URL.
Btw, this behavior happened with google chrome, but I think the same thing happens on safari and firefox.
OK, I've fixed it. Man was that hard! Mainly because you forgot to set the imageCanvas' canvas height. It also didn't help that the image has a white border. I spent a hell of a lot of time trying to figure out where the padding was coming from.
So to start, for the case of the fiddle, in function doBlending(), set imageCanvas.canvas.height = height;
Then the calculations in crop() need to cover 2 possibilities. Is the image being scaled for height and truncated on the left or scaled for width and truncated on the bottom? I'm not going to write both for you, but here's the one for the case where it is scaled for height:
function crop(imageObj, imageCanvas, colorCanvas) {
// Assumes bg image is scaled for hight
var scale = imageObj.height / window.innerHeight;
var targetHeight = imageCanvas.canvas.height;
var targetWidth = window.innerWidth;
imageCanvas.drawImage(imageObj,
0, 0, targetWidth * scale, targetHeight * scale,
0, 0, targetWidth, targetHeight);
}
I really have no idea where you came up with the scaling factors in your example. The image is going to be scaled by multiplying both the x and y dimensions by some scale factor. That's how you preserve the aspect ratio. The scale factor will be the larger of the one to make the height of the image match the height of the window and the one to make the width of the image match the width of the window.
I think it may not be valid for you to be using window inner dimensions here. Since cover will maintain the aspect ratio of the background image it means that both of its dimensions may not be fully displayed. So if you are trying to transform between aspect ratios to determine where to clip, you would have to account for the fact that the image may flow out of the window borders.