Browse Source

moved groups to v4.0, fixed some bugs in edges

flowchartTest
Alex de Mulder 9 years ago
parent
commit
b9c97e18d8
9 changed files with 5321 additions and 5364 deletions
  1. +5188
    -5197
      dist/vis.js
  2. +0
    -1
      index.js
  3. +0
    -107
      lib/network/Groups.js
  4. +6
    -42
      lib/network/Network.js
  5. +0
    -4
      lib/network/modules/EdgesHandler.js
  6. +116
    -0
      lib/network/modules/Groups.js
  7. +1
    -1
      lib/network/modules/InteractionHandler.js
  8. +3
    -3
      lib/network/modules/components/Edge.js
  9. +7
    -9
      lib/network/modules/components/edges/util/EdgeBase.js

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


+ 0
- 1
index.js View File

@ -54,7 +54,6 @@ exports.timeline = {
// Network // Network
exports.Network = require('./lib/network/Network'); exports.Network = require('./lib/network/Network');
exports.network = { exports.network = {
Groups: require('./lib/network/Groups'),
Images: require('./lib/network/Images'), Images: require('./lib/network/Images'),
dotparser: require('./lib/network/dotparser'), dotparser: require('./lib/network/dotparser'),
gephiParser: require('./lib/network/gephiParser') gephiParser: require('./lib/network/gephiParser')

+ 0
- 107
lib/network/Groups.js View File

@ -1,107 +0,0 @@
var util = require('../util');
/**
* @class Groups
* This class can store groups and options specific for groups.
*/
function Groups() {
this.clear();
this.defaultIndex = 0;
this.groupsArray = [];
this.groupIndex = 0;
this.useDefaultGroups = true;
}
/**
* default constants for group colors
*/
Groups.DEFAULT = [
{border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}, hover: {border: "#2B7CE9", background: "#D2E5FF"}}, // 0: blue
{border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}, hover: {border: "#FFA500", background: "#FFFFA3"}}, // 1: yellow
{border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}, hover: {border: "#FA0A10", background: "#FFAFB1"}}, // 2: red
{border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}, hover: {border: "#41A906", background: "#A1EC76"}}, // 3: green
{border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}, hover: {border: "#E129F0", background: "#F0B3F5"}}, // 4: magenta
{border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}, hover: {border: "#7C29F0", background: "#D3BDF0"}}, // 5: purple
{border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}, hover: {border: "#C37F00", background: "#FFCA66"}}, // 6: orange
{border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}, hover: {border: "#4220FB", background: "#9B9BFD"}}, // 7: darkblue
{border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}, hover: {border: "#FD5A77", background: "#FFD1D9"}}, // 8: pink
{border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}, hover: {border: "#4AD63A", background: "#E6FFE3"}}, // 9: mint
{border: "#990000", background: "#EE0000", highlight: {border: "#BB0000", background: "#FF3333"}, hover: {border: "#BB0000", background: "#FF3333"}}, // 10:bright red
{border: "#FF6000", background: "#FF6000", highlight: {border: "#FF6000", background: "#FF6000"}, hover: {border: "#FF6000", background: "#FF6000"}}, // 12: real orange
{border: "#97C2FC", background: "#2B7CE9", highlight: {border: "#D2E5FF", background: "#2B7CE9"}, hover: {border: "#D2E5FF", background: "#2B7CE9"}}, // 13: blue
{border: "#399605", background: "#255C03", highlight: {border: "#399605", background: "#255C03"}, hover: {border: "#399605", background: "#255C03"}}, // 14: green
{border: "#B70054", background: "#FF007E", highlight: {border: "#B70054", background: "#FF007E"}, hover: {border: "#B70054", background: "#FF007E"}}, // 15: magenta
{border: "#AD85E4", background: "#7C29F0", highlight: {border: "#D3BDF0", background: "#7C29F0"}, hover: {border: "#D3BDF0", background: "#7C29F0"}}, // 16: purple
{border: "#4557FA", background: "#000EA1", highlight: {border: "#6E6EFD", background: "#000EA1"}, hover: {border: "#6E6EFD", background: "#000EA1"}}, // 17: darkblue
{border: "#FFC0CB", background: "#FD5A77", highlight: {border: "#FFD1D9", background: "#FD5A77"}, hover: {border: "#FFD1D9", background: "#FD5A77"}}, // 18: pink
{border: "#C2FABC", background: "#74D66A", highlight: {border: "#E6FFE3", background: "#74D66A"}, hover: {border: "#E6FFE3", background: "#74D66A"}}, // 19: mint
{border: "#EE0000", background: "#990000", highlight: {border: "#FF3333", background: "#BB0000"}, hover: {border: "#FF3333", background: "#BB0000"}}, // 20:bright red
];
/**
* Clear all groups
*/
Groups.prototype.clear = function () {
this.groups = {};
this.groups.length = function()
{
var i = 0;
for ( var p in this ) {
if (this.hasOwnProperty(p)) {
i++;
}
}
return i;
}
};
/**
* get group options of a groupname. If groupname is not found, a new group
* is added.
* @param {*} groupname Can be a number, string, Date, etc.
* @return {Object} group The created group, containing all group options
*/
Groups.prototype.get = function (groupname) {
var group = this.groups[groupname];
if (group == undefined) {
if (this.useDefaultGroups === false && this.groupsArray.length > 0) {
// create new group
var index = this.groupIndex % this.groupsArray.length;
this.groupIndex++;
group = {};
group.color = this.groups[this.groupsArray[index]];
this.groups[groupname] = group;
}
else {
// create new group
var index = this.defaultIndex % Groups.DEFAULT.length;
this.defaultIndex++;
group = {};
group.color = Groups.DEFAULT[index];
this.groups[groupname] = group;
}
}
return group;
};
/**
* Add a custom group style
* @param {String} groupName
* @param {Object} style An object containing borderColor,
* backgroundColor, etc.
* @return {Object} group The created group object
*/
Groups.prototype.add = function (groupName, style) {
this.groups[groupName] = style;
this.groupsArray.push(groupName);
return style;
};
module.exports = Groups;

