1 /*
  2     Copyright 2008-2023
  3         Matthias Ehmann,
  4         Michael Gerhaeuser,
  5         Carsten Miller,
  6         Bianca Valentin,
  7         Alfred Wassermann,
  8         Peter Wilfahrt
  9 
 10     This file is part of JSXGraph.
 11 
 12     JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
 13 
 14     You can redistribute it and/or modify it under the terms of the
 15 
 16       * GNU Lesser General Public License as published by
 17         the Free Software Foundation, either version 3 of the License, or
 18         (at your option) any later version
 19       OR
 20       * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
 21 
 22     JSXGraph is distributed in the hope that it will be useful,
 23     but WITHOUT ANY WARRANTY; without even the implied warranty of
 24     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 25     GNU Lesser General Public License for more details.
 26 
 27     You should have received a copy of the GNU Lesser General Public License and
 28     the MIT License along with JSXGraph. If not, see <https://www.gnu.org/licenses/>
 29     and <https://opensource.org/licenses/MIT/>.
 30  */
 31 
 32 /*global JXG: true, define: true*/
 33 /*jslint nomen: true, plusplus: true*/
 34 
 35 /**
 36  * @fileoverview Example file for a triangle implemented as a extension to JSXGraph.
 37  */
 38 
 39 import JXG from "../jxg";
 40 import Type from "../utils/type";
 41 import Const from "../base/constants";
 42 import Polygon from "../base/polygon";
 43 
 44 var priv = {
 45     removeSlopeTriangle: function () {
 46         Polygon.prototype.remove.call(this);
 47 
 48         this.board.removeObject(this.toppoint);
 49         this.board.removeObject(this.glider);
 50 
 51         this.board.removeObject(this.baseline);
 52         this.board.removeObject(this.basepoint);
 53 
 54         this.board.removeObject(this.label);
 55 
 56         if (this._isPrivateTangent) {
 57             this.board.removeObject(this.tangent);
 58         }
 59     },
 60     Value: function () {
 61         return this.tangent.getSlope();
 62     }
 63 };
 64 
 65 /**
 66  * @class Slope triangle for a point on a line.
 67  * @pseudo
 68  * @name Slopetriangle
 69  * @augments JXG.Line
 70  * @constructor
 71  * @type JXG.Polygon
 72  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
 73  * Parameter options:
 74  * @param {JXG.Line} t A tangent based on a glider on some object, e.g. curve, circle, line or turtle.
 75  * @param {JXG.Line_JXG.Point} li, p A line and a point on that line.
 76  *  The user has to take care that the point is a member of the line.
 77  * @example
 78  * // Create a slopetriangle on a tangent
 79  * var f = board.create('plot', ['sin(x)']),
 80  *     g = board.create('glider', [1, 2, f]),
 81  *     t = board.create('tangent', [g]),
 82  *
 83  *     st = board.create('slopetriangle', [t]);
 84  *
 85  * </pre><div class="jxgbox" id="JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b" style="width: 300px; height: 300px;"></div>
 86  * <script type="text/javascript">
 87  * (function () {
 88  *   var board = JXG.JSXGraph.initBoard('JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}),
 89  *     f = board.create('plot', ['sin(x)']),
 90  *     g = board.create('glider', [1, 2, f]),
 91  *     t = board.create('tangent', [g]),
 92  *
 93  *     st = board.create('slopetriangle', [t]);
 94  * })();
 95  * </script><pre>
 96  *
 97  * @example
 98  * // Create a on a line and a point on that line
 99  * var p1 = board.create('point', [-2, 3]),
100  *     p2 = board.create('point', [2, -3]),
101  *     li = board.create('line', [p1, p2]),
102  *     p = board.create('glider', [0, 0, li]),
103  *
104  *     st = board.create('slopetriangle', [li, p]);
105  *
106  * </pre><div class="jxgbox" id="JXGb52f451c-22cf-4677-852a-0bb9d764ee95" style="width: 300px; height: 300px;"></div>
107  * <script type="text/javascript">
108  * (function () {
109  *   var board = JXG.JSXGraph.initBoard('JXGb52f451c-22cf-4677-852a-0bb9d764ee95', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}),
110  *     p1 = board.create('point', [-2, 3]),
111  *     p2 = board.create('point', [2, -3]),
112  *     li = board.create('line', [p1, p2]),
113  *     p = board.create('glider', [0, 0, li]),
114  *
115  *     st = board.create('slopetriangle', [li, p]);
116  * })();
117  * </script><pre>
118  */
119 JXG.createSlopeTriangle = function (board, parents, attributes) {
120     var el,
121         tangent,
122         tglide,
123         glider,
124         toppoint,
125         baseline,
126         basepoint,
127         label,
128         attr,
129         isPrivateTangent = false;
130 
131     if (parents.length === 1 && parents[0].type === Const.OBJECT_TYPE_TANGENT) {
132         tangent = parents[0];
133         tglide = tangent.glider;
134     } else if (parents.length === 1 && parents[0].type === Const.OBJECT_TYPE_GLIDER) {
135         tglide = parents[0];
136         attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "tangent");
137         tangent = board.create("tangent", [tglide], attr);
138         isPrivateTangent = true;
139     } else if (
140         parents.length === 2 &&
141         parents[0].elementClass === Const.OBJECT_CLASS_LINE &&
142         Type.isPoint(parents[1])
143     ) {
144         tangent = parents[0];
145         tglide = parents[1];
146     } else {
147         throw new Error(
148             "JSXGraph: Can't create slope triangle with parent types '" +
149                 typeof parents[0] +
150                 "'."
151         );
152     }
153 
154     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "basepoint");
155     basepoint = board.create(
156         "point",
157         [
158             function () {
159                 return [tglide.X() + 1, tglide.Y()];
160             }
161         ],
162         attr
163     );
164 
165     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "baseline");
166     baseline = board.create("line", [tglide, basepoint], attr);
167 
168     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "glider");
169     glider = board.create("glider", [tglide.X() + 1, tglide.Y(), baseline], attr);
170 
171     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "toppoint");
172     toppoint = board.create(
173         "point",
174         [
175             function () {
176                 return [
177                     glider.X(),
178                     glider.Y() + (glider.X() - tglide.X()) * tangent.getSlope()
179                 ];
180             }
181         ],
182         attr
183     );
184 
185     attr = Type.copyAttributes(attributes, board.options, "slopetriangle");
186     attr.borders = Type.copyAttributes(attr.borders, board.options, "slopetriangle", "borders");
187     el = board.create("polygon", [tglide, glider, toppoint], attr);
188 
189     /**
190      * Returns the value of the slope triangle, that is the slope of the tangent.
191      * @name Value
192      * @memberOf Slopetriangle.prototype
193      * @function
194      * @returns {Number} slope of the tangent.
195      */
196     el.Value = priv.Value;
197     el.tangent = tangent;
198     el._isPrivateTangent = isPrivateTangent;
199 
200     //el.borders[0].setArrow(false, {type: 2, size: 10});
201     //el.borders[1].setArrow(false, {type: 2, size: 10});
202     el.borders[2].setArrow(false, false);
203 
204     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "label");
205     label = board.create(
206         "text",
207         [
208             function () {
209                 return glider.X() + 0.1;
210             },
211             function () {
212                 return (glider.Y() + toppoint.Y()) * 0.5;
213             },
214             function () {
215                 return "";
216             }
217         ],
218         attr
219     );
220 
221     label._setText(function () {
222         return Type.toFixed(el.Value(), Type.evaluate(label.visProp.digits));
223     });
224     label.fullUpdate();
225 
226     el.glider = glider;
227     el.basepoint = basepoint;
228     el.baseline = baseline;
229     el.toppoint = toppoint;
230     el.label = label;
231 
232     el.subs = {
233         glider: glider,
234         basePoint: basepoint,
235         baseLine: baseline,
236         topPoint: toppoint,
237         label: label
238     };
239     el.inherits.push(glider, basepoint, baseline, toppoint, label);
240 
241     el.methodMap = JXG.deepCopy(el.methodMap, {
242         tangent: "tangent",
243         glider: "glider",
244         basepoint: "basepoint",
245         baseline: "baseline",
246         toppoint: "toppoint",
247         label: "label",
248         Value: "Value",
249         V: "Value"
250     });
251 
252     el.remove = priv.removeSlopeTriangle;
253 
254     return el;
255 };
256 
257 JXG.registerElement("slopetriangle", JXG.createSlopeTriangle);
258 
259 // export default {
260 //     createSlopeTriangle: JXG.createSlopeTriangle
261 // };
262