online_agree.html 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>在线签署</title>
  6. <meta content="IE=edge" http-equiv="X-UA-Compatible" />
  7. <meta content="yes" name="apple-mobile-web-app-capable" />
  8. <meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1">
  9. <meta content="black" name="apple-mobile-web-app-status-bar-style" />
  10. <link href="base.css" rel="stylesheet" type="text/css">
  11. <!--<link href="layer/need/layer.css" rel="stylesheet" type="text/css">-->
  12. <script src="layer/layer.js" type="text/javascript"></script>
  13. <style>
  14. body, html {
  15. overflow: hidden;
  16. position: fixed;
  17. width: 100%;
  18. top: 0;
  19. left: 0;
  20. }
  21. canvas {
  22. background: white;
  23. border: 1px dashed black;
  24. /*position: absolute;
  25. top: 0;
  26. left: 0;*/
  27. }
  28. .top_bars {
  29. /*position: fixed;*/
  30. background: #f1f1f1;
  31. }
  32. .tools {
  33. /*position: absolute;
  34. width: 1.3rem;
  35. height: .5rem;
  36. left: -18px;*/
  37. margin-left: 2.5rem;
  38. margin-right: 2.5rem;
  39. margin-top: 0.15rem;
  40. float: left;
  41. background: #495060;
  42. color: white;
  43. line-height: 0.5rem;
  44. text-align: center;
  45. /*transform: rotateZ(90deg);*/
  46. }
  47. .clearCanvas {
  48. width: 1.3rem;
  49. }
  50. .pencilOrMove {
  51. width: 1.3rem;
  52. }
  53. .finish {
  54. width: 1.3rem;
  55. background: #0590ff;
  56. }
  57. .reload {
  58. width: 1.3rem;
  59. }
  60. .tips {
  61. font-size: 0.32rem;
  62. text-align: center;
  63. }
  64. /*.secondState {
  65. transform: rotate(90deg);
  66. z-index: 10;
  67. position: fixed;
  68. top: 50%;
  69. width: 8.4rem;
  70. left: 52px;
  71. font-size: 0.25rem;
  72. }*/
  73. /*.btn_put {
  74. border: 0;
  75. padding: 10px;
  76. color: white;
  77. border-radius: 4px;
  78. outline: none;
  79. }
  80. .btn_success {
  81. background: #58c73d;
  82. }
  83. .btn_fail {
  84. background: #d63c3c;
  85. }*/
  86. .flex_bottom {
  87. position: fixed;
  88. bottom: 10px;
  89. z-index: 90;
  90. display: flex;
  91. justify-content: space-around;
  92. align-items: center;
  93. width: 100%;
  94. }
  95. .mask {
  96. position: fixed;
  97. top: 0;
  98. left: 0;
  99. background: white;
  100. width: 100%;
  101. height: 100%;
  102. z-index: 40;
  103. }
  104. #canvas2 {
  105. width: 100%;
  106. height: 100%;
  107. }
  108. #resultImg{
  109. position:absolute;
  110. left:0;
  111. top:0;
  112. z-index: 50;
  113. }
  114. </style>
  115. </head>
  116. <body>
  117. <div class="top_bars" id="top">
  118. <div class="tools clearCanvas" id="clear">清除文字</div>
  119. <div class="tools pencilOrMove" id="isUsePencil">移动签字板</div>
  120. <div class="tools finish" id="finish">提交签名</div>
  121. <div class="tools reload" id="reload">重新签署</div>
  122. </div>
  123. <div>
  124. <canvas id="canvas"></canvas>
  125. </div>
  126. <div>
  127. <p class="tips" id="tips">请在空白虚线区域内手写您的姓名</p>
  128. </div>
  129. <script>
  130. var NAME = 0;//签名状态
  131. var STATEMENT = 1;//抄写状态
  132. var supportsPassive = false;
  133. var canvasPaint = {};//画布相关状态变量
  134. var events = null;//是移动端还是pc端
  135. var state = NAME;
  136. try {
  137. var opts = Object.defineProperty({}, 'passive', {
  138. get: function () {
  139. supportsPassive = true;
  140. }
  141. });
  142. window.addEventListener("test", null, opts);
  143. } catch (e) {
  144. }
  145. window.onload = function () {
  146. //show_msg('请使用手机模式预览DEMO');
  147. canvasPaint.canPaint = true;//是否可以写字
  148. canvasPaint.piece = 17;//canvas的高度乘以了17倍(拖动画布功能)
  149. canvasPaint.width = 1200;
  150. //window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  151. canvasPaint.height = 600;
  152. //window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
  153. document.getElementById("top").style.width = canvasPaint.width + 'px';
  154. document.getElementById("top").style.height = 50 + 'px';
  155. //document.getElementById("top").style.height = canvasPaint.height + 'px';
  156. //canvasPaint.width = canvasPaint.width - 40;//预留工具栏宽度
  157. canvasPaint.clearBtn = document.getElementById("clear");
  158. canvasPaint.pencilBtn = document.getElementById("isUsePencil");
  159. canvasPaint.finish = document.getElementById("finish");
  160. //canvasPaint.tips = document.getElementById("tips");
  161. canvasPaint.reload = document.getElementById("reload");
  162. //canvasPaint.secondState = document.getElementById("secondState");
  163. //canvasPaint.back = document.getElementById("back");
  164. //canvasPaint.btn_success = document.getElementById("btn_success");
  165. //canvasPaint.btn_fail = document.getElementById("btn_fail");
  166. if (state === NAME) {
  167. //签名模式隐藏拖动画布按钮
  168. canvasPaint.pencilBtn.style.display = 'none';
  169. }
  170. try {
  171. canvasPaint.canvas = document.getElementById("canvas");
  172. canvasPaint.ctx = document.getElementById("canvas").getContext("2d");
  173. canvasPaint.canvas.width = canvasPaint.width;
  174. canvasPaint.canvas.height = canvasPaint.height;
  175. //* canvasPaint.piece;
  176. canvasPaint.canvas.style.width = canvasPaint.canvas.width + 'px';
  177. canvasPaint.canvas.style.height = canvasPaint.canvas.height + 'px';
  178. } catch (e) {
  179. layer.open({
  180. content: '您的手机版本过低,不支持在线签署,请使用打印方式签字'
  181. , btn: ['确定'],
  182. shadeClose: false
  183. , yes: function (index) {
  184. layer.close(index);
  185. location.reload();
  186. }
  187. });
  188. }
  189. canvasPaint.ctx.lineCap = 'round';
  190. canvasPaint.ctx.lineJoin = 'round';
  191. canvasPaint.ctx.strokeWidth = 8;
  192. canvasPaint.ctx.lineWidth = 8;
  193. canvasPaint.isSupportTouch = ("ontouchstart" in document);
  194. events = ('ontouchstart' in window) ? ['touchstart', 'touchmove', 'touchend'] : ['mousedown', 'mousemove', 'mouseup'];
  195. canvasPaint.canvas.addEventListener(events[0], startEventHandler, supportsPassive ? { passive: false } : false);
  196. canvasPaint.clearBtn.addEventListener(events[0], clearCanvas, false);
  197. canvasPaint.pencilBtn.addEventListener(events[0], togglePencil, false);
  198. canvasPaint.finish.addEventListener(events[0], finish, false);
  199. canvasPaint.reload.addEventListener(events[0], reload, false);
  200. //canvasPaint.btn_fail.addEventListener(events[0], reload, false);
  201. //canvasPaint.btn_success.addEventListener(events[0], putImg, false);
  202. console.log(canvasPaint);
  203. };
  204. //清除画布
  205. function clearCanvas() {
  206. canvasPaint.ctx.clearRect(0, 0, canvasPaint.canvas.width, canvasPaint.canvas.height);
  207. }
  208. //根据base64加载图片
  209. function preLoadImg(source, callBack, args) {
  210. debugger;
  211. var pr = [];
  212. for (var i = 0; i < source.length; i++) {
  213. var p = loadImage(source[i])
  214. .then(function (img) {
  215. return img;
  216. })
  217. .catch(function (err) {
  218. alert("绘制失败,您的手机不支持在线签署");
  219. });
  220. pr.push(p);
  221. }
  222. Promise.all(pr)
  223. .then(function (imgArray) {
  224. callBack(imgArray, args);
  225. });
  226. }
  227. function loadImage(url) {
  228. return new Promise((resolve, reject) => {
  229. var img = new Image();
  230. img.onload = function () {
  231. resolve(img);
  232. };
  233. img.onerror = reject;
  234. img.src = url;
  235. });
  236. }
  237. //点击完成时的逻辑处理函数
  238. function finish() {
  239. debugger;
  240. canvasPaint.layerIndex = layer.open({ type: 2, shadeClose: false });//遮罩
  241. if (state === NAME) {
  242. let image = new Image();
  243. image.src = canvasPaint.canvas.toDataURL("image/png");
  244. console.log(image.src);
  245. return image
  246. //window.open(image);
  247. //加载模板图和签的字,回调函数是result函数
  248. //preLoadImg(['agree.jpg', canvasPaint.canvas.toDataURL()], result);
  249. //var imgURL = canvasPaint.canvas.toDataURL();
  250. }
  251. if (state === STATEMENT) {
  252. debugger;
  253. //加载抄的字,回调函数是stateResult函数
  254. preLoadImg([canvasPaint.canvas.toDataURL()], stateResult);
  255. }
  256. }
  257. function stateResult(imgArr) {
  258. try {
  259. statementDraw(imgArr);
  260. canvasPaint.canvas.removeEventListener(events[0], startEventHandler, false);
  261. document.removeEventListener(events[0], documentStartEventHandler, false);
  262. layer.close(canvasPaint.layerIndex);
  263. } catch (e) {
  264. layer.close(canvasPaint.layerIndex);
  265. alert('绘制失败');
  266. }
  267. }
  268. function result(imgArr) {
  269. try {
  270. drawName(imgArr);
  271. layer.close(canvasPaint.layerIndex);
  272. } catch (e) {
  273. layer.close(canvasPaint.layerIndex);
  274. alert('绘制失败');
  275. }
  276. }
  277. //绘制抄写的句子的方法
  278. function statementDraw(imgArr) {
  279. canvasPaint.context2.save();
  280. canvasPaint.context2.translate(490, 3085);
  281. canvasPaint.context2.rotate(270 * Math.PI / 180);
  282. canvasPaint.context2.drawImage(imgArr[0], 80, 50, 80, 80 * canvasPaint.ratio);//画反转后的名字
  283. canvasPaint.context2.restore();
  284. // console.log(canvasPaint.canvas2.toDataURL());
  285. document.getElementById('resultImg').setAttribute('src', canvasPaint.canvas2.toDataURL());
  286. document.getElementById('resultImg').style.display = "block";
  287. document.getElementById('mask').style.display = "block";
  288. document.getElementById('flex_bottom').style.visibility = "visible";
  289. canvasPaint.imgResult = canvasPaint.canvas2.toDataURL();
  290. console.warn(canvasPaint.imgResult);
  291. show_msg('到控制台拷贝Base64到浏览器地址可查看大图');
  292. }
  293. //抄句子前的预处理
  294. function prevDrawStatement() {
  295. clearCanvas();//清除名字
  296. canvasPaint.finish.innerHTML = "提交抄写";
  297. canvasPaint.pencilBtn.style.display = 'block';
  298. canvasPaint.secondState.style.display = 'block';
  299. canvasPaint.tips.innerHTML = "(最后一步)请抄写屏幕上方引号内的确认语句";
  300. canvasPaint.tips.style.color = 'red';
  301. setTimeout(function () {
  302. canvasPaint.tips.style.color = '#666';
  303. }, 2000);
  304. state = STATEMENT;//开始写句子
  305. }
  306. //写名字的函数
  307. function drawName(imgArr) {
  308. //绘制名字和底部的名字和日期
  309. canvasPaint.canvas2 = document.getElementById('canvas2');
  310. canvasPaint.context2 = canvasPaint.canvas2.getContext('2d');
  311. canvasPaint.ratio = canvasPaint.canvas.height / canvasPaint.canvas.width;
  312. canvasPaint.context2.drawImage(imgArr[0], 0, 0, 2480, 3507);//img0是底图原合同
  313. canvasPaint.context2.save();
  314. canvasPaint.context2.translate(455, 612);//1
  315. canvasPaint.context2.rotate(270 * Math.PI / 180);
  316. canvasPaint.context2.drawImage(imgArr[1], 80, 50, 70, 70 * canvasPaint.ratio);//画反转后的名字
  317. canvasPaint.context2.restore();
  318. canvasPaint.context2.save();
  319. canvasPaint.context2.translate(550, 3210);//下方的字 2
  320. canvasPaint.context2.rotate(270 * Math.PI / 180);
  321. canvasPaint.context2.drawImage(imgArr[1], 80, 50, 70, 70 * canvasPaint.ratio);//画反转后的名字
  322. canvasPaint.context2.restore();
  323. canvasPaint.context2.save();
  324. canvasPaint.context2.translate(1920, 3100);//下方的字
  325. canvasPaint.context2.font = "32px bold 微软雅黑";
  326. canvasPaint.context2.fillStyle = "#000";
  327. canvasPaint.context2.textAlign = "center";
  328. canvasPaint.context2.textBaseline = "middle";
  329. var date = new Date();
  330. var Y = date.getFullYear() + '/';
  331. var M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '/';
  332. var D = date.getDate();
  333. canvasPaint.context2.fillText((Y + M + D), 0, 0);
  334. canvasPaint.context2.restore();
  335. prevDrawStatement();
  336. }
  337. //是否写字的逻辑(拖动画布)
  338. function togglePencil() {
  339. if (canvasPaint.canPaint) {
  340. canvasPaint.canPaint = false;
  341. canvasPaint.pencilBtn.innerText = "使用签字笔";
  342. //不能签字时应该把开始事件去掉,同时加上document事件
  343. canvasPaint.canvas.removeEventListener(events[0], startEventHandler, false);
  344. document.addEventListener(events[0], documentStartEventHandler, supportsPassive ? { passive: false } : false);
  345. } else {
  346. canvasPaint.canPaint = true;
  347. canvasPaint.pencilBtn.innerText = "移动签字板";
  348. //能签字时应该把开始事件绑定上去,同时去掉document事件
  349. canvasPaint.canvas.addEventListener(events[0], startEventHandler, supportsPassive ? { passive: false } : false);
  350. document.removeEventListener(events[0], documentStartEventHandler, false);
  351. }
  352. }
  353. function reload() {
  354. location.reload();
  355. }
  356. function documentStartEventHandler(event) {
  357. event.preventDefault();
  358. var evt = canvasPaint.isSupportTouch ? event.touches[0] : event;
  359. canvasPaint.y = evt.clientY;
  360. canvasPaint.top = parseFloat(canvasPaint.canvas.style.top);
  361. document.addEventListener(events[1], documentMoveEventHandler, supportsPassive ? { passive: false } : false);
  362. document.addEventListener(events[2], documentEndEventHandler, supportsPassive ? { passive: false } : false);
  363. }
  364. function documentMoveEventHandler(event) {
  365. event.preventDefault();
  366. var evt = canvasPaint.isSupportTouch ? event.touches[0] : event;
  367. canvasPaint.newY = evt.clientY - canvasPaint.y;
  368. if (canvasPaint.canPaint === false) {
  369. //边界的判断
  370. canvasPaint.canvas.style.top = canvasPaint.newY + canvasPaint.top + 'px';
  371. if (parseFloat(canvasPaint.canvas.style.top) > 0) {
  372. canvasPaint.canvas.style.top = 0 + 'px';
  373. }
  374. if (Math.abs(parseFloat(canvasPaint.canvas.style.top)) > canvasPaint.canvas.height - canvasPaint.canvas.height / canvasPaint.piece) {
  375. canvasPaint.canvas.style.top = -(canvasPaint.canvas.height - canvasPaint.canvas.height / canvasPaint.piece) + 'px';
  376. }
  377. }
  378. }
  379. function documentEndEventHandler(event) {
  380. event.preventDefault();
  381. }
  382. function startEventHandler(event) {
  383. event.preventDefault();
  384. canvasPaint.ctx.beginPath();
  385. canvasPaint.canvas.addEventListener(events[1], moveEventHandler, supportsPassive ? { passive: false } : false);
  386. canvasPaint.canvas.addEventListener(events[2], endEventHandler, supportsPassive ? { passive: false } : false);
  387. }
  388. function moveEventHandler(event) {
  389. event.preventDefault();
  390. var evt = canvasPaint.isSupportTouch ? event.touches[0] : event;
  391. var coverPos = canvasPaint.canvas.getBoundingClientRect();
  392. canvasPaint.mouseX = evt.clientX - coverPos.left;
  393. canvasPaint.mouseY = evt.clientY - coverPos.top;
  394. if (canvasPaint.canPaint === true) {
  395. //根据坐标绘制
  396. canvasPaint.ctx.lineTo(
  397. canvasPaint.mouseX,
  398. canvasPaint.mouseY
  399. );
  400. canvasPaint.ctx.stroke();
  401. }
  402. }
  403. function endEventHandler(event) {
  404. event.preventDefault();
  405. canvasPaint.canvas.removeEventListener(events[1], moveEventHandler, false);
  406. canvasPaint.canvas.removeEventListener(events[2], endEventHandler, false);
  407. }
  408. //提交图片
  409. function putImg() {
  410. canvasPaint.layerIndex = layer.open({ type: 2, shadeClose: false });
  411. var formData = new FormData();
  412. var file = canvasPaint.imgResult;
  413. formData.append('record', file);
  414. console.log('模拟成功');
  415. layer.open({
  416. content: '上传成功,请等待审核'
  417. , btn: ['确定'],
  418. shadeClose: false
  419. , yes: function (index) {
  420. location.reload();
  421. layer.close(index);
  422. },
  423. });
  424. layer.close(canvasPaint.layerIndex);
  425. /*$.ajax({
  426. url: "agreement_img",
  427. type: 'POST',
  428. data: formData,
  429. processData: false,
  430. contentType: false,
  431. success: function (data) {
  432. layer.close(canvasPaint.layerIndex);
  433. if (data.code === 200) {
  434. layer.open({
  435. content: '上传成功,请等待审核'
  436. , btn: ['确定'],
  437. shadeClose: false
  438. , yes: function (index) {
  439. location.reload();
  440. layer.close(index);
  441. },
  442. });
  443. } else {
  444. layer.close(canvasPaint.layerIndex);
  445. show_msg('上传失败,请重试');
  446. }
  447. },
  448. error: function (error) {
  449. layer.close(canvasPaint.layerIndex);
  450. show_msg('上传失败,请重试');
  451. }
  452. });*/
  453. }
  454. function show_msg(content) {
  455. layer.open({
  456. content: content
  457. , skin: 'msg'
  458. , time: 5
  459. });
  460. }
  461. </script>
  462. </body>
  463. </html>