This is my new JavaScript plugin for generating Android like Pattern locker for web applications.
This is fully customizable plugin. Don't know where it can be used.... Just developed in my own interest.... please suggest some improvements for the same..... I think the captcha can be replaced with this plugin.
I have created the plugin using raphaeljs.
I have created the plugin using raphaeljs.
How to use?
Step 1: Include the following scripts in your head section (click here to download raphaeljs , click here to download pattern.js)
<script src="raphael-min.js" type="text/javascript"></script>
<script src="pattern.js" type="text/javascript"></script>
Step 2: Create an instance for the pattern with your custom properties and draw the pattern within the container with instance.draw(container).
var s = new Pattern(properties);
s.draw(container);
Properties
Property | Description | Default Value |
dimension | Dimension of the patern
No. of rows x No. of columns Eg: dimension:‘5x5’ |
3x3 |
patternRadius | Radius of the pattern circle
Eg: patternRadius:25 |
20 |
patternGap | Gap between each Pattern Circle
Eg: patternGap:70 |
50 |
outerColor | Color of the Pattern Circle. The color value can be either hex color or hex gradient color
Eg: outerColor:’#FC0000’ outerColor :‘90-#239EE0:5-#1951A0:95’ |
#333333 |
innerColor | Color of the inner circle within the Pattern Circle
Eg: innerColor:’#FC0000’ innerColor :‘90-#239EE0:5-#1951A0:95’ |
90-#239EE0:5-#1951A0:95 |
background | Pattern box background color
Eg: background:’#FF00F0’ |
#000000 |
backgroundOpacity | Pattern box background opacity
Eg: background:0.5 |
1 |
hoverColor | Stroke color of Pattern Circle when mouse over
Eg: hoverColor:’#FF00F0’ |
#c8ee17 |
errorColor | Stroke color of Pattern Circle for Invalid Pattern
Eg: errorColor:’#FF00F0’ |
#FF0000 |
padding | Pattern Box padding
Eg: padding:25 |
Value of pattern radius |
onFinish | Handler to be executed when the user completes the pattern
Eg: onFinish:function(value){ } value – value of the pattern drawn passed to the handler |
null |
also you can set the property values externally with the created pattern Object
Functions
Function | Description | Return value |
draw (container) | Draw the pattern within the container. Should be called with pattern instance.
Eg: s.draw(‘mydiv’); Here ‘mydiv’ represents containerId s.draw(document.getElementById(‘mydiv’)); |
Return Pattern Object |
clear() | Resets the pattern.
Eg: s.clear(); |
Return Pattern Object |
error() | Used to mark the drawn pattern as error
Eg: s.error(); |
Return Pattern Object |
val() | Used to get the value of drawn pattern
Eg: s.val(); for the image attached in this post, the value returned will be ‘3-4-5-10-15’ |
Return pattern value |
eg:
var samplePattern = "3-4-5-10-15";
var s = new Pattern({
dimension: '5x5',
outerColor: '#000',
patternRadius: 20,
patternGap: 30,
padding: 20,
background: '#333',
backgroundOpacity: 0.5
});
s.onFinish = function (v) {
if (v == samplePattern) alert('success');
else this.error();
};
s.draw('mypattern');
Plugin
var Pattern = function (options) {
this.dimension = options.dimension && options.dimension.indexOf('x') !== -1 ? options.dimension.split('x') : [3, 3];
this.patternRadius = options.patternRadius || 20;
this.patternGap = options.patternGap || 50;
this.innerColor = options.innerColor || '90-#239EE0:5-#1951A0:95';
this.outerColor = options.outerColor || '#333333';
this.background = options.background || '#000000';
this.backgroundOpacity = options.backgroundOpacity || 1;
this.hoverColor = options.hoverColor || '#c8ee17';
this.errorColor = options.errorColor || '#FF0000';
this.padding = options.padding || this.patternRadius;
this.onFinish = options.onFinish || function (v) {};
this.width = this.dimension[0] * (2 * this.patternRadius + this.patternGap) + (this.padding * 4) - this.patternGap;
this.height = this.dimension[1] * (2 * this.patternRadius + this.patternGap) + (this.padding * 4) - this.patternGap;
this.paper = null;
this.patternCircle = [];
this.value = [];
this.blocker = null;
var patternObj = this;
this.isMouseDown = false;
this.lineX = 0;
this.lineY = 0;
this.currentPath = null;
this.currentTarget = null;
//styes
this.paperStyle = {
fill: patternObj.background,
'stroke-width': 0,
opacity: patternObj.backgroundOpacity
};
this.selectedStyle = {
'fill': '#CCC',
'fill-opacity': 0.3,
'stroke-width': 3,
'stroke': '#C8E02A'
};
this.innerStyle = {
'fill': patternObj.innerColor,
'stroke-width': 0
};
this.outerStyle = {
'fill': patternObj.outerColor,
'stroke-width': 0,
'fill-opacity': 1,
};
this.hoverStyle = {
'stroke-width': 3,
'stroke': patternObj.hoverColor,
'stroke-opacity': 1
};
this.pathStyle = {
stroke: '#FFF',
'stroke-width': '5',
'stroke-linecap': 'round',
'opacity': 0.3
};
this.errorStyle = {
'stroke-width': 3,
'stroke': patternObj.errorColor,
'stroke-opacity': 0.75
};
//common handlers
var paperMouseUpHandler = function () {
patternObj.isMouseDown = false;
if (patternObj.currentPath) {
patternObj.currentPath.remove();
}
if (patternObj.currentTarget.length && patternObj.currentTarget[0].data('connection') == 1) {
patternObj.blocker = patternObj.paper.rect(0, 0, patternObj.width, patternObj.height, patternObj.patternRadius).attr({
fill: '#000',
'stroke-width': 0,
'fill-opacity': 0
});
}
patternObj.currentPath = [];
patternObj.currentTarget = [];
if (typeof (patternObj.onFinish)) {
patternObj.onFinish(patternObj.val());
}
};
var drawPathHandler = function (e) {
e = e || window.event;
var pX = e.pageX;
var pY = e.pageY;
if (pX === undefined) {
pX = e.clientX;
pY = e.clientY;
}
pX = pX - ((window.pageXOffset || document.body.scrollLeft) + patternObj.paper.canvas.getBoundingClientRect().left);
pY = pY - ((window.pageYOffset || document.body.scrollTop) + patternObj.paper.canvas.getBoundingClientRect().top);
e.stopPropagation();
if (patternObj.isMouseDown && patternObj.currentPath) {
patternObj.currentPath.attr('path', "M" + patternObj.lineX + " " + patternObj.lineY + "L" + pX + " " + pY);
}
};
this.disableSelection = function (target) {
if (typeof target.onselectstart != "undefined") {
target.onselectstart = function () {
return false
};
} else if (typeof target.style.MozUserSelect != "undefined") {
target.style.MozUserSelect = "none";
} else {
target.onmousedown = function () {
return false
};
}
};
this.createPattern = function (paperObj) {
var x = 0,
y = 0,
i, j, elm = null;
for (i = 0; i < patternObj.dimension[0]; i++) {
x = i * (patternObj.patternGap + patternObj.patternRadius * 2) + patternObj.padding + patternObj.patternRadius;
for (j = 0; j < patternObj.dimension[1]; j++) {
y = j * (patternObj.patternGap + patternObj.patternRadius * 2) + patternObj.patternRadius + patternObj.padding;
elm = patternObj.drawPatternPoint(paperObj, x, y, i, j);
patternObj.patternCircle.push(elm);
elm[0].data({
x: i,
y: j
});
}
}
patternObj.sort();
};
this.sort = function () {
var i, j, tmpAry = [],
elm, cnt = 1;
for (i = 0; i < patternObj.dimension[1]; i++) {
for (j = 0; j < patternObj.dimension[0]; j++) {
elm = patternObj.getByXY(j, i);
elm[0].data({
'value': cnt
});
elm[1].data({
'value': cnt
});
tmpAry.push(elm);
cnt++;
}
}
patternObj.patternCircle = tmpAry;
};
this.drawConnection = function (oCircle, iCircle, currentTarget) {
patternObj.currentPath.attr('path', "M" + patternObj.lineX + " " + patternObj.lineY + "L" + (oCircle.getBBox().x + oCircle.getBBox().width / 2) + " " + (oCircle.getBBox().y + oCircle.getBBox().height / 2));
patternObj.lineX = (oCircle.getBBox().x + oCircle.getBBox().width / 2);
patternObj.lineY = (oCircle.getBBox().y + oCircle.getBBox().height / 2);
patternObj.currentPath = patternObj.paper.path("M" + patternObj.lineX + " " + patternObj.lineY + "L" + patternObj.lineX - 2 + " " + patternObj.lineY - 2).attr(patternObj.pathStyle);
patternObj.currentPath.mouseup(paperMouseUpHandler);
currentTarget.data({
'connection': 1
}).attr(patternObj.selectedStyle);
iCircle.data({
'connection': 1
});
oCircle.data({
'connection': 1
}).attr(patternObj.selectedStyle);
patternObj.value.push(oCircle.data('value'));
};
this.getByXY = function (x, y) {
for (var i = 0; i < this.patternCircle.length; i++) {
if (this.patternCircle[i][0].data('x') == x && this.patternCircle[i][0].data('y') == y) {
return this.patternCircle[i];
}
}
return null;
};
this.drawPatternPoint = function (paperObj, x, y, xi, yi) {
var patternElm = paperObj.set();
var oCircle = paperObj.circle(patternObj.padding + x, patternObj.padding + y, patternObj.patternRadius).attr(patternObj.outerStyle);
var iCircle = paperObj.circle(patternObj.padding + x, patternObj.padding + y, patternObj.patternRadius / 3).attr(patternObj.innerStyle);
iCircle.data({
'connection': 0,
'x': xi,
'y': yi
});
oCircle.data({
'connection': 0,
'x': xi,
'y': yi
});
patternElm.push(oCircle, iCircle);
var patternMousemoveHandler = function (e) {
oCircle.attr(patternObj.hoverStyle);
if (patternObj.currentPath && (patternObj.currentTarget[0] !== oCircle[0] && patternObj.currentTarget[1] !== iCircle[0]) && (iCircle.data('connection') == 0)) {
var x1 = patternObj.currentTarget[0].data('x');
var y1 = patternObj.currentTarget[0].data('y');
var x2 = oCircle.data('x');
var y2 = oCircle.data('y');
var xs = x1 > x2 ? x2 : x1;
var xe = x1 > x2 ? x1 : x2;
var ys = y1 > y2 ? y2 : y1;
var ye = y1 > y2 ? y1 : y2;
var i, j;
var telm = null;
var connect = function (a, b) {
telm = patternObj.getByXY(a, b);
if (telm[0].data('connection') == 0) {
patternObj.drawConnection(telm[0], telm[1], telm[0]);
}
};
if (x1 == x2 && y1 !== y2) {
if (y1 < y2) {
for (i = ys; i <= ye; i++) {
connect(xs, i);
}
} else {
for (i = ye; i >= ys; i--) {
connect(xs, i);
}
}
} else if (y1 == y2 && x1 !== x2) {
if (x1 > x2) {
for (i = xe; i >= xs; i--) {
connect(i, ys);
}
} else {
for (i = xs; i <= xe; i++) {
connect(i, ys);
}
}
} else if (Math.abs(x1 - x2) == Math.abs(y1 - y2)) {
for (i = 0; i <= Math.abs(ys - ye); i++) {
if (y1 < y2 && x1 > x2) {
connect(x1 - i, y1 + i);
} else if (y1 > y2 && x1 < x2) {
connect(x1 + i, y1 - i);
} else if (y1 < y2) {
connect(x1 + i, y1 + i);
} else {
connect(x1 - i, y1 - i);
}
}
}
patternObj.currentTarget.pop();
patternObj.currentTarget = [oCircle, iCircle];
}
};
var patternMouseoutHandler = function () {
if (oCircle.data('connection') == 0) {
oCircle.attr({
'stroke-width': 0
});
}
};
var patternMouseDownHandler = function (e) {
patternObj.isMouseDown = true;
patternObj.currentTarget = [oCircle, iCircle];
patternObj.lineX = patternElm.getBBox().x + patternElm.getBBox().width / 2;
patternObj.lineY = patternElm.getBBox().y + patternElm.getBBox().height / 2;
patternObj.currentPath = patternObj.paper.path("M" + patternObj.lineX + " " + patternObj.lineY + "L" + patternObj.lineX - 2 + " " + patternObj.lineY - 2).attr(patternObj.pathStyle);
patternObj.currentPath.touchend(paperMouseUpHandler);
patternObj.currentPath.mouseup(paperMouseUpHandler);
};
patternElm.mousemove(patternMousemoveHandler);
patternElm.mouseout(patternMouseoutHandler);
patternElm.mousedown(patternMouseDownHandler);
patternElm.mouseup(paperMouseUpHandler);
return [oCircle, iCircle];
};
this.drawPaper = function (elm) {
var paper = Raphael(elm, patternObj.width, patternObj.height);
var rect = paper.rect(0, 0, patternObj.width, patternObj.height, patternObj.patternRadius).attr(patternObj.paperStyle);
rect.mousemove(drawPathHandler);
rect.mouseup(paperMouseUpHandler);
return paper;
};
this.draw = function (elm) {
patternObj.paper = patternObj.drawPaper(elm);
patternObj.createPattern(this.paper);
patternObj.disableSelection(patternObj.paper.canvas);
return this;
};
this.clear = function () {
var paths = patternObj.paper.canvas.getElementsByTagName('path');
var cnt = paths.length;
for (var i = 0; i < cnt; i++) {
paths[0].parentNode.removeChild(paths[0]);
}
patternObj.paper.forEach(function (el) {
if (el[0].tagName.toLowerCase() == 'circle') {
el.data({
'connection': 0
});
if (patternObj.patternRadius == el.attr('r')) {
el.attr(patternObj.outerStyle);
}
}
});
if (patternObj.blocker) {
patternObj.blocker.remove();
}
patternObj.blocker = null;
patternObj.currentPath = null;
patternObj.currentTarget = [];
patternObj.value = [];
return this;
};
this.error = function () {
for (var i = 0; i < patternObj.patternCircle.length; i++) {
if (patternObj.patternCircle[i][0].data('connection') == 1) {
patternObj.patternCircle[i][0].attr(patternObj.errorStyle);
}
}
return this;
};
this.val = function () {
return patternObj.value.toString().replace(/,/g, '-');
};
};
Comments
Post a Comment