diff --git a/index.html b/index.html
index ac7e4b6db..f268672c2 100644
--- a/index.html
+++ b/index.html
@@ -3,7 +3,7 @@
GroundForge : A web based toolbox to design bobbin lace grounds with matching diagrams.
-
+
diff --git a/js/index.js b/js/index.js
index 41b583718..660ecbb2d 100644
--- a/js/index.js
+++ b/js/index.js
@@ -45,8 +45,6 @@ function load() {
palette: colors,
onAnimationEnd: function() {setHref(document.getElementById("dlThread"),'threads')}
})
- var p = document.getElementById("pairs" ); p.scrollTop = p.scrollTop==0 ? 180 : p.scrollTop
- var t = document.getElementById("threads"); t.scrollTop = t.scrollTop==0 ? 140 : t.scrollTop
}
function onChangeColor(el) {
if (el.value == 'FFFFFF') {
diff --git a/js/show-graph.js b/js/show-graph.js
index cb1439904..78e362a40 100644
--- a/js/show-graph.js
+++ b/js/show-graph.js
@@ -1,27 +1,15 @@
fullyTransparant = 0 // global to allow override while testing
var diagram = {}
-diagram.startThread = function(svgDefs){
+diagram.start = function(svgDefs, id, shape){
svgDefs.append('svg:marker')
- .attr('id', "start-thread")
+ .attr('id', id)
.attr('viewBox', '-7 -7 14 14')
.attr('markerWidth', 12)
.attr('markerHeight', 12 )
.attr('orient', 'auto')
.attr('markerUnits', 'userSpaceOnUse')
.append('svg:path')
- .attr('d', d3.svg.symbol().type("square"))
- .attr('fill', "#000").style('opacity',0.5)
-}
-diagram.startPair = function(svgDefs){
- svgDefs.append('svg:marker')
- .attr('id', "start-pair")
- .attr('viewBox', '-7 -7 14 14')
- .attr('markerWidth', 10)
- .attr('markerHeight', 12 )
- .attr('orient', 'auto')
- .attr('markerUnits', 'userSpaceOnUse')
- .append('svg:path')
- .attr('d', d3.svg.symbol().type("diamond"))
+ .attr('d', shape)
.attr('fill', "#000").style('opacity',0.5)
}
diagram.twistMark = function(svgDefs){
@@ -67,40 +55,27 @@ diagram.markers = function(svgDefs,id,color){
diagram.shape = {}
diagram.shape.stitch = "M 6,0 A 6,6 0 0 1 0,6 6,6 0 0 1 -6,0 6,6 0 0 1 0,-6 6,6 0 0 1 6,0 Z" // larger circle
diagram.shape.pin = "M 4,0 A 4,4 0 0 1 0,4 4,4 0 0 1 -4,0 4,4 0 0 1 0,-4 4,4 0 0 1 4,0 Z" // smaller circle
+diagram.shape.square = "M -6,-6 6,-6 6,6 -6,6 Z"
+diagram.shape.diamond = "M -5,0 0,8 5,0 0,-8 Z"
diagram.shape.bobbin = "m 0,40 c -3.40759,0 -6.01351,3.60204 -1.63269,3.60204 l 0,19.82157 c -3.67432,-0.008 -1.7251,5.087 -1.32784,7.27458 0.76065,4.18864 1.01701,8.40176 0.3478,12.58551 -1.68869,10.55725 -2.31894,21.67593 1.25552,31.9161 0.2088,0.59819 0.68935,2.7631 1.40054,2.7636 0.71159,0 1.19169,-2.16521 1.40057,-2.7636 C 5.01838,104.95964 4.38954,93.84095 2.70085,83.2837 2.03164,79.09995 2.28656,74.88683 3.04721,70.69819 3.44447,68.51061 5.61865,63.44146 1.71951,63.42361 l 0,-19.82157 C 5.86853,43.60204 3.4855,39.99659 0,40 L 0,0"
-diagram.transform = function(d) {
- return "translate(" + d.x + "," + d.y + ")"
-}
diagram.markLinks = function(links) {
links
.style('marker-start', function(d) { if (d.start != "white") return 'url(#start-'+d.start+')' })
.style('marker-end', function(d) { if (d.end != "white") return 'url(#end-'+d.end+')' })
.style('marker-mid', function(d,i) { if (d.mid) return 'url(#twist-1)' })
}
-diagram.path = function(d) {
- var sX = d.source.x
- var sY = d.source.y
- var tX = d.target.x
- var tY = d.target.y
- var dX = (tX - sX)
- var dY = (tY - sY)
- var mid = d.left ? ("S" + (sX - dY/3 + dX/3) + "," + (sY + dX/3 + dY/3)) :
- d.right ? ("S" + (sX + dY/3 + dX/3) + "," + (sY + dY/3 - dX/3)) :
- " "
- if (d.end && d.end == "white")
- return "M"+ sX + "," + sY + mid + " " + (tX - dX/4) + "," + (tY - dY/4)
- if (d.start && d.start == "white")
- return "M"+ (sX + dX/4) + "," + (sY + dY/4) + mid + " " + tX + "," + tY
- if (d.mid)
- return "M"+ sX + "," + sY + " " + (sX + dX/2) + "," + (sY + dY/2) + " " + tX + "," + tY
- return "M"+ sX + "," + sY + " " + tX + "," + tY
-}
-diagram.showGraph = function(args) {
- var colorpicker = (args.threadColor == undefined ? undefined : d3.select(args.threadColor)[0][0])
+diagram.showGraph = function(args) {
args.width = args.width ? args.width : 744
args.height = args.height? args.height : 1052
+ var m = args.links.length
+ for (i = 0; i < m; ++i) {
+ var link = args.links[i]
+ link.source = args.nodes[link.source];
+ link.target = args.nodes[link.target];
+ }
+
// document creation
var svgRoot = d3.select(args.container).append("svg")
.attr("width", args.width)
@@ -110,8 +85,8 @@ diagram.showGraph = function(args) {
// marker definitions
var defs = svgRoot.append('svg:defs')
- diagram.startThread(defs)
- diagram.startPair(defs)
+ diagram.start(defs, "start-thread", diagram.shape.square)
+ diagram.start(defs, "start-pair", diagram.shape.diamond)
diagram.twistMark(defs)
diagram.markers(defs, 'green','#0f0')
diagram.markers(defs, 'red','#f00')
@@ -121,7 +96,8 @@ diagram.showGraph = function(args) {
// zoom functionality
var container = svgRoot.append('svg:g')
- .call(d3.behavior.zoom().scale(args.scale).on("zoom", redraw))
+ //.call(d3.zoom().scaleTo(args.scale).on("zoom", redraw))
+ //https://github.com/d3/d3/blob/master/CHANGES.md#zooming-d3-zoom
.append('svg:g')
.attr("transform", args.transform)
@@ -141,40 +117,27 @@ diagram.showGraph = function(args) {
var isIE = document.documentURI == undefined // wrong feature check
var isMobileMac = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream
- var link = container.selectAll(".path").data(args.links).enter().append("svg:path")
- .attr("class", function(d) { return d.thread ? "link thread" + d.thread : "link"})
+ var links = container.selectAll(".path").data(args.links).enter().append("svg:path")
+ .attr("class", function(d) { return d.thread ? "link thread" + d.thread : "link" })
.attr("id",function(d,i) { return "link_" + i; })
.style('opacity', function(d) { return d.border || d.toPin ? fullyTransparant : 1})
.style('stroke', '#000')
.style('fill', 'none')
- if (!isIE) diagram.markLinks(link)
+ if (!isIE) diagram.markLinks(links)
- var sh // an inline assignment prevent two lookups
- var node = container.selectAll(".node").data(args.nodes).enter().append("svg:path")
+ var nodes = container.selectAll(".node").data(args.nodes).enter().append("svg:path")
.attr("d", function(d) { return (d.bobbin ? diagram.shape.bobbin : d.pin ? diagram.shape.pin : diagram.shape.stitch)})
.attr("class", function(d) { return "node " + (d.startOf ? "threadStart" : d.thread ? ("thread"+d.thread) : "")})
.style('opacity', function(d) { return d.bobbin || d.pin ? 1 : fullyTransparant})
.style('fill', '#000000')
.style('stroke', function(d) { return d.pin ? 'none' : '#000000'})
- node.append("svg:title").text(function(d) { return d.title ? d.title : "" })
- var threadStarts = container.selectAll(".threadStart")
-
- // configure layout
-
- var force = d3.layout.force()
- .nodes(args.nodes)
- .links(args.links)
- .size([args.width, args.height])
- .charge(-20)
- .linkDistance(10)
- .linkStrength(10)
- .start()
- .alpha(0.01)
+ nodes.append("svg:title").text(function(d) { return d.title ? d.title : "" })
+ var threadStarts = container.selectAll(".threadStart")
if ( args.palette ) {
var colors = args.palette.split(',')
- for(i=threadStarts[0].length ; i >= 0 ; i--) {
+ for(i=threadStarts.size() ; i >= 0 ; i--) {
var n = (i - 1 + colors.length) % colors.length
container.selectAll(".thread"+i)
.style('stroke', colors[n])
@@ -184,24 +147,84 @@ diagram.showGraph = function(args) {
// event listeners
- threadStarts.on('click', function (d) {
- if (d3.event.defaultPrevented) return
- container.selectAll("."+d.startOf)
- .style('stroke', '#'+colorpicker.value)
- .style('fill', function(d) { return d.bobbin ? '#'+colorpicker.value : 'none' })
- })
-
+ var colorpicker = (args.threadColor == undefined ? undefined : d3.select(args.threadColor).node())
+ if (colorpicker) {
+ threadStarts.on('click', function (d) {
+ if (d3.event.defaultPrevented) return
+ container.selectAll("."+d.startOf)
+ .style('stroke', '#'+colorpicker.value)
+ .style('fill', function(d) { return d.bobbin ? '#'+colorpicker.value : 'none' })
+ })
+ }
+ nodes.call(d3.drag()
+ .on("start", dragstarted)
+ .on("drag", dragged)
+ .on("end", dragended))
+
+ var drawPath = function(d) {
+ var sX = d.source.x
+ var sY = d.source.y
+ var tX = d.target.x
+ var tY = d.target.y
+ var dX = (tX - sX)
+ var dY = (tY - sY)
+ var mid = d.left ? ("S" + (sX - dY/3 + dX/3) + "," + (sY + dX/3 + dY/3)) :
+ d.right ? ("S" + (sX + dY/3 + dX/3) + "," + (sY + dY/3 - dX/3)) :
+ " "
+ if (d.end && d.end == "white")
+ return "M"+ sX + "," + sY + mid + " " + (tX - dX/4) + "," + (tY - dY/4)
+ if (d.start && d.start == "white")
+ return "M"+ (sX + dX/4) + "," + (sY + dY/4) + mid + " " + tX + "," + tY
+ if (d.mid)
+ return "M"+ sX + "," + sY + " " + (sX + dX/2) + "," + (sY + dY/2) + " " + tX + "," + tY
+ return "M"+ sX + "," + sY + " " + tX + "," + tY
+ }
+ var moveNode = function(d) {
+ d.x = d.x ? d.x : 0
+ d.y = d.y ? d.y : 0
+ return "translate(" + d.x + "," + d.y + ")"
+ }
// a higher speed for IE as marks only appear when the animation is finished
var mod = isMobileMac ? 10 : isIE ? 3 : 2
var step = 0
- // layout simulation step
- force.on("tick", function() {
- if ( ((step++)%mod) != 0) return
- link.attr("d", diagram.path)
- node.attr("transform", diagram.transform)
- })
- force.on("end", function(){
- if (isIE) diagram.markLinks(link)
- if (args.onAnimationEnd) args.onAnimationEnd()
- })
+ var simTicked = function() {
+ //if ( ((step++)%mod) != 0) return // skip rendering
+ //step++
+ nodes.attr("transform", moveNode)
+ links.attr("d", drawPath)
+ }
+ var simEnded = function(){
+ if (isIE) diagram.markLinks(links)
+ if (args.onAnimationEnd) args.onAnimationEnd()
+ }
+// var force = d3.layout.force()
+// .nodes(args.nodes)
+// .links(args.links)
+// .size([args.width, args.height])
+// .charge(-20)
+// .linkDistance(10)
+// .linkStrength(10)
+// .start()
+// .alpha(0.01)
+// Above calibration with the v3 API resulted in a relative quick compact animation.
+ var sim = d3.forceSimulation(args.nodes)
+ .force("charge", d3.forceManyBody().strength(-2))
+ .force("link", d3.forceLink(links).strength(1).distance(5).iterations(10))
+ .on("tick", simTicked)
+ .on("end", simEnded)
+
+ function dragstarted(d) {
+ if (!d3.event.active) sim.alphaTarget(0.3).restart();
+ d.fx = d.x;
+ d.fy = d.y;
+ }
+ function dragged(d) {
+ d.fx = d3.event.x;
+ d.fy = d3.event.y;
+ }
+ function dragended(d) {
+ if (!d3.event.active) sim.alphaTarget(0.3);
+ d.fx = null;
+ d.fy = null;
+ }
}