1 import "../legacy/d3/d3v4Min.js";
2 import "../legacy/jquery.js";
3 import "../legacy/brapi/BrAPI.js";
5 // Colors to use when labelling multiple trials
18 const trial_colors_text = [
31 export function init() {
33 constructor(trial_id) {
34 this.trial_id = String;
35 this.plot_arr = Array;
36 this.plot_object = Object;
38 this.brapi_plots = Object;
39 this.heatmap_queried = false;
40 this.heatmap_selected = false;
41 this.heatmap_selection = String;
42 this.heatmap_object = Object;
43 this.display_borders = true;
44 this.linked_trials = {};
48 this.trial_id = trial_id;
51 set_linked_trials(trials = []) {
52 this.linked_trials = {};
53 trials.forEach((t, i) => {
54 const index = i % trial_colors.length;
55 this.linked_trials[t.trial_name] = {
58 bg: trial_colors[index],
59 fg: trial_colors_text[index],
65 return this.linked_trials;
68 format_brapi_post_object() {
69 let brapi_post_plots = [];
71 for (let plot of this.plot_arr.filter((plot) => plot.type == "filler")) {
72 brapi_post_plots.push({
74 invert_row_checkmark: document.getElementById(
75 "invert_row_checkmark"
77 top_border_selection: this.meta_data.top_border_selection || false,
78 left_border_selection:
79 this.meta_data.left_border_selection || false,
80 right_border_selection:
81 this.meta_data.right_border_selection || false,
82 bottom_border_selection:
83 this.meta_data.bottom_border_selection || false,
84 plot_layout: this.meta_data.plot_layout || "serpentine",
86 germplasmDbId: this.meta_data.filler_accession_id,
87 germplasmName: this.meta_data.filler_accession_name,
91 (parseInt(this.meta_data.max_level_code) + count),
92 observationUnitPosition: {
94 levelCode: parseInt(this.meta_data.max_level_code) + count,
99 plot.observationUnitPosition.positionCoordinateX,
101 plot.observationUnitPosition.positionCoordinateY,
103 trialDbId: this.trial_id,
104 studyDbId: this.trial_id,
108 return brapi_post_plots;
111 format_brapi_put_object() {
112 let brapi_plots = {};
113 for (let plot of this.plot_arr.filter((plot) => plot.type == "data")) {
114 brapi_plots[plot.observationUnitDbId] = {
116 invert_row_checkmark: document.getElementById(
117 "invert_row_checkmark"
119 top_border_selection: this.meta_data.top_border_selection || false,
120 left_border_selection:
121 this.meta_data.left_border_selection || false,
122 right_border_selection:
123 this.meta_data.right_border_selection || false,
124 bottom_border_selection:
125 this.meta_data.bottom_border_selection || false,
126 plot_layout: this.meta_data.plot_layout || "serpentine",
128 germplasmDbId: plot.germplasmDbId,
129 germplasmName: plot.gerplasmName,
130 observationUnitName: plot.observationUnitName,
131 observationUnitPosition: {
134 plot.observationUnitPosition.observationLevel.levelCode,
139 plot.observationUnitPosition.positionCoordinateX,
141 plot.observationUnitPosition.positionCoordinateY,
143 trialDbId: this.trial_id,
150 var pseudo_layout = {};
151 var plot_object = {};
152 for (let plot of data) {
154 if (isNaN(parseInt(plot.observationUnitPosition.positionCoordinateY))) {
155 plot.observationUnitPosition.positionCoordinateY = isNaN(
157 plot.observationUnitPosition.observationLevelRelationships[1]
161 ? plot.observationUnitPosition.observationLevelRelationships[0]
163 : plot.observationUnitPosition.observationLevelRelationships[1]
166 plot.observationUnitPosition.positionCoordinateY in pseudo_layout
169 plot.observationUnitPosition.positionCoordinateY
171 plot.observationUnitPosition.positionCoordinateX =
172 pseudo_layout[plot.observationUnitPosition.positionCoordinateY];
174 pseudo_layout[plot.observationUnitPosition.positionCoordinateY] = 1;
175 plot.observationUnitPosition.positionCoordinateX = 1;
178 var obs_level = plot.observationUnitPosition.observationLevel;
179 if (obs_level.levelName == "plot") {
180 plot.observationUnitPosition.positionCoordinateX = parseInt(
181 plot.observationUnitPosition.positionCoordinateX
183 plot.observationUnitPosition.positionCoordinateY = parseInt(
184 plot.observationUnitPosition.positionCoordinateY
186 // if (plot.additionalInfo && plot.additionalInfo.type == "filler") {
187 // plot.type = "filler";
189 // plot.type = "data";
191 plot_object[plot.observationUnitDbId] = plot;
194 this.plot_object = plot_object;
197 filter_heatmap(observations) {
198 this.heatmap_object = {};
199 for (let observation of observations) {
200 let trait_name = observation.observationVariableName;
201 if (!this.heatmap_object[trait_name]) {
202 this.heatmap_object[trait_name] = {
203 [observation.observationUnitDbId]: {
204 val: observation.value,
205 plot_name: observation.observationUnitName,
206 id: observation.observationDbId,
210 this.heatmap_object[trait_name][observation.observationUnitDbId] = {
211 val: observation.value,
212 plot_name: observation.observationUnitName,
213 id: observation.observationDbId,
225 additional_properties
227 let q = new URLSearchParams({
230 ...Object.keys(this.linked_trials).map(
231 (e) => this.linked_trials[e].id
237 top_border: !!include_borders && !!this.meta_data.top_border_selection,
239 !!include_borders && !!this.meta_data.right_border_selection,
241 !!include_borders && !!this.meta_data.bottom_border_selection,
243 !!include_borders && !!this.meta_data.left_border_selection,
244 gaps: !!include_gaps,
245 ...additional_properties,
247 window.open(`/ajax/breeders/trial_plot_order?${q}`, "_blank");
251 this.plot_arr = Object.values(this.plot_object);
252 var min_col = 100000;
253 var min_row = 100000;
256 var max_level_code = 0;
257 this.plot_arr.forEach((plot) => {
259 plot.observationUnitPosition.positionCoordinateX > max_col
260 ? plot.observationUnitPosition.positionCoordinateX
263 plot.observationUnitPosition.positionCoordinateX < min_col
264 ? plot.observationUnitPosition.positionCoordinateX
267 plot.observationUnitPosition.positionCoordinateY > max_row
268 ? plot.observationUnitPosition.positionCoordinateY
271 plot.observationUnitPosition.positionCoordinateY < min_row
272 ? plot.observationUnitPosition.positionCoordinateY
275 parseInt(plot.observationUnitPosition.observationLevel.levelCode) >
277 ? plot.observationUnitPosition.observationLevel.levelCode
280 this.meta_data.min_row = min_row;
281 this.meta_data.max_row = max_row;
282 this.meta_data.min_col = min_col;
283 this.meta_data.max_col = max_col;
284 this.meta_data.num_rows = max_row - min_row + 1;
285 this.meta_data.num_cols = max_col - min_col + 1;
286 this.meta_data.max_level_code = max_level_code;
287 this.meta_data.display_borders = !jQuery(
288 "#include_linked_trials_checkmark"
290 this.meta_data.overlapping_plots = {};
294 var fieldmap_hole_fillers = [];
296 for (let plot of this.plot_arr) {
297 if (last_coord === undefined) {
300 if (plot === undefined) {
301 if (last_coord[0] < this.meta_data.max_col) {
302 fieldmap_hole_fillers.push(
303 this.get_plot_format(
304 `Empty_Space_(${last_coord[0] + 1}_${last_coord[1]})`,
309 last_coord = [last_coord[0] + 1, last_coord[1]];
311 "Empty Space" + String(last_coord[0]) + String(last_coord[1])
312 ] = this.get_plot_format(
318 fieldmap_hole_fillers.push(
319 this.get_plot_format(
320 `Empty_Space_${this.meta_data.min_col}_${last_coord[1] + 1}`,
321 this.meta_data.min_col,
325 last_coord = [this.meta_data.min_col, last_coord[1]];
327 "Empty Space" + String(last_coord[0]) + String(last_coord[1])
328 ] = this.get_plot_format(
330 this.meta_data.min_col,
336 plot.observationUnitPosition.positionCoordinateX,
337 plot.observationUnitPosition.positionCoordinateY,
342 ...this.plot_arr.filter((plot) => plot !== undefined),
343 ...fieldmap_hole_fillers,
347 check_element(selection, element_id) {
348 document.getElementById(element_id).checked = selection;
351 check_elements(additionalInfo) {
353 "top_border_selection",
354 "left_border_selection",
355 "right_border_selection",
356 "bottom_border_selection",
357 "invert_row_checkmark",
359 for (let element of elements) {
360 this.check_element(additionalInfo[element], element);
361 this.meta_data[element] = additionalInfo[element];
365 get_plot_format(type, x, y) {
366 // Use the first plot from the trial to get trial-level metadata to give to a border plot
367 // NOTE: this will break if plots from multiple trials are loaded
368 let p = this.plot_arr[0];
371 observationUnitName: this.trial_id + " " + type,
372 observationUnitPosition: {
373 positionCoordinateX: x,
374 positionCoordinateY: y,
376 locationName: p.locationName,
377 studyName: p.studyName,
381 change_dimensions(cols, rows) {
382 var cols = parseInt(cols);
383 var rows = parseInt(rows);
384 this.meta_data.post = false;
385 this.meta_data.num_cols = cols;
386 this.meta_data.num_rows = rows;
388 ...this.plot_arr.slice(0, Object.entries(this.plot_object).length),
391 if (this.meta_data.retain_layout == false) {
392 this.meta_data.max_row = rows + this.meta_data.min_row - 1;
393 this.meta_data.max_col = cols + this.meta_data.min_col - 1;
394 this.meta_data.plot_layout = this.meta_data.plot_layout
395 ? this.meta_data.plot_layout
398 this.plot_arr = this.plot_arr.filter((plot) => plot.type == "data");
399 this.plot_arr.sort(function (a, b) {
401 parseFloat(a.observationUnitPosition.observationLevel.levelCode) -
402 parseFloat(b.observationUnitPosition.observationLevel.levelCode)
409 let j = this.meta_data.min_row;
410 j < this.meta_data.min_row + rows;
415 this.meta_data.plot_layout == "serpentine" && j % 2 === 0;
418 let i = this.meta_data.min_col;
419 i < this.meta_data.min_col + cols;
424 var col = swap_columns ? this.meta_data.max_col - col_count + 1 : i;
426 plot_count >= this.plot_arr.length &&
427 this.meta_data.filler_accession_id
429 this.meta_data.post = true;
430 this.plot_arr[plot_count] = this.get_plot_format(
436 plot_count < this.plot_arr.length &&
437 this.plot_arr[plot_count].observationUnitPosition
441 ].observationUnitPosition.positionCoordinateX = col;
444 ].observationUnitPosition.positionCoordinateY = row;
453 var add_corner = (condition_1, condition_2, x, y) => {
454 if (condition_1 && condition_2) {
455 this.plot_arr.push(this.get_plot_format("border", x, y));
459 this.meta_data.top_border_selection,
460 this.meta_data.left_border_selection,
461 this.meta_data.min_col - 1,
462 this.meta_data.min_row - 1
465 this.meta_data.top_border_selection,
466 this.meta_data.right_border_selection,
467 this.meta_data.max_col + 1,
468 this.meta_data.min_row - 1
471 this.meta_data.bottom_border_selection,
472 this.meta_data.left_border_selection,
473 this.meta_data.min_col - 1,
474 this.meta_data.max_row + 1
477 this.meta_data.bottom_border_selection,
478 this.meta_data.right_border_selection,
479 this.meta_data.max_col + 1,
480 this.meta_data.max_row + 1
483 add_border(border_element, row_or_col, min_or_max) {
486 if (row_or_col == "row") {
487 start_iter = this.meta_data.min_col;
488 end_iter = this.meta_data.max_col;
489 } else if (row_or_col == "col") {
490 start_iter = this.meta_data.min_row;
491 end_iter = this.meta_data.max_row;
494 if (this.meta_data[border_element]) {
495 for (let i = start_iter; i <= end_iter; i++) {
497 this.get_plot_format(
499 row_or_col == "row" ? i : min_or_max,
500 row_or_col == "row" ? min_or_max : i
508 if (this.meta_data.display_borders) {
510 "left_border_selection",
512 this.meta_data.min_col - 1
515 "top_border_selection",
517 this.meta_data.min_row - 1
520 "right_border_selection",
522 this.meta_data.max_col + 1
525 "bottom_border_selection",
527 this.meta_data.max_row + 1
534 this.plot_arr = this.plot_arr.filter((plot) => plot.type != "border");
535 this.plot_arr.map((plot) => {
536 let tempX = plot.observationUnitPosition.positionCoordinateX;
537 plot.observationUnitPosition.positionCoordinateX =
538 plot.observationUnitPosition.positionCoordinateY;
539 plot.observationUnitPosition.positionCoordinateY = tempX;
542 let tempMaxCol = this.meta_data.max_col;
543 this.meta_data.max_col = this.meta_data.max_row;
544 this.meta_data.max_row = tempMaxCol;
546 let tempMinCol = this.meta_data.min_col;
547 this.meta_data.min_col = this.meta_data.min_row;
548 this.meta_data.min_row = tempMinCol;
550 let tempNumCols = this.meta_data.num_cols;
551 this.meta_data.num_cols = this.meta_data.num_rows;
552 this.meta_data.num_rows = tempNumCols;
553 d3.select("svg").remove();
560 var event = d3.dispatch("click", "dblclick");
561 function cc(selection) {
566 function dist(a, b) {
567 return Math.sqrt(Math.pow(a[0] - b[0], 2), Math.pow(a[1] - b[1], 2));
570 selection.on("mousedown", function () {
571 down = d3.mouse(document.body);
574 selection.on("mouseup", function () {
576 if (dist(down, d3.mouse(document.body)) > tolerance) {
580 window.clearTimeout(wait);
582 event.call("dblclick", this, d3.event);
585 wait = window.setTimeout(
588 event.call("click", this, e);
598 // return d3.rebind(cc, event, 'on');
599 return _rebind(cc, event, "on");
601 // Copies a variable number of methods from source to target.
602 function _rebind(target, source) {
605 n = arguments.length,
608 target[(method = arguments[i])] = d3_rebind(
616 // Method is assumed to be a standard D3 getter-setter:
617 // If passed with no arguments, gets the value.
618 // If passed with arguments, sets the value and returns the target.
619 function d3_rebind(target, source, method) {
622 var value = method.apply(source, arguments);
623 return arguments.length ? target : value;
628 heatmap_plot_click(plot, heatmap_object, trait_name) {
629 if (d3.event && d3.event.detail > 1) {
632 trait_name in heatmap_object &&
633 heatmap_object[trait_name][plot.observationUnitDbId]
635 let val, plot_name, pheno_id;
636 val = heatmap_object[trait_name][plot.observationUnitDbId].val;
638 heatmap_object[trait_name][plot.observationUnitDbId].plot_name;
639 pheno_id = heatmap_object[trait_name][plot.observationUnitDbId].id;
640 jQuery("#suppress_plot_pheno_dialog").modal("show");
641 jQuery("#myplot_name").html(plot_name);
642 jQuery("#pheno_value").html(val);
643 jQuery("#mytrait_id").html(trait_name);
644 jQuery("#mypheno_id").html(pheno_id);
648 fieldmap_plot_click(plot) {
649 if (d3.event && d3.event.detail > 1) {
652 function btnClick(n) {
654 jQuery("#hm_view_plot_image_submit").addClass("disabled");
656 jQuery("#hm_view_plot_image_submit").removeClass("disabled");
660 if (plot.type == "data") {
661 var image_ids = plot.plotImageDbIds || [];
662 var replace_accession = plot.germplasmName;
663 var replace_plot_id = plot.observationUnitDbId;
664 var replace_plot_name = plot.observationUnitName;
666 var replace_plot_number =
667 plot.observationUnitPosition.observationLevel.levelCode;
669 jQuery("#plot_image_ids").html(image_ids);
670 jQuery("#hm_replace_accessions_link").find("button").trigger("click");
671 jQuery("#hm_replace_accessions_link").on("click", function () {
674 jQuery("#hm_edit_plot_information").html(
675 "<b>Selected Plot Information: </b>"
677 jQuery("#hm_edit_plot_name").html(replace_plot_name);
678 jQuery("#hm_edit_plot_number").html(replace_plot_number);
679 var old_plot_id = jQuery("#hm_edit_plot_id").html(replace_plot_id);
680 var old_plot_accession = jQuery("#hm_edit_plot_accession").html(
683 jQuery("#hm_replace_plot_accessions_dialog").modal("show");
687 url: "/ajax/breeders/trial/" + trial_id + "/retrieve_plot_images",
690 image_ids: JSON.stringify(image_ids),
691 plot_name: replace_plot_name,
692 plot_id: replace_plot_id,
694 success: function (response) {
695 jQuery("#working_modal").modal("hide");
696 var images = response.image_html;
697 if (response.error) {
698 alert("Error Retrieving Plot Images: " + response.error);
700 jQuery("#show_plot_image_ids").html(images);
702 // jQuery('#view_plot_image_dialog').modal("show");
706 jQuery("#working_modal").modal("hide");
707 alert("An error occurred retrieving plot images");
714 addEventListeners() {
715 let LocalThis = this;
716 let transposeBtn = document.getElementById("transpose_fieldmap");
717 transposeBtn.onclick = function () {
718 LocalThis.transpose();
723 this.addEventListeners();
724 var cc = this.clickcancel();
736 var trait_name = this.heatmap_selection;
737 var heatmap_object = this.heatmap_object;
738 var plot_click = !this.heatmap_selected
739 ? this.fieldmap_plot_click
740 : this.heatmap_plot_click;
742 var local_this = this;
744 if (this.heatmap_selected) {
745 let plots_with_selected_trait = heatmap_object[trait_name];
746 for (let obs_unit of Object.values(plots_with_selected_trait)) {
747 trait_vals.push(obs_unit.val);
750 var colorScale = d3.scaleQuantile().domain(trait_vals).range(colors);
753 var is_plot_overlapping = function (plot) {
754 if (plot.observationUnitPosition) {
755 let k = `${plot.observationUnitPosition.positionCoordinateX}-${plot.observationUnitPosition.positionCoordinateY}`;
756 return Object.keys(local_this.meta_data.overlapping_plots).includes(
763 var get_fieldmap_plot_color = function (plot) {
765 if (plot.observationUnitPosition.observationLevelRelationships) {
766 if (is_plot_overlapping(plot)) {
768 } else if (plot.observationUnitPosition.entryType == "check") {
771 plot.observationUnitPosition.observationLevelRelationships[1]
778 plot.observationUnitName.includes(local_this.trial_id + " filler")
790 var get_heatmap_plot_color = function (plot) {
792 if (is_plot_overlapping(plot)) {
794 } else if (!plot.observationUnitPosition.observationLevel) {
797 var cs = heatmap_object.hasOwnProperty(trait_name) && heatmap_object[trait_name].hasOwnProperty(plot.observationUnitDbId)
798 ? colorScale(heatmap_object[trait_name][plot.observationUnitDbId].val)
800 color = cs ? cs : "lightgrey";
804 var get_stroke_color = function (plot) {
806 if (plot.observationUnitPosition.observationLevel) {
808 plot.observationUnitPosition.observationLevelRelationships[0]
813 stroke_color = "red";
815 stroke_color = "green";
818 stroke_color = "#666";
823 var get_plot_message = function (plot) {
825 if (is_plot_overlapping(plot)) {
826 let k = `${plot.observationUnitPosition.positionCoordinateX}-${plot.observationUnitPosition.positionCoordinateY}`;
827 let plots = local_this.meta_data.overlapping_plots[k];
828 html += `<strong>Overlapping Plots:</strong> ${plots.join(", ")}`;
830 html += jQuery("#include_linked_trials_checkmark").is(":checked")
831 ? `<strong>Trial Name:</strong> <span style='padding: 1px 2px; border-radius: 4px; color: ${local_this.linked_trials[plot.studyName].fg
832 }; background-color: ${local_this.linked_trials[plot.studyName].bg
833 }'>${plot.studyName}</span><br />`
835 html += `<strong>Plot Name:</strong> ${plot.observationUnitName}<br />`;
836 if (plot.type == "data") {
837 html += `<strong>Plot Number:</strong> ${plot.observationUnitPosition.observationLevel.levelCode}<br />
838 <strong>Block Number:</strong> ${plot.observationUnitPosition.observationLevelRelationships[1].levelCode}<br />
839 <strong>Rep Number:</strong> ${plot.observationUnitPosition.observationLevelRelationships[0].levelCode}<br />
840 <strong>Accession Name:</strong> ${plot.germplasmName}`;
841 if ( local_this.heatmap_selected ) {
842 let v = '<em>NA</em>';
843 if ( heatmap_object.hasOwnProperty(trait_name) && heatmap_object[trait_name].hasOwnProperty(plot.observationUnitDbId) ) {
844 v = heatmap_object[trait_name][plot.observationUnitDbId].val;
845 v = isNaN(v) ? v : Math.round((parseFloat(v) + Number.EPSILON) * 100) / 100;
847 html += `<br /><strong>Trait Value:</strong> ${v}`;
854 var handle_mouseover = function (d) {
855 if (d.observationUnitPosition.observationLevel) {
856 d3.select(`#fieldmap-plot-${d.observationUnitDbId}`)
858 .style("fill", "green")
859 .style("cursor", "pointer")
861 .style("stroke-width", 3)
862 .style("stroke", "#000000");
864 .style("opacity", 0.9)
865 .style("left", window.event.clientX + 25 + "px")
866 .style("top", window.event.clientY + "px")
867 .html(get_plot_message(d));
872 var handle_mouseout = function (d) {
873 d3.select(`#fieldmap-plot-${d.observationUnitDbId}`)
876 !isHeatMap ? get_fieldmap_plot_color(d) : get_heatmap_plot_color(d)
878 .style("cursor", "default")
879 .style("stroke-width", 2)
880 .style("stroke", get_stroke_color);
881 tooltip.style("opacity", 0);
882 plots.exit().remove();
885 var plot_x_coord = function (plot) {
887 plot.observationUnitPosition.positionCoordinateX -
894 var plot_y_coord = function (plot) {
896 plot.observationUnitPosition.positionCoordinateY -
900 plot.type !== "border" &&
901 document.getElementById("invert_row_checkmark").checked !== true
903 y = num_rows - y - 1;
909 this.meta_data.display_borders && this.meta_data.left_border_selection
910 ? this.meta_data.num_cols + 3
911 : this.meta_data.num_cols + 2;
913 this.meta_data.display_borders && this.meta_data.right_border_selection
917 this.meta_data.display_borders && this.meta_data.top_border_selection
918 ? this.meta_data.num_rows + 3
919 : this.meta_data.num_rows + 2;
921 this.meta_data.display_borders && this.meta_data.bottom_border_selection
924 var row_increment = this.meta_data.invert_row_checkmark ? 1 : 0;
926 this.meta_data.display_borders &&
927 this.meta_data.top_border_selection &&
928 this.meta_data.invert_row_checkmark
932 this.meta_data.display_borders &&
933 this.meta_data.top_border_selection &&
934 !this.meta_data.invert_row_checkmark
938 this.meta_data.display_borders && this.meta_data.left_border_selection
942 // Check the fieldmap for any overlapping plots (plots that share the same x/y coordinates)
943 this.meta_data.overlapping_plots = {};
944 let plot_positions = {};
945 this.plot_arr.forEach((plot) => {
946 if (plot.observationUnitPosition) {
947 let x = plot.observationUnitPosition.positionCoordinateX;
948 let y = plot.observationUnitPosition.positionCoordinateY;
949 let p = plot.observationUnitPosition.observationLevel
950 ? plot.observationUnitPosition.observationLevel.levelCode
952 let t = plot.studyName;
955 if (!plot_positions.hasOwnProperty(k)) plot_positions[k] = [];
956 plot_positions[k].push(
957 jQuery("#include_linked_trials_checkmark").is(":checked")
961 if (plot_positions[k].length > 1) {
962 this.meta_data.overlapping_plots[k] = plot_positions[k];
968 var min_row = this.meta_data.min_row;
969 var max_row = this.meta_data.max_row;
970 var min_col = this.meta_data.min_col;
971 var max_col = this.meta_data.max_col;
972 var num_rows = this.meta_data.num_rows;
973 var isHeatMap = this.heatmap_selected;
977 .select("#fieldmap_chart")
979 .attr("width", width * 50 + 20 + "px")
980 .attr("height", height * 50 + 20 + "px");
984 .select("#fieldmap_chart")
986 .attr("id", "tooltip")
987 .attr("class", "tooltip")
988 .style("position", "fixed")
989 .style("opacity", 0);
991 var plots = grid.selectAll("plots").data(this.plot_arr);
992 plots.append("title");
997 return plot_x_coord(d) * 50;
1000 return plot_y_coord(d) * 50 + 15 + y_offset;
1003 .attr("id", (d) => {
1004 return `fieldmap-plot-${d.observationUnitDbId}`;
1006 .attr("class", "col bordered")
1009 .style("stroke-width", 2)
1010 .style("stroke", get_stroke_color)
1013 !isHeatMap ? get_fieldmap_plot_color : get_heatmap_plot_color
1015 .on("mouseover", handle_mouseover)
1016 .on("mouseout", handle_mouseout)
1020 cc.on("click", (el) => {
1021 var plot = d3.select(el.srcElement).data()[0];
1022 plot_click(plot, heatmap_object, trait_name);
1024 cc.on("dblclick", (el) => {
1025 var me = d3.select(el.srcElement);
1026 var d = me.data()[0];
1027 if (d.observationUnitDbId) {
1028 window.open("/stock/" + d.observationUnitDbId + "/view");
1032 // Add a colored band to the bottom of the plot box to indicate different trials
1033 if (jQuery("#include_linked_trials_checkmark").is(":checked")) {
1038 return plot_x_coord(d) * 50 + 4;
1041 return plot_y_coord(d) * 50 + 54 + y_offset;
1046 .style("fill", (d) => {
1047 return local_this.linked_trials[d.studyName].bg;
1049 .style("opacity", (d) => {
1050 return is_plot_overlapping(d) ? "0" : "100";
1054 plots.append("text");
1059 return plot_x_coord(d) * 50 + 10;
1062 return plot_y_coord(d) * 50 + 50 + y_offset;
1066 !d.observationUnitName.includes(local_this.trial_id + " filler") &&
1068 !is_plot_overlapping(d)
1070 return d.observationUnitPosition.observationLevel.levelCode;
1073 .on("mouseover", handle_mouseover)
1074 .on("mouseout", handle_mouseout);
1076 var image_icon = function (d) {
1077 var image = d.plotImageDbIds || [];
1079 if (image.length > 0) {
1080 plot_image = "/static/css/images/plot_images.png";
1090 .attr("xlink:href", image_icon)
1092 return plot_x_coord(d) * 50 + 5;
1095 return plot_y_coord(d) * 50 + 15 + y_offset;
1099 .on("mouseover", handle_mouseover)
1100 .on("mouseout", handle_mouseout);
1102 plots.exit().remove();
1104 var row_label_arr = [];
1105 var col_label_arr = [];
1106 for (let i = min_row; i <= max_row; i++) {
1107 row_label_arr.push(i);
1109 for (let i = min_col; i <= max_col; i++) {
1110 col_label_arr.push(i);
1113 var row_labels_col = 1;
1114 var col_labels_row = 0;
1115 if (!this.meta_data.invert_row_checkmark) {
1117 this.meta_data.display_borders &&
1118 this.meta_data.bottom_border_selection
1121 row_label_arr.reverse();
1125 .selectAll(".rowLabels")
1126 .data(row_label_arr)
1129 .attr("x", row_labels_col * 50 - 25)
1130 .attr("y", (label, i) => {
1131 let y = this.meta_data.invert_row_checkmark ? i + 1 : i;
1133 this.meta_data.display_borders &&
1134 this.meta_data.top_border_selection &&
1135 this.meta_data.invert_row_checkmark
1138 return y * 50 + 45 + y_offset;
1145 .selectAll(".colLabels")
1146 .data(col_label_arr)
1149 .attr("x", (label, i) => {
1150 let x = label - min_col + col_increment + 2;
1153 .attr("y", col_labels_row * 50 + 45 + y_offset)
1160 d3.select("svg").remove();
1161 this.change_dimensions(this.meta_data.num_cols, this.meta_data.num_rows);
1167 jQuery("#working_modal").modal("hide");
1168 jQuery("#fieldmap_chart").css({ display: "inline-block" });
1169 jQuery("#container_fm").css({
1170 display: "inline-block",
1173 jQuery("#trait_heatmap").css("display", "none");
1174 jQuery("#container_heatmap").css("display", "none");
1175 jQuery("#trait_heatmap").css("display", "none");
1180 const mapObj = new FieldMap();