src/View/graphView.coffee
__ = require('underscore')
Backbone = require('backbone')
XAxisView = require('./xAxisView')
YAxisView = require('./yAxisView')
GraphCanvasView = require('./graphCanvasView')
GraphPointView = require('./graphPointView')
ScaleChangeView = require('./scaleChangeView')
RangeView = require('./rangeView')
GestureView = require('./gestureView')
ScaleData = require('../Model/scaleData')
OffsetData = require('../Model/offsetData')
RangeData = require('../Model/rangeData')
AxisData = require('../Model/axisData')
RectRegion = require('../Model/rectRegion')
GestureData = require('../Model/gestureData')
GestureDataCollection = require('../Model/gestureDataCollection')
class GraphView extends Backbone.View
@ORIGIN_OFFSET_X : 40
@ORIGIN_OFFSET_Y : 30
@FONT_SIZE : 12
@SCROLL_WIDTH : 20
@RANGE_RESIZE_WIDTH: 3
tagName: "div"
_graphOptions = ['width', 'height', 'xAxis', 'yAxis', 'range']
#options =
# collection: GraphDataCollectionClassObject
# width: w
# height: h
# xAxis:{max:max, interval:i, subInterval:s, axisColor:"#RRGGBB"}
# yAxis:{max:max, interval:i, subInterval:s, axisColor:"#RRGGBB"}
# range:{color: "##RRGGBB", opacity: o}
initialize: (options) ->
__.extend(@, __.pick(options, _graphOptions))
@_xAxisData = new AxisData(@xAxis)
@_yAxisData = new AxisData(@yAxis)
@_xScaleData = new ScaleData({title: "X"})
@_yScaleData = new ScaleData({title: "Y"})
@_xOffsetData = new OffsetData({
width: @width - GraphView.ORIGIN_OFFSET_X
scale: @_xScaleData
})
@_xRangeData = new RangeData({
width: @width - GraphView.ORIGIN_OFFSET_X
scale: @_xScaleData
axis: @_xAxisData
offset: @_xOffsetData
targetGraph: @collection.models[0]
rangeColor: @range.color
rangeOpacity: @range.opacity
})
@render()
@_registerEvent()
@_registerDefaultGesture()
render: ->
@_yAxisView = new YAxisView({
model: @_yAxisData
pos: [0, 0, GraphView.ORIGIN_OFFSET_X, @height - GraphView.ORIGIN_OFFSET_Y]
yScale: @_yScaleData
})
@_yAxisView.$wrap.appendTo(@$el)
@_graphCanvasView = new GraphCanvasView({
collection: @collection
pos: [GraphView.ORIGIN_OFFSET_X, 0, @width - GraphView.ORIGIN_OFFSET_X, @height - GraphView.ORIGIN_OFFSET_Y]
xAxis: @_xAxisData
yAxis: @_yAxisData
xScale: @_xScaleData
yScale: @_yScaleData
xOffset: @_xOffsetData
})
@_graphCanvasView.$wrap.appendTo(@$el)
@_xAxisView = new XAxisView({
model: @_xAxisData
pos: [GraphView.ORIGIN_OFFSET_X, @height - GraphView.ORIGIN_OFFSET_Y, @width - GraphView.ORIGIN_OFFSET_X, GraphView.ORIGIN_OFFSET_Y]
xScale: @_xScaleData
xOffset: @_xOffsetData
})
@_xAxisView.$wrap.appendTo(@$el)
@_rangeView = new RangeView({
model: @_xRangeData
pos: [GraphView.ORIGIN_OFFSET_X, 0, @width - GraphView.ORIGIN_OFFSET_X, @height - GraphView.ORIGIN_OFFSET_Y]
xAxis: @_xAxisData
xScale: @_xScaleData
xOffset: @_xOffsetData
})
@_rangeView.$wrap.appendTo(@$el)
@_xScaleChangeView = new ScaleChangeView({
model: @_xScaleData
})
@_xScaleChangeView.$el.appendTo(@$el)
@$el
.css({
left: 0
top: 0
width: @width
height: @height
})
@
_registerEvent: ->
@listenTo(@collection, "change", =>
@_xAxisData.max = @collection.xMax
@_yAxisData.max = @collection.yMax
@_yAxisView.render()
@_graphCanvasView.render()
@_xAxisView.render()
@_rangeView.render()
@_registerRangeGesture()
@_registerPointGesture()
)
@listenTo(@_xScaleData, "change", =>
@_xOffsetData.scroll(0)
@_graphCanvasView.render()
@_xAxisView.render()
@_rangeView.render()
@_registerRangeGesture()
@_registerPointGesture()
)
@listenTo(@_xOffsetData, "change", =>
@_graphCanvasView.scrollX()
@_xAxisView.scrollX()
@_rangeView.scrollX()
)
@listenTo(@_xRangeData, "change", =>
@_rangeView.render()
)
_registerDefaultGesture: ->
@_rangeRegion = new RectRegion(
GraphView.ORIGIN_OFFSET_X
, GraphView.ORIGIN_OFFSET_Y
, =>
divWidth = (@width - GraphView.ORIGIN_OFFSET_X) * @_xScaleData.scale / 100 - GraphView.ORIGIN_OFFSET_Y + GraphView.ORIGIN_OFFSET_X
return Math.min(divWidth + @_xOffsetData.offset, @width)
, @height - GraphView.ORIGIN_OFFSET_Y * 2 - 1
)
@_rangeRepeatRegion = [
new RectRegion(null, null, GraphView.ORIGIN_OFFSET_X - 1, null)
new RectRegion(@width - GraphView.ORIGIN_OFFSET_Y + 1, null, null, null)
]
rangeGesture = new GestureData({
actionRegion: @_rangeRegion
roundRegion: @_rangeRegion
cursor: "crosshair"
repeat: @_rangeRepeatRegion
})
.on({
click: (mousePos) =>
if @_xRangeData.selected
@_xRangeData.selected = false
else
@_xRangeData.autoSelectX(mousePos.currentPos.x - GraphView.ORIGIN_OFFSET_X)
@_registerRangeGesture()
dragStart: (mousePos) =>
@_xRangeData.selectStartX(mousePos.currentPos.x - GraphView.ORIGIN_OFFSET_X)
dragging: (mousePos) =>
@_xRangeData.selectEndX(mousePos.roundPos.x - GraphView.ORIGIN_OFFSET_X)
dragEnd: (mousePos) =>
@_registerRangeGesture()
@_registerPointGesture()
repeat: (mousePos, index) =>
if index == 0
@_xOffsetData.scroll(GraphView.SCROLL_WIDTH)
else
@_xOffsetData.scroll(-GraphView.SCROLL_WIDTH)
@_xRangeData.selectEndX(mousePos.roundPos.x - GraphView.ORIGIN_OFFSET_X)
})
@_scrollRegion = new RectRegion(GraphView.ORIGIN_OFFSET_X, @height - GraphView.ORIGIN_OFFSET_Y * 2, @width, @height)
scrollGesture = new GestureData({
actionRegion: @_scrollRegion
roundRegion: @_scrollRegion
cursor: "move"
repeat: []
})
.on({
dragging: (mousePos) =>
@_xOffsetData.scroll(mousePos.differencePos.x)
dragEnd: (mousePos) =>
@_registerRangeGesture()
@_registerPointGesture()
})
@_gestureCollection = new GestureDataCollection([rangeGesture, scrollGesture])
@_gestureView = new GestureView({
el: @$el
collection: @_gestureCollection
})
_rangeGestures = []
_registerRangeGesture: ->
@_gestureCollection.remove(_rangeGestures)
_rangeGestures = []
@_xRangeData.determineSelection()
if @_xRangeData.selected
screenStart = @_xRangeData.screenStart + GraphView.ORIGIN_OFFSET_X
screenEnd = @_xRangeData.screenEnd + GraphView.ORIGIN_OFFSET_X
if screenStart >= GraphView.ORIGIN_OFFSET_X && screenStart <= @width
rangeStartGesture = new GestureData({
actionRegion: new RectRegion(
screenStart - GraphView.RANGE_RESIZE_WIDTH
, GraphView.ORIGIN_OFFSET_Y
, screenStart + GraphView.RANGE_RESIZE_WIDTH
, @height - GraphView.ORIGIN_OFFSET_Y * 2 - 1
)
roundRegion: @_rangeRegion
cursor: "col-resize"
repeat: @_rangeRepeatRegion
})
.on({
dragging: (mousePos) =>
@_xRangeData.selectStartX(mousePos.roundPos.x - GraphView.ORIGIN_OFFSET_X)
dragEnd: (mousePos) =>
@_registerRangeGesture()
@_registerPointGesture()
repeat: (mousePos, index) =>
if index == 0
@_xOffsetData.scroll(GraphView.SCROLL_WIDTH)
else
@_xOffsetData.scroll(-GraphView.SCROLL_WIDTH)
@_xRangeData.selectStartX(mousePos.roundPos.x - GraphView.ORIGIN_OFFSET_X)
})
@_gestureCollection.add(rangeStartGesture)
_rangeGestures.push(rangeStartGesture)
range = [screenStart, screenEnd].sort((a,b) -> a - b)
range[0] += GraphView.RANGE_RESIZE_WIDTH
range[1] -= GraphView.RANGE_RESIZE_WIDTH
if range[0] >= range[1]
return
if screenEnd >= GraphView.ORIGIN_OFFSET_X && screenEnd <= @width
rangeEndGesture = new GestureData({
actionRegion: new RectRegion(
screenEnd - GraphView.RANGE_RESIZE_WIDTH
, GraphView.ORIGIN_OFFSET_Y
, screenEnd + GraphView.RANGE_RESIZE_WIDTH
, @height - GraphView.ORIGIN_OFFSET_Y * 2 - 1
)
roundRegion: @_rangeRegion
cursor: "col-resize"
repeat: @_rangeRepeatRegion
})
.on({
dragging: (mousePos) =>
@_xRangeData.selectEndX(mousePos.roundPos.x - GraphView.ORIGIN_OFFSET_X)
dragEnd: (mousePos) =>
@_registerRangeGesture()
@_registerPointGesture()
repeat: (mousePos, index) =>
if index == 0
@_xOffsetData.scroll(GraphView.SCROLL_WIDTH)
else
@_xOffsetData.scroll(-GraphView.SCROLL_WIDTH)
@_xRangeData.selectEndX(mousePos.roundPos.x - GraphView.ORIGIN_OFFSET_X)
})
@_gestureCollection.add(rangeEndGesture)
_rangeGestures.push(rangeEndGesture)
if range[0] <= @width && range[1] >= GraphView.ORIGIN_OFFSET_X
rangeGesture = new GestureData({
actionRegion: new RectRegion(
Math.max(range[0], GraphView.ORIGIN_OFFSET_X)
, GraphView.ORIGIN_OFFSET_Y
, Math.min(range[1], @width)
, @height - GraphView.ORIGIN_OFFSET_Y * 2 - 1
)
roundRegion: @_rangeRegion
cursor: "move"
repeat: @_rangeRepeatRegion
})
.on({
dragging: (mousePos) =>
@_xRangeData.shiftX(mousePos.differencePos.x)
dragEnd: (mousePos) =>
@_registerRangeGesture()
@_registerPointGesture()
repeat: (mousePos, index) =>
if index == 0
if @_xRangeData.start > 0
@_xOffsetData.scroll(GraphView.SCROLL_WIDTH)
@_xRangeData.shiftX(mousePos.differencePos.x - GraphView.SCROLL_WIDTH)
else
if @_xRangeData.end < @_xAxisData.max
@_xOffsetData.scroll(-GraphView.SCROLL_WIDTH)
@_xRangeData.shiftX(mousePos.differencePos.x + GraphView.SCROLL_WIDTH)
})
@_gestureCollection.add(rangeGesture)
_rangeGestures.push(rangeGesture)
_pointGestures = []
_registerPointGesture: ->
@_gestureCollection.remove(_pointGestures)
_pointGestures = []
@_graphCanvasView.subView.forEach((subView) =>
if subView instanceof GraphPointView
subView.drawPointList.forEach((drawPoint, index) =>
if @_rangeRegion.isInside(drawPoint.x + GraphView.ORIGIN_OFFSET_X + @_xOffsetData.offset, drawPoint.y)
pointRegion = new RectRegion(
drawPoint.x + GraphView.ORIGIN_OFFSET_X + @_xOffsetData.offset - 5
, drawPoint.y - 7
, drawPoint.x + GraphView.ORIGIN_OFFSET_X + @_xOffsetData.offset + 5
, drawPoint.y + 7
)
pointGesture = new GestureData({
actionRegion: pointRegion
roundRegion: pointRegion
cursor: "pointer"
repeat: []
})
.on({
click: (mousePos) =>
subView.model.triggerEvent('click', index, mousePos.currentPos)
mouseenter: (mousePos) =>
subView.model.triggerEvent('mouseenter', index, mousePos.currentPos)
mouseleave: (mousePos) =>
subView.model.triggerEvent('mouseleave', index)
})
@_gestureCollection.add(pointGesture)
_pointGestures.push(pointGesture)
)
)
module.exports = GraphView