UNPKG

c2

Version:

d3 component canvas

494 lines (434 loc) 15 kB
const GEAR=0, REFRESH = 1, SUCCESS = 2, ERROR = 3, data = [createNode()]; var ids = 0, canvas = document.querySelector('canvas'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; function createNode () { return { type : GEAR, id : ids++ }; } function load (canvas) { var context = d3.select(canvas) .select(c2.Context2d); context.on('tick',function (canvas) { this.context.clearRect(0,0,this.canvas.width,this.canvas.height); }); const data = []; var progress, front,back,error,workflow,processed; for (var i=0,ln=250;i<ln;i++) { progress = Math.random(); front = progress*Math.random(); back = progress - front; workflow = Math.round(Math.random()*3) === 3 && true || false; error = Math.round(Math.random()*3) === 3 && true || false; processed = Math.round(Math.random()*3) === 3 && true || false; if (workflow || error || processed) { front = 1 back = 1 } data.push({ id : i, workflow : (!error && !processed) ? workflow : processed, error : (!processed) && error, processed : processed, frontProgress : front, backProgress : back }) } var selection = context.selectAll(Gear).data(data,function (d) { return d.id; }), exited = selection.exit() .transition() .duration(50) .ease(d3.easeLinear) .attr('size',0) .remove(), entered = selection.enter(); selection = entered.append(Gear) .attr('x' , 0) .attr('y' , 0) .attr('size' , 0) .attr('rotation' , 0) .attr('color' , 'yellow') .attr('borderRadius' , radius / 2 ) .attr('lineWidth' , 3) .attr('stroke' , '#5e50db') .attr('fill' , '#5e50db') .attr('innerIndicatorRadius' , 0) .attr('innerInnerRadius' , 0) .attr('gearSpokeRadius' , 0) .attr('outerCircleRadius' , 0) .attr('innerRectSize' , 0) .attr('triangleSize' , 0) .attr('endAngle' , 0) .merge(selection); /* * var selectedIndex = selection._groups[0].indexOf(selected), * selectedRow; * * if (selected) { * selectedRow = selectedIndex % yElements; * } */ const yElements = Math.min(data.length,10), xElements = Math.ceil(data.length/yElements), startY = canvas.offsetTop + 35, margin = .1, width = canvas.clientWidth-30, height = canvas.clientHeight-50;//(selection ? 200 : 0); var radius = Math.min(height/yElements,width/xElements), startX = (width + 30 - ((xElements * radius)))/ 2, ot = startY; if (data.length < 10) { startX += margin * radius / 2; ot += ((height-70) - yElements * (radius)) / 2; ot = Math.max(startY,ot); } radius = radius - radius * margin; const xScale = d3.scaleLinear().domain([0,xElements]).range([startX,width-startX]), yScale = d3.scaleLinear().domain([0,yElements]).range([ot,height+startY-20]); selection.each(function (d,i) { var me = this, //is_preview = i === previewIndex, //is_selected = selected === this, or = r = size = Math.max(radius - 5,10), ni = Math.floor(i/yElements) * radius, oPosX = posX = startX + ni + ni*margin, row = i%yElements, oPosY = posY = yScale(row), processed = d.processed, progress = d.frontProgress + d.backProgress, color = !processed ? '#5e50db' : (d.accession !== undefined ? 'green' : 'red'), workflow = d.workflow, //indicates that the document is being processed in the workflow error = d.error, divisions, innerInnerRadius, innerIndicatorRadius, outerCircleRadius, innerRectSize, endAngle, gearSpokeRadius, triangleSize; //selRow = selectedRow; /* *if (selRow !== undefined && row > selRow) { * posY += 175; *} */ /* *if (workflow) { * workflow = true; * workflows.add(d.s3BaseKey,this); *} else { * workflows.remove(d.s3BaseKey); *} */ /* *if (is_preview) { * r*=1.15; * r = Math.min(r,375); * posX -= (r-size)/2 * posY -= (r-size)/2 *} */ //if (is_selected) { //this.stroke = 'white'; //} else if (this.stroke === 'white') { this.stroke = '#5e50db'; } if (posX !== this.posX || posY !== this.posY || size !== this.r || this.progress !== progress || this.processed !== processed || this.color !== color || error !== this.error) { this.error = error; this.color = color; this.posX = posX; this.posY = posY; this.progress = progress; this.r = size; this.processed = processed; if (processed) { innerIndicatorRadius = 0; innerInnerRadius = 0; gearSpokeRadius = 0; innerRectSize = r/2; } else { innerRectSize = 0; if (workflow) { innerIndicatorRadius = r/4; innerInnerRadius = r/8; gearSpokeRadius = r/25; } else { innerIndicatorRadius = r/3; innerInnerRadius = r/6; gearSpokeRadius = 0; } } outerCircleRadius = r/2; this._posY = oPosY; this._posX = oPosX; this._outerCircleRadius = or/2; if (workflow) { divisions = 12; } else { divisions = 30; } if (error) { innerInnerRadius = r/4; innerIndicatorRadius = innerInnerRadius + 2; gearSpokeRadius = 0; endAngle = 2*Math.PI*.85; triangleSize = r/1.5; divisions = 30; } else { endAngle = progress * 2 * Math.PI; triangleSize = 0; } d3.select(this) .attr('x',posX) .attr('y',posY) .attr('divisions' , divisions) .transition().duration(3000).ease(d3.easeElastic) .attr('fill' , color) .attr('innerIndicatorRadius' , innerIndicatorRadius) .attr('innerInnerRadius' , innerInnerRadius) .attr('gearSpokeRadius' , gearSpokeRadius) .attr('outerCircleRadius' , outerCircleRadius) .attr('innerRectSize' , innerRectSize) .attr('triangleSize' , triangleSize) .attr('endAngle' , endAngle); } }); requestAnimationFrame(function timer (dt) { selection.attr('dt',dt/1000); requestAnimationFrame(timer); },14) } const Gear = c2.element(function (context,d,i) { var r = this.r, innerRectSize = this.innerRectSize, outerCircleRadius = Math.max(this.outerCircleRadius,0), innerIndicatorRadius = Math.max(this.innerIndicatorRadius,0), endAngle = this.endAngle, fill = this.fill, stroke = this.stroke, gearSpokeRadius = Math.max(this.gearSpokeRadius,0), i, ln, divisions = this.divisions, full = Math.PI * 2, degrees = 0, mhalf, phalf, alt = 1, increment = full / divisions, half = increment/2, spoke, x=this.x + outerCircleRadius ,y=this.y+outerCircleRadius, innerInnerRadius = this.innerInnerRadius, triangleSize, sx,sy, diff,t, t1,t2,t3; context.save(); context.strokeStyle !== stroke && ( context.strokeStyle = stroke ); context.fillStyle !== fill && ( context.fillStyle = fill ); if (innerRectSize !== 0) { diff = innerRectSize/2; context.fillRect(x - diff,y-diff,innerRectSize,innerRectSize); } if (outerCircleRadius !== 0) { context.beginPath(); context.lineWidth !== 1 && ( context.lineWidth = 1 ); context.arc(x,y,outerCircleRadius,0,full,false); context.stroke(); } if (innerIndicatorRadius !== 0) { context.lineWidth !== 1 && ( context.lineWidth = 1 ); gearSpokeRadius = Math.max(gearSpokeRadius,0); innerInnerRadius = Math.max(innerInnerRadius,0); innerIndicatorRadius = Math.max(innerIndicatorRadius,0); if (gearSpokeRadius > .05) { context.beginPath(); mhalf = degrees - half alt *= -1; t = innerIndicatorRadius+gearSpokeRadius; sx = x+Math.cos(mhalf)*(t*-alt); sy = y+Math.sin(mhalf)*(t*-alt); if (!d.error) { context.translate(x,y); context.rotate(this.dt); context.translate(-x,-y); } t = endAngle + half/2; while (degrees + half <= t) { mhalf = degrees - half; phalf = degrees + half; spoke = innerIndicatorRadius+gearSpokeRadius*alt; context.arcTo( //tangent x+Math.cos(mhalf)*spoke, y+Math.sin(mhalf)*spoke, //end x+Math.cos(degrees)*spoke, y+Math.sin(degrees)*spoke, //radius gearSpokeRadius ); t1 = Math.cos(phalf); t2 = Math.sin(phalf); context.arcTo( //tangent x+t1*spoke, y+t2*spoke, //end x+t1*innerIndicatorRadius, y+t2*innerIndicatorRadius, //radius gearSpokeRadius ); degrees += increment; alt *= -1; } context.lineTo(x+innerInnerRadius*Math.cos(degrees),y+innerInnerRadius*Math.sin(degrees)); t = -half * 2; while (degrees - half >= t) { phalf = degrees - half; mhalf = degrees + half; context.arcTo( //tangent x+Math.cos(mhalf)*innerInnerRadius, y+Math.sin(mhalf)*innerInnerRadius, //end x+Math.cos(degrees)*innerInnerRadius, y+Math.sin(degrees)*innerInnerRadius, //radius innerInnerRadius ); t1 = Math.cos(phalf) * innerInnerRadius; t2 = Math.sin(phalf) * innerInnerRadius; context.arcTo( //tangent x+t1, y+t2, //end x+t1, y+t2, //radius innerInnerRadius ); degrees -= increment; alt *= -1; } t = innerIndicatorRadius - gearSpokeRadius; context.lineTo(x+Math.cos(degrees)*(t),y+Math.sin(degrees+half*1)*(t)); context.fill(); } else { mhalf = degrees - half; context.moveTo(x+Math.cos(mhalf)*(innerIndicatorRadius),y+Math.sin(mhalf)*(innerIndicatorRadius)) context.beginPath(); while (degrees + half <= endAngle) { mhalf = degrees - half; phalf = degrees + half; t1 = Math.cos(phalf)*innerIndicatorRadius; t2 = Math.sin(phalf)*innerIndicatorRadius; context.arcTo( //tangent x+t1, y+t2, //end x+t1, y+t2, //radius innerIndicatorRadius ); degrees += increment; } if (degrees < endAngle) { t1 = Math.cos(endAngle)*innerIndicatorRadius; t2 = Math.sin(endAngle)*innerIndicatorRadius; context.arcTo(x+t1,y+t2,x+t1,y+t2,innerIndicatorRadius); degrees = endAngle; } //context.lineTo(x+spoke*Math.cos(degrees),y+spoke*Math.sin(degrees)); context.lineTo(x+innerInnerRadius*Math.cos(degrees),y+innerInnerRadius*Math.sin(degrees)); t = -half*2; while (degrees - half >= t) { phalf = degrees - half; mhalf = degrees + half; t1 = Math.cos(phalf) * innerInnerRadius; t2 = Math.sin(phalf) * innerInnerRadius; context.arcTo( //tangent x+t1, y+t2, //end x+t1, y+t2, //radius innerInnerRadius ); degrees -= increment; } context.lineTo(x+Math.cos(degrees)*(innerIndicatorRadius),y+Math.sin(degrees+half)*innerIndicatorRadius); context.fill(); } triangleSize = Math.max(this.triangleSize,0); if (triangleSize > 1) { innerIndicatorRadius = (innerIndicatorRadius + innerInnerRadius)/2; t = Math.sqrt(triangleSize) ; t1 = Math.cos(endAngle); t2 = Math.sin(endAngle); t3 = innerIndicatorRadius - t; x1 = x + t1*t3; y1 = y + t2*t3; t3 = innerIndicatorRadius + t; x2 = x + t1*t3; y2 = y + t2*t3; t1 = (x2 - x1); angle = Math.acos((t1/2)/t1)/3 * (triangleSize/(r/1.5)); t = endAngle + angle; x = x+Math.cos(t)*innerIndicatorRadius; y = y+Math.sin(t)*innerIndicatorRadius; context.beginPath(); context.moveTo(x,y); context.lineTo(x1,y1); context.lineTo(x2,y2); context.lineTo(x,y); context.fill(); } } context.restore(); }).attributes({ x : c2.types.float, y : c2.types.float, stroke : c2.types.string, fill : c2.types.string, innerIndicatorRadius : c2.types.float, gearSpokeRadius : c2.types.float, endAngle : c2.types.float, outerCircleRadius : c2.types.float, dt : c2.types.float, innerRectSize : c2.types.float, divisions : c2.types.float, triangleSize : c2.types.float }); window.Gear = Gear; load(canvas);