Add and Remove corresponding classes to capture higher contrast/print friendly png and jpg exports (#2088)

* add and remove corrensponding class to capture better images (wip)

* pass class through exportAsPng and exportAsJpg directly

* pass classname from stacked plots into exportImageService

* Adding additional export styles

Fixes #2088
- WIP

* WIP export styles

Fixes #2080
- Styling WIP;
- Moved styles into plots-main.scss;
- Change to how plot hashes are rendered;

* add class before clone, because adding it on clone was not rendering new css styles

* Export styles

Fixes #2080
- Code indenting cleaned up;
- Additional styles for export;
- Added hide effects for .h-local-controls and unsynced state;

* Apply class to cloned element only
This commit is contained in:
Deep Tailor 2018-07-20 15:17:10 -07:00 committed by Pete Richards
parent d2c5476cdd
commit 9288880e47
6 changed files with 256 additions and 180 deletions

View File

@ -33,8 +33,8 @@
display: flex; display: flex;
flex-flow: column nowrap; flex-flow: column nowrap;
.gl-plot.child-frame { .gl-plot.child-frame {
mct-plot { mct-plot {
display: flex; display: flex;
flex: 1 1 auto; flex: 1 1 auto;
height: 100%; height: 100%;
position: relative; position: relative;
@ -51,18 +51,15 @@
display: block; display: block;
} }
} }
} }
.gl-plot { .gl-plot {
color: $colorPlotFg; color: $colorPlotFg;
display: flex; display: flex;
font-size: 0.7rem; font-size: 0.7rem;
position: relative; position: relative;
width: 100%; width: 100%;
height: 100%; height: 100%;
min-height: $plotMinH; min-height: $plotMinH;
/********************************************* AXIS AND DISPLAY AREA */ /********************************************* AXIS AND DISPLAY AREA */
@ -74,7 +71,8 @@
position: absolute; position: absolute;
display: block; display: block;
font-size: 1.5em; font-size: 1.5em;
top: $interiorMarginSm; left: $interiorMarginSm; top: $interiorMarginSm;
left: $interiorMarginSm;
} }
} }
@ -105,71 +103,71 @@
} }
} }
.gl-plot-axis-area { .gl-plot-axis-area {
position: absolute; position: absolute;
&.gl-plot-y { &.gl-plot-y {
top: nth($plotDisplayArea, 1); top: nth($plotDisplayArea, 1);
right: auto; right: auto;
bottom: nth($plotDisplayArea, 3); bottom: nth($plotDisplayArea, 3);
left: 0; left: 0;
width: $plotYBarW; width: $plotYBarW;
} }
} }
.gl-plot-coords { .gl-plot-coords {
box-sizing: border-box; box-sizing: border-box;
border-radius: $controlCr; border-radius: $controlCr;
background: black; background: black;
color: lighten($colorBodyFg, 30%); color: lighten($colorBodyFg, 30%);
padding: 2px 5px; padding: 2px 5px;
position: absolute; position: absolute;
top: nth($plotDisplayArea,1) + $interiorMarginLg; top: nth($plotDisplayArea,1) + $interiorMarginLg;
right: auto; right: auto;
bottom: auto; bottom: auto;
left: nth($plotDisplayArea,4) + $interiorMarginLg; left: nth($plotDisplayArea,4) + $interiorMarginLg;
z-index: 10; z-index: 10;
&:empty { &:empty {
display: none; display: none;
} }
} }
.gl-plot-label, .gl-plot-label,
.l-plot-label { .l-plot-label {
color: $colorPlotLabelFg; color: $colorPlotLabelFg;
position: absolute; position: absolute;
text-align: center; text-align: center;
&.gl-plot-x-label, &.gl-plot-x-label,
&.l-plot-x-label { &.l-plot-x-label {
top: auto; top: auto;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
height: auto; height: auto;
} }
&.gl-plot-y-label, &.gl-plot-y-label,
&.l-plot-y-label { &.l-plot-y-label {
$x: -50%; $x: -50%;
$r: -90deg; $r: -90deg;
transform-origin: 50% 0; transform-origin: 50% 0;
transform: translateX($x) rotate($r); transform: translateX($x) rotate($r);
display: inline-block; display: inline-block;
margin-left: $interiorMargin; // Kick off the left edge margin-left: $interiorMargin; // Kick off the left edge
left: 0; left: 0;
top: 50%; top: 50%;
white-space: nowrap; white-space: nowrap;
} }
} }
.gl-plot-x-options, .gl-plot-x-options,
.gl-plot-y-options { .gl-plot-y-options {
$h: 24px; $h: 24px;
position: absolute; position: absolute;
height: $h; height: $h;
min-height: $h; min-height: $h;
z-index: 2; z-index: 2;
} }
.gl-plot-x-options { .gl-plot-x-options {
transform: translateX(-50%); transform: translateX(-50%);
@ -190,119 +188,192 @@
right: $interiorMargin; right: $interiorMargin;
} }
.gl-plot-hash { .gl-plot-hash {
position: absolute; position: absolute;
border: 0 $colorPlotHash $stylePlotHash; opacity: $opacityPlotHash;
&.hash-v { &.hash-v {
border-right-width: 1px; border-right: 1px $colorPlotHash $stylePlotHash;
height: 100%; height: 100%;
} }
&.hash-h { &.hash-h {
border-bottom-width: 1px; border-bottom: 1px $colorPlotHash $stylePlotHash;
width: 100%; width: 100%;
} }
} }
/****************************** Limits and Out-of-Bounds data */ /****************************** Limits and Out-of-Bounds data */
.l-limit-bar, .l-limit-bar,
.l-oob-data { .l-oob-data {
position: absolute; position: absolute;
left: 0; left: 0;
right: 0; right: 0;
width: auto; width: auto;
} }
.l-limit-bar { .l-limit-bar {
// Limits in plot display area // Limits in plot display area
@mixin limitBg($c) { @mixin limitBg($c) {
background: rgba($c, 0.2); background: rgba($c, 0.2);
} }
height: auto; height: auto;
z-index: 0; z-index: 0;
&.s-limit-yellow { @include limitBg($colorLimitYellowBg); } &.s-limit-yellow {
&.s-limit-red { @include limitBg($colorLimitRedBg); } @include limitBg($colorLimitYellowBg);
} }
&.s-limit-red {
@include limitBg($colorLimitRedBg);
}
}
.l-oob-data { .l-oob-data {
$c: #7748d6; $c: #7748d6;
$a: 0.5; $a: 0.5;
$h: 10px; $h: 10px;
@include absPosDefault(); @include absPosDefault();
pointer-events: none; pointer-events: none;
height: $h; height: $h;
z-index: 1; z-index: 1;
&.l-oob-data-up { &.l-oob-data-up {
top: 0; top: 0;
bottom: auto; bottom: auto;
@include linearGlow(0deg, $c, $a); @include linearGlow(0deg, $c, $a);
} }
&.l-oob-data-dwn { &.l-oob-data-dwn {
bottom: 0; bottom: 0;
top: auto; top: auto;
@include linearGlow(180deg, $c, $a); @include linearGlow(180deg, $c, $a);
} }
} }
} }
.gl-plot-display-area, .gl-plot-display-area,
.plot-display-area { .plot-display-area {
@if $colorPlotBg != none { background-color: $colorPlotBg; } @if $colorPlotBg != none {
background-color: $colorPlotBg;
}
cursor: crosshair; cursor: crosshair;
border: 1px solid $colorPlotAreaBorder; border: 1px solid $colorPlotAreaBorder;
} }
.tick { .tick {
position: absolute; position: absolute;
border: 0 $colorPlotHash solid; border: 0 $colorPlotHash solid;
&.tick-x { &.tick-x {
border-right-width: 1px; border-right-width: 1px;
height: 100%; // Assumption is that the tick will be in a holder that will set it's height; height: 100%; // Assumption is that the tick will be in a holder that will set it's height;
} }
} }
.gl-plot-tick, .gl-plot-tick,
.tick-label { .tick-label {
@include reverseEllipsis(); @include reverseEllipsis();
font-size: 0.7rem; font-size: 0.7rem;
position: absolute; position: absolute;
&.gl-plot-x-tick-label, &.gl-plot-x-tick-label,
&.tick-label-x { &.tick-label-x {
right: auto; right: auto;
bottom: auto; bottom: auto;
left: auto; left: auto;
height: auto; height: auto;
width: 20%; width: 20%;
margin-left: -10%; margin-left: -10%;
text-align: center; text-align: center;
} }
&.gl-plot-y-tick-label, &.gl-plot-y-tick-label,
&.tick-label-y { &.tick-label-y {
top: auto; top: auto;
height: 1em; height: 1em;
width: auto; width: auto;
margin-bottom: -0.5em; margin-bottom: -0.5em;
text-align: right; text-align: right;
} }
} }
.gl-plot-tick { .gl-plot-tick {
&.gl-plot-x-tick-label { &.gl-plot-x-tick-label {
top: $interiorMargin; top: $interiorMargin;
} }
&.gl-plot-y-tick-label { &.gl-plot-y-tick-label {
right: $interiorMargin; right: $interiorMargin;
left: $interiorMargin; left: $interiorMargin;
} }
} }
.tick-label { .tick-label {
&.tick-label-x { &.tick-label-x {
top: 0; top: 0;
} }
&.tick-label-y { &.tick-label-y {
right: 0; left: 0; right: 0;
} left: 0;
}
}
.export-plot {
$bg: white;
$fg: black;
$gry: #999;
background: $bg !important;
z-index: -10;
.l-view-section {
$m: $interiorMargin;
top: $m !important;
right: $m;
bottom: $m;
left: $m;
.s-status-timeconductor-unsynced .holder-plot {
.t-object-alert.t-alert-unsynced {
display: none;
}
}
}
.gl-plot-display-area {
background: none !important;
border-color: $gry !important;
.gl-plot-local-controls,
.h-local-controls {
opacity: 0;
}
}
.gl-plot {
color: $fg;
.gl-plot-hash {
opacity: 0.1;
border-color: $fg;
}
}
table {
thead {
border-bottom: none;
th {
background: #eee;
border-left-color: $bg;
color: #666;
}
tr {
border: none;
}
}
tbody {
tr {
border-top: 1px solid #ccc;
}
td {
color: $fg;
}
}
}
} }

