| | |
| | | <!-- 涂色连线题控件 --> |
| | | <template> |
| | | <div class="page" :style="{height:imgHeight + 120 + 'px'}"> |
| | | <div class="page" :style="{ height: imgHeight + 120 + 'px' }"> |
| | | <div class="main"> |
| | | <div id="canvas_panel"> |
| | | <canvas |
| | |
| | | > |
| | | </div> |
| | | </div> |
| | | <div class="footer" :style="{backgroundColor:bcColor}"> |
| | | <BrushSize :size="brushSize" @change-size="onChangeSize" @change-color="onChangeColor" /> |
| | | <div class="footer" :style="{ backgroundColor: bcColor }"> |
| | | <BrushSize |
| | | :size="brushSize" |
| | | @change-size="onChangeSize" |
| | | @change-color="onChangeColor" |
| | | /> |
| | | <ToolBtns :tool="brushTool" @change-tool="onChangeTool" /> |
| | | </div> |
| | | </div> |
| | |
| | | export default { |
| | | name: "graffiti", |
| | | components: { BrushSize, ToolBtns }, |
| | | props:{ |
| | | page:{ |
| | | type:Number |
| | | props: { |
| | | page: { |
| | | type: Number, |
| | | }, |
| | | bcImg:{ |
| | | type:String |
| | | bcImg: { |
| | | type: String, |
| | | }, |
| | | imgWidth:{ |
| | | type:Number |
| | | imgWidth: { |
| | | type: Number, |
| | | }, |
| | | imgHeight:{ |
| | | type:Number |
| | | imgHeight: { |
| | | type: Number, |
| | | }, |
| | | bcColor:{ |
| | | type:String, |
| | | default:'#fff' |
| | | } |
| | | bcColor: { |
| | | type: String, |
| | | default: "#fff", |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | canvas: null, |
| | | context: null, |
| | | painting: false, // 记录状态,鼠标是否在按下状态 |
| | | painting: false, // 记录状态,鼠标是否在按下状态 |
| | | historyData: [], // 存储历史数据,用于撤销 |
| | | brushSize: 5, // 笔刷大小 |
| | | brushColor: "#000000", // 笔刷颜色 |
| | |
| | | left: 0, |
| | | top: 0, |
| | | }, |
| | | backgroundImage: |
| | | "", |
| | | backgroundImage: "", |
| | | }; |
| | | }, |
| | | mounted() { |
| | | this.backgroundImage = this.bcImg |
| | | this.canvas = (this.container ? this.container : document).getElementById("canvas"); |
| | | this.backgroundImage = this.bcImg; |
| | | this.canvas = (this.container ? this.container : document).getElementById( |
| | | "canvas" |
| | | ); |
| | | if (this.canvas.getContext) { |
| | | this.context = this.canvas.getContext("2d", { willReadFrequently: true }); |
| | | this.initCanvas(); |
| | | // window.addEventListener('resize', updateCanvasPosition); |
| | | ( |
| | | this.container ? this.container : document |
| | | ).addEventListener("scroll",this.updateCanvasOffset,true); // 添加滚动条滚动事件监听器 |
| | | (this.container ? this.container : document).addEventListener( |
| | | "scroll", |
| | | this.updateCanvasOffset, |
| | | true |
| | | ); // 添加滚动条滚动事件监听器 |
| | | this.getCanvasOffset(); |
| | | this.context.lineGap = "round"; |
| | | this.context.lineJoin = "round"; |
| | |
| | | this.canvas.addEventListener("mouseleave", this.closePaint); |
| | | } |
| | | this.toolClear(); |
| | | const oldData = localStorage.getItem(this.config.activeBook.name + '-graffiti-' + this.page) |
| | | if(oldData) { |
| | | this.backgroundImage = oldData |
| | | const oldData = localStorage.getItem( |
| | | this.config.activeBook.name + "-graffiti-" + this.page |
| | | ); |
| | | if (oldData) { |
| | | this.backgroundImage = oldData; |
| | | } |
| | | }, |
| | | // watch:{ |
| | |
| | | }, |
| | | // 初始化 画布,设置大小背景色 |
| | | initCanvas() { |
| | | const that = this |
| | | const that = this; |
| | | const resetCanvas = () => { |
| | | const elPanel = ( |
| | | this.container ? this.container : document |
| | | ).getElementById("canvas_panel"); |
| | | that.canvas.width = elPanel.clientWidth; |
| | | that.canvas.height = elPanel.clientHeight; |
| | | this.container ? this.container : document |
| | | ).getElementById("canvas_panel"); |
| | | try { |
| | | that.canvas.width = elPanel.clientWidth; |
| | | that.canvas.height = elPanel.clientHeight; |
| | | } catch (error) {} |
| | | |
| | | that.context = that.canvas.getContext("2d", { |
| | | willReadFrequently: true, |
| | | }); // 添加这一行 |
| | |
| | | // 设置画布背景图 |
| | | const imgData = new Image(); |
| | | // 分两种情况,初次的图片 直接用外部链接,需要加跨域和时间戳,二次保存的作为背景则不需要 |
| | | const oldData = localStorage.getItem(this.config.activeBook.name + '-graffiti-' + this.page) |
| | | if(oldData) { |
| | | imgData.src = oldData |
| | | const oldData = localStorage.getItem( |
| | | this.config.activeBook.name + "-graffiti-" + this.page |
| | | ); |
| | | if (oldData) { |
| | | imgData.src = oldData; |
| | | } else { |
| | | imgData.src = this.backgroundImage + '?' + new Date().getTime(); |
| | | imgData.setAttribute('crossOrigin', ''); |
| | | imgData.src = this.backgroundImage + "?" + new Date().getTime(); |
| | | imgData.setAttribute("crossOrigin", ""); |
| | | } |
| | | imgData.onload = () => { |
| | | this.context.drawImage(imgData,0,0,this.imgWidth,this.imgHeight) |
| | | } |
| | | } |
| | | this.context.drawImage(imgData, 0, 0, this.imgWidth, this.imgHeight); |
| | | }; |
| | | }; |
| | | resetCanvas(); |
| | | // 监听窗口大小 ,窗口改变重新渲染画布 |
| | | window.addEventListener("resize", resetCanvas); |
| | |
| | | }, |
| | | // 重新计算画布的偏移值 |
| | | updateCanvasOffset() { |
| | | this.getCanvasOffset(); |
| | | this.getCanvasOffset(); |
| | | }, |
| | | // 改变笔刷大小 |
| | | onChangeSize(size) { |
| | |
| | | // 新加内容,清空后将背景图再设置上去 |
| | | const imgData = new Image(); |
| | | // 分两种情况,初次的图片 直接用外部链接,需要加跨域和时间戳,二次保存的作为背景则不需要 |
| | | const oldData = localStorage.getItem(this.config.activeBook.name + '-graffiti-' + this.page) |
| | | if(oldData) { |
| | | imgData.src = oldData |
| | | const oldData = localStorage.getItem( |
| | | this.config.activeBook.name + "-graffiti-" + this.page |
| | | ); |
| | | if (oldData) { |
| | | imgData.src = oldData; |
| | | } else { |
| | | imgData.src = this.backgroundImage + '?' + new Date().getTime(); |
| | | imgData.setAttribute('crossOrigin', ''); |
| | | imgData.src = this.backgroundImage + "?" + new Date().getTime(); |
| | | imgData.setAttribute("crossOrigin", ""); |
| | | } |
| | | imgData.onload = () => { |
| | | this.context.drawImage(imgData,0,0,this.imgWidth,this.imgHeight) |
| | | } |
| | | this.context.drawImage(imgData, 0, 0, this.imgWidth, this.imgHeight); |
| | | }; |
| | | }, |
| | | // 保存画布背景和划线到本地方法 |
| | | toolSave() { |
| | | var imgData = this.canvas.toDataURL({format: 'png', quality:1, width:800,}); |
| | | localStorage.setItem(this.config.activeBook.name + '-graffiti-' + this.page,imgData) |
| | | var imgData = this.canvas.toDataURL({ |
| | | format: "png", |
| | | quality: 1, |
| | | width: 800, |
| | | }); |
| | | localStorage.setItem( |
| | | this.config.activeBook.name + "-graffiti-" + this.page, |
| | | imgData |
| | | ); |
| | | }, |
| | | // 保存为一张图片并下载的方法 |
| | | saveImgData() { |
| | | var link = ( |
| | | this.container ? this.container : document |
| | | ).createElement("a"); |
| | | var imgData = this.canvas.toDataURL({format: 'png', quality:1, width:20000, height:4000}); |
| | | var link = (this.container ? this.container : document).createElement( |
| | | "a" |
| | | ); |
| | | var imgData = this.canvas.toDataURL({ |
| | | format: "png", |
| | | quality: 1, |
| | | width: 20000, |
| | | height: 4000, |
| | | }); |
| | | var strDataURI = imgData.substr(22, imgData.length); |
| | | var blob = dataURLtoBlob(imgData); |
| | | var objurl = URL.createObjectURL(blob); |
| | | link.download = "grid1.png"; |
| | | link.href = objurl; |
| | | link.click(); |
| | | |
| | | function dataURLtoBlob(dataurl) { |
| | | var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], |
| | | bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); |
| | | while(n--){ |
| | | |
| | | function dataURLtoBlob(dataurl) { |
| | | var arr = dataurl.split(","), |
| | | mime = arr[0].match(/:(.*?);/)[1], |
| | | bstr = atob(arr[1]), |
| | | n = bstr.length, |
| | | u8arr = new Uint8Array(n); |
| | | while (n--) { |
| | | u8arr[n] = bstr.charCodeAt(n); |
| | | } |
| | | return new Blob([u8arr], {type:mime}); |
| | | return new Blob([u8arr], { type: mime }); |
| | | } |
| | | }, |
| | | // 返回上一步方法(撤销) |
| | | toolUndo() { |
| | | // |
| | | // |
| | | if (this.historyData.length <= 0) { |
| | | this.resetToolActive(); |
| | | return; |
| | |
| | | .page { |
| | | display: flex; |
| | | flex-direction: column; |
| | | width:100%; |
| | | width: 100%; |
| | | } |
| | | |
| | | .main { |