mirror of
https://github.com/kevingruesser/bootstrap-vz.git
synced 2025-08-24 15:36:27 +00:00
Move taskoverview into docs/
This commit is contained in:
parent
de76c3aadd
commit
f86e15aa49
6 changed files with 223 additions and 0 deletions
1
docs/_static/graph.json
vendored
Normal file
1
docs/_static/graph.json
vendored
Normal file
File diff suppressed because one or more lines are too long
177
docs/_static/taskoverview.coffee
vendored
Normal file
177
docs/_static/taskoverview.coffee
vendored
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
class window.TaskOverview
|
||||||
|
viewBoxHeight = 800
|
||||||
|
viewBoxWidth = 200
|
||||||
|
margins =
|
||||||
|
top: 100
|
||||||
|
left: 50
|
||||||
|
bottom: 100
|
||||||
|
right: 50
|
||||||
|
gravity =
|
||||||
|
lateral: .1
|
||||||
|
longitudinal: .2
|
||||||
|
|
||||||
|
length = ([x,y]) -> Math.sqrt(x*x + y*y)
|
||||||
|
sum = ([x1,y1], [x2,y2]) -> [x1+x2, y1+y2]
|
||||||
|
diff = ([x1,y1], [x2,y2]) -> [x1-x2, y1-y2]
|
||||||
|
prod = ([x,y], scalar) -> [x*scalar, y*scalar]
|
||||||
|
div = ([x,y], scalar) -> [x/scalar, y/scalar]
|
||||||
|
unit = (vector) -> div(vector, length(vector))
|
||||||
|
scale = (vector, scalar) -> prod(unit(vector), scalar)
|
||||||
|
position = (coord, vector) -> [coord, sum(coord, vector)]
|
||||||
|
|
||||||
|
free = ([coord1, coord2]) -> diff(coord2, coord1)
|
||||||
|
pmult = (pvector=[coord1, _], scalar) -> position(coord1, prod(free(pvector), scalar))
|
||||||
|
pdiv = (pvector=[coord1, _], scalar) -> position(coord1, div(free(pvector), scalar))
|
||||||
|
|
||||||
|
constructor: ({@selector}) ->
|
||||||
|
@svg = d3.select(@selector)
|
||||||
|
.attr('viewBox', "0 0 #{viewBoxWidth} #{viewBoxHeight}")
|
||||||
|
d3.json '_static/graph.json', @buildGraph
|
||||||
|
|
||||||
|
buildGraph: (error, @data) =>
|
||||||
|
@createDefinitions()
|
||||||
|
taskLayout = @createNodes()
|
||||||
|
taskLayout.start()
|
||||||
|
|
||||||
|
createDefinitions: () ->
|
||||||
|
definitions = @svg.append 'defs'
|
||||||
|
arrow = definitions.append('marker')
|
||||||
|
arrow.attr('id', 'right-arrowhead')
|
||||||
|
.attr('refX', arrowHeight = 4)
|
||||||
|
.attr('refY', (arrowWidth = 6) / 2)
|
||||||
|
.attr('markerWidth', arrowHeight)
|
||||||
|
.attr('markerHeight', arrowWidth)
|
||||||
|
.attr('orient', 'auto')
|
||||||
|
.append('path').attr('d', "M0,0 V#{arrowWidth} L#{arrowHeight},#{arrowWidth/2} Z")
|
||||||
|
|
||||||
|
partitionKey = 'phase'
|
||||||
|
nodeColorKey = 'module'
|
||||||
|
|
||||||
|
keyMap:
|
||||||
|
phase: 'phases'
|
||||||
|
module: 'modules'
|
||||||
|
partition: (key, idx) ->
|
||||||
|
return @data[@keyMap[key]]
|
||||||
|
|
||||||
|
nodeRadius = 10
|
||||||
|
nodePadding = 10
|
||||||
|
createNodes: () ->
|
||||||
|
options =
|
||||||
|
gravity: 0
|
||||||
|
linkDistance: 50
|
||||||
|
linkStrength: .8
|
||||||
|
charge: -130
|
||||||
|
size: [viewBoxWidth, viewBoxHeight]
|
||||||
|
|
||||||
|
layout = d3.layout.force()
|
||||||
|
layout[option](value) for option, value of options
|
||||||
|
|
||||||
|
array_sum = (list) -> list.reduce(((a,b) -> a + b), 0)
|
||||||
|
partitioning =
|
||||||
|
nonLinear: (groupCounts, range, k=2) ->
|
||||||
|
ratios = (Math.pow(count, 1/k) for count in groupCounts)
|
||||||
|
fraction = range / (array_sum ratios)
|
||||||
|
return (fraction * ratio for ratio in ratios)
|
||||||
|
linear: (groups, range) ->
|
||||||
|
fraction = range / groups
|
||||||
|
return (fraction for _ in [0..groups])
|
||||||
|
offset: (ranges, i) -> (array_sum ranges.slice 0, i) + ranges[i] / 2
|
||||||
|
|
||||||
|
layout.nodes @data.nodes
|
||||||
|
layout.links @data.links
|
||||||
|
|
||||||
|
grouping = d3.nest().key((d) -> d[partitionKey]).sortKeys(d3.ascending)
|
||||||
|
|
||||||
|
widths = partitioning.nonLinear((d.values for d in grouping.rollup((d) -> d.length).entries(@data.nodes)),
|
||||||
|
viewBoxWidth - margins.left - margins.right)
|
||||||
|
heights = partitioning.nonLinear((d.values for d in grouping.rollup((d) -> d.length).entries(@data.nodes)),
|
||||||
|
viewBoxHeight - margins.top - margins.bottom, 4)
|
||||||
|
for node in @data.nodes
|
||||||
|
# node.cx = margins.left + partitioning.offset(widths, node[partitionKey])
|
||||||
|
# node.cy = viewBoxHeight / 2 + margins.top
|
||||||
|
node.cx = viewBoxWidth / 2 + margins.left
|
||||||
|
node.cy = margins.top + partitioning.offset(heights, node[partitionKey])
|
||||||
|
node.radius = nodeRadius
|
||||||
|
|
||||||
|
|
||||||
|
groups = d3.nest().key((d) -> d[partitionKey])
|
||||||
|
.sortKeys(d3.ascending)
|
||||||
|
.entries(layout.nodes())
|
||||||
|
|
||||||
|
hullColors = d3.scale.category20()
|
||||||
|
nodeColors = d3.scale.category20c()
|
||||||
|
|
||||||
|
hulls = @svg.append('g').attr('class', 'hulls')
|
||||||
|
.selectAll('path').data(groups).enter()
|
||||||
|
.append('path').attr('id', (d) -> "hull-#{d.key}")
|
||||||
|
.style
|
||||||
|
'fill': (d, i) -> hullColors(i)
|
||||||
|
'stroke': (d, i) -> hullColors(i)
|
||||||
|
|
||||||
|
hullLabels = @svg.append('g').attr('class', 'hull-labels')
|
||||||
|
.selectAll('text').data(groups).enter()
|
||||||
|
.append('text')
|
||||||
|
hullLabels.append('textPath').attr('xlink:href', (d) -> "#hull-#{d.key}")
|
||||||
|
.text((d) => @partition(partitionKey)[d.key].name)
|
||||||
|
|
||||||
|
links = @svg.append('g').attr('class', 'links')
|
||||||
|
.selectAll('line').data(layout.links()).enter()
|
||||||
|
.append('line').attr('marker-end', 'url(#right-arrowhead)')
|
||||||
|
|
||||||
|
nodes = @svg.append('g').attr('class', 'nodes')
|
||||||
|
.selectAll('g.partition').data(groups).enter()
|
||||||
|
.append('g').attr('class', 'partition')
|
||||||
|
.selectAll('circle').data((d) -> d.values).enter()
|
||||||
|
.append('circle').attr('r', (d) -> d.radius)
|
||||||
|
.style('fill', (d, i) -> nodeColors(d[nodeColorKey]))
|
||||||
|
.call(layout.drag)
|
||||||
|
.on('mouseover', (d) -> (labels.filter (l) -> d is l).classed 'hover', true)
|
||||||
|
.on('mouseout', (d) -> (labels.filter (l) -> d is l).classed 'hover', false)
|
||||||
|
|
||||||
|
labels = @svg.append('g').attr('class', 'node-labels')
|
||||||
|
.selectAll('g.partition').data(groups).enter()
|
||||||
|
.append('g').attr('class', 'partition')
|
||||||
|
.selectAll('text').data((d) -> d.values).enter()
|
||||||
|
.append('text').text((d) -> d.name)
|
||||||
|
.attr('transform', (d) -> offset=-(d.radius + 5); "translate(0,#{offset})")
|
||||||
|
|
||||||
|
rotate = (x, n) ->
|
||||||
|
n = n % x.length
|
||||||
|
x.slice(0,-n).reverse().concat(x.slice(-n).reverse()).reverse()
|
||||||
|
circle_coords = (parts) ->
|
||||||
|
partSize = 2*Math.PI/parts
|
||||||
|
return (for i in [0..parts]
|
||||||
|
theta = partSize*i
|
||||||
|
[(Math.cos theta), (Math.sin theta)])
|
||||||
|
hullPointMatrix = (prod(v, nodeRadius*2) for v in circle_coords(16))
|
||||||
|
hullBoundaries = (d) ->
|
||||||
|
nodePoints = d.values.map (i) -> [i.x, i.y]
|
||||||
|
padded_points = []
|
||||||
|
padded_points.push sum(p, v) for v in hullPointMatrix for p in nodePoints
|
||||||
|
points = d3.geom.hull(padded_points)
|
||||||
|
points = rotate points, Math.floor -points.length / 2.5
|
||||||
|
"M#{points.join('L')}Z"
|
||||||
|
|
||||||
|
gravity_fn = (alpha) =>
|
||||||
|
(d) ->
|
||||||
|
d.x += (d.cx - d.x) * alpha * gravity.lateral
|
||||||
|
d.y += (d.cy - d.y) * alpha * gravity.longitudinal
|
||||||
|
|
||||||
|
layout.on 'tick', (e) =>
|
||||||
|
hulls.attr('d', hullBoundaries)
|
||||||
|
nodes.each gravity_fn(e.alpha)
|
||||||
|
nodes.attr
|
||||||
|
cx: ({x}) -> x
|
||||||
|
cy: ({y}) -> y
|
||||||
|
labels.each gravity_fn(e.alpha)
|
||||||
|
labels.attr
|
||||||
|
x: ({x}) -> x
|
||||||
|
y: ({y}) -> y
|
||||||
|
links.each ({source:{x:x1,y:y1},target:{x:x2,y:y2}}, i) ->
|
||||||
|
[x,y] = scale(free([[x1,y1], [x2,y2]]), nodeRadius)
|
||||||
|
@setAttribute 'x1', x1 + x
|
||||||
|
@setAttribute 'y1', y1 + y
|
||||||
|
@setAttribute 'x2', x2 - x
|
||||||
|
@setAttribute 'y2', y2 - y
|
||||||
|
|
||||||
|
return layout
|
28
docs/_static/taskoverview.less
vendored
Normal file
28
docs/_static/taskoverview.less
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#taskoverview-graph {
|
||||||
|
g.hulls path {
|
||||||
|
opacity: 0.25;
|
||||||
|
}
|
||||||
|
g.hull-labels text {
|
||||||
|
}
|
||||||
|
g.nodes circle {
|
||||||
|
stroke: #000000;
|
||||||
|
opacity: .9;
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
}
|
||||||
|
g.node-labels text {
|
||||||
|
pointer-events: none;
|
||||||
|
font: 10px sans-serif;
|
||||||
|
text-anchor: middle;
|
||||||
|
text-shadow: 0 0 2px #FFFFFF;
|
||||||
|
font-weight: bold;
|
||||||
|
opacity: 0;
|
||||||
|
&.hover {
|
||||||
|
transition: opacity .5s;
|
||||||
|
opacity: .9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.links line {
|
||||||
|
stroke: #999;
|
||||||
|
stroke-opacity: .6;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
Development guidelines
|
Development guidelines
|
||||||
======================
|
======================
|
||||||
The following guidelines should serve as general advice when
|
The following guidelines should serve as general advice when
|
||||||
|
|
|
@ -16,6 +16,7 @@ Contents:
|
||||||
plugins/index
|
plugins/index
|
||||||
providers/index
|
providers/index
|
||||||
guidelines
|
guidelines
|
||||||
|
taskoverview
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
==================
|
==================
|
||||||
|
|
15
docs/taskoverview.rst
Normal file
15
docs/taskoverview.rst
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
Taskoverview
|
||||||
|
============
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<svg id="taskoverview-graph"></svg>
|
||||||
|
<link rel="stylesheet/less" type="text/css" href="_static/taskoverview.less">
|
||||||
|
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/less.js/1.5.0/less.min.js"></script>
|
||||||
|
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/coffee-script/1.6.3/coffee-script.min.js"></script>
|
||||||
|
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.3.11/d3.js"></script>
|
||||||
|
<script type="text/coffeescript" src="_static/taskoverview.coffee"></script>
|
||||||
|
<script type="text/coffeescript">
|
||||||
|
overview = new window.TaskOverview selector: '#taskoverview-graph'
|
||||||
|
</script>
|
Loading…
Add table
Reference in a new issue