GithubHelp home page GithubHelp logo

aullman / opentok-layout-js Goto Github PK

View Code? Open in Web Editor NEW
128.0 128.0 68.0 59.42 MB

Layout Manager for OpenTok - automatically lays out your Publishers and Subscribers nicely

License: MIT License

JavaScript 70.76% HTML 7.93% TypeScript 21.32%

opentok-layout-js's People

Contributors

anthonyzou avatar aoberoi avatar aullman avatar dependabot[bot] avatar ggarber avatar leahcimic avatar maikthomas avatar sedenardi avatar stuff 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

opentok-layout-js's Issues

Layout Doesn't Work

Hi @aullman. I've played extensively to try to get opentok-layout-js to work like the GIF in the README but have had no luck at all. I'd be happy if you could point out what I could be doing wrong.

First of all, I see this note in the README

This library adds an ot-layout className to elements once they have been layed out.

Now, I don't see any ot-layout class on my elements so this makes me think there's something wrong right off the bat. I can verify I have added the library.

So far my HTML looks something like this:

<div id="layoutContainer">
  <div id="publisherContainer" style="position: absolute; left: 731px; top: 0px; height: 0px;">
    <video autoplay="" id="local-video-undefined"></video>
    <video autoplay="" id=""></video>
  </div>
</div>

And the animation doesn't work. If I move the video element with ID "local-video-undefined" out of the "publisherContainer" div, the animation works but the layout is broken and doesn't fill the screen like in the GIF on the README.

What could I have messed up? Any pointers please?

PS: I'm not using OpenTok. My guess is it doesn't matter as long as I have video elements in a container.

opentok-react styling and demo functionality

Im trying to get the functionality of your demo where I can click a subscriber or publisher and have it become big and have the others go to the right side. I've followed your guidelines to the point where the sub streams will appear in a container. I'm looking at issue #52 for reference. Is there any example code we can see for your demo?

Integration with React Opentok

Hi, im using your library with React Opentok and i have this issue:

Im trying to use the opentok layout but i can't deliver the streams or the layout to my component:

        <div className={classes.streams}>
          <OTStreams>
            <OTSubscriber
              onSubscribe={onSubscribe}
              onError={onSubscribeError}
              eventHandlers={subscriberEventHandlers}
              properties={{
                fitMode: "contain",
              }}
            />
          </OTStreams>
        </div>

Is there anything im missing?.

Thanks for the reply!

Padding, Border, and Margin not taken into account due to camelCase CSS property names

The layout should take into account border, padding and margin as stated in the readme.
However this is not working. It appears to be due to the css properties being in cameCasel e.g. here https://github.com/aullman/opentok-layout-js/blob/master/opentok-layout.js#L691

I wrote this test html page and opened it on a few browsers. None seemed to support these properties in camelCase format.

<html>
  <head>
    <style>
      .my-element {
        border-top: 1px;
        border-bottom: 2px;
        padding-top: 2px;
        margin-top: 3px;
      }
    </style>
  </head>
  <body>
    <div id="myElement" class="my-element">
    </div>
    <script type="text/javascript">
      const myElement = document.getElementById('myElement');
      const computedStyle = getComputedStyle(myElement);
    const checkCssPropName = (propName) => {
      const value = computedStyle.getPropertyValue(propName);
      console.log(`${propName}: ${value}`);
    }

    const propNames = [
      'borderTop',
      'border-top',
      'marginTop',
      'margin-top',
      'paddingTop',
      'padding-top',
    ];
    propNames.forEach(checkCssPropName);
    </script>
  </body>
</html>

Top align elements

Hi. Love this, thanks. Would it be an easy change to top align elements in their container. At the moment they are vertically middle aligned which makes it hard for me to line things up as per design. Thanks!

register on bower registry

do we think this component is ready for distribution on bower? if so, i think it should be on the registry.

subscriber.destroy() depreciated

Thank you for that package it saved us hours of work. We use the streamDestroyed snipped, but always get the following warning in the console:

Subscriber#destroy is deprecated and will be removed. Please use Session#unsubscribe instead +0ms

On the other side session.unsubscribe(subscriber) brings back:

OT.Session.unsubscribe:: tried to unsubscribe a subscriber that had no stream +0ms

Is there anything we do wrong, or do we just not need the destroy() command anymore?

session.on('streamDestroyed', (event) => {
  event.preventDefault();
  session.getSubscribersForStream(event.stream).forEach((subscriber) => {
    subscriber.element.classList.remove('ot-layout');
    setTimeout(() => {
      subscriber.destroy();
      layout();
    }, 200);
  });
});

How do we add a an option like "OT_big" on an other class other than subscribers and publishers?

