2014-01-31 02:13:37 +00:00
/*globals $, svgedit, unescape, DOMParser, ActiveXObject, getStrokedBBox*/
/*jslint vars: true, eqeq: true, bitwise: true, continue: true, forin: true*/
2010-10-26 02:48:36 +00:00
/ * *
2010-11-05 17:00:32 +00:00
* Package : svgedit . utilities
2010-10-26 02:48:36 +00:00
*
2012-09-16 18:53:27 +00:00
* Licensed under the MIT License
2010-10-26 02:48:36 +00:00
*
* Copyright ( c ) 2010 Alexis Deveria
* Copyright ( c ) 2010 Jeff Schiller
* /
2010-10-26 16:33:44 +00:00
// Dependencies:
// 1) jQuery
2015-11-05 03:25:30 +00:00
// 2) pathseg.js
// 3) browser.js
// 4) svgtransformlist.js
// 5) units.js
2010-10-26 02:48:36 +00:00
2014-05-22 10:21:29 +00:00
( function ( undef ) { 'use strict' ;
2010-10-26 16:33:44 +00:00
2010-11-05 17:00:32 +00:00
if ( ! svgedit . utilities ) {
svgedit . utilities = { } ;
2010-10-28 06:08:45 +00:00
}
2010-10-26 02:48:36 +00:00
2010-10-29 05:09:39 +00:00
// Constants
2010-10-26 02:48:36 +00:00
// String used to encode base64.
2010-12-02 17:14:24 +00:00
var KEYSTR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' ;
2013-02-16 15:02:26 +00:00
var NS = svgedit . NS ;
2010-10-26 02:48:36 +00:00
2010-11-05 15:29:30 +00:00
// Much faster than running getBBox() every time
var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use' ;
var visElems _arr = visElems . split ( ',' ) ;
//var hidElems = 'clipPath,defs,desc,feGaussianBlur,filter,linearGradient,marker,mask,metadata,pattern,radialGradient,stop,switch,symbol,title,textPath';
2010-12-02 17:14:24 +00:00
var editorContext _ = null ;
2011-02-04 08:02:46 +00:00
var domdoc _ = null ;
var domcontainer _ = null ;
var svgroot _ = null ;
2010-12-02 17:14:24 +00:00
svgedit . utilities . init = function ( editorContext ) {
editorContext _ = editorContext ;
2011-02-04 08:02:46 +00:00
domdoc _ = editorContext . getDOMDocument ( ) ;
domcontainer _ = editorContext . getDOMContainer ( ) ;
svgroot _ = editorContext . getSVGRoot ( ) ;
2010-12-02 17:14:24 +00:00
} ;
2010-11-05 17:00:32 +00:00
// Function: svgedit.utilities.toXml
2010-10-26 02:48:36 +00:00
// Converts characters in a string to XML-friendly entities.
//
2013-02-15 17:02:24 +00:00
// Example: '&' becomes '&'
2010-10-26 02:48:36 +00:00
//
// Parameters:
// str - The string to be converted
//
// Returns:
// The converted string
2010-11-05 17:00:32 +00:00
svgedit . utilities . toXml = function ( str ) {
2014-02-12 10:10:56 +00:00
// ' is ok in XML, but not HTML
// > does not normally need escaping, though it can if within a CDATA expression (and preceded by "]]")
return str . replace ( /&/g , '&' ) . replace ( /</g , '<' ) . replace ( />/g , '>' ) . replace ( /"/g , '"' ) . replace ( /'/ , ''' ) ;
2010-10-26 02:48:36 +00:00
} ;
2013-02-15 23:05:23 +00:00
2010-11-05 17:00:32 +00:00
// Function: svgedit.utilities.fromXml
2013-02-15 23:05:23 +00:00
// Converts XML entities in a string to single characters.
2013-02-15 17:02:24 +00:00
// Example: '&' becomes '&'
2010-10-26 02:48:36 +00:00
//
// Parameters:
// str - The string to be converted
//
2013-02-15 23:05:23 +00:00
// Returns:
2010-10-26 02:48:36 +00:00
// The converted string
2010-11-05 17:00:32 +00:00
svgedit . utilities . fromXml = function ( str ) {
2010-10-26 02:48:36 +00:00
return $ ( '<p/>' ) . html ( str ) . text ( ) ;
} ;
// This code was written by Tyler Akins and has been placed in the
// public domain. It would be nice if you left this header intact.
// Base64 code from Tyler Akins -- http://rumkin.com
// schiller: Removed string concatenation in favour of Array.join() optimization,
2014-01-31 02:13:37 +00:00
// also precalculate the size of the array needed.
2010-10-26 02:48:36 +00:00
2010-11-05 17:00:32 +00:00
// Function: svgedit.utilities.encode64
2010-10-26 02:48:36 +00:00
// Converts a string to base64
2010-11-05 17:00:32 +00:00
svgedit . utilities . encode64 = function ( input ) {
2010-10-26 02:48:36 +00:00
// base64 strings are 4/3 larger than the original string
2014-02-01 16:13:51 +00:00
input = svgedit . utilities . encodeUTF8 ( input ) ; // convert non-ASCII characters
// input = svgedit.utilities.convertToXMLReferences(input);
if ( window . btoa ) {
return window . btoa ( input ) ; // Use native if available
2014-05-22 10:21:29 +00:00
}
var output = [ ] ;
output . length = Math . floor ( ( input . length + 2 ) / 3 ) * 4 ;
2010-10-26 02:48:36 +00:00
var chr1 , chr2 , chr3 ;
var enc1 , enc2 , enc3 , enc4 ;
var i = 0 , p = 0 ;
do {
chr1 = input . charCodeAt ( i ++ ) ;
chr2 = input . charCodeAt ( i ++ ) ;
chr3 = input . charCodeAt ( i ++ ) ;
enc1 = chr1 >> 2 ;
enc2 = ( ( chr1 & 3 ) << 4 ) | ( chr2 >> 4 ) ;
enc3 = ( ( chr2 & 15 ) << 2 ) | ( chr3 >> 6 ) ;
enc4 = chr3 & 63 ;
if ( isNaN ( chr2 ) ) {
enc3 = enc4 = 64 ;
} else if ( isNaN ( chr3 ) ) {
enc4 = 64 ;
}
2010-10-29 05:09:39 +00:00
output [ p ++ ] = KEYSTR . charAt ( enc1 ) ;
output [ p ++ ] = KEYSTR . charAt ( enc2 ) ;
output [ p ++ ] = KEYSTR . charAt ( enc3 ) ;
output [ p ++ ] = KEYSTR . charAt ( enc4 ) ;
2010-10-26 02:48:36 +00:00
} while ( i < input . length ) ;
return output . join ( '' ) ;
} ;
2010-11-05 17:00:32 +00:00
// Function: svgedit.utilities.decode64
2010-10-26 02:48:36 +00:00
// Converts a string from base64
2010-11-05 17:00:32 +00:00
svgedit . utilities . decode64 = function ( input ) {
2014-01-31 00:06:50 +00:00
if ( window . atob ) {
2014-06-12 23:42:27 +00:00
return svgedit . utilities . decodeUTF8 ( window . atob ( input ) ) ;
2014-01-31 00:06:50 +00:00
}
2013-02-15 17:02:24 +00:00
var output = '' ;
var chr1 , chr2 , chr3 = '' ;
var enc1 , enc2 , enc3 , enc4 = '' ;
2010-10-26 02:48:36 +00:00
var i = 0 ;
2013-02-19 11:18:04 +00:00
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
input = input . replace ( /[^A-Za-z0-9\+\/\=]/g , '' ) ;
2010-10-26 02:48:36 +00:00
2013-02-19 11:18:04 +00:00
do {
2010-10-29 05:09:39 +00:00
enc1 = KEYSTR . indexOf ( input . charAt ( i ++ ) ) ;
enc2 = KEYSTR . indexOf ( input . charAt ( i ++ ) ) ;
enc3 = KEYSTR . indexOf ( input . charAt ( i ++ ) ) ;
enc4 = KEYSTR . indexOf ( input . charAt ( i ++ ) ) ;
2010-10-26 02:48:36 +00:00
chr1 = ( enc1 << 2 ) | ( enc2 >> 4 ) ;
chr2 = ( ( enc2 & 15 ) << 4 ) | ( enc3 >> 2 ) ;
chr3 = ( ( enc3 & 3 ) << 6 ) | enc4 ;
output = output + String . fromCharCode ( chr1 ) ;
if ( enc3 != 64 ) {
2013-02-19 11:18:04 +00:00
output = output + String . fromCharCode ( chr2 ) ;
2010-10-26 02:48:36 +00:00
}
if ( enc4 != 64 ) {
2013-02-19 11:18:04 +00:00
output = output + String . fromCharCode ( chr3 ) ;
2010-10-26 02:48:36 +00:00
}
2013-02-15 17:02:24 +00:00
chr1 = chr2 = chr3 = '' ;
enc1 = enc2 = enc3 = enc4 = '' ;
2010-10-26 02:48:36 +00:00
2013-02-19 11:18:04 +00:00
} while ( i < input . length ) ;
2014-06-12 23:42:27 +00:00
return svgedit . utilities . decodeUTF8 ( output ) ;
} ;
svgedit . utilities . decodeUTF8 = function ( argString ) {
return decodeURIComponent ( escape ( argString ) ) ;
2010-10-26 02:48:36 +00:00
} ;
2014-02-01 16:13:51 +00:00
// codedread:does not seem to work with webkit-based browsers on OSX // Brettz9: please test again as function upgraded
svgedit . utilities . encodeUTF8 = function ( argString ) {
2014-06-12 23:42:27 +00:00
return unescape ( encodeURIComponent ( argString ) ) ;
2014-02-01 16:13:51 +00:00
} ;
2010-10-26 02:48:36 +00:00
2013-02-15 23:05:23 +00:00
// Function: svgedit.utilities.convertToXMLReferences
2010-10-26 02:48:36 +00:00
// Converts a string to use XML references
2010-11-05 17:00:32 +00:00
svgedit . utilities . convertToXMLReferences = function ( input ) {
2014-01-31 02:13:37 +00:00
var n ,
output = '' ;
for ( n = 0 ; n < input . length ; n ++ ) {
2010-10-26 02:48:36 +00:00
var c = input . charCodeAt ( n ) ;
if ( c < 128 ) {
output += input [ n ] ;
2010-11-12 19:08:29 +00:00
} else if ( c > 127 ) {
2013-02-15 17:02:24 +00:00
output += ( '&#' + c + ';' ) ;
2010-10-26 02:48:36 +00:00
}
}
return output ;
} ;
2011-02-02 17:28:43 +00:00
// Function: svgedit.utilities.text2xml
2010-10-26 02:48:36 +00:00
// Cross-browser compatible method of converting a string to an XML tree
// found this function here: http://groups.google.com/group/jquery-dev/browse_thread/thread/c6d11387c580a77f
2010-11-05 17:00:32 +00:00
svgedit . utilities . text2xml = function ( sXML ) {
2010-10-26 02:48:36 +00:00
if ( sXML . indexOf ( '<svg:svg' ) >= 0 ) {
sXML = sXML . replace ( /<(\/?)svg:/g , '<$1' ) . replace ( 'xmlns:svg' , 'xmlns' ) ;
}
2014-01-31 02:13:37 +00:00
var out , dXML ;
2010-10-26 02:48:36 +00:00
try {
2014-01-31 02:13:37 +00:00
dXML = ( window . DOMParser ) ? new DOMParser ( ) : new ActiveXObject ( 'Microsoft.XMLDOM' ) ;
2010-10-26 02:48:36 +00:00
dXML . async = false ;
2013-02-15 23:05:23 +00:00
} catch ( e ) {
throw new Error ( 'XML Parser could not be instantiated' ) ;
2013-02-19 11:18:04 +00:00
}
2010-10-26 02:48:36 +00:00
try {
2014-01-31 02:13:37 +00:00
if ( dXML . loadXML ) {
out = ( dXML . loadXML ( sXML ) ) ? dXML : false ;
}
else {
out = dXML . parseFromString ( sXML , 'text/xml' ) ;
}
2010-10-26 02:48:36 +00:00
}
2014-01-31 02:13:37 +00:00
catch ( e2 ) { throw new Error ( 'Error parsing XML string' ) ; }
2010-10-26 02:48:36 +00:00
return out ;
} ;
2011-02-02 17:28:43 +00:00
// Function: svgedit.utilities.bboxToObj
2010-10-26 02:48:36 +00:00
// Converts a SVGRect into an object.
//
// Parameters:
// bbox - a SVGRect
//
// Returns:
// An object with properties names x, y, width, height.
2010-11-05 17:00:32 +00:00
svgedit . utilities . bboxToObj = function ( bbox ) {
2010-10-26 02:48:36 +00:00
return {
x : bbox . x ,
y : bbox . y ,
width : bbox . width ,
height : bbox . height
2013-02-19 11:18:04 +00:00
} ;
2010-10-26 02:48:36 +00:00
} ;
2010-10-26 16:33:44 +00:00
2011-02-02 17:28:43 +00:00
// Function: svgedit.utilities.walkTree
2010-10-26 17:11:23 +00:00
// Walks the tree and executes the callback on each element in a top-down fashion
//
// Parameters:
// elem - DOM element to traverse
// cbFn - Callback function to run on each element
2010-11-05 17:00:32 +00:00
svgedit . utilities . walkTree = function ( elem , cbFn ) {
2010-10-26 17:11:23 +00:00
if ( elem && elem . nodeType == 1 ) {
cbFn ( elem ) ;
var i = elem . childNodes . length ;
while ( i -- ) {
2010-11-05 17:00:32 +00:00
svgedit . utilities . walkTree ( elem . childNodes . item ( i ) , cbFn ) ;
2010-10-26 17:11:23 +00:00
}
}
} ;
2011-02-02 17:28:43 +00:00
// Function: svgedit.utilities.walkTreePost
2010-10-26 17:11:23 +00:00
// Walks the tree and executes the callback on each element in a depth-first fashion
// TODO: FIXME: Shouldn't this be calling walkTreePost?
//
// Parameters:
// elem - DOM element to traverse
// cbFn - Callback function to run on each element
2010-11-05 17:00:32 +00:00
svgedit . utilities . walkTreePost = function ( elem , cbFn ) {
2010-10-26 17:11:23 +00:00
if ( elem && elem . nodeType == 1 ) {
var i = elem . childNodes . length ;
while ( i -- ) {
2010-11-05 17:00:32 +00:00
svgedit . utilities . walkTree ( elem . childNodes . item ( i ) , cbFn ) ;
2010-10-26 17:11:23 +00:00
}
cbFn ( elem ) ;
}
} ;
2010-11-05 17:00:32 +00:00
// Function: svgedit.utilities.getUrlFromAttr
2013-02-15 23:05:23 +00:00
// Extracts the URL from the url(...) syntax of some attributes.
2010-10-26 17:11:23 +00:00
// Three variants:
2013-02-19 11:18:04 +00:00
// * <circle fill="url(someFile.svg#foo)" />
2010-10-26 17:11:23 +00:00
// * <circle fill="url('someFile.svg#foo')" />
// * <circle fill='url("someFile.svg#foo")' />
//
// Parameters:
// attrVal - The attribute value as a string
2013-02-15 23:05:23 +00:00
//
2010-10-26 17:11:23 +00:00
// Returns:
// String with just the URL, like someFile.svg#foo
2010-11-05 17:00:32 +00:00
svgedit . utilities . getUrlFromAttr = function ( attrVal ) {
2013-02-15 23:05:23 +00:00
if ( attrVal ) {
2010-10-26 17:11:23 +00:00
// url("#somegrad")
if ( attrVal . indexOf ( 'url("' ) === 0 ) {
2013-02-15 16:51:48 +00:00
return attrVal . substring ( 5 , attrVal . indexOf ( '"' , 6 ) ) ;
2010-10-26 17:11:23 +00:00
}
// url('#somegrad')
2014-01-31 02:13:37 +00:00
if ( attrVal . indexOf ( "url('" ) === 0 ) {
2013-02-15 16:51:48 +00:00
return attrVal . substring ( 5 , attrVal . indexOf ( "'" , 6 ) ) ;
2010-10-26 17:11:23 +00:00
}
2014-01-31 02:13:37 +00:00
if ( attrVal . indexOf ( "url(" ) === 0 ) {
2013-02-15 16:51:48 +00:00
return attrVal . substring ( 4 , attrVal . indexOf ( ')' ) ) ;
2010-10-26 17:11:23 +00:00
}
}
return null ;
} ;
2010-11-05 17:00:32 +00:00
// Function: svgedit.utilities.getHref
2010-10-28 05:50:39 +00:00
// Returns the given element's xlink:href value
2010-11-05 17:00:32 +00:00
svgedit . utilities . getHref = function ( elem ) {
2013-02-16 15:02:26 +00:00
return elem . getAttributeNS ( NS . XLINK , 'href' ) ;
2013-02-19 11:18:04 +00:00
} ;
2010-10-28 05:50:39 +00:00
2010-11-05 17:00:32 +00:00
// Function: svgedit.utilities.setHref
2010-10-28 05:50:39 +00:00
// Sets the given element's xlink:href value
2010-11-05 17:00:32 +00:00
svgedit . utilities . setHref = function ( elem , val ) {
2013-02-16 15:02:26 +00:00
elem . setAttributeNS ( NS . XLINK , 'xlink:href' , val ) ;
2013-02-19 11:18:04 +00:00
} ;
2010-10-28 05:50:39 +00:00
// Function: findDefs
//
// Returns:
// The document's <defs> element, create it first if necessary
2013-02-14 15:19:46 +00:00
svgedit . utilities . findDefs = function ( ) {
2013-02-14 19:11:30 +00:00
var svgElement = editorContext _ . getSVGContent ( ) ;
2013-02-16 15:02:26 +00:00
var defs = svgElement . getElementsByTagNameNS ( NS . SVG , 'defs' ) ;
2010-10-28 05:50:39 +00:00
if ( defs . length > 0 ) {
defs = defs [ 0 ] ;
2013-02-15 23:05:23 +00:00
} else {
2013-02-16 15:02:26 +00:00
defs = svgElement . ownerDocument . createElementNS ( NS . SVG , 'defs' ) ;
2013-02-14 15:19:46 +00:00
if ( svgElement . firstChild ) {
// first child is a comment, so call nextSibling
svgElement . insertBefore ( defs , svgElement . firstChild . nextSibling ) ;
} else {
svgElement . appendChild ( defs ) ;
}
2010-10-28 05:50:39 +00:00
}
return defs ;
} ;
2010-11-08 08:42:46 +00:00
// TODO(codedread): Consider moving the next to functions to bbox.js
2010-11-05 17:00:32 +00:00
// Function: svgedit.utilities.getPathBBox
2010-11-05 15:29:30 +00:00
// Get correct BBox for a path in Webkit
// Converted from code found here:
// http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
2013-02-15 23:05:23 +00:00
//
2010-11-05 15:29:30 +00:00
// Parameters:
// path - The path DOM element to get the BBox for
//
// Returns:
// A BBox-like object
2010-11-05 17:00:32 +00:00
svgedit . utilities . getPathBBox = function ( path ) {
2010-11-05 15:29:30 +00:00
var seglist = path . pathSegList ;
var tot = seglist . numberOfItems ;
2013-02-15 23:05:23 +00:00
2010-11-05 15:29:30 +00:00
var bounds = [ [ ] , [ ] ] ;
var start = seglist . getItem ( 0 ) ;
var P0 = [ start . x , start . y ] ;
2012-03-30 03:50:54 +00:00
2014-01-31 02:13:37 +00:00
var i ;
for ( i = 0 ; i < tot ; i ++ ) {
2010-11-05 15:29:30 +00:00
var seg = seglist . getItem ( i ) ;
2012-03-30 03:50:54 +00:00
2014-05-22 10:21:29 +00:00
if ( seg . x === undef ) { continue ; }
2012-03-30 03:50:54 +00:00
2010-11-05 15:29:30 +00:00
// Add actual points to limits
bounds [ 0 ] . push ( P0 [ 0 ] ) ;
bounds [ 1 ] . push ( P0 [ 1 ] ) ;
2013-02-15 23:05:23 +00:00
2014-05-22 10:21:29 +00:00
if ( seg . x1 ) {
2010-11-05 15:29:30 +00:00
var P1 = [ seg . x1 , seg . y1 ] ,
P2 = [ seg . x2 , seg . y2 ] ,
P3 = [ seg . x , seg . y ] ;
2014-01-31 02:13:37 +00:00
var j ;
for ( j = 0 ; j < 2 ; j ++ ) {
2010-11-05 15:29:30 +00:00
var calc = function ( t ) {
2013-02-15 23:05:23 +00:00
return Math . pow ( 1 - t , 3 ) * P0 [ j ]
2010-11-05 15:29:30 +00:00
+ 3 * Math . pow ( 1 - t , 2 ) * t * P1 [ j ]
2013-02-15 16:51:48 +00:00
+ 3 * ( 1 - t ) * Math . pow ( t , 2 ) * P2 [ j ]
2010-11-05 15:29:30 +00:00
+ Math . pow ( t , 3 ) * P3 [ j ] ;
} ;
var b = 6 * P0 [ j ] - 12 * P1 [ j ] + 6 * P2 [ j ] ;
var a = - 3 * P0 [ j ] + 9 * P1 [ j ] - 9 * P2 [ j ] + 3 * P3 [ j ] ;
var c = 3 * P1 [ j ] - 3 * P0 [ j ] ;
2013-02-15 23:05:23 +00:00
2014-01-31 02:13:37 +00:00
if ( a == 0 ) {
if ( b == 0 ) {
2010-11-05 15:29:30 +00:00
continue ;
}
var t = - c / b ;
2014-01-31 02:13:37 +00:00
if ( 0 < t && t < 1 ) {
2010-11-05 15:29:30 +00:00
bounds [ j ] . push ( calc ( t ) ) ;
}
continue ;
}
var b2ac = Math . pow ( b , 2 ) - 4 * c * a ;
2014-01-31 02:13:37 +00:00
if ( b2ac < 0 ) { continue ; }
2010-11-05 15:29:30 +00:00
var t1 = ( - b + Math . sqrt ( b2ac ) ) / ( 2 * a ) ;
2014-01-31 02:13:37 +00:00
if ( 0 < t1 && t1 < 1 ) { bounds [ j ] . push ( calc ( t1 ) ) ; }
2010-11-05 15:29:30 +00:00
var t2 = ( - b - Math . sqrt ( b2ac ) ) / ( 2 * a ) ;
2014-01-31 02:13:37 +00:00
if ( 0 < t2 && t2 < 1 ) { bounds [ j ] . push ( calc ( t2 ) ) ; }
2010-11-05 15:29:30 +00:00
}
P0 = P3 ;
} else {
bounds [ 0 ] . push ( seg . x ) ;
bounds [ 1 ] . push ( seg . y ) ;
}
}
2013-02-15 23:05:23 +00:00
2010-11-05 15:29:30 +00:00
var x = Math . min . apply ( null , bounds [ 0 ] ) ;
var w = Math . max . apply ( null , bounds [ 0 ] ) - x ;
var y = Math . min . apply ( null , bounds [ 1 ] ) ;
var h = Math . max . apply ( null , bounds [ 1 ] ) - y ;
return {
'x' : x ,
'y' : y ,
'width' : w ,
'height' : h
} ;
} ;
2011-02-09 21:32:53 +00:00
// Function: groupBBFix
// Get the given/selected element's bounding box object, checking for
// horizontal/vertical lines (see issue 717)
// Note that performance is currently terrible, so some way to improve would
// be great.
//
2013-02-15 23:05:23 +00:00
// Parameters:
2011-02-09 21:32:53 +00:00
// selected - Container or <use> DOM element
function groupBBFix ( selected ) {
if ( svgedit . browser . supportsHVLineContainerBBox ( ) ) {
2013-02-15 23:05:23 +00:00
try { return selected . getBBox ( ) ; } catch ( e ) { }
2011-02-09 21:32:53 +00:00
}
var ref = $ . data ( selected , 'ref' ) ;
var matched = null ;
2014-01-31 02:13:37 +00:00
var ret , copy ;
2013-02-15 23:05:23 +00:00
2011-02-09 21:32:53 +00:00
if ( ref ) {
2014-01-31 02:13:37 +00:00
copy = $ ( ref ) . children ( ) . clone ( ) . attr ( 'visibility' , 'hidden' ) ;
2011-02-09 21:32:53 +00:00
$ ( svgroot _ ) . append ( copy ) ;
matched = copy . filter ( 'line, path' ) ;
} else {
matched = $ ( selected ) . find ( 'line, path' ) ;
}
2013-02-15 23:05:23 +00:00
2011-02-09 21:32:53 +00:00
var issue = false ;
if ( matched . length ) {
matched . each ( function ( ) {
var bb = this . getBBox ( ) ;
if ( ! bb . width || ! bb . height ) {
issue = true ;
}
} ) ;
if ( issue ) {
var elems = ref ? copy : $ ( selected ) . children ( ) ;
2014-01-31 02:13:37 +00:00
ret = getStrokedBBox ( elems ) ; // getStrokedBBox defined in svgcanvas
2011-02-09 21:32:53 +00:00
} else {
ret = selected . getBBox ( ) ;
}
} else {
ret = selected . getBBox ( ) ;
}
if ( ref ) {
copy . remove ( ) ;
}
return ret ;
}
2010-11-05 17:00:32 +00:00
// Function: svgedit.utilities.getBBox
2010-11-05 15:29:30 +00:00
// Get the given/selected element's bounding box object, convert it to be more
// usable when necessary
//
// Parameters:
// elem - Optional DOM element to get the BBox for
2010-11-05 17:00:32 +00:00
svgedit . utilities . getBBox = function ( elem ) {
2010-12-02 17:14:24 +00:00
var selected = elem || editorContext _ . geSelectedElements ( ) [ 0 ] ;
2014-01-31 02:13:37 +00:00
if ( elem . nodeType != 1 ) { return null ; }
2010-11-05 15:29:30 +00:00
var ret = null ;
var elname = selected . nodeName ;
2013-02-15 23:05:23 +00:00
2011-02-09 16:30:11 +00:00
switch ( elname ) {
case 'text' :
if ( selected . textContent === '' ) {
selected . textContent = 'a' ; // Some character needed for the selector to use.
ret = selected . getBBox ( ) ;
selected . textContent = '' ;
} else {
2015-12-01 03:08:13 +00:00
if ( selected . getBBox ) { ret = selected . getBBox ( ) ; }
2011-02-09 16:30:11 +00:00
}
break ;
case 'path' :
if ( ! svgedit . browser . supportsPathBBox ( ) ) {
ret = svgedit . utilities . getPathBBox ( selected ) ;
} else {
2015-12-01 03:08:13 +00:00
if ( selected . getBBox ) { ret = selected . getBBox ( ) ; }
2011-02-09 16:30:11 +00:00
}
break ;
case 'g' :
case 'a' :
2011-02-09 21:32:53 +00:00
ret = groupBBFix ( selected ) ;
2011-02-09 16:30:11 +00:00
break ;
default :
2011-02-09 21:32:53 +00:00
if ( elname === 'use' ) {
ret = groupBBFix ( selected , true ) ;
}
2013-02-15 17:02:24 +00:00
if ( elname === 'use' || ( elname === 'foreignObject' && svgedit . browser . isWebkit ( ) ) ) {
2014-01-31 02:13:37 +00:00
if ( ! ret ) { ret = selected . getBBox ( ) ; }
2012-11-28 05:39:48 +00:00
// This is resolved in later versions of webkit, perhaps we should
// have a featured detection for correct 'use' behavior?
// ——————————
2015-12-11 06:34:03 +00:00
if ( ! svgedit . browser . isWebkit ( ) ) {
2011-02-23 15:56:14 +00:00
var bb = { } ;
bb . width = ret . width ;
bb . height = ret . height ;
bb . x = ret . x + parseFloat ( selected . getAttribute ( 'x' ) || 0 ) ;
bb . y = ret . y + parseFloat ( selected . getAttribute ( 'y' ) || 0 ) ;
ret = bb ;
2015-12-11 06:34:03 +00:00
}
2011-02-09 16:30:11 +00:00
} else if ( ~ visElems _arr . indexOf ( elname ) ) {
2015-12-01 03:08:13 +00:00
if ( selected ) { ret = selected . getBBox ( ) ; }
else {
2011-02-09 16:30:11 +00:00
// Check if element is child of a foreignObject
2013-02-15 17:02:24 +00:00
var fo = $ ( selected ) . closest ( 'foreignObject' ) ;
2015-12-01 03:08:13 +00:00
if ( fo . length ) {
if ( fo [ 0 ] . getBBox ) {
2011-02-09 16:30:11 +00:00
ret = fo [ 0 ] . getBBox ( ) ;
}
}
}
}
}
if ( ret ) {
ret = svgedit . utilities . bboxToObj ( ret ) ;
}
// get the bounding box from the DOM (which is in that element's coordinate system)
return ret ;
2010-11-05 15:29:30 +00:00
} ;
2016-04-22 16:24:52 +00:00
svgedit . utilities . getPathDFromSegments = function ( pathSegments ) {
var d = '' ;
$ . each ( pathSegments , function ( j , seg ) {
var i ;
var l = seg [ 0 ] , pts = seg [ 1 ] ;
d += l ;
for ( i = 0 ; i < pts . length ; i += 2 ) {
d += ( pts [ i ] + ',' + pts [ i + 1 ] ) + ' ' ;
}
} ) ;
return d
}
svgedit . utilities . getPathDFromElement = function ( elem ) {
// Possibly the cubed root of 6, but 1.81 works best
var num = 1.81 ;
var d , a , rx , ry ;
switch ( elem . tagName ) {
case 'ellipse' :
case 'circle' :
a = $ ( elem ) . attr ( [ 'rx' , 'ry' , 'cx' , 'cy' ] ) ;
var cx = a . cx , cy = a . cy ;
rx = a . rx ;
ry = a . ry ;
if ( elem . tagName == 'circle' ) {
rx = ry = $ ( elem ) . attr ( 'r' ) ;
}
d = svgedit . utilities . getPathDFromSegments ( [
[ 'M' , [ ( cx - rx ) , ( cy ) ] ] ,
[ 'C' , [ ( cx - rx ) , ( cy - ry / num ) , ( cx - rx / num ) , ( cy - ry ) , ( cx ) , ( cy - ry ) ] ] ,
[ 'C' , [ ( cx + rx / num ) , ( cy - ry ) , ( cx + rx ) , ( cy - ry / num ) , ( cx + rx ) , ( cy ) ] ] ,
[ 'C' , [ ( cx + rx ) , ( cy + ry / num ) , ( cx + rx / num ) , ( cy + ry ) , ( cx ) , ( cy + ry ) ] ] ,
[ 'C' , [ ( cx - rx / num ) , ( cy + ry ) , ( cx - rx ) , ( cy + ry / num ) , ( cx - rx ) , ( cy ) ] ] ,
[ 'Z' , [ ] ]
] ) ;
break ;
case 'path' :
d = elem . getAttribute ( 'd' ) ;
break ;
case 'line' :
a = $ ( elem ) . attr ( [ 'x1' , 'y1' , 'x2' , 'y2' ] ) ;
d = 'M' + a . x1 + ',' + a . y1 + 'L' + a . x2 + ',' + a . y2 ;
break ;
case 'polyline' :
d = 'M' + elem . getAttribute ( 'points' ) ;
break ;
case 'polygon' :
d = 'M' + elem . getAttribute ( 'points' ) + ' Z' ;
break ;
case 'rect' :
var r = $ ( elem ) . attr ( [ 'rx' , 'ry' ] ) ;
rx = r . rx ;
ry = r . ry ;
var b = elem . getBBox ( ) ;
var x = b . x , y = b . y , w = b . width , h = b . height ;
num = 4 - num ; // Why? Because!
if ( ! rx && ! ry ) {
// Regular rect
d = svgedit . utilities . getPathDFromSegments ( [
[ 'M' , [ x , y ] ] ,
[ 'L' , [ x + w , y ] ] ,
[ 'L' , [ x + w , y + h ] ] ,
[ 'L' , [ x , y + h ] ] ,
[ 'L' , [ x , y ] ] ,
[ 'Z' , [ ] ]
] ) ;
} else {
d = svgedit . utilities . getPathDFromSegments ( [
[ 'M' , [ x , y + ry ] ] ,
[ 'C' , [ x , y + ry / num , x + rx / num , y , x + rx , y ] ] ,
[ 'L' , [ x + w - rx , y ] ] ,
[ 'C' , [ x + w - rx / num , y , x + w , y + ry / num , x + w , y + ry ] ] ,
[ 'L' , [ x + w , y + h - ry ] ] ,
[ 'C' , [ x + w , y + h - ry / num , x + w - rx / num , y + h , x + w - rx , y + h ] ] ,
[ 'L' , [ x + rx , y + h ] ] ,
[ 'C' , [ x + rx / num , y + h , x , y + h - ry / num , x , y + h - ry ] ] ,
[ 'L' , [ x , y + ry ] ] ,
[ 'Z' , [ ] ]
] ) ;
}
break ;
default :
break ;
}
return d ;
} ;
svgedit . utilities . addAttributesForConvertToPath = function ( elem , attrs ) {
// TODO: make this list global so that we can properly maintain it
// TODO: what about @transform, @clip-rule, @fill-rule, etc?
$ . each ( [ 'marker-start' , 'marker-end' , 'marker-mid' , 'filter' , 'clip-path' ] , function ( ) {
if ( elem . getAttribute ( this ) ) {
attrs [ this ] = elem . getAttribute ( this ) ;
}
} ) ;
} ;
// Function: getBBoxOfElementAsPath
// Get the BBox of an element-as-path
//
// Parameters:
// elem - The DOM element to be probed
// addSvgElementFromJson - Function to add the path element to the current layer. See canvas.addSvgElementFromJso
// pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions.
//
// Returns:
// The resulting path's bounding box object.
svgedit . utilities . getBBoxOfElementAsPath = function ( elem , addSvgElementFromJson , pathActions ) {
var attrs = { }
// any attribute on the element not covered by the above
svgedit . utilities . addAttributesForConvertToPath ( elem , attrs )
var path = addSvgElementFromJson ( {
'element' : 'path' ,
'attr' : attrs
} ) ;
var eltrans = elem . getAttribute ( 'transform' ) ;
if ( eltrans ) {
path . setAttribute ( 'transform' , eltrans ) ;
}
var id = elem . id ;
var parent = elem . parentNode ;
if ( elem . nextSibling ) {
parent . insertBefore ( path , elem ) ;
} else {
parent . appendChild ( path ) ;
}
var d = svgedit . utilities . getPathDFromElement ( elem ) ;
if ( d )
path . setAttribute ( 'd' , d ) ;
else
path . parentNode . removeChild ( path ) ;
// Get the correct BBox of the new path, then discard it
pathActions . resetOrientation ( path ) ;
var bb = false ;
try {
bb = path . getBBox ( ) ;
} catch ( e ) {
// Firefox fails
}
path . parentNode . removeChild ( path ) ;
return bb ;
}
2016-04-22 17:36:10 +00:00
// Function: convertToPath
2016-04-22 16:24:52 +00:00
// Convert selected element to a path.
//
// Parameters:
// elem - The DOM element to be converted
// attrs - Apply attributes to new path. see canvas.convertToPath
// addSvgElementFromJson - Function to add the path element to the current layer. See canvas.addSvgElementFromJso
// pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions.
// clearSelection - see canvas.clearSelection
// addToSelection - see canvas.addToSelection
// history - see svgedit.history
// addCommandToHistory - see canvas.addCommandToHistory
//
// Returns:
2016-04-22 17:39:20 +00:00
// The converted path element or null if the DOM element was not recognized.
2016-04-22 16:24:52 +00:00
svgedit . utilities . convertToPath = function ( elem , attrs , addSvgElementFromJson , pathActions , clearSelection , addToSelection , history , addCommandToHistory ) {
var batchCmd = new history . BatchCommand ( 'Convert element to Path' ) ;
// any attribute on the element not covered by the above
// TODO: make this list global so that we can properly maintain it
// TODO: what about @transform, @clip-rule, @fill-rule, etc?
$ . each ( [ 'marker-start' , 'marker-end' , 'marker-mid' , 'filter' , 'clip-path' ] , function ( ) {
if ( elem . getAttribute ( this ) ) {
attrs [ this ] = elem . getAttribute ( this ) ;
}
} ) ;
var path = addSvgElementFromJson ( {
'element' : 'path' ,
'attr' : attrs
} ) ;
var eltrans = elem . getAttribute ( 'transform' ) ;
if ( eltrans ) {
path . setAttribute ( 'transform' , eltrans ) ;
}
var id = elem . id ;
var parent = elem . parentNode ;
if ( elem . nextSibling ) {
parent . insertBefore ( path , elem ) ;
} else {
parent . appendChild ( path ) ;
}
var d = svgedit . utilities . getPathDFromElement ( elem ) ;
if ( d ) {
path . setAttribute ( 'd' , d ) ;
// Replace the current element with the converted one
// Reorient if it has a matrix
if ( eltrans ) {
var tlist = svgedit . transformlist . getTransformList ( path ) ;
if ( svgedit . math . hasMatrixTransform ( tlist ) ) {
pathActions . resetOrientation ( path ) ;
}
}
var nextSibling = elem . nextSibling ;
batchCmd . addSubCommand ( new history . RemoveElementCommand ( elem , nextSibling , parent ) ) ;
batchCmd . addSubCommand ( new history . InsertElementCommand ( path ) ) ;
clearSelection ( ) ;
elem . parentNode . removeChild ( elem ) ;
path . setAttribute ( 'id' , id ) ;
path . removeAttribute ( 'visibility' ) ;
addToSelection ( [ path ] , true ) ;
addCommandToHistory ( batchCmd ) ;
return path ;
} else {
// the elem.tagName was not recognized, so no "d" attribute. Remove it, so we've haven't changed anything.
path . parentNode . removeChild ( path ) ;
return null ;
}
} ;
2016-04-24 20:43:20 +00:00
// Function: getBBoxWithTransform
// Get bounding box that includes any transforms.
//
// Parameters:
// elem - The DOM element to be converted
// addSvgElementFromJson - Function to add the path element to the current layer. See canvas.addSvgElementFromJson
// pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions.
//
// Returns:
// A single bounding box object
svgedit . utilities . getBBoxWithTransform = function ( elem , addSvgElementFromJson , pathActions ) {
// TODO: Fix issue with rotated groups. Currently they work
// fine in FF, but not in other browsers (same problem mentioned
// in Issue 339 comment #2).
2016-04-22 16:24:52 +00:00
2016-04-24 20:43:20 +00:00
var bb = svgedit . utilities . getBBox ( elem ) ;
if ( ! bb ) {
return null ;
}
var tlist = svgedit . transformlist . getTransformList ( elem )
var angle = svgedit . utilities . getRotationAngleFromTransformList ( tlist ) ;
if ( angle || svgedit . math . hasMatrixTransform ( tlist ) ) {
var good _bb = false ;
// Get the BBox from the raw path for these elements
// TODO: why ellipse and not circle
var elemNames = [ 'ellipse' , 'path' , 'line' , 'polyline' , 'polygon' ] ;
if ( elemNames . indexOf ( elem . tagName ) >= 0 ) {
bb = good _bb = svgedit . utilities . getBBoxOfElementAsPath ( elem , addSvgElementFromJson , pathActions ) ;
} else if ( elem . tagName == 'rect' ) {
// Look for radius
var rx = elem . getAttribute ( 'rx' ) ;
var ry = elem . getAttribute ( 'ry' ) ;
if ( rx || ry ) {
bb = good _bb = svgedit . utilities . getBBoxOfElementAsPath ( elem , addSvgElementFromJson , pathActions ) ;
}
}
if ( ! good _bb ) {
var matrix = svgedit . math . transformListToTransform ( tlist ) . matrix ;
bb = svgedit . math . transformBox ( bb . x , bb . y , bb . width , bb . height , matrix ) . aabox ;
// Old technique that was exceedingly slow with large documents.
//
// Accurate way to get BBox of rotated element in Firefox:
// Put element in group and get its BBox
//
// Must use clone else FF freaks out
//var clone = elem.cloneNode(true);
//var g = document.createElementNS(NS.SVG, 'g');
//var parent = elem.parentNode;
//parent.appendChild(g);
//g.appendChild(clone);
//var bb2 = svgedit.utilities.bboxToObj(g.getBBox());
//parent.removeChild(g);
}
}
return bb ;
} ;
// TODO: This is problematic with large stroke-width and, for example, a single horizontal line. The calculated BBox extends way beyond left and right sides.
function getStrokeOffsetForBBox ( elem ) {
var sw = elem . getAttribute ( 'stroke-width' ) ;
return ( ! isNaN ( sw ) && elem . getAttribute ( 'stroke' ) != 'none' ) ? sw / 2 : 0 ;
} ;
// Function: getStrokedBBox
// Get the bounding box for one or more stroked and/or transformed elements
2010-11-05 15:59:30 +00:00
//
// Parameters:
2016-04-24 20:43:20 +00:00
// elems - Array with DOM elements to check
// addSvgElementFromJson - Function to add the path element to the current layer. See canvas.addSvgElementFromJson
// pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions.
//
// Returns:
// A single bounding box object
svgedit . utilities . getStrokedBBox = function ( elems , addSvgElementFromJson , pathActions ) {
if ( ! elems || ! elems . length ) { return false ; }
var full _bb ;
$ . each ( elems , function ( ) {
if ( full _bb ) { return ; }
if ( ! this . parentNode ) { return ; }
full _bb = svgedit . utilities . getBBoxWithTransform ( this , addSvgElementFromJson , pathActions ) ;
} ) ;
// This shouldn't ever happen...
if ( full _bb === undefined ) { return null ; }
// full_bb doesn't include the stoke, so this does no good!
// if (elems.length == 1) return full_bb;
var max _x = full _bb . x + full _bb . width ;
var max _y = full _bb . y + full _bb . height ;
var min _x = full _bb . x ;
var min _y = full _bb . y ;
// If only one elem, don't call the potentially slow getBBoxWithTransform method again.
if ( elems . length === 1 ) {
var offset = getStrokeOffsetForBBox ( elems [ 0 ] ) ;
min _x -= offset ;
min _y -= offset ;
max _x += offset ;
max _y += offset ;
} else {
$ . each ( elems , function ( i , elem ) {
var cur _bb = svgedit . utilities . getBBoxWithTransform ( elem , addSvgElementFromJson , pathActions ) ;
if ( cur _bb ) {
var offset = getStrokeOffsetForBBox ( elem ) ;
min _x = Math . min ( min _x , cur _bb . x - offset ) ;
min _y = Math . min ( min _y , cur _bb . y - offset ) ;
// TODO: The old code had this test for max, but not min. I suspect this test should be for both min and max
if ( elem . nodeType == 1 ) {
max _x = Math . max ( max _x , cur _bb . x + cur _bb . width + offset ) ;
max _y = Math . max ( max _y , cur _bb . y + cur _bb . height + offset ) ;
}
}
} ) ;
}
full _bb . x = min _x ;
full _bb . y = min _y ;
full _bb . width = max _x - min _x ;
full _bb . height = max _y - min _y ;
return full _bb ;
} ;
// Function: svgedit.utilities.getRotationAngleFromTransformList
// Get the rotation angle of the given transform list.
//
// Parameters:
// tlist - List of transforms
2010-11-05 15:59:30 +00:00
// to_rad - Boolean that when true returns the value in radians rather than degrees
//
// Returns:
// Float with the angle in degrees or radians
2016-04-24 20:43:20 +00:00
svgedit . utilities . getRotationAngleFromTransformList = function ( tlist , to _rad ) {
2014-01-31 02:13:37 +00:00
if ( ! tlist ) { return 0 ; } // <svg> elements have no tlist
2010-11-05 15:59:30 +00:00
var N = tlist . numberOfItems ;
2014-01-31 02:13:37 +00:00
var i ;
for ( i = 0 ; i < N ; ++ i ) {
2010-11-05 15:59:30 +00:00
var xform = tlist . getItem ( i ) ;
if ( xform . type == 4 ) {
return to _rad ? xform . angle * Math . PI / 180.0 : xform . angle ;
}
}
return 0.0 ;
} ;
2010-11-05 15:29:30 +00:00
2016-04-24 20:43:20 +00:00
// Function: svgedit.utilities.getRotationAngle
// Get the rotation angle of the given/selected DOM element
//
// Parameters:
// elem - Optional DOM element to get the angle for
// to_rad - Boolean that when true returns the value in radians rather than degrees
//
// Returns:
// Float with the angle in degrees or radians
svgedit . utilities . getRotationAngle = function ( elem , to _rad ) {
var selected = elem || editorContext _ . getSelectedElements ( ) [ 0 ] ;
// find the rotation transform (if any) and set it
var tlist = svgedit . transformlist . getTransformList ( selected ) ;
return svgedit . utilities . getRotationAngleFromTransformList ( tlist , to _rad )
} ;
2013-02-14 15:19:46 +00:00
// Function getRefElem
// Get the reference element associated with the given attribute value
//
// Parameters:
// attrVal - The attribute value as a string
2013-02-15 23:05:23 +00:00
svgedit . utilities . getRefElem = function ( attrVal ) {
2013-02-14 15:19:46 +00:00
return svgedit . utilities . getElem ( svgedit . utilities . getUrlFromAttr ( attrVal ) . substr ( 1 ) ) ;
} ;
2011-02-04 08:02:46 +00:00
// Function: getElem
// Get a DOM element by ID within the SVG root element.
//
// Parameters:
// id - String with the element's new ID
if ( svgedit . browser . supportsSelectors ( ) ) {
svgedit . utilities . getElem = function ( id ) {
// querySelector lookup
return svgroot _ . querySelector ( '#' + id ) ;
} ;
} else if ( svgedit . browser . supportsXpath ( ) ) {
svgedit . utilities . getElem = function ( id ) {
// xpath lookup
return domdoc _ . evaluate (
'svg:svg[@id="svgroot"]//svg:*[@id="' + id + '"]' ,
2013-02-15 23:05:23 +00:00
domcontainer _ ,
2013-02-16 15:02:26 +00:00
function ( ) { return svgedit . NS . SVG ; } ,
2011-02-04 08:02:46 +00:00
9 ,
null ) . singleNodeValue ;
} ;
} else {
svgedit . utilities . getElem = function ( id ) {
// jQuery lookup: twice as slow as xpath in FF
return $ ( svgroot _ ) . find ( '[id=' + id + ']' ) [ 0 ] ;
} ;
}
// Function: assignAttributes
// Assigns multiple attributes to an element.
//
// Parameters:
// node - DOM element to apply new attribute values to
// attrs - Object with attribute keys/values
// suspendLength - Optional integer of milliseconds to suspend redraw
// unitCheck - Boolean to indicate the need to use svgedit.units.setUnitAttr
svgedit . utilities . assignAttributes = function ( node , attrs , suspendLength , unitCheck ) {
2014-01-31 02:13:37 +00:00
var i ;
for ( i in attrs ) {
2013-02-16 15:02:26 +00:00
var ns = ( i . substr ( 0 , 4 ) === 'xml:' ? NS . XML :
i . substr ( 0 , 6 ) === 'xlink:' ? NS . XLINK : null ) ;
2013-02-15 23:05:23 +00:00
2011-02-04 08:02:46 +00:00
if ( ns ) {
node . setAttributeNS ( ns , i , attrs [ i ] ) ;
} else if ( ! unitCheck ) {
node . setAttribute ( i , attrs [ i ] ) ;
} else {
svgedit . units . setUnitAttr ( node , i , attrs [ i ] ) ;
}
}
} ;
2011-02-10 04:10:03 +00:00
// Function: cleanupElement
// Remove unneeded (default) attributes, makes resulting SVG smaller
//
// Parameters:
// element - DOM element to clean up
svgedit . utilities . cleanupElement = function ( element ) {
var defaults = {
'fill-opacity' : 1 ,
'stop-opacity' : 1 ,
'opacity' : 1 ,
'stroke' : 'none' ,
'stroke-dasharray' : 'none' ,
'stroke-linejoin' : 'miter' ,
'stroke-linecap' : 'butt' ,
'stroke-opacity' : 1 ,
'stroke-width' : 1 ,
2016-02-25 08:05:50 +00:00
'rx' : 0 ,
'ry' : 0
2013-02-19 11:18:04 +00:00
} ;
2013-02-15 23:05:23 +00:00
2016-02-26 08:46:32 +00:00
if ( element . nodeName === 'ellipse' ) {
2016-02-25 08:03:20 +00:00
// Ellipse elements requires rx and ry attributes
delete defaults . rx ;
delete defaults . ry ;
}
2014-01-31 02:13:37 +00:00
var attr ;
for ( attr in defaults ) {
2011-02-10 04:10:03 +00:00
var val = defaults [ attr ] ;
if ( element . getAttribute ( attr ) == val ) {
element . removeAttribute ( attr ) ;
}
}
} ;
2013-02-17 04:58:04 +00:00
// Function: snapToGrid
// round value to for snapping
// NOTE: This function did not move to svgutils.js since it depends on curConfig.
svgedit . utilities . snapToGrid = function ( value ) {
var stepSize = editorContext _ . getSnappingStep ( ) ;
var unit = editorContext _ . getBaseUnit ( ) ;
if ( unit !== "px" ) {
stepSize *= svgedit . units . getTypeMap ( ) [ unit ] ;
}
value = Math . round ( value / stepSize ) * stepSize ;
return value ;
} ;
2014-02-19 01:37:21 +00:00
svgedit . utilities . preg _quote = function ( str , delimiter ) {
// From: http://phpjs.org/functions
return String ( str ) . replace ( new RegExp ( '[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + ( delimiter || '' ) + '-]' , 'g' ) , '\\$&' ) ;
} ;
2014-05-22 10:21:29 +00:00
/ * *
* @ param { string } globalCheck A global which can be used to determine if the script is already loaded
* @ param { array } scripts An array of scripts to preload ( in order )
* @ param { function } cb The callback to execute upon load .
* /
svgedit . utilities . executeAfterLoads = function ( globalCheck , scripts , cb ) {
return function ( ) {
var args = arguments ;
function endCallback ( ) {
cb . apply ( null , args ) ;
}
if ( window [ globalCheck ] ) {
endCallback ( ) ;
}
else {
scripts . reduceRight ( function ( oldFunc , script ) {
return function ( ) {
$ . getScript ( script , oldFunc ) ;
} ;
} , endCallback ) ( ) ;
}
} ;
} ;
svgedit . utilities . buildCanvgCallback = function ( callCanvg ) {
return svgedit . utilities . executeAfterLoads ( 'canvg' , [ 'canvg/rgbcolor.js' , 'canvg/canvg.js' ] , callCanvg ) ;
} ;
svgedit . utilities . buildJSPDFCallback = function ( callJSPDF ) {
return svgedit . utilities . executeAfterLoads ( 'RGBColor' , [ 'canvg/rgbcolor.js' ] , function ( ) {
var arr = [ ] ;
if ( ! RGBColor || RGBColor . ok === undef ) { // It's not our RGBColor, so we'll need to load it
arr . push ( 'canvg/rgbcolor.js' ) ;
}
svgedit . utilities . executeAfterLoads ( 'jsPDF' , arr . concat ( 'jspdf/underscore-min.js' , 'jspdf/jspdf.min.js' , 'jspdf/jspdf.plugin.svgToPdf.js' ) , callJSPDF ) ( ) ;
} ) ;
} ;
2014-01-31 02:13:37 +00:00
} ( ) ) ;