4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 最近因为产品需要,用js 写了一个能网页截图并涂鸦的js库(类似QQ 截图工具)。这个库与html2canvas 等类似的库有巨大的差异:html2canvas 只能做到截取“网页”的部分元素类型,而网页之外的内容(浏览器窗口之外),或者跨域的iframe,java applet 等元素是无法截取的。而我们的需求是要能截取桌面上的任何东西,不限窗口和元素类型,换言之:要做一个类似“QQ 截图工具“的js库来在网页上使用。
2 |
3 | 所以就只能自己琢磨了,我们的产品用的是dojo,所以我最开始写的是一个dojo的widget,后来又单独写成了一个jquery的插件,如下使用即可:
4 |
5 | 
6 |
7 | 初始化的参数就是图片上传的相关地址,demo 效果如下:
8 |
9 | 
10 |
11 | 当点击截图后,鼠标状态会变成截图状态,然后拉取桌面的任意一个区域即可:
12 |
13 | 
14 |
15 | 截取到的区域会“立刻绘制到页面的canvas“(严格来说,图片此时还没有绘制到画布上,后面有介绍) 中,在这里我也添加了一些操作到画布上,比如添加文字、矩形、圆,设置颜色等,如下所示:
16 |
17 | 
18 |
19 | 各种操作完成之后,点击确定即可:
20 |
21 | 
22 |
23 | 图片就会插入到编辑框中,查看dom:
24 |
25 | 
26 |
27 | 如上就是完整的过程,当然,也可以只截图不涂鸦。这里说下相关的注意事项:
28 |
29 | > 前提:
30 | > >1. 安装一个截图插件(如果你会C++,可以查看我的这边文章[《兼容各大浏览器的插件开发》](http://www.chenyp.com/2015/09/11/browser-plugin/) 了解如何开发浏览器插件;
31 | >
32 | > >2. 启动图片上传的服务器(允许跨域)。
33 | >
34 | >流程
35 | >>1. 点击截图,调用插件的方法来截图,完成后,插件会把图片上传到服务器中,并将上传后的地址返回给前端;
36 | >>2. 前端拿到地址后,将此地址当作canvas画布的背景(因为橡皮擦的功能设计,这个时候并不会将图片绘制到canvas上,而是当点击确定后,再把图片绘制到canvas上),img 的crossOrigin 设为anonymous(如果没跨域就不需要);
37 | >>3. 各种操作……. (注意,点击橡皮擦时,要将canvas.context.globalCompositeOperation设为destination-out);
38 | >>4. 点击确定,绘制图片到canvas上,要将canvas.context.globalCompositeOperation设为destination-over;
39 | >>5. 然后通过canvas.toDataURL("image/png")即可取到涂鸦后的图片了。
40 | >
41 | >涂鸦状态中的dom 结构如下所示:
42 |
43 | 
44 |
45 | 可以看到在canvas的下面有一个img,这也就是为什么图片还没绘制到画布上也能看到图片的原因。不足之处,请多多指教。
46 |
--------------------------------------------------------------------------------
/SnapScreeServer.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DistChen/DistSnapScreen/af2e4194fa508486ab5f0fe55ec4d8c37a1b7ad9/SnapScreeServer.zip
--------------------------------------------------------------------------------
/css/DistSnapScreen.css:
--------------------------------------------------------------------------------
1 | .SnapContainer{
2 | position: fixed;
3 | top: 0px;
4 | left: 0px;
5 | bottom: 0px;
6 | right: 0px;
7 | background-color: rgba(0,0,0,0.5);
8 | display: none;
9 | }
10 | .SnapContainer > div{
11 | position: absolute;
12 | background-color: #ffffff;
13 | display: none;
14 | }
15 | .SnapContainerCanvas {
16 | }
17 | .SnapContainerCanvas > img{
18 | position: absolute;
19 | left: 0px;
20 | top: 0px;
21 | -webkit-user-select: none;
22 | -moz-user-select: none;
23 | -ms-user-select: none;
24 | user-select: none;
25 | }
26 | .SnapContainerCanvas > input{
27 | position: absolute;
28 | display: block;
29 | border: 1px dashed;
30 | outline: none;
31 | background-color: transparent;
32 | display: none;
33 | }
34 | .SnapContainerCanvas > canvas{
35 | cursor: crosshair;
36 | position: relative;
37 | }
38 | .SnapContainerCanvas > div{
39 | text-align: right;
40 | background-color: white;
41 | margin-top: -3px;
42 | padding-bottom: 1px;
43 | }
44 | .SnapContainerCanvas > div > button{
45 | display:inline-block;
46 | outline:none;
47 | border: none;
48 | background-color: #585d68;
49 | color: white;
50 | font-size: 12px;
51 | padding: 2px 8px;
52 | cursor: pointer;
53 | margin-left: -3px;
54 | }
55 | .SnapContainerCanvas > div > button:last-child,
56 | .SnapContainerCanvas > div > .active,
57 | .SnapContainerCanvas > div > button:hover{
58 | background-color:#f97935;
59 | }
60 | .SnapContainerCanvas > div > button:last-child{
61 | margin-left: 3px;
62 | }
63 | .SnapContainerDownLoad{
64 | text-align: center;
65 | width: 340px;
66 | height: 100px;
67 | left: calc(50% - 170px);
68 | top: calc(50% - 50px);
69 | }
70 | .SnapContainerDownLoad a{
71 | display: inline-block;
72 | height: 30px;
73 | line-height: 30px;
74 | background-color: #f97935;
75 | color: white;
76 | text-decoration: none;
77 | width: 60px;
78 | cursor: pointer;
79 | }
80 | .SnapContainerDownLoad a:last-child{
81 | margin-left: 5px;
82 | background-color: #585d68;
83 | }
--------------------------------------------------------------------------------
/js/DistSnapScreen.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date:2016/6/5
3 | * Author: DistChen
4 | * Desc:www.chenyp.com
5 | */
6 | (function (factory) {
7 | if (typeof define === "function" && define.amd) {
8 | define([ "jquery" ], factory);
9 | } else {
10 | factory(jQuery);
11 | }
12 | }(function ($) {
13 | 'use strict';
14 |
15 | if (typeof $ === 'undefined') {
16 | throw new Error('DistSnapScreen\'s JavaScript requires jQuery');
17 | }
18 |
19 | var DistSnapScreen=function(){
20 | this.plugin = null;
21 | this.context = null;
22 | this.snapContainer = null;
23 | this.snapContainerCanvas = null;
24 | this.snapContainerDownLoad = null;
25 | this.img = null;
26 | this.textInput = null;
27 | this.paintType = 1;
28 | };
29 |
30 | DistSnapScreen.prototype.PaintType={
31 | Pencil:1,
32 | Eraser:1,
33 | Rect:2,
34 | Circle:3,
35 | Text:4
36 | };
37 |
38 | DistSnapScreen.prototype.config={
39 | host:"127.0.0.1",
40 | port:"8080",
41 | serverApp:"SnapScreen",
42 | uploadAction:"/upload.jsp?action=uploadimage"
43 | };
44 |
45 | DistSnapScreen.prototype.init=function(options){
46 | $.extend(DistSnapScreen.prototype.config,options);
47 | _insertTemplate.apply(this);
48 | };
49 |
50 | DistSnapScreen.prototype.snapScreen=function(){
51 | var result;
52 | try{
53 | result = this.plugin.saveSnapshot(this.config.host, "/"+this.config.serverApp+this.config.uploadAction, this.config.port);
54 | }catch (e){
55 | this.snapContainer.show();
56 | this.snapContainerDownLoad.show();
57 | this.snapContainerCanvas.hide();
58 | return "";
59 | }
60 | result = eval("("+ result +")");
61 | return "http://"+this.config.host+":"+this.config.port+"/"+this.config.serverApp+"/"+result.url;
62 | };
63 |
64 | DistSnapScreen.prototype.snapScreenAndScrawl=function(callback){
65 | var url = this.snapScreen();
66 | if(url!=""){
67 | this.callback = callback;
68 | this.snapContainer.show();
69 | this.snapContainerCanvas.show();
70 | _renderBackgroundImg.call(this,url);
71 | }
72 | };
73 |
74 | var _renderBackgroundImg = function(url){
75 | var widget = this;
76 | this.img.setAttribute('crossOrigin', 'Anonymous');
77 | this.img.src=url;
78 | this.img.onload = function(){
79 | var width = widget.img.naturalWidth;
80 | var height = widget.img.naturalHeight;
81 | widget.canvas.width = width;
82 | widget.canvas.height = height;
83 | widget.snapContainerCanvas.css({
84 | width:width+"px",
85 | height:height+"px",
86 | left:"calc(50% - "+width/2+"px)",
87 | top:"calc(50% - "+height/2+"px)"
88 | });
89 | _switchBoard.call(widget,{});
90 | };
91 | };
92 |
93 | var _insertTemplate=function(){
94 | var container = $('').appendTo(document.body);
95 | _insertSnapContainer.apply(this,container);
96 | _insertSnapPlugin.apply(this,container);
97 | };
98 |
99 | var _insertSnapContainer = function(container){
100 | this.snapContainer = $('').appendTo(container);
101 | _insertSnapContainerCanvas.apply(this);
102 | _insertSnapContainerDownLoad.apply(this);
103 | };
104 |
105 | var _insertSnapContainerCanvas=function(){
106 | this.snapContainerCanvas = $('').appendTo(this.snapContainer);
107 | this.img = $('').appendTo(this.snapContainerCanvas)[0];
108 | this.canvas = $('').appendTo(this.snapContainerCanvas)[0];
109 | this.textInput = $('').appendTo(this.snapContainerCanvas)[0];
110 | _registerOpeBtn.apply(this,$("").appendTo(this.snapContainerCanvas));
111 | };
112 |
113 | var _registerOpeBtn=function(container){
114 | var widget = this;
115 | var activeBtn;
116 | var textBtn = $("").appendTo(container);
117 | textBtn.on("click",function(){
118 | activeBtn = _activeBtn(activeBtn,textBtn);
119 | _switchBoard.call(widget,{
120 | paintType:widget.PaintType.Text,
121 | fillStyle:"red",
122 | font:"20px Arial"
123 | });
124 | });
125 | var rectBtn = $("").appendTo(container);
126 | rectBtn.on("click",function(){
127 | activeBtn = _activeBtn(activeBtn,rectBtn);
128 | _switchBoard.call(widget,{
129 | paintType:widget.PaintType.Rect
130 | });
131 | });
132 | var circleBtn = $("").appendTo(container);
133 | circleBtn.on("click",function(){
134 | activeBtn = _activeBtn(activeBtn,circleBtn);
135 | _switchBoard.call(widget,{
136 | paintType:widget.PaintType.Circle
137 | });
138 | });
139 | var pencilBtn = $("").appendTo(container);
140 | pencilBtn.on("click",function(){
141 | activeBtn = _activeBtn(activeBtn,pencilBtn);
142 | _switchBoard.call(widget,{
143 | paintType:widget.PaintType.Pencil
144 | });
145 | });
146 | var eraserBtn = $("").appendTo(container);
147 | eraserBtn.on("click",function(){
148 | activeBtn = _activeBtn(activeBtn,eraserBtn);
149 | _switchBoard.call(widget,{
150 | paintType:widget.PaintType.Eraser,
151 | lineWidth:10,
152 | globalCompositeOperation:"destination-out"
153 | });
154 | });
155 | var okBtn = $("").appendTo(container);
156 | okBtn.on("click",function(){
157 | widget.context.globalCompositeOperation = "destination-over";
158 | widget.context.drawImage(widget.img,0,0);
159 | widget.snapContainer.css("display","none");
160 | widget.snapContainerCanvas.css("display","none");
161 | widget.callback(widget.canvas.toDataURL("image/png"));
162 | });
163 | activeBtn = pencilBtn;
164 | activeBtn.addClass("active");
165 | };
166 |
167 | var _activeBtn=function(lastBtn,btn){
168 | lastBtn.removeClass("active");
169 | btn.addClass("active");
170 | return btn;
171 | };
172 |
173 | var _switchBoard = function(paras){
174 | if(!this.context){
175 | this.context = this.canvas.getContext("2d");
176 | _addCanvasEvent.apply(this);
177 | }
178 | this.context.closePath();
179 | this.paintType = paras.paintType||this.paintType;
180 | this.context.font = paras.font||"14px Arial";
181 | this.context.lineWidth = paras.lineWidth||3;
182 | this.context.strokeStyle = paras.strokeStyle||"red";
183 | this.context.fillStyle=paras.fillStyle||"transparent";
184 | this.context.lineCap = paras.lineCap||"round";
185 | this.context.globalCompositeOperation = paras.globalCompositeOperation || "source-over";
186 | this.textInput.value="";
187 | $(this.textInput).css({
188 | display:"none",
189 | font:this.context.font,
190 | color:this.context.fillStyle,
191 | "border-color":this.context.fillStyle
192 | });
193 | };
194 |
195 | var _addCanvasEvent = function(){
196 | var widget = this;
197 | var painting = false;
198 | var startX,startY,endX,endY,lineWidth;
199 | var minX,minY,maxX=0,maxY= 0,maxRadius = -1;
200 | $(this.canvas).mousedown(function(e){
201 | lineWidth = widget.context.lineWidth;
202 | painting = true;
203 | startX = e.offsetX;
204 | startY = e.offsetY;
205 | if(widget.paintType==widget.PaintType.Pencil||
206 | widget.paintType==widget.PaintType.Eraser){
207 | widget.context.beginPath();
208 | }else if(widget.paintType==widget.PaintType.Text){
209 | painting = false;
210 | if(widget.textInput.value.trim()!=""){
211 | widget.context.fillText(widget.textInput.value.trim(),widget.textX-7,widget.textY+8);
212 | widget.textInput.value="";
213 | $(widget.textInput).hide();
214 | }else{
215 | $(widget.textInput).css({
216 | display:"block",
217 | left:startX-10+"px",
218 | top:startY-15+"px"
219 | });
220 | widget.textX = startX;
221 | widget.textY = startY;
222 | }
223 | }else if(widget.paintType==widget.PaintType.Rect){
224 | minX = startX;
225 | minY = startY;
226 | maxX = startX;
227 | maxY = startY;
228 | }else if(widget.paintType==widget.PaintType.Circle){
229 | maxRadius = -1;
230 | }
231 | });
232 | $(this.canvas).mousemove(function(e){
233 | if(painting){
234 | endX = e.offsetX;
235 | endY = e.offsetY;
236 | if(widget.paintType==widget.PaintType.Pencil || widget.paintType==widget.PaintType.Eraser) {
237 | widget.context.moveTo(startX, startY);
238 | widget.context.lineTo(endX, endY);
239 | startX = endX;
240 | startY = endY;
241 | widget.context.stroke();
242 | }else if(widget.paintType==widget.PaintType.Rect){
243 | if(endX > maxX){maxX = endX;}
244 | if(endX < minX){minX = endX;}
245 | if(endY > maxY){maxY = endY;}
246 | if(endY < minY){minY = endY;}
247 | widget.context.clearRect(minX-lineWidth,minY-lineWidth,maxX - minX+2*lineWidth,maxY - minY+2*lineWidth);
248 | widget.context.strokeRect(startX,startY,e.offsetX -startX,e.offsetY - startY);
249 | }else if(widget.paintType==widget.PaintType.Circle){
250 | var radius = Math.sqrt(Math.pow(e.offsetX -startX,2),Math.pow(e.offsetY - startY,2));
251 | if(maxRadius < radius){maxRadius = radius;}
252 | widget.context.clearRect(startX-maxRadius-lineWidth,startY-maxRadius-lineWidth,2*maxRadius+2*lineWidth,2*maxRadius+2*lineWidth);
253 | widget.context.beginPath();
254 | widget.context.arc(startX,startY,radius,0,2*Math.PI);
255 | widget.context.stroke();
256 | widget.context.closePath();
257 | }
258 | }
259 | });
260 | $(this.canvas).mouseup(function(e){
261 | painting = false;
262 | widget.context.closePath();
263 | });
264 | };
265 | var _insertSnapContainerDownLoad=function(){
266 | this.snapContainerDownLoad = $('