radialMenu.js 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /** Modified from original Node-Red source, for audio system visualization
  2. * vim: set ts=4:
  3. * Copyright 2014 IBM Corp.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. **/
  17. RED.touch = RED.touch||{};
  18. RED.touch.radialMenu = (function() {
  19. var touchMenu = null;
  20. var isActive = false;
  21. var isOutside = false;
  22. var activeOption = null;
  23. function createRadial(obj,pos,options) {
  24. isActive = true;
  25. try {
  26. var w = $("body").width();
  27. var h = $("body").height();
  28. touchMenu = d3.select("body").append("div")
  29. .style({
  30. position:"absolute",
  31. top: 0,
  32. left:0,
  33. bottom:0,
  34. right:0,
  35. "z-index": 1000
  36. })
  37. .on('touchstart',function() {
  38. hide();
  39. d3.event.preventDefault();
  40. });
  41. var menu = touchMenu.append("div")
  42. .style({
  43. position: "absolute",
  44. top: (pos[1]-80)+"px",
  45. left:(pos[0]-80)+"px",
  46. "border-radius": "80px",
  47. width: "160px",
  48. height: "160px",
  49. background: "rgba(255,255,255,0.6)",
  50. border: "1px solid #666"
  51. });
  52. var menuOpts = [];
  53. var createMenuOpt = function(x,y,opt) {
  54. opt.el = menu.append("div")
  55. .style({
  56. position: "absolute",
  57. top: (y+80-25)+"px",
  58. left:(x+80-25)+"px",
  59. "border-radius": "20px",
  60. width: "50px",
  61. height: "50px",
  62. background: "#fff",
  63. border: "2px solid #666",
  64. "text-align": "center",
  65. "line-height":"50px"
  66. });
  67. if (opt.icon) {
  68. opt.el.append("i").attr("class","icon "+opt.icon)
  69. } else {
  70. opt.el.html(opt.name);
  71. }
  72. if (opt.disabled) {
  73. opt.el.style({"border-color":"#ccc",color:"#ccc"});
  74. }
  75. opt.x = x;
  76. opt.y = y;
  77. menuOpts.push(opt);
  78. opt.el.on('touchstart',function() {
  79. opt.el.style("background","#999");
  80. d3.event.preventDefault();
  81. d3.event.stopPropagation();
  82. });
  83. opt.el.on('touchend',function() {
  84. hide();
  85. opt.onselect();
  86. d3.event.preventDefault();
  87. d3.event.stopPropagation();
  88. });
  89. }
  90. var n = options.length;
  91. var dang = Math.max(Math.PI/(n-1),Math.PI/4);
  92. var ang = Math.PI;
  93. for (var i=0;i<n;i++) {
  94. var x = Math.floor(Math.cos(ang)*80);
  95. var y = Math.floor(Math.sin(ang)*80);
  96. if (options[i].name) {
  97. createMenuOpt(x,y,options[i]);
  98. }
  99. ang += dang;
  100. }
  101. var hide = function() {
  102. isActive = false;
  103. activeOption = null;
  104. touchMenu.remove();
  105. touchMenu = null;
  106. }
  107. obj.on('touchend.radial',function() {
  108. obj.on('touchend.radial',null);
  109. obj.on('touchmenu.radial',null);
  110. if (activeOption) {
  111. try {
  112. activeOption.onselect();
  113. } catch(err) {
  114. RED._debug(err);
  115. }
  116. hide();
  117. } else if (isOutside) {
  118. hide();
  119. }
  120. });
  121. obj.on('touchmove.radial',function() {
  122. try {
  123. var touch0 = d3.event.touches.item(0);
  124. var p = [touch0.pageX - pos[0],touch0.pageY-pos[1]];
  125. for (var i=0;i<menuOpts.length;i++) {
  126. var opt = menuOpts[i];
  127. if (!opt.disabled) {
  128. if (p[0]>opt.x-30 && p[0]<opt.x+30 && p[1]>opt.y-30 && p[1]<opt.y+30) {
  129. if (opt !== activeOption) {
  130. opt.el.style("background","#999");
  131. activeOption = opt;
  132. }
  133. } else if (opt === activeOption) {
  134. opt.el.style("background","#fff");
  135. activeOption = null;
  136. } else {
  137. opt.el.style("background","#fff");
  138. }
  139. }
  140. }
  141. if (!activeOption) {
  142. var d = Math.abs((p[0]*p[0])+(p[1]*p[1]));
  143. isOutside = (d > 80*80);
  144. }
  145. } catch(err) {
  146. RED._debug(err);
  147. }
  148. });
  149. } catch(err) {
  150. RED._debug(err);
  151. }
  152. }
  153. return {
  154. show: createRadial,
  155. active: function() {
  156. return isActive;
  157. }
  158. }
  159. })();