canvasDrawer.vue 17 KB

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