You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

553 lines
24 KiB

3 years ago
  1. $axure.internal(function($ax) {
  2. $ax.public.fn.matrixMultiply = function(matrix, vector) {
  3. if(!matrix.tx) matrix.tx = 0;
  4. if(!matrix.ty) matrix.ty = 0;
  5. var outX = matrix.m11 * vector.x + matrix.m12 * vector.y + matrix.tx;
  6. var outY = matrix.m21 * vector.x + matrix.m22 * vector.y + matrix.ty;
  7. return { x: outX, y: outY };
  8. }
  9. $ax.public.fn.matrixInverse = function(matrix) {
  10. if(!matrix.tx) matrix.tx = 0;
  11. if(!matrix.ty) matrix.ty = 0;
  12. var determinant = matrix.m11*matrix.m22 - matrix.m12*matrix.m21;
  13. //var threshold = (M11 * M11 + M22 *M22 + M12 *M12+ M21 *M21) / 100000;
  14. //if(determinant.DeltaEquals(0, threshold) && determinant < 0.01) {
  15. // return Invalid;
  16. //}
  17. return {
  18. m11 : matrix.m22/determinant,
  19. m12 : -matrix.m12/determinant,
  20. tx : (matrix.ty*matrix.m12 - matrix.tx*matrix.m22)/determinant,
  21. m21: -matrix.m21 / determinant,
  22. m22: matrix.m11 / determinant,
  23. ty: (matrix.tx * matrix.m21 - matrix.ty * matrix.m11) / determinant
  24. };
  25. }
  26. $ax.public.fn.matrixMultiplyMatrix = function (matrix1, matrix2) {
  27. if (!matrix1.tx) matrix1.tx = 0;
  28. if (!matrix1.ty) matrix1.ty = 0;
  29. if (!matrix2.tx) matrix2.tx = 0;
  30. if (!matrix2.ty) matrix2.ty = 0;
  31. return {
  32. m11: matrix1.m12*matrix2.m21 + matrix1.m11*matrix2.m11,
  33. m12: matrix1.m12*matrix2.m22 + matrix1.m11*matrix2.m12,
  34. tx: matrix1.m12 * matrix2.ty + matrix1.m11 * matrix2.tx + matrix1.tx,
  35. m21: matrix1.m22 * matrix2.m21 + matrix1.m21 * matrix2.m11,
  36. m22: matrix1.m22 * matrix2.m22 + matrix1.m21 * matrix2.m12,
  37. ty: matrix1.m22 * matrix2.ty + matrix1.m21 * matrix2.tx + matrix1.ty,
  38. };
  39. }
  40. $ax.public.fn.transformFromElement = function (element) {
  41. var st = window.getComputedStyle(element, null);
  42. var tr = st.getPropertyValue("-webkit-transform") ||
  43. st.getPropertyValue("-moz-transform") ||
  44. st.getPropertyValue("-ms-transform") ||
  45. st.getPropertyValue("-o-transform") ||
  46. st.getPropertyValue("transform");
  47. if (tr.indexOf('none') < 0) {
  48. var matrix = tr.split('(')[1];
  49. matrix = matrix.split(')')[0];
  50. matrix = matrix.split(',');
  51. for (var l = 0; l < matrix.length; l++) {
  52. matrix[l] = Number(matrix[l]);
  53. }
  54. } else { matrix = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]; }
  55. return matrix;
  56. // matrix[0] = cosine, matrix[1] = sine.
  57. // Assuming the element is still orthogonal.
  58. }
  59. $ax.public.fn.vectorMinus = function(vector1, vector2) { return { x: vector1.x - vector2.x, y: vector1.y - vector2.y }; }
  60. $ax.public.fn.vectorPlus = function (vector1, vector2) { return { x: vector1.x + vector2.x, y: vector1.y + vector2.y }; }
  61. $ax.public.fn.vectorMidpoint = function (vector1, vector2) { return { x: (vector1.x + vector2.x) / 2.0, y: (vector1.y + vector2.y) / 2.0 }; }
  62. $ax.public.fn.fourCornersToBasis = function (fourCorners) {
  63. return {
  64. widthVector: $ax.public.fn.vectorMinus(fourCorners.widgetTopRight, fourCorners.widgetTopLeft),
  65. heightVector: $ax.public.fn.vectorMinus(fourCorners.widgetBottomLeft, fourCorners.widgetTopLeft)
  66. };
  67. }
  68. $ax.public.fn.matrixString = function(m11, m21, m12, m22, tx, ty) {
  69. return "Matrix(" + m11 + "," + m21 + "," + m12 + "," + m22 + ", " + tx + ", " + ty + ")";
  70. }
  71. //$ax.public.fn.getWidgetBoundingRect = function (widgetId) {
  72. // var emptyRect = { left: 0, top: 0, centerPoint: { x: 0, y: 0 }, width: 0, height: 0 };
  73. // var element = document.getElementById(widgetId);
  74. // if (!element) return emptyRect;
  75. // var object = $obj(widgetId);
  76. // if (object && object.type && $ax.public.fn.IsLayer(object.type)) {
  77. // var layerChildren = _getLayerChildrenDeep(widgetId);
  78. // if (!layerChildren) return emptyRect;
  79. // else return _getBoundingRectForMultipleWidgets(layerChildren);
  80. // }
  81. // return _getBoundingRectForSingleWidget(widgetId);
  82. //};
  83. var _getLayerChildrenDeep = $ax.public.fn.getLayerChildrenDeep = function (layerId, includeLayers, includeHidden) {
  84. var deep = [];
  85. var children = $ax('#' + layerId).getChildren()[0].children;
  86. for (var index = 0; index < children.length; index++) {
  87. var childId = children[index];
  88. if(!includeHidden && !$ax.visibility.IsIdVisible(childId)) continue;
  89. if ($ax.public.fn.IsLayer($obj(childId).type)) {
  90. if (includeLayers) deep.push(childId);
  91. var recursiveChildren = _getLayerChildrenDeep(childId, includeLayers, includeHidden);
  92. for (var j = 0; j < recursiveChildren.length; j++) deep.push(recursiveChildren[j]);
  93. } else deep.push(childId);
  94. }
  95. return deep;
  96. };
  97. //var _getBoundingRectForMultipleWidgets = function (widgetsIdArray, relativeToPage) {
  98. // if (!widgetsIdArray || widgetsIdArray.constructor !== Array) return undefined;
  99. // if (widgetsIdArray.length == 0) return { left: 0, top: 0, centerPoint: { x: 0, y: 0 }, width: 0, height: 0 };
  100. // var widgetRect = _getBoundingRectForSingleWidget(widgetsIdArray[0], relativeToPage, true);
  101. // var boundingRect = { left: widgetRect.left, right: widgetRect.right, top: widgetRect.top, bottom: widgetRect.bottom };
  102. // for (var index = 1; index < widgetsIdArray.length; index++) {
  103. // widgetRect = _getBoundingRectForSingleWidget(widgetsIdArray[index], relativeToPage);
  104. // boundingRect.left = Math.min(boundingRect.left, widgetRect.left);
  105. // boundingRect.top = Math.min(boundingRect.top, widgetRect.top);
  106. // boundingRect.right = Math.max(boundingRect.right, widgetRect.right);
  107. // boundingRect.bottom = Math.max(boundingRect.bottom, widgetRect.bottom);
  108. // }
  109. // boundingRect.centerPoint = { x: (boundingRect.right + boundingRect.left) / 2.0, y: (boundingRect.bottom + boundingRect.top) / 2.0 };
  110. // boundingRect.width = boundingRect.right - boundingRect.left;
  111. // boundingRect.height = boundingRect.bottom - boundingRect.top;
  112. // return boundingRect;
  113. //};
  114. //var _getBoundingRectForSingleWidget = function (widgetId, relativeToPage, justSides) {
  115. // var element = document.getElementById(widgetId);
  116. // var boundingRect, tempBoundingRect, position;
  117. // var displayChanged = _displayHackStart(element);
  118. // if (_isCompoundVectorHtml(element)) {
  119. // //tempBoundingRect = _getCompoundImageBoundingClientSize(widgetId);
  120. // //position = { left: tempBoundingRect.left, top: tempBoundingRect.top };
  121. // position = $(element).position();
  122. // tempBoundingRect = {};
  123. // tempBoundingRect.left = position.left; //= _getCompoundImageBoundingClientSize(widgetId);
  124. // tempBoundingRect.top = position.top;
  125. // tempBoundingRect.width = Number(element.getAttribute('data-width'));
  126. // tempBoundingRect.height = Number(element.getAttribute('data-height'));
  127. // } else {
  128. // var boundingElement = element;
  129. // if($ax.dynamicPanelManager.isIdFitToContent(widgetId)) {
  130. // var stateId = $ax.visibility.GetPanelState(widgetId);
  131. // if(stateId != '') boundingElement = document.getElementById(stateId);
  132. // }
  133. // tempBoundingRect = boundingElement.getBoundingClientRect();
  134. // var jElement = $(element);
  135. // position = jElement.position();
  136. // if(jElement.css('position') == 'fixed') {
  137. // position.left += Number(jElement.css('margin-left').replace("px", ""));
  138. // position.top += Number(jElement.css('margin-top').replace("px", ""));
  139. // }
  140. // }
  141. // var layers = $ax('#' + widgetId).getParents(true, ['layer'])[0];
  142. // var flip = '';
  143. // var mirrorWidth = 0;
  144. // var mirrorHeight = 0;
  145. // for (var i = 0; i < layers.length; i++) {
  146. // //should always be 0,0
  147. // var layerPos = $jobj(layers[i]).position();
  148. // position.left += layerPos.left;
  149. // position.top += layerPos.top;
  150. // var outer = $ax.visibility.applyWidgetContainer(layers[i], true, true);
  151. // if (outer.length) {
  152. // var outerPos = outer.position();
  153. // position.left += outerPos.left;
  154. // position.top += outerPos.top;
  155. // }
  156. // //when a group is flipped we find the unflipped position
  157. // var inner = $jobj(layers[i] + '_container_inner');
  158. // var taggedFlip = inner.data('flip');
  159. // if (inner.length && taggedFlip) {
  160. // //only account for flip if transform is applied
  161. // var matrix = taggedFlip && (inner.css("-webkit-transform") || inner.css("-moz-transform") ||
  162. // inner.css("-ms-transform") || inner.css("-o-transform") || inner.css("transform"));
  163. // if (matrix !== 'none') {
  164. // flip = taggedFlip;
  165. // mirrorWidth = $ax.getNumFromPx(inner.css('width'));
  166. // mirrorHeight = $ax.getNumFromPx(inner.css('height'));
  167. // }
  168. // }
  169. // }
  170. // //Now account for flip
  171. // if (flip == 'x') position.top = mirrorHeight - position.top - element.getBoundingClientRect().height;
  172. // else if (flip == 'y') position.left = mirrorWidth - position.left - element.getBoundingClientRect().width;
  173. // boundingRect = {
  174. // left: position.left,
  175. // right: position.left + tempBoundingRect.width,
  176. // top: position.top,
  177. // bottom: position.top + tempBoundingRect.height
  178. // };
  179. // _displayHackEnd(displayChanged);
  180. // if (justSides) return boundingRect;
  181. // boundingRect.width = boundingRect.right - boundingRect.left;
  182. // boundingRect.height = boundingRect.bottom - boundingRect.top;
  183. // boundingRect.centerPoint = {
  184. // x: boundingRect.width / 2 + boundingRect.left,
  185. // y: boundingRect.height / 2 + boundingRect.top
  186. // };
  187. // return boundingRect;
  188. //};
  189. var _getPointAfterRotate = $ax.public.fn.getPointAfterRotate = function (angleInDegrees, pointToRotate, centerPoint) {
  190. var displacement = $ax.public.fn.vectorMinus(pointToRotate, centerPoint);
  191. var rotationMatrix = $ax.public.fn.rotationMatrix(angleInDegrees);
  192. rotationMatrix.tx = centerPoint.x;
  193. rotationMatrix.ty = centerPoint.y;
  194. return $ax.public.fn.matrixMultiply(rotationMatrix, displacement);
  195. };
  196. $ax.public.fn.getBoundingSizeForRotate = function(width, height, rotation) {
  197. // point to rotate around doesn't matter since we just care about size, if location matter we need more args and location matters.
  198. var origin = { x: 0, y: 0 };
  199. var corner1 = { x: width, y: 0 };
  200. var corner2 = { x: 0, y: height };
  201. var corner3 = { x: width, y: height };
  202. corner1 = _getPointAfterRotate(rotation, corner1, origin);
  203. corner2 = _getPointAfterRotate(rotation, corner2, origin);
  204. corner3 = _getPointAfterRotate(rotation, corner3, origin);
  205. var left = Math.min(0, corner1.x, corner2.x, corner3.x);
  206. var right = Math.max(0, corner1.x, corner2.x, corner3.x);
  207. var top = Math.min(0, corner1.y, corner2.y, corner3.y);
  208. var bottom = Math.max(0, corner1.y, corner2.y, corner3.y);
  209. return { width: right - left, height: bottom - top };
  210. }
  211. $ax.public.fn.getBoundingRectForRotate = function (boundingRect, rotation) {
  212. var centerPoint = boundingRect.centerPoint;
  213. var corner1 = { x: boundingRect.left, y: boundingRect.top };
  214. var corner2 = { x: boundingRect.right, y: boundingRect.top };
  215. var corner3 = { x: boundingRect.right, y: boundingRect.bottom };
  216. var corner4 = { x: boundingRect.left, y: boundingRect.bottom };
  217. corner1 = _getPointAfterRotate(rotation, corner1, centerPoint);
  218. corner2 = _getPointAfterRotate(rotation, corner2, centerPoint);
  219. corner3 = _getPointAfterRotate(rotation, corner3, centerPoint);
  220. corner4 = _getPointAfterRotate(rotation, corner4, centerPoint);
  221. var left = Math.min(corner1.x, corner2.x, corner3.x, corner4.x);
  222. var right = Math.max(corner1.x, corner2.x, corner3.x, corner4.x);
  223. var top = Math.min(corner1.y, corner2.y, corner3.y, corner4.y);
  224. var bottom = Math.max(corner1.y, corner2.y, corner3.y, corner4.y);
  225. return { left: left, top: top, width: right - left, height: bottom - top };
  226. }
  227. //$ax.public.fn.getPositionRelativeToParent = function (elementId) {
  228. // var element = document.getElementById(elementId);
  229. // var list = _displayHackStart(element);
  230. // var position = $(element).position();
  231. // _displayHackEnd(list);
  232. // return position;
  233. //};
  234. //var _displayHackStart = $ax.public.fn.displayHackStart = function (element) {
  235. // // TODO: Options: 1) stop setting display none. Big change for this late in the game. 2) Implement our own bounding.
  236. // // TODO: 3) Current method is look for any parents that are set to none, and and temporarily unblock. Don't like it, but it works.
  237. // var parent = element;
  238. // var displays = [];
  239. // while (parent) {
  240. // if (parent.style.display == 'none') {
  241. // displays.push(parent);
  242. // //use block to overwrites default hidden objects' display
  243. // parent.style.display = 'block';
  244. // }
  245. // parent = parent.parentElement;
  246. // }
  247. // return displays;
  248. //};
  249. //var _displayHackEnd = $ax.public.fn.displayHackEnd = function (displayChangedList) {
  250. // for (var i = 0; i < displayChangedList.length; i++) displayChangedList[i].style.display = 'none';
  251. //};
  252. var _isCompoundVectorHtml = $ax.public.fn.isCompoundVectorHtml = function(hElement) {
  253. return hElement.hasAttribute('compoundmode') && hElement.getAttribute('compoundmode') == "true";
  254. }
  255. $ax.public.fn.removeCompound = function (jobj) { if(_isCompoundVectorHtml(jobj[0])) jobj.removeClass('compound'); }
  256. $ax.public.fn.restoreCompound = function (jobj) { if (_isCompoundVectorHtml(jobj[0])) jobj.addClass('compound'); }
  257. $ax.public.fn.compoundIdFromComponent = function(id) {
  258. var pPos = id.indexOf('p');
  259. var dashPos = id.indexOf('-');
  260. if (pPos < 1) return id;
  261. else if (dashPos < 0) return id.substring(0, pPos);
  262. else return id.substring(0, pPos) + id.substring(dashPos);
  263. }
  264. $ax.public.fn.l2 = function (x, y) { return Math.sqrt(x * x + y * y); }
  265. $ax.public.fn.convertToSingleImage = function (jobj) {
  266. if(!jobj[0]) return;
  267. var widgetId = jobj[0].id;
  268. var object = $obj(widgetId);
  269. if ($ax.public.fn.IsLayer(object.type)) {
  270. var recursiveChildren = _getLayerChildrenDeep(widgetId, true);
  271. for (var j = 0; j < recursiveChildren.length; j++)
  272. $ax.public.fn.convertToSingleImage($jobj(recursiveChildren[j]));
  273. return;
  274. }
  275. //var layer =
  276. if(!_isCompoundVectorHtml(jobj[0])) return;
  277. $('#' + widgetId).removeClass("compound");
  278. $('#' + widgetId + '_img').removeClass("singleImg");
  279. jobj[0].setAttribute('compoundmode', 'false');
  280. var components = object.compoundChildren;
  281. delete object.generateCompound;
  282. for (var i = 0; i < components.length; i++) {
  283. var componentJobj = $jobj($ax.public.fn.getComponentId(widgetId, components[i]));
  284. componentJobj.css('display', 'none');
  285. componentJobj.css('visibility', 'hidden');
  286. }
  287. }
  288. $ax.public.fn.getContainerDimensions = function(query) {
  289. // returns undefined if no containers found.
  290. var containerDimensions;
  291. for (var i = 0; i < query[0].children.length; i++) {
  292. var node = query[0].children[i];
  293. if (node.id.indexOf(query[0].id) >= 0 && node.id.indexOf('container') >= 0) {
  294. containerDimensions = node.style;
  295. }
  296. }
  297. return containerDimensions;
  298. }
  299. $ax.public.fn.rotationMatrix = function (angleInDegrees) {
  300. var angleInRadians = angleInDegrees * (Math.PI / 180);
  301. var cosTheta = Math.cos(angleInRadians);
  302. var sinTheta = Math.sin(angleInRadians);
  303. return { m11: cosTheta, m12: -sinTheta, m21: sinTheta, m22: cosTheta, tx: 0.0, ty: 0.0 };
  304. }
  305. $ax.public.fn.GetFieldFromStyle = function (query, field) {
  306. var raw = query[0].style[field];
  307. if (!raw) raw = query.css(field);
  308. return Number(raw.replace('px', ''));
  309. }
  310. $ax.public.fn.setTransformHowever = function (transformString) {
  311. return {
  312. '-webkit-transform': transformString,
  313. '-moz-transform': transformString,
  314. '-ms-transform': transformString,
  315. '-o-transform': transformString,
  316. 'transform': transformString
  317. };
  318. }
  319. $ax.public.fn.getCornersFromComponent = function (id) {
  320. var element = document.getElementById(id);
  321. var matrix = element ? $ax.public.fn.transformFromElement(element) : [1.0, 0.0, 0.0, 1.0, 0.0, 0.0];
  322. var currentMatrix = { m11: matrix[0], m21: matrix[1], m12: matrix[2], m22: matrix[3], tx: matrix[4], ty: matrix[5] };
  323. var dimensions = {};
  324. var axObj = $ax('#' + id);
  325. var viewportLocation = axObj.offsetLocation();
  326. dimensions.left = viewportLocation.left;
  327. dimensions.top = viewportLocation.top;
  328. //dimensions.left = axObj.left(true);
  329. //dimensions.top = axObj.top(true);
  330. var size = axObj.size();
  331. dimensions.width = size.width;
  332. dimensions.height = size.height;
  333. //var transformMatrix1 = { m11: 1, m12: 0, m21: 0, m22: 1, tx: -invariant.x, ty: -invariant.y };
  334. //var transformMatrix2 = { m11: 1, m12: 0, m21: 0, m22: 1, tx: 500, ty: 500 };
  335. var halfWidth = dimensions.width * 0.5;
  336. var halfHeight = dimensions.height * 0.5;
  337. //var preTransformTopLeft = { x: -halfWidth, y: -halfHeight };
  338. //var preTransformBottomLeft = { x: -halfWidth, y: halfHeight };
  339. var preTransformTopRight = { x: halfWidth, y: -halfHeight };
  340. var preTransformBottomRight = { x: halfWidth, y: halfHeight };
  341. return {
  342. //relativeTopLeft: $ax.public.fn.matrixMultiply(currentMatrix, preTransformTopLeft),
  343. //relativeBottomLeft: $ax.public.fn.matrixMultiply(currentMatrix, preTransformBottomLeft),
  344. relativeTopRight: $ax.public.fn.matrixMultiply(currentMatrix, preTransformTopRight),
  345. relativeBottomRight: $ax.public.fn.matrixMultiply(currentMatrix, preTransformBottomRight),
  346. centerPoint: { x: dimensions.left + halfWidth, y: dimensions.top + halfHeight }
  347. //originalDimensions: dimensions,
  348. //transformShift: { x: matrix[4], y: matrix[5] }
  349. }
  350. }
  351. $ax.public.fn.inversePathLengthFunction = function (pathFunction) {
  352. // these are for computing the inverse functions of path integrals.
  353. var makeDivisionNode = function(node1, node2) {
  354. var param = 0.5 * (node1.Param + node2.Param);
  355. var inBetweenNode = {
  356. LowerStop: node1,
  357. HigherStop: node2,
  358. Param: param,
  359. Position: pathFunction(param),
  360. Cumulative: 0.0
  361. };
  362. var lowerDisplacement = $ax.public.fn.vectorMinus(node1.Position, inBetweenNode.Position);
  363. inBetweenNode.LowerInterval = {
  364. Length: $ax.public.fn.l2(lowerDisplacement.x, lowerDisplacement.y),
  365. Node: inBetweenNode,
  366. IsHigher: false
  367. };
  368. var higherDisplacement = $ax.public.fn.vectorMinus(node2.Position, inBetweenNode.Position);
  369. inBetweenNode.HigherInterval = {
  370. Length: $ax.public.fn.l2(higherDisplacement.x, higherDisplacement.y),
  371. Node: inBetweenNode,
  372. IsHigher: true
  373. };
  374. return inBetweenNode;
  375. };
  376. var expandLower = function(node) {
  377. node.LowerChild = makeDivisionNode(node.LowerStop, node);
  378. node.LowerChild.Parent = node;
  379. };
  380. var expandHigher = function(node) {
  381. node.HigherChild = makeDivisionNode(node, node.HigherStop);
  382. node.HigherChild.Parent = node;
  383. };
  384. // for this function, cumulative is a global variable
  385. var cumulative = 0.0;
  386. var labelCumulativeLength = function(node) {
  387. if(!node.LowerChild) {
  388. node.LowerStop.Cumulative = cumulative;
  389. cumulative += node.LowerInterval.Length;
  390. node.Cumulative = cumulative;
  391. } else labelCumulativeLength(node.LowerChild);
  392. if(!node.HigherChild) {
  393. node.Cumulative = cumulative;
  394. cumulative += node.HigherInterval.Length;
  395. node.HigherStop.Cumulative = cumulative;
  396. } else labelCumulativeLength(node.HigherChild);
  397. };
  398. var getIntervalFromPathLength = function(node, length) {
  399. if(length < node.Cumulative) {
  400. return node.LowerChild ? getIntervalFromPathLength(node.LowerChild, length) : node.LowerInterval;
  401. } else return node.HigherChild ? getIntervalFromPathLength(node.HigherChild, length) : node.HigherInterval;
  402. };
  403. var intervalLowerEnd = function(interval) {
  404. return interval.IsHigher ? interval.Node : interval.Node.LowerStop;
  405. };
  406. var intervalHigherEnd = function(interval) {
  407. return interval.IsHigher ? interval.Node.HigherStop : interval.Node;
  408. };
  409. var getParameterFromPathLength = function (node, length) {
  410. var interval = getIntervalFromPathLength(node, length);
  411. var lowerNode = intervalLowerEnd(interval);
  412. var higherNode = intervalHigherEnd(interval);
  413. return lowerNode.Param + (higherNode.Param - lowerNode.Param) * (length - lowerNode.Cumulative) / (higherNode.Cumulative - lowerNode.Cumulative);
  414. };
  415. var insertIntoSortedList = function (longer, shorter, toInsert) {
  416. while (true) {
  417. if (!longer) {
  418. longer = shorter;
  419. shorter = shorter.NextLongest;
  420. continue;
  421. } else if (!shorter) longer.NextLongest = toInsert;
  422. else {
  423. if (longer.Length >= toInsert.Length && shorter.Length <= toInsert.Length) {
  424. longer.NextLongest = toInsert;
  425. toInsert.NextLongest = shorter;
  426. } else {
  427. longer = shorter;
  428. shorter = shorter.NextLongest;
  429. continue;
  430. }
  431. }
  432. break;
  433. }
  434. }
  435. var head = {Param: 0.0, Position: pathFunction(0.0) };
  436. var tail = { Param: 1.0, Position: pathFunction(1.0) };
  437. var root = makeDivisionNode(head, tail);
  438. var currentCurveLength = root.LowerInterval.Length + root.HigherInterval.Length;
  439. var longestInterval;
  440. if (root.LowerInterval.Length < root.HigherInterval.Length) {
  441. longestInterval = root.HigherInterval;
  442. longestInterval.NextLongest = root.LowerInterval;
  443. } else {
  444. longestInterval = root.LowerInterval;
  445. longestInterval.NextLongest = root.HigherInterval;
  446. }
  447. while (longestInterval.Length * 100.0 > currentCurveLength) {
  448. var newNode;
  449. if (longestInterval.IsHigher) {
  450. expandHigher(longestInterval.Node);
  451. newNode = longestInterval.Node.HigherChild;
  452. } else {
  453. expandLower(longestInterval.Node);
  454. newNode = longestInterval.Node.LowerChild;
  455. }
  456. currentCurveLength += (newNode.LowerInterval.Length + newNode.HigherInterval.Length - longestInterval.Length);
  457. insertIntoSortedList(null, longestInterval, newNode.LowerInterval);
  458. insertIntoSortedList(null, longestInterval, newNode.HigherInterval);
  459. longestInterval = longestInterval.NextLongest;
  460. }
  461. labelCumulativeLength(root);
  462. return function(lengthParam) {
  463. return getParameterFromPathLength(root, lengthParam * cumulative);
  464. };
  465. }
  466. });