Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nasa/openmct.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Bell <scott@scottbell.name>2021-07-30 08:05:18 +0300
committerGitHub <noreply@github.com>2021-07-30 08:05:18 +0300
commit5c15e53abbed3d1ce2a87660d4147de07eca7ced (patch)
tree8f67a92f15f7258c69c9c39af243ff7aded8fd96
parentf58b3881f2789e8973cf8999757986798acc726b (diff)
Mct4039 (#4057)vista-r4.8.0-rc1
Re-implements ImageExportService as ES6 class instead of Angular managed service. Co-authored-by: John Hill <jchill2.spam@gmail.com> Co-authored-by: Andrew Henry <akhenry@gmail.com>
-rw-r--r--src/adapter/bundle.js13
-rw-r--r--src/adapter/services/ExportImageService.js218
-rw-r--r--src/exporters/ImageExporter.js185
-rw-r--r--src/exporters/ImageExporterSpec.js58
-rw-r--r--src/plugins/notebook/components/NotebookEmbed.vue7
-rw-r--r--src/plugins/notebook/snapshot.js6
-rw-r--r--src/plugins/plot/Plot.vue12
-rw-r--r--src/plugins/plot/pluginSpec.js8
-rw-r--r--src/plugins/plot/stackedPlot/StackedPlot.vue15
-rw-r--r--src/plugins/viewDatumAction/pluginSpec.js2
10 files changed, 265 insertions, 259 deletions
diff --git a/src/adapter/bundle.js b/src/adapter/bundle.js
index 894e8df91..0fc7c2d11 100644
--- a/src/adapter/bundle.js
+++ b/src/adapter/bundle.js
@@ -36,8 +36,7 @@ define([
'./views/installLegacyViews',
'./policies/LegacyCompositionPolicyAdapter',
'./actions/LegacyActionAdapter',
- './services/LegacyPersistenceAdapter',
- './services/ExportImageService'
+ './services/LegacyPersistenceAdapter'
], function (
ActionDialogDecorator,
AdapterCapability,
@@ -54,8 +53,7 @@ define([
installLegacyViews,
legacyCompositionPolicyAdapter,
LegacyActionAdapter,
- LegacyPersistenceAdapter,
- ExportImageService
+ LegacyPersistenceAdapter
) {
return {
name: 'src/adapter',
@@ -84,13 +82,6 @@ define([
"identifierService",
"cacheService"
]
- },
- {
- "key": "exportImageService",
- "implementation": ExportImageService,
- "depends": [
- "dialogService"
- ]
}
],
components: [
diff --git a/src/adapter/services/ExportImageService.js b/src/adapter/services/ExportImageService.js
deleted file mode 100644
index 014e4a911..000000000
--- a/src/adapter/services/ExportImageService.js
+++ /dev/null
@@ -1,218 +0,0 @@
-/*****************************************************************************
- * Open MCT, Copyright (c) 2014-2021, United States Government
- * as represented by the Administrator of the National Aeronautics and Space
- * Administration. All rights reserved.
- *
- * Open MCT is licensed under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- * Open MCT includes source code licensed under additional open source
- * licenses. See the Open Source Licenses file (LICENSES.md) included with
- * this source code distribution or the Licensing information page available
- * at runtime from the About dialog for additional information.
- *****************************************************************************/
-
-/**
- * Module defining ExportImageService. Created by hudsonfoo on 09/02/16
- */
-define(
- [
- "html2canvas",
- "saveAs"
- ],
- function (
- html2canvas,
- { saveAs }
- ) {
-
- /**
- * The export image service will export any HTML node to
- * JPG, or PNG.
- * @param {object} dialogService
- * @constructor
- */
- function ExportImageService(dialogService) {
- this.dialogService = dialogService;
- this.exportCount = 0;
- }
-
- /**
- * Converts an HTML element into a PNG or JPG Blob.
- * @private
- * @param {node} element that will be converted to an image
- * @param {object} options Image options.
- * @returns {promise}
- */
- ExportImageService.prototype.renderElement = function (element, {imageType, className, thumbnailSize}) {
- const self = this;
- const dialogService = this.dialogService;
- const dialog = dialogService.showBlockingMessage({
- title: "Capturing...",
- hint: "Capturing an image",
- unknownProgress: true,
- severity: "info",
- delay: true
- });
-
- let mimeType = "image/png";
- if (imageType === "jpg") {
- mimeType = "image/jpeg";
- }
-
- let exportId = undefined;
- let oldId = undefined;
- if (className) {
- exportId = 'export-element-' + this.exportCount;
- this.exportCount++;
- oldId = element.id;
- element.id = exportId;
- }
-
- return html2canvas(element, {
- onclone: function (document) {
- if (className) {
- const clonedElement = document.getElementById(exportId);
- clonedElement.classList.add(className);
- }
-
- element.id = oldId;
- },
- removeContainer: true // Set to false to debug what html2canvas renders
- }).then(function (canvas) {
- dialog.dismiss();
-
- return new Promise(function (resolve, reject) {
- if (thumbnailSize) {
- const thumbnail = self.getThumbnail(canvas, mimeType, thumbnailSize);
-
- return canvas.toBlob(blob => resolve({
- blob,
- thumbnail
- }), mimeType);
- }
-
- return canvas.toBlob(blob => resolve({ blob }), mimeType);
- });
- }, function (error) {
- console.log('error capturing image', error);
- dialog.dismiss();
- const errorDialog = dialogService.showBlockingMessage({
- title: "Error capturing image",
- severity: "error",
- hint: "Image was not captured successfully!",
- options: [{
- label: "OK",
- callback: function () {
- errorDialog.dismiss();
- }
- }]
- });
- });
- };
-
- ExportImageService.prototype.getThumbnail = function (canvas, mimeType, size) {
- const thumbnailCanvas = document.createElement('canvas');
- thumbnailCanvas.setAttribute('width', size.width);
- thumbnailCanvas.setAttribute('height', size.height);
- const ctx = thumbnailCanvas.getContext('2d');
- ctx.globalCompositeOperation = "copy";
- ctx.drawImage(canvas, 0, 0, canvas.width, canvas.height, 0, 0, size.width, size.height);
-
- return thumbnailCanvas.toDataURL(mimeType);
- };
-
- /**
- * Takes a screenshot of a DOM node and exports to JPG.
- * @param {node} element to be exported
- * @param {string} filename the exported image
- * @param {string} className to be added to element before capturing (optional)
- * @returns {promise}
- */
- ExportImageService.prototype.exportJPG = function (element, filename, className) {
- const processedFilename = replaceDotsWithUnderscores(filename);
-
- return this.renderElement(element, {
- imageType: 'jpg',
- className
- })
- .then(function (img) {
- saveAs(img.blob, processedFilename);
- });
- };
-
- /**
- * Takes a screenshot of a DOM node and exports to PNG.
- * @param {node} element to be exported
- * @param {string} filename the exported image
- * @param {string} className to be added to element before capturing (optional)
- * @returns {promise}
- */
- ExportImageService.prototype.exportPNG = function (element, filename, className) {
- const processedFilename = replaceDotsWithUnderscores(filename);
-
- return this.renderElement(element, {
- imageType: 'png',
- className
- })
- .then(function (img) {
- saveAs(img.blob, processedFilename);
- });
- };
-
- /**
- * Takes a screenshot of a DOM node in PNG format.
- * @param {node} element to be exported
- * @param {string} filename the exported image
- * @returns {promise}
- */
-
- ExportImageService.prototype.exportPNGtoSRC = function (element, options) {
-
- return this.renderElement(element, {
- imageType: 'png',
- ...options
- });
- };
-
- function replaceDotsWithUnderscores(filename) {
- const regex = /\./gi;
-
- return filename.replace(regex, '_');
- }
-
- /**
- * canvas.toBlob() not supported in IE < 10, Opera, and Safari. This polyfill
- * implements the method in browsers that would not otherwise support it.
- * https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob
- */
- function polyfillToBlob() {
- if (!HTMLCanvasElement.prototype.toBlob) {
- Object.defineProperty(HTMLCanvasElement.prototype, "toBlob", {
- value: function (callback, mimeType, quality) {
- const binStr = atob(this.toDataURL(mimeType, quality).split(',')[1]);
- const len = binStr.length;
- const arr = new Uint8Array(len);
-
- for (let i = 0; i < len; i++) {
- arr[i] = binStr.charCodeAt(i);
- }
-
- callback(new Blob([arr], {type: mimeType || "image/png"}));
- }
- });
- }
- }
-
- polyfillToBlob();
-
- return ExportImageService;
- }
-);
diff --git a/src/exporters/ImageExporter.js b/src/exporters/ImageExporter.js
new file mode 100644
index 000000000..1fea59e16
--- /dev/null
+++ b/src/exporters/ImageExporter.js
@@ -0,0 +1,185 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2021, United States Government
+ * as represented by the Administrator of the National Aeronautics and Space
+ * Administration. All rights reserved.
+ *
+ * Open MCT is licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * Open MCT includes source code licensed under additional open source
+ * licenses. See the Open Source Licenses file (LICENSES.md) included with
+ * this source code distribution or the Licensing information page available
+ * at runtime from the About dialog for additional information.
+ *****************************************************************************/
+
+/**
+ * Class defining an image exporter for JPG/PNG output.
+ * Originally created by hudsonfoo on 09/02/16
+ */
+
+function replaceDotsWithUnderscores(filename) {
+ const regex = /\./gi;
+
+ return filename.replace(regex, '_');
+}
+
+import {saveAs} from 'file-saver/FileSaver';
+import html2canvas from 'html2canvas';
+import uuid from 'uuid';
+
+class ImageExporter {
+ constructor(openmct) {
+ this.openmct = openmct;
+ }
+ /**
+ * Converts an HTML element into a PNG or JPG Blob.
+ * @private
+ * @param {node} element that will be converted to an image
+ * @param {object} options Image options.
+ * @returns {promise}
+ */
+ renderElement(element, { imageType, className, thumbnailSize }) {
+ const self = this;
+ const overlays = this.openmct.overlays;
+ const dialog = overlays.dialog({
+ iconClass: 'info',
+ message: 'Caputuring an image',
+ buttons: [
+ {
+ label: 'Cancel',
+ emphasis: true,
+ callback: function () {
+ dialog.dismiss();
+ }
+ }
+ ]
+ });
+
+ let mimeType = 'image/png';
+ if (imageType === 'jpg') {
+ mimeType = 'image/jpeg';
+ }
+
+ let exportId = undefined;
+ let oldId = undefined;
+ if (className) {
+ const newUUID = uuid();
+ exportId = `$export-element-${newUUID}`;
+ oldId = element.id;
+ element.id = exportId;
+ }
+
+ return html2canvas(element, {
+ onclone: function (document) {
+ if (className) {
+ const clonedElement = document.getElementById(exportId);
+ clonedElement.classList.add(className);
+ }
+
+ element.id = oldId;
+ },
+ removeContainer: true // Set to false to debug what html2canvas renders
+ }).then(function (canvas) {
+ dialog.dismiss();
+
+ return new Promise(function (resolve, reject) {
+ if (thumbnailSize) {
+ const thumbnail = self.getThumbnail(canvas, mimeType, thumbnailSize);
+
+ return canvas.toBlob(blob => resolve({
+ blob,
+ thumbnail
+ }), mimeType);
+ }
+
+ return canvas.toBlob(blob => resolve({ blob }), mimeType);
+ });
+ }, function (error) {
+ console.log('error capturing image', error);
+ dialog.dismiss();
+ const errorDialog = overlays.dialog({
+ iconClass: 'error',
+ message: 'Image was not captured successfully!',
+ buttons: [
+ {
+ label: "OK",
+ emphasis: true,
+ callback: function () {
+ errorDialog.dismiss();
+ }
+ }
+ ]
+ });
+ });
+ }
+
+ getThumbnail(canvas, mimeType, size) {
+ const thumbnailCanvas = document.createElement('canvas');
+ thumbnailCanvas.setAttribute('width', size.width);
+ thumbnailCanvas.setAttribute('height', size.height);
+ const ctx = thumbnailCanvas.getContext('2d');
+ ctx.globalCompositeOperation = "copy";
+ ctx.drawImage(canvas, 0, 0, canvas.width, canvas.height, 0, 0, size.width, size.height);
+
+ return thumbnailCanvas.toDataURL(mimeType);
+ }
+
+ /**
+ * Takes a screenshot of a DOM node and exports to JPG.
+ * @param {node} element to be exported
+ * @param {string} filename the exported image
+ * @param {string} className to be added to element before capturing (optional)
+ * @returns {promise}
+ */
+ async exportJPG(element, filename, className) {
+ const processedFilename = replaceDotsWithUnderscores(filename);
+
+ const img = await this.renderElement(element, {
+ imageType: 'jpg',
+ className
+ });
+ saveAs(img.blob, processedFilename);
+ }
+
+ /**
+ * Takes a screenshot of a DOM node and exports to PNG.
+ * @param {node} element to be exported
+ * @param {string} filename the exported image
+ * @param {string} className to be added to element before capturing (optional)
+ * @returns {promise}
+ */
+ async exportPNG(element, filename, className) {
+ const processedFilename = replaceDotsWithUnderscores(filename);
+
+ const img = await this.renderElement(element, {
+ imageType: 'png',
+ className
+ });
+ saveAs(img.blob, processedFilename);
+ }
+
+ /**
+ * Takes a screenshot of a DOM node in PNG format.
+ * @param {node} element to be exported
+ * @param {string} filename the exported image
+ * @returns {promise}
+ */
+
+ exportPNGtoSRC(element, options) {
+ return this.renderElement(element, {
+ imageType: 'png',
+ ...options
+ });
+ }
+}
+
+export default ImageExporter;
+
diff --git a/src/exporters/ImageExporterSpec.js b/src/exporters/ImageExporterSpec.js
new file mode 100644
index 000000000..bb00cfd4a
--- /dev/null
+++ b/src/exporters/ImageExporterSpec.js
@@ -0,0 +1,58 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2021, United States Government
+ * as represented by the Administrator of the National Aeronautics and Space
+ * Administration. All rights reserved.
+ *
+ * Open MCT is licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * Open MCT includes source code licensed under additional open source
+ * licenses. See the Open Source Licenses file (LICENSES.md) included with
+ * this source code distribution or the Licensing information page available
+ * at runtime from the About dialog for additional information.
+ *****************************************************************************/
+
+import ImageExporter from './ImageExporter';
+import { createOpenMct, resetApplicationState } from '../utils/testing';
+
+describe('The Image Exporter', () => {
+ let openmct;
+ let imageExporter;
+
+ beforeEach(() => {
+ openmct = createOpenMct();
+ });
+
+ afterEach(() => {
+ return resetApplicationState(openmct);
+ });
+
+ describe("basic instatation", () => {
+ it("can be instatiated", () => {
+ imageExporter = new ImageExporter(openmct);
+
+ expect(imageExporter).not.toEqual(null);
+ });
+ it("can render an element to a blob", async () => {
+ const mockHeadElement = document.createElement("h1");
+ const mockTextNode = document.createTextNode('foo bar');
+ mockHeadElement.appendChild(mockTextNode);
+ document.body.appendChild(mockHeadElement);
+ imageExporter = new ImageExporter(openmct);
+ const returnedBlob = await imageExporter.renderElement(document.body, {
+ imageType: 'png'
+ });
+ expect(returnedBlob).not.toEqual(null);
+ expect(returnedBlob.blob).not.toEqual(null);
+ expect(returnedBlob.blob).toBeInstanceOf(Blob);
+ });
+ });
+});
diff --git a/src/plugins/notebook/components/NotebookEmbed.vue b/src/plugins/notebook/components/NotebookEmbed.vue
index c343299f2..6011a0d54 100644
--- a/src/plugins/notebook/components/NotebookEmbed.vue
+++ b/src/plugins/notebook/components/NotebookEmbed.vue
@@ -31,6 +31,7 @@ import PainterroInstance from '../utils/painterroInstance';
import SnapshotTemplate from './snapshot-template.html';
import { updateNotebookImageDomainObject } from '../utils/notebook-image';
+import ImageExporter from '../../../exporters/ImageExporter';
import PopupMenu from './PopupMenu.vue';
import Vue from 'vue';
@@ -71,7 +72,7 @@ export default {
},
mounted() {
this.addPopupMenuItems();
- this.exportImageService = this.openmct.$injector.get('exportImageService');
+ this.imageExporter = new ImageExporter(this.openmct);
},
methods: {
addPopupMenuItems() {
@@ -234,9 +235,9 @@ export default {
let element = this.snapshot.$refs['snapshot-image'];
if (type === 'png') {
- this.exportImageService.exportPNG(element, this.embed.name);
+ this.imageExporter.exportPNG(element, this.embed.name);
} else {
- this.exportImageService.exportJPG(element, this.embed.name);
+ this.imageExporter.exportJPG(element, this.embed.name);
}
},
previewEmbed() {
diff --git a/src/plugins/notebook/snapshot.js b/src/plugins/notebook/snapshot.js
index 05a384d3a..fd43be5fe 100644
--- a/src/plugins/notebook/snapshot.js
+++ b/src/plugins/notebook/snapshot.js
@@ -4,24 +4,24 @@ import { NOTEBOOK_DEFAULT } from '@/plugins/notebook/notebook-constants';
import { createNotebookImageDomainObject, DEFAULT_SIZE } from './utils/notebook-image';
import SnapshotContainer from './snapshot-container';
+import ImageExporter from '../../exporters/ImageExporter';
export default class Snapshot {
constructor(openmct) {
this.openmct = openmct;
this.snapshotContainer = new SnapshotContainer(openmct);
+ this.imageExporter = new ImageExporter(openmct);
this.capture = this.capture.bind(this);
this._saveSnapShot = this._saveSnapShot.bind(this);
}
capture(snapshotMeta, notebookType, domElement) {
- const exportImageService = this.openmct.$injector.get('exportImageService');
-
const options = {
className: 's-status-taking-snapshot',
thumbnailSize: DEFAULT_SIZE
};
- exportImageService.exportPNGtoSRC(domElement, options)
+ this.imageExporter.exportPNGtoSRC(domElement, options)
.then(function ({blob, thumbnail}) {
const reader = new window.FileReader();
reader.readAsDataURL(blob);
diff --git a/src/plugins/plot/Plot.vue b/src/plugins/plot/Plot.vue
index 0512830ea..c8c1e3ffc 100644
--- a/src/plugins/plot/Plot.vue
+++ b/src/plugins/plot/Plot.vue
@@ -72,7 +72,8 @@
</template>
<script>
-import eventHelpers from "./lib/eventHelpers";
+import eventHelpers from './lib/eventHelpers';
+import ImageExporter from '../../exporters/ImageExporter';
import MctPlot from './MctPlot.vue';
export default {
@@ -102,8 +103,7 @@ export default {
},
mounted() {
eventHelpers.extend(this);
-
- this.exportImageService = this.openmct.$injector.get('exportImageService');
+ this.imageExporter = new ImageExporter(this.openmct);
},
beforeDestroy() {
this.destroy();
@@ -118,14 +118,12 @@ export default {
exportJPG() {
const plotElement = this.$refs.plotContainer;
-
- this.exportImageService.exportJPG(plotElement, 'plot.jpg', 'export-plot');
+ this.imageExporter.exportJPG(plotElement, 'plot.jpg', 'export-plot');
},
exportPNG() {
const plotElement = this.$refs.plotContainer;
-
- this.exportImageService.exportPNG(plotElement, 'plot.png', 'export-plot');
+ this.imageExporter.exportPNG(plotElement, 'plot.png', 'export-plot');
},
toggleCursorGuide() {
diff --git a/src/plugins/plot/pluginSpec.js b/src/plugins/plot/pluginSpec.js
index f82fad8f5..e3d18876a 100644
--- a/src/plugins/plot/pluginSpec.js
+++ b/src/plugins/plot/pluginSpec.js
@@ -325,14 +325,6 @@ describe("the plugin", function () {
start: 0,
end: 4
});
- const getFunc = openmct.$injector.get;
- spyOn(openmct.$injector, "get")
- .withArgs("exportImageService").and.returnValue({
- exportPNG: () => {},
- exportJPG: () => {}
- })
- .and.callFake(getFunc);
-
testTelemetryObject = {
identifier: {
namespace: "",
diff --git a/src/plugins/plot/stackedPlot/StackedPlot.vue b/src/plugins/plot/stackedPlot/StackedPlot.vue
index eb0386bba..d342ce8d5 100644
--- a/src/plugins/plot/stackedPlot/StackedPlot.vue
+++ b/src/plugins/plot/stackedPlot/StackedPlot.vue
@@ -67,8 +67,9 @@
</template>
<script>
-import eventHelpers from "../lib/eventHelpers";
-import StackedPlotItem from "./StackedPlotItem.vue";
+import eventHelpers from '../lib/eventHelpers';
+import StackedPlotItem from './StackedPlotItem.vue';
+import ImageExporter from '../../../exporters/ImageExporter';
export default {
components: {
@@ -103,7 +104,7 @@ export default {
mounted() {
eventHelpers.extend(this);
- this.exportImageService = this.openmct.$injector.get('exportImageService');
+ this.imageExporter = new ImageExporter(this.openmct);
this.tickWidthMap = {};
@@ -159,9 +160,9 @@ export default {
exportJPG() {
this.hideExportButtons = true;
- const plotElement = this.$refs.plotContainer;
+ const plotElement = this.$el;
- this.exportImageService.exportJPG(plotElement, 'stacked-plot.jpg', 'export-plot')
+ this.imageExporter.exportJPG(plotElement, 'stacked-plot.jpg', 'export-plot')
.finally(function () {
this.hideExportButtons = false;
}.bind(this));
@@ -170,9 +171,9 @@ export default {
exportPNG() {
this.hideExportButtons = true;
- const plotElement = this.$refs.plotContainer;
+ const plotElement = this.$el;
- this.exportImageService.exportPNG(plotElement, 'stacked-plot.png', 'export-plot')
+ this.imageExporter.exportPNG(plotElement, 'stacked-plot.png', 'export-plot')
.finally(function () {
this.hideExportButtons = false;
}.bind(this));
diff --git a/src/plugins/viewDatumAction/pluginSpec.js b/src/plugins/viewDatumAction/pluginSpec.js
index 3867d35cf..847c5e7dd 100644
--- a/src/plugins/viewDatumAction/pluginSpec.js
+++ b/src/plugins/viewDatumAction/pluginSpec.js
@@ -66,8 +66,6 @@ describe("the plugin", () => {
};
}
};
-
- done();
});
afterEach(() => {