Giter VIP home page Giter VIP logo

leaflet-sidebar-v2's Introduction

leaflet-sidebar-v2

A responsive sidebar for Leaflet. A fork of sidebar-v2 that only contains the necessary ingredients for use in Leaflet and provides enhanced functionality.

Demo

Hint: There's a Angular wrapper available at https://github.com/runette/ngx-leaflet-sidebar

Why the Fork?

  • JS API for panel modification
  • "autopan" feature, moving the map content next to the sidebar content
  • only supports leaflet (0.x and 1.x) to maintain a smaller codebase and support more features
  • compatibility with bootstrap (no generic .sidebar class)
  • provide a npm package leaflet-sidebar-v2 with main and style fields in package.json

Examples

in examples folder, available live at https://noerw.github.io/leaflet-sidebar-v2/examples

Usage

API

leaflet-sidebar-v2 provides a simple API to dynamically modify the sidebar. All functions may be chained.

creation

The parameters object is fully optional. The default values are shown:

var sidebar = L.control.sidebar({
    autopan: false,       // whether to maintain the centered map point when opening the sidebar
    closeButton: true,    // whether t add a close button to the panes
    container: 'sidebar', // the DOM container or #ID of a predefined sidebar container that should be used
    position: 'left',     // left or right
}).addTo(map);

modification

/* add a new panel */
var panelContent = {
    id: 'userinfo',                     // UID, used to access the panel
    tab: '<i class="fa fa-gear"></i>',  // content can be passed as HTML string,
    pane: someDomNode.innerHTML,        // DOM elements can be passed, too
    title: 'Your Profile',              // an optional pane header
    position: 'bottom'                  // optional vertical alignment, defaults to 'top'
};
sidebar.addPanel(panelContent);

/* add an external link */
sidebar.addPanel({
    id: 'ghlink',
    tab: '<i class="fa fa-github"></i>',
    button: 'https://github.com/noerw/leaflet-sidebar-v2',
});

/* add a button with click listener */
sidebar.addPanel({
    id: 'click',
    tab: '<i class="fa fa-info"></i>',
    button: function (event) { console.log(event); }
});

/* remove a panel */
sidebar.removePanel('userinfo');

/* en- / disable a panel */
sidebar.disablePanel('userinfo');
sidebar.enablePanel('userinfo');

open / close / show content

/* open a panel */
sidebar.open('userinfo');

/* close the sidebar */
sidebar.close();

remove sidebar

/* remove the sidebar (keeping the sidebar container) */
sidebar.remove();
sidebar.removeFrom(map); // leaflet 0.x

/* to clear the sidebar state, remove the container reference */
sidebar._container = null

markup

If you use the sidebar with static content only, you can predefine content in HTML:

<div id="sidebar" class="leaflet-sidebar collapsed">
    <!-- Nav tabs -->
    <div class="leaflet-sidebar-tabs">
        <ul role="tablist"> <!-- top aligned tabs -->
            <li><a href="#home" role="tab"><i class="fa fa-bars"></i></a></li>
            <li class="disabled"><a href="#messages" role="tab"><i class="fa fa-envelope"></i></a></li>
            <li><a href="#profile" role="tab"><i class="fa fa-user"></i></a></li>
        </ul>

        <ul role="tablist"> <!-- bottom aligned tabs -->
            <li><a href="#settings" role="tab"><i class="fa fa-gear"></i></a></li>
        </ul>
    </div>

    <!-- Tab panes -->
    <div class="leaflet-sidebar-content">
        <div class="leaflet-sidebar-pane" id="home">
            <h1 class="leaflet-sidebar-header">
                sidebar-v2
                <div class="leaflet-sidebar-close"><i class="fa fa-caret-left"></i></div>
            </h1>
            <p>A responsive sidebar for mapping libraries</p>
        </div>

        <div class="leaflet-sidebar-pane" id="messages">
            <h1 class="leaflet-sidebar-header">Messages<div class="leaflet-sidebar-close"><i class="fa fa-caret-left"></i></div></h1>
        </div>

        <div class="leaflet-sidebar-pane" id="profile">
            <h1 class="leaflet-sidebar-header">Profile<div class="leaflet-sidebar-close"><i class="fa fa-caret-left"></i></div></h1>
        </div>
    </div>
</div>

You still need to initialize the sidebar (see API.creation)

Events

The sidebar fires 3 types of events: opening, closing, and content. The latter has a payload including the id of the activated content div.

You can listen for them like this:

sidebar.on('content', function(e) {
    // e.id contains the id of the opened panel
})

License

leaflet-sidebar-v2 is free software, and may be redistributed under the MIT license.

