I'm creating a form builder and I'm using interact.js to move elements and change their size. The problem is that when I drag them the design is not responsive anymore. This is the code of the function that is fired on dragmove event:
function dragMoveListener (event) {
var target = event.target,
// keep the dragged position in the data-x/data-y attributes
x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy
console.log($(target).parent().attr('id'))
// translate the element
target.style.webkitTransform = target.style.transform
= 'translate(' + x + 'px, ' + y + 'px)'
// update the posiion attributes
target.setAttribute('data-x', x)
target.setAttribute('data-y', y)
}
I tried to use percentages and em but it didn't work. I'm really stuck and I will be grateful for any help you can provide.
Related
I'm trying to overlay a bpmn flow using bpmn.io with a heatmap using heatmap.js. If the canvas is set to the first and only element in the dom it actually works, but once you add anything else like in my sample a header, the coordinate system between both gets off.
I've prepared a fiddle that shows exactly what I mean.
https://jsfiddle.net/rafaturtle/qt8Ly4ez/16/
const rect = canvas.getGraphics(element).getBoundingClientRect();
const x = (rect.x + rect.width / 2);
const y = (rect.y + rect.height / 2);
data.push({
x: x.toFixed(0),
y: y.toFixed(0),
value: stats[element.id]
});
I believe its on the calculation of x,y of each element, off setting it by a factor but after trying every combination I could think of I didn't manage.
thanks
I am not sure if I misunderstood what you aim for, but laying the heatmap over the elements can be easily achieved by using the dimensions of the current element, element.x, element.y, element.width, element.height.
The following code places the heatmap at the exact position of the elements:
var registry = bpmnJS.get('elementRegistry');
for (var i in registry.getAll()) {
var element = registry.getAll()[i];
if (stats[element.id] != null) {
const centerx = element.x + (element.width / 2 )
const centery = element.y + (element.height / 2 )
data.push({
x: centerx,
y: centery,
value: stats[element.id]
});
}
}
Working example: https://jsfiddle.net/cr8Lg53a/
const x = (rect.x + rect.width / 2) - canvas.getContainer().getBoundingClientRect().x;
const y = (rect.y + rect.height / 2) - canvas.getContainer().getBoundingClientRect().y;
try this
I've been working with HTML5 drag and drop, and canvas. I'm trying to put the two together: I drag an element to a drop-area; in the drop-area I want to be able to move the dropped items around to position them as needed.
I know how to drop elements into a div, for ex, but:
does the drop-area have to be a canvas for (re)positioning?
is there a specific term for the moving/repositioning of elements in the drop-area/canvas. I've done a lot of searching and can't find a term for this specifically. simply 'dragging'??
sample drop-area.
No the canvas element is not required anyhow.
You can achieve the exact same result as the linked example you gave without using any canvas.
Here is an example code, among many others possible, certainly far from being perfect, but which does the same as your example, using only <div> elements, css and javascript, but it could also be made with svg.
// we will increment it to get the dragged element atop of everything
var zIndex = 0;
// our constructor
var newElement = function() {
var that = {};
// first get its dimension and position randomly
that.rad = Math.random() * 20 + 10;
// x and y are the center of our element
that.x = Math.random() * (500 - that.rad * 2) + that.rad;
that.y = Math.random() * (300 - that.rad * 2) + that.rad;
// define the element that will be appended to the doc
that.el = document.createElement('div');
// a shortcut to the style property of the element
// since we'll play with this to update our object's position
var s = that.el.style;
// don't forget we're talking in css
s.width = that.rad * 2 + 'px';
s.height = that.rad * 2 + 'px';
s.left = that.x - that.rad + 'px';
s.top = that.y - that.rad + 'px';
s.backgroundColor = get_random_color();
// needed to make be sure we're not in a corner of the circle shaped elements
that.isCircle = Math.random() > .5;
if (that.isCircle) {
that.el.className = 'circle';
}
// happens on mousedown
that.startDrag = function(x, y) {
that.lastX = x;
that.lastY = y;
s.zIndex = ++zIndex;
}
// happens on mousemove if we're the one being dragged
that.move = function(x, y) {
that.x += x - that.lastX;
that.y += y - that.lastY;
that.lastX = x;
that.lastY = y;
s.left = that.x - that.rad + 'px';
s.top = that.y - that.rad + 'px';
};
container.appendChild(that.el);
return that;
};
var elements = [];
for (var i = 0; i < (~~(Math.random() * 50)) + 15; i++) {
elements.push(newElement());
}
var dragged;
var mousedown = function(e) {
var rect = container.getBoundingClientRect();
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
dragged = null;
// sort our elements, higher zIndex firsts
elements.sort(function(a, b) {
return (+b.el.style.zIndex) - (+a.el.style.zIndex);
});
elements.forEach(function(el) {
// we already found the One, no need to go further
// (no "break;" in forEach method...)
if (dragged) return;
// is our mouse over the rectangular bounds of this element
if (x >= el.x - el.rad && x <= el.x + el.rad &&
y >= el.y - el.rad && y <= el.y + el.rad) {
if (el.isCircle) {
// a little bit of Pythagorian
var a = el.x - x;
var b = el.y - y;
var dist = Math.sqrt(a * a + b * b);
// too far from the center, we were in the corner
if (dist > el.rad) {
return;
}
}
// we got through here,
// tell the whole app we've got the One
dragged = el;
el.startDrag(x, y);
}
});
};
var mousemove = function(e) {
// nobody is being dragged, so don't do anything
if (!dragged) return;
// otherwise, tell the browser we handle the event
e.preventDefault();
e.stopPropagation();
// get the coordinates of our container
var rect = container.getBoundingClientRect();
// get the relative coordinates of our event
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
// move the dragged element accordingly
dragged.move(x, y);
};
var mouseup = function() {
// we dropped it..
dragged = null;
};
container.onmousedown = mousedown;
container.onmousemove = mousemove;
container.onmouseup = mouseup;
function get_random_color() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.round(Math.random() * 15)];
}
return color;
};
body {
text-align: center;
}
#container {
width: 500px;
height: 300px;
background-color: black;
margin: 0 auto;
position: relative;
overflow: hidden;
}
#container>div {
position: absolute;
opacity: .7;
}
.circle {
border-radius: 50%;
}
<div id="container"></div>
As you can see, I myself used the word dragged to refer to the object that we do move while we move the mouse with the button down. Yes, dragging is how this action is called...
But, this has very little to do with the HTML drag and drop API where what is important is not the positioning of your elements, but their content.
You can drag and drop elements into others, but it was mainly developed to drag data (external files or text content) to the document.
For this particular example, that would make things a lot harder and while the name "dragging" still applies to the action of the end-user, this shall not be confused with the API and every events related.
A canvas element is required by your linked canvas demo, but you can alternatively use the drag/drop API built into html+JS. And you can "manually" move DOM objects using mouse events as described in Kaiido's answer.
The canvas is required for your linked demo to work.
That exact demo was coded using a canvas element's drawing capabilities and that exact demo will not work if you try to substitute a DIV.
Think of html5 canvas as a re-writable bitmap. You can't "move" or "drag" anything on the canvas. Instead, you completely erase the canvas surface and redraw your circles in their new positions.
In the case of dragging, you listen for mousemove events on the canvas and reposition the circle under the mouse by the distance the mouse has moved since the last mousemove event.
As shown in JSFiddle, when you move the mouse over the 3d transformed div, I tried to convert the mouse position into the css 3d transformed element space.
Which means, the red spot should always be display at the exact position of the mouse.
However, the DIV html element doesn't have method getScreenCTM or getTransformToElement or matrixTransform which can be used to transform the point. Does anybody know how to achieve that?
http://jsfiddle.net/9cv2y0dp/
var tel = $('#transformed')[0];
var box = $('#box')[0];
tel.style.transform
= 'translate3d(100px,100px,0px) rotateY(45deg)';
var rect = tel.getBoundingClientRect();
$('#transformed').bind('mousedown', function(e){
var evt = e || event;
var x = evt.clientX;
var y = evt.clientY;
$('#cursor')[0].style.left = (x - rect.left) + 'px';
$('#cursor')[0].style.top = (y - rect.top) + 'px';
box.innerHTML = (x - rect.left) + 'px<br/>' + (y - rect.top) + 'px';
});
I need to reproduce the effect created on this site about Team : http://www.case-3d.com/#about
I try to look on the web but I can not find a tutorial or site that talks about this html5 effect .... I was wondering if someone could help me ?
thanking you in advance
If you inspect the element you can find out they use a canvas. Looking further you can see the script that uses the canvas (by searching in the inspector for the ID or some similar techinque) is called "1". I pulled some of the basic structure so you can follow it:
//This part sets up the canvas and gets the pictures
function setupCanvas() {
// Get canvas and context references
teamCanvas = document.getElementById("stage1");
teamContext = teamCanvas.getContext("2d");
// Get images references
img1 = document.getElementById("01");
img2 = document.getElementById("02");
...
// This part sets the initial position of the shapes
// You can see that it is based of the window size and in reference to each other
// Shape #1
x1_1 = teamCanvas.width / 2;
x1_2 = teamCanvas.width;
x1_3 = teamCanvas.width;
x1_4 = 0;
x1_5 = 0;
y1_1 = ssp1_1 = 929 + diff;
y1_2 = ssp1_2 = 2000 + diff;
y1_3 = ssp1_3 = 4000;
y1_4 = ssp1_4 = 4000;
y1_5 = ssp1_5 = 2000 + diff;
// Shape #2
x2_1 = 0;
x2_2 = teamCanvas.width / 2;
x2_3 = teamCanvas.width;
x2_4 = teamCanvas.width;
x2_5 = 0;
y2_1 = ssp2_1 = 3000;
y2_2 = ssp2_2 = 4000;
y2_3 = ssp2_3 = 3000;
y2_4 = ssp2_4 = 6000;
y2_5 = ssp2_5 = 6000;
...
// Some other stuff goes here, I didn't copy all of it
}
// Then it goes into this function to handle the scroll and redraw it on the canvas
function redrawAbout(scrollPosition) {
// Refresh canvas
teamContext.clearRect(0, 0, teamCanvas.width, teamCanvas.height);
var scrollAmt = scrollPosition / maskModifier;
// Redraw
// Mask #1
if (scrollPosition > -4000) {
teamContext.save();
teamContext.beginPath();
teamContext.moveTo(x1_1, ssp1_1 + scrollAmt);
teamContext.lineTo(x1_2, ssp1_2 + scrollAmt);
teamContext.lineTo(x1_3, ssp1_3 + scrollAmt);
teamContext.lineTo(x1_4, ssp1_4 + scrollAmt);
teamContext.lineTo(x1_5, ssp1_5 + scrollAmt);
teamContext.lineTo(x1_1, ssp1_1 + scrollAmt);
teamContext.clip();
teamContext.drawImage(img1, 0, -200);
teamContext.restore();
}
// Mask #2
if (scrollPosition <= -2100 && scrollPosition > -5900) {
teamContext.save();
teamContext.beginPath();
teamContext.moveTo(x2_1, ssp2_1 + scrollAmt);
teamContext.lineTo(x2_2, ssp2_2 + scrollAmt);
teamContext.lineTo(x2_3, ssp2_3 + scrollAmt);
teamContext.lineTo(x2_4, ssp2_4 + scrollAmt);
teamContext.lineTo(x2_5, ssp2_5 + scrollAmt);
teamContext.lineTo(x2_1, ssp2_1 + scrollAmt);
teamContext.clip();
teamContext.drawImage(img2, 0, -200);
teamContext.restore();
}
In essence, they create some geometric shapes based on x and y co-ordinates, cut the images to fit within their respective geometric area based on those variables, calculate how much is being scrolled (through another plug in I believe), and redraw everything based on how far a user has scrolled.
Inspect element is an incredibly useful tool, learn to use it
When asking questions on StackOverflow, stay away from generics like this. Try to solve it yourself and post what you've tried so far and what is giving you trouble. Give detail and be articulate. If you do that you won't be down voted and you'll get relevant, all around good answers
I have implemented a basic Isometric tile engine that can be explored by dragging the map with the mouse. Please see the fiddle below and drag away:
http://jsfiddle.net/kHydg/14/
The code broken down is (CoffeeScript):
The draw function
draw = ->
requestAnimFrame draw
canvas.width = canvas.width
for row in [0..width]
for col in [0..height]
xpos = (row - col) * tileHeight + width
xpos += (canvas.width / 2) - (tileWidth / 2) + scrollPosition.x
ypos = (row + col) * (tileHeight / 2) + height + scrollPosition.y
context.drawImage(defaultTile, Math.round(xpos), Math.round(ypos), tileWidth, tileHeight)
Mouse drag-scrolling control
scrollPosition =
x: 0
y: 0
dragHelper =
active: false
x: 0
y: 0
window.addEventListener 'mousedown', (e) =>
handleMouseDown(e)
, false
window.addEventListener 'mousemove', (e) =>
handleDrag(e)
, false
window.addEventListener 'mouseup', (e) =>
handleMouseUp(e)
, false
handleDrag = (e) =>
e.preventDefault()
if dragHelper.active
x = e.clientX
y = e.clientY
scrollPosition.x -= Math.round((dragHelper.x - x) / 28)
scrollPosition.y -= Math.round((dragHelper.y - y) / 28)
handleMouseUp = (e) =>
e.preventDefault()
dragHelper.active = false
handleMouseDown = (e) =>
e.preventDefault()
x = e.clientX
y = e.clientY
dragHelper.active = true
dragHelper.x = x
dragHelper.y = y
The Problem
As you can see from the fiddle the dragging action is ok but not perfect. How would I change the code to make the dragging action more smooth? What I would like is the point of the map you click on to stay under the mouse point whilst you drag; the same as they have done here: http://craftyjs.com/demos/isometric/
Lots of libraries help with things like this. I would recommend using the data manipulation abilities of d3 to help, for several reasons.
First, in d3, there is a drag behavior where the origin of the object is stored and a mouse position relative to the origin is computed when the drag starts. Then, you can use the absolute position of the mouse to determine where the object should be and avoid the incremental errors that occur when you use relative changes - which get far worse when you start rounding them, as above.
dragMap = (d) ->
d.x = d3.event.x # d3.event.x, y are computed relative to the origin for you!
d.y = d3.event.y
dragBehavior = d3.behavior.drag()
.origin(Object) # equivalent to (d) -> d
.on("drag", dragMap)
d3.select(canvas)
.datum(x: 0, y: 0) # Load your canvas with an arbitary origin
.call(dragBehavior) # And now you can drag it!
Second, by using d3's linear or other numerical scales you can avoid doing typical drawing math yourself which is error-prone especially when you have to do it all over the place. Before you were scaling the drag by 28. In my current approach it's unnecessary, but if you change your drawing algorithm to use tiles instead of pixels, you can change this scale which will automatically convert mouse pixels into tile sizes.
pixelToTile = d3.scale.linear()
.domain([0, 1])
.range([0, 1])
Here's your fiddle re-done with d3 help. No dragHelper and all that extraneous code necessary. All the Math.round calls are also unnecessary except the one for canvas draw, which prevents antialiasing.
http://jsfiddle.net/kHydg/23/
Isn't that much shorter and sweeter?
P.S. Isometric real-time browser games are an awesome idea. I will definitely try making one when I have time.