Showing posts with label ReactJS. Show all posts
Showing posts with label ReactJS. Show all posts

Monday, October 23, 2023

React JS Material UI icons for Mastodon and Blogger

Other than the Linkedin icon, I couldn't find the Mastodon and Blogger React Material UI (MUI) icons in the React @mui/icons-material library so I had to make my own with Inkscape and a good old text editor. The results are shown in the screenshot below.

 Here is the MastodonIcon.js code for the Mastodon icon:

import * as React from 'react';
import SvgIcon from '@mui/material/SvgIcon';

export default function MastodonIcon() {
  return (
    <SvgIcon>
      <svg className="mastodon" width="16" height="16" fill="currentColor" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
        <path d="m10.751 11.617c1.7387-0.20699 3.2514-1.2721 3.4412-2.2449 0.30012-1.5334 0.27598-3.7421 0.27598-3.7421 0-2.9926-1.9715-3.8706-1.9715-3.8706-0.99355-0.45451-2.7002-0.6451-4.4734-0.65976h-0.043122c-1.774 0.014661-3.48 0.20526-4.4734 0.65976 0 0-1.9706 0.87709-1.9706 3.8706l-0.00173 0.57093c-0.00345 0.55195-0.00603 1.1643 0.0095 1.8033 0.071582 2.9271 0.53988 5.8128 3.26 6.5286 1.2539 0.33031 2.3311 0.39931 3.1988 0.35188 1.5722-0.08625 2.4554-0.55799 2.4554-0.55799l-0.05176-1.1358s-1.1237 0.3536-2.3864 0.31047c-1.2505-0.04312-2.57-0.13454-2.7728-1.6628a3.1169 3.1169 0 0 1-0.028456-0.42777s1.2281 0.2984 2.784 0.36912c0.95126 0.04312 1.843-0.0552 2.7495-0.163zm1.3911-2.1302h-1.4429v-3.5188c0-0.74083-0.31393-1.1168-0.94091-1.1168-0.69339 0-1.041 0.44587-1.041 1.329v1.9258h-1.4351v-1.9266c0-0.88313-0.34756-1.329-1.041-1.329-0.62699 0-0.94091 0.37602-0.94091 1.1177v3.5179h-1.4429v-3.6239c0-0.74083 0.18973-1.329 0.56921-1.7646 0.39327-0.43553 0.90728-0.6589 1.5463-0.6589 0.73824 0 1.2971 0.28288 1.6671 0.84777l0.35964 0.5994 0.35964-0.5994c0.36998-0.5649 0.92884-0.84777 1.668-0.84777 0.6382 0 1.1522 0.22337 1.5446 0.6589 0.38119 0.43553 0.57007 1.0237 0.57007 1.7646z" strokeWidth=".86244" />
      </svg>
    </SvgIcon>
  );
}

And here is the BloggerIcon.js code for the Blogger icon:

import * as React from 'react';
import SvgIcon from '@mui/material/SvgIcon';

