canvasDrawer.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. <template>
  2. <div>
  3. <el-form :inline="true">
  4. <el-form-item label="考号类型">
  5. <el-radio v-model="khType" :label="1" :value="1">手写</el-radio>
  6. <el-radio v-model="khType" :label="2" :value="2">条码</el-radio>
  7. </el-form-item>
  8. <el-form-item label="考号位数">
  9. <el-input-number size="mini" v-model="khLength" :min="6" :max="20" label="描述文字"></el-input-number>
  10. </el-form-item>
  11. <el-form-item label="识别设置">
  12. <el-radio v-model="recTarget" :label="1" :value="1">整块区域</el-radio>
  13. <el-radio v-model="recTarget" :label="2" :value="2">单个涂点</el-radio>
  14. </el-form-item>
  15. <el-form-item>
  16. <el-button type="primary" size="mini" @click="updateStdKhInfo">保存</el-button>
  17. </el-form-item>
  18. </el-form>
  19. <div style="border:1px solid #ccc;overflow: scroll;" @contextmenu.prevent="onContextmenu">
  20. <canvas id="myCanvas" ref="myCanvas" :width="srcImgWidth" :height="srcImgHeight" @click="findRect"
  21. @mousedown="mousedown" @mouseup="mouseup" @mousemove="mousemove">
  22. </canvas>
  23. <canvas id="myCopyCanvas" ref="myCopyCanvas" :width="srcImgWidth" :height="srcImgHeight"
  24. style="display: none;">
  25. </canvas>
  26. <canvas id="myCropCanvas" ref="myCropCanvas" :width="rectWidth" :height="rectHeight">
  27. </canvas>
  28. <img :src="srcImg" width="100%" alt="" id="stdKhImg" style="display:none;">
  29. </div>
  30. </div>
  31. </template>
  32. <script>
  33. export default {
  34. name: "canvasDrawer",
  35. props: {
  36. srcImg: String,
  37. curId:String
  38. },
  39. data() {
  40. return {
  41. flag: false,
  42. rectWidth: 0, //矩形框的宽
  43. rectHeight: 0, //矩形框的高
  44. totalRect: [], //画的所有的矩形坐标长度数据存储在数组中
  45. downX: 0, //鼠标点击图片落下时的位置(X)
  46. downY: 0, //鼠标点击图片落下时的位置(Y)
  47. ctx: "", //dom节点
  48. canvas: null,
  49. rectTag: false,
  50. delIndex: null, //删除时选中的矩形框的index
  51. atime: null,
  52. dialogVisible: false, //删除的弹出框
  53. keyCode: null,
  54. startX: null,
  55. startY: null,
  56. img: null,
  57. imgWidth: null,
  58. imgHeight: null,
  59. cropWidth: 0,
  60. cropHeight: 0,
  61. khType: 1,
  62. khLength: 6,
  63. recTarget: 1,
  64. curArea:null,
  65. stdRect:null,
  66. srcImgWidth:null,
  67. srcImgHeight:null,
  68. stdKhList:[]
  69. };
  70. },
  71. created() {
  72. var image = new Image();
  73. image.src = this.srcImg
  74. this.srcImgWidth = image.width;
  75. this.srcImgHeight = image.height;
  76. this.getData();
  77. },
  78. mounted() {
  79. var image = new Image();
  80. image.src = this.srcImg
  81. this.srcImgWidth = image.width;
  82. this.srcImgHeight = image.height;
  83. let that = this
  84. // 绘图canvas
  85. this.canvas = this.$refs.myCanvas;
  86. this.canvas = document.getElementById("myCanvas")
  87. this.ctx = this.canvas.getContext("2d");
  88. // 复制canvas
  89. this.copyCanvas = document.getElementById("myCopyCanvas")
  90. this.copyCtx = this.copyCanvas.getContext("2d");
  91. // 裁剪canvas
  92. this.cropCanvas = document.getElementById("myCropCanvas")
  93. this.cropCtx = this.cropCanvas.getContext("2d");
  94. let img = document.getElementById("stdKhImg");
  95. img.onload = function () {
  96. that.ctx.drawImage(img, 0, 0, that.srcImgWidth, that.srcImgHeight, 0, 0, that.srcImgWidth, that
  97. .srcImgHeight)
  98. that.copyCtx.drawImage(img, 0, 0, 672, 264, 0, 0, 672, 264)
  99. }
  100. that.img = img
  101. document.onkeydown = function (event) {
  102. that.keyCode = event.keyCode
  103. }
  104. document.onkeyup = function (event) {
  105. that.keyCode = null
  106. that.downX = that.startX
  107. that.downY = that.downY
  108. that.startX = null
  109. that.startY = null
  110. }
  111. },
  112. methods: {
  113. onContextmenu(event) {
  114. this.$contextmenu({
  115. items: [{
  116. label: "复制",
  117. onClick: () => {
  118. this.message = "返回(B)";
  119. console.log("返回(B)");
  120. }
  121. }, {
  122. label: "删除",
  123. onClick: () => {
  124. this.del()
  125. }
  126. }, {
  127. label: "刷新",
  128. onClick: () => {
  129. this.clear();
  130. this.totalRect = [];
  131. this.redrawAll();
  132. }
  133. },{
  134. label: "正列",
  135. onClick: () => {
  136. this.message = "返回(B)";
  137. console.log("返回(B)");
  138. this.zhenlie();
  139. }
  140. }],
  141. x: event.clientX,
  142. y: event.clientY,
  143. zIndex: 10000,
  144. minWidth: 100
  145. })
  146. },
  147. copy() {
  148. console.log("复制操作");
  149. },
  150. delete() {
  151. console.log("删除操作");
  152. },
  153. zhenlie(){
  154. let stdW = this.stdRect["w"];
  155. let stdH = this.stdRect["h"];
  156. // 计算涂点间距
  157. let totalWidth = this.curArea["w"];
  158. let totalHeight = this.curArea["h"];
  159. let startX = this.curArea["x"];
  160. let startY = this.curArea["y"];
  161. let stepW = (totalWidth - stdW*this.khLength)/(this.khLength-1);
  162. let stepH = (totalHeight - stdH*10)/9;
  163. // 计算阵列矩形列表
  164. let rectArray = [];
  165. let stdKhList = [];
  166. for(var i=0;i<this.khLength;i++){
  167. let tmpRow = [];
  168. for(var j=0;j<10;j++){
  169. let tmp = {
  170. beforex:(stepW+stdW)*i+startX,
  171. beforey:(stepH+stdH)*j+startY,
  172. rectW:stdW,
  173. rectH:stdH
  174. }
  175. rectArray.push(tmp)
  176. tmpRow.push(tmp)
  177. }
  178. stdKhList.push(tmpRow)
  179. }
  180. this.clear();
  181. this.totalRect = rectArray;
  182. this.stdKhList = stdKhList;
  183. this.redrawAll();
  184. },
  185. zoom2(flag = true) {
  186. const scale = 0.8;
  187. const beta = flag ? 1 / scale : scale;
  188. this.ctx.scale(beta, beta);
  189. },
  190. // 放下鼠标
  191. mousedown(e) {
  192. console.log("鼠标落下");
  193. this.atime = new Date().getTime();
  194. this.flag = true;
  195. this.downX = e.offsetX; // 鼠标落下时的X
  196. this.downY = e.offsetY; // 鼠标落下时的Y
  197. this.mousemove(e);
  198. },
  199. // 移动鼠标
  200. mousemove(e) {
  201. if (this.flag) {
  202. //判断如果重右下往左上画,这种画法直接return
  203. if (this.downX - e.offsetX > 0 || this.downY - e.offsetY > 0) {
  204. console.log("重右下往左上画");
  205. return
  206. } else {
  207. console.log("重左上往右下画");
  208. this.clear(); //清空画布
  209. this.redrawAll();
  210. console.log(this.keyCode)
  211. if (this.keyCode == 32) {
  212. this.startX = this.downX + (e.offsetX - this.downX) - this.rectWidth
  213. this.startY = this.downY + (e.offsetY - this.downY) - this.rectHeight
  214. // console.log(startX,startY,this.rectWidth,this.rectHeight)
  215. this.drawRect(
  216. this.startX,
  217. this.startY,
  218. this.rectWidth,
  219. this.rectHeight
  220. )
  221. } else {
  222. //如果重左上往右下画,计算出鼠标移动的距离,也就是矩形框的宽和高
  223. this.rectWidth = Math.abs(this.downX - e.offsetX)
  224. this.rectHeight = Math.abs(this.downY - e.offsetY)
  225. console.log("this.rectWidth", this.rectWidth);
  226. console.log("this.rectHeight", this.rectHeight);
  227. //判断这个宽高的长度,如果小于10,直接return,因为鼠标移动距离过于短
  228. //防止点击页面时,会画成一个点,没有意义
  229. if (this.rectWidth < 10 || this.rectHeight < 10) {
  230. console.log("只是点击");
  231. this.rectWidth = 0;
  232. this.rectHeight = 0;
  233. return;
  234. }
  235. if (this.startX) {
  236. this.downX = this.startX
  237. }
  238. if (this.startY) {
  239. this.downY = this.startY
  240. }
  241. this.drawRect(
  242. this.downX,
  243. this.downY,
  244. this.rectWidth,
  245. this.rectHeight
  246. )
  247. }
  248. }
  249. }
  250. },
  251. // 抬起鼠标
  252. mouseup(e) {
  253. // console.log("鼠标抬起");
  254. this.flag = false;
  255. let a = new Date().getTime();
  256. console.log(a - this.atime, 444444444)
  257. if (a - this.atime > 150) {
  258. this.rectTag = false;
  259. } else {
  260. this.rectTag = true;
  261. }
  262. if (this.rectWidth || this.rectHeight) {
  263. //将画出的数据保存在totalRect中
  264. this.totalRect.push({
  265. beforex: this.downX,
  266. beforey: this.downY,
  267. rectW: this.rectWidth,
  268. rectH: this.rectHeight,
  269. });
  270. let data = this.copyCtx.getImageData(this.downX, this.downY, this.rectWidth, this.rectHeight)
  271. this.cropWidth = this.rectWidth;
  272. this.cropHeight = this.rectHeight;
  273. let c = document.getElementById("myCropCanvas");
  274. let ctx = c.getContext("2d");
  275. ctx.putImageData(data, 0, 0)
  276. let val = c.toDataURL("image/jpeg");
  277. // 单个涂点
  278. if (this.recTarget == 2) {
  279. this.$api.tryRecArray({
  280. sx: this.downX,
  281. sy: this.downY,
  282. img: val,
  283. khLength: 15
  284. }).then(res => {
  285. let oneRect = res.data.data.oneRect;
  286. this.totalRect.pop()
  287. this.totalRect.push({
  288. beforex: oneRect.x,
  289. beforey: oneRect.y,
  290. rectW: oneRect.w,
  291. rectH: oneRect.h
  292. })
  293. this.stdRect = {x:oneRect.x,y:oneRect.y,w:oneRect.w,h:oneRect.h}
  294. this.clear(); //清空画布
  295. this.redrawAll();
  296. })
  297. }else{
  298. this.curArea = {x:this.downX,y:this.downY,w:this.rectWidth,h:this.rectHeight}
  299. }
  300. }
  301. },
  302. redrawAll() {
  303. // console.log("先画之前画过的图,保证画多个的时候看起来像前一个不消失");
  304. this.ctx.drawImage(this.img, 0, 0)
  305. if (this.totalRect.length > 0) {
  306. this.totalRect.forEach((e) => {
  307. // console.log("eeeeeeeeeeeeeeeee",e);
  308. this.drawRect(e.beforex, e.beforey, e.rectW, e.rectH);
  309. });
  310. }
  311. },
  312. //清除画布
  313. clear() {
  314. this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
  315. },
  316. drawRect(x, y, lineW, lineY) {
  317. // 开始绘制;
  318. this.ctx.beginPath();
  319. // //设置线条颜色,必须放在绘制之前
  320. this.ctx.strokeStyle = "#850a1e";
  321. // console.log("44444444");
  322. // // 线宽设置,必须放在绘制之前
  323. this.ctx.lineWidth = 1;
  324. // console.log("5555555555");
  325. // strokeRect参数:(左上角x坐标,y:左上角y坐标,绘画矩形的宽度,绘画矩形的高度)
  326. this.ctx.strokeRect(x, y, lineW, lineY);
  327. // console.log("66666666666666");
  328. },
  329. //点击画布
  330. findRect(e) {
  331. console.log(e,88888888888888)
  332. if (this.rectTag || true) {
  333. console.log("this.totalRect", this.totalRect);
  334. //当点击画布的时候,计算有没有点再矩形框内、哪个矩形框内
  335. this.totalRect.map((item, index) => {
  336. if (
  337. e.offsetX - item.beforex > item.rectW ||
  338. e.offsetX < item.beforex ||
  339. e.offsetY - item.beforey > item.rectH ||
  340. e.offsetY < item.beforey
  341. ) {
  342. return;
  343. } else {
  344. //找到之后,设置下标
  345. this.delIndex = index;
  346. //打开删除弹框
  347. this.dialogVisible = true;
  348. console.log("this.delIndex", this.delIndex);
  349. }
  350. });
  351. }
  352. },
  353. //点击删除按钮
  354. del() {
  355. this.dialogVisible = false;
  356. //删除
  357. this.ctx.clearRect(
  358. this.totalRect[this.delIndex].beforex - 2,
  359. this.totalRect[this.delIndex].beforey - 2,
  360. this.totalRect[this.delIndex].rectW + 4,
  361. this.totalRect[this.delIndex].rectH + 4
  362. );
  363. //删掉totalRect的数据,真正的项目中需要调用后台接口,删掉数据库中存储的数据
  364. this.totalRect.splice(this.delIndex, 1);
  365. //删掉之后,再画一次,刷新页面
  366. this.redrawAll();
  367. console.log(this.totalRect, "删除了没");
  368. },
  369. getData(){
  370. this.totalRect = [];
  371. this.$api.getPaperInfo({id:this.curId}).then((res) => {
  372. this.khType = res.data.data.khType;
  373. this.khLength = res.data.data.khLength;
  374. let stdKhList = JSON.parse(res.data.data.stdKhList);
  375. stdKhList.forEach((children,index)=>{
  376. children.forEach((item,index)=>{
  377. this.totalRect.push(item)
  378. })
  379. })
  380. this.redrawAll();
  381. });
  382. },
  383. updateStdKhInfo(){
  384. let params = {
  385. id: this.curId,
  386. stdKhList:this.stdKhList,
  387. khType:this.khType,
  388. khLength:this.khLength,
  389. khPoints:this.srcImg
  390. }
  391. this.$api.updatePaperInfo(params).then(res => {
  392. this.msgSuccess("成功!");
  393. this.open = false;
  394. })
  395. }
  396. },
  397. };
  398. </script>
  399. <style lang="scss" scoped>
  400. #myCanvas {
  401. background-color: #ccc;
  402. }
  403. .dislog {
  404. /* width: 200px; */
  405. /* height: 200px; */
  406. background-color: pink;
  407. }
  408. </style>