import FillStylePattern from './FillStylePattern'; import FillStyleLinearGradient from './FillStyleLinearGradient'; import FillStyleRadialGradient from './FillStyleRadialGradient'; import GImage from '../env/image.js'; import { ArrayBufferToBase64, Base64ToUint8ClampedArray } from '../env/tool.js'; export default class CanvasRenderingContext2D { _drawCommands = ''; _globalAlpha = 1.0; _fillStyle = 'rgb(0,0,0)'; _strokeStyle = 'rgb(0,0,0)'; _lineWidth = 1; _lineCap = 'butt'; _lineJoin = 'miter'; _miterLimit = 10; _globalCompositeOperation = 'source-over'; _textAlign = 'start'; _textBaseline = 'alphabetic'; _font = '10px sans-serif'; _savedGlobalAlpha = []; timer = null; componentId = null; _notCommitDrawImageCache = []; _needRedrawImageCache = []; _redrawCommands = ''; _autoSaveContext = true; // _imageMap = new GHashMap(); // _textureMap = new GHashMap(); constructor() { this.className = 'CanvasRenderingContext2D'; //this.save() } setFillStyle(value) { this.fillStyle = value; } set fillStyle(value) { this._fillStyle = value; if (typeof(value) == 'string') { this._drawCommands = this._drawCommands.concat("F" + value + ";"); } else if (value instanceof FillStylePattern) { const image = value._img; if (!image.complete) { image.onload = () => { var index = this._needRedrawImageCache.indexOf(image); if (index > -1) { this._needRedrawImageCache.splice(index, 1); CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); this._redrawflush(true); } } this._notCommitDrawImageCache.push(image); } else { CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); } //CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";"); } else if (value instanceof FillStyleLinearGradient) { var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + value._stop_count; for (var i = 0; i < value._stop_count; ++i) { command += ("," + value._stops[i]._pos + "," + value._stops[i]._color); } this._drawCommands = this._drawCommands.concat(command + ";"); } else if (value instanceof FillStyleRadialGradient) { var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r .toFixed(2) + "," + value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + value._end_pos._r.toFixed(2) + "," + value._stop_count; for (var i = 0; i < value._stop_count; ++i) { command += ("," + value._stops[i]._pos + "," + value._stops[i]._color); } this._drawCommands = this._drawCommands.concat(command + ";"); } } get fillStyle() { return this._fillStyle; } get globalAlpha() { return this._globalAlpha; } setGlobalAlpha(value) { this.globalAlpha = value; } set globalAlpha(value) { this._globalAlpha = value; this._drawCommands = this._drawCommands.concat("a" + value.toFixed(2) + ";"); } get strokeStyle() { return this._strokeStyle; } setStrokeStyle(value) { this.strokeStyle = value; } set strokeStyle(value) { this._strokeStyle = value; if (typeof(value) == 'string') { this._drawCommands = this._drawCommands.concat("S" + value + ";"); } else if (value instanceof FillStylePattern) { CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); this._drawCommands = this._drawCommands.concat("G" + image._id + "," + value._style + ";"); } else if (value instanceof FillStyleLinearGradient) { var command = "D" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._end_pos._x.toFixed(2) + "," + value._end_pos._y.toFixed(2) + "," + value._stop_count; for (var i = 0; i < value._stop_count; ++i) { command += ("," + value._stops[i]._pos + "," + value._stops[i]._color); } this._drawCommands = this._drawCommands.concat(command + ";"); } else if (value instanceof FillStyleRadialGradient) { var command = "H" + value._start_pos._x.toFixed(2) + "," + value._start_pos._y.toFixed(2) + "," + value._start_pos._r .toFixed(2) + "," + value._end_pos._x.toFixed(2) + "," + value._end_pos._y + ",".toFixed(2) + value._end_pos._r.toFixed(2) + "," + value._stop_count; for (var i = 0; i < value._stop_count; ++i) { command += ("," + value._stops[i]._pos + "," + value._stops[i]._color); } this._drawCommands = this._drawCommands.concat(command + ";"); } } get lineWidth() { return this._lineWidth; } setLineWidth(value) { this.lineWidth = value; } set lineWidth(value) { this._lineWidth = value; this._drawCommands = this._drawCommands.concat("W" + value + ";"); } get lineCap() { return this._lineCap; } setLineCap(value) { this.lineCap = value; } set lineCap(value) { this._lineCap = value; this._drawCommands = this._drawCommands.concat("C" + value + ";"); } get lineJoin() { return this._lineJoin; } setLineJoin(value) { this.lineJoin = value } set lineJoin(value) { this._lineJoin = value; this._drawCommands = this._drawCommands.concat("J" + value + ";"); } get miterLimit() { return this._miterLimit; } setMiterLimit(value) { this.miterLimit = value } set miterLimit(value) { this._miterLimit = value; this._drawCommands = this._drawCommands.concat("M" + value + ";"); } get globalCompositeOperation() { return this._globalCompositeOperation; } set globalCompositeOperation(value) { this._globalCompositeOperation = value; let mode = 0; switch (value) { case "source-over": mode = 0; break; case "source-atop": mode = 5; break; case "source-in": mode = 0; break; case "source-out": mode = 2; break; case "destination-over": mode = 4; break; case "destination-atop": mode = 4; break; case "destination-in": mode = 4; break; case "destination-out": mode = 3; break; case "lighter": mode = 1; break; case "copy": mode = 2; break; case "xor": mode = 6; break; default: mode = 0; } this._drawCommands = this._drawCommands.concat("B" + mode + ";"); } get textAlign() { return this._textAlign; } setTextAlign(value) { this.textAlign = value } set textAlign(value) { this._textAlign = value; let Align = 0; switch (value) { case "start": Align = 0; break; case "end": Align = 1; break; case "left": Align = 2; break; case "center": Align = 3; break; case "right": Align = 4; break; default: Align = 0; } this._drawCommands = this._drawCommands.concat("A" + Align + ";"); } get textBaseline() { return this._textBaseline; } setTextBaseline(value) { this.textBaseline = value } set textBaseline(value) { this._textBaseline = value; let baseline = 0; switch (value) { case "alphabetic": baseline = 0; break; case "middle": baseline = 1; break; case "top": baseline = 2; break; case "hanging": baseline = 3; break; case "bottom": baseline = 4; break; case "ideographic": baseline = 5; break; default: baseline = 0; break; } this._drawCommands = this._drawCommands.concat("E" + baseline + ";"); } get font() { return this._font; } setFontSize(size) { var str = this._font; var strs = str.trim().split(/\s+/); for (var i = 0; i < strs.length; i++) { var values = ["normal", "italic", "oblique", "normal", "small-caps", "normal", "bold", "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900", "normal", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed", "semi-expanded", "expanded", "extra-expanded", "ultra-expanded" ]; if (-1 == values.indexOf(strs[i].trim())) { if (typeof size === 'string') { strs[i] = size; } else if (typeof size === 'number') { strs[i] = String(size) + 'px'; } break; } } this.font = strs.join(" "); } set font(value) { this._font = value; this._drawCommands = this._drawCommands.concat("j" + value + ";"); } setTransform(a, b, c, d, tx, ty) { this._drawCommands = this._drawCommands.concat("t" + (a === 1 ? "1" : a.toFixed(2)) + "," + (b === 0 ? "0" : b.toFixed(2)) + "," + (c === 0 ? "0" : c.toFixed(2)) + "," + (d === 1 ? "1" : d.toFixed(2)) + "," + tx.toFixed(2) + "," + ty.toFixed(2) + ";"); } transform(a, b, c, d, tx, ty) { this._drawCommands = this._drawCommands.concat("f" + (a === 1 ? "1" : a.toFixed(2)) + "," + (b === 0 ? "0" : b.toFixed(2)) + "," + (c === 0 ? "0" : c.toFixed(2)) + "," + (d === 1 ? "1" : d.toFixed(2)) + "," + tx + "," + ty + ";"); } resetTransform() { this._drawCommands = this._drawCommands.concat("m;"); } scale(a, d) { this._drawCommands = this._drawCommands.concat("k" + a.toFixed(2) + "," + d.toFixed(2) + ";"); } rotate(angle) { this._drawCommands = this._drawCommands .concat("r" + angle.toFixed(6) + ";"); } translate(tx, ty) { this._drawCommands = this._drawCommands.concat("l" + tx.toFixed(2) + "," + ty.toFixed(2) + ";"); } save() { this._savedGlobalAlpha.push(this._globalAlpha); this._drawCommands = this._drawCommands.concat("v;"); } restore() { this._drawCommands = this._drawCommands.concat("e;"); this._globalAlpha = this._savedGlobalAlpha.pop(); } createPattern(img, pattern) { if (typeof img === 'string') { var imgObj = new GImage(); imgObj.src = img; img = imgObj; } return new FillStylePattern(img, pattern); } createLinearGradient(x0, y0, x1, y1) { return new FillStyleLinearGradient(x0, y0, x1, y1); } createRadialGradient = function(x0, y0, r0, x1, y1, r1) { return new FillStyleRadialGradient(x0, y0, r0, x1, y1, r1); }; createCircularGradient = function(x0, y0, r0) { return new FillStyleRadialGradient(x0, y0, 0, x0, y0, r0); }; strokeRect(x, y, w, h) { this._drawCommands = this._drawCommands.concat("s" + x + "," + y + "," + w + "," + h + ";"); } clearRect(x, y, w, h) { this._drawCommands = this._drawCommands.concat("c" + x + "," + y + "," + w + "," + h + ";"); } clip() { this._drawCommands = this._drawCommands.concat("p;"); } resetClip() { this._drawCommands = this._drawCommands.concat("q;"); } closePath() { this._drawCommands = this._drawCommands.concat("o;"); } moveTo(x, y) { this._drawCommands = this._drawCommands.concat("g" + x.toFixed(2) + "," + y.toFixed(2) + ";"); } lineTo(x, y) { this._drawCommands = this._drawCommands.concat("i" + x.toFixed(2) + "," + y.toFixed(2) + ";"); } quadraticCurveTo = function(cpx, cpy, x, y) { this._drawCommands = this._drawCommands.concat("u" + cpx + "," + cpy + "," + x + "," + y + ";"); } bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, ) { this._drawCommands = this._drawCommands.concat( "z" + cp1x.toFixed(2) + "," + cp1y.toFixed(2) + "," + cp2x.toFixed(2) + "," + cp2y.toFixed(2) + "," + x.toFixed(2) + "," + y.toFixed(2) + ";"); } arcTo(x1, y1, x2, y2, radius) { this._drawCommands = this._drawCommands.concat("h" + x1 + "," + y1 + "," + x2 + "," + y2 + "," + radius + ";"); } beginPath() { this._drawCommands = this._drawCommands.concat("b;"); } fillRect(x, y, w, h) { this._drawCommands = this._drawCommands.concat("n" + x + "," + y + "," + w + "," + h + ";"); } rect(x, y, w, h) { this._drawCommands = this._drawCommands.concat("w" + x + "," + y + "," + w + "," + h + ";"); } fill() { this._drawCommands = this._drawCommands.concat("L;"); } stroke(path) { this._drawCommands = this._drawCommands.concat("x;"); } arc(x, y, radius, startAngle, endAngle, anticlockwise) { let ianticlockwise = 0; if (anticlockwise) { ianticlockwise = 1; } this._drawCommands = this._drawCommands.concat( "y" + x.toFixed(2) + "," + y.toFixed(2) + "," + radius.toFixed(2) + "," + startAngle + "," + endAngle + "," + ianticlockwise + ";" ); } fillText(text, x, y) { let tmptext = text.replace(/!/g, "!!"); tmptext = tmptext.replace(/,/g, "!,"); tmptext = tmptext.replace(/;/g, "!;"); this._drawCommands = this._drawCommands.concat("T" + tmptext + "," + x + "," + y + ",0.0;"); } strokeText = function(text, x, y) { let tmptext = text.replace(/!/g, "!!"); tmptext = tmptext.replace(/,/g, "!,"); tmptext = tmptext.replace(/;/g, "!;"); this._drawCommands = this._drawCommands.concat("U" + tmptext + "," + x + "," + y + ",0.0;"); } measureText(text) { return CanvasRenderingContext2D.GBridge.measureText(text, this.font, this.componentId); } isPointInPath = function(x, y) { throw new Error('GCanvas not supported yet'); } drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) { if (typeof image === 'string') { var imgObj = new GImage(); imgObj.src = image; image = imgObj; } if (image instanceof GImage) { if (!image.complete) { imgObj.onload = () => { var index = this._needRedrawImageCache.indexOf(image); if (index > -1) { this._needRedrawImageCache.splice(index, 1); CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); this._redrawflush(true); } } this._notCommitDrawImageCache.push(image); } else { CanvasRenderingContext2D.GBridge.bindImageTexture(this.componentId, image.src, image._id); } var srcArgs = [image, sx, sy, sw, sh, dx, dy, dw, dh]; var args = []; for (var arg in srcArgs) { if (typeof(srcArgs[arg]) != 'undefined') { args.push(srcArgs[arg]); } } this.__drawImage.apply(this, args); //this.__drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh); } } __drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) { const numArgs = arguments.length; function drawImageCommands() { if (numArgs === 3) { const x = parseFloat(sx) || 0.0; const y = parseFloat(sy) || 0.0; return ("d" + image._id + ",0,0," + image.width + "," + image.height + "," + x + "," + y + "," + image.width + "," + image.height + ";"); } else if (numArgs === 5) { const x = parseFloat(sx) || 0.0; const y = parseFloat(sy) || 0.0; const width = parseInt(sw) || image.width; const height = parseInt(sh) || image.height; return ("d" + image._id + ",0,0," + image.width + "," + image.height + "," + x + "," + y + "," + width + "," + height + ";"); } else if (numArgs === 9) { sx = parseFloat(sx) || 0.0; sy = parseFloat(sy) || 0.0; sw = parseInt(sw) || image.width; sh = parseInt(sh) || image.height; dx = parseFloat(dx) || 0.0; dy = parseFloat(dy) || 0.0; dw = parseInt(dw) || image.width; dh = parseInt(dh) || image.height; return ("d" + image._id + "," + sx + "," + sy + "," + sw + "," + sh + "," + dx + "," + dy + "," + dw + "," + dh + ";"); } } this._drawCommands += drawImageCommands(); } _flush(reserve, callback) { const commands = this._drawCommands; this._drawCommands = ''; CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback); this._needRender = false; } _redrawflush(reserve, callback) { const commands = this._redrawCommands; CanvasRenderingContext2D.GBridge.render2d(this.componentId, commands, callback); if (this._needRedrawImageCache.length == 0) { this._redrawCommands = ''; } } draw(reserve, callback) { if (!reserve) { this._globalAlpha = this._savedGlobalAlpha.pop(); this._savedGlobalAlpha.push(this._globalAlpha); this._redrawCommands = this._drawCommands; this._needRedrawImageCache = this._notCommitDrawImageCache; if (this._autoSaveContext) { this._drawCommands = ("v;" + this._drawCommands); this._autoSaveContext = false; } else { this._drawCommands = ("e;X;v;" + this._drawCommands); } } else { this._needRedrawImageCache = this._needRedrawImageCache.concat(this._notCommitDrawImageCache); this._redrawCommands += this._drawCommands; if (this._autoSaveContext) { this._drawCommands = ("v;" + this._drawCommands); this._autoSaveContext = false; } } this._notCommitDrawImageCache = []; if (this._flush) { this._flush(reserve, callback); } } getImageData(x, y, w, h, callback) { CanvasRenderingContext2D.GBridge.getImageData(this.componentId, x, y, w, h, function(res) { res.data = Base64ToUint8ClampedArray(res.data); if (typeof(callback) == 'function') { callback(res); } }); } putImageData(data, x, y, w, h, callback) { if (data instanceof Uint8ClampedArray) { data = ArrayBufferToBase64(data); CanvasRenderingContext2D.GBridge.putImageData(this.componentId, data, x, y, w, h, function(res) { if (typeof(callback) == 'function') { callback(res); } }); } } toTempFilePath(x, y, width, height, destWidth, destHeight, fileType, quality, callback) { CanvasRenderingContext2D.GBridge.toTempFilePath(this.componentId, x, y, width, height, destWidth, destHeight, fileType, quality, function(res) { if (typeof(callback) == 'function') { callback(res); } }); } }