/** @preserve jSignature v2 jSignature's custom "base30" format export and import plugins. */ /** Copyright (c) 2011 Willow Systems Corp http://willow-systems.com MIT License */ ;(function(){ var chunkSeparator = '_' , charmap = {} // {'1':'g','2':'h','3':'i','4':'j','5':'k','6':'l','7':'m','8':'n','9':'o','a':'p','b':'q','c':'r','d':'s','e':'t','f':'u','0':'v'} , charmap_reverse = {} // will be filled by 'uncompress*" function // need to split below for IE7 (possibly others), which does not understand string[position] it seems (returns undefined) , allchars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX'.split('') , bitness = allchars.length / 2 , minus = 'Z' , plus = 'Y' for(var i = bitness-1; i > -1; i--){ charmap[allchars[i]] = allchars[i+bitness] charmap_reverse[allchars[i+bitness]] = allchars[i] } var remapTailChars = function(number){ // for any given number as string, returning string with trailing chars remapped something like so: // '345' -> '3de' var chars = number.split('') , l = chars.length // we are skipping first char. standard hex number char = delimiter for (var i = 1; i < l; i++ ){ chars[i] = charmap[chars[i]] } return chars.join('') } , compressstrokeleg = function(data){ // we convert half-stroke (only 'x' series or only 'y' series of numbers) // data is like this: // [517,516,514,513,513,513,514,516,519,524,529,537,541,543,544,544,539,536] // that is converted into this: // "5agm12100p1235584210m53" // each number in the chain is converted such: // - find diff from previous number // - first significant digit is kept as digit char. digit char = start of new number. // - consecutive numbers are mapped to letters, where 1 to 9 are A to I, 0 is O // Sign changes are denoted by "P" - plus, "M" for minus. var answer = [] , lastwhole = 0 , last = 0 , lastpolarity = 1 , l = data.length , nwhole, n, absn for(var i = 0; i < l; i++){ // we start with whole coordinates for each point // coords are converted into series of vectors: // [512, 514, 520] // [512, +2, +6] nwhole = Math.round(data[i]) n = nwhole - lastwhole lastwhole = nwhole // inserting sign change when needed. if (n < 0 && lastpolarity > 0) { lastpolarity = -1 answer.push(minus) } else if (n > 0 && lastpolarity < 0) { lastpolarity = 1 answer.push(plus) } // since we have dealt with sign. let's absolute the value. absn = Math.abs(n) // adding number to list We convert these to Hex before storing on the string. if (absn >= bitness) { answer.push(remapTailChars(absn.toString(bitness))) } else { answer.push(absn.toString(bitness)) } } return answer.join('') } , uncompressstrokeleg = function(datastring){ // we convert half-stroke (only 'x' series or only 'y' series of numbers) // datastring like this: // "5agm12100p1235584210m53" // is converted into this: // [517,516,514,513,513,513,514,516,519,524,529,537,541,543,544,544,539,536] // each number in the chain is converted such: // - digit char = start of new whole number. Alpha chars except "p","m" are numbers in hiding. // These consecutive digist expressed as alphas mapped back to digit char. // resurrected number is the diff between this point and prior coord. // - running polaritiy is attached to the number. // - we undiff (signed number + prior coord) the number. // - if char 'm','p', flip running polarity var answer = [] , chars = datastring.split('') , l = chars.length , ch , polarity = 1 , partial = [] , preprewhole = 0 , prewhole for(var i = 0; i < l; i++){ ch = chars[i] if (ch in charmap || ch === minus || ch === plus){ // this is new number - start of a new whole number. // before we can deal with it, we need to flush out what we already // parsed out from string, but keep in limbo, waiting for this sign // that prior number is done. // we deal with 3 numbers here: // 1. start of this number - a diff from previous number to // whole, new number, which we cannot do anything with cause // we don't know its ending yet. // 2. number that we now realize have just finished parsing = prewhole // 3. number we keep around that came before prewhole = preprewhole if (partial.length !== 0) { // yep, we have some number parts in there. prewhole = parseInt( partial.join(''), bitness) * polarity + preprewhole answer.push( prewhole ) preprewhole = prewhole } if (ch === minus){ polarity = -1 partial = [] } else if (ch === plus){ polarity = 1 partial = [] } else { // now, let's start collecting parts for the new number: partial = [ch] } } else /* alphas replacing digits */ { // more parts for the new number partial.push(charmap_reverse[ch]) } } // we always will have something stuck in partial // because we don't have closing delimiter answer.push( parseInt( partial.join(''), bitness ) * polarity + preprewhole ) return answer } , compressstrokes = function(data){ var answer = [] , l = data.length , stroke for(var i = 0; i < l; i++){ stroke = data[i] answer.push(compressstrokeleg(stroke.x)) answer.push(compressstrokeleg(stroke.y)) } return answer.join(chunkSeparator) } , uncompressstrokes = function(datastring){ var data = [] , chunks = datastring.split(chunkSeparator) , l = chunks.length / 2 for (var i = 0; i < l; i++){ data.push({ 'x':uncompressstrokeleg(chunks[i*2]) , 'y':uncompressstrokeleg(chunks[i*2+1]) }) } return data } , acceptedformat = 'image/jsignature;base30' , pluginCompressor = function(data){ return [acceptedformat , compressstrokes(data)] } , pluginDecompressor = function(data, formattype, importcallable){ if (typeof data !== 'string') return if (data.substring(0, acceptedformat.length).toLowerCase() === acceptedformat) { data = data.substring(acceptedformat.length + 1) // chopping off "," there } importcallable( uncompressstrokes(data) ) } , Initializer = function($){ var mothership = $.fn['jSignature'] mothership( 'addPlugin' ,'export' ,'base30' // alias ,pluginCompressor ) mothership( 'addPlugin' ,'export' ,acceptedformat // full name ,pluginCompressor ) mothership( 'addPlugin' ,'import' ,'base30' // alias ,pluginDecompressor ) mothership( 'addPlugin' ,'import' ,acceptedformat // full name ,pluginDecompressor ) } // //Because plugins are minified together with jSignature, multiple defines per (minified) file blow up and dont make sense // //Need to revisit this later. // if ( typeof define === "function" && define.amd != null) { // // AMD-loader compatible resource declaration // // you need to call this one with jQuery as argument. // define(function(){return Initializer} ) // } else { // global-polluting outcome. if(this.jQuery == null) {throw new Error("We need jQuery for some of the functionality. jQuery is not detected. Failing to initialize...")} Initializer(this.jQuery) // } if (this.jSignatureDebug) { this.jSignatureDebug['base30'] = { 'remapTailChars':remapTailChars , 'compressstrokeleg':compressstrokeleg , 'uncompressstrokeleg':uncompressstrokeleg , 'compressstrokes':compressstrokes , 'uncompressstrokes':uncompressstrokes , 'charmap': charmap } } }).call(typeof window !== 'undefined'? window : this);