赞
踩
微信小程序 canvas 页面布局效果
实现功能:
1、落笔的时候开始计时
2、色卡:点击色卡,选择画笔的颜色
3、文本:文本可以选择格式
4、画笔:画笔粗细和透明度选择
5、把画布生成图片,并上传到服务器
借助mini-color-picker组件实现色卡的选择
- <view class="page_view" style="margin-top:{{navBarHeight*2+0}}rpx;">
- <canvas canvas-id="myCanvas" class="canvasBox _box-shadow" bindtouchstart="start" bindtouchmove="move"></canvas>
- <view class="bottomBox" bindtap="closeDialog">
- <view class="brushDialog" hidden="{{brushDialogHidden}}" catchtap="preventevents">
- <view class="brushWidthBox">
- <image bindtap="checkBrush" data-value="{{item.value}}" wx:for="{{brushList}}" wx:key="index" src="../../images/img/{{item.url}}" mode="heightFix"/>
- </view>
- <view class="sliderBg" style="margin: 20rpx 30rpx;">
- <view class="setBgOpacity" style="background-image: linear-gradient(to right, {{tools.setOpacticy(strokeStyle, 0)}}, {{tools.setOpacticy(strokeStyle, 1)}});"></view>
- <slider value="{{globalAlpha}}" class="globalAlphaBox" bindchanging="sliderchange" bindchange="sliderchange" min="0" max="1" step="0.01" block-size="20" activeColor="rgba(255,255,255,0)" backgroundColor="rgba(255,255,255,0)"/>
- </view>
- </view>
- <view class="canvasToll _box-shadow">
- <image src="../../images/img/colorSwatches.png" mode="heightFix" bindtap="openColorDialog" />
- <image src="../../images/img/text.png" mode="heightFix" bindtap="chengeText" />
- <!-- <image src="../../images/img/bucket.png" mode="heightFix"/> -->
- <image src="../../images/img/brush.png" mode="heightFix" catchtap="openBrushDialog"/>
- </view>
- <view class="btnBox">
- <button hidden="{{!hiddenFormat}}" class="btn" bindtap="submit">确定完成</button>
- </view>
- </view>
- <input focus="{{focus}}" value="{{inputValue}}" type="text" class="textInput" bindinput="bindKeyInput" bindconfirm="confirmInput" hidden="{{hiddenFormat}}" />
- </view>
-
- <view class="countdownBox" style="top:{{navBarHeight*2+100}}rpx;">
- <image src="/images/img/alarmClock.png" mode="heightFix"/>{{timerValue.text}}
- </view>
-
- <view class="textFormat" hidden="{{hiddenFormat}}" bindtap="openFormat">格式</view>
-
- <view class="maskBackground" wx:if="{{showDialog}}" bindtap="hideMask">
- <view class="pickerBox" catchtap="preventevents" style="background-color: {{showDialog == 2 ? '#fff' : '#F4F6F4'}};">
- <view class="maskTitle">
- <view class="">{{showDialog == 2 ? '格式' : '颜色'}}</view>
- <image src="../../images/img/guan.png" mode="widthFix" class="guanImg" bindtap="hideMask" />
- </view>
- <view wx:if="{{showDialog == 2}}" class="formatContent">
- <view wx:for="{{formatList}}" wx:key="index" bindtap="changeFormat" data-value="{{item}}">{{item}}</view>
- </view>
- <view wx:if="{{showDialog == 1}}" class="colorContent">
- <color-picker bindchangeColor="pickColor" initColor="{{strokeStyle}}" />
- <view class="opticyLabel">不透明度</view>
- <view class="sliderBox">
- <view class="sliderBg">
- <view class="setBgOpacity" style="background-image: linear-gradient(to right, {{tools.setOpacticy(strokeStyle, 0)}}, {{tools.setOpacticy(strokeStyle, 1)}});"></view>
- <slider value="{{globalAlpha}}" class="globalAlphaBoxInColor" bindchanging="sliderchange" bindchange="sliderchange" min="0" max="1" step="0.01" block-size="28" activeColor="rgba(255,255,255,0)" backgroundColor="rgba(255,255,255,0)" />
- </view>
- <view class="slideValue _box-shadow">{{tools.integer(globalAlpha * 100)}}%</view>
- </view>
- <view class="colorBottomBox">
- <view class="activeColorBox" style="background-color: {{strokeStyle}};opacity: {{globalAlpha}};"></view>
- <view class="activeColorArr">
- <view wx:for="{{activeColorList}}" wx:key="index" class="activeColor _box-shadow" style="background-color: {{item}}; margin-top: {{index > 4 ? '32rpx' : 0}}" bindtap="checkCorlor" data-color="{{item}}"></view>
- <image bindtap="addColor" class="activeColor" src="../../images/img/increase.png" mode="widthFix" style="margin-top: {{activeColorList.length > 4 ? '32rpx' : 0}}"/>
- </view>
- </view>
- </view>
- </view>
- </view>
-
- <wxs src = "../../utils/tools.wxs" module="tools"></wxs>

