Giter Club home page Giter Club logo

essential-js-design-patterns's Introduction

Built with Grunt Build Status

Learning JavaScript Design Patterns

This is the source code for Learning JavaScript Design Patterns. It is licensed under the Creative Commons Attribution-Non Commercial-Share Alike 3.0 license. I hope you enjoy it, I hope it helps you learn, and I hope you'll support O'Reilly and me by purchasing a print copy of the book at O'Reilly.com.

Design patterns are reusable solutions to commonly occurring problems in software development and are a very useful tool to have at your disposal. You can read the latest version online for free at any time.

Why is this book needed?

I wanted to write this book as I felt that patterns were an area a lot of new and intermediate JavaScript developers may not have had a chance to explore just yet and I'm hopeful my book will encourage you to check them out as they can be quite powerful.

Contributing and Errata

I'm always welcome to feedback on how the book can be improved.

Pull requests

If you would like to help improve the project, please feel free to send over a pull request. Some useful notes:

  • All changes should be made against the master branch.
  • The source of the book is currently in book/index.html.
  • Atomic commits make it easier to review changes. If you can separate changes out in this form, it'll save us time when trying to land.
  • Please review the version of the book online before requesting a change. It is updated more frequently than the physical version of the book but we do bring changes back in every few months.

Building the project

Install dependencies : npm install Build the project: grunt Preview: grunt serve

Additional formats

The project is currently authored in HTML, however we do plan on introducing builds for other formats (PDF, ePub) shortly. In the mean time, official releases for other formats can be obtained via O'Reilly.

Translations

If you would like to get involved with translating this project to another language, please open up a new issue. O'Reilly have a process for handling translations to ensure that they go through the same review process that the English version goes through.

So far, we've successfully had the book translated to Japanese. You can find that version on the O'Reilly Japan site.

License

This book is released under a Creative Commons Attribution-Noncommercial- No Derivative Works 3.0 United States License.

What this means it that the project is free to read and use, but the license does not permit commercial use of the material (i.e you can freely print out the book for your own use, but you can't sell it). I'm trying to best to publish all of my books in a free + purchased (if you would like to support these projects) form so I would greatly appreciate it if you would respect these terms.

Copyright Addy Osmani, 2017.

essential-js-design-patterns's People

Contributors

addyosmani avatar alejandrolechuga avatar calvein avatar chasingmaxwell avatar classicemi avatar comfreek avatar cvbuelow avatar daniel-hug avatar dsbonev avatar eliperelman avatar gchan avatar himanshusingh avatar jugglinmike avatar karlpatrickespiritu avatar msemenistyi avatar neojski avatar nicoder avatar nishant8bits avatar patrickjs avatar pwhisenhunt avatar rmurphey avatar rps avatar samyakbhuta avatar sequoia avatar silvenon avatar svenheden avatar timkg avatar wojciech-lakomy avatar wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww avatar yuyokk 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  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

essential-js-design-patterns's Issues

Decorator Pattern, this.superclass.constructor() and extend()

Addy,

These codes were extracted from your example for abstract decorator. I got confused by this.superclass.constructor() and extend().

I can understand this refers to myMacbookPro, an instance of CaseDecorator here. But what does this.superclass refer? Why not just this.constructor(macbook)?

CaseDecorator's superclass is MacbookDecorator? Where did the inheritance happen? Are they part of native Javascript or an 3rd party library?

Thanks

var CaseDecorator = function( macbook ){

// call the superclass's constructor next
this.superclass.constructor( macbook );

};

// Let's now extend the superclass
extend( CaseDecorator, MacbookDecorator );
....
// Decorate the macbook
myMacbookPro = new CaseDecorator( myMacbookPro );

typo

Chapter MVVM -> Model -> example in knockout.js
After the example sourcecode the name of the function should be "observable()" and not "observables()".

Typo

From twitter: in your book "Learning JavaScript Design Patterns" is a mistake. "Abstract Factories"-> Line: 10 (double return)

PubSub example #4 - subscribe callbacks require event as first argument

Hi,

I believe there is an error in example #4, "Decoupling applications using Ben Alman's pub/sub implementation". Ben Alman's subscribe callbacks require the event object as first argument. His example states this specifically:

// taken from https://gist.github.com/661855
function handle(e, a, b, c) {
// e is the event object, you probably don't care about it.
console.log(a + b + c);
};

The handler functions given in your example lack this first argument:

// taken from http://addyosmani.com/resources/essentialjsdesignpatterns/book/#detailedobserver
$.subscribe( "/new/user", function( userName ){
// ...
});
$.subscribe( "/new/rating", function( movieTitle, userRating ){
// ...
});

When we enter those functions, the first argument gets overwritten by the jQuery event object. It should be:

$.subscribe( "/new/user", function( e, userName ){
// ...
});
$.subscribe( "/new/rating", function( e, movieTitle, userRating ){
// ...
});

Singleton Pattern example error

console.log( badSingleA.getRandomNumber() !== badSingleB.getRandomNumber() ); // true

I know what's meant to be illustrated in this example but actually you can't be sure two random numbers are unequal.

Possible singleton issue

From the blog:

"hello, appreciate that you write the wonderful book , found an error in the example of Singleton Pattern chapter, at the end of the example, i think it should be:
mySingleton.getInstance(); "

Flyweight issue

Hi

I'm reading your book "Learning JavaScript Design Patterns" and I found an error in the code example for the flyweight pattern.

The CoffeFlavorFactory is not working properly because "var flavor = falvors[flavorName];" is always undefined.

Here is a fix proposal:

// FlyweightFactory object
function CoffeeFlavorFactory() {
var flavors = {},
length = 0;

return {
getCoffeeFlavor: function( flavorName ) {

var flavor = flavors[flavorName];
if (flavor === undefined) {
flavor = new CoffeeFlavor( flavorName );
flavors[flavorName] = flavor;
length++;
}
return flavor;
},

getTotalCoffeeFlavorsMade: function() {
return length;
}
};
}

Your original code instantiate 15 CoffeFlavor objects where this one only instantiate 3, which is what is expected.

Anyway, thank you for this amazing helpful book ;)

