I have a 500x400px container, where I'm working with RaphaelJS to manage some SVG goodies. I've loaded an image with this code:
var img = paper.image("images/image.jpg", 50, 200, 90, 110);
Now I want to draw a path relative to this element. How should I do?
If I write something like:
var c = paper.path("M 18.00,79.75 C 18.00,79.50 52.50,79.75 52.50,79.75...");
The path is being created relative to the parent container, and doesn't take the proper position over my image.
Thanks for your support
--- edit ----
This is my dashboard with its styling:
#canvas {
float: left;
width: 500px;
height: 400px;
border: 1px solid #333;
}
<div id="canvas"></div>
And this is part of the javascript code:
// Creates canvas 500 × 400 inside canvas div
var paper = Raphael(document.getElementById('canvas'), 500, 400);
// Load an image at 50, 200
var img = paper.image("images/image.jpg", 50, 200, 90, 110);
After that, I would like to fill an SVG path, positioning it over my image.
If I write something like:
var c = paper.path("M 18.00,79.75 C 18.00,79.50 52.50,79.75 52.50,79.75...");
This path is created upon the #canvas container, starting from 0,0 coords.
How do I do?
Please look into this fiddle http://jsfiddle.net/XRBRz/. In this fiddle, imagine the black rectangle as your image.
The staircase path is drawn relative to the black rectangle, by translating the path to the origin of the rectangle.
Also the path(staircase) is given a clip-path having the same dimension of the black rectangle, to clip the path outside the black rectangle.
It sounds like you are thinking that Raphael keeps a reference to a current pen position between creation of shapes, etc. I don't think this is true... I believe that when you add a path, the starting position of that path is relative to the canvas 0,0. (Note that the path 'M' command does allow a relative moveTo 'm', but I think this only works after the initial one in a path string... at the beginning, it seems to be absolute, regardless of case)
So, if you want to start the path from the top left corner of the image, start the path string with "M50,200" - for bottom right, start it with "M140,310".
If you want the path to stay attached to the image at that point, add them to a set. But that is another post... :-)
Related
I am working on a project where I have a page that lists job positions and I need to visually show progression (how to get from one job to another) using lines/arrows so the user can follow along. I created a page that contains all the data for this and now I am trying to use SVG paths to create lines on top of the data and draw paths.
I found some code in another answer that I converted to pure JS and removed the jQuery references to be able to use it in my project.
Here is the working fiddle with one path example:
http://jsfiddle.net/x4nmqkLj/
Here is my attempt:
http://jsfiddle.net/szrdb263/
My issue that I am facing is that the SVG and Path appear to be created BUT, I am unable to see the line/path on the DOM. However if I view the elements in the web tools, I can see the SVG element and path element and they appear to be in the correct location to where the path would be drawn from the starting and ending position.
My rendered path is as follows:
<path class="path" id="path1" d="M449.953125 512.34375 V568.03125 A55.6875 55.6875 0 0 0 505.640625 623.71875 H765.515625 A55.6875 55.6875 0 0 1 821.203125 679.40625 V1055.3203125"></path>
Here is the SVG Element:
Here is the Path Element:
The path should be drawing a line from the first box 1A to the bottom row, second box 2D. The path appears to be where its expected, the bottom center of the first box to the top center of the bottom box where the arrow would be drawn.
CSS:
#svgContainer {
z-index: -10;
opacity: 0.5;
margin: 2.5em 2.5em;
position: absolute;
background-color: #999;
}
path {
fill: none !important;
stroke: #000 !important;
stroke-width: 0.7em !important;
}
Is anything angular specific that I am missing causing this to not show up?
I am not terribly familiar with SVG but seeing both the SVG element and Path element in the DOM makes me think its pretty close. I can't imagine the arrow is outside of the DOM anywhere but I may be wrong.
Update:
I pasted my path code in a few "validator" sites for SVG to see if it would draw it and I am not getting any visual indication. This would suggest that there is something wrong with the coordinates that it is using to create the path. However, the same code is being used on the working example so I am wondering if this is an angular quirk after all with manipulating the DOM of sorts.
Update 2:
I believe I have solved the issue. I had to change how I was getting the ending coordinates in the JS.
Before:
// calculate path's end (x,y) coords
var endX = endCoord.offsetLeft + 0.5 * endElem.offsetWidth - svgLeft;
var endY = endCoord.offsetTop - svgTop;
After:
// calculate path's end (x,y) coords
var endX = endCoord.getBoundingClientRect().left + 0.5 * endElem.offsetWidth - svgLeft;
var endY = endCoord.getBoundingClientRect().top - svgTop;
New Fiddle: http://jsfiddle.net/8dumowvt/
I got your example working by doing the following:
Replaced offsetTop and offsetLeft by getBoundingClientRect().top and getBoundingClientRect().left in connectElements()
Adjusted style of svgContainer to give it a positive z-index, so that the svg is drawn over the other elements
Added pointer-events: none; to the svgContainer so that you can still interact with the elements behind it
Here's the updated Fiddle.
I have some question regarding HTML 5 Canvas and I hope you can help me to clear them.
Situation:
I have a canvas and some absolute positioned divs which are children of a relative positioned div.
<div class="relativeposition">
<canvas id="drawarea" height="700" width="800"></canvas>
<div id="absoluteposition1"></div>
<div id="absoluteposition2"></div>
<div id="absoluteposition3"></div>
</div>
So you can see the canvas and on the canvas there are the 3 different divs. Now I want to draw a polygon under every div in an each loop. The position of this polygon should almost be centered under the div. Under every div this position should be equal to the others divs.
The red caros are the positioned divs and just imagine that they are at the same position under every div. The Pseudo Code for drawing these caros is the following:
$.each(absolutepositionedDivs, function(index, value) {
var divtop = absolutepositionedDiv.position().top;
var divleft = absolutepositionedDiv.position().left;
context.beginPath();
context.moveTo(playerLeft + 76, playerTop + 154);
context.lineTo(playerLeft + 46, playerTop + 174);
context.lineTo(playerLeft + 55, playerTop + 190);
context.lineTo(playerLeft + 97, playerTop + 190);
context.lineTo(playerLeft + 106, playerTop + 174);
context.lineTo(playerLeft + 76, playerTop + 154);
context.closePath();
context.lineWidth = 2;
context.strokeStyle = "red";
context.stroke();
});
The initialization of canvas and so isn't in the code but I wrote it and it worked. Just ignore that the outcome of the draw isn't a caro...So the problem now is that the drawn objects aren't in an equal position as you can see in the following picture:
So I don't understand why every drawn object has a different position, even when I wrote that they all start from the same position of their div but end up in a different. Can you tell me why this is happening or have a solution do position all drawn polygons in the same position under their div?
EDIT: Here is a fiddle https://jsfiddle.net/asfga/yjjhqpyL/
Your fiddle is a mess so I needed to clean it up...
First, you have magic numbers spread across HTML javaScript and CSS which is a maintenance nightmare. So I cleaned it up and put all the positioning information into the JS file as that is where it is needed.
The shape was hand coded and with crazy offset that had no meaning. So made the shape an array of points with its origin at center top. (don't need the last point as you were closing the path when not needed).
Then removed jquery as you don't need that and you were not using it properly so effectively slowing your whole page down.
Added divs in code as that is a lot easier than typing all that by hand every time you want to make a change. Stored divs in array so you don't have to query the DOM when you need them later.
You need the canvas position. So I got that via the getBoundingClientRect function, so we can adjust the div positions to fit the canvas coordinates.
Then iterate each div and find its top Left with getBoundingClientRect subtracted the canvas top left and thus had the canvas coordinates of that div. Then as I needed to know where the background image was I added a function to load that background image and query its dimensions.
THAT is when I found out what your problem is.
Your background image is a full sized image with all the pentagons already drawn. It has no relationship the the divs as you don't clip it. You could never line it up unless you had the div coordinates correctly matching the image pentagon positions.
You need to use an image editor and locate each pentagon on the image. Add the locations as an array and draw the shapes at those positions.
I gave up at this point and just added a rectangle over the text in the canvas to show that it is lined up. You will have to workout what you want for the background image. If you want the whole image you will have to find the coordinates for each pentagon by hand. If you just want the first pentagon, clip the image and save one pentagon as an image. Then uncomment the background position rule I commented out and add the magic number offset to the code which will be constant for all divs.
You can find the resulting fiddle here but it will only be up for a short time as I will remove it once you have had a look.
In HTML/CSS we can align a child to any side of the parent through: top, right, left, bottom
Can this be applied to rectangles, lines etc.. on canvas's?
Alternatively is their a way to use percentages in positioning?
My end goal is to get a rectangle whose position snaps to the right of the canvas and stays their if the canvas is resized.
I can't seam to figure out a way to do this.
This is what I'm working with it.
ctx.rect(20,20,150,100);
Html & CSS can reposition child elements because the definitions of those children are saved in the Document Object Model (DOM).
The Html Canvas element does not save the definitions of any rectangles, lines, etc. that it draws on itself. Therefore, it cannot "recall" your rectangle to reposition it. To Canvas, your rectangle becomes unremembered pixels on its bitmap display.
To reposition your rectangle, you will have to manually "remember" its definition using code. This is usually done by saving your rectangle's definition in a javascript object like this:
var myRect={
x:20,
y:20,
width:150,
height:100,
}
When you want to reposition a canvas rectangle (as when you want it to "stick" to a resized canvas), you:
Resize the canvas. (Note: resizing the canvas element automatically clears its contents).
Calculate the new [x,y] that will keep your rectangle "stuck" to the right side of the canvas. If you want your rectangle stuck to the right side, you recalculate: var newX=canvas.width-myRect.width
Change the [x,y] in myRect to those new x,y values.
Use myRect to redraw your rectangle in its new desired postion.
Here's annotated example code and a Demo:
// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
// the definition of your rectangle
// (this definition is used when your rectangle must be redrawn)
var myRect={
x:20,
y:20,
width:150,
height:100,
}
// call helper function to reset your rectangle's "x"
// so it's positioned to the right side
stickRight(myRect);
// call helper function to redraw your rectangle
redrawRect(myRect);
// listen for changes in the html slider that resizes the canvas
$myslider=$('#myslider');
$myslider.change(function(){
// fetch the scaling factor the user has specified with the slider
var scale=parseInt($(this).val());
// resize the canvas to the specified size
// NOTE: resizing the canvas automatically erases all content
canvas.width=cw*scale/100;
canvas.height=ch*scale/100;
// again call helper function to reset your rectangle's "x"
// so it's positioned to the right side
stickRight(myRect);
// call helper function to redraw your rectangle
redrawRect(myRect);
});
function stickRight(rect){
rect.x=canvas.width-myRect.width;
}
function redrawRect(rect){
ctx.beginPath();
ctx.rect(rect.x,rect.y,rect.width,rect.height);
ctx.stroke()
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
Resize: <input id=myslider type=range min=0 max=200 value=100><br>
<canvas id="canvas" width=300 height=300></canvas>
Problem is in title. It used to do it on the odd occasion. Then i added the jQuery rotate.js plugin to spin my heading 360 degrees and now it is constantly placed to the right of where it should be. It may be interesting to note that i got the offset of the canvas with
var rect = gameController.canvas.getBoundingClientRect();
var offset = {
x: rect.left,
y: rect.top
};
And that still has coordinates of 0,0 in the top left corner of where it should be ( which is correct and how it should be when the canvas has not moved).
#canvas {
z-index: 1;
position: absolute;
margin-top: 52px;
margin-left: 44px;
background-image:url(images/background.jpg);
}
If the position is absolute, it is removed from the document and nothing will make it move. Strange.
getBoundingClientRect() returns the sum of the canvas and its css border-boxes.
Maybe check the canvas with getClientRects() to see exactly where it is.
I'm not sure why it moved, i probably have a css error somewhere..but i had my canvas as position absolute, relative to a div that it was inside. I placed my canvas right at the top of the body tag so it was absolute, relative to the whole page, then changed the placement of it with top and bottom to get it correct. Now nothing will move it. It works fine with the rotate.js plugin. Thanks for having a look at my question.
I am using a Kinetic.image object like this:
this.icon = new Kinetic.Image({
x: self.x,
y: self.y,
offset: [32,32],
image: self.imageItem.image,
width: self.size,
height: self.size,
scale: self.scale,
rotationDeg: self.angle,
draggable: true
});
The image is a PNG with transparent pixels. I also create a image hit region:
self.icon.createImageHitRegion(function() {
self.icon.getLayer().drawHit();
});
However, the hit region is wrong when I use the mouseover event. I suspect the hitregion is not scaled. Note that I also use offset so that the image rotates around it's center.
Am I doing something wrong of am I dealing with a bug here?
I had the same problem when the image is created passing width and height.
The library uses the width and height of the image to create the canvas to draw the hit region but the width and height is not used to scale the image that is drawn on the canvas.
If you search the kineticjs source you will see that inside createImageHitRegion there is a line that looks something like:
_context.drawImage(image, 0, 0);
Add the width and height for the image and it should work as expected:
_context.drawImage(image, 0, 0, this.getWidth(), this.getHeight());
In my case I didn't have to pass the scale attribute while creating the image, please verify if this is working when you provide the scale attribute otherwise you will have to tweak createImageHitRegion to account for that.