|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
|
|
<script src="http://d3js.org/d3.v3.js"></script>
|
|
|
|
<style>
|
|
|
|
body {
|
|
font: 13pt courier;
|
|
font-weight: bold;
|
|
background-color: #111;
|
|
overflow-y:hidden;
|
|
color: #ccc;
|
|
-webkit-user-select: none;
|
|
-moz-user-select: none;
|
|
user-select: none;
|
|
}
|
|
|
|
.red_line {
|
|
fill: none;
|
|
stroke: crimson;
|
|
stroke-width: 2px;
|
|
stroke-linecap: round;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.blue {
|
|
fill: #66C;
|
|
opacity:0.8;
|
|
}
|
|
|
|
.red {
|
|
fill: crimson;
|
|
opacity:0.8;
|
|
}
|
|
|
|
.blue_line {
|
|
fill: none;
|
|
stroke: #66C;
|
|
stroke-width: 2px;
|
|
stroke-linecap: round;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.yellow {
|
|
fill: #CC4 ;
|
|
opacity:0.8;
|
|
}
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<script type="text/javascript">
|
|
var width = 320 ;
|
|
var height = 320 ;
|
|
var dom = 4 ;
|
|
var maxL = dom * 2 / 5 ;
|
|
var minL = 0 ;
|
|
var maxL2 = maxL * maxL ;
|
|
var minL2 = minL * minL ;
|
|
var markHeight = 4 ;
|
|
var pad = .45 ;
|
|
|
|
var x = d3.scale.linear()
|
|
.domain([-dom, dom])
|
|
.range([0, width]) ;
|
|
|
|
var y = d3.scale.linear()
|
|
.domain([-dom, dom])
|
|
.range([height, 0]) ;
|
|
|
|
var invMark = x.invert(markHeight) - x.invert(0) ;
|
|
var scale = 1 - invMark ;
|
|
maxL -= invMark ;
|
|
minL += invMark ;
|
|
|
|
var line = d3.svg.line()
|
|
.interpolate('basis')
|
|
.x(function(d) { return x(d.x) ; })
|
|
.y(function(d) { return y(d.y) ; }) ;
|
|
|
|
var svg = d3
|
|
.select("body")
|
|
.append("svg")
|
|
.attr("viewBox", '0 0 ' + 2 * width + ' ' + 2 * height) ;
|
|
// .attr("preserveAspectRatio", "xMidYMin meet") ;
|
|
// .style('max-height', '90%')
|
|
// .style('min-height', '600px') ;
|
|
|
|
svg
|
|
.append('defs')
|
|
.append('marker')
|
|
.attr('id', 'redMarker')
|
|
.attr('orient', 'auto')
|
|
.attr('markerWidth', 2)
|
|
.attr('markerHeight', markHeight)
|
|
.attr('refX', 0.1)
|
|
.attr('refY', 2)
|
|
.append('path')
|
|
.attr('d', 'M0,0 V4 L2,2 Z')
|
|
.attr('fill', 'crimson') ;
|
|
|
|
svg
|
|
.append('marker')
|
|
.attr('id', 'blueMarker')
|
|
.attr('orient', 'auto')
|
|
.attr('markerWidth', 2)
|
|
.attr('markerHeight', markHeight)
|
|
.attr('refX', 0.1)
|
|
.attr('refY', 2)
|
|
.append('path')
|
|
.attr('d', 'M0,0 V4 L2,2 Z')
|
|
.attr('fill', '#66C') ;
|
|
|
|
var g = svg
|
|
.append("g")
|
|
.style('opacity', 0) ;
|
|
//.attr("transform", "rotate(-60, 160, 160)")
|
|
|
|
var gs = g.append('g') ; // more-or-less static stuff that is not part of the animation
|
|
|
|
var unitCircle = gs
|
|
.append('circle')
|
|
.attr('fill', '#FFF')
|
|
.attr('opacity', .05)
|
|
.attr('r', x(1) - x(0))
|
|
.attr('cx', x(0))
|
|
.attr('cy', y(0))
|
|
|
|
var ga = g.append('g') ;
|
|
|
|
var redLine = ga
|
|
.append('path')
|
|
.style('pointer-events', 'none')
|
|
.attr('class', 'red_line')
|
|
.attr('marker-end', 'url(#redMarker)') ;
|
|
|
|
var gb = g.append('g') ;
|
|
|
|
var blueLine = gb
|
|
.append('path')
|
|
.style('pointer-events', 'none')
|
|
.attr('class', 'blue_line')
|
|
.attr('marker-end', 'url(#blueMarker)') ;
|
|
|
|
var root2 = Math.sqrt(2) ;
|
|
var r2i = 1 / root2 ;
|
|
var t0 = Math.PI / 2 - 0.1 - 0.5 * Math.random() ;
|
|
var t1 = 0.2 + 0.3 * (Math.random() - 0.5) ;
|
|
var l1 = 0.6 * maxL + (0.4 * Math.random() * maxL) ;
|
|
var l2 = 0.6 * maxL + (0.4 * Math.random() * maxL) ;
|
|
var da = [{x: 0, y: 0}, {x: Math.cos(t0) * scale * l1, y: Math.sin(t0) * scale * l1}] ;
|
|
var db = [{x: 0, y: 0}, {x: Math.cos(t1) * scale * l2, y: Math.sin(t1) * scale * l2}] ;
|
|
var dur = 710 ;
|
|
var longDelay = 2 * dur ;
|
|
|
|
redLine
|
|
.datum(da)
|
|
.attr("d", line)
|
|
|
|
blueLine
|
|
.datum(db)
|
|
.attr("d", line)
|
|
|
|
//var dragSwitch = true ;
|
|
|
|
var length = function(d) {
|
|
return Math.sqrt(d.x * d.x + d.y * d.y) ;
|
|
}
|
|
|
|
var circHover = function(node) {
|
|
//dragSwitch = true ;
|
|
d3.select(node)
|
|
.transition()
|
|
.ease('linear')
|
|
.duration(dur * 0.5)
|
|
.style('opacity', 0.3) ;
|
|
} ;
|
|
|
|
var circOut = function(node) {
|
|
//dragSwitch = false ;
|
|
d3.select(node)
|
|
.transition()
|
|
.ease('linear')
|
|
.duration(dur * 0.5)
|
|
.style('opacity', 0) ;
|
|
} ;
|
|
|
|
var unitSwitch = false ;
|
|
|
|
var set_unit = function(animateSwitch) {
|
|
if(animateSwitch === undefined) animateSwitch = false ;
|
|
var xk, yk, l ;
|
|
xk = da[1].x ;
|
|
yk = da[1].y ;
|
|
l = Math.sqrt(xk * xk + yk * yk) / scale ;
|
|
da[1].x /= l ;
|
|
da[1].y /= l ;
|
|
xk = db[1].x ;
|
|
yk = db[1].y ;
|
|
l = Math.sqrt(xk * xk + yk * yk) / scale ;
|
|
db[1].x /= l ;
|
|
db[1].y /= l ;
|
|
if(animateSwitch) {
|
|
redLine
|
|
.transition()
|
|
.ease('linear')
|
|
.duration(dur * 0.5)
|
|
.attr('d', line)
|
|
blueLine
|
|
.transition()
|
|
.ease('linear')
|
|
.duration(dur * 0.5)
|
|
.attr('d', line) ;
|
|
redCircle
|
|
.transition()
|
|
.ease('linear')
|
|
.duration(dur * 0.5)
|
|
.attr('cx', x(da[1].x))
|
|
.attr('cy', y(da[1].y)) ;
|
|
blueCircle
|
|
.transition()
|
|
.ease('linear')
|
|
.duration(dur * 0.5)
|
|
.attr('cx', x(db[1].x))
|
|
.attr('cy', y(db[1].y))
|
|
.each('end', vecText) ;
|
|
aText
|
|
.transition()
|
|
.ease('linear')
|
|
.duration(dur * 0.5)
|
|
.attr('x', x(da[1].x + pad * da[1].x / length(da[1])))
|
|
.attr('y', y(da[1].y + pad * da[1].y / length(da[1]))) ;
|
|
|
|
bText
|
|
.transition()
|
|
.ease('linear')
|
|
.duration(dur * 0.5)
|
|
.attr('x', x(db[1].x + pad * db[1].x / length(db[1])))
|
|
.attr('y', y(db[1].y + pad * db[1].y / length(db[1]))) ;
|
|
} else {
|
|
redLine.attr('d', line) ;
|
|
blueLine.attr('d', line) ;
|
|
redCircle
|
|
.attr('cx', x(da[1].x))
|
|
.attr('cy', y(da[1].y)) ;
|
|
blueCircle
|
|
.attr('cx', x(db[1].x))
|
|
.attr('cy', y(db[1].y)) ;
|
|
aText
|
|
.attr('x', x(da[1].x + pad * da[1].x / length(da[1])))
|
|
.attr('y', y(da[1].y + pad * da[1].y / length(da[1]))) ;
|
|
|
|
bText
|
|
.attr('x', x(db[1].x + pad * db[1].x / length(db[1])))
|
|
.attr('y', y(db[1].y + pad * db[1].y / length(db[1]))) ;
|
|
}
|
|
} ;
|
|
|
|
//
|
|
// arc * angle:
|
|
//
|
|
|
|
var angle = function() {
|
|
var angA = angl(da) ;
|
|
var angB = angl(db) ;
|
|
if(Math.abs(angA - angB) > Math.PI) {
|
|
if(angA < 0 && angB > 0) {
|
|
angA += 2 * Math.PI ;
|
|
} else if(angA > 0 && angB < 0) {
|
|
angB += 2 * Math.PI ;
|
|
} else if(angA > 0 && angB > 0) {
|
|
if(angA > Math.PI) {
|
|
angA -= 2 * Math.PI ;
|
|
} else {
|
|
angB -= 2 * Math.PI ;
|
|
}
|
|
} else {
|
|
if(angA < -Math.PI) {
|
|
angA += 2 * Math.PI ;
|
|
} else {
|
|
angB += 2 * Math.PI ;
|
|
}
|
|
}
|
|
}
|
|
return [angA, angB] ;
|
|
} ;
|
|
|
|
var angl = function(d) {
|
|
return (Math.PI / 2 - Math.atan2(d[1].y, d[1].x)) ;
|
|
} ;
|
|
|
|
var ang = angle() ;
|
|
|
|
var arc = d3.svg.arc()
|
|
.innerRadius(8)
|
|
.outerRadius(10)
|
|
.startAngle(ang[0])
|
|
.endAngle(ang[1]) ;
|
|
|
|
var arcLine = gs
|
|
.insert("path", ":first-child")
|
|
.attr("d", arc)
|
|
.attr('class', 'yellow')
|
|
.attr("transform", 'translate(' + width / 2 + ',' + height / 2 + ')') ;
|
|
|
|
var get_mid = function() {
|
|
var lenA = Math.sqrt(da[1].x * da[1].x + da[1].y * da[1].y) ;
|
|
var lenB = Math.sqrt(db[1].x * db[1].x + db[1].y * db[1].y) ;
|
|
var xMid = 0.5 * (da[1].x / lenA + db[1].x / lenB) ;
|
|
var yMid = 0.5 * (da[1].y / lenA + db[1].y / lenB) ;
|
|
var mLen = Math.sqrt(xMid * xMid + yMid * yMid) ;
|
|
var mscale = .5 / mLen ;
|
|
xMid *= mscale ;
|
|
yMid *= mscale ;
|
|
return [xMid, yMid] ;
|
|
}
|
|
|
|
var mid = get_mid() ;
|
|
|
|
var thetaText = gs
|
|
.append('text')
|
|
.attr('x', x(mid[0]))
|
|
.attr('y', y(mid[1]))
|
|
.text('θ') //
|
|
.style('pointer-events', 'none')
|
|
.style('font', 'courier')
|
|
.style('font-size', '6pt')
|
|
.attr('class', 'yellow') ;
|
|
|
|
//
|
|
// ******************
|
|
// ****** drag ******
|
|
// ******************
|
|
//
|
|
var circDrag = function(d, element) {
|
|
//var xy0 = d3.mouse(g.node()) ;
|
|
//if(dragSwitch === false) {
|
|
// return ;
|
|
//}
|
|
var dx = d3.event.dx ;
|
|
var dy = d3.event.dy ;
|
|
var dd = d.datum() ;
|
|
var x1 = dd[1].x ;
|
|
var y1 = dd[1].y ;
|
|
var xi = x(x1) + dx ;
|
|
var yi = y(y1) + dy ;
|
|
x1 = x.invert(xi) ;
|
|
y1 = y.invert(yi) ;
|
|
var l2 = x1 * x1 + y1 * y1 ;
|
|
var len = Math.sqrt(l2) ;
|
|
if(l2 > maxL2) {
|
|
var li = 1 / len ;
|
|
x1 = x1 * li * maxL ;
|
|
y1 = y1 * li * maxL ;
|
|
len = maxL ;
|
|
}
|
|
if(l2 < minL2) {
|
|
var li = 1 / len ;
|
|
x1 = x1 * li * minL ;
|
|
y1 = y1 * li * minL ;
|
|
len = minL ;
|
|
}
|
|
|
|
d3.select(element)
|
|
.attr('cx', x(x1))
|
|
.attr('cy', y(y1)) ;
|
|
|
|
dd[1].x = x1 ;
|
|
dd[1].y = y1 ;
|
|
if(unitSwitch) {
|
|
set_unit() ;
|
|
} else {
|
|
d.attr('d', line) ; // console.log('drag', element, xy0) ;
|
|
}
|
|
|
|
var ang = angle() ;
|
|
|
|
arc
|
|
.startAngle(ang[0])
|
|
.endAngle(ang[1]) ;
|
|
|
|
arcLine.attr('d', arc)
|
|
|
|
mid = get_mid() ;
|
|
|
|
thetaText
|
|
.attr('x', x(mid[0]))
|
|
.attr('y', y(mid[1])) ;
|
|
|
|
aText
|
|
.attr('x', x(da[1].x + pad * da[1].x / length(da[1])))
|
|
.attr('y', y(da[1].y + pad * da[1].y / length(da[1]))) ;
|
|
|
|
bText
|
|
.attr('x', x(db[1].x + pad * db[1].x / length(db[1])))
|
|
.attr('y', y(db[1].y + pad * db[1].y / length(db[1]))) ;
|
|
|
|
vecText() ;
|
|
|
|
var dax = [{x: 0, y: 0}, {x: da[1].x, y: 0}] ;
|
|
var day = [{x: 0, y: 0}, {x: 0, y: da[1].y}] ;
|
|
|
|
var dbx = [{x: 0, y: 0}, {x: db[1].x, y: 0}] ;
|
|
var dby = [{x: 0, y: 0}, {x: 0, y: db[1].y}] ;
|
|
|
|
ax.datum(dax) ;
|
|
ay.datum(day) ;
|
|
|
|
bx.datum(dbx) ;
|
|
by.datum(dby) ;
|
|
|
|
ax.attr('d', line) ;
|
|
ay.attr('d', line) ;
|
|
|
|
bx.attr('d', line) ;
|
|
by.attr('d', line) ;
|
|
|
|
axText
|
|
.attr('x', x(dax[1].x + 0.5 * pad * dax[1].x / length(dax[1])) + (shift * Math.min(0, dax[1].x / Math.abs(dax[1].x))))
|
|
.attr('y', y(dax[1].y + 0.5 * pad * dax[1].y / length(dax[1]))) ;
|
|
|
|
ayText
|
|
.attr('x', x(day[1].x + 0.5 * pad * day[1].x / length(day[1])))
|
|
.attr('y', y(day[1].y + 0.5 * pad * day[1].y / length(day[1])) - (shift * Math.min(0, day[1].y / Math.abs(day[1].y)))) ;
|
|
|
|
bxText
|
|
.attr('x', x(dbx[1].x + 0.5 * pad * dbx[1].x / length(dbx[1])) + (shift * Math.min(0, dbx[1].x / Math.abs(dbx[1].x))))
|
|
.attr('y', y(dbx[1].y + 0.5 * pad * dbx[1].y / length(dbx[1]))) ;
|
|
|
|
byText
|
|
.attr('x', x(dby[1].x + 0.5 * pad * dby[1].x / length(dby[1])))
|
|
.attr('y', y(dby[1].y + 0.5 * pad * dby[1].y / length(dby[1])) - (shift * Math.min(0, dby[1].y / Math.abs(dby[1].y)))) ;
|
|
|
|
} ;
|
|
|
|
//
|
|
// **************************
|
|
// ****** primary text ******
|
|
// **************************
|
|
//
|
|
|
|
var aText = ga
|
|
.append('text')
|
|
.text('a')
|
|
.attr('x', x(da[1].x + pad * da[1].x / length(da[1])))
|
|
.attr('y', y(da[1].y + pad * da[1].y / length(da[1])))
|
|
.style('pointer-events', 'none')
|
|
.style('font', 'courier')
|
|
.style('font-size', '12pt')
|
|
.attr('class', 'red') ;
|
|
|
|
var bText = gb
|
|
.append('text')
|
|
.text('b')
|
|
.attr('x', x(db[1].x + pad * db[1].x / length(db[1])))
|
|
.attr('y', y(db[1].y + pad * db[1].y / length(db[1])))
|
|
.style('pointer-events', 'none')
|
|
.style('font', 'courier')
|
|
.style('font-size', '12pt')
|
|
.attr('class', 'blue') ;
|
|
|
|
var redCircle = ga
|
|
.insert('circle', ":first-child")
|
|
.datum(redLine)
|
|
.attr('fill', '#0C0')
|
|
.attr('opacity', 0)
|
|
.attr('r', 20)
|
|
.attr('cx', x(da[1].x))
|
|
.attr('cy', y(da[1].y))
|
|
.on('mouseup', function() { circOut(this) })
|
|
.on('mousedown', function() { circHover(this) })
|
|
.on('mouseleave', function() { circOut(this) })
|
|
.on('mouseenter', function() { circHover(this) }) ;
|
|
|
|
var blueCircle = gb
|
|
.insert('circle', ":first-child")
|
|
.datum(blueLine)
|
|
.attr('fill', '#0C0')
|
|
.attr('opacity', 0)
|
|
.attr('r', 20)
|
|
.attr('cx', x(db[1].x))
|
|
.attr('cy', y(db[1].y))
|
|
.on('mouseup', function() { circOut(this) })
|
|
.on('mousedown', function() { circHover(this) })
|
|
.on('mouseleave', function() { circOut(this) })
|
|
.on('mouseenter', function() { circHover(this) }) ;
|
|
|
|
blueCircle
|
|
.call(d3.behavior.drag()
|
|
.origin(Object)
|
|
.on("dragstart", function(d) {
|
|
circHover(blueCircle.node()) ;
|
|
blueCircle
|
|
.on('mouseup', null)
|
|
.on('mousedown', null)
|
|
.on('mouseleave', null)
|
|
.on('mouseenter', null) ;
|
|
})
|
|
.on("drag", function(d) { circDrag(d, this) } )
|
|
.on("dragend", function(d) {
|
|
circOut(blueCircle.node())
|
|
blueCircle
|
|
.on('mouseup', function() { circOut(this) })
|
|
.on('mousedown', function() { circHover(this) })
|
|
.on('mouseleave', function() { circOut(this) })
|
|
.on('mouseenter', function() { circHover(this) }) ;
|
|
})
|
|
) ;
|
|
|
|
redCircle
|
|
.call(d3.behavior.drag()
|
|
.origin(Object)
|
|
.on("dragstart", function(d) {
|
|
circHover(redCircle.node()) ;
|
|
redCircle
|
|
.on('mouseup', null)
|
|
.on('mousedown', null)
|
|
.on('mouseleave', null)
|
|
.on('mouseenter', null) ;
|
|
})
|
|
.on("drag", function(d) { circDrag(d, this) } )
|
|
.on("dragend", function(d) {
|
|
circOut(redCircle.node())
|
|
redCircle
|
|
.on('mouseup', function() { circOut(this) })
|
|
.on('mousedown', function() { circHover(this) })
|
|
.on('mouseleave', function() { circOut(this) })
|
|
.on('mouseenter', function() { circHover(this) }) ;
|
|
})
|
|
) ;
|
|
|
|
var unitBox = gs
|
|
.append('rect') ;
|
|
|
|
var unitToggle = function() {
|
|
var fill ;
|
|
if(unitSwitch) {
|
|
unitSwitch = false ;
|
|
fill = '#111' ;
|
|
} else {
|
|
unitSwitch = true ;
|
|
fill = '#999' ;
|
|
var animateSwitch = true ;
|
|
set_unit(animateSwitch) ;
|
|
}
|
|
unitBox
|
|
.transition()
|
|
.duration(100)
|
|
.ease('linear')
|
|
.attr('fill', fill) ;
|
|
} ;
|
|
|
|
unitBox
|
|
.attr('x', 20)
|
|
.attr('y', 10)
|
|
.attr('rx', 2)
|
|
.attr('ry', 2)
|
|
.attr('fill', '#111')
|
|
.attr('width', 10)
|
|
.attr('height', 10)
|
|
.attr('stroke', '#CCC')
|
|
.attr('stroke-width', 1.5)
|
|
.style('cursor', 'pointer')
|
|
.on('click', unitToggle) ;
|
|
|
|
var unitText = gs
|
|
.append('text') ;
|
|
|
|
unitText
|
|
.attr('x', 34)
|
|
.attr('y', 17)
|
|
.text('unit length')
|
|
.style('font', 'courier')
|
|
.style('font-size', '6pt')
|
|
.style('fill', '#ccc')
|
|
.style('cursor', 'pointer')
|
|
.on('click', unitToggle) ;
|
|
|
|
var dotDef = gs
|
|
.append('text')
|
|
.attr('x', 120)
|
|
.attr('y', 42)
|
|
.style('font', 'courier')
|
|
.style('font-size', '6pt')
|
|
.style('fill', '#ccc') ;
|
|
|
|
var boxy = d3.scale.linear()
|
|
.domain([-maxL * maxL, maxL * maxL])
|
|
.range([-200 / height, 200 / height]) ;
|
|
|
|
var boxc = d3.scale.linear()
|
|
.domain([-maxL * maxL, 0, maxL * maxL])
|
|
.range([d3.rgb('#95F'), d3.rgb('#959'), d3.rgb('#F59')]) ;
|
|
|
|
var dotbarX = 103 ;
|
|
|
|
var dotBar = gs.append('path')
|
|
.datum([{x: x.invert(dotbarX), y: y.invert(42)}, {x: x.invert(dotbarX), y: y.invert(42) + boxy(0)}])
|
|
.attr('d', line)
|
|
.attr('stroke-width', 10)
|
|
.attr('stroke', boxc(1)) ;
|
|
|
|
var unscale = function(d) {
|
|
var len = length(d) ;
|
|
len = (len + invMark) / len ;
|
|
return [d.x * len, d.y * len] ;
|
|
} ;
|
|
|
|
var aVec = gs
|
|
.append('text')
|
|
.attr('x', 120)
|
|
.attr('y', 10)
|
|
.style('font', 'courier')
|
|
.style('font-size', '6pt')
|
|
.style('fill', '#ccc') ;
|
|
|
|
var aLen = gs
|
|
.append('text')
|
|
.attr('x', 240)
|
|
.attr('y', 10)
|
|
.style('font', 'courier')
|
|
.style('font-size', '6pt')
|
|
.style('fill', '#ccc') ;
|
|
|
|
var bVec = gs
|
|
.append('text')
|
|
.attr('x', 120)
|
|
.attr('y', 20)
|
|
.style('font', 'courier')
|
|
.style('font-size', '6pt')
|
|
.style('fill', '#ccc') ;
|
|
|
|
var bLen = gs
|
|
.append('text')
|
|
.attr('x', 240)
|
|
.attr('y', 20)
|
|
.style('font', 'courier')
|
|
.style('font-size', '6pt')
|
|
.style('fill', '#ccc') ;
|
|
|
|
var thetaVal = gs
|
|
.append('text')
|
|
.attr('x', 120)
|
|
.attr('y', 30)
|
|
.style('font', 'courier')
|
|
.style('font-size', '6pt')
|
|
.style('fill', '#ccc') ;
|
|
|
|
var cosVal = gs
|
|
.append('text')
|
|
.attr('x', 240)
|
|
.attr('y', 30)
|
|
.style('font', 'courier')
|
|
.style('font-size', '6pt')
|
|
.style('fill', '#ccc') ;
|
|
|
|
var vecText = function() {
|
|
var a = unscale(da[1]) ;
|
|
var b = unscale(db[1]) ;
|
|
var dot = a[0] * b[0] + a[1] * b[1] ;
|
|
aVec.html('a = (' + a[0].toPrecision(3) + ', ' + a[1].toPrecision(3) + ')') ;
|
|
bVec.html('b = (' + b[0].toPrecision(3) + ', ' + b[1].toPrecision(3) + ')') ;
|
|
aLen.html('|a| = ' + Math.sqrt(a[0] * a[0] + a[1] * a[1]).toPrecision(4)) ;
|
|
bLen.html('|b| = ' + Math.sqrt(b[0] * b[0] + b[1] * b[1]).toPrecision(4)) ;
|
|
var ang = angle() ;
|
|
thetaVal.html('θ = ' + Math.abs(ang[0] - ang[1]).toPrecision(3)) ;
|
|
cosVal.html('cos θ = ' + Math.cos(Math.abs(ang[0] - ang[1])).toPrecision(3)) ;
|
|
dotDef.html('⟨a, b⟩ = |a| |b| cos θ = a1 b1 + a2 b2 = ' + dot.toPrecision(3)) ;
|
|
dotBar
|
|
.datum([{x: x.invert(dotbarX), y: y.invert(42)}, {x: x.invert(dotbarX), y: y.invert(42) + boxy(dot)}])
|
|
.attr('stroke', boxc(dot))
|
|
.attr('d', line)
|
|
|
|
} ;
|
|
|
|
vecText() ;
|
|
|
|
//
|
|
// ****************************
|
|
// ****** secondary text ******
|
|
// ****************************
|
|
//
|
|
|
|
var atx = Number(aText.attr('x')) ; // + (txtShift * Number(aText.attr('x')) / Math.abs(Number(aText.attr('x')))) ;
|
|
var aty = Number(aText.attr('y')) ; // + (txtShift * Number(aText.attr('y')) / Math.abs(Number(aText.attr('y')))) ;
|
|
var btx = Number(bText.attr('x')) ; // + (txtShift * Number(bText.attr('x')) / Math.abs(Number(bText.attr('x')))) ;
|
|
var bty = Number(bText.attr('y')) ; // + (txtShift * Number(bText.attr('y')) / Math.abs(Number(bText.attr('y')))) ;
|
|
|
|
var yCut = 20 ;
|
|
var dya = Math.abs(x(da[1].y) - x(0)) ;
|
|
var dyb = Math.abs(x(db[1].y) - x(0)) ;
|
|
|
|
if(dya < yCut) {
|
|
aty += yCut * dya / Math.abs(dya) ;
|
|
}
|
|
if(dyb < yCut) {
|
|
bty += yCut * dyb / Math.abs(dyb) ;
|
|
}
|
|
|
|
ga1 = ga
|
|
.append('g')
|
|
.style('opacity', 0) ;
|
|
|
|
gb1 = gb
|
|
.append('g')
|
|
.style('opacity', 0) ;
|
|
|
|
gax = ga1.append('g') ;
|
|
gay = ga1.append('g') ;
|
|
gbx = gb1.append('g') ;
|
|
gby = gb1.append('g') ;
|
|
|
|
var ax = gax
|
|
.append('path')
|
|
.attr('class', 'red_line')
|
|
.attr('marker-end', 'url(#redMarker)') ;
|
|
|
|
var ay = gay
|
|
.append('path')
|
|
.attr('class', 'red_line')
|
|
.attr('marker-end', 'url(#redMarker)') ;
|
|
|
|
var bx = gbx
|
|
.append('path')
|
|
.attr('class', 'blue_line')
|
|
.attr('marker-end', 'url(#blueMarker)') ;
|
|
|
|
var by = gby
|
|
.append('path')
|
|
.attr('class', 'blue_line')
|
|
.attr('marker-end', 'url(#blueMarker)') ;
|
|
|
|
var dax = [{x: 0, y: 0}, {x: da[1].x, y: 0}] ;
|
|
var day = [{x: 0, y: 0}, {x: 0, y: da[1].y}] ;
|
|
|
|
var dbx = [{x: 0, y: 0}, {x: db[1].x, y: 0}] ;
|
|
var dby = [{x: 0, y: 0}, {x: 0, y: db[1].y}] ;
|
|
|
|
ax.datum(dax) ;
|
|
ay.datum(day) ;
|
|
|
|
bx.datum(dbx) ;
|
|
by.datum(dby) ;
|
|
|
|
ax.attr('d', line) ;
|
|
ay.attr('d', line) ;
|
|
|
|
bx.attr('d', line) ;
|
|
by.attr('d', line) ;
|
|
|
|
var shift = 15 ;
|
|
|
|
var axText = gax
|
|
.append('text')
|
|
.html('ax')
|
|
.attr('x', x(dax[1].x + 0.5 * pad * dax[1].x / length(dax[1])) + (shift * Math.min(0, dax[1].x / Math.abs(dax[1].x))))
|
|
.attr('y', y(dax[1].y + 0.5 * pad * dax[1].y / length(dax[1])))
|
|
.style('pointer-events', 'none')
|
|
.style('font', 'courier')
|
|
.style('font-size', '10pt')
|
|
.attr('class', 'red')
|
|
.style('opacity', 0) ;
|
|
|
|
var ayText = gay
|
|
.append('text')
|
|
.html('ay')
|
|
.attr('x', x(day[1].x + 0.5 * pad * day[1].x / length(day[1])))
|
|
.attr('y', y(day[1].y + 0.5 * pad * day[1].y / length(day[1])) - (shift * Math.min(0, day[1].y / Math.abs(day[1].y))))
|
|
.style('pointer-events', 'none')
|
|
.style('font', 'courier')
|
|
.style('font-size', '10pt')
|
|
.attr('class', 'red')
|
|
.style('opacity', 0) ;
|
|
|
|
var bxText = gbx
|
|
.append('text')
|
|
.html('bx')
|
|
.attr('x', x(dbx[1].x + 0.5 * pad * dbx[1].x / length(dbx[1])) + (shift * Math.min(0, dbx[1].x / Math.abs(dbx[1].x))))
|
|
.attr('y', y(dbx[1].y + 0.5 * pad * dbx[1].y / length(dbx[1])))
|
|
.style('pointer-events', 'none')
|
|
.style('font', 'courier')
|
|
.style('font-size', '10pt')
|
|
.attr('class', 'blue')
|
|
.style('opacity', 0) ;
|
|
|
|
var byText = gby
|
|
.append('text')
|
|
.html('by')
|
|
.attr('x', x(dby[1].x + 0.5 * pad * dby[1].x / length(dby[1])))
|
|
.attr('y', y(dby[1].y + 0.5 * pad * dby[1].y / length(dby[1])) - (shift * Math.min(0, dby[1].y / Math.abs(dby[1].y))))
|
|
.style('pointer-events', 'none')
|
|
.style('font', 'courier')
|
|
.style('font-size', '10pt')
|
|
.attr('class', 'blue')
|
|
.style('opacity', 0) ;
|
|
|
|
g
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
//
|
|
// ***********************
|
|
// ****** animation ******
|
|
// ***********************
|
|
//
|
|
var animating = false ;
|
|
|
|
var yShift = 60 ;
|
|
var xShifta = -width * 0.15 ;
|
|
var xShiftb = width * 0.65 ;
|
|
|
|
var ga1 ;
|
|
var gb1 ;
|
|
|
|
var gax ;
|
|
var gay ;
|
|
var gbx ;
|
|
var gby ;
|
|
|
|
var gdt ;
|
|
|
|
var gc = g
|
|
.append('g')
|
|
.style('opacity', 0) ;
|
|
|
|
var gn = gc
|
|
.append('g')
|
|
.style('pointer-events', 'all')
|
|
.style('opacity', 0) ;
|
|
|
|
var animate = function() {
|
|
if(animating) return ; // don't respond to animation requests until previous one has completed (one at a time)
|
|
animating = true ;
|
|
|
|
gs
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 0)
|
|
.each('end', function() {
|
|
goText
|
|
.transition()
|
|
.duration(dur)
|
|
.style('opacity', 0)
|
|
.transition()
|
|
.delay(dur)
|
|
.duration(dur)
|
|
.text('back')
|
|
.style('opacity', 1) ;
|
|
|
|
goBox
|
|
.on('click', null)
|
|
.on('click', home) ;
|
|
|
|
}) ;
|
|
|
|
//ga.style('opacity', 0) ;
|
|
//gb.style('opacity', 0) ;
|
|
|
|
ga1
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
|
|
gb1
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
|
|
gc
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
|
|
aText
|
|
.html('a = ax + ay')
|
|
.transition()
|
|
.duration(longDelay)
|
|
.ease('linear')
|
|
.style('opacity', 0.4)
|
|
.style('font-size', '6pt') ;
|
|
|
|
bText
|
|
.html('b = bx + by')
|
|
.transition()
|
|
.duration(longDelay)
|
|
.ease('linear')
|
|
.style('opacity', 0.4)
|
|
.style('font-size', '6pt') ;
|
|
|
|
byText
|
|
.transition()
|
|
.duration(dur)
|
|
.delay(longDelay)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
|
|
bxText
|
|
.transition()
|
|
.duration(dur)
|
|
.delay(longDelay)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
|
|
ayText
|
|
.transition()
|
|
.duration(dur)
|
|
.delay(longDelay)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
|
|
axText
|
|
.transition()
|
|
.duration(dur)
|
|
.delay(longDelay)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
|
|
redLine
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 0.4) ;
|
|
|
|
blueLine
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 0.4) ;
|
|
|
|
// var txtShift = -40 ;
|
|
|
|
var gScale = 1 ;
|
|
|
|
g
|
|
.transition()
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.attr('transform', 'translate(' + width/4 + ',' + height/4 + ')scale(' + gScale + ')translate(' + -width/4 + ',' + -height/4 + ')') ;
|
|
|
|
ga
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 1)
|
|
.attr('transform', 'translate(' + xShifta + ',' + yShift + ')translate(' + width/4 + ',' + height/4 + ')scale(1)translate(' + -width/4 + ',' + -height/4 + ')') ;
|
|
|
|
gb
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 1)
|
|
.attr('transform', 'translate(' + xShiftb + ',' + yShift + ')translate(' + width/4 + ',' + height/4 + ')scale(1)translate(' + -width/4 + ',' + -height/4 + ')') ;
|
|
|
|
var xgc = 60 ;
|
|
|
|
var dTxt = gc
|
|
.append('text')
|
|
.attr('x', xgc + 20)
|
|
.attr('y', 35)
|
|
.html('⟨a, b⟩ =')
|
|
.style('fill', '#999')
|
|
.style('pointer-events', 'none')
|
|
.style('font', 'courier')
|
|
.style('font-size', '10pt') ;
|
|
|
|
var dotTxt = gc
|
|
.append('text')
|
|
.attr('x', xgc + 90)
|
|
.attr('y', 35)
|
|
.html('⟨ax + ay, bx + by⟩ ')
|
|
.style('fill', '#999')
|
|
.style('pointer-events', 'none')
|
|
.style('font', 'courier')
|
|
.style('font-size', '10pt') ;
|
|
|
|
gc
|
|
.transition()
|
|
.delay(dur)
|
|
.duration(2 * dur)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
|
|
gdt = gc
|
|
.append('g')
|
|
.style('opacity', 0) ;
|
|
|
|
var anim2 = function() {
|
|
|
|
nextButton.on('click', null) ;
|
|
fade_out(gn) ;
|
|
|
|
dotTxt
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 0)
|
|
.remove()
|
|
.each('end', function() {
|
|
dotTxt = [] ;
|
|
dTxt = [['x', 'x'], ['x', 'y'], ['y', 'x'], ['y', 'y']] ;
|
|
tTxt = ['0', 'π/2', 'π/2', '0'] ;
|
|
|
|
for(var k = 0 ; k < 4 ; k++) {
|
|
dotTxt[k] = gdt
|
|
.append('g')
|
|
.style('pointer-events', 'all') ;
|
|
|
|
dotTxt[k]
|
|
.append('text')
|
|
.attr('x', xgc + 90 + k * 85)
|
|
.attr('y', 35)
|
|
.style('fill', '#999')
|
|
.style('pointer-events', 'none')
|
|
.style('font', 'courier')
|
|
.style('font-size', '10pt') ;
|
|
|
|
dotTxt[k]
|
|
.append('rect')
|
|
.attr('x', xgc + 90 + k * 85)
|
|
.attr('y', 20)
|
|
.attr('width', 60)
|
|
.attr('height', 25)
|
|
.attr('fill', '#FFF')
|
|
.attr('opacity', '.01') ;
|
|
|
|
var sk = '⟨a' + dTxt[k][0] + ', b' + dTxt[k][1] + '⟩' ;
|
|
if(k < 3) {
|
|
gdt
|
|
.append('text')
|
|
.attr('x', xgc + 159 + k * 85)
|
|
.attr('y', 35)
|
|
.style('fill', '#999')
|
|
.style('pointer-events', 'none')
|
|
.style('font', 'courier')
|
|
.style('font-size', '10pt')
|
|
.text('+') ;
|
|
}
|
|
dotTxt[k].select('text').html(sk) ;
|
|
}
|
|
|
|
dotTxt[0]
|
|
.on('mouseenter', function() {
|
|
dotTxt[0]
|
|
.select('text')
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('fill', '#FF9') ;
|
|
|
|
arrows_up(gax, gbx) ;
|
|
var k = 0 ;
|
|
animTxt
|
|
.html('|a' + dTxt[k][0] + '| |b' + dTxt[k][1] + '| cos ' + tTxt[k] + ' = a1 b1')
|
|
.transition()
|
|
.duration(0.5 * dur)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
})
|
|
.on('mouseleave', function() {
|
|
dotTxt[0]
|
|
.select('text')
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('fill', '#999') ;
|
|
arrows_down(gax, gbx) ;
|
|
fade_out(animTxt) ;
|
|
})
|
|
|
|
dotTxt[1]
|
|
.on('mouseenter', function() {
|
|
dotTxt[1]
|
|
.select('text')
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('fill', '#FF9') ;
|
|
arrows_up(gax, gby)
|
|
var k = 1 ;
|
|
animTxt.html('|a' + dTxt[k][0] + '| |b' + dTxt[k][1] + '| cos ' + tTxt[k] + ' = 0')
|
|
.transition()
|
|
.duration(0.5 * dur)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
})
|
|
.on('mouseleave', function() {
|
|
dotTxt[1]
|
|
.select('text')
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('fill', '#999') ;
|
|
arrows_down(gax, gby)
|
|
fade_out(animTxt) ;
|
|
})
|
|
|
|
dotTxt[2]
|
|
.on('mouseenter', function() {
|
|
dotTxt[2]
|
|
.select('text')
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('fill', '#FF9') ;
|
|
arrows_up(gay, gbx)
|
|
var k = 2 ;
|
|
animTxt.html('|a' + dTxt[k][0] + '| |b' + dTxt[k][1] + '| cos ' + tTxt[k] + ' = 0')
|
|
.transition()
|
|
.duration(0.5 * dur)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
})
|
|
.on('mouseleave', function() {
|
|
dotTxt[2]
|
|
.select('text')
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('fill', '#999') ;
|
|
arrows_down(gay, gbx)
|
|
fade_out(animTxt) ;
|
|
})
|
|
|
|
dotTxt[3]
|
|
.on('mouseenter', function() {
|
|
dotTxt[3]
|
|
.select('text')
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('fill', '#FF9') ;
|
|
arrows_up(gay, gby)
|
|
var k = 3 ;
|
|
animTxt
|
|
.html('|a' + dTxt[k][0] + '| |b' + dTxt[k][1] + '| cos ' + tTxt[k] + ' = a2 b2')
|
|
.transition()
|
|
.duration(0.5 * dur)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
})
|
|
.on('mouseleave', function() {
|
|
dotTxt[3]
|
|
.select('text')
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('fill', '#999') ;
|
|
arrows_down(gay, gby)
|
|
fade_out(animTxt) ;
|
|
})
|
|
|
|
var animTxt = gdt
|
|
.append('text')
|
|
.attr('x', 160)
|
|
.attr('y', 80)
|
|
.style('opacity', 1)
|
|
.style('fill', '#FF9')
|
|
.style('pointer-events', 'none')
|
|
.style('font', 'courier')
|
|
.style('font-size', '10pt') ;
|
|
|
|
var pause = 4 * dur ;
|
|
|
|
animTxt.text('mouse over the terms above to animate')
|
|
|
|
gdt
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
}) ;
|
|
} ;
|
|
|
|
var nextButton = gn
|
|
.append('rect')
|
|
.attr('x', 10)
|
|
.attr('y', 46)
|
|
.attr('rx', 2)
|
|
.attr('ry', 2)
|
|
.attr('width', 46)
|
|
.attr('height', 15)
|
|
.attr('fill', '#CCC')
|
|
.attr('stroke', 'none')
|
|
.style('cursor', 'pointer')
|
|
.on('click', anim2) ;
|
|
|
|
var nextTxt = gn
|
|
.append('text')
|
|
.attr('x', 18.5)
|
|
.attr('y', 56.5)
|
|
.text('next')
|
|
.style('font', 'courier')
|
|
.style('font-size', '7pt')
|
|
.style('fill', '#111')
|
|
.style('pointer-events', 'none') ;
|
|
|
|
gn
|
|
.transition()
|
|
.delay(longDelay)
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
|
|
} ;
|
|
|
|
var fade_out = function(element) {
|
|
element
|
|
.transition()
|
|
.duration(0.5 * dur)
|
|
.ease('linear')
|
|
.style('opacity', 0) ;
|
|
}
|
|
|
|
var home = function() {
|
|
redLine
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
|
|
blueLine
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 1) ;
|
|
|
|
aText
|
|
.html('a')
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 1)
|
|
.style('font-size', '12pt')
|
|
|
|
bText
|
|
.html('b')
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 1)
|
|
.style('font-size', '12pt')
|
|
|
|
ga1
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 0) ;
|
|
|
|
gb1
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 0) ;
|
|
|
|
gc
|
|
.transition()
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 0)
|
|
.each('end', function() {
|
|
gdt.remove() ;
|
|
}) ;
|
|
|
|
ga
|
|
.transition()
|
|
.delay(dur)
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.attr('transform', 'translate(0,0)scale(1)translate(0,0)') ;
|
|
|
|
gb
|
|
.transition()
|
|
.delay(dur)
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.attr('transform', 'translate(0,0)scale(1)translate(0,0)') ;
|
|
|
|
g
|
|
.transition()
|
|
.delay(dur)
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.attr('transform', 'translate(0,0)scale(1)translate(0,0)') ;
|
|
|
|
gs
|
|
.transition()
|
|
.delay(2 * dur)
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.style('opacity', 1)
|
|
.each('end', function() {
|
|
axText.style('opacity', 0) ;
|
|
bxText.style('opacity', 0) ;
|
|
ayText.style('opacity', 0) ;
|
|
byText.style('opacity', 0) ;
|
|
gn.style('opacity', 0) ;
|
|
goText
|
|
.transition()
|
|
.duration(dur)
|
|
.style('opacity', 0)
|
|
.transition()
|
|
.delay(dur)
|
|
.duration(0.5 * dur)
|
|
.text('start')
|
|
.style('opacity', 1) ;
|
|
|
|
goBox
|
|
.on('click', null)
|
|
.on('click', animate) ;
|
|
}) ;
|
|
|
|
animating = false ;
|
|
}
|
|
|
|
var yShift2 = -0.8 * yShift ;
|
|
var xShift = 0.5 * (Math.abs(xShifta) + Math.abs(xShiftb)) ;
|
|
var xShift1 = xShift ;
|
|
var xShift2 = -xShift ;
|
|
|
|
var arrows_up = function(a, b) {
|
|
a
|
|
.transition()
|
|
.delay(.2 * dur)
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.attr('transform', 'translate(' + xShift1 + ',' + yShift2 + ')') ;
|
|
b
|
|
.transition()
|
|
.delay(.2 * dur)
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.attr('transform', 'translate(' + xShift2 + ',' + yShift2 + ')') ;
|
|
} ;
|
|
|
|
var arrows_down = function(a, b) {
|
|
a
|
|
.transition()
|
|
.delay(.2 * dur)
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.attr('transform', 'translate(0,0)') ;
|
|
b
|
|
.transition()
|
|
.delay(.2 * dur)
|
|
.duration(dur)
|
|
.ease('linear')
|
|
.attr('transform', 'translate(0,0)') ;
|
|
} ;
|
|
|
|
var gbox = g.append('g') ;
|
|
|
|
var goBox = gbox.append('rect')
|
|
.attr('x', 10)
|
|
.attr('y', 29)
|
|
.attr('rx', 2)
|
|
.attr('ry', 2)
|
|
.attr('fill', '#CCC')
|
|
.attr('width', 46)
|
|
.attr('height', 15)
|
|
.attr('stroke', 'none')
|
|
.style('cursor', 'pointer')
|
|
.on('click', animate) ;
|
|
|
|
var goText = gbox
|
|
.append('text') ;
|
|
|
|
goText
|
|
.attr('x', 19)
|
|
.attr('y', 39.5)
|
|
.text('start')
|
|
.style('font', 'courier')
|
|
.style('font-size', '7pt')
|
|
.style('fill', '#111')
|
|
.style('pointer-events', 'none') ;
|
|
|
|
</script>
|
|
</body>
|
|
</html> |