Mhret Aatifa

Mhret Aatifa

1600376640

Set of components and helpers for building complex and beautifully animated charts

React Native Animated Charts

Set of components and helpers for building complex and beautifully animated charts.

The library was designed to create aesthetic, animated (so far only linear) charts based on a given input. The main assumptions of the library were to create smooth transitions between subsequent data sets. For this reason, we have discovered a shortage of existing libraries related to the charts. The current package was created as part of the Rainbow.me project and for this reason it was not designed as a complete and comprehensive solution for displaying various types of charts. However, we will be now using more charts in the whole application, so we believe that the number of functionalities in the application will gradually grow.

Additionally, we are open to new Pull Requests. We want this library to become popular and complete thanks to community activity.

It’s a part of the Rainbow.me project.

TODO

The library has been released in a production-ready version. We use it inside the Rainbow.me project so it’s verified for use in production. However, it relies on React Native Reanimated 2.0 in the alpha version thus it might not work perfectly. Test it deeply before using it. Until the stable release of Reanimated, I think it’s worth not marking this library as stable. Although the library works with Reanimated without any changes, we faced a few issues related to our (quite advanced) usage of the library. Thus we made some hacks we’re not very proud of and it’s for 99% something you should not do. However, if you see some crashes, you may try one of our hacks.

There’re a few things left to make it polished regarding linear charts:

  • [ ] cleanup API. ChartProvider and ChartPath have been split for two components to separated responsibilities of providing data and displaying charts. I’m still not sure if it’s a good move so we can decide to move some props from one to another or connect them inside one component.
  • [ ] Support for gestures - pinching, swiping, etc.
  • [ ] more parameters regarding interpolation, smoothing, and animations (i.e. allow to override springConfig and timingConfig)

Installation

  1. Install react-native-reanimated in the newest version.
yarn add @rainbow-me/animated-charts
npm i @rainbow-me/animated-charts
  1. If you want to use haptic feedback on the press in / out, install
yarn add react-native-haptic-feedback
npm i react-native-haptic-feedback

The library is verified on 2.0.0-alpha.6 version of reanimated.

Reanimated

Using TurboModules might have an impact on your current development flow and most likely you don’t want to decrease your DX. Since we’re not using reanimated in other places in the app, we made some tweaks to disable charts in development mode with compilation macros on iOS. You can find it here

Also, because we’re using libraries which currently do not support reanimated 2, we patched exports in reanimated

Furthermore, we found few differences in how the Animated module works with and without TurboModules support, so we made a trick to fallback to the not-TM version of Animated.

Most likely, you don’t need any of those patches.

Example app

We made a generic example to show briefly what’s possible to achieve with this library. A Real-life example is available inside Rainbow!

In order to run an example clone this repo and navigate to Example then:

yarn && cd ios && pod install && cd ..
react-native run-android
react-native run-ios

API

The library has been designed to provide as much flexibility as possible with the component-based API for easy integration with existing applications.

Basic API Example

import React from 'react';
import {Dimensions, View} from 'react-native';
import {ChartDot, ChartPath, ChartPathProvider, monotoneCubicInterpolation} from '@rainbow-me/animated-charts';

export const {width: SIZE} = Dimensions.get('window');

export const data = [
  {x: 1453075200, y: 1.47}, {x: 1453161600, y: 1.37},
  {x: 1453248000, y: 1.53}, {x: 1453334400, y: 1.54},
  {x: 1453420800, y: 1.52}, {x: 1453507200, y: 2.03},
  {x: 1453593600, y: 2.10}, {x: 1453680000, y: 2.50},
  {x: 1453766400, y: 2.30}, {x: 1453852800, y: 2.42},
  {x: 1453939200, y: 2.55}, {x: 1454025600, y: 2.41},
  {x: 1454112000, y: 2.43}, {x: 1454198400, y: 2.20},
];

const points = monotoneCubicInterpolation(data)(40);

const BasicExample = () => (
  <View style={{ backgroundColor: 'black' }}>
    <ChartPathProvider data={{ points, smoothingStrategy: 'bezier' }}>
      <ChartPath height={SIZE / 2} stroke="yellow" width={SIZE} />
      <ChartDot style={{ backgroundColor: 'blue' }} />
    </ChartPathProvider>
  </View>
);

The code above generates the chart below:

Linear charts

ChartPathProvider

The whole chart’s structure has to be wrapped with ChartProvider. It’s responsible for data managing and itself does not have a visual impact on the layout. Under the hood, it uses context API to simplify manipulation with other components. The rule is to use one data series for each wrapper.

Prop name type default / obligatory description
softMargin number 0 While scrubbing the chart touching edges of the screen you may want make points on the edges more accessible. With softMargin it’s possible to access points on edges doubling the speed of scrubbing beyond this margin.
enableHaptics boolean false On pressing in/out on the chart it might be expected to make haptic feedback. It will happen with enableHaptics set to true and react-native-haptic-feedback installed
data `{ points: [Point], nativePoints: [Point], smoothingStrategy?: ‘bezier’ ‘simple’ ‘complex’, smoothingFactor }`
springConfig object {damping: 15, mass: 1, stiffness: 600} Object defining the spring animation. This spring is used for a dot’s scale.
timingFeedbackConfig object {duration: 80} Object defining the timing animation. timingFeedbackConfig is used for a path’s opacity and width.
timingAnimationConfig object {duration: 300} Object defining the timing animation. timingAnimationConfig is used for the transition between chart’s data.
  • data is an array containing points to be displayed. A Point is an object containing x and y as a number.
  • nativeData is an array of points that will not be drawn. However, if you used some strategy of interpolating data or simplifying you might want to present data slightly different from the real one. Then if you’d like labels to be fully correct you may want to provide real data before adjusting them.
  • smoothingStrategy. While presenting points path can be drawn with different approaches.
    • If smoothingStrategy is not provided (or set to any other value but for listed here), connects points using linear interpolation.
    • The bezier strategy connects points with a bezier path inspired by d3 shape. It’s not parametrized by smoothingFactor.
    • The complex strategy uses approach explained here using cubic splines. It’s parametrized by smoothingFactor.
    • The simple strategy is a bit simplified complex strategy using quadratic splines. It’s parametrized by smoothingFactor.
  • smoothingFactor. Is a value from 0 to 1 defining how smooth a presentation should be. 0 means no smoothing, and it’s the default. smoothingFactor has an impact if smoothingStrategy is simple or complex.

ChartPath

This component is used for showing the path itself.

Prop name type default / obligatory description
disableSmoothingWhileTransitioning number false Although smoothing is not complex computing, it might impact performance in some low-end devices so while having a big set of data it might be worth disable smoothing while transitioning.
height number obligatory Height od the SVG canvas
width number obligatory Width od the SVG canvas
strokeWidth number 1 Width of the path.
strokeWidthSelected number 1 Width of the path selected.
gestureEnabled boolean true Defines if interaction with the chart should be allowed or not
longPressGestureHandlerProps object {maxDist: 100000, minDurationMs: 0, shouldCancelWhenOutside: false} Under the hood we’re using LongPressGestureHandler for handling interactions. It’s recommended to not override its props. However, it might be useful while interacting with another GH.
selectedOpacity number 0.7 Target opacity of the path while touching the chart.
…rest object {} Props applied to SVG Path.

ChartDot

Component for displaying the dot for scrubbing on the chart.

Prop name type default description
size number 10 Size of the dot.
…props object {} Rest of the props applied to Reanimated.View including style

ChartYLabel&ChartXLabel

Labels are useful while moving finger through the chart to show the exact value in given point.

Prop name type default description
format reanimated worklet a => a Worklet for formatting data from the chart. It can be useful when your data is a timestamp or currency.
…props object {} Rest of the props applied to TextInput including style

Candle Charts

TODO

Pie charts

TODO

Helpers

It’s not essential in the library, but we have decided to include a lot of helpers we are (or we were) using for displaying charts.

Interpolations

We have two interpolators which share the most of the API: bSplineInterpolation and monotoneCubicInterpolation.