View File

@ -183,7 +183,8 @@ $colorTabHeaderBorder: $colorBodyBg;
// Plot // Plot
$colorPlotBg: rgba(black, 0.1); $colorPlotBg: rgba(black, 0.1);
$colorPlotFg: $colorBodyFg; $colorPlotFg: $colorBodyFg;
$colorPlotHash: $colorTick; $colorPlotHash: white;
$opacityPlotHash: 0.2;
$stylePlotHash: dashed; $stylePlotHash: dashed;
$colorPlotAreaBorder: $colorInteriorBorder; $colorPlotAreaBorder: $colorInteriorBorder;
$colorPlotLabelFg: pushBack($colorPlotFg, 20%); $colorPlotLabelFg: pushBack($colorPlotFg, 20%);

View File

@ -183,7 +183,8 @@ $colorTabHeaderBorder: $colorBodyBg;
// Plot // Plot
$colorPlotBg: rgba(black, 0.05); $colorPlotBg: rgba(black, 0.05);
$colorPlotFg: $colorBodyFg; $colorPlotFg: $colorBodyFg;
$colorPlotHash: $colorTick; $colorPlotHash: black;
$opacityPlotHash: 0.2;
$stylePlotHash: dashed; $stylePlotHash: dashed;
$colorPlotAreaBorder: $colorInteriorBorder; $colorPlotAreaBorder: $colorInteriorBorder;
$colorPlotLabelFg: pushBack($colorPlotFg, 20%); $colorPlotLabelFg: pushBack($colorPlotFg, 20%);