Best,
Jeremie Patonnier

Typo in 'Mixins' Section

In the first paragraph of this section:

"Prototypes can inherit from other object prototypes but can even more importantly, can define properties for any number of object instances."

Should read:

"Prototypes can inherit from other object prototypes but, even more importantly, can define properties for any number of object instances."

Summary:

  • Remove repeated 'can'
  • add comma after 'but'

Minor tweak to object creation

In JavaScript, the common way of creating new objects (collections of name/values pairs) is by using an object literal var newObject = {};, which is shorthand for the object constructor var newObject = new Object(); (already have all this), but drop the Object.create() which is just confusing in this context.

Also when we talk about it, there's a grammar error: (collections of name/values) pairs - "pairs" should be inside the parens

error in PubSub implementation?

The sample implementation in the chapter "The Observer (Pub/Sub) pattern" starts by defining an empty object literal. Next comes an anonymous function wrapped in parentesis... which never gets executed:

var PubSub = {};

(function(p){
// code...
});

Shouldn't it be:

var PubSub = {};

(function(p){
// code...
})(PubSub);

This way, the anonymous function expands PubSub with the relevant methods.

Small typo

Hey, here's a small type in README:

"I wanted to write this mini-book was because ..."

(redundant "was")

Incorrect sample used for Singleton?

Wikipedia states:

In software engineering, the singleton pattern is a design pattern that restricts the instantiation of a class to one object.

So below code from your book is misleading:

var mySingleton = function () {

    // here are our private methods and variables
    var privateVariable = "something private";

    function showPrivate() {
      console.log( privateVariable );
    }

    // public variables and methods (which can access 
    // private variables and methods )
    return {

      publicMethod: function () {
        showPrivate();
      },

      publicVar: "the public can see this!"

    };
  };

// Usage:

// Create a new singleton
var single = mySingleton();

// Execute our public method which accesses
// a private one. 
// Outputs: "something private"
single.publicMethod(); 

// Outputs: "the public can see this!"
console.log( single.publicVar ); 

With such code you can easily create two instances. For example this code results in unacceptable behavior in singleton pattern:

var single = mySingleton();
var another = mySingleton();

// Outputs: "the public can see this!"
console.log( single.publicVar ); 
// Outputs: "the public can see this!"
console.log( another.publicVar ); 

// this should affect singleton object accessible by both variables
another.publicVar  = 'changed'

// but...
// Outputs: "the public can see this!"
console.log( single.publicVar ); 
// Outputs: "changed"
console.log( another.publicVar ); 

Issue with observer pattern chapter

From the site:

Addy,
First, thank you for writing Learning Javascript Design Patterns, I reference it all the time, and would not understand javascript nearly as well without your publication!

Going through the Observer Pattern today, I noticed an omission in the RemoveAt function:

// Currently Printed Online:

ObserverList.prototype.RemoveAt = function( index ){
if( index === 0 ){
this.observerList.shift();
}else if( index === this.observerList.length -1 ){
this.observerList.pop();
}
};

// Correction

