%\iffalse %<*copyright> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Acroflex.sty package, %% %% Copyright (C) 2008 -- 2016 D. P. Story %% %% dpstory@acrotex.net %% %% %% %% 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 of the %% %% License, or (at your option) any later version. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %\NeedsTeXFormat{LaTeX2e}[1997/12/01] %\ProvidesPackage{acroflex} % [2016/08/29 v1.6c AcroFLeX: AcroTeX and Adobe Flex (dps)] %<*driver> \documentclass{ltxdoc} \usepackage[colorlinks,hyperindex]{hyperref} \begin{document} \def\AcroFLeX{AcroF\kern-.1667em\lower.5ex\hbox{L}\kern-.3eme\kern-.125emX\@} \GetFileInfo{acroflex.sty} \title{% \texorpdfstring {\AcroFLeX: Merging {Acro\negthinspace\TeX} and FLEX} {AcroFLeX: Merging AcroTeX and FLEX}} \author{D. P. Story\\ Email: \texttt{dpstory@acrotex.net}} \date{processed \today} \maketitle \tableofcontents \let\Email\texttt \DocInput{acroflex.dtx} \PrintIndex \end{document} % % \fi % \MakeShortVerb{|} % \StopEventually{} % % \DoNotIndex{\def,\edef,\gdef,\xdef,\global,\long,\let} % \DoNotIndex{\expandafter,\string,\the,\ifx,\else,\fi} % \DoNotIndex{\csname,\endcsname,\relax,\begingroup,\endgroup} % \DoNotIndex{\DeclareTextCommand,\DeclareTextCompositeCommand} % \DoNotIndex{\space,\@empty,\special} % % \begin{macrocode} %<*package> % \end{macrocode} % % \section{Introduction} % % The word \textbf{\AcroFLeX} is meant to convey a merging of two computer technologies: % \begin{itemize} % \item \textbf{Acro}: connotes both \textbf{Adobe Acrobat} (\textbf{Adobe Reader}) % and \textbf{{Acro\negthinspace\TeX}} (as in the % \textbf{{Acro\negthinspace\TeX} eDucation Bundle} or, just \textbf{AeB}). % \item \textbf{F\kern-.1667em\lower.5ex\hbox{L}\kern-.3eme\kern-.125emX\@}: connotes % \textbf{Adobe FLEX 3}. FLEX 3 is used to create SWF files to interact with the user. % In the case of graphing, plotting information is passed from Acrobat, via JavaScript, % to the Flash widget. ActionScript receives the data, plots the points, and % connects them with a smooth curve or a straight line segment. % \end{itemize} % Acrobat 9 Pro introduces the rich media annotation which plays FLV movies % and SWF files natively. Acrobat also provides a scripting bridge % between JavaScript for Acrobat, and ActionScript, the scripting % language of Flash player. This bridge enables the PDF and the % Flash widget, embedded in the rich media annotation, to communicate. The scripting bridge % opens up wonderful opportunities for application to the education % sector. The graphing of {\AcroFLeX} is one such application of the new % PDF-Flash connection to education. % % \textbf{{\AcroFLeX}} uses the commercial product Adobe FLEX Builder~3 and % FLEX~3 SDK to produce Flash widgets, and the AeB % to create PDF documents with appropriate JavaScript to communicate % with the Flash widget. FLEX Builder~3 is currently free for students % and educators, the FLEX 3 SDK is free to all. % % This style file defines some basic controls for % \textbf{{\AcroFLeX} Graphing} for controlling graphical SWF files % for graphing. % % These commands are general {\LaTeX} commands, that require no special driver, so % they can be used by, for example, pdftex; however, we use SWF files to produce % the graphing screen with the built-in ActionScript to communicate with the PDF. % For this, you will need Acrobat 9 Pro. In that case, you might as well use the % Acrobat Distiller to produce your PDF, but it is not necessary. % % \medskip\noindent % Let's begin with a declaration of the {\AcroFLeX} logo. % \begin{macrocode} \RequirePackage{rmannot}[2016/02/01] % \end{macrocode} %\changes{v1.6}{2015/10/13}{Save catcodes of subscript and superscript, both % of these are used in ordinary characters in the file.} % Change catcodes of subscript and superscript to other. % \begin{macrocode} \edef\af@subscriptCat{\the\catcode`\_} \edef\af@superscriptCat{\the\catcode`\^} \def\af@restoreCats{% \catcode`\_=\af@subscriptCat \catcode`\^=\af@superscriptCat } \catcode`\_=12\relax \catcode`\^=12\relax \def\AcroFLeX{% AcroF\kern-.1667em\lower.5ex\hbox{L}\kern-.3eme\kern-.125emX\@} % \end{macrocode} % \begin{macro}{\pathToAcroFlex} % Set the path to {\AcroFLeX} widget, \texttt{AcroFlex.swf}, that actually does the % graphing. % \begin{macrocode} \newcommand{\pathToAcroFlex}[1]{\def\af@pathToAcroFlex{#1}% \ifx\af@pathToAcroFlex\@empty \PackageError{acroflex}{% You must specify a full path to AcroFlex.swf}{}\else \saveNamedPath{acroflexWidget}{\af@pathToAcroFlex/AcroFlex.swf}\fi } \def\af@pathToAcroFlex{} \@onlypreamble{\pathToAcroFlex} % \end{macrocode} % \end{macro} % \paragraph*{Define package options.} % \begin{macro}{lang} % We offer up a single package option, \texttt{lang}. The only languages supported % at this time are \texttt{english} and \texttt{german}. Additional languages may be supported in the % future. % \begin{macrocode} \define@choicekey*+{acroflex.sty}{lang}[\val\nr]{english,german} {% \ifcase\nr\relax \def\af@lang@type{afcustom_us.def} \or \def\af@lang@type{afcustom_de.def} \else \def\af@lang@type{afcustom.def} \fi }{\PackageWarning{acroflex}{Bad choice for lang, permissible values are english and german. No lang key is equivalent to english. Try again}} \def\af@lang@type{afcustom.def} % \end{macrocode} % \end{macro} % \paragraph*{Process the options.} % We process our meager number of options here. % \begin{macrocode} \ProcessOptionsX % \end{macrocode} % \paragraph*{Input Configuration File.} At this point, we input the configuration file. The % major entry, and probably the only entry in this file is the \cs{pathToAcroFlex}. The file % should contain a line of code like this one: %\begin{verbatim} % \pathToAcroFlex{c:/acrotex/aebpro/acroflex/swf} %\end{verbatim} % \begin{macrocode} \InputIfFileExists{acroflex.cfg}{}{} % \end{macrocode} % % \section{Graphing a Single Function} % % This section describes the graphing screen and its controls. % % \subsection{Some Initial Parameters} % % Should you wish to use an {\AcroFLeX} graphic in your PDF, you will need to declare % several parameters for each graphic: \cs{dimScreenGraph} and \cs{graphName}, % these are the rich media annotation dimensions, the rich media annot number of this annot % on this page, and a unique name (unique to the document) for the graph. % % You also need to declare a default function, if different from the one set by this package, % the default domain/range of $x$ and $y$ (the graph view window), and the default domain % of parameter equations (this last is options if no parametric equations are to be used). % % \paragraph{Setting the Dimensions of the Annotation} % % \begin{macro}{\dimScreenGraph} % This is a convenience command for storing the dimensions of the Flash widget. It assumes % you do not resize using \cs{resizebox} or \cs{scalebox}. The command defines two % commands available to the document author, these are \cs{hScreenGraph} and % \cs{vScreenGraph}, for the width and height respectively. % \begin{macrocode} \newcommand{\dimScreenGraph}[2]{{% \setlength{\dimen@}{#1}\xdef\hScreenGraph{\the\dimen@}% \setlength{\dimen@}{#2}\xdef\vScreenGraph{\the\dimen@}% }} % \end{macrocode} % \end{macro} % % \paragraph{Setting the Name of the Graph} % % \begin{macro}{\graphName} % Each graphing screen must have a unique (base)name, the name is specified % using the command \cs{graphName}; for example \verb!\graphName{mygraph}! % specifies the base name for the next graphing screen. This name is use % in creating the control for the graphing screen (a Flash widget). % % \begin{macrocode} \newcommand{\graphName}[1]{\def\afgraphName{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{\defaultFunction} % Declare the default function to appear in the \cs{fileInputField} on startup % or on reset. The function takes two arguments, the first is a display version of % the function, the second is a proper JavaScript form of the function. The default % is \verb!\defaultFunction{x^2}! % \begin{macrocode} \newcommand{\defaultFunction}[1]{\def\af@DefaultFunction{#1}} \defaultFunction{x^2} % \end{macrocode} % \end{macro} % % \paragraph{Setting the View Screen Dimensions: Range/Domain} % % \begin{macro}{\defaultDomRng} % \begin{macro}{\defaultDomP} % Set the default domain and range of the default function. These values will appear % on start-up, and when the graph is cleared. % \begin{macrocode} \def\defaultDomRng#1#2#3#4{% \def\af@DefaultDomMin{#1}\def\af@DefaultDomMax{#2}% \def\af@DefaultRngMin{#3}\def\af@DefaultRngMax{#4}% } \def\defaultDomP#1#2{% \def\af@DefaultDomMint{#1}\def\af@DefaultDomMaxt{#2}% } % \end{macrocode} % We set the default domain and range to correspond with the % default function. % \begin{macrocode} \defaultDomRng{-2}{2}{0}{4} \defaultDomP{0}{2*PI} % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{The Graphing Screen and its Controls} % % Here, we describe the graphing screen and its controls. The graphing screens and % its controls may be arranged on the page in any way the document author wishes. % % \subsubsection{The Graphing Screen} % % The graphing screen is the centerpiece of the {\AcroFLeX} graphing system. % % \begin{macro}{\graphScreen} % % The \cs{graphScreen} command is just the \cs{rmAnnot} command with the % fourth argument set to the \texttt{acroflexWidget}. The command takes % three parameters, each just passed to \cs{rmAnnot}: The first is optional % that sets the key-value pairs, an important one is \texttt{poster=afposter} % to get the famous \AcroFLeX{} logo inserted as the opster; the second % is the width; the third is the height. The widget resizes itself, so the choice % of the dimensions is up to the document author. % % If \cs{dimSreenGraph} is used then you can simply use the dimensions declared there; % for example, %\begin{verbatim} % \dimScreenGraph{186bp}{186bp*3/4} % ... % \graphScreen[poster=aflogo]{\hScreenGraph}{\vScreenGraph} %\end{verbatim} % Note the use of calculated height, three-fourths of the width. \cs{graphScreen} can be, % in turn, be resized using \cs{resizebox} or \cs{scalebox}. % % \begin{macrocode} \newcommand{\graphScreen}[3][]{\rmAnnot[#1,% name=afRM\afgraphName]{#2}{#3}{acroflexWidget}}% % \end{macrocode} % \end{macro} % \begin{macro}{\iconFloatGraphScreen} % Should you wish to create a graphing screen in a floating window, use the % \cs{iconFloatGraphScreen}. It takes three arguments, the first one is optional % and is passed to the first argument the underlying \cs{graphScreen}. A typical % first argument is a poster key value: \texttt{poster=aflogo}. The second two are % dimensions (width and height). We use \cs{resizebox} from the graphicx package. % The \cs{resizebox} can take an exclamation point (!) as its arguments, in this % case, the object will be resized to keep its aspect ratio. See the documentation % of \cs{resizebox} for more details. Below is an example, %\begin{verbatim} % \iconFloatGraphScreen[poster=aflogo]{40bp}{!} %\end{verbatim} % The rich media annotation has a transparent button on top of it. The poster of the annotation % can be see through the button. Pressing on the button activates, or deactivates the annotation. % % The default is not to allow the user to close the window or go into full screen mode, however % by executing\DescribeMacro{\allowFSFloatGS} \cs{allowFSFloatGS} before the % \cs{iconFloatGraphScreen} command, we allow for full screen, while % \DescribeMacro{\defaultFloatGS} \cs{defaultFloatGS} returns to the default state. % \begin{macrocode} \newcommand{\allowFSFloatGS}{\def\af@passcontext{\@gobble}} \newcommand{\defaultFloatGS}{\def\af@passcontext{passcontext}} % \end{macrocode} % We set the default value, we do no allow full screen. % \begin{macrocode} \defaultFloatGS % \end{macrocode} % Now for the \cs{iconFloatGraphScreen} command % \begin{macrocode} \newcommand{\iconFloatGraphScreen}[3][]{% \makebox[0pt][l]{% \resizebox{#2}{#3}{% % \end{macrocode} % Here is the graphing screen % \begin{macrocode} \graphScreen[#1,windowed,\af@passcontext,deactivated=pageclose ]{\hScreenGraph}{\vScreenGraph}}}% \resizebox{#2}{#3}{% % \end{macrocode} % And the button that overlays it % \begin{macrocode} \pushButton[\S{S}\H{N}\autoCenter{n}\W0\BG{}\BC{} \TU{\tt@iconFloatGraphScreen}\A{\JS{% var rm = this.getAnnotRichMedia(% this.pageNum, "afRM\afgraphName");\r rm.activated=!rm.activated; }}]{float\afgraphName Btn-\therm@Cnt}{\hScreenGraph} {\vScreenGraph}}% } \newcommand{\tticonFloatGraphScreen}[1]{% \def\tt@iconFloatGraphScreen{#1}} \tticonFloatGraphScreen{Click to view graphing screen, click again to hide graphing screen.} % \end{macrocode} % \end{macro} % % \subsubsection{Various Controls} % % The graphing screen, obviously, graphs functions of the form $ y = f(x) $. The user % must have a way of entering the functional part, the $f(x)$. \cs{fileInputField} % is used for this purpose. The \cs{graphBtn} is used to graph the function, while % \cs{graphClrBtn} is used to clear the graph and deactivate the Flash widget. % % The domain of the variable $x$ is specified though the commands % \cs{domMin} and \cs{domMax}; while the range of values on % the $y$ axis is specified by \cs{rngMin} and \cs{rngMax}. The number of points % that are plotted can be specified through \cs{numPoints}. % % \paragraph{The Input Function.} % \begin{macro}{\funcInputField} % The parameters for all the above mentioned functions, with the exception of % \cs{afDefaultFunction}, take three parameters generally described below: % % \begin{enumerate} % \item[\texttt{[\#1]}:] optional arguments to modify appearance of the form field % \item[\texttt{\#2}:] the width of the form field % \item[\texttt{\#3}:] the height of the form field % \end{enumerate} % The definitions below use two new keys, \cs{nuDV} and \cs{nuV}, to avoid the use % of unicode when the unicode option of hyperref has been invoked. The initial and % default values of the function input field may contain symbols like \texttt{\string^} % that hyperref does not like and strips out. These two keys are also used in % \cs{functionSelect} below, for the same reason. % \begin{macrocode} \newcommand{\funcInputField}[3][]{\makebox[0pt][l]{% \textField[% \nuDV{\af@DefaultFunction}\nuV{\af@DefaultFunction} \F{\FHidden}\Ff{\FfReadOnly} ]{\afgraphName theHiddenFunction}{1bp}{1bp}}% \textField[% \BC{0 0 0}\nuDV{\af@DefaultFunction}\nuV{\af@DefaultFunction} \TU{\tt@funcInputField}#1\AA{\AAFormat{% \formatFunctionInput{"\afgraphName theHiddenFunction"}} \AAKeystroke{\keystrokeFunctionInput} }% ]{\afgraphName theFunction}{#2}{#3}% } \newcommand{\ttfuncInputField}[1]{% \def\tt@funcInputField{#1}} \ttfuncInputField{Enter any of the following for expressions:\r \space\space1. A function of x of the form f(x);\r \space\space2. A polar function of t of the form f(t);\r \space\space3. A set of parametric functions of t of the form f(t);g(t) \r\space\space\space\space\space(separated by a semi-colon);\r \space\space4. A list of points, (a1,b1);(a2,b2);...;(an,bn)\r \space\space\space\space\space(separated by semi-colons). } % \end{macrocode} % I originally named the previous macro definition \cs{fileInputField}. My bad! % In case there is someone out there that uses this package, I'll let % \cs{fileInputField} to \cs{funcInputField}. % \begin{macrocode} \let\fileInputField\funcInputField % \end{macrocode} % \end{macro} % \begin{macro}{\formatFunctionInput} % \cs{formatFunctionInput} supplies format event for the % \cs{funcInputField}. Then the user enters a new function, the JavaScript function % \texttt{formatFunctionInput} executes \texttt{ParseInput} (from \textsf{exerquiz}), and places it % in the hidden function field. % \begin{macrocode} \def\formatFunctionInput#1{% try{ formatFunctionInput(#1) } catch(e){}; } \def\keystrokeFunctionInput{% try{ keystrokeFunctionInput() } catch(e){}; } % \end{macrocode} % \end{macro} % \paragraph{The Curve Select Combo Box.} % \begin{macro}{\functionSelect} % \begin{macro}{\initFuncSelect} % \begin{macro}{\savedelSelBtn} % This is an optional combo box for selecting curves and points to graph. % Note, this drop down list should not overlay the graphing widget, the widget % is on top, and the list cannot be seen. % \begin{macrocode} \newcommand{\afCurve}[1]{\def\afcurve{#1 }\def\afcurvei{#1}} \afCurve{Curve} \newcommand{\afPoint}[1]{\def\afpoint{#1 }\def\afploti{#1}} \afPoint{Point} \newcommand{\afUnused}[1]{\def\afunused{#1}} \afUnused{--unused} % \end{macrocode} % Any re-definitions should take place in the preamble only! % \begin{macrocode} \@onlypreamble\afCurve \@onlypreamble\afPoint \@onlypreamble\afUnused % \end{macrocode} % The listing of the drop-down menu. To begin with, there are eight % menu items: four for curves, and four for plotted points. % \begin{macrocode} \newcommand{\initFuncSelect}[1]{\def\af@initializeFuncSelect{#1}} \initFuncSelect{% [(\af@DefaultFunction)(\afcurve1)]% [(<\afcurve2\afunused>)(\afcurve2)]% [(<\afcurve3\afunused>)(\afcurve3)]% [(<\afcurve4\afunused>)(\afcurve4)]% [(<\afpoint1\afunused>)(\afpoint1)]% [(<\afpoint2\afunused>)(\afpoint2)]% [(<\afpoint3\afunused>)(\afpoint3)]% [(<\afpoint4\afunused>)(\afpoint4)]} % \end{macrocode} % The combo box that displays the above items. On selection, % we populate the \texttt{theFunction} field. % \begin{macrocode} \newcommand{\functionSelect}[3][]{% \comboBox[\TU{\tt@functionSelect}#1\Ff{\FfCommitOnSelChange} \nuDV{\af@DefaultFunction}\nuV{\af@DefaultFunction} \AA{\AAKeystroke{% if (!event.willCommit) {\r\t this.getField( "\afgraphName theFunction").value=event.changeEx;\r }}}]{\afgraphName ComboSelect}{#2}{#3}{\af@initializeFuncSelect}% } \newcommand{\ttfunctionSelect}[1]{% \def\tt@functionSelect{#1}} \ttfunctionSelect{Enter a function on \afcurvei1--\afcurvei4, or a list of points on \afploti1--\afploti4.} % \end{macrocode} % Saves the current function to the list, shift-click deletes % the current list item, and returns it to its default. % \begin{macrocode} \newcommand{\savedelSelBtn}[3][]{% \pushButton[\TU{\tt@savedelSelBtn}#1 \A{\JS{saveDelSelAction("\afgraphName"); }}]{\afgraphName savedelSelectBtn}{#2}{#3}% } \newcommand{\ttsavedelSelBtn}[1]{\def\tt@savedelSelBtn{#1}} \ttsavedelSelBtn{Click to save current function to list, shift-click to delete the current function from list} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \paragraph{The Graphing Button.} % \begin{macro}{\graphBtn} % Clicking on this button when the % rich media annot is not activated will activate it. Clicking on % this button when the rich media annot is activate will cause the % function in the \cs{fileInputField} to be graphed. % \begin{macrocode} \newcommand{\graphBtn}[3][]{% \pushButton [\BC{0 0 0}\CA{Graph It!}\TU{\tt@graphBtn}#1 \A{\JS{graphBtnAction("\afgraphName",this.pageNum); }}]{\afgraphName graphIt}{#2}{#3}% } \newcommand{\ttgraphBtn}[1]{\def\tt@graphBtn{#1}} \ttgraphBtn{Press to graph the function} % \end{macrocode} % \end{macro} % \paragraph{The Clear Screen Button.} % % \begin{macro}{\graphClrBtn} % \begin{macro}{\clearGraphJS} % Click on this button and all fields % associated with this graphing screen are reset. Shift click makes the % AcroFlex widget deactivated. % \begin{macrocode} \newcommand{\clearGraphJS}{% clearGraph("all","\afgraphName",this.pageNum);} \newcommand{\graphClrBtn}[3][]{\pushButton[\BC{0 0 0}\CA{Clear} \A{\JS{\clearGraphJS}}\TU{\tt@graphClrBtn}#1 ]{\afgraphName clearIt}{#2}{#3}% } \newcommand{\ttgraphClrBtn}[1]{\def\tt@graphClrBtn{#1}} \ttgraphClrBtn{Click to clear graph, shift-click to deactivate the graphing screen} % \end{macrocode} % \end{macro} % \end{macro} % % \paragraph{The Domain the function is to be graphed over.} % % \begin{macro}{\domMin} % \begin{macro}{\domMax} % The lower endpoint of the interval over which the function is % graphed. % % \begin{macrocode} \newcommand{\domMin}[3][]{\makebox[0pt][l]{% \textField[\nuDV{\af@DefaultDomMin}\nuV{\af@DefaultDomMin} \F{\FHidden}\Ff{\FfReadOnly} ]{\afgraphName theHiddenDom.min}{1bp}{1bp}}% \textField[\textSize{0}\nuV{\af@DefaultDomMin} \nuDV{\af@DefaultDomMin}\BC{0 0 0}\TU{\tt@domMin}#1\AA{% \AAKeystroke{\keystrokeDomRng{"\afgraphName theHiddenDom.min"}} \AAFormat{\formatVarIntervals{"\afgraphName theHiddenDom.min"}} }]{\afgraphName theDom.min}{#2}{#3}% } \newcommand{\ttdomMin}[1]{\def\tt@domMin{#1}} \ttdomMin{Enter the minimum value for the variable x} % \end{macrocode} % The upper endpoint of the interval over which the function is graphed. % \begin{macrocode} \newcommand{\domMax}[3][]{\makebox[0pt][l]{% \textField[\nuDV{\af@DefaultDomMax}\nuV{\af@DefaultDomMax} \F{\FHidden}\Ff{\FfReadOnly} ]{\afgraphName theHiddenDom.max}{1bp}{1bp}}% \textField[\textSize{0}\nuV{\af@DefaultDomMax} \nuDV{\af@DefaultDomMax}\BC{0 0 0}\TU{\tt@domMax}#1\AA{% \AAKeystroke{\keystrokeDomRng{"\afgraphName theHiddenDom.max"}} \AAFormat{\formatVarIntervals{"\afgraphName theHiddenDom.max"}} }]{\afgraphName theDom.max}{#2}{#3}% } \newcommand{\ttdomMax}[1]{\def\tt@domMax{#1}} \ttdomMax{Enter the maximum value for the variable x} % \end{macrocode} % \end{macro} % \end{macro} % \paragraph{The interval on vertical axis what is to be displayed.} % \begin{macro}{\rngMin} % \begin{macro}{\rngMax} % The lower endpoint of the interval on the $y$-axis that is displayed on the % graphing screen. % \begin{macrocode} \newcommand{\rngMin}[3][]{\makebox[0pt][l]{% \textField[\nuDV{\af@DefaultRngMin}\nuV{\af@DefaultRngMin} \F{\FHidden}\Ff{\FfReadOnly} ]{\afgraphName theHiddenRng.min}{1bp}{1bp}}% \textField[\textSize{0}\nuV{\af@DefaultRngMin} \nuDV{\af@DefaultRngMin}\BC{0 0 0}\TU{\tt@rngMin}#1\AA{% \AAKeystroke{\keystrokeDomRng{"\afgraphName theHiddenRng.min"}} \AAFormat{\formatVarIntervals{"\afgraphName theHiddenRng.min"}} }]{\afgraphName theRng.min}{#2}{#3}% } \newcommand{\ttrngMin}[1]{\def\tt@rngMin{#1}} \ttrngMin{Enter the minimum value for the variable y} % \end{macrocode} % The upper endpoint of the interval on the $y$-axis that is displayed on the % graphing screen. % \begin{macrocode} \newcommand{\rngMax}[3][]{\makebox[0pt][l]{% \textField[\nuDV{\af@DefaultRngMax}\nuV{\af@DefaultRngMax} \F{\FHidden}\Ff{\FfReadOnly} ]{\afgraphName theHiddenRng.max}{1bp}{1bp}}% \textField[\textSize{0}\nuV{\af@DefaultRngMax} \nuDV{\af@DefaultRngMax}\BC{0 0 0}\TU{\tt@rngMax}#1\AA{% \AAKeystroke{\keystrokeDomRng{"\afgraphName theHiddenRng.max"}} \AAFormat{\formatVarIntervals{"\afgraphName theHiddenRng.max"}} }]{\afgraphName theRng.max}{#2}{#3}% } \newcommand{\ttrngMax}[1]{\def\tt@rngMax{#1}} \ttrngMax{Enter the maximum value for the variable y} % \end{macrocode} % \end{macro} % \end{macro} % \paragraph{The Domain parametric equations is to be graphed over.} % \begin{macro}{\domMinP} % \begin{macro}{\domMaxP} % The lower endpoint of the interval over which the function is graphed. % \begin{macrocode} \newcommand{\domMinP}[3][]{\makebox[0pt][l]{% \textField[\nuDV{\af@DefaultDomMint}\nuV{\af@DefaultDomMint} \F{\FHidden}\Ff{\FfReadOnly} ]{\afgraphName theHiddenDom_t.min}{1bp}{1bp}}% \textField[\textSize{0}\nuV{\af@DefaultDomMint} \nuDV{\af@DefaultDomMint}\BC{0 0 0}\TU{\tt@domMinP}#1\AA{% \AAKeystroke{\keystrokeDomRng{"\afgraphName theHiddenDom_t.min"}} \AAFormat{\formatVarIntervals{"\afgraphName theHiddenDom_t.min"}} }]{\afgraphName theDom_t.min}{#2}{#3}% } \newcommand{\ttdomMinP}[1]{\def\tt@domMinP{#1}} \ttdomMinP{Enter the minimum value for the variable t} % \end{macrocode} % The upper endpoint of the interval over which the function is graphed. % \begin{macrocode} \newcommand{\domMaxP}[3][]{\makebox[0pt][l]{% \textField[\nuDV{\af@DefaultDomMaxt}\nuV{\af@DefaultDomMaxt} \F{\FHidden}\Ff{\FfReadOnly} ]{\afgraphName theHiddenDom_t.max}{1bp}{1bp}}% \textField[\textSize{0}\nuV{\af@DefaultDomMaxt} \nuDV{\af@DefaultDomMaxt}\BC{0 0 0}\TU{\tt@domMaxP}#1\AA{% \AAKeystroke{\keystrokeDomRng{"\afgraphName theHiddenDom_t.max"}} \AAFormat{\formatVarIntervals{"\afgraphName theHiddenDom_t.max"}} }]{\afgraphName theDom_t.max}{#2}{#3}% } \newcommand{\ttdomMaxP}[1]{\def\tt@domMaxP{#1}} \ttdomMaxP{Enter the maximum value for the variable t} % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\formatVarIntervals} % \begin{macro}{\keystrokeDomRng} % These are format and keystroke functions that support the above % domain and range commands. % \begin{macrocode} \def\formatVarIntervals#1{% try{ formatVarIntervals(#1) } catch(e){}; } \def\keystrokeDomRng#1{% if (event.willCommit) keystrokeDomRng(#1); } % \end{macrocode} % \end{macro} % \end{macro} % \paragraph{The Number of points to plot.} % \begin{macro}{\numPoints} % \begin{macro}{\defaultNumPoints} % The number of points to use for plotting the specified function. % \begin{macrocode} \newcommand{\defaultNumPoints}[1]{% \def\af@defaultNumPoints{#1}} \defaultNumPoints{40} \newcommand\numPoints[3][]{% \textField[\nuV{\af@defaultNumPoints}\nuDV{\af@defaultNumPoints} \Q1\BC{0 0 0}\TU{\tt@numPoints}#1\AA{% \AAKeystroke{if (event.willCommit) keystrokeNumPoints();}} ]{\afgraphName numNodes}{#2}{#3}% } \newcommand{\ttnumPoints}[1]{\def\tt@numPoints{#1}} \ttnumPoints{Enter the number of points to plot} % \end{macrocode} % \end{macro} % \end{macro} % % \paragraph{Shifting the Graph Screen.} % In this section we provide basic control for shifting the graph screen up and down, % and left and right. Two new text fields are designed to set the amount of vertical % or horizontal shifting. % % \begin{macro}{\amtShift} % Use this text field to enter the amount of horizontal or vertical shift. % % We have the usual three parameters, optional argument to change the appearance, % the width of the form field, the height of the form field. % \begin{macrocode} \newcommand{\defaultShiftAmt}[1]{% \def\af@defaultShiftAmt{#1}} \defaultShiftAmt{1} \newcommand{\amtShift}[3][]{% \textField[\nuV{\af@defaultShiftAmt}\nuDV{\af@defaultShiftAmt}\Q1 \BC{0 0 0}\TU{\tt@amtShift}#1\AA{\AAKeystroke{% if (event.willCommit) keystrokeAmtShift(); }}]{\afgraphName amtshift}{#2}{#3}% } \newcommand{\ttamtShift}[1]{\def\tt@amtShift{#1}} \ttamtShift{Enter the amount to shift, horizontally or vertically} % \end{macrocode} % \end{macro} % % For the controls for initiating the shifting action, we can use forms or links. We'll begin % by using links. % \begin{macro}{\hShiftL} % \begin{macro}{\hShiftR} % \begin{macro}{\vShiftD} % \begin{macro}{\vShiftU} % Basic link to initiate the actions of shifting the viewing screen horizontally or vertically % an amount equal to the entries in \cs{amtShift}. % \begin{macrocode} \newcommand{\hShiftL}[2][]{% \setLinkText[#1\A{\JS{% shiftHorVert ("\afgraphName",this.pageNum,"h","-"); }}]{#2}% } \newcommand{\hShiftR}[2][]{% \setLinkText[#1\A{\JS{% shiftHorVert ("\afgraphName",this.pageNum,"h","+"); }}]{#2}% } \newcommand{\vShiftD}[2][]{% \setLinkText[#1\A{\JS{% shiftHorVert ("\afgraphName",this.pageNum,"v","-"); }}]{#2}% } \newcommand{\vShiftU}[2][]{% \setLinkText[#1\A{\JS{% shiftHorVert ("\afgraphName",this.pageNum,"v","+"); }}]{#2}% } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \paragraph{The Zooming in and out.} % Coming fresh off the success of the horizontal and vertical shifting commands, let's plough % on to zooming in. % \begin{macro}{\zoomInOut} % This push button control zooms out, with a click, or zoom in with a shift-click. % \begin{macrocode} \newcommand{\zoomInOut}[3][]{% \pushButton[\BC{0 0 0}\CA{Zoom}\TU{\tt@zoomInOut}#1 \A{\JS{% var shiftType = (event.shift) ? "+" : "-";\r zoomInOut ("\afgraphName",this.pageNum,shiftType); }} ]{\afgraphName zoominout}{#2}{#3}% } \newcommand{\ttzoomInOut}[1]{\def\tt@zoomInOut{#1}} \ttzoomInOut{Click to zoom out, shift-click to zoom in} % \end{macrocode} % \end{macro} % % \subsection{Non-Interactive Graphing} % % Use the \cs{setLinkText} command to pass a function name, the number of points, and domain/range % information to the graphing screen, without user input. This command is useful for tutorials % that would like to create a graph for the student to inspect, or as part of a quiz. % \begin{macro}{\sgraphLink} % The command \cs{sgraphLink} has four arguments, the first one is an optional argument % to modify the appearance of the link; the second argument consist of key-value pairs that % are options for the {\AcroFLeX} Graphing system; the third argument is the function of the % semi-colon delimited list of points to be plotted; the fourth argument is the text to be used % as the link. %\begin{verbatim} % \sgraphLink[]{}{func|points}{} %\end{verbatim} %\paragraph{Options for the Second Parameter.} We define and briefly discuss % a series of keys for the second parameter. % % \begin{macrocode} % \end{macrocode} % \DescribeMacro{graph} % Curves and points are graphed on chart series. This system uses \texttt{LinearSeries}, % \texttt{PlotSeries}, and \texttt{AreaSeries}. The {\AcroFLeX} graphing widget provides % four series for each of these three. Values of \texttt{c1}, \texttt{c2}, \texttt{c3}, \texttt{c4} for this key graphs the data % on a \texttt{LinearSeries}; values of \texttt{p1}, \texttt{p2}, \texttt{p3}, \texttt{p4} plot the data on a \texttt{PlotSeries}; % and values of \texttt{a1}, \texttt{a2}, \texttt{a3}, \texttt{a4} graphs the data on a \texttt{AreaSeries}. % \begin{macrocode} \define@choicekey+{afsl}{graph}{c1,c2,c3,c4,p1,p2,p3,p4,% a1,a2,a3,a4}[c1]{\edef\afsl@graph{#1}}{\PackageWarning{acroflex} {Bad choice for the graph key, permissible values are c1, c2, c3,c4, p1, p2, p3, p4, a1, a2, a3, a4. Try again}} % \end{macrocode} % \DescribeMacro{type} % The type of curve this is, \texttt{cart} ($y=f(x)$), \texttt{para} % ($x=f(t); y=g(t)$), or \texttt{polar} ($r = f(t)$). When defining a polar function % using \cs{sgraphLink}, use \texttt{type=polar} to signal that the curve is a polar function. % \changes{v1.6c}{2016/08/29}{Set defaults for type and connectwith} % \begin{macrocode} \define@choicekey+{afsl}{type}{cart,para,polar}[cart]{% \edef\afsl@type{#1}}{\PackageWarning{acroflex} {Bad choice for the type key, permissible values are cart, para, and polar. Try again}} \let\afsl@type\@empty % \end{macrocode} % \DescribeMacro{connectwith} % When the graph is either a \texttt{LinearSeries} or an % \texttt{AreaSeries}, the points are connected. Use this key to % specify how the points are to be connected. The default values % for this key are as follows: for % \texttt{graph=cart} it is \texttt{connectwith=curve}, and for % \texttt{graph=para} it is \texttt{connectwith=segment}. % Use this key to override these defaults. For parametric equations, % \texttt{connectwith=curve} is not recommended, the results may not % be good. Use of this key is recommended for \texttt{graph=cart}. % \begin{macrocode} \define@choicekey+{afsl}{connectwith}{curve,segment}[curve]{% \edef\afsl@form{#1}}{\PackageWarning{acroflex} {Bad choice for the connectwith key, permissible values are curve and segment. Try again}} \let\afsl@form\@empty % \end{macrocode} % \DescribeMacro{noquotes} % This key is a workaround for the case when the function or data is passed by % JavaScript. Used when passing things that are already strings, such as \texttt{event.value}. % An example of usage can be found in \texttt{afgraph.tex}. % \begin{macrocode} \define@choicekey+{afsl}{noquotes}[\val\nr]{true,false}[true]{% \ifcase\nr\relax\def\af@quotes{}\or\def\af@quotes{"}\fi} {\PackageWarning{acroflex} {Bad choice for the noquotes key, permissible values are true and false. Try again}} % \end{macrocode} % \DescribeMacro{points} % Use this key to specify the number of points to generate from the function. % The key is ignored if \texttt{PlotSeries} is used, and should not appear, or be set to zero. % \begin{macrocode} \define@key{afsl}{points}[0]{\edef\afsl@nPoints{#1}} % \end{macrocode} % \DescribeMacro{xInterval} % An interval of numbers on the horizontal axis. This interval determines the % domain over which the function of $x$ is to be graphed. The endpoints of this % interval also determine the left and right boundaries of the viewing window. % \begin{macrocode} \define@key{afsl}{xInterval}[]{\edef\afsl@xInterval{#1}} % \end{macrocode} % \DescribeMacro{xPlot} % (10/11/09) Added the \texttt{xPlot} key. With the \texttt{xInterval} key, the interval over which to % plot the curve is bound to the scaling on the x-axis. It is now desired to plot % a graph over a smaller interval than the one on the x-axis, and \texttt{xPlot} will be used for % that purpose; thus one can say \verb!xInterval={[-2,2]},xPlot={[-1,0]}!. If \texttt{xPlot} % is not specified, then $\texttt{xPlot}=\texttt{xInterval}$. % \begin{macrocode} \define@key{afsl}{xPlot}[]{\edef\afsl@xPlot{#1}} % \end{macrocode} % \DescribeMacro{yInterval} % An interval of numbers on the vertical axis. The endpoints of this % interval also determine the lower and upper boundaries of the viewing window. % \begin{macrocode} \define@key{afsl}{yInterval}[]{\edef\afsl@yInterval{#1}} % \end{macrocode} % \DescribeMacro{tInterval} % An interval of numbers on the parameter axis. This interval determines the % domain over which a polar function and parametric equations are to be graphed. % \texttt{xInterval} and \texttt{yInterval} determines the viewing window. % \begin{macrocode} \define@key{afsl}{tInterval}[]{\edef\afsl@tInterval{#1}} % \end{macrocode} % \DescribeMacro{populate} % A Boolean value, which if \texttt{true}, signals \texttt{Graph\_xy()} or % \texttt{Graph\_xyt()} to populate the interactive field controls. When % no controls are provided for the graphing screen, populate should have a % value of \texttt{false}. % \begin{macrocode} \define@choicekey+{afsl}{populate}{true,false}[true]{% \edef\afsl@populate{#1}}{\PackageWarning{acroflex} {Bad choice for the populate key, permissible values are true and false. Try again}} % \end{macrocode} % \DescribeMacro{wait} % When using \cs{defineGraphJS} to create an action with multiple graph events, % use \texttt{wait=true}. This setting gives the {\AcroFLeX} graphing widget to % receive one set of plotting data before trying to digest another. % \begin{macrocode} \define@choicekey+{afsl}{wait}{true,false}[true]{% \edef\afsl@wait{#1}}{\PackageWarning{acroflex} {Bad choice for the wait key, permissible values are true and false. Try again}} % \end{macrocode} % \paragraph*{Set the defaults for all the keys.} % All changes are local to each link, so we set global defaults whose values % are not changed by the changes as a result of the passing key-value pairs % through \cs{sgraphLink}. % \begin{macrocode} \setkeys{afsl}{graph,points,xInterval,xPlot,yInterval,tInterval,% populate=false,type,connectwith,noquotes=false,wait=false} % \end{macrocode} % \begin{macro}{\sgraphLink} % We finally come to the \cs{sgraphLink}. % \begin{macrocode} \newcommand{\sgraphLink}[4][]{{% \defineGraphJS{#2}{#3}{\af@sglnkAction}% \setLinkText[#1\A{\JS{\af@sglnkAction}}]{#4}% }} % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\defineGraphJS} % The \cs{defineGraphJS} is the JS used to call the \texttt{Graph\_xy()} or \texttt{Graph\_xyt()} % JavaScript function defined in this package. It uses the same key-value pairs as the second % argument of \cs{sgraphLink}. The command can be used to construct links that graph several % curves (or plots) with a link or form action. It can be integrated into the exerquiz quizzing system, % using the new key \cs{AddAAKeystroke} of \cs{RespBoxMath}. The use of this key and this command is illustrated % in the \texttt{acroflex.tex} demo file. %\par\medskip\noindent % The \texttt* optional first parameter signals to use \cs{edef} in the subsequent command % \cs{af@defineGraphJS}. % \begin{macrocode} \newcommand{\defineGraphJS}{\@ifstar{\let\AF@exDEF\edef\af@defineGraphJS} {\let\AF@exDEF\xdef\af@defineGraphJS}} % \end{macrocode} % We continue \cs{defineGraphJS}: The first parameter are key-values of the % \texttt{afsl} family; the second parameter is the function; the third is the % name to assign the command being defined. % modify the appearance of the link; the second parameter % \begin{macrocode} \newcommand{\af@defineGraphJS}[3]{{\makeJSspecials \edef\af@tmp@exp{\noexpand\setkeys{afsl}{#1}}\af@tmp@exp \ifx\afsl@xPlot\@empty\let\afsl@xPlot\afsl@xInterval\fi \AF@exDEF#3{Graph_xytJS (\af@quotes#2\af@quotes,"\afsl@xInterval",% "\afsl@yInterval","\afsl@xPlot","\afsl@tInterval","\afsl@graph",% \afsl@populate,\afsl@wait,"\afsl@type","\afsl@form","\afgraphName",% \afsl@nPoints)}% }} % \end{macrocode} % \end{macro} % % \section{Document JS in Support of \texorpdfstring{\protect\AcroFLeX}{AcroFleX}} % % Below are some text macros used in creating error messages. They may be redefined % into better English, or another language. Use the definition file \texttt{afcustom.def} % to make these re-definitions. % \begin{macrocode} \defineJSStr{\af@badNumberMsg}{% The value input does not appear to be a number, please enter a number, or an expression that evaluates to a number.} \defineJSStr{\af@negNumberMsg}{% The number of points is a positive integer, changing to a positive integer.} \defineJSStr{\af@zeroNumberMsg}{% The number of points is a positive integer, changing to the default value of \af@defaultNumPoints.} \defineJSStr{\af@negShiftMsg}{% The amount of shift is a positive number, changing to a positive number.} \defineJSStr{\af@zeroShiftMsg}{% The amount of shift is a positive number, changing to the default value of 1.} \defineJSStr{\af@saveDelSelAlerti}{% There is nothing in the function input text field.} \defineJSStr{\af@saveDelSelAlertii}{% You have not defined any points to plot} \defineJSStr{\af@graphBtnAlerti}{Undefined graph types} % \end{macrocode} % \begin{macrocode} \begin{insDLJS*}[acroflexLoaded]{afgrfJS} \begin{newsegment}{AF: AcroFLeX Graphing Bundle} /* Document Level JavaScript AcroFLeX Graphing Bundle D. P. Story copyright 2008-\the\year */ var acroflexLoaded = true; var _mathVars="xt"; var aGraphData = new Array(); var ck4PtsRe = /\(.+,.+\)/; var badNumberMsg=\af@badNumberMsg; var negNumberMsg=\af@negNumberMsg; var zeroNumberMsg=\af@zeroNumberMsg; var negShiftMsg=\af@negShiftMsg; var zeroShiftMsg=\af@zeroShiftMsg; var saveDelSelAlerti=\af@saveDelSelAlerti; var saveDelSelAlertii=\af@saveDelSelAlertii; var graphBtnAlerti=\af@graphBtnAlerti; var scratchCounter=0; var aTimeOutArray = new Array(); var afSuffixes = new Array("ComboSelect","theFunction", "amtShift","theDom","theRng", "theDom_t", "Rng_t","numNodes"); \end{newsegment} \begin{newsegment}{AF: Graphing Functions} % \end{macrocode} % \DescribeMacro{Graph\_xy} Graphs a function of a single variable in the rectangular % coordinate system. % % The \texttt{Graph\_xy} function takes four or more arguments. In interactive % mode, it takes four. %\begin{enumerate} % \item \texttt{graph\_props}: (Needs Revision) This is a signal for the type of graphing requested. % \texttt{c1,...,c4} for continuous plotting; and \texttt{p1,...,p4} for discrete % plotting. There are four of these types. % \item \texttt{baseName}: The base name of the graphing environment. This is used to % build the field names for the controls, if any, on the page. % \item \texttt{pNum}: The page number of the target rich media annot. This together % with \texttt{baseName} is enough information to get the AnnotRichMedia object using % the \texttt{Doc.AnnotRichMedia} method. %\end{enumerate} % When in interactive mode, we get the function to be graphed, the domain of $x$ % the range of $y$, and the number of points to plot from form fields. % \begin{itemize} % \item The function is input by the user into the field \texttt{baseName+"theFunction"}, % but we get the JS version from \texttt{baseName+"theHiddenFunction"}. % When the user enters a function, it is parsed, and changed into a proper JS % expression: \verb!2x^2sin(x)! becomes \verb!2*Math.pow(x,2)*Math.sin(x)!. % % \item The domain and range values are input by the user through the fields, having field names of % \texttt{baseName+"theDom.min"}, \texttt{baseName+"theDom.max"}, \texttt{baseName+"theRng.min"}, % and \texttt{baseName+"theRng.max"}, but we retrieve the values from hidden fields. % See \texttt{getDomRng} below for the listing of the hidden fields. % When the user enters domain/range info, this info is parsed and made into % property JS expressions. In this way, the user can enter symbolics like \texttt{PI} % or \texttt{sin(PI/3)}, or do arithmetic, like \texttt{2 + 1/3}. % % \item The number of points to plot is obtained from \texttt{baseName+"numNodes"}, % no preprocessing is used. % % \end{itemize} % % \noindent When the number of arguments is greater than four, we are in non-interactive % mode. The 5th argument is the JS function to graph; the 6th is the number of % points to plot; the 7th is an object containing the domain % % \paragraph{Notes on the Modes.} There are three modes of operation: interactive, populate, % and silent. %\begin{itemize} % \item \textbf{Interactive:} This occurs when the user enters a % function through the UI. In this case the number of arguments % passed to \texttt{Graph\_xy} (or \texttt{Graph\_xyt}) is only four. % The number of \texttt{arguments} is determined by the arguments % object, and the switch \texttt{afInteractive} is set to % \texttt{true}. For this mode % % The following controls are \emph{required}: \cs{fileInputField}, % \cs{graphBtn}, \cs{domMin}, \cs{domMax}, \cs{rngMin}, \cs{rngMax}, % and \cs{numPoints}. If parametric or polar graphs are to be used, % then \cs{domMinP} and \cs{domMaxP} are also required. The other % controls are \emph{optional}, \cs{graphClrBtn} (recommended), % \cs{amtShift} (and \cs{hShiftL}, % \cs{hShiftR},\cs{vShiftD},\cs{vShiftU}) and \cs{zoomInOut}. % % \item \textbf{Populate:} This mode occurs when the graphing parameters % are passed to \texttt{Graph\_xy} (or \texttt{Graph\_xyt}) by \cs{sgraphLink} % (or some other command). All the essential information is passed as arguments, % so the number of arguments is greater than four. The command initiating the % graphing should set the \texttt{graph\_props.populate} to \texttt{true}. In this % case the graphing data populate the required fields and the graph will be drawn. % It is the document author's responsibility to only use populate on graphing screens % that have all the required control fields. \texttt{Graph\_xy} (and \texttt{Graph\_xyt}) % checks the value of the \texttt{graph\_props.populate} property, and sets the switch % \texttt{populate} to \texttt{true}. % % Populate behave exactly like interactive, but the graphing data is passed to it in pre-packaged % for my the document author; the user, however, can manipulate the curve once it appears. % % The required controls are the same as the interactive mode. % % \item \textbf{Silent:} This is a non-interactive mode, there must be no controls other than % \cs{graphClrBtn}. Basically, the author prepares some pre-packaged graphs to be displayed % to the user, without interaction. These may go along with a tutorial discussion symmetry, % periodicity, tangent lines, etc. % %\end{itemize} % \begin{macrocode} function Graph_xy(graph_props, baseName, pNum) { _mathVars="x"; var afInteractive = (arguments.length <= 3); if (afInteractive) { var f = this.getField(baseName+"theHiddenFunction").value; % \end{macrocode} % If the file input field does not contain a Cartestian point $(a,b)$, % but it does contain a semi-colon, we figure what is entered is a % set of parametric equations. % \begin{macrocode} if ( !ck4PtsRe.test(f) && (f.indexOf(";")!=-1) ) { var dt = this.getField(baseName+"theDom_t.min"); if ( dt == null ) { syntaxError(); return; } Graph_xyt(graph_props, baseName, pNum); return; } f = this.getField(baseName+"theHiddenFunction").value; } createGraphData(baseName); var which_graph=graph_props.graph; var populate = false; graph_props.type="cart"; var aWhichGraph=/(c|p|a)(\d)/.exec(which_graph); if ( aWhichGraph==null ) aWhichGraph=["","c","1"]; var isGraph = (aWhichGraph[1]=="c" || aWhichGraph[1]=="a"); var connectPoints=false; var plotPoints=false; var wait = false; switch(aWhichGraph[1]) { case "p": var which_series="p"+aWhichGraph[2]; plotPoints=true; break; case "a": var which_series="a"+aWhichGraph[2]; break; default: var which_series="c"+aWhichGraph[2]; } graph_props.graph=which_series; % \end{macrocode} % Get domain and range of x and y, respectively % obtain in math environment so we can evaluate % any symbolic constants, such as \texttt{Math.PI} % \begin{macrocode} if (afInteractive) var oDR = getDomRng (baseName); else { wait=graph_props.wait; populate = graph_props.populate; var oDR = arguments[5]; if (populate) populateDomRng(baseName,oDR); for ( var o in oDR ) oDR[o] = EvalParse(oDR[o]); } aGraphData[baseName].aDomRngs = oDR; % \end{macrocode} % calculate width of intervals. If the user has passed a subinterval to us, then % \texttt{oDR.x\_min} would be defined, and we use it to compute the range. % \begin{macrocode} var rng_x = (typeof oDR.x_u=="undefined") ? (oDR.x_max - oDR.x_min) : (oDR.x_u - oDR.x_l); /* Get the function and calculated the plotted points */ if (afInteractive) { var n = Number(this.getField(baseName+"numNodes").value); if ( isNaN(n) || n <=0 ) n = \af@defaultNumPoints; } else { var f = ParseInput(arguments[2+1]); var n = Number(arguments[2+2]); if (populate) { this.getField(baseName+"theFunction").value=arguments[2+1]; this.getField(baseName+"numNodes").value=n; } if (isGraph) { % \end{macrocode} % Is there a function there? We use n to determine % that, if $n > 0$ we assume a function; otherwise, we % assume plotted points to be connected. % \begin{macrocode} connectPoints = ( n <= 0 ); if ( connectPoints ) plotPoints = true; // passing points to be plotted, not connected } else plotPoints = true; } % \end{macrocode} % Before we calculate the points, let's record what we are graphing. % \begin{macrocode} if (afInteractive || populate) updateGraphData(graph_props,baseName,f); % \end{macrocode} % Now we begin calculating the points to plot. % \begin{macrocode} var plot_x, plot_y; var x = (typeof oDR.x_u=="undefined") ? oDR.x_min : oDR.x_l; var h = rng_x / n; var thismax = (typeof oDR.x_u=="undefined") ? oDR.x_max : oDR.x_u; % \end{macrocode} % The plotted data will be accumulated as XML % \begin{macrocode} var cPlotData=; % \end{macrocode} % We strip out anything of the form \texttt{"y = "}, \texttt{"x = "} or \texttt{"r = "}, % allowing the user to enter the expressions in equational form \verb!"y = x^2"!, for example. % \begin{macrocode} var aSearchResults=/(([a-zA-Z])\s*=\s*)/.exec(f); if ( aSearchResults != null) { if ( aSearchResults[2] != "y" && aSearchResults[2] != "r" ) { syntaxError(); return; } } % \end{macrocode} % This allows functions of the form $y=f(x)$, $r=f(x)$, $y=f(t)$, $r=f(t)$. % \begin{macrocode} f = f.replace(/(([a-zA-Z])\s*=\s*)/g,""); % \end{macrocode} % \begin{macrocode} if ( isGraph && !plotPoints ) { for (var i=0; i<=n; i++) { % \end{macrocode} % We evaluate the function, and try to detect any errors. If an exception is thrown, % we display an \textsf{exerquiz} \texttt{syntaxError()} message. If the result is not % a number, we skip over it. % \begin{macrocode} try { with(Math) {_y = eval(f);} } catch(e) { % \end{macrocode} % We have thrown an exception, so either this is bad code, or the user wants us % to plot this as a polar function. We'll try, but if we're wrong, we'll throw an % exception in \texttt{Graph\_xyt()}. % \begin{macrocode} var paraEqs = "("+f+")*Math.cos(t);("+f+")*Math.sin(t)"; graph_props.type="polar"; this.getField(baseName +"theHiddenFunction").value=paraEqs; Graph_xyt(graph_props, baseName, pNum); return; } // If not a number then skip over. if (isFinite(_y)) { plot_x = util.printf("\%.10f", x); plot_y = util.printf("\%.10f", _y); % \end{macrocode} % We add the latest data point to the end of the XMList % \begin{macrocode} cPlotData.points[cPlotData..point.length()]= {plot_x}{plot_y} } x += h; } } else { // prepare to data for plotting % \end{macrocode} % At this point the variable f should be a string of % points to plot.\\ % \hspace*{30pt}\texttt{f = "(0,1);(2,2);(4,2);...;(5,3)"}.\\ % It's not clear whether the abcissas need to be sorted in % increasing order, or whether FLEX is smart enough to do % that. We'll assume the latter case. % \begin{macrocode} var afBegin = (f.indexOf("\(")+1); var afEnd = f.lastIndexOf("\)"); cPlotData=f.substring(afBegin,afEnd); var re = /\)\s*;\s*\(/; aPlotData= cPlotData.split(re); var cPlotData=; with (Math) { for ( var i=0; i{aTmp[0]}{aTmp[1]} } } } cPlotData=cPlotData.toXMLString(); var annot = this.getAnnotRichMedia(pNum,"afRM"+baseName); if ( annot ) { if (!annot.activated || wait ) { annot.activated=true; afWait4Activation( graph_props,baseName,pNum,oDR,cPlotData,50); } else annot.callAS("getPlotData", graph_props, oDR, cPlotData); } } % \end{macrocode} % \DescribeMacro{Graph\_xyt} This function graphs a set of parametric equations in the % rectangular coordinate system. The function pair is delimited by a semi-colon, early % in the code we get the function and test whether the function has a semi-colon in its % definition, so not, we send assume it is a function of a single variable, and send it % off to \texttt{Graph\_xy}. % % For silent mode, the parameters are the same, except that there are two extra arguments, % the endpoints of the parameter, $t$. The last argument is a Boolean, the author wants the % graphing data to populate the corresponding fields so user can manipulate. % \begin{macrocode} function Graph_xyt(graph_props, baseName, pNum) { _mathVars="t"; var which_graph=graph_props.graph; var populate = false; var afInteractive = (arguments.length <= 3); if (afInteractive) { var f = this.getField(baseName+"theHiddenFunction").value; if ( ck4PtsRe.test(f) || (f.indexOf(";")==-1) ) { Graph_xy(graph_props, baseName, pNum); return; } f = this.getField(baseName+"theHiddenFunction").value; } createGraphData(baseName); if ( graph_props.type!="polar") graph_props.type="para"; var aWhichGraph=/(c|p|a)(\d)/.exec(which_graph); if ( aWhichGraph==null ) aWhichGraph=["","c","1"]; var isGraph = (aWhichGraph[1]=="c" || aWhichGraph[1]=="a"); var connectPoints=false; var plotPoints=false; var wait=false; switch(aWhichGraph[1]) { case "p": var which_series="p"+aWhichGraph[2]; plotPoints=true; break; case "a": var which_series="a"+aWhichGraph[2]; break; default: var which_series="c"+aWhichGraph[2]; } graph_props.graph=which_series; % \end{macrocode} % Get domain and range of x and y, respectively % obtain in math environment so we can evaluate % any symbolic constants, such as \texttt{Math.PI} % \begin{macrocode} if (afInteractive) { var oDR = getDomRng (baseName); var oDp = getParaDom (baseName); } else { wait=graph_props.wait; populate = graph_props.populate; var oDR = arguments[5]; if (populate) populateDomRng(baseName,oDR); for ( var o in oDR ) oDR[o] = EvalParse(oDR[o]); var oDp = arguments[6]; if (populate) populateParaDom(baseName,oDp); for ( var o in oDp ) oDp[o] = EvalParse(oDp[o]); } aGraphData[baseName].aDomRngs = oDR; aGraphData[baseName].aDom_P = oDp; % \end{macrocode} % calculate width of intervals % \begin{macrocode} var rng_t = oDp.t_max - oDp.t_min; /* Get the function and calculated the plotted points */ if (afInteractive) { var n = Number(this.getField(baseName+"numNodes").value); if ( isNaN(n) || n <=0 ) n = \af@defaultNumPoints; } else { % \end{macrocode} % If this is polar, then we need to check if it has been parsed yet. % \begin{macrocode} var f = arguments[2+1]; if ( graph_props.type=="polar") { if(f.indexOf(";")==-1) { f = "("+f+")*cos(t);("+f+")*sin(t)"; f = ParseInput(f); } } else f = ParseInput(f); var n = Number(arguments[2+2]); if (populate) { this.getField(baseName+"theHiddenFunction").value=f; this.getField(baseName+"theFunction").value=arguments[2+1]; this.getField(baseName+"numNodes").value=n; } if (isGraph) { % \end{macrocode} % Is there a function there? We use n to determine % that, if $n > 0$ we assume a function; otherwise, we % assume plotted points to be connected. % \begin{macrocode} connectPoints = ( n <= 0 ); if ( connectPoints ) plotPoints = true; // passing points to be plotted, not connected } else plotPoints = true; } % \end{macrocode} % Before we calculate the points, let's record what we are graphing. % \begin{macrocode} if (afInteractive || populate) updateGraphData(graph_props,baseName,f); % \end{macrocode} % We strip out anything of the form \texttt{"y = "}, \texttt{"x = "} or \texttt{"r = "}, % allowing the user to enter the expressions in equational form \texttt{"r = 1+sin(t)"}, % or \texttt{x=sin(t); y = cos(t)}, for example. % \begin{macrocode} var aFunction = f.split(";"); var x_function = aFunction[0]; var y_function = aFunction[1]; var aSearchResults=/(([a-zA-Z])\s*=\s*)/.exec(x_function); if ( aSearchResults != null && aSearchResults[2] != "x") { syntaxError(); return; } x_function = x_function.replace(/(([a-zA-Z])\s*=\s*)/g,""); aSearchResults=/(([a-zA-Z])\s*=\s*)/.exec(y_function); if ( aSearchResults != null && aSearchResults[2] != "y") { syntaxError(); return; } y_function = y_function.replace(/(([a-zA-Z])\s*=\s*)/,""); var plot_x, plot_y; var t = oDp.t_min; var h = rng_t / n; var thismax = oDp.t_max; % \end{macrocode} % The plotted data will be accumulated as XML % \begin{macrocode} var cPlotData=; % \end{macrocode} % \begin{macrocode} if ( isGraph && !plotPoints ) { for (var i=0; i<=n; i++) { % \end{macrocode} % We evaluate the function, and try to detect any errors. If an exception is thrown, % we display an \textsf{exerquiz} \texttt{syntaxError()} message. If the result is not % a number, we skip over it. % \begin{macrocode} try { with(Math) { _x = eval(x_function); _y = eval(y_function); } } catch(e) { syntaxError(); return;} // If not a number then skip over. if (isFinite(_x)&&isFinite(_y)) { plot_x = util.printf("\%.10f", _x); plot_y = util.printf("\%.10f", _y); % \end{macrocode} % We add the latest data point to the end of the XMList % \begin{macrocode} cPlotData.points[cPlotData..point.length()]= {plot_x}{plot_y} } t += h; } } else { // prepare to data for plotting % \end{macrocode} % At this point the variable f should be a string of % points to plot.\\ % \hspace*{30pt}\texttt{f = "(0,1);(2,2);(4,2);...;(5,3)"}.\\ % It's not clear whether the abcissas need to be sorted in % increasing order, or whether FLEX is smart enough to do % that. We'll assume the latter case. % \begin{macrocode} var afBegin = (f.indexOf("\(")+1); var afEnd = f.lastIndexOf("\)"); cPlotData=f.substring(afBegin,afEnd); var re = /\)\s*;\s*\(/; aPlotData= cPlotData.split(re); var cPlotData=; with (Math) { for ( var i=0; i{aTmp[0]}{aTmp[1]} } } } cPlotData=cPlotData.toXMLString(); var annot = this.getAnnotRichMedia(pNum,"afRM"+baseName); if ( annot ) { if (!annot.activated || wait ) { annot.activated=true; afWait4Activation( graph_props,baseName,pNum,oDR,cPlotData,50); } else annot.callAS("getPlotData", graph_props, oDR, cPlotData); } } function createGraphData(baseName) { if( aGraphData[baseName] == undefined ) { aGraphData[baseName] = new Object(); aGraphData[baseName].aDomRngs=new Object(); aGraphData[baseName].aDom_P=new Object(); aGraphData[baseName].current = new Array(); } } % \end{macrocode} % This function is called by the \texttt{Graph\_xy} or \texttt{Graph\_xyt} % and updates the graphing data we are trying to track. % % Properties of the object % \verb!aGraphData[baseName].current[which_graph]! object are % \texttt{hiddenFN} (a string of the hidden JS version of the % function), \texttt{appearFN} (a string of the function the user % sees), and \texttt{graph\_props} (the graph properties passed from % \texttt{Graph\_xy} or \texttt{Graph\_xyt}. % \begin{macrocode} function updateGraphData(graph_props,baseName,f) { var which_graph=graph_props.graph; if (aGraphData[baseName].current[which_graph] == undefined) aGraphData[baseName].current[which_graph]=new Object(); aGraphData[baseName].current[which_graph].appearFN =this.getField(baseName+"theFunction").value; aGraphData[baseName].current[which_graph].hiddenFN=f; aGraphData[baseName].current[which_graph].graph_props=graph_props; } \end{newsegment} % \end{macrocode} % When there are more than three arguments, we are in non-interactive mode. % The 4th-7th arguments are the domain and range that the graph should be % set to on reset. % % In the flash widget, we call the function \texttt{clearPlotData}, the parameters % of which are %\begin{verbatim} % clearPlotData(graph_props:Object, oDR:Object) %\end{verbatim} % \begin{macrocode} \begin{newsegment}{AF: Supporting Form Fields} function clearGraph(graph_opts,baseName, pNum) { which_graph=graph_opts.graph; var aWhichGraph=/(c|p|a)(\d)/.exec(which_graph); if ( aWhichGraph==null ) aWhichGraph=["","c","1"]; var isGraph = (aWhichGraph[1]=="c" || aWhichGraph[1]=="a"); switch(aWhichGraph[1]) { case "p": var which_series="p"+aWhichGraph[2]; break; case "a": var which_series="a"+aWhichGraph[2]; break; default: var which_series="c"+aWhichGraph[2]; } ProcessIt = false; afResetForms = new Array (); for (var i=0; i"),nIndx); s.currentValueIndices=nIndx; f.value="<"+cAppearV+"\afunused>"; } else { var newFunc = f.value; var newFunc_tmp = newFunc.replace(/\s/g,""); if ( newFunc_tmp == "" ) { app.alert({cTitle:"AcroFLeX Graphing", cMsg:saveDelSelAlerti}); } else { // something there, let's test it if(/\afploti/.test(cAppearV) ) { if (ck4PtsRe.test(newFunc)) { // A set of points to plot s.deleteItemAt(s.currentValueIndices); s.insertItemAt(cAppearV,newFunc,nIndx); s.currentValueIndices=nIndx; } else {/* does not appear to be a point */ app.alert({cTitle:"AcroFLeX Graphing", cMsg:saveDelSelAlertii}); } } else {/* not plot, must be curve*/ s.deleteItemAt(s.currentValueIndices); s.insertItemAt(cAppearV,newFunc,nIndx); s.currentValueIndices=nIndx; } } } } } function graphBtnAction (baseName,pNum) { var s = this.getField(baseName+"ComboSelect"); var d; var d, plot_curve="c1"; if ( s != null ) { var nIndx = s.currentValueIndices; var cAppearV=s.getItemAt(s.currentValueIndices,false); if ( ( d = /\afploti\s+(\d)/.exec(cAppearV) ) != null ) { plot_curve="p"+d[1]; } else { if ( ( d = /\afcurvei\s+(\d)/.exec(cAppearV) ) != null ) { plot_curve="c"+d[1]; } else { app.alert({cTitle:"AcroFLeX Graphing", cMsg:graphBtnAlerti}); } } } Graph_xy({graph:plot_curve},baseName,pNum); } function afsplitInterval(cInterval) { var aDomTmp=stripBrackets(cInterval); aDomTmp=aDomTmp.split(","); return { LEP: aDomTmp[0], UEP: aDomTmp[1] }; } \end{newsegment} \begin{newsegment}{AF: Keystroke/Formatting Functions} function keystrokeDomRng (fname) { if (event.willCommit) { var retn = ParseInput(event.value); if ( !retn ) event.rc = false; else { try { eval ( retn ) } catch(e) { app.alert({cTitle:"AcroFLeX Graphing", cMsg:badNumberMsg}); event.rc=false; }; } } } function formatFileInput (fname) { this.getField(fname).value = ParseInput(event.value); } function formatVarIntervals (fname) { var val = Number(EvalParse(event.value)); this.getField(fname).value = val; } function formatFunctionInput (fname) { var val = ParseInput(event.value); this.getField(fname).value = val; } function keystrokeFunctionInput () { if (event.willCommit) { var str = event.value.replace(/\s/g,""); if ( str == "" ) { app.alert({cTitle:"AcroFleX Graphing", cMsg:saveDelSelAlerti}); event.rc = false; } } } function keystrokeNumPoints () { try{ var val = Number(EvalParse(event.value)); } catch(e) { app.alert({cTitle:"AcroFLeX Graphing", cMsg:badNumberMsg}); event.rc=false; return; } if ( val < 0 ) { app.alert({cTitle:"AcroFLeX Graphing", cMsg:negNumberMsg}); } else { if ( val == 0 ) { app.alert({cTitle:"AcroFLeX Graphing", cMsg:zeroNumberMsg}); val = \af@defaultNumPoints; } } event.value = Math.ceil(Math.abs(val)); } function keystrokeAmtShift() { try{ var val = Number(EvalParse(event.value)); } catch(e) { app.alert({cTitle:"AcroFLeX Graphing", cMsg:badNumberMsg}); event.rc=false; return; } if ( val < 0 ) { app.alert({cTitle:"AcroFLeX Graphing", cMsg:negShiftMsg}); } else { if ( val == 0 ) { app.alert({cTitle:"AcroFLeX Graphing", cMsg:zeroShiftMsg}); val = 1; } } event.value = Math.abs(val); } \end{newsegment} \begin{newsegment}{AF: Support for Custom Graphing Problems} % \end{macrocode} % A general purpose function for graphing that takes into consideration all the % parameters. This is used by the \cs{sgraphLink} and for any JS code that uses % custom methods. The command \cs{defineGraphJS} is used to set up the parameters % for this function.. % \begin{macrocode} function Graph_xytJS (func,xI,yI,xP,tI,graph,populate,wait,% type,form,gName,nPts) { var oDom = afsplitInterval(xI); var oRng = afsplitInterval(yI); var oPlotD = afsplitInterval(xP); var oP=new Object(), oD=new Object(), oDt=new Object(); oP.graph=graph; oP.populate=populate; oP.wait=wait; if (type!="") oP.type=type; if (form!="") oP.form=form; oD={x_min:oDom.LEP,x_max:oDom.UEP,y_min:oRng.LEP,y_max:oRng.UEP,x_l:oPlotD.LEP,x_u:oPlotD.UEP}; if ( tI=="") { Graph_xy(oP,gName,this.pageNum,func,nPts,oD); } else { var oDom_t = afsplitInterval(tI); oDt={t_min:oDom_t.LEP,t_max:oDom_t.UEP}; Graph_xyt(oP,gName,this.pageNum,func,nPts,oD,oDt); } } \end{newsegment} \end{insDLJS*} % \end{macrocode} % Lastly, we define a \texttt{willClose} code and an \texttt{execJS} % code. The first comes in on the ``developer's hook'' so the user % can still use the \texttt{willClose} environment without disturbing % this code. When the document starts to close, we deactivate all % rich media annotations, to prevent exceptions from being thrown. % \begin{macrocode} \begin{defineJS}{\af@WillClose} for (var n=0; n