- /* treatmentPages/drawingCanvas/drawingCanvas.wxss */
- .viewPadd {
- background-color: #fff;
- padding: 0 30rpx;
- border-radius: 14rpx;
- margin-top: 46rpx;
- box-shadow: 0 0 4rpx 6rpx #ededed;
- }
- .viewHeader {
- height: 94rpx;
- line-height: 94rpx;
- border-bottom: 1rpx solid #DCDCDC;
- position: relative;
- font-size: 32rpx;
- font-weight: bold;
- color: #53545F;
- padding-left: 48rpx;
- }
- .viewHeader::before {
- content: '';
- position: absolute;
- top: 50%;
- left: 15rpx;
- transform: translateY(-50%);
- background-color: #007AFF;
- width: 10rpx;
- height: 30rpx;
- border-radius: 5rpx;
- border: none;
- display: block;
- }
- .viewContent {
- padding: 44rpx 20rpx 100rpx;
- color: #666666;
- font-size: 30rpx;
- line-height: 48rpx;
- }
- .btnBox {
- height: 80rpx;
- }
- .btn {
- background-color: #007AFF;
- border-radius: 14rpx;
- color: #fff;
- font-size: 32rpx;
- border: none;
- }
- .canvasBox {
- width: 100%;
- height: calc(100vh - 520rpx);
- background-color: #fff;
- border-radius: 14rpx;
- }
- .canvasToll {
- width: 100%;
- background-color: #fff;
- height: 124rpx;
- border-radius: 14rpx;
- margin: 46rpx 0;
- display: flex;
- justify-content: space-around;
- align-items: center;
- }
- .canvasToll image {
- height: 52rpx;
- }
- .bottomBox {
- position: fixed;
- bottom: 50rpx;
- left: 30rpx;
- right: 30rpx;
- z-index: 2;
- }
- .countdownBox {
- background-color: #fff;
- position: fixed;
- right: 0;
- top: 400rpx;
- border-radius: 30rpx 0 0 30rpx;
- display: flex;
- justify-content: center;
- align-items: center;
- width: 176rpx;
- height: 60rpx;
- color: #666666;
- font-size: 24rpx;
- box-shadow: -2rpx 0 16rpx 10rpx rgba(144, 138, 131, 0.35);
- }
- .countdownBox image {
- height: 35rpx;
- margin-right: 14rpx;
- }
- .textInput {
- position: fixed;
- bottom: 50rpx;
- left: 30rpx;
- right: 30rpx;
- height: 80rpx;
- z-index: 10;
- /* border: none; */
- }
- .textFormat {
- background-color: #fff;
- position: fixed;
- bottom: 200rpx;
- left: 0;
- border-radius: 0 30rpx 30rpx 0;
- display: flex;
- justify-content: center;
- align-items: center;
- width: 100rpx;
- height: 60rpx;
- color: #666666;
- font-size: 24rpx;
- box-shadow: -2rpx 0 16rpx 10rpx rgba(144, 138, 131, 0.35);
- z-index: 3;
- }
- .maskBackground {
- background-color: rgba(144, 138, 131, 0.1);
- }
- .pickerBox {
- position: absolute;
- width: 100%;
- bottom: 0;
- left: 0;
- box-sizing: border-box;
- z-index: 9;
- border-radius: 34rpx 34rpx 0 0;
- overflow: hidden;
- box-shadow: 0rpx 0rpx 4rpx 10rpx #14010128;
- max-height: 80%;
- overflow-y: auto;
- }
- .maskTitle {
- line-height: 120rpx;
- font-weight: bold;
- font-size: 40rpx;
- padding: 0 30rpx;
- display: flex;
- align-items: center;
- justify-content: space-between;
- color: #000000;
- }
- .guanImg {
- width: 51rpx;
- }
- .formatContent {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin: 50rpx 30rpx 100rpx;
- }
- .formatContent view {
- width: 168rpx;
- height: 114rpx;
- line-height: 114rpx;
- text-align: center;
- background-color: #F1F1F6;
- font-weight: bold;
- }
- .formatContent view:nth-child(1) {
- border-radius: 20rpx 0 0 20rpx;
- }
- .formatContent view:nth-child(3) {
- text-decoration: underline;
- }
- .formatContent view:nth-child(4) {
- border-radius: 0 20rpx 20rpx 0;
- text-decoration: line-through;
- }
- .brushDialog {
- background-color: #fff;
- width: 442rpx;
- border-radius: 20rpx;
- position: absolute;
- right: -10rpx;
- top: -180rpx;
- box-shadow: 2rpx 4rpx 8rpx 6rpx rgba(122, 122, 122, 0.40);
- z-index: 3;
- }
- .brushWidthBox {
- display: flex;
- justify-content: space-around;
- padding: 28rpx 0;
- border-bottom: 1rpx solid #C6C6C7;
- }
- .brushWidthBox image {
- height: 46rpx;
- }
- .globalAlphaBox {
- width: 100%;
- margin: 0;
- }
- .brushDialog::after {
- content: "";
- position: absolute;
- bottom: -0rpx;
- right: 85rpx;
- width: 60rpx;
- height: 30rpx;
- background-color: #fff;
- }
- .brushDialog::before {
- content: "";
- position: absolute;
- bottom: -20rpx;
- right: 96rpx;
- box-shadow: 2rpx 4rpx 8rpx 6rpx rgba(122, 122, 122, 0.40);
- border-radius: 6rpx;
- width: 40rpx;
- height: 40rpx;
- background: #fff;
- transform: rotate(45deg);
- }
-
- .globalAlphaBox .wx-slider-handle-wrapper {
- height: 40rpx;
- border-radius: 40rpx !important;
- }
- .globalAlphaBoxInColor {
- width: 510rpx;
- margin: 0;
- }
- .globalAlphaBoxInColor .wx-slider-handle-wrapper {
- height: 70rpx;
- border-radius: 70rpx !important;
- }
- .sliderBg {
- margin: 20rpx 0rpx;
- position: relative;
- }
- .setBgOpacity {
- position: absolute;
- top: 20rpx;
- left: 0;
- bottom: 20rpx;
- width: 100%;
- border-radius: 40rpx;
- }
- .sliderBox {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 30rpx;
- box-sizing: border-box;
- }
- .opticyLabel {
- padding: 70rpx 30rpx 0;
- color: #666666;
- font-size: 24rpx;
- }
- .slideValue {
- width: 144rpx;
- height: 70rpx;
- line-height: 70rpx;
- text-align: center;
- background-color: #fff;
- border-radius: 13rpx;
- color: #666666;
- font-size: 32rpx;
- }
- .colorBottomBox {
- margin: 20rpx 30rpx 80rpx;
- padding: 46rpx 30rpx 46rpx 0;
- border-top: 1rpx solid #C6C6C7;
- display: flex;
- justify-content: space-between;
- }
- .activeColorBox {
- width: 146rpx;
- height: 146rpx;
- border-radius: 16rpx;
- }
- .activeColorArr {
- width: 470rpx;
- height: 146rpx;
- display: flex;
- flex-wrap: wrap;
- }
- .activeColor {
- width: 60rpx;
- height: 60rpx;
- border-radius: 50%;
- margin-left: 34rpx;
- }
- .colorContent {
- height: calc(100% - 120rpx);
- overflow-y: scroll;
- }