export default function SvgIconChildren() {
  return (
    <SvgIcon>
      <svg width="50.664mm" height="50.575mm" version="1.1" viewBox="0 0 179.52 179.2" xmlns="http://www.w3.org/2001/svg">
        <defs>
          <clipPath id="clipPath8">
            <path d="m111.47 137.84c6.8936-0.96075 12.296-3.7837 17.364-9.0736 3.6662-3.8268 5.9611-7.9689 7.4609-13.466 0.62305-2.2837 0.67529-3.3956 0.78946-16.804 0.0863-10.12 0.0143-14.86-0.24367-16.056-0.37384-1.7344-1.4336-3.345-2.6427-4.0165-0.37209-0.20664-2.7561-0.47002-5.2978-0.58526-4.2591-0.19314-4.7356-0.278-6.08-1.0829-2.1324-1.2768-2.7197-2.6555-2.7255-6.3987-0.0111-7.152-2.9243-13.792-8.6802-19.785-4.1006-4.2694-8.6751-7.1592-13.896-8.7785-1.2498-0.38765-4.0484-0.51957-13.422-0.63274-14.708-0.17757-17.973 0.13047-22.98 2.1682-9.2314 3.7568-15.864 11.674-18.284 21.824-0.45444 1.9064-0.54266 4.9618-0.65 22.513-0.13448 21.988 0.01386 25.217 1.3586 29.575 1.111 3.6002 2.232 5.8063 4.5414 8.9376 4.3994 5.9652 10.993 10.273 17.585 11.49 3.137 0.57911 41.84 0.72399 45.804 0.17161z" display="none" fill="#fff" strokeWidth=".86401" />
            <path className="clip" d="m8.0345 6.3499h163.45v166.5h-163.45zm103.44 131.49c6.8936-0.96075 12.296-3.7837 17.364-9.0736 3.6662-3.8268 5.9611-7.9689 7.4609-13.466 0.62305-2.2837 0.67529-3.3956 0.78946-16.804 0.0863-10.12 0.0143-14.86-0.24367-16.056-0.37384-1.7344-1.4336-3.345-2.6427-4.0165-0.37209-0.20664-2.7561-0.47002-5.2978-0.58526-4.2591-0.19314-4.7356-0.278-6.08-1.0829-2.1324-1.2768-2.7197-2.6555-2.7255-6.3987-0.0111-7.152-2.9243-13.792-8.6802-19.785-4.1006-4.2694-8.6751-7.1592-13.896-8.7785-1.2498-0.38765-4.0484-0.51957-13.422-0.63274-14.708-0.17757-17.973 0.13047-22.98 2.1682-9.2314 3.7568-15.864 11.674-18.284 21.824-0.45444 1.9064-0.54266 4.9618-0.65 22.513-0.13448 21.988 0.01386 25.217 1.3586 29.575 1.111 3.6002 2.232 5.8063 4.5414 8.9376 4.3994 5.9652 10.993 10.273 17.585 11.49 3.137 0.57911 41.84 0.72399 45.804 0.17161z" strokeWidth=".86401" />
          </clipPath>
        </defs>
        <path d="m-82.995 87.838v-171.9h1020v343.8h-1020v-171.9z" fill="none" />
        <g transform="matrix(.92141 0 0 .92141 7.0545 7.0421)" fill="#fff" strokeWidth=".86401">
          <path d="m30.568 167.24c-2.8716-0.77176-5.3495-1.9071-7.6348-3.4982-1.9292-1.3431-4.7488-4.1198-5.8212-5.7323-1.3096-1.9694-2.815-5.342-3.4285-7.6809-0.62576-2.3858-0.6359-3.336-0.64713-60.605-0.01116-56.98 0.0015-58.233 0.61488-60.681 2.169-8.6596 8.8857-15.248 17.548-17.214 2.4907-0.56514 113.75-0.66398 116.44-0.10343 7.2734 1.5175 12.991 5.979 16.299 12.719 2.6303 5.3583 2.3951-0.53816 2.5156 63.081 0.0767 40.479 6e-3 57.473-0.24689 59.59-1.1845 9.9072-7.8732 17.592-17.498 20.103-2.462 0.64225-3.3184 0.65142-59.215 0.63395-54.046-0.0166-56.821-0.0454-58.928-0.61194z" clipPath="url(#clipPath8)" />
          <path d="m70.797 77.476c-3.5242-0.9925-4.841-6.1585-2.2508-8.8303 1.6555-1.7077 2.1132-1.7727 12.476-1.7727 9.3029 0 9.6156 0.02079 10.982 0.72599 1.9748 1.0193 2.8328 2.4564 2.8328 4.7444 0 2.0665-0.80586 3.5146-2.6034 4.6784-0.96518 0.62486-1.542 0.66375-10.657 0.71844-5.6283 0.0338-10.112-0.07615-10.78-0.26416zm-0.44157 34.766c-1.5128-0.67346-2.9215-2.5442-3.165-4.203-0.23192-1.5801 0.54532-3.7524 1.7367-4.854 1.5018-1.3886 2.161-1.435 20.63-1.4498 18.999-0.0152 18.9-0.0234 20.701 1.6952 2.5446 2.4274 2.0078 6.749-1.0585 8.5234l-3.151 0.52354-16.423 0.19641c-14.431 0.17258-18.519-0.0973-19.271-0.43172z" />
        </g>
      </svg>
    </SvgIcon>
  );
}

