Related
I need to set up <text> element in the center of pie chart segments in an svg <circle>. Right now I use this formula for coordinates:
x(t) = r cos(t) + j
y(t) = r sin(t) + j
where t must be radians. Actually, it works good the first point. But next points are wrong (see code snippet). The question is do I use the wrong formula?
It's my calculations for <text> coordinates
var textAngle = ((data[c].value/100) *360)/2 + textAngleOffset;
var radians = degrees_to_radians(textAngle);
text.setAttribute("x", radius * Math.cos(radians) + 188.5 );
text.setAttribute("y", radius * Math.sin(radians) + 188.5);
//Pie chart plugin
function initPieChart(segmentsData) {
var data = [];
for (var i = 0; i < segmentsData.length; i++) {
var percent = segmentsData[i].getAttribute('data-percent');
var bgcolor = segmentsData[i].getAttribute('data-bg-color');
var textcolor = segmentsData[i].getAttribute('data-text-color');
data.push({"bgcolor": bgcolor, "textcolor": textcolor, "value" : Number(percent)});
}
var angle = -90;
var textAngleOffset = -90;
// Setup global variables
var svg = document.getElementById('pie-chart'),
list = document.getElementById('pie-values'),
totalValue = 0,
radius = 94,
circleLength = Math.PI * (radius * 2), // Circumference = PI * Diameter
spaceLeft = circleLength;
// Get total value of all data.
for (var i = 0; i < data.length; i++) {
totalValue += data[i].value;
}
function degrees_to_radians(degrees){
var pi = Math.PI;
return degrees * (pi/180);
}
function animate(circle, segmentLength, circleLength) {
// circle.setAttribute("stroke-dasharray", spaceLeft + " " + circleLength);
circle.setAttribute("stroke-dasharray", circleLength *segmentLength + " " + circleLength);
}
var segmentOffset = 0;
var animationDelay = 0;
// Loop trough data to create pie
for (var c = 0; c < data.length; c++) {
var segmentLength = data[c].value/100;
var angleOffset = (data[c].value) *360 + angle;
animationDelay = animationDelay + 800;
if(c>0) {
segmentOffset = segmentOffset -data[c-1].value/100*circleLength;
textAngleOffset = (data[c].value/100) *360 + textAngleOffset;
}
// Create circle
var circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
// Create group for each segment
var group = document.createElementNS("http://www.w3.org/2000/svg", "g");
group.classList.add("segment-group");
//Create text
var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
var textAngle = ((data[c].value/100) *360)/2 + textAngleOffset;
var radians = degrees_to_radians(textAngle);
text.setAttribute("x", radius * Math.cos(radians) + 188.5 );
text.setAttribute("y", radius * Math.sin(radians) + 188.5);
text.setAttribute("text-anchor", "middle");
text.setAttribute("fill", data[c].textcolor);
text.innerHTML = data[c].value + '%';
// Set attributes (self explanatory)
circle.setAttribute("class", "pie-chart-value");
circle.setAttribute("cx", 188.5);
circle.setAttribute("cy", 188.5);
circle.setAttribute("r", radius);
circle.setAttribute("transform", "rotate(" + angleOffset + ", 188.5, 188.5)");
// Set dash on circle
circle.setAttribute("stroke-dasharray", "0" + " " + circleLength);
setTimeout(animate, animationDelay, circle, segmentLength, circleLength);
if(c>0) {
circle.setAttribute("stroke-dashoffset", segmentOffset);
}
// Set Stroke color
circle.style.stroke = data[c].bgcolor;
//Append circle and text to group
group.appendChild(circle);
group.appendChild(text);
// Append group to svg.
svg.appendChild(group);
}
}
//Pie chart call
var chartSegments = document.getElementsByClassName('pie-segment');
initPieChart(chartSegments);
/* Pie chart styles */
.pie-chart-value {
fill: none;
stroke-width: 188.5;
transition: stroke-dasharray 800ms linear;
}
/* */
.time-statistics {
padding-top: 30px;
}
.chart-value {
position: relative;
margin-bottom: 5px;
}
.chart-value:before {
display: none;
}
.chart-value .dot {
width: 8px;
height: 8px;
border-radius: 100%;
margin-right: 10px;
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
}
.pie-chart-container {
position: relative;
}
.pie-chart-bg {
position: absolute;
top: 0px;
left: 0;
z-index: -1;
}
.pie-chart-content {
position: absolute;
top: 0px;
left: 0px;
}
<div class="pie-chart-container">
<span class="pie-segment" data-percent="20" data-bg-color="#d8d8d8" data-text-color="#123431"></span>
<span class="pie-segment" data-percent="40" data-bg-color="#345a57" data-text-color="white"></span>
<span class="pie-segment" data-percent="40" data-bg-color="#133532" data-text-color="white"></span>
<div class="pie-chart-content">
<svg id="pie-chart" width="377" height="377"></svg>
</div>
</div>
You need to adjust the textoffset for the previous value, not the current one. I.e.:
textAngleOffset = (data[c-1].value/100) *360 + textAngleOffset;
Here is working code:
//Pie chart plugin
function initPieChart(segmentsData) {
var data = [];
for (var i = 0; i < segmentsData.length; i++) {
var percent = segmentsData[i].getAttribute('data-percent');
var bgcolor = segmentsData[i].getAttribute('data-bg-color');
var textcolor = segmentsData[i].getAttribute('data-text-color');
data.push({"bgcolor": bgcolor, "textcolor": textcolor, "value" : Number(percent)});
}
var angle = -90;
var textAngleOffset = -90;
// Setup global variables
var svg = document.getElementById('pie-chart'),
list = document.getElementById('pie-values'),
totalValue = 0,
radius = 94,
circleLength = Math.PI * (radius * 2), // Circumference = PI * Diameter
spaceLeft = circleLength;
// Get total value of all data.
for (var i = 0; i < data.length; i++) {
totalValue += data[i].value;
}
function degrees_to_radians(degrees){
var pi = Math.PI;
return degrees * (pi/180);
}
function animate(circle, segmentLength, circleLength) {
// circle.setAttribute("stroke-dasharray", spaceLeft + " " + circleLength);
circle.setAttribute("stroke-dasharray", circleLength *segmentLength + " " + circleLength);
}
var segmentOffset = 0;
var animationDelay = 0;
// Loop trough data to create pie
for (var c = 0; c < data.length; c++) {
var segmentLength = data[c].value/100;
var angleOffset = (data[c].value) *360 + angle;
animationDelay = animationDelay + 800;
if(c>0) {
segmentOffset = segmentOffset -data[c-1].value/100*circleLength;
textAngleOffset = (data[c-1].value/100) *360 + textAngleOffset;
}
// Create circle
var circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
// Create group for each segment
var group = document.createElementNS("http://www.w3.org/2000/svg", "g");
group.classList.add("segment-group");
//Create text
var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
var textAngle = ((data[c].value/100) *360)/2 + textAngleOffset;
var radians = degrees_to_radians(textAngle);
text.setAttribute("x", radius * Math.cos(radians) + 188.5 );
text.setAttribute("y", radius * Math.sin(radians) + 188.5);
text.setAttribute("text-anchor", "middle");
text.setAttribute("fill", data[c].textcolor);
text.innerHTML = data[c].value + '%';
// Set attributes (self explanatory)
circle.setAttribute("class", "pie-chart-value");
circle.setAttribute("cx", 188.5);
circle.setAttribute("cy", 188.5);
circle.setAttribute("r", radius);
circle.setAttribute("transform", "rotate(" + angleOffset + ", 188.5, 188.5)");
// Set dash on circle
circle.setAttribute("stroke-dasharray", "0" + " " + circleLength);
setTimeout(animate, animationDelay, circle, segmentLength, circleLength);
if(c>0) {
circle.setAttribute("stroke-dashoffset", segmentOffset);
}
// Set Stroke color
circle.style.stroke = data[c].bgcolor;
//Append circle and text to group
group.appendChild(circle);
group.appendChild(text);
// Append group to svg.
svg.appendChild(group);
}
}
//Pie chart call
var chartSegments = document.getElementsByClassName('pie-segment');
initPieChart(chartSegments);
/* Pie chart styles */
.pie-chart-value {
fill: none;
stroke-width: 188.5;
transition: stroke-dasharray 800ms linear;
}
/* */
.time-statistics {
padding-top: 30px;
}
.chart-value {
position: relative;
margin-bottom: 5px;
}
.chart-value:before {
display: none;
}
.chart-value .dot {
width: 8px;
height: 8px;
border-radius: 100%;
margin-right: 10px;
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
}
.pie-chart-container {
position: relative;
}
.pie-chart-bg {
position: absolute;
top: 0px;
left: 0;
z-index: -1;
}
.pie-chart-content {
position: absolute;
top: 0px;
left: 0px;
}
<div class="pie-chart-container">
<span class="pie-segment" data-percent="20" data-bg-color="#d8d8d8" data-text-color="#123431"></span>
<span class="pie-segment" data-percent="40" data-bg-color="#345a57" data-text-color="white"></span>
<span class="pie-segment" data-percent="40" data-bg-color="#133532" data-text-color="white"></span>
<div class="pie-chart-content">
<svg id="pie-chart" width="377" height="377"></svg>
</div>
</div>
I have an audio visualizer that creates audio waves based on the inputed music file. The file has to manually be put into the "choose file" area. How do I make it so that I can simply link a pr-existing file, so that when the page loads, it immediately starts playing audio.mp3
Here is the code that Im working with:
window.onload = function() {
var audio,
analyser,
audioContext,
sourceNode,
stream;
var svg = document.getElementById('svg'),
svgNS = svg.namespaceURI,
g = document.createElementNS(svgNS, "g");
var width = window.innerWidth,
height = window.innerHeight,
maxHeight = Math.max(height * 0.3, 300),
fftSize = 512, // 512
tilt = 40,
choke = 110,
c = 0;
var audioInput = document.getElementById('audiofile');
// choose file
audioInput.addEventListener('change', function(event) {
stream = URL.createObjectURL(event.target.files[0]);
audio = new Audio();
audio.src = stream;
setup();
});
function setup() {
audio.addEventListener('canplay', function () {
document.body.className+='loaded';
audioContext = new AudioContext();
analyser = (analyser || audioContext.createAnalyser());
analyser.minDecibels = -90;
analyser.maxDecibels = -10;
analyser.smoothingTimeConstant = 1;//0.75;
analyser.fftSize = fftSize;
sourceNode = audioContext.createMediaElementSource(audio);
sourceNode.connect(analyser);
sourceNode.connect(audioContext.destination);
audio.play();
update();
});
}
function shape(g, freqValue, freqSequence, freqCount, colorSequence) {
var freqRatio = freqSequence/freqCount,
x = (width - (tilt * 2)) * freqRatio + tilt,
y = height / 2;
var polyline = document.createElementNS(svgNS, "polyline"),
// using power to increase highs and decrease lows
freqRatio = freqValue / 255,
throttledRatio = (freqValue - choke) / (255 - choke),
strokeWidth = width / freqCount * 0.6 * throttledRatio,
throttledY = Math.max(throttledRatio, 0) * maxHeight,
// color
color = "hsl(" +
((freqSequence / 2) + Math.floor(colorSequence)) + ", " +
100 + "%," +
freqRatio * 80 + "%" +
")";
var loc_x = x - strokeWidth / 2,
loc_y1 = y - throttledY / 2,
loc_y2 = y + throttledY / 2,
x_offset = tilt * throttledRatio;
if (throttledRatio > 0) {
var point_1 = (loc_x - x_offset) + "," + loc_y1,
point_2 = (loc_x + x_offset) + "," + loc_y2;
var points = [ point_1, point_2 ];
} else {
var points = [loc_x + "," + (y-1),loc_x + "," + (y+1)]
}
polyline.setAttribute("stroke-width", strokeWidth);
polyline.setAttribute("stroke", color);
polyline.setAttribute("points", points.join(" "));
g.appendChild(polyline);
}
svg.setAttribute("width", width+"px");
svg.setAttribute("height", height+"px");
svg.setAttribute("viewBox", "0 0 " + width + " " + height);
svg.appendChild(g);
function update() {
g.remove();
g = document.createElementNS(svgNS, "g");
var freqArray = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteTimeDomainData(freqArray);
for (var i = 0; i < freqArray.length; i++) {
var v = freqArray[i];
shape(g, v, i+1, freqArray.length, c);
}
svg.appendChild(g);
c += 0.5;
requestAnimationFrame(update);
}
};
jakealbaughSignature("light");
body {
margin: 0;
background-color: #000000;
font-family: 'Helvetica', sans-serif;
color: #FFFFFF;
}
input {
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
z-index: 2;
}
body.loaded input {
display: none;
}
#svg {
display: block;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate3d(-50%, -50%, 0);
transform: translate3d(-50%, -50%, 0);
}
#svg polyline {
stroke-linecap: round;
}
<input id=audiofile type=file>
<svg id=svg></svg>
You can't.
Autoplay of audio is disabled on most browsers. There must be some user interaction, and you can only start playback on that user interaction, such as a click event.
Well I have designed a color picker, from where a selected color will show beside the canvas. Now the problem is everytime I am trying to drag the indicator it goes out of the canvas even after the position is relative.
Every time i am trying to drag the indicator it goes out of canvas. I have highlighted the indicator in the image below
var canvas = document.getElementById('color-picker');
var context = canvas.getContext('2d');
var w = 250;
var h = 250;
canvas.width = w;
canvas.height = h;
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = x;
for (var angle = 0; angle <= 360; angle += 1) {
var startAngle = (angle - 2) * Math.PI / 180;
var endAngle = angle * Math.PI / 180;
context.beginPath();
context.moveTo(x, y);
context.arc(x, y, radius, startAngle, endAngle, false);
context.closePath();
var gradient = context.createRadialGradient(x, y, 0, x, y, radius);
gradient.addColorStop(0, 'hsl(' + angle + ', 10%, 100%)');
gradient.addColorStop(1, 'hsl(' + angle + ', 100%, 50%)');
context.fillStyle = gradient;
context.fill();
}
var m = {
x: canvas.width / 2,
y: canvas.height / 2
};
var drag = false;
var location_path = document.getElementById('_lp_');
var lp_width = location_path.offsetWidth;
var lp_height = location_path.offsetHeight;
var container = document.getElementById('container');
var selected_color = document.getElementById('selected_color');
var def_color = "#f8fff9";
selected_color.style.backgroundColor = def_color;
container.addEventListener('mousedown', dragged, false);
container.addEventListener('mousemove', moving, false);
window.addEventListener('mouseup', noDrag, false);
function dragged() {
drag = true;
}
function noDrag() {
drag = false;
}
function moving(e) {
if (drag) {
var ink_x = (e.clientX - container.offsetLeft);
var ink_y = (e.clientY - container.offsetTop);
m.x = e.clientX - container.offsetLeft - lp_width / 2;
m.y = e.clientY - container.offsetTop - lp_height - 10; //why 10? 10 for padding
if (Distance(ink_x, ink_y, w / 2, h / 2) > radius) {
drag = false;
}
location_path.style.left = m.x + 'px';
location_path.style.top = m.y + 'px';
var getData = context.getImageData(ink_x, ink_y, 1, 1);
var pxl = getData.data;
var r = pxl[0];
var g = pxl[1];
var b = pxl[2];
var a = pxl[3];
// indicator.style.background = "rgb(" + r + ',' + g + ',' + b + ")";
selected_color.style.background = "rgb(" + r + ',' + g + ',' + b + ")";
}
}
function rgb2hex(red, green, blue) {
var rgb = blue | (green << 8) | (red << 16);
return '#' + (0x1000000 + rgb).toString(16).slice(1)
}
function Distance(x1, y1, x2, y2) {
var dx = x2 - x1;
var dy = y2 - y1;
return Math.sqrt(dx * dx + dy * dy);
}
.lighting-wrapper {
margin: 5% auto;
}
.lighting-left,
.lighting-right {
padding: 50px;
}
.lighting-color-picker-wrapper,
.lighting-selected-color-wrapper {
position: relative;
width: 250px;
height: 250px;
margin: 150px auto;
border-radius: 50%;
}
.location-path {
position: absolute;
width: 40px;
height: 40px;
padding: 10px;
background: #fff;
border-radius: 50%;
border-bottom-left-radius: 0%;
top: 58px;
left: 92px;
transform: rotate(-45deg);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
user-select: none;
transition: all 0.1s;
}
<div class="container">
<div class="lighting-wrapper shadow-sm">
<div class="row align-items-center">
<div class="col-md-6 d-flex justify-content-center lighting-left">
<div class="lighting-color-picker-wrapper" id="container">
<canvas id="color-picker" class="position-relative"></canvas>
<div id="_lp_" class="location-path"></div>
</div>
</div>
<div class="col-md-6 d-flex justify-content-center lighting-right">
<div class="lighting-selected-color-wrapper" id="selected_color">
</div>
</div>
</div>
</div>
</div>
Looks like your code is affected by the page scroll.
Try change the "e.clientY" to "e.pageY".
var canvas = document.getElementById('color-picker');
var context = canvas.getContext('2d');
var w = 250;
var h = 250;
canvas.width = w;
canvas.height = h;
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = x;
for (var angle = 0; angle <= 360; angle += 1) {
var startAngle = (angle - 2) * Math.PI / 180;
var endAngle = angle * Math.PI / 180;
context.beginPath();
context.moveTo(x, y);
context.arc(x, y, radius, startAngle, endAngle, false);
context.closePath();
var gradient = context.createRadialGradient(x, y, 0, x, y, radius);
gradient.addColorStop(0, 'hsl(' + angle + ', 10%, 100%)');
gradient.addColorStop(1, 'hsl(' + angle + ', 100%, 50%)');
context.fillStyle = gradient;
context.fill();
}
var m = {
x: canvas.width / 2,
y: canvas.height / 2
};
var drag = false;
var location_path = document.getElementById('_lp_');
var lp_width = location_path.offsetWidth;
var lp_height = location_path.offsetHeight;
var container = document.getElementById('container');
var selected_color = document.getElementById('selected_color');
var def_color = "#f8fff9";
selected_color.style.backgroundColor = def_color;
container.addEventListener('mousedown', dragged, false);
container.addEventListener('mousemove', moving, false);
window.addEventListener('mouseup', noDrag, false);
function dragged() {
drag = true;
}
function noDrag() {
drag = false;
}
function moving(e) {
if (drag) {
var ink_x = (e.pageX - container.offsetLeft);
var ink_y = (e.pageY - container.offsetTop);
if (Distance(ink_x, ink_y, w / 2, h / 2) > radius) {
var vector = { x: ink_x - w / 2, y: ink_y - h / 2 };
normalize(vector);
ink_x = Math.trunc(vector.x * radius) + w / 2;
ink_y = Math.trunc(vector.y * radius) + h / 2;
drag = false;
}
m.x = ink_x - lp_width / 2;
m.y = ink_y - lp_height - 10; //why 10? 10 for padding
location_path.style.left = m.x + 'px';
location_path.style.top = m.y + 'px';
var getData = context.getImageData(ink_x, ink_y, 1, 1);
var pxl = getData.data;
var r = pxl[0];
var g = pxl[1];
var b = pxl[2];
var a = pxl[3];
// indicator.style.background = "rgb(" + r + ',' + g + ',' + b + ")";
selected_color.style.background = "rgb(" + r + ',' + g + ',' + b + ")";
}
}
function rgb2hex(red, green, blue) {
var rgb = blue | (green << 8) | (red << 16);
return '#' + (0x1000000 + rgb).toString(16).slice(1)
}
function Distance(x1, y1, x2, y2) {
var dx = x2 - x1;
var dy = y2 - y1;
return Math.sqrt(dx * dx + dy * dy);
}
function normalize(vector) {
var length = Math.sqrt(Math.pow(vector.x, 2) + Math.pow(vector.y, 2));
vector.x = vector.x / length;
vector.y = vector.y / length;
}
.lighting-wrapper {
margin: 5% auto;
}
.lighting-left,
.lighting-right {
padding: 50px;
}
.lighting-color-picker-wrapper,
.lighting-selected-color-wrapper {
position: relative;
width: 250px;
height: 250px;
margin: 150px auto;
border-radius: 50%;
}
.location-path {
position: absolute;
width: 40px;
height: 40px;
padding: 10px;
background: #fff;
border-radius: 50%;
border-bottom-left-radius: 0%;
top: 58px;
left: 92px;
transform: rotate(-45deg);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
user-select: none;
transition: all 0.1s;
}
<div class="container">
<div class="lighting-wrapper shadow-sm">
<div class="row align-items-center">
<div class="col-md-6 d-flex justify-content-center lighting-left">
<div class="lighting-color-picker-wrapper" id="container">
<canvas id="color-picker" class="position-relative"></canvas>
<div id="_lp_" class="location-path"></div>
</div>
</div>
<div class="col-md-6 d-flex justify-content-center lighting-right">
<div class="lighting-selected-color-wrapper" id="selected_color">
</div>
</div>
</div>
</div>
</div>
Div should follow the cursor, but shifted 20px by X and Y axis toward the center of the screen, based on the quarter in which is the mouse cursor?
Like this: https://i.imgur.com/XaDk1hI.png
I used trigonometry to find vector from cursor to center of the window, so I have cursor coordinates, center coordinates, and third point C, but div moves in strange circles and I don't where I made mistake.
var lt = document.getElementById('lt')
var ltPosition = lt.getBoundingClientRect();
var element = document.getElementById('element');
var mousePosX = 0;
var mousePosY = 0;
document.onmousemove = function(e){
function angle(xCursor, yCursor, xCenter, yCenter){
var distanceA = xCursor - xCenter;
var distanceB = yCursor - yCenter;
var distanceC = Math.sqrt(distanceA*distanceA + distanceB*distanceB);
var theta = Math.atan2(distanceA, distanceB);
theta *= 180 / Math.PI;
var offsetX = distanceC * Math.sin(theta);
var offsetY = distanceC * Math.cos(theta);
function follow(x,y){
element.style.left = x + "px";
element.style.top = y +"px";
}
follow(e.clientX + offsetX, e.clientY + offsetY);
}
angle(e.clientX, e.clientY, ltPosition.right, ltPosition.bottom);
}
Here is fiddle: https://jsfiddle.net/sgvpvqhc/
What else should I do here in order to have this functionality?
What is that theta *= 180 / Math.PI; doing there? sin and cos take the angle in radians, just like atan returns it. If you want to display it, sure, convert it to degrees, but inside the Math API no conversion are needed.
(updated fiddle demo)
I though you might like this. I put it here too. https://jsfiddle.net/sgvpvqhc/5/
function mouseMover(element, offX, offY) {
var e = element,
bc = e.getBoundingClientRect();
var ox = offX,
oy = offY;
if (ox === undefined && oy === undefined) {
ox = -Math.round(bc.width / 2);
oy = -Math.round(bc.height / 2);
}
e.parentNode.onmousemove = function(eventObj) {
var ev = eventObj,
b = this.getBoundingClientRect();
var x = Math.round(ev.clientX - b.left);
var y = Math.round(ev.clientY - b.top);
e.style.left = x + (ox) + 'px';
e.style.top = y + (oy) + 'px';
}
}
mouseMover(document.getElementById('element'), 20, 20)
html, body {
margin: 0;
height: 100%;
}
.container {
width: 100%;
height: 100%;
}
#lt, #rt, #ld, #rd {
float: left;
width: 50%;
height: 50%;
display: inline-block;
}
#element {
background-color: red;
width: 50px;
height: 50px;
position: absolute;
}
#lt, #rd {
background-color: green;
}
#rt, #ld {
background-color: yellow;
}
<div id='container' class='container'>
<div id='element'></div>
<div id='lt'></div>
<div id='rt'></div>
<div id='ld'></div>
<div id='rd'></div>
</div>
<div class='box'></div>
I am trying to create something like drag a box (Hello World) to any location, and the second box (Follow World) will follow slowly.
In the code below, the drag box is fine, but the follow box will not follow properly. Also, the drag box cannot drop.
function startDrag(e) {
// determine event object
if (!e) {
var e = window.event;
}
// IE uses srcElement, others use target
var targ = e.target ? e.target : e.srcElement;
if (targ.className != 'dragme') {
return
};
// calculate event X, Y coordinates
offsetX = e.clientX;
offsetY = e.clientY;
// assign default values for top and left properties
if (!targ.style.left) {
targ.style.left = '0px'
};
if (!targ.style.top) {
targ.style.top = '0px'
};
// calculate integer values for top and left
// properties
coordX = parseInt(targ.style.left);
coordY = parseInt(targ.style.top);
drag = true;
// move div element
document.onmousemove = dragDiv;
return false;
}
function dragDiv(e) {
if (!drag) {
return
};
if (!e) {
var e = window.event
};
var targ = e.target ? e.target : e.srcElement;
// move div element
targ.style.left = coordX + e.clientX - offsetX + 'px';
targ.style.top = coordY + e.clientY - offsetY + 'px';
return false;
}
function stopDrag() {
timer();
drag = false;
}
window.onload = function() {
document.onmousedown = startDrag;
document.onmouseup = stopDrag;
}
function disp() {
var step = 1;
var y = document.getElementById('followme').offsetTop;
var x = document.getElementById('followme').offsetLeft;
var ty = document.getElementById('draggable').offsetTop;
var ty = document.getElementById('draggable').offsetLeft;
if (y < ty) {
y = y + step;
document.getElementById('followme').style.top = y + "px"; // vertical movment
} else {
if (x < tx) {
x = x + step;
document.getElementById('followme').style.left = x + "px"; // horizontal movment
}
}
}
function timer() {
disp();
var y = document.getElementById('followme').offsetTop;
var x = document.getElementById('followme').offsetLeft;
document.getElementById("msg").innerHTML = "X: " + tx + " Y : " + ty
my_time = setTimeout('timer()', 10);
}
.dragme {
position: relative;
width: 60px;
height: 80px;
cursor: move;
}
.followme {
position: relative;
width: 60px;
height: 80px;
}
#draggable {
background-color: #ccc;
border: 1px solid #000;
}
#followme {
background-color: #ccc;
border: 1px solid #000;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Drag and drop</title>
</head>
<body>
<div id='msg'></div>
<div id="draggable" class="dragme">"Hello World!"</div>
<div id="followme" class="followme">"Follow World!"</div>
Fix yours disp and timer functions to this:
function disp()
{
var step = 1;
// in dragDiv() you modifying style.left/style.top properties, not offsetTop/offsetLeft
var x = parseInt(document.getElementById('followme').style.left) || 0;
var y = parseInt(document.getElementById('followme').style.top) || 0;
var tx = parseInt(document.getElementById('draggable').style.left) || 0;
var ty = parseInt(document.getElementById('draggable').style.top) || 0;
// properly calculate offset
var dx = ((dx = tx - x) == 0) ? 0 : Math.abs(dx) / dx;
var dy = ((dy = ty - y) == 0) ? 0 : Math.abs(dy) / dy;
document.getElementById('followme').style.left = (x + dx * step) + "px"; // horisontal movment
document.getElementById('followme').style.top = (y + dy * step) + "px"; // vertical movment
}
function timer()
{
disp();
var y=document.getElementById('followme').offsetTop;
var x=document.getElementById('followme').offsetLeft;
document.getElementById("msg").innerHTML="X: " + x + " Y : " + y; // typo was here
my_time = setTimeout(function () {
clearTimeout(my_time); // need to clear timeout or it'll be adding each time 'Hello world' clicked
timer();
},10);
}
In the following snippet, the pink box is draggable and the blue box follows it around. You can change pixelsPerSecond to adjust the speed of movement.
function message(s) {
document.getElementById('messageContainer').innerHTML = s;
}
window.onload = function () {
var pixelsPerSecond = 80,
drag = document.getElementById('drag'),
follow = document.getElementById('follow'),
wrapper = document.getElementById('wrapper'),
messageContainer = document.getElementById('messageContainer'),
leftMax,
topMax;
function setBoundaries() {
leftMax = wrapper.offsetWidth - drag.offsetWidth;
topMax = wrapper.offsetHeight - drag.offsetHeight;
drag.style.left = Math.min(drag.offsetLeft, leftMax) + 'px';
drag.style.top = Math.min(drag.offsetTop, topMax) + 'px';
}
setBoundaries();
window.onresize = setBoundaries;
[drag, follow, messageContainer].forEach(function (element) {
element.className += ' unselectable';
element.ondragstart = element.onselectstart = function (event) {
event.preventDefault();
};
});
var start = Date.now();
drag.onmousedown = function (event) {
event = event || window.event;
var x0 = event.pageX || event.clientX,
y0 = event.pageY || event.clientY,
left0 = drag.offsetLeft,
top0 = drag.offsetTop;
window.onmousemove = function (event) {
var x = event.pageX || event.clientX,
y = event.pageY || event.clientY;
drag.style.left = Math.max(0, Math.min(left0 + x - x0, leftMax)) + 'px';
drag.style.top = Math.max(0, Math.min(top0 + y - y0, topMax)) + 'px';
};
window.onmouseup = function () {
window.onmousemove = window.onmouseup = undefined;
};
};
follow.x = follow.offsetLeft;
follow.y = follow.offsetTop;
function update() {
var elapsed = Date.now() - start;
if (elapsed === 0) {
window.requestAnimationFrame(update);
return;
}
var x1 = drag.offsetLeft,
y1 = drag.offsetTop + (drag.offsetTop + drag.offsetHeight <= topMax ?
drag.offsetHeight : -drag.offsetHeight),
x0 = follow.x,
y0 = follow.y,
dx = x1 - x0,
dy = y1 - y0,
distance = Math.sqrt(dx*dx + dy*dy),
angle = Math.atan2(dy, dx),
dd = Math.min(distance, pixelsPerSecond * elapsed / 1000);
message('x: ' + x1 + ', y: ' + y1);
follow.x += Math.cos(angle) * dd;
follow.style.left = follow.x + 'px';
follow.y += Math.sin(angle) * dd;
follow.style.top = follow.y + 'px';
start = Date.now();
window.requestAnimationFrame(update);
}
window.requestAnimationFrame(update);
};
#wrapper {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: #eee;
font-family: sans-serif;
text-align: center;
}
.unselectable {
-webkit-user-select: none;
-khtml-user-drag: none;
-khtml-user-select: none;
-moz-user-select: none;
-moz-user-select: -moz-none;
-ms-user-select: none;
user-select: none;
}
#messageContainer {
position: absolute;
left: 80px;
top: 50px;
font-size: 36px;
color: #aaa;
cursor: default;
}
.box {
position: absolute;
width: 60px;
height: 80px;
}
.label {
margin: 30px auto;
font-size: 14px;
}
#drag {
left: 100px;
top: 120px;
background: #f0dddb;
border: 2px solid #deb7bb;
cursor: move;
}
#follow {
left: 0;
top: 0;
background-color: #ddebf3;
border: 2px solid #bfd5e1;
cursor: default;
}
<div id="wrapper">
<div id="messageContainer"></div>
<div class="box" id="follow"> <div class="label">it follows</div> </div>
<div class="box" id="drag"> <div class="label">drag me</div> </div>