├── Leaflet
└── dist
│ ├── images
│ ├── layers.png
│ ├── marker.png
│ ├── zoom-in.png
│ ├── zoom-out.png
│ ├── popup-close.png
│ └── marker-shadow.png
│ ├── leaflet.ie.css
│ ├── leaflet.css
│ └── leaflet.js
├── ajax
└── saveMap.php
├── README
├── proxy.php
├── index.html
└── js
├── jquery.plugin.html2canvas.js
├── flashcanvas.min.js
├── html2canvas.min.js
└── html2canvas.js
/Leaflet/dist/images/layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tegansnyder/Leaflet-Save-Map-to-PNG/HEAD/Leaflet/dist/images/layers.png
--------------------------------------------------------------------------------
/Leaflet/dist/images/marker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tegansnyder/Leaflet-Save-Map-to-PNG/HEAD/Leaflet/dist/images/marker.png
--------------------------------------------------------------------------------
/Leaflet/dist/images/zoom-in.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tegansnyder/Leaflet-Save-Map-to-PNG/HEAD/Leaflet/dist/images/zoom-in.png
--------------------------------------------------------------------------------
/Leaflet/dist/images/zoom-out.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tegansnyder/Leaflet-Save-Map-to-PNG/HEAD/Leaflet/dist/images/zoom-out.png
--------------------------------------------------------------------------------
/Leaflet/dist/images/popup-close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tegansnyder/Leaflet-Save-Map-to-PNG/HEAD/Leaflet/dist/images/popup-close.png
--------------------------------------------------------------------------------
/Leaflet/dist/images/marker-shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tegansnyder/Leaflet-Save-Map-to-PNG/HEAD/Leaflet/dist/images/marker-shadow.png
--------------------------------------------------------------------------------
/ajax/saveMap.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | Saving a Leaflet Map to a PNG Example using Javascript and PHP
2 | =============================================================================
3 |
4 | This is an example of taking a Leaflet map and saving it to a PNG.
5 |
6 | To run the source example unzip the files into a directory on your webserver.
7 | Make sure to CHMOD the savedMaps directory 777.
8 |
9 | Load it up in a web browser and click the "Save to PNG button". Give it a few seconds.
10 |
11 |
12 | =============================================================================
13 |
14 | Many thanks to:
15 |
16 | html2canvas by Niklas von Hertzen
17 | https://github.com/niklasvh/html2canvas
18 |
19 | Jamund Ferguson
20 | http://j-query.blogspot.com/2011/02/save-base64-encoded-canvas-image-to-png.html
--------------------------------------------------------------------------------
/Leaflet/dist/leaflet.ie.css:
--------------------------------------------------------------------------------
1 | .leaflet-tile {
2 | filter: inherit;
3 | }
4 |
5 | .leaflet-vml-shape {
6 | width: 1px;
7 | height: 1px;
8 | }
9 | .lvml {
10 | behavior: url(#default#VML);
11 | display: inline-block;
12 | position: absolute;
13 | }
14 |
15 | .leaflet-control {
16 | display: inline;
17 | }
18 |
19 | .leaflet-popup-tip {
20 | width: 21px;
21 | _width: 27px;
22 | margin: 0 auto;
23 | _margin-top: -3px;
24 |
25 | filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
26 | -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
27 | }
28 | .leaflet-popup-tip-container {
29 | margin-top: -1px;
30 | }
31 | .leaflet-popup-content-wrapper, .leaflet-popup-tip {
32 | border: 1px solid #bbb;
33 | }
34 |
35 | .leaflet-control-zoom {
36 | filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#3F000000',EndColorStr='#3F000000');
37 | }
38 | .leaflet-control-zoom a {
39 | background-color: #eee;
40 | }
41 | .leaflet-control-zoom a:hover {
42 | background-color: #fff;
43 | }
44 | .leaflet-control-layers-toggle {
45 | }
46 | .leaflet-control-attribution, .leaflet-control-layers {
47 | background: white;
48 | }
--------------------------------------------------------------------------------
/proxy.php:
--------------------------------------------------------------------------------
1 | $pathinfo,
53 | "error" => $error,
54 | "data" => $data,
55 | "mime_type" => $mime_type
56 | );
57 | }
58 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Save Leaflet Map to PNG
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
45 |
46 |
47 |
48 |
49 | Save this to a png
50 |
51 |
52 |
53 |
54 |
55 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/js/jquery.plugin.html2canvas.js:
--------------------------------------------------------------------------------
1 | /**
2 | @license html2canvas v0.33
3 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
4 | http://www.twitter.com/niklasvh
5 |
6 | Released under MIT License
7 | */
8 | /*
9 | * jQuery helper plugin for examples and tests
10 | */
11 | (function( $ ){
12 | $.fn.html2canvas = function(options) {
13 | if (options && options.profile && window.console && window.console.profile) {
14 | console.profile();
15 | }
16 | var date = new Date(),
17 | $message = null,
18 | timeoutTimer = false,
19 | timer = date.getTime();
20 | options = options || {};
21 | options.elements = this;
22 | options.flashcanvas = "js/flashcanvas.min.js";
23 |
24 | html2canvas.logging = options && options.logging;
25 | options.complete = function(images){
26 | var queue = html2canvas.Parse(this[0], images, options),
27 | $canvas = $(html2canvas.Renderer(queue, options)),
28 | finishTime = new Date();
29 |
30 | if (options && options.profile && window.console && window.console.profileEnd) {
31 | console.profileEnd();
32 | }
33 | $canvas.css({
34 | position: 'absolute',
35 | left: 0,
36 | top: 0,
37 | display: 'none'
38 | }).appendTo(document.body);
39 |
40 | $canvas.attr('id', 'savedMap');
41 |
42 | manipulateCanvasFunction(document.getElementById('savedMap'));
43 |
44 | /*
45 | $canvas.siblings().toggle();
46 |
47 | $(window).click(function(){
48 | $canvas.toggle().siblings().toggle();
49 | throwMessage("Canvas Render " + ($canvas.is(':visible') ? "visible" : "hidden"));
50 | });
51 | throwMessage('Screenshot created in '+ ((finishTime.getTime()-timer)) + " ms
",4000);
52 |
53 | */
54 |
55 | // test if canvas is read-able
56 | try {
57 | $canvas[0].toDataURL();
58 | } catch(e) {
59 | if ($canvas[0].nodeName.toLowerCase() === "canvas") {
60 | // TODO, maybe add a bit less offensive way to present this, but still something that can easily be noticed
61 | alert("Canvas is tainted, unable to read data");
62 | }
63 | }
64 |
65 | };
66 | html2canvas.Preload(this[0], options);
67 |
68 | function throwMessage(msg,duration){
69 | window.clearTimeout(timeoutTimer);
70 | timeoutTimer = window.setTimeout(function(){
71 | $message.fadeOut(function(){
72 | $message.remove();
73 | $message = null;
74 | });
75 | },duration || 2000);
76 | if ($message)
77 | $message.remove();
78 | $message = $('').html(msg).css({
79 | margin:0,
80 | padding:10,
81 | background: "#000",
82 | opacity:0.7,
83 | position:"fixed",
84 | top:10,
85 | right:10,
86 | fontFamily: 'Tahoma',
87 | color:'#fff',
88 | fontSize:12,
89 | borderRadius:12,
90 | width:'auto',
91 | height:'auto',
92 | textAlign:'center',
93 | textDecoration:'none',
94 | display:'none'
95 | }).appendTo(document.body).fadeIn();
96 | html2canvas.log(msg);
97 | }
98 | };
99 | })( jQuery );
100 |
101 |
--------------------------------------------------------------------------------
/Leaflet/dist/leaflet.css:
--------------------------------------------------------------------------------
1 | /* required styles */
2 |
3 | .leaflet-map-pane,
4 | .leaflet-tile,
5 | .leaflet-marker-icon,
6 | .leaflet-marker-shadow,
7 | .leaflet-tile-pane,
8 | .leaflet-overlay-pane,
9 | .leaflet-shadow-pane,
10 | .leaflet-marker-pane,
11 | .leaflet-popup-pane,
12 | .leaflet-overlay-pane svg,
13 | .leaflet-zoom-box,
14 | .leaflet-image-layer { /* TODO optimize classes */
15 | position: absolute;
16 | }
17 | .leaflet-container {
18 | overflow: hidden;
19 | }
20 | .leaflet-tile-pane, .leaflet-container {
21 | -webkit-transform: translate3d(0,0,0);
22 | }
23 | .leaflet-tile,
24 | .leaflet-marker-icon,
25 | .leaflet-marker-shadow {
26 | -moz-user-select: none;
27 | -webkit-user-select: none;
28 | user-select: none;
29 | }
30 | .leaflet-marker-icon,
31 | .leaflet-marker-shadow {
32 | display: block;
33 | }
34 | .leaflet-clickable {
35 | cursor: pointer;
36 | }
37 | .leaflet-container img {
38 | max-width: none !important;
39 | }
40 |
41 | .leaflet-tile-pane { z-index: 2; }
42 |
43 | .leaflet-objects-pane { z-index: 3; }
44 | .leaflet-overlay-pane { z-index: 4; }
45 | .leaflet-shadow-pane { z-index: 5; }
46 | .leaflet-marker-pane { z-index: 6; }
47 | .leaflet-popup-pane { z-index: 7; }
48 |
49 | .leaflet-zoom-box {
50 | width: 0;
51 | height: 0;
52 | }
53 |
54 | .leaflet-tile {
55 | visibility: hidden;
56 | }
57 | .leaflet-tile-loaded {
58 | visibility: inherit;
59 | }
60 |
61 | a.leaflet-active {
62 | outline: 2px solid orange;
63 | }
64 |
65 |
66 | /* Leaflet controls */
67 |
68 | .leaflet-control {
69 | position: relative;
70 | z-index: 7;
71 | }
72 | .leaflet-top,
73 | .leaflet-bottom {
74 | position: absolute;
75 | }
76 | .leaflet-top {
77 | top: 0;
78 | }
79 | .leaflet-right {
80 | right: 0;
81 | }
82 | .leaflet-bottom {
83 | bottom: 0;
84 | }
85 | .leaflet-left {
86 | left: 0;
87 | }
88 | .leaflet-control {
89 | float: left;
90 | clear: both;
91 | }
92 | .leaflet-right .leaflet-control {
93 | float: right;
94 | }
95 | .leaflet-top .leaflet-control {
96 | margin-top: 10px;
97 | }
98 | .leaflet-bottom .leaflet-control {
99 | margin-bottom: 10px;
100 | }
101 | .leaflet-left .leaflet-control {
102 | margin-left: 10px;
103 | }
104 | .leaflet-right .leaflet-control {
105 | margin-right: 10px;
106 | }
107 |
108 | .leaflet-control-zoom, .leaflet-control-layers {
109 | -moz-border-radius: 7px;
110 | -webkit-border-radius: 7px;
111 | border-radius: 7px;
112 | }
113 | .leaflet-control-zoom {
114 | padding: 5px;
115 | background: rgba(0, 0, 0, 0.25);
116 | }
117 | .leaflet-control-zoom a {
118 | background-color: rgba(255, 255, 255, 0.75);
119 | }
120 | .leaflet-control-zoom a, .leaflet-control-layers a {
121 | background-position: 50% 50%;
122 | background-repeat: no-repeat;
123 | display: block;
124 | }
125 | .leaflet-control-zoom a {
126 | -moz-border-radius: 4px;
127 | -webkit-border-radius: 4px;
128 | border-radius: 4px;
129 | width: 19px;
130 | height: 19px;
131 | }
132 | .leaflet-control-zoom a:hover {
133 | background-color: #fff;
134 | }
135 | .leaflet-big-buttons .leaflet-control-zoom a {
136 | width: 27px;
137 | height: 27px;
138 | }
139 | .leaflet-control-zoom-in {
140 | background-image: url(images/zoom-in.png);
141 | margin-bottom: 5px;
142 | }
143 | .leaflet-control-zoom-out {
144 | background-image: url(images/zoom-out.png);
145 | }
146 |
147 | .leaflet-control-layers {
148 | -moz-box-shadow: 0 0 7px #999;
149 | -webkit-box-shadow: 0 0 7px #999;
150 | box-shadow: 0 0 7px #999;
151 |
152 | background: #f8f8f9;
153 | }
154 | .leaflet-control-layers a {
155 | background-image: url(images/layers.png);
156 | width: 36px;
157 | height: 36px;
158 | }
159 | .leaflet-big-buttons .leaflet-control-layers a {
160 | width: 44px;
161 | height: 44px;
162 | }
163 | .leaflet-control-layers .leaflet-control-layers-list,
164 | .leaflet-control-layers-expanded .leaflet-control-layers-toggle {
165 | display: none;
166 | }
167 | .leaflet-control-layers-expanded .leaflet-control-layers-list {
168 | display: block;
169 | position: relative;
170 | }
171 | .leaflet-control-layers-expanded {
172 | padding: 6px 10px 6px 6px;
173 | font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
174 | color: #333;
175 | background: #fff;
176 | }
177 | .leaflet-control-layers input {
178 | margin-top: 2px;
179 | position: relative;
180 | top: 1px;
181 | }
182 | .leaflet-control-layers label {
183 | display: block;
184 | }
185 | .leaflet-control-layers-separator {
186 | height: 0;
187 | border-top: 1px solid #ddd;
188 | margin: 5px -10px 5px -6px;
189 | }
190 |
191 | .leaflet-container .leaflet-control-attribution {
192 | margin: 0;
193 | padding: 0 5px;
194 |
195 | font: 11px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
196 | color: #333;
197 |
198 | background-color: rgba(255, 255, 255, 0.7);
199 |
200 | -moz-box-shadow: 0 0 7px #ccc;
201 | -webkit-box-shadow: 0 0 7px #ccc;
202 | box-shadow: 0 0 7px #ccc;
203 | }
204 |
205 |
206 | /* Fade animations */
207 |
208 | .leaflet-fade-anim .leaflet-tile {
209 | opacity: 0;
210 |
211 | -webkit-transition: opacity 0.2s linear;
212 | -moz-transition: opacity 0.2s linear;
213 | -o-transition: opacity 0.2s linear;
214 | transition: opacity 0.2s linear;
215 | }
216 | .leaflet-fade-anim .leaflet-tile-loaded {
217 | opacity: 1;
218 | }
219 |
220 | .leaflet-fade-anim .leaflet-popup {
221 | opacity: 0;
222 |
223 | -webkit-transition: opacity 0.2s linear;
224 | -moz-transition: opacity 0.2s linear;
225 | -o-transition: opacity 0.2s linear;
226 | transition: opacity 0.2s linear;
227 | }
228 | .leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
229 | opacity: 1;
230 | }
231 |
232 | .leaflet-zoom-anim .leaflet-tile {
233 | -webkit-transition: none;
234 | -moz-transition: none;
235 | -o-transition: none;
236 | transition: none;
237 | }
238 |
239 | .leaflet-zoom-anim .leaflet-objects-pane {
240 | visibility: hidden;
241 | }
242 |
243 |
244 | /* Popup layout */
245 |
246 | .leaflet-popup {
247 | position: absolute;
248 | text-align: center;
249 | -webkit-transform: translate3d(0,0,0);
250 | }
251 | .leaflet-popup-content-wrapper {
252 | padding: 1px;
253 | text-align: left;
254 | }
255 | .leaflet-popup-content {
256 | margin: 19px;
257 | }
258 | .leaflet-popup-tip-container {
259 | margin: 0 auto;
260 | width: 40px;
261 | height: 16px;
262 | position: relative;
263 | overflow: hidden;
264 | }
265 | .leaflet-popup-tip {
266 | width: 15px;
267 | height: 15px;
268 | padding: 1px;
269 |
270 | margin: -8px auto 0;
271 |
272 | -moz-transform: rotate(45deg);
273 | -webkit-transform: rotate(45deg);
274 | -ms-transform: rotate(45deg);
275 | -o-transform: rotate(45deg);
276 | transform: rotate(45deg);
277 | }
278 | .leaflet-popup-close-button {
279 | position: absolute;
280 | top: 9px;
281 | right: 9px;
282 |
283 | width: 10px;
284 | height: 10px;
285 |
286 | overflow: hidden;
287 | }
288 | .leaflet-popup-content p {
289 | margin: 18px 0;
290 | }
291 |
292 |
293 | /* Visual appearance */
294 |
295 | .leaflet-container {
296 | background: #ddd;
297 | }
298 | .leaflet-container a {
299 | color: #0078A8;
300 | }
301 | .leaflet-zoom-box {
302 | border: 2px dotted #05f;
303 | background: white;
304 | opacity: 0.5;
305 | }
306 | .leaflet-popup-content-wrapper, .leaflet-popup-tip {
307 | background: white;
308 |
309 | box-shadow: 0 1px 10px #888;
310 | -moz-box-shadow: 0 1px 10px #888;
311 | -webkit-box-shadow: 0 1px 14px #999;
312 | }
313 | .leaflet-popup-content-wrapper {
314 | -moz-border-radius: 20px;
315 | -webkit-border-radius: 20px;
316 | border-radius: 20px;
317 | }
318 | .leaflet-popup-content {
319 | font: 12px/1.4 "Helvetica Neue", Arial, Helvetica, sans-serif;
320 | }
321 | .leaflet-popup-close-button {
322 | background: white url(images/popup-close.png);
323 | }
324 |
--------------------------------------------------------------------------------
/js/flashcanvas.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * FlashCanvas
3 | *
4 | * Copyright (c) 2009 Tim Cameron Ryan
5 | * Copyright (c) 2009-2011 FlashCanvas Project
6 | * Released under the MIT/X License
7 | */
8 | window.ActiveXObject&&!window.CanvasRenderingContext2D&&function(h,j){function D(a){this.code=a;this.message=T[a]}function U(a){this.width=a}function E(a){this.id=a.C++}function t(a){this.G=a;this.id=a.C++}function u(a,b){this.canvas=a;this.B=b;this.d=a.uniqueID;this.D();this.C=0;this.t="";var c=this;setInterval(function(){n[c.d]===0&&c.e()},30)}function A(){if(j.readyState==="complete"){j.detachEvent(F,A);for(var a=j.getElementsByTagName(r),b=0,c=a.length;b=8?a.src:a.getAttribute("src",4)}function v(a){return(""+a).replace(/&/g,"&").replace(/0)return eval(this.B.CallFunction(''+a.join("")+""))},I:function(a,b){this.e();this.D();if(a>0)this.B.width=a;if(b>0)this.B.height=b;this.a.push(e.resize,a,b)}};t.prototype={addColorStop:function(a,b){if(isNaN(a)||a<0||a>1)i(1);this.G.a.push(e.addColorStop,this.id,a,b)}};D.prototype=Error();var T={1:"INDEX_SIZE_ERR",9:"NOT_SUPPORTED_ERR",11:"INVALID_STATE_ERR",
25 | 12:"SYNTAX_ERR",17:"TYPE_MISMATCH_ERR",18:"SECURITY_ERR"},B={initElement:function(a){if(a.getContext)return a;var b=a.uniqueID,c="external"+b;x[b]=false;n[b]=1;Q(a);a.innerHTML='';
26 | s[b]=a;var d=a.firstChild;y[b]=a.lastChild;var f=j.body.contains;if(f(a))d.movie=w;else var g=setInterval(function(){if(f(a)){clearInterval(g);d.movie=w}},0);if(j.compatMode==="BackCompat"||!h.XMLHttpRequest)y[b].style.overflow="hidden";var o=new u(a,d);a.getContext=function(l){return l==="2d"?o:k};a.toDataURL=function(l,z){(""+l).replace(/[A-Z]+/g,W)==="image/jpeg"?o.a.push(e.toDataURL,l,typeof z==="number"?z:""):o.a.push(e.toDataURL,l);return o.e()};d.attachEvent(K,G);return a},saveImage:function(a){a.firstChild.saveImage()},
27 | setOptions:function(){},trigger:function(a,b){s[a].fireEvent("on"+b)},unlock:function(a,b){n[a]&&--n[a];if(b){var c=s[a],d=c.firstChild,f,g;Q(c);f=c.width;g=c.height;c.style.width=f+"px";c.style.height=g+"px";if(f>0)d.width=f;if(g>0)d.height=g;d.resize(f,g);c.attachEvent(L,H);x[a]=true}}};j.createElement(r);j.createStyleSheet().cssText=r+"{display:inline-block;overflow:hidden;width:300px;height:150px}";j.readyState==="complete"?A():j.attachEvent(F,A);h.attachEvent(J,I);if(w.indexOf(location.protocol+
28 | "//"+location.host+"/")===0){var S=new ActiveXObject("Microsoft.XMLHTTP");S.open("GET",w,false);S.send(k)}h[M]=u;h[N]=t;h[O]=E;h[C]=B;h[P]={init:function(){},init_:function(){},initElement:B.initElement};keep=u.measureText}(window,document);
29 |
--------------------------------------------------------------------------------
/js/html2canvas.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | html2canvas v0.33
3 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
4 | http://www.twitter.com/niklasvh
5 |
6 | Released under MIT License
7 | */
8 | (function(j,L,n){function C(a){l.logging&&j.console&&j.console.log&&j.console.log(a)}function S(a,b){var h=[];return{storage:h,width:a,height:b,fillRect:function(){h.push({type:"function",name:"fillRect",arguments:arguments})},drawImage:function(){h.push({type:"function",name:"drawImage",arguments:arguments})},fillText:function(){h.push({type:"function",name:"fillText",arguments:arguments})},setVariable:function(a,b){h.push({type:"variable",name:a,arguments:b})}}}var l={logging:!1};l.log=C;l.Util=
9 | {};l.Util.backgroundImage=function(a){if(/data:image\/.*;base64,/i.test(a)||/^(-webkit|-moz|linear-gradient|-o-)/.test(a))return a;a.toLowerCase().substr(0,5)==='url("'?(a=a.substr(5),a=a.substr(0,a.length-2)):(a=a.substr(4),a=a.substr(0,a.length-1));return a};l.Util.Bounds=function(a){var b={};if(a.getBoundingClientRect)return a=a.getBoundingClientRect(),b.top=a.top,b.bottom=a.bottom||a.top+a.height,b.left=a.left,b.width=a.width||a.right-a.left,b.height=a.height||a.bottom-a.top,b};l.Util.getCSS=
10 | function(a,b){return $(a).css(b)};l.Util.Extend=function(a,b){for(var h in a)a.hasOwnProperty(h)&&(b[h]=a[h]);return b};l.Util.Children=function(a){var b;try{b=$(a).contents()}catch(h){C("html2canvas.Util.Children failed with exception: "+h.message),b=[]}return b};l.Generate={};l.Generate.Gradient=function(a,b){function h(a){for(var d=-1,b="",r;d++26);return b};l.Generate.ListRoman=function(a){var b=["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"],h=[1E3,900,500,400,100,90,50,40,10,9,5,4,1],l="",j,e=b.length;if(a<=0||a>=4E3)return a;for(j=0;j=h[j];)a-=h[j],l+=b[j];return l};l.Parse=function(a,b,h){function I(c,g){var i=parseInt(t(c,g),10);return isNaN(i)?0:i}function F(c,g,a,H,d,m){m!=="transparent"&&(c.setVariable("fillStyle",
14 | m),c.fillRect(g,a,H,d),i+=1)}function e(c,g){switch(g){case "lowercase":return c.toLowerCase();case "capitalize":return c.replace(/(^|\s|:|-|\(|\))([a-z])/g,function(c,g,i){if(c.length>0)return g+i.toUpperCase()});case "uppercase":return c.toUpperCase();default:return c}}function A(c){return c.replace(/^\s*/g,"").replace(/\s*$/g,"")}function f(c,a,d){var d=d.ctx,H=t(c,"fontFamily"),b=t(c,"fontSize"),r=t(c,"color"),G=t(c,"textDecoration"),h=t(c,"textAlign"),s=t(c,"letterSpacing"),f,D,o=t(c,"fontWeight"),
15 | u=t(c,"fontStyle"),j=t(c,"fontVariant"),v=0;a.nodeValue=e(a.nodeValue,t(c,"textTransform"));if(A(a.nodeValue).length>0){if(G!=="none")if(m[H+"-"+b]!==n)D=m[H+"-"+b];else{D=k.createElement("div");var c=k.createElement("img"),p=k.createElement("span"),z;D.style.visibility="hidden";D.style.fontFamily=H;D.style.fontSize=b;D.style.margin=0;D.style.padding=0;x.appendChild(D);c.src="data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACwAAAAAAQABAAACAkQBADs=";c.width=1;c.height=1;c.style.margin=0;c.style.padding=
16 | 0;c.style.verticalAlign="baseline";p.style.fontFamily=H;p.style.fontSize=b;p.style.margin=0;p.style.padding=0;p.appendChild(k.createTextNode("Hidden Text"));D.appendChild(p);D.appendChild(c);z=c.offsetTop-p.offsetTop+1;D.removeChild(p);D.appendChild(k.createTextNode("Hidden Text"));D.style.lineHeight="normal";c.style.verticalAlign="super";c={baseline:z,lineWidth:1,middle:c.offsetTop-D.offsetTop+1};m[H+"-"+b]=c;x.removeChild(D);D=c}h=h.replace(["-webkit-auto"],["auto"]);h=g.letterRendering===!1&&/^(left|right|justify|auto)$/.test(h)&&
17 | /^(normal|none)$/.test(s)?a.nodeValue.split(/(\b| )/):a.nodeValue.split("");switch(parseInt(o,10)){case 401:o="bold";break;case 400:o="normal"}d.setVariable("fillStyle",r);d.setVariable("font",u+" "+j+" "+o+" "+b+" "+H);d.setVariable("textAlign","left");H=a;for(b=0;b0&&(s.fillText(o,u,j),i+=1);switch(G){case "underline":F(d,f.left,Math.round(f.top+D.baseline+D.lineWidth),f.width,1,r);break;case "overline":F(d,f.left,f.top,f.width,1,r);break;case "line-through":F(d,f.left,Math.ceil(f.top+D.middle+D.lineWidth),
19 | f.width,1,r)}v+=h[b].length}}}function d(c){return(c=b[c])&&c.succeeded===!0?c.img:!1}function K(c,g){var a=Math.max(c.left,g.left),i=Math.max(c.top,g.top);return{left:a,top:i,width:Math.min(c.left+c.width,g.left+g.width)-a,height:Math.min(c.top+c.height,g.top+g.height)-i}}function w(c,g){if(!g)return this.zStack={zindex:0,children:[]};if(c!=="auto"){var a={zindex:c,children:[]};g.children.push(a);return a}return g}function y(c,g,a,i){for(var d=a.left,b=a.top,m=a.width,a=a.height,f,r,h,k,G,e=function(c){var g=
20 | [],a=["Top","Right","Bottom","Left"],i;for(i=0;i<4;i+=1)g.push({width:I(c,"border"+a[i]+"Width"),color:t(c,"border"+a[i]+"Color")});return g}(c),c=0;c<4;c+=1)if(f=e[c],f.width>0){r=d;h=b;k=m;G=a-e[2].width;switch(c){case 0:G=e[0].width;break;case 1:r=d+m-e[1].width;k=e[1].width;break;case 2:h=h+a-e[2].width;G=e[2].width;break;case 3:k=e[3].width}k={left:r,top:h,width:k,height:G};i&&(k=K(k,i));k.width>0&&k.height>0&&F(g,r,h,k.width,k.height,f.color)}return e}function r(c,g,a){var i=k.createElement("valuewrap"),
21 | d=["lineHeight","textAlign","fontFamily","color","fontSize","paddingLeft","paddingTop","width","height","border","borderLeftWidth","borderTopWidth"],b,m,r;b=0;for(m=d.length;b0&&(h=m-a);k-d>0&&(f=k-d);c.drawImage(g,h,f,b-h,r-f,a+h,d+f,b-h,r-f);i+=1}function O(c,g,a,i,d,b,r){var r=Math.min(g.height,r),m,h;a.left-=Math.ceil(a.left/g.width)*g.width;for(h=i+a.left;hb+i?b+i-h:g.width,M(c,g,h,d+a.top,m,r,i,d),h=Math.floor(h+g.width)}function z(c,a){var b=l.Util.Bounds(c),h=b.left,
24 | m=b.top,f=b.width,e=b.height,j,s=t(c,"backgroundColor"),z=t(c,"position"),B,o=t(c,"opacity"),u,q;a?P={}:(P={width:Math.max(Math.max(k.body.scrollWidth,k.documentElement.scrollWidth),Math.max(k.body.offsetWidth,k.documentElement.offsetWidth),Math.max(k.body.clientWidth,k.documentElement.clientWidth)),height:Math.max(Math.max(k.body.scrollHeight,k.documentElement.scrollHeight),Math.max(k.body.offsetHeight,k.documentElement.offsetHeight),Math.max(k.body.clientHeight,k.documentElement.clientHeight))},
25 | a={opacity:1});B=w(t(c,"zIndex"),a.zIndex);u={ctx:S(P.width||f,P.height||e),zIndex:B,opacity:o*a.opacity,cssPosition:z};if(a.clip)u.clip=l.Util.Extend({},a.clip);if(g.useOverflow===!0&&/(hidden|scroll|auto)/.test(t(c,"overflow"))===!0&&/(BODY)/i.test(c.nodeName)===!1)u.clip=u.clip?K(u.clip,b):b;z=B.children.push(u);q=B.children[z-1].ctx;q.setVariable("globalAlpha",u.opacity);o=y(c,q,b,!1);u.borders=o;Q.test(c.nodeName)&&g.iframeDefault!=="transparent"&&(s=g.iframeDefault==="default"?"#efefef":g.iframeDefault);
26 | f={left:h+o[3].width,top:m+o[0].width,width:f-(o[1].width+o[3].width),height:e-(o[0].width+o[2].width)};u.clip&&(f=K(f,u.clip));if(f.height>0&&f.width>0){F(q,f.left,f.top,f.width,f.height,s);var v=f,p=t(c,"backgroundImage"),x=t(c,"backgroundRepeat").split(",")[0],n,E,J;!/data:image\/.*;base64,/i.test(p)&&!/^(-webkit|-moz|linear-gradient|-o-)/.test(p)&&(p=p.split(",")[0]);if(typeof p!=="undefined"&&/^(1|none)$/.test(p)===!1)if(p=l.Util.backgroundImage(p),s=d(p),e=G(c,v,s),s)switch(x){case "repeat-x":O(q,
27 | s,e,v.left,v.top,v.width,v.height);break;case "repeat-y":p=v.left;x=v.top;n=v.height;E=Math.min(s.width,v.width);e.top-=Math.ceil(e.top/s.height)*s.height;for(J=x+e.top;Jn+x?n+x-J:s.height,M(q,s,p+e.left,J,E,v,p,x),J=Math.floor(J+s.height);break;case "no-repeat":p=v.width-e.left;J=v.height-e.top;x=e.left;n=e.top;E=e.left+v.left;e=e.top+v.top;x<0?(x=Math.abs(x),E+=x,p=Math.min(v.width,s.width-x)):(p=Math.min(p,s.width),x=0);n<0?(n=Math.abs(n),e+=n,J=Math.min(v.height,
28 | s.height-n)):(J=Math.min(J,s.height),n=0);J>0&&p>0&&(q.drawImage(s,x,n,p,J,E,e,p,J),i+=1);break;default:e.top-=Math.ceil(e.top/s.height)*s.height;for(p=v.top+e.top;px+p?x+p-p:s.height,p0&&(e.top+=n),p=Math.floor(p+s.height)-n}else C("html2canvas: Error loading background:"+p)}switch(c.nodeName){case "IMG":u=c.getAttribute("src");(j=d(u))?(u=I(c,"paddingLeft"),
29 | f=I(c,"paddingTop"),s=I(c,"paddingRight"),e=I(c,"paddingBottom"),q.drawImage(j,0,0,j.width,j.height,h+u+o[3].width,m+f+o[0].width,b.width-(o[1].width+o[3].width+u+s),b.height-(o[0].width+o[2].width+f+e)),i+=1):C("html2canvas: Error loading
:"+u);break;case "INPUT":/^(text|url|email|submit|button|reset)$/.test(c.type)&&c.value.length>0&&r(c,b,u);break;case "TEXTAREA":c.value.length>0&&r(c,b,u);break;case "SELECT":c.options.length>0&&r(c,b,u);break;case "LI":b=f;h=t(c,"listStylePosition");o=t(c,
30 | "listStyleType");m=t(c,"fontWeight");if(/^(decimal|decimal-leading-zero|upper-alpha|upper-latin|upper-roman|lower-alpha|lower-greek|lower-latin|lower-roman)$/i.test(o)){q=$(c).index()+1;switch(o){case "decimal":j=q;break;case "decimal-leading-zero":j=q.toString().length===1?"0"+q.toString():q.toString();break;case "upper-roman":j=l.Generate.ListRoman(q);break;case "lower-roman":j=l.Generate.ListRoman(q).toLowerCase();break;case "lower-alpha":j=l.Generate.ListAlpha(q).toLowerCase();break;case "upper-alpha":j=
31 | l.Generate.ListAlpha(q)}j+=". ";u=j;o=k.createElement("boundelement");o.style.display="inline";q=c.style.listStyleType;c.style.listStyleType="none";o.appendChild(k.createTextNode(u));c.insertBefore(o,c.firstChild);u=l.Util.Bounds(o);c.removeChild(o);c.style.listStyleType=q;switch(m){case 401:m="bold";break;case 400:m="normal"}N.setVariable("fillStyle",t(c,"color"));N.setVariable("font",t(c,"fontVariant")+" "+m+" "+t(c,"fontStyle")+" "+t(c,"fontSize")+" "+t(c,"fontFamily"));if(h==="inside")N.setVariable("textAlign",
32 | "left"),b=b.left,h=u.bottom,m=N,A(j).length>0&&(m.fillText(j,b,h),i+=1)}break;case "CANVAS":u=I(c,"paddingLeft"),f=I(c,"paddingTop"),s=I(c,"paddingRight"),e=I(c,"paddingBottom"),q.drawImage(c,0,0,c.width,c.height,h+u+o[3].width,m+f+o[0].width,b.width-(o[1].width+o[3].width+u+s),b.height-(o[0].width+o[2].width+f+e)),i+=1}return B.children[z-1]}function q(a,g){if(t(a,"display")!=="none"&&t(a,"visibility")!=="hidden"&&(g=z(a,g)||g,N=g.ctx,!Q.test(a.nodeName))){var i=l.Util.Children(a),b,d,h;b=0;for(h=
33 | i.length;b=d.numTotal&&(typeof f.complete==="function"&&f.complete(d),C("Finished loading images: # "+d.numTotal+" (failed: "+
35 | d.numFailed+")"))}function I(a,i,b){var k,q=f.proxy,l;z.href=a;a=z.href;k="html2canvas_"+r++;b.callbackname=k;q+=q.indexOf("?")>-1?"&":"?";q+="url="+encodeURIComponent(a)+"&callback="+k;l=G.createElement("script");j[k]=function(a){a.substring(0,6)==="error:"?(b.succeeded=!1,d.numLoaded++,d.numFailed++,h()):(e(i,b),i.src=a);j[k]=n;try{delete j[k]}catch(g){}l.parentNode.removeChild(l);l=null;delete b.script;delete b.callbackname};l.setAttribute("type","text/javascript");l.setAttribute("src",q);b.script=
36 | l;j.document.body.appendChild(l)}function F(a){var i=l.Util.Children(a),b,f=i.length,e,r=!1;for(b=0;b0&&(B=j.setTimeout(w.cleanupDOM,f.timeout));C("html2canvas: Preload starts: finding background-images");d.firstRun=!0;F(a);C("html2canvas: Preload: Finding images");for(y=0;y0?(b.push(f),e.push(f.zindex)):A.push(f);e.sort(function(a,b){return a-b});a=0;for(d=e.length;a0&&m.arguments[7]){if(q&&e.taintTest&&B.indexOf(m.arguments[0].src)===-1){g.drawImage(m.arguments[0],0,0);try{g.getImageData(0,0,1,1)}catch(k){g=L.createElement("canvas");g=g.getContext("2d");continue}B.push(m.arguments[0].src)}b.drawImage.apply(b,m.arguments)}}}a.clip&&
45 | b.restore()}C("html2canvas: Renderer: Canvas renderer done - returning canvas obj");y=e.elements.length;return y===1&&typeof e.elements[0]==="object"&&e.elements[0].nodeName!=="BODY"&&d===!1?(B=l.Util.Bounds(e.elements[0]),q=w.createElement("canvas"),q.width=B.width,q.height=B.height,b=q.getContext("2d"),b.drawImage(f,B.left,B.top,B.width,B.height,0,0,B.width,B.height),delete f,q):f}function F(a){h(a.zIndex);var b=w.createElementNS("http://www.w3.org/2000/svg","svg"),d=w.createElementNS("http://www.w3.org/2000/svg",
46 | "defs"),f,j,l,n,g,i,m={},k,y=0;b.setAttribute("version","1.1");b.setAttribute("baseProfile","full");b.setAttribute("viewBox","0 0 "+Math.max(a.ctx.width,e.width)+" "+Math.max(a.ctx.height,e.height));b.setAttribute("width",Math.max(a.ctx.width,e.width)+"px");b.setAttribute("height",Math.max(a.ctx.height,e.height)+"px");b.setAttribute("preserveAspectRatio","none");b.appendChild(d);a=0;for(j=A.length;a0&&g.arguments[7]&&(i=w.createElementNS("http://www.w3.org/2000/svg",
49 | "clipPath"),i.setAttribute("id","clipId"+y),k=w.createElementNS("http://www.w3.org/2000/svg","rect"),k.setAttribute("x",g.arguments[5]),k.setAttribute("y",g.arguments[6]),k.setAttribute("width",g.arguments[3]),k.setAttribute("height",g.arguments[4]),i.appendChild(k),d.appendChild(i),i=w.createElementNS("http://www.w3.org/2000/svg","image"),i.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",g.arguments[0].src),i.setAttribute("width",g.arguments[0].width),i.setAttribute("height",g.arguments[0].height),
50 | i.setAttribute("x",g.arguments[5]-g.arguments[1]),i.setAttribute("y",g.arguments[6]-g.arguments[2]),i.setAttribute("clip-path","url(#clipId"+y+")"),i.setAttribute("preserveAspectRatio","none"),b.appendChild(i),y+=1)}}C("html2canvas: Renderer: SVG Renderer done - returning SVG DOM obj");return b}var e={width:null,height:null,renderer:"canvas",taintTest:!0},A=[],f,d=!1,K=2880,w=L,e=l.Util.Extend(b,e);switch(e.renderer.toLowerCase()){case "canvas":if(f=w.createElement("canvas"),f.getContext)return C("html2canvas: Renderer: using canvas renderer"),
51 | I(a);else{d=!0;C("html2canvas: Renderer: canvas not available, using flashcanvas");var y=w.createElement("script");y.src=e.flashcanvas;y.onload=function(a,b){var d;if(a.onload===n)a.onreadystatechange!==n?(d=function(){a.readyState!=="loaded"&&a.readyState!=="complete"?j.setTimeout(d,250):b()},j.setTimeout(d,250)):C("html2canvas: Renderer: Can't track when flashcanvas is loaded");else return b}(y,function(){typeof j.FlashCanvas!=="undefined"&&(C("html2canvas: Renderer: Flashcanvas initialized"),j.FlashCanvas.initElement(f),
52 | I(a))});w.body.appendChild(y);return f}case "svg":if(w.createElementNS)return C("html2canvas: Renderer: using SVG renderer"),F(a)}return this};j.html2canvas=l})(window,document);
--------------------------------------------------------------------------------
/Leaflet/dist/leaflet.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2010-2011, CloudMade, Vladimir Agafonkin
3 | Leaflet is a modern open-source JavaScript library for interactive maps.
4 | http://leaflet.cloudmade.com
5 | */
6 | (function(a){a.L={VERSION:"0.3",ROOT_URL:a.L_ROOT_URL||function(){var a=document.getElementsByTagName("script"),b=/\/?leaflet[\-\._]?([\w\-\._]*)\.js\??/,c,d,e,f;for(c=0,d=a.length;c0},removeEventListener:function(a,b,c){if(!this.hasEventListeners(a))return this;for(var d=0,e=this._leaflet_events,f=e[a].length;d=this.min.x&&c.x<=this.max.x&&b.y>=this.min.y&&c.y<=this.max.y},intersects:function(a){var b=this.min,c=this.max,d=a.min,e=a.max,f=e.x>=b.x&&d.x<=c.x,g=e.y>=b.y&&d.y<=c.y;return f&&g}}),L.Transformation=L.Class.extend({initialize:function(a,b,c,d){this._a=a,this._b=b,this._c=c,this._d=d},transform:function(a,b){return this._transform(a.clone(),b)},_transform:function(a,b){return b=b||1,a.x=b*(this._a*a.x+this._b),a.y=b*(this._c*a.y+this._d),a},untransform:function(a,b){return b=b||1,new L.Point((a.x/b-this._b)/this._a,(a.y/b-this._d)/this._c)}}),L.DomUtil={get:function(a){return typeof a=="string"?document.getElementById(a):a},getStyle:function(a,b){var c=a.style[b];!c&&a.currentStyle&&(c=a.currentStyle[b]);if(!c||c==="auto"){var d=document.defaultView.getComputedStyle(a,null);c=d?d[b]:null}return c==="auto"?null:c},getViewportOffset:function(a){var b=0,c=0,d=a,e=document.body;do{b+=d.offsetTop||0,c+=d.offsetLeft||0;if(d.offsetParent===e&&L.DomUtil.getStyle(d,"position")==="absolute")break;d=d.offsetParent}while(d);d=a;do{if(d===e)break;b-=d.scrollTop||0,c-=d.scrollLeft||0,d=d.parentNode}while(d);return new L.Point(c,b)},create:function(a,b,c){var d=document.createElement(a);return d.className=b,c&&c.appendChild(d),d},disableTextSelection:function(){document.selection&&document.selection.empty&&document.selection.empty(),this._onselectstart||(this._onselectstart=document.onselectstart,document.onselectstart=L.Util.falseFn)},enableTextSelection:function(){document.onselectstart=this._onselectstart,this._onselectstart=null},hasClass:function(a,b){return a.className.length>0&&RegExp("(^|\\s)"+b+"(\\s|$)").test(a.className)},addClass:function(a,b){L.DomUtil.hasClass(a,b)||(a.className+=(a.className?" ":"")+b)},removeClass:function(a,b){a.className=a.className.replace(/(\S+)\s*/g,function(a,c){return c===b?"":a}).replace(/^\s+/,"")},setOpacity:function(a,b){L.Browser.ie?a.style.filter="alpha(opacity="+Math.round(b*100)+")":a.style.opacity=b},testProp:function(a){var b=document.documentElement.style;for(var c=0;c=b.lat&&e.lat<=c.lat&&d.lng>=b.lng&&e.lng<=c.lng},intersects:function(a){var b=this._southWest,c=this._northEast,d=a.getSouthWest(),e=a.getNorthEast(),f=e.lat>=b.lat&&d.lat<=c.lat,g=e.lng>=b.lng&&d.lng<=c.lng;return f&&g},toBBoxString:function(){var a=this._southWest,b=this._northEast;return[a.lng,a.lat,b.lng,b.lat].join(",")}}),L.Projection={},L.Projection.SphericalMercator={MAX_LATITUDE:85.0511287798,project:function(a){var b=L.LatLng.DEG_TO_RAD,c=this.MAX_LATITUDE,d=Math.max(Math.min(c,a.lat),-c),e=a.lng*b,f=d*b;return f=Math.log(Math.tan(Math.PI/4+f/2)),new L.Point(e,f)},unproject:function(a,b){var c=L.LatLng.RAD_TO_DEG,d=a.x*c,e=(2*Math.atan(Math.exp(a.y))-Math.PI/2)*c;return new L.LatLng(e,d,b)}},L.Projection.LonLat={project:function(a){return new L.Point(a.lng,a.lat)},unproject:function(a,b){return new L.LatLng(a.y,a.x,b)}},L.CRS={latLngToPoint:function(a,b){var c=this.projection.project(a);return this.transformation._transform(c,b)},pointToLatLng:function(a,b,c){var d=this.transformation.untransform(a,b);return this.projection.unproject(d,c)},project:function(a){return this.projection.project(a)}},L.CRS.EPSG3857=L.Util.extend({},L.CRS,{code:"EPSG:3857",projection:L.Projection.SphericalMercator,transformation:new L.Transformation(.5/Math.PI,.5,-0.5/Math.PI,.5),project:function(a){var b=this.projection.project(a),c=6378137;return b.multiplyBy(c)}}),L.CRS.EPSG900913=L.Util.extend({},L.CRS.EPSG3857,{code:"EPSG:900913"}),L.CRS.EPSG4326=L.Util.extend({},L.CRS,{code:"EPSG:4326",projection:L.Projection.LonLat,transformation:new L.Transformation(1/360,.5,-1/360,.5)}),L.Map=L.Class.extend({includes:L.Mixin.Events,options:{crs:L.CRS.EPSG3857||L.CRS.EPSG4326,scale:function(a){return 256*Math.pow(2,a)},center:null,zoom:null,layers:[],dragging:!0,touchZoom:L.Browser.touch&&!L.Browser.android,scrollWheelZoom:!L.Browser.touch,doubleClickZoom:!0,boxZoom:!0,zoomControl:!0,attributionControl:!0,fadeAnimation:L.DomUtil.TRANSITION&&!L.Browser.android,zoomAnimation:L.DomUtil.TRANSITION&&!L.Browser.android&&!L.Browser.mobileOpera,trackResize:!0,closePopupOnClick:!0,worldCopyJump:!0},initialize:function(a,b){L.Util.setOptions(this,b),this._container=L.DomUtil.get(a);if(this._container._leaflet)throw Error("Map container is already initialized.");this._container._leaflet=!0,this._initLayout(),L.DomEvent&&(this._initEvents(),L.Handler&&this._initInteraction(),L.Control&&this._initControls()),this.options.maxBounds&&this.setMaxBounds(this.options.maxBounds);var c=this.options.center,d=this.options.zoom;c!==null&&d!==null&&this.setView(c,d,!0);var e=this.options.layers;e=e instanceof Array?e:[e],this._tileLayersNum=0,this._initLayers(e)},setView:function(a,b){return this._resetView(a,this._limitZoom(b)),this},setZoom:function(a){return this.setView(this.getCenter(),a)},zoomIn:function(){return this.setZoom(this._zoom+1)},zoomOut:function(){return this.setZoom(this._zoom-1)},fitBounds:function(a){var b=this.getBoundsZoom(a);return this.setView(a.getCenter(),b)},fitWorld:function(){var a=new L.LatLng(-60,-170),b=new L.LatLng(85,179);return this.fitBounds(new L.LatLngBounds(a,b))},panTo:function(a){return this.setView(a,this._zoom)},panBy:function(a){return this.fire("movestart"),this._rawPanBy(a),this.fire("move"),this.fire("moveend"),this},setMaxBounds:function(a){this.options.maxBounds=a;if(!a)return this._boundsMinZoom=null,this;var b=this.getBoundsZoom(a,!0);return this._boundsMinZoom=b,this._loaded&&(this._zoomf.x&&(g=f.x-d.x),c.y>e.y&&(h=e.y-c.y),c.xl&&--m>0)o=h*Math.sin(j),n=Math.PI/2-2*Math.atan(i*Math.pow((1-o)/(1+o),.5*h))-j,j+=n;return new L.LatLng(j*c,f,b)}},L.CRS.EPSG3395=L.Util.extend({},L.CRS,{code:"EPSG:3395",projection:L.Projection.Mercator,transformation:function(){var a=L.Projection.Mercator,b=a.R_MAJOR,c=a.R_MINOR;return new L.Transformation(.5/(Math.PI*b),.5,-0.5/(Math.PI*c),.5)}()}),L.TileLayer=L.Class.extend({includes:L.Mixin.Events,options:{minZoom:0,maxZoom:18,tileSize:256,subdomains:"abc",errorTileUrl:"",attribution:"",opacity:1,scheme:"xyz",continuousWorld:!1,noWrap:!1,zoomOffset:0,zoomReverse:!1,unloadInvisibleTiles:L.Browser.mobile,updateWhenIdle:L.Browser.mobile,reuseTiles:!1},initialize:function(a,b,c){L.Util.setOptions(this,b),this._url=a,this._urlParams=c,typeof this.options.subdomains=="string"&&(this.options.subdomains=this.options.subdomains.split(""))},onAdd:function(a,b){this._map=a,this._insertAtTheBottom=b,this._initContainer(),this._createTileProto(),a.on("viewreset",this._resetCallback,this),this.options.updateWhenIdle?a.on("moveend",this._update,this):(this._limitedUpdate=L.Util.limitExecByInterval(this._update,150,this),a.on("move",this._limitedUpdate,this)),this._reset(),this._update()},onRemove:function(a){this._map.getPanes().tilePane.removeChild(this._container),this._container=null,this._map.off("viewreset",this._resetCallback,this),this.options.updateWhenIdle?this._map.off("moveend",this._update,this):this._map.off("move",this._limitedUpdate,this)},getAttribution:function(){return this.options.attribution},setOpacity:function(a){this.options.opacity=a,this._setOpacity(a);if(L.Browser.webkit)for(var b in this._tiles)this._tiles.hasOwnProperty(b)&&(this._tiles[b].style.webkitTransform+=" translate(0,0)")},_setOpacity:function(a){a<1&&L.DomUtil.setOpacity(this._container,a)},_initContainer:function(){var a=this._map.getPanes().tilePane,b=a.firstChild;if(!this._container||a.empty)this._container=L.DomUtil.create("div","leaflet-layer"),this._insertAtTheBottom&&b?a.insertBefore(this._container,b):a.appendChild(this._container),this._setOpacity(this.options.opacity)},_resetCallback:function(a){this._reset(a.hard)},_reset:function(a){var b;for(b in this._tiles)this._tiles.hasOwnProperty(b)&&this.fire("tileunload",{tile:this._tiles[b]});this._tiles={},this.options.reuseTiles&&(this._unusedTiles=[]),a&&this._container&&(this._container.innerHTML=""),this._initContainer()},_update:function(){var a=this._map.getPixelBounds(),b=this._map.getZoom(),c=this.options.tileSize;if(b>this.options.maxZoom||ba.max.x||da.max.y)f=this._tiles[e],this.fire("tileunload",{tile:f,url:f.src}),f.parentNode===this._container&&this._container.removeChild(f),this.options.reuseTiles&&this._unusedTiles.push(this._tiles[e]),f.src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=",delete this._tiles[e]}},_addTile:function(a,b){var c=this._getTilePos(a),d=this._map.getZoom(),e=a.x+":"+a.y,f=Math.pow(2,this._getOffsetZoom(d));if(!this.options.continuousWorld){if(!this.options.noWrap)a.x=(a.x%f+f)%f;else if(a.x<0||a.x>=f){this._tilesToLoad--;return}if(a.y<0||a.y>=f){this._tilesToLoad--;return}}var g=this._getTile();L.DomUtil.setPosition(g,c),this._tiles[e]=g,this.options.scheme==="tms"&&(a.y=f-a.y-1),this._loadTile(g,a,d),b.appendChild(g)},_getOffsetZoom:function(a){return a=this.options.zoomReverse?this.options.maxZoom-a:a,a+this.options.zoomOffset},_getTilePos:function(a){var b=this._map.getPixelOrigin(),c=this.options.tileSize;return a.multiplyBy(c).subtract(b)},getTileUrl:function(a,b){var c=this.options.subdomains,d=this.options.subdomains[(a.x+a.y)%c.length];return L.Util.template(this._url,L.Util.extend({s:d,z:this._getOffsetZoom(b),x:a.x,y:a.y},this._urlParams))},_createTileProto:function(){this._tileImg=L.DomUtil.create("img","leaflet-tile"),this._tileImg.galleryimg="no";var a=this.options.tileSize;this._tileImg.style.width=a+"px",this._tileImg.style.height=a+"px"},_getTile:function(){if(this.options.reuseTiles&&this._unusedTiles.length>0){var a=this._unusedTiles.pop();return this._resetTile(a),a}return this._createTile()},_resetTile:function(a){},_createTile:function(){var a=this._tileImg.cloneNode(!1);return a.onselectstart=a.onmousemove=L.Util.falseFn,a},_loadTile:function(a,b,c){a._layer=this,a.onload=this._tileOnLoad,a.onerror=this._tileOnError,a.src=this.getTileUrl(b,c)},_tileOnLoad:function(a){var b=this._layer;this.className+=" leaflet-tile-loaded",b.fire("tileload",{tile:this,url:this.src}),b._tilesToLoad--,b._tilesToLoad||b.fire("load")},_tileOnError:function(a){var b=this._layer;b.fire("tileerror",{tile:this,url:this.src});var c=b.options.errorTileUrl;c&&(this.src=c)}}),L.TileLayer.WMS=L.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",version:"1.1.1",layers:"",styles:"",format:"image/jpeg",transparent:!1},initialize:function(a,b){this._url=a,this.wmsParams=L.Util.extend({},this.defaultWmsParams),this.wmsParams.width=this.wmsParams.height=this.options.tileSize;for(var c in b)this.options.hasOwnProperty(c)||(this.wmsParams[c]=b[c]);L.Util.setOptions(this,b)},onAdd:function(a){var b=parseFloat(this.wmsParams.version)<1.3?"srs":"crs";this.wmsParams[b]=a.options.crs.code,L.TileLayer.prototype.onAdd.call(this,a)},getTileUrl:function(a,b){var c=this.options.tileSize,d=a.multiplyBy(c),e=d.add(new L.Point(c,c)),f=this._map.unproject(d,this._zoom,!0),g=this._map.unproject(e,this._zoom,!0),h=this._map.options.crs.project(f),i=this._map.options.crs.project(g),j=[h.x,i.y,i.x,h.y].join(",");return this._url+L.Util.getParamString(this.wmsParams)+"&bbox="+j}}),L.TileLayer.Canvas=L.TileLayer.extend({options:{async:!1},initialize:function(a){L.Util.setOptions(this,a)},redraw:function(){for(var a in this._tiles){var b=this._tiles[a];this._redrawTile(b)}},_redrawTile:function(a){this.drawTile(a,a._tilePoint,a._zoom)},_createTileProto:function(){this._canvasProto=L.DomUtil.create("canvas","leaflet-tile");var a=this.options.tileSize;this._canvasProto.width=a,this._canvasProto.height=a},_createTile:function(){var a=this._canvasProto.cloneNode(!1);return a.onselectstart=a.onmousemove=L.Util.falseFn,a},_loadTile:function(a,b,c){a._layer=this,a._tilePoint=b,a._zoom=c,this.drawTile(a,b,c),this.options.async||this.tileDrawn(a)},drawTile:function(a,b,c){},tileDrawn:function(a){this._tileOnLoad.call(a)}}),L.ImageOverlay=L.Class.extend({includes:L.Mixin.Events,initialize:function(a,b){this._url=a,this._bounds=b},onAdd:function(a){this._map=a,this._image||this._initImage(),a.getPanes().overlayPane.appendChild(this._image),a.on("viewreset",this._reset,this),this._reset()},onRemove:function(a){a.getPanes().overlayPane.removeChild(this._image),a.off("viewreset",this._reset,this)},_initImage:function(){this._image=L.DomUtil.create("img","leaflet-image-layer"),this._image.style.visibility="hidden",L.Util.extend(this._image,{galleryimg:"no",onselectstart:L.Util.falseFn,onmousemove:L.Util.falseFn,onload:L.Util.bind(this._onImageLoad,this),src:this._url})},_reset:function(){var a=this._map.latLngToLayerPoint(this._bounds.getNorthWest()),b=this._map.latLngToLayerPoint(this._bounds.getSouthEast()),c=b.subtract(a);L.DomUtil.setPosition(this._image,a),this._image.style.width=c.x+"px",this._image.style.height=c.y+"px"},_onImageLoad:function(){this._image.style.visibility="",this.fire("load")}}),L.Icon=L.Class.extend({iconUrl:L.ROOT_URL+"images/marker.png",shadowUrl:L.ROOT_URL+"images/marker-shadow.png",iconSize:new L.Point(25,41),shadowSize:new L.Point(41,41),iconAnchor:new L.Point(13,41),popupAnchor:new L.Point(0,-33),initialize:function(a){a&&(this.iconUrl=a)},createIcon:function(){return this._createIcon("icon")},createShadow:function(){return this._createIcon("shadow")},_createIcon:function(a){var b=this[a+"Size"],c=this[a+"Url"];if(!c&&a==="shadow")return null;var d;return c?d=this._createImg(c):d=this._createDiv(),d.className="leaflet-marker-"+a,d.style.marginLeft=-this.iconAnchor.x+"px",d.style.marginTop=-this.iconAnchor.y+"px",b&&(d.style.width=b.x+"px",d.style.height=b.y+"px"),d},_createImg:function(a){var b;return L.Browser.ie6?(b=document.createElement("div"),b.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+a+'")'):(b=document.createElement("img"),b.src=a),b},_createDiv:function(){return document.createElement("div")}}),L.Marker=L.Class.extend({includes:L.Mixin.Events,options:{icon:new L.Icon,title:"",clickable:!0,draggable:!1,zIndexOffset:0},initialize:function(a,b){L.Util.setOptions(this,b),this._latlng=a},onAdd:function(a){this._map=a,this._initIcon(),a.on("viewreset",this._reset,this),this._reset()},onRemove:function(a){this._removeIcon(),this.closePopup&&this.closePopup(),this._map=null,a.off("viewreset",this._reset,this)},getLatLng:function(){return this._latlng},setLatLng:function(a){this._latlng=a,this._icon&&(this._reset(),this._popup&&this._popup.setLatLng(this._latlng))},setZIndexOffset:function(a){this.options.zIndexOffset=a,this._icon&&this._reset()},setIcon:function(a){this._map&&this._removeIcon(),this.options.icon=a,this._map&&(this._initIcon(),this._reset())},_initIcon:function(){this._icon||(this._icon=this.options.icon.createIcon(),this.options.title&&(this._icon.title=this.options.title),this._initInteraction()),this._shadow||(this._shadow=this.options.icon.createShadow()),this._map._panes.markerPane.appendChild(this._icon),this._shadow&&this._map._panes.shadowPane.appendChild(this._shadow)},_removeIcon:function(){this._map._panes.markerPane.removeChild(this._icon),this._shadow&&this._map._panes.shadowPane.removeChild(this._shadow),this._icon=this._shadow=null},_reset:function(){var a=this._map.latLngToLayerPoint(this._latlng).round();L.DomUtil.setPosition(this._icon,a),this._shadow&&L.DomUtil.setPosition(this._shadow,a),this._icon.style.zIndex=a.y+this.options.zIndexOffset},_initInteraction:function(){if(this.options.clickable){this._icon.className+=" leaflet-clickable",L.DomEvent.addListener(this._icon,"click",this._onMouseClick,this);var a=["dblclick","mousedown","mouseover","mouseout"];for(var b=0;bthis.options.maxWidth?this.options.maxWidth:af.x&&(d.x=c.x+this._containerWidth-f.x+e.x),c.y<0&&(d.y=c.y-e.y),c.y+a>f.y&&(d.y=c.y+a-f.y+e.y),(d.x||d.y)&&this._map.panBy(d)},_onCloseButtonClick:function(a){this._close(),L.DomEvent.stop(a)}}),L.Marker.include({openPopup:function(){return this._popup.setLatLng(this._latlng),this._map&&this._map.openPopup(this._popup),this},closePopup:function(){return this._popup&&this._popup._close(),this},bindPopup:function(a,b){return b=L.Util.extend({offset:this.options.icon.popupAnchor},b),this._popup||this.on("click",this.openPopup,this),this._popup=new L.Popup(b,this),this._popup.setContent(a),this},unbindPopup:function(){return this._popup&&(this._popup=null,this.off("click",this.openPopup)),this}}),L.Map.include({openPopup:function(a){return this.closePopup(),this._popup=a,this.addLayer(a),this.fire("popupopen",{popup:this._popup}),this},closePopup:function(){return this._popup&&(this.removeLayer(this._popup),this.fire("popupclose",{popup:this._popup}),this._popup=null),this}}),L.LayerGroup=L.Class.extend({initialize:function(a){this._layers={};if(a)for(var b=0,c=a.length;b')}}catch(a){return function(a){return document.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}()},_initPath:function(){this._container=L.Path._createElement("shape"),this._container.className+=" leaflet-vml-shape"+(this.options.clickable?" leaflet-clickable":""),this._container.coordsize="1 1",this._path=L.Path._createElement("path"),this._container.appendChild(this._path),this._map._pathRoot.appendChild(this._container)},_initStyle:function(){this.options.stroke?(this._stroke=L.Path._createElement("stroke"),this._stroke.endcap="round",this._container.appendChild(this._stroke)):this._container.stroked=!1,this.options.fill?(this._container.filled=!0,this._fill=L.Path._createElement("fill"),this._container.appendChild(this._fill)):this._container.filled=!1,this._updateStyle()},_updateStyle:function(){this.options.stroke&&(this._stroke.weight=this.options.weight+"px",this._stroke.color=this.options.color,this._stroke.opacity=this.options.opacity),this.options.fill&&(this._fill.color=this.options.fillColor||this.options.color,this._fill.opacity=this.options.fillOpacity)},_updatePath:function(){this._container.style.display="none",this._path.v=this.getPathString()+" ",this._container.style.display=""}}),L.Map.include(L.Browser.svg||!L.Browser.vml?{}:{_initPathRoot:function(){this._pathRoot||(this._pathRoot=document.createElement("div"),this._pathRoot.className="leaflet-vml-container",this._panes.overlayPane.appendChild(this._pathRoot),this.on("moveend",this._updatePathViewport),this._updatePathViewport())}}),L.Browser.canvas=function(){return!!document.createElement("canvas").getContext}(),L.Path=L.Path.SVG&&!window.L_PREFER_CANVAS||!L.Browser.canvas?L.Path:L.Path.extend({statics:{CANVAS:!0,SVG:!1},options:{updateOnMoveEnd:!0},_initElements:function(){this._map._initPathRoot(),this._ctx=this._map._canvasCtx},_updateStyle:function(){this.options.stroke&&(this._ctx.lineWidth=this.options.weight,this._ctx.strokeStyle=this.options.color),this.options.fill&&(this._ctx.fillStyle=this.options.fillColor||this.options.color)},_drawPath:function(){var a,b,c,d,e,f;this._ctx.beginPath();for(a=0,c=this._parts.length;af&&(g=h,f=i);f>c&&(b[g]=1,this._simplifyDPStep(a,b,c,d,g),this._simplifyDPStep(a,b,c,g,e))},_reducePoints:function(a,b){var c=[a[0]];for(var d=1,e=0,f=a.length;db&&(c.push(a[d]),e=d);return eb.max.x&&(c|=2),a.yb.max.y&&(c|=8),c},_sqDist:function(a,b){var c=b.x-a.x,d=b.y-a.y;return c*c+d*d},_sqClosestPointOnSegment:function(a,b,c,d){var e=b.x,f=b.y,g=c.x-e,h=c.y-f,i=g*g+h*h,j;return i>0&&(j=((a.x-e)*g+(a.y-f)*h)/i,j>1?(e=c.x,f=c.y):j>0&&(e+=g*j,f+=h*j)),g=a.x-e,h=a.y-f,d?g*g+h*h:new L.Point(e,f)}},L.Polyline=L.Path.extend({initialize:function(a,b){L.Path.prototype.initialize.call(this,b),this._latlngs=a},options:{smoothFactor:1,noClip:!1,updateOnMoveEnd:!0},projectLatlngs:function(){this._originalPoints=[];for(var a=0,b=this._latlngs.length;aa.max.x||c.y-b>a.max.y||c.x+ba.y!=e.y>a.y&&a.x<(e.x-d.x)*(a.y-d.y)/(e.y-d.y)+d.x&&(b=!b)}return b}}:{}),L.Circle.include(L.Path.CANVAS?{_drawPath:function(){var a=this._point;this._ctx.beginPath(),this._ctx.arc(a.x,a.y,this._radius,0,Math.PI*2)},_containsPoint:function(a){var b=this._point,c=this.options.stroke?this.options.weight/2:0;return a.distanceTo(b)<=this._radius+c}}:{}),L.GeoJSON=L.FeatureGroup.extend({initialize:function(a,b){L.Util.setOptions(this,b),this._geojson=a,this._layers={},a&&this.addGeoJSON(a)},addGeoJSON:function(a){if(a.features){for(var b=0,c=a.features.length;b1)return;var b=a.touches&&a.touches.length===1?a.touches[0]:a,c=b.target;L.DomEvent.preventDefault(a),L.Browser.touch&&c.tagName.toLowerCase()==="a"&&(c.className+=" leaflet-active"),this._moved=!1;if(this._moving)return;L.Browser.touch||(L.DomUtil.disableTextSelection(),this._setMovingCursor()),this._startPos=this._newPos=L.DomUtil.getPosition(this._element),this._startPoint=new L.Point(b.clientX,b.clientY),L.DomEvent.addListener(document,L.Draggable.MOVE,this._onMove,this),L.DomEvent.addListener(document,L.Draggable.END,this._onUp,this)},_onMove:function(a){if(a.touches&&a.touches.length>1)return;L.DomEvent.preventDefault(a);var b=a.touches&&a.touches.length===1?a.touches[0]:a;this._moved||(this.fire("dragstart"),this._moved=!0),this._moving=!0;var c=new L.Point(b.clientX,b.clientY);this._newPos=this._startPos.add(c).subtract(this._startPoint),L.Util.requestAnimFrame(this._updatePosition,this,!0,this._dragStartTarget)},_updatePosition:function(){this.fire("predrag"),L.DomUtil.setPosition(this._element,this._newPos),this.fire("drag")},_onUp:function(a){if(a.changedTouches){var b=a.changedTouches[0],c=b.target,d=this._newPos&&this._newPos.distanceTo(this._startPos)||0;c.tagName.toLowerCase()==="a"&&(c.className=c.className.replace(" leaflet-active","")),d0&&c<=f,d=b}function l(a){e&&(g.type="dblclick",b(g),d=null)}var d,e=!1,f=250,g,h="_leaflet_",i="touchstart",j="touchend";a[h+i+c]=k,a[h+j+c]=l,a.addEventListener(i,k,!1),a.addEventListener(j,l,!1)},removeDoubleTapListener:function(a,b){var c="_leaflet_";a.removeEventListener(a,a[c+"touchstart"+b],!1),a.removeEventListener(a,a[c+"touchend"+b],!1)}}),L.Map.TouchZoom=L.Handler.extend({addHooks:function(){L.DomEvent.addListener(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){L.DomEvent.removeListener(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(a){if(!a.touches||a.touches.length!==2||this._map._animatingZoom)return;var b=this._map.mouseEventToLayerPoint(a.touches[0]),c=this._map.mouseEventToLayerPoint(a.touches[1]),d=this._map.containerPointToLayerPoint(this._map.getSize().divideBy(2));this._startCenter=b.add(c).divideBy(2,!0),this._startDist=b.distanceTo(c),this._moved=!1,this._zooming=!0,this._centerOffset=d.subtract(this._startCenter),L.DomEvent.addListener(document,"touchmove",this._onTouchMove,this),L.DomEvent.addListener(document,"touchend",this._onTouchEnd,this),L.DomEvent.preventDefault(a)},_onTouchMove:function(a){if(!a.touches||a.touches.length!==2)return;this._moved||(this._map._mapPane.className+=" leaflet-zoom-anim",this._map.fire("zoomstart").fire("movestart")._prepareTileBg(),this._moved=!0);var b=this._map.mouseEventToLayerPoint(a.touches[0]),c=this._map.mouseEventToLayerPoint(a.touches[1]);this._scale=b.distanceTo(c)/this._startDist,this._delta=b.add(c).divideBy(2,!0).subtract(this._startCenter),this._map._tileBg.style.webkitTransform=[L.DomUtil.getTranslateString(this._delta),L.DomUtil.getScaleString(this._scale,this._startCenter)].join(" "),L.DomEvent.preventDefault(a)},_onTouchEnd:function(a){if(!this._moved||!this._zooming)return;this._zooming=!1;var b=this._map.getZoom(),c=Math.log(this._scale)/Math.LN2,d=c>0?Math.ceil(c):Math.floor(c),e=this._map._limitZoom(b+d),f=e-b,g=this._centerOffset.subtract(this._delta).divideBy(this._scale),h=this._map.getPixelOrigin().add(this._startCenter).add(g),i=this._map.unproject(h);L.DomEvent.removeListener(document,"touchmove",this._onTouchMove),L.DomEvent.removeListener(document,"touchend",this._onTouchEnd);var j=Math.pow(2,f);this._map._runAnimation(i,e,j/this._scale,this._startCenter.add(g))}}),L.Map.BoxZoom=L.Handler.extend({initialize:function(a){this._map=a,this._container=a._container,this._pane=a._panes.overlayPane},addHooks:function(){L.DomEvent.addListener(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){L.DomEvent.removeListener(this._container,"mousedown",this._onMouseDown)},_onMouseDown:function(a){if(!a.shiftKey||a.which!==1&&a.button!==1)return!1;L.DomUtil.disableTextSelection(),this._startLayerPoint=this._map.mouseEventToLayerPoint(a),this._box=L.DomUtil.create("div","leaflet-zoom-box",this._pane),L.DomUtil.setPosition(this._box,this._startLayerPoint),this._container.style.cursor="crosshair",L.DomEvent.addListener(document,"mousemove",this._onMouseMove,this),L.DomEvent.addListener(document,"mouseup",this._onMouseUp,this),L.DomEvent.preventDefault(a)},_onMouseMove:function(a){var b=this._map.mouseEventToLayerPoint(a),c=b.x-this._startLayerPoint.x,d=b.y-this._startLayerPoint.y,e=Math.min(b.x,this._startLayerPoint.x),f=Math.min(b.y,this._startLayerPoint.y),g=new L.Point(e,f);L.DomUtil.setPosition(this._box,g),this._box.style.width=Math.abs(c)-4+"px",this._box.style.height=Math.abs(d)-4+"px"},_onMouseUp:function(a){this._pane.removeChild(this._box),this._container.style.cursor="",L.DomUtil.enableTextSelection(),L.DomEvent.removeListener(document,"mousemove",this._onMouseMove),L.DomEvent.removeListener(document,"mouseup",this._onMouseUp);var b=this._map.mouseEventToLayerPoint(a),c=new L.LatLngBounds(this._map.layerPointToLatLng(this._startLayerPoint),this._map.layerPointToLatLng(b));this._map.fitBounds(c)}}),L.Handler.MarkerDrag=L.Handler.extend({initialize:function(a){this._marker=a},addHooks:function(){var a=this._marker._icon;this._draggable||(this._draggable=new L.Draggable(a,a),this._draggable.on("dragstart",this._onDragStart,this).on("drag",this._onDrag,this).on("dragend",this._onDragEnd,this)),this._draggable.enable()},removeHooks:function(){this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},_onDragStart:function(a){this._marker.closePopup().fire("movestart").fire("dragstart")},_onDrag:function(a){var b=L.DomUtil.getPosition(this._marker._icon);this._marker._shadow&&L.DomUtil.setPosition(this._marker._shadow,b),this._marker._latlng=this._marker._map.layerPointToLatLng(b),this._marker.fire("move").fire("drag")},_onDragEnd:function(){this._marker.fire("moveend").fire("dragend")}}),L.Control={},L.Control.Position={TOP_LEFT:"topLeft",TOP_RIGHT:"topRight",BOTTOM_LEFT:"bottomLeft",BOTTOM_RIGHT:"bottomRight"},L.Map.include({addControl:function(a){a.onAdd(this);var b=a.getPosition(),c=this._controlCorners[b],d=a.getContainer();return L.DomUtil.addClass(d,"leaflet-control"),b.indexOf("bottom")!==-1?c.insertBefore(d,c.firstChild):c.appendChild(d),this},removeControl:function(a){var b=a.getPosition(),c=this._controlCorners[b],d=a.getContainer();return c.removeChild(d),a.onRemove&&a.onRemove(this),this},_initControlPos:function(){var a=this._controlCorners={},b="leaflet-",c=b+"top",d=b+"bottom",e=b+"left",f=b+"right",g=L.DomUtil.create("div",b+"control-container",this._container);L.Browser.touch&&(g.className+=" "+b+"big-buttons"),a.topLeft=L.DomUtil.create("div",c+" "+e,g),a.topRight=L.DomUtil.create("div",c+" "+f,g),a.bottomLeft=L.DomUtil.create("div",d+" "+e,g),a.bottomRight=L.DomUtil.create("div",d+" "+f,g)}}),L.Control.Zoom=L.Class.extend({onAdd:function(a){this._map=a,this._container=L.DomUtil.create("div","leaflet-control-zoom"),this._zoomInButton=this._createButton("Zoom in","leaflet-control-zoom-in",this._map.zoomIn,this._map),this._zoomOutButton=this._createButton("Zoom out","leaflet-control-zoom-out",this._map.zoomOut,this._map),this._container.appendChild(this._zoomInButton),this._container.appendChild(this._zoomOutButton)},getContainer:function(){return this._container},getPosition:function(){return L.Control.Position.TOP_LEFT},_createButton:function(a,b,c,d){var e=document.createElement("a");return e.href="#",e.title=a,e.className=b,L.Browser.touch||L.DomEvent.disableClickPropagation(e),L.DomEvent.addListener(e,"click",L.DomEvent.preventDefault),L.DomEvent.addListener(e,"click",c,d),e}}),L.Control.Attribution=L.Class.extend({initialize:function(a){this._prefix=a||'Powered by Leaflet',this._attributions={}},onAdd:function(a){this._container=L.DomUtil.create("div","leaflet-control-attribution"),L.DomEvent.disableClickPropagation(this._container),this._map=a,this._update()},getPosition:function(){return L.Control.Position.BOTTOM_RIGHT},getContainer:function(){return this._container},setPrefix:function(a){this._prefix=a,this._update()},addAttribution:function(a){if(!a)return;this._attributions[a]||(this._attributions[a]=0),this._attributions[a]++,this._update()},removeAttribution:function(a){if(!a)return;this._attributions[a]--,this._update()},_update:function(){if(!this._map)return;var a=[];for(var b in this._attributions)this._attributions.hasOwnProperty(b)&&a.push(b);var c=[];this._prefix&&c.push(this._prefix),a.length&&c.push(a.join(", ")),this._container.innerHTML=c.join(" — ")}}),L.Control.Layers=L.Class.extend({options:{collapsed:!0},initialize:function(a,b,c){L.Util.setOptions(this,c),this._layers={};for(var d in a)a.hasOwnProperty(d)&&this._addLayer(a[d],d);for(d in b)b.hasOwnProperty(d)&&this._addLayer(b[d],d,!0)},onAdd:function(a){this._map=a,this._initLayout(),this._update()},getContainer:function(){return this._container},getPosition:function(){return L.Control.Position.TOP_RIGHT},addBaseLayer:function(a,b){return this._addLayer(a,b),this._update(),this},addOverlay:function(a,b){return this._addLayer(a,b,!0),this._update(),this},removeLayer:function(a){var b=L.Util.stamp(a);return delete this._layers[b],this._update(),this},_initLayout:function(){this._container=L.DomUtil.create("div","leaflet-control-layers"),L.Browser.touch||L.DomEvent.disableClickPropagation(this._container),this._form=L.DomUtil.create("form","leaflet-control-layers-list");if(this.options.collapsed){L.DomEvent.addListener(this._container,"mouseover",this._expand,this),L.DomEvent.addListener(this._container,"mouseout",this._collapse,this);var a=this._layersLink=L.DomUtil.create("a","leaflet-control-layers-toggle");a.href="#",a.title="Layers",L.Browser.touch?L.DomEvent.addListener(a,"click",this._expand,this):L.DomEvent.addListener(a,"focus",this._expand,this),this._map.on("movestart",this._collapse,this),this._container.appendChild(a)}else this._expand();this._baseLayersList=L.DomUtil.create("div","leaflet-control-layers-base",this._form),this._separator=L.DomUtil.create("div","leaflet-control-layers-separator",this._form),this._overlaysList=L.DomUtil.create("div","leaflet-control-layers-overlays",this._form),this._container.appendChild(this._form)},_addLayer:function(a,b,c){var d=L.Util.stamp(a);this._layers[d]={layer:a,name:b,overlay:c}},_update:function(){if(!this._container)return;this._baseLayersList.innerHTML="",this._overlaysList.innerHTML="";var a=!1,b=!1;for(var c in this._layers)if(this._layers.hasOwnProperty(c)){var d=this._layers[c];this._addItem(d),b=b||d.overlay,a=a||!d.overlay}this._separator.style.display=b&&a?"":"none"},_addItem:function(a,b){var c=document.createElement("label"),d=document.createElement("input");a.overlay||(d.name="leaflet-base-layers"),d.type=a.overlay?"checkbox":"radio",d.checked=this._map.hasLayer(a.layer),d.layerId=L.Util.stamp(a.layer),L.DomEvent.addListener(d,"click",this._onInputClick,this);var e=document.createTextNode(" "+a.name);c.appendChild(d),c.appendChild(e);var f=a.overlay?this._overlaysList:this._baseLayersList;f.appendChild(c)},_onInputClick:function(){var a,b,c,d=this._form.getElementsByTagName("input"),e=d.length;for(a=0;a
3 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
4 | http://www.twitter.com/niklasvh
5 |
6 | Released under MIT License
7 | */
8 | (function(window, document, undefined){
9 |
10 | /*
11 | html2canvas v0.33
12 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
13 | http://www.twitter.com/niklasvh
14 |
15 | Released under MIT License
16 | */
17 |
18 | var html2canvas = {};
19 |
20 | html2canvas.logging = false;
21 |
22 | function h2clog(a) {
23 | if (html2canvas.logging && window.console && window.console.log) {
24 | window.console.log(a);
25 | }
26 | }
27 |
28 | html2canvas.log = h2clog; // for compatibility with the jquery plugin
29 |
30 | html2canvas.Util = {};
31 |
32 | html2canvas.Util.backgroundImage = function (src) {
33 |
34 | if (/data:image\/.*;base64,/i.test( src ) || /^(-webkit|-moz|linear-gradient|-o-)/.test( src )) {
35 | return src;
36 | }
37 |
38 | if (src.toLowerCase().substr( 0, 5 ) === 'url("') {
39 | src = src.substr( 5 );
40 | src = src.substr( 0, src.length - 2 );
41 | } else {
42 | src = src.substr( 4 );
43 | src = src.substr( 0, src.length - 1 );
44 | }
45 |
46 | return src;
47 | };
48 |
49 | html2canvas.Util.Bounds = function getBounds (el) {
50 | var clientRect,
51 | bounds = {};
52 |
53 | if (el.getBoundingClientRect){
54 | clientRect = el.getBoundingClientRect();
55 |
56 |
57 | // TODO add scroll position to bounds, so no scrolling of window necessary
58 | bounds.top = clientRect.top;
59 | bounds.bottom = clientRect.bottom || (clientRect.top + clientRect.height);
60 | bounds.left = clientRect.left;
61 |
62 | // older IE doesn't have width/height, but top/bottom instead
63 | bounds.width = clientRect.width || (clientRect.right - clientRect.left);
64 | bounds.height = clientRect.height || (clientRect.bottom - clientRect.top);
65 |
66 | return bounds;
67 |
68 | } /*else{
69 |
70 |
71 | p = $(el).offset();
72 |
73 | return {
74 | left: p.left + getCSS(el,"borderLeftWidth", true),
75 | top: p.top + getCSS(el,"borderTopWidth", true),
76 | width:$(el).innerWidth(),
77 | height:$(el).innerHeight()
78 | };
79 |
80 |
81 | } */
82 | }
83 |
84 | html2canvas.Util.getCSS = function (el, attribute) {
85 | // return jQuery(el).css(attribute);
86 | /*
87 | var val,
88 | left,
89 | rsLeft = el.runtimeStyle && el.runtimeStyle[ attribute ],
90 | style = el.style;
91 |
92 | if ( el.currentStyle ) {
93 | val = el.currentStyle[ attribute ];
94 | } else if (window.getComputedStyle) {
95 | val = document.defaultView.getComputedStyle(el, null)[ attribute ];
96 | }
97 | */
98 | // Check if we are not dealing with pixels, (Opera has issues with this)
99 | // Ported from jQuery css.js
100 | // From the awesome hack by Dean Edwards
101 | // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
102 |
103 | // If we're not dealing with a regular pixel number
104 | // but a number that has a weird ending, we need to convert it to pixels
105 |
106 | // if ( !/^-?\d+(?:px)?$/i.test( val ) && /^-?\d/.test( val ) ) {
107 | /*
108 | // Remember the original values
109 | left = style.left;
110 |
111 | // Put in the new values to get a computed value out
112 | if ( rsLeft ) {
113 | el.runtimeStyle.left = el.currentStyle.left;
114 | }
115 | style.left = attribute === "fontSize" ? "1em" : (val || 0);
116 | val = style.pixelLeft + "px";
117 |
118 | // Revert the changed values
119 | style.left = left;
120 | if ( rsLeft ) {
121 | el.runtimeStyle.left = rsLeft;
122 | }*/
123 | // val = $(el).css(attribute);
124 | // }
125 |
126 | /*
127 | var val = $(el).css(attribute);
128 |
129 | if (val === "medium") {
130 | val = 3;
131 | }*/
132 |
133 | return $(el).css(attribute);
134 |
135 |
136 | };
137 |
138 | html2canvas.Util.Extend = function (options, defaults) {
139 | var key;
140 | for (key in options) {
141 | if (options.hasOwnProperty(key)) {
142 | defaults[key] = options[key];
143 | }
144 | }
145 | return defaults;
146 | };
147 |
148 | html2canvas.Util.Children = function(el) {
149 | // $(el).contents() !== el.childNodes, Opera / IE have issues with that
150 | var children;
151 | try {
152 | children = $(el).contents();
153 | } catch (ex) {
154 | h2clog("html2canvas.Util.Children failed with exception: " + ex.message);
155 | children = [];
156 | }
157 | return children;
158 | };
159 |
160 | /*
161 | html2canvas v0.33
162 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
163 | http://www.twitter.com/niklasvh
164 |
165 | Released under MIT License
166 | */
167 |
168 | html2canvas.Generate = {};
169 |
170 |
171 |
172 | html2canvas.Generate.Gradient = function(src, bounds) {
173 | var canvas = document.createElement('canvas'),
174 | ctx = canvas.getContext('2d'),
175 | tmp,
176 | p0 = 0,
177 | p1 = 0,
178 | p2 = 0,
179 | p3 = 0,
180 | steps = [],
181 | position,
182 | i,
183 | len,
184 | lingrad,
185 | increment,
186 | p,
187 | img;
188 |
189 | canvas.width = bounds.width;
190 | canvas.height = bounds.height;
191 |
192 |
193 | function getColors(input) {
194 | var j = -1,
195 | color = '',
196 | chr;
197 |
198 | while( j++ < input.length ) {
199 | chr = input.charAt( j );
200 | if (chr === ')') {
201 | color += chr;
202 | steps.push( color );
203 | color = '';
204 | while (j++ < input.length && input.charAt( j ) !== ',') {
205 | }
206 | } else {
207 | color += chr;
208 | }
209 | }
210 | }
211 |
212 | if ( tmp = src.match(/-webkit-linear-gradient\((.*)\)/) ) {
213 |
214 | position = tmp[1].split( ",", 1 )[0];
215 | getColors( tmp[1].substr( position.length + 2 ) );
216 | position = position.split(' ');
217 |
218 | for (p = 0; p < position.length; p+=1) {
219 |
220 | switch(position[p]) {
221 | case 'top':
222 | p3 = bounds.height;
223 | break;
224 |
225 | case 'right':
226 | p0 = bounds.width;
227 | break;
228 |
229 | case 'bottom':
230 | p1 = bounds.height;
231 | break;
232 |
233 | case 'left':
234 | p2 = bounds.width;
235 | break;
236 | }
237 |
238 | }
239 |
240 | } else if (tmp = src.match(/-webkit-gradient\(linear, (\d+)[%]{0,1} (\d+)[%]{0,1}, (\d+)[%]{0,1} (\d+)[%]{0,1}, from\((.*)\), to\((.*)\)\)/)) {
241 |
242 | p0 = (tmp[1] * bounds.width) / 100;
243 | p1 = (tmp[2] * bounds.height) / 100;
244 | p2 = (tmp[3] * bounds.width) / 100;
245 | p3 = (tmp[4] * bounds.height) / 100;
246 |
247 | steps.push(tmp[5]);
248 | steps.push(tmp[6]);
249 |
250 | } else if (tmp = src.match(/-moz-linear-gradient\((\d+)[%]{0,1} (\d+)[%]{0,1}, (.*)\)/)) {
251 |
252 | p0 = (tmp[1] * bounds.width) / 100;
253 | p1 = (tmp[2] * bounds.width) / 100;
254 | p2 = bounds.width - p0;
255 | p3 = bounds.height - p1;
256 | getColors( tmp[3] );
257 |
258 | } else {
259 | return;
260 | }
261 |
262 | lingrad = ctx.createLinearGradient( p0, p1, p2, p3 );
263 | increment = 1 / (steps.length - 1);
264 |
265 | for (i = 0, len = steps.length; i < len; i+=1) {
266 | try {
267 | lingrad.addColorStop(increment * i, steps[i]);
268 | }
269 | catch(e) {
270 | h2clog(['failed to add color stop: ', e, '; tried to add: ', steps[i], '; stop: ', i, '; in: ', src]);
271 | }
272 | }
273 |
274 | ctx.fillStyle = lingrad;
275 |
276 | // draw shapes
277 | ctx.fillRect(0, 0, bounds.width,bounds.height);
278 |
279 | img = new Image();
280 | img.src = canvas.toDataURL();
281 |
282 | return img;
283 |
284 | }
285 |
286 | html2canvas.Generate.ListAlpha = function(number) {
287 | var tmp = "",
288 | modulus;
289 |
290 | do {
291 | modulus = number % 26;
292 | tmp = String.fromCharCode((modulus) + 64) + tmp;
293 | number = number / 26;
294 | }while((number*26) > 26);
295 |
296 | return tmp;
297 | }
298 |
299 | html2canvas.Generate.ListRoman = function(number) {
300 | var romanArray = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"],
301 | decimal = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1],
302 | roman = "",
303 | v,
304 | len = romanArray.length;
305 |
306 | if (number <= 0 || number >= 4000) {
307 | return number;
308 | }
309 |
310 | for (v=0; v < len; v+=1) {
311 | while (number >= decimal[v]) {
312 | number -= decimal[v];
313 | roman += romanArray[v];
314 | }
315 | }
316 |
317 | return roman;
318 |
319 | }
320 |
321 | /*
322 | html2canvas v0.33
323 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
324 | http://www.twitter.com/niklasvh
325 |
326 | Released under MIT License
327 | */
328 |
329 | /*
330 | * New function for traversing elements
331 | */
332 |
333 | html2canvas.Parse = function (element, images, opts) {
334 | window.scroll(0,0);
335 | opts = opts || {};
336 |
337 | // select body by default
338 | if (element === undefined) {
339 | element = document.body;
340 | }
341 |
342 |
343 | var support = {
344 | rangeBounds: false
345 |
346 | },
347 | options = {
348 | iframeDefault: "default",
349 | ignoreElements: "IFRAME|OBJECT|PARAM",
350 | useOverflow: true,
351 | letterRendering: false
352 | },
353 | needReorder = false,
354 | numDraws = 0,
355 | fontData = {},
356 | doc = element.ownerDocument,
357 | ignoreElementsRegExp = new RegExp("(" + options.ignoreElements + ")"),
358 | body = doc.body,
359 | r,
360 | testElement,
361 | rangeBounds,
362 | rangeHeight,
363 | stack,
364 | ctx,
365 | docDim,
366 | i,
367 | children,
368 | childrenLen;
369 |
370 | options = html2canvas.Util.Extend(opts, options);
371 |
372 | images = images || {};
373 |
374 | // Test whether we can use ranges to measure bounding boxes
375 | // Opera doesn't provide valid bounds.height/bottom even though it supports the method.
376 |
377 |
378 | if (doc.createRange) {
379 | r = doc.createRange();
380 | //this.support.rangeBounds = new Boolean(r.getBoundingClientRect);
381 | if (r.getBoundingClientRect){
382 | testElement = doc.createElement('boundtest');
383 | testElement.style.height = "123px";
384 | testElement.style.display = "block";
385 | body.appendChild(testElement);
386 |
387 | r.selectNode(testElement);
388 | rangeBounds = r.getBoundingClientRect();
389 | rangeHeight = rangeBounds.height;
390 |
391 | if (rangeHeight === 123) {
392 | support.rangeBounds = true;
393 | }
394 | body.removeChild(testElement);
395 |
396 |
397 | }
398 |
399 | }
400 |
401 |
402 | /*
403 | var rootStack = new this.storageContext($(document).width(),$(document).height());
404 | rootStack.opacity = this.getCSS(this.element,"opacity");
405 | var stack = this.newElement(this.element,rootStack);
406 |
407 |
408 | this.parseElement(this.element,stack);
409 | */
410 |
411 |
412 | function docSize(){
413 |
414 | return {
415 | width: Math.max(
416 | Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth),
417 | Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth),
418 | Math.max(doc.body.clientWidth, doc.documentElement.clientWidth)
419 | ),
420 | height: Math.max(
421 | Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight),
422 | Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight),
423 | Math.max(doc.body.clientHeight, doc.documentElement.clientHeight)
424 | )
425 | };
426 |
427 | }
428 |
429 | var getCSS = html2canvas.Util.getCSS;
430 | function getCSSInt(element, attribute) {
431 | var val = parseInt(getCSS(element, attribute), 10);
432 | return (isNaN(val)) ? 0 : val; // borders in old IE are throwing 'medium' for demo.html
433 | }
434 |
435 | // Drawing a rectangle
436 | function renderRect (ctx, x, y, w, h, bgcolor) {
437 | if (bgcolor !=="transparent"){
438 | ctx.setVariable("fillStyle", bgcolor);
439 | ctx.fillRect (x, y, w, h);
440 | numDraws+=1;
441 | }
442 | }
443 |
444 |
445 | function textTransform (text, transform) {
446 | switch(transform){
447 | case "lowercase":
448 | return text.toLowerCase();
449 |
450 | case "capitalize":
451 | return text.replace( /(^|\s|:|-|\(|\))([a-z])/g , function (m, p1, p2) {
452 | if (m.length > 0) {
453 | return p1 + p2.toUpperCase();
454 | }
455 | } );
456 |
457 | case "uppercase":
458 | return text.toUpperCase();
459 |
460 | default:
461 | return text;
462 |
463 | }
464 |
465 | }
466 |
467 | function trimText (text) {
468 | return text.replace(/^\s*/g, "").replace(/\s*$/g, "");
469 | }
470 |
471 | function fontMetrics (font, fontSize) {
472 |
473 | if (fontData[font + "-" + fontSize] !== undefined) {
474 | return fontData[font + "-" + fontSize];
475 | }
476 |
477 |
478 | var container = doc.createElement('div'),
479 | img = doc.createElement('img'),
480 | span = doc.createElement('span'),
481 | baseline,
482 | middle,
483 | metricsObj;
484 |
485 |
486 | container.style.visibility = "hidden";
487 | container.style.fontFamily = font;
488 | container.style.fontSize = fontSize;
489 | container.style.margin = 0;
490 | container.style.padding = 0;
491 |
492 | body.appendChild(container);
493 |
494 |
495 |
496 | // http://probablyprogramming.com/2009/03/15/the-tiniest-gif-ever (handtinywhite.gif)
497 | img.src = "data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACwAAAAAAQABAAACAkQBADs=";
498 | img.width = 1;
499 | img.height = 1;
500 |
501 | img.style.margin = 0;
502 | img.style.padding = 0;
503 | img.style.verticalAlign = "baseline";
504 |
505 | span.style.fontFamily = font;
506 | span.style.fontSize = fontSize;
507 | span.style.margin = 0;
508 | span.style.padding = 0;
509 |
510 |
511 |
512 |
513 | span.appendChild(doc.createTextNode('Hidden Text'));
514 | container.appendChild(span);
515 | container.appendChild(img);
516 | baseline = (img.offsetTop - span.offsetTop) + 1;
517 |
518 | container.removeChild(span);
519 | container.appendChild(doc.createTextNode('Hidden Text'));
520 |
521 | container.style.lineHeight = "normal";
522 | img.style.verticalAlign = "super";
523 |
524 | middle = (img.offsetTop-container.offsetTop) + 1;
525 | metricsObj = {
526 | baseline: baseline,
527 | lineWidth: 1,
528 | middle: middle
529 | };
530 |
531 |
532 | fontData[font + "-" + fontSize] = metricsObj;
533 |
534 | body.removeChild(container);
535 |
536 | return metricsObj;
537 |
538 | }
539 |
540 |
541 | function drawText(currentText, x, y, ctx){
542 | if (trimText(currentText).length>0) {
543 | ctx.fillText(currentText,x,y);
544 | numDraws+=1;
545 | }
546 | }
547 |
548 |
549 | function renderText(el, textNode, stack) {
550 | var ctx = stack.ctx,
551 | family = getCSS(el, "fontFamily"),
552 | size = getCSS(el, "fontSize"),
553 | color = getCSS(el, "color"),
554 | text_decoration = getCSS(el, "textDecoration"),
555 | text_align = getCSS(el, "textAlign"),
556 | letter_spacing = getCSS(el, "letterSpacing"),
557 | bounds,
558 | text,
559 | metrics,
560 | renderList,
561 | bold = getCSS(el, "fontWeight"),
562 | font_style = getCSS(el, "fontStyle"),
563 | font_variant = getCSS(el, "fontVariant"),
564 | align = false,
565 | newTextNode,
566 | textValue,
567 | textOffset = 0,
568 | oldTextNode,
569 | c,
570 | range,
571 | parent,
572 | wrapElement,
573 | backupText;
574 |
575 | // apply text-transform:ation to the text
576 |
577 |
578 |
579 | textNode.nodeValue = textTransform(textNode.nodeValue, getCSS(el, "textTransform"));
580 | text = trimText(textNode.nodeValue);
581 |
582 | if (text.length>0){
583 |
584 | if (text_decoration !== "none"){
585 | metrics = fontMetrics(family, size);
586 | }
587 |
588 | text_align = text_align.replace(["-webkit-auto"],["auto"]);
589 |
590 | if (options.letterRendering === false && /^(left|right|justify|auto)$/.test(text_align) && /^(normal|none)$/.test(letter_spacing)){
591 | // this.setContextVariable(ctx,"textAlign",text_align);
592 | renderList = textNode.nodeValue.split(/(\b| )/);
593 |
594 | }else{
595 | // this.setContextVariable(ctx,"textAlign","left");
596 | renderList = textNode.nodeValue.split("");
597 | }
598 |
599 | switch(parseInt(bold, 10)){
600 | case 401:
601 | bold = "bold";
602 | break;
603 | case 400:
604 | bold = "normal";
605 | break;
606 | }
607 |
608 | ctx.setVariable("fillStyle", color);
609 |
610 | /*
611 | need to be defined in the order as defined in http://www.w3.org/TR/CSS21/fonts.html#font-shorthand
612 | to properly work in Firefox
613 | */
614 | ctx.setVariable("font", font_style+ " " + font_variant + " " + bold + " " + size + " " + family);
615 |
616 | if (align){
617 | ctx.setVariable("textAlign", "right");
618 | }else{
619 | ctx.setVariable("textAlign", "left");
620 | }
621 |
622 |
623 | /*
624 | if (stack.clip){
625 | ctx.rect (stack.clip.left, stack.clip.top, stack.clip.width, stack.clip.height);
626 | ctx.clip();
627 | }
628 | */
629 |
630 |
631 | oldTextNode = textNode;
632 |
633 |
634 | for (c=0; c < renderList.length; c+=1) {
635 | textValue = null;
636 |
637 |
638 |
639 | if (support.rangeBounds){
640 | // getBoundingClientRect is supported for ranges
641 | if (text_decoration !== "none" || trimText(renderList[c]).length !== 0) {
642 | textValue = renderList[c];
643 | if (doc.createRange){
644 | range = doc.createRange();
645 |
646 | range.setStart(textNode, textOffset);
647 | range.setEnd(textNode, textOffset + textValue.length);
648 | }else{
649 | // TODO add IE support
650 | range = body.createTextRange();
651 | }
652 |
653 | if (range.getBoundingClientRect()) {
654 | bounds = range.getBoundingClientRect();
655 | }else{
656 | bounds = {};
657 | }
658 |
659 | }
660 | }else{
661 | // it isn't supported, so let's wrap it inside an element instead and get the bounds there
662 |
663 | // IE 9 bug
664 | if (typeof oldTextNode.nodeValue !== "string" ){
665 | continue;
666 | }
667 |
668 | newTextNode = oldTextNode.splitText(renderList[c].length);
669 |
670 | parent = oldTextNode.parentNode;
671 | wrapElement = doc.createElement('wrapper');
672 | backupText = oldTextNode.cloneNode(true);
673 |
674 | wrapElement.appendChild(oldTextNode.cloneNode(true));
675 | parent.replaceChild(wrapElement, oldTextNode);
676 |
677 | bounds = html2canvas.Util.Bounds(wrapElement);
678 |
679 | textValue = oldTextNode.nodeValue;
680 |
681 | oldTextNode = newTextNode;
682 | parent.replaceChild(backupText, wrapElement);
683 |
684 |
685 | }
686 |
687 | if (textValue !== null){
688 | drawText(textValue, bounds.left, bounds.bottom, ctx);
689 | }
690 |
691 | switch(text_decoration) {
692 | case "underline":
693 | // Draws a line at the baseline of the font
694 | // TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size
695 | renderRect(ctx, bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, 1, color);
696 | break;
697 | case "overline":
698 | renderRect(ctx, bounds.left, bounds.top, bounds.width, 1, color);
699 | break;
700 | case "line-through":
701 | // TODO try and find exact position for line-through
702 | renderRect(ctx, bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 1, color);
703 | break;
704 |
705 | }
706 |
707 |
708 |
709 |
710 |
711 | textOffset += renderList[c].length;
712 |
713 | }
714 |
715 |
716 |
717 | }
718 |
719 | }
720 |
721 | function listPosition (element, val) {
722 | var boundElement = doc.createElement( "boundelement" ),
723 | type,
724 | bounds;
725 |
726 | boundElement.style.display = "inline";
727 | //boundElement.style.width = "1px";
728 | //boundElement.style.height = "1px";
729 |
730 | type = element.style.listStyleType;
731 | element.style.listStyleType = "none";
732 |
733 | boundElement.appendChild( doc.createTextNode( val ) );
734 |
735 |
736 | element.insertBefore(boundElement, element.firstChild);
737 |
738 |
739 | bounds = html2canvas.Util.Bounds( boundElement );
740 | element.removeChild( boundElement );
741 | element.style.listStyleType = type;
742 | return bounds;
743 |
744 | }
745 |
746 |
747 | function renderListItem(element, stack, elBounds) {
748 |
749 |
750 | var position = getCSS(element, "listStylePosition"),
751 | x,
752 | y,
753 | type = getCSS(element, "listStyleType"),
754 | currentIndex,
755 | text,
756 | listBounds,
757 | bold = getCSS(element, "fontWeight");
758 |
759 | if (/^(decimal|decimal-leading-zero|upper-alpha|upper-latin|upper-roman|lower-alpha|lower-greek|lower-latin|lower-roman)$/i.test(type)) {
760 |
761 | // TODO remove jQuery dependency
762 | currentIndex = $(element).index()+1;
763 |
764 | switch(type){
765 | case "decimal":
766 | text = currentIndex;
767 | break;
768 | case "decimal-leading-zero":
769 | if (currentIndex.toString().length === 1){
770 | text = currentIndex = "0" + currentIndex.toString();
771 | }else{
772 | text = currentIndex.toString();
773 | }
774 | break;
775 | case "upper-roman":
776 | text = html2canvas.Generate.ListRoman( currentIndex );
777 | break;
778 | case "lower-roman":
779 | text = html2canvas.Generate.ListRoman( currentIndex ).toLowerCase();
780 | break;
781 | case "lower-alpha":
782 | text = html2canvas.Generate.ListAlpha( currentIndex ).toLowerCase();
783 | break;
784 | case "upper-alpha":
785 | text = html2canvas.Generate.ListAlpha( currentIndex );
786 | break;
787 | }
788 |
789 |
790 | text += ". ";
791 | listBounds = listPosition(element, text);
792 |
793 |
794 |
795 | switch(bold){
796 | case 401:
797 | bold = "bold";
798 | break;
799 | case 400:
800 | bold = "normal";
801 | break;
802 | }
803 |
804 |
805 |
806 |
807 | ctx.setVariable( "fillStyle", getCSS(element, "color") );
808 | ctx.setVariable( "font", getCSS(element, "fontVariant") + " " + bold + " " + getCSS(element, "fontStyle") + " " + getCSS(element, "fontSize") + " " + getCSS(element, "fontFamily") );
809 |
810 |
811 | if ( position === "inside" ) {
812 | ctx.setVariable("textAlign", "left");
813 | // this.setFont(stack.ctx, element, false);
814 | x = elBounds.left;
815 |
816 | }else{
817 | return;
818 | /*
819 | TODO really need to figure out some more accurate way to try and find the position.
820 | as defined in http://www.w3.org/TR/CSS21/generate.html#propdef-list-style-position, it does not even have a specified "correct" position, so each browser
821 | may display it whatever way it feels like.
822 | "The position of the list-item marker adjacent to floats is undefined in CSS 2.1. CSS 2.1 does not specify the precise location of the marker box or its position in the painting order"
823 | */
824 | ctx.setVariable("textAlign", "right");
825 | // this.setFont(stack.ctx, element, true);
826 | x = elBounds.left - 10;
827 | }
828 |
829 | y = listBounds.bottom;
830 |
831 | drawText(text, x, y, ctx)
832 |
833 |
834 | }
835 |
836 |
837 | }
838 |
839 | function loadImage (src){
840 | var img = images[src];
841 | if (img && img.succeeded === true) {
842 | return img.img;
843 | } else {
844 | return false;
845 | }
846 | }
847 |
848 |
849 |
850 |
851 |
852 |
853 | function clipBounds(src, dst){
854 |
855 | var x = Math.max(src.left, dst.left),
856 | y = Math.max(src.top, dst.top),
857 | x2 = Math.min((src.left + src.width), (dst.left + dst.width)),
858 | y2 = Math.min((src.top + src.height), (dst.top + dst.height));
859 |
860 | return {
861 | left:x,
862 | top:y,
863 | width:x2-x,
864 | height:y2-y
865 | };
866 |
867 | }
868 |
869 | function setZ(zIndex, parentZ){
870 | // TODO fix static elements overlapping relative/absolute elements under same stack, if they are defined after them
871 |
872 | if (!parentZ){
873 | this.zStack = h2czContext(0);
874 | return this.zStack;
875 | }
876 |
877 | if (zIndex !== "auto"){
878 | needReorder = true;
879 | var newContext = h2czContext(zIndex);
880 | parentZ.children.push(newContext);
881 | return newContext;
882 |
883 | }
884 |
885 | return parentZ;
886 |
887 | }
888 |
889 | function renderBorders(el, ctx, bounds, clip){
890 |
891 | /*
892 | * TODO add support for different border-style's than solid
893 | */
894 |
895 | var x = bounds.left,
896 | y = bounds.top,
897 | w = bounds.width,
898 | h = bounds.height,
899 | borderSide,
900 | borderData,
901 | bx,
902 | by,
903 | bw,
904 | bh,
905 | borderBounds,
906 | borders = (function(el){
907 | var borders = [],
908 | sides = ["Top","Right","Bottom","Left"],
909 | s;
910 |
911 | for (s = 0; s < 4; s+=1){
912 | borders.push({
913 | width: getCSSInt(el, 'border' + sides[s] + 'Width'),
914 | color: getCSS(el, 'border' + sides[s] + 'Color')
915 | });
916 | }
917 |
918 | return borders;
919 |
920 | }(el));
921 |
922 |
923 | for (borderSide = 0; borderSide < 4; borderSide+=1){
924 | borderData = borders[borderSide];
925 |
926 | if (borderData.width>0){
927 | bx = x;
928 | by = y;
929 | bw = w;
930 | bh = h - (borders[2].width);
931 |
932 | switch(borderSide){
933 | case 0:
934 | // top border
935 | bh = borders[0].width;
936 | break;
937 | case 1:
938 | // right border
939 | bx = x + w - (borders[1].width);
940 | bw = borders[1].width;
941 | break;
942 | case 2:
943 | // bottom border
944 | by = (by + h) - (borders[2].width);
945 | bh = borders[2].width;
946 | break;
947 | case 3:
948 | // left border
949 | bw = borders[3].width;
950 | break;
951 | }
952 |
953 | borderBounds = {
954 | left:bx,
955 | top:by,
956 | width: bw,
957 | height:bh
958 | };
959 |
960 | if (clip){
961 | borderBounds = clipBounds(borderBounds, clip);
962 | }
963 |
964 |
965 | if (borderBounds.width>0 && borderBounds.height>0){
966 | renderRect(ctx, bx, by, borderBounds.width, borderBounds.height, borderData.color);
967 | }
968 |
969 |
970 | }
971 | }
972 |
973 | return borders;
974 |
975 | }
976 |
977 |
978 | function renderFormValue (el, bounds, stack){
979 |
980 | var valueWrap = doc.createElement('valuewrap'),
981 | cssArr = ['lineHeight','textAlign','fontFamily','color','fontSize','paddingLeft','paddingTop','width','height','border','borderLeftWidth','borderTopWidth'],
982 | i,
983 | textValue,
984 | textNode,
985 | arrLen,
986 | style;
987 |
988 | for (i = 0, arrLen = cssArr.length; i < arrLen; i+=1){
989 | style = cssArr[i];
990 |
991 | try {
992 | valueWrap.style[style] = getCSS(el, style);
993 | } catch( e ) {
994 | // Older IE has issues with "border"
995 | h2clog("html2canvas: Parse: Exception caught in renderFormValue: " + e.message);
996 | }
997 | }
998 |
999 |
1000 | valueWrap.style.borderColor = "black";
1001 | valueWrap.style.borderStyle = "solid";
1002 | valueWrap.style.display = "block";
1003 | valueWrap.style.position = "absolute";
1004 | if (/^(submit|reset|button|text|password)$/.test(el.type) || el.nodeName === "SELECT"){
1005 | valueWrap.style.lineHeight = getCSS(el, "height");
1006 | }
1007 |
1008 |
1009 | valueWrap.style.top = bounds.top + "px";
1010 | valueWrap.style.left = bounds.left + "px";
1011 |
1012 | if (el.nodeName === "SELECT"){
1013 | // TODO increase accuracy of text position
1014 | textValue = el.options[el.selectedIndex].text;
1015 | } else{
1016 | textValue = el.value;
1017 | }
1018 | textNode = doc.createTextNode(textValue);
1019 |
1020 | valueWrap.appendChild(textNode);
1021 | body.appendChild(valueWrap);
1022 |
1023 |
1024 | renderText(el, textNode, stack);
1025 | body.removeChild(valueWrap);
1026 |
1027 |
1028 |
1029 | }
1030 |
1031 |
1032 |
1033 | function getBackgroundPosition(el, bounds, image){
1034 | // TODO add support for multi image backgrounds
1035 |
1036 | var bgposition = (function( bgp ){
1037 |
1038 | if (bgp !== undefined) {
1039 | return (bgp.split(",")[0] || "0 0").split(" ");
1040 | } else {
1041 | // Older IE uses -x and -y
1042 | return [ getCSS(el, "backgroundPositionX"), getCSS(el, "backgroundPositionY") ];
1043 | }
1044 |
1045 |
1046 | })( getCSS(el, "backgroundPosition") ),
1047 | topPos,
1048 | left,
1049 | percentage,
1050 | val;
1051 |
1052 | if (bgposition.length === 1){
1053 | val = bgposition;
1054 |
1055 | bgposition = [];
1056 |
1057 | bgposition[0] = val;
1058 | bgposition[1] = val;
1059 | }
1060 |
1061 |
1062 |
1063 | if (bgposition[0].toString().indexOf("%") !== -1){
1064 | percentage = (parseFloat(bgposition[0])/100);
1065 | left = ((bounds.width * percentage)-(image.width*percentage));
1066 |
1067 | }else{
1068 | left = parseInt(bgposition[0],10);
1069 | }
1070 |
1071 | if (bgposition[1].toString().indexOf("%") !== -1){
1072 |
1073 | percentage = (parseFloat(bgposition[1])/100);
1074 | topPos = ((bounds.height * percentage)-(image.height*percentage));
1075 | }else{
1076 | topPos = parseInt(bgposition[1],10);
1077 | }
1078 |
1079 |
1080 |
1081 |
1082 | return {
1083 | top: topPos,
1084 | left: left
1085 | };
1086 |
1087 | }
1088 |
1089 | function renderImage (ctx, image, sx, sy, sw, sh, dx, dy, dw, dh) {
1090 | ctx.drawImage(
1091 | image,
1092 | sx, //sx
1093 | sy, //sy
1094 | sw, //sw
1095 | sh, //sh
1096 | dx, //dx
1097 | dy, // dy
1098 | dw, //dw
1099 | dh //dh
1100 | );
1101 | numDraws+=1;
1102 |
1103 | }
1104 |
1105 |
1106 | function renderBackgroundRepeat (ctx, image, x, y, width, height, elx, ely){
1107 | var sourceX = 0,
1108 | sourceY=0;
1109 | if (elx-x>0){
1110 | sourceX = elx-x;
1111 | }
1112 |
1113 | if (ely-y>0){
1114 | sourceY = ely-y;
1115 | }
1116 |
1117 | renderImage(
1118 | ctx,
1119 | image,
1120 | sourceX, // source X
1121 | sourceY, // source Y
1122 | width-sourceX, // source Width
1123 | height-sourceY, // source Height
1124 | x+sourceX, // destination X
1125 | y+sourceY, // destination Y
1126 | width-sourceX, // destination width
1127 | height-sourceY // destination height
1128 | );
1129 | }
1130 |
1131 |
1132 | function renderBackgroundRepeatY (ctx, image, bgp, x, y, w, h){
1133 |
1134 | var height,
1135 | width = Math.min(image.width,w),bgy;
1136 |
1137 | bgp.top = bgp.top-Math.ceil(bgp.top/image.height)*image.height;
1138 |
1139 |
1140 | for(bgy=(y+bgp.top);bgyh+y){
1144 | height = (h+y)-bgy;
1145 | }else{
1146 | height = image.height;
1147 | }
1148 | renderBackgroundRepeat(ctx,image,x+bgp.left,bgy,width,height,x,y);
1149 |
1150 | bgy = Math.floor(bgy+image.height);
1151 |
1152 | }
1153 | }
1154 |
1155 | function renderBackgroundRepeatX(ctx, image, bgp, x, y, w, h){
1156 |
1157 | var height = Math.min(image.height,h),
1158 | width,bgx;
1159 |
1160 |
1161 | bgp.left = bgp.left-Math.ceil(bgp.left/image.width)*image.width;
1162 |
1163 |
1164 | for (bgx=(x+bgp.left);bgxw+x){
1167 | width = (w+x)-bgx;
1168 | }else{
1169 | width = image.width;
1170 | }
1171 |
1172 | renderBackgroundRepeat(ctx,image,bgx,(y+bgp.top),width,height,x,y);
1173 |
1174 | bgx = Math.floor(bgx+image.width);
1175 |
1176 |
1177 | }
1178 | }
1179 |
1180 | function renderBackground(el,bounds,ctx){
1181 |
1182 | // TODO add support for multi background-images
1183 | var background_image = getCSS(el, "backgroundImage"),
1184 | background_repeat = getCSS(el, "backgroundRepeat").split(",")[0],
1185 | image,
1186 | bgp,
1187 | bgy,
1188 | bgw,
1189 | bgsx,
1190 | bgsy,
1191 | bgdx,
1192 | bgdy,
1193 | bgh,
1194 | h,
1195 | height,
1196 | add;
1197 |
1198 | // if (typeof background_image !== "undefined" && /^(1|none)$/.test(background_image) === false && /^(-webkit|-moz|linear-gradient|-o-)/.test(background_image)===false){
1199 |
1200 | if ( !/data:image\/.*;base64,/i.test(background_image) && !/^(-webkit|-moz|linear-gradient|-o-)/.test(background_image) ) {
1201 | background_image = background_image.split(",")[0];
1202 | }
1203 |
1204 | if ( typeof background_image !== "undefined" && /^(1|none)$/.test( background_image ) === false ) {
1205 | background_image = html2canvas.Util.backgroundImage( background_image );
1206 | image = loadImage( background_image );
1207 |
1208 |
1209 | bgp = getBackgroundPosition(el, bounds, image);
1210 |
1211 |
1212 | if ( image ){
1213 | switch ( background_repeat ) {
1214 |
1215 | case "repeat-x":
1216 | renderBackgroundRepeatX( ctx, image, bgp, bounds.left, bounds.top, bounds.width, bounds.height );
1217 | break;
1218 |
1219 | case "repeat-y":
1220 | renderBackgroundRepeatY( ctx, image, bgp, bounds.left, bounds.top, bounds.width, bounds.height );
1221 | break;
1222 |
1223 | case "no-repeat":
1224 | /*
1225 | this.drawBackgroundRepeat(
1226 | ctx,
1227 | image,
1228 | bgp.left+bounds.left, // sx
1229 | bgp.top+bounds.top, // sy
1230 | Math.min(bounds.width,image.width),
1231 | Math.min(bounds.height,image.height),
1232 | bounds.left,
1233 | bounds.top
1234 | );*/
1235 |
1236 |
1237 | // console.log($(el).css('background-image'));
1238 | bgw = bounds.width - bgp.left;
1239 | bgh = bounds.height - bgp.top;
1240 | bgsx = bgp.left;
1241 | bgsy = bgp.top;
1242 | bgdx = bgp.left+bounds.left;
1243 | bgdy = bgp.top+bounds.top;
1244 |
1245 | //
1246 | // bgw = Math.min(bgw,image.width);
1247 | // bgh = Math.min(bgh,image.height);
1248 |
1249 | if (bgsx<0){
1250 | bgsx = Math.abs(bgsx);
1251 | bgdx += bgsx;
1252 | bgw = Math.min(bounds.width,image.width-bgsx);
1253 | }else{
1254 | bgw = Math.min(bgw,image.width);
1255 | bgsx = 0;
1256 | }
1257 |
1258 | if (bgsy<0){
1259 | bgsy = Math.abs(bgsy);
1260 | bgdy += bgsy;
1261 | // bgh = bgh-bgsy;
1262 | bgh = Math.min(bounds.height,image.height-bgsy);
1263 | }else{
1264 | bgh = Math.min(bgh,image.height);
1265 | bgsy = 0;
1266 | }
1267 |
1268 |
1269 | // bgh = Math.abs(bgh);
1270 | // bgw = Math.abs(bgw);
1271 | if (bgh>0 && bgw > 0){
1272 | renderImage(
1273 | ctx,
1274 | image,
1275 | bgsx, // source X : 0
1276 | bgsy, // source Y : 1695
1277 | bgw, // source Width : 18
1278 | bgh, // source Height : 1677
1279 | bgdx, // destination X :906
1280 | bgdy, // destination Y : 1020
1281 | bgw, // destination width : 18
1282 | bgh // destination height : 1677
1283 | );
1284 |
1285 | // ctx.drawImage(image,(bounds.left+bgp.left),(bounds.top+bgp.top));
1286 |
1287 | }
1288 | break;
1289 | default:
1290 |
1291 |
1292 |
1293 | bgp.top = bgp.top-Math.ceil(bgp.top/image.height)*image.height;
1294 |
1295 |
1296 | for(bgy=(bounds.top+bgp.top);bgyh+bgy){
1304 | height = (h+bgy)-bgy;
1305 | }else{
1306 | height = image.height;
1307 | }
1308 | // console.log(height);
1309 |
1310 | if (bgy0){
1320 | bgp.top += add;
1321 | }
1322 | bgy = Math.floor(bgy+image.height)-add;
1323 | }
1324 | break;
1325 |
1326 |
1327 | }
1328 | }else{
1329 | h2clog("html2canvas: Error loading background:" + background_image);
1330 | //console.log(images);
1331 | }
1332 |
1333 | }
1334 | }
1335 |
1336 |
1337 |
1338 | function renderElement(el, parentStack){
1339 |
1340 | var bounds = html2canvas.Util.Bounds(el),
1341 | x = bounds.left,
1342 | y = bounds.top,
1343 | w = bounds.width,
1344 | h = bounds.height,
1345 | image,
1346 | bgcolor = getCSS(el, "backgroundColor"),
1347 | cssPosition = getCSS(el, "position"),
1348 | zindex,
1349 | opacity = getCSS(el, "opacity"),
1350 | stack,
1351 | stackLength,
1352 | borders,
1353 | ctx,
1354 | bgbounds,
1355 | imgSrc,
1356 | paddingLeft,
1357 | paddingTop,
1358 | paddingRight,
1359 | paddingBottom;
1360 |
1361 | if (!parentStack){
1362 | docDim = docSize();
1363 | parentStack = {
1364 | opacity: 1
1365 | };
1366 | }else{
1367 | docDim = {};
1368 | }
1369 |
1370 |
1371 | //var zindex = this.formatZ(this.getCSS(el,"zIndex"),cssPosition,parentStack.zIndex,el.parentNode);
1372 |
1373 | zindex = setZ( getCSS( el, "zIndex"), parentStack.zIndex );
1374 |
1375 |
1376 |
1377 | stack = {
1378 | ctx: h2cRenderContext( docDim.width || w , docDim.height || h ),
1379 | zIndex: zindex,
1380 | opacity: opacity * parentStack.opacity,
1381 | cssPosition: cssPosition
1382 | };
1383 |
1384 |
1385 |
1386 | // TODO correct overflow for absolute content residing under a static position
1387 |
1388 | if (parentStack.clip){
1389 | stack.clip = html2canvas.Util.Extend( {}, parentStack.clip );
1390 | //stack.clip = parentStack.clip;
1391 | // stack.clip.height = stack.clip.height - parentStack.borders[2].width;
1392 | }
1393 |
1394 |
1395 | if ( options.useOverflow === true && /(hidden|scroll|auto)/.test(getCSS(el, "overflow")) === true && /(BODY)/i.test(el.nodeName) === false ){
1396 | if (stack.clip){
1397 | stack.clip = clipBounds(stack.clip, bounds);
1398 | }else{
1399 | stack.clip = bounds;
1400 | }
1401 | }
1402 |
1403 |
1404 | stackLength = zindex.children.push(stack);
1405 |
1406 | ctx = zindex.children[stackLength-1].ctx;
1407 |
1408 | ctx.setVariable("globalAlpha", stack.opacity);
1409 |
1410 | // draw element borders
1411 | borders = renderBorders(el, ctx, bounds, false);
1412 | stack.borders = borders;
1413 |
1414 |
1415 | // let's modify clip area for child elements, so borders dont get overwritten
1416 |
1417 | /*
1418 | if (stack.clip){
1419 | stack.clip.width = stack.clip.width-(borders[1].width);
1420 | stack.clip.height = stack.clip.height-(borders[2].width);
1421 | }
1422 | */
1423 | if (ignoreElementsRegExp.test(el.nodeName) && options.iframeDefault !== "transparent"){
1424 | if (options.iframeDefault === "default"){
1425 | bgcolor = "#efefef";
1426 | }else{
1427 | bgcolor = options.iframeDefault;
1428 | }
1429 | }
1430 |
1431 | // draw base element bgcolor
1432 |
1433 | bgbounds = {
1434 | left: x + borders[3].width,
1435 | top: y + borders[0].width,
1436 | width: w - (borders[1].width + borders[3].width),
1437 | height: h - (borders[0].width + borders[2].width)
1438 | };
1439 |
1440 | //if (this.withinBounds(stack.clip,bgbounds)){
1441 |
1442 | if (stack.clip){
1443 | bgbounds = clipBounds(bgbounds, stack.clip);
1444 |
1445 | //}
1446 |
1447 | }
1448 |
1449 |
1450 | if (bgbounds.height > 0 && bgbounds.width > 0){
1451 | renderRect(
1452 | ctx,
1453 | bgbounds.left,
1454 | bgbounds.top,
1455 | bgbounds.width,
1456 | bgbounds.height,
1457 | bgcolor
1458 | );
1459 |
1460 | renderBackground(el, bgbounds, ctx);
1461 | }
1462 |
1463 | switch(el.nodeName){
1464 | case "IMG":
1465 | imgSrc = el.getAttribute('src');
1466 | image = loadImage(imgSrc);
1467 | if (image){
1468 |
1469 | paddingLeft = getCSSInt(el, 'paddingLeft');
1470 | paddingTop = getCSSInt(el, 'paddingTop');
1471 | paddingRight = getCSSInt(el, 'paddingRight');
1472 | paddingBottom = getCSSInt(el, 'paddingBottom');
1473 |
1474 |
1475 | renderImage(
1476 | ctx,
1477 | image,
1478 | 0, //sx
1479 | 0, //sy
1480 | image.width, //sw
1481 | image.height, //sh
1482 | x + paddingLeft + borders[3].width, //dx
1483 | y + paddingTop + borders[0].width, // dy
1484 | bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight), //dw
1485 | bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom) //dh
1486 | );
1487 |
1488 | }else{
1489 | h2clog("html2canvas: Error loading
:" + imgSrc);
1490 | }
1491 | break;
1492 | case "INPUT":
1493 | // TODO add all relevant type's, i.e. HTML5 new stuff
1494 | // todo add support for placeholder attribute for browsers which support it
1495 | if (/^(text|url|email|submit|button|reset)$/.test(el.type) && el.value.length > 0){
1496 |
1497 | renderFormValue(el, bounds, stack);
1498 |
1499 |
1500 | /*
1501 | this just doesn't work well enough
1502 |
1503 | this.newText(el,{
1504 | nodeValue:el.value,
1505 | splitText: function(){
1506 | return this;
1507 | },
1508 | formValue:true
1509 | },stack);
1510 | */
1511 | }
1512 | break;
1513 | case "TEXTAREA":
1514 | if (el.value.length > 0){
1515 | renderFormValue(el, bounds, stack);
1516 | }
1517 | break;
1518 | case "SELECT":
1519 | if (el.options.length > 0){
1520 | renderFormValue(el, bounds, stack);
1521 | }
1522 | break;
1523 | case "LI":
1524 | renderListItem(el, stack, bgbounds);
1525 | break;
1526 | case "CANVAS":
1527 | paddingLeft = getCSSInt(el, 'paddingLeft');
1528 | paddingTop = getCSSInt(el, 'paddingTop');
1529 | paddingRight = getCSSInt(el, 'paddingRight');
1530 | paddingBottom = getCSSInt(el, 'paddingBottom');
1531 | renderImage(
1532 | ctx,
1533 | el,
1534 | 0, //sx
1535 | 0, //sy
1536 | el.width, //sw
1537 | el.height, //sh
1538 | x + paddingLeft + borders[3].width, //dx
1539 | y + paddingTop + borders[0].width, // dy
1540 | bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight), //dw
1541 | bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom) //dh
1542 | );
1543 | break;
1544 | }
1545 |
1546 | return zindex.children[stackLength - 1];
1547 | }
1548 |
1549 |
1550 |
1551 | function parseElement (el, stack) {
1552 |
1553 | // skip hidden elements and their children
1554 | if (getCSS(el, 'display') !== "none" && getCSS(el, 'visibility') !== "hidden") {
1555 |
1556 | stack = renderElement(el, stack) || stack;
1557 |
1558 | ctx = stack.ctx;
1559 |
1560 | if ( !ignoreElementsRegExp.test( el.nodeName ) ) {
1561 | var elementChildren = html2canvas.Util.Children( el ),
1562 | i,
1563 | node,
1564 | childrenLen;
1565 | for (i = 0, childrenLen = elementChildren.length; i < childrenLen; i+=1) {
1566 | node = elementChildren[i];
1567 |
1568 | if ( node.nodeType === 1 ) {
1569 | parseElement(node, stack);
1570 | }else if ( node.nodeType === 3 ) {
1571 | renderText(el, node, stack);
1572 | }
1573 |
1574 | }
1575 |
1576 | }
1577 | }
1578 | }
1579 |
1580 | stack = renderElement(element, null);
1581 |
1582 | // parse every child element
1583 | for (i = 0, children = element.children, childrenLen = children.length; i < childrenLen; i+=1){
1584 | parseElement(children[i], stack);
1585 | }
1586 |
1587 |
1588 | stack.backgroundColor = getCSS( body, "backgroundColor" );
1589 |
1590 | return stack;
1591 |
1592 | };
1593 |
1594 | function h2czContext(zindex) {
1595 | return {
1596 | zindex: zindex,
1597 | children: []
1598 | };
1599 | };
1600 |
1601 | /*
1602 | html2canvas v0.33
1603 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
1604 | http://www.twitter.com/niklasvh
1605 |
1606 | Released under MIT License
1607 | */
1608 |
1609 | html2canvas.Preload = function(element, opts){
1610 |
1611 | var options = {
1612 | proxy: "http://html2canvas.appspot.com/",
1613 | timeout: 0, // no timeout
1614 | useCORS: false, // try to load images as CORS (where available), before falling back to proxy
1615 | allowTaint: false // whether to allow images to taint the canvas, won't need proxy if set to true
1616 | },
1617 | images = {
1618 | numLoaded: 0, // also failed are counted here
1619 | numFailed: 0,
1620 | numTotal: 0,
1621 | cleanupDone: false
1622 | },
1623 | pageOrigin,
1624 | methods,
1625 | i,
1626 | count = 0,
1627 | doc = element.ownerDocument,
1628 | domImages = doc.images, // TODO probably should limit it to images present in the element only
1629 | imgLen = domImages.length,
1630 | link = doc.createElement("a"),
1631 | supportCORS = (function( img ){
1632 | return (img.crossOrigin !== undefined);
1633 | })(new Image()),
1634 | timeoutTimer;
1635 |
1636 | link.href = window.location.href;
1637 | pageOrigin = link.protocol + link.host;
1638 | opts = opts || {};
1639 |
1640 | options = html2canvas.Util.Extend(opts, options);
1641 |
1642 |
1643 |
1644 | element = element || doc.body;
1645 |
1646 | function isSameOrigin(url){
1647 | link.href = url;
1648 | link.href = link.href; // YES, BELIEVE IT OR NOT, that is required for IE9 - http://jsfiddle.net/niklasvh/2e48b/
1649 | var origin = link.protocol + link.host;
1650 | return (origin === pageOrigin);
1651 | }
1652 |
1653 | function start(){
1654 | h2clog("html2canvas: start: images: " + images.numLoaded + " / " + images.numTotal + " (failed: " + images.numFailed + ")");
1655 | if (!images.firstRun && images.numLoaded >= images.numTotal){
1656 |
1657 | /*
1658 | this.log('Finished loading '+this.imagesLoaded+' images, Started parsing');
1659 | this.bodyOverflow = document.getElementsByTagName('body')[0].style.overflow;
1660 | document.getElementsByTagName('body')[0].style.overflow = "hidden";
1661 | */
1662 | if (typeof options.complete === "function"){
1663 | options.complete(images);
1664 | }
1665 |
1666 | h2clog("Finished loading images: # " + images.numTotal + " (failed: " + images.numFailed + ")");
1667 | }
1668 | }
1669 |
1670 | // TODO modify proxy to serve images with CORS enabled, where available
1671 | function proxyGetImage(url, img, imageObj){
1672 | var callback_name,
1673 | scriptUrl = options.proxy,
1674 | script;
1675 |
1676 | link.href = url;
1677 | url = link.href; // work around for pages with base href="" set - WARNING: this may change the url
1678 |
1679 | callback_name = 'html2canvas_' + (count++);
1680 | imageObj.callbackname = callback_name;
1681 |
1682 | if (scriptUrl.indexOf("?") > -1) {
1683 | scriptUrl += "&";
1684 | } else {
1685 | scriptUrl += "?";
1686 | }
1687 | scriptUrl += 'url=' + encodeURIComponent(url) + '&callback=' + callback_name;
1688 | script = doc.createElement("script");
1689 |
1690 | window[callback_name] = function(a){
1691 | if (a.substring(0,6) === "error:"){
1692 | imageObj.succeeded = false;
1693 | images.numLoaded++;
1694 | images.numFailed++;
1695 | start();
1696 | } else {
1697 | setImageLoadHandlers(img, imageObj);
1698 | img.src = a;
1699 | }
1700 | window[callback_name] = undefined; // to work with IE<9 // NOTE: that the undefined callback property-name still exists on the window object (for IE<9)
1701 | try {
1702 | delete window[callback_name]; // for all browser that support this
1703 | } catch(ex) {}
1704 | script.parentNode.removeChild(script);
1705 | script = null;
1706 | delete imageObj.script;
1707 | delete imageObj.callbackname;
1708 | };
1709 |
1710 | script.setAttribute("type", "text/javascript");
1711 | script.setAttribute("src", scriptUrl);
1712 | imageObj.script = script;
1713 | window.document.body.appendChild(script);
1714 |
1715 | }
1716 |
1717 | function getImages (el) {
1718 |
1719 |
1720 |
1721 | // if (!this.ignoreRe.test(el.nodeName)){
1722 | //
1723 |
1724 | var contents = html2canvas.Util.Children(el),
1725 | i,
1726 | contentsLen = contents.length,
1727 | background_image,
1728 | src,
1729 | img,
1730 | elNodeType = false;
1731 |
1732 | for (i = 0; i < contentsLen; i+=1 ){
1733 | // var ignRe = new RegExp("("+this.ignoreElements+")");
1734 | // if (!ignRe.test(element.nodeName)){
1735 | getImages(contents[i]);
1736 | // }
1737 | }
1738 |
1739 | // }
1740 | try {
1741 | elNodeType = el.nodeType;
1742 | } catch (ex) {
1743 | elNodeType = false;
1744 | h2clog("html2canvas: failed to access some element's nodeType - Exception: " + ex.message);
1745 | }
1746 |
1747 | if (elNodeType === 1 || elNodeType === undefined){
1748 |
1749 | // opera throws exception on external-content.html
1750 | try {
1751 | background_image = html2canvas.Util.getCSS(el, 'backgroundImage');
1752 | }catch(e) {
1753 | h2clog("html2canvas: failed to get background-image - Exception: " + e.message);
1754 | }
1755 | if ( background_image && background_image !== "1" && background_image !== "none" ) {
1756 |
1757 | // TODO add multi image background support
1758 |
1759 | if (background_image.substring(0,7) === "-webkit" || background_image.substring(0,3) === "-o-" || background_image.substring(0,4) === "-moz") {
1760 |
1761 | img = html2canvas.Generate.Gradient( background_image, html2canvas.Util.Bounds( el ) );
1762 |
1763 | if ( img !== undefined ){
1764 | images[background_image] = {
1765 | img: img,
1766 | succeeded: true
1767 | };
1768 | images.numTotal++;
1769 | images.numLoaded++;
1770 | start();
1771 |
1772 | }
1773 |
1774 | } else {
1775 | src = html2canvas.Util.backgroundImage(background_image.match(/data:image\/.*;base64,/i) ? background_image : background_image.split(",")[0]);
1776 | methods.loadImage(src);
1777 | }
1778 |
1779 | /*
1780 | if (background_image && background_image !== "1" && background_image !== "none" && background_image.substring(0,7) !== "-webkit" && background_image.substring(0,3)!== "-o-" && background_image.substring(0,4) !== "-moz"){
1781 | // TODO add multi image background support
1782 | src = html2canvas.Util.backgroundImage(background_image.split(",")[0]);
1783 | methods.loadImage(src); */
1784 | }
1785 | }
1786 | }
1787 |
1788 | function setImageLoadHandlers(img, imageObj) {
1789 | img.onload = function() {
1790 | if ( imageObj.timer !== undefined ) {
1791 | // CORS succeeded
1792 | window.clearTimeout( imageObj.timer );
1793 | }
1794 | images.numLoaded++;
1795 | imageObj.succeeded = true;
1796 | start();
1797 | };
1798 | img.onerror = function() {
1799 |
1800 | if (img.crossOrigin === "anonymous") {
1801 | // CORS failed
1802 | window.clearTimeout( imageObj.timer );
1803 |
1804 | // let's try with proxy instead
1805 | if ( options.proxy ) {
1806 | var src = img.src;
1807 | img = new Image();
1808 | imageObj.img = img;
1809 | img.src = src;
1810 |
1811 | proxyGetImage( img.src, img, imageObj );
1812 | return;
1813 | }
1814 | }
1815 |
1816 |
1817 | images.numLoaded++;
1818 | images.numFailed++;
1819 | imageObj.succeeded = false;
1820 | start();
1821 |
1822 | };
1823 | }
1824 |
1825 | // work around for https://bugs.webkit.org/show_bug.cgi?id=80028
1826 | function isComplete() {
1827 | if (!this.img.complete) {
1828 | this.timer = window.setTimeout(this.img.customComplete, 100)
1829 | } else {
1830 | this.img.onerror();
1831 | }
1832 | }
1833 |
1834 | methods = {
1835 | loadImage: function( src ) {
1836 | var img, imageObj;
1837 | if ( src && images[src] === undefined ) {
1838 | img = new Image();
1839 | if ( src.match(/data:image\/.*;base64,/i) ) {
1840 | img.src = src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, '');
1841 | imageObj = images[src] = { img: img };
1842 | images.numTotal++;
1843 | setImageLoadHandlers(img, imageObj);
1844 | } else if ( isSameOrigin( src ) || options.allowTaint === true ) {
1845 | imageObj = images[src] = { img: img };
1846 | images.numTotal++;
1847 | setImageLoadHandlers(img, imageObj);
1848 | img.src = src;
1849 | } else if ( supportCORS && !options.allowTaint && options.useCORS ) {
1850 | // attempt to load with CORS
1851 |
1852 | img.crossOrigin = "anonymous";
1853 | imageObj = images[src] = { img: img };
1854 | images.numTotal++;
1855 | setImageLoadHandlers(img, imageObj);
1856 | img.src = src;
1857 |
1858 | img.customComplete = isComplete.bind(imageObj);
1859 | img.customComplete();
1860 |
1861 | } else if ( options.proxy ) {
1862 | imageObj = images[src] = { img: img };
1863 | images.numTotal++;
1864 | proxyGetImage( src, img, imageObj );
1865 | }
1866 | }
1867 |
1868 | },
1869 | cleanupDOM: function(cause) {
1870 | var img, src;
1871 | if (!images.cleanupDone) {
1872 | if (cause && typeof cause === "string") {
1873 | h2clog("html2canvas: Cleanup because: " + cause);
1874 | } else {
1875 | h2clog("html2canvas: Cleanup after timeout: " + options.timeout + " ms.");
1876 | }
1877 |
1878 | for (src in images) {
1879 | if (images.hasOwnProperty(src)) {
1880 | img = images[src];
1881 | if (typeof img === "object" && img.callbackname && img.succeeded === undefined) {
1882 | // cancel proxy image request
1883 | window[img.callbackname] = undefined; // to work with IE<9 // NOTE: that the undefined callback property-name still exists on the window object (for IE<9)
1884 | try {
1885 | delete window[img.callbackname]; // for all browser that support this
1886 | } catch(ex) {}
1887 | if (img.script && img.script.parentNode) {
1888 | img.script.setAttribute("src", "about:blank"); // try to cancel running request
1889 | img.script.parentNode.removeChild(img.script);
1890 | }
1891 | images.numLoaded++;
1892 | images.numFailed++;
1893 | h2clog("html2canvas: Cleaned up failed img: '" + src + "' Steps: " + images.numLoaded + " / " + images.numTotal);
1894 | }
1895 | }
1896 | }
1897 |
1898 | // cancel any pending requests
1899 | if(window.stop !== undefined) {
1900 | window.stop();
1901 | } else if(document.execCommand !== undefined) {
1902 | document.execCommand("Stop", false);
1903 | }
1904 | if (document.close !== undefined) {
1905 | document.close();
1906 | }
1907 | images.cleanupDone = true;
1908 | if (!(cause && typeof cause === "string")) {
1909 | start();
1910 | }
1911 | }
1912 | },
1913 | renderingDone: function() {
1914 | if (timeoutTimer) {
1915 | window.clearTimeout(timeoutTimer);
1916 | }
1917 | }
1918 |
1919 | };
1920 |
1921 | if (options.timeout > 0) {
1922 | timeoutTimer = window.setTimeout(methods.cleanupDOM, options.timeout);
1923 | }
1924 | h2clog('html2canvas: Preload starts: finding background-images');
1925 | images.firstRun = true;
1926 |
1927 | getImages( element );
1928 |
1929 | h2clog('html2canvas: Preload: Finding images');
1930 | // load
images
1931 | for (i = 0; i < imgLen; i+=1){
1932 | methods.loadImage( domImages[i].getAttribute( "src" ) );
1933 | }
1934 |
1935 | images.firstRun = false;
1936 | h2clog('html2canvas: Preload: Done.');
1937 | if ( images.numTotal === images.numLoaded ) {
1938 | start();
1939 | }
1940 |
1941 | return methods;
1942 |
1943 | };
1944 |
1945 |
1946 |
1947 |
1948 | /*
1949 | html2canvas v0.33
1950 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
1951 | http://www.twitter.com/niklasvh
1952 |
1953 | Released under MIT License
1954 | */
1955 | function h2cRenderContext(width, height) {
1956 | var storage = [];
1957 | return {
1958 | storage: storage,
1959 | width: width,
1960 | height: height,
1961 | fillRect: function () {
1962 | storage.push({
1963 | type: "function",
1964 | name: "fillRect",
1965 | 'arguments': arguments
1966 | });
1967 | },
1968 | drawImage: function () {
1969 | storage.push({
1970 | type: "function",
1971 | name: "drawImage",
1972 | 'arguments': arguments
1973 | });
1974 | },
1975 | fillText: function () {
1976 | storage.push({
1977 | type: "function",
1978 | name: "fillText",
1979 | 'arguments': arguments
1980 | });
1981 | },
1982 | setVariable: function (variable, value) {
1983 | storage.push({
1984 | type: "variable",
1985 | name: variable,
1986 | 'arguments': value
1987 | });
1988 | }
1989 | };
1990 | }
1991 |
1992 | /*
1993 | html2canvas v0.33
1994 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
1995 | http://www.twitter.com/niklasvh
1996 |
1997 | Released under MIT License
1998 | */
1999 | html2canvas.Renderer = function(parseQueue, opts){
2000 |
2001 |
2002 | var options = {
2003 | "width": null,
2004 | "height": null,
2005 | "renderer": "canvas",
2006 | "taintTest": true // do a taint test with all images before applying to canvas
2007 | },
2008 | queue = [],
2009 | canvas,
2010 | usingFlashcanvas = false,
2011 | flashMaxSize = 2880, // flash bitmap limited to 2880x2880px // http://stackoverflow.com/questions/2033792/argumenterror-error-2015-invalid-bitmapdata
2012 | doc = document;
2013 |
2014 | options = html2canvas.Util.Extend(opts, options);
2015 |
2016 |
2017 |
2018 | function sortZ(zStack){
2019 | var subStacks = [],
2020 | stackValues = [],
2021 | zStackChildren = zStack.children,
2022 | s,
2023 | i,
2024 | stackLen,
2025 | zValue,
2026 | zLen,
2027 | stackChild,
2028 | b,
2029 | subStackLen;
2030 |
2031 |
2032 | for (s = 0, zLen = zStackChildren.length; s < zLen; s+=1){
2033 |
2034 | stackChild = zStackChildren[s];
2035 |
2036 | if (stackChild.children && stackChild.children.length > 0){
2037 | subStacks.push(stackChild);
2038 | stackValues.push(stackChild.zindex);
2039 | }else{
2040 | queue.push(stackChild);
2041 | }
2042 |
2043 | }
2044 |
2045 | stackValues.sort(function(a, b) {
2046 | return a - b;
2047 | });
2048 |
2049 | for (i = 0, stackLen = stackValues.length; i < stackLen; i+=1){
2050 | zValue = stackValues[i];
2051 | for (b = 0, subStackLen = subStacks.length; b <= subStackLen; b+=1){
2052 |
2053 | if (subStacks[b].zindex === zValue){
2054 | stackChild = subStacks.splice(b, 1);
2055 | sortZ(stackChild[0]);
2056 | break;
2057 |
2058 | }
2059 | }
2060 | }
2061 |
2062 | }
2063 |
2064 | function canvasRenderer(zStack){
2065 |
2066 | sortZ(zStack.zIndex);
2067 |
2068 |
2069 | var ctx = canvas.getContext("2d"),
2070 | storageContext,
2071 | i,
2072 | queueLen,
2073 | a,
2074 | newCanvas,
2075 | bounds,
2076 | testCanvas = document.createElement("canvas"),
2077 | hasCTX = ( testCanvas.getContext !== undefined ),
2078 | storageLen,
2079 | renderItem,
2080 | testctx = ( hasCTX ) ? testCanvas.getContext("2d") : {},
2081 | safeImages = [],
2082 | fstyle;
2083 |
2084 | canvas.width = canvas.style.width = (!usingFlashcanvas) ? options.width || zStack.ctx.width : Math.min(flashMaxSize, (options.width || zStack.ctx.width) );
2085 | canvas.height = canvas.style.height = (!usingFlashcanvas) ? options.height || zStack.ctx.height : Math.min(flashMaxSize, (options.height || zStack.ctx.height) );
2086 |
2087 | fstyle = ctx.fillStyle;
2088 | ctx.fillStyle = zStack.backgroundColor;
2089 | ctx.fillRect(0, 0, canvas.width, canvas.height);
2090 | ctx.fillStyle = fstyle;
2091 |
2092 | for (i = 0, queueLen = queue.length; i < queueLen; i+=1){
2093 |
2094 | storageContext = queue.splice(0, 1)[0];
2095 | storageContext.canvasPosition = storageContext.canvasPosition || {};
2096 |
2097 | //this.canvasRenderContext(storageContext,parentctx);
2098 |
2099 | // set common settings for canvas
2100 | ctx.textBaseline = "bottom";
2101 |
2102 | if (storageContext.clip){
2103 | ctx.save();
2104 | ctx.beginPath();
2105 | // console.log(storageContext);
2106 | ctx.rect(storageContext.clip.left, storageContext.clip.top, storageContext.clip.width, storageContext.clip.height);
2107 | ctx.clip();
2108 |
2109 | }
2110 |
2111 | if (storageContext.ctx.storage){
2112 |
2113 | for (a = 0, storageLen = storageContext.ctx.storage.length; a < storageLen; a+=1){
2114 |
2115 | renderItem = storageContext.ctx.storage[a];
2116 |
2117 |
2118 | switch(renderItem.type){
2119 | case "variable":
2120 | ctx[renderItem.name] = renderItem['arguments'];
2121 | break;
2122 | case "function":
2123 | if (renderItem.name === "fillRect") {
2124 |
2125 | if (!usingFlashcanvas || renderItem['arguments'][0] + renderItem['arguments'][2] < flashMaxSize && renderItem['arguments'][1] + renderItem['arguments'][3] < flashMaxSize) {
2126 | ctx.fillRect.apply( ctx, renderItem['arguments'] );
2127 | }
2128 | }else if(renderItem.name === "fillText") {
2129 | if (!usingFlashcanvas || renderItem['arguments'][1] < flashMaxSize && renderItem['arguments'][2] < flashMaxSize) {
2130 | ctx.fillText.apply( ctx, renderItem['arguments'] );
2131 | }
2132 | }else if(renderItem.name === "drawImage") {
2133 |
2134 | if (renderItem['arguments'][8] > 0 && renderItem['arguments'][7]){
2135 | if ( hasCTX && options.taintTest ) {
2136 | if ( safeImages.indexOf( renderItem['arguments'][ 0 ].src ) === -1 ) {
2137 | testctx.drawImage( renderItem['arguments'][ 0 ], 0, 0 );
2138 | try {
2139 | testctx.getImageData( 0, 0, 1, 1 );
2140 | } catch(e) {
2141 | testCanvas = document.createElement("canvas");
2142 | testctx = testCanvas.getContext("2d");
2143 | continue;
2144 | }
2145 |
2146 | safeImages.push( renderItem['arguments'][ 0 ].src );
2147 |
2148 | }
2149 | }
2150 | ctx.drawImage.apply( ctx, renderItem['arguments'] );
2151 | }
2152 | }
2153 |
2154 |
2155 | break;
2156 | default:
2157 |
2158 | }
2159 |
2160 | }
2161 |
2162 | }
2163 | if (storageContext.clip){
2164 | ctx.restore();
2165 | }
2166 |
2167 |
2168 |
2169 |
2170 | }
2171 | h2clog("html2canvas: Renderer: Canvas renderer done - returning canvas obj");
2172 |
2173 | // this.canvasRenderStorage(queue,this.ctx);
2174 | queueLen = options.elements.length;
2175 |
2176 | if (queueLen === 1) {
2177 | if (typeof options.elements[ 0 ] === "object" && options.elements[ 0 ].nodeName !== "BODY" && usingFlashcanvas === false) {
2178 | // crop image to the bounds of selected (single) element
2179 | bounds = html2canvas.Util.Bounds( options.elements[ 0 ] );
2180 | newCanvas = doc.createElement('canvas');
2181 | newCanvas.width = bounds.width;
2182 | newCanvas.height = bounds.height;
2183 | ctx = newCanvas.getContext("2d");
2184 |
2185 | ctx.drawImage( canvas, bounds.left, bounds.top, bounds.width, bounds.height, 0, 0, bounds.width, bounds.height );
2186 | delete canvas;
2187 | return newCanvas;
2188 | }
2189 | } else {
2190 | // TODO clip and resize multiple elements
2191 | /*
2192 | for ( i = 0; i < queueLen; i+=1 ) {
2193 | if (options.elements[ i ] instanceof Element) {
2194 |
2195 | }
2196 |
2197 | }*/
2198 | }
2199 |
2200 |
2201 |
2202 |
2203 | return canvas;
2204 | }
2205 |
2206 | function svgRenderer(zStack){
2207 | sortZ(zStack.zIndex);
2208 |
2209 | var svgNS = "http://www.w3.org/2000/svg",
2210 | svg = doc.createElementNS(svgNS, "svg"),
2211 | xlinkNS = "http://www.w3.org/1999/xlink",
2212 | defs = doc.createElementNS(svgNS, "defs"),
2213 | i,
2214 | a,
2215 | queueLen,
2216 | storageLen,
2217 | storageContext,
2218 | renderItem,
2219 | el,
2220 | settings = {},
2221 | text,
2222 | fontStyle,
2223 | clipId = 0;
2224 |
2225 | svg.setAttribute("version", "1.1");
2226 | svg.setAttribute("baseProfile", "full");
2227 |
2228 | svg.setAttribute("viewBox", "0 0 " + Math.max(zStack.ctx.width, options.width) + " " + Math.max(zStack.ctx.height, options.height));
2229 | svg.setAttribute("width", Math.max(zStack.ctx.width, options.width) + "px");
2230 | svg.setAttribute("height", Math.max(zStack.ctx.height, options.height) + "px");
2231 | svg.setAttribute("preserveAspectRatio", "none");
2232 | svg.appendChild(defs);
2233 |
2234 |
2235 |
2236 | for (i = 0, queueLen = queue.length; i < queueLen; i+=1){
2237 |
2238 | storageContext = queue.splice(0, 1)[0];
2239 | storageContext.canvasPosition = storageContext.canvasPosition || {};
2240 |
2241 | //this.canvasRenderContext(storageContext,parentctx);
2242 |
2243 |
2244 | /*
2245 | if (storageContext.clip){
2246 | ctx.save();
2247 | ctx.beginPath();
2248 | // console.log(storageContext);
2249 | ctx.rect(storageContext.clip.left, storageContext.clip.top, storageContext.clip.width, storageContext.clip.height);
2250 | ctx.clip();
2251 |
2252 | }*/
2253 |
2254 | if (storageContext.ctx.storage){
2255 |
2256 | for (a = 0, storageLen = storageContext.ctx.storage.length; a < storageLen; a+=1){
2257 |
2258 | renderItem = storageContext.ctx.storage[a];
2259 |
2260 |
2261 |
2262 | switch(renderItem.type){
2263 | case "variable":
2264 | settings[renderItem.name] = renderItem['arguments'];
2265 | break;
2266 | case "function":
2267 | if (renderItem.name === "fillRect") {
2268 |
2269 | el = doc.createElementNS(svgNS, "rect");
2270 | el.setAttribute("x", renderItem['arguments'][0]);
2271 | el.setAttribute("y", renderItem['arguments'][1]);
2272 | el.setAttribute("width", renderItem['arguments'][2]);
2273 | el.setAttribute("height", renderItem['arguments'][3]);
2274 | el.setAttribute("fill", settings.fillStyle);
2275 | svg.appendChild(el);
2276 |
2277 | } else if(renderItem.name === "fillText") {
2278 | el = doc.createElementNS(svgNS, "text");
2279 |
2280 | fontStyle = settings.font.split(" ");
2281 |
2282 | el.style.fontVariant = fontStyle.splice(0, 1)[0];
2283 | el.style.fontWeight = fontStyle.splice(0, 1)[0];
2284 | el.style.fontStyle = fontStyle.splice(0, 1)[0];
2285 | el.style.fontSize = fontStyle.splice(0, 1)[0];
2286 |
2287 | el.setAttribute("x", renderItem['arguments'][1]);
2288 | el.setAttribute("y", renderItem['arguments'][2] - (parseInt(el.style.fontSize, 10) + 3));
2289 |
2290 | el.setAttribute("fill", settings.fillStyle);
2291 |
2292 |
2293 |
2294 |
2295 | // TODO get proper baseline
2296 | el.style.dominantBaseline = "text-before-edge";
2297 | el.style.fontFamily = fontStyle.join(" ");
2298 |
2299 | text = doc.createTextNode(renderItem['arguments'][0]);
2300 | el.appendChild(text);
2301 |
2302 |
2303 | svg.appendChild(el);
2304 |
2305 |
2306 |
2307 | } else if(renderItem.name === "drawImage") {
2308 |
2309 | if (renderItem['arguments'][8] > 0 && renderItem['arguments'][7]){
2310 |
2311 | // TODO check whether even any clipping is necessary for this particular image
2312 | el = doc.createElementNS(svgNS, "clipPath");
2313 | el.setAttribute("id", "clipId" + clipId);
2314 |
2315 | text = doc.createElementNS(svgNS, "rect");
2316 | text.setAttribute("x", renderItem['arguments'][5] );
2317 | text.setAttribute("y", renderItem['arguments'][6]);
2318 |
2319 | text.setAttribute("width", renderItem['arguments'][3]);
2320 | text.setAttribute("height", renderItem['arguments'][4]);
2321 | el.appendChild(text);
2322 | defs.appendChild(el);
2323 |
2324 | el = doc.createElementNS(svgNS, "image");
2325 | el.setAttributeNS(xlinkNS, "xlink:href", renderItem['arguments'][0].src);
2326 | el.setAttribute("width", renderItem['arguments'][0].width);
2327 | el.setAttribute("height", renderItem['arguments'][0].height);
2328 | el.setAttribute("x", renderItem['arguments'][5] - renderItem['arguments'][1]);
2329 | el.setAttribute("y", renderItem['arguments'][6] - renderItem['arguments'][2]);
2330 | el.setAttribute("clip-path", "url(#clipId" + clipId + ")");
2331 | // el.setAttribute("xlink:href", );
2332 |
2333 |
2334 | el.setAttribute("preserveAspectRatio", "none");
2335 |
2336 | svg.appendChild(el);
2337 |
2338 |
2339 | clipId += 1;
2340 | /*
2341 | ctx.drawImage(
2342 | renderItem['arguments'][0],
2343 | renderItem['arguments'][1],
2344 | renderItem['arguments'][2],
2345 | renderItem['arguments'][3],
2346 | renderItem['arguments'][4],
2347 | renderItem['arguments'][5],
2348 | renderItem['arguments'][6],
2349 | renderItem['arguments'][7],
2350 | renderItem['arguments'][8]
2351 | );
2352 | */
2353 | }
2354 | }
2355 |
2356 |
2357 |
2358 | break;
2359 | default:
2360 |
2361 | }
2362 |
2363 | }
2364 |
2365 | }
2366 | /*
2367 | if (storageContext.clip){
2368 | ctx.restore();
2369 | }
2370 | */
2371 |
2372 |
2373 |
2374 | }
2375 |
2376 |
2377 |
2378 |
2379 |
2380 |
2381 |
2382 |
2383 |
2384 |
2385 | h2clog("html2canvas: Renderer: SVG Renderer done - returning SVG DOM obj");
2386 |
2387 | return svg;
2388 |
2389 | }
2390 |
2391 |
2392 | //this.each(this.opts.renderOrder.split(" "),function(i,renderer){
2393 |
2394 | //options.renderer = "svg";
2395 |
2396 | switch(options.renderer.toLowerCase()){
2397 | case "canvas":
2398 | canvas = doc.createElement('canvas');
2399 | if (canvas.getContext){
2400 | h2clog("html2canvas: Renderer: using canvas renderer");
2401 | return canvasRenderer(parseQueue);
2402 | } else {
2403 | usingFlashcanvas = true;
2404 | h2clog("html2canvas: Renderer: canvas not available, using flashcanvas");
2405 | var script = doc.createElement("script");
2406 | script.src = options.flashcanvas;
2407 |
2408 | script.onload = (function(script, func){
2409 | var intervalFunc;
2410 |
2411 | if (script.onload === undefined) {
2412 | // IE lack of support for script onload
2413 |
2414 | if( script.onreadystatechange !== undefined ) {
2415 |
2416 | intervalFunc = function() {
2417 | if (script.readyState !== "loaded" && script.readyState !== "complete") {
2418 | window.setTimeout( intervalFunc, 250 );
2419 |
2420 | } else {
2421 | // it is loaded
2422 | func();
2423 |
2424 | }
2425 |
2426 | };
2427 |
2428 | window.setTimeout( intervalFunc, 250 );
2429 |
2430 | } else {
2431 | h2clog("html2canvas: Renderer: Can't track when flashcanvas is loaded");
2432 |
2433 | }
2434 |
2435 | } else {
2436 | return func;
2437 | }
2438 |
2439 | })(script, function(){
2440 |
2441 | if (typeof window.FlashCanvas !== "undefined") {
2442 | h2clog("html2canvas: Renderer: Flashcanvas initialized");
2443 | window.FlashCanvas.initElement( canvas );
2444 | canvasRenderer(parseQueue);
2445 | }
2446 | });
2447 |
2448 | doc.body.appendChild( script );
2449 |
2450 | return canvas;
2451 | }
2452 | break;
2453 | case "svg":
2454 | if (doc.createElementNS){
2455 | h2clog("html2canvas: Renderer: using SVG renderer");
2456 | return svgRenderer(parseQueue);
2457 | }
2458 | break;
2459 |
2460 | }
2461 |
2462 |
2463 |
2464 | //});
2465 |
2466 |
2467 | return this;
2468 |
2469 |
2470 |
2471 | };
2472 |
2473 | /*
2474 | html2canvas v0.33
2475 | Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
2476 | http://www.twitter.com/niklasvh
2477 |
2478 | Released under MIT License
2479 | */
2480 | window.html2canvas = html2canvas;
2481 | }(window, document));
2482 |
2483 |
--------------------------------------------------------------------------------