Compare commits

...

1 commit

Author SHA1 Message Date
Connor Turland a763484235 move more event handling into native jit, and decouple 2017-10-25 14:15:55 -04:00
8 changed files with 1588 additions and 3412 deletions

View file

@ -23,8 +23,6 @@ import TopicCard from './Views/TopicCard'
import Util from './Util'
import Visualize from './Visualize'
let panningInt
const JIT = {
tempInit: false,
tempNode: null,
@ -272,14 +270,27 @@ const JIT = {
graphSettings: {
// id of the visualization container
injectInto: 'infovis',
// Enable zooming and panning
// by scrolling and DnD
// Number of iterations for the FD algorithm
iterations: 200,
// Edge length
levelDistance: 200,
Navigation: {
enable: true,
// Enable panning events only if we're dragging the empty
// canvas (and not a node).
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
// color and width.
@ -299,81 +310,36 @@ const JIT = {
lineWidth: 2,
alpha: 1
},
// Native canvas text styling
Label: {
type: 'Native', // Native or HTML
type: 'Native',
size: 20,
family: 'arial',
textBaseline: 'alphabetic',
color: Settings.colors.labels.text
},
// Add Tips
Tips: {
enable: false,
onShow: function(tip, node) {}
},
// Add node events
// this is events for clicking on edges and nodes in particular
Events: {
enable: true,
enableForEdges: true,
onMouseMove: function(node, eventInfo, e) {
JIT.onMouseMoveHandler(node, eventInfo, e)
// console.log('called mouse move handler')
},
// Update node positions when dragged
onDragMove: function(node, eventInfo, e) {
JIT.onDragMoveTopicHandler(node, eventInfo, e)
// console.log('called drag move handler')
},
onDragEnd: function(node, eventInfo, e) {
JIT.onDragEndTopicHandler(node, eventInfo, e, false)
// console.log('called drag end handler')
},
onDragCancel: function(node, eventInfo, e) {
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) {
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) {
// remove the rightclickmenu
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
// clicking on a edge, node, or clicking on blank part of canvas?
if (node.nodeFrom) {
JIT.selectEdgeOnClickHandler(node, e)
@ -387,34 +353,15 @@ const JIT = {
onRightClick: function(node, eventInfo, e) {
// remove the rightclickmenu
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
// clicking on a edge, node, or clicking on blank part of canvas?
if (node.nodeFrom) {
JIT.selectEdgeOnRightClickHandler(node, e)
} else if (node && !node.nodeFrom) {
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: {
'customNode': {
@ -509,97 +456,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: {
animate: {
modes: ['polar'],
@ -1103,12 +960,12 @@ const JIT = {
return {}
}
},
selectWithBox: function(e) {
selectWithBox: function(e, corner, oppositeCorner) {
const self = this
let sX = Mouse.boxStartCoordinates.x
let sY = Mouse.boxStartCoordinates.y
let eX = Mouse.boxEndCoordinates.x
let eY = Mouse.boxEndCoordinates.y
let sX = corner.x
let sY = corner.y
let eX = oppositeCorner.x
let eY = oppositeCorner.y
if (!e.shiftKey) {
Control.deselectAllNodes()
@ -1245,30 +1102,7 @@ const JIT = {
}
}
})
Mouse.boxStartCoordinates = false
Mouse.boxEndCoordinates = false
Visualize.mGraph.plot()
}, // 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) {
if (Visualize.mGraph.busy) return
@ -1398,26 +1232,6 @@ const JIT = {
Control.selectEdge(adj)
ContextMenu.selectEdge(ReactApp.render, adj, {x: e.clientX, y: e.clientY})
}, // 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) {
const ctx = canvas.getCtx()
// invert edge direction
@ -1522,53 +1336,11 @@ const JIT = {
},
centerMap: function(canvas) {
const offsetScale = canvas.scaleOffsetX
canvas.scale(1 / offsetScale, 1 / offsetScale)
const offsetX = canvas.translateOffsetX
const offsetY = canvas.translateOffsetY
canvas.scale(1 / offsetScale, 1 / offsetScale)
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) {
JIT.centerMap(canvas)
let height = canvas.getSize().height

View file

@ -0,0 +1,6 @@
import $jit from '../patched/JIT'
const mJit = {}
$jit(mJit)
export default mJit

View file

@ -1,11 +1,5 @@
const Mouse = {
didPan: false,
didBoxZoom: false,
changeInX: 0,
changeInY: 0,
edgeHoveringOver: false,
boxStartCoordinates: false,
boxEndCoordinates: false,
synapseStartCoordinates: [],
synapseEndCoordinates: null,
lastNodeClick: 0,

View file

@ -201,34 +201,6 @@ const Util = {
},
isTester: function(currentUser) {
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)
}
}

View file

@ -12,10 +12,8 @@ import TopicCard from './Views/TopicCard'
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"
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
touchDragNode: null,
init: function(serverData) {
var self = Visualize
@ -32,16 +30,10 @@ const Visualize = {
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
$('#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
Visualize.touchDragNode = false
})
},
computePositions: function() {
@ -98,8 +90,6 @@ const Visualize = {
n.setPos(startPos, 'start')
n.setPos(endPos, 'end')
})
} else if (self.type === 'ForceDirected3D') {
self.mGraph.compute()
}
},
/**
@ -137,13 +127,6 @@ const Visualize = {
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()
}
@ -168,8 +151,6 @@ const Visualize = {
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)
}
}
}

View file

@ -13,6 +13,7 @@ import GlobalUI, {
} from './GlobalUI'
import Import from './Import'
import JIT from './JIT'
import JitExtended from './JitExtended'
import Listeners from './Listeners'
import Loading from './Loading'
import Map, { CheatSheet, InfoBox } from './Map'
@ -49,6 +50,7 @@ Metamaps.GlobalUI.CreateMap = CreateMap
Metamaps.GlobalUI.ImportDialog = ImportDialog
Metamaps.Import = Import
Metamaps.JIT = JIT
Metamaps.JitExtended = JitExtended
Metamaps.Listeners = Listeners
Metamaps.Loading = Loading
Metamaps.Map = Map

View file

@ -5,7 +5,9 @@ Backbone.ajax = (opts) => window.$.ajaxq('backbone-ajaxq', opts)
import _ from 'lodash'
import Metamaps from './Metamaps'
import $jit from './patched/JIT'
// create global references
window._ = _
window.Metamaps = Metamaps
window.$jit = $jit

File diff suppressed because it is too large Load diff