3 page_formats
["Select a page format"] = {};
4 page_formats
["US Letter PDF"] = {
8 'Select a label format' : {},
59 'CASS [1" x 5 1/4"]': {
69 'MUSA [1" x 5 1/4"]': {
79 'IITA-3 | IITA-2 [2/5" x 5 1/4"]': {
89 '32 Label Size Sticker [1" x 1 1/3"]': {
99 '20 Label Size Sticker [5/6" x 3 3/5"]': {
106 number_of_columns
: 2,
113 page_formats
["A4 PDF"] = {
117 'Select a label format' : {},
131 page_formats
["Zebra printer file"] = {
133 'Select a label format' : {},
151 page_formats
["Custom"] = {
153 'Select a label format' : {},
167 var label_options
= {};
168 label_options
["Select an element type"] = { name
: "Select an element type" };
169 label_options
["PDFText"] = {
179 label_options
["ZebraText"] = {
180 name
: "Text (Zebra)",
193 label_options
["Code128"] = {
194 name
: "1D Barcode (Code128)",
203 label_options
["QRCode"] = {
204 name
: "2D Barcode (QRCode)",
217 "Courier": "font-family:courier;",
218 "Courier-Bold": "font-family:courier;font-weight:bold;",
219 "Courier-Oblique": "font-family:courier;font-style: oblique;",
220 "Courier-BoldOblique": "font-family:courier;font-weight:bold;font-style: oblique;",
221 "Helvetica": "font-family:helvetica;",
222 "Helvetica-Bold": "font-family:helvetica;font-weight:bold;",
223 "Helvetica-Oblique": "font-family:helvetica;font-style: oblique;",
224 "Helvetica-BoldOblique": "font-family:helvetica;font-weight:bold;font-style: oblique;",
225 "Times": "font-family:times;",
226 "Times-Bold": "font-family:times;font-weight:bold;",
227 "Times-Italic": "font-family:times;font-style: italic;",
228 "Times-BoldItalic": "font-family:times;font-weight:bold;font-style: italic;"
231 var add_fields
= {}; // retrieved when data source is selected
232 var num_units
= 0; // updated when data source is selected
234 resizer_behaviour
= d3
.behavior
.drag().on(
238 var bb
= getTransGroupBounds(target
.node())
241 // if (d3.select("#d3-snapping-check").property("checked")){
242 mx
= Math
.round(mx
/ doSnap
.size
) * doSnap
.size
243 my
= Math
.round(my
/ doSnap
.size
) * doSnap
.size
245 var xexpand
= (mx
- bb
.x
) / bb
.width
246 var yexpand
= (my
- bb
.y
) / bb
.height
247 expand
= Math
.max(xexpand
, yexpand
)
248 if (!isNaN(expand
)) {
249 target
.call(doTransform
, function(state
, selection
) {
250 var expX
= state
.scale
[0] * expand
;
251 var expY
= state
.scale
[1] * expand
;
252 var mi
= Math
.min(expX
* bb
.width
, expY
* bb
.height
);
254 expX
= state
.scale
[0];
255 expY
= state
.scale
[1];
257 state
.scale
[0] = expX
;
258 state
.scale
[1] = expY
;
261 var newbb
= getTransGroupBounds(target
.node())
262 d3
.select(this.parentNode
).select(".selection-tool-outline")
267 height
: newbb
.height
,
269 d3
.select(this.parentNode
).select(".selection-tool-resizer")
271 x
: newbb
.x
+ newbb
.width
- 3,
272 y
: newbb
.y
+ newbb
.height
- 3,
274 d3
.select(this.parentNode
).select(".selection-tool-remover")
281 //set up drag behaviour
282 var drag_behaviour
= d3
.behavior
.drag().on(
285 var o
= d3
.select(this)
286 .call(doTransform
, function(state
, selection
) {
287 state
.translate
[0] += d3
.event
.dx
;
288 state
.translate
[1] += d3
.event
.dy
;
292 $(document
).ready(function($) {
294 initializeDrawArea();
295 $('#source_type_select').focus();
298 // jQuery('#pagetitle_h3').append(' <a id="label_designer_docs_link" href="http://solgenomics.github.io/sgn/03_managing_breeding_data/03_12.html"><span class="glyphicon glyphicon-info-sign"></span></a>');
300 // Always focus on autofocus elements when modals are opened.
301 $('.modal').on('shown.bs.modal', function() {
302 $(this).find('[autofocus]').folabel
305 $('#d3-save-button').click(function() {
309 $('#design_label_button').click(function() {
310 $("#d3-draw-area").prependTo("#save-labels-display");
311 $(".workflow-complete").click(function() {
312 var title
= $(this).children().text();
313 //console.log("workflow element with title "+title+" was just clicked\n");
315 if (title
== "Design Your Label") {
316 $("#d3-draw-area").prependTo("#d3-draw-div");
317 } else if (title
== "More Options, Save, And Download") {
318 $("#d3-draw-area").prependTo("#save-labels-display");
322 $("ol.workflow-prog li").click(function() {
323 var title
= $(this).children().text();
324 //console.log("workflow element with title "+title+" was just clicked\n");
325 if (title
== "More Options, Save, And Download") {
326 $("#d3-draw-area").prependTo("#save-labels-display");
332 getDataSourceSelect();
334 $("#edit_additional_settings").on("click", function() {
335 $('#editAdditionalSettingsModal').modal('show');
338 $(document
).on("change", "#source_select", function() {
340 var name
= jQuery('#source_select :selected').text();
341 jQuery('#selected_data_source').text(name
);
343 var data_type
= $('#source_select :selected').parent().attr('label');
345 // updateFields(data_type, this.value, '');
347 if (data_type
== 'Field Trials') {
349 url
: '/ajax/breeders/trial/'+this.value
+'/has_data_levels',
351 beforeSend: function() {
354 complete: function() {
356 jQuery('#page_format').focus();
358 success: function(response
) {
359 var html
= '<select class="form-control" id="label_designer_data_level" ><option value="" selected>Select a Level</option><option value="plots">Plot</option>';
360 if(response
.has_plants
){
361 html
= html
+ '<option value="plants">Plant</option>';
363 if(response
.has_subplots
){
364 html
= html
+ '<option value="subplots">Subplot</option>';
366 if(response
.has_tissue_samples
){
367 html
= html
+ '<option value="tissue_samples">Tissue Sample</option>';
369 html
= html
+ '</select>';
370 jQuery('#label_designer_data_level_select_div').html(html
);
371 jQuery("#label_designer_data_level").focus();
373 error: function(response
) {
374 alert('There was a problem checking the data levels available for your field trial. Please contact us.');
377 } else if (data_type
== 'Genotyping Plates') {
379 jQuery('#label_designer_data_level_select_div').html('<select class="form-control" id="label_designer_data_level" ><option value="" selected>Select a Level</option><option value="plate">Plate</option></select>');
380 jQuery("#label_designer_data_level").focus();
382 } else if (data_type
== 'Crossing Experiments') {
384 jQuery('#label_designer_data_level_select_div').html('<select class="form-control" id="label_designer_data_level" ><option value="" selected>Select a Level</option><option value="crosses">Cross</option></select>');
385 jQuery("#label_designer_data_level").focus();
387 } else if ((data_type
== 'Lists') || (data_type
== 'Public Lists')) {
389 var html
= '<select class="form-control" id="label_designer_data_level" ><option value="" selected>Select a Level</option><option value="list">List Items</option>';
390 // Check list type, if Plot, Plant, or Tissue Sample add details option
391 var name
= $('#source_select :selected').text();
395 data
: { 'name': name
},
396 beforeSend: function() {
399 complete: function() {
401 jQuery('#page_format').focus();
403 success: function(response
) {
404 if ( response
.list_type
=== 'trials' ) {
405 html
+= '<option value="plots">Plot Details</option>';
406 } else if (response
.list_type
== 'plots') {
407 html
= html
+ '<option value="plots">Plot Details</option>';
408 } else if (response
.list_type
== 'subplots') {
409 html
= html
+ '<option value="subplots">Subplot Details</option>';
410 } else if (response
.list_type
== 'plants') {
411 html
= html
+ '<option value="plants">Plant Details</option>';
412 } else if (response
.list_type
== 'tissue_samples') {
413 html
= html
+ '<option value="tissue_samples">Tissue Sample Details</option>';
414 } else if (response
.list_type
== 'crosses') {
415 html
= html
+ '<option value="crosses">Cross Details</option>';
416 } else if (response
.list_type
== 'identifier_generation') {
417 // remove list item select options and add options for each id batch
418 html
= '<select class="form-control" id="label_designer_data_level" ><option value="" selected>Select a Level</option>';
419 var lo
= new CXGN
.List();
420 var list_data
= lo
.getListData(response
.list_id
);
421 var elements
= list_data
.elements
;
422 var identifier_object
= JSON
.parse(elements
[0][1]);
423 var records
= identifier_object
.records
;
424 for (var x
= 0; x
< records
.length
; x
++) {
425 var generated_identifiers
= records
[x
].generated_identifiers
;
426 if (generated_identifiers
) {
427 //console.log("current identifiers are: "+generated_identifiers);
428 var min
= generated_identifiers
.shift();
429 var max
= generated_identifiers
.pop();
430 var id
= records
[x
].next_number
;
431 html
= html
+ '<option value="batch-'+id
+'">ID Batch '+min
+' - '+max
+'</option>';
435 html
= html
+ '</select>';
436 jQuery('#label_designer_data_level_select_div').html(html
);
437 jQuery("#label_designer_data_level").focus();
439 error: function(response
) {
440 alert('There was a problem checking the data levels available for your field trial. Please contact us.');
446 jQuery(document
).on('change', '#label_designer_data_level', function(){
447 var data_type
= $('#source_select :selected').parent().attr('label');
448 var source_id
= jQuery('#source_select').val();
450 var name
= jQuery('#label_designer_data_level :selected').text();
451 jQuery('#selected_data_level').text(name
);
453 if (this.value
) { jQuery('#select_datasource_button').prop('disabled', false); }
454 updateFields(data_type
, source_id
, this.value
);
457 jQuery(document
).on('change', 'input[type=radio][name=optradio]', function(){
458 if (this.value
== 'saved') {
459 document
.getElementById("design_list").style
.display
= "inline";
461 document
.getElementById("design_list").style
.display
= "none";
465 var page_format_select
= d3
.select("#page_format");
466 page_format_select
.on("input", function() {
467 var page
= d3
.select(this).node().value
;
468 if (!page
|| page
== 'Select a page format') {
470 d3
.select("#label_format").selectAll("option").remove();
472 switchPageDependentOptions(page
); // show correct download and text options
476 $('#label_format').change(function() {
477 var label
= $(this).find('option:selected').val();
478 if (!label
|| label
== 'Select a label format') {
480 jQuery('#select_layout_button').prop('disabled',true)
482 switchLabelDependentOptions(label
);
486 d3
.select("#d3-apply-custom-label-size").on("click", function() {
488 //save and apply custom label size
489 jQuery('#select_layout_button').prop('disabled', false)
490 var page
= d3
.select("#page_format").node().value
;
491 var custom_label
= page_formats
[page
].label_sizes
['Custom'];
493 custom_label
.label_width
= document
.getElementById("label_width").value
;
494 custom_label
.label_height
= document
.getElementById("label_height").value
;
495 changeLabelSize(custom_label
.label_width
, custom_label
.label_height
);
496 $("#d3-add-and-download-div").removeAttr('style');
498 $('#d3-add-type-input').focus();
501 $('#d3-add-field-input').change(function() {
502 $("#d3-add-size-input").focus();
505 $("#d3-custom-field").on("click", function() {
506 $("#d3-custom-input").val('');
507 $('#customFieldModal').modal('show');
510 d3
.select("#d3-custom-field-save")
511 .on("click", function() {
512 var custom_text
= $("#d3-custom-input").val();
513 var custom_value
= custom_text
.replace(/\{(.*?)\}/g, function(match
, token
) {
514 //console.log("token is "+token);
515 if (token
.match(/Number:/)) {
516 var parts
= token
.split(':');
519 return add_fields
[token
];
523 $("#d3-add-field-input").append($('<option>', {
530 $('#d3-add-type-input').change(function() {
531 if (!this.value
|| this.value
== 'Select an element type') {
534 switchTypeDependentOptions(this.value
);
535 $("#d3-add-field-input").focus();
540 $("#d3-edit-additional-settings").on("click", function() {
541 saveAdditionalOptions(
542 document
.getElementById("top_margin").value
,
543 document
.getElementById("left_margin").value
,
544 document
.getElementById("horizontal_gap").value
,
545 document
.getElementById("vertical_gap").value
,
546 document
.getElementById("number_of_columns").value
,
547 document
.getElementById("number_of_rows").value
,
548 document
.getElementById("plot_filter").value
,
549 document
.getElementById("sort_order_1").value
,
550 document
.getElementById("sort_order_2").value
,
551 document
.getElementById("sort_order_3").value
,
552 document
.getElementById("copies_per_plot").value
556 $("#d3-add").on("click", function() {
557 var type
= document
.getElementById("d3-add-type-input").value
;
558 if (!type
|| type
== 'Select an element type') {
559 alert("A valid type must be selected.");
562 var field
= $('#d3-add-field-input').find('option:selected').text();
563 if (!field
|| field
== 'Select a field') {
564 alert("A valid field must be selected.");
567 // check if add_fields[field] is defined. If so, add {}s
568 if (add_fields
[field
]) {
569 field
= "{"+field
+"}";
571 var text
= document
.getElementById("d3-add-field-input").value
;
572 var size
= document
.getElementById("d3-add-size-input").value
;
573 var font
= document
.getElementById("d3-add-font-input").value
|| 'Courier';
574 addToLabel(field
, text
, type
, size
, font
);
575 jQuery('#design_label_button').prop('disabled', false)
578 $("#d3-pdf-button, #d3-zpl-button").on("click", function() {
579 var design
= retrievePageParams();
580 var download_type
= $(this).val();
581 console
.log("Design is "+JSON
.stringify(design
));
583 // if over 1,000 to download, throw warning with editable start and end number and text recommending to download in batches of 1,000 or less
584 var label_count
= num_units
* design
.copies_per_plot
;
585 var labels_to_download
= design
.labels_to_download
;
586 if (label_count
< 1000 || (labels_to_download
&& labels_to_download
< 1000)) {
587 downloadLabels(design
, download_type
);
588 } else if (label_count
>= 1000) {
589 //show warning with editable inputs for start and end
590 var message
= "You are trying to download "+label_count
+ " labels ("+label_count
+" "+jQuery('#label_designer_data_level :selected').text()+" x "+design
.copies_per_plot
+" copy(ies) each). Downloading this many at a time may result in slow speeds. Please use the input boxes below to control how many are downloaded at a time.";
591 $("#batch_download_message").text(message
);
592 $("#d3-batch-download-submit").val(download_type
);
593 $('#batchDownloadModal').modal('show');
598 $("#d3-batch-download-submit").on("click", function() {
599 var download_type
= $(this).val();
600 var design
= retrievePageParams();
601 downloadLabels(design
, download_type
);
606 function downloadLabels (design
, download_type
) {
607 var label_elements
= document
.getElementsByClassName('label-element');
608 label_elements
= Array
.prototype.slice
.call(label_elements
); // convert to array
609 if (label_elements
.length
< 1) {
610 alert("No elements in the design. Please add design elements before downloading");
613 var data_type
= $('#source_select :selected').parent().attr('label');
614 var source_id
= $("#source_select").val();
615 var source_name
= $("#source_select :selected").text();
616 //console.log("Id is "+source_id+" and name is "+source_name);
617 if (!source_id
|| source_id
== 'Please select a trial' || source_id
== 'Select a plot list') {
618 alert("No data source selected. Please select a data source before downloading");
623 alert("No design. Please define a design before downloading");
626 design
.label_elements
= label_elements
.filter(checkIfVisible
).map(getLabelDetails
);
628 var design_json
= JSON
.stringify(design
);
629 console
.log("design is"+design_json
);
630 var data_level
= jQuery('#label_designer_data_level').val();
632 //send to server to build pdf file
634 url
: '/tools/label_designer/download',
638 'download_type': download_type
,
639 'data_type' : data_type
,
640 'source_id': source_id
,
641 'source_name': source_name
,
642 'design_json': design_json
,
643 'data_level': data_level
645 beforeSend: function() {
646 console
.log("Downloading "+download_type
+" file . . . ");
649 complete: function() {
652 success: function(response
) {
653 if (response
.error
) {
655 alert(response
.error
);
657 console
.log("Got file "+response
.filename
);
659 window
.location
.href
= "/download/" + response
.filename
;
662 error: function(request
, status
, err
) {
664 alert("Error. Unable to download labels.");
669 function updateFields(data_type
, source_id
, data_level
){
671 //console.log("running update fields");
672 if (data_type
.match(/List/)) {
673 jQuery('#sort_order_1').val('list_order');
677 url
: '/tools/label_designer/retrieve_longest_fields',
681 data_type
: data_type
,
682 source_id
: source_id
,
683 data_level
: data_level
685 beforeSend: function() {
688 complete: function() {
690 jQuery('#page_format').focus();
692 success: function(response
) {
693 if (response
.error
) {
694 alert("An error occured while retrieving the design elements of this trial: " + JSON
.stringify(response
.error
));
695 getDataSourceSelect();
697 add_fields
= response
.fields
;
699 // if reps, add reps as options for filtering
700 reps
= response
.reps
;
701 num_units
= response
.num_units
;
703 addSortOrders(add_fields
, data_type
, data_level
);
704 createAdders(add_fields
);
705 initializeCustomModal(add_fields
);
708 if ( d3
.select("#page_format").node().value
&& d3
.select("#page_format").node().value
!= 'Select a page format') {
709 switchPageDependentOptions( d3
.select("#page_format").node().value
);
711 var page_format_select
= d3
.select("#page_format");
712 page_format_select
.selectAll("option")
713 .data(Object
.keys(page_formats
))
714 .enter().append("option")
721 error: function(request
, status
, err
) {
722 alert("Unable to retrieve design elements of this trial. Please confirm this trial has a design, or try again with a different trial. Please contact us!");
727 function changeLabelSize(width
, height
) {
728 var width
= width
* 2.83 //convert from pixels to dots (72/inch to 8/mm)
729 var height
= height
* 2.83 //convert from pixels to dots (72/inch to 8/mm)
730 d3
.select(".label-template").attr("viewBox", "0 0 " + width
+ " " + height
);
731 d3
.select(".d3-bg").attr("width", width
);
732 d3
.select(".d3-bg").attr("height", height
);
736 function initializeDrawArea() {
739 d3
.select(".label-template").remove();
740 var svg
= d3
.select("#d3-draw-area")
742 .classed("label-template", true)
745 viewBox
: "0 0 510 204"
746 }).classed("d3-draw-svg", true);
749 var rect
= svg
.append('rect')
750 .classed("d3-bg", true)
758 "stroke-width": "2px"
760 .on("click", clearSelection
);
762 .classed("d3-intro-text", true)
767 "text-anchor": "middle",
768 "alignment-baseline": "central",
770 .text('Label Design Area')
772 .classed("d3-intro-text", true)
777 "style": "font-style: oblique;",
778 "text-anchor": "middle",
779 "alignment-baseline": "central",
781 .text('Set source, page, and label formats above to start designing.');
784 var grid
= svg
.append("g").classed("d3-bg-grid", true);
785 grid
.append('g').classed("d3-bg-grid-vert", true);
786 grid
.append('g').classed("d3-bg-grid-horz", true);
791 function draggable(d
, i
) {
792 var bb
= this.node().getBBox();
797 .call(doTransform
, function(state
, selection
) {
798 state
.translate
= [-bb
.x
, -bb
.y
]
800 .call(drag_behaviour
);
803 function selectable(selection
, resizeable
) {
804 this.on("mousedown", function() {
805 d3
.select(".selection-tools").remove();
807 this.on("click", function() {
808 var o
= d3
.select(".d3-draw-svg");
809 var bb
= getTransGroupBounds(this);
810 var target
= d3
.select(this);
811 var tools
= o
.append('g')
812 .classed("selection-tools", true)
815 .classed("selection-tool-outline", true)
823 "stroke-dasharray": ("3,3"),
827 .classed("selection-tool-remover", true)
836 .on("click", function() {
837 d3
.event
.stopPropagation();
843 .classed("selection-tool-resizer", true)
844 .on("click", function() {
845 d3
.event
.stopPropagation();
848 x
: bb
.x
+ bb
.width
- 4,
849 y
: bb
.y
+ bb
.height
- 4,
854 }).call(resizer_behaviour
);
859 function doTransform(selection
, transformFunc
) {
860 var state
= d3
.transform(selection
.attr("transform"));
861 transformFunc(state
, selection
);
862 selection
.attr("transform", state
.toString());
865 function clearSelection() {
866 d3
.select(".selection-tools").remove();
869 function getTransGroupBounds(node
) {
870 var bb
= node
.getBBox()
871 var state
= d3
.transform(d3
.select(node
).attr("transform"));
872 bb
.x
= bb
.x
* state
.scale
[0]
873 bb
.y
= bb
.y
* state
.scale
[1]
874 bb
.width
= bb
.width
* state
.scale
[0]
875 bb
.height
= bb
.height
* state
.scale
[1]
876 bb
.x
+= state
.translate
[0]
877 bb
.y
+= state
.translate
[1]
881 function updateGrid(size
) {
882 //set snapping distance
885 var width
= document
.getElementById("d3-label-area").viewBox
.baseVal
.width
; //.getBoundingClientRect().width();
886 var height
= document
.getElementById("d3-label-area").viewBox
.baseVal
.height
;
888 for (var x
= size
; x
< width
; x
+= size
) {
891 var vert
= d3
.select(".d3-bg-grid-vert").selectAll("line")
894 vert
.enter().append('line')
898 stroke
: "rgba(0,0,0,0.2)",
901 .attr("x1", function(d
) {
904 .attr("x2", function(d
) {
907 .on("click", clearSelection
);
910 for (var y
= size
; y
< height
; y
+= size
) {
913 var horz
= d3
.select(".d3-bg-grid-horz").selectAll("line")
916 horz
.enter().append('line')
920 stroke
: "rgba(0,0,0,0.2)",
923 .attr("y1", function(d
) {
926 .attr("y2", function(d
) {
929 .on("click", clearSelection
);
932 function doSnap(state
, selection
) {
933 var bb
= getTransGroupBounds(selection
.node());
934 var left_snap_d
= (Math
.round(bb
.x
/ doSnap
.size
)) * doSnap
.size
- bb
.x
935 var right_snap_d
= (Math
.round((bb
.x
+ bb
.width
) / doSnap
.size
) * doSnap
.size
- bb
.width
) - bb
.x
936 var top_snap_d
= (Math
.round(bb
.y
/ doSnap
.size
)) * doSnap
.size
- bb
.y
937 var bottom_snap_d
= (Math
.round((bb
.y
+ bb
.height
) / doSnap
.size
) * doSnap
.size
- bb
.height
) - bb
.y
938 state
.translate
[0] += Math
.abs(left_snap_d
) < Math
.abs(right_snap_d
) ? left_snap_d
: right_snap_d
939 state
.translate
[1] += Math
.abs(top_snap_d
) < Math
.abs(bottom_snap_d
) ? top_snap_d
: bottom_snap_d
942 function getDataSourceSelect() {
943 get_select_box('label_data_source_types', 'data_source_type', {
944 name
: 'source_type_select',
945 id
: 'source_type_select',
946 default: 'Select a type of data source for the labels',
949 updateDataSourceSelect();
950 jQuery(document
).off("change").on("change", "#source_type_select", updateDataSourceSelect
);
953 function updateDataSourceSelect() {
954 get_select_box('label_data_sources', 'data_source',
956 name
: 'source_select',
958 default: 'Select a data source for the labels',
960 type
: jQuery("#source_type_select option:selected").val()
965 function switchPageDependentOptions(page
) {
966 // load label size and label field options based on page type
967 var label_sizes
= page_formats
[page
].label_sizes
;
968 d3
.select("#label_format").selectAll("option").remove();
969 d3
.select("#label_format").selectAll("option")
970 .data(Object
.keys(label_sizes
))
971 .enter().append("option")
976 d3
.select("#d3-add-type-input").selectAll("option").remove();
977 d3
.select("#d3-add-type-input").selectAll("option")
978 .data(Object
.keys(label_options
))
979 .enter().append("option")
981 return label_options
[d
].name
983 .attr("value", function(d
) {
987 if (page
== 'Zebra printer file') { // disable PDF text option and pdf download, clear pdf text elements
988 $("#d3-add-type-input option[value='PDFText']").remove();
989 switchTypeDependentOptions('ZebraText');
990 document
.getElementById("d3-pdf-button").style
.display
= "none";
991 document
.getElementById("d3-zpl-button").style
.display
= "inline";
992 document
.getElementById("d3-add-font-input").value
= "Courier"; // default for Zebra
994 var label_elements
= document
.getElementsByClassName("label-element");
995 label_elements
= Array
.prototype.slice
.call(label_elements
); // convert to array
996 for (var i
=0; i
<label_elements
.length
; i
++) {
997 var element
= label_elements
[i
];
998 if (element
.getAttribute("type") != "ZebraText") { // remove all non-Zebra elements, barcodes too in case they have been scaled
999 element
.parentNode
.removeChild(element
);
1003 } else { // disable Zebra text option and zpl download, clear zpl text elements
1004 switchTypeDependentOptions('PDFText');
1005 $("#d3-add-type-input option[value='ZebraText']").remove();
1006 document
.getElementById("d3-zpl-button").style
.display
= "none";
1007 document
.getElementById("d3-pdf-button").style
.display
= "inline";
1009 var label_elements
= document
.getElementsByClassName("label-element");
1010 label_elements
= Array
.prototype.slice
.call(label_elements
); // convert to array
1011 for (var i
=0; i
<label_elements
.length
; i
++) {
1012 var element
= label_elements
[i
];
1013 if (element
.getAttribute("type") == "ZebraText") { // remove only text, barcodes can stay
1014 element
.parentNode
.removeChild(element
);
1019 if (page
== 'Custom') { // show Custom inputs and attach handlers
1020 document
.getElementById("d3-custom-dimensions-div").style
.display
= "inline";
1021 document
.getElementById("d3-page-custom-dimensions-div").style
.visibility
= "visible";
1022 document
.getElementById("d3-label-custom-dimensions-div").style
.visibility
= "visible";
1023 document
.getElementById("label_format").value
= 'Custom';
1024 $('#page_width').focus();
1026 $('#page_width').on("change", function() {
1027 page_formats
[page
].page_width
= this.value
;
1030 $('#page-height').on("change", function() {
1031 page_formats
[page
].page_height
= this.value
;
1033 } else { //hide page custom input
1034 document
.getElementById("d3-page-custom-dimensions-div").style
.visibility
= "hidden";
1035 $('#label_format').focus();
1038 if ( page
!= 'Custom' && document
.getElementById("label_format").value
!= 'Custom') { //hide all Custom inputs
1039 document
.getElementById("d3-custom-dimensions-div").style
.display
= "none";
1040 document
.getElementById("d3-page-custom-dimensions-div").style
.visibility
= "hidden";
1041 document
.getElementById("d3-label-custom-dimensions-div").style
.visibility
= "hidden";
1046 function switchLabelDependentOptions(label
) {
1048 var page
= d3
.select("#page_format").node().value
;
1049 var label_sizes
= page_formats
[page
].label_sizes
;
1051 if (label
== 'Custom') {
1052 document
.getElementById("d3-custom-dimensions-div").style
.display
= "inline";
1053 document
.getElementById("d3-label-custom-dimensions-div").style
.visibility
= "visible";
1054 $('#label_width').focus();
1056 jQuery('#select_layout_button').prop('disabled', false)
1057 document
.getElementById("d3-custom-dimensions-div").style
.display
= "none";
1058 document
.getElementById("d3-label-custom-dimensions-div").style
.visibility
= "hidden";
1059 changeLabelSize( label_sizes
[label
].label_width
, label_sizes
[label
].label_height
);
1060 $("#d3-add-and-download-div").removeAttr('style');
1061 $('#d3-add-type-input').focus();
1064 //set addtional options
1065 document
.getElementById("top_margin").value
= label_sizes
[label
].top_margin
;
1066 document
.getElementById("left_margin").value
= label_sizes
[label
].left_margin
;
1067 document
.getElementById("horizontal_gap").value
= label_sizes
[label
].horizontal_gap
;
1068 document
.getElementById("vertical_gap").value
= label_sizes
[label
].vertical_gap
;
1069 document
.getElementById("number_of_columns").value
= label_sizes
[label
].number_of_columns
;
1070 document
.getElementById("number_of_rows").value
= label_sizes
[label
].number_of_rows
;
1073 function switchTypeDependentOptions(type
){
1075 var sizes
= label_options
[type
].sizes
;
1076 if (type
== "PDFText") {
1078 // set up font select
1079 d3
.select("#d3-add-font-input").selectAll("option").remove();
1080 d3
.select("#d3-add-font-input").selectAll("option")
1081 .data(Object
.keys(font_styles
).sort())
1082 .enter().append("option")
1086 .attr("style", function(d
) {
1087 return font_styles
[d
]
1089 .attr("value", function(d
) {
1092 document
.getElementById("d3-add-font-div").style
.visibility
= "visible";
1094 // set up size input and slider
1095 $("#d3-add-size-input").replaceWith('<input type="number" id="d3-add-size-input" class="form-control"></input>');
1096 var size_input
= d3
.select("#d3-add-size-input");
1097 var size_slider
= d3
.select("#d3-add-size-slider");
1098 size_input
.attr(sizes
);
1099 size_slider
.attr(sizes
);
1100 size_slider
.on("input", function() {
1101 size_input
.property("value", this.value
)
1103 size_input
.on("change", function() {
1104 size_slider
.node().value
= this.value
;
1106 $("#d3-add-size-slider").show();
1109 document
.getElementById("d3-add-font-div").style
.visibility
= "hidden";
1110 $("#d3-add-size-input").replaceWith('<select id="d3-add-size-input" class="form-control"></select>  ');
1111 d3
.select("#d3-add-size-input").selectAll("option")
1112 .data(Object
.keys(sizes
))
1113 .enter().append("option")
1117 .attr("value", function(d
) {
1120 $("#d3-add-size-slider").hide();
1124 function addToLabel(field
, text
, type
, size
, font
, x
, y
, width
, height
) {
1125 //console.log("Field is: "+field+" and text is: "+text+" and type is: "+type+" and size is: "+size+" and font is: "+font);
1126 svg
= d3
.select(".d3-draw-svg");
1128 //get x,y coords and scale
1129 if ((typeof x
|| typeof y
) === 'undefined') {
1130 x
= document
.getElementById("d3-label-area").viewBox
.baseVal
.width
/2;
1131 y
= document
.getElementById("d3-label-area").viewBox
.baseVal
.height
/2;
1133 //console.log(" X is: "+x+" and y is: "+y);
1135 //count existing elements
1136 var label_elements
= document
.getElementsByClassName('label-element');
1137 label_elements
= Array
.prototype.slice
.call(label_elements
); // convert to array
1138 var count
= label_elements
.length
;
1140 //set up new element
1141 var new_element
= svg
.append("g")
1142 .classed("draggable", true)
1143 .classed("selectable", true)
1149 //console.log("Adding barcode of type "+type);
1150 //add barcode specific attributes
1152 var page
= d3
.select("#page_format").node().value
;
1153 new_element
.classed("barcode", true)
1154 if ( page
.match(/Zebra/) ) {
1155 new_element
.call(selectable
, false);
1157 new_element
.call(selectable
, true);
1159 var img
= new Image();
1160 img
.src
= "/tools/label_designer/preview?content=" + encodeURIComponent(text
) + "&type=" + encodeURIComponent(type
) + "&size=" + encodeURIComponent(size
);
1161 img
.onload = function() {
1162 var element_width
= width
|| this.width
;
1163 var element_height
= height
|| this.height
;
1164 x
= x
- (element_width
/2);
1165 y
= y
- (element_height
/2);
1166 //console.log("Final x is "+x+" and final y is "+y);
1167 new_element
.call(doTransform
, function(state
, selection
) {
1168 state
.translate
= [x
,y
]
1170 .append("svg:image")
1172 "id": "element"+count
,
1173 "class": "label-element",
1177 "width": element_width
,
1178 "height": element_height
,
1179 "href": "/tools/label_designer/preview?content=" + encodeURIComponent(text
) + "&type=" + encodeURIComponent(type
) + "&size=" + encodeURIComponent(size
),
1186 //add text specific attributes
1187 //console.log("Adding text of type "+type);
1188 var font_size
= parseInt(size
);
1189 if (type
=="ZebraText") {
1190 font_size
= font_size
+ parseInt(font_size
/9);
1192 new_element
.classed("text-box", true)
1193 .call(selectable
, false)
1194 .call(doTransform
, function(state
, selection
) {
1195 state
.translate
= [x
,y
]
1199 "id": "element"+count
,
1200 "class": "label-element",
1204 "font-size": font_size
,
1206 "style": font_styles
[font
],
1207 "text-anchor": "middle",
1208 "alignment-baseline": "middle",
1211 //console.log("Field is: "+field+" and size is: "+size+" and type is: "+type+" and font size is: "+font_size+" and font is: "+font+" and style is: "+font_styles[font]+" and text is: "+text);
1217 function saveAdditionalOptions(top_margin
, left_margin
, horizontal_gap
, vertical_gap
, number_of_columns
, number_of_rows
, plot_filter
, sort_order_1
, sort_order_2
, sort_order_3
, copies_per_plot
) {
1218 // save options in javascript object and in html elements
1219 var page
= d3
.select("#page_format").node().value
;
1220 var label
= d3
.select("#label_format").node().value
;
1221 page_formats
[page
].label_sizes
[label
].top_margin
= top_margin
;
1222 page_formats
[page
].label_sizes
[label
].left_margin
= left_margin
;
1223 page_formats
[page
].label_sizes
[label
].horizontal_gap
= horizontal_gap
;
1224 page_formats
[page
].label_sizes
[label
].vertical_gap
= vertical_gap
;
1225 page_formats
[page
].label_sizes
[label
].number_of_columns
= number_of_columns
;
1226 page_formats
[page
].label_sizes
[label
].number_of_rows
= number_of_rows
;
1227 page_formats
[page
].label_sizes
[label
].plot_filter
= plot_filter
;
1228 page_formats
[page
].label_sizes
[label
].sort_order_1
= sort_order_1
;
1229 page_formats
[page
].label_sizes
[label
].sort_order_2
= sort_order_2
;
1230 page_formats
[page
].label_sizes
[label
].sort_order_3
= sort_order_3
;
1231 page_formats
[page
].label_sizes
[label
].copies_per_plot
= copies_per_plot
;
1232 document
.getElementById("top_margin").value
= top_margin
;
1233 document
.getElementById("left_margin").value
= left_margin
;
1234 document
.getElementById("horizontal_gap").value
= horizontal_gap
;
1235 document
.getElementById("vertical_gap").value
= vertical_gap
;
1236 document
.getElementById("number_of_columns").value
= number_of_columns
;
1237 document
.getElementById("number_of_rows").value
= number_of_rows
;
1238 document
.getElementById("plot_filter").value
= plot_filter
|| 'all';
1239 document
.getElementById("sort_order_1").value
= sort_order_1
;
1240 document
.getElementById("sort_order_2").value
= sort_order_2
;
1241 document
.getElementById("sort_order_3").value
= sort_order_3
;
1242 document
.getElementById("copies_per_plot").value
= copies_per_plot
;
1245 function dragSnap() {
1246 d3
.select(this).call(doTransform
, doSnap
);
1249 function createAdders(add_fields
) {
1250 // load type select options
1251 d3
.select("#d3-add-type-input").selectAll("option").remove();
1252 d3
.select("#d3-add-type-input").selectAll("option")
1253 .data(Object
.keys(label_options
))
1254 .enter().append("option")
1256 return label_options
[d
].name
1258 .attr("value", function(d
) {
1262 //load field options
1263 d3
.select("#d3-add-field-input").selectAll("option").remove();
1264 d3
.select("#d3-add-field-input").selectAll("option")
1265 .data(["Select a field", ...Object
.keys(add_fields
).sort()])
1266 .enter().append("option")
1270 .attr("value", function(d
) {
1271 return add_fields
[d
]
1276 function addPlotFilter(reps
) {
1278 Object
.keys(reps
).forEach(function(key
) {
1279 var newkey
= "Rep "+key
+" only";
1283 reps
['All'] = 'all';
1285 d3
.select("#plot_filter").selectAll("option").remove();
1286 d3
.select("#plot_filter").selectAll("option")
1287 .data(Object
.keys(reps
).sort())
1288 .enter().append("option")
1292 .attr("value", function(d
) {
1298 function addSortOrders(add_fields
, data_type
, data_level
) {
1300 // Set type-specific sorting options
1301 let data_type_fields
= [];
1302 // Sort by trial layout for plot-level labels...
1303 if ( ['Field Trials', 'Lists', 'Public Lists'].includes(data_type
) && data_level
=== 'plots' ) {
1304 data_type_fields
= ['Trial Layout: Plot Order'];
1308 d3
.selectAll("#sort_order_1, #sort_order_2, #sort_order_3").selectAll("option").remove();
1309 d3
.selectAll("#sort_order_1").selectAll("option")
1310 .data(["Select a field", ...data_type_fields
, ...Object
.keys(add_fields
).sort()])
1311 .enter().append("option")
1315 .attr("value", function(d
) {
1318 d3
.selectAll("#sort_order_2, #sort_order_3").selectAll("option")
1319 .data(["Select a field", ...Object
.keys(add_fields
).sort()])
1320 .enter().append("option")
1324 .attr("value", function(d
) {
1327 jQuery("#sort_order_1").off("change").on("change", () => {
1328 const sel
= jQuery("#sort_order_1").val();
1329 if ( sel
=== 'Select a field' ) {
1330 jQuery("#sort_order_2_container, #sort_order_3_container").hide();
1331 jQuery("#sort_order_layout_order_container, #sort_order_layout_start_container").hide();
1333 else if ( sel
=== 'Trial Layout: Plot Order' ) {
1334 jQuery("#sort_order_2_container, #sort_order_3_container").hide();
1335 jQuery("#sort_order_layout_order_container, #sort_order_layout_start_container").show();
1338 jQuery("#sort_order_2_container").show();
1339 jQuery("#sort_order_layout_order_container, #sort_order_layout_start_container").hide();
1342 jQuery("#sort_order_2").off("change").on("change", () => {
1343 const sel
= jQuery("#sort_order_2").val();
1344 if ( sel
=== 'Select a field' ) {
1345 jQuery("#sort_order_3_container").hide();
1348 jQuery("#sort_order_3_container").show();
1353 function checkIfVisible(element
) {
1354 var label_width
= document
.getElementById("d3-label-area").viewBox
.baseVal
.width
;
1355 var label_height
= document
.getElementById("d3-label-area").viewBox
.baseVal
.height
;
1356 var transform_attributes
= parseTransform(element
.parentNode
.getAttribute('transform')); // return transform attributes as an object
1357 var coords
= transform_attributes
.translate
;
1358 var type
= element
.getAttribute("type");
1359 if (coords
[0] > label_width
|| coords
[1] > label_height
) { // ignore elements not visible in draw area
1360 return false; // skip
1366 function getLabelDetails(element
) {
1367 var transform_attributes
= parseTransform(element
.parentNode
.getAttribute('transform')); // return transform attributes as an object
1368 //console.log("Transform attributes are: "+JSON.stringify(transform_attributes));
1369 var coords
= transform_attributes
.translate
;
1370 var scale
= transform_attributes
.scale
|| new Array(1,1);
1371 var rect
= element
.getBBox();
1372 var width
= rect
.width
* scale
[0];
1373 var height
= rect
.height
* scale
[1];
1374 //console.log("Height is: "+height+" and width is: "+width);
1375 var type
= element
.getAttribute("type");
1378 if (type
.match(/Text/)) {
1379 x
= parseInt(coords
[0])
1380 y
= parseInt(coords
[1])
1382 x
= parseInt(coords
[0]) + (width
/2);
1383 y
= parseInt(coords
[1]) + (height
/2);
1391 value
: element
.getAttribute("value"),
1392 type
: element
.getAttribute("type"),
1393 font
: element
.getAttribute("font") || 'Courier',
1394 size
: element
.getAttribute("size")
1398 function parseTransform(transform
) {
1399 var attribute_object
= {};
1400 var attributes
= transform
.split(')');
1402 for (var i
= 0; i
< attributes
.length
; i
++) {
1403 var attribute
= attributes
[i
];
1404 var parts
= attribute
.split('(');
1405 var name
= parts
.shift();
1406 var values
= parts
.join(',');
1407 attribute_object
[name
] = values
.split(',');
1410 return attribute_object
;
1413 function retrievePageParams() {
1415 var page
= d3
.select("#page_format").node().value
;
1416 if (!page
|| page
== 'Select a page format') {
1417 alert("No page format select. Please select a page format");
1420 var label
= d3
.select("#label_format").node().value
;
1421 if (!label
|| label
== 'Select a label format') {
1422 alert("No label format select. Please select a label format");
1425 var label_sizes
= page_formats
[page
].label_sizes
;
1429 page_width
: page_formats
[page
].page_width
|| document
.getElementById("page_width").value
,
1430 page_height
: page_formats
[page
].page_height
|| document
.getElementById("page_height").value
,
1431 left_margin
: label_sizes
[label
].left_margin
,
1432 top_margin
: label_sizes
[label
].top_margin
,
1433 horizontal_gap
: label_sizes
[label
].horizontal_gap
,
1434 vertical_gap
: label_sizes
[label
].vertical_gap
,
1435 number_of_columns
: label_sizes
[label
].number_of_columns
,
1436 number_of_rows
: label_sizes
[label
].number_of_rows
,
1437 plot_filter
: document
.getElementById("plot_filter").value
,
1438 sort_order_1
: document
.getElementById("sort_order_1").value
,
1439 sort_order_2
: document
.getElementById("sort_order_2").value
,
1440 sort_order_3
: document
.getElementById("sort_order_3").value
,
1441 sort_order_layout_order
: document
.getElementById("sort_order_layout_order").value
,
1442 sort_order_layout_start
: document
.getElementById("sort_order_layout_start").value
,
1443 copies_per_plot
: document
.getElementById("copies_per_plot").value
,
1444 labels_to_download
: document
.getElementById("label_designer_labels_to_download").value
,
1445 start_number
: document
.getElementById("label_designer_start_number").value
,
1446 end_number
: document
.getElementById("label_designer_end_number").value
,
1447 label_format
: label
,
1448 label_width
: label_sizes
[label
].label_width
,
1449 label_height
: label_sizes
[label
].label_height
,
1450 start_col
: document
.getElementById("start_col").value
,
1451 start_row
: document
.getElementById("start_row").value
,
1457 function initializeCustomModal(add_fields
) {
1458 //load field options
1459 d3
.select("#d3-custom-add-field-input").selectAll("option").remove();
1460 d3
.select("#d3-custom-add-field-input").selectAll("option")
1461 .data(["Select a field", ...Object
.keys(add_fields
).sort()])
1462 .enter().append("option")
1466 .attr("value", function(d
) {
1467 return add_fields
[d
]
1470 $('#d3-custom-add-field-input').on("change", function() {
1472 var value
= $(this).find('option:selected').text();
1473 if (!value
|| value
== 'Select a field') {
1476 var custom_field
= $("#d3-custom-input").val() + "{" + value
+ "}";
1477 $("#d3-custom-input").val(custom_field
);
1482 $("#d3-custom-preview").on("click", function() {
1483 var custom_field
= $("#d3-custom-input").val();
1484 var result
= custom_field
.replace(/\{(.*?)\}/g, function(match
, token
) {
1485 console
.log("token is "+token
);
1486 if (token
.match(/Number:/)) {
1487 var parts
= token
.split(':');
1490 return add_fields
[token
];
1493 $("#d3-custom-content").text(result
);
1496 $("#d3-add-number").on("click", function() {
1497 var custom_field
= $("#d3-custom-input").val() + "{Number:" + $('#start_number').val() +":"+ $('#increment_number').val()+"}";
1498 $("#d3-custom-input").val(custom_field
);
1503 function enableDrawArea() {
1504 var intro_elements
= document
.getElementsByClassName("d3-intro-text");
1505 for (var i
=0; i
<intro_elements
.length
; i
++) { intro_elements
[i
].style
.display
= "none"; }
1506 var label_elements
= document
.getElementsByClassName("label-element");
1507 for(var i
=0; i
<label_elements
.length
; i
++) { label_elements
[i
].style
.display
= "inline"; }
1510 function disableDrawArea() {
1511 var intro_elements
= document
.getElementsByClassName("d3-intro-text");
1512 for (var i
=0; i
<intro_elements
.length
; i
++) { intro_elements
[i
].style
.display
= "inline"; }
1513 var label_elements
= document
.getElementsByClassName("label-element");
1514 for(var i
=0; i
<label_elements
.length
; i
++) { label_elements
[i
].style
.display
= "none"; }
1517 function saveLabelDesign() {
1518 var label_elements
= document
.getElementsByClassName('label-element');
1519 label_elements
= Array
.prototype.slice
.call(label_elements
); // convert to array
1520 if (label_elements
.length
< 1) {
1521 alert("No elements in the design. Please add design elements before saving");
1525 var lo
= new CXGN
.List();
1526 var new_name
= $('#save_design_name').val();
1527 page_params
= JSON
.stringify(retrievePageParams());
1529 if (!page_params
) {return;}
1530 var data
= page_params
.slice(1, -1).split(",").join("\n"); // get key value pairs in list format
1531 label_params
= label_elements
.filter(checkIfVisible
).map(getLabelDetails
);
1533 for (i
=0; i
< label_params
.length
; i
++) { // add numbered element key for each set of label params
1534 data
+= '\n"element'+i
+'": '+JSON
.stringify(label_params
[i
]);
1537 list_id
= lo
.newList(new_name
);
1539 var elementsAdded
= lo
.addToList(list_id
, data
);
1540 lo
.setListType(list_id
, 'label_design');
1542 if (elementsAdded
) {
1543 alert("Saved label design with name " + new_name
);
1547 function fillInPlaceholders(match
, placeholder
) { // replace placeholders with actual values
1548 var filled
= add_fields
[placeholder
];
1549 // console.log("Filling "+placeholder+" with "+filled);
1550 if (typeof filled
=== 'undefined' && !placeholder
.match(/Number:/)) {
1551 // console.log(placeholder+" is undefined. Alerting with warning");
1552 alert("Missing field. Your selected design includes the field "+placeholder
+" which is not available from the selected data source. Please pick a different saved design or data source, or remove the undefined field from the design area.")
1557 function showLoadOption() {
1558 // document.getElementById('design_label').style.display = "inline";
1559 // document.getElementById('design_list').style.display = "inline";
1560 var lo
= new CXGN
.List();
1561 $('#design_list').html(lo
.listSelect('design_list', ['label_design'], 'Select a saved design', 'refresh', undefined));
1562 $('#design_list_list_select').change(
1564 Workflow
.complete(this);
1565 loadDesign(this.value
);
1566 jQuery('#design_label_button').prop('disabled', false);
1570 function loadDesign (list_id
) {
1571 // console.log("Loading design from list with ID "+list_id);
1572 // clear existing draw area
1573 initializeDrawArea();
1575 var lo
= new CXGN
.List();
1576 var list_data
= lo
.getListData(list_id
);
1577 var elements
= list_data
.elements
;
1579 //parse into javascript object
1580 var fixed_elements
= Object
.values(elements
).map(function(e
){ return e
.pop(); });
1581 var params
= JSON
.parse("{"+fixed_elements
.join(',')+"}");
1583 for (var key
in params
) {
1584 if (key
.match(/element/)) {
1585 var element_obj
= params
[key
];
1586 var value
= element_obj
.value
;
1587 var text
= value
.replace(/\{(.*?)\}/g, fillInPlaceholders
);
1588 //console.log("Width is "+element_obj.width);
1589 addToLabel(value
, text
, element_obj
.type
, element_obj
.size
, element_obj
.font
, element_obj
.x
, element_obj
.y
, element_obj
.width
, element_obj
.height
);
1593 var page
= params
['page_format'];
1594 document
.getElementById('page_format').value
= page
;
1595 //console.log("page is "+page);
1596 switchPageDependentOptions(page
);
1597 if (page
== 'Custom') {
1598 document
.getElementById("page_width").value
= params
['page_width'];
1599 document
.getElementById("page_height").value
= params
['page_height'];
1602 var label
= params
['label_format'];
1603 document
.getElementById('label_format').value
= label
;
1604 switchLabelDependentOptions(label
);
1605 if (label
== 'Custom') {
1606 document
.getElementById("label_width").value
= params
['label_width'];
1607 document
.getElementById("label_height").value
= params
['label_height'];
1608 page_formats
[page
].label_sizes
['Custom'].label_width
= params
['label_width'];
1609 page_formats
[page
].label_sizes
['Custom'].label_height
= params
['label_height'];
1610 changeLabelSize(params
['label_width'], params
['label_height']);
1611 $("#d3-add-and-download-div").removeAttr('style');
1615 saveAdditionalOptions(
1616 params
['top_margin'],
1617 params
['left_margin'],
1618 params
['horizontal_gap'],
1619 params
['vertical_gap'],
1620 params
['number_of_columns'],
1621 params
['number_of_rows'],
1622 params
['plot_filter'],
1623 params
['sort_order_1'],
1624 params
['sort_order_2'],
1625 params
['sort_order_3'],
1626 params
['copies_per_plot']