Release of 0.99.6

Major new release

The long awaited version 0.99.6 of JSXGraph has just been released! This is a There are quite a few new features which are - hopefully -

The most noteable new features are:

  • JSXGraph is (again) working in AMD, CommonJS, and much more
  • Unified control of zooming and panning
  • All relevant attributes may have functions as values
  • CSS styles for (HTML) texts and images
  • Flexible arrow heads
  • Symbolic differentiation

Further, one critical bug has been fixed: JSXgraph has stopped working in IE / Edge on touch devices, because Microsoft had removed the -ms-prefix from the CSS attribute -ms-touch-action.

We thank all contributors which supplied patches, bug reports and suggestions for improvements.

For a full list of all changes see the CHANGELOG.

Enjoy, Alfred

Examples for the new features

New board attributes

When creating a new board, the attributes showZoom and showNavigation control the visibility of the zoom and navigation icons in the lower right corner. Further with the zoom and pan objects zooming and panning behaviour can be better controlled:

  • max, min: determine the maximum and minimum zoom level
  • If needShift, needCtrl are true, these keys have to pressed during zoom or pan.
  • For touch devices there is the attribute needsTwoFingers.
  • If pinchHorizontal or pinchVertical are true, zooming is restricted to one direction if the pinch gesture is horizontal or vertical. The sensitivity of this behavior can be controlled with pinchSensitivity (in degrees).
  • Another new feature is the attribute defaultAxes which enables to style the default axes during creation.
   var board = JXG.JSXGraph.initBoard("box", {
        boundingbox: [-5, 5, 5, -5],
        axis: true,
        defaultAxes: {
            y: {
                strokeColor: 'blue',
                ticks: {
                    visible: 'inherit',
                }
            },
        },
        zoom: {
            pinchHorizontal: false,
            pinchVertical: false,
            pinchSensitivity: 7,
            min: 0.5,
            max: 2,
            wheel: true,
            needShift: true
        },
        pan: {
            needTwoFingers: true,
            needShift: false
        },

        showZoom: false,
        showNavigation: true,
    });

Ticks labels for sliders

Sliders can have (correct) ticks labels now, and the display of the value composed from three attributes:

    var board = JXG.JSXGraph.initBoard('box', {
        boundingbox: [-5, 5, 5, -5], 
    });
    var sl = board.create('slider', [[-4,1], [2,1], [-10, 1, 10]], {
        name:'a', 
        suffixLabel: 'A = ',
        unitLabel: 'm',
        postLabel: ' !!!',
        withLabel: true, 
        ticks: { 
            drawLabels: true, 
        }});
    })();

Positioning of hatches and ticks

With the anchor attribute, relative positions other than the middle position are possible.

    var board = JXG.JSXGraph.initBoard('box', {
        boundingbox: [-5, 5, 5, -5], 
    });
    var p = board.create('point', [-4, 0]);
    var q = board.create('point', [4, 0]);
    var li = board.create('line', [p, q]);
    var h = board.create('hatch', [li, 2], {anchor: 0.2});
    var h = board.create('hatch', [li, 3], {anchor: 0.8, strokeColor: 'orange'});

New attribute: “cssStyle”

The new attribute cssStyle adds CSS style attributes to the default style of HTML texts. There is also the new attribute cssDefaultStyle. The latter sets the font-family to a sans-serif font. Further, there are variants for highlighing, namely highlightCssDefaultStyle and highlightCssStyle. Since, there is also the attribute cssClass, there are many possiblities to style text and image elements. The priority of these attributes are (from high to low):

  • Separate attribute, e.g. fontSize
  • cssStyle
  • cssDefaulStyle
  • cssClass

The cssStyle attributes allow a flexible styling of texts and images in environments where the use of a separate CSS file is not possible.

    var txt = board.create('text', [0, 0, 'hello'], {
        cssStyle: 'padding: 5px; border: 1px solid orange; border-radius: 5px'
    });

New attribute: “dragToTopOfLayer”

    var im1 = board.create('image', ['perched_birds.jpg', [0, 0], [2, 2]], {
        dragToTopOfLayer: true
    });
    var im2 = board.create('image', ['uccellino.jpg', [-1, -1], [2, 2]], {
        dragToTopOfLayer: true
    });

Visvalingam-Whyatt algorithm for curve simplification

See Visvalingam, M; Whyatt, JD (1992). Line Generalisation by Repeated Elimination of the Smallest Area (Technical report). Discussion Paper. Cartographic Information Systems Research Group (CISRG), The University of Hull. 10.

    var i, p = [];
    for (i = 0; i < 4; ++i) {
        p.push(
            board.create('point', [Math.random() * 12 - 6, Math.random() * 12 - 6])
        );
    }
    var sl = board.create('slider', [[-8,9], [6,9], [-0.5, 0.5, 1.5]], {
        name:'a', withLabel: true
    });

    
    var splineArr = JXG.Math.Numerics.CardinalSpline(p, function(){ return sl.Value(); });
    var cu2 = board.create('curve', splineArr, {strokeColor: 'orange', strokeWidth:4});


    var c = board.create('curve', [[0],[0]], {strokeWidth: 2, strokeColor: 'black'});
    c.updateDataArray = function() {
        var i, len, points;

        // Reduce number of intermediate points with Visvalingam-Whyatt to 6
        points = JXG.Math.Numerics.Visvalingam(cu2.points, 6);

        // Plot the remaining points
        len = points.length;
        this.dataX = [];
        this.dataY = [];
        for (i = 0; i < len; i++) {
            this.dataX.push(points[i].usrCoords[1]);
            this.dataY.push(points[i].usrCoords[2]);
        }
    };
    board.update();

