Code Monkey home page Code Monkey logo

comet's Introduction

Comet

Comet is a modern PHP framework for building blazing fast REST APIs, CRUDs, admin panels and microservices.

What's new in Comet v2

  • Performance improvments - up to 20-30% faster than first version!
  • Embedded secure web-server to serve static content like images, CSS styles and JS scripts
  • Extended session support for complex authentication and authorizathion services
  • Hassle-free out-of-the-box integration with full-featured Auth library

Superpowers at your disposal

  • Blazing fast with 100K HTTP requests per second and ~0.1 ms latency on commodity cloud hardware
  • Really cross-platform, works like a charm on Linux, MacOS and Windows 7/10
  • Embedded web-server to serve static content like CSS/JS and images
  • Integration with full-featured auth library Comet\Auth for users management
  • Embedded validation and testing features you could use with easy to create robust software
  • Based on bullet-proof components from Guzzle, SlimPHP and Workerman
  • Extendable with Composer: use ORM and templating engine of your choice (Eloquent and Twig are recommended)
  • PSR compliant with native implementations of all PSR-7 interfaces and PHP sessions abstraction
  • Has its own efficient HTTP client with simple programming interface

Standing on the shoulders of giants

Comet combines all superpowers of Slim PHP, Guzzle and Workerman and mix its own magic to achieve 10x speed up.

Slim is a micro-framework that helps write web applications and APIs based on modern PSR standards.

Guzzle is a set of PHP components to work with HTTP/1.1 and HTTP/2 services.

Workerman is an asynchronous event-driven framework to build fast and scalable network applications.

Comet allows you natively use all the classes and methods of Slim framework: http://www.slimframework.com/docs/v4/

Performance

PHP is often criticized for its low throughput and high latency. But that is not necessarily true for modern frameworks. Let's see how Comet outperforms others.

Benchmarking stripped versions of frameworks with no ORM under 1,000 concurrent connections

As you can see, the right architecture provides it with tenfold advantage over Symfony and other popular frameworks.

Latency

How long it takes to get response from API often is even more important than overall service throughput. And that is where Comet really shines!

Response latency of minimal versions of popular PHP frameworks under series of serial web requests

Comet provides sub-millisecond latency for typical scenarios. Even under hard pressure of thousand concurrent connections it can compete with frameworks of compiled platforms like Go and Java.

Too good to be true?

You may run all benchmarks on your own to be sure charts are not scam: https://github.com/gotzmann/benchmarks

Basics

Installation

It is recommended that you use Composer to install Comet.

$ composer require gotzmann/comet

This will install framework itself and all required dependencies. Comet requires PHP 7.2 or newer.

Hello Comet

Create single app.php file at project root folder with content:

<?php
require_once __DIR__ . '/vendor/autoload.php';

$app = new Comet\Comet();

$app->get('/hello', 
    function ($request, $response) {              
        return $response
            ->with("Hello, Comet!");
});

$app->run();

Start it from command line:

$ php app.php start

Then open browser and type in default address http://localhost - you'll see hello from Comet!

Simple JSON Response

Let's start Comet server listening on custom host:port and returning JSON payload.

<?php
require_once __DIR__ . '/vendor/autoload.php';

$app = new Comet\Comet([
    'host' => '127.0.0.1',
    'port' => 8080,
]);

$app->get('/json', 
    function ($request, $response) {        
        $data = [ "message" => "Hello, Comet!" ];
        return $response
            ->with($data);
});

$app->run();

Start browser or Postman and see the JSON resonse from GET http://127.0.0.1:8080

Authorization, authentication, ACL and users management

There special full featured Comet/Auth library which allows you to create secure and sofisticated scenarios for user registration, email checking, password management, role-based access and so on.

Please refer for the corresponging documentation on how to use Comet\Auth in your own projects.

Validation

Comet validation engine is based on clean yet powerful Rakit Validation library.

To start using Comet Validation in your own project, specify use statement:

