please help to remove the new Bullet. jsfiddle
after the object it moves across the screen from the bottom up. coordinate with y <= 5px method works helper.deleteElement (), but the object is still there exists (see the console - console.log ('move') ;)
I need to to be removed completely
js:
Bullet = function(bulletId){
var self = this;
self.id = bulletId;
self.x = 100;
self.y = 500;
self.move = function(){
console.log('move');
var offsetY = -10,
newY = self.y + offsetY;
if(newY <= 5){
helper.deleteElement(self.id);
if(observerable.removeListener(this, "makeMoveBullet", "move")){
console.log('dont worked!');
}
}
self.y = newY;
self.render(self.x, newY);
return;
};
self.render = function(x, y){
$('#' +self.id).css({
'left': (self.x = x || self.x) + 'px',
'top': (self.y = y || self.y) + 'px'
}).appendTo('#wrap');
return;
};
self.init = function(playerX, playerY){
$('<div class="bullet" id="' + self.id + '" />').appendTo('#wrap');
self.x = playerX + 31;
self.y = playerY - 9;
self.render(self.x, self.y);
return;
};
};
// ------------------------------------------------------------------------------------ observer
var observerable = {
listeners: {},
addListener: function (object, evt, callback) {
if (!this.listeners.hasOwnProperty(evt)) {
this.listeners[evt] = [];
}
this.listeners[evt].push(object[callback]);
},
removeListener: function (object, evt, callback) {
if (this.listeners.hasOwnProperty(evt)) {
var i, length;
for (i = 0, length = this.listeners[evt].length; i < length; i += 1) {
if (this.listeners[evt][i] === object[callback]) {
this.listeners[evt].splice(i, 1);
}
}
}
},
publisher: function (evt, args) {
if (this.listeners.hasOwnProperty(evt)){
var i, length;
for (i = 0, length = this.listeners[evt].length; i < length; i += 1){
this.listeners[evt][i](args);
}
}
}
};
// ------------------------------------------------------------------------------------ helper
function Helper(){
this.deleteElement = function(id){
$('#' + id).remove();
return;
};
};
// ------------------------------------------------------------------------------------ init
var helper = new Helper();
bullet = new Bullet('bullet_0');
bullet.init(500, 500);
observerable.addListener(bullet, "makeMoveBullet", "move");
setInterval(function(){
observerable.publisher("makeMoveBullet");
}, 100);
JavaScript uses a Garbage Collector to remove unused variables. I would say to do something like this:
delete this.x; delete this.y ; ... ; delete this;
When you want to remove the object (also remove it from any other external data structures). Remove all it's properties then the object itself. Then the GC should remove it.
setInterval returns an interval identifier. Clear the interval using clearInterval function when you don't want more executions of the interval.
var int = setInterval(...);
...
clearInterval(int);
removeListener: function (object, evt, callback) {
if (this.listeners.hasOwnProperty(evt)) {
var i, length;
for (i = 0, length = this.listeners[evt].length; i < length; i += 1) {
if (this.listeners[evt][i] === object[callback]) {
this.listeners[evt].splice(i, 1);
}
}
}
}
object[callback] is always undefined so this.listeners[evt].splice(i, 1); cannot be executed;
Related
When I click on an anchor I pass the attribute ' data-target ' to my target var. In the scroll function I pass the target in the parameters and everything works well. My problem is that the console logs an error showing the target returning a null in this line:
var targetPosition = target.offsetTop;
Can anyone explain why this is happening?
var anchors = document.querySelectorAll('a[href^="#"]');
var headerHeight = document.querySelector('header').offsetHeight;
for (var i = 0; i < anchors.length; i++) {
anchors[i].addEventListener('click', function(event) {
event.preventDefault();
var anchor_location = this.getAttribute('data-target');
// Find the element with ID that matches data-target value.
var target = document.querySelector(anchor_location);
scroll(target, headerHeight);
})
}
function scroll(target, headerHeight) {
var start = null;
var duration = 1100; //d
var targetPosition = target.offsetTop;
var startPosition = window.pageYOffset; //b
var distance = targetPosition - startPosition - headerHeight; //c
console.log(distance);
window.requestAnimationFrame(step);
function step(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start; //t
// window.scrollTo(0, distance*(progress/duration) + startPosition);
window.scrollTo(0, quintic(progress, startPosition, distance, duration));
if (progress < duration) {
window.requestAnimationFrame(step);
}
}
}
// http://www.gizma.com/easing/ [easing equations]
function quintic (t, b, c, d) {
t /= d/2;
if (t < 1) return c/2*t*t*t*t*t + b;
t -= 2;
return c/2*(t*t*t*t*t + 2) + b;
};
I want to implement two signature pads in ONE form. One signature is for the applicant and the other one is for the evaluator.
The first pad works but the second pad is unresponsive. I am using JavaScript for the signature pads but it only works for the first pad. The signature will be saved to the database when the submit button is clicked. That is why id="save-signature-btn" is together with the code for the 'Submit' button.
form.blade.php
#extends('layouts.app')
#section('content')
<!doctype html>
<html lang="en">
<head>
</head>
<body>
{!! Form::open(['url' => 'page3/submit']) !!}
<h4 style="text-decoration: underline; font-weight: bold">Approved By:</h4>
<table class="table table-bordered">
<tr>
<th colspan="3">Approved By:</th>
</tr>
<tr>
<th colspan="1">Name</th>
<th colspan="1">Signature</th>
<th colspan="1">Date</th>
</tr>
<tr colspan=4>
<td colspan="1">
<div class="form-group">
{{Form::text('Officer_Name', '', ['class' => 'form-control', 'placeholder' => 'John Smith'])}}
</div>
</td>
<td colspan="1">
<div class="form-group">
<canvas id="signature-canvas" style="width:375px;height:150px;max-width:100%;border:8px #CCC solid;background-color: white;"></canvas>
<div id="signature-message"></div>
<div id="signature-buttons">
<input type="button" id="clear-signature-btn" value="Clear">
</div>
<input type="hidden" name="officer_signature" id="signature-data" value="">
</div>
</td>
<td>
<div class="form-group">
{{Form::date('Approval_Date', '', ['class' => 'form-control'])}}
</div>
</td>
</tr>
</table>
<br/>
<h4 style="text-decoration: underline; font-weight: bold">Applicant Signature:</h4>
<div class="form-group">
<canvas id="signature-canvas2" style="width:375px;height:150px;max-width:100%;border:8px #CCC solid;background-color: white;"></canvas>
<div id="signature-message2"></div>
<div id="signature-buttons2">
<input type="button" id="clear-signature-btn2" value="Clear">
</div>
<input type="hidden" name="applicant_signature" id="signature-data2" value="">
</div>
<br>
<div class="signature_pad_save">
<button type="submit" class="btn btn-primary" id="save-signature-btn">Submit</button>
</div>
<script src="js/signature_pad.js"></script>
<script src="js/signature_data.js"></script>
</body>
</html>
#endsection('content')
signature data.js
var clearButton = document.getElementById('clear-signature-btn'),
saveButton = document.getElementById('save-signature-btn'),
canvas = document.getElementById('signature-canvas'),
signaturePad;
function resizeCanvas() {
var ratio = Math.max(window.devicePixelRatio || 1, 1);
canvas.width = canvas.offsetWidth * ratio;
canvas.height = canvas.offsetHeight * ratio;
canvas.getContext("2d").scale(ratio, ratio);
}
window.onresize = resizeCanvas;
resizeCanvas();
signaturePad = new SignaturePad(canvas);
clearButton.addEventListener('click', function (event) {
signaturePad.clear();
});
saveButton.addEventListener('click', function (event) {
if (signaturePad.isEmpty()) {
alert('Signature pad is blank. Please draw your signature.');
} else {
var sdata = signaturePad.toDataURL();
document.getElementById('signature-data').value = sdata;
document.getElementById('signature-form').submit();
}
});
signature pad.js
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.SignaturePad = factory());
}(this, (function () { 'use strict';
function Point(x, y, time) {
this.x = x;
this.y = y;
this.time = time || new Date().getTime();
}
Point.prototype.velocityFrom = function (start) {
return this.time !== start.time ? this.distanceTo(start) / (this.time - start.time) : 1;
};
Point.prototype.distanceTo = function (start) {
return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
};
Point.prototype.equals = function (other) {
return this.x === other.x && this.y === other.y && this.time === other.time;
};
function Bezier(startPoint, control1, control2, endPoint) {
this.startPoint = startPoint;
this.control1 = control1;
this.control2 = control2;
this.endPoint = endPoint;
}
// Returns approximated length.
Bezier.prototype.length = function () {
var steps = 10;
var length = 0;
var px = void 0;
var py = void 0;
for (var i = 0; i <= steps; i += 1) {
var t = i / steps;
var cx = this._point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
var cy = this._point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
if (i > 0) {
var xdiff = cx - px;
var ydiff = cy - py;
length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
}
px = cx;
py = cy;
}
return length;
};
/* eslint-disable no-multi-spaces, space-in-parens */
Bezier.prototype._point = function (t, start, c1, c2, end) {
return start * (1.0 - t) * (1.0 - t) * (1.0 - t) + 3.0 * c1 * (1.0 - t) * (1.0 - t) * t + 3.0 * c2 * (1.0 - t) * t * t + end * t * t * t;
};
/* eslint-disable */
// http://stackoverflow.com/a/27078401/815507
function throttle(func, wait, options) {
var context, args, result;
var timeout = null;
var previous = 0;
if (!options) options = {};
var later = function later() {
previous = options.leading === false ? 0 : Date.now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
return function () {
var now = Date.now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
}
function SignaturePad(canvas, options) {
var self = this;
var opts = options || {};
this.velocityFilterWeight = opts.velocityFilterWeight || 0.7;
this.minWidth = opts.minWidth || 0.5;
this.maxWidth = opts.maxWidth || 2.5;
this.throttle = 'throttle' in opts ? opts.throttle : 16; // in miliseconds
this.minDistance = 'minDistance' in opts ? opts.minDistance : 5;
if (this.throttle) {
this._strokeMoveUpdate = throttle(SignaturePad.prototype._strokeUpdate, this.throttle);
} else {
this._strokeMoveUpdate = SignaturePad.prototype._strokeUpdate;
}
this.dotSize = opts.dotSize || function () {
return (this.minWidth + this.maxWidth) / 2;
};
this.penColor = opts.penColor || 'black';
this.backgroundColor = opts.backgroundColor || 'rgba(0,0,0,0)';
this.onBegin = opts.onBegin;
this.onEnd = opts.onEnd;
this._canvas = canvas;
this._ctx = canvas.getContext('2d');
this.clear();
// We need add these inline so they are available to unbind while still having
// access to 'self' we could use _.bind but it's not worth adding a dependency.
this._handleMouseDown = function (event) {
if (event.which === 1) {
self._mouseButtonDown = true;
self._strokeBegin(event);
}
};
this._handleMouseMove = function (event) {
if (self._mouseButtonDown) {
self._strokeMoveUpdate(event);
}
};
this._handleMouseUp = function (event) {
if (event.which === 1 && self._mouseButtonDown) {
self._mouseButtonDown = false;
self._strokeEnd(event);
}
};
this._handleTouchStart = function (event) {
if (event.targetTouches.length === 1) {
var touch = event.changedTouches[0];
self._strokeBegin(touch);
}
};
this._handleTouchMove = function (event) {
// Prevent scrolling.
event.preventDefault();
var touch = event.targetTouches[0];
self._strokeMoveUpdate(touch);
};
this._handleTouchEnd = function (event) {
var wasCanvasTouched = event.target === self._canvas;
if (wasCanvasTouched) {
event.preventDefault();
self._strokeEnd(event);
}
};
// Enable mouse and touch event handlers
this.on();
}
// Public methods
SignaturePad.prototype.clear = function () {
var ctx = this._ctx;
var canvas = this._canvas;
ctx.fillStyle = this.backgroundColor;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(0, 0, canvas.width, canvas.height);
this._data = [];
this._reset();
this._isEmpty = true;
};
SignaturePad.prototype.fromDataURL = function (dataUrl) {
var _this = this;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var image = new Image();
var ratio = options.ratio || window.devicePixelRatio || 1;
var width = options.width || this._canvas.width / ratio;
var height = options.height || this._canvas.height / ratio;
this._reset();
image.src = dataUrl;
image.onload = function () {
_this._ctx.drawImage(image, 0, 0, width, height);
};
this._isEmpty = false;
};
SignaturePad.prototype.toDataURL = function (type) {
var _canvas;
switch (type) {
case 'image/svg+xml':
return this._toSVG();
default:
for (var _len = arguments.length, options = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
options[_key - 1] = arguments[_key];
}
return (_canvas = this._canvas).toDataURL.apply(_canvas, [type].concat(options));
}
};
SignaturePad.prototype.on = function () {
this._handleMouseEvents();
this._handleTouchEvents();
};
SignaturePad.prototype.off = function () {
this._canvas.removeEventListener('mousedown', this._handleMouseDown);
this._canvas.removeEventListener('mousemove', this._handleMouseMove);
document.removeEventListener('mouseup', this._handleMouseUp);
this._canvas.removeEventListener('touchstart', this._handleTouchStart);
this._canvas.removeEventListener('touchmove', this._handleTouchMove);
this._canvas.removeEventListener('touchend', this._handleTouchEnd);
};
SignaturePad.prototype.isEmpty = function () {
return this._isEmpty;
};
// Private methods
SignaturePad.prototype._strokeBegin = function (event) {
this._data.push([]);
this._reset();
this._strokeUpdate(event);
if (typeof this.onBegin === 'function') {
this.onBegin(event);
}
};
SignaturePad.prototype._strokeUpdate = function (event) {
var x = event.clientX;
var y = event.clientY;
var point = this._createPoint(x, y);
var lastPointGroup = this._data[this._data.length - 1];
var lastPoint = lastPointGroup && lastPointGroup[lastPointGroup.length - 1];
var isLastPointTooClose = lastPoint && point.distanceTo(lastPoint) < this.minDistance;
// Skip this point if it's too close to the previous one
if (!(lastPoint && isLastPointTooClose)) {
var _addPoint = this._addPoint(point),
curve = _addPoint.curve,
widths = _addPoint.widths;
if (curve && widths) {
this._drawCurve(curve, widths.start, widths.end);
}
this._data[this._data.length - 1].push({
x: point.x,
y: point.y,
time: point.time,
color: this.penColor
});
}
};
SignaturePad.prototype._strokeEnd = function (event) {
var canDrawCurve = this.points.length > 2;
var point = this.points[0]; // Point instance
if (!canDrawCurve && point) {
this._drawDot(point);
}
if (point) {
var lastPointGroup = this._data[this._data.length - 1];
var lastPoint = lastPointGroup[lastPointGroup.length - 1]; // plain object
// When drawing a dot, there's only one point in a group, so without this check
// such group would end up with exactly the same 2 points.
if (!point.equals(lastPoint)) {
lastPointGroup.push({
x: point.x,
y: point.y,
time: point.time,
color: this.penColor
});
}
}
if (typeof this.onEnd === 'function') {
this.onEnd(event);
}
};
SignaturePad.prototype._handleMouseEvents = function () {
this._mouseButtonDown = false;
this._canvas.addEventListener('mousedown', this._handleMouseDown);
this._canvas.addEventListener('mousemove', this._handleMouseMove);
document.addEventListener('mouseup', this._handleMouseUp);
};
SignaturePad.prototype._handleTouchEvents = function () {
// Pass touch events to canvas element on mobile IE11 and Edge.
this._canvas.style.msTouchAction = 'none';
this._canvas.style.touchAction = 'none';
this._canvas.addEventListener('touchstart', this._handleTouchStart);
this._canvas.addEventListener('touchmove', this._handleTouchMove);
this._canvas.addEventListener('touchend', this._handleTouchEnd);
};
SignaturePad.prototype._reset = function () {
this.points = [];
this._lastVelocity = 0;
this._lastWidth = (this.minWidth + this.maxWidth) / 2;
this._ctx.fillStyle = this.penColor;
};
SignaturePad.prototype._createPoint = function (x, y, time) {
var rect = this._canvas.getBoundingClientRect();
return new Point(x - rect.left, y - rect.top, time || new Date().getTime());
};
SignaturePad.prototype._addPoint = function (point) {
var points = this.points;
var tmp = void 0;
points.push(point);
if (points.length > 2) {
// To reduce the initial lag make it work with 3 points
// by copying the first point to the beginning.
if (points.length === 3) points.unshift(points[0]);
tmp = this._calculateCurveControlPoints(points[0], points[1], points[2]);
var c2 = tmp.c2;
tmp = this._calculateCurveControlPoints(points[1], points[2], points[3]);
var c3 = tmp.c1;
var curve = new Bezier(points[1], c2, c3, points[2]);
var widths = this._calculateCurveWidths(curve);
// Remove the first element from the list,
// so that we always have no more than 4 points in points array.
points.shift();
return { curve: curve, widths: widths };
}
return {};
};
SignaturePad.prototype._calculateCurveControlPoints = function (s1, s2, s3) {
var dx1 = s1.x - s2.x;
var dy1 = s1.y - s2.y;
var dx2 = s2.x - s3.x;
var dy2 = s2.y - s3.y;
var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
var dxm = m1.x - m2.x;
var dym = m1.y - m2.y;
var k = l2 / (l1 + l2);
var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
var tx = s2.x - cm.x;
var ty = s2.y - cm.y;
return {
c1: new Point(m1.x + tx, m1.y + ty),
c2: new Point(m2.x + tx, m2.y + ty)
};
};
SignaturePad.prototype._calculateCurveWidths = function (curve) {
var startPoint = curve.startPoint;
var endPoint = curve.endPoint;
var widths = { start: null, end: null };
var velocity = this.velocityFilterWeight * endPoint.velocityFrom(startPoint) + (1 - this.velocityFilterWeight) * this._lastVelocity;
var newWidth = this._strokeWidth(velocity);
widths.start = this._lastWidth;
widths.end = newWidth;
this._lastVelocity = velocity;
this._lastWidth = newWidth;
return widths;
};
SignaturePad.prototype._strokeWidth = function (velocity) {
return Math.max(this.maxWidth / (velocity + 1), this.minWidth);
};
SignaturePad.prototype._drawPoint = function (x, y, size) {
var ctx = this._ctx;
ctx.moveTo(x, y);
ctx.arc(x, y, size, 0, 2 * Math.PI, false);
this._isEmpty = false;
};
SignaturePad.prototype._drawCurve = function (curve, startWidth, endWidth) {
var ctx = this._ctx;
var widthDelta = endWidth - startWidth;
var drawSteps = Math.floor(curve.length());
ctx.beginPath();
for (var i = 0; i < drawSteps; i += 1) {
// Calculate the Bezier (x, y) coordinate for this step.
var t = i / drawSteps;
var tt = t * t;
var ttt = tt * t;
var u = 1 - t;
var uu = u * u;
var uuu = uu * u;
var x = uuu * curve.startPoint.x;
x += 3 * uu * t * curve.control1.x;
x += 3 * u * tt * curve.control2.x;
x += ttt * curve.endPoint.x;
var y = uuu * curve.startPoint.y;
y += 3 * uu * t * curve.control1.y;
y += 3 * u * tt * curve.control2.y;
y += ttt * curve.endPoint.y;
var width = startWidth + ttt * widthDelta;
this._drawPoint(x, y, width);
}
ctx.closePath();
ctx.fill();
};
SignaturePad.prototype._drawDot = function (point) {
var ctx = this._ctx;
var width = typeof this.dotSize === 'function' ? this.dotSize() : this.dotSize;
ctx.beginPath();
this._drawPoint(point.x, point.y, width);
ctx.closePath();
ctx.fill();
};
SignaturePad.prototype._fromData = function (pointGroups, drawCurve, drawDot) {
for (var i = 0; i < pointGroups.length; i += 1) {
var group = pointGroups[i];
if (group.length > 1) {
for (var j = 0; j < group.length; j += 1) {
var rawPoint = group[j];
var point = new Point(rawPoint.x, rawPoint.y, rawPoint.time);
var color = rawPoint.color;
if (j === 0) {
// First point in a group. Nothing to draw yet.
// All points in the group have the same color, so it's enough to set
// penColor just at the beginning.
this.penColor = color;
this._reset();
this._addPoint(point);
} else if (j !== group.length - 1) {
// Middle point in a group.
var _addPoint2 = this._addPoint(point),
curve = _addPoint2.curve,
widths = _addPoint2.widths;
if (curve && widths) {
drawCurve(curve, widths, color);
}
} else {
// Last point in a group. Do nothing.
}
}
} else {
this._reset();
var _rawPoint = group[0];
drawDot(_rawPoint);
}
}
};
SignaturePad.prototype._toSVG = function () {
var _this2 = this;
var pointGroups = this._data;
var canvas = this._canvas;
var ratio = Math.max(window.devicePixelRatio || 1, 1);
var minX = 0;
var minY = 0;
var maxX = canvas.width / ratio;
var maxY = canvas.height / ratio;
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttributeNS(null, 'width', canvas.width);
svg.setAttributeNS(null, 'height', canvas.height);
this._fromData(pointGroups, function (curve, widths, color) {
var path = document.createElement('path');
// Need to check curve for NaN values, these pop up when drawing
// lines on the canvas that are not continuous. E.g. Sharp corners
// or stopping mid-stroke and than continuing without lifting mouse.
if (!isNaN(curve.control1.x) && !isNaN(curve.control1.y) && !isNaN(curve.control2.x) && !isNaN(curve.control2.y)) {
var attr = 'M ' + curve.startPoint.x.toFixed(3) + ',' + curve.startPoint.y.toFixed(3) + ' ' + ('C ' + curve.control1.x.toFixed(3) + ',' + curve.control1.y.toFixed(3) + ' ') + (curve.control2.x.toFixed(3) + ',' + curve.control2.y.toFixed(3) + ' ') + (curve.endPoint.x.toFixed(3) + ',' + curve.endPoint.y.toFixed(3));
path.setAttribute('d', attr);
path.setAttribute('stroke-width', (widths.end * 2.25).toFixed(3));
path.setAttribute('stroke', color);
path.setAttribute('fill', 'none');
path.setAttribute('stroke-linecap', 'round');
svg.appendChild(path);
}
}, function (rawPoint) {
var circle = document.createElement('circle');
var dotSize = typeof _this2.dotSize === 'function' ? _this2.dotSize() : _this2.dotSize;
circle.setAttribute('r', dotSize);
circle.setAttribute('cx', rawPoint.x);
circle.setAttribute('cy', rawPoint.y);
circle.setAttribute('fill', rawPoint.color);
svg.appendChild(circle);
});
var prefix = 'data:image/svg+xml;base64,';
var header = '<svg' + ' xmlns="http://www.w3.org/2000/svg"' + ' xmlns:xlink="http://www.w3.org/1999/xlink"' + (' viewBox="' + minX + ' ' + minY + ' ' + maxX + ' ' + maxY + '"') + (' width="' + maxX + '"') + (' height="' + maxY + '"') + '>';
var body = svg.innerHTML;
// IE hack for missing innerHTML property on SVGElement
if (body === undefined) {
var dummy = document.createElement('dummy');
var nodes = svg.childNodes;
dummy.innerHTML = '';
for (var i = 0; i < nodes.length; i += 1) {
dummy.appendChild(nodes[i].cloneNode(true));
}
body = dummy.innerHTML;
}
var footer = '</svg>';
var data = header + body + footer;
return prefix + btoa(data);
};
SignaturePad.prototype.fromData = function (pointGroups) {
var _this3 = this;
this.clear();
this._fromData(pointGroups, function (curve, widths) {
return _this3._drawCurve(curve, widths.start, widths.end);
}, function (rawPoint) {
return _this3._drawDot(rawPoint);
});
this._data = pointGroups;
};
SignaturePad.prototype.toData = function () {
return this._data;
};
return SignaturePad;
})));
In your javascript code you are working only with
canvas = document.getElementById('signature-canvas')
So that is the problem.
You should add a class on both signature canvases in html code for example signature like this:
<canvas id="signature-canvas" class="signature" style="width:375px;height:150px;max-width:100%;border:8px #CCC solid;background-color: white;"></canvas>
<canvas id="signature-canvas2" class="signature" style="width:375px;height:150px;max-width:100%;border:8px #CCC solid;background-color: white;"></canvas>
And then in javascript add one more pair of commands for second signature pad for control buttons (submit and reset) for second canvas.
I am making a game where it's about clicking on the nearest yellow dot from the green dot.
I got a list named dots.
You can check out my codepen to see the code I'm using.
My problem is that when you're playing the game, sometimes some of the yellow dots are too close to each other. So I am thinking if it's possible to make a collision-detection or something else, to check if the yellow dots collides?
Here is a picture of my game...
I made a red circle around the problem:
The link to my codepen project: /lolkie02/pen/PJVOdy?editors=0010
If you wanna try the game, it only works through iPhone or Android browser since I made the buttons etc. 'touchstart' in the javascript.
function getDistance(obj1, obj2) {
return Math.floor(
Math.sqrt(Math.pow(obj1.cx - obj2.cx, 2) + Math.pow(obj1.cy - obj2.cy, 2))
);
}
function getRandomArbitrary(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
function comparator(a, b) {
if (a[1] < b[1]) return -1;
if (a[1] > b[1]) return 1;
return 0;
}
function difference(source, toRemove) {
return source.filter(function(value) {
return toRemove.indexOf(value) == -1;
});
}
////////////////
// global vars
////////////////
var svg = document.getElementById("svg");
var dotMatrix = document.createElementNS(
"http://www.w3.org/2000/svg",
"circle"
);
var lineMatrix = document.createElementNS("http://www.w3.org/2000/svg", "line");
var screenW = window.innerWidth;
var screenH = window.innerHeight;
var totalDist = document.getElementById("distance");
////////////////
// line constructor
////////////////
function Line(x1, y1, x2, y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.el = document.createElementNS("http://www.w3.org/2000/svg", "line");
this.class = "line";
this.update = function(x1, y1, x2, y2) {
this.el.setAttribute("x1", x1 || this.x1);
this.el.setAttribute("y1", y1 || this.y1);
this.el.setAttribute("x2", x2 || this.x2);
this.el.setAttribute("y2", y2 || this.y2);
this.setAttr("class", this.class);
};
this.setAttr = function(attr, value) {
this.el.setAttribute(attr, value);
};
this.append = function() {
svg.insertBefore(this.el, svg.firstChild);
};
}
////////////////
// dot constructor
////////////////
function Dot(r, cx, cy) {
this.r = r;
this.cx = cx;
this.cy = cy;
this.el = document.createElementNS("http://www.w3.org/2000/svg", "circle");
this.class = "dot";
this.update = function() {
this.el.setAttribute("r", this.r);
this.el.setAttribute("cx", this.cx);
this.el.setAttribute("cy", this.cy);
this.setAttr("class", this.class);
};
// activates a dot
this.activate = function() {
for (i = 0; i < dots.num; i++) {
dots.list[i].setAttr("data-selected", "false");
}
this.setAttr("data-selected", "true");
};
this.visited = function() {
this.setAttr("data-visited", "true");
};
// sets attribute to element
this.setAttr = function(attr, value) {
this.el.setAttribute(attr, value);
};
// gets attribute to element
this.getAttr = function(attr) {
return this.el.getAttribute(attr);
};
// appends element to svg and attaches event listeners
this.append = function() {
svg.appendChild(this.el);
this.el.addEventListener("touchstart", this.onClick);
};
// on click on element
this.onClick = function(event) {
//gets the id and the coords of the dot
var thisId = Number(event.target.getAttribute("data-id").substr(3, 2));
var thisCx = dots.list[thisId].cx;
var thisCy = dots.list[thisId].cy;
// calculates the distance between dots
var distances = [];
for (i = 0; i < dots.num; i++) {
distances[i] = [i, getDistance(dots.selected, dots.list[i])];
}
distances.sort(comparator);
distances.splice(0, 1);
var distancesLeft = [];
for (i = 0; i < distances.length; i++) {
if (dots.left.includes(distances[i][0])) {
distancesLeft.push(distances[i][0]);
}
}
//if the element is the nearest
if (thisId == distancesLeft[0] && dots.left.includes(thisId)) {
// calculates distances
var newDistance = getDistance(dots.list[thisId], dots.selected);
app.score.update(1); // punteggio x numero di poi
// app.score.update(newDistance); punteggio x distanza
//sets the active class to the selected dot
dots.list[thisId].activate();
dots.list[thisId].visited();
// creates the line
lines.list.push(
new Line(
dots.selected.cx,
dots.selected.cy,
dots.list[thisId].cx,
dots.list[thisId].cy
)
);
lines.list[lines.list.length - 1].update();
lines.list[lines.list.length - 1].append();
// creates the preview line
//TODO: eliminare le vecchie preline che rimangono vive
svg.addEventListener("mousemove", function prelineMove(e) {
mouseX = e.pageX;
mouseY = e.pageY;
app.preline.update(thisCx, thisCy, mouseX, mouseY);
});
//saves the selected dots coordinates
dots.selected.id = thisId;
dots.selected.cx = thisCx;
dots.selected.cy = thisCy;
//removes the dot from the list of remaining dots
for (i = 0; i < dots.left.length; i++) {
if (dots.left[i] === thisId) {
dots.left.splice(i, 1);
}
}
if (dots.left.length == 0) {
app.end(true);
}
} else {
app.end(false);
}
};
}
////////////////
// lines group
////////////////
var lines = {
list: []
};
////////////////
// dots group
////////////////
var dots = {};
dots.num = 20;
dots.list = [];
dots.start = 0;
dots.selected = {};
dots.selected.id = dots.start;
dots.left = [];
dots.preline;
////////////////
// app
////////////////
var app = {};
app.level = 2;
app.score = {};
app.score.number = 0;
app.score.el = document.getElementById("score");
app.score.update = function(score) {
app.score.number += score;
app.score.el.textContent = app.score.number;
};
app.score.reset = function() {
app.score.number = 0;
app.score.update(0);
};
app.results = function(points) {
if (points == "reset") {
sessionStorage.setItem("results", 0);
} else {
if (!sessionStorage.getItem("results")) {
sessionStorage.setItem("results", points);
} else {
var newscore = points;
sessionStorage.setItem("results", newscore);
}
}
};
app.launchScreen = function(lastScore, title, description, btnText) {
app.launchScreen.el = document.getElementById("launch-screen");
app.launchScreen.el.setAttribute("class", "is-visible");
var launchScreenTitle = document.getElementById("launch-screen__title");
launchScreenTitle.textContent = title;
var launchScreenDescription = document.getElementById(
"launch-screen__description"
);
launchScreenDescription.textContent = description;
app.launchScreen.btn = document.getElementById("start-btn");
app.launchScreen.btn.textContent = btnText;
app.launchScreen.btn.addEventListener("touchstart", function lauch() {
app.launchScreen.el.setAttribute("class", "");
app.start(app.level);
document.getElementById("score2").style.display = "block";
app.launchScreen.btn.removeEventListener("touchstart", lauch);
});
};
app.preline = new Line(0, 0, 200, 200);
app.preline.setAttr("id", "preline");
app.start = function(dotsNum) {
dots.num = dotsNum;
for (i = 0; i < dots.num; i++) {
var cx = getRandomArbitrary(45, screenW - 45);
var cy = getRandomArbitrary(45, screenH - 45);
dots.list[i] = new Dot(14, cx, cy);
dots.list[i].setAttr("data-id", "id-" + i);
dots.list[i].setAttr(
"style",
"animation-delay:" + i / 10 + "s; transform-origin: " + cx + 'px ' + cy + 'px;');
dots.list[i].update();
dots.list[i].append();
dots.left.push(i);
if (i == dots.start) {
dots.selected.cx = dots.list[dots.start].cx;
dots.selected.cy = dots.list[dots.start].cy;
dots.list[dots.start].setAttr("class", "dot dot--starting");
dots.left.splice(i, 1);
}
// adds the preline
app.preline.update(
dots.selected.cx,
dots.selected.cy,
dots.selected.cx,
dots.selected.cy
);
app.preline.append();
svg.addEventListener("mousemove", function prelineMove(e) {
mouseX = e.pageX;
mouseY = e.pageY;
app.preline.update(dots.selected.cx, dots.selected.cy, mouseX, mouseY);
});
}
// sets starting point
dots.list[dots.start].setAttr("data-selected", "true");
};
app.end = function(win) {
if (win) {
app.level += 2;
app.results(app.score.number);
} else {
app.level = 2;
}
dots.list = [];
dots.selected = {};
dots.left.length = 0;
svg.innerHTML = "";
if (win) {
app.launchScreen(
app.score.number,
"", //"Sådan!",
"", //"Din score er nu: " + sessionStorage.getItem("results") + ' Det næste level vil blive endnu hårdere.',
"NÆSTE LEVEL"
);
} else {
app.launchScreen(
0,
"", //"ARGH!",
"", //"Din endelige score blev: " + sessionStorage.getItem("results"),
"PRØV IGEN"
);
app.results("reset");
app.score.reset();
var score2 = document.getElementById('score2');
var number = score2.innerHTML;
number = 0;
score2.innerHTML = number;
document.getElementById("score2").style.display = "none";
}
};
app.launchScreen(
0,
"STIFINDER",
"Find den tætteste gule prik",
"SPIL"
);
$('.btn').on('touchstart',function(e,data) {
var score2 = document.getElementById('score2');
var number = score2.innerHTML;
number++;
score2.innerHTML = number;
});
Use Pythagorean theorem to determine whether the distance of the centers of two dots are closer (or equal) to the sum of their radii - in that case you have collision.
My answer to the similar question :https://stackoverflow.com/a/46973584/4154250
I'm trying to capture user input (jquery event objects) in a captured array. I am tacking a t property on to the event, which is each event's elapsed time from the start of recording. Then I want to walk back through that array, using a setTimeout within a closure in a for loop in order to trigger those events with the same timing as user input.
I just don't understand why the animations won't play on the way back... !??!
Please, if anyone has insight into this... HELP!
$(function() {
var dancer = document.getElementById('dancer');
var $dancer = $(dancer);
var dancerContainer = document.querySelector('.dancer-container');
var $dancerContainer = $(dancerContainer);
var count = 3;
var captured = [];
var countInterval;
function replayDance(captured) {
for (i = 0; i < captured.length; i++) {
e = captured[i];
t = e.t;
setTimeout((function (e) {
return function () {
// $dancer.trigger(e.type);
// this should be
$dancer.trigger(e.originalEvent);
};
})(e), t);
}
}
function countdown() {
console.log(count);
--count;
if (count == 0) {
console.log('recording')
captureInput();
clearInterval(countInterval);
count = 3;
}
}
function captureInput() {
var mouseCapture = [];
var keyCapture = [];
var start = new Date().getTime();
$(document).on('mousemove.capture', function(event) {
event.t = new Date().getTime() - start;
captured.push(event);
});
$(document).on('keyup.capture', function(event) {
event.t = new Date().getTime() - start;
captured.push(event);
});
setTimeout(function() {
console.log('finished capturing');
$(document).off('.capture');
}, 3000);
}
function followMouse(event) {
var width = $(window).width();
var height = $(window).height();
var mouseX = event.pageX - (width * 0.25);
var mouseY = event.pageY - (height * 0.25);
var angleX = (mouseY / height) * 45;
var angleY = (mouseX / width) * 45;
dancer.style.webkitTransform = "rotateX(" + angleX + "deg) rotateY(" + angleY + "deg)";
console.log(dancer.style.webkitTransform);
}
function resize() {
var y = ($(window).height() - 250) * 0.5;
$("#box").css('margin-top', y + 'px');
}
function triggerAnimation(el, klassName) {
el.stop(true, false).addClass(klassName).one('webkitAnimationEnd', function() { el.removeClass(klassName) });
}
$(document).on('keyup', function(event) {
switch (event.which) {
case 49:
triggerAnimation($dancerContainer, 'shake');
break;
case 50:
triggerAnimation($dancerContainer, 'bounce');
break;
case 51:
triggerAnimation($dancerContainer, 'swing');
break;
case 52:
triggerAnimation($dancerContainer, 'wobble');
break;
}
});
$('#button-record').on('click', function(e) {
countInterval = setInterval(countdown, 1000);
});
$('#button-replay').on('click', function(e) {
if (captured.length) {
replayDance(captured);
} else {
console.log('nothing captured!');
}
})
$(window).on('resize', resize);
$(document).ready(resize);
$(document).on('mousemove', followMouse);
});
I needed to trigger the originalEvent attached to the Event object, rather than trying to trigger the e.type again. Corrected the offending line of code in my post.
/*jslint browser: true, devel: true */
//*********************** Constants **************************
var FPS = 30;
var ANIMATIONOBJECTX = 1;
var ANIMATIONOBJECTY = 2;
var ANIMATIONOBJECTOPACITY = 3;
var ANIMATIONOBJECTWIDTH = 4;
var ANIMATIONOBJECTHEIGHT = 5;
var ANIMATIONOBJECTROTATION = 6;
//*********************** Rotation **************************
function setRotation(view, angle) {
"use strict";
view.css({
"-webkit-transform" : "rotate(" + angle + "deg)",
"-moz-transform" : "rotate(" + angle + "deg)",
"-ms-transform" : "rotate(" + angle + "deg)",
"-o-transform" : "rotate(" + angle + "deg)",
"transform" : "rotate(" + angle + "deg)"
});
view.angle = angle; //For getting the angle later
}
//*********************** Classes **************************
var AnimationObject = function (start, end, time, isSmooth, type, object) {
"use strict";
this.type = type;
this.stages = [];
var dif = end - start,
a,
b,
steps = time * FPS;
if (isSmooth) {
for (a = 0; a < steps; a += 1) {
if (a <= steps / 2) {
//Normal parabola
b = (2.0 / 9) * Math.pow(a, 2) * Math.pow(1.0 / time, 2);
} else {
//Upside down parabola
b = (-2.0 / 9) * Math.pow(a - (FPS * time), 2) * Math.pow(1.0 / time, 2) + 100;
}
this.stages.push(b / 100 * dif + start);
}
} else {
for (a = 0; a < steps; a += 1) {
this.stages.push(a / steps * dif + start);
}
}
//Applies animation value differently depending on type
if (type === ANIMATIONOBJECTX) {
this.applyAnimation = function (step) {
object.css("left", this.stages[step]);
};
} else if (type === ANIMATIONOBJECTY) {
this.applyAnimation = function (step) {
object.css("top", this.stages[step]);
};
} else if (type === ANIMATIONOBJECTOPACITY) {
this.applyAnimation = function (step) {
object.css("opacity", this.stages[step]);
};
} else if (type === ANIMATIONOBJECTWIDTH) {
this.applyAnimation = function (step) {
object.css("width", this.stages[step]);
};
} else if (type === ANIMATIONOBJECTHEIGHT) {
this.applyAnimation = function (step) {
object.css("height", this.stages[step]);
};
} else if (type === ANIMATIONOBJECTROTATION) {
this.applyAnimation = function (step) {
setRotation(object, this.stages[step]);
};
}
};
var AnimationManager = function (time, completionMethod) {
"use strict";
this.animationObjects = [];
this.time = time;
this.add = function (animationObject) {
this.animationObjects.push(animationObject);
};
this.completionMethod = completionMethod;
this.currentStage = 0;
this.maximumStage = this.time * FPS;
this.tick = function () {
this.currentStage += 1;
if (this.currentStage < this.maximumStage) {
setTimeout(this.tick.bind(this), 1000.0 / FPS);
} else {
//Set manager to nil in the completion method
this.completionMethod();
}
var i;
for (i = 0; i < this.animationObjects.length; i += 1) {
this.animationObjects[i].applyAnimation(this.currentStage);
}
};
//Call this to start
this.startAnimation = function () {
this.timer = setTimeout(this.tick.bind(this), 1000.0 / FPS);
};
};
//*********************** Animate Objects **************************
function animatePosition(object, manager, x, y, smooth) {
"use strict";
var curX = parseFloat(object.position().left),
curY = parseFloat(object.position().top);
manager.add(
new AnimationObject(curX, x, manager.time, smooth, ANIMATIONOBJECTX, object)
);
manager.add(
new AnimationObject(curY, y, manager.time, smooth, ANIMATIONOBJECTY, object)
);
}
function animateSize(object, manager, w, h, smooth) {
"use strict";
var curW = parseFloat(object.css("width")),
curH = parseFloat(object.css("height"));
manager.add(
new AnimationObject(curW, w, manager.time, smooth, ANIMATIONOBJECTWIDTH, object)
);
manager.add(
new AnimationObject(curH, h, manager.time, smooth, ANIMATIONOBJECTHEIGHT, object)
);
}
function animateOpacity(object, manager, opacity) {
"use strict";
var curO = parseFloat(object.css("opacity"));
manager.add(
new AnimationObject(curO, opacity, manager.time, false, ANIMATIONOBJECTOPACITY, object)
);
}
function animateRotation(object, manager, angle, smooth) {
"use strict";
console.log(object.angle);
if (object.angle === undefined) {
object.angle = 0;
}
manager.add(
new AnimationObject(object.angle, angle, manager.time, smooth, ANIMATIONOBJECTROTATION, object)
);
}
var view;
function doSomething() {
"use strict";
view = $("#test");
var manager;
view.html("animating");
var complete = function () {
view.html("complete");
manager = null;
setTimeout(doSomething, 100);
};
manager = new AnimationManager(Math.random() * 1.0, complete);
animatePosition(view, manager, Math.random() * 400, Math.random() * 500, true);
animateOpacity(view, manager, Math.random());
animateSize(view, manager, Math.random() * 500, Math.random() * 500, true);
animateRotation(view, manager, Math.random() * 360, Math.round(Math.random()));
manager.startAnimation();
}
That doSomething method at the bottom runs when I press a button. The animateRotation method detects that the object.angle is undefined and sets it to 0. During the animation, the setRotation is called and sets the object.angle to it's angle (and i can console.log it fine too). But when the complete function is called and the animation starts again, the object(view in the doSomething method).angle is reset back to undefined again. What is going on here?
As it is right now, view = $("#test"); runs everytime doSomething is called, which selects the same DOM node, but returns a different jQuery object everytime.
The easiest way of fixing this would be to do the following:
view = view || $("#test");
However you should probably refactor your code so that it doesn't rely on a global variable.
Once you will fix this, you will notice that an angle property will exist on the object, but it will still be undefined at the end of the animation. That's because the last time setRotation is called, angle is also undefined.