PHP & More

A technical blog about programming in PHP and about technology in general: programming, workarounds and troubleshooting

Drawing Simple 3D Shapes in HTML5 — May 5, 2019

Drawing Simple 3D Shapes in HTML5

HTML5 includes some features that allows developers to draw 3D shapes by drawing bi dimensional shapes and applying 3d transform, such as rotateX, rotateY and rotateZ. For convenience, you can shift the origin of axes using the style property If you don’t want the 3D image too flat (for example, all the faces of a cube having the same size) use perspective and perspective-origin style properties.

You can use the matrix3d style properties instead of the named transforms if, for example, you don’t want to compute angles.

The Style Properties

A style property can be defined by adding the attribute style to an HTML element, defining a CSS class or accessing a DOM node.

In this section I will explain the properties using a little Javascript program that draws a regular tetrahedron.

enter image description here

Drawing a tetrahedron is done by drawing 4 isosceles triangles and rotating each of them once or twice.

“perspective” and “perspective-origin”

The distance and angle from which the shape is viewed.

“perspective” holds the distance

“perspective-origin” – a position value.

For example:

        var main_div = d3.select('body')
                         .append('div')
                         .style('position','absolute')
                         .style('top','50px')
                         .style('left','50px')
                         .style('perspective','50px')
                         .style('perspective-origin','bottom left');

Transform Values: “rotateX”, “rotateY”, “rotate” and “transform-origin”

Rotate an axis. Keep the value of the rotated axis coordinate unchanged, and change the rest. The axis is rotated around the position defined by “transform-origin”

The following code adds the data for creating 4 triangles, and rotates 1 triangle 120 degrees to the right and 1 triangle 120 degrees to the left. Rotation is done around the bottom face’s centroid.

        main_div.selectAll('div').
                 data([{color: 'red', transform: null,upperVertexInd: true},
                       {color: 'black', transform: 'rotateX(90deg)', 'origin':'
100px 100px 0'},
                       {color: 'blue', transform: 'rotateY(120deg)',origin: cent
roidString,upperVertexInd: true},
                       {color: 'green', transform: 'rotateY(-120deg)',origin: ce
ntroidString,upperVertexInd: true}])
                .enter()
                .append('div')
                .style('position','absolute')
                .style('top',0)
                .style('left',0)
                .style('transform',d=>d.transform)
                .style('transform-origin',d=>d.origin)
                .style('transform-style','preserve-3d')

(To be more precise, it rotates the DIV elements)

enter image description here

Tarnsform Values: “matrix3d”

This matrix is used if you want to use a transformation out of the comfort zone. For example, a rotation transform with cosines and sines of the angle. The argument list contains 16 values, which are the cells of a square matrix of order 4 (4 rows and 4 columns).

This matrix will be applied on (x,y,z,w) vector to get the target vector. When rotating a 2d vector )point), our original z-coordinate will be 0, and w will be 1.

To specify the matrix:

\left( \begin{matrix} a_0 \ a_4 \ a_8 \ a_{12} \\ a_1 \ a_5 \ a_9 \ a_{13} \\ a_2 \ a_6 \ a_{10} a_{14} \\ a_3 \ a_7 \ a_{11} \ a_{15}\end{matrix} \right)

use

matrix3d(a_0,a_1,a_2,...,a_{15})

In my example, I will rotate 3 triangles, so their top vertex will go to a line perpendicular to the tetrahedron base, and passing through the base’s median.

The median of a triangle is the point where median cross its other, dividing each median at the ratio 1:2.

So, if each side of a triangle is of length 1. The height is \sqrt(3)\over2

Since, the height is the length of the median, the distance from a side to the centroid is the height divided by 3, and the requested sine is latex13latex 1 \over 3

The cosine is \sqrt {1 - {1 \over 3}^2} = {\sqrt 8 \over 3}