import { bSplineInterpolation as interpolator } from '@rainbow-me/animated-charts';
// import { monotoneCubicInterpolation as interpolator } from '@rainbow-me/animated-charts';

const interpolatedData = interpolator(data)(80, true, false);

Code above generates 80 equidistant points from given dataset. Interpolator (monotoneCubicInterpolation or bSplineInterpolation) returns generator. Generator accepts 3 arguments: range, includeExtremes, removePointsSurroundingExtremes.

  • range is the number of points of the output.

  • includeExtremes. If it’s vital to include extremes in the output, set to true. However, the data might not be fully equidistant.

  • removePointsSurroundingExtremes. Makes sense only if includeExtremes set to true. When disabled, it might be possible that extremes look very “pointy”. To get rid of this, you can remove points surrounding extremes. E.g.

    • removePointsSurroundingExtremes = false

      o---------o----Min--o---------o---------o---------o---------o

    • removePointsSurroundingExtremes = true

      o--------------Min------------o---------o---------o---------o

bSplineInterpolation(data, degree = 3)

bSplineInterpolation is inspired by victorian lib and uses B-spline interpolation of a given degree.

monotoneCubicInterpolation(data, degree = 3)

This curve is inspired by d3 shape. "Produces a cubic spline that preserves monotonicity in y, assuming monotonicity in x, as proposed by Steffen in A simple method for monotonic interpolation in one dimension: “a smooth curve with continuous first-order derivatives that passes through any given set of data points without spurious oscillations. Local extrema can occur only at grid points where they are given by the data, but not in between two adjacent grid points.”

simplifyData(data, pickRange = 10, includeExtremes = true)

This helper takes only one point per pickRange. Might be useful for very dense data. If it’s important, it’s possible to include extremes with the includeExtremes flag. E.g.

pickRange = 3, includeExtremes = true

X are equidistant in this case

Y:0          1          7          2         -3          0          1          2
  S----------o----------E----------X----------E----------o----------X----------o----------S

X - points picked because index%3=0

S – the first and the last points are always included.

E – extremes.

Download Details:

Author: rainbow-me

Source Code: https://github.com/rainbow-me/react-native-animated-charts

#react-native #react #mobile-apps

What is GEEK

Buddha Community

Set of components and helpers for building complex and beautifully animated charts
Hermann  Frami

Hermann Frami

1651383480

A Simple Wrapper Around Amplify AppSync Simulator

This serverless plugin is a wrapper for amplify-appsync-simulator made for testing AppSync APIs built with serverless-appsync-plugin.

Install

npm install serverless-appsync-simulator
# or
yarn add serverless-appsync-simulator

Usage

This plugin relies on your serverless yml file and on the serverless-offline plugin.

plugins:
  - serverless-dynamodb-local # only if you need dynamodb resolvers and you don't have an external dynamodb
  - serverless-appsync-simulator
  - serverless-offline

Note: Order is important serverless-appsync-simulator must go before serverless-offline

To start the simulator, run the following command:

sls offline start

You should see in the logs something like:

...
Serverless: AppSync endpoint: http://localhost:20002/graphql
Serverless: GraphiQl: http://localhost:20002
...

Configuration

Put options under custom.appsync-simulator in your serverless.yml file

| option | default | description | | ------------------------ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | | apiKey | 0123456789 | When using API_KEY as authentication type, the key to authenticate to the endpoint. | | port | 20002 | AppSync operations port; if using multiple APIs, the value of this option will be used as a starting point, and each other API will have a port of lastPort + 10 (e.g. 20002, 20012, 20022, etc.) | | wsPort | 20003 | AppSync subscriptions port; if using multiple APIs, the value of this option will be used as a starting point, and each other API will have a port of lastPort + 10 (e.g. 20003, 20013, 20023, etc.) | | location | . (base directory) | Location of the lambda functions handlers. | | refMap | {} | A mapping of resource resolutions for the Ref function | | getAttMap | {} | A mapping of resource resolutions for the GetAtt function | | importValueMap | {} | A mapping of resource resolutions for the ImportValue function | | functions | {} | A mapping of external functions for providing invoke url for external fucntions | | dynamoDb.endpoint | http://localhost:8000 | Dynamodb endpoint. Specify it if you're not using serverless-dynamodb-local. Otherwise, port is taken from dynamodb-local conf | | dynamoDb.region | localhost | Dynamodb region. Specify it if you're connecting to a remote Dynamodb intance. | | dynamoDb.accessKeyId | DEFAULT_ACCESS_KEY | AWS Access Key ID to access DynamoDB | | dynamoDb.secretAccessKey | DEFAULT_SECRET | AWS Secret Key to access DynamoDB | | dynamoDb.sessionToken | DEFAULT_ACCESS_TOKEEN | AWS Session Token to access DynamoDB, only if you have temporary security credentials configured on AWS | | dynamoDb.* | | You can add every configuration accepted by DynamoDB SDK | | rds.dbName | | Name of the database | | rds.dbHost | | Database host | | rds.dbDialect | | Database dialect. Possible values (mysql | postgres) | | rds.dbUsername | | Database username | | rds.dbPassword | | Database password | | rds.dbPort | | Database port | | watch | - *.graphql
- *.vtl | Array of glob patterns to watch for hot-reloading. |

Example:

custom:
  appsync-simulator:
    location: '.webpack/service' # use webpack build directory
    dynamoDb:
      endpoint: 'http://my-custom-dynamo:8000'

Hot-reloading

By default, the simulator will hot-relad when changes to *.graphql or *.vtl files are detected. Changes to *.yml files are not supported (yet? - this is a Serverless Framework limitation). You will need to restart the simulator each time you change yml files.

Hot-reloading relies on watchman. Make sure it is installed on your system.

You can change the files being watched with the watch option, which is then passed to watchman as the match expression.

e.g.

custom:
  appsync-simulator:
    watch:
      - ["match", "handlers/**/*.vtl", "wholename"] # => array is interpreted as the literal match expression
      - "*.graphql"                                 # => string like this is equivalent to `["match", "*.graphql"]`

Or you can opt-out by leaving an empty array or set the option to false

Note: Functions should not require hot-reloading, unless you are using a transpiler or a bundler (such as webpack, babel or typescript), un which case you should delegate hot-reloading to that instead.

Resource CloudFormation functions resolution

This plugin supports some resources resolution from the Ref, Fn::GetAtt and Fn::ImportValue functions in your yaml file. It also supports some other Cfn functions such as Fn::Join, Fb::Sub, etc.

Note: Under the hood, this features relies on the cfn-resolver-lib package. For more info on supported cfn functions, refer to the documentation

Basic usage

You can reference resources in your functions' environment variables (that will be accessible from your lambda functions) or datasource definitions. The plugin will automatically resolve them for you.

provider:
  environment:
    BUCKET_NAME:
      Ref: MyBucket # resolves to `my-bucket-name`

resources:
  Resources:
    MyDbTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: myTable
      ...
    MyBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: my-bucket-name
    ...

# in your appsync config
dataSources:
  - type: AMAZON_DYNAMODB
    name: dynamosource
    config:
      tableName:
        Ref: MyDbTable # resolves to `myTable`

Override (or mock) values

Sometimes, some references cannot be resolved, as they come from an Output from Cloudformation; or you might want to use mocked values in your local environment.

In those cases, you can define (or override) those values using the refMap, getAttMap and importValueMap options.

  • refMap takes a mapping of resource name to value pairs
  • getAttMap takes a mapping of resource name to attribute/values pairs
  • importValueMap takes a mapping of import name to values pairs

Example:

custom:
  appsync-simulator:
    refMap:
      # Override `MyDbTable` resolution from the previous example.
      MyDbTable: 'mock-myTable'
    getAttMap:
      # define ElasticSearchInstance DomainName
      ElasticSearchInstance:
        DomainEndpoint: 'localhost:9200'
    importValueMap:
      other-service-api-url: 'https://other.api.url.com/graphql'

