Compare commits
6 commits
develop
...
feature/ji
Author | SHA1 | Date | |
---|---|---|---|
|
355a0f014e | ||
|
1b2f7717ef | ||
|
7a465dc2fb | ||
|
67750b61b7 | ||
|
12ef63b20d | ||
|
a763484235 |
57 changed files with 2398 additions and 3754 deletions
|
@ -4,7 +4,7 @@ import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import outdent from 'outdent'
|
import outdent from 'outdent'
|
||||||
|
|
||||||
import ImportDialogBox from '../../routes/MapView/ImportDialogBox'
|
import ImportDialogBox from '../../components/ImportDialogBox'
|
||||||
|
|
||||||
import PasteInput from '../PasteInput'
|
import PasteInput from '../PasteInput'
|
||||||
import Map from '../Map'
|
import Map from '../Map'
|
||||||
|
|
|
@ -2,10 +2,13 @@
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
|
import { createStore } from 'redux'
|
||||||
|
import { Provider } from 'react-redux'
|
||||||
import { Router, browserHistory } from 'react-router'
|
import { Router, browserHistory } from 'react-router'
|
||||||
import { merge } from 'lodash'
|
import { merge } from 'lodash'
|
||||||
import apply from 'async/apply'
|
import apply from 'async/apply'
|
||||||
|
|
||||||
|
import reducers from '../../reducers'
|
||||||
import { notifyUser } from './index.js'
|
import { notifyUser } from './index.js'
|
||||||
import ImportDialog from './ImportDialog'
|
import ImportDialog from './ImportDialog'
|
||||||
import Notifications from './Notifications'
|
import Notifications from './Notifications'
|
||||||
|
@ -21,6 +24,11 @@ import Visualize from '../Visualize'
|
||||||
import makeRoutes from '../../routes/makeRoutes'
|
import makeRoutes from '../../routes/makeRoutes'
|
||||||
let routes
|
let routes
|
||||||
|
|
||||||
|
let store = createStore(
|
||||||
|
reducers,
|
||||||
|
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
|
||||||
|
)
|
||||||
|
|
||||||
// 220 wide + 16 padding on both sides
|
// 220 wide + 16 padding on both sides
|
||||||
const MAP_WIDTH = 252
|
const MAP_WIDTH = 252
|
||||||
const MOBILE_VIEW_BREAKPOINT = 504
|
const MOBILE_VIEW_BREAKPOINT = 504
|
||||||
|
@ -92,12 +100,15 @@ const ReactApp = {
|
||||||
render: function() {
|
render: function() {
|
||||||
const self = ReactApp
|
const self = ReactApp
|
||||||
const createElement = (Component, props) => <Component {...props} {...self.getProps()}/>
|
const createElement = (Component, props) => <Component {...props} {...self.getProps()}/>
|
||||||
const app = <Router createElement={createElement} routes={routes} history={browserHistory} onUpdate={self.handleUpdate} />
|
const app = <Provider store={store}>
|
||||||
|
<Router createElement={createElement} routes={routes} history={browserHistory} onUpdate={self.handleUpdate} />
|
||||||
|
</Provider>
|
||||||
ReactDOM.render(app, document.getElementById('react-app'))
|
ReactDOM.render(app, document.getElementById('react-app'))
|
||||||
},
|
},
|
||||||
getProps: function() {
|
getProps: function() {
|
||||||
const self = ReactApp
|
const self = ReactApp
|
||||||
return merge({
|
return merge({
|
||||||
|
DataModel: DataModel,
|
||||||
unreadNotificationsCount: Notifications.unreadNotificationsCount,
|
unreadNotificationsCount: Notifications.unreadNotificationsCount,
|
||||||
currentUser: Active.Mapper,
|
currentUser: Active.Mapper,
|
||||||
toast: self.toast,
|
toast: self.toast,
|
||||||
|
|
|
@ -23,8 +23,6 @@ import TopicCard from './Views/TopicCard'
|
||||||
import Util from './Util'
|
import Util from './Util'
|
||||||
import Visualize from './Visualize'
|
import Visualize from './Visualize'
|
||||||
|
|
||||||
let panningInt
|
|
||||||
|
|
||||||
const JIT = {
|
const JIT = {
|
||||||
tempInit: false,
|
tempInit: false,
|
||||||
tempNode: null,
|
tempNode: null,
|
||||||
|
@ -40,7 +38,6 @@ const JIT = {
|
||||||
zoom: 'Metamaps:JIT:events:zoom',
|
zoom: 'Metamaps:JIT:events:zoom',
|
||||||
animationDone: 'Metamaps:JIT:events:animationDone'
|
animationDone: 'Metamaps:JIT:events:animationDone'
|
||||||
},
|
},
|
||||||
vizData: [], // contains the visualization-compatible graph
|
|
||||||
/**
|
/**
|
||||||
* This method will bind the event handlers it is interested and initialize the class.
|
* This method will bind the event handlers it is interested and initialize the class.
|
||||||
*/
|
*/
|
||||||
|
@ -57,8 +54,6 @@ const JIT = {
|
||||||
*/
|
*/
|
||||||
convertModelsToJIT: function(topics, synapses) {
|
convertModelsToJIT: function(topics, synapses) {
|
||||||
const jitReady = []
|
const jitReady = []
|
||||||
|
|
||||||
const synapsesToRemove = []
|
|
||||||
let mapping
|
let mapping
|
||||||
let node
|
let node
|
||||||
const nodes = {}
|
const nodes = {}
|
||||||
|
@ -72,11 +67,7 @@ const JIT = {
|
||||||
})
|
})
|
||||||
synapses.each(function(s) {
|
synapses.each(function(s) {
|
||||||
edge = s.createEdge()
|
edge = s.createEdge()
|
||||||
|
if (nodes[edge.nodeFrom] && nodes[edge.nodeTo]) {
|
||||||
if (topics.get(s.get('topic1_id')) === undefined || topics.get(s.get('topic2_id')) === undefined) {
|
|
||||||
// this means it's an invalid synapse
|
|
||||||
synapsesToRemove.push(s)
|
|
||||||
} else if (nodes[edge.nodeFrom] && nodes[edge.nodeTo]) {
|
|
||||||
existingEdge = _.find(edges, {
|
existingEdge = _.find(edges, {
|
||||||
nodeFrom: edge.nodeFrom,
|
nodeFrom: edge.nodeFrom,
|
||||||
nodeTo: edge.nodeTo
|
nodeTo: edge.nodeTo
|
||||||
|
@ -105,29 +96,8 @@ const JIT = {
|
||||||
jitReady.push(node)
|
jitReady.push(node)
|
||||||
})
|
})
|
||||||
|
|
||||||
return [jitReady, synapsesToRemove]
|
return jitReady
|
||||||
},
|
},
|
||||||
prepareVizData: function() {
|
|
||||||
const self = JIT
|
|
||||||
let mapping
|
|
||||||
self.vizData = []
|
|
||||||
Visualize.loadLater = false
|
|
||||||
const results = self.convertModelsToJIT(DataModel.Topics, DataModel.Synapses)
|
|
||||||
self.vizData = results[0]
|
|
||||||
// clean up the synapses array in case of any faulty data
|
|
||||||
_.each(results[1], function(synapse) {
|
|
||||||
mapping = synapse.getMapping()
|
|
||||||
DataModel.Synapses.remove(synapse)
|
|
||||||
if (DataModel.Mappings) DataModel.Mappings.remove(mapping)
|
|
||||||
})
|
|
||||||
if (self.vizData.length === 0) {
|
|
||||||
Map.setHasLearnedTopicCreation(false)
|
|
||||||
Visualize.loadLater = true
|
|
||||||
} else {
|
|
||||||
Map.setHasLearnedTopicCreation(true)
|
|
||||||
}
|
|
||||||
Visualize.render()
|
|
||||||
}, // prepareVizData
|
|
||||||
edgeRender: function(adj, canvas) {
|
edgeRender: function(adj, canvas) {
|
||||||
// get nodes cartesian coordinates
|
// get nodes cartesian coordinates
|
||||||
const pos = adj.nodeFrom.pos.getc(true)
|
const pos = adj.nodeFrom.pos.getc(true)
|
||||||
|
@ -272,14 +242,27 @@ const JIT = {
|
||||||
graphSettings: {
|
graphSettings: {
|
||||||
// id of the visualization container
|
// id of the visualization container
|
||||||
injectInto: 'infovis',
|
injectInto: 'infovis',
|
||||||
// Enable zooming and panning
|
// Number of iterations for the FD algorithm
|
||||||
// by scrolling and DnD
|
iterations: 200,
|
||||||
|
// Edge length
|
||||||
|
levelDistance: 200,
|
||||||
Navigation: {
|
Navigation: {
|
||||||
enable: true,
|
enable: true,
|
||||||
// Enable panning events only if we're dragging the empty
|
|
||||||
// canvas (and not a node).
|
|
||||||
panning: 'avoid nodes',
|
panning: 'avoid nodes',
|
||||||
zooming: 28 // zoom speed. higher is more sensible
|
zooming: 28, // zoom speed. higher is more sensible
|
||||||
|
onZoom: function (event) {
|
||||||
|
$(document).trigger(Metamaps.JIT.events.zoom, [event]);
|
||||||
|
},
|
||||||
|
onPan: function () {
|
||||||
|
$(document).trigger(Metamaps.JIT.events.pan);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Selection: {
|
||||||
|
enable: true,
|
||||||
|
type: 'Native',
|
||||||
|
onDrawSelectBox: function (e, corner, oppositeCorner) {
|
||||||
|
JIT.selectWithBox(e, corner, oppositeCorner);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// Change node and edge styles such as
|
// Change node and edge styles such as
|
||||||
// color and width.
|
// color and width.
|
||||||
|
@ -299,81 +282,36 @@ const JIT = {
|
||||||
lineWidth: 2,
|
lineWidth: 2,
|
||||||
alpha: 1
|
alpha: 1
|
||||||
},
|
},
|
||||||
// Native canvas text styling
|
|
||||||
Label: {
|
Label: {
|
||||||
type: 'Native', // Native or HTML
|
type: 'Native',
|
||||||
size: 20,
|
size: 20,
|
||||||
family: 'arial',
|
family: 'arial',
|
||||||
textBaseline: 'alphabetic',
|
textBaseline: 'alphabetic',
|
||||||
color: Settings.colors.labels.text
|
color: Settings.colors.labels.text
|
||||||
},
|
},
|
||||||
// Add Tips
|
// this is events for clicking on edges and nodes in particular
|
||||||
Tips: {
|
|
||||||
enable: false,
|
|
||||||
onShow: function(tip, node) {}
|
|
||||||
},
|
|
||||||
// Add node events
|
|
||||||
Events: {
|
Events: {
|
||||||
enable: true,
|
enable: true,
|
||||||
enableForEdges: true,
|
enableForEdges: true,
|
||||||
onMouseMove: function(node, eventInfo, e) {
|
onMouseMove: function(node, eventInfo, e) {
|
||||||
JIT.onMouseMoveHandler(node, eventInfo, e)
|
JIT.onMouseMoveHandler(node, eventInfo, e)
|
||||||
// console.log('called mouse move handler')
|
|
||||||
},
|
},
|
||||||
// Update node positions when dragged
|
|
||||||
onDragMove: function(node, eventInfo, e) {
|
onDragMove: function(node, eventInfo, e) {
|
||||||
JIT.onDragMoveTopicHandler(node, eventInfo, e)
|
JIT.onDragMoveTopicHandler(node, eventInfo, e)
|
||||||
// console.log('called drag move handler')
|
|
||||||
},
|
},
|
||||||
onDragEnd: function(node, eventInfo, e) {
|
onDragEnd: function(node, eventInfo, e) {
|
||||||
JIT.onDragEndTopicHandler(node, eventInfo, e, false)
|
JIT.onDragEndTopicHandler(node, eventInfo, e, false)
|
||||||
// console.log('called drag end handler')
|
|
||||||
},
|
},
|
||||||
onDragCancel: function(node, eventInfo, e) {
|
onDragCancel: function(node, eventInfo, e) {
|
||||||
JIT.onDragCancelHandler(node, eventInfo, e, false)
|
JIT.onDragCancelHandler(node, eventInfo, e, false)
|
||||||
},
|
},
|
||||||
// Implement the same handler for touchscreens
|
|
||||||
onTouchStart: function(node, eventInfo, e) {},
|
|
||||||
// Implement the same handler for touchscreens
|
|
||||||
onTouchMove: function(node, eventInfo, e) {
|
onTouchMove: function(node, eventInfo, e) {
|
||||||
JIT.onDragMoveTopicHandler(node, eventInfo, e)
|
JIT.onDragMoveTopicHandler(node, eventInfo, e)
|
||||||
},
|
},
|
||||||
// Implement the same handler for touchscreens
|
|
||||||
onTouchEnd: function(node, eventInfo, e) {},
|
|
||||||
// Implement the same handler for touchscreens
|
|
||||||
onTouchCancel: function(node, eventInfo, e) {},
|
|
||||||
// Add also a click handler to nodes
|
|
||||||
onClick: function(node, eventInfo, e) {
|
onClick: function(node, eventInfo, e) {
|
||||||
// remove the rightclickmenu
|
// remove the rightclickmenu
|
||||||
ContextMenu.reset(ReactApp.render)
|
ContextMenu.reset(ReactApp.render)
|
||||||
|
|
||||||
if (Mouse.boxStartCoordinates) {
|
|
||||||
if (e.ctrlKey) {
|
|
||||||
Visualize.mGraph.busy = false
|
|
||||||
Mouse.boxEndCoordinates = eventInfo.getPos()
|
|
||||||
|
|
||||||
const bS = Mouse.boxStartCoordinates
|
|
||||||
const bE = Mouse.boxEndCoordinates
|
|
||||||
if (Math.abs(bS.x - bE.x) > 20 && Math.abs(bS.y - bE.y) > 20) {
|
|
||||||
JIT.zoomToBox(e)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
Mouse.boxStartCoordinates = null
|
|
||||||
Mouse.boxEndCoordinates = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.shiftKey) {
|
|
||||||
Visualize.mGraph.busy = false
|
|
||||||
Mouse.boxEndCoordinates = eventInfo.getPos()
|
|
||||||
JIT.selectWithBox(e)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.target.id !== 'infovis-canvas') return false
|
if (e.target.id !== 'infovis-canvas') return false
|
||||||
|
|
||||||
// clicking on a edge, node, or clicking on blank part of canvas?
|
// clicking on a edge, node, or clicking on blank part of canvas?
|
||||||
if (node.nodeFrom) {
|
if (node.nodeFrom) {
|
||||||
JIT.selectEdgeOnClickHandler(node, e)
|
JIT.selectEdgeOnClickHandler(node, e)
|
||||||
|
@ -387,34 +325,15 @@ const JIT = {
|
||||||
onRightClick: function(node, eventInfo, e) {
|
onRightClick: function(node, eventInfo, e) {
|
||||||
// remove the rightclickmenu
|
// remove the rightclickmenu
|
||||||
ContextMenu.reset(ReactApp.render)
|
ContextMenu.reset(ReactApp.render)
|
||||||
|
|
||||||
if (Mouse.boxStartCoordinates) {
|
|
||||||
Create.newSynapse.hide()
|
|
||||||
Create.newTopic.hide()
|
|
||||||
Visualize.mGraph.busy = false
|
|
||||||
Mouse.boxEndCoordinates = eventInfo.getPos()
|
|
||||||
JIT.selectWithBox(e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.target.id !== 'infovis-canvas') return false
|
if (e.target.id !== 'infovis-canvas') return false
|
||||||
|
|
||||||
// clicking on a edge, node, or clicking on blank part of canvas?
|
// clicking on a edge, node, or clicking on blank part of canvas?
|
||||||
if (node.nodeFrom) {
|
if (node.nodeFrom) {
|
||||||
JIT.selectEdgeOnRightClickHandler(node, e)
|
JIT.selectEdgeOnRightClickHandler(node, e)
|
||||||
} else if (node && !node.nodeFrom) {
|
} else if (node && !node.nodeFrom) {
|
||||||
JIT.selectNodeOnRightClickHandler(node, e)
|
JIT.selectNodeOnRightClickHandler(node, e)
|
||||||
} else {
|
|
||||||
// right click open space
|
|
||||||
Create.newSynapse.hide()
|
|
||||||
Create.newTopic.hide()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
// Number of iterations for the FD algorithm
|
|
||||||
iterations: 200,
|
|
||||||
// Edge length
|
|
||||||
levelDistance: 200
|
|
||||||
},
|
},
|
||||||
nodeSettings: {
|
nodeSettings: {
|
||||||
'customNode': {
|
'customNode': {
|
||||||
|
@ -509,97 +428,7 @@ const JIT = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, // ForceDirected
|
},
|
||||||
ForceDirected3D: {
|
|
||||||
animate: {
|
|
||||||
modes: ['linear'],
|
|
||||||
// TODO fix tests so we don't need _.get
|
|
||||||
transition: _.get($jit, 'Trans.Elastic.easeOut'),
|
|
||||||
duration: 2500,
|
|
||||||
onComplete: function() {
|
|
||||||
Visualize.mGraph.busy = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
graphSettings: {
|
|
||||||
// id of the visualization container
|
|
||||||
injectInto: 'infovis',
|
|
||||||
type: '3D',
|
|
||||||
Scene: {
|
|
||||||
Lighting: {
|
|
||||||
enable: false,
|
|
||||||
ambient: [0.5, 0.5, 0.5],
|
|
||||||
directional: {
|
|
||||||
direction: {
|
|
||||||
x: 1,
|
|
||||||
y: 0,
|
|
||||||
z: -1
|
|
||||||
},
|
|
||||||
color: [0.9, 0.9, 0.9]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Enable zooming and panning
|
|
||||||
// by scrolling and DnD
|
|
||||||
Navigation: {
|
|
||||||
enable: false,
|
|
||||||
// Enable panning events only if we're dragging the empty
|
|
||||||
// canvas (and not a node).
|
|
||||||
panning: 'avoid nodes',
|
|
||||||
zooming: 10 // zoom speed. higher is more sensible
|
|
||||||
},
|
|
||||||
// Change node and edge styles such as
|
|
||||||
// color and width.
|
|
||||||
// These properties are also set per node
|
|
||||||
// with dollar prefixed data-properties in the
|
|
||||||
// JSON structure.
|
|
||||||
Node: {
|
|
||||||
overridable: true,
|
|
||||||
type: 'sphere',
|
|
||||||
dim: 15,
|
|
||||||
color: '#ffffff'
|
|
||||||
},
|
|
||||||
Edge: {
|
|
||||||
overridable: false,
|
|
||||||
type: 'tube',
|
|
||||||
color: '#111',
|
|
||||||
lineWidth: 3
|
|
||||||
},
|
|
||||||
// Native canvas text styling
|
|
||||||
Label: {
|
|
||||||
type: 'HTML', // Native or HTML
|
|
||||||
size: 10,
|
|
||||||
style: 'bold'
|
|
||||||
},
|
|
||||||
// Add node events
|
|
||||||
Events: {
|
|
||||||
enable: true,
|
|
||||||
type: 'Native',
|
|
||||||
i: 0,
|
|
||||||
onMouseMove: function(node, eventInfo, e) {
|
|
||||||
// if(this.i++ % 3) return
|
|
||||||
const pos = eventInfo.getPos()
|
|
||||||
Visualize.cameraPosition.x += (pos.x - Visualize.cameraPosition.x) * 0.5
|
|
||||||
Visualize.cameraPosition.y += (-pos.y - Visualize.cameraPosition.y) * 0.5
|
|
||||||
Visualize.mGraph.plot()
|
|
||||||
},
|
|
||||||
onMouseWheel: function(delta) {
|
|
||||||
Visualize.cameraPosition.z += -delta * 20
|
|
||||||
Visualize.mGraph.plot()
|
|
||||||
},
|
|
||||||
onClick: function() {}
|
|
||||||
},
|
|
||||||
// Number of iterations for the FD algorithm
|
|
||||||
iterations: 200,
|
|
||||||
// Edge length
|
|
||||||
levelDistance: 100
|
|
||||||
},
|
|
||||||
nodeSettings: {
|
|
||||||
|
|
||||||
},
|
|
||||||
edgeSettings: {
|
|
||||||
|
|
||||||
}
|
|
||||||
}, // ForceDirected3D
|
|
||||||
RGraph: {
|
RGraph: {
|
||||||
animate: {
|
animate: {
|
||||||
modes: ['polar'],
|
modes: ['polar'],
|
||||||
|
@ -1103,12 +932,12 @@ const JIT = {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
selectWithBox: function(e) {
|
selectWithBox: function(e, corner, oppositeCorner) {
|
||||||
const self = this
|
const self = this
|
||||||
let sX = Mouse.boxStartCoordinates.x
|
let sX = corner.x
|
||||||
let sY = Mouse.boxStartCoordinates.y
|
let sY = corner.y
|
||||||
let eX = Mouse.boxEndCoordinates.x
|
let eX = oppositeCorner.x
|
||||||
let eY = Mouse.boxEndCoordinates.y
|
let eY = oppositeCorner.y
|
||||||
|
|
||||||
if (!e.shiftKey) {
|
if (!e.shiftKey) {
|
||||||
Control.deselectAllNodes()
|
Control.deselectAllNodes()
|
||||||
|
@ -1245,30 +1074,7 @@ const JIT = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Mouse.boxStartCoordinates = false
|
|
||||||
Mouse.boxEndCoordinates = false
|
|
||||||
Visualize.mGraph.plot()
|
|
||||||
}, // selectWithBox
|
}, // selectWithBox
|
||||||
drawSelectBox: function(eventInfo, e) {
|
|
||||||
const ctx = Visualize.mGraph.canvas.getCtx()
|
|
||||||
|
|
||||||
const startX = Mouse.boxStartCoordinates.x
|
|
||||||
const startY = Mouse.boxStartCoordinates.y
|
|
||||||
const currX = eventInfo.getPos().x
|
|
||||||
const currY = eventInfo.getPos().y
|
|
||||||
|
|
||||||
Visualize.mGraph.canvas.clear()
|
|
||||||
Visualize.mGraph.plot()
|
|
||||||
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.moveTo(startX, startY)
|
|
||||||
ctx.lineTo(startX, currY)
|
|
||||||
ctx.lineTo(currX, currY)
|
|
||||||
ctx.lineTo(currX, startY)
|
|
||||||
ctx.lineTo(startX, startY)
|
|
||||||
ctx.strokeStyle = 'black'
|
|
||||||
ctx.stroke()
|
|
||||||
}, // drawSelectBox
|
|
||||||
selectNodeOnClickHandler: function(node, e) {
|
selectNodeOnClickHandler: function(node, e) {
|
||||||
if (Visualize.mGraph.busy) return
|
if (Visualize.mGraph.busy) return
|
||||||
|
|
||||||
|
@ -1398,26 +1204,6 @@ const JIT = {
|
||||||
Control.selectEdge(adj)
|
Control.selectEdge(adj)
|
||||||
ContextMenu.selectEdge(ReactApp.render, adj, {x: e.clientX, y: e.clientY})
|
ContextMenu.selectEdge(ReactApp.render, adj, {x: e.clientX, y: e.clientY})
|
||||||
}, // selectEdgeOnRightClickHandler
|
}, // selectEdgeOnRightClickHandler
|
||||||
SmoothPanning: function() {
|
|
||||||
const sx = Visualize.mGraph.canvas.scaleOffsetX
|
|
||||||
const sy = Visualize.mGraph.canvas.scaleOffsetY
|
|
||||||
const yVelocity = Mouse.changeInY // initial y velocity
|
|
||||||
const xVelocity = Mouse.changeInX // initial x velocity
|
|
||||||
let easing = 1 // frictional value
|
|
||||||
|
|
||||||
window.clearInterval(panningInt)
|
|
||||||
panningInt = setInterval(function() {
|
|
||||||
myTimer()
|
|
||||||
}, 1)
|
|
||||||
|
|
||||||
function myTimer() {
|
|
||||||
Visualize.mGraph.canvas.translate(xVelocity * easing * 1 / sx, yVelocity * easing * 1 / sy)
|
|
||||||
$(document).trigger(JIT.events.pan)
|
|
||||||
easing = easing * 0.75
|
|
||||||
|
|
||||||
if (easing < 0.1) window.clearInterval(panningInt)
|
|
||||||
}
|
|
||||||
}, // SmoothPanning
|
|
||||||
renderMidArrow: function(from, to, dim, swap, canvas, placement, newSynapse) {
|
renderMidArrow: function(from, to, dim, swap, canvas, placement, newSynapse) {
|
||||||
const ctx = canvas.getCtx()
|
const ctx = canvas.getCtx()
|
||||||
// invert edge direction
|
// invert edge direction
|
||||||
|
@ -1522,53 +1308,11 @@ const JIT = {
|
||||||
},
|
},
|
||||||
centerMap: function(canvas) {
|
centerMap: function(canvas) {
|
||||||
const offsetScale = canvas.scaleOffsetX
|
const offsetScale = canvas.scaleOffsetX
|
||||||
|
|
||||||
canvas.scale(1 / offsetScale, 1 / offsetScale)
|
|
||||||
|
|
||||||
const offsetX = canvas.translateOffsetX
|
const offsetX = canvas.translateOffsetX
|
||||||
const offsetY = canvas.translateOffsetY
|
const offsetY = canvas.translateOffsetY
|
||||||
|
canvas.scale(1 / offsetScale, 1 / offsetScale)
|
||||||
canvas.translate(-1 * offsetX, -1 * offsetY)
|
canvas.translate(-1 * offsetX, -1 * offsetY)
|
||||||
},
|
},
|
||||||
zoomToBox: function(event) {
|
|
||||||
const sX = Mouse.boxStartCoordinates.x
|
|
||||||
const sY = Mouse.boxStartCoordinates.y
|
|
||||||
const eX = Mouse.boxEndCoordinates.x
|
|
||||||
const eY = Mouse.boxEndCoordinates.y
|
|
||||||
|
|
||||||
let canvas = Visualize.mGraph.canvas
|
|
||||||
JIT.centerMap(canvas)
|
|
||||||
|
|
||||||
let height = $(document).height()
|
|
||||||
let width = $(document).width()
|
|
||||||
|
|
||||||
let spanX = Math.abs(sX - eX)
|
|
||||||
let spanY = Math.abs(sY - eY)
|
|
||||||
let ratioX = width / spanX
|
|
||||||
let ratioY = height / spanY
|
|
||||||
|
|
||||||
let newRatio = Math.min(ratioX, ratioY)
|
|
||||||
|
|
||||||
if (canvas.scaleOffsetX * newRatio <= 5 && canvas.scaleOffsetX * newRatio >= 0.2) {
|
|
||||||
canvas.scale(newRatio, newRatio)
|
|
||||||
} else if (canvas.scaleOffsetX * newRatio > 5) {
|
|
||||||
newRatio = 5 / canvas.scaleOffsetX
|
|
||||||
canvas.scale(newRatio, newRatio)
|
|
||||||
} else {
|
|
||||||
newRatio = 0.2 / canvas.scaleOffsetX
|
|
||||||
canvas.scale(newRatio, newRatio)
|
|
||||||
}
|
|
||||||
|
|
||||||
const cogX = (sX + eX) / 2
|
|
||||||
const cogY = (sY + eY) / 2
|
|
||||||
|
|
||||||
canvas.translate(-1 * cogX, -1 * cogY)
|
|
||||||
$(document).trigger(JIT.events.zoom, [event])
|
|
||||||
|
|
||||||
Mouse.boxStartCoordinates = false
|
|
||||||
Mouse.boxEndCoordinates = false
|
|
||||||
Visualize.mGraph.plot()
|
|
||||||
},
|
|
||||||
zoomExtents: function(event, canvas, denySelected) {
|
zoomExtents: function(event, canvas, denySelected) {
|
||||||
JIT.centerMap(canvas)
|
JIT.centerMap(canvas)
|
||||||
let height = canvas.getSize().height
|
let height = canvas.getSize().height
|
||||||
|
|
6
frontend/src/Metamaps/JitExtended.js
Normal file
6
frontend/src/Metamaps/JitExtended.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import $jit from '../patched/JIT'
|
||||||
|
|
||||||
|
const mJit = {}
|
||||||
|
$jit(mJit)
|
||||||
|
|
||||||
|
export default mJit
|
|
@ -1,7 +1,7 @@
|
||||||
/* global $ */
|
/* global $ */
|
||||||
|
|
||||||
import outdent from 'outdent'
|
import outdent from 'outdent'
|
||||||
import { find as _find } from 'lodash'
|
import _, { find as _find } from 'lodash'
|
||||||
import { browserHistory } from 'react-router'
|
import { browserHistory } from 'react-router'
|
||||||
|
|
||||||
import Active from '../Active'
|
import Active from '../Active'
|
||||||
|
@ -89,12 +89,31 @@ const Map = {
|
||||||
}
|
}
|
||||||
ReactApp.render()
|
ReactApp.render()
|
||||||
},
|
},
|
||||||
|
cleanUpSynapses: function () {
|
||||||
|
const synapsesToRemove = []
|
||||||
|
const topics = DataModel.Topics
|
||||||
|
DataModel.Synapses.each(function(s) {
|
||||||
|
if (topics.get(s.get('topic1_id')) === undefined || topics.get(s.get('topic2_id')) === undefined) {
|
||||||
|
// this means it's an invalid synapse
|
||||||
|
synapsesToRemove.push(s)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// clean up the synapses array in case of any faulty data
|
||||||
|
_.each(synapsesToRemove, function(synapse) {
|
||||||
|
mapping = synapse.getMapping()
|
||||||
|
DataModel.Synapses.remove(synapse)
|
||||||
|
if (DataModel.Mappings) DataModel.Mappings.remove(mapping)
|
||||||
|
})
|
||||||
|
},
|
||||||
launch: function(id) {
|
launch: function(id) {
|
||||||
const self = Map
|
const self = Map
|
||||||
var dataIsReadySetupMap = function() {
|
var dataIsReadySetupMap = function() {
|
||||||
|
if (DataModel.Topics.length === 0) {
|
||||||
|
Map.setHasLearnedTopicCreation(false)
|
||||||
|
} else {
|
||||||
|
Map.setHasLearnedTopicCreation(true)
|
||||||
|
}
|
||||||
Map.setAccessRequest()
|
Map.setAccessRequest()
|
||||||
Visualize.type = 'ForceDirected'
|
|
||||||
JIT.prepareVizData()
|
|
||||||
Selected.reset()
|
Selected.reset()
|
||||||
InfoBox.load()
|
InfoBox.load()
|
||||||
Filter.reset()
|
Filter.reset()
|
||||||
|
@ -127,6 +146,7 @@ const Map = {
|
||||||
DataModel.Mappings = new DataModel.MappingCollection(data.mappings)
|
DataModel.Mappings = new DataModel.MappingCollection(data.mappings)
|
||||||
DataModel.Messages = data.messages
|
DataModel.Messages = data.messages
|
||||||
DataModel.Stars = data.stars
|
DataModel.Stars = data.stars
|
||||||
|
Map.cleanUpSynapses()
|
||||||
DataModel.attachCollectionEvents()
|
DataModel.attachCollectionEvents()
|
||||||
self.requests = data.requests
|
self.requests = data.requests
|
||||||
isLoaded()
|
isLoaded()
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
const Mouse = {
|
const Mouse = {
|
||||||
didPan: false,
|
|
||||||
didBoxZoom: false,
|
|
||||||
changeInX: 0,
|
|
||||||
changeInY: 0,
|
|
||||||
edgeHoveringOver: false,
|
edgeHoveringOver: false,
|
||||||
boxStartCoordinates: false,
|
|
||||||
boxEndCoordinates: false,
|
|
||||||
synapseStartCoordinates: [],
|
synapseStartCoordinates: [],
|
||||||
synapseEndCoordinates: null,
|
synapseEndCoordinates: null,
|
||||||
lastNodeClick: 0,
|
lastNodeClick: 0,
|
||||||
|
|
|
@ -201,34 +201,6 @@ const Util = {
|
||||||
},
|
},
|
||||||
isTester: function(currentUser) {
|
isTester: function(currentUser) {
|
||||||
return ['connorturland@gmail.com', 'devin@callysto.com', 'chessscholar@gmail.com', 'solaureum@gmail.com', 'ishanshapiro@gmail.com'].indexOf(currentUser.get('email')) > -1
|
return ['connorturland@gmail.com', 'devin@callysto.com', 'chessscholar@gmail.com', 'solaureum@gmail.com', 'ishanshapiro@gmail.com'].indexOf(currentUser.get('email')) > -1
|
||||||
},
|
|
||||||
zoomOnPoint: function(graph, ans, zoomPoint) {
|
|
||||||
var s = graph.canvas.getSize(),
|
|
||||||
p = graph.canvas.getPos(),
|
|
||||||
ox = graph.canvas.translateOffsetX,
|
|
||||||
oy = graph.canvas.translateOffsetY,
|
|
||||||
sx = graph.canvas.scaleOffsetX,
|
|
||||||
sy = graph.canvas.scaleOffsetY
|
|
||||||
|
|
||||||
var pointerCoordX = (zoomPoint.x - p.x - s.width / 2 - ox) * (1 / sx),
|
|
||||||
pointerCoordY = (zoomPoint.y - p.y - s.height / 2 - oy) * (1 / sy)
|
|
||||||
|
|
||||||
// This translates the canvas to be centred over the zoomPoint, then the canvas is zoomed as intended.
|
|
||||||
graph.canvas.translate(-pointerCoordX, -pointerCoordY)
|
|
||||||
graph.canvas.scale(ans, ans)
|
|
||||||
|
|
||||||
// Get the canvas attributes again now that is has changed
|
|
||||||
s = graph.canvas.getSize(),
|
|
||||||
p = graph.canvas.getPos(),
|
|
||||||
ox = graph.canvas.translateOffsetX,
|
|
||||||
oy = graph.canvas.translateOffsetY,
|
|
||||||
sx = graph.canvas.scaleOffsetX,
|
|
||||||
sy = graph.canvas.scaleOffsetY
|
|
||||||
var newX = (zoomPoint.x - p.x - s.width / 2 - ox) * (1 / sx),
|
|
||||||
newY = (zoomPoint.y - p.y - s.height / 2 - oy) * (1 / sy)
|
|
||||||
|
|
||||||
// Translate the canvas to put the pointer back over top the same coordinate it was over before
|
|
||||||
graph.canvas.translate(newX - pointerCoordX, newY - pointerCoordY)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,15 +11,12 @@ import Loading from './Loading'
|
||||||
import TopicCard from './Views/TopicCard'
|
import TopicCard from './Views/TopicCard'
|
||||||
|
|
||||||
const Visualize = {
|
const Visualize = {
|
||||||
mGraph: null, // a reference to the graph object.
|
|
||||||
cameraPosition: null, // stores the camera position when using a 3D visualization
|
|
||||||
type: 'ForceDirected', // the type of graph we're building, could be "RGraph", "ForceDirected", or "ForceDirected3D"
|
|
||||||
loadLater: false, // indicates whether there is JSON that should be loaded right in the offset, or whether to wait till the first topic is created
|
|
||||||
touchDragNode: null,
|
|
||||||
init: function(serverData) {
|
init: function(serverData) {
|
||||||
var self = Visualize
|
var self = Visualize
|
||||||
|
|
||||||
if (serverData.VisualizeType) self.type = serverData.VisualizeType
|
$jit.RGraph.Plot.NodeTypes.implement(JIT.ForceDirected.nodeSettings)
|
||||||
|
$jit.RGraph.Plot.EdgeTypes.implement(JIT.ForceDirected.edgeSettings)
|
||||||
|
|
||||||
|
|
||||||
// disable awkward dragging of the canvas element that would sometimes happen
|
// disable awkward dragging of the canvas element that would sometimes happen
|
||||||
$('#infovis-canvas').on('dragstart', function(event) {
|
$('#infovis-canvas').on('dragstart', function(event) {
|
||||||
|
@ -32,75 +29,41 @@ const Visualize = {
|
||||||
self.mGraph.events.touched = true
|
self.mGraph.events.touched = true
|
||||||
})
|
})
|
||||||
|
|
||||||
// prevent touch events on the canvas from default behaviour
|
|
||||||
$('#infovis-canvas').bind('touchmove', function(event) {
|
|
||||||
// JIT.touchPanZoomHandler(event)
|
|
||||||
})
|
|
||||||
|
|
||||||
// prevent touch events on the canvas from default behaviour
|
// prevent touch events on the canvas from default behaviour
|
||||||
$('#infovis-canvas').bind('touchend touchcancel', function(event) {
|
$('#infovis-canvas').bind('touchend touchcancel', function(event) {
|
||||||
if (!self.mGraph.events.touchMoved && !Visualize.touchDragNode) TopicCard.hideCurrentCard()
|
if (!self.mGraph.events.touchMoved) TopicCard.hideCurrentCard()
|
||||||
self.mGraph.events.touched = self.mGraph.events.touchMoved = false
|
self.mGraph.events.touched = self.mGraph.events.touchMoved = false
|
||||||
Visualize.touchDragNode = false
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
computePositions: function() {
|
computePositions: function() {
|
||||||
const self = Visualize
|
const self = Visualize
|
||||||
|
|
||||||
if (self.type === 'RGraph') {
|
// for RGraph
|
||||||
let i
|
let i
|
||||||
let l
|
let l
|
||||||
|
|
||||||
self.mGraph.graph.eachNode(function(n) {
|
self.mGraph.graph.eachNode(function(n) {
|
||||||
const topic = DataModel.Topics.get(n.id)
|
const topic = DataModel.Topics.get(n.id)
|
||||||
topic.set({ node: n }, { silent: true })
|
topic.set({ node: n }, { silent: true })
|
||||||
topic.updateNode()
|
topic.updateNode()
|
||||||
|
|
||||||
n.eachAdjacency(function(edge) {
|
n.eachAdjacency(function(edge) {
|
||||||
if (!edge.getData('init')) {
|
if (!edge.getData('init')) {
|
||||||
edge.setData('init', true)
|
edge.setData('init', true)
|
||||||
|
|
||||||
l = edge.getData('synapseIDs').length
|
l = edge.getData('synapseIDs').length
|
||||||
for (i = 0; i < l; i++) {
|
for (i = 0; i < l; i++) {
|
||||||
const synapse = DataModel.Synapses.get(edge.getData('synapseIDs')[i])
|
const synapse = DataModel.Synapses.get(edge.getData('synapseIDs')[i])
|
||||||
synapse.set({ edge: edge }, { silent: true })
|
synapse.set({ edge: edge }, { silent: true })
|
||||||
synapse.updateEdge()
|
synapse.updateEdge()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
var pos = n.getPos()
|
|
||||||
pos.setc(-200, -200)
|
|
||||||
})
|
})
|
||||||
self.mGraph.compute('end')
|
|
||||||
} else if (self.type === 'ForceDirected') {
|
|
||||||
self.mGraph.graph.eachNode(function(n) {
|
|
||||||
const topic = DataModel.Topics.get(n.id)
|
|
||||||
topic.set({ node: n }, { silent: true })
|
|
||||||
topic.updateNode()
|
|
||||||
const mapping = topic.getMapping()
|
|
||||||
|
|
||||||
n.eachAdjacency(function(edge) {
|
var pos = n.getPos()
|
||||||
if (!edge.getData('init')) {
|
pos.setc(-200, -200)
|
||||||
edge.setData('init', true)
|
})
|
||||||
|
self.mGraph.compute('end')
|
||||||
const l = edge.getData('synapseIDs').length
|
|
||||||
for (let i = 0; i < l; i++) {
|
|
||||||
const synapse = DataModel.Synapses.get(edge.getData('synapseIDs')[i])
|
|
||||||
synapse.set({ edge: edge }, { silent: true })
|
|
||||||
synapse.updateEdge()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const startPos = new $jit.Complex(0, 0)
|
|
||||||
const endPos = new $jit.Complex(mapping.get('xloc'), mapping.get('yloc'))
|
|
||||||
n.setPos(startPos, 'start')
|
|
||||||
n.setPos(endPos, 'end')
|
|
||||||
})
|
|
||||||
} else if (self.type === 'ForceDirected3D') {
|
|
||||||
self.mGraph.compute()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* render does the heavy lifting of creating the engine that renders the graph with the properties we desire
|
* render does the heavy lifting of creating the engine that renders the graph with the properties we desire
|
||||||
|
@ -108,101 +71,12 @@ const Visualize = {
|
||||||
*/
|
*/
|
||||||
render: function() {
|
render: function() {
|
||||||
const self = Visualize
|
const self = Visualize
|
||||||
|
const RGraphSettings = $.extend(true, {}, JIT.ForceDirected.graphSettings)
|
||||||
if (self.type === 'RGraph') {
|
RGraphSettings.width = $(document).width()
|
||||||
// clear the previous canvas from #infovis
|
RGraphSettings.height = $(document).height()
|
||||||
$('#infovis').empty()
|
RGraphSettings.background = JIT.RGraph.background
|
||||||
|
RGraphSettings.levelDistance = JIT.RGraph.levelDistance
|
||||||
const RGraphSettings = $.extend(true, {}, JIT.ForceDirected.graphSettings)
|
self.mGraph = new $jit.RGraph(RGraphSettings)
|
||||||
|
|
||||||
$jit.RGraph.Plot.NodeTypes.implement(JIT.ForceDirected.nodeSettings)
|
|
||||||
$jit.RGraph.Plot.EdgeTypes.implement(JIT.ForceDirected.edgeSettings)
|
|
||||||
|
|
||||||
RGraphSettings.width = $(document).width()
|
|
||||||
RGraphSettings.height = $(document).height()
|
|
||||||
RGraphSettings.background = JIT.RGraph.background
|
|
||||||
RGraphSettings.levelDistance = JIT.RGraph.levelDistance
|
|
||||||
|
|
||||||
self.mGraph = new $jit.RGraph(RGraphSettings)
|
|
||||||
} else if (self.type === 'ForceDirected') {
|
|
||||||
// clear the previous canvas from #infovis
|
|
||||||
$('#infovis').empty()
|
|
||||||
|
|
||||||
const FDSettings = $.extend(true, {}, JIT.ForceDirected.graphSettings)
|
|
||||||
|
|
||||||
$jit.ForceDirected.Plot.NodeTypes.implement(JIT.ForceDirected.nodeSettings)
|
|
||||||
$jit.ForceDirected.Plot.EdgeTypes.implement(JIT.ForceDirected.edgeSettings)
|
|
||||||
|
|
||||||
FDSettings.width = $('body').width()
|
|
||||||
FDSettings.height = $('body').height()
|
|
||||||
|
|
||||||
self.mGraph = new $jit.ForceDirected(FDSettings)
|
|
||||||
} else if (self.type === 'ForceDirected3D' && !self.mGraph) {
|
|
||||||
// clear the previous canvas from #infovis
|
|
||||||
$('#infovis').empty()
|
|
||||||
|
|
||||||
// init ForceDirected3D
|
|
||||||
self.mGraph = new $jit.ForceDirected3D(JIT.ForceDirected3D.graphSettings)
|
|
||||||
self.cameraPosition = self.mGraph.canvas.canvases[0].camera.position
|
|
||||||
} else {
|
|
||||||
self.mGraph.graph.empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
function runAnimation() {
|
|
||||||
Loading.hide()
|
|
||||||
// load JSON data, if it's not empty
|
|
||||||
if (!self.loadLater) {
|
|
||||||
// load JSON data.
|
|
||||||
var rootIndex = 0
|
|
||||||
if (Active.Topic) {
|
|
||||||
var node = _.find(JIT.vizData, function(node) {
|
|
||||||
return node.id === Active.Topic.id
|
|
||||||
})
|
|
||||||
rootIndex = _.indexOf(JIT.vizData, node)
|
|
||||||
}
|
|
||||||
self.mGraph.loadJSON(JIT.vizData, rootIndex)
|
|
||||||
// compute positions and plot.
|
|
||||||
self.computePositions()
|
|
||||||
self.mGraph.busy = true
|
|
||||||
if (self.type === 'RGraph') {
|
|
||||||
self.mGraph.fx.animate(JIT.RGraph.animate)
|
|
||||||
} else if (self.type === 'ForceDirected') {
|
|
||||||
self.mGraph.animate(JIT.ForceDirected.animateSavedLayout)
|
|
||||||
} else if (self.type === 'ForceDirected3D') {
|
|
||||||
self.mGraph.animate(JIT.ForceDirected.animateFDLayout)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// hold until all the needed metacode images are loaded
|
|
||||||
// hold for a maximum of 80 passes, or 4 seconds of waiting time
|
|
||||||
var tries = 0
|
|
||||||
function hold() {
|
|
||||||
const unique = _.uniq(DataModel.Topics.models, function(metacode) { return metacode.get('metacode_id') })
|
|
||||||
const requiredMetacodes = _.map(unique, function(metacode) { return metacode.get('metacode_id') })
|
|
||||||
let loadedCount = 0
|
|
||||||
|
|
||||||
_.each(requiredMetacodes, function(metacodeId) {
|
|
||||||
const metacode = DataModel.Metacodes.get(metacodeId)
|
|
||||||
const img = metacode ? metacode.get('image') : false
|
|
||||||
|
|
||||||
if (img && (img.complete || (typeof img.naturalWidth !== 'undefined' && img.naturalWidth !== 0))) {
|
|
||||||
loadedCount += 1
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (loadedCount === requiredMetacodes.length || tries > 80) {
|
|
||||||
runAnimation()
|
|
||||||
} else {
|
|
||||||
setTimeout(function() { tries++; hold() }, 50)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hold()
|
|
||||||
},
|
|
||||||
clearVisualization: function() {
|
|
||||||
Visualize.mGraph.graph.empty()
|
|
||||||
Visualize.mGraph.plot()
|
|
||||||
JIT.centerMap(Visualize.mGraph.canvas)
|
|
||||||
$('#infovis').empty()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import GlobalUI, {
|
||||||
} from './GlobalUI'
|
} from './GlobalUI'
|
||||||
import Import from './Import'
|
import Import from './Import'
|
||||||
import JIT from './JIT'
|
import JIT from './JIT'
|
||||||
|
import JitExtended from './JitExtended'
|
||||||
import Listeners from './Listeners'
|
import Listeners from './Listeners'
|
||||||
import Loading from './Loading'
|
import Loading from './Loading'
|
||||||
import Map, { CheatSheet, InfoBox } from './Map'
|
import Map, { CheatSheet, InfoBox } from './Map'
|
||||||
|
@ -49,6 +50,7 @@ Metamaps.GlobalUI.CreateMap = CreateMap
|
||||||
Metamaps.GlobalUI.ImportDialog = ImportDialog
|
Metamaps.GlobalUI.ImportDialog = ImportDialog
|
||||||
Metamaps.Import = Import
|
Metamaps.Import = Import
|
||||||
Metamaps.JIT = JIT
|
Metamaps.JIT = JIT
|
||||||
|
Metamaps.JitExtended = JitExtended
|
||||||
Metamaps.Listeners = Listeners
|
Metamaps.Listeners = Listeners
|
||||||
Metamaps.Loading = Loading
|
Metamaps.Loading = Loading
|
||||||
Metamaps.Map = Map
|
Metamaps.Map = Map
|
||||||
|
|
96
frontend/src/actions/constants.js
Normal file
96
frontend/src/actions/constants.js
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
export const OPEN_CHAT = 'OPEN_CHAT'
|
||||||
|
export const CLOSE_CHAT = 'CLOSE_CHAT'
|
||||||
|
export const CREATE_MESSAGE = 'CREATE_MESSAGE'
|
||||||
|
|
||||||
|
export const OPEN_NOTIFICATIONS = 'OPEN_NOTIFICATIONS'
|
||||||
|
export const CLOSE_NOTIFICATIONS = 'CLOSE_NOTIFICATIONS'
|
||||||
|
export const MARK_NOTIFICATION_READ = 'MARK_NOTIFICATION_READ'
|
||||||
|
export const MARK_NOTIFICATION_UNREAD = 'MARK_NOTIFICATION_UNREAD'
|
||||||
|
|
||||||
|
export const OPEN_ACCOUNT_MENU = 'OPEN_ACCOUNT_MENU'
|
||||||
|
export const CLOSE_ACCOUNT_MENU = 'CLOSE_ACCOUNT_MENU'
|
||||||
|
export const STAR_MAP = 'STAR_MAP'
|
||||||
|
export const UNSTAR_MAP = 'UNSTAR_MAP'
|
||||||
|
export const FOLLOW_MAP = 'FOLLOW_MAP'
|
||||||
|
export const UNFOLLOW_MAP = 'UNFOLLOW_MAP'
|
||||||
|
export const FOLLOW_TOPIC = 'FOLLOW_TOPIC'
|
||||||
|
export const UNFOLLOW_TOPIC = 'UNFOLLOW_TOPIC'
|
||||||
|
|
||||||
|
export const PIN_CREATE_TOPIC = 'PIN_CREATE_TOPIC_OPEN'
|
||||||
|
export const UNPIN_CREATE_TOPIC = 'UNPIN_CREATE_TOPIC'
|
||||||
|
export const OPEN_CREATE_TOPIC = 'OPEN_CREATE_TOPIC'
|
||||||
|
export const CLOSE_CREATE_TOPIC = 'CLOSE_CREATE_TOPIC'
|
||||||
|
export const CREATE_TOPIC = 'CREATE_TOPIC'
|
||||||
|
export const UPDATE_TOPIC = 'UPDATE_TOPIC'
|
||||||
|
|
||||||
|
export const OPEN_CREATE_SYNAPSE = 'OPEN_CREATE_SYNAPSE'
|
||||||
|
export const CLOSE_CREATE_SYNAPSE = 'CLOSE_CREATE_SYNAPSE'
|
||||||
|
export const CREATE_SYNAPSE = 'CREATE_SYNAPSE'
|
||||||
|
export const UPDATE_SYNAPSE = 'UPDATE_SYNAPSE'
|
||||||
|
|
||||||
|
export const UPDATE_METACODE_SET = 'UPDATE_METACODE_SET'
|
||||||
|
export const MAKE_SELECTION = 'MAKE_SELECTION'
|
||||||
|
export const HIDE_SELECTED = 'HIDE_SELECTED'
|
||||||
|
export const REMOVE_SELECTED = 'REMOVE_SELECTED'
|
||||||
|
export const DELETE_SELECTED = 'DELETE_SELECTED'
|
||||||
|
export const CHANGE_PERMISSION_SELECTED = 'CHANGE_PERMISSION_SELECTED'
|
||||||
|
export const CHANGE_METACODE_SELECTED = 'CHANGE_METACODE_SELECTED'
|
||||||
|
|
||||||
|
export const OPEN_TOPIC_CARD = 'OPEN_TOPIC_CARD'
|
||||||
|
export const CLOSE_TOPIC_CARD = 'CLOSE_TOPIC_CARD'
|
||||||
|
|
||||||
|
export const OPEN_SYNAPSE_CARD = 'OPEN_SYNAPSE_CARD'
|
||||||
|
export const CLOSE_SYNAPSE_CARD = 'CLOSE_SYNAPSE_CARD'
|
||||||
|
|
||||||
|
export const OPEN_METACODE_SET_SELECT = 'OPEN_METACODE_SET_SELECT'
|
||||||
|
export const CLOSE_METACODE_SET_SELECT = 'CLOSE_METACODE_SET_SELECT'
|
||||||
|
export const SELECT_METACODE_SET = 'SELECT_METACODE_SET'
|
||||||
|
|
||||||
|
export const OPEN_MAP_INFO_BOX = 'OPEN_MAP_INFO_BOX'
|
||||||
|
export const CLOSE_MAP_INFO_BOX = 'CLOSE_MAP_INFO_BOX'
|
||||||
|
export const UPDATE_MAP = 'UPDATE_MAP'
|
||||||
|
|
||||||
|
export const OPEN_HELP = 'OPEN_HELP'
|
||||||
|
export const CLOSE_HELP = 'CLOSE_HELP'
|
||||||
|
|
||||||
|
export const MAP_CENTER_VIEW = 'MAP_CENTER_VIEW'
|
||||||
|
export const MAP_ZOOM_IN = 'MAP_ZOOM_IN'
|
||||||
|
export const MAP_ZOOM_OUT = 'MAP_ZOOM_OUT'
|
||||||
|
|
||||||
|
export const MAP_DISABLE_SOUND = 'MAP_DISABLE_SOUND'
|
||||||
|
export const MAP_ENABLE_SOUND = 'MAP_ENABLE_SOUND'
|
||||||
|
|
||||||
|
export const MAP_DISABLE_CURSOR = 'MAP_DISABLE_CURSOR'
|
||||||
|
export const MAP_ENABLE_CURSOR = 'MAP_ENABLE_CURSOR'
|
||||||
|
|
||||||
|
export const MAP_HIDE_VIDEOS = 'MAP_HIDE_VIDEOS'
|
||||||
|
export const MAP_UNHIDE_VIDEOS = 'MAP_UNHIDE_VIDEOS'
|
||||||
|
|
||||||
|
export const OPEN_IMPORT_DIALOGUE = 'OPEN_IMPORT_DIALOGUE'
|
||||||
|
export const CLOSE_IMPORT_DIALOGUE = 'CLOSE_IMPORT_DIALOGUE'
|
||||||
|
|
||||||
|
export const OPEN_FILTERS = 'OPEN_FILTERS'
|
||||||
|
export const CLOSE_FILTERS = 'CLOSE_FILTERS'
|
||||||
|
|
||||||
|
export const FILTER_ALL_PEOPLE = 'FILTER_ALL_PEOPLE'
|
||||||
|
export const FILTER_NO_PEOPLE = 'FILTER_NO_PEOPLE'
|
||||||
|
export const FILTER_HIDE_PERSON = 'FILTER_HIDE_PERSON'
|
||||||
|
export const FILTER_SHOW_PERSON = 'FILTER_SHOW_PERSON'
|
||||||
|
|
||||||
|
export const FILTER_ALL_METACODES = 'FILTER_ALL_METACODES'
|
||||||
|
export const FILTER_NO_METACODES = 'FILTER_NO_METACODES'
|
||||||
|
export const FILTER_HIDE_METACODE = 'FILTER_HIDE_METACODE'
|
||||||
|
export const FILTER_SHOW_METACODE = 'FILTER_SHOW_METACODE'
|
||||||
|
|
||||||
|
export const FILTER_ALL_SYNAPSES = 'FILTER_ALL_SYNAPSES'
|
||||||
|
export const FILTER_NO_SYNAPSES = 'FILTER_NO_SYNAPSES'
|
||||||
|
export const FILTER_HIDE_SYNAPSE = 'FILTER_HIDE_SYNAPSE'
|
||||||
|
export const FILTER_SHOW_SYNAPSE = 'FILTER_SHOW_SYNAPSE'
|
||||||
|
|
||||||
|
export const OPEN_FORK_MAP = 'OPEN_FORK_MAP'
|
||||||
|
export const CLOSE_FORK_MAP = 'CLOSE_FORK_MAP'
|
||||||
|
|
||||||
|
export const RIGHT_CLICK_ON_NODE = 'RIGHT_CLICK_ON_NODE'
|
||||||
|
export const RIGHT_CLICK_ON_EDGE = 'RIGHT_CLICK_ON_EDGE'
|
||||||
|
|
||||||
|
export const MAP_REQUEST_ACCESS = 'MAP_REQUEST_ACCESS'
|
13
frontend/src/actions/index.js
Normal file
13
frontend/src/actions/index.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import * as c from './constants'
|
||||||
|
|
||||||
|
export const openChat = () => {
|
||||||
|
return {
|
||||||
|
type: c.OPEN_CHAT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const closeChat = () => {
|
||||||
|
return {
|
||||||
|
type: c.CLOSE_CHAT
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +0,0 @@
|
||||||
import React, { Component } from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
class DataVis extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
return <div id="infovis" />
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DataVis
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
import MapInfoBox from '../routes/MapView/MapInfoBox'
|
import MapInfoBox from './MapInfoBox'
|
||||||
|
|
||||||
class InfoAndHelp extends Component {
|
class InfoAndHelp extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Autolinker from 'autolinker'
|
import Autolinker from 'autolinker'
|
||||||
import Util from '../../../Metamaps/Util'
|
import Util from '../../Metamaps/Util'
|
||||||
|
|
||||||
const linker = new Autolinker({ newWindow: true, truncate: 50, email: false, phone: false })
|
const linker = new Autolinker({ newWindow: true, truncate: 50, email: false, phone: false })
|
||||||
|
|
|
@ -4,7 +4,7 @@ import Unread from './Unread'
|
||||||
import Participant from './Participant'
|
import Participant from './Participant'
|
||||||
import Message from './Message'
|
import Message from './Message'
|
||||||
import NewMessage from './NewMessage'
|
import NewMessage from './NewMessage'
|
||||||
import Util from '../../../Metamaps/Util'
|
import Util from '../../Metamaps/Util'
|
||||||
|
|
||||||
function makeList(messages) {
|
function makeList(messages) {
|
||||||
let currentHeader
|
let currentHeader
|
154
frontend/src/components/MapVis.js
Normal file
154
frontend/src/components/MapVis.js
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
/* global $ */
|
||||||
|
|
||||||
|
import _ from 'lodash'
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import $jit from '../patched/JIT'
|
||||||
|
import JIT from '../Metamaps/JIT'
|
||||||
|
|
||||||
|
// There would be separate one of these for mapview and topicview
|
||||||
|
|
||||||
|
/*
|
||||||
|
it could use the diffing intelligently to know when you
|
||||||
|
update the visualization
|
||||||
|
|
||||||
|
// JIT MORPH to move between states?
|
||||||
|
|
||||||
|
use componentDidUpdate to check for differences in
|
||||||
|
- topic list, synapse list, mapping list, etc
|
||||||
|
- use that info to intelligently update and animate the viz.
|
||||||
|
|
||||||
|
basically port everything from VISUALIZE module over into here
|
||||||
|
|
||||||
|
it should dynamically generate and pass in callbacks to the visualization
|
||||||
|
*/
|
||||||
|
|
||||||
|
class MapVis extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
DataModel: PropTypes.object,
|
||||||
|
filters: PropTypes.array,
|
||||||
|
selectedNodes: PropTypes.array,
|
||||||
|
selectedEdges: PropTypes.array,
|
||||||
|
onSelect: PropTypes.func,
|
||||||
|
onPan: PropTypes.func,
|
||||||
|
onZoom: PropTypes.func,
|
||||||
|
onDrawSelectBox: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.jitGraph = null
|
||||||
|
this.vizData = null
|
||||||
|
this.state = {
|
||||||
|
loading: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
$jit.ForceDirected.Plot.NodeTypes.implement(JIT.ForceDirected.nodeSettings)
|
||||||
|
$jit.ForceDirected.Plot.EdgeTypes.implement(JIT.ForceDirected.edgeSettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
const { map, DataModel } = this.props
|
||||||
|
const prevMap = prevProps.map
|
||||||
|
const prevDataModel = prevProps.DataModel
|
||||||
|
if (DataModel) {
|
||||||
|
if (map !== prevMap) {
|
||||||
|
this.initialize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
const { DataModel } = this.props
|
||||||
|
this.createJitGraph()
|
||||||
|
this.vizData = JIT.convertModelsToJIT(DataModel.Topics, DataModel.Synapses)
|
||||||
|
this.waitForMetacodesThenLoad()
|
||||||
|
}
|
||||||
|
|
||||||
|
divMounted(div) {
|
||||||
|
console.log(div)
|
||||||
|
}
|
||||||
|
|
||||||
|
createJitGraph() {
|
||||||
|
const FDSettings = $.extend(true, {}, JIT.ForceDirected.graphSettings)
|
||||||
|
FDSettings.width = $('body').width()
|
||||||
|
FDSettings.height = $('body').height()
|
||||||
|
this.jitGraph = new $jit.ForceDirected(FDSettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForMetacodesThenLoad() {
|
||||||
|
const { DataModel } = this.props
|
||||||
|
// hold until all the needed metacode images are loaded
|
||||||
|
// hold for a maximum of 80 passes, or 4 seconds of waiting time
|
||||||
|
var tries = 0
|
||||||
|
const hold = () => {
|
||||||
|
const unique = _.uniq(DataModel.Topics.models, function(metacode) { return metacode.get('metacode_id') })
|
||||||
|
const requiredMetacodes = _.map(unique, function(metacode) { return metacode.get('metacode_id') })
|
||||||
|
let loadedCount = 0
|
||||||
|
|
||||||
|
_.each(requiredMetacodes, function(metacodeId) {
|
||||||
|
const metacode = DataModel.Metacodes.get(metacodeId)
|
||||||
|
const img = metacode ? metacode.get('image') : false
|
||||||
|
|
||||||
|
if (img && (img.complete || (typeof img.naturalWidth !== 'undefined' && img.naturalWidth !== 0))) {
|
||||||
|
loadedCount += 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (loadedCount === requiredMetacodes.length || tries > 80) {
|
||||||
|
this.runAnimation()
|
||||||
|
} else {
|
||||||
|
setTimeout(function() { tries++; hold() }, 50)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hold()
|
||||||
|
}
|
||||||
|
|
||||||
|
computePositions() {
|
||||||
|
const { DataModel } = this.props
|
||||||
|
this.jitGraph.graph.eachNode(function(n) {
|
||||||
|
const topic = DataModel.Topics.get(n.id)
|
||||||
|
topic.set({ node: n }, { silent: true })
|
||||||
|
topic.updateNode()
|
||||||
|
const mapping = topic.getMapping()
|
||||||
|
n.eachAdjacency(function(edge) {
|
||||||
|
if (!edge.getData('init')) {
|
||||||
|
edge.setData('init', true)
|
||||||
|
const l = edge.getData('synapseIDs').length
|
||||||
|
for (let i = 0; i < l; i++) {
|
||||||
|
const synapse = DataModel.Synapses.get(edge.getData('synapseIDs')[i])
|
||||||
|
synapse.set({ edge: edge }, { silent: true })
|
||||||
|
synapse.updateEdge()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const startPos = new $jit.Complex(0, 0)
|
||||||
|
const endPos = new $jit.Complex(mapping.get('xloc'), mapping.get('yloc'))
|
||||||
|
n.setPos(startPos, 'start')
|
||||||
|
n.setPos(endPos, 'end')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
runAnimation() {
|
||||||
|
// load JSON data, if it's not empty
|
||||||
|
if (this.vizData) {
|
||||||
|
// load JSON data.
|
||||||
|
var rootIndex = 0
|
||||||
|
// 0 is rootIndex
|
||||||
|
this.jitGraph.loadJSON(this.vizData, 0)
|
||||||
|
// compute positions and plot.
|
||||||
|
this.computePositions()
|
||||||
|
this.jitGraph.animate(JIT.ForceDirected.animateSavedLayout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { loading } = this.state
|
||||||
|
// display loading while loading
|
||||||
|
return <div id="infovis" ref={this.divMounted} />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MapVis
|
49
frontend/src/components/TopicVis.js
Normal file
49
frontend/src/components/TopicVis.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
|
// There would be separate one of these for mapview and topicview
|
||||||
|
|
||||||
|
/*
|
||||||
|
it could use the diffing intelligently to know when you
|
||||||
|
update the visualization
|
||||||
|
|
||||||
|
use componentDidUpdate to check for differences in
|
||||||
|
- topic list, synapse list, mapping list, etc
|
||||||
|
- use that info to intelligently update and animate the viz.
|
||||||
|
|
||||||
|
basically port everything from VISUALIZE module over into here
|
||||||
|
|
||||||
|
it should dynamically generate and pass in callbacks to the visualization
|
||||||
|
*/
|
||||||
|
|
||||||
|
class MapVis extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
topics: PropTypes.array,
|
||||||
|
synapses: PropTypes.array,
|
||||||
|
mappings: PropTypes.array,
|
||||||
|
filters: PropTypes.array,
|
||||||
|
selectedNodes: PropTypes.array,
|
||||||
|
selectedEdges: PropTypes.array,
|
||||||
|
onSelect: PropTypes.func,
|
||||||
|
onPan: PropTypes.func,
|
||||||
|
onZoom: PropTypes.func,
|
||||||
|
onDrawSelectBox: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {
|
||||||
|
mGraph: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return <div id="infovis" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MapVis
|
5
frontend/src/containers/ContextMenu.js
Normal file
5
frontend/src/containers/ContextMenu.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { mapStateToProps, mapDispatchToProps } from './UpperOptions.store'
|
||||||
|
import UpperOptions from '../components/UpperOptions'
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(UpperOptions)
|
24
frontend/src/containers/ContextMenu.store.js
Normal file
24
frontend/src/containers/ContextMenu.store.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// import { } from '../actions'
|
||||||
|
|
||||||
|
export const mapStateToProps = (state, ownProps) => {
|
||||||
|
return {
|
||||||
|
map: ownProps.map,
|
||||||
|
currentUser: ownProps.currentUser,
|
||||||
|
openImportLightbox: ownProps.openImportLightbox,
|
||||||
|
forkMap: ownProps.forkMap,
|
||||||
|
canEditMap: ownProps.canEditMap,
|
||||||
|
filterData: ownProps.filterData,
|
||||||
|
allForFiltering: ownProps.allForFiltering,
|
||||||
|
visibleForFiltering: ownProps.visibleForFiltering,
|
||||||
|
toggleMetacode: ownProps.toggleMetacode,
|
||||||
|
toggleMapper: ownProps.toggleMapper,
|
||||||
|
toggleSynapse: ownProps.toggleSynapse,
|
||||||
|
filterAllMetacodes: ownProps.filterAllMetacodes,
|
||||||
|
filterAllMappers: ownProps.filterAllMappers,
|
||||||
|
filterAllSynapses: ownProps.filterAllSynapses
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mapDispatchToProps = (dispatch, ownProps) => {
|
||||||
|
return {}
|
||||||
|
}
|
5
frontend/src/containers/InfoAndHelp.js
Normal file
5
frontend/src/containers/InfoAndHelp.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { mapStateToProps, mapDispatchToProps } from './InfoAndHelp.store'
|
||||||
|
import InfoAndHelp from '../components/InfoAndHelp'
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(InfoAndHelp)
|
18
frontend/src/containers/InfoAndHelp.store.js
Normal file
18
frontend/src/containers/InfoAndHelp.store.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// import { } from '../actions'
|
||||||
|
|
||||||
|
export const mapStateToProps = (state, ownProps) => {
|
||||||
|
return {
|
||||||
|
mapIsStarred: ownProps.mapIsStarred,
|
||||||
|
currentUser: ownProps.currentUser,
|
||||||
|
map: ownProps.map,
|
||||||
|
onInfoClick: ownProps.toggleMapInfoBox,
|
||||||
|
onMapStar: ownProps.onMapStar,
|
||||||
|
onMapUnstar: ownProps.onMapUnstar,
|
||||||
|
onHelpClick: ownProps.openHelpLightbox,
|
||||||
|
infoBoxHtml: ownProps.infoBoxHtml
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mapDispatchToProps = (dispatch, ownProps) => {
|
||||||
|
return {}
|
||||||
|
}
|
5
frontend/src/containers/TopicCard.js
Normal file
5
frontend/src/containers/TopicCard.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { mapStateToProps, mapDispatchToProps } from './TopicCard.store'
|
||||||
|
import TopicCard from '../components/TopicCard'
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(TopicCard)
|
24
frontend/src/containers/TopicCard.store.js
Normal file
24
frontend/src/containers/TopicCard.store.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// import { } from '../actions'
|
||||||
|
|
||||||
|
export const mapStateToProps = (state, ownProps) => {
|
||||||
|
return {
|
||||||
|
map: ownProps.map,
|
||||||
|
currentUser: ownProps.currentUser,
|
||||||
|
openImportLightbox: ownProps.openImportLightbox,
|
||||||
|
forkMap: ownProps.forkMap,
|
||||||
|
canEditMap: ownProps.canEditMap,
|
||||||
|
filterData: ownProps.filterData,
|
||||||
|
allForFiltering: ownProps.allForFiltering,
|
||||||
|
visibleForFiltering: ownProps.visibleForFiltering,
|
||||||
|
toggleMetacode: ownProps.toggleMetacode,
|
||||||
|
toggleMapper: ownProps.toggleMapper,
|
||||||
|
toggleSynapse: ownProps.toggleSynapse,
|
||||||
|
filterAllMetacodes: ownProps.filterAllMetacodes,
|
||||||
|
filterAllMappers: ownProps.filterAllMappers,
|
||||||
|
filterAllSynapses: ownProps.filterAllSynapses
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mapDispatchToProps = (dispatch, ownProps) => {
|
||||||
|
return {}
|
||||||
|
}
|
5
frontend/src/containers/UpperOptions.js
Normal file
5
frontend/src/containers/UpperOptions.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { mapStateToProps, mapDispatchToProps } from './UpperOptions.store'
|
||||||
|
import UpperOptions from '../components/UpperOptions'
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(UpperOptions)
|
24
frontend/src/containers/UpperOptions.store.js
Normal file
24
frontend/src/containers/UpperOptions.store.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// import { } from '../actions'
|
||||||
|
|
||||||
|
export const mapStateToProps = (state, ownProps) => {
|
||||||
|
return {
|
||||||
|
map: ownProps.map,
|
||||||
|
currentUser: ownProps.currentUser,
|
||||||
|
openImportLightbox: ownProps.openImportLightbox,
|
||||||
|
forkMap: ownProps.forkMap,
|
||||||
|
canEditMap: ownProps.canEditMap,
|
||||||
|
filterData: ownProps.filterData,
|
||||||
|
allForFiltering: ownProps.allForFiltering,
|
||||||
|
visibleForFiltering: ownProps.visibleForFiltering,
|
||||||
|
toggleMetacode: ownProps.toggleMetacode,
|
||||||
|
toggleMapper: ownProps.toggleMapper,
|
||||||
|
toggleSynapse: ownProps.toggleSynapse,
|
||||||
|
filterAllMetacodes: ownProps.filterAllMetacodes,
|
||||||
|
filterAllMappers: ownProps.filterAllMappers,
|
||||||
|
filterAllSynapses: ownProps.filterAllSynapses
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mapDispatchToProps = (dispatch, ownProps) => {
|
||||||
|
return {}
|
||||||
|
}
|
5
frontend/src/containers/VisualizationControls.js
Normal file
5
frontend/src/containers/VisualizationControls.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { mapStateToProps, mapDispatchToProps } from './VisualizationControls.store'
|
||||||
|
import VisualizationControls from '../components/VisualizationControls'
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(VisualizationControls)
|
15
frontend/src/containers/VisualizationControls.store.js
Normal file
15
frontend/src/containers/VisualizationControls.store.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// import { } from '../actions'
|
||||||
|
|
||||||
|
export const mapStateToProps = (state, ownProps) => {
|
||||||
|
return {
|
||||||
|
topic: ownProps.topic,
|
||||||
|
map: ownProps.map,
|
||||||
|
onClickZoomExtents: ownProps.onZoomExtents,
|
||||||
|
onClickZoomIn: ownProps.onZoomIn,
|
||||||
|
onClickZoomOut: ownProps.onZoomOut
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mapDispatchToProps = (dispatch, ownProps) => {
|
||||||
|
return {}
|
||||||
|
}
|
|
@ -5,7 +5,9 @@ Backbone.ajax = (opts) => window.$.ajaxq('backbone-ajaxq', opts)
|
||||||
|
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import Metamaps from './Metamaps'
|
import Metamaps from './Metamaps'
|
||||||
|
import $jit from './patched/JIT'
|
||||||
|
|
||||||
// create global references
|
// create global references
|
||||||
window._ = _
|
window._ = _
|
||||||
window.Metamaps = Metamaps
|
window.Metamaps = Metamaps
|
||||||
|
window.$jit = $jit
|
||||||
|
|
File diff suppressed because it is too large
Load diff
9
frontend/src/reducers/index.js
Normal file
9
frontend/src/reducers/index.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { combineReducers } from 'redux'
|
||||||
|
|
||||||
|
import map from './map'
|
||||||
|
//import notifications from './notifications'
|
||||||
|
|
||||||
|
export default combineReducers({
|
||||||
|
map//,
|
||||||
|
//notifications
|
||||||
|
})
|
22
frontend/src/reducers/map/chat.js
Normal file
22
frontend/src/reducers/map/chat.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import {
|
||||||
|
OPEN_CHAT,
|
||||||
|
CLOSE_CHAT
|
||||||
|
} from '../../actions/constants'
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
isOpen: false
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function (state = initialState, action) {
|
||||||
|
switch (action.type) {
|
||||||
|
case OPEN_CHAT:
|
||||||
|
return {
|
||||||
|
isOpen: true
|
||||||
|
}
|
||||||
|
case CLOSE_CHAT:
|
||||||
|
return {
|
||||||
|
isOpen: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
}
|
5
frontend/src/reducers/map/contextMenu.js
Normal file
5
frontend/src/reducers/map/contextMenu.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const initialState = {}
|
||||||
|
|
||||||
|
export default function (state = initialState, action) {
|
||||||
|
return state
|
||||||
|
}
|
5
frontend/src/reducers/map/createSynapse.js
Normal file
5
frontend/src/reducers/map/createSynapse.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const initialState = {}
|
||||||
|
|
||||||
|
export default function (state = initialState, action) {
|
||||||
|
return state
|
||||||
|
}
|
5
frontend/src/reducers/map/createTopic.js
Normal file
5
frontend/src/reducers/map/createTopic.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const initialState = {}
|
||||||
|
|
||||||
|
export default function (state = initialState, action) {
|
||||||
|
return state
|
||||||
|
}
|
21
frontend/src/reducers/map/filters.js
Normal file
21
frontend/src/reducers/map/filters.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
const initialState = {
|
||||||
|
dataForPresentation: {
|
||||||
|
metacodes: {},
|
||||||
|
mappers: {},
|
||||||
|
synapses: {}
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
metacodes: [],
|
||||||
|
mappers: [],
|
||||||
|
synapses: []
|
||||||
|
},
|
||||||
|
visible: {
|
||||||
|
metacodes: [],
|
||||||
|
mappers: [],
|
||||||
|
synapses: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function (state = initialState, action) {
|
||||||
|
return state
|
||||||
|
}
|
5
frontend/src/reducers/map/importDialogue.js
Normal file
5
frontend/src/reducers/map/importDialogue.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const initialState = {}
|
||||||
|
|
||||||
|
export default function (state = initialState, action) {
|
||||||
|
return state
|
||||||
|
}
|
33
frontend/src/reducers/map/index.js
Normal file
33
frontend/src/reducers/map/index.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import { combineReducers } from 'redux'
|
||||||
|
|
||||||
|
import filters from './filters'
|
||||||
|
import selected from './selected'
|
||||||
|
import chat from './chat'
|
||||||
|
import createTopic from './createTopic'
|
||||||
|
import createSynapse from './createSynapse'
|
||||||
|
import contextMenu from './contextMenu'
|
||||||
|
import topicCard from './topicCard'
|
||||||
|
import synapseCard from './synapseCard'
|
||||||
|
import realtime from './realtime'
|
||||||
|
import settings from './settings'
|
||||||
|
import importDialogue from './importDialogue'
|
||||||
|
import layout from './layout'
|
||||||
|
import mouse from './mouse'
|
||||||
|
import metacodeSelect from './metacodeSelect'
|
||||||
|
|
||||||
|
export default combineReducers({
|
||||||
|
chat,
|
||||||
|
filters,
|
||||||
|
selected,
|
||||||
|
createTopic,
|
||||||
|
createSynapse,
|
||||||
|
contextMenu,
|
||||||
|
topicCard,
|
||||||
|
synapseCard,
|
||||||
|
realtime,
|
||||||
|
settings,
|
||||||
|
importDialogue,
|
||||||
|
layout,
|
||||||
|
mouse,
|
||||||
|
metacodeSelect
|
||||||
|
})
|
5
frontend/src/reducers/map/layout.js
Normal file
5
frontend/src/reducers/map/layout.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const initialState = {}
|
||||||
|
|
||||||
|
export default function (state = initialState, action) {
|
||||||
|
return state
|
||||||
|
}
|
5
frontend/src/reducers/map/metacodeSelect.js
Normal file
5
frontend/src/reducers/map/metacodeSelect.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const initialState = {}
|
||||||
|
|
||||||
|
export default function (state = initialState, action) {
|
||||||
|
return state
|
||||||
|
}
|
5
frontend/src/reducers/map/mouse.js
Normal file
5
frontend/src/reducers/map/mouse.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const initialState = {}
|
||||||
|
|
||||||
|
export default function (state = initialState, action) {
|
||||||
|
return state
|
||||||
|
}
|
5
frontend/src/reducers/map/realtime.js
Normal file
5
frontend/src/reducers/map/realtime.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
const initialState = {}
|
||||||
|
|
||||||
|
export default function (state = initialState, action) {
|
||||||
|
return state
|
||||||
|
}
|
8
frontend/src/reducers/map/selected.js
Normal file
8
frontend/src/reducers/map/selected.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
const initialState = {
|
||||||
|
Nodes: [],
|
||||||
|
Edges: []
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function (state = initialState, action) {
|
||||||
|
return state
|
||||||
|
}
|
21
frontend/src/reducers/map/settings.js
Normal file
21
frontend/src/reducers/map/settings.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
const initialState = {
|
||||||
|
colors: {
|
||||||
|
background: '#344A58',
|
||||||
|
synapses: {
|
||||||
|
normal: '#888888',
|
||||||
|
hover: '#888888',
|
||||||
|
selected: '#FFFFFF'
|
||||||
|
},
|
||||||
|
topics: {
|
||||||
|
selected: '#FFFFFF'
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
background: '#18202E',
|
||||||
|
text: '#DDD'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function (state = initialState, action) {
|
||||||
|
return state
|
||||||
|
}
|
3
frontend/src/reducers/map/synapseCard.js
Normal file
3
frontend/src/reducers/map/synapseCard.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export default function (state = null, action) {
|
||||||
|
return state
|
||||||
|
}
|
3
frontend/src/reducers/map/topicCard.js
Normal file
3
frontend/src/reducers/map/topicCard.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export default function (state = null, action) {
|
||||||
|
return state
|
||||||
|
}
|
3
frontend/src/reducers/notifications/index.js
Normal file
3
frontend/src/reducers/notifications/index.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export default function notifications(state = [], action) {
|
||||||
|
return state
|
||||||
|
}
|
95
frontend/src/routes/MapView/MapView.js
Normal file
95
frontend/src/routes/MapView/MapView.js
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
import React, { Component } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
|
import UpperOptions from '../../containers/UpperOptions'
|
||||||
|
import InfoAndHelp from '../../containers/InfoAndHelp'
|
||||||
|
import VisualizationControls from '../../containers/VisualizationControls'
|
||||||
|
import ContextMenu from '../../containers/ContextMenu'
|
||||||
|
import TopicCard from '../../containers/TopicCard'
|
||||||
|
|
||||||
|
import Instructions from '../../components/Instructions'
|
||||||
|
import MapChat from '../../components/MapChat'
|
||||||
|
import MapVis from '../../components/MapVis'
|
||||||
|
|
||||||
|
export default class MapView extends Component {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
contextMenu: PropTypes.bool,
|
||||||
|
mobile: PropTypes.bool,
|
||||||
|
mapId: PropTypes.string,
|
||||||
|
map: PropTypes.object,
|
||||||
|
mapIsStarred: PropTypes.bool,
|
||||||
|
onMapStar: PropTypes.func,
|
||||||
|
onMapUnstar: PropTypes.func,
|
||||||
|
filterData: PropTypes.object,
|
||||||
|
allForFiltering: PropTypes.object,
|
||||||
|
visibleForFiltering: PropTypes.object,
|
||||||
|
toggleMetacode: PropTypes.func,
|
||||||
|
toggleMapper: PropTypes.func,
|
||||||
|
toggleSynapse: PropTypes.func,
|
||||||
|
filterAllMetacodes: PropTypes.func,
|
||||||
|
filterAllMappers: PropTypes.func,
|
||||||
|
filterAllSynapses: PropTypes.func,
|
||||||
|
toggleMapInfoBox: PropTypes.func,
|
||||||
|
infoBoxHtml: PropTypes.string,
|
||||||
|
currentUser: PropTypes.object,
|
||||||
|
endActiveMap: PropTypes.func,
|
||||||
|
launchNewMap: PropTypes.func,
|
||||||
|
openImportLightbox: PropTypes.func,
|
||||||
|
forkMap: PropTypes.func,
|
||||||
|
openHelpLightbox: PropTypes.func,
|
||||||
|
onZoomExtents: PropTypes.func,
|
||||||
|
onZoomIn: PropTypes.func,
|
||||||
|
onZoomOut: PropTypes.func,
|
||||||
|
hasLearnedTopicCreation: PropTypes.bool,
|
||||||
|
chatIsOpen: PropTypes.bool,
|
||||||
|
closeChat: PropTypes.func,
|
||||||
|
openChat: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.endMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
endMap() {
|
||||||
|
this.props.closeChat()
|
||||||
|
this.mapChat.reset()
|
||||||
|
// TODO: fix upperOptions ref
|
||||||
|
this.upperOptions.reset()
|
||||||
|
this.props.endActiveMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
const oldMapId = prevProps.mapId
|
||||||
|
const { mapId, launchNewMap } = this.props
|
||||||
|
if (!oldMapId && mapId) launchNewMap(mapId)
|
||||||
|
else if (oldMapId && mapId && oldMapId !== mapId) {
|
||||||
|
this.endMap()
|
||||||
|
launchNewMap(mapId)
|
||||||
|
}
|
||||||
|
else if (oldMapId && !mapId) this.endMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
render = () => {
|
||||||
|
const { mobile, map, currentUser, closeChat, openChat, chatIsOpen,
|
||||||
|
toggleMapInfoBox, infoBoxHtml, allForFiltering, visibleForFiltering,
|
||||||
|
toggleMetacode, toggleMapper, toggleSynapse, filterAllMetacodes,
|
||||||
|
filterAllMappers, filterAllSynapses, filterData,
|
||||||
|
openImportLightbox, forkMap, openHelpLightbox,
|
||||||
|
mapIsStarred, onMapStar, onMapUnstar, openTopic,
|
||||||
|
onZoomExtents, onZoomIn, onZoomOut, hasLearnedTopicCreation,
|
||||||
|
contextMenu, DataModel } = this.props
|
||||||
|
const canEditMap = map && map.authorizeToEdit(currentUser)
|
||||||
|
// TODO: stop using {...this.props} and make explicit
|
||||||
|
return <div className="mapWrapper">
|
||||||
|
<UpperOptions ref={x => this.upperOptions = x} {...this.props} />
|
||||||
|
<MapVis map={map} DataModel={DataModel} />
|
||||||
|
{openTopic && <TopicCard {...this.props} />}
|
||||||
|
{contextMenu && <ContextMenu {...this.props} />}
|
||||||
|
{currentUser && <Instructions mobile={mobile} hasLearnedTopicCreation={hasLearnedTopicCreation} />}
|
||||||
|
{currentUser && <MapChat {...this.props} onOpen={openChat} onClose={closeChat} chatOpen={chatIsOpen} ref={x => this.mapChat = x} />}
|
||||||
|
<VisualizationControls {...this.props} />
|
||||||
|
<InfoAndHelp {...this.props} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
23
frontend/src/routes/MapView/MapView.store.js
Normal file
23
frontend/src/routes/MapView/MapView.store.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import {
|
||||||
|
closeChat,
|
||||||
|
openChat
|
||||||
|
} from '../../actions'
|
||||||
|
|
||||||
|
export const mapStateToProps = (state, ownProps) => {
|
||||||
|
return {
|
||||||
|
chatIsOpen: state.map.chat.isOpen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mapDispatchToProps = (dispatch, ownProps) => {
|
||||||
|
return {
|
||||||
|
openChat: () => {
|
||||||
|
ownProps.onOpen()
|
||||||
|
return dispatch(openChat())
|
||||||
|
},
|
||||||
|
closeChat: () => {
|
||||||
|
ownProps.onClose()
|
||||||
|
return dispatch(closeChat())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,132 +1,5 @@
|
||||||
import React, { Component } from 'react'
|
import { connect } from 'react-redux'
|
||||||
import PropTypes from 'prop-types'
|
import { mapStateToProps, mapDispatchToProps } from './MapView.store'
|
||||||
|
import MapView from './MapView'
|
||||||
|
|
||||||
import ContextMenu from '../../components/ContextMenu'
|
export default connect(mapStateToProps, mapDispatchToProps)(MapView)
|
||||||
import DataVis from '../../components/DataVis'
|
|
||||||
import UpperOptions from '../../components/UpperOptions'
|
|
||||||
import InfoAndHelp from '../../components/InfoAndHelp'
|
|
||||||
import Instructions from './Instructions'
|
|
||||||
import VisualizationControls from '../../components/VisualizationControls'
|
|
||||||
import MapChat from './MapChat'
|
|
||||||
import TopicCard from '../../components/TopicCard'
|
|
||||||
|
|
||||||
export default class MapView extends Component {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
contextMenu: PropTypes.bool,
|
|
||||||
mobile: PropTypes.bool,
|
|
||||||
mapId: PropTypes.string,
|
|
||||||
map: PropTypes.object,
|
|
||||||
mapIsStarred: PropTypes.bool,
|
|
||||||
onMapStar: PropTypes.func,
|
|
||||||
onMapUnstar: PropTypes.func,
|
|
||||||
filterData: PropTypes.object,
|
|
||||||
allForFiltering: PropTypes.object,
|
|
||||||
visibleForFiltering: PropTypes.object,
|
|
||||||
toggleMetacode: PropTypes.func,
|
|
||||||
toggleMapper: PropTypes.func,
|
|
||||||
toggleSynapse: PropTypes.func,
|
|
||||||
filterAllMetacodes: PropTypes.func,
|
|
||||||
filterAllMappers: PropTypes.func,
|
|
||||||
filterAllSynapses: PropTypes.func,
|
|
||||||
toggleMapInfoBox: PropTypes.func,
|
|
||||||
infoBoxHtml: PropTypes.string,
|
|
||||||
currentUser: PropTypes.object,
|
|
||||||
endActiveMap: PropTypes.func,
|
|
||||||
launchNewMap: PropTypes.func,
|
|
||||||
openImportLightbox: PropTypes.func,
|
|
||||||
forkMap: PropTypes.func,
|
|
||||||
openHelpLightbox: PropTypes.func,
|
|
||||||
onZoomExtents: PropTypes.func,
|
|
||||||
onZoomIn: PropTypes.func,
|
|
||||||
onZoomOut: PropTypes.func,
|
|
||||||
hasLearnedTopicCreation: PropTypes.bool
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props)
|
|
||||||
this.state = {
|
|
||||||
chatOpen: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.endMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
endMap() {
|
|
||||||
this.setState({
|
|
||||||
chatOpen: false
|
|
||||||
})
|
|
||||||
this.mapChat.reset()
|
|
||||||
this.upperOptions.reset()
|
|
||||||
this.props.endActiveMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
const oldMapId = prevProps.mapId
|
|
||||||
const { mapId, launchNewMap } = this.props
|
|
||||||
if (!oldMapId && mapId) launchNewMap(mapId)
|
|
||||||
else if (oldMapId && mapId && oldMapId !== mapId) {
|
|
||||||
this.endMap()
|
|
||||||
launchNewMap(mapId)
|
|
||||||
}
|
|
||||||
else if (oldMapId && !mapId) this.endMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
render = () => {
|
|
||||||
const { mobile, map, currentUser, onOpen, onClose,
|
|
||||||
toggleMapInfoBox, infoBoxHtml, allForFiltering, visibleForFiltering,
|
|
||||||
toggleMetacode, toggleMapper, toggleSynapse, filterAllMetacodes,
|
|
||||||
filterAllMappers, filterAllSynapses, filterData,
|
|
||||||
openImportLightbox, forkMap, openHelpLightbox,
|
|
||||||
mapIsStarred, onMapStar, onMapUnstar, openTopic,
|
|
||||||
onZoomExtents, onZoomIn, onZoomOut, hasLearnedTopicCreation,
|
|
||||||
contextMenu } = this.props
|
|
||||||
const { chatOpen } = this.state
|
|
||||||
const onChatOpen = () => {
|
|
||||||
this.setState({chatOpen: true})
|
|
||||||
onOpen()
|
|
||||||
}
|
|
||||||
const onChatClose = () => {
|
|
||||||
this.setState({chatOpen: false})
|
|
||||||
onClose()
|
|
||||||
}
|
|
||||||
const canEditMap = map && map.authorizeToEdit(currentUser)
|
|
||||||
// TODO: stop using {...this.props} and make explicit
|
|
||||||
return <div className="mapWrapper">
|
|
||||||
<UpperOptions ref={x => this.upperOptions = x}
|
|
||||||
map={map}
|
|
||||||
currentUser={currentUser}
|
|
||||||
onImportClick={openImportLightbox}
|
|
||||||
onForkClick={forkMap}
|
|
||||||
canEditMap={canEditMap}
|
|
||||||
filterData={filterData}
|
|
||||||
allForFiltering={allForFiltering}
|
|
||||||
visibleForFiltering={visibleForFiltering}
|
|
||||||
toggleMetacode={toggleMetacode}
|
|
||||||
toggleMapper={toggleMapper}
|
|
||||||
toggleSynapse={toggleSynapse}
|
|
||||||
filterAllMetacodes={filterAllMetacodes}
|
|
||||||
filterAllMappers={filterAllMappers}
|
|
||||||
filterAllSynapses={filterAllSynapses} />
|
|
||||||
<DataVis />
|
|
||||||
{openTopic && <TopicCard {...this.props} />}
|
|
||||||
{contextMenu && <ContextMenu {...this.props} />}
|
|
||||||
{currentUser && <Instructions mobile={mobile} hasLearnedTopicCreation={hasLearnedTopicCreation} />}
|
|
||||||
{currentUser && <MapChat {...this.props} onOpen={onChatOpen} onClose={onChatClose} chatOpen={chatOpen} ref={x => this.mapChat = x} />}
|
|
||||||
<VisualizationControls map={map}
|
|
||||||
onClickZoomExtents={onZoomExtents}
|
|
||||||
onClickZoomIn={onZoomIn}
|
|
||||||
onClickZoomOut={onZoomOut} />
|
|
||||||
<InfoAndHelp mapIsStarred={mapIsStarred}
|
|
||||||
currentUser={currentUser}
|
|
||||||
map={map}
|
|
||||||
onInfoClick={toggleMapInfoBox}
|
|
||||||
onMapStar={onMapStar}
|
|
||||||
onMapUnstar={onMapUnstar}
|
|
||||||
onHelpClick={openHelpLightbox}
|
|
||||||
infoBoxHtml={infoBoxHtml} />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
|
||||||
import ContextMenu from '../components/ContextMenu'
|
import ContextMenu from '../containers/ContextMenu'
|
||||||
import DataVis from '../components/DataVis'
|
import UpperOptions from '../containers/UpperOptions'
|
||||||
import UpperOptions from '../components/UpperOptions'
|
import InfoAndHelp from '../containers/InfoAndHelp'
|
||||||
import InfoAndHelp from '../components/InfoAndHelp'
|
import VisualizationControls from '../containers/VisualizationControls'
|
||||||
import VisualizationControls from '../components/VisualizationControls'
|
import TopicCard from '../containers/TopicCard'
|
||||||
import TopicCard from '../components/TopicCard'
|
|
||||||
|
import TopicVis from '../components/TopicVis'
|
||||||
|
|
||||||
export default class TopicView extends Component {
|
export default class TopicView extends Component {
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ export default class TopicView extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
endTopic() {
|
endTopic() {
|
||||||
|
// TODO: fix upperOptions ref
|
||||||
this.upperOptions.reset()
|
this.upperOptions.reset()
|
||||||
this.props.endActiveTopic()
|
this.props.endActiveTopic()
|
||||||
}
|
}
|
||||||
|
@ -60,26 +62,12 @@ export default class TopicView extends Component {
|
||||||
openHelpLightbox, onZoomIn, onZoomOut, contextMenu } = this.props
|
openHelpLightbox, onZoomIn, onZoomOut, contextMenu } = this.props
|
||||||
// TODO: stop using {...this.props} and make explicit
|
// TODO: stop using {...this.props} and make explicit
|
||||||
return <div className="topicWrapper">
|
return <div className="topicWrapper">
|
||||||
<UpperOptions ref={x => this.upperOptions = x}
|
<UpperOptions ref={x => this.upperOptions = x} {...this.props} />
|
||||||
currentUser={currentUser}
|
<TopicVis />
|
||||||
topic={topic}
|
|
||||||
onForkClick={forkMap}
|
|
||||||
filterData={filterData}
|
|
||||||
allForFiltering={allForFiltering}
|
|
||||||
visibleForFiltering={visibleForFiltering}
|
|
||||||
toggleMetacode={toggleMetacode}
|
|
||||||
toggleMapper={toggleMapper}
|
|
||||||
toggleSynapse={toggleSynapse}
|
|
||||||
filterAllMetacodes={filterAllMetacodes}
|
|
||||||
filterAllMappers={filterAllMappers}
|
|
||||||
filterAllSynapses={filterAllSynapses} />
|
|
||||||
<DataVis />
|
|
||||||
<TopicCard {...this.props} />
|
<TopicCard {...this.props} />
|
||||||
{contextMenu && <ContextMenu {...this.props} />}
|
{contextMenu && <ContextMenu {...this.props} />}
|
||||||
<VisualizationControls onClickZoomIn={onZoomIn}
|
<VisualizationControls {...this.props} />
|
||||||
onClickZoomOut={onZoomOut} />
|
<InfoAndHelp {...this.props} />
|
||||||
<InfoAndHelp topic={topic}
|
|
||||||
onHelpClick={openHelpLightbox} />
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,9 @@
|
||||||
"react-draggable": "3.0.3",
|
"react-draggable": "3.0.3",
|
||||||
"react-dropzone": "4.1.2",
|
"react-dropzone": "4.1.2",
|
||||||
"react-onclickoutside": "6.5.0",
|
"react-onclickoutside": "6.5.0",
|
||||||
|
"react-redux": "^5.0.6",
|
||||||
"react-router": "3.0.5",
|
"react-router": "3.0.5",
|
||||||
"redux": "3.7.2",
|
"redux": "^3.7.2",
|
||||||
"riek": "1.1.0",
|
"riek": "1.1.0",
|
||||||
"simplewebrtc": "2.2.2",
|
"simplewebrtc": "2.2.2",
|
||||||
"socket.io": "1.3.7",
|
"socket.io": "1.3.7",
|
||||||
|
|
Loading…
Add table
Reference in a new issue