use Comet\Validator;

You can use different predefined and user-defined rules, custom error messages and controller logic to deal with errors. Look at this example:

$payload = (string) $request->getBody();

// Prior to 7.3 PHP does not support RFC3339_EXTENDED (milliseconds are broken)
$version = explode('.', PHP_VERSION);
$dateFormat = ($version[0] == 7 && $version[1] >= 3) ? \DateTime::RFC3339_EXTENDED : "Y-m-d?H:i:s.???P";

$rules = [
    'paymentOrderId' => 'required',
    'customerId'     => 'required|uuid',
    'clientKey'      => 'required|alpha_dash',
    'paymentDate'    => 'required|date:' . $dateFormat,
];

$messages = [
    'required'   => 'field is required',
    'alpha_num'  => 'only alphabet and digits allowed',
    'alpha_dash' => 'only alphabet chars, digits and dashes are allowed',
    'uuid'       => 'UUID is wrong',
    'date'       => 'should be RFC3339 date',
];        

$validator = new Validator;
$validation = $validator->validate($payload, $rules, $messages);        
if (count($validation->getErrors())) {
    return $response
        ->with($validation->getErrors(), 400);
}        

Please refer to the docs about Rakit Validation for more information on available rules and possibilities.

Advanced Topics

PSR-4 and Autoloading

Before you proceed with complex examples, be sure that your composer.json contains "autoload" section like this:

{
    "require": {
        "gotzmann/comet": "^1.0",
    },
    "autoload": {
        "psr-4": { "App\\": "src/" }
    }
}

If not, you should add the section mentioned above and update all vendor packages and autoload logic by command:

$ composer update

Controllers

Create src/Controllers/SimpleController.php:

<?php
declare(strict_types=1);

namespace App\Controllers;

use Comet\Request;
use Comet\Response;

class SimpleController
{    
    private static $counter = 0;

    public function getCounter(Request $request, Response $response, $args)
    {
        $response->getBody()->write(self::$counter);  
        return $response->withStatus(200);
    }

    public function setCounter(Request $request, Response $response, $args)    
    {        
        $body = (string) $request->getBody();
        $json = json_decode($body);
        if (!$json) {
            return $response->withStatus(500);
        }  
        self::$counter = $json->counter;
        return $response;        
    }
}  

Then create Comet server app.php at project root folder:

<?php
declare(strict_types=1);

use Comet\Comet;
use App\Controllers\SimpleController;

require_once __DIR__ . '/vendor/autoload.php';

$app = new Comet([
    'host' => 'localhost',
    'port' => 8080,    
]);

$app->setBasePath("/api/v1"); 

$app->get('/counter',
    'App\Controllers\SimpleController:getCounter');

$app->post('/counter',    
    'App\Controllers\SimpleController:setCounter');

$app->run();

Now you are ready to get counter value with API GET endpoint. And pay attention to '/api/v1' prefix of URL:

GET http://localhost:8080/api/v1/counter

You can change counter sending JSON request for POST method:

POST http://localhost:8080/api/v1/counter with body { "counter": 100 } and 'application/json' header.

Any call with malformed body will be replied with HTTP 500 code, as defined in controller.

Deployment

Debugging and Logging

Comet allows you to debug application showing errors and warnings on the screen console. When you move service to the production it better to use file logs instead. Code snippet below shows you how to enable on-the-screen debug and logging with popular Monolog library:

<?php
declare(strict_types=1);

use Comet\Comet;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Formatter\LineFormatter;

require_once __DIR__ . '/vendor/autoload.php';

$formatter = new LineFormatter("\n%datetime% >> %channel%:%level_name% >> %message%", "Y-m-d H:i:s");
$stream = new StreamHandler(__DIR__ . '/log/app.log', Logger::INFO);
$stream->setFormatter($formatter);
$logger = new Logger('app');
$logger->pushHandler($stream);

