| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347 |
- /* jshint esversion: 6 */
- /* eslint "indent": [ "error", 4, { "SwitchCase": 1 } ] */
- var view = view || {};
- var zip = zip || require('./zip');
- var gzip = gzip || require('./gzip');
- var tar = tar || require('./tar');
- var protobuf = protobuf || require('protobufjs');
- var prototxt = prototxt || require('protobufjs/ext/prototxt');
- var d3 = d3 || require('d3');
- var dagre = dagre || require('dagre');
- var sidebar = sidebar || require('./view-sidebar');
- var grapher = grapher || require('./view-grapher');
- view.View = class {
- constructor(host) {
- this._host = host;
- this._model = null;
- this._selection = [];
- this._sidebar = new sidebar.Sidebar(this._host);
- this._host.initialize(this);
- this._showAttributes = false;
- this._showInitializers = true;
- this._showNames = false;
- this._searchText = '';
- this._modelFactoryService = new view.ModelFactoryService(this._host);
- this._host.document.documentElement.style.overflow = 'hidden';
- this._host.document.body.scroll = 'no';
- this._host.document.getElementById('zoom-in-button').addEventListener('click', () => {
- this.zoomIn();
- });
- this._host.document.getElementById('zoom-out-button').addEventListener('click', () => {
- this.zoomOut();
- });
- this._host.document.getElementById('toolbar').addEventListener('mousewheel', (e) => {
- this.preventZoom(e);
- });
- this._host.document.getElementById('sidebar').addEventListener('mousewheel', (e) => {
- this.preventZoom(e);
- });
- this._host.document.addEventListener('keydown', () => {
- this.clearSelection();
- });
- if (this._host.environment('zoom') == 'scroll') {
- this._host.document.getElementById('graph-container').addEventListener('mousewheel', (e) => {
- this._mouseWheelHandler(e);
- });
- this._host.document.getElementById('graph').addEventListener('mousewheel', (e) => {
- this._mouseWheelHandler(e);
- });
- }
- }
-
- show(page) {
- if (!page) {
- page = (!this._model && !this._activeGraph) ? 'Welcome' : 'Graph';
- }
- this._host.screen(page);
- this._sidebar.close();
- var welcomeElement = this._host.document.getElementById('welcome');
- var openFileButton = this._host.document.getElementById('open-file-button');
- var spinnerElement = this._host.document.getElementById('spinner');
- var graphElement = this._host.document.getElementById('graph');
- var toolbarElement = this._host.document.getElementById('toolbar');
-
- if (page == 'Welcome') {
- this._host.document.body.style.cursor = 'default';
- welcomeElement.style.display = 'block';
- openFileButton.style.display = 'block';
- openFileButton.style.opacity = 1;
- spinnerElement.style.display = 'none';
- graphElement.style.display = 'none';
- graphElement.style.opacity = 0;
- toolbarElement.style.display = 'none';
- }
- if (page == 'Spinner') {
- this._host.document.body.style.cursor = 'wait';
- welcomeElement.style.display = 'block';
- spinnerElement.style.display = 'block';
- openFileButton.style.display = 'block';
- graphElement.style.display = 'block';
- graphElement.style.opacity = 0;
- toolbarElement.style.display = 'none';
- }
- if (page == 'Graph') {
- welcomeElement.style.display = 'none';
- openFileButton.style.display = 'none';
- openFileButton.style.opacity = 0;
- spinnerElement.style.display = 'none';
- graphElement.style.display = 'block';
- graphElement.style.opacity = 1;
- toolbarElement.style.display = 'block';
- this._host.document.body.style.cursor = 'default';
- }
- }
- cut() {
- this._host.document.execCommand('cut');
- }
- copy() {
- this._host.document.execCommand('copy');
- }
- paste() {
- this._host.document.execCommand('paste');
- }
- selectAll() {
- this._host.document.execCommand('selectall');
- }
- find() {
- if (this._activeGraph) {
- this.clearSelection();
- var graphElement = document.getElementById('graph');
- var view = new sidebar.FindSidebar(this._host, graphElement, this._activeGraph);
- view.on('search-text-changed', (sender, text) => {
- this._searchText = text;
- });
- view.on('select', (sender, selection) => {
- this._sidebar.close();
- this.select(selection);
- });
- this._sidebar.open(view.content, 'Find');
- view.focus(this._searchText);
- }
- }
- toggleAttributes() {
- this._showAttributes = !this._showAttributes;
- this._reload();
- }
- get showAttributes() {
- return this._showAttributes;
- }
- toggleInitializers() {
- this._showInitializers = !this._showInitializers;
- this._reload();
- }
- get showInitializers() {
- return this._showInitializers;
- }
- toggleNames() {
- this._showNames = !this._showNames;
- this._reload();
- }
- get showNames() {
- return this._showNames;
- }
- _reload() {
- this.show('Spinner');
- if (this._model && this._activeGraph) {
- this._updateGraph(this._model, this._activeGraph).catch((error) => {
- if (error) {
- this.error('Graph update failed.', error);
- }
- });
- }
- }
- _timeout(time) {
- return new Promise((resolve) => {
- setTimeout(() => { resolve(); }, time);
- });
- }
- zoomIn() {
- switch (this._host.environment('zoom')) {
- case 'scroll':
- if (this._zoom) {
- this._zoom = this._zoom * 1.05;
- if (this._zoom > 2) {
- this._zoom = 2;
- }
- this.applyZoom();
- }
- break;
- case 'd3':
- if (this._zoom) {
- this._zoom.scaleBy(d3.select(this._host.document.getElementById('graph')), 1.2);
- }
- break;
- }
- }
- zoomOut() {
- switch (this._host.environment('zoom')) {
- case 'scroll':
- if (this._zoom) {
- this._zoom = this._zoom * 0.95;
- if (this._zoom < 0.1) {
- this._zoom = 0.1;
- }
- this.applyZoom();
- }
- break;
- case 'd3':
- if (this._zoom) {
- this._zoom.scaleBy(d3.select(this._host.document.getElementById('graph')), 0.8);
- }
- break;
- }
- }
- resetZoom() {
- switch (this._host.environment('zoom')) {
- case 'scroll':
- if (this._zoom) {
- this._zoom = 1;
- this.applyZoom();
- }
- break;
- case 'd3':
- if (this._zoom) {
- this._zoom.scaleTo(d3.select(this._host.document.getElementById('graph')), 1);
- }
- break;
- }
- }
- preventZoom(e) {
- if (e.shiftKey || e.ctrlKey) {
- e.preventDefault();
- }
- }
- applyZoom() {
- var svgElement = this._host.document.getElementById('graph');
- svgElement.setAttribute('style', 'zoom: ' + this._zoom + ';');
- // svgElement.setAttribute('style', 'transform: scale(' + this._zoom + ',' + this._zoom + ')');
- // svgElement.setAttribute('width', this._width * this._zoom);
- // svgElement.setAttribute('height', this._height * this._zoom);
- }
- _mouseWheelHandler(e) {
- if (e.shiftKey || e.ctrlKey) {
- if (this._zoom) {
- // var oldWidth = this._width * this._zoom;
- // var oldHeight = this._height * this._zoom;
- this._zoom = this._zoom + (e.wheelDelta * 1.0 / 6000.0);
- if (this._zoom < 0.1) { this._zoom = 0.1; }
- if (this._zoom > 2) { this._zoom = 2; }
- this.applyZoom();
- /* var svgElement = document.getElementById('graph');
- va r newWidth = this._width * this._zoom;
- var newHeight = this._height * this._zoom;
- svgElement.setAttribute('width', newWidth);
- svgElement.setAttribute('height', newHeight); */
- // var dx = (oldWidth - newWidth) / 2;
- // var dy = (oldHeight - newHeight) / 2;
- // window.scrollBy(dx, dy);
- e.preventDefault();
- }
- }
- }
-
- select(selection) {
- this.clearSelection();
- if (selection && selection.length > 0) {
- var graphElement = this._host.document.getElementById('graph');
- var graphRect = graphElement.getBoundingClientRect();
- var x = 0;
- var y = 0;
- for (var element of selection) {
- element.classList.add('select');
- this._selection.push(element);
- var box = element.getBBox();
- var ex = box.x + (box.width / 2);
- var ey = box.y + (box.height / 2);
- var transform = element.transform.baseVal.consolidate();
- if (transform) {
- ex = transform.matrix.e;
- ey = transform.matrix.f;
- }
- x += ex;
- y += ey;
- }
- x = x / selection.length;
- y = y / selection.length;
- this._zoom.transform(d3.select(graphElement), d3.zoomIdentity.translate((graphRect.width / 2) - x, (graphRect.height / 2) - y));
- }
- }
- clearSelection() {
- while (this._selection.length > 0) {
- var element = this._selection.pop();
- element.classList.remove('select');
- }
- }
- error(message, err) {
- this._sidebar.close();
- this._host.exception(err, false);
- this._host.error(message, err.toString());
- this.show('Welcome');
- }
- accept(file) {
- return this._modelFactoryService.accept(file);
- }
- open(context) {
- this._host.event('Model', 'Open', 'Size', context.buffer.length);
- this._sidebar.close();
- return this._timeout(2).then(() => {
- return this._modelFactoryService.open(context).then((model) => {
- var format = model.format;
- if (format) {
- format = format + (model.producer ? ' (' + model.producer + ')' : '');
- this._host.event('Model', 'Format', format);
- }
- return this._timeout(20).then(() => {
- var graph = model.graphs.length > 0 ? model.graphs[0] : null;
- return this._updateGraph(model, graph);
- });
- });
- });
- }
- _updateActiveGraph(name) {
- this._sidebar.close();
- if (this._model) {
- var model = this._model;
- var graph = model.graphs.filter(graph => name == graph.name).shift();
- if (graph) {
- this.show('Spinner');
- this._timeout(200).then(() => {
- return this._updateGraph(model, graph).catch((error) => {
- if (error) {
- this.error('Graph update failed.', error);
- }
- });
- });
- }
- }
- }
- _updateGraph(model, graph) {
- return this._timeout(100).then(() => {
- if (graph && graph != this._activeGraph) {
- var nodes = graph.nodes;
- if (nodes.length > 1400) {
- if (!this._host.confirm('Large model detected.', 'This graph contains a large number of nodes and might take a long time to render. Do you want to continue?')) {
- this._host.event('Graph', 'Render', 'Skip', nodes.length);
- this.show(null);
- return null;
- }
- }
- }
- return this.renderGraph(graph).then(() => {
- this._model = model;
- this._activeGraph = graph;
- this.show('Graph');
- return this._model;
- }).catch((error) => {
- this.renderGraph(this._activeGraph).then(() => {
- this.show('Graph');
- throw error;
- }).catch(() => {
- throw error;
- });
- });
- });
- }
- renderGraph(graph) {
- try {
- if (!graph) {
- return Promise.resolve();
- }
- else {
- var graphElement = this._host.document.getElementById('graph');
- while (graphElement.lastChild) {
- graphElement.removeChild(graphElement.lastChild);
- }
-
- switch (this._host.environment('zoom')) {
- case 'scroll':
- this._zoom = 0;
- graphElement.style.position = 'static';
- graphElement.style.margin = 'auto';
- break;
- case 'd3':
- this._zoom = null;
- graphElement.style.position = 'absolute';
- graphElement.style.margin = '0';
- break;
- }
-
- var groups = graph.groups;
-
- var graphOptions = {};
- graphOptions.nodesep = 25;
- graphOptions.ranksep = 20;
- var g = new dagre.graphlib.Graph({ compound: groups });
- g.setGraph(graphOptions);
- g.setDefaultEdgeLabel(() => { return {}; });
-
- var nodeId = 0;
- var edgeMap = {};
-
- var clusterMap = {};
- var clusterParentMap = {};
-
- var id = new Date().getTime();
- var nodes = graph.nodes;
- if (nodes.length > 1500) {
- graphOptions.ranker = 'longest-path';
- }
- this._host.event('Graph', 'Render', 'Size', nodes.length);
- var node;
- if (groups) {
- for (node of nodes) {
- if (node.group) {
- var path = node.group.split('/');
- while (path.length > 0) {
- var name = path.join('/');
- path.pop();
- clusterParentMap[name] = path.join('/');
- }
- }
- }
- }
- var input;
- var output;
- var argument;
- var tuple;
- var self = this;
- for (node of nodes) {
-
- var element = new grapher.NodeElement(this._host.document);
- var addNode = function(element, node, edges) {
- var header = element.block('header');
- var styles = [ 'node-item-operator' ];
- var category = node.category;
- if (category) {
- styles.push('node-item-operator-' + category.toLowerCase());
- }
- var content = self.showNames && node.name ? node.name : node.operator;
- var tooltip = self.showNames && node.name ? node.operator : node.name;
- header.add(null, styles, content, tooltip, () => {
- self.showNodeProperties(node, null);
- });
- if (node.function) {
- header.add(null, [ 'node-item-function' ], '+', null, () => {
- // debugger;
- });
- }
- var initializers = [];
- var hiddenInitializers = false;
- if (self._showInitializers) {
- for (var input of node.inputs) {
- if (input.visible && input.arguments.length == 1 && input.arguments[0].initializer != null) {
- initializers.push(input);
- }
- if ((!input.visible || input.arguments.length > 1) &&
- input.arguments.some((argument) => argument.initializer != null)) {
- hiddenInitializers = true;
- }
- }
- }
- var attributes = [];
- if (self.showAttributes && node.attributes) {
- attributes = node.attributes.filter((attribute) => attribute.visible);
- }
- if (initializers.length > 0 || hiddenInitializers || attributes.length > 0) {
- var block = element.block('list');
- block.handler = () => {
- self.showNodeProperties(node);
- };
- for (var initializer of initializers) {
- var argument = initializer.arguments[0];
- var type = argument.type;
- var shape = '';
- var separator = '';
- if (type &&
- type.shape &&
- type.shape.dimensions &&
- Object.prototype.hasOwnProperty.call(type.shape.dimensions, 'length')) {
- shape = '\u3008' + type.shape.dimensions.map((d) => d ? d : '?').join('\u00D7') + '\u3009';
- if (type.shape.dimensions.length == 0 && argument.initializer && !argument.initializer.state) {
- shape = argument.initializer.toString();
- if (shape && shape.length > 10) {
- shape = shape.substring(0, 10) + '\u2026';
- }
- separator = ' = ';
- }
- }
- block.add('initializer-' + argument.id, initializer.name, shape, type ? type.toString() : '', separator);
- }
- if (hiddenInitializers) {
- block.add(null, '\u3008' + '\u2026' + '\u3009', '', null, '');
- }
- for (var attribute of attributes) {
- if (attribute.visible) {
- var attributeValue = sidebar.NodeSidebar.formatAttributeValue(attribute.value, attribute.type);
- if (attributeValue && attributeValue.length > 25) {
- attributeValue = attributeValue.substring(0, 25) + '\u2026';
- }
- block.add(null, attribute.name, attributeValue, attribute.type, ' = ');
- }
- }
- }
- if (edges) {
- var inputs = node.inputs;
- for (input of inputs) {
- for (argument of input.arguments) {
- if (argument.id != '' && !argument.initializer) {
- var tuple = edgeMap[argument.id];
- if (!tuple) {
- tuple = { from: null, to: [] };
- edgeMap[argument.id] = tuple;
- }
- tuple.to.push({
- node: nodeId,
- name: input.name
- });
- }
- }
- }
- var outputs = node.outputs;
- if (node.chain && node.chain.length > 0) {
- var chainOutputs = node.chain[node.chain.length - 1].outputs;
- if (chainOutputs.length > 0) {
- outputs = chainOutputs;
- }
- }
- for (output of outputs) {
- for (argument of output.arguments) {
- if (argument.id != '') {
- tuple = edgeMap[argument.id];
- if (!tuple) {
- tuple = { from: null, to: [] };
- edgeMap[argument.id] = tuple;
- }
- tuple.from = {
- node: nodeId,
- name: output.name,
- type: argument.type
- };
- }
- }
- }
- }
-
- if (node.chain && node.chain.length > 0) {
- for (var innerNode of node.chain) {
- addNode(element, innerNode, false);
- }
- }
- if (node.inner) {
- addNode(element, node.inner, false);
- }
- }
-
- addNode(element, node, true);
- if (node.controlDependencies && node.controlDependencies.length > 0) {
- for (var controlDependency of node.controlDependencies) {
- tuple = edgeMap[controlDependency];
- if (!tuple) {
- tuple = { from: null, to: [] };
- edgeMap[controlDependency] = tuple;
- }
- tuple.to.push({
- node: nodeId,
- name: controlDependency,
- controlDependency: true
- });
- }
- }
- var nodeName = node.name;
- if (nodeName) {
- g.setNode(nodeId, { label: element.format(graphElement), id: 'node-' + nodeName });
- }
- else {
- g.setNode(nodeId, { label: element.format(graphElement), id: 'node-' + id.toString() });
- id++;
- }
-
- var createCluster = function(name) {
- if (!clusterMap[name]) {
- g.setNode(name, { rx: 5, ry: 5});
- clusterMap[name] = true;
- var parent = clusterParentMap[name];
- if (parent) {
- createCluster(parent);
- g.setParent(name, parent);
- }
- }
- }
-
- if (groups) {
- var groupName = node.group;
- if (groupName && groupName.length > 0) {
- if (!Object.prototype.hasOwnProperty.call(clusterParentMap, groupName)) {
- var lastIndex = groupName.lastIndexOf('/');
- if (lastIndex != -1) {
- groupName = groupName.substring(0, lastIndex);
- if (!Object.prototype.hasOwnProperty.call(clusterParentMap, groupName)) {
- groupName = null;
- }
- }
- else {
- groupName = null;
- }
- }
- if (groupName) {
- createCluster(groupName);
- g.setParent(nodeId, groupName);
- }
- }
- }
-
- nodeId++;
- }
- for (input of graph.inputs) {
- for (argument of input.arguments) {
- tuple = edgeMap[argument.id];
- if (!tuple) {
- tuple = { from: null, to: [] };
- edgeMap[argument.id] = tuple;
- }
- tuple.from = {
- node: nodeId,
- type: argument.type
- };
- }
- var types = input.arguments.map((argument) => argument.type || '').join('\n');
- var inputName = input.name || '';
- if (inputName.length > 16) {
- inputName = inputName.split('/').pop();
- }
-
- var inputElement = new grapher.NodeElement(this._host.document);
- var inputHeader = inputElement.block('header');
- inputHeader.add(null, [ 'graph-item-input' ], inputName, types, () => {
- this.showModelProperties();
- });
- g.setNode(nodeId++, { label: inputElement.format(graphElement), class: 'graph-input' } );
- }
-
- for (output of graph.outputs) {
- for (argument of output.arguments) {
- tuple = edgeMap[argument.id];
- if (!tuple) {
- tuple = { from: null, to: [] };
- edgeMap[argument.id] = tuple;
- }
- tuple.to.push({ node: nodeId });
- }
- var outputTypes = output.arguments.map((argument) => argument.type || '').join('\n');
- var outputName = output.name || '';
- if (outputName.length > 16) {
- outputName = outputName.split('/').pop();
- }
-
- var outputElement = new grapher.NodeElement(this._host.document);
- var outputHeader = outputElement.block('header');
- outputHeader.add(null, [ 'graph-item-output' ], outputName, outputTypes, () => {
- this.showModelProperties();
- });
- g.setNode(nodeId++, { label: outputElement.format(graphElement) } );
- }
- for (var edge of Object.keys(edgeMap)) {
- tuple = edgeMap[edge];
- if (tuple.from != null) {
- for (var to of tuple.to) {
- var text = '';
- var type = tuple.from.type;
- if (type && type.shape && type.shape.dimensions && type.shape.dimensions.length > 0) {
- text = type.shape.dimensions.join('\u00D7');
- }
-
- if (this._showNames) {
- text = edge.split('\n').shift(); // custom argument id
- }
-
- if (to.controlDependency) {
- g.setEdge(tuple.from.node, to.node, { label: text, id: 'edge-' + edge, arrowhead: 'vee', class: 'edge-path-control-dependency' } );
- }
- else {
- g.setEdge(tuple.from.node, to.node, { label: text, id: 'edge-' + edge, arrowhead: 'vee' } );
- }
- }
- }
- }
- // Workaround for Safari background drag/zoom issue:
- // https://stackoverflow.com/questions/40887193/d3-js-zoom-is-not-working-with-mousewheel-in-safari
- var backgroundElement = this._host.document.createElementNS('http://www.w3.org/2000/svg', 'rect');
- backgroundElement.setAttribute('id', 'background');
- if (this._host.environment('zoom') == 'd3') {
- backgroundElement.setAttribute('width', '100%');
- backgroundElement.setAttribute('height', '100%');
- }
- backgroundElement.setAttribute('fill', 'none');
- backgroundElement.setAttribute('pointer-events', 'all');
- graphElement.appendChild(backgroundElement);
- var originElement = this._host.document.createElementNS('http://www.w3.org/2000/svg', 'g');
- originElement.setAttribute('id', 'origin');
- graphElement.appendChild(originElement);
-
- if (this._host.environment('zoom') == 'd3') {
- // Set up zoom support
- var svg = d3.select(graphElement);
- this._zoom = d3.zoom();
- this._zoom(svg);
- this._zoom.scaleExtent([0.1, 2]);
- this._zoom.on('zoom', () => {
- originElement.setAttribute('transform', d3.event.transform.toString());
- });
- this._zoom.transform(svg, d3.zoomIdentity);
- }
- return this._timeout(20).then(() => {
- var graphRenderer = new grapher.Renderer(this._host.document, originElement);
- graphRenderer.render(g);
- var inputElements = graphElement.getElementsByClassName('graph-input');
- switch (this._host.environment('zoom')) {
- case 'scroll':
- var size = graphElement.getBBox();
- var graphMin = Math.min(size.width, size.height);
- var windowMin = Math.min(window.innerWidth, window.innerHeight);
- var delta = (Math.max(graphMin, windowMin) / 2.0) * 0.2;
- var width = Math.ceil(delta + size.width + delta);
- var height = Math.ceil(delta + size.height + delta);
- originElement.setAttribute('transform', 'translate(' + delta.toString() + ', ' + delta.toString() + ') scale(1)');
- backgroundElement.setAttribute('width', width);
- backgroundElement.setAttribute('height', height);
- this._width = width;
- this._height = height;
- this._zoom = 1;
- graphElement.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
- graphElement.setAttribute('width', width / this._zoom);
- graphElement.setAttribute('height', height / this._zoom);
- if (inputElements && inputElements.length > 0) {
- // Center view based on input elements
- for (var j = 0; j < inputElements.length; j++) {
- inputElements[j].scrollIntoView({ behavior: 'instant' });
- break;
- }
- }
- else {
- // this._zoom.transform(svg, d3.zoomIdentity.translate((svgSize.width - g.graph().width) / 2, (svgSize.height - g.graph().height) / 2));
- }
- break;
- case 'd3':
- var svgSize = graphElement.getBoundingClientRect();
- if (inputElements && inputElements.length > 0) {
- // Center view based on input elements
- var xs = [];
- var ys = [];
- for (var i = 0; i < inputElements.length; i++) {
- var inputTransform = inputElements[i].transform.baseVal.consolidate().matrix;
- xs.push(inputTransform.e);
- ys.push(inputTransform.f);
- }
- var x = xs[0];
- var y = ys[0];
- if (ys.every(y => y == ys[0])) {
- x = xs.reduce((a,b) => { return a + b; }) / xs.length;
- }
- this._zoom.transform(svg, d3.zoomIdentity.translate((svgSize.width / 2) - x, (svgSize.height / 4) - y));
- }
- else {
- this._zoom.transform(svg, d3.zoomIdentity.translate((svgSize.width - g.graph().width) / 2, (svgSize.height - g.graph().height) / 2));
- }
- break;
- }
- return;
- });
- }
- }
- catch (error) {
- return Promise.reject(error);
- }
- }
- applyStyleSheet(element, name) {
- var rules = [];
- for (var i = 0; i < this._host.document.styleSheets.length; i++) {
- var styleSheet = this._host.document.styleSheets[i];
- if (styleSheet && styleSheet.href && styleSheet.href.endsWith('/' + name)) {
- rules = styleSheet.cssRules;
- break;
- }
- }
- var nodes = element.getElementsByTagName('*');
- for (var j = 0; j < nodes.length; j++) {
- var node = nodes[j];
- for (var k = 0; k < rules.length; k++) {
- var rule = rules[k];
- if (node.matches(rule.selectorText)) {
- for (var l = 0; l < rule.style.length; l++) {
- var item = rule.style.item(l);
- node.style[item] = rule.style[item];
- }
- }
- }
- }
- }
- export(file) {
- var extension = '';
- var lastIndex = file.lastIndexOf('.');
- if (lastIndex != -1) {
- extension = file.substring(lastIndex + 1);
- }
- if (this._activeGraph && (extension == 'png' || extension == 'svg')) {
- var graphElement = this._host.document.getElementById('graph');
- var exportElement = graphElement.cloneNode(true);
- this.applyStyleSheet(exportElement, 'view-grapher.css');
- exportElement.setAttribute('id', 'export');
- exportElement.removeAttribute('width');
- exportElement.removeAttribute('height');
- exportElement.style.removeProperty('opacity');
- exportElement.style.removeProperty('display');
- var backgroundElement = exportElement.querySelector('#background');
- var originElement = exportElement.querySelector('#origin');
- originElement.setAttribute('transform', 'translate(0,0) scale(1)');
- backgroundElement.removeAttribute('width');
- backgroundElement.removeAttribute('height');
- var parentElement = graphElement.parentElement;
- parentElement.insertBefore(exportElement, graphElement);
- var size = exportElement.getBBox();
- parentElement.removeChild(exportElement);
- parentElement.removeChild(graphElement);
- parentElement.appendChild(graphElement);
- var delta = (Math.min(size.width, size.height) / 2.0) * 0.1;
- var width = Math.ceil(delta + size.width + delta);
- var height = Math.ceil(delta + size.height + delta);
- originElement.setAttribute('transform', 'translate(' + delta.toString() + ', ' + delta.toString() + ') scale(1)');
- exportElement.setAttribute('width', width);
- exportElement.setAttribute('height', height);
- backgroundElement.setAttribute('width', width);
- backgroundElement.setAttribute('height', height);
- backgroundElement.setAttribute('fill', '#fff');
-
- var data = new XMLSerializer().serializeToString(exportElement);
-
- if (extension == 'svg') {
- var blob = new Blob([ data ], { type: 'image/svg' });
- this._host.export(file, blob);
- }
-
- if (extension == 'png') {
- var imageElement = new Image();
- imageElement.onload = () => {
- var max = Math.max(width, height);
- var scale = ((max * 2.0) > 24000) ? (24000.0 / max) : 2.0;
- var canvas = this._host.document.createElement('canvas');
- canvas.width = Math.ceil(width * scale);
- canvas.height = Math.ceil(height * scale);
- var context = canvas.getContext('2d');
- context.scale(scale, scale);
- context.drawImage(imageElement, 0, 0);
- this._host.document.body.removeChild(imageElement);
- canvas.toBlob((blob) => {
- if (blob) {
- this._host.export(file, blob);
- }
- else {
- var err = new Error();
- err.name = 'Error exporting image.';
- err.message = 'Image may be too large to render as PNG.';
- this._host.exception(err, false);
- this._host.error(err.name, err.message);
- }
- }, 'image/png');
- };
- imageElement.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(data)));
- this._host.document.body.insertBefore(imageElement, this._host.document.body.firstChild);
- }
- }
- }
- showModelProperties() {
- if (this._model) {
- var modelSidebar = new sidebar.ModelSidebar(this._host, this._model, this._activeGraph);
- modelSidebar.on('update-active-graph', (sender, name) => {
- this._updateActiveGraph(name);
- });
- this._sidebar.open(modelSidebar.render(), 'Model Properties');
- }
- }
-
- showNodeProperties(node, input) {
- if (node) {
- var nodeSidebar = new sidebar.NodeSidebar(this._host, node);
- nodeSidebar.on('show-documentation', (/* sender, e */) => {
- this.showOperatorDocumentation(node);
- });
- nodeSidebar.on('export-tensor', (sender, tensor) => {
- this._host.require('./numpy').then((numpy) => {
- var defaultPath = tensor.name ? tensor.name.split('/').join('_').split(':').join('_').split('.').join('_') : 'tensor';
- this._host.save('NumPy Array', 'npy', defaultPath, (file) => {
- try {
- var array = new numpy.Array(tensor.value, tensor.type.dataType, tensor.type.shape.dimensions);
- var blob = new Blob([ array.toBuffer() ], { type: 'application/octet-stream' });
- this._host.export(file, blob);
- }
- catch (error) {
- this.error('Error saving NumPy tensor.', error);
- }
- });
- }).catch(() => {
- });
- });
- if (input) {
- nodeSidebar.toggleInput(input.name);
- }
- this._sidebar.open(nodeSidebar.render(), 'Node Properties');
- }
- }
- showOperatorDocumentation(node) {
- var documentation = node.documentation;
- if (documentation) {
- var documentationSidebar = new sidebar.OperatorDocumentationSidebar(documentation);
- documentationSidebar.on('navigate', (sender, e) => {
- this._host.openURL(e.link);
- });
- this._sidebar.push(documentationSidebar.render(), 'Documentation');
- }
- }
- };
- class ModelError extends Error {
- constructor(message) {
- super(message);
- this.name = 'Error loading model.';
- }
- }
- class ModelContext {
- constructor(context) {
- this._context = context;
- this._tags = new Map();
- }
- request(file, encoding) {
- return this._context.request(file, encoding);
- }
- get identifier() {
- return this._context.identifier;
- }
- get buffer() {
- return this._context.buffer;
- }
- get text() {
- if (!this._text) {
- this._text = new TextDecoder('utf-8').decode(this.buffer);
- }
- return this._text;
- }
- tags(extension) {
- var tags = this._tags.get(extension);
- if (!tags) {
- tags = new Map();
- try {
- var reader = null;
- switch (extension) {
- case 'pbtxt':
- var b = this.buffer;
- var length = b.length;
- var signature =
- (length >= 3 && b[0] === 0xef && b[1] === 0xbb && b[2] === 0xbf) ||
- (length >= 4 && b[0] === 0x00 && b[1] === 0x00 && b[2] === 0xfe && b[3] === 0xff) ||
- (length >= 4 && b[0] === 0xff && b[1] === 0xfe && b[2] === 0x00 && b[3] === 0x00) ||
- (length >= 4 && b[0] === 0x84 && b[1] === 0x31 && b[2] === 0x95 && b[3] === 0x33) ||
- (length >= 2 && b[0] === 0xfe && b[1] === 0xff) ||
- (length >= 2 && b[0] === 0xff && b[1] === 0xfe);
- if (!signature && b.subarray(0, Math.min(1024, length)).some((c) => c < 7 || (c > 14 && c < 32))) {
- break;
- }
- reader = prototxt.TextReader.create(this.text);
- reader.start(false);
- while (!reader.end(false)) {
- var tag = reader.tag();
- tags.set(tag, true);
- reader.skip();
- }
- break;
- case 'pb':
- reader = new protobuf.Reader.create(this.buffer);
- while (reader.pos < reader.len) {
- var tagType = reader.uint32();
- tags.set(tagType >>> 3, tagType & 7);
- try {
- reader.skipType(tagType & 7);
- }
- catch (err) {
- tags = new Map();
- break;
- }
- }
- break;
- }
- }
- catch (error) {
- tags = new Map();
- }
- this._tags.set(extension, tags);
- }
- return tags;
- }
- }
- class ArchiveContext {
- constructor(entries, rootFolder, identifier, buffer) {
- this._entries = {};
- if (entries) {
- for (var entry of entries) {
- if (entry.name.startsWith(rootFolder)) {
- var name = entry.name.substring(rootFolder.length);
- if (identifier.length > 0 && identifier.indexOf('/') < 0) {
- this._entries[name] = entry;
- }
- }
- }
- }
- this._identifier = identifier.substring(rootFolder.length);
- this._buffer = buffer;
- }
- request(file, encoding) {
- var entry = this._entries[file];
- if (!entry) {
- return Promise.reject(new Error('File not found.'));
- }
- var data = entry.data;
- if (encoding != null) {
- data = new TextDecoder(encoding).decode(data);
- }
- return Promise.resolve(data);
- }
- get identifier() {
- return this._identifier;
- }
- get buffer() {
- return this._buffer;
- }
- }
- class ArchiveError extends Error {
- constructor(message) {
- super(message);
- this.name = 'Error loading archive.';
- }
- }
- view.ModelFactoryService = class {
- constructor(host) {
- this._host = host;
- this._extensions = [];
- this.register('./onnx', [ '.onnx', '.pb', '.pbtxt', '.prototxt' ]);
- this.register('./mxnet', [ '.mar', '.model', '.json', '.params' ]);
- this.register('./keras', [ '.h5', '.hd5', '.hdf5', '.keras', '.json', '.model' ]);
- this.register('./coreml', [ '.mlmodel' ]);
- this.register('./caffe', [ '.caffemodel', '.pbtxt', '.prototxt', '.pt' ]);
- this.register('./caffe2', [ '.pb', '.pbtxt', '.prototxt' ]);
- this.register('./pytorch', [ '.pt', '.pth', '.pkl', '.h5', '.t7', '.model', '.dms', '.pth.tar', '.ckpt', '.bin' ]);
- this.register('./torch', [ '.t7' ]);
- this.register('./torchscript', [ '.pt', '.pth' ]);
- this.register('./tflite', [ '.tflite', '.lite', '.tfl', '.bin' ]);
- this.register('./tf', [ '.pb', '.meta', '.pbtxt', '.prototxt', '.json' ]);
- this.register('./sklearn', [ '.pkl', '.joblib', '.model' ]);
- this.register('./cntk', [ '.model', '.cntk', '.cmf', '.dnn' ]);
- this.register('./openvino', [ '.xml' ]);
- this.register('./darknet', [ '.cfg' ]);
- this.register('./paddle', [ '.paddle', '__model__' ]);
- this.register('./ncnn', [ '.param', '.bin', '.cfg.ncnn', '.weights.ncnn' ]);
- this.register('./dl4j', [ 'configuration.json' ]);
- }
- register(id, extensions) {
- for (var extension of extensions) {
- this._extensions.push({ extension: extension, id: id });
- }
- }
-
- open(context) {
- return this._openArchive(context).then((context) => {
- context = new ModelContext(context);
- var extension = context.identifier.split('.').pop().toLowerCase();
- var modules = this._filter(context);
- if (modules.length == 0) {
- throw new ModelError("Unsupported file extension '." + extension + "'.");
- }
- var errors = [];
- var match = false;
- var nextModule = () => {
- if (modules.length > 0) {
- var id = modules.shift();
- return this._host.require(id).then((module) => {
- if (!module.ModelFactory) {
- throw new ModelError("Failed to load module '" + id + "'.");
- }
- var modelFactory = new module.ModelFactory();
- if (!modelFactory.match(context)) {
- return nextModule();
- }
- match++;
- return modelFactory.open(context, this._host).then((model) => {
- return model;
- }).catch((error) => {
- errors.push(error);
- return nextModule();
- });
- });
- }
- else {
- if (match) {
- if (errors.length == 1) {
- throw errors[0];
- }
- throw new ModelError(errors.map((err) => err.message).join('\n'));
- }
- throw new ModelError("Unsupported file content for extension '." + extension + "' in '" + context.identifier + "'.");
- }
- };
- return nextModule();
- });
- }
- _openArchive(context) {
- var extension;
- var archive;
- var entry;
- var message;
- var identifier = context.identifier;
- var buffer = context.buffer;
- try {
- extension = identifier.split('.').pop().toLowerCase();
- if (extension == 'gz' || extension == 'tgz') {
- archive = new gzip.Archive(buffer);
- if (archive.entries.length == 1) {
- entry = archive.entries[0];
- if (entry.name) {
-
- identifier = entry.name;
- }
- else {
- identifier = identifier.substring(0, identifier.lastIndexOf('.'));
- if (extension == 'tgz') {
- identifier += '.tar';
- }
- }
- buffer = entry.data;
- archive = null;
- }
- }
- }
- catch (error) {
- message = error && error.message ? error.message : error.toString();
- message = message.endsWith('.') ? message.substring(0, message.length - 1) : message;
- return Promise.reject(new ArchiveError(message + " in '" + identifier + "'."));
- }
- try {
- extension = identifier.split('.').pop().toLowerCase();
- switch (extension) {
- case 'tar':
- // handle .pth.tar
- var torch = [ 0x8a, 0x0a, 0x6c, 0xfc, 0x9c, 0x46, 0xf9, 0x20, 0x6a, 0xa8, 0x50, 0x19 ];
- if (!buffer || buffer.length < 14 || buffer[0] != 0x80 || !torch.every((v, i) => v == buffer[i + 2])) {
- archive = new tar.Archive(buffer);
- }
- break;
- case 'zip':
- archive = new zip.Archive(buffer);
- break;
- }
- }
- catch (error) {
- message = error && error.message ? error.message : error.toString();
- message = message.endsWith('.') ? message.substring(0, message.length - 1) : message;
- return Promise.reject(new ArchiveError(message + " in '" + identifier + "'."));
- }
- if (!archive) {
- return Promise.resolve(context);
- }
- try {
- var folders = {};
- for (entry of archive.entries) {
- if (entry.name.indexOf('/') != -1) {
- folders[entry.name.split('/').shift() + '/'] = true;
- }
- else {
- folders['/'] = true;
- }
- }
- if (extension == 'tar') {
- delete folders['PaxHeader/'];
- }
- var rootFolder = Object.keys(folders).length == 1 ? Object.keys(folders)[0] : '';
- rootFolder = rootFolder == '/' ? '' : rootFolder;
- var matches = [];
- var entries = archive.entries.slice();
- var nextEntry = () => {
- if (entries.length > 0) {
- var entry = entries.shift();
- if (entry.name.startsWith(rootFolder)) {
- var identifier = entry.name.substring(rootFolder.length);
- if (identifier.length > 0 && identifier.indexOf('/') < 0 && !identifier.startsWith('.')) {
- var context = new ModelContext(new ArchiveContext(null, rootFolder, entry.name, entry.data));
- var modules = this._filter(context);
- var nextModule = () => {
- if (modules.length > 0) {
- var id = modules.shift();
- return this._host.require(id).then((module) => {
- if (!module.ModelFactory) {
- throw new ArchiveError("Failed to load module '" + id + "'.", null);
- }
- var factory = new module.ModelFactory();
- if (factory.match(context)) {
- matches.push(entry);
- modules = [];
- }
- return nextModule();
- });
- }
- else {
- return nextEntry();
- }
- };
- return nextModule();
- }
- }
- return nextEntry();
- }
- else {
- if (matches.length == 0) {
- return Promise.reject(new ArchiveError('Archive does not contain model file.'));
- }
- else if (matches.length > 1) {
- if (matches.length == 2 &&
- matches.some((e) => e.name.endsWith('.params')) &&
- matches.some((e) => e.name.endsWith('-symbol.json'))) {
- matches = matches.filter((e) => e.name.endsWith('.params'));
- }
- else {
- return Promise.reject(new ArchiveError('Archive contains multiple model files.'));
- }
- }
- var match = matches[0];
- return Promise.resolve(new ModelContext(new ArchiveContext(archive.entries, rootFolder, match.name, match.data)));
- }
- };
- return nextEntry();
- }
- catch (error) {
- return Promise.reject(new ArchiveError(error.message));
- }
- }
- accept(identifier) {
- identifier = identifier.toLowerCase();
- for (var extension of this._extensions) {
- if (identifier.endsWith(extension.extension)) {
- return true;
- }
- }
- if (identifier.endsWith('.zip') ||
- identifier.endsWith('.tar') ||
- identifier.endsWith('.tar.gz') ||
- identifier.endsWith('.tgz')) {
- return true;
- }
- return false;
- }
- _filter(context) {
- var moduleList = [];
- var moduleMap = {};
- var identifier = context.identifier.toLowerCase();
- for (var extension of this._extensions) {
- if (identifier.endsWith(extension.extension)) {
- if (!moduleMap[extension.id]) {
- moduleList.push(extension.id);
- moduleMap[extension.id] = true;
- }
- }
- }
- return moduleList;
- }
- };
- if (typeof module !== 'undefined' && typeof module.exports === 'object') {
- module.exports.View = view.View;
- module.exports.ModelFactoryService = view.ModelFactoryService;
- }
|