Hope these help somebody.

Monday, February 1, 2021

Koordinat2 WebApp for geo-coordinates conversion and display

Koordinat2 WebApp (https://dominoc925-pages.appspot.com/webapp/koordinat2/default.html) was developed using ReactJS and WebAssembly for converting geo-coordinates and showing them on a map. The WebApp uses Proj4 in the backend for performing the projection conversion and datum conversion; hence it supports over a thousand coordinate reference systems. 

Using the Koordinat2 WebApp is easy. The following shows what can be done with the WebApp.

Opening the WebApp

  1. Using a modern browser, open up the the Koordinat2 WebApp at this url https://dominoc925-pages.appspot.com/webapp/koordinat2/default.html

    The WebApp page is displayed.


Choosing Coordinate Systems

  1. To define the primary input coordinate system, click the gear icon in the Input Coordinates panel.

    The Select Source Coordinate System dialog appears.


  2. In the Search field, type in a EPSG code e.g. 3414 for SVY21. Or type in part of a coordinate system name, e.g. Borneo.

    One or more entries are listed.


  3. Click on a listed entry, e.g. Timbalai 1948 / RSO Borneo (m).

    The selected coordinate system is chosen.


  4. To define the secondary or output coordinate system, click the gear icon in the Output Coordinates panel.


  5. Choose the Output coordinate system e.g. EPSG 4326 using similar procedure as the previous steps 3 to 4.

Converting Coordinates

  1. To convert coordinates in the Input Coordinate system, type in the Easting and Northing (or Latitude and Longitude) values in the corresponding entry fields.

    The converted coordinates are displayed immediately in the Output Coordinates Longitude and Latitude fields (or Easting and Northing fields).

    A corresponding marker is also created on the Map pointing to the location of the coordinate.


  2. Optional. Clicking on the marker will pop up a moveable Information box.

 

Displaying Coordinates of Map Locations

  1. To display coordinates of locations on the map, simply click the map location with the mouse.

    A marker is placed at the clicked location.

    The clicked location coordinates are displayed in the Input Coordinates and Output Coordinates panels.
     

  Displaying a Grid

  1. On the toolbar on the top right, click the Grid icon.

    The Select Grid Settings dialog box appears.


  2. Optional. Click the Line color field to choose a grid color.

  3. In the Grid type field, choose the grid type to display e.g. UTM or Geographic.

  4. Click Okay.

    The selected grid is displayed on the map.

Selecting a Base Layer

  1. On the tool bar on the top right, click the Layer icon.

    The Select Base Layer dialog box appears.

     
  2.  Choose a layer to display, e.g. Open Street Map Landscape.

    The base layer changes to the selected layer.

Monday, December 28, 2020

How to setup a C++ WebAssembly component to run in a create-react-app React project

I had a hard time trying to get a C/C++ WebAssembly component to work in a React application generated from the create-react-app utility. Some blogs suggested using the react-app-rewired package to override the configuration and use the wasm-loader; but I kept getting magic header not detected errors when loading the wasm file or some ES6 syntax errors. Finally I found a StackOverflow post that gave me some ideas on getting it to work. 

In this post, I outline the steps I did to create, use a C/C++ WebAssembly in a ReactJS application generated by the create-react-app tool, on a Linux Ubuntu machine. This example will call the WebAssembly's function to add in two numbers (1 and 2) and return the resultant value. The resultant value would be displayed at the top of the web page as shown in the screen shot below.

Create a ReactJS application with create-react-app

  1. Open up a Terminal. Change to your project directory and type in the following commands to create the ReactJS application cra-wasm-adder.

    $ cd /path/to/reactprj/
    $ npx create-react-app cra-wasm-adder


    The cra-wasm-adder ReactJS application is created.

  2. Underneath the root of the newly created project, create a source directory, e.g. src_cpp for the C/C++ WebAssembly code.

    $ cd /path/to/reactprj/cra-wasm-adder/
    $ mkdir src_cpp


    The src_cpp directory is created.

Create the C/C++ source code files

  1. In the newly created src_cpp directory, use a favorite source code editor to create a C/C++ file, e.g. adder.cpp. Enter the following code.



    Note: the adder function simply sums up two integer numbers and returns the value.

  2. Create a Shell script file, e.g. make.sh to call the Emscripten compiler emcc to compile the C/C++ source code.

    Note: the emcc compiles the C/C++ source code into a Javascript plumbing helper file and a WebAssembly (*.wasm) file.

  3. In the make.sh file, define the module name and output file names.



  4. Then type in the emcc command to generate a Javascript plumbing helper file and the WebAssembly (*.wasm) file.


    Note: the Javascript generated by the emcc compiler (my version is 2.0.5) is not fully compatible with the ReactJS transpiler. The file has to be edited for compatibility purposes. This modifications may differ for different versions of the compiler

  5. Type in the sed command to insert a line /* eslint-disable */  at the top of the Javascript plumbing file to disable the Ecmascript linting.



  6. Type in the sed command to replace the import.meta.url string to the WebAssembly file relative to the root of the public directory of the ReactJS project, e.g. /path/to/reactprj/public/.


    Note: in this example, the *.wasm file is placed directly underneath the root of the /path/to/reactprj/public/; so the resultant change looks like the code below.


  7. Type in the sed command to add in the window object to the self.location.href string.


    The result change Javascript looks like the snippet below.


  8. Type in the sed commands to comment out the dataURIPrefix declaration  and isDataURI function block.



    The resultant Javascript code is shown below.


  9. Next, type in the sed commands to modify the wasmBinaryFile variable to point to the actual relative location in the ReactJS' public directory and to remove and replace the getBinary and getBinaryPromise function blocks.


    After running the commands, the Javascript should like the code below:



  10.  Finally, type in the sed command to remove the call to the isDataURI function in the instantiateAsync function.


    The resultant Javascript:


  11. The last thing the make.sh script needs to do is to move the generated WebAssembly file to the /path/to/reactprj/public/ directory and the modified Javascript file to the /path/to/reactprj/src/ directory.

    mv $OUTPUT_JS ../src/
    mv $OUTPUT_WASM ../public/



    The directory structure should look like the screen shot below:

Run the Shell script

  1. In a Terminal, change directory to the location of the make.sh shell script.

    $ cd /path/to/reactprj/src_cpp/

  2. Type in the following to run the script.

    $ bash make.sh

    If the compilation is successful, the resultant Javascript and WebAssembly should be placed in the directories as shown below.


Create WebAssembly React component

  1. In a text editor, create the React component under the /path/to/reactprj/src/ directory to use the WebAssembly component, e.g. AddNumbers.js .


  2. Type in the following code to import in the generated Javascript plumbing file and call the WebAssembly adder function.


Running the ReactJS application

  1. In a Terminal, run the React JS application.

    $ npm run start

    The browser opens up the development site.


  2. Note the message at the top which prints out the result of calling the WebAssembly's adder function: Hello 1+2=3.

The source code for this example is freely available on https://gitlab.com/dominoc925/cra-wasm-adder


Monday, December 9, 2019

Fix error 400 bad request when trying to use create-react-app

While attempting to create a new ReactJS app with the create-react-app tool, I encountered the following error: "error 400 Bad Request: run-async@^2.2.0". See the screenshot below.

After some research, I found the node npm cache could be corrupted. So running the following command fixed the issue for me.

$ npm cache verify


The create-react-app tool now can complete successfully, as shown below:
$ npx create-react-app myapp


Monday, October 14, 2019

Simple example of a ReactJS and OpenLayers map component

OpenLayers (https://openlayers.org/) is a "high-performance, feature-packed (Javascript) library for all your mapping needs" for web sites. I spent some time figuring out how to use it with ReactJS. As most of the available examples in the official documentation are for plain vanilla HTML/Javascript, I stumbled a few times trying to get it to work. This post summarises the steps to get a minimal OpenLayers - React component to work. 


Installing OpenLayers for ReactJS
Assuming a ReactJS project has been created e.g. /path/to/React/project/, the first thing is to install the prerequisite software.
  1. Install OpenLayers package for node. Open a Terminal, change directory to the project root directory and type in the following command.

    $ npm install ol --save
  2. Optional. Install Proj4Js and Material-UI.

    $ npm install proj4 @material-ui/core --save
Create the React component for OpenLayers map
Under the ReactJS project e.g. /path/to/React/project/src/components/, create the OpenLayers React component e.g. OLMapFragment.js.

Code listing of OLMapFragment.js
import React from 'react'
import Grid from '@material-ui/core/Grid'

// Start Openlayers imports
import { 
    Map,
    View
 } from 'ol'
import {
    GeoJSON,
    XYZ
} from 'ol/format'
import {
    Tile as TileLayer,
    Vector as VectorLayer
} from 'ol/layer'
import {
    Vector as VectorSource,
    OSM as OSMSource,
    XYZ as XYZSource,
    TileWMS as TileWMSSource
} from 'ol/source'
import {
    Select as SelectInteraction,
    defaults as DefaultInteractions
} from 'ol/interaction'
import { 
    Attribution,
    ScaleLine,
    ZoomSlider,
    Zoom,
    Rotate,
    MousePosition,
    OverviewMap,
    defaults as DefaultControls
} from 'ol/control'
import {
    Style,
    Fill as FillStyle,
    RegularShape as RegularShapeStyle,
    Stroke as StrokeStyle
} from 'ol/style'

import { 
    Projection,
    get as getProjection
 } from 'ol/proj'

// End Openlayers imports

class OLMapFragment extends React.Component {
    constructor(props) {
        super(props)
        this.updateDimensions = this.updateDimensions.bind(this)
    }
    updateDimensions(){
        const h = window.innerWidth >= 992 ? window.innerHeight : 400
        this.setState({height: h})
    }
    componentWillMount(){
        window.addEventListener('resize', this.updateDimensions)
        this.updateDimensions()
    }
    componentDidMount(){

        // Create an Openlayer Map instance with two tile layers
        const map = new Map({
            //  Display the map in the div with the id of map
            target: 'map',
            layers: [
                new TileLayer({
                    source: new XYZSource({
                        url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png',
                        projection: 'EPSG:3857'
                    })
                }),
                new TileLayer({
                    source: new TileWMSSource({
                        url: 'https://ahocevar.com/geoserver/wms',
                        params: {
                            layers: 'topp:states',
                            'TILED': true,
                        },
                        projection: 'EPSG:4326'
                    }),
                    name: 'USA'
                }),
            ],
            // Add in the following map controls
            controls: DefaultControls().extend([
                new ZoomSlider(),
                new MousePosition(),
                new ScaleLine(),
                new OverviewMap()
            ]),
            // Render the tile layers in a map view with a Mercator projection
            view: new View({
                projection: 'EPSG:3857',
                center: [0, 0],
                zoom: 2
            })
        })
    }
    componentWillUnmount(){
        window.removeEventListener('resize', this.updateDimensions)
    }
    render(){
        const style = {
            width: '100%',
            height:this.state.height,
            backgroundColor: '#cccccc',
        }
        return (
            <Grid container>
                <Grid item xs={12}>
                    <div id='map' style={style} >
                    </div>
                </Grid>
            </Grid>
        )
    }
}
export default OLMapFragment

Use the React OpenLayers map component
Now in the ReactJS project's index.js file under /path/to/React/project/src/, import in the newly created OLMapFragment component and render it.

Listing of index.js
import React from 'react'
import { render} from 'react-dom'
import OLMapFragment from './js/components/OLMapFragment'

render(
    <OLMapFragment />
    ,
    document.getElementById('react-container')
)

Create the default index.html file
Finally, include links to OpenLayer's style sheets in the project's index.html file under /path/to/React/project/src/.
Listing of index.html file
<!DOCTYPE html>
<html class="no-js" lang="en">

<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content='ie=edge'>
    <title>Openlayers React</title>
    <meta name="description" content="Explore planet Mars">
    <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no" />
    <!-- material-ui prerequisites -->
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
    <!-- end material-ui prerequisites -->

    <link rel="stylesheet" href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css"
        type="text/css" />

</head>

<body>
    <!--[if lte IE 8]
        <p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com">upgrade your browser</a></p>
        <![endif]-->
    <div id='react-container'></div>

</body>

</html>

Now, run the ReactJS project with a web server and open the web page with an Internet browser.

The web map tiles are rendered in the React OpenLayers component.