$app = new Comet([
    'debug' => true,
    'logger' => $logger,
]);

$app->run();

Docker

Please see Dockerfile at this repo as starting point for creating your own app images and containers.

Nginx

If you would like to use Nginx as reverse proxy or load balancer for your Comet app, insert into nginx.conf these lines:

http {
 
    upstream app {
        server http://path.to.your.app:port;
    }
  
    server {
        listen 80;
         location / {
            proxy_pass         http://app;
            proxy_redirect     off;
        }
    }
}    

FAQ

Got error stream_socket_server(): unable to connect to tcp://0.0.0.0:80 (Permission denied) trying to start Comet under my Ubuntu?

Comet needs to be run as root in order to bind to port 80 or any other port lower than 1000. So either start with sudo or just use port like 8080.

comet's People

Contributors

gotzmann avatar wedrix avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

comet's Issues

Database and Middleware example

Thanks for your framework. I try to use this, but i have a couple of questions.

  1. Can you add some example for Slim Middleware integration?
  • JWT
  • Rate Limit
  1. Explain an example the correct way to mysql connect with illuminate/database

Problem with example controller

There is another closed issue on this but I think I see the same thing:

Using SimpleController.php exactly as in the readme, I get this on the GET request:
GET http://10.1.2.23:8080/api/v1/counter
Returns 500
Log from the web server says:

[ERR] /home/wordgame/webtest/vendor/gotzmann/comet/src/Stream.php:250 >> fwrite(): Argument #2 ($data) must be of type string, int given

I'm not sure exactly what I'm supposed to do with that.

Using the earlier example this doesn't happen. Also, the POST from the controller works fine too.
$app->get('/json',
function ($request, $response) {
$data = [ "message" => "Hello, Comet!" ];
return $response
->with($data);
}); ----works

Логирование в Comet

При создании экземпляра Comet я определяю логгер:

// ...
$logger = new Logger('comet');
$logger->pushHandler($stream);

$app = new Comet([
    'host' => $_ENV['COMET_HOST'],
    'port' => $_ENV['COMET_PORT'],
    'logger' => $logger,
]);

Я могу писать лог вручную, обратившись к логгеру напрямую:

$logger->error(...);

Как мне получить доступ к логгеру, скажем, из контроллера или из любого другого контекста??

class EventController {
    /**
     * @param Comet\Request $request
     * @param Comet\Response $response
     * @param array $args
     * @return Comet\Response
     */
    public function create(Request $request, Response $response, array $args): Response {
        // Экземпляр логгера тут??
    }

    // ...
}

unserialize(): Error in Session.php

Hello,

I'm testing the simple "Hello Comet" example in my local machine using EasyPHP-Devserver running PHP 7.2.24.

When I run "php app.php start", I get this error message:

PHP Notice: unserialize(): Error at offset 0 of 143 bytes in C:\Program Files (x86)\EasyPHP-Devserver-17\eds-www\comet\vendor\gotzmann\comet\src\Session.php on line 97

Any idea what I'm doing wrong?

Deploy comet on Heroku get error

Trying deploy comet on heroku but unsuccessfully display hello message, using Procfile worker: php app.php start
and get 404:

2021-09-19T01:11:42.728966+00:00 heroku[web.1]: State changed from crashed to starting
2021-09-19T01:11:43.678266+00:00 heroku[web.1]: Starting process with command heroku-php-apache2
2021-09-19T01:11:46.240735+00:00 app[web.1]: Detected 536870912 Bytes of RAM
2021-09-19T01:11:46.270256+00:00 app[web.1]: PHP memory_limit is 128M Bytes
2021-09-19T01:11:46.276889+00:00 app[web.1]: Starting php-fpm with 4 workers...
2021-09-19T01:11:46.341334+00:00 app[web.1]: Starting httpd...
2021-09-19T01:11:46.943079+00:00 heroku[web.1]: State changed from starting to up
2021-09-19T01:12:10.831225+00:00 heroku[router]: at=info method=GET path="/hello" host=immense-peak-00785.herokuapp.com request_id=3c6b4bb7-d72e-4765-a11c-a15c3e66e5c6 fwd="175.158.38.125" dyno=web.1 connect=0ms service=1ms status=404 bytes=360 protocol=https
2021-09-19T01:12:10.832719+00:00 app[web.1]: 10.1.22.86 - - [19/Sep/2021:01:12:10 +0000] "GET /hello HTTP/1.1" 404 196 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36