# in your appsync config
dataSources:
  - type: AMAZON_ELASTICSEARCH
    name: elasticsource
    config:
      # endpoint resolves as 'http://localhost:9200'
      endpoint:
        Fn::Join:
          - ''
          - - https://
            - Fn::GetAtt:
                - ElasticSearchInstance
                - DomainEndpoint

Key-value mock notation

In some special cases you will need to use key-value mock nottation. Good example can be case when you need to include serverless stage value (${self:provider.stage}) in the import name.

This notation can be used with all mocks - refMap, getAttMap and importValueMap

provider:
  environment:
    FINISH_ACTIVITY_FUNCTION_ARN:
      Fn::ImportValue: other-service-api-${self:provider.stage}-url

custom:
  serverless-appsync-simulator:
    importValueMap:
      - key: other-service-api-${self:provider.stage}-url
        value: 'https://other.api.url.com/graphql'

Limitations

This plugin only tries to resolve the following parts of the yml tree:

  • provider.environment
  • functions[*].environment
  • custom.appSync

If you have the need of resolving others, feel free to open an issue and explain your use case.

For now, the supported resources to be automatically resovled by Ref: are:

  • DynamoDb tables
  • S3 Buckets

Feel free to open a PR or an issue to extend them as well.

External functions

When a function is not defined withing the current serverless file you can still call it by providing an invoke url which should point to a REST method. Make sure you specify "get" or "post" for the method. Default is "get", but you probably want "post".

custom:
  appsync-simulator:
    functions:
      addUser:
        url: http://localhost:3016/2015-03-31/functions/addUser/invocations
        method: post
      addPost:
        url: https://jsonplaceholder.typicode.com/posts
        method: post

Supported Resolver types

This plugin supports resolvers implemented by amplify-appsync-simulator, as well as custom resolvers.

From Aws Amplify:

  • NONE
  • AWS_LAMBDA
  • AMAZON_DYNAMODB
  • PIPELINE

Implemented by this plugin

  • AMAZON_ELASTIC_SEARCH
  • HTTP
  • RELATIONAL_DATABASE

Relational Database

Sample VTL for a create mutation

#set( $cols = [] )
#set( $vals = [] )
#foreach( $entry in $ctx.args.input.keySet() )
  #set( $regex = "([a-z])([A-Z]+)")
  #set( $replacement = "$1_$2")
  #set( $toSnake = $entry.replaceAll($regex, $replacement).toLowerCase() )
  #set( $discard = $cols.add("$toSnake") )
  #if( $util.isBoolean($ctx.args.input[$entry]) )
      #if( $ctx.args.input[$entry] )
        #set( $discard = $vals.add("1") )
      #else
        #set( $discard = $vals.add("0") )
      #end
  #else
      #set( $discard = $vals.add("'$ctx.args.input[$entry]'") )
  #end
#end
#set( $valStr = $vals.toString().replace("[","(").replace("]",")") )
#set( $colStr = $cols.toString().replace("[","(").replace("]",")") )
#if ( $valStr.substring(0, 1) != '(' )
  #set( $valStr = "($valStr)" )
#end
#if ( $colStr.substring(0, 1) != '(' )
  #set( $colStr = "($colStr)" )
#end
{
  "version": "2018-05-29",
  "statements":   ["INSERT INTO <name-of-table> $colStr VALUES $valStr", "SELECT * FROM    <name-of-table> ORDER BY id DESC LIMIT 1"]
}

Sample VTL for an update mutation

#set( $update = "" )
#set( $equals = "=" )
#foreach( $entry in $ctx.args.input.keySet() )
  #set( $cur = $ctx.args.input[$entry] )
  #set( $regex = "([a-z])([A-Z]+)")
  #set( $replacement = "$1_$2")
  #set( $toSnake = $entry.replaceAll($regex, $replacement).toLowerCase() )
  #if( $util.isBoolean($cur) )
      #if( $cur )
        #set ( $cur = "1" )
      #else
        #set ( $cur = "0" )
      #end
  #end
  #if ( $util.isNullOrEmpty($update) )
      #set($update = "$toSnake$equals'$cur'" )
  #else
      #set($update = "$update,$toSnake$equals'$cur'" )
  #end
#end
{
  "version": "2018-05-29",
  "statements":   ["UPDATE <name-of-table> SET $update WHERE id=$ctx.args.input.id", "SELECT * FROM <name-of-table> WHERE id=$ctx.args.input.id"]
}

Sample resolver for delete mutation

{
  "version": "2018-05-29",
  "statements":   ["UPDATE <name-of-table> set deleted_at=NOW() WHERE id=$ctx.args.id", "SELECT * FROM <name-of-table> WHERE id=$ctx.args.id"]
}

Sample mutation response VTL with support for handling AWSDateTime

#set ( $index = -1)
#set ( $result = $util.parseJson($ctx.result) )
#set ( $meta = $result.sqlStatementResults[1].columnMetadata)
#foreach ($column in $meta)
    #set ($index = $index + 1)
    #if ( $column["typeName"] == "timestamptz" )
        #set ($time = $result["sqlStatementResults"][1]["records"][0][$index]["stringValue"] )
        #set ( $nowEpochMillis = $util.time.parseFormattedToEpochMilliSeconds("$time.substring(0,19)+0000", "yyyy-MM-dd HH:mm:ssZ") )
        #set ( $isoDateTime = $util.time.epochMilliSecondsToISO8601($nowEpochMillis) )
        $util.qr( $result["sqlStatementResults"][1]["records"][0][$index].put("stringValue", "$isoDateTime") )
    #end
#end
#set ( $res = $util.parseJson($util.rds.toJsonString($util.toJson($result)))[1][0] )
#set ( $response = {} )
#foreach($mapKey in $res.keySet())
    #set ( $s = $mapKey.split("_") )
    #set ( $camelCase="" )
    #set ( $isFirst=true )
    #foreach($entry in $s)
        #if ( $isFirst )
          #set ( $first = $entry.substring(0,1) )
        #else
          #set ( $first = $entry.substring(0,1).toUpperCase() )
        #end
        #set ( $isFirst=false )
        #set ( $stringLength = $entry.length() )
        #set ( $remaining = $entry.substring(1, $stringLength) )
        #set ( $camelCase = "$camelCase$first$remaining" )
    #end
    $util.qr( $response.put("$camelCase", $res[$mapKey]) )
#end
$utils.toJson($response)

Using Variable Map

Variable map support is limited and does not differentiate numbers and strings data types, please inject them directly if needed.

Will be escaped properly: null, true, and false values.

{
  "version": "2018-05-29",
  "statements":   [
    "UPDATE <name-of-table> set deleted_at=NOW() WHERE id=:ID",
    "SELECT * FROM <name-of-table> WHERE id=:ID and unix_timestamp > $ctx.args.newerThan"
  ],
  variableMap: {
    ":ID": $ctx.args.id,
##    ":TIMESTAMP": $ctx.args.newerThan -- This will be handled as a string!!!
  }
}

Requires

Author: Serverless-appsync
Source Code: https://github.com/serverless-appsync/serverless-appsync-simulator 
License: MIT License

#serverless #sync #graphql 

Top 10 Best React Chart Component for App

React chart is a graphical representation of data, in which “the data is represented by symbols, such as bars in a bar chart, lines in a line chart, or slices in a pie chart”. Using the right type of chart is one decision to make when presenting data but as React developers, we have our own set of concerns, mainly, choosing the right chart component library.

Here are the 10 best react charts component I’ve picked. You can view and apply to your application.

1. Rough Charts

A responsive, composable react charting library with a hand-drawn style.

Features

  • It’s responsive.
  • It’s flexible and easy to compose. You can compose all available ChartSeries Components and render any shapes you like.
  • It’s lovely.
  • It’s written in TypeScript.

Rough Charts

View Demo: https://beizhedenglong.github.io/rough-charts/?path=/docs/roughcharts–page

Github: https://github.com/beizhedenglong/rough-charts

Download Link: https://github.com/beizhedenglong/rough-charts/archive/master.zip

