Skip to content

Commit

Permalink
Add layout feature
Browse files Browse the repository at this point in the history
  • Loading branch information
64json committed Feb 13, 2019
1 parent 7271b34 commit c7ec896
Show file tree
Hide file tree
Showing 26 changed files with 213 additions and 148 deletions.
2 changes: 1 addition & 1 deletion src/backend/controllers/tracers.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const trace = lang => (req, res, next) => {
}).finally(() => clearTimeout(timer));
})
.then(() => new Promise((resolve, reject) => {
const visualizationPath = path.resolve(tempPath, 'traces.json');
const visualizationPath = path.resolve(tempPath, 'visualization.json');
res.sendFile(visualizationPath, err => {
if (err) return reject(new Error('Visualization Not Found'));
resolve();
Expand Down
2 changes: 1 addition & 1 deletion src/backend/tracers/js/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ onmessage = e => {
const lines = e.data.split('\n').map((line, i) => line.replace(/(\.\s*delay\s*)\(\s*\)/g, `$1(${i})`));
const code = lines.join('\n');
sandbox(code);
postMessage(AlgorithmVisualizer.Tracer.traces);
postMessage(AlgorithmVisualizer.Commander.commands);
};
8 changes: 4 additions & 4 deletions src/frontend/apis/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ const GitHubApi = {

const TracerApi = {
md: ({ code }) => Promise.resolve([{
tracerKey: '0-MarkdownTracer-Markdown',
method: 'construct',
args: ['MarkdownTracer', 'Markdown'],
key: 'markdown',
method: 'MarkdownTracer',
args: ['Markdown'],
}, {
tracerKey: '0-MarkdownTracer-Markdown',
key: 'markdown',
method: 'set',
args: [code],
}]),
Expand Down
34 changes: 23 additions & 11 deletions src/frontend/components/App/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@ class App extends BaseComponent {
super(props);

this.state = {
navigatorOpened: true,
workspaceVisibles: [true, true, true],
workspaceWeights: [1, 2, 2],
};

this.codeEditorRef = React.createRef();

this.ignoreHistoryBlock = this.ignoreHistoryBlock.bind(this);
this.handleClickTitleBar = this.handleClickTitleBar.bind(this);
this.loadScratchPapers = this.loadScratchPapers.bind(this);
this.handleChangeWorkspaceWeights = this.handleChangeWorkspaceWeights.bind(this);
}

componentDidMount() {
Expand Down Expand Up @@ -161,7 +164,7 @@ class App extends BaseComponent {
login: undefined,
gistId,
title: 'Untitled',
files: [CONTRIBUTING_MD, createUserFile('traces.json', JSON.stringify(content))],
files: [CONTRIBUTING_MD, createUserFile('visualization.json', JSON.stringify(content))],
});
});
} else if (gistId === 'new') {
Expand All @@ -182,7 +185,10 @@ class App extends BaseComponent {
return Promise.resolve();
};
fetch()
.then(() => this.selectDefaultTab())
.then(() => {
this.selectDefaultTab();
return null; // to suppress unnecessary bluebird warning
})
.catch(error => {
this.handleError(error);
this.props.history.push('/');
Expand All @@ -204,28 +210,34 @@ class App extends BaseComponent {
this.codeEditorRef.current.getWrappedInstance().handleResize();
}

toggleNavigatorOpened(navigatorOpened = !this.state.navigatorOpened) {
this.setState({ navigatorOpened });
toggleNavigatorOpened(navigatorOpened = !this.state.workspaceVisibles[0]) {
const workspaceVisibles = [...this.state.workspaceVisibles];
workspaceVisibles[0] = navigatorOpened;
this.setState({ workspaceVisibles });
}

render() {
const { navigatorOpened, workspaceWeights } = this.state;
handleClickTitleBar() {
this.toggleNavigatorOpened();
}

render() {
const { workspaceVisibles, workspaceWeights } = this.state;
const { titles, description, saved } = this.props.current;

const title = `${saved ? '' : '(Unsaved) '}${titles.join(' - ')}`;
const [navigatorOpened] = workspaceVisibles;

return (
<div className={styles.app}>
<Helmet>
<title>{title}</title>
<meta name="description" content={description} />
</Helmet>
<Header className={styles.header} onClickTitleBar={() => this.toggleNavigatorOpened()}
navigatorOpened={navigatorOpened} loadScratchPapers={() => this.loadScratchPapers()}
<Header className={styles.header} onClickTitleBar={this.handleClickTitleBar}
navigatorOpened={navigatorOpened} loadScratchPapers={this.loadScratchPapers}
ignoreHistoryBlock={this.ignoreHistoryBlock} />
<ResizableContainer className={styles.workspace} horizontal weights={workspaceWeights}
visibles={[navigatorOpened, true, true]}
onChangeWeights={weights => this.handleChangeWorkspaceWeights(weights)}>
visibles={workspaceVisibles} onChangeWeights={this.handleChangeWorkspaceWeights}>
<Navigator />
<VisualizationViewer className={styles.visualization_viewer} />
<TabContainer className={styles.editor_tab_container}>
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/components/CodeEditor/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class CodeEditor extends React.Component {
}

handleResize() {
this.aceEditorRef.current.editor.resize();
this.aceEditorRef.current.getWrappedInstance().resize();
}

render() {
Expand Down
6 changes: 5 additions & 1 deletion src/frontend/components/FoldableAceEditor/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import 'brace/theme/tomorrow_night_eighties';
import 'brace/ext/searchbox';
import { actions } from '/reducers';

@connect(({ current }) => ({ current }), actions)
@connect(({ current }) => ({ current }), actions, null, { withRef: true })
class FoldableAceEditor extends AceEditor {
componentDidMount() {
super.componentDidMount();
Expand Down Expand Up @@ -40,6 +40,10 @@ class FoldableAceEditor extends AceEditor {
}
}
}

resize() {
this.editor.resize();
}
}

export default FoldableAceEditor;
21 changes: 11 additions & 10 deletions src/frontend/components/Player/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,23 @@ class Player extends BaseComponent {
}
}

reset(traces = []) {
reset(commands = []) {
const chunks = [{
traces: [],
commands: [],
lineNumber: undefined,
}];
while (traces.length) {
const trace = traces.shift();
if (trace.method === 'delay') {
const [lineNumber] = trace.args;
while (commands.length) {
const command = commands.shift();
const { key, method, args } = command;
if (key === null && method === 'delay') {
const [lineNumber] = args;
chunks[chunks.length - 1].lineNumber = lineNumber;
chunks.push({
traces: [],
commands: [],
lineNumber: undefined,
});
} else {
chunks[chunks.length - 1].traces.push(trace);
chunks[chunks.length - 1].commands.push(command);
}
}
this.props.setChunks(chunks);
Expand All @@ -76,10 +77,10 @@ class Player extends BaseComponent {
const ext = extension(file.name);
if (ext in TracerApi) {
TracerApi[ext]({ code: file.content }, undefined, this.tracerApiSource.token)
.then(traces => {
.then(commands => {
this.tracerApiSource = null;
this.setState({ building: false });
this.reset(traces);
this.reset(commands);
this.next();
})
.catch(error => {
Expand Down
7 changes: 4 additions & 3 deletions src/frontend/components/ResizableContainer/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ResizableContainer extends React.Component {
let totalWeight = 0;
let subtotalWeight = 0;
weights.forEach((weight, i) => {
if (!visibles[i]) return;
if (visibles && !visibles[i]) return;
totalWeight += weight;
if (i < index) subtotalWeight += weight;
});
Expand All @@ -34,9 +34,10 @@ class ResizableContainer extends React.Component {

const elements = [];
let lastIndex = -1;
const totalWeight = weights.filter((weight, i) => visibles[i]).reduce((sumWeight, weight) => sumWeight + weight, 0);
const totalWeight = weights.filter((weight, i) => !visibles || visibles[i])
.reduce((sumWeight, weight) => sumWeight + weight, 0);
children.forEach((child, i) => {
if (visibles[i]) {
if (!visibles || visibles[i]) {
if (~lastIndex) {
const prevIndex = lastIndex;
elements.push(
Expand Down
83 changes: 30 additions & 53 deletions src/frontend/components/VisualizationViewer/index.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import React from 'react';
import { connect } from 'react-redux';
import { classes } from '/common/util';
import { BaseComponent, ResizableContainer } from '/components';
import { BaseComponent } from '/components';
import { actions } from '/reducers';
import styles from './stylesheet.scss';
import { Array1DData, Array2DData, ChartData, Data, GraphData, LogData, MarkdownData } from '/core/datas';
import * as TracerClasses from '/core/tracers';
import * as LayoutClasses from '/core/layouts';
import { classes } from '/common/util';

@connect(({ player }) => ({ player }), actions)
class VisualizationViewer extends BaseComponent {
constructor(props) {
super(props);

this.state = {
dataWeights: {},
};
this.reset();
}

this.datas = [];
reset() {
this.root = null;
this.objects = {};
}

componentDidMount() {
Expand All @@ -36,19 +38,11 @@ class VisualizationViewer extends BaseComponent {
if (cursor > oldCursor) {
applyingChunks = chunks.slice(oldCursor, cursor);
} else {
this.datas = [];
this.reset();
applyingChunks = chunks.slice(0, cursor);
}
applyingChunks.forEach(chunk => this.applyChunk(chunk));

const dataWeights = chunks === oldChunks ? { ...this.state.dataWeights } : {};
this.datas.forEach(data => {
if (!(data.tracerKey in dataWeights)) {
dataWeights[data.tracerKey] = 1;
}
});
this.setState({ dataWeights });

const lastChunk = applyingChunks[applyingChunks.length - 1];
if (lastChunk && lastChunk.lineNumber !== undefined) {
this.props.setLineIndicator({ lineNumber: lastChunk.lineNumber, cursor });
Expand All @@ -57,60 +51,43 @@ class VisualizationViewer extends BaseComponent {
}
}

addTracer(className, tracerKey, title) {
const DataClass = {
Tracer: Data,
MarkdownTracer: MarkdownData,
LogTracer: LogData,
Array2DTracer: Array2DData,
Array1DTracer: Array1DData,
ChartTracer: ChartData,
GraphTracer: GraphData,
}[className];
const data = new DataClass(tracerKey, title, this.datas);
this.datas.push(data);
}

applyTrace(trace) {
const { tracerKey, method, args } = trace;
applyCommand(command) {
const { key, method, args } = command;
try {
if (method === 'construct') {
const [className, title] = args;
this.addTracer(className, tracerKey, title);
if (key === null && method === 'setRoot') {
const [root] = args;
this.root = this.objects[root];
} else if (method === 'destroy') {
delete this.objects[key];
} else if (method in LayoutClasses) {
const [children] = args;
const LayoutClass = LayoutClasses[method];
this.objects[key] = new LayoutClass(key, key => this.objects[key], children);
} else if (method in TracerClasses) {
const [title] = args;
const TracerClass = TracerClasses[method];
this.objects[key] = new TracerClass(key, key => this.objects[key], title);
} else {
const data = this.datas.find(data => data.tracerKey === tracerKey);
data[method](...args);
this.objects[key][method](...args);
}
} catch (error) {
this.handleError(error);
}
}

applyChunk(chunk) {
chunk.traces.forEach(trace => this.applyTrace(trace));
}

handleChangeWeights(weights) {
const dataWeights = {};
weights.forEach((weight, i) => {
dataWeights[this.datas[i].tracerKey] = weight;
});
this.setState({ dataWeights });
chunk.commands.forEach(command => this.applyCommand(command));
}

render() {
const { className } = this.props;
const { dataWeights } = this.state;

return (
<ResizableContainer className={classes(styles.visualization_viewer, className)}
weights={this.datas.map(data => dataWeights[data.tracerKey])}
visibles={this.datas.map(() => true)}
onChangeWeights={weights => this.handleChangeWeights(weights)}>
<div className={classes(styles.visualization_viewer, className)}>
{
this.datas.map(data => data.render())
this.root && this.root.render()
}
</ResizableContainer>
</div>
);
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/frontend/components/VisualizationViewer/stylesheet.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
@import "~/common/stylesheet/index";

.visualization_viewer {
}
flex: 1;
display: flex;
flex-direction: column;
align-items: stretch;
}
10 changes: 0 additions & 10 deletions src/frontend/core/datas/ChartData.js

This file was deleted.

7 changes: 0 additions & 7 deletions src/frontend/core/datas/index.js

This file was deleted.

6 changes: 6 additions & 0 deletions src/frontend/core/layouts/HorizontalLayout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Layout } from '/core/layouts';

class HorizontalLayout extends Layout {
}

export default HorizontalLayout;
Loading

0 comments on commit c7ec896

Please sign in to comment.