ObserverList.prototype.RemoveAt = function( index ){
if( index === 0 ){
this.observerList.shift();
}else if( index === this.observerList.length -1 ){
this.observerList.pop();
} else {
this.observerList.splice( index, 1 );
};

Thank you again,

Tim

Constructor pattern bug

From the site:

I read your book about design Patterns.

And I think I this fragment:

http://addyosmani.com/resources/essentialjsdesignpatterns/book/#constructorpatternjavascript

Have some little error.

You write the code :

var newObject = {};

var newObject = Object.create( null );

var newObject = new Object();

And the context imply that all these methods provide the same result.

But as the matter of fact the:

  var newObject = Object.create( null ); 

Creates object without Object in prototype chain.

Missing </ol> in "Implementing Classical Flyweights"

The first list in the chapter "Implementing Classical Flyweights" on the website misses a closing tag. That affects everything coming after the list.

The error is not present in the repository, but I still wanted to point this out in case there is an error in the compiler / preprocessor.

Another namespacing pattern recommendation

function ns(str, root) {
  return str.split(".").reduce(function(p, n){return p[n]=p[n]||{}}, root||this)
}

!function(self){
  self.x = 1
}(ns("myApp.util"))

!function(self){
  // dependencies
  var util = ns("myApp.util")

  self.x = util.x + 1
}(ns("myApp.other"))

Minor fixes

From an email:
Since attending the London jQuery Meetup last week I managed to find time to read your js patterns book.

First of all thank you very much for making it freely available. It's really well written and will help many people to improve their js/programming skills.

Secondly I wanted to draw your attention to a couple of small errors I found whilst reading the online version...

  1. You misspelt trivia as trviai...

"A piece of trivia is that the module pattern was originally formally defined by Douglas Crockford (famous for his book 'JavaScript: The Good Parts, and more), although it is likely that variations of this pattern were used long before this. Another piece of trviai is that if you've ever played with Yahoo's YUI library, some of its features may appear quite familiar and the reason for this is that the module pattern was a strong influence for YUI when creating their components."

  1. Something isn't flowing right here. Not sure if the 'in' needs to be removed or if you meant to include some other words.

"The Revealing Module Pattern came about as Heilmann (now at Mozilla) was frustrated with the fact that in you had to repeat the name of the main object when you wanted to call one public method from another or access public variables. He also disliked the Module pattern’s requirement for having to switch to object literal notation for the things you wished to make public."

RMP is very cool by the way, I was already aware of the MP but it is just a little bit cleaner. Not sure I totally grasped the pub/sub code (I was reading on the ipad rather late last night) but I see you have another book/blog post dedicated to that so I guess that is next on the reading list!

Keep up the great work,

C

Some examples can't be tried out

In my opinion, each example should be complete and not use some off-screen code, because I personally find the code a lot harder to understand if I can't try it out. One example is the Interface concept of the Decorator Pattern, where the Interface class is pre-defined.

Update/fix namespacing

We decided on making the following recommendations:

Option 1: var myApplication = myApplication || {};
Option 2 if(!MyApplication) MyApplication = {};
Option 3: var myApplication = myApplication = myApplication || {}
Option 4: myApplication || (myApplication = {});
Option 5: var myApplication = myApplication === undefined ? {} :
myApplication;

myApplication || (myApplication = {}); assumes that myApplication
has been initialized already, so used like this, it’s only useful for
a parameter/argument:

    function foo() {
      myApplication || (myApplication = {});
    }

    foo(); // myApplication hasn’t been initialized, so this throws a
ReferenceError

    function foo(myApplication) {
      myApplication || (myApplication = {});
    }

    foo(); // myApplication === undefined, so no error

If you want to use this pattern elsewhere, you need to make it a
property accessor to avoid the error, e.g. in the global scope:

    window.myApplication || (window.myApplication = {});

As it’s written there 3 is not useful at all. This pattern can be
useful in cases like:

    var myPlugin = $.fn.myPlugin = function() { … };

    // then later, instead of having to type:
    $.fn.myPlugin.defaults = {};
    // you could do:
    myPlugin.defaults = {};
    // this results in better compression (minification) and saves
some scope lookups

suggestion for removeAt() of ObserverList

Hello,

the function removeAt() of ObserverList is only removing entries that are either the first or the last entry in the list.
I think this is not a bug in itself, but for making the example complete it would be good to fix this, so that any entry in the list can be removed as the function name suggests.

BR
Frank

Flyweight Pattern

"Data wise, if we have 30 copies of the same book, we are now only storing it once. Also, every function takes up memory. With the flyweight pattern these functions exist in one place (on the manager) and not on every object, thus saving on memory use."

In the example with Book class above we have its methods defined as conscructor's prototype, so there won't be a function for each instance created and no extra memory consuming.

Book.prototype = {

  getTitle: function () {
     return this.title;
  },

  getAuthor: function () {
     return this.author;
  },

  getISBN: function (){
     return this.ISBN;
  }
...
}

I suggest adding note that memory consumed by function depends on methods implementation.

Dark Theme for Site

I'd love to see a dark option for reading the book here. I've been reading it on my laptop for a while, and I loved how clean the site was. However, it's not simple to create a user style to make the site dark while maintaining the clean appearance (as there are some inline styles on the table rows).

Is this a possibility? If so, I'd be willing to work on it.

var i = 2 under Mixin Pattern?

Mentioned this on Twitter as well, but realised this would be much more convenient.

Under Mixin pattern, the code sample, line 23, shouldn't "var i=0" be "var i=2"?

function augment(receivingClass, givingClass) {
    /* only provide certain methods */
    if (arguments[2]) {
        for (var i=0, len=arguments.length; i<len; i++) {
            receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];
        }
    }
// ...

vs.

function augment(receivingClass, givingClass) {
    /* only provide certain methods */
    if (arguments[2]) {
        for (var i=2, len=arguments.length; i<len; i++) {
            receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];
        }
    }
// ...

Otherwise I think you would be copying the receivingClass and givingClass into the prototype properties, if that would even be possible.

Missing word?

In the Observer Pattern / Implementations section:

Pub/Sub is a design pattern which fits in very well in JavaScript ecosystems, largely because at the core, ECMAScript implements are event driven

Not sure if there is a word missing in the the ECMAScript implements are event driven part as it does not entirely make sense.

Improve ability to reference examples out of the book

  1. Examples are not numbered ( or named). Difficult to communicate with others.
  2. Cannot point to a particular example using hyperlink. Makes it difficult in written communication. Moving examples to Gist and embedding them back in a page looks to be a sane option ? I suppose, this would bring other benefits as well. e.g. people can fork the example gist and do what not.

Example error

I think line 8954: var mod = extend(myApp, "myApp.modules.module2");
should be 8954: var mod = extend(myApp, "modules.module2");

P.S.: Great book, thanks.

question: design pattern to avoid memory leaks

Hi @addyosmani ,

Your design pattern book is awesome. I am working with nodejs and need some advice on scenarios like below:

Lets say i have a function that makes persistent tcp connection to say twitter and does all the parsing on that.
Eg:

function addTwitter(somedata) {

   var twit = new Twitter(somedata);
   twit.on('twit', function(err,data) {
      //do something here
      // use somedata variable here.
   }

}

addTwitter(somehandle);
addTwitter(anotherhandle);

so basically this addTwitter is used to make multiple connections to twitter server.

I am wondering if this style will leak memory. Also, If there is a better way of doing this.

typo

Chapter MVVM -> View -> example in knockout.js

in the HTML

<input id="source" data-bind="value: contactName, valueUpdate: "keyup" /></p>
there should be no " before the word keyup.

Best regards
Frank

Typo in singleton example

The example code for the singleton pattern shows:

/*calling public methods is then as easy as:*/
Singleton.getInstance.publicMethod();

Should be (note addition of parens)

/*calling public methods is then as easy as:*/
Singleton.getInstance().publicMethod();

Typo correction

Select all of the elements in the page and then store references them. => to them

Separate code examples from HTML, suggestions

Would it make sense for you to keep the code examples in separate js files?
It would make it easier to fiddle with each given example.

Gists or jsFiddles would be even better (I'm sure followers would like to help with the transition).

Address official technical reviews

The official technical reviews from O'Reilly have started to come in. So far on the list of suggested changes are:

  • Focus the structure of the book - the greater detail/JS pattern sections should be merged into one. Avoid duplication and people having to flip back and forth.
  • Consider pitching the title as a jQuery patterns book - the reviewer felt that with JavaScript Patterns and Pro JS design patterns already out, it would make more sense to set this apart. It was said to be more focused than the existing titles, but it needs a way of defining this more clearly. My current concern is that it's both JavaScript and jQuery oriented. Does this mean many existing examples need to be rewritten and would this mean the book loses value?
  • Consider including diagrams. The reviewer felt that the lack of diagrams in the title would be a disservice to readers. I'm on the fence about this as no one that's read the book so far has requested diagrams, but will be open to whether this gets done.
  • Improve code style consistency. One example given was that there are three versions of IIFE's in the book. I agree that due to the approach taken to writing the book style consistency could certainly be improved so this will definitely be getting tackled.

Insert function of ObserverList is missing a branch

The current code only inserts the passed object if the index is 0 or the length of list:

ObserverList.prototype.Insert = function( obj, index ){
  var pointer = -1;

  if( index === 0 ){
    this.observerList.unshift( obj );
    pointer = index;
  }else if( index === this.observerList.length ){
    this.observerList.push( obj );
    pointer = index;
  }

  return pointer;
};

missing operator in ObserverList indexOf-function

in the indexOf function of ObserverList in the Observer Pattern chapter the value of i does not get changed inside the while loop.
my guess is that at some point it should make an i++, or we create an infinite loop.

BR
Frank

Constructor pattern issue

From the blog:
I think that in your book about js patterns you have to correct defineProp because config is undefined.It's in The Constructor Pattern.Thanks.

Mediator pattern and Pub/Sub clarifications

I think a better job could be done of explaining the differences between these patterns in the book. I think I've seen you more clearly define them elsewhere but unsure if these have been brought back to EJDP.

This is your implementation of pub/sub

var pubsub = {};

(function(q) {

    var topics = {},
        subUid = -1;

    // Publish or broadcast events of interest
    // with a specific topic name and arguments
    // such as the data to pass along
    q.publish = function( topic, args ) {

        if ( !topics[topic] ) {
            return false;
        }

        var subscribers = topics[topic],
            len = subscribers ? subscribers.length : 0;

        while (len--) {
            subscribers[len].func( topic, args );
        }

        return this;
    };

    // Subscribe to events of interest
    // with a specific topic name and a
    // callback function, to be executed
    // when the topic/event is observed
    q.subscribe = function( topic, func ) {

        if (!topics[topic]) {
            topics[topic] = [];
        }

        var token = ( ++subUid ).toString();
        topics[topic].push({
            token: token,
            func: func
        });
        return token;
    };

    // Unsubscribe from a specific
    // topic, based on a tokenized reference
    // to the subscription
    q.unsubscribe = function( token ) {
        for ( var m in topics ) {
            if ( topics[m] ) {
                for ( var i = 0, j = topics[m].length; i < j; i++ ) {
                    if ( topics[m][i].token === token) {
                        topics[m].splice( i, 1 );
                        return token;
                    }
                }
            }
        }
        return this;
    };
}( pubsub ));

Here goes mediator:

var mediator = (function(){

    // Storage for topics that can be broadcast or listened to
    var topics = {};

    // Subscribe to a topic, supply a callback to be executed
    // when that topic is broadcast to
    var subscribe = function( topic, fn ){

        if ( !topics[topic] ){ 
          topics[topic] = [];
        }

        topics[topic].push( { context: this, callback: fn } );

        return this;
    };

    // Publish/broadcast an event to the rest of the application
    var publish = function( topic ){

        var args;

        if ( !topics[topic] ){
          return false;
        } 

        args = Array.prototype.slice.call( arguments, 1 );
        for ( var i = 0, l = topics[topic].length; i < l; i++ ) {

            var subscription = topics[topic][i];
            subscription.callback.apply( subscription.context, args );
        }
        return this;
    };

    return {
        Publish: publish,
        Subscribe: subscribe,
        installTo: function( obj ){
            obj.subscribe = subscribe;
            obj.publish = publish;
        }
    };

}());

They are identical. In fact they both look exactly like correct pub/sub pattern.
Mediator pattern if I understand correctly works as follows:

  • mediator knows all components - components may inform mediator about it's existence during creation - this is preferred way.
  • components informs mediator
  • mediator decides what to do - it decides which components need updates and in what form.

In other words - pub/sub is not adequate here. We don't wont components to subscribe. They don't decide in this strategy. They should only inform mediator about information from their scope. They also should expose some api - mediator uses this api to control components.

Namespacing Fundamentals TOC is missing an entry

The Namespacing Fundamentals TOC is missing an entry. The TOC currently reads:

  1. Single global variables
  2. Object literal notation
  3. Nested namespacing
  4. Immediately-invoked Function Expressions
  5. Namespace injection

But the actual subsections are as follows:

  1. Single global variables
  2. Prefix namespacing
  3. Object literal notation
  4. Nested namespacing
  5. Immediately-invoked Function Expressions
  6. Namespace injection

typo

Chapter on Mediator Pattern, the example "chatForm" has an semicolon instead of a comma inside a var statement.

line 06: from = $( "#fromBox" ).val();

Therefore the statement that follows will make the variable "to" implicit global.

br
Frank

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.