Files
secondo/WebGui2/war/resources/js/d3-graphics.js
2026-01-23 17:03:45 +08:00

728 lines
22 KiB
JavaScript

/**
* This file contains all javascript functions using the d3-library to draw elements in the graphical view.
* The functions are called from the JSNI-methods in the graphical view and from the controller classes of
* each datatype.
*
* @author Kristina Steiger
*/
//Width and height and padding of the svg
var w ;
var h ;
var padding = 55;
var svg ;
var xAxis ;
var yAxis ;
var outputRange = [];
//datasets for each implemented datatype
var datasetPoints = [];
var datasetLines = [];
var datasetPolylines = [];
var datasetPolygonPoints = [];//[x, y]
var datasetPolygons = []; //[[][]..]
//elements for moving points
var mpointPath = []; //[x, y]
var mpointTime = [];
var datasetMPoints = []; //[[][]..]
var duration = 10000;
/***********************************************************
* Functions for Main SVG and Axes
***********************************************************/
/**Create the main SVG*/
function createSVG(div, width, height){
w = height;
h = height;
svg = d3.select(div)
.append("svg")
.attr("id", "mainsvg")
.attr("width", w)
.attr("height", h);
}
/**Add a point to the output range*/
function addPointToOutputRange(x, y){
var newNumber1 = x;
var newNumber2 = y;
outputRange.push([newNumber1, newNumber2]);
}
/**Reset the range for the output and the axes*/
function resetOutputRange(){
if (outputRange) {
for (i in outputRange) {
delete i;
}
outputRange.length = 0;
}
}
/**Create the SVG, scale the axes to the outputrange and draw the axes*/
function drawAxes(){
//Create scale functions for x and y axis, get minimum and maximum of the first entry of the pointarray
var xScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[0]; }), d3.max(outputRange, function(d) { return d[0]; })])
.range([padding, w - padding]); //w, the SVGs width, surrounded by a padding.
var yScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[1]; }), d3.max(outputRange, function(d) { return d[1]; })])
.range([h - padding, padding]);
//get the max number of values for the axis
var axisXScale;
var axisYScale;
if(d3.max(outputRange, function(d) { return d[0]; }) > d3.max(outputRange, function(d) { return d[1]; })){
axisXScale = xScale;
axisYScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[0]; }), d3.max(outputRange, function(d) { return d[0]; })])
.range([h - padding, padding]);
}
else{
axisXScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[1]; }), d3.max(outputRange, function(d) { return d[1]; })])
.range([padding, w - padding]);
axisYScale = yScale;
}
//Define X axis
xAxis = d3.svg.axis()
.scale(axisXScale)
.orient("bottom")
.ticks(5); //Set rough # of ticks;
//Define Y axis
yAxis = d3.svg.axis()
.scale(axisYScale)
.orient("left")
.ticks(5);
//Create X axis
d3.select("#mainsvg").append("g")
.attr("class", "x axis")
.attr("shape-rendering", "crispEdges")
.attr("transform", "translate(0," + (h - padding) + ")")// transform the entire axis group (g), pushing it to the bottom:
.call(xAxis);
//Create Y axis
d3.select("#mainsvg").append("g")
.attr("class", "y axis")
.attr("shape-rendering", "crispEdges")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
}
/**Remove the svg from the view*/
function removeSVG(){
d3.select("svg").remove();
}
/**Remove all overlays from the svg*/
function removeAllOverlays(){
d3.select("#mainsvg").selectAll("circle").remove();
d3.select("#mainsvg").selectAll("line").remove();
d3.select("#mainsvg").selectAll("polygon").remove();
d3.select("#mainsvg").selectAll("path").remove();
}
/***********************************************************
* Functions for Points
***********************************************************/
/**check if any points are in the array*/
function hasPoints(){
if (datasetPoints.length > 0) {
return true;
} else {
return false;
}
}
/**Add a point to the dataset for points*/
function addPointToDataset(x, y, text, id, color){
var newNumber1 = x;
var newNumber2 = y;
var newText = text;
datasetPoints.push([newNumber1, newNumber2, text, id, color]); //Add new point to array
}
/**Show the point with the given id*/
function showPoint(id, color){
d3.select("#" + "point" + id.toString()) // ids can't start with a number.
.attr("r", 4)
.attr("fill", color);
}
/**Hide the point with the given id*/
function hidePoint(id){
d3.select("#" + "point" + id.toString())
.attr("r", 0)
.attr("fill", "white");
}
/**Draw given point to the output panel*/
function drawPoint(id, index, name, color){
var point = datasetPoints[index];
//Create scale functions for x and y axis
var xScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[0]; }), d3.max(outputRange, function(d) { return d[0]; })])
.range([padding, w - padding]);
var yScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[1]; }), d3.max(outputRange, function(d) { return d[1]; })])
.range([h - padding, padding]);
//Create a circle with a tooltip
var circles = d3.select("#mainsvg")
.append("circle")
.attr("id", "point" + id)
.attr("cx", xScale(point[0]))
.attr("cy", yScale(point[1]))
.attr("r", 4)
.attr("fill", color)
.on('mouseover', function(d){ d3.select(this).style({fill: 'red'}); })
.on('mouseout', function(d){ d3.select(this).style({fill: color }); })
.append("title")
.text(name);
}
/**Draw all points from the pointarray and scale them to the output panel*/
function showPointArray(){
//Create scale functions for x and y axis
var xScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[0]; }), d3.max(outputRange, function(d) { return d[0]; })])
.range([padding, w - padding]);
var yScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[1]; }), d3.max(outputRange, function(d) { return d[1]; })])
.range([h - padding, padding]);
//Create circles with tooltips
var circles = d3.select("#mainsvg").selectAll("circle")
.data(datasetPoints)
.enter()
.append("circle")
.attr("id", function(d) { return "point" + d[3].toString();
})
.attr("cx", function(d) {
return xScale(d[0]);
})
.attr("cy", function(d) {
return yScale(d[1]);
})
.attr("r", 4)
.attr("fill", (function(d) { return d[4];
}))
.on('mouseover', function(d){ d3.select(this).style({fill: 'red'}); })
.on('mouseout', function(d){ d3.select(this).style({fill: (function(d) { return d[4];
})}); })
.append("title")
.text(function(d) { return d[2];
});
}
/**Delete all points in the array by removing references to them*/
function deleteAllPoints() {
if (datasetPoints) {
for (i in datasetPoints) {
delete i;
}
datasetPoints.length = 0;
}
}
/**Remove all circles from the view*/
function removeCircles(){
d3.select("#mainsvg").selectAll("circle").remove();
}
/**Remove the point with the given id*/
function removePoint(id){
d3.select("#mainsvg").select("#" + "point" + id.toString()).remove();
}
/***********************************************************
* Functions for Lines
***********************************************************/
/**Check if any lines are in the array*/
function hasLines(){
if (datasetLines.length > 0) {
return true;
} else {
return false;
}
}
/**Check if any polylines are in the array*/
function hasPolylines(){
if (datasetPolylines.length > 0) {
return true;
} else {
return false;
}
}
/**Add a line to the dataset for lines*/
function addLineToDataset(x1, y1, x2, y2){
var newNumber1 = x1;
var newNumber2 = y1;
var newNumber3 = x2;
var newNumber4 = y2;
datasetLines.push([newNumber1, newNumber2, newNumber3, newNumber4]);//Add new line to array
}
/**Add polyline to the dataset for polylines*/
function addPolyline(){
var polyline = [];
for (i in datasetLines) {
polyline[i] = datasetLines[i];
}
datasetPolylines.push(polyline);
}
/**Show the polyline with the given id*/
function showPolyline(id){
d3.select("#" + "polyline" + id.toString()) //ids can't start with a number.
.attr("stroke-width", 2);
}
/**Hide the polyline with the given id*/
function hidePolyline(id){
d3.select("#" + "polyline" + id.toString())
.attr("stroke-width", 0);
}
/**Draw all lines for one polyline from the linearray to the svg*/
function showLineArray(id, index, color){
var lineArray = datasetPolylines[index];
//Create scale functions for x and y axis
var xScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[0]; }), d3.max(outputRange, function(d) { return d[0]; })])
.range([padding, w - padding]);
var yScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[1]; }), d3.max(outputRange, function(d) { return d[1]; })])
.range([h - padding, padding]);
//Create lines
var polylineGroup = d3.select("#mainsvg")
.append("g")
.attr("id", "polyline" + id)
/* .on("mouseover", function() { d3.select(this).selectAll("line").style("stroke", "red");
})
.on("mouseout", function() { d3.select(this).selectAll("line").style("stroke", color);
})*/
.selectAll("line")
.data(lineArray)
.enter()
.append("line")
.attr("x1", function(d) {
return xScale(d[0]);
})
.attr("y1", function(d) {
return yScale(d[1]);
})
.attr("x2", function(d) {
return xScale(d[2]);
})
.attr("y2", function(d) {
return yScale(d[3]);
})
.attr("stroke-width", 2)
.attr("stroke", color);
}
/**Delete all lines in the array by removing references to them*/
function deleteAllLines() {
if (datasetLines) {
for (i in datasetLines) {
delete i;
}
datasetLines.length = 0;
}
}
/**Delete all polylines in the polyline array*/
function deleteAllPolylines(){
if (datasetPolylines) {
for (i in datasetPolylines) {
delete i;
}
datasetPolylines.length = 0;
}
}
/**Remove all lines from the view*/
function removeLines(){
d3.select("#mainsvg").selectAll("line").remove();
}
/**Remove the polyline with the given id*/
function removePolyline(id){
d3.select("#mainsvg").select("#" + "polyline" + id.toString()).remove();
}
/***********************************************************
* Functions for Polygons
***********************************************************/
/**Check if any polygons are in the array*/
function hasPolygons(){
if (datasetPolygons.length > 0) {
return true;
} else {
return false;
}
}
/**Add a point to the path for a polygon or polyline*/
function addPointToPolygonPath(x, y){
var newNumber1 = x;
var newNumber2 = y;
datasetPolygonPoints.push([newNumber1, newNumber2]);
}
/**Add all points from the patharray as a polygon to the polygonarray*/
function addPolygon(text, id, color){
var polygon = [];
for (i in datasetPolygonPoints) {
polygon[i] = datasetPolygonPoints[i];
}
datasetPolygons.push([polygon, text, id, color]);
}
/**Show the polygon with the given id*/
function showPolygon(id, color){
d3.select("#" + "polygon" + id.toString())
.attr("fill", color)
.attr("stroke-width", 1);
}
/**Hide the polygon with the given id*/
function hidePolygon(id){
d3.select("#" + "polygon" + id.toString())//ids can't start with a number.
.attr("fill", "white")
.attr("stroke-width", 0);
}
/**Change the color of the polygon with the given id*/
function changePolygonColor(id, color){
d3.select("#" + "polygon" + id.toString())
.attr("fill", color);
}
/**Draw all points from the pointarray and scale them to the output panel*/
function drawPolygon(id, index, name, color){
var pathArray = datasetPolygons[index];
//Create scale functions for x and y axis
var xScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[0]; }), d3.max(outputRange, function(d) { return d[0]; })])
.range([padding, w - padding]);
var yScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[1]; }), d3.max(outputRange, function(d) { return d[1]; })])
.range([h - padding, padding]);
//Create a path of points filled as a polygon
d3.select("#mainsvg").selectAll("polygon")
.data([pathArray])
.enter()
.append("polygon")
.attr("id", "polygon" + id)
.attr("points",function(d) {
return d.map(function(d) {
return [xScale(d[0]),yScale(d[1])].join(",");
}).join(" ");
})
.attr("fill", color)
.style('fill-opacity', .45)
.attr("stroke-width", 1)
.attr("stroke", "red")
.on('mouseover', function(d){ d3.select(this).style('fill-opacity', .6); })
.on('mouseout', function(d){ d3.select(this).style('fill-opacity', .45); })
.append("title")
.text(name);
}
/**Draw a path of all points for a polygon from the pathpointarray and scale them to the output panel*/
function showPolygonArray(){
//Create scale functions for x and y axis
var xScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[0]; }), d3.max(outputRange, function(d) { return d[0]; })])
.range([padding, w - padding]);
var yScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[1]; }), d3.max(outputRange, function(d) { return d[1]; })])
.range([h - padding, padding]);
d3.select("#mainsvg").selectAll("polygon")
.data(datasetPolygons)
.enter()
.append("polygon")
.attr("id", function(d) { return "polygon" + d[2].toString();
})
.attr("points",function(d) {
return d[0].map(function(d) {
return [xScale(d[0]),yScale(d[1])].join(",");
}).join(" ");
})
.attr("fill", function(d) { return d[3]; })
.style('fill-opacity', .45)
.attr("stroke-width", 1)
.attr("stroke", "blue")
.on('mouseover', function(d){ d3.select(this).style('fill-opacity', .6); })
.on('mouseout', function(d){ d3.select(this).style('fill-opacity', .45); })
.append("title")
.text(function(d) { return d[1]; });
}
/**Delete all points in the array of the path*/
function deleteAllPolygonPoints(){
if (datasetPolygonPoints) {
for (i in datasetPolygonPoints) {
delete i;
}
datasetPolygonPoints.length = 0;
}
}
/**Delete all polygons in the polygon array*/
function deleteAllPolygons(){
if (datasetPolygons) {
for (i in datasetPolygons) {
delete i;
}
datasetPolygons.length = 0;
}
}
/**Remove all polygons from the view*/
function removePolygons(){
d3.select("#mainsvg").selectAll("polygon").remove();
}
/***********************************************************
* Functions for Moving Points
***********************************************************/
/**Check if any mpoints are in the array*/
function hasMPoints(){
if (mpointPath.length > 0) {
return true;
} else {
return false;
}
}
/**Add a point to the path for the moving point*/
function addPointToMPointPath(x, y){
var newNumber1 = x;
var newNumber2 = y;
mpointPath.push([newNumber1, newNumber2]);
}
/**Add all points from the mpointpatharray as a path to the mpointarray*/
function addMPoint(){
var mpoint = [];
for (i in mpointPath) {
mpoint[i] = mpointPath[i];
}
datasetMPoints.push(mpoint);
}
/**Draw the moving point with its path without moving it yet*/
function drawMovingPoint(id, index, color){
var pathMPoint = datasetMPoints[index];
//Create scale functions
var xScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[0]; }), d3.max(outputRange, function(d) { return d[0]; })])
.range([padding, w - padding]); //w, the SVGs width. without padding 0,w
var yScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[1]; }), d3.max(outputRange, function(d) { return d[1]; })])
.range([h - padding, padding]); //without padding h,0
//This is the line accessor function
var lineFunction = d3.svg.line()
.x(function(d) {
return xScale(d[0]);
})
.y(function(d) {
return yScale(d[1]);
})
.interpolate("linear");
var path = d3.select("#mainsvg").append("path")
.attr("id", "mpath" + id)
.attr("d", lineFunction(pathMPoint))
.attr("fill", "none")
.attr("stroke-width", 2)
.attr("stroke", "steelblue");
var cx = xScale(pathMPoint[0][0]);
var cy = yScale(pathMPoint[0][1]);
//add moving point to the beginning of the path
var movingpoint = d3.select("#mainsvg").append("circle")
.attr("id", "mpoint" + id)
.attr("cx", cx)
.attr("cy", cy)
.attr("r", 8)
.attr("fill", color);
}
/**Draw all data from the mpointarray, scale them to the output panel and move the point along the path*/
function animateMovingPoint(id, index, color){
var pathMPoint = datasetMPoints[index];
//Create scale functions
var xScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[0]; }), d3.max(outputRange, function(d) { return d[0]; })])
.range([padding, w - padding]);
var yScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[1]; }), d3.max(outputRange, function(d) { return d[1]; })])
.range([h - padding, padding]);
//This is the line accessor function
var lineFunction = d3.svg.line()
.x(function(d) {
return xScale(d[0]);
})
.y(function(d) {
return yScale(d[1]);
})
.interpolate("linear");
var path = d3.select("#mainsvg").append("path")
.attr("id", "mpath" + id)
.attr("d", lineFunction(pathMPoint))
.attr("fill", "none")
.attr("stroke-width", 2)
.attr("stroke", "steelblue");
//create moving point
var movingpoint = d3.select("#mainsvg").append("circle")
.attr("id", "mpoint" + id)
.attr("r", 8)
.attr("fill", color)
.on("mousedown", transition);
transition();
function transition() {
movingpoint.transition()
.ease( "linear" )
.duration(duration)
.attrTween("transform", translateAlong(path.node()));
}
// Returns an attrTween for translating along the specified path element.
function translateAlong(path) {
var l = path.getTotalLength();
return function(d, i, a) {
return function(t) {
var p = path.getPointAtLength(t * l);
return "translate(" + p.x + "," + p.y + ")";
};
};
}
}
/**Move the point to the given position*/
function movePoint(id, x, y){
//Create scale functions
var xScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[0]; }), d3.max(outputRange, function(d) { return d[0]; })])
.range([padding, w - padding]);
var yScale = d3.scale.linear()
.domain([d3.min(outputRange, function(d) { return d[1]; }), d3.max(outputRange, function(d) { return d[1]; })])
.range([h - padding, padding]);
var cx = xScale(x);
var cy = yScale(y);
d3.select("#" + "mpoint" + id)
.transition()
.attr("cx", cx)
.attr("cy", cy)
.duration(50);
}
/**Remove to given moving point from the view*/
function removeMovingPoint(id){
d3.select("#mpoint" + id).remove();
d3.select("#mpath" + id).remove();
}
/**Change the color of the moving point with the given id*/
function changeMPointColor(id, color){
d3.select("#" + "mpoint" + id.toString())
.attr("fill", color);
}
/**Delete all pathpoints from the mpoint path array*/
function deletePathOfMPoint(){
if (mpointPath) {
for (i in mpointPath) {
delete i;
}
mpointPath.length = 0;
}
}
/**Delete all mpoint paths in the array of the mpoints*/
function deleteAllMPointPaths(){
if (datasetMPoints) {
for (i in datasetMPoints) {
delete i;
}
datasetMPoints.length = 0;
}
}