Skip to content

Commit a1331b7

Browse files
committed
Merge branch 'master' into open933
2 parents d1960b2 + e73bb4f commit a1331b7

File tree

10 files changed

+553
-100
lines changed

10 files changed

+553
-100
lines changed

bower.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
"FileSaver.js": "^0.0.2",
2121
"zepto": "^1.1.6",
2222
"eventemitter3": "^1.2.0",
23-
"d3": "~4.1.0"
23+
"d3": "~4.1.0",
24+
"html2canvas": "^0.4.1",
25+
"jspdf": "^1.2.61"
2426
}
2527
}

main.js

+8
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ requirejs.config({
2929
"csv": "bower_components/comma-separated-values/csv.min",
3030
"es6-promise": "bower_components/es6-promise/promise.min",
3131
"EventEmitter": "bower_components/eventemitter3/index",
32+
"html2canvas": "bower_components/html2canvas/build/html2canvas.min",
33+
"jsPDF": "bower_components/jspdf/dist/jspdf.min",
3234
"moment": "bower_components/moment/moment",
3335
"moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format",
3436
"saveAs": "bower_components/FileSaver.js/FileSaver.min",
@@ -45,6 +47,12 @@ requirejs.config({
4547
"angular-route": {
4648
"deps": ["angular"]
4749
},
50+
"html2canvas": {
51+
"exports": "html2canvas"
52+
},
53+
"jsPDF": {
54+
"exports": "jsPDF"
55+
},
4856
"EventEmitter": {
4957
"exports": "EventEmitter"
5058
},

platform/features/plot/bundle.js

+54
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ define([
2525
"./src/PlotController",
2626
"./src/policies/PlotViewPolicy",
2727
"./src/PlotOptionsController",
28+
"./src/services/ExportImageService",
2829
"text!./res/templates/plot.html",
2930
"text!./res/templates/plot-options-browse.html",
3031
'legacyRegistry'
@@ -33,6 +34,7 @@ define([
3334
PlotController,
3435
PlotViewPolicy,
3536
PlotOptionsController,
37+
exportImageService,
3638
plotTemplate,
3739
plotOptionsBrowseTemplate,
3840
legacyRegistry
@@ -70,6 +72,8 @@ define([
7072
"implementation": PlotController,
7173
"depends": [
7274
"$scope",
75+
"$element",
76+
"exportImageService",
7377
"telemetryFormatter",
7478
"telemetryHandler",
7579
"throttle",
@@ -84,12 +88,30 @@ define([
8488
]
8589
}
8690
],
91+
"services": [
92+
{
93+
"key": "exportImageService",
94+
"implementation": exportImageService,
95+
"depends": [
96+
"$q",
97+
"$timeout",
98+
"$log",
99+
"EXPORT_IMAGE_TIMEOUT"
100+
]
101+
102+
}
103+
],
87104
"constants": [
88105
{
89106
"key": "PLOT_FIXED_DURATION",
90107
"value": 900000,
91108
"priority": "fallback",
92109
"comment": "Fifteen minutes."
110+
},
111+
{
112+
"key": "EXPORT_IMAGE_TIMEOUT",
113+
"value": 500,
114+
"priority": "fallback"
93115
}
94116
],
95117
"policies": [
@@ -103,6 +125,38 @@ define([
103125
"key": "plot-options-browse",
104126
"template": plotOptionsBrowseTemplate
105127
}
128+
],
129+
"licenses": [
130+
{
131+
"name": "FileSaver.js",
132+
"version": "0.0.2",
133+
"author": "Eli Grey",
134+
"description": "File download initiator (for file exports)",
135+
"website": "https://github.com/eligrey/FileSaver.js/",
136+
"copyright": "Copyright © 2015 Eli Grey.",
137+
"license": "license-mit",
138+
"link": "https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md"
139+
},
140+
{
141+
"name": "html2canvas",
142+
"version": "0.4.1",
143+
"author": "Niklas von Hertzen",
144+
"description": "JavaScript HTML renderer",
145+
"website": "https://github.com/niklasvh/html2canvas",
146+
"copyright": "Copyright © 2012 Niklas von Hertzen.",
147+
"license": "license-mit",
148+
"link": "https://github.com/niklasvh/html2canvas/blob/master/LICENSE"
149+
},
150+
{
151+
"name": "jsPDF",
152+
"version": "1.2.61",
153+
"author": "James Hall",
154+
"description": "JavaScript HTML renderer",
155+
"website": "https://github.com/MrRio/jsPDF",
156+
"copyright": "Copyright © 2010-2016 James Hall",
157+
"license": "license-mit",
158+
"link": "https://github.com/MrRio/jsPDF/blob/master/MIT-LICENSE.txt"
159+
}
106160
]
107161
}
108162
});

platform/features/plot/res/templates/plot.html

+119-98
Original file line numberDiff line numberDiff line change
@@ -20,120 +20,141 @@
2020
at runtime from the About dialog for additional information.
2121
-->
2222
<span ng-controller="PlotController as plot"
23-
class="abs holder holder-plot">
24-
<div class="gl-plot"
25-
ng-style="{ height: 100 / plot.getSubPlots().length + '%'}"
26-
ng-repeat="subplot in plot.getSubPlots()">
27-
<div class="gl-plot-legend">
28-
<!-- ng-class is temporarily hard-coded in next element -->
23+
class="abs holder holder-plot has-control-bar">
24+
<div class="l-control-bar" ng-show="!plot.hideExportButtons">
25+
<span class="l-btn-set">
26+
<a class="s-button t-export icon-download labeled first"
27+
ng-click="plot.exportPDF()"
28+
title="Export This View's Data as PDF">
29+
PDF
30+
</a>
31+
<a class="s-button t-export labeled"
32+
ng-click="plot.exportPNG()"
33+
title="Export This View's Data as PNG">
34+
PNG
35+
</a>
36+
<a class="s-button t-export labeled last"
37+
ng-click="plot.exportJPG()"
38+
title="Export This View's Data as JPG">
39+
JPG
40+
</a>
41+
</span>
42+
</div>
43+
<div class="l-view-section">
44+
<div class="gl-plot"
45+
ng-style="{ height: 100 / plot.getSubPlots().length + '%'}"
46+
ng-repeat="subplot in plot.getSubPlots()">
47+
<div class="gl-plot-legend">
48+
<!-- ng-class is temporarily hard-coded in next element -->
2949
<span
30-
class='plot-legend-item'
31-
ng-repeat="telemetryObject in subplot.getTelemetryObjects()"
32-
ng-class="plot.getLegendClass(telemetryObject)">
50+
class='plot-legend-item'
51+
ng-repeat="telemetryObject in subplot.getTelemetryObjects()"
52+
ng-class="plot.getLegendClass(telemetryObject)">
3353
<span class='plot-color-swatch'
3454
ng-style="{ 'background-color': plot.getColor($index) }">
3555
</span>
3656
<span class='title-label'>{{telemetryObject.getModel().name}}</span>
3757
</span>
38-
</div>
39-
<div class="gl-plot-coords"
40-
ng-if="subplot.isHovering() && subplot.getHoverCoordinates()">
41-
{{subplot.getHoverCoordinates()}}
42-
</div>
43-
<div class="gl-plot-axis-area gl-plot-y">
44-
<div class="gl-plot-label gl-plot-y-label">
45-
{{axes[1].active.name}}
4658
</div>
47-
<div ng-repeat="tick in subplot.getRangeTicks()"
48-
class="gl-plot-tick gl-plot-y-tick-label"
49-
ng-style="{ bottom: (100 * $index / (subplot.getRangeTicks().length - 1)) + '%' }">
50-
{{tick.label | reverse}}
59+
<div class="gl-plot-coords"
60+
ng-if="subplot.isHovering() && subplot.getHoverCoordinates()">
61+
{{subplot.getHoverCoordinates()}}
5162
</div>
52-
<div class="gl-plot-y-options gl-plot-local-controls"
53-
ng-if="axes[1].options.length > 1">
54-
<div class='form-control shell select'>
55-
<select class="form-control input shell"
56-
ng-model="axes[1].active"
57-
ng-options="option.name for option in axes[1].options">
58-
</select>
63+
<div class="gl-plot-axis-area gl-plot-y">
64+
<div class="gl-plot-label gl-plot-y-label">
65+
{{axes[1].active.name}}
66+
</div>
67+
<div ng-repeat="tick in subplot.getRangeTicks()"
68+
class="gl-plot-tick gl-plot-y-tick-label"
69+
ng-style="{ bottom: (100 * $index / (subplot.getRangeTicks().length - 1)) + '%' }">
70+
{{tick.label | reverse}}
71+
</div>
72+
<div class="gl-plot-y-options gl-plot-local-controls"
73+
ng-if="axes[1].options.length > 1">
74+
<div class='form-control shell select'>
75+
<select class="form-control input shell"
76+
ng-model="axes[1].active"
77+
ng-options="option.name for option in axes[1].options">
78+
</select>
79+
</div>
5980
</div>
6081
</div>
61-
</div>
62-
<div class="gl-plot-display-area"
63-
ng-mouseenter="subplot.isHovering(true);"
64-
ng-mouseleave="subplot.isHovering(false)"
65-
ng-class="{ loading: plot.isRequestPending() }">
66-
<!-- Out-of-bounds data indicators -->
67-
<!-- ng-show is temporarily hard-coded in next element -->
68-
<div ng-show="false" class="l-oob-data l-oob-data-up"></div>
69-
<div ng-show="false" class="l-oob-data l-oob-data-dwn"></div>
70-
<div class="gl-plot-hash hash-v"
71-
ng-repeat="tick in subplot.getDomainTicks()"
72-
ng-style="{ left: (100 * $index / (subplot.getDomainTicks().length - 1)) + '%', height: '100%' }"
73-
ng-show="$index > 0 && $index < (subplot.getDomainTicks().length - 1)">
74-
</div>
75-
<div class="gl-plot-hash hash-h"
76-
ng-repeat="tick in subplot.getRangeTicks()"
77-
ng-style="{ bottom: (100 * $index / (subplot.getRangeTicks().length - 1)) + '%', width: '100%' }"
78-
ng-show="$index > 0 && $index < (subplot.getRangeTicks().length - 1)">
79-
</div>
80-
<mct-chart draw="subplot.getDrawingObject()"
81-
ng-if="subplot.getTelemetryObjects().length > 0"
82-
ng-mousemove="subplot.hover($event)"
83-
mct-drag="subplot.continueDrag($event)"
84-
mct-drag-down="subplot.startDrag($event)"
85-
mct-drag-up="subplot.endDrag($event); plot.update()">
86-
</mct-chart>
87-
<!-- TODO: Move into correct position; make part of group; infer from set of actions -->
88-
<div class="l-local-controls gl-plot-local-controls t-plot-display-controls"
89-
ng-if="$first">
90-
<a class="s-button icon-arrow-left"
91-
ng-click="plot.stepBackPanZoom()"
92-
ng-show="plot.isZoomed()"
93-
title="Restore previous pan/zoom">
94-
</a>
95-
<a class="s-button icon-arrows-out"
96-
ng-click="plot.unzoom()"
97-
ng-show="plot.isZoomed()"
98-
title="Reset pan/zoom">
99-
</a>
100-
<div class="menu-element s-menu-button menus-to-left {{plot.getMode().cssclass}}"
101-
ng-if="plot.getModeOptions().length > 1"
102-
ng-controller="ClickAwayController as toggle">
103-
<span class="l-click-area" ng-click="toggle.toggle()"></span>
104-
<span>{{plot.getMode().name}}</span>
105-
<div class="menu" ng-show="toggle.isActive()">
106-
<ul>
107-
<li ng-repeat="option in plot.getModeOptions()"
108-
ng-click="plot.setMode(option); toggle.setState(false)"
109-
class="{{option.cssclass}}">
82+
<div class="gl-plot-display-area"
83+
ng-mouseenter="subplot.isHovering(true);"
84+
ng-mouseleave="subplot.isHovering(false)"
85+
ng-class="{ loading: plot.isRequestPending() }">
86+
<!-- Out-of-bounds data indicators -->
87+
<!-- ng-show is temporarily hard-coded in next element -->
88+
<div ng-show="false" class="l-oob-data l-oob-data-up"></div>
89+
<div ng-show="false" class="l-oob-data l-oob-data-dwn"></div>
90+
<div class="gl-plot-hash hash-v"
91+
ng-repeat="tick in subplot.getDomainTicks()"
92+
ng-style="{ left: (100 * $index / (subplot.getDomainTicks().length - 1)) + '%', height: '100%' }"
93+
ng-show="$index > 0 && $index < (subplot.getDomainTicks().length - 1)">
94+
</div>
95+
<div class="gl-plot-hash hash-h"
96+
ng-repeat="tick in subplot.getRangeTicks()"
97+
ng-style="{ bottom: (100 * $index / (subplot.getRangeTicks().length - 1)) + '%', width: '100%' }"
98+
ng-show="$index > 0 && $index < (subplot.getRangeTicks().length - 1)">
99+
</div>
100+
<mct-chart draw="subplot.getDrawingObject()"
101+
ng-if="subplot.getTelemetryObjects().length > 0"
102+
ng-mousemove="subplot.hover($event)"
103+
mct-drag="subplot.continueDrag($event)"
104+
mct-drag-down="subplot.startDrag($event)"
105+
mct-drag-up="subplot.endDrag($event); plot.update()">
106+
</mct-chart>
107+
<!-- TODO: Move into correct position; make part of group; infer from set of actions -->
108+
<div class="l-local-controls gl-plot-local-controls t-plot-display-controls"
109+
ng-if="$first">
110+
<a class="s-button icon-arrow-left"
111+
ng-click="plot.stepBackPanZoom()"
112+
ng-show="plot.isZoomed()"
113+
title="Restore previous pan/zoom">
114+
</a>
115+
<a class="s-button icon-arrows-out"
116+
ng-click="plot.unzoom()"
117+
ng-show="plot.isZoomed()"
118+
title="Reset pan/zoom">
119+
</a>
120+
<div class="menu-element s-menu-button menus-to-left {{plot.getMode().cssclass}}"
121+
ng-if="plot.getModeOptions().length > 1"
122+
ng-controller="ClickAwayController as toggle">
123+
<span class="l-click-area" ng-click="toggle.toggle()"></span>
124+
<span>{{plot.getMode().name}}</span>
125+
<div class="menu" ng-show="toggle.isActive()">
126+
<ul>
127+
<li ng-repeat="option in plot.getModeOptions()"
128+
ng-click="plot.setMode(option); toggle.setState(false)"
129+
class="{{option.cssclass}}">
110130
{{option.name}}
111-
</li>
112-
</ul>
131+
</li>
132+
</ul>
133+
</div>
113134
</div>
114135
</div>
115136
</div>
116-
</div>
117-
<div ng-if="$last" class="gl-plot-axis-area gl-plot-x">
118-
<div ng-repeat="tick in subplot.getDomainTicks()"
119-
class="gl-plot-tick gl-plot-x-tick-label"
120-
ng-show="$index > 0 && $index < (subplot.getDomainTicks().length - 1)"
121-
ng-style="{ left: (100 * $index / (subplot.getDomainTicks().length - 1)) + '%' }">
122-
{{tick.label | reverse}}
123-
</div>
124-
<div class="gl-plot-label gl-plot-x-label">
125-
{{axes[0].active.name}}
126-
</div>
127-
<div class="gl-plot-x-options gl-plot-local-controls"
128-
ng-if="axes[0].options.length > 1">
129-
<div class='form-control shell select'>
130-
<select class="form-control input shell"
131-
ng-model="axes[0].active"
132-
ng-options="option.name for option in axes[0].options">
133-
</select>
137+
<div ng-if="$last" class="gl-plot-axis-area gl-plot-x">
138+
<div ng-repeat="tick in subplot.getDomainTicks()"
139+
class="gl-plot-tick gl-plot-x-tick-label"
140+
ng-show="$index > 0 && $index < (subplot.getDomainTicks().length - 1)"
141+
ng-style="{ left: (100 * $index / (subplot.getDomainTicks().length - 1)) + '%' }">
142+
{{tick.label | reverse}}
143+
</div>
144+
<div class="gl-plot-label gl-plot-x-label">
145+
{{axes[0].active.name}}
146+
</div>
147+
<div class="gl-plot-x-options gl-plot-local-controls"
148+
ng-if="axes[0].options.length > 1">
149+
<div class='form-control shell select'>
150+
<select class="form-control input shell"
151+
ng-model="axes[0].active"
152+
ng-options="option.name for option in axes[0].options">
153+
</select>
154+
</div>
134155
</div>
135-
</div>
136156

157+
</div>
137158
</div>
138159
</div>
139160
</span>

platform/features/plot/src/GLChart.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ define(
5454
* @throws {Error} an error is thrown if WebGL is unavailable.
5555
*/
5656
function GLChart(canvas) {
57-
var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"),
57+
var gl = canvas.getContext("webgl", { preserveDrawingBuffer: true }) ||
58+
canvas.getContext("experimental-webgl", { preserveDrawingBuffer: true }),
5859
vertexShader,
5960
fragmentShader,
6061
program,

0 commit comments

Comments
 (0)