diff --git a/src/core/service/api/context/canvas.js b/src/core/service/api/context/canvas.js
new file mode 100644
index 0000000000000000000000000000000000000000..c872216ae5e287f484543e9dd5f17f4b41bd18fe
--- /dev/null
+++ b/src/core/service/api/context/canvas.js
@@ -0,0 +1,561 @@
+import createCallbacks from 'uni-helpers/callbacks'
+
+const canvasEventCallbacks = createCallbacks('canvasEvent')
+
+UniServiceJSBridge.subscribe('onDrawCanvas', ({
+ reqId,
+ res
+}) => {
+ const callback = canvasEventCallbacks.pop(reqId)
+ if (callback) {
+ callback(res)
+ }
+})
+
+function operateCanvas (canvasId, pageId, type, data) {
+ UniServiceJSBridge.publishHandler(pageId + '-canvas-' + canvasId, {
+ canvasId,
+ type,
+ data
+ }, pageId)
+}
+
+const predefinedColor = {
+ aliceblue: '#f0f8ff',
+ antiquewhite: '#faebd7',
+ aqua: '#00ffff',
+ aquamarine: '#7fffd4',
+ azure: '#f0ffff',
+ beige: '#f5f5dc',
+ bisque: '#ffe4c4',
+ black: '#000000',
+ blanchedalmond: '#ffebcd',
+ blue: '#0000ff',
+ blueviolet: '#8a2be2',
+ brown: '#a52a2a',
+ burlywood: '#deb887',
+ cadetblue: '#5f9ea0',
+ chartreuse: '#7fff00',
+ chocolate: '#d2691e',
+ coral: '#ff7f50',
+ cornflowerblue: '#6495ed',
+ cornsilk: '#fff8dc',
+ crimson: '#dc143c',
+ cyan: '#00ffff',
+ darkblue: '#00008b',
+ darkcyan: '#008b8b',
+ darkgoldenrod: '#b8860b',
+ darkgray: '#a9a9a9',
+ darkgrey: '#a9a9a9',
+ darkgreen: '#006400',
+ darkkhaki: '#bdb76b',
+ darkmagenta: '#8b008b',
+ darkolivegreen: '#556b2f',
+ darkorange: '#ff8c00',
+ darkorchid: '#9932cc',
+ darkred: '#8b0000',
+ darksalmon: '#e9967a',
+ darkseagreen: '#8fbc8f',
+ darkslateblue: '#483d8b',
+ darkslategray: '#2f4f4f',
+ darkslategrey: '#2f4f4f',
+ darkturquoise: '#00ced1',
+ darkviolet: '#9400d3',
+ deeppink: '#ff1493',
+ deepskyblue: '#00bfff',
+ dimgray: '#696969',
+ dimgrey: '#696969',
+ dodgerblue: '#1e90ff',
+ firebrick: '#b22222',
+ floralwhite: '#fffaf0',
+ forestgreen: '#228b22',
+ fuchsia: '#ff00ff',
+ gainsboro: '#dcdcdc',
+ ghostwhite: '#f8f8ff',
+ gold: '#ffd700',
+ goldenrod: '#daa520',
+ gray: '#808080',
+ grey: '#808080',
+ green: '#008000',
+ greenyellow: '#adff2f',
+ honeydew: '#f0fff0',
+ hotpink: '#ff69b4',
+ indianred: '#cd5c5c',
+ indigo: '#4b0082',
+ ivory: '#fffff0',
+ khaki: '#f0e68c',
+ lavender: '#e6e6fa',
+ lavenderblush: '#fff0f5',
+ lawngreen: '#7cfc00',
+ lemonchiffon: '#fffacd',
+ lightblue: '#add8e6',
+ lightcoral: '#f08080',
+ lightcyan: '#e0ffff',
+ lightgoldenrodyellow: '#fafad2',
+ lightgray: '#d3d3d3',
+ lightgrey: '#d3d3d3',
+ lightgreen: '#90ee90',
+ lightpink: '#ffb6c1',
+ lightsalmon: '#ffa07a',
+ lightseagreen: '#20b2aa',
+ lightskyblue: '#87cefa',
+ lightslategray: '#778899',
+ lightslategrey: '#778899',
+ lightsteelblue: '#b0c4de',
+ lightyellow: '#ffffe0',
+ lime: '#00ff00',
+ limegreen: '#32cd32',
+ linen: '#faf0e6',
+ magenta: '#ff00ff',
+ maroon: '#800000',
+ mediumaquamarine: '#66cdaa',
+ mediumblue: '#0000cd',
+ mediumorchid: '#ba55d3',
+ mediumpurple: '#9370db',
+ mediumseagreen: '#3cb371',
+ mediumslateblue: '#7b68ee',
+ mediumspringgreen: '#00fa9a',
+ mediumturquoise: '#48d1cc',
+ mediumvioletred: '#c71585',
+ midnightblue: '#191970',
+ mintcream: '#f5fffa',
+ mistyrose: '#ffe4e1',
+ moccasin: '#ffe4b5',
+ navajowhite: '#ffdead',
+ navy: '#000080',
+ oldlace: '#fdf5e6',
+ olive: '#808000',
+ olivedrab: '#6b8e23',
+ orange: '#ffa500',
+ orangered: '#ff4500',
+ orchid: '#da70d6',
+ palegoldenrod: '#eee8aa',
+ palegreen: '#98fb98',
+ paleturquoise: '#afeeee',
+ palevioletred: '#db7093',
+ papayawhip: '#ffefd5',
+ peachpuff: '#ffdab9',
+ peru: '#cd853f',
+ pink: '#ffc0cb',
+ plum: '#dda0dd',
+ powderblue: '#b0e0e6',
+ purple: '#800080',
+ rebeccapurple: '#663399',
+ red: '#ff0000',
+ rosybrown: '#bc8f8f',
+ royalblue: '#4169e1',
+ saddlebrown: '#8b4513',
+ salmon: '#fa8072',
+ sandybrown: '#f4a460',
+ seagreen: '#2e8b57',
+ seashell: '#fff5ee',
+ sienna: '#a0522d',
+ silver: '#c0c0c0',
+ skyblue: '#87ceeb',
+ slateblue: '#6a5acd',
+ slategray: '#708090',
+ slategrey: '#708090',
+ snow: '#fffafa',
+ springgreen: '#00ff7f',
+ steelblue: '#4682b4',
+ tan: '#d2b48c',
+ teal: '#008080',
+ thistle: '#d8bfd8',
+ tomato: '#ff6347',
+ turquoise: '#40e0d0',
+ violet: '#ee82ee',
+ wheat: '#f5deb3',
+ white: '#ffffff',
+ whitesmoke: '#f5f5f5',
+ yellow: '#ffff00',
+ yellowgreen: '#9acd32',
+ transparent: '#00000000'
+}
+
+function checkColor (e) {
+ var t = null
+ if ((t = /^#([0-9|A-F|a-f]{6})$/.exec(e)) != null) {
+ let n = parseInt(t[1].slice(0, 2), 16)
+ let o = parseInt(t[1].slice(2, 4), 16)
+ let r = parseInt(t[1].slice(4), 16)
+ return [n, o, r, 255]
+ }
+ if ((t = /^#([0-9|A-F|a-f]{3})$/.exec(e)) != null) {
+ let n = t[1].slice(0, 1)
+ let o = t[1].slice(1, 2)
+ let r = t[1].slice(2, 3)
+ n = parseInt(n + n, 16)
+ o = parseInt(o + o, 16)
+ r = parseInt(r + r, 16)
+ return [n, o, r, 255]
+ }
+ if ((t = /^rgb\((.+)\)$/.exec(e)) != null) {
+ return t[1].split(',').map(function (e) {
+ return Math.min(255, parseInt(e.trim()))
+ }).concat(255)
+ }
+ if ((t = /^rgba\((.+)\)$/.exec(e)) != null) {
+ return t[1].split(',').map(function (e, t) {
+ return t === 3 ? Math.floor(255 * parseFloat(e.trim())) : Math.min(255, parseInt(e.trim()))
+ })
+ }
+ var i = e.toLowerCase()
+ if (predefinedColor.hasOwnProperty(i)) {
+ t = /^#([0-9|A-F|a-f]{6,8})$/.exec(predefinedColor[i])
+ let n = parseInt(t[1].slice(0, 2), 16)
+ let o = parseInt(t[1].slice(2, 4), 16)
+ let r = parseInt(t[1].slice(4, 6), 16)
+ let a = parseInt(t[1].slice(6, 8), 16)
+ a = a >= 0 ? a : 255
+ return [n, o, r, a]
+ }
+ console.group('非法颜色: ' + e)
+ console.error('不支持颜色:' + e)
+ console.groupEnd()
+ return [0, 0, 0, 255]
+}
+
+function TextMetrics (width) {
+ this.width = width
+}
+
+function Pattern (image, repetition) {
+ this.image = image
+ this.repetition = repetition
+}
+
+class CanvasGradient {
+ constructor (type, data) {
+ this.type = type
+ this.data = data
+ this.colorStop = []
+ }
+ addColorStop (position, color) {
+ this.colorStop.push([position, checkColor(color)])
+ }
+}
+var methods1 = ['scale', 'rotate', 'translate', 'setTransform', 'transform']
+var methods2 = ['drawImage', 'fillText', 'fill', 'stroke', 'fillRect', 'strokeRect', 'clearRect',
+ 'strokeText'
+]
+var methods3 = ['setFillStyle', 'setTextAlign', 'setStrokeStyle', 'setGlobalAlpha', 'setShadow',
+ 'setFontSize', 'setLineCap', 'setLineJoin', 'setLineWidth', 'setMiterLimit',
+ 'setTextBaseline', 'setLineDash'
+]
+var c2d
+class CanvasContext {
+ constructor (id, pageId) {
+ this.id = id
+ this.pageId = pageId
+ this.actions = []
+ this.currentTransform = []
+ this.currentStepAnimates = []
+ this.drawingState = []
+ this.state = {
+ lineDash: [0, 0],
+ shadowOffsetX: 0,
+ shadowOffsetY: 0,
+ shadowBlur: 0,
+ shadowColor: [0, 0, 0, 0],
+ font: '10px sans-serif',
+ fontSize: 10,
+ fontWeight: 'normal',
+ fontStyle: 'normal',
+ fontFamily: 'sans-serif'
+ }
+ }
+ draw (reserve = false, callback) {
+ var actions = [...this.actions]
+ this.actions = []
+ this.path = []
+ var callbackId
+
+ if (typeof callback === 'function') {
+ callbackId = canvasEventCallbacks.push(callback)
+ }
+
+ operateCanvas(this.id, this.pageId, 'actionsChanged', {
+ actions,
+ reserve,
+ callbackId
+ })
+ }
+ createLinearGradient (x0, y0, x1, y1) {
+ return new CanvasGradient('linear', [x0, y0, x1, y1])
+ }
+ createCircularGradient (x, y, r) {
+ return new CanvasGradient('radial', [x, y, r])
+ }
+ createPattern (image, repetition) {
+ if (undefined === repetition) {
+ console.error("Failed to execute 'createPattern' on 'CanvasContext': 2 arguments required, but only 1 present.")
+ } else if (['repeat', 'repeat-x', 'repeat-y', 'no-repeat'].indexOf(repetition) < 0) {
+ console.error("Failed to execute 'createPattern' on 'CanvasContext': The provided type ('" + repetition + "') is not one of 'repeat', 'no-repeat', 'repeat-x', or 'repeat-y'.")
+ } else {
+ return new Pattern(image, repetition)
+ }
+ }
+ measureText (text) {
+ if (!c2d) {
+ let canvas = document.createElement('canvas')
+ c2d = canvas.getContext('2d')
+ }
+ c2d.font = this.state.font
+ return new TextMetrics(c2d.measureText(text).width || 0)
+ }
+ save () {
+ this.actions.push({
+ method: 'save',
+ data: []
+ })
+ this.drawingState.push(this.state)
+ }
+ restore () {
+ this.actions.push({
+ method: 'restore',
+ data: []
+ })
+ this.state = this.drawingState.pop() || {
+ lineDash: [0, 0],
+ shadowOffsetX: 0,
+ shadowOffsetY: 0,
+ shadowBlur: 0,
+ shadowColor: [0, 0, 0, 0],
+ font: '10px sans-serif',
+ fontSize: 10,
+ fontWeight: 'normal',
+ fontStyle: 'normal',
+ fontFamily: 'sans-serif'
+ }
+ }
+ beginPath () {
+ this.path = []
+ this.subpath = []
+ }
+ moveTo (x, y) {
+ this.path.push({
+ method: 'moveTo',
+ data: [x, y]
+ })
+ this.subpath = [
+ [x, y]
+ ]
+ }
+ lineTo (x, y) {
+ if (this.path.length === 0 && this.subpath.length === 0) {
+ this.path.push({
+ method: 'moveTo',
+ data: [x, y]
+ })
+ } else {
+ this.path.push({
+ method: 'lineTo',
+ data: [x, y]
+ })
+ }
+ this.subpath.push([x, y])
+ }
+ quadraticCurveTo (cpx, cpy, x, y) {
+ this.path.push({
+ method: 'quadraticCurveTo',
+ data: [cpx, cpy, x, y]
+ })
+ this.subpath.push([x, y])
+ }
+ bezierCurveTo (cp1x, cp1y, cp2x, cp2y, x, y) {
+ this.path.push({
+ method: 'bezierCurveTo',
+ data: [cp1x, cp1y, cp2x, cp2y, x, y]
+ })
+ this.subpath.push([x, y])
+ }
+ arc (x, y, r, sAngle, eAngle, counterclockwise = false) {
+ this.path.push({
+ method: 'arc',
+ data: [x, y, r, sAngle, eAngle, counterclockwise]
+ })
+ this.subpath.push([x, y])
+ }
+ rect (x, y, width, height) {
+ this.path.push({
+ method: 'rect',
+ data: [x, y, width, height]
+ })
+ this.subpath = [
+ [x, y]
+ ]
+ }
+ arcTo (x1, y1, x2, y2, radius) {
+ this.path.push({
+ method: 'arcTo',
+ data: [x1, y1, x2, y2, radius]
+ })
+ this.subpath.push([x2, y2])
+ }
+ clip () {
+ this.actions.push({
+ method: 'clip',
+ data: [...this.path]
+ })
+ }
+ closePath () {
+ this.path.push({
+ method: 'closePath',
+ data: []
+ })
+ if (this.subpath.length) {
+ this.subpath = [this.subpath.shift()]
+ }
+ }
+}
+
+[...methods1, ...methods2].forEach(function (method) {
+ function get (method) {
+ switch (method) {
+ case 'fill':
+ case 'stroke':
+ return function () {
+ this.actions.push({
+ method: method + 'Path',
+ data: [...this.path]
+ })
+ }
+ case 'fillRect':
+ return function (x, y, width, height) {
+ this.actions.push({
+ method: 'fillPath',
+ data: [{
+ method: 'rect',
+ data: [x, y, width, height]
+ }]
+ })
+ }
+ case 'strokeRect':
+ return function (x, y, width, height) {
+ this.actions.push({
+ method: 'strokePath',
+ data: [{
+ method: 'rect',
+ data: [x, y, width, height]
+ }]
+ })
+ }
+ case 'fillText':
+ case 'strokeText':
+ return function (text, x, y, maxWidth) {
+ var data = [text.toString(), x, y]
+ if (typeof maxWidth === 'number') {
+ data.push(maxWidth)
+ }
+ this.actions.push({
+ method,
+ data
+ })
+ }
+ case 'drawImage':
+ return function (imageResource, dx, dy, dWidth, dHeight, sx, sy, sWidth, sHeight) {
+ if (sHeight === undefined) {
+ sx = dx
+ sy = dy
+ sWidth = dWidth
+ sHeight = dHeight
+ dx = undefined
+ dy = undefined
+ dWidth = undefined
+ dHeight = undefined
+ }
+ var data
+ function isNumber (e) {
+ return typeof e === 'number'
+ }
+ data = isNumber(dx) && isNumber(dy) && isNumber(dWidth) && isNumber(dHeight) ? [imageResource, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight] : isNumber(sWidth) && isNumber(
+ sHeight) ? [imageResource, sx, sy, sWidth, sHeight] : [imageResource, sx, sy]
+ this.actions.push({
+ method,
+ data
+ })
+ }
+ default:
+ return function (...data) {
+ this.actions.push({
+ method,
+ data
+ })
+ }
+ }
+ }
+ CanvasContext.prototype[method] = get(method)
+})
+methods3.forEach(function (method) {
+ function get (method) {
+ switch (method) {
+ case 'setFillStyle':
+ case 'setStrokeStyle':
+ return function (color) {
+ this.actions.push({
+ method,
+ data: ['normal', checkColor(color)]
+ })
+ }
+ case 'setGlobalAlpha':
+ return function (alpha) {
+ alpha = Math.floor(255 * parseFloat(alpha))
+ this.actions.push({
+ method,
+ data: [alpha]
+ })
+ }
+ case 'setShadow':
+ return function (offsetX, offsetY, blur, color) {
+ color = checkColor(color)
+ this.actions.push({
+ method,
+ data: [offsetX, offsetY, blur, color]
+ })
+ this.state.shadowBlur = blur
+ this.state.shadowColor = color
+ this.state.shadowOffsetX = offsetX
+ this.state.shadowOffsetY = offsetY
+ }
+ case 'setLineDash':
+ return function (pattern, offset) {
+ pattern = pattern || [0, 0]
+ offset = offset || 0
+ this.actions.push({
+ method,
+ data: [pattern, offset]
+ })
+ this.state.lineDash = pattern
+ }
+ case 'setFontSize':
+ return function (fontSize) {
+ this.state.font = this.state.font.replace(/\d+\.?\d*px/, fontSize + 'px')
+ this.state.fontSize = fontSize
+ this.actions.push({
+ method,
+ data: [fontSize]
+ })
+ }
+ default:
+ return function (...data) {
+ this.actions.push({
+ method,
+ data
+ })
+ }
+ }
+ }
+ CanvasContext.prototype[method] = get(method)
+})
+
+export function createCanvasContext (id, context) {
+ if (context) {
+ return new CanvasContext(id, context.$page.id)
+ }
+ const app = getApp()
+ if (app.$route && app.$route.params.__id__) {
+ return new CanvasContext(id, app.$route.params.__id__)
+ } else {
+ UniServiceJSBridge.emit('onError', 'createCanvasContext:fail')
+ }
+}
diff --git a/src/core/view/components/canvas/index.vue b/src/core/view/components/canvas/index.vue
index d1faacc47d0bd7411324a5628c4f9568ae792f3b..a510fb867d3993dc505645b191c4cde2d27b08c9 100644
--- a/src/core/view/components/canvas/index.vue
+++ b/src/core/view/components/canvas/index.vue
@@ -1,8 +1,337 @@
-
+
+
+
+
diff --git a/src/core/view/mixins/subscriber.js b/src/core/view/mixins/subscriber.js
index d79ad13cd095f12b244533a76ec9c0f500a7396b..1be0a9ca5b014525fa0ffc8791a1c43371de2564 100644
--- a/src/core/view/mixins/subscriber.js
+++ b/src/core/view/mixins/subscriber.js
@@ -3,12 +3,13 @@ import {
} from 'uni-shared'
export default {
- props: {
- id: {
- type: String,
- default: ''
- }
- },
+ // 取消id的定义,某些组件(canvas)内不在props内定义id
+ // props: {
+ // id: {
+ // type: String,
+ // default: ''
+ // }
+ // },
mounted () {
this._toggleListeners('subscribe', this.id) // 初始化监听
this.$watch('id', (newId, oldId) => { // watch id