and then using Procfile:
web: php app.php start
given error

2021-09-19T01:04:55.618066+00:00 heroku[web.1]: State changed from crashed to starting
2021-09-19T01:04:56.566507+00:00 heroku[web.1]: Starting process with command php app.php start
2021-09-19T01:04:57.539709+00:00 app[web.1]: Comet v2.0.1 [32 workers] ready on http://0.0.0.0:80
2021-09-19T01:04:57.541251+00:00 app[web.1]: Workerman[app.php] start in DEBUG mode
2021-09-19T01:04:57.541784+00:00 app[web.1]: stream_socket_server(): unable to connect to tcp://0.0.0.0:80 (Permission denied) in file /app/vendor/workerman/workerman/Worker.php on line 2255
2021-09-19T01:04:57.541825+00:00 app[web.1]: PHP Fatal error: Uncaught Exception: Permission denied in /app/vendor/workerman/workerman/Worker.php:2257
2021-09-19T01:04:57.541826+00:00 app[web.1]: Stack trace:
2021-09-19T01:04:57.541826+00:00 app[web.1]: #0 /app/vendor/workerman/workerman/Worker.php(679): Workerman\Worker->listen()
2021-09-19T01:04:57.541827+00:00 app[web.1]: #1 /app/vendor/workerman/workerman/Worker.php(538): Workerman\Worker::initWorkers()
2021-09-19T01:04:57.541827+00:00 app[web.1]: #2 /app/vendor/gotzmann/comet/src/Comet.php(358): Workerman\Worker::runAll()
2021-09-19T01:04:57.541827+00:00 app[web.1]: #3 /app/app.php(45): Comet\Comet->run()
2021-09-19T01:04:57.541828+00:00 app[web.1]: #4 {main}
2021-09-19T01:04:57.541828+00:00 app[web.1]: thrown in /app/vendor/workerman/workerman/Worker.php on line 2257
2021-09-19T01:04:57.541830+00:00 app[web.1]:
2021-09-19T01:04:57.541830+00:00 app[web.1]: Fatal error: Uncaught Exception: Permission denied in /app/vendor/workerman/workerman/Worker.php:2257
2021-09-19T01:04:57.541830+00:00 app[web.1]: Stack trace:
2021-09-19T01:04:57.541831+00:00 app[web.1]: #0 /app/vendor/workerman/workerman/Worker.php(679): Workerman\Worker->listen()
2021-09-19T01:04:57.541831+00:00 app[web.1]: #1 /app/vendor/workerman/workerman/Worker.php(538): Workerman\Worker::initWorkers()
2021-09-19T01:04:57.541831+00:00 app[web.1]: #2 /app/vendor/gotzmann/comet/src/Comet.php(358): Workerman\Worker::runAll()
2021-09-19T01:04:57.541832+00:00 app[web.1]: #3 /app/app.php(45): Comet\Comet->run()
2021-09-19T01:04:57.541832+00:00 app[web.1]: #4 {main}
2021-09-19T01:04:57.541832+00:00 app[web.1]: thrown in /app/vendor/workerman/workerman/Worker.php on line 2257
2021-09-19T01:04:57.665303+00:00 heroku[web.1]: Process exited with status 255
2021-09-19T01:04:57.746373+00:00 heroku[web.1]: State changed from starting to crashed
2021-09-19T01:05:19.214768+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/hello" host=immense-peak-00785.herokuapp.com request_id=c052d808-12e9-48d1-8048-30c42a513294 fwd="175.158.38.125" dyno= connect= service= status=503 bytes= protocol=https`

