From 975e919d2236ce00c3e5445abb0f4919bacd90eb Mon Sep 17 00:00:00 2001
From: Diego Rey <diego.despaux@izundo.com>
Date: Wed, 15 Aug 2018 20:08:49 -0300
Subject: [PATCH] Added export and center graph functionalities for graph2D
 Component

---
 Frontend Angular 4/package-lock.json          |   2 +-
 .../plotter/graph2D/graph2D.component.html    |   7 +-
 .../plotter/graph2D/graph2D.component.ts      | 124 +++++++++++++++---
 .../layout/plotter/graph2D/graph2D.helper.ts  |  44 +++----
 4 files changed, 132 insertions(+), 45 deletions(-)

diff --git a/Frontend Angular 4/package-lock.json b/Frontend Angular 4/package-lock.json
index 19ab35b2..bc975140 100644
--- a/Frontend Angular 4/package-lock.json	
+++ b/Frontend Angular 4/package-lock.json	
@@ -4139,7 +4139,7 @@
       "dev": true
     },
     "function-plot": {
-      "version": "git://github.com/diego-rey/function-plot.git#d8b7147168ab7a595f8323d28ffc944735117606",
+      "version": "git://github.com/diego-rey/function-plot.git#1543ff3b723285e0119c53a9bd3d37ab7e671ca9",
       "from": "git://github.com/diego-rey/function-plot.git#feature/integration-domain-shape",
       "requires": {
         "array-range": "^1.0.1",
diff --git a/Frontend Angular 4/src/app/layout/plotter/graph2D/graph2D.component.html b/Frontend Angular 4/src/app/layout/plotter/graph2D/graph2D.component.html
index 4cc1455a..b99d1328 100755
--- a/Frontend Angular 4/src/app/layout/plotter/graph2D/graph2D.component.html	
+++ b/Frontend Angular 4/src/app/layout/plotter/graph2D/graph2D.component.html	
@@ -2,7 +2,12 @@
     <div class="card-block contenedor-canvas" >
         <button ngbPopover="Zoom +"  triggers="mouseenter:mouseleave" data-placement="bottom" class="btn btn-sm btn-secondary" style="float:right; margin-right: 165px; margin-top: -55px" (click)=zoomIn() ><i class="fa fa-plus"></i></button>
         <button ngbPopover="Zoom -"  triggers="mouseenter:mouseleave" data-placement="bottom" class="btn btn-sm btn-secondary" style="float:right; margin-right: 132px; margin-top: -55px" (click)=zoomOut() ><i class="fa fa-minus"></i></button>
-        
+        <button ngbPopover="Centrar"  triggers="mouseenter:mouseleave" data-placement="bottom" class="btn btn-sm btn-secondary" style=" float:right; margin-right: 99px; margin-top: -55px" (click)="recenterPlot()" ><i class="fa fa-arrows"></i></button>
+		<button ngbPopover="Borrar"  triggers="mouseenter:mouseleave" data-placement="bottom" class="btn btn-sm btn-secondary" style=" float:right; margin-right: 66px; margin-top: -55px" (click)="cleanPlot()" ><i class="fa fa-trash"></i></button>
+
+		<button ngbPopover="Descargar PNG"  triggers="mouseenter:mouseleave" data-placement="bottom" class="btn btn-sm btn-secondary" style="float:right; margin-right: 33px; margin-top: -55px" (click)=exportPlot() ><i class="fa fa-download"></i></button>
+		<a id="download-plot" class="download-plot" href="#" download="Plot.svg" style="display: none">Download Canvas</a>
+
         <button class="btn btn-sm btn-secondary" data-placement="bottom" *ngIf="!animation.playing && animation.data.length>0" style=" float:left; margin-top: -5px; margin-right: 5px" (click)="runAnimation()" ><i class="fa fa-play"></i></button>
 		<button class="btn btn-sm btn-secondary" data-placement="bottom" *ngIf="animation.playing && animation.data.length>0" style=" float:left; margin-top: -5px; margin-right: 5px" (click)="pauseAnimation()" ><i class="fa fa-pause"></i></button>
 
diff --git a/Frontend Angular 4/src/app/layout/plotter/graph2D/graph2D.component.ts b/Frontend Angular 4/src/app/layout/plotter/graph2D/graph2D.component.ts
index 41f79f8c..4a48313e 100755
--- a/Frontend Angular 4/src/app/layout/plotter/graph2D/graph2D.component.ts	
+++ b/Frontend Angular 4/src/app/layout/plotter/graph2D/graph2D.component.ts	
@@ -1,7 +1,7 @@
 import { Component } from '@angular/core';
 import { GHCIService } from '../../../shared/services/ghci.service';
 import functionPlot from 'function-plot';
-import { Animation } from './graph2D.helper';
+import { Animation, toJSON, triggerDownload } from './graph2D.helper';
 
 @Component({
     moduleId: module.id,
@@ -99,10 +99,9 @@ export class Graph2DComponent {
                         break; 
                     }
                     case 'canvas': {
-                        console.log('TIPO', canvas.tipo);
-                        var shapesData = JSON.parse(canvas.resultado);
+                        var shapesData = JSON.parse(toJSON(canvas.resultado));
                         var shapesDataNormalized = this.normalizeShapesData(shapesData);
-    
+                        this.instance = null;
                         this.instance = functionPlot({
                             target: '#graph2D-container',
                             width: 800,
@@ -122,9 +121,7 @@ export class Graph2DComponent {
                         })
                         break; 
                     }
-                    case 'animacion': {
-                        console.log('TIPO', canvas.tipo);
-                        
+                    case 'animacion': {                        
                         if(!this.animation.init) {
                             this.animation.init = true;
                             var animationData = canvas.resultado.map(res => JSON.parse(res));
@@ -142,6 +139,42 @@ export class Graph2DComponent {
         )
     }
 
+    /**
+     * Angular lifecycle hook.
+     * called after Angular has fully initialized a component's view.
+     */
+    ngAfterViewInit() {
+        if (!this.instance) {
+            this.instance = functionPlot({
+                target: '#graph2D-container',
+                width: 800,
+                height: 700,
+                xAxis: {
+                    label: 'x - axis',
+                    scale: 'linear',
+                    domain: {
+                        initial: [-10, 10],
+                        type: 'discrete'
+                    }
+                },
+                data: [],
+                plugins: [
+                    functionPlot.plugins.zoomBox()
+                ]
+            })
+        }
+    }
+
+    /**
+     * Angular lifecycle hook.
+     * called when a directive, pipe, or service is destroyed.
+     */
+    ngOnDestroy() {
+        if (this.ghciServiceSub) {
+          this.ghciServiceSub.unsubscribe();
+        }
+    }
+
     /**
      * @name updateFrame
      * @desc update data for Function Plot and redraw the graph
@@ -170,7 +203,6 @@ export class Graph2DComponent {
             })
         }
     }
-
     /**
      * @name runAnimation
      * @desc Run Shapes Animation
@@ -209,6 +241,58 @@ export class Graph2DComponent {
     public zoomIn = function () {
         this.instance.zoomIn();
     }
+    /**
+     * @name recenterPlot
+     * @desc center the plot and it returns to the initial state.
+     */
+    public recenterPlot = function () {
+        this.instance.recenter();
+    }
+    /**
+     * @name cleanPlot
+     * @desc remove all the graph from the instance.
+     */
+    public cleanPlot = function () {
+    }
+
+    /**
+     * @name exportPlot
+     * @desc Download Plot as an SVG image.
+     */
+    public exportPlot = function() {
+        // Objects
+        var svg = document.querySelector('svg');
+        var canvas = document.createElement("canvas");
+
+        // Set dimensions of the image
+        var svgSize = svg.getBoundingClientRect();
+        canvas.width = svgSize.width;
+        canvas.height = svgSize.height;
+
+        // Convert SVG DOM structure to xml
+        var ctx = canvas.getContext('2d');
+        var data = new XMLSerializer().serializeToString(svg);
+
+        // URL Object used to parse, construct, normalise, and encode URLs.
+        var DOMURL = window.URL || (<any>window).webkitURL || window;
+
+        var img = new Image();
+        var svgBlob = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });
+        var url = DOMURL.createObjectURL(svgBlob);
+
+        img.onload = function () {
+            ctx.drawImage(img, 0, 0);
+            DOMURL.revokeObjectURL(url);
+
+            var imgURI = canvas
+                .toDataURL('image/png')
+                .replace('image/png', 'image/octet-stream');
+
+            triggerDownload(imgURI);
+        };
+        img.src = url;
+    }
+
 
     /**
      * @name normalizeRectData
@@ -275,10 +359,10 @@ export class Graph2DComponent {
     
         return $textNormalized;
     }
-        /**
-     * @name normalizeTextData
-     * @desc Normalize Text data for Function Plot Library 
-     * @param {Object} textData Data of Text to be normalized
+    /**
+     * @name normalizeLineData
+     * @desc Normalize Line data for Function Plot Library 
+     * @param {Object} lineData Data of Line to be normalized
      * @returns {Object}
      */
     // public normalizeLineData = function ($lineData) {
@@ -296,10 +380,10 @@ export class Graph2DComponent {
     
     //     return $lineNormalized;
     // }
-        /**
-     * @name normalizeTextData
-     * @desc Normalize Text data for Function Plot Library 
-     * @param {Object} textData Data of Text to be normalized
+    /**
+     * @name normalizePolygonData
+     * @desc Normalize Polygon data for Function Plot Library 
+     * @param {Object} textData Data of Polygon to be normalized
      * @returns {Object}
      */
     // public normalizePolygonData = function ($textData) {
@@ -354,6 +438,8 @@ export class Graph2DComponent {
         return normalized;
     }
 
+
+
     getRandomArbitrary = function (min, max) {
         return Math.round(Math.random() * (max - min) + min);
     }
@@ -571,11 +657,7 @@ export class Graph2DComponent {
         return funcionString;
     }
 
-    ngOnDestroy() {
-        if (this.ghciServiceSub) {
-          this.ghciServiceSub.unsubscribe();
-        }
-    }
+
 
 }
 
diff --git a/Frontend Angular 4/src/app/layout/plotter/graph2D/graph2D.helper.ts b/Frontend Angular 4/src/app/layout/plotter/graph2D/graph2D.helper.ts
index 18bd27ed..28b6f40a 100644
--- a/Frontend Angular 4/src/app/layout/plotter/graph2D/graph2D.helper.ts	
+++ b/Frontend Angular 4/src/app/layout/plotter/graph2D/graph2D.helper.ts	
@@ -7,27 +7,27 @@ export interface Animation {
 	init: boolean
 }
 
+export function toJSON(data: string) : string {
+	console.log('data',data);
+	const regexPts = /(?:\"pts\"\:\[(?:\((x),(y)\))+,?\])/g;
+	var dataJSON = data.replace(regexPts, (match, x, y) => {
+		return `"points": [[${x},${y}]]`
+	})
+	console.log('dataJSON', dataJSON);
+	return dataJSON;
+}
+
+export function triggerDownload(imgURI: string) {
+	var evt = new MouseEvent('click', {
+		view: window,
+		bubbles: false,
+		cancelable: true
+	});
 
-// export function toJSON(data: any) : string {
-// 	var $points = data.pts;
-// 	var $pointsJson = [];
-// 	for (var p of $points) {
-// 		$pointsJson.push([p[0],p[1]]);
-// 	}
-	
-// 	var dataJson = data;
-// 	dataJson.pts
-// }
+	var a = document.createElement('a');
+	a.setAttribute('download', 'Matefun_2D_plot.png');
+	a.setAttribute('href', imgURI);
+	a.setAttribute('target', '_blank');
 
-// 	return jsonString
-// 		.replace(
-// 			regexRot, (match, x, y, z) => {
-// 				return `"rot": { "x": ${x}, "y": ${y}, "z": ${z} }`
-// 			}
-// 		)
-// 		.replace(
-// 			regexPts, (match, x1, y1, z1, x2, y2, z2) => {
-// 				return `"pts": [{ "x": ${x1}, "y": ${y1}, "z": ${z1} },{ "x": ${x2}, "y": ${y2}, "z": ${z2} }]`
-// 			}
-// 		)
-// }
\ No newline at end of file
+	a.dispatchEvent(evt);
+}
\ No newline at end of file
-- 
GitLab