/** * Copyright (c) 2006-2017, JGraph Ltd */ /** * Class: mxVsdxCanvas2D * * Constructor: mxVsdxCanvas2D * * Constructs a new abstract canvas. */ function mxVsdxCanvas2D() { mxAbstractCanvas2D.call(this); }; /** * Extends mxAbstractCanvas2D */ mxUtils.extend(mxVsdxCanvas2D, mxAbstractCanvas2D); /** * Variable: textEnabled * * Specifies if text output should be enabled. Default is true. */ mxVsdxCanvas2D.prototype.textEnabled = true; /** * Function: init * * Initialize the canvas for a new vsdx file. */ mxVsdxCanvas2D.prototype.init = function (zip) { this.filesLoading = 0; this.zip = zip; }; /** * Function: onFilesLoaded * * Called after all pending files have finished loading. */ mxVsdxCanvas2D.prototype.onFilesLoaded = function () { // hook for subclassers }; /** * Function: createElt * * Create a new geo section. */ mxVsdxCanvas2D.prototype.createElt = function (name) { return (this.xmlDoc.createElementNS != null) ? this.xmlDoc.createElementNS(VsdxExport.prototype.XMLNS, name) : this.xmlDoc.createElement(name); }; /** * Function: createGeoSec * * Create a new geo section. */ mxVsdxCanvas2D.prototype.createGeoSec = function () { if (this.geoSec != null) { this.shape.appendChild(this.geoSec); } var geoSec = this.createElt("Section"); geoSec.setAttribute("N", "Geometry"); geoSec.setAttribute("IX", this.geoIndex++); this.geoSec = geoSec; this.geoStepIndex = 1; this.lastX = 0; this.lastY = 0; this.lastMoveToX = 0; this.lastMoveToY = 0; }; /** * Function: newShape * * Create a new shape. */ mxVsdxCanvas2D.prototype.newShape = function (shape, cellState, xmlDoc) { this.geoIndex = 0; this.shape = shape; this.cellState = cellState; this.xmGeo = cellState.cell.geometry; this.xmlDoc = xmlDoc; this.geoSec = null; this.shapeImg = null; this.shapeType = "Shape"; this.createGeoSec(); }; /** * Function: newEdge * * Create a new edge. */ mxVsdxCanvas2D.prototype.newEdge = function (shape, cellState, xmlDoc) { this.shape = shape; this.cellState = cellState; this.xmGeo = cellState.cellBounds; var s = this.state; this.xmlDoc = xmlDoc; }; /** * Function: endShape * * End current shape. */ mxVsdxCanvas2D.prototype.endShape = function () { if (this.shapeImg != null) { this.addForeignData(this.shapeImg.type, this.shapeImg.id); } }; /** * Function: newPage * * Start a new page. */ mxVsdxCanvas2D.prototype.newPage = function () { this.images = []; }; /** * Function: newPage * * Start a new page. */ mxVsdxCanvas2D.prototype.getShapeType = function () { return this.shapeType; }; /** * Function: getShapeGeo * * return the current geo section. */ mxVsdxCanvas2D.prototype.getShapeGeo = function () { return this.geoSec; }; /** * Function: createCellElemScaled * * Creates a cell element and scale the value. */ mxVsdxCanvas2D.prototype.createCellElemScaled = function (name, val, formula) { return this.createCellElem(name, val / VsdxExport.prototype.CONVERSION_FACTOR, formula); }; /** * Function: createCellElem * * Creates a cell element. */ mxVsdxCanvas2D.prototype.createCellElem = function (name, val, formula) { var cell = this.createElt("Cell"); cell.setAttribute("N", name); cell.setAttribute("V", val); if (formula) cell.setAttribute("F", formula); return cell; }; mxVsdxCanvas2D.prototype.createRowScaled = function(type, index, x, y, a, b, c , d, xF, yF, aF, bF, cF, dF) { return this.createRowRel(type, index, x / VsdxExport.prototype.CONVERSION_FACTOR, y / VsdxExport.prototype.CONVERSION_FACTOR, a / VsdxExport.prototype.CONVERSION_FACTOR, b / VsdxExport.prototype.CONVERSION_FACTOR, c / VsdxExport.prototype.CONVERSION_FACTOR, d / VsdxExport.prototype.CONVERSION_FACTOR, xF, yF, aF, bF, cF, dF); }; mxVsdxCanvas2D.prototype.createRowRel = function(type, index, x, y, a, b, c , d, xF, yF, aF, bF, cF, dF) { var row = this.createElt("Row"); row.setAttribute("T", type); row.setAttribute("IX", index); row.appendChild(this.createCellElem("X", x, xF)); row.appendChild(this.createCellElem("Y", y, yF)); if (a != null && isFinite(a)) row.appendChild(this.createCellElem("A", a, aF)); if (b != null && isFinite(b)) row.appendChild(this.createCellElem("B", b, bF)); if (c != null && isFinite(c)) row.appendChild(this.createCellElem("C", c, cF)); if (d != null && isFinite(d)) row.appendChild(this.createCellElem("D", d, dF)); return row; }; /** * Function: begin * * Extends superclass to create path. */ mxVsdxCanvas2D.prototype.begin = function() { if (this.geoStepIndex > 1) this.createGeoSec(); }; /** * Function: rect * * Private helper function to create SVG elements */ mxVsdxCanvas2D.prototype.rect = function(x, y, w, h) { if (this.geoStepIndex > 1) this.createGeoSec(); var s = this.state; w = w * s.scale; h = h * s.scale; var geo = this.xmGeo; x = ((x - geo.x + s.dx) * s.scale); y = ((geo.height - y + geo.y - s.dy) * s.scale); this.geoSec.appendChild(this.createRowScaled("MoveTo", this.geoStepIndex++, x, y)); this.geoSec.appendChild(this.createRowScaled("LineTo", this.geoStepIndex++, x + w, y)); this.geoSec.appendChild(this.createRowScaled("LineTo", this.geoStepIndex++, x + w, y - h)); this.geoSec.appendChild(this.createRowScaled("LineTo", this.geoStepIndex++, x, y - h)); this.geoSec.appendChild(this.createRowScaled("LineTo", this.geoStepIndex++, x, y)); }; /** * Function: roundrect * * Private helper function to create SVG elements */ mxVsdxCanvas2D.prototype.roundrect = function(x, y, w, h, dx, dy) { this.rect(x, y, w, h); //TODO this assume dx and dy are equal and only one rounding is needed this.shape.appendChild(this.createCellElemScaled("Rounding", dx)); }; /** * Function: ellipse * * Private helper function to create SVG elements */ mxVsdxCanvas2D.prototype.ellipse = function(x, y, w, h) { if (this.geoStepIndex > 1) this.createGeoSec(); var s = this.state; w = w * s.scale; h = h * s.scale; var geo = this.xmGeo; var gh = geo.height * s.scale; var gw = geo.width * s.scale; x = (x - geo.x + s.dx) * s.scale; y = gh + (-y + geo.y - s.dy) * s.scale; var xWr = (x + w/2) / gw; var yHr = (y - h/2) / gh; var aWr = x / gw; var bHr = (y - h/2) / gh; var cWr = (x + w/2) / gw; var dHr = y / gh; this.geoSec.appendChild(this.createRowScaled("Ellipse", this.geoStepIndex++, x + w/2, y - h/2, x, y - h/2, x + w/2, y , "Width*" + xWr, "Height*" + yHr, "Width*" + aWr, "Height*" + bHr, "Width*" + cWr, "Height*" + dHr)); }; /** * Function: moveTo * * Moves the current path the given point. * * Parameters: * * x - Number that represents the x-coordinate of the point. * y - Number that represents the y-coordinate of the point. */ mxVsdxCanvas2D.prototype.moveTo = function(x, y) { //MoveTo inside a geo usually produce incorrect fill if (this.geoStepIndex > 1) this.createGeoSec(); this.lastMoveToX = x; this.lastMoveToY = y; this.lastX = x; this.lastY = y; var geo = this.xmGeo; var s = this.state; x = (x - geo.x + s.dx) * s.scale; y = (geo.height - y + geo.y - s.dy) * s.scale; var h = geo.height * s.scale; var w = geo.width * s.scale; this.geoSec.appendChild(this.createRowRel("RelMoveTo", this.geoStepIndex++, x/w, y/h)); }; /** * Function: lineTo * * Draws a line to the given coordinates. * * Parameters: * * x - Number that represents the x-coordinate of the endpoint. * y - Number that represents the y-coordinate of the endpoint. */ mxVsdxCanvas2D.prototype.lineTo = function(x, y) { this.lastX = x; this.lastY = y; var geo = this.xmGeo; var s = this.state; x = (x - geo.x + s.dx) * s.scale; y = (geo.height - y + geo.y - s.dy) * s.scale; var h = geo.height * s.scale; var w = geo.width * s.scale; this.geoSec.appendChild(this.createRowRel("RelLineTo", this.geoStepIndex++, x/w, y/h)); }; /** * Function: quadTo * * Adds a quadratic curve to the current path. * * Parameters: * * x1 - Number that represents the x-coordinate of the control point. * y1 - Number that represents the y-coordinate of the control point. * x2 - Number that represents the x-coordinate of the endpoint. * y2 - Number that represents the y-coordinate of the endpoint. */ mxVsdxCanvas2D.prototype.quadTo = function(x1, y1, x2, y2) { this.lastX = x2; this.lastY = y2; var s = this.state; var geo = this.xmGeo; var h = geo.height * s.scale; var w = geo.width * s.scale; x1 = (x1 - geo.x + s.dx) * s.scale; y1 = (geo.height - y1 + geo.y - s.dy) * s.scale; x2 = (x2 - geo.x + s.dx) * s.scale; y2 = (geo.height - y2 + geo.y - s.dy) * s.scale; x1 = x1 / w; y1 = y1 / h; x2 = x2 / w; y2 = y2 / h; this.geoSec.appendChild(this.createRowRel("RelQuadBezTo", this.geoStepIndex++, x2, y2, x1, y1)); }; /** * Function: curveTo * * Adds a bezier curve to the current path. * * Parameters: * * x1 - Number that represents the x-coordinate of the first control point. * y1 - Number that represents the y-coordinate of the first control point. * x2 - Number that represents the x-coordinate of the second control point. * y2 - Number that represents the y-coordinate of the second control point. * x3 - Number that represents the x-coordinate of the endpoint. * y3 - Number that represents the y-coordinate of the endpoint. */ mxVsdxCanvas2D.prototype.curveTo = function(x1, y1, x2, y2, x3, y3) { this.lastX = x3; this.lastY = y3; var s = this.state; var geo = this.xmGeo; var h = geo.height * s.scale; var w = geo.width * s.scale; x1 = (x1 - geo.x + s.dx) * s.scale; y1 = (geo.height - y1 + geo.y - s.dy) * s.scale; x2 = (x2 - geo.x + s.dx) * s.scale; y2 = (geo.height - y2 + geo.y - s.dy) * s.scale; x3 = (x3 - geo.x + s.dx) * s.scale; y3 = (geo.height - y3 + geo.y - s.dy) * s.scale; x1 = x1 / w; y1 = y1 / h; x2 = x2 / w; y2 = y2 / h; x3 = x3 / w; y3 = y3 / h; this.geoSec.appendChild(this.createRowRel("RelCubBezTo", this.geoStepIndex++, x3, y3, x1, y1, x2, y2)); }; /** * Function: close * * Closes the current path. */ mxVsdxCanvas2D.prototype.close = function() { //Closing with a line if last point != last MoveTo point if (this.lastMoveToX != this.lastX || this.lastMoveToY != this.lastY) this.lineTo(this.lastMoveToX, this.lastMoveToY); }; /** * Function: addForeignData * * Add ForeignData to current shape using last image in the images array */ mxVsdxCanvas2D.prototype.addForeignData = function(type, index) { var foreignData = this.createElt("ForeignData"); foreignData.setAttribute("ForeignType", "Bitmap"); type = type.toUpperCase(); if (type != "BMP") foreignData.setAttribute("CompressionType", type); var rel = this.createElt("Rel"); rel.setAttribute("r:id", "rId" + index); foreignData.appendChild(rel); this.shape.appendChild(foreignData); this.shapeType = "Foreign"; }; mxVsdxCanvas2D.prototype.convertSvg2Png = function(svgData, isBase64, callback) { var that = this; this.filesLoading++; try { var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); if (!isBase64) { svgData = String.fromCharCode.apply(null, new Uint8Array(svgData)); svgData = ((window.btoa)? btoa(svgData) : Base64.encode(svgData, true)); } var svgUrl = "data:image/svg+xml;base64," + svgData; img = new Image; img.onload = function () { canvas.width = this.width; canvas.height = this.height; ctx.drawImage(this, 0, 0); try { callback(canvas.toDataURL("image/png")); } catch(e){}//ignore that.filesLoading--; if (that.filesLoading == 0) { that.onFilesLoaded(); } }; img.onerror = function () { console.log("SVG2PNG conversion failed"); try { callback(svgData); //Error, just return the original data! } catch(e){}//ignore that.filesLoading--; if (that.filesLoading == 0) { that.onFilesLoaded(); } }; img.src = svgUrl; } catch(e) { console.log("SVG2PNG conversion failed" + e.message); try { callback(svgData); //just to keep going! } catch(e){}//ignore this.filesLoading--; if (that.filesLoading == 0) { that.onFilesLoaded(); } } }; /** * Function: image * * Add image to vsdx file as a media (Foreign Object) */ mxVsdxCanvas2D.prototype.image = function(x, y, w, h, src, aspect, flipH, flipV) { var that = this; //TODO image reusing, if the same image is used more than once, reuse it. Applicable for URLs specifically (but can also be applied to embedded ones) var imgName = "image" + (this.images.length + 1) + "."; var type; if (src.indexOf("data:") == 0) { var p = src.indexOf("base64,"); var base64 = src.substring(p + 7); //7 is the length of "base64," type = src.substring(11, p-1); //11 is the length of "data:image/" //SVG files cannot be embedded in vsdx files, TODO convert them to a visio shape if (type.indexOf('svg') == 0) { type = 'png'; imgName += type; this.convertSvg2Png(base64, true, function(pngData){ that.zip.file("visio/media/" + imgName, pngData.substring(22), {base64: true}); //22 is the length of "data:image/png;base64," }); } else { imgName += type; this.zip.file("visio/media/" + imgName, base64, {base64: true}); } } else if (window.XMLHttpRequest) //URL src, fetch it { src = this.converter.convert(src); this.filesLoading++; var p = src.lastIndexOf("."); type = src.substring(p+1); var convertSvg = false; if (type.indexOf('svg') == 0) { type = 'png'; convertSvg = true; } imgName += type; //The old browsers binary workaround doesn't work with jszip and converting to base64 encoding doesn't work also var xhr = new XMLHttpRequest(); xhr.open('GET', src, true); xhr.responseType = 'arraybuffer'; xhr.onreadystatechange = function(e) { if (this.readyState == 4) { if (this.status == 200) { //SVG files cannot be embedded in vsdx files, TODO convert them to a visio shape if (convertSvg) { that.convertSvg2Png(this.response, false, function(pngData){ that.zip.file("visio/media/" + imgName, pngData.substring(22), {base64: true}); //22 is the length of "data:image/png;base64," }); } else { that.zip.file("visio/media/" + imgName, this.response); } } that.filesLoading--; if (that.filesLoading == 0) { that.onFilesLoaded(); } } }; xhr.send(); } this.images.push(imgName); //TODO can a shape has more than one image? //We add one to the id as rId1 is reserved for the edges master this.shapeImg = {type: type, id: this.images.length + 1}; //TODO support these! aspect = (aspect != null) ? aspect : true; flipH = (flipH != null) ? flipH : false; flipV = (flipV != null) ? flipV : false; var s = this.state; w = w * s.scale; h = h * s.scale; var geo = this.xmGeo; x = (x - geo.x + s.dx) * s.scale; y = (geo.height - y + geo.y - s.dy) * s.scale; this.shape.appendChild(this.createCellElemScaled("ImgOffsetX", x)); this.shape.appendChild(this.createCellElemScaled("ImgOffsetY", y - h)); this.shape.appendChild(this.createCellElemScaled("ImgWidth", w)); this.shape.appendChild(this.createCellElemScaled("ImgHeight", h)); // var s = this.state; // x += s.dx; // y += s.dy; // // if (s.alpha < 1 || s.fillAlpha < 1) // { // node.setAttribute('opacity', s.alpha * s.fillAlpha); // } // // var tr = this.state.transform || ''; // // if (flipH || flipV) // { // var sx = 1; // var sy = 1; // var dx = 0; // var dy = 0; // // if (flipH) // { // sx = -1; // dx = -w - 2 * x; // } // // if (flipV) // { // sy = -1; // dy = -h - 2 * y; // } // // // Adds image tansformation to existing transform // tr += 'scale(' + sx + ',' + sy + ')translate(' + (dx * s.scale) + ',' + (dy * s.scale) + ')'; // } // // if (tr.length > 0) // { // node.setAttribute('transform', tr); // } // // if (!this.pointerEvents) // { // node.setAttribute('pointer-events', 'none'); // } }; /** * Function: text * * Paints the given text. Possible values for format are empty string for * plain text and html for HTML markup. HTML labels * are not available as part of shapes with no foreignObject support in SVG * (eg. IE9, IE10). * * Parameters: * * x - Number that represents the x-coordinate of the text. * y - Number that represents the y-coordinate of the text. * w - Number that represents the available width for the text or 0 for automatic width. * h - Number that represents the available height for the text or 0 for automatic height. * str - String that specifies the text to be painted. * align - String that represents the horizontal alignment. * valign - String that represents the vertical alignment. * wrap - Boolean that specifies if word-wrapping is enabled. Requires w > 0. * format - Empty string for plain text or 'html' for HTML markup. * overflow - Specifies the overflow behaviour of the label. Requires w > 0 and/or h > 0. * clip - Boolean that specifies if the label should be clipped. Requires w > 0 and/or h > 0. * rotation - Number that specifies the angle of the rotation around the anchor point of the text. * dir - Optional string that specifies the text direction. Possible values are rtl and lrt. */ mxVsdxCanvas2D.prototype.text = function(x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation, dir) { var that = this; if (this.textEnabled && str != null) { if (mxUtils.isNode(str)) { str = mxUtils.getOuterHtml(str); } //This is the case with edges if (w == 0 && h == 0) { var strSize = mxUtils.getSizeForString(str, that.cellState.style["fontSize"], that.cellState.style["fontFamily"]); w = strSize.width * 2; h = strSize.height * 2; } //TODO support HTML text formatting and remaining attributes if (format == 'html') { if (mxUtils.getValue(this.cellState.style, 'nl2Br', '1') != '0') { // Removes newlines from HTML and converts breaks to newlines // to match the HTML output in plain text str = str.replace(/\n/g, '').replace(//g, '\n'); } // Removes HTML tags if (this.html2txtDiv == null) this.html2txtDiv = document.createElement('div'); this.html2txtDiv.innerHTML = Graph.sanitizeHtml(str); str = mxUtils.extractTextWithWhitespace(this.html2txtDiv.childNodes); } var s = this.state; var geo = this.xmGeo; w = w * s.scale; h = h * s.scale; var charSect = this.createElt("Section"); charSect.setAttribute('N', 'Character'); var pSect = this.createElt("Section"); pSect.setAttribute('N', 'Paragraph'); var text = this.createElt("Text"); var rgb2hex = function (rgb){ rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i); return (rgb && rgb.length === 4) ? "#" + ("0" + parseInt(rgb[1],10).toString(16)).slice(-2) + ("0" + parseInt(rgb[2],10).toString(16)).slice(-2) + ("0" + parseInt(rgb[3],10).toString(16)).slice(-2) : ''; }; var rowIndex = 0, pIndex = 0; var calcW = 0, calcH = 0, lastW = 0, lastH = 0, lineH = 0; var createTextRow = function(styleMap, charSect, pSect, textEl, txt) { var fontSize = styleMap['fontSize']; var fontFamily = styleMap['fontFamily']; var strRect = mxUtils.getSizeForString(txt, fontSize, fontFamily); var wrapped = false; if (wrap && strRect.width > w) { strRect = mxUtils.getSizeForString(txt, fontSize, fontFamily, w); wrapped = true; } if (styleMap['blockElem']) { lastW += strRect.width; calcW = Math.min(Math.max(calcW, lastW), w); lastW = 0; lastH = Math.max(lastH, strRect.height); calcH += lastH + lineH; lineH = lastH; lastH = 0; } else { lastW += strRect.width; calcW = Math.min(Math.max(calcW, lastW), w); lastH = Math.max(lastH, strRect.height); calcH = Math.max(calcH, lastH); } var charRow = that.createElt("Row"); charRow.setAttribute('IX', rowIndex); if (styleMap['fontColor']) charRow.appendChild(that.createCellElem("Color", styleMap['fontColor'])); if (fontSize) charRow.appendChild(that.createCellElemScaled("Size", fontSize * 0.97)); //the magic number 0.97 is needed such that text do not overflow if (fontFamily) charRow.appendChild(that.createCellElem("Font", fontFamily)); //0x00 No format //0x01 Specifies that the text run has a bold character property. //0x02 Specifies that the text run has an italic character property. //0x04 Specifies that the text run has an underline character property. //0x08 Specifies that the text run has a small caps character property. var style = 0; if (styleMap['bold']) style |= 0x11; if (styleMap['italic']) style |= 0x22; if (styleMap['underline']) style |= 0x4; charRow.appendChild(that.createCellElem("Style", style)); charRow.appendChild(that.createCellElem("Case", "0")); charRow.appendChild(that.createCellElem("Pos", "0")); charRow.appendChild(that.createCellElem("FontScale", "1")); charRow.appendChild(that.createCellElem("Letterspace", "0")); charSect.appendChild(charRow); var pRow = that.createElt("Row"); pRow.setAttribute('IX', pIndex); var align = 1; //center is default switch(styleMap['align']) { case 'left': align = 0; break; case 'center': align = 1; break; case 'right': align = 2; break; case 'start': align = 0; break; //TODO check right-to-left case 'end': align = 2; break; //TODO check right-to-left case 'justify': align = 0; break; default: align = 1; } pRow.appendChild(that.createCellElem("HorzAlign", align)); // pRow.appendChild(that.createCellElem("SpLine", "-1.2")); pSect.appendChild(pRow); // var pp = that.createElt("pp"); // pp.setAttribute('IX', pIndex++); // textEl.appendChild(pp); var cp = that.createElt("cp"); cp.setAttribute('IX', rowIndex++); textEl.appendChild(cp); var txtNode = that.xmlDoc.createTextNode(txt + (styleMap['blockElem']? "\n" : "")); textEl.appendChild(txtNode); }; var processNodeChildren = function(ch, pStyle) { pStyle = pStyle || {}; for (var i=0; i= 0 || pStyle['underline'], align: style.getPropertyValue('text-align'), fontColor: rgb2hex(style.getPropertyValue('color')), fontSize: parseFloat(style.getPropertyValue('font-size')), fontFamily: style.getPropertyValue('font-family').replace(/"/g, ''), //remove quotes blockElem: style.getPropertyValue('display') == 'block' || nodeName == "BR" || nodeName == "LI", OL: pStyle['OL'], LiIndex: pStyle['LiIndex'] }; if (nodeName == "UL") { var pRow = that.createElt("Row"); pRow.setAttribute('IX', pIndex); pRow.appendChild(that.createCellElem("HorzAlign", "0")); pRow.appendChild(that.createCellElem("Bullet", "1")); pSect.appendChild(pRow); var pp = that.createElt("pp"); pp.setAttribute('IX', pIndex++); text.appendChild(pp); } //VSDX doesn't have numbered list! else if (nodeName == "OL") { styleMap['OL'] = true; } else if (nodeName == "LI") { styleMap['LiIndex'] = i + 1; } if (chLen > 0) { processNodeChildren(curCh.childNodes, styleMap); //Close the UL by adding another pp with no Vullets if (nodeName == "UL") { var pRow = that.createElt("Row"); pRow.setAttribute('IX', pIndex); pRow.appendChild(that.createCellElem("Bullet", "0")); pSect.appendChild(pRow); var pp = that.createElt("pp"); pp.setAttribute('IX', pIndex++); text.appendChild(pp); } createTextRow(styleMap, charSect, pSect, text, ""); //to handle block elements if any } else { //VSDX doesn't have numbered list! createTextRow(styleMap, charSect, pSect, text, (pStyle['OL']? pStyle['LiIndex'] + '. ' : '') + curCh.textContent); } } } }; if (format == 'html' && mxClient.IS_SVG) { //Get the actual HTML label node var elt = this.cellState.text.node.getElementsByTagName('div')[mxClient.NO_FO? 0 : 1]; if (elt != null) { var ch = elt.childNodes; processNodeChildren(ch, {}); } } else { //If it is not HTML or SVG, we fall back to removing html format var styleMap = { fontColor: that.cellState.style["fontColor"], fontSize: that.cellState.style["fontSize"], fontFamily: that.cellState.style["fontFamily"] }; createTextRow(styleMap, charSect, pSect, text, str); } var wShift = 0, hShift = 0; h = Math.max(h, calcH); w = Math.max(w, calcW); var hw = w/2, hh = h/2; var pRotDegrees = parseInt(mxUtils.getValue(this.cellState.style, 'rotation', '0')); var pRot = pRotDegrees * Math.PI / 180; //TODO Fix align and valign for rotated cases. Currently, all rotated shapes labels are centered switch(align) { case "right": if (pRotDegrees != 0) { x -= hw * Math.cos(pRot); y -= hw * Math.sin(pRot); } else { wShift = calcW/2; } break; case "center": //nothing break; case "left": if (pRotDegrees != 0) { x += hw * Math.cos(pRot); y += hw * Math.sin(pRot); } else { wShift = -calcW/2; } break; } switch(valign) { case "top": if (pRotDegrees != 0) { x += hh * Math.sin(pRot); y += hh * Math.cos(pRot); } else { hShift = calcH/2; } break; case "middle": //nothing break; case "bottom": if (pRotDegrees != 0) { x -= hh * Math.sin(pRot); y -= hh * Math.cos(pRot); } else { hShift = -calcH/2; } break; } x = (x - geo.x + s.dx) * s.scale; y = (geo.height - y + geo.y - s.dy) * s.scale; this.shape.appendChild(this.createCellElemScaled("TxtPinX", x)); this.shape.appendChild(this.createCellElemScaled("TxtPinY", y)); this.shape.appendChild(this.createCellElemScaled("TxtWidth", w)); this.shape.appendChild(this.createCellElemScaled("TxtHeight", h)); this.shape.appendChild(this.createCellElemScaled("TxtLocPinX", hw + wShift)); this.shape.appendChild(this.createCellElemScaled("TxtLocPinY", hh + hShift)); rotation -= pRotDegrees; if (rotation != 0) this.shape.appendChild(this.createCellElem("TxtAngle", (360 - rotation) * Math.PI / 180)); this.shape.appendChild(charSect); this.shape.appendChild(pSect); this.shape.appendChild(text); // if (overflow != null) // { // elem.setAttribute('overflow', overflow); // } // // if (clip != null) // { // elem.setAttribute('clip', (clip) ? '1' : '0'); // } // // if (dir != null) // { // elem.setAttribute('dir', dir); // } } }; /** * Function: rotate * * Sets the rotation of the canvas. Note that rotation cannot be concatenated. */ mxVsdxCanvas2D.prototype.rotate = function(theta, flipH, flipV, cx, cy) { //Vsdx has flipX/Y support separate from rotation if (theta != 0) { var s = this.state; cx += s.dx; cy += s.dy; cx *= s.scale; cy *= s.scale; this.shape.appendChild(this.createCellElem("Angle", (360 - theta) * Math.PI / 180)); s.rotation = s.rotation + theta; s.rotationCx = cx; s.rotationCy = cy; } }; /** * Function: stroke * * Paints the outline of the current drawing buffer. */ mxVsdxCanvas2D.prototype.stroke = function() { this.geoSec.appendChild(this.createCellElem("NoFill", "1")); this.geoSec.appendChild(this.createCellElem("NoLine", "0")); }; /** * Function: fill * * Fills the current drawing buffer. */ mxVsdxCanvas2D.prototype.fill = function() { this.geoSec.appendChild(this.createCellElem("NoFill", "0")); this.geoSec.appendChild(this.createCellElem("NoLine", "1")); }; /** * Function: fillAndStroke * * Fills the current drawing buffer and its outline. */ mxVsdxCanvas2D.prototype.fillAndStroke = function() { this.geoSec.appendChild(this.createCellElem("NoFill", "0")); this.geoSec.appendChild(this.createCellElem("NoLine", "0")); };