2. Channel Grapher

This is a responsive ThingSpeak API grapher. It uses a JSON router to overcome CORS.

Built using ReactJS, Bootstrap and ChartJS.

Channel Grapher

View Demo: https://opens3.net/channel-grapher.html

Github: https://github.com/wilyarti/channel-grapher

Download Link: https://github.com/wilyarti/channel-grapher/archive/master.zip

3. react-charts

Simple, immersive and interactive charts for React.

Features

  • Line, Bar, Bubble, & Area Charts
  • Hyper Responsive
  • Powered by D3
  • Fully Declarative
  • Flexible data model

react-charts

View Demo: https://react-charts.js.org/examples/line

Github: https://github.com/tannerlinsley/react-charts

Download Link: https://github.com/tannerlinsley/react-charts/archive/master.zip

4. react-charts-and-maps

This project contains the implementation of libraries D3, highcharts and react-google-maps with the ReactJS. It shows how easy is adding those libraries in ReactJS.

react-charts-and-maps

View Demo: https://marekdano.github.io/react-charts-and-maps/

Github: https://github.com/marekdano/react-charts-and-maps

Download Link: https://github.com/marekdano/react-charts-and-maps/archive/master.zip

5. STORM React Diagrams

React Diagrams is currently getting a bit of a rewrite to enable much more advanced features.

STORM React Diagrams

View Demo: http://projectstorm.cloud/react-diagrams/?path=/story/simple-usage–simple-flow-example

Github: https://github.com/projectstorm/react-diagrams

Download Link: https://github.com/projectstorm/react-diagrams/archive/master.zip

6. React-d3-graph

Interactive and configurable graphs with react and d3 effortlessly.

React-d3-graph

View Demo: https://goodguydaniel.com/react-d3-graph/sandbox/index.html

Github: https://github.com/jcapobianco-cbi/react-d3-graph-cbi

Download Link: https://github.com/jcapobianco-cbi/react-d3-graph-cbi/archive/master.zip

7. React-VizGrammar

React VizGrammar is a wrapper around Victory JS and it makes charting easier by adding boilerplate code so that designers and developers can get started and set it up in a few minutes.

A chart can be embedded in a React environment simply by using the VizG react component.

React VizGrammar

View Demo: https://wso2.github.io/react-vizgrammar/#/

Github: https://github.com/wso2/react-vizgrammar

Download Link: https://github.com/wso2/react-vizgrammar/archive/master.zip

8. preact-charts

preact based charting library. Written with d3-maths, and TypeScript!

preact-charts

View Demo: https://codesandbox.io/s/ko300qzppv

Github: http://github.com/pmkroeker/preact-charts

Download Link: https://github.com/pmkroeker/preact-charts/archive/master.zip

9. REAVIZ

REAVIZ is a modular chart component library that leverages React natively for rendering the components while using D3js under the hood for calculations. The library provides an easy way to get started creating charts without sacrificing customization ability.

REAVIZ

View Demo: https://reaviz.io/?path=/docs/docs-intro–page

Github: https://github.com/jask-oss/reaviz

Download Link: https://github.com/jask-oss/reaviz/archive/master.zip

10. React Signals Plot

This is React Signals Plot component for geophysical data visualization.

The component supports ‘on the fly’ data compression. That’s why you can use it for drawing line charts which contain millions of points. ReactSignalsPlot is an interactive component. You can use a mouse or touch to move and zoom.

React Signals Plot

View Demo: https://gromtech.github.io/react-signals-plot/

Github: https://github.com/gromtech/react-signals-plot

Download Link: https://github.com/gromtech/react-signals-plot/archive/develop.zip

#react #react-chart #react-chart-component #chart #chart-component

Hermann  Frami

Hermann Frami

1651319520

Serverless APIGateway Service Proxy

Serverless APIGateway Service Proxy

This Serverless Framework plugin supports the AWS service proxy integration feature of API Gateway. You can directly connect API Gateway to AWS services without Lambda.

Install

Run serverless plugin install in your Serverless project.

serverless plugin install -n serverless-apigateway-service-proxy

Supported AWS services

Here is a services list which this plugin supports for now. But will expand to other services in the feature. Please pull request if you are intersted in it.

  • Kinesis Streams
  • SQS
  • S3
  • SNS
  • DynamoDB
  • EventBridge

How to use

Define settings of the AWS services you want to integrate under custom > apiGatewayServiceProxies and run serverless deploy.

Kinesis

Sample syntax for Kinesis proxy in serverless.yml.

custom:
  apiGatewayServiceProxies:
    - kinesis: # partitionkey is set apigateway requestid by default
        path: /kinesis
        method: post
        streamName: { Ref: 'YourStream' }
        cors: true
    - kinesis:
        path: /kinesis
        method: post
        partitionKey: 'hardcordedkey' # use static partitionkey
        streamName: { Ref: 'YourStream' }
        cors: true
    - kinesis:
        path: /kinesis/{myKey} # use path parameter
        method: post
        partitionKey:
          pathParam: myKey
        streamName: { Ref: 'YourStream' }
        cors: true
    - kinesis:
        path: /kinesis
        method: post
        partitionKey:
          bodyParam: data.myKey # use body parameter
        streamName: { Ref: 'YourStream' }
        cors: true
    - kinesis:
        path: /kinesis
        method: post
        partitionKey:
          queryStringParam: myKey # use query string param
        streamName: { Ref: 'YourStream' }
        cors: true
    - kinesis: # PutRecords
        path: /kinesis
        method: post
        action: PutRecords
        streamName: { Ref: 'YourStream' }
        cors: true

resources:
  Resources:
    YourStream:
      Type: AWS::Kinesis::Stream
      Properties:
        ShardCount: 1

Sample request after deploying.

curl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/kinesis -d '{"message": "some data"}'  -H 'Content-Type:application/json'

SQS

Sample syntax for SQS proxy in serverless.yml.

custom:
  apiGatewayServiceProxies:
    - sqs:
        path: /sqs
        method: post
        queueName: { 'Fn::GetAtt': ['SQSQueue', 'QueueName'] }
        cors: true

resources:
  Resources:
    SQSQueue:
      Type: 'AWS::SQS::Queue'

Sample request after deploying.

curl https://xxxxxx.execute-api.us-east-1.amazonaws.com/dev/sqs -d '{"message": "testtest"}' -H 'Content-Type:application/json'

Customizing request parameters

If you'd like to pass additional data to the integration request, you can do so by including your custom API Gateway request parameters in serverless.yml like so:

custom:
  apiGatewayServiceProxies:
    - sqs:
        path: /queue
        method: post
        queueName: !GetAtt MyQueue.QueueName
        cors: true

        requestParameters:
          'integration.request.querystring.MessageAttribute.1.Name': "'cognitoIdentityId'"
          'integration.request.querystring.MessageAttribute.1.Value.StringValue': 'context.identity.cognitoIdentityId'
          'integration.request.querystring.MessageAttribute.1.Value.DataType': "'String'"
          'integration.request.querystring.MessageAttribute.2.Name': "'cognitoAuthenticationProvider'"
          'integration.request.querystring.MessageAttribute.2.Value.StringValue': 'context.identity.cognitoAuthenticationProvider'
          'integration.request.querystring.MessageAttribute.2.Value.DataType': "'String'"

The alternative way to pass MessageAttribute parameters is via a request body mapping template.

Customizing request body mapping templates

See the SQS section under Customizing request body mapping templates

Customizing responses

Simplified response template customization

You can get a simple customization of the responses by providing a template for the possible responses. The template is assumed to be application/json.