So I am using the layout library to automatically resize the caller's window. I added the option of maxWidth: Infinity to both the subscribers and the publishers. However, I am adding another element to the main call div, that is, subscribers, publisher, customElement and I want the customElement to get the option of "OT_big" to make the customElement bigger than the other elements. But the issue is, I tried to add the attribute of class="OT_big" to the customElement in my html but the effect does not apply when customElement joins the call. I have to resize my window for it to apply for some reasons. Is there any way to fix it?

npm install fails

I tried installing the library with npm, but it fails during the postinstall gulp step. It failed on both OSX and my Linux box with similar errors.

OSX

npm ERR! Darwin 15.2.0
npm ERR! argv "/usr/local/bin/node" "/usr/local/bin/npm" "i" "opentok-layout-js"
npm ERR! node v4.1.2
npm ERR! npm  v2.14.4
npm ERR! code ELIFECYCLE

npm ERR! [email protected] postinstall: `gulp`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] postinstall script 'gulp'.
npm ERR! This is most likely a problem with the opentok-layout-js package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     gulp
npm ERR! You can get their info via:
npm ERR!     npm owner ls opentok-layout-js
npm ERR! There is likely additional logging output above.

CentOS

error Linux 3.10.0-229.20.1.el7.x86_64
error argv "/usr/local/bin/node" "/usr/local/bin/npm" "i" "opentok-layout-js"
error node v4.2.1
error npm  v2.14.7
error code ELIFECYCLE
error [email protected] postinstall: `gulp`
error Exit status 1
error Failed at the [email protected] postinstall script 'gulp'.
error This is most likely a problem with the opentok-layout-js package,
error not with npm itself.
error Tell the author that this fails on your system:
error     gulp
error You can get their info via:
error     npm owner ls opentok-layout-js
error There is likely additional logging output above.

Padding Around Video Elements

Hello, big fan of this library.

So one thing that is common in mainstream video applications is padding between video elements. See here
image.

One thing that I think could be possible with this library is to have a variable padding option (default 0) that puts this padding on elements to give them a more spaced look.

I would be happy to do the work and put in a PR, I'm just a bit lost when I'm looking at the code. Would it be possible to work with you on this to get the feature merged?

Layout Doesn't Work

Creating a new issue because I can't reopen #89

In response to your comment on #89, I'm calling the layout method when the first video element of the publisher shows up. And for each time a peer join the call also I call the layout method again. No luck.


Hi @aullman. I've played extensively to try to get opentok-layout-js to work like the GIF in the README but have had no luck at all. I'd be happy if you could point out what I could be doing wrong.

First of all, I see this note in the README

This library adds an ot-layout className to elements once they have been layed out.

Now, I don't see any ot-layout class on my elements so this makes me think there's something wrong right off the bat. I can verify I have added the library.

So far my HTML looks something like this:

<div id="layoutContainer">
  <div id="publisherContainer" style="position: absolute; left: 731px; top: 0px; height: 0px;">
    <video autoplay="" id="local-video-undefined"></video>
    <video autoplay="" id=""></video>
  </div>
</div>

And the animation doesn't work. If I move the video element with ID "local-video-undefined" out of the "publisherContainer" div, the animation works but the layout is broken and doesn't fill the screen like in the GIF on the README.

What could I have messed up? Any pointers please?

PS: I'm not using OpenTok. My guess is it doesn't matter as long as I have video elements in a container.

EDIT:

Also I see classes like "OT_bar OT_edge-bar-item OT_mode-auto" in the demo app where are they coming from?

resize technique breaks zoom/crop with opentok.js v2.4.0

since the 2.4.0 update, the layout container's resizing of elements improperly impacts the crop/zoom behavior of publishers/subscribers. examples using the demo page in this repo:

