How to give image element a "selected" look using Raphael.js - javascript

I'm using Raphael.js to draw images to canvas. I need to be able to select certain image elements (this I can do) and make them look like they are selected (this is the problem).
Before Raphael.js I used regular Html5 canvas and simple rectangles. It was simple to delete selected rectangle and draw a new one with a different color to that same place.
But now that I'm using images, it's a different story. The image I'm using is here. It's a small gif.
So the question(s):
Is there a simple way to change color of a Raphael.js image-element programmatically?
Can I make an image-element to blink by changing its opacity?
Only requirement is that the selected element must be movable.
Code for drawing image when user clicks on canvas:
var NodeImage = RCanvas.image("../vci3/images/valaisin.gif", position.x, position.y, 30, 30);
NodeImage.toFront();
RSet.push(NodeImage);
NodeImage.node.id = 'lamp';
NodeImage.node.name = name;
NodeImage.click(function() {
console.log("Clicked on node " + NodeImage.node.name);
// Here should be the code that blinks or changes color or does something else
});
Is this completely bad idea? Is there a better way to achieve my goal?

i would suggest granting the image with an opacity of some level, and assign a value of 1 to it upon click:
NodeImage.attr('opacity', 0.6);
// ...
NodeImage.click(function() {
this.attr('opacity', 1);
});
of course, you will probably want to manage the shape's selected state, to switch the selected style off later on. in fact, you'll want to manage all selectable shapes in the same manner, so let's do that:
// keep all selectable shapes in a group to easily manage them
var selectableShapesArray = [NodeImage, otherNodeImage, anotherSelectableShape];
// define the behavior for shape click event
var clickHandler = function() {
for (var i in selectableShapesArray) {
var image = selectableShapesArray[i];
if (image.selected) {
image.attr('opacity', .6);
image.selected = false;
break;
}
}
this.attr('opacity', 1);
this.selected = true;
}
// attach this behavior as a click handler to each shape
for (var i in selectableShapesArray) {
var shape = selectableShapesArray[i];
shape.click(clickHandler);
}​

Related

Recognize Image clicking over in Raphael

I have a canvas where using raphael I'm going to draw some images.
The images's names are in a list: images_list and I will draw three images for row. All the images have the same dimensions, are equaly spaced and are .png files (no vector).
Some example code:
var paper_images_list = Raphael(canvas_images_list, '100%', '100%');
var images_for_row=3
var y_max=Math.ceil(image_list.length/images_for_row)*40
paper_images_list.setSize(div_width, y_max);
for (var i=0; i<image_list.length; i++) {
var col=parseInt(i/images_for_row)
var y=col*40
var x=(i-images_for_row*col)*40
var image = paper_images_list.image('/media/images/'+image_list[i], x, y, 33, 27);
};
What I want: clicking on an image I want to know which image that is, for use it in another paper/canvas.
I'm using Raphael because I thinked it could make that easy but maybe I'm wrong. Is it possible to recognize the image just clicking over it?
If not, I can find the coordinates of the click and calculate which image there is, but I don't need Raphael for that, right? There are better solutions?
I'm using Phyton3.5, Django 1.9, Javascript/JQuery, Windows7
Thanks to Ian I found it's so simple like:
document.getElementById('canvas_images_list').onclick=function(event) {
var myimage = event.target
if (myimage.tagName == 'image') {
myimage = myimage.href.baseVal;
};
};
The if statement excludes the clicks outside any images

Mouse click transformation to svg after pan and zoom

