Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #317: Added multiple layer deletion functionality to action bar #333

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions ide/static/js/canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Canvas extends React.Component {
this.disableZoom = true;
}
/* this function returns the layers between a specified output y and input y
it also sneaks in another functionallity of determining which direction is most crowded. this is specifically
it also sneaks in another functionallity of determining which direction is most crowded. this is specifically
implemented in this function becuase performance will be very low if implemented in another loop. */
getBetween(net, output, input, x) {
var toReturn = [];
Expand All @@ -42,11 +42,11 @@ class Canvas extends React.Component {
}
});
var dir = 0;
if (neg>pos) dir = -1; else dir = 1;
if (neg>pos) dir = -1; else dir = 1;
return [dir, toReturn];
}
/* this function takes in a var of net and pos
net has an array of all the nodes, and pos is a array of x and y coordinates that this
net has an array of all the nodes, and pos is a array of x and y coordinates that this
function checks to see whether a line will cut through nodes in the pathway.
*/
checkIfCuttingLine(net, pos) {
Expand All @@ -64,7 +64,7 @@ class Canvas extends React.Component {
var xcalc = ((y - pos[1][1]) / slope) + pos[1][0];
if (Math.abs(x - xcalc) < 100) {
var extend = x - xcalc;
//the following code is used for positioning the direction of the line and the while loop controling the function iteslf.
//the following code is used for positioning the direction of the line and the while loop controling the function iteslf.
if (extend < 0) {
return 1;
}
Expand Down Expand Up @@ -123,7 +123,7 @@ class Canvas extends React.Component {
componentWillUpdate() {
this.placeholder = false;
const net = this.props.net;
if (Object.keys(net).length > 0) { //enable zoom buttons if there are layers
if (Object.keys(net).length > 0) { //enable zoom buttons if there are layers
this.disableZoom = false;
}
}
Expand Down Expand Up @@ -188,7 +188,7 @@ class Canvas extends React.Component {
lastLayerId = `l${lastLayerId}`; //add 'l' ahead of the index
prevLayerId = `l${prevLayerId}`;
const x1 = parseInt(net[prevLayerId].state.top.split('px'));
const x2 = parseInt(net[lastLayerId].state.top.split('px'));
const x2 = parseInt(net[lastLayerId].state.top.split('px'));
const s = instance.getEndpoints(prevLayerId)[0];
var t = instance.getEndpoints(lastLayerId);
// To handle case of loss layer being target
Expand All @@ -202,15 +202,19 @@ class Canvas extends React.Component {
instance.connect({
source: s,
target: t});
}
}
}
}
allowDrop(event) {
event.preventDefault();
}
clickLayerEvent(event, layerId) { // happens when layer is clicked and also dragged
if (this.clickOrDraggedLayer === 0) {
this.props.changeSelectedLayer(layerId); // clicked
if (this.props.deleteMode){
this.props.deleteLayer(layerId);
}
else
this.props.changeSelectedLayer(layerId); // clicked
} else if (this.clickOrDraggedLayer === 1) {
this.clickOrDraggedLayer = 0; // dragged
}
Expand All @@ -231,7 +235,7 @@ class Canvas extends React.Component {
this.placeholder = false;
event.preventDefault();
if (event.target.id === 'panZoomContainer' && !this.mouseState.pan) {
if (this.props.selectedLayer!=null)
if (this.props.selectedLayer!=null)
this.props.modifyLayer(this.props.net[this.props.selectedLayer], this.props.selectedLayer);
this.props.changeSelectedLayer(null);
}
Expand All @@ -248,8 +252,8 @@ class Canvas extends React.Component {
layer.state.left = `${event.pos['0']}px`;
layer.state.top = `${event.pos['1']}px`;
this.props.modifyLayer(layer, layerId);
let net = this.props.net
this.checkCutting(net);
let net = this.props.net
this.checkCutting(net);
}
connectionEvent(connInfo, originalEvent) {
if (originalEvent != null) { // user manually makes a connection
Expand Down Expand Up @@ -466,7 +470,9 @@ Canvas.propTypes = {
totalParameters: React.PropTypes.number,
setDraggingLayer: React.PropTypes.func,
draggingLayer: React.PropTypes.string,
selectedLayer: React.PropTypes.string
selectedLayer: React.PropTypes.string,
deleteLayer: React.PropTypes.func,
deleteMode: React.PropTypes.bool
};

export default Canvas;
64 changes: 37 additions & 27 deletions ide/static/js/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Modal from 'react-modal';
import ModelZoo from './modelZoo';
import ImportTextbox from './importTextbox';
import UrlImportModal from './urlImportModal';
import $ from 'jquery'
import $ from 'jquery';

const infoStyle = {
content : {
Expand Down Expand Up @@ -45,7 +45,8 @@ class Content extends React.Component {
modalIsOpen: false,
totalParameters: 0,
modelConfig: null,
modelFramework: 'caffe'
modelFramework: 'caffe',
deleteMode: false
};
this.addNewLayer = this.addNewLayer.bind(this);
this.changeSelectedLayer = this.changeSelectedLayer.bind(this);
Expand Down Expand Up @@ -84,6 +85,7 @@ class Content extends React.Component {
this.calculateParameters = this.calculateParameters.bind(this);
this.getLayerParameters = this.getLayerParameters.bind(this);
this.updateLayerShape = this.updateLayerShape.bind(this);
this.toggleDeleteMode = this.toggleDeleteMode.bind(this);
this.modalContent = null;
this.modalHeader = null;
// Might need to improve the logic of clickEvent
Expand Down Expand Up @@ -145,7 +147,6 @@ class Content extends React.Component {
}
this.setState({ net, hoveredLayer: layerId });
}

modifyLayer(layer, layerId = this.state.selectedLayer) {
const net = this.state.net;
var oldLayerParams = this.state.totalParameters;
Expand Down Expand Up @@ -224,7 +225,7 @@ class Content extends React.Component {
const input = net[layerId].connection.input;
const output = net[layerId].connection.output;
const layerIdNum = parseInt(layerId.substring(1,layerId.length)); //numeric value of the layerId
const nextLayerId = this.state.nextLayerId - 1 == layerIdNum ? layerIdNum : this.state.nextLayerId;
const nextLayerId = this.state.nextLayerId - 1 == layerIdNum ? layerIdNum : this.state.nextLayerId;
//if last layer was deleted nextLayerId is replaced by deleted layer's id
var totalParameters = this.state.totalParameters;
let index;
Expand All @@ -240,7 +241,9 @@ class Content extends React.Component {
});
this.setState({ net, selectedLayer: null, nextLayerId: nextLayerId, totalParameters: totalParameters });
}

toggleDeleteMode(){
this.setState({deleteMode: !this.state.deleteMode});
}
updateLayerShape(net, layerId) {
const netData = JSON.parse(JSON.stringify(net));
Object.keys(netData[layerId].params).forEach(param => {
Expand Down Expand Up @@ -287,7 +290,7 @@ class Content extends React.Component {

if(filter_layers.includes(layer.info.type)) {
// if layer is Conv or DeConv calculating total parameter of the layer using:
// N_Input * K_H * K_W * N_Output
// N_Input * K_H * K_W * N_Output
var kernel_params = 1;
if(layer.params['kernel_h'][0] != '')
kernel_params *= layer.params['kernel_h'][0];
Expand Down Expand Up @@ -326,7 +329,7 @@ class Content extends React.Component {
if (layer.params['use_bias'][0] == false)
bias_params = 0;
}

// Update the total parameters of model after considering this layer.
return (weight_params + bias_params);
}
Expand Down Expand Up @@ -356,7 +359,7 @@ class Content extends React.Component {
// call to intermediate method which will iterate over layers & calculate the parameters separately
this.calculateParameters(net);
// update the net object with shape attributes added
this.setState({ net });
this.setState({ net });
}.bind(this),
error() {
//console.log('error'+response.error);
Expand Down Expand Up @@ -850,7 +853,7 @@ class Content extends React.Component {
infoModal() {
this.modalHeader = "About"
this.modalContent = `Fabrik is an online collaborative platform to build and visualize deep\
learning models via a simple drag-and-drop interface. It allows researchers to\
learning models via a simple drag-and-drop interface. It allows researchers to\
collaboratively develop and debug models using a web GUI that supports importing,\
editing and exporting networks written in widely popular frameworks like Caffe,\
Keras, and TensorFlow.`;
Expand Down Expand Up @@ -917,11 +920,11 @@ class Content extends React.Component {
const id = event.target.id;
const prev = net[`l${this.state.nextLayerId-1}`];
const next = data[id];
const zoom = instance.getZoom();
const zoom = instance.getZoom();
const layer = {};
let phase = this.state.selectedPhase;
if (this.state.nextLayerId>0 //makes sure that there are other layers

if (this.state.nextLayerId>0 //makes sure that there are other layers
&&data[prev.info.type].endpoint.src == "Bottom" //makes sure that the source has a bottom
&&next.endpoint.trg == "Top") { //makes sure that the target has a top
layer.connection = { input: [], output: [] };
Expand All @@ -932,17 +935,17 @@ class Content extends React.Component {
}
layer.params = {
'endPoint' : [next['endpoint'], false] //This key is endpoint in data.js, but endPoint in everywhere else.
}
}
Object.keys(next.params).forEach(j => {
layer.params[j] = [next.params[j].value, false]; //copys all params from data.js
});
});
layer.props = JSON.parse(JSON.stringify(next.props)) //copys all props rom data.js
layer.state = {
top: `${(parseInt(prev.state.top.split('px')[0])/zoom + 80)}px`, // This makes the new layer is exactly 80px under the previous one.
left: `${(parseInt(prev.state.left.split('px')[0])/zoom)}px`, // This aligns the new layer with the previous one.
class: ''
class: ''
}
layer.props.name = `${next.name}${this.state.nextLayerId}`;
layer.props.name = `${next.name}${this.state.nextLayerId}`;
prev.connection.output.push(`l${this.state.nextLayerId}`);
layer.connection.input.push(`l${this.state.nextLayerId-1}`);
this.addNewLayer(layer);
Expand All @@ -957,10 +960,10 @@ class Content extends React.Component {
}
layer.params = {
'endPoint' : [next['endpoint'], false] //This key is endpoint in data.js, but endPoint in everywhere else.
}
}
Object.keys(next.params).forEach(j => {
layer.params[j] = [next.params[j].value, false]; //copys all params from data.js
});
});
layer.props = JSON.parse(JSON.stringify(next.props)) //copys all props from data.js
const height = Math.round(0.05*window.innerHeight, 0); // 5% of screen height, rounded to zero decimals
const width = Math.round(0.35*window.innerWidth, 0); // 35% of screen width, rounded to zero decimals
Expand All @@ -969,10 +972,10 @@ class Content extends React.Component {
layer.state = {
top: `${top}px`,
left: `${left}px`,
class: ''
class: ''
}
layer.props.name = `${next.name}${this.state.nextLayerId}`;
this.addNewLayer(layer);
layer.props.name = `${next.name}${this.state.nextLayerId}`;
this.addNewLayer(layer);
}
}
render() {
Expand All @@ -998,9 +1001,14 @@ class Content extends React.Component {
zooModal={this.zooModal}
textboxModal={this.textboxModal}
urlModal={this.urlModal}
net={this.state.net}
selectedLayer={this.state.selectedLayer}
selectedPhase={this.state.selectedPhase}
deleteMode={this.state.deleteMode}
toggleDeleteMode={this.toggleDeleteMode}
/>
<h5 className="sidebar-heading">INSERT LAYER</h5>
<Pane
<Pane
handleClick = {this.handleClick}
setDraggingLayer = {this.setDraggingLayer}
/>
Expand All @@ -1014,12 +1022,12 @@ class Content extends React.Component {
</div>
</div>
<div id="main">
<input type="text"
<input type="text"
className={$.isEmptyObject(this.state.net) ? "hidden": ""}
id="netName"
placeholder="Net name"
value={this.state.net_name}
onChange={this.changeNetName}
id="netName"
placeholder="Net name"
value={this.state.net_name}
onChange={this.changeNetName}
spellCheck="false"
/>
{loader}
Expand All @@ -1041,6 +1049,8 @@ class Content extends React.Component {
draggingLayer={this.state.draggingLayer}
setDraggingLayer={this.setDraggingLayer}
selectedLayer={this.state.selectedLayer}
deleteLayer={this.deleteLayer}
deleteMode={this.state.deleteMode}
/>
<SetParams
net={this.state.net}
Expand Down
34 changes: 33 additions & 1 deletion ide/static/js/topBar.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
import React from 'react';
import ReactTooltip from 'react-tooltip';
import data from './data';

class TopBar extends React.Component {
render() {
//Delete button class options
var delete_button_class_options = "btn btn-default";
if (this.props.selectedLayer){
const layer = this.props.net[this.props.selectedLayer];
if ((layer.info.phase === null) && (this.props.selectedPhase === 1) && (data[layer.info.type].learn))
delete_button_class_options = "btn btn-default disabled";
}

//Delete button's span's class class_options
var delete_span_class_options = null;
if (!this.props.deleteMode)
delete_span_class_options = " glyphicon glyphicon-remove";
else
delete_span_class_options = " glyphicon glyphicon-remove text-warning";


return (
<div className="topBar">
<div className="topbar-row">
Expand Down Expand Up @@ -78,6 +95,16 @@ class TopBar extends React.Component {
</button>
</div>
</div>
<div className="topbar-col">
<div className="form-group">
<div className="dropdown">
<button id="topbar-icon" className={delete_button_class_options}
onClick={() => this.props.toggleDeleteMode()} data-tip="Select a layer to delete it">
<span className={delete_span_class_options} aria-hidden="true"></span>
</button>
</div>
</div>
</div>
</div>
<ReactTooltip type="dark" multiline={true}/>
</div>
Expand All @@ -86,13 +113,18 @@ class TopBar extends React.Component {
}

TopBar.propTypes = {
selectedLayer: React.PropTypes.string,
net: React.PropTypes.object,
selectedPhase: React.PropTypes.number,
exportNet: React.PropTypes.func,
importNet: React.PropTypes.func,
saveDb: React.PropTypes.func,
loadDb: React.PropTypes.func,
zooModal: React.PropTypes.func,
textboxModal: React.PropTypes.func,
urlModal: React.PropTypes.func
urlModal: React.PropTypes.func,
deleteMode: React.PropTypes.bool,
toggleDeleteMode: React.PropTypes.func
};

export default TopBar;