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, tangent, tglide, glider,
121         toppoint, baseline, basepoint,
122         label, attr,
123         isPrivateTangent = false;
124 
125     if (parents.length === 1 && parents[0].type === Const.OBJECT_TYPE_TANGENT) {
126         tangent = parents[0];
127         tglide = tangent.glider;
128     } else if (parents.length === 1 && parents[0].type === Const.OBJECT_TYPE_GLIDER) {
129         tglide = parents[0];
130         attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "tangent");
131         tangent = board.create("tangent", [tglide], attr);
132         isPrivateTangent = true;
133     } else if (
134         parents.length === 2 &&
135         parents[0].elementClass === Const.OBJECT_CLASS_LINE &&
136         Type.isPoint(parents[1])
137     ) {
138         tangent = parents[0];
139         tglide = parents[1];
140     } else {
141         throw new Error(
142             "JSXGraph: Can't create slope triangle with parent types '" +
143                 typeof parents[0] +
144                 "'."
145         );
146     }
147 
148     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "basepoint");
149     basepoint = board.create(
150         "point",
151         [
152             function () {
153                 return [tglide.X() + 1, tglide.Y()];
154             }
155         ],
156         attr
157     );
158 
159     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "baseline");
160     baseline = board.create("line", [tglide, basepoint], attr);
161 
162     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "glider");
163     glider = board.create("glider", [tglide.X() + 1, tglide.Y(), baseline], attr);
164 
165     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "toppoint");
166     toppoint = board.create(
167         "point",
168         [
169             function () {
170                 return [
171                     glider.X(),
172                     glider.Y() + (glider.X() - tglide.X()) * tangent.getSlope()
173                 ];
174             }
175         ],
176         attr
177     );
178 
179     attr = Type.copyAttributes(attributes, board.options, "slopetriangle");
180     attr.borders = Type.copyAttributes(attr.borders, board.options, "slopetriangle", "borders");
181     el = board.create("polygon", [tglide, glider, toppoint], attr);
182 
183     /**
184      * Returns the value of the slope triangle, that is the slope of the tangent.
185      * @name Value
186      * @memberOf Slopetriangle.prototype
187      * @function
188      * @returns {Number} slope of the tangent.
189      */
190     el.Value = priv.Value;
191     el.tangent = tangent;
192     el._isPrivateTangent = isPrivateTangent;
193 
194     //el.borders[0].setArrow(false, {type: 2, size: 10});
195     //el.borders[1].setArrow(false, {type: 2, size: 10});
196     el.borders[2].setArrow(false, false);
197 
198     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "label");
199     label = board.create(
200         "text",
201         [
202             function () {
203                 return glider.X() + 0.1;
204             },
205             function () {
206                 return (glider.Y() + toppoint.Y()) * 0.5;
207             },
208             function () {
209                 return "";
210             }
211         ],
212         attr
213     );
214 
215     label._setText(function () {
216         var digits = Type.evaluate(label.visProp.digits);
217 
218         if (label.useLocale()) {
219             return label.formatNumberLocale(el.Value(), digits);
220         }
221         return Type.toFixed(el.Value(), digits);
222     });
223     label.fullUpdate();
224 
225     el.glider = glider;
226     el.basepoint = basepoint;
227     el.baseline = baseline;
228     el.toppoint = toppoint;
229     el.label = label;
230 
231     el.subs = {
232         glider: glider,
233         basePoint: basepoint,
234         baseLine: baseline,
235         topPoint: toppoint,
236         label: label
237     };
238     el.inherits.push(glider, basepoint, baseline, toppoint, label);
239 
240     el.methodMap = JXG.deepCopy(el.methodMap, {
241         tangent: "tangent",
242         glider: "glider",
243         basepoint: "basepoint",
244         baseline: "baseline",
245         toppoint: "toppoint",
246         label: "label",
247         Value: "Value",
248         V: "Value"
249     });
250 
251     el.remove = priv.removeSlopeTriangle;
252 
253     return el;
254 };
255 
256 JXG.registerElement("slopetriangle", JXG.createSlopeTriangle);
257 
258 // export default {
259 //     createSlopeTriangle: JXG.createSlopeTriangle
260 // };
261