Im using snap.svg an snap.svg.zpd libraries. Same issue I have if I use snap.svg and jQuery panzoom library combination.
Code sample you can find here.
var mySvg = $("#plan")[0];
var snap = Snap("#plan");
//create an image
var imagePlan = snap.image("http://upload.wikimedia.org/wikipedia/commons/4/42/Cathedral_schematic_plan_fr_vectorial.svg", 10, 10, 900, 500);
var group = snap.group(imagePlan);
snap.zpd();
var pt = mySvg.createSVGPoint(); // create the point;
imagePlan.click(function(evt)
{
console.log(evt);
pt.x = evt.x;
pt.y = evt.y;
console.log(mySvg.getScreenCTM().inverse());
//When click, create a rect
var transformed = pt.matrixTransform(mySvg.getScreenCTM().inverse());
var rect1 = snap.rect(transformed.x, transformed.y, 40, 40);
group.add(rect1);
});
Problem is...if you click on initial svg it will add rectangle to the mouse position. If you pan/zoom image and then add rectangle it will be shiffted.
It looks like problem is in method mySvg.getScreenCTM().inverse(). Matrix returned is always same one, panning and zooming does not change it. It always use matrix from initialy rendered svg. However, if I inspect svg element, I can see that pann/zoom change transform matrix directly on element (image below).
Does anybody know how to fix this. My requirement is to be able to drag and drop elements outside svg into svg on any zoom scale or pan context, so I need transformation from mouse click point to svg offset coordinates. If you know any other approach or any other library combination that could done this, it would be ok for me.
Thanks in advance.
Problem is, the transform isn't in mySvg. Its on the 'g' group element thats inside the svg. Zpd will create a group to operate on as far as I know, so you want to look at that.
To hightlight this, take a look at
console.log(mySvg.firstElementChild.getScreenCTM().inverse());
In this case its the g element (there's more direct ways of accessing it, depending on whether you want to just work in js, or snap, or svg.js).
jsfiddle
Its not quite clear from your description where you want the rect (within the svg, separate or whatt) to go and at what scale etc though, and if you want it to be part of the zoom/panning, or static or whatever. So I'm not sure whether you need this or not.
I'm guessing you want something like this
var tpt = pt.matrixTransform( mySvg.firstElementChild.getScreenCTM().inverse() )
var rect1 = snap.rect(tpt.x, tpt.y, 40, 40);

Highlight zoomed-in area

I have a project for manipulating SVGs.
Users can zoom in and out of the image. I want to have a thumbnail of the whole image that shows and highlights the area that users are currently zooming in/out.
Something along these lines http://www.ancientlives.org/transcribe
I have tried playing around with http://snapsvg.io/, without success.
Can anyone help working something out with the library?
As the specific question mentions Snap, I'll go down that road.
You could clone the svg element, and drag a rect over it, or I was wondering if you could drag a rect thats actually a clip or something, that could be a slightly better solution, but a bit fiddlier to work out, so for the moment here's the first way.
First off, we can load our image..
Snap.load("Dreaming_Tux.svg", onLoad)
Then the main onLoad func..
This works by cloning the image (I also use toDefs() which isn't necessary, but if the image is a large file, you could possibly use just one the set of elements, and reference them in a 'use' method. So I'm leaving that in as just a simple example for the moment.
We also define a viewBox,
var svg = s.svg(0,0,800,800,0,0,200,200);
Which will be our 'window'
And then when we drag the rect, we make the image (placed in a group so we can transform it) move.
You will need to tweak the drag handler, to make it work completely (atm it will just drag via dx,dy and reset each time) and also tweak the zoom and window sizes and relationship to what you want, but it should give a proof of concept.
example (drag the rect)
function onLoad( fragment ) {
s.append( fragment );
var tux = s.select('#tux');
var clone = tux.clone();
var svg = s.svg(0,0,800,800,0,0,200,200);
var g = s.g( tux ).transform('t0,0').appendTo(svg);
var defElement = svg.toDefs();
var dragRect = s.rect(0,0,100,100).attr({ opacity: 0.2, transform: 't600,50', id: 'dragrect' }).drag( dragMove, dragStart );
var tux1 = defElement.use().appendTo( s );
var tux2 = clone.appendTo( s.g().transform('t600,50s0.5') );
s.append( dragRect );
function dragMove(dx,dy) {
this.attr({
transform: this.data('origTransform') + (this.data('origTransform') ? "T" : "t") + [dx, dy]
});
g.transform('t' + -dx +',' + -dy);
}
function dragStart() {
this.data('origTransform', this.transform().local );
}
};

Move object on Canvas using textbox input

I've got a canvas on which I can add layers, these layers I can move, select, rotate, resize etc. Below the canvas I display the properties of the layer (x, y, width, height).
What I am trying to do is when I change the values in the textboxes containing the x and y coördinates the layer should be repositioned to the coördinates I typed in.
I've tried several things but everything seems to mess up the canvas, I am using this to move the layer on mousemove now:
else if (layerState == MOVING && mouseDown) {
selectedLayer.offsetX += e.pageX - canvasOffsetX - mousePrevX;
selectedLayer.offsetY += e.pageY - canvasOffsetY - mousePrevY;
drawMarker(selectedLayer);
}
And I use this to get the x and y of the layer:
document.getElementById('x').value = Math.round(layer.offsetX*100)/100;
document.getElementById('y').value = Math.round(layer.offsetY*100)/100;
A working example of my canvas and the code can be found here:
http://cdpn.io/fjzcv
I've also tried to work with these examples but couldn't get any of them to work:
http://chimera.labs.oreilly.com/books/1234000001654/ch03.html#text_arranger_version_2.0
http://fabricjs.com/controls/
I have tried setting an eventListener on the texboxes but when I do this the canvas will dissapear.
If anyone knows how to do this it would be great!
EDIT:
I found out a way to change the coördinates onchange with the textbox but now I can just change them to a set number instead of taking the value I filled in the textbox:
document.getElementById('x').onchange=function(){selectedLayer.offsetX = 100;
drawMarker(selectedLayer);
};
document.getElementById('y').onchange=function(){selectedLayer.offsetY = 100;
drawMarker(selectedLayer);
};
Anyone knows how to get it to move to the filled in coördinate?
I tried editing the HTML on the code pen and I think this should work.
Firstly add an event listener to your text boxes, where you've got the canvas ones.
document.getElementById('x').addEventListener('onchange',updatePos,false);
canvas.addEventListener('mousemove', mouseMoveEvent, false);
....
Then create a similar function to your mouseMoveEvent(e) to change the selected layer values
function updatePos(e) {
var temp = document.getElementById('x').value;
selectedLayer.offsetX = canvas.offsetX + temp;
drawMarker(selectedLayer);
}
Obviously you may need to add in validation or change this to suit your code, but it should get the object moving around.

erase part moving image

Is there a way to clear the canvas (html5)of only 1 element only ? I have a moving image on a canvas and when I erase the image the background color goes as well. Is there a way to just remove the image and not the whole background. My background is just a simple color but in the future it will be more complicated.
This is also tricky because there is no way to get image x,y pos from a property.
ClassLoadImages.prototype.m_move = function(){
this.x=++img1_x;
this.y=++img1_y;
//img1_x++;
//img1_y++;
// alert(img.x);
ctx.drawImage(img.imgElement, this.x, this.y);
// ctx.fillText("finished loading " ,10,40);
};
function doGameLoop() {
ctx.clearRect(0,0,600,400);
img.m_move();
if (img.x>30)
{
clearInterval(gameLoop);
}
}
var img= new ClassLoadImages('images/image4.jpg');
gameLoop = setInterval(doGameLoop, 100);
</script>
Simple answer is no. A canvas is a flat bitmap, not a layered collection of objects. Once you draw to it you lose the background behind the thing you draw.
You could try to implement the functionality yourself by recording the steps you used to create the canvas in the first place, and re-creating it with or without the relevant image.

Categories