Move object on Canvas using textbox input - javascript

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.

Related

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);

Rotating a CSS3 3d cube with javascript

I am trying to rotate a 3d cube with two controls - for left and right. When you click on the left button, for example, I'd like to add extra 40 degrees to the rotateY value on the left.
My question is: Since I can't work with exact values (I want everytime to add new values to the existing ones!), I guess I will have to split up the string for the transform into something like this:
$(cube).css("-webkit-transform", "rotateX(-100deg) rotateZ(-50deg + add 40 degrees to the existing one!) translateZ(-30px)");
Here is the pen I am working on:
http://codepen.io/gbnikolov/pen/hHEBG
The easiest way to keep track of the rotation is to do it yourself, as jQuery's css() will return the matrix, and then you'll have to calculate that etc. and it's just easier to keep track of the value in an attribute instead.
Keep the value in a data attribute, and increment that together with the css value, and it should be straight forward, and it's accessible from other functions as well.
cube.data('rot', -50);
left.click(function(){
var deg = cube.data('rot') + 40;
cube.css("-webkit-transform", "rotateX(-100deg) rotateZ("+deg+"deg) translateZ(-30px)");
cube.data('rot', deg);
});
right.click(function(){
var deg = cube.data('rot') - 40;
cube.css("-webkit-transform", "rotateX(-100deg) rotateZ("+deg+"deg) translateZ(-30px)");
cube.data('rot', deg);
});
CodePen
To keep track of the rotation and increment it on each click with JS, this is what you can do :
jQuery :
var btn = $('.nav'),
body = $('body'),
cube = $(".cube"),
left = $('.left'),
v_transZ = -40 ;
// REST OF YOUR jQuery CODE
left.click(function(){
v_transZ = v_transZ - 10;
var counter = 0,
v_trans = 'rotateX(-100deg) rotateZ('+ v_transZ +'deg) translateZ(-30px)';
$(cube).css("-webkit-transform", v_trans);
});
As you are using CSS3 transitions, I would tend to use them also to rotate the cube and use JS only to trigger the animation with class changes on click. But as you ask for a JS solution...
Well, since you are changing the angle on only one axis this is not exactly what you are looking for, but it might give you a clue:
Css Tricks
I would try to solve the problem completely in the meantime, though!
I'm not sure whether your question is about how to keep do incremental changes (instead of hardcoded ones) or how to find a more elegant way for setting those values.
For the first one, I think the only way is to keep track of rotation values in your JavaScript code: http://codepen.io/anon/pen/dsIgn (I worked on it in Firefox, just change back -moz- to -webkit-.)
You have to declare a variable outside the click function and store the current value there
Then in every click you add 40 to that variable
JS
var currentRotateZ = -50
left.click(function(){
$(cube).css("-webkit-transform", "rotateX(-100deg) rotateZ(" + (currentRotateZ += 40) + "deg) translateZ(-30px)");
});

Designing a mouse using javascript and css

I felt like testing some stuff with javascript and html 5 canvas, they seemed really exciting to me. The first thing I have created is a very basic paint, you can only place squares and set the color, width, and height of the squares. When you mouse over the canvas I would like for it to show a "preview" of what shape you will be placing, the closest I have came is this:
elem.addEventListener('mousemove', function(event)
{
var x = event.pageX - elemLeft, y = event.pageY - elemTop;
// Render elements.
elements.forEach(function(element)
{
//Listen for controls.
var brushHeight = document.getElementById('brushHeight').value;
var brushWidth = document.getElementById('brushWidth').value;
var brushColor = document.getElementById('brushColor').value;
context.fillStyle = brushColor;
context.fillRect(x, y, brushWidth, brushHeight);
});
// Add element.
elements.push(
{
colour: brushColor,
width: brushWidth,
height: brushHeight,
});
}, false);
But there are several problems with this, I couldn't figure out how to delete the "preview" without deleting things underneath (shapes placed before) so it just kind of draws lines infinitely. Is there any possible way to just make this code the cursor itself? If not does anyone have any ideas of how I can fix the code above to be what I want it to be?
I had trouble putting this into words, any other information you need please just ask!
Here's the fiddle: http://jsfiddle.net/35wqJ/1/

