%\iffalse
% makeindex -s gglo.ist -o bargraph-js.gls bargraph-js.glo
% makeindex -s gind.ist -o bargraph-js.ind bargraph-js.idx
%<*copyright>
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% bargraph-js.sty package,                              %%
%% Copyright (C) 2019                                    %%
%%   dpstory@uakron.edu                                  %%
%%                                                       %%
%% This program can redistributed and/or modified under  %%
%% the terms of the LaTeX Project Public License         %%
%% Distributed from CTAN archives in directory           %%
%% macros/latex/base/lppl.txt; either version 1.2 of the %%
%% License, or (at your option) any later version.       %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%</copyright>
%<package>\NeedsTeXFormat{LaTeX2e}[1997/12/01]
%<package>\ProvidesPackage{bargraph-js}
%<package> [2019/04/07 v0.8 bargraph-js: Create bar graphs using form fields and JavaScript]
%<*driver>
\documentclass{ltxdoc}
\usepackage{xcolor}
\usepackage[colorlinks,hyperindex=false,bookmarksopen=false]{hyperref}
\usepackage{bargraph-js}
%\pdfstringdefDisableCommands{\let\\\textbackslash}
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\gdef\brpr#1{\texttt{\char123\relax#1\char125\relax}}
\let\darg\brpr
\let\env\texttt
\let\opt\texttt
\let\app\textsf
\let\pkg\textsf
\def\visispace{\symbol{32}}
\def\ameta#1{\ensuremath{\langle\textit{\texttt{#1}}\rangle}}
\def\meta#1{\textsl{\texttt{#1}}}
\def\SUB#1{\ensuremath{{}_{\mbox{\scriptsize\ttfamily#1}}}}
%\def\cs#1{\texttt{\bslash#1}}
\DeclareRobustCommand{\tmspace}[3]{%
  \ifmmode\mskip#1#2\else\kern#1#3\fi\relax}
\renewcommand{\,}{\tmspace+\thinmuskip{.1667em}}
\let\thinspace\,
\renewcommand{\!}{\tmspace-\thinmuskip{.1667em}}
\let\negthinspace\!
\renewcommand{\:}{\tmspace+\medmuskip{.2222em}}
\let\medspace\:
\newcommand{\negmedspace}{\tmspace-\medmuskip{.2222em}}
\renewcommand{\;}{\tmspace+\thickmuskip{.2777em}}
\let\thickspace\;
\newcommand{\negthickspace}{\tmspace-\thickmuskip{.2777em}}
\makeatletter
\renewcommand{\paragraph}
    {\@startsection{paragraph}{4}{0pt}{6pt}{-3pt}
    {\normalfont\normalsize\bfseries}}
\renewenvironment{quote}[1][]
   {\def\@rgi{#1}\ifx\@rgi\@empty
    \let\rghtm\@empty\else\def\rghtm{\rightmargin\leftmargin}\fi
    \list{}{\rghtm} %{\rightmargin\leftmargin}%
    \item\relax}
   {\endlist}
\makeatother
\InputIfFileExists{aebdocfmt.def}{\PackageInfo{bargraph-js}{Inputting aebdocfmt.def}}
    {\def\IndexOpt{\DescribeMacro}\def\IndexKey{\DescribeMacro}\let\setupFullwidth\relax
     \PackageInfo{bargraph-js}{aebdocfmt.def cannot be found}}
\begin{document}
\def\CMD#1{\textbackslash#1}
  \GetFileInfo{bargraph-js.sty}
  \title{\textsf{bargraph-js}: Create dynamic bar graphs using form fields and JavaScript}
  \author{D. P. Story\\
    Email: \texttt{dpstory@acrotex.net}}
  \date{processed \today}
  \maketitle
  \tableofcontents
  \let\Email\texttt
  \DocInput{bargraph-js.dtx}
\IfFileExists{\jobname.ind}{\newpage\setupFullwidth\par\PrintIndex}{\paragraph*{Index} The index goes here.\\Execute
    \texttt{makeindex -s gind.ist -o bargraph-js.ind bargraph-js.idx}\\on the command line and recompile
    \texttt{bargraph-js.dtx}.}
\IfFileExists{\jobname.gls}{\PrintChanges}{\paragraph*{Change History} The list of changes goes here.\\Execute
    \texttt{makeindex -s gglo.ist -o bargraph-js.gls bargraph-js.glo}\\on the command line and recompile
    \texttt{bargraph-js.dtx}.}
\end{document}
%</driver>
% \fi
% \MakeShortVerb{|}
%
% \InputIfFileExists{aebdonotindex.def}{\PackageInfo{web}{Inputting aebdonotindex.def}}
%    {\PackageInfo{web}{cannot find aebdonotindex.def}}
%
%    \begin{macrocode}
%<*package>
\RequirePackage{xkeyval}
%    \end{macrocode}
%    \section{Introduction}
%    Through {\LaTeX} markup, a document author can create a PDF with form fields.
%    \app{Adobe Acrobat Reader DC} (as well as the \app{Acrobat} application itself) allows you to change
%    the properties of this field through the JavaScript engine; in particular, the dimensions
%    of the bounding rectangles of the form fields can be changed. Changes to form fields can be saved as well.
%
%    An {Acro\negthinspace\TeX} user (GBH) wanted to create a bar graph
%    reflecting the responses of his students. This package is a generalization
%    of that solution.
%
%    A bar graph is based on qualitative (or categorical) data. The raw data
%    is classified by some criterion and and a numerical value is assigned (often times the value is a count,
%    but need not be). Totals for each category are
%    recorded in the form of a bar graph. Graphs may be vertically or
%    horizontally oriented. In this package, we address such problems as (1)
%    creation and coloring of the bar graph; (2) scaling; and (3) labeling.
%    Conceptually, more than one bar graph can be placed, one superimposed on
%    top the other.
%    \section{Options and requirements}
%    We only have one option, \IndexOpt{dynamic}\opt{dynamic}, this brings in some JavaScript to support
%    the creation of bar graphs with no explicit use of \cs{barfor} commands; this is
%    used in creating histograms for discrete probability distributions.
%    \begin{macrocode}
\DeclareOptionX{dynamic}{\def\bgjs@importDynamic
  {\InputIfFileExists{dynam-js.def}{}{\PackageWarning{bargraph-js}
    {The file dynam-js.def cannot be found}}}}
\let\bgjs@importDynamic\relax
\ProcessOptionsX\relax
\AtEndOfPackage{\bgjs@importDynamic}
\RequirePackage{xcolor}
\RequirePackage{eforms}[2019/05/24]
\edef\bgjs@restoreCats{\catcode`\noexpand\"=\the\catcode`\"\relax}
\@makeother\"
%    \end{macrocode}
%    An initial scale factor. The scale factor is dynamically reset, as needed. However, when a bar graph
%    is cleared, \DescribeMacro\scaleFactorDef\cs{scaleFactorDef} is used.
%    \begin{macrocode}
\def\scaleFactorDef#1{\def\sc@leF@ctorDef{#1}}
\scaleFactorDef{2}
%    \end{macrocode}
%
%    \section{The \texttt{bargraphenv} and \texttt{bargraph} environments}
%    A bar graph is built within an \env{bargraphenv} environment that controls it.
%    \begin{environment}{bargraphenv}
%    A \env{bargraph} environment (defined later)  is contained within the \env{bargraphenv}
%    environment. The \env{bargraphenv} has a number of key-values to set.
%    \paragraph*{Key-values for \env{bargraphenv}} \leavevmode\IndexKey{width}\texttt{width} is the width of the underlying
%    \texttt{minipage}; similarly, \IndexKey{height}\texttt{height} is its height.
%    \begin{macrocode}
\define@key{bgrphenv}{width}[\linewidth]{\setlength{\@tempdima}{#1}%
  \ifxetex\else\addtolength{\@tempdima}{2bp}\fi
  \edef\bgrphenv@width{\the\@tempdima}\@tempdima=.99626\@tempdima
  \edef\bgrphenv@widthbp{\strip@pt\@tempdima}}
\define@key{bgrphenv}{height}[2in]{\setlength{\@tempdima}{#1}%
  \edef\bgrphenv@height{\the\@tempdima}\@tempdima=.99626\@tempdima
  \edef\bgrphenv@heightbp{\strip@pt\@tempdima}}
%    \end{macrocode}
% A switch, a counter, and a token register used by this package.
%    \begin{macrocode}
\newif\ifhorizontalbars \horizontalbarsfalse
\newcount\cntbars \cntbars=0
\newtoks\bgtoks
%    \end{macrocode}
%    \leavevmode\IndexKey{o}\hskip-\marginparsep\texttt{=\ameta{{\upshape{horiz\string|vert}}}}
%    When \texttt{o=vert}, the default, the bars of the bargraph
%    increase/decrease vertically (height changes); while for
%    \texttt{o=horiz}, they increase/decrease horizontally (width changes).
%    \begin{macrocode}
\define@choicekey{bgrphenv}{o}[\val\nr]{horiz,vert}{%
  \ifcase\nr\relax
    \horizontalbarstrue\or
    \horizontalbarsfalse\else
    \horizontalbarsfalse\fi}
%    \end{macrocode}
%    \leavevmode\IndexKey{origin}\hskip-\marginparsep\texttt{=\ameta{\upshape0\string|.5}} Sets the origin of the bar graph.
%    When \texttt{origin=0}, the baseline of the bars is the horizontal axis (\texttt{o=vert}) or the vertical
%    axis (\texttt{o=horiz}); when \texttt{origin=.5}, the baseline of the bars is on a line positioned half-way
%    up the vertical axis (\texttt{o=vert}) or half-way across the horizontal axis (\texttt{o=horiz}).
%    \begin{macrocode}
\define@choicekey+{bgrphenv}{origin}{0,.5}[0]{\def\bgjs@origin{#1}}
  {\PackageWarning{bargraph-js}{Bad choice for origin,
  permissible values are 0 and .5.\MessageBreak
  Will use a value of 0. Try again}}
\def\bgjs@origin{0}
%    \end{macrocode}
%    \leavevmode\IndexKey{showaxis}\hskip-\marginparsep\texttt{=\ameta{\upshape{true\string|false}}}
%    If true, a horizontal or vertical axis is drawn, depending on the setting of the \texttt{o} key.
%    \begin{macrocode}
\newif\if@bgshowaxis \@bgshowaxisfalse % dps23 \catcode`\%=14\relax
\define@boolkey{bgrphenv}[@bg]{showaxis}[true]{}
%    \end{macrocode}
%    The following \env{defineJS} environment defines \cs{hided@t@Fmt}. It declares
%    some vital data for the current \env{bargraphenv} environment. In this environment
%    we make exclamation point (\texttt!) the escape, and the comment character as \texttt{\%}.
%    \begin{macrocode}
\begin{defineJS}[\catcode`\!=0\relax]{\hided@t@Fmt}
if (typeof dataForEnv=="undefined")
  var dataForEnv=new Object;
dataForEnv["!p(1)"]=new Object;
dataForEnv["!p(1)"].width=!bgrphenv@widthbp;
dataForEnv["!p(1)"].height=!bgrphenv@heightbp;
dataForEnv["!p(1)"].horiz=!ifhorizontalbars(true)!else(false)!fi;
dataForEnv["!p(1)"].sf=!sc@leF@ctorDef;
dataForEnv["!p(1)"].bgs=[!bg@list];
dataForEnv["!p(1)"].origin=!bgjs@origin;
var _nO=!bgjs@origin;
var r=event.target.rect;
if (dataForEnv["!p(1)"].horiz){
  var _w1=_nO*dataForEnv["!p(1)"].width;
  dataForEnv["!p(1)"].maxDim=(_nO==0)?!%
!bgrphenv@widthbp:Math.min(_w1,!bgrphenv@widthbp-_w1);
  dataForEnv["!p(1)"].baseline=r[0]+_w1;
} else {
  var _h1=_nO*dataForEnv["!p(1)"].height;
  dataForEnv["!p(1)"].maxDim=(_nO==0)?!%
!bgrphenv@heightbp:Math.min(_h1,!bgrphenv@heightbp-_h1);
  dataForEnv["!p(1)"].baseline=r[3]+_h1;
}
dataForEnv["!p(1)"].values=new Object;
\end{defineJS}
%    \end{macrocode}
%    This text field holds various information about the \env{bargraphenv} named \texttt{\#1}.
%    In this definition, we say |\cmd{\let\%\defjsLB}|; the format code is passed using
%    \cs{hided@t@Fmt}, which is defined by a \env{defineJS} environment above. We also pass
%    a parameter (|\bgrphenv@name=|\ameta{bgenv-name}) to \cs{hided@t@Fmt} through the \cs{bParams}/\cs{eParams} mechanism.
%    \begin{macrocode}
\def\internalD@t@Hidden#1{%
  \llap{\textField[\cmd{\bParams{#1}\eParams\let\%\defjsLB}
  \autoCenter{n}\BC{}\BG{}\S{S}\textSize{0}\Ff{\FfReadOnly}
  \AA{\AAFormat{\hided@t@Fmt}}]{internalData.#1}{2bp}{2bp}}}
%    \end{macrocode}
%    \DescribeEnv{bargraphenv}\hskip-\marginparsep\texttt{[\ameta{KV-pairs}]\darg{\ameta{env-name}}}
%    The \env{bargraphenv} simply encloses the \env{bargraph} environment in a
%    \env{minipage} of dimensions specified by the key-values.
%    \begin{macrocode}
\def\bg@vs#1{\setlength\@tempdima{#1}\vskip\@tempdima}
\def\bg@hs#1{\setlength\@tempdima{#1}\hskip\@tempdima}
%    \end{macrocode}
%    \DescribeMacro\oBgEnvs is an internal command that will hold a comma-delimited list
%    of all \env{bargraphenv}s in the document.
%    \begin{macrocode}
\let\oBgEnvs\@gobble
\newif\ifisbgenv\isbgenvfalse
\let\barNum\ef@Zero
\def\bg@warning{\PackageWarningNoLine{bargraph-js}
  {At least one more compile is required}\global\let\bg@warning\@empty}
\newenvironment{bargraphenv}[2][]{\offinterlineskip
%    \end{macrocode}
% Within the \env{bargraphenv}, we define \DescribeMacro\vs\cs{vs} and \DescribeMacro\hs\cs{hs} to position objects
% vertically and horizontally.
% These are local definitions. Syntax: \cs{vs\darg{\ameta{dimen}}} and \cs{hs\darg{\ameta{dimen}}}.
%    \begin{macrocode}
  \let\vs\bg@vs\let\hs\bg@hs\global\isbgenvtrue
  \@ifundefined{envname@#2}{\global\@namedef{envname@#2}{#2}}
    {\PackageWarning{bargraph-js}
      {The name '#2' has been used in an earlier\MessageBreak
      bargraphenv environment, please choose another\MessageBreak
      name for the bargraphenv environment that\MessageBreak
      appears}}%
  \g@addto@macro\oBgEnvs{,"#2":\dl@lBrace\dl@rBrace}%
  \def\bgrphenv@name{#2}\setkeys{bgrphenv}{width,height,#1}%
  \ifhorizontalbars
    \@tempdima\bgrphenv@width\relax
    \@tempdima=\bgjs@origin\@tempdima
    \edef\bgjs@setorigin{\the\@tempdima}%
  \else % vertical
    \@tempdima\bgrphenv@height\relax
    \@tempdima=\bgjs@origin\@tempdima
    \edef\bgjs@setorigin{\the\@tempdima}%
  \fi
  \@tempdima=.99626\@tempdima
  \edef\bgrphenv@setoriginbp{\strip@pt\@tempdima}%
  \let\isdynamic\relax\let\bg@list\@gobble
  \global\let\barNum\ef@Zero
  \begin{minipage}[b][\bgrphenv@height][b]{\bgrphenv@width}\hfuzz4pt}
    {\hfill\end{minipage}\leavevmode
    \ifx\txtBgValues\relax\else
      \@ifundefined{OBgEnvs}{\bg@warning}{\txtBgValues
      \global\let\txtBgValues\relax}\fi
    \internalD@t@Hidden{\bgrphenv@name}}
%    \end{macrocode}
%    \end{environment}
%    \begin{environment}{bargraph}\hskip-\marginparsep\texttt{[\ameta{KV-pairs}]\darg{\ameta{bar-name}}}
%    The description of an individual bar graph. This environment is contained
%    within the \env{bargraphenv} environment. The content of the environment
%    \emph{must consist exclusively} of the commands
%    \cs{barfor\darg{\ameta{bar-name}}} and \cs{cmd\darg{\ameta{tex-cmds}}}.
%    These pairs of tokens are collected and stacked up in their natural order.
%    The \env{bargraph} environment has number of key-values to set
%
%    \paragraph*{Key-values for \env{bargraph}} The environment has several key-value pairs.\medskip
%
%    \noindent\IndexKey{nbars}\hskip-\marginparsep\texttt{=\ameta{pos-int}}
%    \texttt{nbars} is the number of bars in this environment.
%    \begin{macrocode}
\define@key{bargraph}{nbars}[0]{\gdef\nbars{#1}}
\def\nb@rsDef{0}
\def\nbars{0}
%    \end{macrocode}
%    \leavevmode\IndexKey{gap}\hskip-\marginparsep\texttt{=\ameta{pos-num}}
%    \texttt{gap} is the gap between bars; it is a positive number (\emph{no dimensions}).
%    It is interpreted as printer points (bp, big points).
%    \begin{macrocode}
\define@key{bargraph}{gap}[0]{\gdef\bargap{#1bp}}
\def\b@rgapDef{0}
\def\bargap{0bp} % in bp units
%    \end{macrocode}
%    \leavevmode\IndexKey{bardimen}\hskip-\marginparsep\texttt{=\ameta{pos-num}}
%    is the width/height of the bars (measured in bp points). When
%    \texttt{o=vert}, then the value of \texttt{bardimen} is the width of each bar;
%    when \texttt{o=horiz}, the value of \texttt{bardimen} is the height of each bar.
%    The value \ameta{pos-num} is a dimensionless number.
%    \begin{macrocode}
\define@key{bargraph}{bardimen}{\gdef\bardimen{#1bp}}
\def\b@rdimenDef{20}
\def\bardimen{20bp} % in bp units
%    \end{macrocode}
%     \cs{bgjs@seto} begins the process of gathering the command pairs
%     \cs{barfor\darg{\ameta{name}}} and \cs{cmd\darg{\ameta{cmds}}}.
%    \begin{macrocode}
\def\bgjs@seto{\cntbars\@ne
  \ifx\barNum\ef@Zero\relax
    \global\let\barNum\ef@One
    \toks@={\ifhorizontalbars\else\ifxetex\else
      \hskip2bp\fi\fi}\else\toks@={}\fi\bgjs@gettype}
%    \end{macrocode}
%     \cs{bgjs@gettype} continues \cs{bgjs@seto}, it determines if this is a dynamic \env{bargraph} environment or not
%    \begin{macrocode}
\def\bgjs@gettype{\@ifnextchar\relax
  {\bgjs@dynamic}{\bgjs@@getbartoks}}
\def\expbarfor#1\@nil{#1}
%    \end{macrocode}
%     The \cs{bgjs@dynamic} command continues \cs{bgjs@gettype} in the first case. It is the case where JavaScript does it
%     all. We create only an initial bar, whose name is `\texttt{x\ameta{bar-name}.bgnoname@\ameta{env}}'.
%    \begin{macrocode}
\def\bgjs@dynamic{\let\b@rforCommon\dyb@rforCommon
  \edef\bgrph@name{x\bgrph@name}\leavevmode
  \rlap{\barfor{bgnoname}}}
%    \end{macrocode}
%     The \cs{bgjs@@getbartoks} command continues \cs{bgjs@gettype} in the
%     second case. We detect two types of tokens:
%     \cs{barfor\darg{\ameta{arg}}} and \cs{cmd\darg{\ameta{arg}}}. If this
%     former, we jump to \cs{bgjs@@getbarfor}, otherwise, we jump to
%     \cs{bgjs@@getcmd}.
%    \begin{macrocode}
\def\bgjs@@getbartoks{\@ifnextchar\barfor
  {\bgjs@@getbarfor}{\@ifnextchar\cmd
    {\bgjs@@getcmd}{\relax}}}%
%    \end{macrocode}
%   The \cs{bgjs@@getbarfor} command handles \cs{barfor} tokens, processing depends on
%   \texttt{o=\ameta{\upshape{vert\string|horiz}}}.
%    \begin{macrocode}
\def\hmrk{\hskip\bgjs@setorigin\relax}
\def\bgjs@@getbarfor\barfor#1{%
  \ifhorizontalbars % o=horiz
    \toks@=\expandafter{\the\toks@\leavevmode
      \rlap{\hmrk\bgjs@adj\barfor{#1}}}%
    \ifnum\cntbars=\nbars\relax
      \toks@=\expandafter{\the\toks@\vcgBdry[0bp]}\else
      \toks@=\expandafter{\the\toks@\vcgBdry[\bargap]}\fi
  \else % o=vert
    \toks@=\expandafter{\the\toks@
      \raisebox{\bgjs@setorigin+\bgjs@adj}{\barfor{#1}}}%
    \ifnum\cntbars=\nbars\relax
      \toks@=\expandafter{\the\toks@\cgBdry[0bp]}\else
      \toks@=\expandafter{\the\toks@\cgBdry[\bargap]}\fi
  \fi
  \advance\cntbars\@ne
  \ifnum\cntbars>\nbars
    \def\bgjs@next{\@ifnextchar\cmd{\bgjs@@getbartoks}
    {\let\\\expbarfor\the\toks@}}%
  \else
    \def\bgjs@next{\bgjs@@getbartoks}\fi
  \unskip\bgjs@next}
%    \end{macrocode}
%   The \cs{bgjs@@getcmd} command handles \cs{barfor} tokens. Again, the processing depends on
%   \texttt{o=\ameta{\upshape{vert\string|horiz}}}.
%    \begin{macrocode}
\def\bgjs@@getcmd\cmd#1{%
  \toks@=\expandafter{\the\toks@#1}%
  \ifhorizontalbars % o=horiz
    \ifnum\cntbars=\nbars\relax
      \toks@=\expandafter{\the\toks@}\else
      \toks@=\expandafter{\the\toks@}\fi
  \else % o=vert
    \ifnum\cntbars=\@ne
      \toks@=\expandafter{\the\toks@}\else
      \toks@=\expandafter{\the\toks@}\fi
  \fi
  \ifnum\cntbars>\nbars
    \def\bgjs@next{\@ifnextchar\cmd{\bgjs@@getbartoks}
    {\let\\\expbarfor\the\toks@}}\else
    \def\bgjs@next{\bgjs@@getbartoks}\fi
\bgjs@next}
%    \end{macrocode}
%    Here we finally define the \DescribeEnv{bargraph}\env{bargraph} environment; it records its name,
%    processes its key-values, and expands \cs{bgjs@seto}.
%    \begin{macrocode}
\newenvironment{bargraph}[2][]{\def\bgrph@name{#2}%
  \g@addto@macro\bg@list{,"#2"}\setkeys{bargraph}{nbars=\nb@rsDef,
    bardimen=\b@rdimenDef,gap=\b@rgapDef,#1}%
  \edef\bg@sign{\ifxetex-\else+\fi}%
  \edef\bgjs@adj{\ifhorizontalbars
    \ifxetex\else\hskip2bp\fi\else+\ifxetex0pt\else2bp\fi\fi}%
  \if@bgshowaxis\ifhorizontalbars\else\leavevmode
    \smash{\makebox[0pt][l]{\raisebox{\bgjs@setorigin\bg@sign.5pt}%
      {\rule{\bgrphenv@width}{1pt}}}}\fi\fi
  \bgjs@seto}{\if@bgshowaxis\ifhorizontalbars
    \smash{\rlap{\setlength{\@tempdima}
      {\bgjs@setorigin\bg@sign.5pt}%
    \hskip\@tempdima\rule{1pt}{\bgrphenv@height}}}\fi\fi}
%    \end{macrocode}
%    \end{environment}
%\paragraph*{Saving the bar data.} We need to save the value of each bar so that
%  when the user re-opens the document, the bar graphs will work as designed,
%  including the optimization. We initialize this text field using \cs{OBgEnvs}.
%    \begin{macrocode}
\def\txtBgValues{%\leavevmode
  \llap{\textField[\S{S}\H{N}\BG{}\BC{}\F{\FHidden}%
  \autoCenter{n}\DV{(\{\OBgEnvs\})}\V{(\{\OBgEnvs\})}
  ]{bgValues}{2bp}{2bp}}\llap{\textField[\S{S}\H{N}\BG{}\BC{}
  \F{\FHidden}\autoCenter{n}\DV{}\V{}]{barLabeling}{2bp}{2bp}}%
}
%    \end{macrocode}
%    The definition of \DescribeMacro\OBgEnvs\cs{OBgEnvs} is written the auxiliary
%    file and is based in \DescribeMacro\oBgEnvs\cs{oBgEnvs}, which is an ongoing comma-delimited list of
%    all names of \env{bargraphenvs} in the document.
%    \begin{macrocode}
\gdef\bg@wrtBbValues{\immediate\write\@auxout{\string
  \gdef\string\OBgEnvs{\oBgEnvs}}}
%    \end{macrocode}
%    At the end of the document, we issued \cs{wrtBgValues}, which defines the command
%    \cs{OBgEnvs}. The command is a list of all \env{bargraphenv}s in the document and is used
%    to build a JavaScript object that will hold the values of each bar in the document.
%    \begin{macrocode}
\AtEndDocument{\ifisbgenv\bg@wrtBbValues\fi}
%    \end{macrocode}
%    \section{Designing the bars}
%    The bars themselves are pushbuttons (created by \cs{pushButton} of \pkg{eforms}). The problem is to pass
%    any appearance changes to the \env{bargraph} environment. We pass the bars in two ways:
%    (1) key-values that are common to all bars; (2) key-values that are individual to a bar.
%    \begin{macro}{\barforCommon}\leavevmode
%    \hskip-\marginparsep\texttt{\,\darg{\ameta{KV-pairs}}}
%    Pass \pkg{eforms} key-values that will be applied to all bars in this environment.
%    \begin{macrocode}
\def\barforCommon#1{\def\b@rforCommon{#1}}
%    \end{macrocode}
%     Below are the default common key-value properties for a bar.
%    \begin{macrocode}
\barforCommon{\S{S}\H{N}\BG{}\BC{}\F{\FHidden}\autoCenter{n}}
%    \end{macrocode}
%     \leavevmode\DescribeMacro{\dybarforCommon}
%    \hskip-\marginparsep\texttt{\,\darg{\ameta{KV-pairs}}}
%     The properties set by \cs{dybarforCommon} are the properties of the bars when the bars are dynamically generated. Bar
%     are generated
%     dynamically when there are no \cs{barfor} commands in the \env{bargraph} environment.
%    \begin{macrocode}
\def\dybarforCommon#1{\def\dyb@rforCommon{#1}}
\dybarforCommon{\S{S}\H{N}\BG{}\BC{}\F{\FHidden}}
%    \end{macrocode}
%    \end{macro}
%    \begin{macro}{\presetsbarfor}
%    \leavevmode
%    \hskip-\marginparsep\texttt{\,\darg{\ameta{bar-name}}\darg{\ameta{name}}\darg{\ameta{KV-pairs}}}
%    Pass customizing key-values to an individual bar. A bar (as defined by \cs{barfor}, defined below)
%    takes a \ameta{name} argument, which is used to reference that bar. For example, to color the
%    bar \ameta{name}, we say \cs{presetbarfor\darg{\ameta{bar-name}}\darg{\ameta{name}}\darg{\cs{BG\darg{red}}}}.
%    \begin{macrocode}
\def\presetsbarfor#1#2#3{\protectedKeys{#1.#2@\bgrphenv@name}{#3}}
%\toks@={}\bgjs@gettwo#3\bgjs@stop\relax
%  \expandafter\edef\csname #1.#2@\bgrphenv@name\endcsname{\the\toks@}}
%\def\bgjs@stop{\relax}\def\bgjs@relax{\relax}
%    \end{macrocode}
%    For this preset, we need to fully expand, while protecting the key-values. We store
%    key-value pairs in \cs{toks@} but we place \cs{noexpand} front of the key; for example
%    \cs{BG\darg{red}} is stored as \cs{noexpand\cs{BG}\darg{red}}.
%    \begin{macrocode}
%\def\bgjs@gettwo#1#2{\ifx#1\bgjs@stop\else
%  \toks@=\expandafter{\the\toks@\noexpand#1{#2}}\expandafter
%  \bgjs@gettwo\fi}
\def\presetsb@rfor#1{\@nameuse{\bgrph@name.#1@\bgrphenv@name}}
%    \end{macrocode}
%    \end{macro}
%    \begin{macro}{\barfor}\hskip-\marginparsep\texttt{\,\darg{\ameta{name}}}
%     Within the \env{bargraph} environment, place the named \cs{barfor} command.
%    \begin{macrocode}
\def\barfor#1{\ifhorizontalbars\def\bgenv@angle{0}\else
  \def\bgenv@angle{90}\fi
  \@ifundefined{\bgrph@name.#1@\bgrphenv@name}
    {\let\@presets\@gobble}{\let\@presets\presetsb@rfor}%
  \pushButton[\presets{\b@rforCommon\R{\bgenv@angle}}
%    \end{macrocode}
%     We use \cs{epresets} key, new to \pkg{eforms} (2019/01/22).
%    \begin{macrocode}
    \epresets{\@presets{#1}}
%    \end{macrocode}
%    The field name of the \cs{pushButton} for the \cs{barfor} command is
%    \begin{quote}\texttt{\ameta{bar-name}.\ameta{name}@\ameta{env-name}}\end{quote}
%    \changes{v0.7}{2019/04/07}{Change field name of \string\cs{barfor}}
%    We change the field name of \cs{barfor} to
%    \begin{quote}\texttt{\ameta{env-name}@\ameta{bar-name}.\ameta{name}}\end{quote}
%    In this way, the same \ameta{name} can be used in more than one environments.
%    \begin{macrocode}
  ]{\bgrphenv@name @\bgrph@name.#1}{\bardimen}{\bardimen}}
%    \end{macrocode}
%\DescribeMacro\getBarName\leavevmode\hskip-\marginparsep
% \texttt{\darg{\ameta{env-name}}\darg{\ameta{bar-name}}\darg{\ameta{name}}} is the field name of the corresponding
% to the bar identified by its arguments. The second argument is assumed to be dynamic, not literal. If the second
% argument is a literal, then you can say \cs{getBarName\darg{\ameta{bar-name}}\darg{"myBar"}\darg{\ameta{name}}}; i.e.,
% enclosed it in quotation marks.
%    \begin{macrocode}
\def\getBarName(#1,#2,#3){#1+"@"+#2+"."+#3}
%    \end{macrocode}
%    \end{macro}
%    \section{Inputting count data into a bar}
%    \begin{macro}{\inputFor}\hskip-\marginparsep\texttt{\,\darg{\ameta{env}}\darg{\ameta{bar}}\darg{\ameta{name}}}
%    Use \cs{inputFor} to create a text field to input count data. We need to set up
%    a correspondence between \cs{inputFor} and a particular bar. The key-value options are passed to this
%    field using \cs{presetinputfor}; its argument uses \ameta{bar} and \ameta{name}, which are used for labeling purposes
%    (see the default definition of \cs{presetinptfor}).
%    \begin{macrocode}
\def\inputFor#1#2#3{% env, bar, name
  \textField[\cmd{\bParams{#1}{#2.#3}\eParams}
    \presets{\priorpresetinputfor{#1}{#2.#3}}
    \presets{\presetinputfor{#1}{#2.#3}}
%    \end{macrocode}
%   This package uses a lot of calculation events, we try to reduce the number of events processed by
%   registering the current input field as an active graph. All the subsequent calculations are made only
%   if the active graph (\texttt{updateBG.activegraph}) matches the \texttt{\ameta{env}.\ameta{bar}@\ameta{bgenv}}.
%    \begin{macrocode}
    \AAonfocus{updateBG.activegraph="#1@#2.#3";}]%
%    \end{macrocode}
%   The field name of this \cs{textField} shall be
%   \begin{quote}\texttt{\ameta{env-name}.\ameta{bar-name}@\ameta{name}}\end{quote}
%    \begin{macrocode}
    {#1.#2@#3}}
%    \end{macrocode}
%    \end{macro}
%    Below is the default definition of \DescribeMacro\presetinputfor\cs{presetinputfor}, it defines calculate, keystroke,
%    format,
%    and validate events. In this setup, we accept only natural numbers (or count data). We call the
%    \pkg{bargraph-js}-defined JavaScript function \texttt{updateGG} (update bar graph). This command
%    can be redefined. \cs{presetinputfor} takes one argument, which is internally pass as \texttt{\ameta{env-name}.\ameta{bar-name}},
%     as seen above in the definition of \cs{inputFor}.
%    \begin{macrocode}
\def\priorpresetinputfor#1#2{\AddAAcalculate{%
  updateBG.env=getEnvName(event.targetName);\r
  updateBG(event.value,"#1@#2",\usebarlabel);\r}
  \AAcalculate{;}
}
\newcommand{\presetinputfor}[2]{%
  \AAkeystroke{AFNumber_Keystroke(0, 0, 0, 0, "", true);}
  \AAformat{AFNumber_Format(0, 0, 0, 0, "", true);}
  \AAvalidate{AFRange_Validate(true, 0, false, 0);}
}
%    \end{macrocode}
% Manually re-scale all bar graphs in a particular bar graph environment,
% using both \DescribeMacro\displaysfFor\cs{displaysfFor}, which both displays
% the current scale factor and allows input for a new scale factor, and
% a push button \DescribeMacro\manualsfFor\cs{manualsfFor} to re-scale. For each
% of these commands, the first argument is optional arguments to pass to the
% form field, the second argument is the name of the \env{bargraphenv} to be re-scaled.
%    \begin{macrocode}
\begin{defineJS}{\dsfForKeyStr}
if(event.willCommit) {
  var v=event.value;
  try { v=eval(v) } catch(e){};
  if(isNaN(v)) {
    app.beep(0);
    app.alert("Enter a nonnegative number")
    event.rc=false;
  }
}
\end{defineJS}
\newcommand{\displaysfFor}[2][]{%
  \textField[\DV{2}\V{2}\TU{Current scale factor}
  \AAkeystroke{\dsfForKeyStr}
  \AAvalidate{AFRange_Validate(true, 0, false);}
  #1]{txtRescale.#2}%
}
\begin{defineJS}[\catcode`\!=0\relax]{\msfForMU}
var f=this.getField("txtRescale.!p(1)");
var v=eval(f.value);
if (v>0){
  dataForEnv["!p(1)"].sf=v;
  rescaleBargraph("!p(1)");
}
\end{defineJS}
\newcommand{\manualsfFor}[2][]{%
  \pushButton[\cmd{\bParams{#2}\eParams}
    \AAmouseup{\msfForMU}#1]{btnRescale.#2}%
}
%    \end{macrocode}
%
%\subsection{A labeling scheme}
% Labeling by typesetting the label is possible, but we also provide labeling through
% Acrobat forms tool tips property. We have two approaches:\par\medskip\noindent
% \DescribeMacro\barLabelsTU\hskip-\marginparsep\texttt{\,\darg{\ameta{string}\string|\ameta{function}}}
% When the argument is a \ameta{string}, the label becomes
% `\texttt{\ameta{string}\,\ameta{env}.\ameta{bar},\,Value:\,value}',
% and with it is a \ameta{function}, the function must return a string representing the label. The argument of
% \cs{barLabelsTU}
% is used when the bar has a tool tip already defined. In this case, the form of the tool tip
% is a string which incorporates the token \texttt{@v@}; this token will be replaced by the value of the bar.
%    \begin{macrocode}
\def\barLabelsTU#1{\def\usebarlabel{#1}\ifx\usebarlabel\@empty
  \def\usebarlabel{""}\fi}
\barLabelsTU{""}
%    \end{macrocode}
%    \leavevmode\DescribeMacro\barLabelsNoTU
%    \hskip-\marginparsep\texttt{\,\darg{\ameta{string}\string|\ameta{function}}}
%    When the \cs{barFor} command has no associated tool tip (\cs{TU}), the value of \cs{barLabelsNoTU} is used.
%    When the argument is a string the tokens \texttt{\#1} and \texttt{\#2} are used as placeholders for
%    \texttt{\ameta{env}.\env{bar}} and \texttt{\ameta{value}}, respectively. When it is a \ameta{function},
%    the function returns a string based on its argument of \texttt{fld} (usually \texttt{\ameta{env-name}.\ameta{bar-name}}) and
%    \texttt{v} (the \texttt{\ameta{value}}.
%    \begin{macrocode}
\def\barLabelsNoTU#1{\def\@rgi{#1}\ifx\@empty
  \edef\barLabelsNoTUJS{\barLabelsNoTUJSDef}\else
  \def\barLabelsNoTUJS{#1}\fi}
\def\barLabelsNoTUJSDef{o.barname+": "+o.bar+", Value: "+o.value}
\expandafter\barLabelsNoTU\expandafter{\barLabelsNoTUJSDef}
\def\simpleBarLabels(#1,#2){"Bar for "+#1+", Value: "+#2;}
%    \end{macrocode}
%    \leavevmode\DescribeMacro\labelFld\hskip-\marginparsep
%    \texttt{[\ameta{form-opts}]\darg{\ameta{caption}}\darg{\ameta{bg-name}.\ameta{bar-name}}\darg{\ameta{width}}\darg{\ameta{height}}}\\
%    The command creates a text field that is used to label horizontal or vertical bars. For vertical bars
%    use the key \cs{R\darg{90}} in the \ameta{form-opts}.
%    \begin{macrocode}
\newcommand\labelFld[4][]{\textField[\Ff{\FfReadOnly}\F{\FHidden}
  \BC{}\BG{}#1\autoCenter{n}\DV{#2}\V{#2}]{#3@\bgrphenv@name}{#4}}
%    \end{macrocode}
%   \subsection{Saving and restoring critical data}
%    \textbf{Restore critical data with an open action.}
%    If the first page is opened, and \texttt{oBarLabeling} needs
%    to be restored, we call \texttt{gbRestoreData()}.
%    \begin{macrocode}
\begin{defineJS}[\catcode`\!=0\relax]{\bgOpenAction}
if(oBarLabeling.needsRestore) {
  var bgTO=app.setTimeOut("bgRestoreData();!%
app.clearTimeOut(bgTO);!%
oBarLabeling.needsRestore=false",1000);
}
\end{defineJS}
\begingroup\@makeother\%\let\%\defjsLB
\thisPageAction{\JS{\bgOpenAction}}{}
\endgroup
%    \end{macrocode}
%    \textbf{Saving critical data.} We save the object \texttt{oBarLabeling} as a string to
%    the hidden field \texttt{barLabeling}.
%    \begin{macrocode}
\begin{willSave}
bgSaveData();
\end{willSave}
%    \end{macrocode}
%    \section{Document JavaScript}
%    JavaScript that supports the creation of bar graphs.
%    \begin{macrocode}
\def\barDefColor{color.blue}
%    \end{macrocode}
%    \leavevmode\DescribeMacro\populateCommaData\hskip-\marginparsep\texttt{(env,bar,str[,validate])} is
%    a convenience command to access the JavaScript function \texttt{populateCommaData}, which is defined in Section~\ref{s:labelcd}
%    \begin{macrocode}
\newcommand{\populateCommaData}{%
  populateCommaData.usebarlabel=\usebarlabel;\r
  populateCommaData
}
\begin{insDLJS*}{bgjs}
\begin{newsegment}{AeB: bargraph-js}
/*
        Document Level JavaScript
        bargraph-js Package
        D. P. Story copyright \the\year
*/
\end{newsegment}
%    \end{macrocode}
%   \leavevmode\IndexJS{updateBG}\hskip-\marginparsep\texttt{(v,fld,o)}
%    function is designed for bar graph with explicit \cs{barFor} commands
%   inserted by the document author.
%    \begin{macrocode}
\begin{newsegment}{Bar Graph of preset bars}
var _scaleFactorDef=\sc@leF@ctorDef;
var oBarLabeling = new Object;
    oBarLabeling.needsRestore=true;
function updateBG (v,fld,o) {
%    \end{macrocode}
%    If \texttt{updateBG.activegraph} is different from \texttt{fld}, we exit, don't do any calculations.
%    The form of \texttt{fld} is \texttt{\ameta{env-name}@\ameta{bar-name}.\ameta{name}}.
%    \begin{macrocode}
  if (typeof v=="undefined") return;
  if (updateBG.activegraph!=fld) return;
  var useDefLabeling=(typeof o=="string");
  var env=updateBG.env;
  var w=dataForEnv[env].width;
  var h=dataForEnv[env].height;
  var baseline=dataForEnv[env].baseline
  var isHoriz=dataForEnv[env].horiz;
  var bRescaleNeeded=false;
  var f=this.getField(fld);
  var cachedValue=getBarValue(env,fld);
  saveBarValue(env,fld,v); // dps13
  bRescaleNeeded=getNewScaleFactor(env,v);
  var sf=dataForEnv[env].sf;
  sf=(sf<0)?-sf:sf;
  var r=f.rect;
%    \end{macrocode}
%    \textbf{Calculating the new rectangle.}
%    \texttt{cachedValue} is the previous value of the bar, and \texttt{v} is the new
%    value. There are several cases: horizontal versus vertical; \texttt{v<0} versus
%    \texttt{v>=0}; and whether the rectangle is changing direction (neg to pos) or not.
%    \begin{macrocode}
  if(isHoriz) { // dps01
    if (v<0) {
     if (cachedValue<0) // no change in sign
        r[0]=r[2]+(v*sf);
      else { // change from pos to neg
        r[2]=r[0];
        r[0]=r[2]+(v*sf);
      }
    } else {
      if (cachedValue<0) { // from neg to pos
        r[0]=r[2];
        r[2]=r[0]+(v*sf);
      } else // from pos to pos
        r[2]=r[0]+(v*sf);
      }
  } else { // vertical
  	if (v<0) { // dps01
  		if (cachedValue<0) { // no change in sign
        r[3]=r[1]+(v*sf);
  		} else { // switching from pos to neg
        r[1]=r[3];
  		  r[3]=r[1]+(v*sf);
      }
  	} else {
      if (cachedValue<0)  // change in sign: neg to pos
    		r[3]=r[1]+(v*sf);
      else // no change
        r[1]=r[3]+(v*sf);
    }
  }
  f.rect=r;
%    \end{macrocode}
%   \textbf{Applying a label to current bar.} If a field has an empty \cs{TU} property,
%   we save this in \texttt{oBarLabeling}, if not already saved. If the field has an
%   empty \cs{TU} field, we record this with a \texttt{-1}.
%    \begin{macrocode}
  if (typeof oBarLabeling[fld]=="undefined")
    oBarLabeling[fld]=(f.userName!="")?f.userName:-1;
%    \end{macrocode}
%   If this field has no \cs{TU} property, we use the default, as expressed through
%   \texttt{barLabelsDef}.
%    \begin{macrocode}
  if (oBarLabeling[fld]==-1)f.userName=barLabelsDef(fld,v);
  else {
%    \end{macrocode}
%   If this field has a nonempty \cs{TU} property, we either use \texttt{simpleBarLabels},
%   passing a formatting string with it, or we pass the function name with is arguments.
%   If the \texttt{o} argument is not passed, there is no change to the labeling.
%    \begin{macrocode}
    if (typeof o!="undefined")
      f.userName=(useDefLabeling)?((o=="")?%
(simpleBarLabels(fld,v,oBarLabeling[fld])):%
%(simpleBarLabels(fld,v,f.userName)):%
(simpleBarLabels(fld,v,o))):o(fld,v);
  }	
%    \end{macrocode}
%   \textbf{Default fill color.} If the bar does not have an associated fill color,
%   we apply the default color of \cs{barDefColor}
%    \begin{macrocode}
  f.fillColor=(color.equal(f.fillColor,color.transparent))?%
\barDefColor:f.fillColor;
%    \end{macrocode}
%   Make the bar visible (initially they are hidden)
%    \begin{macrocode}
  f.display=display.visible;
  if(bRescaleNeeded) {
%    \end{macrocode}
%   If we must re-scale, we cannot allow the user to enter any more data
%   until the re-scaling is finished; otherwise, data is occasionally lost.
%    \begin{macrocode}
    var g=this.getField(env);
    if (g!=null)g.readonly=true;
    app.setTimeOut("rescaleBargraph(\""+env+"\")",5);
  }
}
%    \end{macrocode}
%   \leavevmode\IndexJS{barLabelsDef}\hskip-\marginparsep\texttt{(fld,v)} is the default function for
%   labeling the bars using the tooltip property of a form field.
%   inserted by the document author.
%    \begin{macrocode}
function parseFld(fld,v) {
  var pos=fld.indexOf("@");
  var env=fld.substring(0,pos);
  fld=fld.substring(pos+1);
  pos=fld.indexOf(".");
  var barname=fld.substring(0,pos);
  var bar=fld.substring(pos+1);
  parseFld.env=env;
  parseFld.barname=barname;
  parseFld.bar=bar;
  parseFld.value=v;
}
function barLabelsDef(fld,v){
  parseFld(fld,v);
  var o=parseFld;
  var strOrFnc=\barLabelsNoTUJS;
  return ((typeof strOrFnc=="string")?strOrFnc:strOrFnc(fld,v));
}
function simpleBarLabels(fld,v){
%  parseFld(fld,v);
%  var o=parseFld;
  if (arguments.length==2)
%    return o.barname + ": "+o.bar+", Value: "+v;
     return customBarLabels(fld,v);
  else {
    parseFld(fld,v);
    var s=arguments[2];
    return replaceLblVars(s);
  }
}
%    \end{macrocode}
%   \leavevmode\IndexJS{getNewScaleFactor}\hskip-\marginparsep\texttt{(env,v)}
%   is a utility function for calculating the scale factor of the graph.
%    \begin{macrocode}
function getNewScaleFactor(env,v) {
  var w=dataForEnv[env].width;
  var h=dataForEnv[env].height;
  var maxDimen=dataForEnv[env].maxDim;
  var nO=dataForEnv[env].origin;
  var sf=dataForEnv[env].sf;
  var isHoriz=dataForEnv[env].horiz;
  v=(v<0)?-v:v;
  if(isHoriz) {
    maxDimen=(nO==0)?w:maxDimen;
    if( sf*v > maxDimen ) {
      sf=maxDimen/v;
      dataForEnv[env].sf=sf;
      return true;
    }
  } else {
    maxDimen=(nO==0)?h:maxDimen;
    if ( sf*v > maxDimen ) {
      sf=maxDimen/v;
      dataForEnv[env].sf=sf;
      return true;
    }
  }
  return false;
}
%    \end{macrocode}
%   This function converts the field name for a \texttt{\string\inputFor} field
%   to the field name of corresponding bar.
%    \begin{macrocode}
// <env>.<barname>@<name> --> <env>@<barbane>.<name>
function getBarName(name) {
  var pos=name.indexOf(".");
  var env=name.substring(0,pos);
  name=name.substring(pos+1);
  return env+"@"+name.replace(/@/,".");
}
function getEnvName(name) {
  var pos=name.indexOf(".");
  var env=name.substring(0,pos);
  return env;
}
%    \end{macrocode}
%   \leavevmode\IndexJS{rescaleBargraph}\hskip-\marginparsep\texttt{(env)}
%   touches each field causing the calculation fields to activate.
%   Here, \texttt{env} is the name of the \texttt{bargraphenv} that encloses
%   the active bar graph.
%    \begin{macrocode}
function rescaleBargraph(env) {
  var oInputFor=this.getField(env);
  this.delay=true;
  // date input by the \\inputFor
  if (oInputFor!=null) {
    var a=oInputFor.getArray()
    for (var i=0; i<a.length; i++) {
%    \end{macrocode}
%    If \texttt{updateBG.activegraph} is the same as \texttt{getBarName(a[i].name)},
%    we make the calculations.
%    \begin{macrocode}
      updateBG.activegraph=getBarName(a[i].name);
      if (a[i].display!=display.hidden) {
        this.calculate=false;
        a[i].value=1*a[i].value + 1;
        this.calculate=true;
        a[i].value=1*a[i].value - 1;
      }
    }
  } else {
%    \end{macrocode}
%    \texttt{env} does not exist, this means there are no input fields, what to do?
%    \begin{macrocode}
    var aBars=dataForEnv[env].bgs;
    for (var i=0; i<aBars.length; i++) {
      var bars=this.getField(env+"@"+aBars[i]); // dps07
      var widgets=bars.getArray();
      for (var j=0; j<widgets.length; j++) {
        var name=widgets[j].name;
        var Value=getBarValue(env,name); // dps13
        updateBG.env=env;
        updateBG.activegraph=name;
        updateBG(Value,updateBG.activegraph);
      }
    }
  }
  var f=this.getField("txtRescale."+env);
  if (f!=null) f.value=Math.round(dataForEnv[env].sf*1000)/1000;
  this.delay=false;
  var g=this.getField(env);
  if (g!=null)g.readonly=false;
%  g.strokeColor=color.black;
}
%    \end{macrocode}
%   \leavevmode\IndexJS{optimizeScaling}\hskip-\marginparsep\texttt{(env)}
%   calculates the height/length of each bar, selected the largest one, and rescales
%   the bar graph so that the largest one not extends the entire height/width of the
%   bar graph region. Here, \env{env} is the name of the \env{bargraphenv}, and
%   \texttt{bars} is the name of the \env{bargraph} environment. If we ever get
%   to where we are putting multiple \env{bargraph} environment within a
%   \env{bargraphenv}, then \texttt{bars} might be an array. At the end of the function,
%   \texttt{rescaleBargraph()} is called with a timed delay.
%    \begin{macrocode}
function optimizeScaling(env) {
  var w=dataForEnv[env].width;
  var h=dataForEnv[env].height;
  var sf=dataForEnv[env].sf;
  var isHoriz=dataForEnv[env].horiz;
  var aBGs=dataForEnv[env].bgs;
  for (var i=0; i<aBGs.length; i++) {
    var o=this.getField(env+"@"+aBGs[i]); // dps07
    var a=o.getArray();
    maxFldName=a[0].name;
    if (isHoriz) { // if horizontal bars
      var maxDim=0; maxFldName="";
      for (var i=0; i<a.length; i++) {
        if (a[i].display==display.hidden) continue;
        var thisDim=a[i].rect[2]-a[i].rect[0];
        thisDim=(thisDim<0)?-thisDim:thisDim; // dps01
        if ( thisDim > maxDim ) {
          maxDim=thisDim;
          maxFldName=a[i].name;
        }
      }
      if (maxFldName=="") return;
  // get name of input field env.bar@name
      var v=getBarValue(env,maxFldName);
  // now rescale all bars
  	  v=(v<0)?-v:v; // dps01
      if (v !=0) {
        sf=w/v; // if v !=0
        dataForEnv[env].sf=sf;
        var g=this.getField(env);
%        g.strokeColor=color.red;
        if (g!=null)g.readonly=true;
        app.setTimeOut("rescaleBargraph(\""+env+"\")",5);
      }
    } else { // if vertical bars
      var maxDim=0; maxFldName="";
      for (var i=0; i< a.length; i++) {
        if (a[i].display==display.hidden) continue;
        var thisDim=a[i].rect[1]-a[i].rect[3];
        thisDim=(thisDim<0)?-thisDim:thisDim; // dps01
        if ( thisDim > maxDim ) {
          maxDim=thisDim;
          maxFldName=a[i].name;
        }
      }
      if (maxFldName=="") return;
      var v=getBarValue(env,maxFldName); // dps13
      if ( typeof v == "undefined" ) return;
  // now rescale all bars
  	  v=(v<0)?-v:v; // dps01
      if (v !=0) {
        sf=h/v;
        dataForEnv[env].sf=sf;
        var g=this.getField(env);
        if (g!=null)g.readonly=true;
%        g.strokeColor=color.red;
        app.setTimeOut("rescaleBargraph(\""+env+"\")",5);
      }
    }
  }
}
%    \end{macrocode}
%   \leavevmode\IndexJS{resetBargraphs}\hskip-\marginparsep\texttt{(\ameta{various})}
%   resets the bar graphs and the input fields. The unspecified argument
%   is a list of names for \env{bargraphenv} and \env{bargraph} names.
%    \begin{macrocode}
function resetBargraphs() {
  this.calculate=false;
  this.resetForm(arguments);
  for (var n=0; n<arguments.length; n++){
	  var f=this.getField("internalData."+arguments[n]);
	  if (f!=null) {
      dataForEnv[arguments[n]].sf=_scaleFactorDef;
      var env=arguments[n]; // dps01
      var isHoriz=dataForEnv[env].horiz;
  	  aBGs=dataForEnv[arguments[n]].bgs;
      // an environment name
	    for (var i=0; i<aBGs.length; i++) {
        var o=this.getField(env+"@"+aBGs[i]); // dps07
		    var a=o.getArray();
		    o.display=display.hidden;
        if (isHoriz) {
          for(j=0;j<a.length;j++) {
            var name=a[j].name; // dps01
            var value=getBarValue(env,name); // dps01
            if (value<0) { // dps01
              var r=a[j].rect;
              r[0]=r[2]+20;
              a[j].rect=r;
            }
            saveBarValue(arguments[n],a[j].name,"0");
          }
        } else {
          for(j=0;j<a.length;j++) {
            var name=a[j].name; // dps01
            var value=getBarValue(env,name); // dps01
            if (value<0) { // dps01
              var r=a[j].rect;
              r[3]=r[1]+20;
              a[j].rect=r;
            }
            saveBarValue(arguments[n],a[j].name,"0");
          }
        }
      }
    }
  }
  this.calculate=true;
}
// fld="<bgenv-name><bg-name>.<bar-name>", v=value of field
%    \end{macrocode}
%   \leavevmode\IndexJS{customBarLabels}\hskip-\marginparsep\texttt{(fld,v)}
%   If you declare \cs{barLabelsTU\darg{customBarLabels}}, then any \cs{barFor}
%   field that has a non-empty \cs{TU} key will be processed by this built-in function.
%   An example from \texttt{bargraph-js-cnt-data.tex} declares
%   \begin{quote}\small|\presetsbarfor{don}{\BG{red}\TU{AcroTeX revenues are \textdollar@v@}}|\end{quote} The function
%   below, replaces \texttt{@v@} with the actual value of the bar data.
%    \begin{macrocode}
function customBarLabels(fld,v){
  var f=this.getField(fld);
  if ( oBarLabeling[fld] != -1 ) {
    var s=oBarLabeling[fld];
    if (s.indexOf("@v@")==-1)
      return barLabelsDef(fld,v);
    else {
      parseFld(fld,v);
      return replaceLblVars(s);
    }
  } else return barLabelsDef(fld,v);
}
function replaceLblVars(s) {
  var o=parseFld;
  s=s.replace(/@env@/g,o.env);
  s=s.replace(/@barname@/g,o.barname);
  s=s.replace(/@bar@/g,o.bar);
  s=s.replace(/@v@/g,o.value);
  return s;
}
%    \end{macrocode}
%    \leavevmode\IndexJS{getBarValue}\hskip-\marginparsep\texttt{(env,name)}
%    returns the value of the bar, whose field name is \texttt{name} and is part
%    of the \texttt{env} \env{bargraphenv} environment. The value is retrieved
%    from the hidden field \texttt{"bgVAlues"}, that holds an object of key-values.
%    \begin{macrocode}
function getBarValue(env,name){
  var f=this.getField("bgValues");
  var o=eval(f.value);
  var v=o[env][name];
  var retn=(typeof v=="undefined")?0:v;
  return retn;
}
%    \end{macrocode}
%    \leavevmode\IndexJS{saveBarValue}\hskip-\marginparsep\texttt{(env,name,v)}
%    saves the value of the bar. The value \texttt{v} is saved to the hidden
%    field \texttt{"bgVAlues"}.
%    \begin{macrocode}
function saveBarValue(env,name,v) {
  var f=this.getField("bgValues");
  var o=eval(f.value);
  o[env][name]=v;
  f.value=o.toSource();
}
\end{newsegment}
%    \end{macrocode}
%    \leavevmode\IndexJS{toggleFldVisibility}\hskip-\marginparsep\texttt{(name,bOk)}
%    If \texttt{bOk} is true, display the field whose name is \texttt{name};
%    otherwise, hide the field.
%    \begin{macrocode}
\begin{newsegment}{Toggle field visibility}
function toggleFldVisibility(name,bOk) {
  var f=this.getField(name);
  f.display=(bOk)?display.visible:display.hidden;
}
\end{newsegment}
%    \end{macrocode}
% \subsection{Support for comma-delimited data}\label{s:labelcd}
%    \leavevmode\IndexJS{populateCommData}\hskip-\marginparsep\texttt{(env,bar,v[,validate])}
%    Populates the bars characterized by \texttt{env} and \texttt{bar}. The \texttt{v} argument
%    is a string of comma-delimited numbers. When the \texttt{validate} argument is passed, it
%    should be a JS function that validates each entry in the list; for example, passing
%    \texttt{validateArrayNonNegNums} determines whether each entry is a nonnegative number.
%    \begin{macrocode}
\begin{newsegment}{Comma-delimited Data}
function populateCommaData(env,bar,str) {
  var value;
  var f=this.getField(env+"@"+bar);
  var g=f.getArray();
  var aValue=str.split(",");
  var bOk=(arguments.length>3)?arguments[3](aValue):true;
  if (bOk) {
    for (var i=0; i<g.length; i++){
      updateBG.env=env;
      updateBG.activegraph=g[i].name;
      value=(typeof(aValue[i])=="undefined")?0:aValue[i];
      updateBG(value,updateBG.activegraph,%
populateCommaData.usebarlabel);
    }
  } else app.alert(arguments[3].msg);
}
\end{newsegment}
%    \end{macrocode}
%    Determines whether each entry in the array \texttt{aValue}
%    is a non-negative number. Returns false if not.
%    \begin{macrocode}
\begin{newsegment}{Validate input data for comma-delimited data}
validateArrayNonNegNums.msg="Enter only non-negative numbers";
function validateArrayNonNegNums(aValue){
  var bOk=true;
  for (var i=0; i<aValue.length; i++) {
    var x=1*aValue[i];
    if(isNaN(x)) {bOk=false; break;}
    else if (x<0) {bOk=false; break;}
  }
  return bOk
}
%    \end{macrocode}
%    Determines whether each entry in the array \texttt{aValue}
%    is a number. Returns false if not.
%    \begin{macrocode}
validateArrayOfNums.msg="Enter only numerical values";
function validateArrayOfNums(aValue){
  var bOk=true;
  for (var i=0; i<aValue.length; i++) {
    var x=1*aValue[i];
    if(isNaN(x)) {bOk=false; break;}
  }
  return bOk
}
\end{newsegment}
%    \end{macrocode}
% \subsection{Saving and restoring bar graph data}
%    Save the contents of the \texttt{oBarLabeling} object as a string
%    to the hidden text field \texttt{barLabeling}.
%    \begin{macrocode}
\begin{newsegment}{Restore Data}
function bgSaveData() {
  var f=this.getField("barLabeling");
  if(f!=null)f.value=oBarLabeling.toSource();
}
%    \end{macrocode}
%    Restore \texttt{oBarLabeling} object from
%    the hidden text field \texttt{barLabeling}.
%    \begin{macrocode}
function bgRestoreData(){
  var f=this.getField("barLabeling");
  if(f!=null&&f.value!="")oBarLabeling=eval(f.value);
}
\end{newsegment}
\end{insDLJS*}
%</package>
%<*dynam>
%    \end{macrocode}
%     \subsection{Creating and displaying dynamic bar graph data}\leavevmode
%     \IndexJS{displayDyBargraph}\unskip
%     This function is designed for discrete probability distributions,
%     it can build the probability mass function (pmf) and the cumulative
%     distribution function (cdf). \texttt{displayDyBargraph}
%     is a function that creates a (dynamic) bar graph, based on the arguments passed to it.
%     The arguments are
%\begin{description}
% \item[\texttt{bar}] is the name \ameta{bgenv-name}\texttt@\ameta{bg-name}
% \item[\texttt{aPr}] is the array of probability distributions; \texttt{[k,pmfPr,cdfPr]} is the form of each entry
% in this array,  where \texttt{k} is a value of the distribution,
% \texttt{pmfPr} is the probability mass at that value; and \texttt{cdfPr} is the cumulative
% mass up to and including the value \texttt{k}.
% \item[\texttt{bPmf}] is true if we are to calculate a probability mass function,
% and false if we calculate a cumulative distribution function.
% \item[\texttt{bOptimize}] is true if we optimize the graph (applies to Pmf only),
% otherwise, we use the current scale factor.
%\end{description}
%    \begin{macrocode}
\begin{insDLJS}{dynam}{Display dynamic bar graphs}
%function displayDyBargraph(bar,aPr,bPmf,bOptimize) { // bar=env@bar-name
function displayDyBargraph(env,aPr,bPmf,bOptimize) {
  if (typeof aPr[0]=="undefined") return;
  var aBars=dataForEnv[env].bgs;
  var bar=env+"@"+dataForEnv[env].bgs[0];
  var n=aPr.length;
  var index=(bPmf)?1:2;
  var bc=color.red;
  var fc=color.blue;
  var lbl=_labelDyBars;
  if (arguments.length>4) {
    var o=arguments[4];
    bc=(o.bc==undefined)?bc:o.bc;
    fc=(o.fc==undefined)?fc:o.fc;
    var lbl=(o.lbl==undefined)?_labelDyBars:o.lbl;
  } else {
    var f=this.getField(bar+".bar0");
    if ( f !=null ) {
      bc=f.strokeColor;
      fc=f.fillColor;
    }
  }
%  var hbar="x"+bar;
  var hbar=bar.replace(/@/,"@x"); // dps07
%console.println("removing bar: "+bar);
  this.removeField(bar);
  var pos=hbar.indexOf("@");
  var env=hbar.substring(0,pos);
// get aux info, begin with
%console.println("hbar: "+ hbar);
  var hb=this.getField(hbar);
  var f=hb.getArray()[0];
  var pg=f.page;
  var wd=dataForEnv[env].width;
  var ht=dataForEnv[env].height;
  var isHoriz=dataForEnv[env].horiz;
  var frameH=ht; // frameH is one unit high
  if (bPmf&&bOptimize) {
    var maxValue=0;
    for (var i=0; i<n; i++)
      if (aPr[i][index]>maxValue) maxValue=aPr[i][index];
  }
  var w=wd/(n+1);
  var r=f.rect;
  var defwidth=r[2]-r[0];
  if (defwidth*(n+1)>=wd) r[2]=r[0]+w;
  else w=defwidth;
  var gap=-1; // contiguous boundaries overlap
  var sf=(bPmf&&bOptimize)?frameH/maxValue:frameH;
  for (var i=0; i<n; i++){
    var g=this.addField(bar+".bar"+i,"button",pg,r);
    // calculate height
    var Rect=g.rect;
    var v=aPr[i][index];
    this.delay=true;
    Rect[1]=Rect[3]+(v*sf);
    var pr=aPr[i][0];
    g.userName=lbl(pr,v,bPmf);
%    g.userName=bPmf?("Pr(X="+pr+")="+v):("Pr(X<="+pr+")="+v);
    g.display=display.visible;
    g.rect=Rect;
    r[0]+=(w+gap);
    r[2]+=(w+gap);
    this.delay=false;
  }
  if (!bPmf) { // cdf
    var totalW=(n+1)*(w+gap);
    var delta=wd-totalW;
    r[2]+=delta;
    g=this.addField(bar+".bar"+n,"button",pg,r);
    var Rect=g.rect;
    var v=1;
    this.delay=true;
    Rect[1]=Rect[3]+(v*sf);
    g.display=display.visible;
    g.rect=Rect;
  }
// Now set color properties
  g=this.getField(bar);
  g.fillColor=fc;
  g.strokeColor=bc;
  this.delay=false;
}
function _labelDyBars(pr,v,bPmf) {
  return bPmf?("Pr(X="+pr+")="+v):("Pr(X<="+pr+")="+v);
}
\end{insDLJS}
%</dynam>
%<*package>
\bgjs@restoreCats
%</package>
%    \end{macrocode}
\endinput