leaflet-sidebar-v2's People

Contributors

aaxee avatar boldtrn avatar bqtran avatar chaudhryatif avatar csxphil avatar greenkeeper[bot] avatar jbelien avatar lksv avatar micahstevens avatar muellermatthew avatar nickpeihl avatar noerw avatar pka avatar pkozak2 avatar rhewitt22 avatar roastedmonk avatar rrooij avatar runette avatar sharpchi avatar stanguy avatar thomasg77 avatar turbo87 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

leaflet-sidebar-v2's Issues

Position: right, caret should be flipped

If you init a container on the right side, the caret that closes the panel, should be flipped. Right now it looks like it would move further out.

Probably we should consider the position at this point:

 if (this.options.closeButton)
                    content += '<span class="leaflet-sidebar-close"><i class="fa fa-caret-left"></i></span>';

Remove Github link

Good morning,

I integrated your module in my web app. There is a tab with a Github link. I would like to know how remove this tab.

Thank you.

Typescript support

Can Typerscript support be added for the sidebar? The parent repo has a file that can be dropped-in, or used as a starting point.
leaflet-sidebar.d.ts

Currently gives me the following error:

Property 'sidebar' does not exist on type 'typeof control'.

When trying to do the following (using autopan example):

L.control.sidebar('sidebar', { autopan: true })
    .addTo(map)
    .open('autopan');

And if possible, please add an angular 2+ example.

Allow determining whether sidebar is currently open or closed.

The original sidebar plugin (v1) provided an isVisible() function that would allow the user to determine whether the sidebar was open or closed.

This is particularly useful feature as it allows toggling of other element's (e.g. dialogs) styles and classes to better resize on the screen when the sidebar is open and closed.

Is it possible to provide something similar for this newer plugin?

Close and open the sidebar simultaneously

I was using the leaflet-sidebar-v2 API and because a chain of processes my code was closing the sidebar and opening it in a new tab, while the autopan: true . The center of my map was always getting displaced, all the time the sidebar was being opened again.

It's not the case, but just to understand the bug:
Imagine you have this following button, that all the time you click on it, it closes the sidebar and open a tab. Remembering autopan: true . If you click on it twice. The center of the map will be displaced.

<button id="btn_test">TEST</button>

   $( "#btn_test" ).click(function() {
     ctlSidebar.close(); 
     ctlSidebar.open("home");
   });

It's not a big deal, but it took me so long to realize why it was being caused. And I decided to post it here maybe others face the same or it possibly get corrected in future releases.

addPanel() - check ID for uniqueness

Currently, when using the addPanel method using an already existing id, the panels get added on top of each other, which is not ideal. Maybe it would make sense to add an overwrite flag to the method or show a warning if the panel already exists?

vue js wrapper

Thank you for this very useful plugin.

Is there a vue js wrapper for leaflet sidebar v2 available?
It would be great to be able to use it as a component.

Can see tabs, can't see content

Environment: I'm working in Node, using browserify to bundle all the JS files/libraries into one file, working in localhost, leaflet has been working fine thus far. All the CSS files are loading properly, and the JS is functioning, because I can see the active class get passed around when I click on tabs.

Issue: the actual panels of the sidebar are never visible. When a tab is selected, I can see that its content is present and active in the devtools inspector, but it looks like it's got opacity: 0 or it's stuck behind the map or something. I've tried this in both Firefox and Chrome. All the example projects work in my browser, though I haven't tried them through my localhost server. Edit to mention: I've tried both having the sidebar div inside the map div and having them separate. It doesn't make a difference.

Relevant code:

index.html

<html>
	<head>
		<link rel="stylesheet" href="node_modules/leaflet/dist/leaflet.css">
		<link rel="stylesheet" href="node_modules/leaflet-sidebar-v2/css/leaflet-sidebar.min.css">
		<!--[if lte IE 8]>
			<link rel="stylesheet" href="node_modules/leaflet/dist/leaflet.ie.css" />
		<![endif]-->
		<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">
		<link rel="stylesheet" href="assets/css/style.css" />
	</head>
	<body>
		<div id="map">
			<div id="leaf-sidebar"></div>
		</div>
		<script src="./assets/js/bundle.js"></script>
	</body>
</html>

important parts of bundle.js:

let sidebar = L.control.sidebar({
	position: 'left',
	container: 'leaf-sidebar'
}).addTo(map);

sidebar.addPanel({
	id: "home",
	tab: "<i class='fa fa-bars'></i>",
	title: "Home",
	pane: "This is a test home panel!",
}).open('home');

