智能照明系统APP-本地串口
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
LightingSystemApp-serial/.svn/pristine/32/32852b5556c14cd7c92861deea3...

584 lines
17 KiB

<template>
<uni-canvas
:canvas-id="canvasId"
:disable-scroll="disableScroll"
v-on="_listeners"
>
<canvas
ref="canvas"
width="300"
height="150"
/>
<div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden;">
<slot />
</div>
<v-uni-resize-sensor
ref="sensor"
@resize="_resize"
/>
</uni-canvas>
</template>
<script>
import {
subscriber
} from 'uni-mixins'
import {
pixelRatio,
wrapper
} from 'uni-helpers/hidpi'
import saveImage from 'uni-platform/helpers/save-image'
function resolveColor (color) {
color = color.slice(0)
color[3] = color[3] / 255
return 'rgba(' + color.join(',') + ')'
}
function processTouches (target, touches) {
return ([]).map.call(touches, (touch) => {
var boundingClientRect = target.getBoundingClientRect()
return {
identifier: touch.identifier,
x: touch.clientX - boundingClientRect.left,
y: touch.clientY - boundingClientRect.top
}
})
}
var tempCanvas
function getTempCanvas (width = 0, height = 0) {
if (!tempCanvas) {
tempCanvas = document.createElement('canvas')
}
tempCanvas.width = width
tempCanvas.height = height
return tempCanvas
}
export default {
name: 'Canvas',
mixins: [subscriber],
props: {
canvasId: {
type: String,
default: ''
},
disableScroll: {
type: [Boolean, String],
default: false
}
},
data () {
return {
actionsWaiting: false
}
},
computed: {
id () {
return this.canvasId
},
_listeners () {
var $listeners = Object.assign({}, this.$listeners)
var events = ['touchstart', 'touchmove', 'touchend']
events.forEach(event => {
var existing = $listeners[event]
var eventHandler = []
if (existing) {
eventHandler.push(($event) => {
this.$trigger(event, Object.assign({}, $event, {
touches: processTouches($event.currentTarget, $event.touches),
changedTouches: processTouches($event.currentTarget, $event
.changedTouches)
}))
})
}
if (this.disableScroll && event === 'touchmove') {
eventHandler.push(this._touchmove)
}
$listeners[event] = eventHandler
})
return $listeners
}
},
created () {
this._actionsDefer = []
this._images = {}
},
mounted () {
this._resize({
width: this.$refs.sensor.$el.offsetWidth,
height: this.$refs.sensor.$el.offsetHeight
})
},
beforeDestroy () {
const canvas = this.$refs.canvas
canvas.height = canvas.width = 0
},
methods: {
_handleSubscribe ({
type,
data = {}
}) {
var method = this[type]
if (type.indexOf('_') !== 0 && typeof method === 'function') {
method(data)
}
},
_resize () {
var canvas = this.$refs.canvas
if (canvas.width > 0 && canvas.height > 0) {
var context = canvas.getContext('2d')
var imageData = context.getImageData(0, 0, canvas.width, canvas.height)
wrapper(this.$refs.canvas)
context.putImageData(imageData, 0, 0)
} else {
wrapper(this.$refs.canvas)
}
},
_touchmove (event) {
event.preventDefault()
},
actionsChanged ({
actions,
reserve,
callbackId
}) {
var self = this
if (!actions) {
return
}
if (this.actionsWaiting) {
this._actionsDefer.push([actions, reserve, callbackId])
return
}
var canvas = this.$refs.canvas
var c2d = canvas.getContext('2d')
if (!reserve) {
c2d.fillStyle = '#000000'
c2d.strokeStyle = '#000000'
c2d.shadowColor = '#000000'
c2d.shadowBlur = 0
c2d.shadowOffsetX = 0
c2d.shadowOffsetY = 0
c2d.setTransform(1, 0, 0, 1, 0, 0)
c2d.clearRect(0, 0, canvas.width, canvas.height)
}
this.preloadImage(actions)
for (let index = 0; index < actions.length; index++) {
const action = actions[index]
let method = action.method
const data = action.data
if (/^set/.test(method) && method !== 'setTransform') {
const method1 = method[3].toLowerCase() + method.slice(4)
let color
if (method1 === 'fillStyle' || method1 === 'strokeStyle') {
if (data[0] === 'normal') {
color = resolveColor(data[1])
} else if (data[0] === 'linear') {
const LinearGradient = c2d.createLinearGradient(...data[1])
data[2].forEach(function (data2) {
const offset = data2[0]
const color = resolveColor(data2[1])
LinearGradient.addColorStop(offset, color)
})
color = LinearGradient
} else if (data[0] === 'radial') {
const x = data[1][0]
const y = data[1][1]
const r = data[1][2]
const LinearGradient = c2d.createRadialGradient(x, y, 0, x, y, r)
data[2].forEach(function (data2) {
const offset = data2[0]
const color = resolveColor(data2[1])
LinearGradient.addColorStop(offset, color)
})
color = LinearGradient
} else if (data[0] === 'pattern') {
const loaded = this.checkImageLoaded(data[1], actions.slice(index + 1), callbackId,
function (image) {
if (image) {
c2d[method1] = c2d.createPattern(image, data[2])
}
})
if (!loaded) {
break
}
continue
}
c2d[method1] = color
} else if (method1 === 'globalAlpha') {
c2d[method1] = data[0] / 255
} else if (method1 === 'shadow') {
var _ = ['shadowOffsetX', 'shadowOffsetY', 'shadowBlur', 'shadowColor']
data.forEach(function (color_, method_) {
c2d[_[method_]] = _[method_] === 'shadowColor' ? resolveColor(color_) : color_
})
} else {
if (method1 === 'fontSize') {
c2d.font = c2d.font.replace(/\d+\.?\d*px/, data[0] + 'px')
} else {
if (method1 === 'lineDash') {
c2d.setLineDash(data[0])
c2d.lineDashOffset = data[1] || 0
} else {
if (method1 === 'textBaseline') {
if (data[0] === 'normal') {
data[0] = 'alphabetic'
}
c2d[method1] = data[0]
} else {
c2d[method1] = data[0]
}
}
}
}
} else if (method === 'fillPath' || method === 'strokePath') {
method = method.replace(/Path/, '')
c2d.beginPath()
data.forEach(function (data_) {
c2d[data_.method].apply(c2d, data_.data)
})
c2d[method]()
} else if (method === 'fillText') {
c2d.fillText.apply(c2d, data)
} else if (method === 'drawImage') {
var A = (function () {
var dataArray = [...data]
var url = dataArray[0]
var otherData = dataArray.slice(1)
self._images = self._images || {}
if (!self.checkImageLoaded(url, actions.slice(index + 1), callbackId, function (
image) {
if (image) {
c2d.drawImage.apply(c2d, [image].concat([...otherData.slice(4, 8)],
[...otherData.slice(0, 4)]))
}
})) return 'break'
}())
if (A === 'break') {
break
}
} else {
if (method === 'clip') {
data.forEach(function (data_) {
c2d[data_.method].apply(c2d, data_.data)
})
c2d.clip()
} else {
c2d[method].apply(c2d, data)
}
}
}
if (!this.actionsWaiting && callbackId) {
UniViewJSBridge.publishHandler('onDrawCanvas', {
callbackId,
data: {
errMsg: 'drawCanvas:ok'
}
}, this.$page.id)
}
},
preloadImage: function (actions) {
var self = this
actions.forEach(function (action) {
var method = action.method
var data = action.data
var src = ''
if (method === 'drawImage') {
src = data[0]
src = self.$getRealPath(src)
data[0] = src
} else if (method === 'setFillStyle' && data[0] === 'pattern') {
src = data[1]
src = self.$getRealPath(src)
data[1] = src
}
if (src && !self._images[src]) {
loadImage()
}
/**
* 加载图像
*/
function loadImage () {
self._images[src] = new Image()
self._images[src].onload = function () {
self._images[src].ready = true
}
/**
* 从Blob加载
* @param {Blob} blob
*/
function loadBlob (blob) {
self._images[src].src = (window.URL || window.webkitURL).createObjectURL(blob)
}
/**
* 从本地文件加载
* @param {string} path 文件路径
*/
function loadFile (path) {
var bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
bitmap.load(path, function () {
self._images[src].src = bitmap.toBase64Data()
bitmap.clear()
}, function () {
bitmap.clear()
console.error('preloadImage error')
})
}
/**
* 从网络加载
* @param {string} url 文件地址
*/
function loadUrl (url) {
function plusDownload () {
plus.downloader.createDownload(url, {
filename: '_doc/uniapp_temp/download/'
}, function (d, status) {
if (status === 200) {
loadFile(d.filename)
} else {
self._images[src].src = src
}
}).start()
}
var xhr = new XMLHttpRequest()
xhr.open('GET', url, true)
xhr.responseType = 'blob'
xhr.onload = function () {
if (this.status === 200) {
loadBlob(this.response)
}
}
xhr.onerror = __PLATFORM__ === 'app-plus' ? plusDownload : function () {
self._images[src].src = src
}
xhr.send()
}
if (__PLATFORM__ === 'app-plus' && (!window.webkit || !window.webkit.messageHandlers)) {
self._images[src].src = src
} else {
// 解决 PLUS-APP(wkwebview)以及 H5 图像跨域问题(H5图像响应头需包含access-control-allow-origin)
if (__PLATFORM__ === 'app-plus' && src.indexOf('http://') !== 0 && src.indexOf('https://') !==
0 && !/^data:.*,.*/.test(src)) {
loadFile(src)
} else if (/^data:.*,.*/.test(src)) {
self._images[src].src = src
} else {
loadUrl(src)
}
}
}
})
},
checkImageLoaded: function (src, actions, callbackId, fn) {
var self = this
var image = this._images[src]
if (image.ready) {
fn(image)
return true
} else {
this._actionsDefer.unshift([actions, true])
this.actionsWaiting = true
image.onload = function () {
image.ready = true
fn(image)
self.actionsWaiting = false
var actions = self._actionsDefer.slice(0)
self._actionsDefer = []
for (var action = actions.shift(); action;) {
self.actionsChanged({
actions: action[0],
reserve: action[1],
callbackId
})
action = actions.shift()
}
}
return false
}
},
getImageData ({
x = 0,
y = 0,
width,
height,
destWidth,
destHeight,
hidpi = true,
dataType,
qualit = 1,
type = 'png',
callbackId
}) {
const canvas = this.$refs.canvas
let data
if (!width) {
width = canvas.offsetWidth - x
}
if (!height) {
height = canvas.offsetHeight - y
}
try {
if (!hidpi) {
if (!destWidth && !destHeight) {
destWidth = Math.round(width * pixelRatio)
destHeight = Math.round(height * pixelRatio)
} else if (!destWidth) {
destWidth = Math.round(width / height * destHeight)
} else if (!destHeight) {
destHeight = Math.round(height / width * destWidth)
}
} else {
destWidth = width
destHeight = height
}
const newCanvas = getTempCanvas(destWidth, destHeight)
const context = newCanvas.getContext('2d')
if (type === 'jpeg' || type === 'jpg') {
type = 'jpeg'
context.fillStyle = '#fff'
context.fillRect(0, 0, destWidth, destHeight)
}
context.__hidpi__ = true
context.drawImageByCanvas(canvas, x, y, width, height, 0, 0, destWidth, destHeight, false)
if (dataType === 'base64') {
data = newCanvas.toDataURL(`image/${type}`, qualit)
} else {
const imgData = context.getImageData(0, 0, destWidth, destHeight)
// fix [...]展开TypedArray在低版本手机报错的问题,使用Array.prototype.slice
data = Array.prototype.slice.call(imgData.data)
}
newCanvas.height = newCanvas.width = 0
context.__hidpi__ = false
} catch (error) {
if (!callbackId) {
return
}
UniViewJSBridge.publishHandler('onCanvasMethodCallback', {
callbackId,
data: {
errMsg: 'canvasGetImageData:fail'
}
}, this.$page.id)
return
}
if (!callbackId) {
return {
data,
width: destWidth,
height: destHeight
}
} else {
UniViewJSBridge.publishHandler('onCanvasMethodCallback', {
callbackId,
data: {
errMsg: 'canvasGetImageData:ok',
data,
width: destWidth,
height: destHeight
}
}, this.$page.id)
}
},
putImageData ({
data,
x,
y,
width,
height,
callbackId
}) {
try {
if (!height) {
height = Math.round(data.length / 4 / width)
}
const canvas = getTempCanvas(width, height)
const context = canvas.getContext('2d')
context.putImageData(new ImageData(new Uint8ClampedArray(data), width, height), 0, 0)
this.$refs.canvas.getContext('2d').drawImage(canvas, x, y, width, height)
canvas.height = canvas.width = 0
} catch (error) {
UniViewJSBridge.publishHandler('onCanvasMethodCallback', {
callbackId,
data: {
errMsg: 'canvasPutImageData:fail'
}
}, this.$page.id)
return
}
UniViewJSBridge.publishHandler('onCanvasMethodCallback', {
callbackId,
data: {
errMsg: 'canvasPutImageData:ok'
}
}, this.$page.id)
},
toTempFilePath ({
x = 0,
y = 0,
width,
height,
destWidth,
destHeight,
fileType,
qualit,
dirname,
callbackId
}) {
const res = this.getImageData({
x,
y,
width,
height,
destWidth,
destHeight,
hidpi: false,
dataType: 'base64',
type: fileType,
qualit
})
if (!res.data || !res.data.length) {
UniViewJSBridge.publishHandler('onCanvasMethodCallback', {
callbackId,
data: {
errMsg: 'toTempFilePath:fail'
}
}, this.$page.id)
return
}
saveImage(res.data, dirname, (error, tempFilePath) => {
let errMsg = `toTempFilePath:${error ? 'fail' : 'ok'}`
if (error) {
errMsg += ` ${error.message}`
}
UniViewJSBridge.publishHandler('onCanvasMethodCallback', {
callbackId,
data: {
errMsg,
tempFilePath: tempFilePath
}
}, this.$page.id)
})
}
}
}
</script>
<style>
uni-canvas {
width: 300px;
height: 150px;
display: block;
position: relative;
}
uni-canvas > canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>