1 publisher (doesn't capture full frame and black bar on right):
screen shot 2015-01-17 at 2 49 31 pm

2 publishers (black bars on bottom):
screen shot 2015-01-17 at 2 49 41 pm

3 publishers (black bars on bottom - all different):
screen shot 2015-01-17 at 2 49 48 pm

middle publisher made big (really weird cropping):
screen shot 2015-01-17 at 2 49 53 pm

sorry about the killer stare face ๐Ÿ˜„

TokBox video not resizing on Firefox?

I'm setting up a browser-based subscriber stream that broadcasts a portrait (1280x720p) stream to the viewer.

i'm using Layout and it properly sizes the video container in Chrome. The container first loads as a square then adopts the correct proportions.

However in Firefox, the container first loads as a squasre, and only resizes after I resize the window. It looks like the first "layout()" call (see code below) is entirely ignored.

I've attached 2 images. One shows the initial loading appearance of the video container (it lasts about .5 seconds) then the correct appearance as it shows on Chrome afterwards.

Here is the code:

session.on('streamCreated', function(event){
                                console.log("Successfully linked to session");
                                session.subscribe(event.stream, 'publisher',{
                                    insertMode: 'append',
                                    height: '100%',
                                    width: '100%'
                                }, function (error){
                                    if (error){
                                        console.log("an error");
                                    }else{
                                        layout();
                                        console.log("we're subscribed");
                                        var resizeTimeout;
                                        window.onresize = function() {
                                            clearTimeout(resizeTimeout);
                                            resizeTimeout = setTimeout(function () {
                                                console.log("Hello Resize");
                                                layout();
                                            }, 20);
                                        };



                                    }

                                });

screen shot 2015-08-07 at 12 13 12 am
screen shot 2015-08-07 at 12 13 17 am

Breaking other libraries with exports object

Initial lines of this library define a global exports property on window:

if (typeof module === 'undefined' || typeof module.exports === 'undefined') {
  exports = window;
} else {
  var window = null;
}

This results in breaking all other libraries that are loaded in the same webpage that does checks for Node environment by the use of exports object: typeof exports === 'object'. Therefore I think that modifying window by adding exports object to it is a bad idea and should be fixed and released as fast as possible.

One solution would be to wrap everything in self invoking function and define local variables, instead of global ones, since this exports object isn't used anywhere other than defining initLayoutContainer on it, and in turn on window.
How would you like it handled?

The "Mute" button flies up when adding a stream

mute-bug
When a new stream is added, the mute control is placed at the bottom of the stream element and begins to move upward with a transition.
Can't reproduce the issue without using a layout library.

Are there any ways to avoid this? Thanks in advance!

opentok-layout-js v4.2.0
Browser: Google chrome for windows, v94.0.4606.61

Resizing Subscriber Streams

Is it not possible to resize subscriber streams? I'm using WebRTC on a browser so viewers can consume a live stream that comes from a mobile app. So the viewers on browser are exclusively subscribers, they don't publish (for now).

Once I define the layout in my CSS, however, the subscriber container never changes size. Is this an implementation problem or a decision on your part not to handle subscriber stream resizing?

#tokbox_layout{
    margin: auto;
    position: relative;
    height: 427px;
    width: 240px;

}

And the layout() javascript call:

var layoutContainer = $("#tokbox_layout").get(0);
    var layout = initLayoutContainer(layoutContainer,{
        fixedRatio: true,
        bigFixedRatio: true
    }).layout;

Best way to rearrange publishers and subscribers on demand

I'd like to use the opentok-layout-js app to rearrange the user displays on demand. Layouts I'd like to provide are:

  • picture in picture (floating)
  • grid
  • split screen horizontally
  • split screen vertically
  • horizontal cover flow (google hangout style)
  • vertical cover flow (google hangout style with vertical participant windows on right side)

Can you point me in the right direction on how to accomplish this efficiently using this library? I'm proofing it out within the opentok-meet app at the moment.

Fixed ratio for only one video

Is it possible to keep the aspect ratio for only one element (fixedRatio: true) but not for the others (fixedRatio: false)?

This would be helpful if someone adds a screen to share with others to show a presentation which shouldn't be cropped. (Maybe a "fixedRatio" class)

Broken in node

You can't require this file in node anymore. You get an error:

ReferenceError: window is not defined
    at Object.<anonymous> (/Users/adamu/src/opentok-layout-js/opentok-layout.js:292:5)

Shown as blocks with fixed width instead of auto resizing

Hello,

It's not working like expected:
809mc-Jo
That is what I see, but I expected this kind of behavior:
gif

Code:

<section id="videos">
	<div id="publish-view"></div>
    <div id="subscribers"></div>
</section>
<script>
let self = this;

const initLayoutContainer = require("opentok-layout-js");
const options = {
    maxRatio: 3 / 2, // The narrowest ratio that will be used (default 2x3)
    minRatio: 9 / 16, // The widest ratio that will be used (default 16x9)
    fixedRatio: false, // If this is true then the aspect ratio of the video is maintained and minRatio and maxRatio are ignored (default false)
    alignItems: "center", // Can be 'start', 'center' or 'end'. Determines where to place items when on a row or column that is not full
    bigClass: "OT_big", // The class to add to elements that should be sized bigger
    bigPercentage: 0.8, // The maximum percentage of space the big ones should take up
    bigFixedRatio: false, // fixedRatio for the big ones
    bigAlignItems: "center", // How to align the big items
    smallAlignItems: "center", // How to align the small row or column of items if there is a big one
    maxWidth: Infinity, // The maximum width of the elements
    maxHeight: Infinity, // The maximum height of the elements
    smallMaxWidth: Infinity, // The maximum width of the small elements
    smallMaxHeight: Infinity, // The maximum height of the small elements
    bigMaxWidth: Infinity, // The maximum width of the big elements
    bigMaxHeight: Infinity, // The maximum height of the big elements
    bigMaxRatio: 3 / 2, // The narrowest ratio to use for the big elements (default 2x3)
    bigMinRatio: 9 / 16, // The widest ratio to use for the big elements (default 16x9)
    bigFirst: true, // Whether to place the big one in the top left (true) or bottom right (false).
    // You can also pass 'column' or 'row' to change whether big is first when you are in a row (bottom) or a column (right) layout
    animate: true, // Whether you want to animate the transitions
    window: window, // Lets you pass in your own window object which should be the same window that the element is in
    ignoreClass: "OT_ignore" // Elements with this class will be ignored and not positioned. This lets you do things like picture-in-picture
};
const layout = initLayoutContainer(
    document.getElementById("videos"),
    options
);
layout.layout();

const OT = require("@opentok/client");
var session = OT.initSession(self.apikey, self.sessionid);

var publisherOptions = {
    insertMode: "append",
    fitMode: "cover"
};
var publisher = OT.initPublisher(
    "publish-view",
    publisherOptions
);
self.current_publisher = publisher;
publisher.on({
    accessDenied: function() {
        alert(
            "Error."
        );
        // window.location.reload();
    }
});
session.connect(self.token, function(error) {
    if (error) {
        console.error("Failed to connect", error);
    } else {
        session.publish(publisher, function(error) {
            if (error) {
                console.error("Failed to publish", error);
            }
        });
    }
});
session.on("streamCreated", function(event) {
    session.subscribe(
        event.stream,
        "subscribers",
        {
            // width: 740,
            // height: 480,
            insertMode: "append",
            fitMode: "cover"
            // style: { nameDisplayMode: "on" }
        },
        function(error) {
            if (error) {
                console.error("Failed to subscribe", error);
            } else {
                if (!self.live) {
                    self.live = true;
                }
            }
        }
    );
});
</script>

<style >
	#videos {
		width: 100%;
    min-height: 400px;
    /* background-color: #DDD; */
    position: relative;
}
.container > * {
		transition - property: all;
    transition-duration: 0.5s;
}
</style>

@aullman

Example without OpenTok

Is there an example on how to use it without OpenTok? Especially which HTML layout does the library expect in order to work properly. I see it mentioned in the README that it is supposed to work without OpenTok but all the code references seem to be expecting OpenTok

Integrate with opentok-react

How can i integrate this package using the opentok-react library also?

I'm generating the streams like this, by using components from Opentok-react.

<OTStreams>
    <OTSubscriber
        ref={this.props.setRef}
        properties={{
            subscribeToAudio: this.props.audio,
            subscribeToVideo: this.props.video,
            style: { buttonDisplayMode: 'off' }
        }}
    />
</OTStreams>

Include containerWidth and containerHeight in readme

Hi @aullman, first of all I want to say thanks for this great library!

Do you think we could include containerWidth and containerHeight as part of the options in readme file?

I'm using this lib together with opentok-react and I was wondering why my layout data is not updated when I call the getLayout() on a dynamic-sized container (I passed in default options) until I found out that there are other options: container width & height (i.e undocumented) with default value of 640px for width and 480px for height.

browserify compatibility

browserify expects you to assign your exports to either properties of the exports object or directly to module.exports. (node style CommonJS)

i think that shouldn't be too difficult, but if for some reason a less invasive approach is desired, you can specify additional metadata to shim the CommonJS compatibility by filling out the values for keys that browserify-shim define.

fixed layout

Hi i am new to tokbox. how to setup fixed one big and rest all small, onclick replace the big with clicked small element and the make the big one is small . I tried to achive the same,but unable to get it done. Please guide me on this. thanks for your wonderful work.

Layout works when window is resized, otherwise sometimes it doesn't

Hi @aullman,

I got the library to work but run into this problem where sometimes when I enter the page with video, the video appears smaller on the top-left part of the window, only upon resizing the window that the video element fills up the screen. Why's that?

These are the options I'm using:


  let opts = {
      maxRatio: 3 / 2,
     minRatio:  9 / 16,
     fixedRatio:  false,
      scaleLastRow: true, 
      maxWidth: Infinity,        // The maximum width of the elements
      maxHeight: Infinity,       // The maximum height of the elements
      smallMaxWidth: Infinity,   // The maximum width of the small elements
      smallMaxHeight: Infinity,  // The maximum height of the small elements
      bigMaxWidth: Infinity,     // The maximum width of the big elements
      bigMaxHeight: Infinity,
      alignItems: 'center', 
      bigClass: 'OT_big',
      smallClass:'OT_small',
      bigPercentage: 0.8,
      bigFixedRatio: false,
      bigMaxRatio: 3 / 2,
      bigMinRatio: 9 / 16,
      bigFirst:  true,
      animate: true
  }

This is how I'm calling "layout". With this I expect that when the page opens with a video it fills the screen immediately.

  let layoutContainer = document.getElementById("layout");
  let layout = initLayoutContainer(layoutContainer, opts).layout;
  layout();
 

  var resizeTimeout;
  window.onresize = function() {
    clearTimeout(resizeTimeout);
    resizeTimeout = setTimeout(function () {
      layout();
    }, 20);
  };

Also, I see classes like "OT_bar OT_edge-bar-item OT_mode-auto" in the demo app where are they coming from? And why don't I see the "ot-layout" class that the library is supposed to add?

Add support for use with Cordova

We have tried to get opentok-layout compatible with Apache Cordova and the use of https://github.com/songz/cordova-plugin-opentok. We successfully made some changes to get this implemented.

What we did:

  • OT.$ variable doesn't exist when using Cordova. We wrapped an if statement around all the places where OT.$ variable is used and replaced it with OT.OTHelper.
  • Cordova plug-in is not getting updated (with the OT.updateViews function). So we added an updateViews function to the function positionElement.

See adjusted file on pastebin: http://pastebin.com/vjF5g5sf

use purpose-built animation library

just trying to keep track of our discussion.

instead of optionally depending on jQuery, which has no good way to be declared via the bower.json, we could actually create a hard dependency on something that is smaller, less likely to collide, and specifically built to do animations.

one such library is the zepto.fx module, and it has the same API as jQuery. the only problem is that its not distributed on bower, and even the "clones" do not expose the fx module (with any of its dependencies) on its own.

i think that for now, we just stick to what we've done, which is do a runtime detection of jQuery and use it to animate. one thing we can do to make it a bit nicer is do a console.warn() if the user specifically requested to animate but jQuery wasn't found.

At some screen sizes 'OT_big' is smaller than regular elements

Hi,

Basically what the title says. Specifically, as the screen width moves into smartphone-size range, elements with the 'OT_big' class get smaller while elements without the class get larger, until at a certain point the 'OT_big' elements actually get smaller than the unadorned elements. This is unexpected behavior, & makes using the class on responsive layout for large screens & mobile devices have opposite effects in those two contexts.

Any ideas on how to fix or work around this?

Thanks for your great work!

scaleLastRow: false still scales the last row

When I set scaleLastRow to false, the last row of videos are still scaled up. Here are my settings:

{
      minRatio: 2 / 3,
      maxRatio: 2 / 3,
      fixedRatio: false,
      scaleLastRow: false,
      bigFirst: false,
      bigFixedRatio: true,
      bigAlignItems: 'top',
}

See attached image for reference to issue.
lastRowStillScaled

Is there any other info I can/need to supply?

Include containerWidth and containerHeight in readme

Hi @aullman, first of all I want to say thanks for this great library!

Do you think we could include containerWidth and containerHeight as part of the options in readme file?

It's undocumented at the moment and I was wondering why my layout data is not updated and turns out I found that it used the default value which is 640px for width and 480px for height.

stack small items below

Hi, be a good feature to add that if bigPercentage = 1 then the small videos align below by default and don't stack on the right. Im not sure if i'm just missing this in the advance settings to force this functionality to work, if i am let me know otherwise i will try and arrange a pr for this feature.

Thanks

VueJS: ('element') to Window.getComputedStyle must be an instance of Element

Hi,

I have OpenTok working with Vue, so it's different to get the DOM-elements. I found out that "window" was the property to change. So I did.:

 var layout = initLayoutContainer(layoutContainer, {
                animate: false,
                window: document.getElementById("subscribers")
            }).layout;

With the HTML:

<div class="flex bg-red-50">
   <div   id="subscribers"></div>
</div>

But I keep getting:

TypeError: Argument 1 ('element') to Window.getComputedStyle must be an instance of Element
getComputedStyle โ€” opentok-layout.js:524
n โ€” opentok-layout.js:524
(anonieme functie) โ€” opentok-layout.js:640
(anonieme functie)
(anonieme functie) โ€” Session.vue:219
o โ€” opentok.js:45097

@aullman @leahciMic

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.