sidebar.addPanel({
	id: "test-box",
	tab: "T",
	title: "Test",
	pane: "<p>lorem ipsum etc</p>",
});

How to use in React?

Hello. noerw.

I'm using React, not Typescript.

I am beginner to ES6 or React.

I need help. Can I hear the answer?

Somebody help me plz.

JS API doesnt set Id

If you create the sidebar via the js api and specify a container id, the id is not set to the HTML element.

This could be fixed by something like:

if (!container){
      container = L.DomUtil.create('div', 'leaflet-sidebar collapsed');
      container.id = this.options.container;
}

Place the .leaflet-sidebar-tabs at the bottom horizontally rather than vertically on the left or on the right

Hi,
I would like to place the .leaflet-sidebar-tabs element (the 40 px bar where the icons are located) horizontally at the bottom of the screen rather than vertically on left or on the right.
I guess that is possible but the question is, how complicated that may be?
I just want to relocate the tabs, the pane (the part which dynamically moves) would remain where it is now (vertically on the left or on the right)
Thanks

.remove() doesn't work on Leaflet v1.5.0+

On Leaflet v1.5.0+ removing the sidebar from the map does not work:

Uncaught TypeError: Cannot read property 'off' of null (Control.js:100)

After invoking sidebar.onRemove(), Leaflet v1.5.0+ try to use sidebar._map, but .onRemove() has already set sidebar._map to null.

Sorry for my bad English.

Create Sidebar Footer

Hello,

I'd like to create a sidebar footer in the same manner as the header - where it stays in the same relative space in the screen and the main body ignores it for scrolling purposes. Could you let me know what the css properties the header uses that allows that? I couldn't figure it out from the file.

Thank you!

Typedef incompatible with latest leaflet typedef

Angular 8 spits out the following 2 errors when running ng build:

ERROR in node_modules/leaflet-sidebar-v2/index.d.ts:50:13 - error TS2416: Property 'on' in type 'Sidebar' is not assignable to the same property in base type 'Evented'.
  Type '{ (type: SidebarEvents, fn: LeafletEventHandlerFn, context?: any): this; (eventMap: SidebarEventHandlerFnMap): this; }' is not assignable to type '{ (type: string, fn: LeafletEventHandlerFn, context?: any): this; (type: "baselayerchange" | "overlayadd" | "overlayremove", fn: LayersControlEventHandlerFn, context?: any): this; (type: "layeradd" | "layerremove", fn: LayerEventHandlerFn, context?: any): this; (type: "add" | ... 18 more ... | "predrag", fn: Leaflet...'.
    Types of parameters 'type' and 'type' are incompatible.
      Type '"baselayerchange" | "overlayadd" | "overlayremove"' is not assignable to type 'SidebarEvents'.
        Type '"baselayerchange"' is not assignable to type 'SidebarEvents'.

50             on(type: SidebarEvents, fn: L.LeafletEventHandlerFn, context?: any): this;
               ~~
node_modules/leaflet-sidebar-v2/index.d.ts:51:13 - error TS2416: Property 'on' in type 'Sidebar' is not assignable to the same property in base type 'Evented'.
  Type '{ (type: SidebarEvents, fn: LeafletEventHandlerFn, context?: any): this; (eventMap: SidebarEventHandlerFnMap): this; }' is not assignable to type '{ (type: string, fn: LeafletEventHandlerFn, context?: any): this; (type: "baselayerchange" | "overlayadd" | "overlayremove", fn: LayersControlEventHandlerFn, context?: any): this; (type: "layeradd" | "layerremove", fn: LayerEventHandlerFn, context?: any): this; (type: "add" | ... 18 more ... | "predrag", fn: Leaflet...'.

51             on(eventMap: SidebarEventHandlerFnMap): this;

These are my package.json entries related to leaflet:

"@types/leaflet": "^1.5.6",
 "leaflet": "^1.6.0",
 "leaflet-sidebar-v2": "^3.2.1",

No idea where to go from here. It works, and shows the sidebar, but any deployment to Heroku fails because of the build error.

IE compatibility

Hello!

The sidebar code contains "Object.assign()" method, which does not supported by IE.

For compatibility with IE, please consider adding the following polyfill:

