This commit is contained in:
Connor Turland 2017-10-26 02:48:29 +00:00 committed by GitHub
commit 0d2df4b385
51 changed files with 811 additions and 343 deletions

View file

@ -4,7 +4,7 @@ import React from 'react'
import ReactDOM from 'react-dom'
import outdent from 'outdent'
import ImportDialogBox from '../../routes/MapView/ImportDialogBox'
import ImportDialogBox from '../../components/ImportDialogBox'
import PasteInput from '../PasteInput'
import Map from '../Map'

View file

@ -2,10 +2,13 @@
import React from 'react'
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import { Router, browserHistory } from 'react-router'
import { merge } from 'lodash'
import apply from 'async/apply'
import reducers from '../../reducers'
import { notifyUser } from './index.js'
import ImportDialog from './ImportDialog'
import Notifications from './Notifications'
@ -21,6 +24,11 @@ import Visualize from '../Visualize'
import makeRoutes from '../../routes/makeRoutes'
let routes
let store = createStore(
reducers,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
// 220 wide + 16 padding on both sides
const MAP_WIDTH = 252
const MOBILE_VIEW_BREAKPOINT = 504
@ -92,12 +100,15 @@ const ReactApp = {
render: function() {
const self = ReactApp
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'))
},
getProps: function() {
const self = ReactApp
return merge({
DataModel: DataModel,
unreadNotificationsCount: Notifications.unreadNotificationsCount,
currentUser: Active.Mapper,
toast: self.toast,

View file

@ -38,7 +38,6 @@ const JIT = {
zoom: 'Metamaps:JIT:events:zoom',
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.
*/
@ -55,8 +54,6 @@ const JIT = {
*/
convertModelsToJIT: function(topics, synapses) {
const jitReady = []
const synapsesToRemove = []
let mapping
let node
const nodes = {}
@ -70,11 +67,7 @@ const JIT = {
})
synapses.each(function(s) {
edge = s.createEdge()
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]) {
if (nodes[edge.nodeFrom] && nodes[edge.nodeTo]) {
existingEdge = _.find(edges, {
nodeFrom: edge.nodeFrom,
nodeTo: edge.nodeTo
@ -103,29 +96,8 @@ const JIT = {
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) {
// get nodes cartesian coordinates
const pos = adj.nodeFrom.pos.getc(true)

View file

@ -1,7 +1,7 @@
/* global $ */
import outdent from 'outdent'
import { find as _find } from 'lodash'
import _, { find as _find } from 'lodash'
import { browserHistory } from 'react-router'
import Active from '../Active'
@ -89,12 +89,31 @@ const Map = {
}
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) {
const self = Map
var dataIsReadySetupMap = function() {
if (DataModel.Topics.length === 0) {
Map.setHasLearnedTopicCreation(false)
} else {
Map.setHasLearnedTopicCreation(true)
}
Map.setAccessRequest()
Visualize.type = 'ForceDirected'
JIT.prepareVizData()
Selected.reset()
InfoBox.load()
Filter.reset()
@ -127,6 +146,7 @@ const Map = {
DataModel.Mappings = new DataModel.MappingCollection(data.mappings)
DataModel.Messages = data.messages
DataModel.Stars = data.stars
Map.cleanUpSynapses()
DataModel.attachCollectionEvents()
self.requests = data.requests
isLoaded()

View file

@ -11,13 +11,12 @@ import Loading from './Loading'
import TopicCard from './Views/TopicCard'
const Visualize = {
mGraph: null, // a reference to the graph object.
type: 'ForceDirected', // the type of graph we're building, could be "RGraph", "ForceDirected"
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
init: function(serverData) {
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
$('#infovis-canvas').on('dragstart', function(event) {
@ -39,58 +38,32 @@ const Visualize = {
computePositions: function() {
const self = Visualize
if (self.type === 'RGraph') {
let i
let l
// for RGraph
let i
let l
self.mGraph.graph.eachNode(function(n) {
const topic = DataModel.Topics.get(n.id)
topic.set({ node: n }, { silent: true })
topic.updateNode()
self.mGraph.graph.eachNode(function(n) {
const topic = DataModel.Topics.get(n.id)
topic.set({ node: n }, { silent: true })
topic.updateNode()
n.eachAdjacency(function(edge) {
if (!edge.getData('init')) {
edge.setData('init', true)
n.eachAdjacency(function(edge) {
if (!edge.getData('init')) {
edge.setData('init', true)
l = edge.getData('synapseIDs').length
for (i = 0; i < l; i++) {
const synapse = DataModel.Synapses.get(edge.getData('synapseIDs')[i])
synapse.set({ edge: edge }, { silent: true })
synapse.updateEdge()
}
l = edge.getData('synapseIDs').length
for (i = 0; i < l; i++) {
const synapse = DataModel.Synapses.get(edge.getData('synapseIDs')[i])
synapse.set({ edge: edge }, { silent: true })
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) {
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')
})
}
var pos = n.getPos()
pos.setc(-200, -200)
})
self.mGraph.compute('end')
},
/**
* render does the heavy lifting of creating the engine that renders the graph with the properties we desire
@ -98,92 +71,12 @@ const Visualize = {
*/
render: function() {
const self = Visualize
if (self.type === 'RGraph') {
// clear the previous canvas from #infovis
$('#infovis').empty()
const RGraphSettings = $.extend(true, {}, JIT.ForceDirected.graphSettings)
$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 {
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)
}
}
}
// 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()
const RGraphSettings = $.extend(true, {}, JIT.ForceDirected.graphSettings)
RGraphSettings.width = $(document).width()
RGraphSettings.height = $(document).height()
RGraphSettings.background = JIT.RGraph.background
RGraphSettings.levelDistance = JIT.RGraph.levelDistance
self.mGraph = new $jit.RGraph(RGraphSettings)
}
}

View 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'

View 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
}
}

View file

@ -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

View file

@ -1,7 +1,7 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import MapInfoBox from '../routes/MapView/MapInfoBox'
import MapInfoBox from './MapInfoBox'
class InfoAndHelp extends Component {
static propTypes = {

View file

@ -1,6 +1,6 @@
import React from 'react'
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 })

View file

@ -4,7 +4,7 @@ import Unread from './Unread'
import Participant from './Participant'
import Message from './Message'
import NewMessage from './NewMessage'
import Util from '../../../Metamaps/Util'
import Util from '../../Metamaps/Util'
function makeList(messages) {
let currentHeader

View 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

View 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

View 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)

View 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 {}
}

View 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)

View 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 {}
}

View 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)

View 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 {}
}

View 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)

View 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 {}
}

View 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)

View 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 {}
}

View file

@ -0,0 +1,9 @@
import { combineReducers } from 'redux'
import map from './map'
//import notifications from './notifications'
export default combineReducers({
map//,
//notifications
})

View 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
}

View file

@ -0,0 +1,5 @@
const initialState = {}
export default function (state = initialState, action) {
return state
}

View file

@ -0,0 +1,5 @@
const initialState = {}
export default function (state = initialState, action) {
return state
}

View file

@ -0,0 +1,5 @@
const initialState = {}
export default function (state = initialState, action) {
return state
}

View 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
}

View file

@ -0,0 +1,5 @@
const initialState = {}
export default function (state = initialState, action) {
return state
}

View 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
})

View file

@ -0,0 +1,5 @@
const initialState = {}
export default function (state = initialState, action) {
return state
}

View file

@ -0,0 +1,5 @@
const initialState = {}
export default function (state = initialState, action) {
return state
}

View file

@ -0,0 +1,5 @@
const initialState = {}
export default function (state = initialState, action) {
return state
}

View file

@ -0,0 +1,5 @@
const initialState = {}
export default function (state = initialState, action) {
return state
}

View file

@ -0,0 +1,8 @@
const initialState = {
Nodes: [],
Edges: []
}
export default function (state = initialState, action) {
return state
}

View 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
}

View file

@ -0,0 +1,3 @@
export default function (state = null, action) {
return state
}

View file

@ -0,0 +1,3 @@
export default function (state = null, action) {
return state
}

View file

@ -0,0 +1,3 @@
export default function notifications(state = [], action) {
return state
}

View 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>
}
}

View 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())
}
}
}

View file

@ -1,132 +1,5 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { mapStateToProps, mapDispatchToProps } from './MapView.store'
import MapView from './MapView'
import ContextMenu from '../../components/ContextMenu'
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>
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MapView)

