<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>SVG Based Pattern Lock Example</title>
<link href="https://www.jqueryscript.net/css/jquerysctipttop.css" rel="stylesheet" type="text/css">
<style media="screen">
* {
box-sizing: border-box;
}
html,
body {
padding: 0;
margin: 0;
height: 100vh;
max-height: 100vh;
overflow: hidden;
}
body {
font-family: 'Varela Round', sans-serif;
background-color: #fafafa;
}
.container {
margin: 150px auto;
height: 100%;
}
h1 {
text-align: center;
margin: 0;
height: 15vh;
line-height: 15vh;
text-align: center;
font-size: 6vh;
}
#lock {
width: 100%;
height: calc(100% - 15vh);
padding-bottom: 12vh;
min-height: 120px;
}
.stars {
margin: auto;
display: block;
}
</style>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="jquery-script-menu">
<div class="jquery-script-center">
<div class="jquery-script-clear"></div>
</div>
</div>
<div class="container">
<h1>SVG Based Pattern Lock Example</h1>
<svg class="patternlock" id="lock" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<g class="lock-actives"></g>
<g class="lock-lines"></g>
<g class="lock-dots">
<circle cx="20" cy="20" r="2"/>
<circle cx="50" cy="20" r="2"/>
<circle cx="80" cy="20" r="2"/>
<circle cx="20" cy="50" r="2"/>
<circle cx="50" cy="50" r="2"/>
<circle cx="80" cy="50" r="2"/>
<circle cx="20" cy="80" r="2"/>
<circle cx="50" cy="80" r="2"/>
<circle cx="80" cy="80" r="2"/>
</g>
<svg>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="patternlock.js"></script>
<script type="text/javascript">
var e = document.getElementById('lock')
var p = new PatternLock(e, {
onPattern: function() {
this.success()
}
});
</script>
</body>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36251023-1']);
_gaq.push(['_setDomainName', 'jqueryscript.net']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</html>
svg.patternlock g.lock-lines line {
stroke-width: 1.5;
stroke: black;
opacity: 0.5;
}
svg.patternlock g.lock-dots circle {
stroke: transparent;
fill: black;
stroke-width: 13.5;
}
svg.patternlock g.lock-actives circle {
fill: black;
opacity: .2;
animation: lock-activate-dot .15s 0s ease 1;
transform-origin: center;
}
svg.patternlock g.lock-lines line {
stroke-width: 1.5;
stroke-linecap: round;
}
svg.patternlock.success g.lock-actives circle {
fill: green;
}
svg.patternlock.error g.lock-actives circle {
fill: red;
}
@keyframes lock-activate-dot {
0% {
transform: scale(0);
}
75% {
transform: scale(1.1);
}
100% {
transform: scale(1.0);
}
}
'use strict';
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
(function (factory) {
var global = Function('return this')() || (0, eval)('this');
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], function ($) {
return factory($, global);
});
} else if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory(require('jquery'), global);
} else {
// Browser globals (global is window)
global.PatternLock = factory(global.jQuery, global);
}
})(function ($, window) {
var _scrollKeys;
var svgns = 'http://www.w3.org/2000/svg';
var moveEvent = 'touchmove mousemove';
var scrollKeys = (_scrollKeys = {
37: true, // left
38: true, // up
39: true, // right
40: true, // down
32: true }, _defineProperty(_scrollKeys, '38', true), _defineProperty(_scrollKeys, 34, true), _defineProperty(_scrollKeys, 35, true), _defineProperty(_scrollKeys, 36, true), _scrollKeys);
function vibrate() {
navigator.vibrate = navigator.vibrate || navigator.webkitVibrate || navigator.mozVibrate || navigator.msVibrate;
if (navigator.vibrate) {
window.navigator.vibrate(25);
}
}
function PatternLock(element, options) {
var svg = $(element);
var self = this;
var root = svg[0];
var dots = svg.find('.lock-dots circle');
var lines = svg.find('.lock-lines');
var actives = svg.find('.lock-actives');
var pt = root.createSVGPoint();
var code = [];
var currentline = void 0;
var currenthandler = void 0;
options = Object.assign(PatternLock.defaults, options || {});
svg.on('touchstart mousedown', function (e) {
clear();
e.preventDefault();
disableScroll();
svg.on(moveEvent, discoverDot);
var endEvent = e.type == 'touchstart' ? 'touchend' : 'mouseup';
$(document).one(endEvent, function (e) {
end();
});
});
// Exported methods
Object.assign(this, {
clear: clear,
success: success,
error: error,
getPattern: getPattern
});
function success() {
svg.removeClass('error');
svg.addClass('success');
}
function error() {
svg.removeClass('success');
svg.addClass('error');
}
function getPattern() {
return parseInt(code.map(function (i) {
return dots.index(i) + 1;
}).join(''));
}
function end() {
enableScroll();
stopTrack(currentline);
currentline && currentline.remove();
svg.off(moveEvent, discoverDot);
var val = options.onPattern.call(self, getPattern());
if (val === true) {
success();
} else if (val === false) {
error();
}
}
function clear() {
code = [];
currentline = undefined;
currenthandler = undefined;
svg.removeClass('success error');
lines.empty();
actives.empty();
}
function preventDefault(e) {
e = e || window.event;
if (e.preventDefault) e.preventDefault();
e.returnValue = false;
}
function preventDefaultForScrollKeys(e) {
if (scrollKeys[e.keyCode]) {
preventDefault(e);
return false;
}
}
function disableScroll() {
if (window.addEventListener) // older FF
window.addEventListener('DOMMouseScroll', preventDefault, false);
window.onwheel = preventDefault; // modern standard
window.onmousewheel = document.onmousewheel = preventDefault; // older browsers, IE
window.ontouchmove = preventDefault; // mobile
document.onkeydown = preventDefaultForScrollKeys;
}
function enableScroll() {
if (window.removeEventListener) window.removeEventListener('DOMMouseScroll', preventDefault, false);
window.onmousewheel = document.onmousewheel = null;
window.onwheel = null;
window.ontouchmove = null;
document.onkeydown = null;
}
function isUsed(target) {
for (var i = 0; i < code.length; i++) {
if (code[i] === target) {
return true;
}
}
return false;
}
function isAvailable(target) {
for (var i = 0; i < dots.length; i++) {
if (dots[i] === target) {
return true;
}
}
return false;
}
function updateLine(line) {
return function (e) {
e.preventDefault();
if (currentline !== line) return;
var pos = svgPosition(e.target, e);
line.setAttribute('x2', pos.x);
line.setAttribute('y2', pos.y);
return false;
};
}
function discoverDot(e, target) {
if (!target) {
var _getMousePos = getMousePos(e),
x = _getMousePos.x,
y = _getMousePos.y;
target = document.elementFromPoint(x, y);
}
var cx = target.getAttribute('cx');
var cy = target.getAttribute('cy');
if (isAvailable(target) && !isUsed(target)) {
stopTrack(currentline, target);
currentline = beginTrack(target);
}
}
function stopTrack(line, target) {
if (line === undefined) return;
if (currenthandler) {
svg.off('touchmove mousemove', currenthandler);
}
if (target === undefined) return;
var x = target.getAttribute('cx');
var y = target.getAttribute('cy');
line.setAttribute('x2', x);
line.setAttribute('y2', y);
}
function beginTrack(target) {
code.push(target);
var x = target.getAttribute('cx');
var y = target.getAttribute('cy');
var line = createNewLine(x, y);
var marker = createNewMarker(x, y);
actives.append(marker);
currenthandler = updateLine(line);
svg.on('touchmove mousemove', currenthandler);
lines.append(line);
if (options.vibrate) vibrate();
return line;
}
function createNewMarker(x, y) {
var marker = document.createElementNS(svgns, "circle");
marker.setAttribute('cx', x);
marker.setAttribute('cy', y);
marker.setAttribute('r', 6);
return marker;
}
function createNewLine(x1, y1, x2, y2) {
var line = document.createElementNS(svgns, "line");
line.setAttribute('x1', x1);
line.setAttribute('y1', y1);
if (x2 === undefined || y2 == undefined) {
line.setAttribute('x2', x1);
line.setAttribute('y2', y1);
} else {
line.setAttribute('x2', x2);
line.setAttribute('y2', y2);
}
return line;
}
function getMousePos(e) {
return {
x: e.clientX || e.originalEvent.touches[0].clientX,
y: e.clientY || e.originalEvent.touches[0].clientY
};
}
function svgPosition(element, e) {
var _getMousePos2 = getMousePos(e),
x = _getMousePos2.x,
y = _getMousePos2.y;
pt.x = x;pt.y = y;
return pt.matrixTransform(element.getScreenCTM().inverse());
}
}
PatternLock.defaults = {
onPattern: function onPattern() {},
vibrate: true
};
return PatternLock;
});