проблема с Workerman

что бы это могло значить?
права -rw-rw-r-- Worker.php

Fatal error: Uncaught Exception: Permission denied in public_html/comet.api/vendor/workerman/workerman/Worker.php:2235
Stack trace:
#0 public_html/comet.api/vendor/workerman/workerman/Worker.php(1524): Workerman\Worker->listen()
#1 public_html/comet.api/vendor/workerman/workerman/Worker.php(1371): Workerman\Worker::forkOneWorkerForLinux()
#2 public_html/comet.api/vendor/workerman/workerman/Worker.php(1345): Workerman\Worker::forkWorkersForLinux()
#3 public_html/comet.api/vendor/workerman/workerman/Worker.php(1675): Workerman\Worker::forkWorkers()
#4 public_html/comet.api/vendor/workerman/workerman/Worker.php(1624): Workerman\Worker::monitorWorkersForLinux()
#5 public_html/comet.api/vendor/workerman/workerman/Worker.php(548): Workerman\Worker::monitorWorkers()
#6 public_html/comet.api/vendor/got in public_html/comet.api/vendor/workerman/workerman/Worker.php on line 2235
worker[Comet v0.3.2:14356] exit with status 65280
worker[Comet v0.3.2:14357] exit with status 65280
worker[Comet v0.3.2:14359] exit with status 65280
Workerman[app.php] has been stopped

Wrong sample: Expecting string in sample code, but int given

I have tried to launch controller sample and caught that error:
.....\vendor\gotzmann\comet\src\Stream.php:250 >> fwrite(): Argument #2 ($data) must be of type string, int given

It's very dumb, cause the exception accurs because of that line from sample:
$response->getBody()->write(self::$counter);
And can be solved by:
$response->getBody()->write((string)self::$counter);

Comet вместе с Laravel 8 одном проекте

У Laravel в цепочке зависимостей guzzlehttp/psr7 v2.0, а у Comet — guzzlehttp/psr7 v1.7, что не дает установить Comet без дополнительных манипуляций и понижения версии guzzlehttp/psr7.

500 error with controller example