- {
- "usingComponents": {
- "color-picker":"../components/mini-color-picker/color-picker"
- }
- }
- var app = getApp()
- Page({
-
- /**
- * 页面的初始数据
- */
- data: {
- navBarHeight: app.globalData.navBarHeight,
- navBarObj: {
- bgColor: '#fff',
- showBackBtn: true,
- showHomeBtn: true,
- title: '心理绘画'
- },
- appraisalPlanid: null, //患者疗愈计划id
- id: null, //疗愈具体数据的id
- x: 0, //开始的位置
- y: 0,
- newx: 0, //移动的位置
- newy: 0,
- timerValue: {
- text: '00:00:00', //显示的时间
- seconds: 0 //秒数
- },
- timer: null, //计时器
- canvasType: 1, // 1 线 2 文本
- inputValue: '', //文本内容
- hiddenFormat: true,
- focus: false,
- showDialog: false, //底部的弹窗 1 颜色 2 文本格式
- formatList: ['B', '/', 'U', 'S'],
- textFormat: null, //选中的文本格式
- brushList: [
- {url: 'brushLine1.png', value: 1},
- {url: 'brushLine2.png', value: 5},
- {url: 'brushLine3.png', value: 10},
- {url: 'brushLine4.png', value: 15},
- {url: 'brushLine5.png', value: 20}
- ],
- lineWidth: 1, //线的宽度
- globalAlpha: '1', //笔的透明度 范围 0-1
- brushDialogHidden: true,
- activeColorList: [],
- strokeStyle: 'rgb(0,0,0)',//线的颜色 初始值
- pick: true
- },
-
- /**
- * 生命周期函数--监听页面加载
- */
- onLoad(options) {
- this.setData({
- appraisalPlanid: options.appraisalplanid,
- id: options.id
- })
- this._canvasInit();
- this.getDrawingColor()
- },
- getDrawingColor() {
- wx.request({
- url: app.globalData.serverAddress + '/hcHealRemind/getUserDrawingColor',
- method: 'GET',
- data: {
- userId: app.globalData.userid
- },
- success: (res) => {
- if(res.data.code !== 0) {
- return wx.showToast({
- title: res.data.msg || '获取用户画板颜色数据失败',
- icon: 'none'
- })
- }
- this.setData({
- activeColorList: res.data.data
- })
- }
- })
- },
-
- _starTimer() {
- let that = this;
- if(that.data.timer) return
- let setSeconds = `timerValue.seconds`
- let textTime = `timerValue.text`
- that.data.timer = setInterval(() => {
- let seconds = that.data.timerValue.seconds + 1;
- that.setData({
- [setSeconds]: seconds,
- [textTime]: that._getTimeBySecond(seconds)
- })
- }, 1000);
- },
- _endTimer() {
- const that = this;
- if(that.data.timer) {
- clearInterval(that.data.timer)
- }
- },
- // 秒转时间
- _getTimeBySecond(seconds) {
- let hour = Math.floor(seconds / 3600);
- let minute = Math.floor(seconds % 3600 / 60);
- let second = seconds % 3600 % 60
- hour < 10 ? hour = '0' + hour : '';
- minute < 10 ? minute = '0' + minute : '';
- second < 10 ? second = '0' + second : '';
- return hour + ":" + minute + ":" + second
- },
- _canvasInit() {
- var ctx = wx.createCanvasContext('myCanvas');
- ctx.setFontSize(16) //设置字体的字号
- this.ctx = ctx
- },
- //触摸开始
- start(e) {
- this._starTimer(10);
- let startx = e.changedTouches[0].x;
- let starty = e.changedTouches[0].y;
- this.setData({
- x: startx,
- y: starty
- })
- this.hideBrushDialog();
- if(this.data.canvasType == 2) { //文本
- this.setData({
- hiddenFormat: false,
- focus: true
- })
- }
- },
- //触摸移动
- move(e) {
- if(this.data.canvasType == 2) { //文本
- return
- }
- let movex = e.changedTouches[0].x;
- let movey = e.changedTouches[0].y;
- this.setData({
- newx: movex,
- newy: movey
- })
- this._drawingLine(this.data.x, this.data.y, this.data.newx, this.data.newy)
- this.setData({
- x: movex,
- y: movey
- })
- },
- // 画线方法
- _drawingLine(startx, starty, movex, movey) {
- // 设置线
- if(this.data.canvasType == 2) { //文本里面的线
- this.ctx.setLineWidth(1)
- this.ctx.strokeStyle = "rgb(0,0,0)"
- this.ctx.setGlobalAlpha(1)
- } else {
- this.ctx.setLineWidth(this.data.lineWidth)
- this.ctx.strokeStyle = this.data.strokeStyle
- this.ctx.setGlobalAlpha(this.data.globalAlpha)
- }
- this.ctx.beginPath() //开始定义路径
- this.ctx.moveTo(startx, starty) //起始点
- this.ctx.lineTo(movex, movey) //连接到的坐标点
- this.ctx.stroke() //沿着绘制的坐标点路径绘制直线
- this.ctx.draw(true) //将之前在绘图上下文中画到 canvas 中
- },
- //绘制文本
- _drawingText() {
- let textFormat = this.data.textFormat;
- this.ctx.font = "normal 16px Arial"
- if(textFormat == 'B') {
- this.ctx.font = "bold 16px Arial" //加粗
- } else if(textFormat == '/') {
- this.ctx.font = "italic 16px Arial" //倾斜
- } else if(textFormat == 'U') { //下划线
- let textWidth = this.ctx.measureText(this.data.inputValue).width;
- this._drawingLine(this.data.x, this.data.y + 5, this.data.x + textWidth, this.data.y + 5)
- } else if(textFormat == 'S') { //删除线
- let textWidth = this.ctx.measureText(this.data.inputValue).width;
- this._drawingLine(this.data.x, this.data.y - 5, this.data.x + textWidth, this.data.y - 5)
- }
- // this.ctx.setFillStyle('blue') //设置填充色
- this.ctx.fillText(this.data.inputValue, this.data.x, this.data.y) //在画布上输出的文本 内容 x y
- this.ctx.draw(true)
- },
- //点击文本
- chengeText() {
- this.setData({
- canvasType: 2,
- textFormat: null
- })
- },
- //输入框
- bindKeyInput(e) {
- this.setData({
- inputValue: e.detail.value
- })
- },
- //输入框点击完成按钮
- confirmInput(e) {
- this._drawingText()
- this.setData({
- canvasType: 1,
- hiddenFormat: true,
- focus: false,
- inputValue: ''
- })
- },
- //点击格式
- openFormat() {
- this.setData({
- showDialog: 2
- })
- },
- //选中绘本文字的格式
- changeFormat(e) {
- this.setData({
- textFormat: e.currentTarget.dataset.value
- })
- this.hideMask()
- },
- preventevents() {},
- hideMask() {
- if(this.data.showDialog == 1) {
- this.addColor()
- }
- this.setData({
- showDialog: false
- })
- if(this.data.canvasType == 2) {
- this.setData({
- focus: true
- })
- }
- },
- //打开画笔弹窗
- openBrushDialog() {
- this.setData({
- brushDialogHidden: !this.data.brushDialogHidden,
- hiddenFormat: true
- })
- },
- //关闭画笔的弹窗
- hideBrushDialog() {
- if(!this.data.brushDialogHidden) {
- this.setData({
- brushDialogHidden: true
- })
- }
- },
- //点击底部区域
- closeDialog() {
- this.hideBrushDialog();
- this.setData({
- hiddenFormat: true
- })
- },
- //选择画笔
- checkBrush(e) {
- this.setData({
- lineWidth: e.currentTarget.dataset.value
- })
- },
- // 画笔透明度
- sliderchange(e) {
- this.setData({
- globalAlpha: e.detail.value
- })
- },
- //打开颜色对话框
- openColorDialog() {
- this.setData({
- showDialog: 1
- })
- },
- //取色结果回调
- pickColor(e) {
- let rgb = e.detail.color;
- this.setData({
- strokeStyle: rgb
- })
- },
- checkCorlor(e) {
- this.setData({
- strokeStyle: e.currentTarget.dataset.color,
- showDialog: false
- })
- },
- // 保存用户画板颜色
- addColor() {
- wx.request({
- url: app.globalData.serverAddress + '/hcHealRemind/insertUserDrawingColor',
- method: 'POST',
- data: {
- userId: app.globalData.userid,
- drawingColor: this.data.strokeStyle
- },
- success: (res) => {
- if(res.data.code !== 0) {
- return wx.showToast({
- title: res.data.msg || '保存用户画板颜色失败',
- icon: 'none'
- })
- }
- this.setData({
- activeColorList: res.data.data
- })
- }
- })
- },
- submit() {
- let that = this;
- that._endTimer();
- wx.showLoading({
- title: '图片生成中...',
- })
- wx.canvasToTempFilePath({
- x: 0,
- y: 0,
- canvasId: 'myCanvas',
- success(res) {
- wx.uploadFile({
- url: app.globalData.serverAddress + '/hcHealRemind/finishPsychologyDrawing',
- filePath: res.tempFilePath,
- name: 'file',
- formData: {
- appraisalPlanid: that.data.appraisalPlanid,
- remindId: that.data.id,
- workingHours: that.data.timerValue.seconds
- },
- success (res){
- wx.switchTab({
- url: '/pages/healing/index',
- })
- },
- complete() {
- wx.hideLoading()
- }
- })
- }
- })
- },
- /**
- * 生命周期函数--监听页面初次渲染完成
- */
- onReady() {
-
- },
-
- /**
- * 生命周期函数--监听页面显示
- */
- onShow() {
-
- },
-
- /**
- * 生命周期函数--监听页面隐藏
- */
- onHide() {
-
- },
-
- /**
- * 生命周期函数--监听页面卸载
- */
- onUnload() {
- this._endTimer();
- },
-
- /**
- * 页面相关事件处理函数--监听用户下拉动作
- */
- onPullDownRefresh() {
-
- },
-
- /**
- * 页面上拉触底事件的处理函数
- */
- onReachBottom() {
-
- },
-
- /**
- * 用户点击右上角分享
- */
- onShareAppMessage() {
-
- }
- })

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。