Browse Source

fixed bug where playing with physics would not load when hierarchical is selected. Fixed bug where hierarchical physics settings wouldnt carry over to constants (#123)

css_transitions
Alex de Mulder 10 years ago
parent
commit
c4e5533c8d
4 changed files with 377 additions and 28 deletions
  1. +350
    -14
      dist/vis.js
  2. +10
    -10
      dist/vis.min.js
  3. +11
    -0
      src/graph/Graph.js
  4. +6
    -4
      src/graph/graphMixins/physics/PhysicsMixin.js

+ 350
- 14
dist/vis.js View File

@ -4,8 +4,8 @@
*
* A dynamic, browser-based visualization library.
*
* @version 1.0.1-SNAPSHOT
* @date 2014-05-02
* @version @@version
* @date @@date
*
* @license
* Copyright (C) 2011-2014 Almende B.V, http://almende.com
@ -417,7 +417,7 @@ util.extend = function (a, b) {
util.equalArray = function (a, b) {
if (a.length != b.length) return false;
for (var i = 1, len = a.length; i < len; i++) {
for (var i = 0, len = a.length; i < len; i++) {
if (a[i] != b[i]) return false;
}
@ -2595,7 +2595,7 @@ stack.collision = function collision (a, b, margin) {
* @param {Date} [end] The end date
* @param {Number} [minimumStep] Optional. Minimum step size in milliseconds
*/
TimeStep = function(start, end, minimumStep) {
function TimeStep(start, end, minimumStep) {
// variables
this.current = new Date();
this._start = new Date();
@ -2607,7 +2607,7 @@ TimeStep = function(start, end, minimumStep) {
// initialize the range
this.setRange(start, end, minimumStep);
};
}
/// enum scale
TimeStep.SCALE = {
@ -4669,6 +4669,301 @@ CustomTime.prototype._onDragEnd = function (event) {
event.preventDefault();
};
/**
* Created by Alex on 5/6/14.
*/
var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items
/**
* An ItemSet holds a set of items and ranges which can be displayed in a
* range. The width is determined by the parent of the ItemSet, and the height
* is determined by the size of the items.
* @param {Panel} backgroundPanel Panel which can be used to display the
* vertical lines of box items.
* @param {Panel} axisPanel Panel on the axis where the dots of box-items
* can be displayed.
* @param {Panel} sidePanel Left side panel holding labels
* @param {Object} [options] See ItemSet.setOptions for the available options.
* @constructor ItemSet
* @extends Panel
*/
function Linegraph(backgroundPanel, axisPanel, sidePanel, options) {
this.id = util.randomUUID();
// one options object is shared by this itemset and all its items
this.options = options || {};
this.backgroundPanel = backgroundPanel;
this.axisPanel = axisPanel;
this.sidePanel = sidePanel;
this.itemOptions = Object.create(this.options);
this.dom = {};
this.hammer = null;
var me = this;
this.itemsData = null; // DataSet
this.groupsData = null; // DataSet
this.range = null; // Range or Object {start: number, end: number}
// listeners for the DataSet of the items
// this.itemListeners = {
// 'add': function (event, params, senderId) {
// if (senderId != me.id) me._onAdd(params.items);
// },
// 'update': function (event, params, senderId) {
// if (senderId != me.id) me._onUpdate(params.items);
// },
// 'remove': function (event, params, senderId) {
// if (senderId != me.id) me._onRemove(params.items);
// }
// };
//
// // listeners for the DataSet of the groups
// this.groupListeners = {
// 'add': function (event, params, senderId) {
// if (senderId != me.id) me._onAddGroups(params.items);
// },
// 'update': function (event, params, senderId) {
// if (senderId != me.id) me._onUpdateGroups(params.items);
// },
// 'remove': function (event, params, senderId) {
// if (senderId != me.id) me._onRemoveGroups(params.items);
// }
// };
this.items = {}; // object with an Item for every data item
this.groups = {}; // Group object for every group
this.groupIds = [];
this.selection = []; // list with the ids of all selected nodes
this.stackDirty = true; // if true, all items will be restacked on next repaint
this.touchParams = {}; // stores properties while dragging
// create the HTML DOM
this._create();
}
Linegraph.prototype = new Panel();
/**
* Create the HTML DOM for the ItemSet
*/
Linegraph.prototype._create = function _create(){
var frame = document.createElement('div');
frame['timeline-linegraph'] = this;
this.frame = frame;
this.frame.className = 'itemset';
// create background panel
var background = document.createElement('div');
background.className = 'background';
this.backgroundPanel.frame.appendChild(background);
this.dom.background = background;
// create foreground panel
var foreground = document.createElement('div');
foreground.className = 'foreground';
frame.appendChild(foreground);
this.dom.foreground = foreground;
// // create axis panel
// var axis = document.createElement('div');
// axis.className = 'axis';
// this.dom.axis = axis;
// this.axisPanel.frame.appendChild(axis);
//
// // create labelset
// var labelSet = document.createElement('div');
// labelSet.className = 'labelset';
// this.dom.labelSet = labelSet;
// this.sidePanel.frame.appendChild(labelSet);
console.log(this.frame,this.frame.offsetWidth);
this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg");
this.svg.style.position = "relative"
this.svg.style.height = "300px";
this.path = document.createElementNS('http://www.w3.org/2000/svg',"path");
this.path.setAttributeNS(null, "fill","none");
this.path.setAttributeNS(null, "stroke","blue");
this.path.setAttributeNS(null, "stroke-width","1");
this.path2 = document.createElementNS('http://www.w3.org/2000/svg',"path");
this.path2.setAttributeNS(null, "fill","none");
this.path2.setAttributeNS(null, "stroke","red");
this.path2.setAttributeNS(null, "stroke-width","2");
this.dom.foreground.appendChild(this.svg);
this.svg.appendChild(this.path2);
this.svg.appendChild(this.path);
};
Linegraph.prototype.setData = function setData() {
console.log(this.frame,this.frame.offsetWidth);
var data = [];
this.startTime = this.range.start;
var min = 0;
var max = 1920;
var count = 10;
var scale = 30;
var offset = 0;
var step = (max-min) / count;
for (var i = 0; i < count; i++) {
data.push({x:Date.now() + i*step, y: 300*(i%2)})
}
console.log(data, this.width, this._previousWidth);
// catmull rom
var p0, p1, p2, p3, bp1, bp2, bp3;
var d2 = "M" + data[0].x + "," + data[0].y + " ";
for (var i = 0; i < data.length - 2; i++) {
if (i == 0) {
p0 = data[0]
}
else {
p0 = data[i-1];
}
p1 = data[i];
p2 = data[i+1];
p3 = data[i+2];
// Catmull-Rom to Cubic Bezier conversion matrix
// 0 1 0 0
// -1/6 1 1/6 0
// 0 1/6 1 -1/6
// 0 0 1 0
// bp0 = { x: p1.x, y: p1.y };
bp1 = { x: ((-p0.x + 6*p1.x + p2.x) / 6), y: ((-p0.y + 6*p1.y + p2.y) / 6)};
bp2 = { x: ((p1.x + 6*p2.x - p3.x) / 6), y: ((p1.y + 6*p2.y - p3.y) / 6)};
bp3 = { x: p2.x, y: p2.y };
d2 += "C" + bp1.x + "," + bp1.y + " " + bp2.x + "," + bp2.y + " " + bp3.x + "," + bp3.y + " ";
}
// linear
var d = "";
for (var i = 0; i < data.length - 1; i++) {
if (i == 0) {
d += "M" + data[i].x + "," + data[i].y;
}
else {
d += " " + data[i].x + "," + data[i].y;
}
}
this.path.setAttributeNS(null, "d",d);
this.path2.setAttributeNS(null, "d",d2);
//
}
/**
* Set options for the Linegraph. Existing options will be extended/overwritten.
* @param {Object} [options] The following options are available:
* {String | function} [className]
* class name for the itemset
* {String} [type]
* Default type for the items. Choose from 'box'
* (default), 'point', or 'range'. The default
* Style can be overwritten by individual items.
* {String} align
* Alignment for the items, only applicable for
* ItemBox. Choose 'center' (default), 'left', or
* 'right'.
* {String} orientation
* Orientation of the item set. Choose 'top' or
* 'bottom' (default).
* {Number} margin.axis
* Margin between the axis and the items in pixels.
* Default is 20.
* {Number} margin.item
* Margin between items in pixels. Default is 10.
* {Number} padding
* Padding of the contents of an item in pixels.
* Must correspond with the items css. Default is 5.
* {Function} snap
* Function to let items snap to nice dates when
* dragging items.
*/
Linegraph.prototype.setOptions = function setOptions(options) {
Component.prototype.setOptions.call(this, options);
};
/**
* Set range (start and end).
* @param {Range | Object} range A Range or an object containing start and end.
*/
Linegraph.prototype.setRange = function setRange(range) {
if (!(range instanceof Range) && (!range || !range.start || !range.end)) {
throw new TypeError('Range must be an instance of Range, ' +
'or an object containing start and end.');
}
this.range = range;
};
Linegraph.prototype.repaint = function repaint() {
var margin = this.options.margin,
range = this.range,
asSize = util.option.asSize,
asString = util.option.asString,
options = this.options,
orientation = this.getOption('orientation'),
resized = false,
frame = this.frame;
// TODO: document this feature to specify one margin for both item and axis distance
if (typeof margin === 'number') {
margin = {
item: margin,
axis: margin
};
}
// update className
this.frame.className = 'itemset' + (options.className ? (' ' + asString(options.className)) : '');
// check whether zoomed (in that case we need to re-stack everything)
// TODO: would be nicer to get this as a trigger from Range
var visibleInterval = this.range.end - this.range.start;
var zoomed = (visibleInterval != this.lastVisibleInterval) || (this.width != this.lastWidth);
if (zoomed) this.stackDirty = true;
this.lastVisibleInterval = visibleInterval;
this.lastWidth = this.width;
// reposition frame
this.frame.style.left = asSize(options.left, '');
this.frame.style.right = asSize(options.right, '');
this.frame.style.top = asSize((orientation == 'top') ? '0' : '');
this.frame.style.bottom = asSize((orientation == 'top') ? '' : '0');
this.frame.style.width = asSize(options.width, '100%');
// frame.style.height = asSize(height);
//frame.style.height = asSize('height' in options ? options.height : height); // TODO: reckon with height
// calculate actual size and position
this.top = this.frame.offsetTop;
this.left = this.frame.offsetLeft;
this.width = this.frame.offsetWidth;
// this.height = height;
// check if this component is resized
resized = this._isResized() || resized;
if (resized) {
this.svg.style.width = asSize(3*this.width)
}
this.setData();
}
var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items
/**
@ -4976,6 +5271,7 @@ ItemSet.prototype.repaint = function repaint() {
};
}
// update className
frame.className = 'itemset' + (options.className ? (' ' + asString(options.className)) : '');
@ -7399,6 +7695,11 @@ function Timeline (container, items, options) {
this.itemSet.on('change', me.rootPanel.repaint.bind(me.rootPanel));
this.contentPanel.appendChild(this.itemSet);
this.linegraph = new Linegraph(this.backgroundPanel, this.axisPanel, this.sideContentPanel, itemOptions);
this.linegraph.setRange(this.range);
this.linegraph.on('change', me.rootPanel.repaint.bind(me.rootPanel));
this.contentPanel.appendChild(this.linegraph);
this.itemsData = null; // DataSet
this.groupsData = null; // DataSet
@ -10779,10 +11080,10 @@ Popup.prototype.hide = function () {
* @class Groups
* This class can store groups and properties specific for groups.
*/
Groups = function () {
function Groups() {
this.clear();
this.defaultIndex = 0;
};
}
/**
@ -10860,11 +11161,11 @@ Groups.prototype.add = function (groupname, style) {
* @class Images
* This class loads images and keeps them stored.
*/
Images = function () {
function Images() {
this.images = {};
this.callback = undefined;
};
}
/**
* Set an onload callback function. This will be called each time an image
@ -11541,10 +11842,12 @@ function switchConfigurations () {
this.constants.physics.barnesHut.enabled = false;
}
else if (radioButton == "H") {
this.constants.hierarchicalLayout.enabled = true;
this.constants.physics.hierarchicalRepulsion.enabled = true;
this.constants.physics.barnesHut.enabled = false;
this._setupHierarchicalLayout();
if (this.constants.hierarchicalLayout.enabled == false) {
this.constants.hierarchicalLayout.enabled = true;
this.constants.physics.hierarchicalRepulsion.enabled = true;
this.constants.physics.barnesHut.enabled = false;
this._setupHierarchicalLayout();
}
}
else {
this.constants.hierarchicalLayout.enabled = false;
@ -11628,7 +11931,6 @@ var hierarchalRepulsionMixin = {
node1 = nodes[nodeIndices[i]];
for (j = i + 1; j < nodeIndices.length; j++) {
node2 = nodes[nodeIndices[j]];
dx = node2.x - node1.x;
dy = node2.y - node1.y;
distance = Math.sqrt(dx * dx + dy * dy);
@ -12206,6 +12508,7 @@ var HierarchicalLayoutMixin = {
* @private
*/
_placeNodesByHierarchy : function(distribution) {
var nodeId, node;
// start placing all the level 0 nodes first. Then recursively position their branches.
@ -16096,6 +16399,17 @@ Graph.prototype.setOptions = function (options) {
}
}
}
if (options.physics.hierarchicalRepulsion) {
this.constants.hierarchicalLayout.enabled = true;
this.constants.physics.hierarchicalRepulsion.enabled = true;
this.constants.physics.barnesHut.enabled = false;
for (prop in options.physics.hierarchicalRepulsion) {
if (options.physics.hierarchicalRepulsion.hasOwnProperty(prop)) {
this.constants.physics.hierarchicalRepulsion[prop] = options.physics.hierarchicalRepulsion[prop];
}
}
}
}
if (options.hierarchicalLayout) {
@ -16499,6 +16813,7 @@ Graph.prototype._handleOnDrag = function(event) {
this.drag.translation.y + diffY);
this._redraw();
this.moving = true;
this.start();
}
};
@ -17273,6 +17588,27 @@ Graph.prototype._yToCanvas = function(y) {
return y * this.scale + this.translation.y ;
};
/**
*
* @param {object} pos = {x: number, y: number}
* @returns {{x: number, y: number}}
* @constructor
*/
Graph.prototype.DOMtoCanvas = function(pos) {
return {x:this._xToCanvas(pos.x),y:this._yToCanvas(pos.y)};
}
/**
*
* @param {object} pos = {x: number, y: number}
* @returns {{x: number, y: number}}
* @constructor
*/
Graph.prototype.canvasToDOM = function(pos) {
return {x:this._canvasToX(pos.x),y:this._canvasToY(pos.y)};
}
/**
* Redraw all nodes
* The 2d context of a HTML canvas can be retrieved by canvas.getContext('2d');

+ 10
- 10
dist/vis.min.js
File diff suppressed because it is too large
View File


+ 11
- 0
src/graph/Graph.js View File

@ -557,6 +557,17 @@ Graph.prototype.setOptions = function (options) {
}
}
}
if (options.physics.hierarchicalRepulsion) {
this.constants.hierarchicalLayout.enabled = true;
this.constants.physics.hierarchicalRepulsion.enabled = true;
this.constants.physics.barnesHut.enabled = false;
for (prop in options.physics.hierarchicalRepulsion) {
if (options.physics.hierarchicalRepulsion.hasOwnProperty(prop)) {
this.constants.physics.hierarchicalRepulsion[prop] = options.physics.hierarchicalRepulsion[prop];
}
}
}
}
if (options.hierarchicalLayout) {

+ 6
- 4
src/graph/graphMixins/physics/PhysicsMixin.js View File

@ -641,10 +641,12 @@ function switchConfigurations () {
this.constants.physics.barnesHut.enabled = false;
}
else if (radioButton == "H") {
this.constants.hierarchicalLayout.enabled = true;
this.constants.physics.hierarchicalRepulsion.enabled = true;
this.constants.physics.barnesHut.enabled = false;
this._setupHierarchicalLayout();
if (this.constants.hierarchicalLayout.enabled == false) {
this.constants.hierarchicalLayout.enabled = true;
this.constants.physics.hierarchicalRepulsion.enabled = true;
this.constants.physics.barnesHut.enabled = false;
this._setupHierarchicalLayout();
}
}
else {
this.constants.hierarchicalLayout.enabled = false;

Loading…
Cancel
Save