Remove highlight from bars google chart

I have a working Google Combochart. Now i want to remove the highlight on specific moments when i hover over an item in the legend. I used the option "enableInteractivity", but this also removes things like the tooltips.
I want to keep the tooltips of course. I can't seem to find anything on the internet about how this is possible. I know i can disable the tooltips only, but not a method to disable this highlighting (what i want)..
Anybody has an idea how i can achieve this?
Thanks in advance!
Following this approach for styling on hover, you can get rid of the grey outline highlighting on hover by applying this css style.
#mychart svg g g g g rect {
stroke-width:0px;
}
There is no built-in method to do this. The highlights are drawn in to the SVG and the tooltips are also drawn by the google internal charts API code. So either you'd have to find a way to stop the highlights from being drawn in to the SVG (while still allowing the tooltips), or to disable interactivity and implement your own tooltips like this answer does. Answer quoted below (by jeffery_the_wind):
I ended up making a custom tool-tip pop-up that is working pretty
well.
Assuming your div for the bubble chart is defined like this:
<div id="bubble_chart_div"></div>
Then I used the JavaScript below. Please note that I left out that
stuff about how to set up your google chart data and loading the
google charts package. This code just shows how to get your custom
toolip popup.
var mouseX;
var mouseY;
$(document).mousemove( function(e) {
mouseX = e.pageX;
mouseY = e.pageY;
});
/*
*
*instantiate and render the chart to the screen
*
*/
var bubble_chart = new google.visualization.BubbleChart(document.getElementById('bubble_chart_div'));
bubble_chart.draw(customer_product_grid_data_table, options);
/*
* These functions handle the custom tooltip display
*/
function handler1(e){
var x = mouseX;
var y = mouseY - 130;
var a = 1;
var b = 2;
$('#custom_tooltip').html('<div>Value of A is'+a+' and value of B is'+b+'</div>').css({'top':y,'left':x}).fadeIn('slow');
}
function handler2(e){
$('#custom_tooltip').fadeOut('fast');
}
/*
* Attach the functions that handle the tool-tip pop-up
* handler1 is called when the mouse moves into the bubble, and handler 2 is called when mouse moves out of bubble
*/
google.visualization.events.addListener(bubble_chart, 'onmouseover', handler1);
google.visualization.events.addListener(bubble_chart, 'onmouseout', handler2);

Handling a "drop" event in javascript with Raphael

I am trying to build a board game in javascript with Raphael, which involves having the user drag and drop some pictures. I know Raphael objects have a method drag that enables pictures to be dragged.
I want the user to move a piece (represented by a picture) only according to the rules. To do this, I can write a method move in that way (in this example, a piece can only move by one square vertically):
move = function (dx, dy) {
document.getElementById("xCoord").innerHTML = dx;
document.getElementById("yCoord").innerHTML = dy;
startSquareX = coordToSquare(this.ox);
startSquareY = coordToSquare(this.oy);
newSquareX = coordToSquare(this.ox+dx);
newSquareY = coordToSquare(this.oy+dy);
var deltaX = newSquareX - startSquareX;
var deltaY = newSquareY - startSquareY;
if((deltaX*deltaX + deltaY*deltaY)===1) {
this.attr({x: this.ox + dx, y: this.oy+dy});
} else {
this.attr({x: this.ox, y: this.oy});
}}
The code above enables to user to move a piece in the only squares in the board that the rules allow. I would prefer to have it sightly differently:
- the user can drag a piece wherever she wants on the board
- when the piece is dropped on a square, if the piece is moved according to the rules, then the piece is put where the user dropped it. Otherwise, it is put back on its initial square.
This is the second point I am unable to do, because I don't know how to handle the event "drop" with Raphael. Can somebody help?
There isn't a drop event in in Raphael but Element.drag has an event handler for onend. That's where you define your "drop".
Refer to this demo. Notice the up handler (view source) that is called when element stops being dragged.

Categories