+ 6
- 42
lib/network/Network.js View File

@ -8,13 +8,13 @@ var DataSet = require('../DataSet');
var DataView = require('../DataView'); var DataView = require('../DataView');
var dotparser = require('./dotparser'); var dotparser = require('./dotparser');
var gephiParser = require('./gephiParser'); var gephiParser = require('./gephiParser');
var Groups = require('./Groups');
var Images = require('./Images'); var Images = require('./Images');
var Activator = require('../shared/Activator'); var Activator = require('../shared/Activator');
var locales = require('./locales'); var locales = require('./locales');
import Groups from './modules/Groups';
import NodesHandler from './modules/NodesHandler'; import NodesHandler from './modules/NodesHandler';
import EdgesHandler from './modules/EdgesHandler'; import EdgesHandler from './modules/EdgesHandler';
import PhysicsEngine from './modules/PhysicsEngine'; import PhysicsEngine from './modules/PhysicsEngine';
@ -50,7 +50,6 @@ function Network (container, data, options) {
}, },
locale: 'en', locale: 'en',
locales: locales, locales: locales,
useDefaultGroups: true
}; };
// containers for nodes and edges // containers for nodes and edges
@ -97,9 +96,9 @@ function Network (container, data, options) {
this.bindEventListeners(); this.bindEventListeners();
// setting up all modules // setting up all modules
var groups = new Groups(); // object with groups
var images = new Images(() => this.body.emitter.emit("_requestRedraw")); // object with images
var images = new Images(() => this.body.emitter.emit("_requestRedraw")); // object with images
this.groups = new Groups(); // object with groups
this.canvas = new Canvas(this.body); // DOM handler this.canvas = new Canvas(this.body); // DOM handler
this.selectionHandler = new SelectionHandler(this.body, this.canvas); // Selection handler this.selectionHandler = new SelectionHandler(this.body, this.canvas); // Selection handler
this.interactionHandler = new InteractionHandler(this.body, this.canvas, this.selectionHandler); // Interaction handler handles all the hammer bindings (that are bound by canvas), key this.interactionHandler = new InteractionHandler(this.body, this.canvas, this.selectionHandler); // Interaction handler handles all the hammer bindings (that are bound by canvas), key
@ -109,8 +108,8 @@ function Network (container, data, options) {
this.layoutEngine = new LayoutEngine(this.body); this.layoutEngine = new LayoutEngine(this.body);
this.clustering = new ClusterEngine(this.body); // clustering api this.clustering = new ClusterEngine(this.body); // clustering api
this.nodesHandler = new NodesHandler(this.body, images, groups, this.layoutEngine); // Handle adding, deleting and updating of nodes as well as global options
this.edgesHandler = new EdgesHandler(this.body, images, groups); // Handle adding, deleting and updating of edges as well as global options
this.nodesHandler = new NodesHandler(this.body, images, this.groups, this.layoutEngine); // Handle adding, deleting and updating of nodes as well as global options
this.edgesHandler = new EdgesHandler(this.body, images, this.groups); // Handle adding, deleting and updating of edges as well as global options
// create the DOM elements // create the DOM elements
this.canvas.create(); this.canvas.create();
@ -165,8 +164,6 @@ Network.prototype.bindEventListeners = function() {
// call the dataUpdated event because the only difference between the two is the updating of the indices // call the dataUpdated event because the only difference between the two is the updating of the indices
this.body.emitter.emit("_dataUpdated"); this.body.emitter.emit("_dataUpdated");
// start simulation (can be called safely, even if already running)
this.body.emitter.emit("startSimulation");
console.log("_dataChanged took:", new Date().valueOf() - t0); console.log("_dataChanged took:", new Date().valueOf() - t0);
}); });
@ -176,11 +173,9 @@ Network.prototype.bindEventListeners = function() {
// update values // update values
this._updateValueRange(this.body.nodes); this._updateValueRange(this.body.nodes);
this._updateValueRange(this.body.edges); this._updateValueRange(this.body.edges);
// update edges
this._reconnectEdges();
this._markAllEdgesAsDirty();
// start simulation (can be called safely, even if already running) // start simulation (can be called safely, even if already running)
this.body.emitter.emit("startSimulation"); this.body.emitter.emit("startSimulation");
console.log("_dataUpdated took:", new Date().valueOf() - t0); console.log("_dataUpdated took:", new Date().valueOf() - t0);
}); });
} }
@ -246,13 +241,6 @@ Network.prototype.setData = function(data) {
*/ */
Network.prototype.setOptions = function (options) { Network.prototype.setOptions = function (options) {
if (options !== undefined) { if (options !== undefined) {
//var fields = ['nodes','edges','smoothCurves','hierarchicalLayout','navigation',
// 'keyboard','dataManipulation','onAdd','onEdit','onEditEdge','onConnect','onDelete','clickToUse'
//];
// extend all but the values in fields
//util.selectiveNotDeepExtend(fields,this.constants, options);
//util.selectiveNotDeepExtend(['color'],this.constants.nodes, options.nodes);
//util.selectiveNotDeepExtend(['color','length'],this.constants.edges, options.edges);
//this.groups.useDefaultGroups = this.constants.useDefaultGroups; //this.groups.useDefaultGroups = this.constants.useDefaultGroups;
@ -269,31 +257,7 @@ Network.prototype.setOptions = function (options) {
this.selectionHandler.setOptions(options.selection); this.selectionHandler.setOptions(options.selection);
this.clustering.setOptions(options.clustering); this.clustering.setOptions(options.clustering);
//util.mergeOptions(this.constants, options,'smoothCurves');
//util.mergeOptions(this.constants, options,'hierarchicalLayout');
//util.mergeOptions(this.constants, options,'clustering');
//util.mergeOptions(this.constants, options,'navigation');
//util.mergeOptions(this.constants, options,'keyboard');
//util.mergeOptions(this.constants, options,'dataManipulation');
//if (options.dataManipulation) {
// this.editMode = this.constants.dataManipulation.initiallyVisible;
//}
//// TODO: work out these options and document them
//
//
// //
//if (options.groups) {
// for (var groupname in options.groups) {
// if (options.groups.hasOwnProperty(groupname)) {
// var group = options.groups[groupname];
// this.groups.add(groupname, group);
// }
// }
//}
// //
//if (options.tooltip) { //if (options.tooltip) {
// for (prop in options.tooltip) { // for (prop in options.tooltip) {

+ 0
- 4
lib/network/modules/EdgesHandler.js View File

@ -123,12 +123,8 @@ class EdgesHandler {
// this is called when options of EXISTING nodes or edges have changed. // this is called when options of EXISTING nodes or edges have changed.
this.body.emitter.on("_dataUpdated", () => { this.body.emitter.on("_dataUpdated", () => {
var t0 = new Date().valueOf();
// update values
this.reconnectEdges(); this.reconnectEdges();
this.markAllEdgesAsDirty(); this.markAllEdgesAsDirty();
// start simulation (can be called safely, even if already running)
console.log("_dataUpdated took:", new Date().valueOf() - t0);
}); });
} }

+ 116
- 0
lib/network/modules/Groups.js View File

@ -0,0 +1,116 @@
let util = require('../../util');
/**
* @class Groups
* This class can store groups and options specific for groups.
*/
class Groups {
constructor() {
this.clear();
this.defaultIndex = 0;
this.groupsArray = [];
this.groupIndex = 0;
this.defaultGroups = [
{border: "#2B7CE9", background: "#97C2FC", highlight: {border: "#2B7CE9", background: "#D2E5FF"}, hover: {border: "#2B7CE9", background: "#D2E5FF"}}, // 0: blue
{border: "#FFA500", background: "#FFFF00", highlight: {border: "#FFA500", background: "#FFFFA3"}, hover: {border: "#FFA500", background: "#FFFFA3"}}, // 1: yellow
{border: "#FA0A10", background: "#FB7E81", highlight: {border: "#FA0A10", background: "#FFAFB1"}, hover: {border: "#FA0A10", background: "#FFAFB1"}}, // 2: red
{border: "#41A906", background: "#7BE141", highlight: {border: "#41A906", background: "#A1EC76"}, hover: {border: "#41A906", background: "#A1EC76"}}, // 3: green
{border: "#E129F0", background: "#EB7DF4", highlight: {border: "#E129F0", background: "#F0B3F5"}, hover: {border: "#E129F0", background: "#F0B3F5"}}, // 4: magenta
{border: "#7C29F0", background: "#AD85E4", highlight: {border: "#7C29F0", background: "#D3BDF0"}, hover: {border: "#7C29F0", background: "#D3BDF0"}}, // 5: purple
{border: "#C37F00", background: "#FFA807", highlight: {border: "#C37F00", background: "#FFCA66"}, hover: {border: "#C37F00", background: "#FFCA66"}}, // 6: orange
{border: "#4220FB", background: "#6E6EFD", highlight: {border: "#4220FB", background: "#9B9BFD"}, hover: {border: "#4220FB", background: "#9B9BFD"}}, // 7: darkblue
{border: "#FD5A77", background: "#FFC0CB", highlight: {border: "#FD5A77", background: "#FFD1D9"}, hover: {border: "#FD5A77", background: "#FFD1D9"}}, // 8: pink
{border: "#4AD63A", background: "#C2FABC", highlight: {border: "#4AD63A", background: "#E6FFE3"}, hover: {border: "#4AD63A", background: "#E6FFE3"}}, // 9: mint
{border: "#990000", background: "#EE0000", highlight: {border: "#BB0000", background: "#FF3333"}, hover: {border: "#BB0000", background: "#FF3333"}}, // 10:bright red
{border: "#FF6000", background: "#FF6000", highlight: {border: "#FF6000", background: "#FF6000"}, hover: {border: "#FF6000", background: "#FF6000"}}, // 12: real orange
{border: "#97C2FC", background: "#2B7CE9", highlight: {border: "#D2E5FF", background: "#2B7CE9"}, hover: {border: "#D2E5FF", background: "#2B7CE9"}}, // 13: blue
{border: "#399605", background: "#255C03", highlight: {border: "#399605", background: "#255C03"}, hover: {border: "#399605", background: "#255C03"}}, // 14: green
{border: "#B70054", background: "#FF007E", highlight: {border: "#B70054", background: "#FF007E"}, hover: {border: "#B70054", background: "#FF007E"}}, // 15: magenta
{border: "#AD85E4", background: "#7C29F0", highlight: {border: "#D3BDF0", background: "#7C29F0"}, hover: {border: "#D3BDF0", background: "#7C29F0"}}, // 16: purple
{border: "#4557FA", background: "#000EA1", highlight: {border: "#6E6EFD", background: "#000EA1"}, hover: {border: "#6E6EFD", background: "#000EA1"}}, // 17: darkblue
{border: "#FFC0CB", background: "#FD5A77", highlight: {border: "#FFD1D9", background: "#FD5A77"}, hover: {border: "#FFD1D9", background: "#FD5A77"}}, // 18: pink
{border: "#C2FABC", background: "#74D66A", highlight: {border: "#E6FFE3", background: "#74D66A"}, hover: {border: "#E6FFE3", background: "#74D66A"}}, // 19: mint
{border: "#EE0000", background: "#990000", highlight: {border: "#FF3333", background: "#BB0000"}, hover: {border: "#FF3333", background: "#BB0000"}}, // 20:bright red
];
this.options = {};
this.defaultOptions = {
useDefaultGroups: true
}
util.extend(this.options, this.defaultOptions);
}
setOptions(options) {
let optionFields = ['useDefaultGroups'];
if (options !== undefined) {
for (let groupname in options) {
if (options.hasOwnProperty(groupname)) {
if (optionFields.indexOf(groupName) == -1) {
let group = options[groupname];
this.add(groupname, group);
}
}
}
}
}
/**
* Clear all groups
*/
clear() {
this.groups = {};
this.groupsArray = [];
}
/**
* get group options of a groupname. If groupname is not found, a new group
* is added.
* @param {*} groupname Can be a number, string, Date, etc.
* @return {Object} group The created group, containing all group options
*/
get(groupname) {
let group = this.groups[groupname];
if (group == undefined) {
if (this.options.useDefaultGroups === false && this.groupsArray.length > 0) {
// create new group
let index = this.groupIndex % this.groupsArray.length;
this.groupIndex++;
group = {};
group.color = this.groups[this.groupsArray[index]];
this.groups[groupname] = group;
}
else {
// create new group
let index = this.defaultIndex % this.defaultGroups.length;
this.defaultIndex++;
group = {};
group.color = this.defaultGroups[index];
this.groups[groupname] = group;
}
}
return group;
}
/**
* Add a custom group style
* @param {String} groupName
* @param {Object} style An object containing borderColor,
* backgroundColor, etc.
* @return {Object} group The created group object
*/
add(groupName, style) {
this.groups[groupName] = style;
this.groupsArray.push(groupName);
return style;
}
}
export default Groups;

+ 1
- 1
lib/network/modules/InteractionHandler.js View File

@ -404,7 +404,7 @@ class InteractionHandler {
scale *= (1 + zoom); scale *= (1 + zoom);
// calculate the pointer location // calculate the pointer location
let pointer = {x:event.pageX, y:event.pageY};
let pointer = this.getPointer({x:event.pageX, y:event.pageY});
// apply the new scale // apply the new scale
this.zoom(scale, pointer); this.zoom(scale, pointer);

+ 3
- 3
lib/network/modules/components/Edge.js View File

@ -294,9 +294,9 @@ class Edge {
} }
drawArrows(ctx, viaNode) { drawArrows(ctx, viaNode) {
if (this.options.arrows.from.enabled === true) {this.edgeType.drawArrowHead(ctx,'from', viaNode);}
if (this.options.arrows.middle.enabled === true) {this.edgeType.drawArrowHead(ctx,'middle', viaNode);}
if (this.options.arrows.to.enabled === true) {this.edgeType.drawArrowHead(ctx,'to', viaNode);}
if (this.options.arrows.from.enabled === true) {this.edgeType.drawArrowHead(ctx,'from', viaNode, this.selected, this.hover);}
if (this.options.arrows.middle.enabled === true) {this.edgeType.drawArrowHead(ctx,'middle', viaNode, this.selected, this.hover);}
if (this.options.arrows.to.enabled === true) {this.edgeType.drawArrowHead(ctx,'to', viaNode, this.selected, this.hover);}
} }
drawLabel(ctx, viaNode) { drawLabel(ctx, viaNode) {

+ 7
- 9
lib/network/modules/components/edges/util/EdgeBase.js View File

@ -28,7 +28,7 @@ class EdgeBase {
drawLine(ctx, selected, hover) { drawLine(ctx, selected, hover) {
// set style // set style
ctx.strokeStyle = this.getColor(ctx); ctx.strokeStyle = this.getColor(ctx);
ctx.lineWidth = this.getLineWidth();
ctx.lineWidth = this.getLineWidth(selected, hover);
let via = undefined; let via = undefined;
if (this.from != this.to) { if (this.from != this.to) {
// draw line // draw line
@ -120,8 +120,6 @@ class EdgeBase {
} }
/** /**
* This function uses binary search to look for the point where the circle crosses the border of the node. * This function uses binary search to look for the point where the circle crosses the border of the node.
* @param x * @param x
@ -151,7 +149,7 @@ class EdgeBase {
while (low <= high && iteration < maxIterations) { while (low <= high && iteration < maxIterations) {
let middle = (low + high) * 0.5; let middle = (low + high) * 0.5;
pos = this._pointOnCircle(x,y,radius,middle);
pos = this._pointOnCircle(x, y, radius, middle);
angle = Math.atan2((node.y - pos.y), (node.x - pos.x)); angle = Math.atan2((node.y - pos.y), (node.x - pos.x));
distanceToBorder = node.distanceToBorder(ctx, angle); distanceToBorder = node.distanceToBorder(ctx, angle);
distanceToPoint = Math.sqrt(Math.pow(pos.x - node.x, 2) + Math.pow(pos.y - node.y, 2)); distanceToPoint = Math.sqrt(Math.pow(pos.x - node.x, 2) + Math.pow(pos.y - node.y, 2));
@ -352,11 +350,11 @@ class EdgeBase {
* @param position * @param position
* @param viaNode * @param viaNode
*/ */
drawArrowHead(ctx,position,viaNode) {
drawArrowHead(ctx, position, viaNode, selected, hover) {
// set style // set style
ctx.strokeStyle = this.getColor(ctx); ctx.strokeStyle = this.getColor(ctx);
ctx.fillStyle = ctx.strokeStyle; ctx.fillStyle = ctx.strokeStyle;
ctx.lineWidth = this.getLineWidth();
ctx.lineWidth = this.getLineWidth(selected, hover);
// set lets // set lets
let angle; let angle;
@ -390,8 +388,8 @@ class EdgeBase {
if (position !== 'middle') { if (position !== 'middle') {
// draw arrow head // draw arrow head
if (this.options.smooth.enabled == true) { if (this.options.smooth.enabled == true) {
arrowPos = this.findBorderPosition(node1, ctx, {via:viaNode});
let guidePos = this.getPoint(Math.max(0.0,Math.min(1.0,arrowPos.t + guideOffset)), viaNode);
arrowPos = this.findBorderPosition(node1, ctx, {via: viaNode});
let guidePos = this.getPoint(Math.max(0.0, Math.min(1.0, arrowPos.t + guideOffset)), viaNode);
angle = Math.atan2((arrowPos.y - guidePos.y), (arrowPos.x - guidePos.x)); angle = Math.atan2((arrowPos.y - guidePos.y), (arrowPos.x - guidePos.x));
} }
else { else {
@ -438,7 +436,7 @@ class EdgeBase {
angle = point.t * -2 * Math.PI + 1.5 * Math.PI - 1.1 * Math.PI; angle = point.t * -2 * Math.PI + 1.5 * Math.PI - 1.1 * Math.PI;
} }
else { else {
point = this.findBorderPosition(x,y,radius,0.175);
point = this.findBorderPosition(x, y, radius, 0.175);
angle = 3.9269908169872414; // == 0.175 * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI; angle = 3.9269908169872414; // == 0.175 * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
} }

Loading…
Cancel
Save