Centripetal Cardinal and Catmull-Rom splines

See e.g. https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline

var i, p = [];
for (i = 0; i < 5; ++i) {
    p.push(board.create('point', [Math.random() * 8 - 4, Math.random() * 8 - 4]));
}

var sl = board.create('slider', [[-8,9], [6,9], [-0.5, 1.3, 1.5]], {
    name:'a', 
    withLabel: true, 
    ticks: { 
        drawLabels: true, 
        minTicksDistance: 30
    }
});

var cu2 = board.create('curve', 
    JXG.Math.Numerics.CardinalSpline(p, function(){ return sl.Value(); }), 
    { strokeColor: 'green', strokeWidth:2}
);
var cu3 = board.create('curve', 
    JXG.Math.Numerics.CardinalSpline(p, function(){ return sl.Value(); }, 'centripetal'), 
    { strokeWidth:2}
);

Line attribute “linecap”

This is useful for very thick lines. Possible values are butt (default), round and square.

    var pol = board.create('polygon',[[0,0],[2,0],[2,2],[0,2]], {
        hasInnerPoints: true,
        vertices: {
          visible: false
        },
        borders: {
          strokeWidth: 30,
          lineCap: 'round'
        },
        fillColor: 'yellow'
    });

Allow functions as values for attribute visible and introduce new value ‘inherit’</h2>

Here is an example: if the x-coordinate of A is positive, the point B is hidden.

    var A = board.create('point', [-1, 2], {size: 10});
    var B = board.create('point', [1, -2], {size: 10,
        visible: function() {
            return A.X() < 0;
        }
    });

New polygon method “Perimeter()”

var pol = board.create('polygon',
        [[0, 0], [4,0], [4,4], [0,4]],
        {
            vertices: {snapToGrid: true, snapSizeX: 0.5, snapSizeY: 0.5}
        }
    );
var txt = board.create('text', [1, 1, function() {
    return "perimeter = " + pol.Perimeter().toFixed(2);
    }]);

CSS transitions when highlighting

    var pol = board.create('polygon',
            [[0, 0], [4,0], [2,4]],
            {
                hasInnerPoints: true,
                transitionDuration: 1000,
                fillColor: 'yellow',
                highlightFillColor: 'red',
                borders: {
                    transitionDuration: 1000,
                    strokeWidth: 5
                }
            }
        );

Arrows

In this release we have three types of arrows. All types may be scaled by the attribute size which defaults to 3.

    var s1 = board.create('segment', [[-2, 4], [2, 4]], {
        lastArrow: true
    });
    var s2 = board.create('segment', [[-2, 2], [2, 2]], {
        lastArrow: {
            type: 1,
            size: 6
        }
    });
    var s3 = board.create('segment', [[-2, 1], [2, 1]], {
        lastArrow: {
            type: 2,
            size: 6
        },
        firstArrow: {
            type: 3,
            size: 3
        }
    });
    var s4 = board.create('segment', [[-2, -1], [2, -1]], {
        lastArrow: {
            type: 2,
            size: 8
        },
        firstArrow: {
            type: 3,
            size: 8
        }
    });

Symbolic differentiation

This is a very preliminary new feature in JessieCode. Symbolic differentiation is fully implemented (which is easy). But it is not very usefull without a good term simplification algorithm. We do have term simplification in JessieCode, but this is not very sophisticated and can be much improved.

<div id="box15" class="jxgbox" style="width:500px; height:500px;"></div>
<textarea id="input_code" cols="50" rows="5" style="float:none;">
f = map (x) -> x^2;
h = D(f, x);
</textarea>
<div style="">
    <p><button id="reset">Reset board</button> 
    <button id="parse">Simplify code</button></p>
</div>
<textarea id="output_code" cols="50" rows="5" style="float:left;">
</textarea>

<script type="text/javascript">
(function () {
    var board,
        init = function () {
            board = JXG.JSXGraph.initBoard('box15', {
                boundingbox: [-5, 5, 5, -5], 
                axis:true
            });
            board.jc = new JXG.JessieCode();
            board.jc.use(board);

            var f = board.create('functiongraph', ['sin(x)*x^2']);
            var df = board.create('functiongraph', ['D(sin(x)*x^2, x)'], {strokeColor: 'red'});
        },
        parse = function () {
            return board.jc.manipulate(document.getElementById('input_code').value);
        };
    init();
    window.board = board;
    parse();
    JXG.addEvent(document.getElementById('reset'), 'click', function () {
        JXG.JSXGraph.freeBoard(board);
        init();
        document.getElementById('output_code').value = '';
    }, this);
    JXG.addEvent(document.getElementById('parse'), 'click', function () {
        document.getElementById('output_code').value = parse();
    }, this);
})();
</script>