View file

@ -1,12 +1,13 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import ContextMenu from '../components/ContextMenu'
import DataVis from '../components/DataVis'
import UpperOptions from '../components/UpperOptions'
import InfoAndHelp from '../components/InfoAndHelp'
import VisualizationControls from '../components/VisualizationControls'
import TopicCard from '../components/TopicCard'
import ContextMenu from '../containers/ContextMenu'
import UpperOptions from '../containers/UpperOptions'
import InfoAndHelp from '../containers/InfoAndHelp'
import VisualizationControls from '../containers/VisualizationControls'
import TopicCard from '../containers/TopicCard'
import TopicVis from '../components/TopicVis'
export default class TopicView extends Component {
@ -38,6 +39,7 @@ export default class TopicView extends Component {
}
endTopic() {
// TODO: fix upperOptions ref
this.upperOptions.reset()
this.props.endActiveTopic()
}
@ -60,26 +62,12 @@ export default class TopicView extends Component {
openHelpLightbox, onZoomIn, onZoomOut, contextMenu } = this.props
// TODO: stop using {...this.props} and make explicit
return <div className="topicWrapper">
<UpperOptions ref={x => this.upperOptions = x}
currentUser={currentUser}
topic={topic}
onForkClick={forkMap}
filterData={filterData}
allForFiltering={allForFiltering}
visibleForFiltering={visibleForFiltering}
toggleMetacode={toggleMetacode}
toggleMapper={toggleMapper}
toggleSynapse={toggleSynapse}
filterAllMetacodes={filterAllMetacodes}
filterAllMappers={filterAllMappers}
filterAllSynapses={filterAllSynapses} />
<DataVis />
<UpperOptions ref={x => this.upperOptions = x} {...this.props} />
<TopicVis />
<TopicCard {...this.props} />
{contextMenu && <ContextMenu {...this.props} />}
<VisualizationControls onClickZoomIn={onZoomIn}
onClickZoomOut={onZoomOut} />
<InfoAndHelp topic={topic}
onHelpClick={openHelpLightbox} />
<VisualizationControls {...this.props} />
<InfoAndHelp {...this.props} />
</div>
}
}

View file

@ -49,8 +49,9 @@
"react-draggable": "3.0.3",
"react-dropzone": "4.1.2",
"react-onclickoutside": "6.5.0",
"react-redux": "^5.0.6",
"react-router": "3.0.5",
"redux": "3.7.2",
"redux": "^3.7.2",
"riek": "1.1.0",
"simplewebrtc": "2.2.2",
"socket.io": "1.3.7",