so, we will compute the matrix as follows:

        var rotateXCos = Math.sqrt(8) / 3;
        var rotateXSin = 1 / 3; 
        var rotateXMat3d = [1,0,0,0,
                            0,rotateXCos,rotateXSin,0,
                            0,-rotateXSin,rotateXCos,0,
                            0,0,0,1];
        var matrixTransformString = 'matrix3d(' + rotateXMat3d + ')';

enter image description here

Now, the code to draw the tetrahedron with *d3.js( is:

    
        var side=100;
        var len=100;
        var height=side * Math.sqrt(3)/2;
        var centroidZValue = -height / 3; // The point where medians meet.
        var rotateXCos = Math.sqrt(8) / 3;
        var rotateXSin = 1 / 3;
        var rotateXMat3d = [1,0,0,0,
                            0,rotateXCos,rotateXSin,0,
                            0,-rotateXSin,rotateXCos,0,
                            0,0,0,1];
        var matrixTransformString = 'matrix3d(' + rotateXMat3d + ')';
        var centroidString = '150px 0 ' + centroidZValue + 'px';
        var main_div = d3.select('body')
                         .append('div')
                         .style('position','absolute')
                         .style('top','50px')
                         .style('left','50px')
                         .style('perspective','50px')
                         .style('perspective-origin','bottom left');
        main_div.selectAll('div').
                 data([{color: 'red', transform: null,upperVertexInd: true},
                       {color: 'black', transform: 'rotateX(90deg)', 'origin':'
100px 100px 0'},
                       {color: 'blue', transform: 'rotateY(120deg)',origin: cent
roidString,upperVertexInd: true},
                       {color: 'green', transform: 'rotateY(-120deg)',origin: ce
ntroidString,upperVertexInd: true}])
                .enter()
                .append('div')
                .style('position','absolute')
                .style('top',0)
                .style('left',0)
                .style('transform',d=>d.transform)
                .style('transform-origin',d=>d.origin)
                .style('transform-style','preserve-3d')
                .append('div')
                .style('transform-style','preserve-3d')
                .style('position','absolute')
                .style('top',0)
                .style('left',0)
                .style('transform',function(d){
                          return d.upperVertexInd?matrixTransformString:false;
                       })
                .style('transform-origin',function(d){
                          return d.upperVertexInd?'0 100px 0':false;
                       })
                .append('svg')
                .append('polygon')
                .attr('points',[100,100,150,100-height,200,100])
                .style('fill','none')
                .style('stroke',d=>d.color);
    
    

Advertisements
Ruby TK – The Canvas — September 6, 2011

Ruby TK – The Canvas

If you want to use Ruby TK for painting – and not just displaying pictures from the disk – you can use the widget TkCanvas. To this widget you can add lines, polygons, elipses and circles etc.

Now, to add a shape to a canvas in Perl you would use the syntax:

$canvas->createLine(x1, y1..., xn, yn, ?option, value, option, value, ...?)

In Ruby:
line=TkcLine.new(canvas,x1, y1..., xn, yn, ?option=> value, option=>value, ...?)

x1,y1,…,xn,yn are the coordinates of the shape. They can be changed in response to events.
It also has options such as ‘fill’, the color with which to fill the shape.
The options can be changed in response to events.

What Are Coordinates

Every shape has its coordinates, points that define the shape. You can get or configure the shape’s coordinates using the function ‘coords’.

TkcLine – points along the shape consisting of one or more lines. Each point is where the previous line ends and the next starts.

TkcPolygom – Like TkcLine, but with a line connecting the last point to the first.

TkcRectangle – x1,y1,x2,y2 are the coordinates of two opposite vertexes of a horizontal or vertical rectangle.

TkcOval – x1,y1,x2,y2 of the rectangle enclosing the ellipse or circle.

TkcArc – like TkcOval, but in addition has the options ‘start’ and ‘extent’. ‘start’ is the number of degrees from the 3 o’clock position of the oval. ‘extent’ is the size of the angular range occupied by the arc counterclockwise from the arc’s beginning point.

Learn more at http://perlhelp.web.cern.ch/PerlHelp/ (search for tk/canvas on the right side of the window) or feel free to ask your questions in a comment.