View File

@ -40,8 +40,8 @@ define(
* @constructor * @constructor
*/ */
function ExportImageService(dialogService) { function ExportImageService(dialogService) {
this.exportCount = 0;
this.dialogService = dialogService; this.dialogService = dialogService;
this.exportCount = 0;
} }
/** /**
@ -51,7 +51,8 @@ define(
* @param {string} type of image to convert the element to. * @param {string} type of image to convert the element to.
* @returns {promise} * @returns {promise}
*/ */
ExportImageService.prototype.renderElement = function (element, imageType, color) { ExportImageService.prototype.renderElement = function (element, imageType, className) {
var dialogService = this.dialogService, var dialogService = this.dialogService,
dialog = dialogService.showBlockingMessage({ dialog = dialogService.showBlockingMessage({
title: "Capturing...", title: "Capturing...",
@ -66,18 +67,18 @@ define(
mimeType = "image/jpeg"; mimeType = "image/jpeg";
} }
var exportId = 'export-element-' + this.exportCount; if (className) {
this.exportCount++; var exportId = 'export-element-' + this.exportCount;
var oldId = element.id; this.exportCount++;
element.id = exportId; var oldId = element.id;
element.id = exportId;
}
return html2canvas(element, { return html2canvas(element, {
onclone: function (document) { onclone: function (document) {
// Make export style changes to cloned document so that if (className) {
// users don't see view flickering. var clonedElement = document.getElementById(exportId);
var clonedElement = document.getElementById(exportId); clonedElement.classList.add(className);
if (clonedElement && color) {
clonedElement.style.backgroundColor = color;
} }
element.id = oldId; element.id = oldId;
} }
@ -107,10 +108,11 @@ define(
* Takes a screenshot of a DOM node and exports to JPG. * Takes a screenshot of a DOM node and exports to JPG.
* @param {node} element to be exported * @param {node} element to be exported
* @param {string} filename the exported image * @param {string} filename the exported image
* @param {string} className to be added to element before capturing (optional)
* @returns {promise} * @returns {promise}
*/ */
ExportImageService.prototype.exportJPG = function (element, filename, color) { ExportImageService.prototype.exportJPG = function (element, filename, className) {
return this.renderElement(element, "jpg", color).then(function (img) { return this.renderElement(element, "jpg", className).then(function (img) {
saveAs(img, filename); saveAs(img, filename);
}); });
}; };
@ -119,10 +121,11 @@ define(
* Takes a screenshot of a DOM node and exports to PNG. * Takes a screenshot of a DOM node and exports to PNG.
* @param {node} element to be exported * @param {node} element to be exported
* @param {string} filename the exported image * @param {string} filename the exported image
* @param {string} className to be added to element before capturing (optional)
* @returns {promise} * @returns {promise}
*/ */
ExportImageService.prototype.exportPNG = function (element, filename, color) { ExportImageService.prototype.exportPNG = function (element, filename, className) {
return this.renderElement(element, "png", color).then(function (img) { return this.renderElement(element, "png", className).then(function (img) {
saveAs(img, filename); saveAs(img, filename);
}); });
}; };

View File

@ -245,7 +245,7 @@ define([
*/ */
PlotController.prototype.exportJPG = function () { PlotController.prototype.exportJPG = function () {
this.hideExportButtons = true; this.hideExportButtons = true;
this.exportImageService.exportJPG(this.$element[0], 'plot.jpg', 'white') this.exportImageService.exportJPG(this.$element[0], 'plot.jpg', 'export-plot')
.finally(function () { .finally(function () {
this.hideExportButtons = false; this.hideExportButtons = false;
}.bind(this)); }.bind(this));
@ -256,7 +256,7 @@ define([
*/ */
PlotController.prototype.exportPNG = function () { PlotController.prototype.exportPNG = function () {
this.hideExportButtons = true; this.hideExportButtons = true;
this.exportImageService.exportPNG(this.$element[0], 'plot.png', 'white') this.exportImageService.exportPNG(this.$element[0], 'plot.png', 'export-plot')
.finally(function () { .finally(function () {
this.hideExportButtons = false; this.hideExportButtons = false;
}.bind(this)); }.bind(this));

View File

@ -142,7 +142,7 @@ define([
StackedPlotController.prototype.exportJPG = function () { StackedPlotController.prototype.exportJPG = function () {
this.hideExportButtons = true; this.hideExportButtons = true;
this.exportImageService.exportJPG(this.$element[0], 'stacked-plot.jpg') this.exportImageService.exportJPG(this.$element[0], 'stacked-plot.jpg', 'export-plot')
.finally(function () { .finally(function () {
this.hideExportButtons = false; this.hideExportButtons = false;
}.bind(this)); }.bind(this));
@ -150,7 +150,7 @@ define([
StackedPlotController.prototype.exportPNG = function () { StackedPlotController.prototype.exportPNG = function () {
this.hideExportButtons = true; this.hideExportButtons = true;
this.exportImageService.exportPNG(this.$element[0], 'stacked-plot.png') this.exportImageService.exportPNG(this.$element[0], 'stacked-plot.png', 'export-plot')
.finally(function () { .finally(function () {
this.hideExportButtons = false; this.hideExportButtons = false;
}.bind(this)); }.bind(this));