First, i tried my own controller test, but i was getting a "1" for html source code, but no errors shown in terminal or log (and log successfully logs startup , so it's working). Now, i'm trying the comet controller example, as it's written, and i'm still getting a "1" with no errors logged. When i use curl, it reports a 500 server error.

thanks

Sample to for Real World App

Would you please add any sample to show some real world REST sample like

SSL
MySQL db access
JWT Token auth
Caching
file uploads

Or we need to use barebone Workerman for this

Problems with php 8.1

Deprecated: str_replace(): Passing null to parameter #3 ($subject) of type array|string is deprecated in /comet/vendor/workerman/workerman/Protocols/Http/Request.php on line 166

Possibly it's a problem from workerman, but workerman and other frameworks using it are working.
Could you check it.

Thank you

Comet cannot run

Hi

I have successfully setup comet up beforehand, but when I tried to setup a new project today, I get the following error:

PHP Fatal error:  Type of Comet\Factory\CometPsr17Factory::$responseFactoryClass must be string (as in class Slim\Factory\Psr17\Psr17Factory) in ../vendor/gotzmann/comet/src/Factory/CometPsr17Factory.php on line 6

I have tried various versions of PHP (7.4, 8.0, and 8.1), as well as various versions of Comet, alas, I still get the exact same error. What am I missing?

Simple Hello world app example?

Здравствуйте! Можете скинуть базовый пример приложения Hello world на вашем фреймворке c подключением к БД MySQL?

Several GuzzleHttp classes not imported into Request

When we try to build request from globals:

Request::fromGlobals();

We are going to get few errors:
/var/www/html/vendor/gotzmann/comet/src/Request.php:176 >> Class 'Comet\ServerRequest' not found

It seems this imports are missing:

use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Stream\CachingStream;
use GuzzleHttp\Stream\LazyOpenStream;
use GuzzleHttp\Psr7\ServerRequest;

Parsing body with NULL result if http header content-type is 'application/json; charset=utf-8'

Hello!

If Http header "content-type" is 'application/json; charset=utf-8', then getParsedBody() returns NULL, because in class Request this line:

if ($headers['content-type'] == 'application/json') {
                $this->parsedBody = json_decode($request->rawBody(), true);
} 

maybe replace to:

if (strstr($headers['content-type'], 'application/json')) {
                $this->parsedBody = json_decode($request->rawBody(), true);
}

How to get the client's IP

I tried to add RKA\Middleware\IpAddress and get the client's IP, but it doesn't work.
$_SERVER['REMOTE_ADDR'] also doesn't work. How to fix this?

Call to undefined function pcntl_signal() MacOS

MacOS

$ php app.php start
sh: nproc: command not found
Comet v2.2.0 [0 workers] ready on http://127.0.0.1:9876
Workerman[app.php] start in DEBUG mode

Fatal error: Uncaught Error: Call to undefined function pcntl_signal() in /Users/Desktop/backend/vendor/workerman/workerman/Worker.php:1118
Stack trace:
#0 /Users/Desktop/backend/vendor/workerman/workerman/Worker.php(539): Workerman\Worker::installSignal()
#1 /Users/Desktop/backend/vendor/gotzmann/comet/src/Comet.php(358): Workerman\Worker::runAll()
#2 /Users/Desktop/backend/app.php(16): Comet\Comet->run()
#3 {main}
  thrown in /Users/Desktop/backend/vendor/workerman/workerman/Worker.php on line 1118

On pure MacOS. php -v:
PHP 7.3.24-(to be removed in future macOS) (cli) (built: Dec 21 2020 21:33:25) ( NTS )

i think we shoulda paste guide to install php-pcntl on installing topic

E_COMPILE_ERROR Declaration of Comet\Request::getServerParams()

OS: Debian 12
PHP: 8.3
Comet version: v2.4.4

I use example code:

<?php
require_once __DIR__ . '/vendor/autoload.php';

$app = new Comet\Comet([
    'host' => '10.0.0.7',
    'port' => 8041,
]);

$app->get('/json',
    function ($request, $response) {
        $data = [ "message" => "Hello, Comet!" ];
        return $response
            ->with($data);
});

$app->run();

and receive this error:

php app.php start
Comet v2.4.4 [8 workers] ready on http://10.0.0.7:8041
Workerman[app.php] start in DEBUG mode
PHP Fatal error:  Declaration of Comet\Request::getServerParams() must be compatible with Psr\Http\Message\ServerRequestInterface::getServerParams(): array in /home/user/api/vendor/gotzmann/comet/src/Request.php on line 266
Worker[191114] process terminated with ERROR: E_COMPILE_ERROR "Declaration of Comet\Request::getServerParams() must be compatible with Psr\Http\Message\ServerRequestInterface::getServerParams(): array in /home/user/api/vendor/gotzmann/comet/src/Request.php on line 266"
worker[Comet v2.4.4:191114] exit with status 65280

Lite version of comet

А можно как-нибудь порезать comet от всякой говны чтобы оставить только библиотеку роутера + авторизацию? Очень бы не хотелось тащить всякий мусор из зависимостей, плюс есть уже свои.
Тем более хотелось бы разворачивать comet на сервере непосредственно, а не как отдельное приложение.

проблема с SimpleController

В примере с контроллером после вызова страницы http://**:/api/v1/counter появляется такая ошибка

public_html/comet.api>php app.php start


Server Listen Workers Status

Workerman[app.php] start in DEBUG mode
Callable Controllers\SimpleController does not exist^CWorkerman[app.php] stopping ...
Workerman[app.php] has been stopped

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.