custom:
  apiGatewayServiceProxies:
    - sqs:
        path: /queue
        method: post
        queueName: !GetAtt MyQueue.QueueName
        cors: true
        response:
          template:
            # `success` is used when the integration response is 200
            success: |-
              { "message: "accepted" }
            # `clientError` is used when the integration response is 400
            clientError: |-
              { "message": "there is an error in your request" }
            # `serverError` is used when the integration response is 500
            serverError: |-
              { "message": "there was an error handling your request" }

Full response customization

If you want more control over the integration response, you can provide an array of objects for the response value:

custom:
  apiGatewayServiceProxies:
    - sqs:
        path: /queue
        method: post
        queueName: !GetAtt MyQueue.QueueName
        cors: true
        response:
          - statusCode: 200
            selectionPattern: '2\\d{2}'
            responseParameters: {}
            responseTemplates:
              application/json: |-
                { "message": "accepted" }

The object keys correspond to the API Gateway integration response object.

S3

Sample syntax for S3 proxy in serverless.yml.

custom:
  apiGatewayServiceProxies:
    - s3:
        path: /s3
        method: post
        action: PutObject
        bucket:
          Ref: S3Bucket
        key: static-key.json # use static key
        cors: true

    - s3:
        path: /s3/{myKey} # use path param
        method: get
        action: GetObject
        bucket:
          Ref: S3Bucket
        key:
          pathParam: myKey
        cors: true

    - s3:
        path: /s3
        method: delete
        action: DeleteObject
        bucket:
          Ref: S3Bucket
        key:
          queryStringParam: key # use query string param
        cors: true

resources:
  Resources:
    S3Bucket:
      Type: 'AWS::S3::Bucket'

Sample request after deploying.

curl https://xxxxxx.execute-api.us-east-1.amazonaws.com/dev/s3 -d '{"message": "testtest"}' -H 'Content-Type:application/json'

Customizing request parameters

Similar to the SQS support, you can customize the default request parameters serverless.yml like so:

custom:
  apiGatewayServiceProxies:
    - s3:
        path: /s3
        method: post
        action: PutObject
        bucket:
          Ref: S3Bucket
        cors: true

        requestParameters:
          # if requestParameters has a 'integration.request.path.object' property you should remove the key setting
          'integration.request.path.object': 'context.requestId'
          'integration.request.header.cache-control': "'public, max-age=31536000, immutable'"

Customizing request templates

If you'd like use custom API Gateway request templates, you can do so like so:

custom:
  apiGatewayServiceProxies:
    - s3:
        path: /s3
        method: get
        action: GetObject
        bucket:
          Ref: S3Bucket
        request:
          template:
            application/json: |
              #set ($specialStuff = $context.request.header.x-special)
              #set ($context.requestOverride.path.object = $specialStuff.replaceAll('_', '-'))
              {}

Note that if the client does not provide a Content-Type header in the request, ApiGateway defaults to application/json.

Customize the Path Override in API Gateway

Added the new customization parameter that lets the user set a custom Path Override in API Gateway other than the {bucket}/{object} This parameter is optional and if not set, will fall back to {bucket}/{object} The Path Override will add {bucket}/ automatically in front

Please keep in mind, that key or path.object still needs to be set at the moment (maybe this will be made optional later on with this)

Usage (With 2 Path Parameters (folder and file and a fixed file extension)):

custom:
  apiGatewayServiceProxies:
    - s3:
        path: /s3/{folder}/{file}
        method: get
        action: GetObject
        pathOverride: '{folder}/{file}.xml'
        bucket:
          Ref: S3Bucket
        cors: true

        requestParameters:
          # if requestParameters has a 'integration.request.path.object' property you should remove the key setting
          'integration.request.path.folder': 'method.request.path.folder'
          'integration.request.path.file': 'method.request.path.file'
          'integration.request.path.object': 'context.requestId'
          'integration.request.header.cache-control': "'public, max-age=31536000, immutable'"

This will result in API Gateway setting the Path Override attribute to {bucket}/{folder}/{file}.xml So for example if you navigate to the API Gatway endpoint /language/en it will fetch the file in S3 from {bucket}/language/en.xml

Can use greedy, for deeper Folders

The forementioned example can also be shortened by a greedy approach. Thanks to @taylorreece for mentioning this.

custom:
  apiGatewayServiceProxies:
    - s3:
        path: /s3/{myPath+}
        method: get
        action: GetObject
        pathOverride: '{myPath}.xml'
        bucket:
          Ref: S3Bucket
        cors: true

        requestParameters:
          # if requestParameters has a 'integration.request.path.object' property you should remove the key setting
          'integration.request.path.myPath': 'method.request.path.myPath'
          'integration.request.path.object': 'context.requestId'
          'integration.request.header.cache-control': "'public, max-age=31536000, immutable'"

This will translate for example /s3/a/b/c to a/b/c.xml

Customizing responses

You can get a simple customization of the responses by providing a template for the possible responses. The template is assumed to be application/json.

custom:
  apiGatewayServiceProxies:
    - s3:
        path: /s3
        method: post
        action: PutObject
        bucket:
          Ref: S3Bucket
        key: static-key.json
        response:
          template:
            # `success` is used when the integration response is 200
            success: |-
              { "message: "accepted" }
            # `clientError` is used when the integration response is 400
            clientError: |-
              { "message": "there is an error in your request" }
            # `serverError` is used when the integration response is 500
            serverError: |-
              { "message": "there was an error handling your request" }

SNS

Sample syntax for SNS proxy in serverless.yml.

custom:
  apiGatewayServiceProxies:
    - sns:
        path: /sns
        method: post
        topicName: { 'Fn::GetAtt': ['SNSTopic', 'TopicName'] }
        cors: true

resources:
  Resources:
    SNSTopic:
      Type: AWS::SNS::Topic

Sample request after deploying.

curl https://xxxxxx.execute-api.us-east-1.amazonaws.com/dev/sns -d '{"message": "testtest"}' -H 'Content-Type:application/json'

Customizing responses

Simplified response template customization

You can get a simple customization of the responses by providing a template for the possible responses. The template is assumed to be application/json.

custom:
  apiGatewayServiceProxies:
    - sns:
        path: /sns
        method: post
        topicName: { 'Fn::GetAtt': ['SNSTopic', 'TopicName'] }
        cors: true
        response:
          template:
            # `success` is used when the integration response is 200
            success: |-
              { "message: "accepted" }
            # `clientError` is used when the integration response is 400
            clientError: |-
              { "message": "there is an error in your request" }
            # `serverError` is used when the integration response is 500
            serverError: |-
              { "message": "there was an error handling your request" }

Full response customization

If you want more control over the integration response, you can provide an array of objects for the response value:

custom:
  apiGatewayServiceProxies:
    - sns:
        path: /sns
        method: post
        topicName: { 'Fn::GetAtt': ['SNSTopic', 'TopicName'] }
        cors: true
        response:
          - statusCode: 200
            selectionPattern: '2\d{2}'
            responseParameters: {}
            responseTemplates:
              application/json: |-
                { "message": "accepted" }

The object keys correspond to the API Gateway integration response object.

Content Handling and Pass Through Behaviour customization

If you want to work with binary fata, you can not specify contentHandling and PassThrough inside the request object.

custom:
  apiGatewayServiceProxies:
    - sns:
        path: /sns
        method: post
        topicName: { 'Fn::GetAtt': ['SNSTopic', 'TopicName'] }
        request:
          contentHandling: CONVERT_TO_TEXT
          passThrough: WHEN_NO_TEMPLATES

The allowed values correspond with the API Gateway Method integration for ContentHandling and PassthroughBehavior

DynamoDB

Sample syntax for DynamoDB proxy in serverless.yml. Currently, the supported DynamoDB Operations are PutItem, GetItem and DeleteItem.

custom:
  apiGatewayServiceProxies:
    - dynamodb:
        path: /dynamodb/{id}/{sort}
        method: put
        tableName: { Ref: 'YourTable' }
        hashKey: # set pathParam or queryStringParam as a partitionkey.
          pathParam: id
          attributeType: S
        rangeKey: # required if also using sort key. set pathParam or queryStringParam.
          pathParam: sort
          attributeType: S
        action: PutItem # specify action to the table what you want
        condition: attribute_not_exists(Id) # optional Condition Expressions parameter for the table
        cors: true
    - dynamodb:
        path: /dynamodb
        method: get
        tableName: { Ref: 'YourTable' }
        hashKey:
          queryStringParam: id # use query string parameter
          attributeType: S
        rangeKey:
          queryStringParam: sort
          attributeType: S
        action: GetItem
        cors: true
    - dynamodb:
        path: /dynamodb/{id}
        method: delete
        tableName: { Ref: 'YourTable' }
        hashKey:
          pathParam: id
          attributeType: S
        action: DeleteItem
        cors: true

resources:
  Resources:
    YourTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: YourTable
        AttributeDefinitions:
          - AttributeName: id
            AttributeType: S
          - AttributeName: sort
            AttributeType: S
        KeySchema:
          - AttributeName: id
            KeyType: HASH
          - AttributeName: sort
            KeyType: RANGE
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1

Sample request after deploying.

curl -XPUT https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/dynamodb/<hashKey>/<sortkey> \
 -d '{"name":{"S":"john"},"address":{"S":"xxxxx"}}' \
 -H 'Content-Type:application/json'

EventBridge

Sample syntax for EventBridge proxy in serverless.yml.

custom:
  apiGatewayServiceProxies:
    - eventbridge:  # source and detailType are hardcoded; detail defaults to POST body
        path: /eventbridge
        method: post
        source: 'hardcoded_source'
        detailType: 'hardcoded_detailType'
        eventBusName: { Ref: 'YourBusName' }
        cors: true
    - eventbridge:  # source and detailType as path parameters
        path: /eventbridge/{detailTypeKey}/{sourceKey}
        method: post
        detailType:
          pathParam: detailTypeKey
        source:
          pathParam: sourceKey
        eventBusName: { Ref: 'YourBusName' }
        cors: true
    - eventbridge:  # source, detail, and detailType as body parameters
        path: /eventbridge/{detailTypeKey}/{sourceKey}
        method: post
        detailType:
          bodyParam: data.detailType
        source:
          bodyParam: data.source
        detail:
          bodyParam: data.detail
        eventBusName: { Ref: 'YourBusName' }
        cors: true

resources:
  Resources:
    YourBus:
      Type: AWS::Events::EventBus
      Properties:
        Name: YourEventBus

Sample request after deploying.

curl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/eventbridge -d '{"message": "some data"}'  -H 'Content-Type:application/json'

Common API Gateway features

Enabling CORS

To set CORS configurations for your HTTP endpoints, simply modify your event configurations as follows:

custom:
  apiGatewayServiceProxies:
    - kinesis:
        path: /kinesis
        method: post
        streamName: { Ref: 'YourStream' }
        cors: true

Setting cors to true assumes a default configuration which is equivalent to:

custom:
  apiGatewayServiceProxies:
    - kinesis:
        path: /kinesis
        method: post
        streamName: { Ref: 'YourStream' }
        cors:
          origin: '*'
          headers:
            - Content-Type
            - X-Amz-Date
            - Authorization
            - X-Api-Key
            - X-Amz-Security-Token
            - X-Amz-User-Agent
          allowCredentials: false

Configuring the cors property sets Access-Control-Allow-Origin, Access-Control-Allow-Headers, Access-Control-Allow-Methods,Access-Control-Allow-Credentials headers in the CORS preflight response. To enable the Access-Control-Max-Age preflight response header, set the maxAge property in the cors object:

custom:
  apiGatewayServiceProxies:
    - kinesis:
        path: /kinesis
        method: post
        streamName: { Ref: 'YourStream' }
        cors:
          origin: '*'
          maxAge: 86400

If you are using CloudFront or another CDN for your API Gateway, you may want to setup a Cache-Control header to allow for OPTIONS request to be cached to avoid the additional hop.

To enable the Cache-Control header on preflight response, set the cacheControl property in the cors object:

custom:
  apiGatewayServiceProxies:
    - kinesis:
        path: /kinesis
        method: post
        streamName: { Ref: 'YourStream' }
        cors:
          origin: '*'
          headers:
            - Content-Type
            - X-Amz-Date
            - Authorization
            - X-Api-Key
            - X-Amz-Security-Token
            - X-Amz-User-Agent
          allowCredentials: false
          cacheControl: 'max-age=600, s-maxage=600, proxy-revalidate' # Caches on browser and proxy for 10 minutes and doesnt allow proxy to serve out of date content

Adding Authorization

You can pass in any supported authorization type:

custom:
  apiGatewayServiceProxies:
    - sqs:
        path: /sqs
        method: post
        queueName: { 'Fn::GetAtt': ['SQSQueue', 'QueueName'] }
        cors: true

        # optional - defaults to 'NONE'
        authorizationType: 'AWS_IAM' # can be one of ['NONE', 'AWS_IAM', 'CUSTOM', 'COGNITO_USER_POOLS']

        # when using 'CUSTOM' authorization type, one should specify authorizerId
        # authorizerId: { Ref: 'AuthorizerLogicalId' }
        # when using 'COGNITO_USER_POOLS' authorization type, one can specify a list of authorization scopes
        # authorizationScopes: ['scope1','scope2']

resources:
  Resources:
    SQSQueue:
      Type: 'AWS::SQS::Queue'

Source: AWS::ApiGateway::Method docs

Enabling API Token Authentication

You can indicate whether the method requires clients to submit a valid API key using private flag:

custom:
  apiGatewayServiceProxies:
    - sqs:
        path: /sqs
        method: post
        queueName: { 'Fn::GetAtt': ['SQSQueue', 'QueueName'] }
        cors: true
        private: true

resources:
  Resources:
    SQSQueue:
      Type: 'AWS::SQS::Queue'

which is the same syntax used in Serverless framework.

Source: Serverless: Setting API keys for your Rest API

Source: AWS::ApiGateway::Method docs

Using a Custom IAM Role

By default, the plugin will generate a role with the required permissions for each service type that is configured.

You can configure your own role by setting the roleArn attribute:

custom:
  apiGatewayServiceProxies:
    - sqs:
        path: /sqs
        method: post
        queueName: { 'Fn::GetAtt': ['SQSQueue', 'QueueName'] }
        cors: true
        roleArn: # Optional. A default role is created when not configured
          Fn::GetAtt: [CustomS3Role, Arn]

resources:
  Resources:
    SQSQueue:
      Type: 'AWS::SQS::Queue'
    CustomS3Role:
      # Custom Role definition
      Type: 'AWS::IAM::Role'

Customizing API Gateway parameters

The plugin allows one to specify which parameters the API Gateway method accepts.

A common use case is to pass custom data to the integration request:

custom:
  apiGatewayServiceProxies:
    - sqs:
        path: /sqs
        method: post
        queueName: { 'Fn::GetAtt': ['SqsQueue', 'QueueName'] }
        cors: true
        acceptParameters:
          'method.request.header.Custom-Header': true
        requestParameters:
          'integration.request.querystring.MessageAttribute.1.Name': "'custom-Header'"
          'integration.request.querystring.MessageAttribute.1.Value.StringValue': 'method.request.header.Custom-Header'
          'integration.request.querystring.MessageAttribute.1.Value.DataType': "'String'"
resources:
  Resources:
    SqsQueue:
      Type: 'AWS::SQS::Queue'

Any published SQS message will have the Custom-Header value added as a message attribute.

Customizing request body mapping templates

Kinesis

If you'd like to add content types or customize the default templates, you can do so by including your custom API Gateway request mapping template in serverless.yml like so:

# Required for using Fn::Sub
plugins:
  - serverless-cloudformation-sub-variables

custom:
  apiGatewayServiceProxies:
    - kinesis:
        path: /kinesis
        method: post
        streamName: { Ref: 'MyStream' }
        request:
          template:
            text/plain:
              Fn::Sub:
                - |
                  #set($msgBody = $util.parseJson($input.body))
                  #set($msgId = $msgBody.MessageId)
                  {
                      "Data": "$util.base64Encode($input.body)",
                      "PartitionKey": "$msgId",
                      "StreamName": "#{MyStreamArn}"
                  }
                - MyStreamArn:
                    Fn::GetAtt: [MyStream, Arn]

It is important that the mapping template will return a valid application/json string

Source: How to connect SNS to Kinesis for cross-account delivery via API Gateway

SQS

Customizing SQS request templates requires us to force all requests to use an application/x-www-form-urlencoded style body. The plugin sets the Content-Type header to application/x-www-form-urlencoded for you, but API Gateway will still look for the template under the application/json request template type, so that is where you need to configure you request body in serverless.yml:

custom:
  apiGatewayServiceProxies:
    - sqs:
        path: /{version}/event/receiver
        method: post
        queueName: { 'Fn::GetAtt': ['SqsQueue', 'QueueName'] }
        request:
          template:
            application/json: |-
              #set ($body = $util.parseJson($input.body))
              Action=SendMessage##
              &MessageGroupId=$util.urlEncode($body.event_type)##
              &MessageDeduplicationId=$util.urlEncode($body.event_id)##
              &MessageAttribute.1.Name=$util.urlEncode("X-Custom-Signature")##
              &MessageAttribute.1.Value.DataType=String##
              &MessageAttribute.1.Value.StringValue=$util.urlEncode($input.params("X-Custom-Signature"))##
              &MessageBody=$util.urlEncode($input.body)

Note that the ## at the end of each line is an empty comment. In VTL this has the effect of stripping the newline from the end of the line (as it is commented out), which makes API Gateway read all the lines in the template as one line.

Be careful when mixing additional requestParameters into your SQS endpoint as you may overwrite the integration.request.header.Content-Type and stop the request template from being parsed correctly. You may also unintentionally create conflicts between parameters passed using requestParameters and those in your request template. Typically you should only use the request template if you need to manipulate the incoming request body in some way.

Your custom template must also set the Action and MessageBody parameters, as these will not be added for you by the plugin.

When using a custom request body, headers sent by a client will no longer be passed through to the SQS queue (PassthroughBehavior is automatically set to NEVER). You will need to pass through headers sent by the client explicitly in the request body. Also, any custom querystring parameters in the requestParameters array will be ignored. These also need to be added via the custom request body.

SNS

Similar to the Kinesis support, you can customize the default request mapping templates in serverless.yml like so:

# Required for using Fn::Sub
plugins:
  - serverless-cloudformation-sub-variables

custom:
  apiGatewayServiceProxies:
    - kinesis:
        path: /sns
        method: post
        topicName: { 'Fn::GetAtt': ['SNSTopic', 'TopicName'] }
        request:
          template:
            application/json:
              Fn::Sub:
                - "Action=Publish&Message=$util.urlEncode('This is a fixed message')&TopicArn=$util.urlEncode('#{MyTopicArn}')"
                - MyTopicArn: { Ref: MyTopic }

It is important that the mapping template will return a valid application/x-www-form-urlencoded string

Source: Connect AWS API Gateway directly to SNS using a service integration

Custom response body mapping templates

You can customize the response body by providing mapping templates for success, server errors (5xx) and client errors (4xx).

Templates must be in JSON format. If a template isn't provided, the integration response will be returned as-is to the client.

Kinesis Example

custom:
  apiGatewayServiceProxies:
    - kinesis:
        path: /kinesis
        method: post
        streamName: { Ref: 'MyStream' }
        response:
          template:
            success: |
              {
                "success": true
              }
            serverError: |
              {
                "success": false,
                "errorMessage": "Server Error"
              }
            clientError: |
              {
                "success": false,
                "errorMessage": "Client Error"
              }

Author: Serverless-operations
Source Code: https://github.com/serverless-operations/serverless-apigateway-service-proxy 
License: 

#serverless #api #aws 

Einar  Hintz

Einar Hintz

1593235440

Visualizing data with NGX-Charts in Angular

Data Science, Data Analytics, Big Data, these are the buzz words of today’s world. A huge amount of data is being generated and analyzed every day. So communicating the insights from that data becomes crucial. Charts help visualize the data and communicate the result of the analysis with charts, it becomes easy to understand the data.

There are a lot of libraries for angular that can be used to build charts. In this blog, we will look at one such library, NGX-Charts. We will see how to use it in angular and how to build data visualizations.

What we will cover:

  1. Installing ngx-chart.

  2. Building a vertical bar graph.

  3. Building a pie chart.

  4. Building an advanced pie chart.

A brief introduction about NGX-Charts

NGX-Chart charting framework for angular2+. It’s open-source and maintained by Swimlane.

NGX-Charts does not merely wrap d3, nor any other chart engine for that matter. It is using Angular to render and animate the SVG elements with all of its binding and speed goodness and uses d3 for the excellent math functions, scales, axis and shape generators, etc. By having Angular do all of the renderings it opens us up to endless possibilities the Angular platform provides such as AoT, Universal, etc.

NGX-Charts supports various chart types like bar charts, line charts, area charts, pie charts, bubble charts, doughnut charts, gauge charts, heatmap, treemap, and number cards.

Installation and Setup

1. Install the ngx-chart package in your angular app.

npm install @swimlane/ngx-charts --save

2. At the time of installing or when you serve your application is you get an error:

ERROR in The target entry-point "@swimlane/ngx-charts" has missing dependencies: - @angular/cdk/portal

You also need to install angular/cdk

npm install @angular/cdk --save

3. Import NgxChartsModule from ‘ngx-charts’ in AppModule

4. NgxChartModule also requires BrowserAnimationModule. Import is inAppModule.

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { NgxChartsModule }from '@swimlane/ngx-charts';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    NgxChartsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Amazing! Now we can start using ngx-chart component and build the graph we want.

In the AppComponent we will provide data that the chart will represent. It’s a sample data for vehicles on the road survey.

#angular #angular 6 #scala #angular #angular 9 #bar chart #charting #charts #d3 charts #data visualisation #ngx #ngx charts #pie

Mhret Aatifa

Mhret Aatifa

1600376640

Set of components and helpers for building complex and beautifully animated charts

React Native Animated Charts

Set of components and helpers for building complex and beautifully animated charts.

The library was designed to create aesthetic, animated (so far only linear) charts based on a given input. The main assumptions of the library were to create smooth transitions between subsequent data sets. For this reason, we have discovered a shortage of existing libraries related to the charts. The current package was created as part of the Rainbow.me project and for this reason it was not designed as a complete and comprehensive solution for displaying various types of charts. However, we will be now using more charts in the whole application, so we believe that the number of functionalities in the application will gradually grow.

Additionally, we are open to new Pull Requests. We want this library to become popular and complete thanks to community activity.

It’s a part of the Rainbow.me project.

TODO

The library has been released in a production-ready version. We use it inside the Rainbow.me project so it’s verified for use in production. However, it relies on React Native Reanimated 2.0 in the alpha version thus it might not work perfectly. Test it deeply before using it. Until the stable release of Reanimated, I think it’s worth not marking this library as stable. Although the library works with Reanimated without any changes, we faced a few issues related to our (quite advanced) usage of the library. Thus we made some hacks we’re not very proud of and it’s for 99% something you should not do. However, if you see some crashes, you may try one of our hacks.

There’re a few things left to make it polished regarding linear charts:

  • [ ] cleanup API. ChartProvider and ChartPath have been split for two components to separated responsibilities of providing data and displaying charts. I’m still not sure if it’s a good move so we can decide to move some props from one to another or connect them inside one component.
  • [ ] Support for gestures - pinching, swiping, etc.
  • [ ] more parameters regarding interpolation, smoothing, and animations (i.e. allow to override springConfig and timingConfig)

Installation

  1. Install react-native-reanimated in the newest version.
yarn add @rainbow-me/animated-charts
npm i @rainbow-me/animated-charts
  1. If you want to use haptic feedback on the press in / out, install
yarn add react-native-haptic-feedback
npm i react-native-haptic-feedback

The library is verified on 2.0.0-alpha.6 version of reanimated.

Reanimated

Using TurboModules might have an impact on your current development flow and most likely you don’t want to decrease your DX. Since we’re not using reanimated in other places in the app, we made some tweaks to disable charts in development mode with compilation macros on iOS. You can find it here

Also, because we’re using libraries which currently do not support reanimated 2, we patched exports in reanimated

Furthermore, we found few differences in how the Animated module works with and without TurboModules support, so we made a trick to fallback to the not-TM version of Animated.

Most likely, you don’t need any of those patches.

Example app

We made a generic example to show briefly what’s possible to achieve with this library. A Real-life example is available inside Rainbow!

In order to run an example clone this repo and navigate to Example then:

yarn && cd ios && pod install && cd ..
react-native run-android
react-native run-ios

API

The library has been designed to provide as much flexibility as possible with the component-based API for easy integration with existing applications.

Basic API Example

import React from 'react';
import {Dimensions, View} from 'react-native';
import {ChartDot, ChartPath, ChartPathProvider, monotoneCubicInterpolation} from '@rainbow-me/animated-charts';

export const {width: SIZE} = Dimensions.get('window');

export const data = [
  {x: 1453075200, y: 1.47}, {x: 1453161600, y: 1.37},
  {x: 1453248000, y: 1.53}, {x: 1453334400, y: 1.54},
  {x: 1453420800, y: 1.52}, {x: 1453507200, y: 2.03},
  {x: 1453593600, y: 2.10}, {x: 1453680000, y: 2.50},
  {x: 1453766400, y: 2.30}, {x: 1453852800, y: 2.42},
  {x: 1453939200, y: 2.55}, {x: 1454025600, y: 2.41},
  {x: 1454112000, y: 2.43}, {x: 1454198400, y: 2.20},
];

const points = monotoneCubicInterpolation(data)(40);

const BasicExample = () => (
  <View style={{ backgroundColor: 'black' }}>
    <ChartPathProvider data={{ points, smoothingStrategy: 'bezier' }}>
      <ChartPath height={SIZE / 2} stroke="yellow" width={SIZE} />
      <ChartDot style={{ backgroundColor: 'blue' }} />
    </ChartPathProvider>
  </View>
);

The code above generates the chart below:

Linear charts

ChartPathProvider

The whole chart’s structure has to be wrapped with ChartProvider. It’s responsible for data managing and itself does not have a visual impact on the layout. Under the hood, it uses context API to simplify manipulation with other components. The rule is to use one data series for each wrapper.

Prop name type default / obligatory description
softMargin number 0 While scrubbing the chart touching edges of the screen you may want make points on the edges more accessible. With softMargin it’s possible to access points on edges doubling the speed of scrubbing beyond this margin.
enableHaptics boolean false On pressing in/out on the chart it might be expected to make haptic feedback. It will happen with enableHaptics set to true and react-native-haptic-feedback installed
data `{ points: [Point], nativePoints: [Point], smoothingStrategy?: ‘bezier’ ‘simple’ ‘complex’, smoothingFactor }`
springConfig object {damping: 15, mass: 1, stiffness: 600} Object defining the spring animation. This spring is used for a dot’s scale.
timingFeedbackConfig object {duration: 80} Object defining the timing animation. timingFeedbackConfig is used for a path’s opacity and width.
timingAnimationConfig object {duration: 300} Object defining the timing animation. timingAnimationConfig is used for the transition between chart’s data.
  • data is an array containing points to be displayed. A Point is an object containing x and y as a number.
  • nativeData is an array of points that will not be drawn. However, if you used some strategy of interpolating data or simplifying you might want to present data slightly different from the real one. Then if you’d like labels to be fully correct you may want to provide real data before adjusting them.
  • smoothingStrategy. While presenting points path can be drawn with different approaches.
    • If smoothingStrategy is not provided (or set to any other value but for listed here), connects points using linear interpolation.
    • The bezier strategy connects points with a bezier path inspired by d3 shape. It’s not parametrized by smoothingFactor.
    • The complex strategy uses approach explained here using cubic splines. It’s parametrized by smoothingFactor.
    • The simple strategy is a bit simplified complex strategy using quadratic splines. It’s parametrized by smoothingFactor.
  • smoothingFactor. Is a value from 0 to 1 defining how smooth a presentation should be. 0 means no smoothing, and it’s the default. smoothingFactor has an impact if smoothingStrategy is simple or complex.

ChartPath

This component is used for showing the path itself.

Prop name type default / obligatory description
disableSmoothingWhileTransitioning number false Although smoothing is not complex computing, it might impact performance in some low-end devices so while having a big set of data it might be worth disable smoothing while transitioning.
height number obligatory Height od the SVG canvas
width number obligatory Width od the SVG canvas
strokeWidth number 1 Width of the path.
strokeWidthSelected number 1 Width of the path selected.
gestureEnabled boolean true Defines if interaction with the chart should be allowed or not
longPressGestureHandlerProps object {maxDist: 100000, minDurationMs: 0, shouldCancelWhenOutside: false} Under the hood we’re using LongPressGestureHandler for handling interactions. It’s recommended to not override its props. However, it might be useful while interacting with another GH.
selectedOpacity number 0.7 Target opacity of the path while touching the chart.
…rest object {} Props applied to SVG Path.

ChartDot

Component for displaying the dot for scrubbing on the chart.

Prop name type default description
size number 10 Size of the dot.
…props object {} Rest of the props applied to Reanimated.View including style

ChartYLabel&ChartXLabel

Labels are useful while moving finger through the chart to show the exact value in given point.

Prop name type default description
format reanimated worklet a => a Worklet for formatting data from the chart. It can be useful when your data is a timestamp or currency.
…props object {} Rest of the props applied to TextInput including style

Candle Charts

TODO

Pie charts

TODO

Helpers

It’s not essential in the library, but we have decided to include a lot of helpers we are (or we were) using for displaying charts.

Interpolations

We have two interpolators which share the most of the API: bSplineInterpolation and monotoneCubicInterpolation.

import { bSplineInterpolation as interpolator } from '@rainbow-me/animated-charts';
// import { monotoneCubicInterpolation as interpolator } from '@rainbow-me/animated-charts';

const interpolatedData = interpolator(data)(80, true, false);

Code above generates 80 equidistant points from given dataset. Interpolator (monotoneCubicInterpolation or bSplineInterpolation) returns generator. Generator accepts 3 arguments: range, includeExtremes, removePointsSurroundingExtremes.

  • range is the number of points of the output.

  • includeExtremes. If it’s vital to include extremes in the output, set to true. However, the data might not be fully equidistant.

  • removePointsSurroundingExtremes. Makes sense only if includeExtremes set to true. When disabled, it might be possible that extremes look very “pointy”. To get rid of this, you can remove points surrounding extremes. E.g.

    • removePointsSurroundingExtremes = false

      o---------o----Min--o---------o---------o---------o---------o

    • removePointsSurroundingExtremes = true

      o--------------Min------------o---------o---------o---------o

bSplineInterpolation(data, degree = 3)

bSplineInterpolation is inspired by victorian lib and uses B-spline interpolation of a given degree.

monotoneCubicInterpolation(data, degree = 3)

This curve is inspired by d3 shape. "Produces a cubic spline that preserves monotonicity in y, assuming monotonicity in x, as proposed by Steffen in A simple method for monotonic interpolation in one dimension: “a smooth curve with continuous first-order derivatives that passes through any given set of data points without spurious oscillations. Local extrema can occur only at grid points where they are given by the data, but not in between two adjacent grid points.”

simplifyData(data, pickRange = 10, includeExtremes = true)

This helper takes only one point per pickRange. Might be useful for very dense data. If it’s important, it’s possible to include extremes with the includeExtremes flag. E.g.

pickRange = 3, includeExtremes = true

X are equidistant in this case

Y:0          1          7          2         -3          0          1          2
  S----------o----------E----------X----------E----------o----------X----------o----------S

X - points picked because index%3=0

S – the first and the last points are always included.

E – extremes.

Download Details:

Author: rainbow-me

Source Code: https://github.com/rainbow-me/react-native-animated-charts

#react-native #react #mobile-apps