How would you create a JQuery / svg click-drag select outline effect? - javascript

Not sure exactly what to call it, but I am looking for a way to create a dotted outline/selection box effect via javascript/svg when you click and drag over an area, and then goes away on mouseUp (that could be added if it wasn't an original part) .
A jQuery library would be nice if it exists. I've done some looking around, and haven't found exactly what I am looking for.
I guess the theory would be get the coord from the first click, track the mouse coord moment and adjust the box accordingly.
But not writing it from scratch would be nice.

Here's a demo I made just for you :)
Demo (Static): http://jsfiddle.net/HNH2f/1/
Demo (Animated): http://jsfiddle.net/HNH2f/2/
You can use CSS to control the visual style of the marquee.
You can pass one or two functions to the trackMarquee method; both will be called with four arguments: the x1,y1,x2,y2 bounds of the marquee. The first function will be called when the marquee is released. The second function (if present) will be called each time the marquee moves (so that you can, for example, calculate what items are within that bounding box).
When you start dragging on the SVG document (or whatever element you choose to track) it will create a <rect class="marquee" />; during dragging it will adjust the size of the rectangle. Use CSS (as seen in the demo) to style this rectangle however you want. I'm using the stroke-dasharray property to make the border dotted.
For Stack Overflow posterity, here's the code (on the off chance that JSFiddle is down):
(function createMarquee(global){
var svgNS = 'http://www.w3.org/2000/svg',
svg = document.createElementNS(svgNS,'svg'),
pt = svg.createSVGPoint();
// Usage: trackMarquee( mySVG, function(x1,y1,x2,y2){}, function(x1,y1,x2,y2){} );
// The first function (if present) will be called when the marquee is released
// The second function (if present) will be called as the marquee is changed
// Use the CSS selector `rect.marquee` to select the marquee for visual styling
global.trackMarquee = function(forElement,onRelease,onDrag){
forElement.addEventListener('mousedown',function(evt){
var point0 = getLocalCoordinatesFromMouseEvent(forElement,evt);
var marquee = document.createElementNS(svgNS,'rect');
marquee.setAttribute('class','marquee');
updateMarquee(marquee,point0,point0);
forElement.appendChild(marquee);
document.documentElement.addEventListener('mousemove',trackMouseMove,false);
document.documentElement.addEventListener('mouseup',stopTrackingMove,false);
function trackMouseMove(evt){
var point1 = getLocalCoordinatesFromMouseEvent(forElement,evt);
updateMarquee(marquee,point0,point1);
if (onDrag) callWithBBox(onDrag,marquee);
}
function stopTrackingMove(){
document.documentElement.removeEventListener('mousemove',trackMouseMove,false);
document.documentElement.removeEventListener('mouseup',stopTrackingMove,false);
forElement.removeChild(marquee);
if (onRelease) callWithBBox(onRelease,marquee);
}
},false);
};
function callWithBBox(func,rect){
var x = rect.getAttribute('x')*1,
y = rect.getAttribute('y')*1,
w = rect.getAttribute('width')*1,
h = rect.getAttribute('height')*1;
func(x,y,x+w,y+h);
}
function updateMarquee(rect,p0,p1){
var xs = [p0.x,p1.x].sort(sortByNumber),
ys = [p0.y,p1.y].sort(sortByNumber);
rect.setAttribute('x',xs[0]);
rect.setAttribute('y',ys[0]);
rect.setAttribute('width', xs[1]-xs[0]);
rect.setAttribute('height',ys[1]-ys[0]);
}
function getLocalCoordinatesFromMouseEvent(el,evt){
pt.x = evt.clientX; pt.y = evt.clientY;
return pt.matrixTransform(el.getScreenCTM().inverse());
}
function sortByNumber(a,b){ return a-b }
})(window);

You are lucky I just made this myself. I'm using jQuery SVG plugin ( http://keith-wood.name/svg.html )
$("#paper2").mousedown(function(ev) {
ev.preventDefault();
var pX= (ev.pageX - this.offsetLeft) * viewBox[2]/parseInt($("#paper2").css("width"));
var pY= (ev.pageY - this.offsetTop) * viewBox[3]/parseInt($("#paper2").css("height"));
var rect = svg2.rect(
pX, //X
pY, //Y
1,1, //width and height
{ //Settings, you can make the box dotted here
fill: 'black', "fill-opacity": 0.3, stroke: 'red', strokeWidth: 3, id:rect
}
)
$("#paper2").mousemove(function(ev) {
ev.preventDefault();
var rect= $('#rect');
var pX= (ev.pageX - this.offsetLeft) * viewBox[2]/parseInt($("#paper2").css("width")) - rect.attr("x");
var pY= (ev.pageY - this.offsetTop) * viewBox[3]/parseInt($("#paper2").css("height")) - rect.attr("y");
rect.attr("width", pX);
rect.attr("height", pY);
});
$("#paper2").mouseup(function(ev) {
ev.preventDefault();
var div= $("#paper2");
div.unbind('mousemove');
div.unbind('mouseup');
})
});
paper2 is a div in which I have an svg element (so the svg element and the div have the same height/width). This is how I created the svg2 element:
var svg2;
var root2;
$(document).ready(function() {
$("#paper2").svg({
onLoad: function() {
svg2= $("#paper2").svg('get');
svg2.configure({id: 'svg2'});
var div= $("#paper2");
root2= svg2.root();
$("#svg2").attr("viewBox", viewBox[0]+','+viewBox[1]+','+viewBox[2]+','+viewBox[3]);
},
settings: {}
});
}
If you not using viewbox on the svg element you don't need this on the calculations:
* viewBox[2]/parseInt($("#paper2").css("*****"));
viewbox[2] would be the viewbox width and viewbox[3] would be the viewbox height.

Related

How do get I the clickable point from a html element?

how do I get the x,y coordinates from a HTML element relative to screen?
I'm using x,y from getBoundingClientRect() as below, but as you can see in the blow image, if I use move the cursor to this x,y position, the curson is in the middle between 0 and + buttons not the 5 button, which is the target button.
What am I missing?
JS code:
var e = document.querySelector('input[id=five]');"
var r = e.getBoundingClientRect();
var x = r.x;
var y = r.y;
MoveMouseTo(x,y); // imaginary call, the real cursor move is done by C# but I can share the code, as needed.
Image:
NOTE: if this aditional info may help, it's a C# application with embedded browser.
const getCoords = (e) => {
var x = e.clientX
var y = e.clientY
var xx = e.screenX
var yy = e.screenY
console.log(x, y, "client")
console.log(xx, yy, "screen")
}
You're going to want to assign this function to a onmousemove event to the outermost div containing the UI for your calculator. This should at least show you the difference between a screen X,Y and a client X,Y
https://www.w3schools.com/code/tryit.asp?filename=FVXZOK1SPTR0
You can try to add an event listener on your element and use the event to retrieve the coordinates of the mouse.
const $element = document.querySelector('input[id=five]');
$element.addEventListener('mousemove', handleMouseMove);
function handleMouseMove (event) {
console.log('Offset from the screen coordinates', event.screenX, event.screenY);
// The client refers to the element you are bound to;
console.log('Offset from the client coordinates', event.clientX, event.clientY);
};

Drawing an SVG dynamically using javascript

I'm trying to draw an isoceles triangle with it's top vertex in the middle of the screen.
I want to use JavaScript as screen sizes of different users can be different and hence, center of the screen must first be found out.
Here is my code:
function drawRect(){
var w = $(document).width();
var h = $(window).height();
var halfh = h/2;
var halfw = w/2;
var svg = document.createElement("svg");
var poly = document.createElement("polygon");
svg.setAttribute("style", "position: fixed;");
svg.setAttribute("height", ""+h);
svg.setAttribute("width", ""+w);
poly.setAttribute("points", ""+halfw+","+halfh+" 0,"+h+" "+w+","+h);
poly.setAttribute("style", "fill:lime;stroke:purple;stroke-width:1");
svg.appendChild(poly);
var svgplace = document.getElementById("carpet");
svgplace.appendChild(svg);
}
No triangle appears on the screen. But, if I open the 'Inspect Element' console on chrome, and I modify the created html element slightly, it appears! (Any kind of small mod. Like adding a space in the middle somewhere)
Please help!
Thanks in advance
You need to be using
document.createElementNS("http://www.w3.org/2000/svg", "polygon");
SVG is in its own namespace aside from HTML. Therefore, you need to create elements that are in the SVG namespace using createElementNS.
Consider the following example that works in Chrome and Firefox
var newItem = document.createElementNS("http://www.w3.org/2000/svg", "circle");
newItem.setAttribute("cx", ((16 * 1) + 8));
newItem.setAttribute("cy", "50%");
newItem.setAttribute("r", 4);
newItem.setAttribute("fill", "#333333");
document.getElementById("target").appendChild(newItem);
<svg id="target">
</svg>

give motion to grass field in canvas

i have created a grass field which is a combination of several small 60x36 images.a grass object is introduced and then drawn on the canvas.now i want to give it motion .the continuous scrolling effect .i made a code for it and it isn't working( the images (the grass field)are not scrolling along the width of the canvas which is the goal of this script).i haven't work much with oop in js. a little discussion on the mistakes i have done will be great
(the image i have used is added to the post)
<html>
<body>
<canvas id="mycanvas"></canvas>
<script>
function makeit(){
var canvas=document.getElementById("mycanvas");
var ctx=canvas.getContext('2d');
var height=500-36;
var xpos=[];
var img=new Image();
img.src="grass.jpg";
drawcanvas();
function drawcanvas(){
canvas.width=600;
canvas.height=500;
canvas.style.border="1px solid black";
}
for(i=0;i<10;i++){
xpos.push(i*60);
}
var grass=function(x,y){
this.x=x;
this.y=y;
this.img=img;
ctx.drawImage(this.img,this.x,this.y);
}
grass.prototype.motion=function(){
for(i=0;i<xpos.length;i++){
xpos[i]--;
if(xpos[i]<=-60){
xpos[i]=canvas.width;
}
ctx.drawImage(this.img,this.x,this.y);
}
}
for(i=0;i<xpos.length;i++){
var grass1=new grass(xpos[i],height);
}
var m=setTimeout(function(){
for(i=0;i<xpos.length;i++){
grass1.motion();
}
},1000);
}
window.onload=makeit;
</script>
</body>
</html>
actual canvas after drawing all the images
In essence, all you need is to create an image pattern then translate and draw it to screen.
An example assuming image has been loaded:
var ph = img.height; // pattern height
var w = canvas.width; // width of canvas/scoll area
var h = canvas.height; // used to calculate y pos.
var x = 0; // scroll position
ctx.fillStyle = ctx.createPattern(img, 'repeat-x'); // pattern
Then in the loop scrolling the grass:
function scroll() {
ctx.translate(x, h - ph); // translate to next position
ctx.fillRect(-x, 0, w, ph); // fill rectangle (fillstyle = pattern)
ctx.translate(-x, -(h -ph)); // translate back for other operations
x--; // scroll speed (here 1 pixel / frame)
requestAnimationFrame(scroll); // loop
}
FIDDLE
Pattern fills are anchored to the coordinate system which is why the translate is necessary. As we translate we also compensate for it using draw position in the opposite direction. This will make the pattern be filled into the same position but at a variable offset which creates the animation effect.
Just note that if you change fillStyle you need to store the pattern in a variable and reinitialize the fill style. If the loop is long-running also limit x so it doesn't overflow. This can be done using w as a condition (or modulo) to reset x to 0.

Move a HTML5 Canvas Element

I'm making a small jigsaw like puzzle in html5. Each jigsaw piece is it's own canvas. I need to move the canvas element using the mouse position. I've managed to get the canvas that is clicked, I just need to move it. I tried manipulating the top and left style attributes but the canvas didn't move. Can this be done or am I trying something impossible.
Thanks!
function MouseDown(can, e)
{
MovingCanvas = can;
clicked = true;
}
function MouseMove(e)
{
if(clicked)
{
var mx = e.clientX;
var my = e.clientY;
MovingCanvas.style.top = my;
MovingCanvas.style.left = mx;
}
}
e.clientX and e.clientY are integers.
Styles expect a string of the form {NUMBER}{UNIT}.
You are missing a unit, therefore it won't work.
MovingCanvas.style.top = my+"px";
MovingCanvas.style.left = mx+"px";

svg appending text element - gives me wrong width

i'm appending a text element to a svg via javascript. After appending i wanna set x and y coordinate, however, it returns me the wrong width of the text element when using it to calculate x.
Interesting:
In Chrome, when actualize the page via F5 or button it returns wrong width, when pressing enter in the adress bar, the width is right - strange!
Here is the small code:
var capt = document.createElementNS("http://www.w3.org/2000/svg", "text");
// Set any attributes as desired
capt.setAttribute("id","capt");
capt.setAttribute("font-family","Righteous");
capt.setAttribute("font-size","30px");
capt.setAttribute("fill", "rgb(19,128,183)");
var myText = document.createTextNode(this.options.captTxt);
capt.appendChild(myText);
this.elements.jSvgElem.append(capt);
capt.setAttribute("x", this.options.windowWidth-this.options.spacer-document.getElementById("capt").offsetWidth);
capt.setAttribute("y", this.options.captY+$('#capt').height());
OK, the problem seems to be that the browser doesn't calculate the correct width when using an other font. Not setting a font results in a correct width.
I solved the problem by setting the reference point ("alignment-point") to the upper right corner ot the text element by setting attributes:
capt.setAttribute("text-anchor", "end");
capt.setAttribute("alignment-baseline", "hanging");
This way i do not have to subtract the width and add the height of the element!
There is a bug:http://code.google.com/p/chromium/issues/detail?id=140472
it just pre init some functions that calculates text width so you should call this function before(i'm sure that there is several extra lines that can be deleted):
fixBug = function () {
var text = makeSVG("text", { x: 0, y: 0, fill: "#ffffff", stroke: '#ffffff'});
text.textContent = "";
var svg = $("svg")[0];
svg.appendChild(text);
var bbox = text.getBBox();
var Twidth = bbox.width;
var Theight = bbox.height;
svg.removeChild(text);
}
$("svg") - Jquery selector

Categories

Resources