gis_visualization.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. "use strict";
  2. /**
  3. * @fileoverview functions used for visualizing GIS data
  4. *
  5. * @requires jquery
  6. * @requires vendor/jquery/jquery.svg.js
  7. * @requires vendor/jquery/jquery.mousewheel.js
  8. */
  9. /* global drawOpenLayers */
  10. // templates/table/gis_visualization/gis_visualization.twig
  11. // Constants
  12. var zoomFactor = 1.5;
  13. var defaultX = 0;
  14. var defaultY = 0; // Variables
  15. var x = 0;
  16. var y = 0;
  17. var scale = 1;
  18. var svg;
  19. /**
  20. * Zooms and pans the visualization.
  21. */
  22. function zoomAndPan() {
  23. var g = svg.getElementById('groupPanel');
  24. if (!g) {
  25. return;
  26. }
  27. g.setAttribute('transform', 'translate(' + x + ', ' + y + ') scale(' + scale + ')');
  28. var id;
  29. var circle;
  30. $('circle.vector').each(function () {
  31. id = $(this).attr('id');
  32. circle = svg.getElementById(id);
  33. $(svg).on('change', circle, {
  34. r: 3 / scale,
  35. 'stroke-width': 2 / scale
  36. });
  37. });
  38. var line;
  39. $('polyline.vector').each(function () {
  40. id = $(this).attr('id');
  41. line = svg.getElementById(id);
  42. $(svg).on('change', line, {
  43. 'stroke-width': 2 / scale
  44. });
  45. });
  46. var polygon;
  47. $('path.vector').each(function () {
  48. id = $(this).attr('id');
  49. polygon = svg.getElementById(id);
  50. $(svg).on('change', polygon, {
  51. 'stroke-width': 0.5 / scale
  52. });
  53. });
  54. }
  55. /**
  56. * Initially loads either SVG or OSM visualization based on the choice.
  57. */
  58. function selectVisualization() {
  59. if ($('#choice').prop('checked') !== true) {
  60. $('#openlayersmap').hide();
  61. } else {
  62. $('#placeholder').hide();
  63. }
  64. }
  65. /**
  66. * Adds necessary styles to the div that contains the openStreetMap.
  67. */
  68. function styleOSM() {
  69. var $placeholder = $('#placeholder');
  70. var cssObj = {
  71. 'border': '1px solid #aaa',
  72. 'width': $placeholder.width(),
  73. 'height': $placeholder.height(),
  74. 'float': 'right'
  75. };
  76. $('#openlayersmap').css(cssObj);
  77. }
  78. /**
  79. * Loads the SVG element and make a reference to it.
  80. */
  81. function loadSVG() {
  82. var $placeholder = $('#placeholder');
  83. $placeholder.svg({
  84. onLoad: function onLoad(svgRef) {
  85. svg = svgRef;
  86. }
  87. }); // Removes the second SVG element unnecessarily added due to the above command
  88. $placeholder.find('svg').eq(1).remove();
  89. }
  90. /**
  91. * Adds controllers for zooming and panning.
  92. */
  93. function addZoomPanControllers() {
  94. var $placeholder = $('#placeholder');
  95. if ($('#placeholder').find('svg').length > 0) {
  96. var themeImagePath = $('#themeImagePath').val(); // add panning arrows
  97. $('<img class="button" id="left_arrow" src="' + themeImagePath + 'west-mini.png">').appendTo($placeholder);
  98. $('<img class="button" id="right_arrow" src="' + themeImagePath + 'east-mini.png">').appendTo($placeholder);
  99. $('<img class="button" id="up_arrow" src="' + themeImagePath + 'north-mini.png">').appendTo($placeholder);
  100. $('<img class="button" id="down_arrow" src="' + themeImagePath + 'south-mini.png">').appendTo($placeholder); // add zooming controls
  101. $('<img class="button" id="zoom_in" src="' + themeImagePath + 'zoom-plus-mini.png">').appendTo($placeholder);
  102. $('<img class="button" id="zoom_world" src="' + themeImagePath + 'zoom-world-mini.png">').appendTo($placeholder);
  103. $('<img class="button" id="zoom_out" src="' + themeImagePath + 'zoom-minus-mini.png">').appendTo($placeholder);
  104. }
  105. }
  106. /**
  107. * Resizes the GIS visualization to fit into the space available.
  108. */
  109. function resizeGISVisualization() {
  110. var $placeholder = $('#placeholder');
  111. var oldWidth = $placeholder.width();
  112. var visWidth = $('#div_view_options').width() - 48; // Assign new value for width
  113. $placeholder.width(visWidth);
  114. $('svg').attr('width', visWidth); // Assign the offset created due to resizing to defaultX and center the svg.
  115. defaultX = (visWidth - oldWidth) / 2;
  116. x = defaultX;
  117. y = 0;
  118. scale = 1;
  119. }
  120. /**
  121. * Initialize the GIS visualization.
  122. */
  123. function initGISVisualization() {
  124. // Loads either SVG or OSM visualization based on the choice
  125. selectVisualization(); // Resizes the GIS visualization to fit into the space available
  126. resizeGISVisualization();
  127. if (typeof ol !== 'undefined') {
  128. // Adds necessary styles to the div that contains the openStreetMap
  129. styleOSM();
  130. } // Loads the SVG element and make a reference to it
  131. loadSVG(); // Adds controllers for zooming and panning
  132. addZoomPanControllers();
  133. zoomAndPan();
  134. }
  135. function drawOpenLayerMap(openLayerCreate) {
  136. $('#placeholder').hide();
  137. $('#openlayersmap').show(); // Function doesn't work properly if #openlayersmap is hidden
  138. if (!openLayerCreate) {
  139. // Draws openStreetMap with openLayers
  140. drawOpenLayers();
  141. return 1;
  142. }
  143. return 0;
  144. }
  145. function getRelativeCoords(e) {
  146. var position = $('#placeholder').offset();
  147. return {
  148. x: e.pageX - position.left,
  149. y: e.pageY - position.top
  150. };
  151. }
  152. /**
  153. * Ajax handlers for GIS visualization page
  154. *
  155. * Actions Ajaxified here:
  156. *
  157. * Zooming in and zooming out on mousewheel movement.
  158. * Panning the visualization on dragging.
  159. * Zooming in on double clicking.
  160. * Zooming out on clicking the zoom out button.
  161. * Panning on clicking the arrow buttons.
  162. * Displaying tooltips for GIS objects.
  163. */
  164. /**
  165. * Unbind all event handlers before tearing down a page
  166. */
  167. AJAX.registerTeardown('table/gis_visualization.js', function () {
  168. $(document).off('click', '#choice');
  169. $(document).off('mousewheel', '#placeholder');
  170. $(document).off('dragstart', 'svg');
  171. $(document).off('mouseup', 'svg');
  172. $(document).off('drag', 'svg');
  173. $(document).off('dblclick', '#placeholder');
  174. $(document).off('click', '#zoom_in');
  175. $(document).off('click', '#zoom_world');
  176. $(document).off('click', '#zoom_out');
  177. $(document).off('click', '#left_arrow');
  178. $(document).off('click', '#right_arrow');
  179. $(document).off('click', '#up_arrow');
  180. $(document).off('click', '#down_arrow');
  181. $('.vector').off('mousemove').off('mouseout');
  182. });
  183. AJAX.registerOnload('table/gis_visualization.js', function () {
  184. var openLayerCreate = 0; // If we are in GIS visualization, initialize it
  185. if ($('#gis_div').length > 0) {
  186. initGISVisualization();
  187. }
  188. if ($('#choice').prop('checked') === true) {
  189. openLayerCreate = drawOpenLayerMap(openLayerCreate);
  190. }
  191. if (typeof ol === 'undefined') {
  192. $('#choice, #labelChoice').hide();
  193. }
  194. $(document).on('click', '#choice', function () {
  195. if ($(this).prop('checked') === false) {
  196. $('#placeholder').show();
  197. $('#openlayersmap').hide();
  198. } else {
  199. openLayerCreate = drawOpenLayerMap(openLayerCreate);
  200. }
  201. });
  202. $(document).on('mousewheel', '#placeholder', function (event, delta) {
  203. var relCoords = getRelativeCoords(event);
  204. if (delta > 0) {
  205. // zoom in
  206. scale *= zoomFactor; // zooming in keeping the position under mouse pointer unmoved.
  207. x = relCoords.x - (relCoords.x - x) * zoomFactor;
  208. y = relCoords.y - (relCoords.y - y) * zoomFactor;
  209. zoomAndPan();
  210. } else {
  211. // zoom out
  212. scale /= zoomFactor; // zooming out keeping the position under mouse pointer unmoved.
  213. x = relCoords.x - (relCoords.x - x) / zoomFactor;
  214. y = relCoords.y - (relCoords.y - y) / zoomFactor;
  215. zoomAndPan();
  216. }
  217. return true;
  218. });
  219. var dragX = 0;
  220. var dragY = 0;
  221. $('svg').draggable({
  222. helper: function helper() {
  223. return $('<div>'); // Give a fake element to be used for dragging display
  224. }
  225. });
  226. $(document).on('dragstart', 'svg', function (event, dd) {
  227. $('#placeholder').addClass('placeholderDrag');
  228. dragX = Math.round(dd.offset.left);
  229. dragY = Math.round(dd.offset.top);
  230. });
  231. $(document).on('mouseup', 'svg', function () {
  232. $('#placeholder').removeClass('placeholderDrag');
  233. });
  234. $(document).on('drag', 'svg', function (event, dd) {
  235. var newX = Math.round(dd.offset.left);
  236. x += newX - dragX;
  237. dragX = newX;
  238. var newY = Math.round(dd.offset.top);
  239. y += newY - dragY;
  240. dragY = newY;
  241. zoomAndPan();
  242. });
  243. $(document).on('dblclick', '#placeholder', function (event) {
  244. scale *= zoomFactor; // zooming in keeping the position under mouse pointer unmoved.
  245. var relCoords = getRelativeCoords(event);
  246. x = relCoords.x - (relCoords.x - x) * zoomFactor;
  247. y = relCoords.y - (relCoords.y - y) * zoomFactor;
  248. zoomAndPan();
  249. });
  250. $(document).on('click', '#zoom_in', function (e) {
  251. e.preventDefault(); // zoom in
  252. scale *= zoomFactor;
  253. var $placeholder = $('#placeholder').find('svg');
  254. var width = $placeholder.attr('width');
  255. var height = $placeholder.attr('height'); // zooming in keeping the center unmoved.
  256. x = width / 2 - (width / 2 - x) * zoomFactor;
  257. y = height / 2 - (height / 2 - y) * zoomFactor;
  258. zoomAndPan();
  259. });
  260. $(document).on('click', '#zoom_world', function (e) {
  261. e.preventDefault();
  262. scale = 1;
  263. x = defaultX;
  264. y = defaultY;
  265. zoomAndPan();
  266. });
  267. $(document).on('click', '#zoom_out', function (e) {
  268. e.preventDefault(); // zoom out
  269. scale /= zoomFactor;
  270. var $placeholder = $('#placeholder').find('svg');
  271. var width = $placeholder.attr('width');
  272. var height = $placeholder.attr('height'); // zooming out keeping the center unmoved.
  273. x = width / 2 - (width / 2 - x) / zoomFactor;
  274. y = height / 2 - (height / 2 - y) / zoomFactor;
  275. zoomAndPan();
  276. });
  277. $(document).on('click', '#left_arrow', function (e) {
  278. e.preventDefault();
  279. x += 100;
  280. zoomAndPan();
  281. });
  282. $(document).on('click', '#right_arrow', function (e) {
  283. e.preventDefault();
  284. x -= 100;
  285. zoomAndPan();
  286. });
  287. $(document).on('click', '#up_arrow', function (e) {
  288. e.preventDefault();
  289. y += 100;
  290. zoomAndPan();
  291. });
  292. $(document).on('click', '#down_arrow', function (e) {
  293. e.preventDefault();
  294. y -= 100;
  295. zoomAndPan();
  296. });
  297. /**
  298. * Detect the mousemove event and show tooltips.
  299. */
  300. $('.vector').on('mousemove', function (event) {
  301. var contents = Functions.escapeHtml($(this).attr('name')).trim();
  302. $('#tooltip').remove();
  303. if (contents !== '') {
  304. $('<div id="tooltip">' + contents + '</div>').css({
  305. position: 'absolute',
  306. top: event.pageY + 10,
  307. left: event.pageX + 10,
  308. border: '1px solid #fdd',
  309. padding: '2px',
  310. 'background-color': '#fee',
  311. opacity: 0.90
  312. }).appendTo('body').fadeIn(200);
  313. }
  314. });
  315. /**
  316. * Detect the mouseout event and hide tooltips.
  317. */
  318. $('.vector').on('mouseout', function () {
  319. $('#tooltip').remove();
  320. });
  321. });