if ("function" !== typeof Object.assign) {
  Object.assign = function(target, varArgs) { // .length of function is 2
    "use strict";
    if (null == target) { // TypeError if undefined or null
      throw new TypeError("Cannot convert undefined or null to object");
    }

    var to = Object(target);

    for (var index = 1; index < arguments.length; ++index) {
      var nextSource = arguments[index];

      if (null != nextSource) { // Skip over if undefined or null
        for (var nextKey in nextSource) {
          // Avoid bugs when hasOwnProperty is shadowed
          if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
    }
    return to;
  };
}

addUser() function not working.

I'm using the addUser() function in my js script but getting an uncaught reference error that the function is not defined.

    var sidebar = L.control.sidebar({ container: 'sidebar'})
      .addTo(myMap)
      .open('home')
    sidebar
      .addPanel({
        id:   'mail',
        tab:  '<i class="fa fa-envelope"></i>',
        title: 'Messages',
        button: function() { alert('opened via JS callback') },
        disabled: true,
    })
    var userid = 0
    function addUser() {
        sidebar.addPanel({
            id:   'user' + userid++,
            tab:  '<i class="fa fa-user"></i>',
            title: 'User Profile ' + userid,
            pane: '<p>user ipsum dolor sit amet</p>',
        });
    }
        

I've added buttons in my html script within the default api panel -

            <p>
                <button onclick="sidebar.enablePanel('mail')">enable mails panel</button>
                <button onclick="sidebar.disablePanel('mail')">disable mails panel</button>
              </p>
              <p>
                <button onclick="addUser()">add user</button> <br><br>
              </p>

Although the example code I'm referencing doesn't include the buttons, I pulled it from the example webpage. (Although it doesn't show up in the HTML source script, when I inspect the button on click I see it in the elements console) The error comes up onclick. (The enable/disable mail panel pulls the same error) https://ibb.co/5R94tmG

The dynamically created panel not close by tap on title.

By tap on tab - closes just fine.

leaflet-sidebar-v2-3.2.1

At first, the sidebar was created static.
Then, I create panel by API from string via eval. `
String content:

	let panelContent = {
		id: 'weatherTab',                     // UID, used to access the panel
		title: 'Weather',              // an optional pane header
		tab: '<img src="img/logo_tk_weatherservice.png" alt="Weather forecast" width="70%">',  // content can be passed as HTML string,
		pane: `
			<div style="height:100%;">
                         ....
		`,        // DOM elements can be passed, too
	};
	sidebar.addPanel(panelContent);

It works, but <span class="leaflet-sidebar-close"><i class="fa fa-caret-left"></i></span> has width 0.

Add and removing panel more than twice

Hi! I have noticed an issue which happens when calling removePaneland addPanel methods more than twice with the same panel. This leads to the panel not being removed.

I believe the solution here is to change this line from this._tabitems.slice(i, 1); to this._tabitems.splice(i, 1); and do the same for panes.

Best regards!

EDIT updated suggested fix

L.Control.Sidebar is not a function

Hello,

I have install leaflet-sidebar-v2 via npm. However when I try to simply initialize the side bar I get this error. L.Control.Sidebar is not a function

<div #sidebar id="sidebar">
  <app-sidebar></app-sidebar>
</div>
  initializeSideBar() {
    this.sidebar = L.Control.Sidebar('sidebar').addTo(this.map);
  }

Any help is greatly appreciated.

Thank you. Darnell

Zoom home offset if sidebar is open

Hi guys, this is my webmap:

www.mainjoin.eu/map/santiago/

Everything works perfectly: sidebar(v2), autopan, popup content go in sidebar panels fine.

Only a few trouble. At top right I have zoom home button.
When sidebar is close everything go fine: zoom home button center my map.
When sidebar is open the zoom home makes the same thing but the sidebar hide part of my center map.
I'd like a little right-offset on result of zoom home button when sidebar is open.
Something like:

if sidebar.close() = true
	zoomhome
else
	zoomhome.offset

Any advices are welcome, thanks!
Valerio

Open sidebar pane on tooltip click?

I'd want to open a sidebar pane when user clicks a tooltip. I've used previous versions of sidebar + old leaflet, and the method described below worked:

  • in my mapdata.js

var tooltipMarker = L.marker([33.65201, -158.34234], {icon: emptyIcon})
.bindTooltip("Tooltip", {permanent: true, direction: 'center', className: 'lab-misc', interactive: true})
.openTooltip().on ('click', function () {sidebar.open('i-tooltip')})
.addTo(continents);

  • in html

<div class="leaflet-sidebar-pane" id="i-tooltip">
<h1 class="leaflet-sidebar-header">
Tooltip Title<div class="leaflet-sidebar-close"><i class="fa fa-caret-left"></i></div>
</h1>
<p>A responsive sidebar for mapping libraries</p>
</div>

Now, this method does not work for this version of sidebar, and throws error as it cannot find the html class? How would I go about making something like this work?

Sidebar is created outside map div

I think it's not intuitive to append the sidebar div to document.body instead of the map div. I want the sidebar to be displayed within the map even if that map doesn't span the entire viewport.

I fixed this for me by changing line 33 in the js from

 this._sidebar = L.DomUtil.create('div', 'sidebar collapsed', document.body);

to

 this._sidebar = L.DomUtil.create('div', 'sidebar collapsed', L.DomUtil.get('map'));

Would you too consider that a smarter default or am I missing a point?
Anyways, thanks for your work!

live examples on gh-pages

would be nice to host the examples on gh-pages (configured to master branch, root dir), and link to them in readme and repo URL

Add Panel broken for Typescript (Temp fix included)

Hello! I have found an issue with Typescript support in the latest version. It boils down to an extra letter (or maybe one less than enough?)

In the vanilla module when you add a panel you set the 'pane' field, yet in the Typescript definition it is the 'panel' field. This would cause the panel to load without the content.

I was able to fix the issue by modifying your leaflet-sidebar.js class. The relevant change was data.pane to data.panel.

// Create pane node

if (data.panel)

{

if (typeof  data.panel  ===  'string')

{

// pane is given as HTML string

pane  =  L.DomUtil.create('DIV', 'leaflet-sidebar-pane', this._paneContainer);

content  =  '';

if (data.title)

content  +=  '<h1 class="leaflet-sidebar-header">'  +  data.title;

if (this.options.closeButton)

content  +=  '<span class="leaflet-sidebar-close"><i class="fa fa-caret-left"></i></span>';

if (data.title)

content  +=  '</h1>';

pane.innerHTML  =  content  +  data.panel;

} else

{

// pane is given as DOM object

pane  =  data.panel;

this._paneContainer.appendChild(pane);

}

pane.id  =  data.id;

Hope this helps!

[Request] Add panel-less button using html

A tab-less button listener can be added via the following js:

/* add an button with click listener */
sidebar.addPanel({
    id: 'click',
    tab: '<i class="fa fa-info"></i>',
    button: function (event) { console.log(event); }
});

It can be done through html (with some help of js) like so:

<ul role="tablist">
    <li><a href="javascript:void(0);" onclick="myFunction()"><i class="fa fa-gear"></i></a></li>
</ul>

Can the following additions be made so that any anchor with a specific class can be made into a panel-less button? I would do a PR, but I haven't done too much of scss to css build and all, so suggesting it instead.

// css
.leaflet-sidebar-button {
    cursor: pointer;
}

// html
<ul role="tablist">
    <li><a class="leaflet-sidebar-button" onclick="myFunction()"><i class="fa fa-gear"></i></a></li>
</ul>

// js
if ((link.hasAttribute('href') && link.getAttribute('href')[0] !== '#' ) || (link.classList.contains("leaflet-sidebar-button"))
    return;

classList browser support + more info

https://github.com/nickpeihl/leaflet-sidebar-v2/blob/09086d779e4fd04e3a65aa8031e340e8a3691bbe/js/leaflet-sidebar.js#L426
Note: Although the code checks if the first character is '#' (and returns if it doesn't), it doesn't work as expected all the time (i.e. for Angular).

Can't refresh content

Hello,

I have a problem when using leaflet and the sidebar in combination with AngularJS.

I have some options on the marker and I put the selected marker in a variable called clickedMarker.

$scope.clickedMarker = e.target;

I then open the sidebar tab and try to display the name of the marker, but it doesn't do it.

Object - {{clickedMarker.options.ObjectName}}

If I open or close the developer tool in chrome(F12) the name get's refreshed.

Is it a bug? Any suggestions or workarounds?

Couple of bug reports/fixes....

Loving what you did to improve upon the original! Definitely help kept my code more modular/cleaner, though I did run into a couple of bugs that you may want to fix:

  1. Using addPanel in addition to addTo functions will effectively double up on the click events for tabs and close icons. This will cause the bar to open & close quickly and make it seem like nothing's working to the user.

  2. Ln 255 should be using setAttribute('role','tab') instead, otherwise the attribute won't appear like the original plugin.

  3. Similar to #2, the tab containers (both top and bottom) are missing a setAttribute('role', 'tablist') attribute to match the original sidebar-v2.

Thanks for the work!

fa-bars do not consider top margin. Is it possible to change in the css file?

I copied the example at https://noerw.github.io/leaflet-sidebar-v2/examples/ to my project, but the result is different and the fa-bars icon is without the top margin, and all others bellow too.
image

In the example it is correct, like bellow:
image
image
I could solve this problem at the close icon, changing from 0 to 10 at the top margin:

.leaflet-sidebar-close { top: 10;

I tried to find where in the css file I could change the top margin of the fa-bars, but was not successful. Any help I would appreciate.

Thanks.

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.