      1 /*
      2     Copyright 2008-2025
      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.js";
     40 import Type from "../utils/type.js";
     41 import Const from "../base/constants.js";
     42 import Polygon from "../base/polygon.js";
     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     Direction: function() {
     64         return this.tangent.Direction();
     65     }
     66 };
     67
     68 /**
     69  * @class Slope triangle to visualize the slope of a tangent to a curve, circle or line.
     70  * @pseudo
     71  * @name Slopetriangle
     72  * @augments JXG.Line
     73  * @constructor
     74  * @type JXG.Polygon
     75  * @throws {Error} If the element cannot be constructed with the given parent objects an exception is thrown.
     76  * Parameter options:
     77  * @param {JXG.Line} t A tangent based on a glider on some object, e.g. curve, circle, line or turtle.
     78  * @param {JXG.Line_JXG.Point} li, p A line and a point on that line.
     79  *  The user has to take care that the point is a member of the line.
     80  * @example
     81  * // Create a slopetriangle on a tangent
     82  * var f = board.create('plot', ['sin(x)']),
     83  *     g = board.create('glider', [1, 2, f]),
     84  *     t = board.create('tangent', [g]),
     85  *
     86  *     st = board.create('slopetriangle', [t]);
     87  *
     88  * </pre><div class="jxgbox" id="JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b" style="width: 300px; height: 300px;"></div>
     89  * <script type="text/javascript">
     90  * (function () {
     91  *   var board = JXG.JSXGraph.initBoard('JXG951ccb6a-52bc-4dc2-80e9-43db064f0f1b', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}),
     92  *     f = board.create('plot', ['sin(x)']),
     93  *     g = board.create('glider', [1, 2, f]),
     94  *     t = board.create('tangent', [g]),
     95  *
     96  *     st = board.create('slopetriangle', [t]);
     97  * })();
     98  * </script><pre>
     99  *
    100  * @example
    101  * // Create a on a line and a point on that line
    102  * var p1 = board.create('point', [-2, 3]),
    103  *     p2 = board.create('point', [2, -3]),
    104  *     li = board.create('line', [p1, p2]),
    105  *     p = board.create('glider', [0, 0, li]),
    106  *
    107  *     st = board.create('slopetriangle', [li, p]);
    108  *
    109  * </pre><div class="jxgbox" id="JXGb52f451c-22cf-4677-852a-0bb9d764ee95" style="width: 300px; height: 300px;"></div>
    110  * <script type="text/javascript">
    111  * (function () {
    112  *   var board = JXG.JSXGraph.initBoard('JXGb52f451c-22cf-4677-852a-0bb9d764ee95', {boundingbox: [-5, 5, 5, -5], axis: true, showcopyright: false, shownavigation: false}),
    113  *     p1 = board.create('point', [-2, 3]),
    114  *     p2 = board.create('point', [2, -3]),
    115  *     li = board.create('line', [p1, p2]),
    116  *     p = board.create('glider', [0, 0, li]),
    117  *
    118  *     st = board.create('slopetriangle', [li, p]);
    119  * })();
    120  * </script><pre>
    121  */
    122 JXG.createSlopeTriangle = function (board, parents, attributes) {
    123     var el, tangent, tglide, glider,
    124         toppoint, baseline, basepoint,
    125         label, attr,
    126         isPrivateTangent = false;
    127
    128     if (parents.length === 1 && parents[0].type === Const.OBJECT_TYPE_TANGENT) {
    129         tangent = parents[0];
    130         tglide = tangent.glider;
    131     } else if (parents.length === 1 && parents[0].type === Const.OBJECT_TYPE_GLIDER) {
    132         tglide = parents[0];
    133         attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "tangent");
    134         tangent = board.create("tangent", [tglide], attr);
    135         isPrivateTangent = true;
    136     } else if (
    137         parents.length === 2 &&
    138         parents[0].elementClass === Const.OBJECT_CLASS_LINE &&
    139         Type.isPoint(parents[1])
    140     ) {
    141         tangent = parents[0];
    142         tglide = parents[1];
    143     } else {
    144         throw new Error(
    145             "JSXGraph: Can't create slope triangle with parent types '" +
    146                 typeof parents[0] +
    147                 "'."
    148         );
    149     }
    150
    151     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "basepoint");
    152     basepoint = board.create(
    153         "point",
    154         [
    155             function () {
    156                 return [tglide.X() + 1, tglide.Y()];
    157             }
    158         ],
    159         attr
    160     );
    161
    162     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "baseline");
    163     baseline = board.create("line", [tglide, basepoint], attr);
    164
    165     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "glider");
    166     glider = board.create("glider", [tglide.X() + 1, tglide.Y(), baseline], attr);
    167
    168     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "toppoint");
    169     toppoint = board.create(
    170         "point",
    171         [
    172             function () {
    173                 return [
    174                     glider.X(),
    175                     glider.Y() + (glider.X() - tglide.X()) * tangent.getSlope()
    176                 ];
    177             }
    178         ],
    179         attr
    180     );
    181
    182     attr = Type.copyAttributes(attributes, board.options, "slopetriangle");
    183     // attr.borders = Type.copyAttributes(attr.borders, board.options, "slopetriangle", "borders");
    184     el = board.create("polygon", [tglide, glider, toppoint], attr);
    185
    186     /**
    187      * Returns the value of the slope triangle, that is the slope of the tangent.
    188      * @name Value
    189      * @memberOf Slopetriangle.prototype
    190      * @function
    191      * @returns {Number} slope of the tangent.
    192      */
    193     el.Value = priv.Value;
    194
    195     /**
    196      * Returns the direction of the slope triangle, that is the direction of the tangent.
    197      * @name Direction
    198      * @memberOf Slopetriangle.prototype
    199      * @see Line#Direction
    200      * @function
    201      * @returns {Number} slope of the tangent.
    202      */
    203     el.Direction = priv.Direction;
    204     el.tangent = tangent;
    205     el._isPrivateTangent = isPrivateTangent;
    206
    207     //el.borders[0].setArrow(false, {type: 2, size: 10});
    208     //el.borders[1].setArrow(false, {type: 2, size: 10});
    209     el.borders[2].setArrow(false, false);
    210
    211     attr = Type.copyAttributes(attributes, board.options, "slopetriangle", "label");
    212     //label = board.create("text", [
    213     //         function () {
    214     //             return glider.X() + 0.1;
    215     //         },
    216     //         function () {
    217     //             return (glider.Y() + toppoint.Y()) * 0.5;
    218     //         },
    219     //         function () {
    220     //             return "";
    221     //         }
    222     //     ],
    223     //     attr
    224     // );
    225
    226     attr = Type.copyAttributes(attr, board.options, "label");
    227     // Add label to vertical polygon edge
    228     attr.isLabel = true;
    229     attr.anchor = el.borders[1];
    230     attr.priv = el.borders[1].visProp.priv;
    231     attr.id = el.borders[1].id + "Label";
    232
    233     label = board.create("text", [0, 0, function () { return ""; }], attr);
    234     label.needsUpdate = true;
    235     label.dump = false;
    236     el.borders[1].label = label;
    237     el.borders[1].hasLabel = true;
    238     el.borders[1].visProp.withlabel = true;
    239
    240     label._setText(function () {
    241         var digits = label.evalVisProp('digits');
    242
    243         if (label.useLocale()) {
    244             return label.formatNumberLocale(el.Value(), digits);
    245         }
    246         return Type.toFixed(el.Value(), digits);
    247     });
    248     label.fullUpdate();
    249
    250     el.glider = glider;
    251     el.basepoint = basepoint;
    252     el.baseline = baseline;
    253     el.toppoint = toppoint;
    254     el.label = label;
    255
    256     el.subs = {
    257         glider: glider,
    258         basePoint: basepoint,
    259         baseLine: baseline,
    260         topPoint: toppoint,
    261         label: label
    262     };
    263     el.inherits.push(glider, basepoint, baseline, toppoint, label);
    264
    265     el.methodMap = JXG.deepCopy(el.methodMap, {
    266         tangent: "tangent",
    267         glider: "glider",
    268         basepoint: "basepoint",
    269         baseline: "baseline",
    270         toppoint: "toppoint",
    271         label: "label",
    272         Value: "Value",
    273         V: "Value",
    274         Direction: "Direction"
    275     });
    276
    277     el.remove = priv.removeSlopeTriangle;
    278
    279     return el;
    280 };
    281
    282 JXG.registerElement("slopetriangle", JXG.createSlopeTriangle);
    283
    284 // export default {
    285 //     createSlopeTriangle: JXG.createSlopeTriangle
    286 // };
    287