skill_wheel.js.tpl 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. {# topbar #}
  2. {% include app.template_style ~ "/layout/topbar.tpl" %}
  3. <script>
  4. /* Skill wheel settings */
  5. var debug = true;
  6. var url = '{{ url }}';
  7. var skill_to_load_from_get = '{{ skill_id_to_load }}';
  8. //Just in case we want to use it
  9. var main_depth = 4;
  10. var main_parent_id = 0;
  11. // Used to split in two word or not
  12. var max_size_text_length = 11;
  13. /* ColorBrewer settings */
  14. var my_domain = [1,2,3,4,5,6,7,8,9];
  15. var col = 9;
  16. var color_patterns = [];
  17. /*
  18. See colorbrewer documentation
  19. color_patterns[1] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.Blues[col]);
  20. color_patterns[2] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.Purples[col]);
  21. color_patterns[2] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.Blues[6]);
  22. color_patterns[3] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.Greens[col]);
  23. color_patterns[4] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.Reds[col]);
  24. color_patterns[5] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.Oranges[col]);
  25. color_patterns[6] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.YlOrBr[col]);
  26. color_patterns[7] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.YlGn[col]);
  27. color_patterns[8] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.YlGnBu[col]);
  28. color_patterns[9] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.GnBu[col]);
  29. color_patterns[10] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.BuGn[col]);
  30. color_patterns[11] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.PuBuGn[col]);
  31. color_patterns[12] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.PuBu[col]);
  32. color_patterns[13] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.BuPu[col]);
  33. color_patterns[14] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.RdPu[col]);
  34. color_patterns[15] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.PuRd[col]);
  35. color_patterns[16] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.OrRd[col]);
  36. color_patterns[17] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.YlOrRd[col]);*/
  37. //Too make the gray tones lighter
  38. col = 3;
  39. color_patterns[18] = d3.scale.ordinal().domain(my_domain).range(colorbrewer.Greys[col]);
  40. //If you want to use the category10()
  41. //var normal_fill = d3.scale.category10().domain(my_domain);
  42. //First 8 colors
  43. var colors = $.xcolor.analogous('#da0'); //8 colors
  44. //How long will be the array of colors?
  45. var color_loops = 4;
  46. // Generating array of colors thanks to the "$.xcolor.analogous" function we can create a rainbow style!
  47. for (i= 0; i < color_loops; i++) {
  48. //Getting the latest color hex of the 8 colors loaded
  49. last_color = colors[colors.length-1].getHex();
  50. //Getting the complementary
  51. glue_color = $.xcolor.complementary(last_color);
  52. //Generating 8 more colors
  53. temp_color_array = $.xcolor.analogous(glue_color);
  54. //Adding the color to the main array
  55. colors = $.merge(colors, temp_color_array);
  56. }
  57. /* The partiton name will have 1 or 2 lines? */
  58. function is_multiline(word) {
  59. if (word) {
  60. if (word.length > max_size_text_length) {
  61. return (word).split(" ").length > 1;
  62. }
  63. }
  64. return false;
  65. }
  66. /* Interpolate the scales! */
  67. function arcTween(d, arc, x, y, r) {
  68. var my = maxY(d),
  69. xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
  70. yd = d3.interpolate(y.domain(), [d.y, my]),
  71. yr = d3.interpolate(y.range(), [d.y ? 20 : 0, r]);
  72. return function(d) {
  73. return function(t) {
  74. x.domain(xd(t));
  75. y.domain(yd(t)).range(yr(t));
  76. return arc(d);
  77. };
  78. };
  79. }
  80. /* Calculate maxY */
  81. function maxY(d) {
  82. return d.children ? Math.max.apply(Math, d.children.map(maxY)) : d.y + d.dy;
  83. }
  84. /* Use a formula for contrasting colour
  85. http://www.w3.org/WAI/ER/WD-AERT/#color-contrast
  86. */
  87. function brightness(rgb) {
  88. return rgb.r * .299 + rgb.g * .587 + rgb.b * .114;
  89. }
  90. /* Returns whether p is parent of c */
  91. function isParentOf(p, c) {
  92. if (p === c) return true;
  93. if (p.children) {
  94. return p.children.some(function(d) {
  95. return isParentOf(d, c);
  96. });
  97. }
  98. return false;
  99. }
  100. function get_color(d) {
  101. depth = d.depth;
  102. if (d.family_id) {
  103. /*var p = color_patterns[d.family_id];
  104. color = p(depth -1 + d.counter);
  105. d.color = color;*/
  106. if (depth > 1) {
  107. family1 = colors[d.family_id];
  108. family2 = colors[d.family_id + 2];
  109. position = d.depth*d.counter;
  110. //part_color = $.xcolor.gradientlevel(family1, family2, position, 100);
  111. part_color = $.xcolor.lighten(family1, position, 15);
  112. color = part_color.getHex();
  113. //console.log(d.depth + " - " + d.name + " + "+ color+ "+ " +d.counter);
  114. } else {
  115. color = colors[d.family_id];
  116. }
  117. return color;
  118. }
  119. color = '#fefefe';
  120. return color; //missing colors
  121. }
  122. /*
  123. gray tones for all skills that have no particular property ("Basic skills wheel" view)
  124. yellow tones for skills that are provided by courses in Chamilo ("Teachable skills" view)
  125. bright blue tones for personal skills already acquired by the student currently looking at the weel ("My skills" view)
  126. dark blue tones for skills already acquired by a series of students, when looking at the will in the "Owned skills" view.
  127. bright green for skills looked for by a HR director ("Profile search" view)
  128. dark green for skills most searched for, summed up from the different saved searches from HR directors ("Most wanted skills")
  129. bright red for missing skills, in the "Required skills" view for a student when looking at the "Most wanted skills" (or later, when we will have developed that, for the "Matching position" view)
  130. */
  131. /**
  132. Manage the partition background colors
  133. **/
  134. function set_skill_style(d, attribute, searched_skill_id) {
  135. //Default border color (stroke)
  136. return_stroke = 'black';
  137. //0. Nice rainbow colors (Comment 1.0 to see the rainbow!)
  138. return_fill = get_color(d);
  139. //1. Grey colors using colorbrewer
  140. var p = color_patterns[18];
  141. color = p(depth -1 + d.counter);
  142. return_fill = color;
  143. //2. Yellow - If the skill has a gradebook attached
  144. if (d.skill_has_gradebook) {
  145. return_fill = '#F89406';
  146. //return_stroke = 'grey';
  147. }
  148. //3. Red - if you search that skill
  149. if (searched_skill_id) {
  150. if (d.id == searched_skill_id) {
  151. return_fill = '#B94A48';
  152. }
  153. }
  154. //4. Blue - if user achieved that skill
  155. if (d.achieved) {
  156. return_fill = '#3A87AD';
  157. //return_stroke = '#FCD23A';
  158. }
  159. switch (attribute) {
  160. case 'fill':
  161. //In order to identify the color of the text (white, black) used in other function
  162. d.color = return_fill;
  163. return return_fill;
  164. break;
  165. case 'stroke':
  166. return return_stroke;
  167. break;
  168. }
  169. }
  170. /* When you click a skill partition */
  171. function click_partition(d, path, text, icon, arc, x, y, r, p, vis) {
  172. //console.log(d.depth);
  173. if (debug) {
  174. console.log('Clicking a partition skill id: '+d.id);
  175. console.log(d);
  176. console.log('real parent_id: '+d.real_parent_id + ' parent_id: ' +d.parent_id);
  177. console.log('depth ' + d.depth);
  178. console.log('main_depth ' + main_depth);
  179. console.log('main_parent_id: ' + main_parent_id);
  180. }
  181. if (d.depth >= main_depth) {
  182. //main_depth += main_depth;
  183. if (main_parent_id) {
  184. load_nodes(main_parent_id, main_depth);
  185. } else {
  186. load_nodes(d.id, main_depth);
  187. }
  188. }
  189. if (d.id) {
  190. console.log('Getting skill info');
  191. skill_info = get_skill_info(d.parent_id);
  192. console.log(skill_info);
  193. main_parent_id = skill_info.extra.parent_id;
  194. main_parent_id = d.parent_id;
  195. console.log('Setting main_parent_id: ' + main_parent_id);
  196. }
  197. //console.log(main_parent_id);
  198. /* "No id" means that we reach the center of the wheel go to the root*/
  199. if (!d.id) {
  200. load_nodes(main_parent_id, main_depth);
  201. }
  202. if (debug) console.log('Continue to click_partition');
  203. //console.log(main_parent_id);
  204. //Duration of the transition
  205. var duration = 1000;
  206. path.transition()
  207. .duration(duration)
  208. .attrTween("d", arcTween(d, arc, x, y, r));
  209. /* Updating text position */
  210. // Somewhat of a hack as we rely on arcTween updating the scales.
  211. text.style("visibility", function(e) {
  212. return isParentOf(d, e) ? null : d3.select(this).style("visibility");
  213. })
  214. .transition().duration(duration)
  215. .attrTween("text-anchor", function(d) {
  216. return function() {
  217. return x(d.x + d.dx / 2) > Math.PI ? "end" : "start";
  218. };
  219. })
  220. .attrTween("transform", function(d) {
  221. var multiline = is_multiline(d.name); //(d.name || "").split(" ").length > 1;
  222. return function() {
  223. var angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,
  224. rotate = angle + (multiline ? -.5 : 0);
  225. return "rotate(" + rotate + ")translate(" + (y(d.y) + p) + ")rotate(" + (angle > 90 ? -180 : 0) + ")";
  226. };
  227. })
  228. .style("fill-opacity", function(e) {
  229. return isParentOf(d, e) ? 1 : 1e-6;
  230. })
  231. .each("end", function(e) {
  232. d3.select(this).style("visibility", isParentOf(d, e) ? null : "hidden");
  233. });
  234. //Add an icon in the partition
  235. /* Updating icon position */
  236. /*
  237. icon.transition().duration(duration)
  238. .attrTween("text-anchor", function(d) {
  239. return function() {
  240. return x(d.x + d.dx / 2) > Math.PI ? "end" : "start";
  241. };
  242. })
  243. .attrTween("transform", function(d) {
  244. return function() {
  245. var angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,
  246. rotate = angle;
  247. return "rotate(" + rotate + ")translate(" + (y(d.y) + p) + ")rotate(" + (angle > 90 ? -180 : 0) + ")";
  248. };
  249. })
  250. .style("fill-opacity", function(e) {
  251. //return isParentOf(d, e) ? 1 : 1e-6;
  252. })
  253. .each("end", function(e) {
  254. //d3.select(this).style("visibility", isParentOf(d, e) ? null : "hidden");
  255. });*/
  256. }
  257. /*
  258. Open a popup in order to modify the skill
  259. */
  260. function open_popup(skill_id, parent_id) {
  261. //Cleaning selects
  262. $("#gradebook_id").find('option').remove();
  263. $("#parent_id").find('option').remove();
  264. //Cleaning lists
  265. $("#gradebook_holder").find('li').remove();
  266. $("#skill_edit_holder").find('li').remove();
  267. var skill = false;
  268. if (skill_id) {
  269. skill = get_skill_info(skill_id);
  270. }
  271. var parent = false;
  272. if (parent_id) {
  273. parent = get_skill_info(parent_id);
  274. }
  275. if (skill) {
  276. var parent_info = get_skill_info(skill.extra.parent_id);
  277. $("#id").attr('value', skill.id);
  278. $("#name").attr('value', skill.name);
  279. $("#short_code").attr('value', skill.short_code);
  280. $("#description").attr('value', skill.description);
  281. //Filling parent_id
  282. $("#parent_id").append('<option class="selected" value="'+skill.extra.parent_id+'" selected="selected" >');
  283. $("#skill_edit_holder").append('<li class="bit-box">'+parent_info.name+'</li>');
  284. //Filling the gradebook_id
  285. jQuery.each(skill.gradebooks, function(index, data) {
  286. $("#gradebook_id").append('<option class="selected" value="'+data.id+'" selected="selected" >');
  287. $("#gradebook_holder").append('<li id="gradebook_item_'+data.id+'" class="bit-box">'+data.name+' <a rel="'+data.id+'" class="closebutton" href="#"></a> </li>');
  288. });
  289. $("#dialog-form").dialog({
  290. buttons: {
  291. "{{ "Edit"|get_lang }}" : function() {
  292. var params = $("#add_item").find(':input').serialize();
  293. add_skill(params);
  294. },
  295. /*"{{ "Delete"|get_lang }}" : function() {
  296. },*/
  297. "{{ "CreateChildSkill"|get_lang }}" : function() {
  298. open_popup(0, skill.id);
  299. },
  300. "{{ "AddSkillToProfileSearch"|get_lang }}" : function() {
  301. add_skill_in_profile_list(skill.id, skill.name);
  302. }
  303. },
  304. close: function() {
  305. $("#name").attr('value','');
  306. $("#description").attr('value', '');
  307. //Redirect to the main root
  308. load_nodes(0, main_depth);
  309. }
  310. });
  311. $("#dialog-form").dialog("open");
  312. }
  313. if (parent) {
  314. $("#id").attr('value','');
  315. $("#name").attr('value', '');
  316. $("#short_code").attr('value', '');
  317. $("#description").attr('value', '');
  318. //Filling parent_id
  319. $("#parent_id").append('<option class="selected" value="'+parent.id+'" selected="selected" >');
  320. $("#skill_edit_holder").append('<li class="bit-box">'+parent.name+'</li>');
  321. //Filling the gradebook_id
  322. jQuery.each(parent.gradebooks, function(index, data) {
  323. $("#gradebook_id").append('<option class="selected" value="'+data.id+'" selected="selected" >');
  324. $("#gradebook_holder").append('<li id="gradebook_item_'+data.id+'" class="bit-box">'+data.name+' <a rel="'+data.id+'" class="closebutton" href="#"></a> </li>');
  325. });
  326. $("#dialog-form").dialog({
  327. buttons: {
  328. "{{ "Save"|get_lang }}" : function() {
  329. var params = $("#add_item").find(':input').serialize();
  330. add_skill(params);
  331. }
  332. },
  333. close: function() {
  334. $("#name").attr('value', '');
  335. $("#description").attr('value', '');
  336. load_nodes(0, main_depth);
  337. }
  338. });
  339. $("#dialog-form").dialog("open");
  340. }
  341. return false;
  342. }
  343. /* Handles mouse clicks */
  344. function handle_mousedown_event(d, path, text, icon, arc, x, y, r, padding, vis) {
  345. switch (d3.event.which) {
  346. case 1:
  347. //alert('Left mouse button pressed');
  348. click_partition(d, path, text, icon, arc, x, y, r, padding, vis);
  349. break;
  350. case 2:
  351. //alert('Middle mouse button pressed');
  352. break;
  353. case 3:
  354. open_popup(d.id);
  355. //alert('Right mouse button pressed');
  356. break;
  357. default:
  358. //alert('You have a strange mouse :D '); //
  359. }
  360. }
  361. /*
  362. Loads the skills partitions thanks to a json call
  363. */
  364. function load_nodes(load_skill_id, main_depth, extra_parent_id) {
  365. if (debug) {
  366. console.log('Load nodes ----->');
  367. console.log('Loading skill id: '+load_skill_id+' with depth ' + main_depth);
  368. console.log('main_parent_id before: ' + main_parent_id);
  369. }
  370. //"Root partition" on click switch
  371. if (main_parent_id && load_skill_id) {
  372. skill_info = get_skill_info(load_skill_id);
  373. if (skill_info && skill_info.extra) {
  374. main_parent_id = skill_info.extra.parent_id;
  375. } else {
  376. main_parent_id = 0;
  377. }
  378. console.log('main_parent_id after: ' + main_parent_id);
  379. }
  380. if (load_skill_id && load_skill_id == 1) {
  381. main_parent_id = 0;
  382. }
  383. /** Define constants and size of the wheel */
  384. /** Total width of the wheel (also counts for the height) */
  385. var w = 900,
  386. h = w,
  387. r = w / 2,
  388. /** x/y positionning of the center of the wheel */
  389. x = d3.scale.linear().range([0, 2 * Math.PI]),
  390. y = d3.scale.pow().exponent(1.1).domain([0, 1]).range([0, r]),
  391. /** Padding in pixels before the string starts */
  392. padding = 3,
  393. /** Levels to show */
  394. levels_to_show = 3;
  395. reduce_top = 1;
  396. /* Locate the #div id element */
  397. $("#skill_wheel").remove();
  398. $("#wheel_container").html('');
  399. $("#wheel_container").append('<div id="skill_wheel"></div>');
  400. var div = d3.select("#skill_wheel");
  401. /* Remove the image (make way for the dynamic stuff */
  402. div.select("img").remove();
  403. /* Append an element "svg" to the #vis section */
  404. var vis = div.append("svg")
  405. //.attr("class", "Blues")
  406. .attr("width", w + padding * 2)
  407. .attr("height", h + padding * 2)
  408. .append("g")
  409. .attr("transform", "translate(" + (r + padding) + "," + (r/reduce_top + padding) + ")");
  410. /* ...update translate variables to change coordinates of wheel's center */
  411. /* Add a small label to help the user */
  412. div.append("p")
  413. .attr("id", "intro")
  414. .text("{{ "ClickToZoom"|get_lang }}");
  415. /* Generate the partition layout */
  416. var partition = d3.layout.partition()
  417. .sort(null)
  418. /** Value here seems to be a calculation of the size of the elements
  419. depending on the level of depth they're at. Changing it makes
  420. elements pass over the limits of others... */
  421. //.size([1, 2])
  422. .value(function(d) {
  423. //return 5.8 - d.depth;
  424. //When having more than 4 children seems that the code above doesn't work
  425. return 1;
  426. });
  427. /* Generate an arc which will define the whole wheel context */
  428. var arc = d3.svg.arc()
  429. .startAngle(function(d) {
  430. return Math.max(0, Math.min(2 * Math.PI, x(d.x)));
  431. })
  432. .endAngle(function(d) {
  433. return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx)));
  434. })
  435. .innerRadius(function(d) {
  436. return Math.max(0, d.y ? y(d.y) : d.y);
  437. })
  438. .outerRadius(function(d) {
  439. return Math.max(0, y(d.y + d.dy));
  440. });
  441. load_skill_condition = '';
  442. //First the $_GET value
  443. if (skill_to_load_from_get != 0) {
  444. load_skill_condition = 'skill_id=' + skill_to_load_from_get;
  445. }
  446. //The JS load
  447. if (load_skill_id != 0) {
  448. load_skill_condition = 'skill_id=' + load_skill_id;
  449. }
  450. d3.json("{{ wheel_url }}&main_depth="+main_depth+"&"+load_skill_condition, function(json) {
  451. /** Define the list of nodes based on the JSON */
  452. var nodes = partition.nodes({
  453. children: json
  454. });
  455. /* Setting all skills */
  456. var path = vis.selectAll("path").data(nodes);
  457. /* Setting all texts */
  458. var text = vis.selectAll("text").data(nodes);
  459. /* Setting icons */
  460. var icon = vis.selectAll("icon").data(nodes);
  461. /* Path settings */
  462. path.enter().append("path")
  463. .attr("id", function(d, i) {
  464. return "path-" + i;
  465. })
  466. .attr("d", arc)
  467. .attr("fill-rule", "evenodd")
  468. .attr("class", "skill_partition skill_background")
  469. // .style("fill", colour)
  470. .style("fill", function(d) {
  471. return set_skill_style(d, 'fill', load_skill_id);
  472. })
  473. .style("stroke", function(d) {
  474. return set_skill_style(d, 'stroke');
  475. })
  476. .on("mouseover", function(d, i) {
  477. //$("#icon-" + i).show();
  478. })
  479. .on("mouseout", function(d, i) {
  480. //$("#icon-" + i).hide();
  481. })
  482. .on("contextmenu", function(d, i) {
  483. //Handles mouse clicks
  484. handle_mousedown_event(d, path, text, icon, arc, x, y, r, padding, vis);
  485. //Blocks "right click menu"
  486. d3.event.preventDefault();
  487. return false;
  488. })
  489. .on("mousedown", function(d, i) {
  490. })
  491. .on("click", function(d) {
  492. //Simple click
  493. handle_mousedown_event(d, path, text, icon, arc, x, y, r, padding, vis);
  494. });
  495. /*//Redefine the root
  496. path_zero = vis.selectAll("#path-0").on("mousedown", function(d){
  497. d = get_skill_info(extra_parent_id);
  498. d.parent_id = d.extra.parent_id;
  499. click_partition(d, path, text, icon, arc, x, y, r, padding, vis);
  500. });*/
  501. /* End setting skills */
  502. /* Text settings */
  503. var textEnter = text.enter().append("text")
  504. .style("fill-opacity", 1)
  505. .style("fill", function(d) {
  506. return brightness(d3.rgb(d.color)) < 125 ? "#eee" : "#000";
  507. })
  508. .attr("text-anchor", function(d) {
  509. return x(d.x + d.dx / 2) > Math.PI ? "end" : "start";
  510. })
  511. .attr("rel", "tooltip_skill")
  512. .attr("title", function(d) {
  513. return d.name;
  514. })
  515. .attr("dy", ".2em")
  516. .attr("transform", function(d) {
  517. /** Get the text details and define the rotation and general position */
  518. var multiline = is_multiline(d.name); //(d.name || "").split(" ").length > 1,
  519. angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,
  520. rotate = angle + (multiline ? -.5 : 0);
  521. return "rotate(" + rotate + ")translate(" + (y(d.y) + padding) + ")rotate(" + (angle > 90 ? -180 : 0) + ")";
  522. })
  523. .on("mouseover", function(d, i) {
  524. //$("#icon-" + i).show();
  525. })
  526. .on("mouseout", function(d, i) {
  527. //$("#icon-" + i).hide();
  528. })
  529. .on("contextmenu", function(d, i) {
  530. handle_mousedown_event(d, path, text, icon, arc, x, y, r, padding, vis);
  531. d3.event.preventDefault();
  532. })
  533. .on("mousedown", function(d, i) {
  534. })
  535. .on("click", function(d) {
  536. handle_mousedown_event(d, path, text, icon, arc, x, y, r, padding, vis);
  537. });
  538. /** Managing text - maximum two words */
  539. var insert_two_words = false;
  540. textEnter.append("tspan")
  541. .attr("x", 0)
  542. .text(function(d) {
  543. if (d.depth && d.name.length > max_size_text_length) {
  544. if (d.depth) {
  545. first_part = d.name.split(" ")[0];
  546. second_part = d.name.split(" ")[1];
  547. if (first_part.length >= max_size_text_length) {
  548. insert_two_words = false;
  549. return first_part.substring(0, max_size_text_length -3) + ' ... ';
  550. } else {
  551. return first_part;
  552. }
  553. } else {
  554. return "";
  555. }
  556. } else {
  557. insert_two_words = false;
  558. return d.depth ? d.name : "";
  559. }
  560. });
  561. if (insert_two_words) {
  562. textEnter.append("tspan")
  563. .attr("x", 0)
  564. .attr("dy", "1em")
  565. .text(function(d) {
  566. return d.depth && d.name.length > max_size_text_length ? d.name.split(" ")[1] || "" : "";
  567. });
  568. }
  569. /* Icon settings */
  570. /*
  571. var icon_click = icon.enter().append("text")
  572. .style("fill-opacity", 1)
  573. .style("fill", function(d) {
  574. //return "#000";
  575. })
  576. .attr("text-anchor", function(d) {
  577. return x(d.x + d.dx / 2) > Math.PI ? "end" : "start";
  578. })
  579. .attr("dy", ".2em")
  580. .attr("transform", function(d) {
  581. ///Get the text details and define the rotation and general position
  582. angle = x(d.x + d.dx / 2) * 180 / Math.PI - 90,
  583. rotate = angle;
  584. return "rotate(" + rotate + ")translate(" + (y(d.y) + padding +80) + ")rotate(" + (angle > 90 ? -180 : 0) + ")";
  585. })
  586. .on("click", function(d){
  587. open_popup(d);
  588. });
  589. icon_click.append("tspan")
  590. .attr("id", function(d, i) {
  591. return "icon-" + i;
  592. })
  593. .attr("x", 0)
  594. .attr("display", 'none')
  595. .text(function(d) {
  596. //return "Click";
  597. });*/
  598. });
  599. if (debug) {
  600. console.log('<------ End load nodes ----->');
  601. }
  602. }
  603. /* Skill AJAX calls */
  604. function get_skill_info(my_id) {
  605. var skill = false;
  606. $.ajax({
  607. url: url+'&a=get_skill_info&id='+my_id,
  608. async: false,
  609. success: function(json) {
  610. skill = jQuery.parseJSON(json);
  611. return skill;
  612. }
  613. });
  614. return skill;
  615. }
  616. function get_gradebook_info(id) {
  617. var item = false;
  618. $.ajax({
  619. url: url+'&a=get_gradebook_info&id='+id,
  620. async: false,
  621. success: function(json) {
  622. item = jQuery.parseJSON(json);
  623. return item;
  624. }
  625. });
  626. return item;
  627. }
  628. $(document).ready(function() {
  629. });
  630. </script>