c2
Version:
d3 component canvas
494 lines (434 loc) • 15 kB
JavaScript
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);