math.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  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('WidgetWidth'));
  126. tempBoundingRect.height = Number(element.getAttribute('WidgetHeight'));
  127. } else {
  128. tempBoundingRect = element.getBoundingClientRect();
  129. var jElement = $(element);
  130. position = jElement.position();
  131. if(jElement.css('position') == 'fixed') {
  132. position.left += Number(jElement.css('margin-left').replace("px", ""));
  133. position.top += Number(jElement.css('margin-top').replace("px", ""));
  134. }
  135. }
  136. var layers = $ax('#' + widgetId).getParents(true, ['layer'])[0];
  137. var flip = '';
  138. var mirrorWidth = 0;
  139. var mirrorHeight = 0;
  140. for (var i = 0; i < layers.length; i++) {
  141. //should always be 0,0
  142. var layerPos = $jobj(layers[i]).position();
  143. position.left += layerPos.left;
  144. position.top += layerPos.top;
  145. var outer = $ax.visibility.applyWidgetContainer(layers[i], true, true);
  146. if (outer.length) {
  147. var outerPos = outer.position();
  148. position.left += outerPos.left;
  149. position.top += outerPos.top;
  150. }
  151. //when a group is flipped we find the unflipped position
  152. var inner = $jobj(layers[i] + '_container_inner');
  153. var taggedFlip = inner.data('flip');
  154. if (inner.length && taggedFlip) {
  155. //only account for flip if transform is applied
  156. var matrix = taggedFlip && (inner.css("-webkit-transform") || inner.css("-moz-transform") ||
  157. inner.css("-ms-transform") || inner.css("-o-transform") || inner.css("transform"));
  158. if (matrix !== 'none') {
  159. flip = taggedFlip;
  160. mirrorWidth = $ax.getNumFromPx(inner.css('width'));
  161. mirrorHeight = $ax.getNumFromPx(inner.css('height'));
  162. }
  163. }
  164. }
  165. //Now account for flip
  166. if (flip == 'x') position.top = mirrorHeight - position.top - element.getBoundingClientRect().height;
  167. else if (flip == 'y') position.left = mirrorWidth - position.left - element.getBoundingClientRect().width;
  168. boundingRect = {
  169. left: position.left,
  170. right: position.left + tempBoundingRect.width,
  171. top: position.top,
  172. bottom: position.top + tempBoundingRect.height
  173. };
  174. _displayHackEnd(displayChanged);
  175. if (justSides) return boundingRect;
  176. boundingRect.width = boundingRect.right - boundingRect.left;
  177. boundingRect.height = boundingRect.bottom - boundingRect.top;
  178. boundingRect.centerPoint = {
  179. x: boundingRect.width / 2 + boundingRect.left,
  180. y: boundingRect.height / 2 + boundingRect.top
  181. };
  182. return boundingRect;
  183. };
  184. var _getPointAfterRotate = $ax.public.fn.getPointAfterRotate = function (angleInDegrees, pointToRotate, centerPoint) {
  185. var displacement = $ax.public.fn.vectorMinus(pointToRotate, centerPoint);
  186. var rotationMatrix = $ax.public.fn.rotationMatrix(angleInDegrees);
  187. rotationMatrix.tx = centerPoint.x;
  188. rotationMatrix.ty = centerPoint.y;
  189. return $ax.public.fn.matrixMultiply(rotationMatrix, displacement);
  190. };
  191. $ax.public.fn.getBoundingSizeForRotate = function(width, height, rotation) {
  192. // point to rotate around doesn't matter since we just care about size, if location matter we need more args and location matters.
  193. var origin = { x: 0, y: 0 };
  194. var corner1 = { x: width, y: 0 };
  195. var corner2 = { x: 0, y: height };
  196. var corner3 = { x: width, y: height };
  197. corner1 = _getPointAfterRotate(rotation, corner1, origin);
  198. corner2 = _getPointAfterRotate(rotation, corner2, origin);
  199. corner3 = _getPointAfterRotate(rotation, corner3, origin);
  200. var left = Math.min(0, corner1.x, corner2.x, corner3.x);
  201. var right = Math.max(0, corner1.x, corner2.x, corner3.x);
  202. var top = Math.min(0, corner1.y, corner2.y, corner3.y);
  203. var bottom = Math.max(0, corner1.y, corner2.y, corner3.y);
  204. return { width: right - left, height: bottom - top };
  205. }
  206. $ax.public.fn.getPositionRelativeToParent = function (elementId) {
  207. var element = document.getElementById(elementId);
  208. var list = _displayHackStart(element);
  209. var position = $(element).position();
  210. _displayHackEnd(list);
  211. return position;
  212. };
  213. var _displayHackStart = $ax.public.fn.displayHackStart = function (element) {
  214. // TODO: Options: 1) stop setting display none. Big change for this late in the game. 2) Implement our own bounding.
  215. // 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.
  216. var parent = element;
  217. var displays = [];
  218. while (parent) {
  219. if (parent.style.display == 'none') {
  220. displays.push(parent);
  221. //use block to overwrites default hidden objects' display
  222. parent.style.display = 'block';
  223. }
  224. parent = parent.parentElement;
  225. }
  226. return displays;
  227. };
  228. var _displayHackEnd = $ax.public.fn.displayHackEnd = function (displayChangedList) {
  229. for (var i = 0; i < displayChangedList.length; i++) displayChangedList[i].style.display = 'none';
  230. };
  231. var _isCompoundVectorHtml = $ax.public.fn.isCompoundVectorHtml = function(hElement) {
  232. return hElement.hasAttribute('compoundmode') && hElement.getAttribute('compoundmode') == "true";
  233. }
  234. $ax.public.fn.removeCompound = function (jobj) { if(_isCompoundVectorHtml(jobj[0])) jobj.removeClass('compound'); }
  235. $ax.public.fn.restoreCompound = function (jobj) { if (_isCompoundVectorHtml(jobj[0])) jobj.addClass('compound'); }
  236. $ax.public.fn.compoundIdFromComponent = function(id) {
  237. var pPos = id.indexOf('p');
  238. var dashPos = id.indexOf('-');
  239. if (pPos < 1) return id;
  240. else if (dashPos < 0) return id.substring(0, pPos);
  241. else return id.substring(0, pPos) + id.substring(dashPos);
  242. }
  243. $ax.public.fn.l2 = function (x, y) { return Math.sqrt(x * x + y * y); }
  244. $ax.public.fn.convertToSingleImage = function (jobj) {
  245. if(!jobj[0]) return;
  246. var widgetId = jobj[0].id;
  247. var object = $obj(widgetId);
  248. if ($ax.public.fn.IsLayer(object.type)) {
  249. var recursiveChildren = _getLayerChildrenDeep(widgetId, true);
  250. for (var j = 0; j < recursiveChildren.length; j++)
  251. $ax.public.fn.convertToSingleImage($jobj(recursiveChildren[j]));
  252. return;
  253. }
  254. //var layer =
  255. if(!_isCompoundVectorHtml(jobj[0])) return;
  256. $('#' + widgetId).removeClass("compound");
  257. $('#' + widgetId + '_img').removeClass("singleImg");
  258. jobj[0].setAttribute('compoundmode', 'false');
  259. var components = object.compoundChildren;
  260. delete object.generateCompound;
  261. for (var i = 0; i < components.length; i++) {
  262. var componentJobj = $jobj($ax.public.fn.getComponentId(widgetId, components[i]));
  263. componentJobj.css('display', 'none');
  264. componentJobj.css('visibility', 'hidden');
  265. }
  266. }
  267. $ax.public.fn.getContainerDimensions = function(query) {
  268. // returns undefined if no containers found.
  269. var containerDimensions;
  270. for (var i = 0; i < query[0].children.length; i++) {
  271. var node = query[0].children[i];
  272. if (node.id.indexOf(query[0].id) >= 0 && node.id.indexOf('container') >= 0) {
  273. containerDimensions = node.style;
  274. }
  275. }
  276. return containerDimensions;
  277. }
  278. $ax.public.fn.rotationMatrix = function (angleInDegrees) {
  279. var angleInRadians = angleInDegrees * (Math.PI / 180);
  280. var cosTheta = Math.cos(angleInRadians);
  281. var sinTheta = Math.sin(angleInRadians);
  282. return { m11: cosTheta, m12: -sinTheta, m21: sinTheta, m22: cosTheta, tx: 0.0, ty: 0.0 };
  283. }
  284. $ax.public.fn.GetFieldFromStyle = function (query, field) {
  285. var raw = query[0].style[field];
  286. if (!raw) raw = query.css(field);
  287. return Number(raw.replace('px', ''));
  288. }
  289. $ax.public.fn.setTransformHowever = function (transformString) {
  290. return {
  291. '-webkit-transform': transformString,
  292. '-moz-transform': transformString,
  293. '-ms-transform': transformString,
  294. '-o-transform': transformString,
  295. 'transform': transformString
  296. };
  297. }
  298. });