Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
VisualDL
提交
989af238
V
VisualDL
项目概览
PaddlePaddle
/
VisualDL
大约 1 年 前同步成功
通知
88
Star
4655
Fork
642
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
5
Wiki
分析
仓库
DevOps
项目成员
Pages
V
VisualDL
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
5
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
未验证
提交
989af238
编写于
4月 11, 2018
作者:
D
daminglu
提交者:
GitHub
4月 11, 2018
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Added a JS lib to help download graph image (#387)
上级
42561cea
变更
3
显示空白变更内容
内联
并排
Showing
3 changed file
with
506 addition
and
27 deletion
+506
-27
frontend/package.json
frontend/package.json
+0
-2
frontend/src/graph/ui/Chart.vue
frontend/src/graph/ui/Chart.vue
+5
-25
frontend/src/graph/ui/svgToPngDownloadHelper.js
frontend/src/graph/ui/svgToPngDownloadHelper.js
+501
-0
未找到文件。
frontend/package.json
浏览文件 @
989af238
...
...
@@ -14,8 +14,6 @@
"dependencies"
:
{
"axios"
:
"^0.16.1"
,
"csshint"
:
"^0.3.3"
,
"cytoscape"
:
"^3.2.11"
,
"cytoscape-dagre"
:
"^2.2.0"
,
"d3"
:
"^4.7.4"
,
"d3-format"
:
"^1.2.1"
,
"dagre"
:
"^0.8.2"
,
...
...
frontend/src/graph/ui/Chart.vue
浏览文件 @
989af238
...
...
@@ -11,6 +11,10 @@
// service
import
{
getPluginGraphsGraph
}
from
'
../../service
'
;
// The name 'svgToPngDownloadHelper' is just a placeholder.
// Loading the JS lib file will bind saveSvgAsPng to window.
import
*
as
svgToPngDownloadHelper
from
'
./svgToPngDownloadHelper.js
'
;
// for d3 drawing
import
*
as
d3
from
'
d3
'
;
...
...
@@ -31,32 +35,8 @@ export default {
watch
:
{
doDownload
:
function
(
val
)
{
if
(
this
.
doDownload
)
{
// TODO(daming-lu): .svg is ugly and colorless.
let
svg
=
this
.
$refs
.
graphSvg
;
// get svg source.
let
serializer
=
new
XMLSerializer
();
let
source
=
serializer
.
serializeToString
(
svg
);
// add name spaces.
if
(
!
source
.
match
(
/^<svg
[^
>
]
+xmlns="http
\:\/\/
www
\.
w3
\.
org
\/
2000
\/
svg"/
))
{
source
=
source
.
replace
(
/^<svg/
,
'
<svg xmlns="http://www.w3.org/2000/svg"
'
);
}
if
(
!
source
.
match
(
/^<svg
[^
>
]
+"http
\:\/\/
www
\.
w3
\.
org
\/
1999
\/
xlink"/
))
{
source
=
source
.
replace
(
/^<svg/
,
'
<svg xmlns:xlink="http://www.w3.org/1999/xlink"
'
);
}
// add xml declaration
source
=
'
<?xml version="1.0" standalone="no"?>
\r\n
'
+
source
;
// convert svg source to URI data scheme.
let
url
=
'
data:image/svg+xml;charset=utf-8,
'
+
encodeURIComponent
(
source
);
let
a
=
document
.
createElement
(
'
a
'
);
a
.
download
=
'
graph.svg
'
;
a
.
href
=
url
;
a
.
click
();
saveSvgAsPng
(
svg
,
"
graph.png
"
,
{
scale
:
1.0
});
this
.
$emit
(
'
triggerDownload
'
,
false
);
}
},
...
...
frontend/src/graph/ui/svgToPngDownloadHelper.js
0 → 100644
浏览文件 @
989af238
// URL for this library : https://github.com/exupero/saveSvgAsPng
// Blog about it: https://spin.atomicobject.com/2014/01/21/convert-svg-to-png/
(
function
()
{
var
out$
=
window
;
var
doctype
=
'
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [<!ENTITY nbsp " ">]>
'
;
function
isElement
(
obj
)
{
return
obj
instanceof
HTMLElement
||
obj
instanceof
SVGElement
;
}
function
requireDomNode
(
el
)
{
if
(
!
isElement
(
el
))
{
throw
new
Error
(
'
an HTMLElement or SVGElement is required; got
'
+
el
);
}
}
function
isExternal
(
url
)
{
return
url
&&
url
.
lastIndexOf
(
'
http
'
,
0
)
==
0
&&
url
.
lastIndexOf
(
window
.
location
.
host
)
==
-
1
;
}
function
inlineImages
(
el
,
callback
)
{
requireDomNode
(
el
);
var
images
=
el
.
querySelectorAll
(
'
image
'
),
left
=
images
.
length
,
checkDone
=
function
()
{
if
(
left
===
0
)
{
callback
();
}
};
checkDone
();
for
(
var
i
=
0
;
i
<
images
.
length
;
i
++
)
{
(
function
(
image
)
{
var
href
=
image
.
getAttributeNS
(
"
http://www.w3.org/1999/xlink
"
,
"
href
"
);
var
canvas
=
document
.
createElement
(
'
canvas
'
);
var
ctx
=
canvas
.
getContext
(
'
2d
'
);
var
img
=
new
Image
();
img
.
crossOrigin
=
"
anonymous
"
;
href
=
href
||
image
.
getAttribute
(
'
href
'
);
if
(
isExternal
(
href
))
{
href
+=
(
href
.
indexOf
(
'
?
'
)
===
-
1
?
'
?
'
:
'
&
'
)
+
'
t=
'
+
(
new
Date
().
valueOf
());
}
if
(
href
)
{
img
.
src
=
href
;
img
.
onload
=
function
()
{
canvas
.
width
=
img
.
width
;
canvas
.
height
=
img
.
height
;
ctx
.
drawImage
(
img
,
0
,
0
);
image
.
setAttributeNS
(
"
http://www.w3.org/1999/xlink
"
,
"
href
"
,
canvas
.
toDataURL
(
'
image/png
'
));
left
--
;
checkDone
();
}
img
.
onerror
=
function
()
{
console
.
log
(
"
Could not load
"
+
href
);
left
--
;
checkDone
();
}
}
else
{
left
--
;
checkDone
();
}
})(
images
[
i
]);
}
}
function
styles
(
el
,
options
,
cssLoadedCallback
)
{
var
selectorRemap
=
options
.
selectorRemap
;
var
modifyStyle
=
options
.
modifyStyle
;
var
modifyCss
=
options
.
modifyCss
||
function
(
selector
,
properties
)
{
var
selector
=
selectorRemap
?
selectorRemap
(
selector
)
:
selector
;
var
cssText
=
modifyStyle
?
modifyStyle
(
properties
)
:
properties
;
return
selector
+
"
{
"
+
cssText
+
"
}
\n
"
;
};
var
css
=
""
;
// Each font that has an external link is saved into queue, and processed asynchronously.
var
fontsQueue
=
[];
var
sheets
=
document
.
styleSheets
;
for
(
var
i
=
0
;
i
<
sheets
.
length
;
i
++
)
{
try
{
var
rules
=
sheets
[
i
].
cssRules
;
}
catch
(
e
)
{
console
.
warn
(
"
Stylesheet could not be loaded:
"
+
sheets
[
i
].
href
);
continue
;
}
if
(
rules
!=
null
)
{
for
(
var
j
=
0
,
match
;
j
<
rules
.
length
;
j
++
,
match
=
null
)
{
var
rule
=
rules
[
j
];
if
(
typeof
(
rule
.
style
)
!=
"
undefined
"
)
{
var
selectorText
;
try
{
selectorText
=
rule
.
selectorText
;
}
catch
(
err
)
{
console
.
warn
(
'
The following CSS rule has an invalid selector: "
'
+
rule
+
'
"
'
,
err
);
}
try
{
if
(
selectorText
)
{
match
=
el
.
querySelector
(
selectorText
)
||
(
el
.
parentNode
&&
el
.
parentNode
.
querySelector
(
selectorText
));
}
}
catch
(
err
)
{
console
.
warn
(
'
Invalid CSS selector "
'
+
selectorText
+
'
"
'
,
err
);
}
if
(
match
)
{
css
+=
modifyCss
(
rule
.
selectorText
,
rule
.
style
.
cssText
);
}
else
if
(
rule
.
cssText
.
match
(
/^@font-face/
))
{
// below we are trying to find matches to external link. E.g.
// @font-face {
// // ...
// src: local('Abel'), url(https://fonts.gstatic.com/s/abel/v6/UzN-iejR1VoXU2Oc-7LsbvesZW2xOQ-xsNqO47m55DA.woff2);
// }
//
// This regex will save extrnal link into first capture group
var
fontUrlRegexp
=
/url
\([
"'
]?(
.+
?)[
"'
]?\)
/
;
// TODO: This needs to be changed to support multiple url declarations per font.
var
fontUrlMatch
=
rule
.
cssText
.
match
(
fontUrlRegexp
);
var
externalFontUrl
=
(
fontUrlMatch
&&
fontUrlMatch
[
1
])
||
''
;
var
fontUrlIsDataURI
=
externalFontUrl
.
match
(
/^data:/
);
if
(
fontUrlIsDataURI
)
{
// We should ignore data uri - they are already embedded
externalFontUrl
=
''
;
}
if
(
externalFontUrl
===
'
about:blank
'
)
{
// no point trying to load this
externalFontUrl
=
''
;
}
if
(
externalFontUrl
)
{
// okay, we are lucky. We can fetch this font later
//handle url if relative
if
(
externalFontUrl
.
startsWith
(
'
../
'
))
{
externalFontUrl
=
sheets
[
i
].
href
+
'
/../
'
+
externalFontUrl
}
else
if
(
externalFontUrl
.
startsWith
(
'
./
'
))
{
externalFontUrl
=
sheets
[
i
].
href
+
'
/.
'
+
externalFontUrl
}
fontsQueue
.
push
({
text
:
rule
.
cssText
,
// Pass url regex, so that once font is downladed, we can run `replace()` on it
fontUrlRegexp
:
fontUrlRegexp
,
format
:
getFontMimeTypeFromUrl
(
externalFontUrl
),
url
:
externalFontUrl
});
}
else
{
// otherwise, use previous logic
css
+=
rule
.
cssText
+
'
\n
'
;
}
}
}
}
}
}
// Now all css is processed, it's time to handle scheduled fonts
processFontQueue
(
fontsQueue
);
function
getFontMimeTypeFromUrl
(
fontUrl
)
{
var
supportedFormats
=
{
'
woff2
'
:
'
font/woff2
'
,
'
woff
'
:
'
font/woff
'
,
'
otf
'
:
'
application/x-font-opentype
'
,
'
ttf
'
:
'
application/x-font-ttf
'
,
'
eot
'
:
'
application/vnd.ms-fontobject
'
,
'
sfnt
'
:
'
application/font-sfnt
'
,
'
svg
'
:
'
image/svg+xml
'
};
var
extensions
=
Object
.
keys
(
supportedFormats
);
for
(
var
i
=
0
;
i
<
extensions
.
length
;
++
i
)
{
var
extension
=
extensions
[
i
];
// TODO: This is not bullet proof, it needs to handle edge cases...
if
(
fontUrl
.
indexOf
(
'
.
'
+
extension
)
>
0
)
{
return
supportedFormats
[
extension
];
}
}
// If you see this error message, you probably need to update code above.
console
.
error
(
'
Unknown font format for
'
+
fontUrl
+
'
; Fonts may not be working correctly
'
);
return
'
application/octet-stream
'
;
}
function
processFontQueue
(
queue
)
{
if
(
queue
.
length
>
0
)
{
// load fonts one by one until we have anything in the queue:
var
font
=
queue
.
pop
();
processNext
(
font
);
}
else
{
// no more fonts to load.
cssLoadedCallback
(
css
);
}
function
processNext
(
font
)
{
// TODO: This could benefit from caching.
var
oReq
=
new
XMLHttpRequest
();
oReq
.
addEventListener
(
'
load
'
,
fontLoaded
);
oReq
.
addEventListener
(
'
error
'
,
transferFailed
);
oReq
.
addEventListener
(
'
abort
'
,
transferFailed
);
oReq
.
open
(
'
GET
'
,
font
.
url
);
oReq
.
responseType
=
'
arraybuffer
'
;
oReq
.
send
();
function
fontLoaded
()
{
// TODO: it may be also worth to wait until fonts are fully loaded before
// attempting to rasterize them. (e.g. use https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet )
var
fontBits
=
oReq
.
response
;
var
fontInBase64
=
arrayBufferToBase64
(
fontBits
);
updateFontStyle
(
font
,
fontInBase64
);
}
function
transferFailed
(
e
)
{
console
.
warn
(
'
Failed to load font from:
'
+
font
.
url
);
console
.
warn
(
e
)
css
+=
font
.
text
+
'
\n
'
;
processFontQueue
(
queue
);
}
function
updateFontStyle
(
font
,
fontInBase64
)
{
var
dataUrl
=
'
url("data:
'
+
font
.
format
+
'
;base64,
'
+
fontInBase64
+
'
")
'
;
css
+=
font
.
text
.
replace
(
font
.
fontUrlRegexp
,
dataUrl
)
+
'
\n
'
;
// schedule next font download on next tick.
setTimeout
(
function
()
{
processFontQueue
(
queue
)
},
0
);
}
}
}
function
arrayBufferToBase64
(
buffer
)
{
var
binary
=
''
;
var
bytes
=
new
Uint8Array
(
buffer
);
var
len
=
bytes
.
byteLength
;
for
(
var
i
=
0
;
i
<
len
;
i
++
)
{
binary
+=
String
.
fromCharCode
(
bytes
[
i
]);
}
return
window
.
btoa
(
binary
);
}
}
function
getDimension
(
el
,
clone
,
dim
)
{
var
v
=
(
el
.
viewBox
&&
el
.
viewBox
.
baseVal
&&
el
.
viewBox
.
baseVal
[
dim
])
||
(
clone
.
getAttribute
(
dim
)
!==
null
&&
!
clone
.
getAttribute
(
dim
).
match
(
/%$/
)
&&
parseInt
(
clone
.
getAttribute
(
dim
)))
||
el
.
getBoundingClientRect
()[
dim
]
||
parseInt
(
clone
.
style
[
dim
])
||
parseInt
(
window
.
getComputedStyle
(
el
).
getPropertyValue
(
dim
));
return
(
typeof
v
===
'
undefined
'
||
v
===
null
||
isNaN
(
parseFloat
(
v
)))
?
0
:
v
;
}
function
reEncode
(
data
)
{
data
=
encodeURIComponent
(
data
);
data
=
data
.
replace
(
/%
([
0-9A-F
]{2})
/g
,
function
(
match
,
p1
)
{
var
c
=
String
.
fromCharCode
(
'
0x
'
+
p1
);
return
c
===
'
%
'
?
'
%25
'
:
c
;
});
return
decodeURIComponent
(
data
);
}
out$
.
prepareSvg
=
function
(
el
,
options
,
cb
)
{
requireDomNode
(
el
);
options
=
options
||
{};
options
.
scale
=
options
.
scale
||
1
;
options
.
responsive
=
options
.
responsive
||
false
;
var
xmlns
=
"
http://www.w3.org/2000/xmlns/
"
;
inlineImages
(
el
,
function
()
{
var
outer
=
document
.
createElement
(
"
div
"
);
var
clone
=
el
.
cloneNode
(
true
);
var
width
,
height
;
if
(
el
.
tagName
==
'
svg
'
)
{
width
=
options
.
width
||
getDimension
(
el
,
clone
,
'
width
'
);
height
=
options
.
height
||
getDimension
(
el
,
clone
,
'
height
'
);
}
else
if
(
el
.
getBBox
)
{
var
box
=
el
.
getBBox
();
width
=
box
.
x
+
box
.
width
;
height
=
box
.
y
+
box
.
height
;
clone
.
setAttribute
(
'
transform
'
,
clone
.
getAttribute
(
'
transform
'
).
replace
(
/translate
\(
.*
?\)
/
,
''
));
var
svg
=
document
.
createElementNS
(
'
http://www.w3.org/2000/svg
'
,
'
svg
'
)
svg
.
appendChild
(
clone
)
clone
=
svg
;
}
else
{
console
.
error
(
'
Attempted to render non-SVG element
'
,
el
);
return
;
}
clone
.
setAttribute
(
"
version
"
,
"
1.1
"
);
if
(
!
clone
.
getAttribute
(
'
xmlns
'
))
{
clone
.
setAttributeNS
(
xmlns
,
"
xmlns
"
,
"
http://www.w3.org/2000/svg
"
);
}
if
(
!
clone
.
getAttribute
(
'
xmlns:xlink
'
))
{
clone
.
setAttributeNS
(
xmlns
,
"
xmlns:xlink
"
,
"
http://www.w3.org/1999/xlink
"
);
}
if
(
options
.
responsive
)
{
clone
.
removeAttribute
(
'
width
'
);
clone
.
removeAttribute
(
'
height
'
);
clone
.
setAttribute
(
'
preserveAspectRatio
'
,
'
xMinYMin meet
'
);
}
else
{
clone
.
setAttribute
(
"
width
"
,
width
*
options
.
scale
);
clone
.
setAttribute
(
"
height
"
,
height
*
options
.
scale
);
}
clone
.
setAttribute
(
"
viewBox
"
,
[
options
.
left
||
0
,
options
.
top
||
0
,
width
,
height
].
join
(
"
"
));
var
fos
=
clone
.
querySelectorAll
(
'
foreignObject > *
'
);
for
(
var
i
=
0
;
i
<
fos
.
length
;
i
++
)
{
if
(
!
fos
[
i
].
getAttribute
(
'
xmlns
'
))
{
fos
[
i
].
setAttributeNS
(
xmlns
,
"
xmlns
"
,
"
http://www.w3.org/1999/xhtml
"
);
}
}
outer
.
appendChild
(
clone
);
// In case of custom fonts we need to fetch font first, and then inline
// its url into data-uri format (encode as base64). That's why style
// processing is done asynchonously. Once all inlining is finshed
// cssLoadedCallback() is called.
styles
(
el
,
options
,
cssLoadedCallback
);
function
cssLoadedCallback
(
css
)
{
// here all fonts are inlined, so that we can render them properly.
var
s
=
document
.
createElement
(
'
style
'
);
s
.
setAttribute
(
'
type
'
,
'
text/css
'
);
s
.
innerHTML
=
"
<![CDATA[
\n
"
+
css
+
"
\n
]]>
"
;
var
defs
=
document
.
createElement
(
'
defs
'
);
defs
.
appendChild
(
s
);
clone
.
insertBefore
(
defs
,
clone
.
firstChild
);
if
(
cb
)
{
var
outHtml
=
outer
.
innerHTML
;
outHtml
=
outHtml
.
replace
(
/NS
\d
+:href/gi
,
'
xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href
'
);
cb
(
outHtml
,
width
,
height
);
}
}
});
}
out$
.
svgAsDataUri
=
function
(
el
,
options
,
cb
)
{
out$
.
prepareSvg
(
el
,
options
,
function
(
svg
)
{
var
uri
=
'
data:image/svg+xml;base64,
'
+
window
.
btoa
(
reEncode
(
doctype
+
svg
));
if
(
cb
)
{
cb
(
uri
);
}
});
}
out$
.
svgAsPngUri
=
function
(
el
,
options
,
cb
)
{
requireDomNode
(
el
);
options
=
options
||
{};
options
.
encoderType
=
options
.
encoderType
||
'
image/png
'
;
options
.
encoderOptions
=
options
.
encoderOptions
||
0.8
;
var
convertToPng
=
function
(
src
,
w
,
h
)
{
var
canvas
=
document
.
createElement
(
'
canvas
'
);
var
context
=
canvas
.
getContext
(
'
2d
'
);
canvas
.
width
=
w
;
canvas
.
height
=
h
;
var
pixelRatio
=
window
.
devicePixelRatio
||
1
;
canvas
.
style
.
width
=
canvas
.
width
+
'
px
'
;
canvas
.
style
.
height
=
canvas
.
height
+
'
px
'
;
canvas
.
width
*=
pixelRatio
;
canvas
.
height
*=
pixelRatio
;
context
.
setTransform
(
pixelRatio
,
0
,
0
,
pixelRatio
,
0
,
0
);
if
(
options
.
canvg
)
{
options
.
canvg
(
canvas
,
src
);
}
else
{
context
.
drawImage
(
src
,
0
,
0
);
}
if
(
options
.
backgroundColor
){
context
.
globalCompositeOperation
=
'
destination-over
'
;
context
.
fillStyle
=
options
.
backgroundColor
;
context
.
fillRect
(
0
,
0
,
canvas
.
width
,
canvas
.
height
);
}
var
png
;
try
{
png
=
canvas
.
toDataURL
(
options
.
encoderType
,
options
.
encoderOptions
);
}
catch
(
e
)
{
if
((
typeof
SecurityError
!==
'
undefined
'
&&
e
instanceof
SecurityError
)
||
e
.
name
==
"
SecurityError
"
)
{
console
.
error
(
"
Rendered SVG images cannot be downloaded in this browser.
"
);
return
;
}
else
{
throw
e
;
}
}
cb
(
png
);
}
if
(
options
.
canvg
)
{
out$
.
prepareSvg
(
el
,
options
,
convertToPng
);
}
else
{
out$
.
svgAsDataUri
(
el
,
options
,
function
(
uri
)
{
var
image
=
new
Image
();
image
.
onload
=
function
()
{
convertToPng
(
image
,
image
.
width
,
image
.
height
);
}
image
.
onerror
=
function
()
{
console
.
error
(
'
There was an error loading the data URI as an image on the following SVG
\n
'
,
window
.
atob
(
uri
.
slice
(
26
)),
'
\n
'
,
"
Open the following link to see browser's diagnosis
\n
"
,
uri
);
}
image
.
src
=
uri
;
});
}
}
out$
.
download
=
function
(
name
,
uri
)
{
if
(
navigator
.
msSaveOrOpenBlob
)
{
navigator
.
msSaveOrOpenBlob
(
uriToBlob
(
uri
),
name
);
}
else
{
var
saveLink
=
document
.
createElement
(
'
a
'
);
var
downloadSupported
=
'
download
'
in
saveLink
;
if
(
downloadSupported
)
{
saveLink
.
download
=
name
;
saveLink
.
style
.
display
=
'
none
'
;
document
.
body
.
appendChild
(
saveLink
);
try
{
var
blob
=
uriToBlob
(
uri
);
var
url
=
URL
.
createObjectURL
(
blob
);
saveLink
.
href
=
url
;
saveLink
.
onclick
=
function
()
{
requestAnimationFrame
(
function
()
{
URL
.
revokeObjectURL
(
url
);
})
};
}
catch
(
e
)
{
console
.
warn
(
'
This browser does not support object URLs. Falling back to string URL.
'
);
saveLink
.
href
=
uri
;
}
saveLink
.
click
();
document
.
body
.
removeChild
(
saveLink
);
}
else
{
window
.
open
(
uri
,
'
_temp
'
,
'
menubar=no,toolbar=no,status=no
'
);
}
}
}
function
uriToBlob
(
uri
)
{
var
byteString
=
window
.
atob
(
uri
.
split
(
'
,
'
)[
1
]);
var
mimeString
=
uri
.
split
(
'
,
'
)[
0
].
split
(
'
:
'
)[
1
].
split
(
'
;
'
)[
0
]
var
buffer
=
new
ArrayBuffer
(
byteString
.
length
);
var
intArray
=
new
Uint8Array
(
buffer
);
for
(
var
i
=
0
;
i
<
byteString
.
length
;
i
++
)
{
intArray
[
i
]
=
byteString
.
charCodeAt
(
i
);
}
return
new
Blob
([
buffer
],
{
type
:
mimeString
});
}
out$
.
saveSvg
=
function
(
el
,
name
,
options
)
{
requireDomNode
(
el
);
options
=
options
||
{};
out$
.
svgAsDataUri
(
el
,
options
,
function
(
uri
)
{
out$
.
download
(
name
,
uri
);
});
}
out$
.
saveSvgAsPng
=
function
(
el
,
name
,
options
)
{
requireDomNode
(
el
);
options
=
options
||
{};
out$
.
svgAsPngUri
(
el
,
options
,
function
(
uri
)
{
out$
.
download
(
name
,
uri
);
});
}
// if define is defined create as an AMD module
if
(
typeof
define
!==
'
undefined
'
)
{
define
(
function
()
{
return
out$
;
});
}
})();
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录