Skip to content

Instantly share code, notes, and snippets.

@wallrat
Created January 7, 2014 15:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save wallrat/8300597 to your computer and use it in GitHub Desktop.
Save wallrat/8300597 to your computer and use it in GitHub Desktop.
A Pen by Andreas Bielk.
<div id="content"></div>
DOM = React.DOM
PANEL_WIDTH = 250
PANEL_HEIGHT = 150
PANEL_MARGIN = 20
Panel = React.createClass
displayName: 'Panel'
render: ->
style =
position: 'absolute'
width: PANEL_WIDTH
height: PANEL_HEIGHT
left: @props.x
top: @props.y
className = 'panel'
if @props.dragging
className = className + ' dragging'
DOM.div
key: @props.id
style: style
className: className
onMouseDown: @props.onMouseDown
, @props.id
Panels = React.createClass
displayName: 'Panels'
getInitialState: ->
data = []
data.push
id: 'panel1'
x: 0
y: 0
data.push
id: 'panel2'
x: PANEL_WIDTH + PANEL_MARGIN
y: PANEL_HEIGHT + PANEL_MARGIN
data.push
id: 'panel3'
x: 2* (PANEL_WIDTH + PANEL_MARGIN)
y: 0
return data: data, dragging: false
snap: (x,y) ->
col = Math.round (x / (PANEL_WIDTH + PANEL_MARGIN))
row = Math.round (y / (PANEL_HEIGHT + PANEL_MARGIN))
sx = col * (PANEL_WIDTH + PANEL_MARGIN)
sy = row * (PANEL_HEIGHT + PANEL_MARGIN)
return [sx,sy]
snapPanels: (panels) ->
that = @
panels.map (p) ->
[p.x,p.y] = that.snap p.x,p.y
return p
shufflePanels: (panels,bully) ->
occupied = (x,y) ->
for p in panels
if p.x is x and p.y is y and (p.id isnt bully.id) then return true
return false
return panels unless occupied(bully.x,bully.y)
result = panels.slice(0)
for p in result
continue if p.id is bully.id
continue if p.y < bully.y
continue if p.x isnt bully.x
p.y += PANEL_HEIGHT + PANEL_MARGIN
return result
getPanel: (id,ps=@state.data) ->
for p in ps
return p if p.id is id
return null
updatePanelPosition: (id,x,y) ->
ds = @state.data.slice(0)
for p in ds
if p.id is id
p.x = x
p.y = y
@setState
data: ds
dragStart: (panel,e) ->
e.preventDefault()
@setState dragging: panel, dragStartX: e.pageX, dragStartY: e.pageY
return
dragEnd: (e) ->
e.preventDefault()
return unless @state.dragging
ps = @state.data
ps = @snapPanels ps
ps = @shufflePanels ps, @getPanel(@state.dragging.id,ps)
@setState dragging: false, data: ps
return
onDrag: (e) ->
e.preventDefault()
dx = e.pageX - @state.dragStartX
dy = e.pageY - @state.dragStartY
@updatePanelPosition @state.dragging.id, @state.dragging.x + dx, @state.dragging.y + dy
render: ->
dragStart = @dragStart
dragEnd = @dragEnd
onMouseMove = if @state.dragging then @onDrag else null
dragging = @state.dragging
panels = []
for p in @state.data
do (p) ->
_p = id:p.id,x:p.x,y:p.y
panels.push Panel
id: p.id
x: p.x
y: p.y
dragging: dragging and (dragging.id is p.id)
onMouseDown: (e) -> dragStart _p,e
# markers
if @state.dragging
style =
position: 'absolute'
width: PANEL_WIDTH
height: PANEL_HEIGHT
left: @state.dragging.x
top: @state.dragging.y
panels.push DOM.div {className: 'drag-from-marker', style: style}, []
cp = @getPanel @state.dragging.id
[x,y] = @snap cp.x,cp.y
unless x is @state.dragging.x and y is @state.dragging.y
style =
position: 'absolute'
width: PANEL_WIDTH
height: PANEL_HEIGHT
left: x
top: y
panels.push DOM.div {className: 'drag-to-marker', style: style}, []
DOM.div {ref: 'panels',className: 'panels',onMouseMove: onMouseMove, onMouseUp: dragEnd},panels
React.renderComponent(
Panels(null),
document.getElementById('content')
);
.panels {
margin-top: 30px;
margin-left: 0px;
padding: 0;
}
.panel {
background: #eef;
z-index: 1000;
transition: left 0.5s, top 0.5s;
}
.panel.dragging {
z-index: 1002;
opacity: 0.5;
transition: left 0, top 0, opacity 0.2s;
}
.drag-from-marker {
background: #fee;
z-index: 500;
}
.drag-to-marker {
background: #efe;
z-index: 1001;
opacity: 0.5;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment