1var mxIsElectron = navigator.userAgent != null && 2 navigator.userAgent.toLowerCase().indexOf(' electron/') > -1; 3var GOOGLE_APPS_MAX_AREA = 25000000; 4var GOOGLE_SHEET_MAX_AREA = 1048576; //1024x1024 5 6//TODO Add support for loading math from a local folder 7Editor.initMath((remoteMath? 'https://app.diagrams.net/' : '') + 'math/MathJax.js'); 8 9function render(data) 10{ 11 var autoScale = false; 12 13 if (data.scale == 'auto') 14 { 15 autoScale = true; 16 data.scale = 1; 17 } 18 19 document.body.innerHTML = ''; 20 var container = document.createElement('div'); 21 container.id = 'graph'; 22 container.style.width = '100%'; 23 container.style.height = '100%'; 24 document.body.appendChild(container); 25 26 var graph = new Graph(container); 27 data.border = parseInt(data.border) || 0; 28 data.w = parseFloat(data.w) || 0; 29 data.h = parseFloat(data.h) || 0; 30 data.scale = parseFloat(data.scale) || 1; 31 32 var extras = null; 33 34 try 35 { 36 extras = JSON.parse(data.extras); 37 } 38 catch (e) 39 { 40 try 41 { 42 extras = JSON.parse(decodeURIComponent(data.extras)); 43 } 44 catch (e) 45 { 46 // ignore 47 } 48 } 49 50 var gridColor = null; 51 52 if (extras != null && extras.grid != null) 53 { 54 graph.gridSize = extras.grid.size; 55 graph.view.gridSteps = extras.grid.steps; 56 gridColor = extras.grid.color; 57 } 58 59 if (extras != null && extras.diagramLanguage != null) 60 { 61 Graph.diagramLanguage = extras.diagramLanguage; 62 Graph.translateDiagram = true; 63 } 64 65 //PNG+XML format 66 if (data.xml.substring(0, 5) == 'iVBOR' || (extras != null && extras.isPng)) 67 { 68 data.xml = Editor.extractGraphModelFromPng('data:image/png;base64,' + data.xml); 69 } 70 71 //IE11 sends incorrect xml 72 if (data.xml.substring(0, 11) == '<#document>') 73 { 74 data.xml = data.xml.substring(11, data.xml.length - 12); 75 } 76 77 // Parses XML 78 var doc = mxUtils.parseXml(data.xml); 79 var node = Editor.extractGraphModel(doc.documentElement, true); 80 81 if (node == null) 82 { 83 //Electron pdf export 84 try 85 { 86 const { ipcRenderer } = require('electron'); 87 88 ipcRenderer.send('render-finished', null); 89 } 90 catch(e) 91 { 92 console.log(e); 93 } 94 95 return graph; 96 } 97 98 var xmlDoc = node.ownerDocument; 99 var diagrams = null; 100 var from = 0; 101 102 if (mxIsElectron && data.format == 'xml') 103 { 104 const { ipcRenderer } = require('electron'); 105 106 try 107 { 108 var xml = mxUtils.getXml(xmlDoc); 109 EditorUi.prototype.createUi = function(){}; 110 EditorUi.prototype.addTrees = function(){}; 111 EditorUi.prototype.updateActionStates = function(){}; 112 var editorUi = new EditorUi(); 113 var tmpFile = new LocalFile(editorUi, xml); 114 editorUi.setCurrentFile(tmpFile); 115 editorUi.setFileData(xml); 116 ipcRenderer.send('xml-data', mxUtils.getXml(editorUi.getXmlFileData(null, null, data.uncompressed))); 117 } 118 catch(e) 119 { 120 ipcRenderer.send('xml-data-error'); 121 } 122 123 return; 124 } 125 126 // Handles mxfile 127 if (xmlDoc.documentElement.nodeName == 'mxfile') 128 { 129 diagrams = xmlDoc.documentElement.getElementsByTagName('diagram'); 130 } 131 132 //Add global variables to graph 133 if (extras != null && extras.globalVars != null) 134 { 135 graph.globalVars = extras.globalVars; 136 } 137 138 /** 139 * Disables custom links on shapes. 140 */ 141 var graphGetLinkForCell = graph.getLinkForCell; 142 143 graph.getLinkForCell = function(cell) 144 { 145 var link = graphGetLinkForCell.apply(this, arguments); 146 147 if (link != null && this.isCustomLink(link)) 148 { 149 link = null; 150 } 151 152 return link; 153 }; 154 155 /** 156 * Disables custom links in labels. 157 */ 158 var cellRendererRedrawLabelShape = graph.cellRenderer.redrawLabelShape; 159 160 graph.cellRenderer.redrawLabelShape = function(shape) 161 { 162 cellRendererRedrawLabelShape.apply(this, arguments); 163 164 if (shape.node != null) 165 { 166 var links = shape.node.getElementsByTagName('a'); 167 168 for (var i = 0; i < links.length; i++) 169 { 170 var href = links[i].getAttribute('href'); 171 172 if (href != null && graph.isCustomLink(href)) 173 { 174 links[i].setAttribute('href', '#'); 175 } 176 } 177 } 178 }; 179 180 var preview = null; 181 var waitCounter = 1; 182 var bounds; 183 var pageId; 184 var expScale; 185 // Waits for all images to finish loading 186 var cache = new Object(); 187 var math = false; 188 189 // Decrements waitCounter and invokes callback when finished 190 function decrementWaitCounter() 191 { 192 if (--waitCounter < 1) 193 { 194 //Note: This code targets Chrome as it is the browser used by export server 195 //Ensure that all fonts has been loaded, this promise is never rejected 196 document.fonts.ready.then(function() 197 { 198 var doneDiv = document.createElement("div"); 199 var pageCount = diagrams != null? diagrams.length : 1; 200 doneDiv.id = 'LoadingComplete'; 201 doneDiv.style.display = 'none'; 202 doneDiv.setAttribute('bounds', JSON.stringify(bounds)); 203 doneDiv.setAttribute('page-id', pageId); 204 doneDiv.setAttribute('scale', expScale); 205 doneDiv.setAttribute('pageCount', pageCount); 206 document.body.appendChild(doneDiv); 207 208 //Electron pdf export 209 if (mxIsElectron) 210 { 211 try 212 { 213 const { ipcRenderer } = require('electron'); 214 215 ipcRenderer.on('get-svg-data', (event, arg) => 216 { 217 graph.mathEnabled = math; //Enable math such that getSvg works as expected 218 // Returns the exported SVG for the given graph (see EditorUi.exportSvg) 219 var bg = graph.background; 220 221 if (bg == mxConstants.NONE) 222 { 223 bg = null; 224 } 225 226 var svgRoot = graph.getSvg(bg, 1, 0, false, null, true, null, null, null); 227 228 if (graph.shadowVisible) 229 { 230 graph.addSvgShadow(svgRoot); 231 } 232 233 // TODO addFontCss cannot be used as it requires this 234 // Adds CSS 235 //Editor.prototype.addFontCss(svgRoot); 236 237 if (math) 238 { 239 Editor.prototype.addMathCss(svgRoot); 240 } 241 242 ipcRenderer.send('svg-data', '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' + 243 mxUtils.getXml(svgRoot)); 244 }); 245 246 //For some reason, Electron 9 doesn't send this object as is without stringifying. Usually when variable is external to function own scope 247 ipcRenderer.send('render-finished', {bounds: JSON.stringify(bounds), pageCount: pageCount}); 248 } 249 catch(e) 250 { 251 console.log(e); 252 } 253 } 254 }); 255 } 256 }; 257 258 function waitForImages(tagName, attributeName) 259 { 260 var imgs = document.body.getElementsByTagName(tagName); 261 waitCounter += imgs.length; 262 263 for (var i = 0; i < imgs.length; i++) 264 { 265 // No load events for image elements in Phantom using indirection instead 266 var src = imgs[i].getAttribute(attributeName); 267 268 if (src != null && src.length > 0 && cache[src] == null) 269 { 270 cache[src] = new Image(); 271 cache[src].onload = decrementWaitCounter; 272 cache[src].onerror = decrementWaitCounter; 273 cache[src].src = src; 274 } 275 else 276 { 277 decrementWaitCounter(); 278 } 279 } 280 }; 281 282 // Waits for MathJax.Hub to become available to register 283 // wait counter callback asynchronously after math render 284 var editorDoMathJaxRender = Editor.doMathJaxRender; 285 286 Editor.doMathJaxRender = function(container) 287 { 288 editorDoMathJaxRender.apply(this, arguments); 289 290 window.setTimeout(function() 291 { 292 window.MathJax.Hub.Queue(function () 293 { 294 decrementWaitCounter(); 295 }); 296 }, 0); 297 }; 298 299 // Adds async MathJax rendering task 300 function renderMath(elt) 301 { 302 if (math && Editor.MathJaxRender != null) 303 { 304 waitCounter++; 305 Editor.MathJaxRender(elt); 306 } 307 }; 308 309 function loadExtFonts(extFonts) 310 { 311 try 312 { 313 extFonts = extFonts.split('|').map(function(ef) 314 { 315 var parts = ef.split('^'); 316 return {name: parts[0], url: parts[1]}; 317 }); 318 } 319 catch(e) 320 { 321 //ignore and return! 322 return; 323 } 324 325 waitCounter += extFonts.length; 326 327 //Note: This code targets Chrome as it is the browser used by export server 328 for (var i = 0; i < extFonts.length; i++) 329 { 330 if (extFonts[i].url.indexOf(Editor.GOOGLE_FONTS) == 0) 331 { 332 var link = document.createElement('link'); 333 334 link.setAttribute('rel', 'stylesheet'); 335 link.setAttribute('charset', 'UTF-8'); 336 link.setAttribute('type', 'text/css'); 337 338 link.onload = decrementWaitCounter; 339 link.onerror = decrementWaitCounter; 340 341 link.setAttribute('href', extFonts[i].url); 342 var head = document.getElementsByTagName('head')[0]; 343 head.appendChild(link); 344 } 345 else 346 { 347 //Relative urls doesn't work 348 if (extFonts[i].url.indexOf(PROXY_URL) == 0 && PROXY_URL.indexOf('http') == -1) 349 { 350 var href = window.location.href; 351 href = href.substring(0, href.lastIndexOf('/') + 1); 352 extFonts[i].url = href + extFonts[i].url; 353 } 354 355 var font = new FontFace(extFonts[i].name, 'url(' + extFonts[i].url + ')'); 356 357 font.load().then(function(loadedFont) 358 { 359 document.fonts.add(loadedFont); 360 decrementWaitCounter(); 361 }).catch(decrementWaitCounter); 362 } 363 } 364 }; 365 366 function renderGrid() 367 { 368 if (gridColor == null) return; 369 370 var view = graph.view; 371 var gridImage = btoa(unescape(encodeURIComponent(view.createSvgGrid(gridColor)))); 372 gridImage = 'url(' + 'data:image/svg+xml;base64,' + gridImage + ')'; 373 var phase = graph.gridSize * view.gridSteps * view.scale; 374 375 var x0 = 0; 376 var y0 = 0; 377 378 if (view.backgroundPageShape != null) 379 { 380 var bds = view.getBackgroundPageBounds(); 381 382 x0 = 1 + bds.x; 383 y0 = 1 + bds.y; 384 } 385 386 // Computes the offset to maintain origin for grid 387 var position = -Math.round(phase - mxUtils.mod(view.translate.x * view.scale - x0, phase)) + 'px ' + 388 -Math.round(phase - mxUtils.mod(view.translate.y * view.scale - y0, phase)) + 'px'; 389 390 var pages = document.querySelectorAll('[id^=mxPage]'); 391 392 var cssTxt = 'margin: 0;padding: 0;background-image: ' + gridImage + ';background-position: ' + position; 393 document.body.style.cssText = cssTxt; 394 395 for (var i = 0; i < pages.length; i++) 396 { 397 pages[i].style.cssText = cssTxt; 398 } 399 }; 400 401 var origAddFont = Graph.addFont; 402 403 Graph.addFont = function(name, url) 404 { 405 waitCounter++; 406 return origAddFont.call(this, name, url, decrementWaitCounter); 407 }; 408 409 function renderPage() 410 { 411 // Enables math typesetting 412 math |= xmlDoc.documentElement.getAttribute('math') == '1'; 413 414 //Load external fonts 415 var extFonts = xmlDoc.documentElement.getAttribute('extFonts'); 416 417 if (extFonts) 418 { 419 loadExtFonts(extFonts); 420 } 421 422 // Configure graph 423 graph.foldingEnabled = false; 424 graph.setEnabled(false); 425 426 // Sets background image 427 var bgImg = xmlDoc.documentElement.getAttribute('backgroundImage'); 428 429 if (bgImg != null) 430 { 431 bgImg = JSON.parse(bgImg); 432 graph.setBackgroundImage(new mxImage(bgImg.src, bgImg.width, 433 bgImg.height, bgImg.x, bgImg.y)); 434 } 435 436 // Parses XML into graph 437 var codec = new mxCodec(xmlDoc); 438 var model = graph.getModel(); 439 codec.decode(xmlDoc.documentElement, model); 440 441 var bg; 442 443 if (data.format == 'pdf') 444 { 445 if (data.bg == 'none') 446 { 447 bg = null; 448 } 449 else 450 { 451 bg = xmlDoc.documentElement.getAttribute('background'); 452 453 if (bg == 'none' || !bg) 454 { 455 bg = '#ffffff'; 456 } 457 } 458 } 459 else 460 { 461 // Loads background color 462 bg = (data.bg != null && data.bg.length > 0) ? 463 data.bg : xmlDoc.documentElement.getAttribute('background'); 464 465 // Normalizes values for transparent backgrounds 466 if (bg == 'none' || bg == '') 467 { 468 bg = null; 469 } 470 471 // Checks if export format supports transparent backgrounds 472 if (bg == null && data.format != 'gif' && data.format != 'png') 473 { 474 bg = '#ffffff'; 475 } 476 } 477 478 // Sets background color on page 479 if (bg != null) 480 { 481 document.body.style.backgroundColor = bg; 482 } 483 484 //handle layers 485 if (extras != null && ((extras.layers != null && extras.layers.length > 0) || 486 (extras.layerIds != null && extras.layerIds.length > 0))) 487 { 488 var childCount = model.getChildCount(model.root); 489 490 // Hides all layers 491 for (var i = 0; i < childCount; i++) 492 { 493 model.setVisible(model.getChildAt(model.root, i), false); 494 } 495 496 if (extras.layerIds != null) 497 { 498 for (var i = 0; i < extras.layerIds.length; i++) 499 { 500 model.setVisible(model.getCell(extras.layerIds[i]), true); 501 } 502 } 503 else 504 { 505 for (var i = 0; i < extras.layers.length; i++) 506 { 507 var layer = model.getChildAt(model.root, extras.layers[i]); 508 509 if (layer != null) 510 { 511 model.setVisible(layer, true); 512 } 513 } 514 } 515 } 516 517 // Sets initial value for PDF page background 518 graph.pdfPageVisible = false; 519 520 // Handles PDF output where the output should match the page format if the page is visible 521 if (data.print || (data.format == 'pdf' && xmlDoc.documentElement.getAttribute('page') == '1' && data.w == 0 && data.h == 0 && data.scale == 1)) 522 { 523 //Electron printing 524 var printScale = 1; 525 526 if (data.print) 527 { 528 document.title = data.fileTitle; 529 530 var gb = graph.getGraphBounds(); 531 printScale = data.pageScale; 532 533 if (isNaN(printScale)) 534 { 535 printScale = 1; 536 } 537 538 if (data.fit) 539 { 540 var h = parseInt(data.sheetsAcross); 541 var v = parseInt(data.sheetsDown); 542 543 data.scale = Math.min((data.pageHeight * v) / (gb.height / graph.view.scale), 544 (data.pageWidth * h) / (gb.width / graph.view.scale)); 545 } 546 else 547 { 548 data.scale = data.scale / graph.pageScale; 549 550 if (isNaN(data.scale)) 551 { 552 printScale = 1 / graph.pageScale; 553 } 554 } 555 } 556 557 var pw = data.pageWidth || xmlDoc.documentElement.getAttribute('pageWidth'); 558 var ph = data.pageHeight || xmlDoc.documentElement.getAttribute('pageHeight'); 559 graph.pdfPageVisible = true; 560 561 if (pw != null && ph != null) 562 { 563 graph.pageFormat = new mxRectangle(0, 0, parseFloat(pw), parseFloat(ph)); 564 } 565 566 var ps = data.pageScale || xmlDoc.documentElement.getAttribute('pageScale'); 567 568 if (ps != null) 569 { 570 graph.pageScale = ps; 571 } 572 573 graph.getPageSize = function() 574 { 575 return new mxRectangle(0, 0, this.pageFormat.width * this.pageScale, 576 this.pageFormat.height * this.pageScale); 577 }; 578 579 graph.getPageLayout = function() 580 { 581 var size = this.getPageSize(); 582 var bounds = this.getGraphBounds(); 583 584 if (bounds.width == 0 || bounds.height == 0) 585 { 586 return new mxRectangle(0, 0, 1, 1); 587 } 588 else 589 { 590 // Computes untransformed graph bounds 591 var x = Math.ceil(bounds.x / this.view.scale - this.view.translate.x); 592 var y = Math.ceil(bounds.y / this.view.scale - this.view.translate.y); 593 var w = Math.floor(bounds.width / this.view.scale); 594 var h = Math.floor(bounds.height / this.view.scale); 595 596 var x0 = Math.floor(x / size.width); 597 var y0 = Math.floor(y / size.height); 598 var w0 = Math.ceil((x + w) / size.width) - x0; 599 var h0 = Math.ceil((y + h) / size.height) - y0; 600 601 return new mxRectangle(x0, y0, w0, h0); 602 } 603 }; 604 605 // Fits the number of background pages to the graph 606 graph.view.getBackgroundPageBounds = function() 607 { 608 var layout = this.graph.getPageLayout(); 609 var page = this.graph.getPageSize(); 610 611 return new mxRectangle(this.scale * (this.translate.x + layout.x * page.width), 612 this.scale * (this.translate.y + layout.y * page.height), 613 this.scale * layout.width * page.width, 614 this.scale * layout.height * page.height); 615 }; 616 } 617 618 if (!graph.pdfPageVisible) 619 { 620 var b = graph.getGraphBounds(); 621 622 // Floor is needed to keep rendering crisp 623 if (data.w > 0 || data.h > 0) 624 { 625 var s = 1; 626 627 if (data.w > 0 && data.h > 0) 628 { 629 s = Math.min(data.w / b.width, data.h / b.height); 630 } 631 else if (data.w > 0) 632 { 633 s = data.w / b.width; 634 } 635 else 636 { 637 s = data.h / b.height; 638 } 639 640 graph.view.scaleAndTranslate(s, 641 Math.floor(data.border / s - Math.floor(b.x)), 642 Math.floor(data.border / s - Math.floor(b.y))); 643 } 644 else 645 { 646 var s = data.scale; 647 648 if (autoScale) 649 { 650 var pageWidth = (extras != null && extras.pageWidth != null) ? extras.pageWidth : 800; 651 652 if (b.width < pageWidth & b.height < 1.5 * pageWidth) 653 { 654 s = 4; 655 } 656 else if (b.width < 2 * pageWidth & b.height < 3 * pageWidth) 657 { 658 s = 3; 659 } 660 else if (b.width < 4 * pageWidth && b.height < 6 * pageWidth) 661 { 662 s = 2; 663 } 664 665 if (extras != null && extras.isGoogleSheet != null) 666 { 667 GOOGLE_APPS_MAX_AREA = GOOGLE_SHEET_MAX_AREA; 668 } 669 670 //The image cannot exceed 25 MP to be included in Google Apps 671 if (b.width * s * b.height * s > GOOGLE_APPS_MAX_AREA) 672 { 673 //Subtracting 0.01 to prevent any other rounding that can make slightly over 25 MP 674 s = Math.sqrt(GOOGLE_APPS_MAX_AREA / (b.width * b.height)) - 0.01; 675 } 676 } 677 678 graph.view.scaleAndTranslate(s, 679 Math.floor(data.border - Math.floor(b.x)), 680 Math.floor(data.border - Math.floor(b.y))); 681 } 682 } 683 else 684 { 685 // Disables border for PDF page export 686 data.border = 0; 687 688 // Moves to first page in page layout 689 var layout = graph.getPageLayout(); 690 var page = graph.getPageSize(); 691 var dx = layout.x * page.width; 692 var dy = layout.y * page.height; 693 694 if (dx != 0 || dy != 0) 695 { 696 graph.view.setTranslate(Math.floor(-dx), Math.floor(-dy)); 697 } 698 } 699 700 // Gets the diagram bounds and sets the document size 701 bounds = (graph.pdfPageVisible) ? graph.view.getBackgroundPageBounds() : graph.getGraphBounds(); 702 bounds.width = Math.ceil(bounds.width + data.border) + 1; //The 1 extra pixels to prevent cutting the cells on the edges when crop is enabled 703 bounds.height = Math.ceil(bounds.height + data.border) + 1; //The 1 extra pixels to prevent starting a new page. TODO Not working in every case 704 expScale = graph.view.scale || 1; 705 706 // Converts the graph to a vertical sequence of pages for PDF export 707 if (graph.pdfPageVisible) 708 { 709 var pf = graph.pageFormat || mxConstants.PAGE_FORMAT_A4_PORTRAIT; 710 var scale = data.print? data.scale : 1 / graph.pageScale; 711 var autoOrigin = (data.print && data.fit != null) ? data.fit : false; 712 var border = 0; 713 714 // Negative coordinates are cropped or shifted if page visible 715 var gb = graph.getGraphBounds(); 716 var x0 = 0; 717 var y0 = 0; 718 719 // Applies print scale 720 pf = mxRectangle.fromRectangle(pf); 721 pf.width = Math.ceil(pf.width * printScale) + 1; //The 1 extra pixels to prevent cutting the cells on the right edge of the page 722 pf.height = Math.ceil(pf.height * printScale) + 1; //The 1 extra pixels to prevent starting a new page. TODO Not working in every case 723 scale *= printScale; 724 725 // Starts at first visible page 726 if (!autoOrigin) 727 { 728 var layout = graph.getPageLayout(); 729 x0 -= layout.x * pf.width; 730 y0 -= layout.y * pf.height; 731 } 732 733 if (preview == null) 734 { 735 preview = new mxPrintPreview(graph, scale, pf, border, x0, y0); 736 preview.printBackgroundImage = true; 737 preview.autoOrigin = autoOrigin; 738 preview.backgroundColor = bg; 739 // Renders print output into this document and removes the graph container 740 preview.open(null, window); 741 graph.container.parentNode.removeChild(graph.container); 742 } 743 else 744 { 745 preview.backgroundColor = bg; 746 preview.autoOrigin = autoOrigin; 747 preview.appendGraph(graph, scale, x0, y0); 748 } 749 750 // Adds shadow 751 // NOTE: Shadow rasterizes output 752 /*if (mxClient.IS_SVG && xmlDoc.documentElement.getAttribute('shadow') == '1') 753 { 754 var svgs = document.getElementsByTagName('svg'); 755 756 for (var i = 0; i < svgs.length; i++) 757 { 758 var svg = svgs[i]; 759 760 var filter = graph.addSvgShadow(svg, null, true); 761 filter.setAttribute('id', 'shadow-' + i); 762 svg.appendChild(filter); 763 svg.setAttribute('filter', 'url(#' + 'shadow-' + i + ')'); 764 } 765 766 border = 7; 767 }*/ 768 769 bounds = new mxRectangle(0, 0, pf.width, pf.height); 770 } 771 else 772 { 773 var bgImg = graph.backgroundImage; 774 775 if (bgImg != null) 776 { 777 var t = graph.view.translate; 778 var s = graph.view.scale; 779 780 bounds.add(new mxRectangle( 781 (t.x + bgImg.x) * s, (t.y + bgImg.y) * s, 782 bgImg.width * s, bgImg.height * s)); 783 } 784 785 // Adds shadow 786 // NOTE: PDF shadow rasterizes output so it's disabled 787 if (data.format != 'pdf' && mxClient.IS_SVG && xmlDoc.documentElement.getAttribute('shadow') == '1') 788 { 789 graph.addSvgShadow(graph.view.canvas.ownerSVGElement, null, true); 790 graph.setShadowVisible(true); 791 bounds.width += 7; 792 bounds.height += 7; 793 } 794 795 document.body.style.width = Math.ceil(bounds.x + bounds.width) + 'px'; 796 document.body.style.height = Math.ceil(bounds.y + bounds.height) + 'px'; 797 } 798 }; 799 800 if (diagrams != null && diagrams.length > 0) 801 { 802 var to = diagrams.length - 1; 803 804 //Parameters to and all pages should not be sent with formats other than PDF with page view enabled 805 if (!data.allPages) 806 { 807 if (data.pageId != null) 808 { 809 for (var i = 0; i < diagrams.length; i++) 810 { 811 if (data.pageId == diagrams[i].getAttribute('id')) 812 { 813 from = i; 814 to = i; 815 break; 816 } 817 } 818 } 819 else 820 { 821 from = Math.max(0, Math.min(parseInt(data.from) || from, diagrams.length - 1)); 822 to = parseInt(data.to); 823 //If to is not defined, use from (so one page), otherwise, to is restricted to the range from "from" to diagrams.length - 1 824 to = isNaN(to)? from : Math.max(from, Math.min(to, diagrams.length - 1)); 825 } 826 } 827 828 /** 829 * Implements %page% and %pagenumber% placeholders 830 */ 831 var graphGetGlobalVariable = graph.getGlobalVariable; 832 833 graph.getGlobalVariable = function(name) 834 { 835 if (name == 'page') 836 { 837 return (diagrams == null) ? 'Page-1' : 838 (diagrams[from].getAttribute('name') || ('Page-' + (from + 1))); 839 } 840 else if (name == 'pagenumber') 841 { 842 return from + 1; 843 } 844 845 return graphGetGlobalVariable.apply(this, arguments); 846 }; 847 848 for (var i = from; i <= to; i++) 849 { 850 if (diagrams[i] != null) 851 { 852 if (pageId == null) 853 { 854 pageId = diagrams[i].getAttribute('id') 855 } 856 857 xmlDoc = Editor.parseDiagramNode(diagrams[i]); 858 859 if (xmlDoc != null) 860 { 861 xmlDoc = xmlDoc.ownerDocument; 862 } 863 864 graph.getModel().clear(); 865 from = i; 866 renderPage(); 867 } 868 } 869 } 870 else 871 { 872 renderPage(); 873 } 874 875 if (fallbackFont) 876 { 877 //Add a fallbackFont font to all labels in case the selected font doesn't support the character 878 //Some systems doesn't have a good fallback fomt that supports all languages 879 //Use this with a custom font-face in export-fonts.css file 880 document.querySelectorAll('foreignObject div').forEach(d => d.style.fontFamily = (d.style.fontFamily || '') + ', ' + fallbackFont); 881 } 882 883 renderGrid(); 884 // Includes images in SVG and HTML labels 885 waitForImages('image', 'xlink:href'); 886 waitForImages('img', 'src'); 887 renderMath(document.body); 888 // Immediate return if not waiting for any content 889 decrementWaitCounter(); 890 891 return graph; 892}; 893 894//Electron pdf export 895if (mxIsElectron) 896{ 897 try 898 { 899 const { ipcRenderer } = require('electron'); 900 901 ipcRenderer.on('render', (event, arg) => 902 { 903 render(arg); 904 }); 905 } 906 catch(e) 907 { 908 console.log(e); 909 } 910} 911