Coder Social home page Coder Social logo

cytoscape.js-edgehandles's Introduction

cytoscape-edgehandles

DOI

Preview

Description

This extension allows for drawing edges between nodes (demo, demo (snapping disabled), compound demo, compound demo (snapping disabled))

You can use Popper to create your own handles, as shown in the demo.

Dependencies

  • Cytoscape.js 3.x, >= 3.2.0
  • Lodash 4.x, >= 4.1
    • memoize
    • throttle

Usage instructions

Download the library:

  • via npm: npm install cytoscape-edgehandles,
  • via bower: bower install cytoscape-edgehandles, or
  • via direct download in the repository (probably from a tag).

Import the library as appropriate for your project:

ES import:

import cytoscape from 'cytoscape';
import edgehandles from 'cytoscape-edgehandles';

cytoscape.use( edgehandles );

CommonJS require:

let cytoscape = require('cytoscape');
let edgehandles = require('cytoscape-edgehandles');

cytoscape.use( edgehandles ); // register extension

AMD:

require(['cytoscape', 'cytoscape-edgehandles'], function( cytoscape, edgehandles ){
  edgehandles( cytoscape ); // register extension
});

Plain HTML/JS has the extension registered for you automatically, because no require() is needed.

Initialisation

You initialise the extension on the Cytoscape instance:

let cy = cytoscape({
  container: document.getElementById('#cy'),
	/* ... */
});

// the default values of each option are outlined below:
let defaults = {
  canConnect: function( sourceNode, targetNode ){
    // whether an edge can be created between source and target
    return !sourceNode.same(targetNode); // e.g. disallow loops
  },
  edgeParams: function( sourceNode, targetNode ){
    // for edges between the specified source and target
    // return element object to be passed to cy.add() for edge
    return {};
  },
  hoverDelay: 150, // time spent hovering over a target node before it is considered selected
  snap: true, // when enabled, the edge can be drawn by just moving close to a target node (can be confusing on compound graphs)
  snapThreshold: 50, // the target node must be less than or equal to this many pixels away from the cursor/finger
  snapFrequency: 15, // the number of times per second (Hz) that snap checks done (lower is less expensive)
  noEdgeEventsInDraw: true, // set events:no to edges during draws, prevents mouseouts on compounds
  disableBrowserGestures: true // during an edge drawing gesture, disable browser gestures such as two-finger trackpad swipe and pinch-to-zoom
};

let eh = cy.edgehandles( defaults );

API

The object returned by cy.edgehandles() has several functions available on it:

  • start( sourceNode ) : manually start the gesture (as if the handle were already held)
  • stop() : manually completes or cancels the gesture
  • disable() : disables edgehandles behaviour
  • enable() : enables edgehandles behaviour
  • enableDrawMode() : turn on draw mode (the entire node body acts like the handle)
  • disableDrawMode() : turn off draw mode
  • destroy() : remove edgehandles behaviour

Classes

These classes can be used for styling the graph as it interacts with the extension:

  • eh-source : The source node
  • eh-target : A target node
  • eh-preview : Preview edges (i.e. shown before releasing the mouse button and the edge creation is confirmed)
  • eh-hover : Added to nodes as they are hovered over as targets
  • eh-ghost-node : The ghost node (target), used when the cursor isn't pointed at a target node yet (i.e. in place of a target node)
  • eh-ghost-edge : The ghost handle line edge, used when the cursor isn't pointed at a target node yet (i.e. the edge is pointing to empty space)
  • eh-ghost : A ghost element
  • eh-presumptive-target : A node that, during an edge drag, may become a target when released
  • eh-preview-active : Applied to the source, target, and ghost edge when the preview is active

Events

During the course of a user's interaction with the extension, several events are generated and triggered on the core. Each event callback has a number of extra parameters, and certain events have associated positions.

  • ehstart : when the edge creation gesture starts
    • (event, sourceNode)
    • event.position : handle position
  • ehcomplete : when the edge is created
    • (event, sourceNode, targetNode, addedEdge)
    • event.position : cursor/finger position
  • ehstop : when the edge creation gesture is stopped (either successfully completed or cancelled)
    • (event, sourceNode)
    • event.position : cursor/finger position
  • ehcancel : when the edge creation gesture is cancelled
    • (event, sourceNode, cancelledTargets)
    • event.position : cursor/finger position
  • ehhoverover : when hovering over a target
    • (event, sourceNode, targetNode)
    • event.position : cursor/finger position
  • ehhoverout : when leaving a target node
    • (event, sourceNode, targetNode)
    • event.position : cursor/finger position
  • ehpreviewon : when a preview is shown
    • (event, sourceNode, targetNode, previewEdge)
    • event.position : cursor/finger position
  • ehpreviewoff : when the preview is removed
    • (event, sourceNode, targetNode, previewEdge)
    • event.position : cursor/finger position
  • ehdrawon : when draw mode is enabled
    • (event)
  • ehdrawoff : when draw mode is disabled
    • (event)

Example binding:

cy.on('ehcomplete', (event, sourceNode, targetNode, addedEdge) => {
	let { position } = event;

  // ...
});

Build targets

  • npm run test : Run Mocha tests in ./test
  • npm run build : Build ./src/** into cytoscape-edgehandles.js
  • npm run watch : Automatically build on changes with live reloading (N.b. you must already have an HTTP server running)
  • npm run dev : Automatically build on changes with live reloading with webpack dev server
  • npm run lint : Run eslint on the source

N.b. all builds use babel, so modern ES features can be used in the src.

Publishing instructions

This project is set up to automatically be published to npm and bower. To publish:

  1. Build the extension : npm run build:release
  2. Commit the build : git commit -am "Build for release"
  3. Bump the version number and tag: npm version major|minor|patch
  4. Push to origin: git push && git push --tags
  5. Publish to npm: npm publish .
  6. If publishing to bower for the first time, you'll need to run bower register cytoscape-edgehandles https://github.com/cytoscape/edgehandles.gita
  7. Make a new release for Zenodo.

cytoscape.js-edgehandles's People

Contributors

alexandrebonaventure avatar alexandrsashin avatar alexcli avatar alexnault avatar amherag avatar buffpojken avatar finger563 avatar ikwattro avatar itf avatar lszanto avatar maxkfranz avatar megawebmaster avatar randallelliott avatar tongbin 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

cytoscape.js-edgehandles's Issues

Breaks with cytoscape.js v2.7.1

Just filling a bug but I see you didn't update the version number yet, so seems normal

  • cytoscape.js?2f17fa0โ€ฆ:4432 Uncaught TypeError: Cannot read property '_private' of undefined
  • cytoscape.js?2f17fa0โ€ฆ:2328 Uncaught TypeError: Cannot read property 'size' of undefined

breaks on line 4432 when selecting a node

      if( badSourceOrTarget ){ removeFromElements(i); continue; } // can't create this

      var src = cy.getElementById( data.source );
      var tgt = cy.getElementById( data.target );

      src._private.edges.push( edge );
      tgt._private.edges.push( edge );

then 2328 when trying to select another one

    for( var i = 0; i < this.length; i++ ){
      var ele = this[ i ];
      var parent = cy.getElementById( ele._private.data.parent );

      if( parent.size() > 0 ){
        parents.push( parent );
      }
    }

selection_127

Not working in IE

Line 540 //var opts = Object.assign({}, defaults, params ); in IE10 not supportet.

Mouse over effect on target

To automatically highlight or add some visual effect when mouse over a target node to which an edge is allowed to be drawn. (see my pull request canAccept() enhancement).

v2.10.3 and later destroys clickable html components

Hi,
I am using this extension with semver ~2.10.2. I realized that clickable html components are not working for me after v2.10.3 of this extension is released. If I switch the semver of this extension to 2.10.2 from ~2.10.2 then the problem disappears. As far as I see the problem is emerged with 4b015c7

Dropping ghost edge when moving mouse throws an error

cytoscape-edgehandles.js:623 Uncaught TypeError: Cannot read property 'id' of null(โ€ฆ)

When handleLineType = ghost and I start creating egde from source node then release mouse button while still moving the mouse - somewhere between the nodes or out of canvas. Throws an error

Add selector to options

It would be great to be able to specify a selector to limit which nodes get the edgeHandles behavior. Unless I'm missing something that functionality is not currently available right>?

Option to position handle

For a parent node with many children nodes, if this parent node is relatively large, the edge handle shown at the top of the node is not always accessible without scrolling.

Would it be possible to add an option for users to specify where the edge handle is displayed? Specifically if we can have the option to display the handle where mouse is, that will be very useful.

Proper support for compound nodes

Currently we're able to use this extension to add edges from a compound node to a simple node but not vice versa (it doesn't always work for some reason)!

Edgehandles canvas not resizing on Cy resize

Hi!

I've found out that when Cytoscape resizes its canvas there are places I cannot use edge handles to create connections. It seems we are missing resizing after cy.resize() :)

We need to add:

cy.on( 'resize', function() {
    $container.trigger( 'cyedgehandles.resize' );
});

on line 417 ;)

`stop` event not being fired in draw mode

Stop event not fired in next initialization sequence, only complete is fired when edge is created. Stop not fired not when edge created, not when just handle released

cy.edgehandles({ toggleOffOnLeave: true, handleSize: 0, cxt: true });
cy.edgehandles('drawon');
cy.on('cyedgehandles.stop', 'node', function(e) {
console.log('stop');
});
cy.on('cyedgehandles.complete', 'node', function(e) {
console.log('complete');
})

cy.edgehandles is not a function

I'm getting this error, as in issue #61. I downloaded the latest release a few weeks ago, and it works, but the current latest isn't working. I also tried with other releases.

Link w/context menu

Both the context menu plugin and this plugin are awesome. What would be even more awesome is to have a drag-able handle be one of the items in the context menu--which would also provide support for touch devices. Basic interaction would be:

  1. Tap node
  2. Context menu appears
  3. Drag the "Link" context menu item to another node
  4. Nodes are now linked

In my view this is a better flow than linking based on hover (edges are much harder to grab and not available on touch devices). It would be awesome if you can make these two plugins that compatible (maybe a 3rd plugin that links the two?).

"Always on" edgehandles?

Have this been considered and rejected or would pull requests be welcome?

I'm thinking basically an option to not have this displayed on hover/mouseover, but rather all the time?

readme.md mistake

All function can be called via cy.edgehandles('function-name'):

cy.edgehandles('enable') : enable the extension

cy.edgehandles('enable') : disable the extension

cy.edgehandles('option', 'preview', false) : set individual option (e.g. 'preview')
cy.edgehandles('option', { /* options */ }) : set all options
cy.edgehandles('option', 'preview') : get option value (e.g. 'preview')
cy.edgehandles('destroy') : destroy the extension instance
cy.edgehandles('start', 'some-node-id') : start the handle drag state on node with specified id (e.g. 'some-node-id')
cy.edgehandles('drawon') : enable draw mode
cy.edgehandles('drawoff') : disable draw mode

Mobile supports for edgehandles

Edgehandles works fine on web browser. But it doesn't work on mobile browser. Is there any solution for support mobile web browser? Can I bind new cytoscape's event listener with edgehandles? e.g: double tap

Crash when importing with browserify: cytoscape is not defined

I'm pretty sure that the reason for crash is calling wrapping function with undefined cytoscape and jQuery as arguments. Browserify enforces strict mode everywhere - so it crushes on unknown variables.
I've managed to fix the crash by simply adding window. before each of these arguments, but I'm not sure if that is a good solution for other ways to import this plugin.

Cytoscape is not a function with version 2.6.3

Hello,

If I try to require and link the modules, as shown here:

var cytoscape = require('cytoscape');
var edgehandles = require('cytoscape-edgehandles');
var jquery = require('jquery');

edgehandles( cytoscape, jquery ); // register extension

i get Uncaught ReferenceError: cytoscape is not defined. It works when I import them global (I use webpack) however then I receive an Uncaught TypeError: $container.cytoscape is not a function when I try to:

cy.edgehandles(edgeConf);

I assume the current version broke something.

Dragging new edge to child node also creates edge to parent node (sometimes)

Consider three nodes: node A, child Node, and parent Node.
If I drag from nodeA to child node and release (to create an edge from node A to child node), sometimes an edge is also created from node A to parent node. Whether or not the edge from node A to parent node is created seems to depend on exactly where the mouseup happens on child node.

Separately, but possibly related to the location issue - there is some small misalignment between mouseup and the targetnode. Sometimes when mouseup is off to the side of the node, the edge is still created to the node. In my particular case this happens off to the left side only, not top or bottom or right.

But this doesn't explain why two edges are created.

I have the cy div set with position: absolute, which might be related to the location issue. I thought that was fixed in this version of the plugin (after separating from the cytoscapejs core)...?

Calling extension function does not forward arguments

If I call a extension function (e.g. cy.edgehandles('start', 'some-node-id') ) the node id is not forwarded to the start function. Instead, always the cy object is used as the only argument on the start function.

Would like to submit a PR for z-index issue->

The hard-coded z-index of 999 on the edgehandles canvas element causes stacking/layout issues.
Example: the graph is used inside of a component that has an action bar with drop-down menus. When cytoscape-edgehandles is initiated the canvas element is rendered above everything including the drop-downs. The drop-down actions are no longer functional because the canvas captures the pointer events.

I have a couple of suggested fixes if there is a way to submit a PR.

Thanks for the plugin!

can this library support multiple handles?

can this library support multiple handles?

I would like to be able to have a node which has X number of handles to a node because in my graph nodes can only support X number of edges

Option to specify multiple handlePosition(s)

Is there a way to specify multiple positions for the handle as per node? For example if the node has css class 'x' the handlePosition: 'left middle | right middle', and if the node has css class 'y' the handlePosition: 'top middle | top bottom'

Essentially I'm talking about two questions/suggestions:

  1. Multiple handelPositions
  2. Different positions for different css class nodes

Can this be done?

edgehandles canvas not overlapping cytoscape layers

I played around with edgehandles and couldn't see the handles (everything worked, just no handles were drawn on the node). Eventually I discovered that the handles do appear on my web page, but outside the cytoscape layer canvases.

Edgehandles creates its own canvas, which it tries to place exactly over the cytoscape canvases. It injects its canvas into the DOM, as follows:

$container.append( $canvas );

For me, this leads to the canvas showing up below (in y coordinates) the cy element (and its layer canvases), instead of overlapping the cy element.

The reason seems to be that edgehandles appends the canvas to the container DIV, instead of the the canvas container DIV.

Changing the above line in cytoscape-edgehandles.js into this:

$container.find('.canvas-container').append($canvas);

together with a corresponding change in the CanvasRenderer function in cytoscape.js (to add the 'canvas-container' class to the canvas container DIV) should fix this:

  r.data.canvasContainer.setAttribute('class', 'canvas-container');

Uncaught TypeError: cy.edgehandles is not a function

When i tried to integrate Edgehandles with Cytoscape, it showed an error:

Uncaught TypeError: cy.edgehandles is not a function

I was pretty sure doing it the right way:
This is my HTML file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <title></title>
    <link href="css/bootstrap.min.css" rel="stylesheet">
    <link href="css/style.css" rel="stylesheet">
</head>
<body>
    <section>
        <div class="container">
            <div class="row">
                <div class="col-xs-12 match-container">
                  <!-- <canvas id="canvas" width=300 height=300></canvas> -->
                  <div id="canvas"></div>
                    <div class="col-xs-4 no-padding">
                      <div id="0" class="draggable">0</div>
                      <div id="1" class="draggable">1</div>
                      <div id="2" class="draggable">2</div>
                    </div>
                    <div id="wrap2" class="col-xs-4 col-xs-offset-4 no-padding">
                      <div id="0r" class="draggable right">0</div>
                      <div id="1r" class="draggable right">1</div>
                      <div id="2r" class="draggable right">2</div>
                    </div>
                </div>
            </div>
        </div>
    </section>
    <script src="js/jquery.js"></script>
    <script src="js/bootstrap.min.js"></script>
    <script src="js/cytoscape.min.js"></script>
    <script src="js/cytoscape-edgehandles.js"></script>
    <script src="js/script.js"></script>
</body>
</html>

This is the JS:

var cy = cytoscape({

  container: document.getElementById('canvas'), // container to render in

  elements: [ // list of graph elements to start with
    { // node a
      data: { id: 'a',class: 'node' }
    },
    { // node b
      data: { id: 'b',class: 'node' }
    },
    { // edge ab
      data: { id: 'ab', source: 'a', target: 'b' }
    },
    { // node a
      data: { id: 'c',class: 'node' }
    },
    { // node b
      data: { id: 'd',class: 'node' }
    },
    { // node a
      data: { id: 'e',class: 'node' }
    },
    { // node b
      data: { id: 'f',class: 'node' }
    }
  ],

  style: [ // the stylesheet for the graph
    {
      selector: 'node',
      style: {
        'background-color': '#666',
        'label': 'data(id)'
      }
    },

    {
      selector: 'edge',
      style: {
        'width': 3,
        'line-color': '#ccc',
        'target-arrow-color': '#ccc',
        'target-arrow-shape': 'triangle'
      }
    }
  ],

  layout: {
    name: 'grid',
    cols: 2
  },

  zoomingEnabled: false,
  userZoomingEnabled: false,
  autoungrabify: true,
  panningEnabled: false,
  userPanningEnabled: false,

});

var defaults = {
  preview: true, // whether to show added edges preview before releasing selection
  stackOrder: 4, // Controls stack order of edgehandles canvas element by setting it's z-index
  handleSize: 10, // the size of the edge handle put on nodes
  handleColor: '#ff0000', // the colour of the handle and the line drawn from it
  handleLineType: 'ghost', // can be 'ghost' for real edge, 'straight' for a straight line, or 'draw' for a draw-as-you-go line
  handleLineWidth: 1, // width of handle line in pixels
  handleIcon: false, // Pass an Image-object to use as icon on handle. Icons are resized according to zoom and centered in handle.
  handleOutlineColor: '#000000', // the colour of the handle outline
  handleOutlineWidth: 0, // the width of the handle outline in pixels
  handleNodes: 'node', // selector/filter function for whether edges can be made from a given node
  handlePosition: 'middle top', // sets the position of the handle in the format of "X-AXIS Y-AXIS" such as "left top", "middle top"
  hoverDelay: 150, // time spend over a target node before it is considered a target selection
  cxt: false, // whether cxt events trigger edgehandles (useful on touch)
  enabled: true, // whether to start the extension in the enabled state
  toggleOffOnLeave: false, // whether an edge is cancelled by leaving a node (true), or whether you need to go over again to cancel (false; allows multiple edges in one pass)
  edgeType: function( sourceNode, targetNode ) {
    // can return 'flat' for flat edges between nodes or 'node' for intermediate node between them
    // returning null/undefined means an edge can't be added between the two nodes
    return 'flat';
  },
  loopAllowed: function( node ) {
    // for the specified node, return whether edges from itself to itself are allowed
    return false;
  },
  nodeLoopOffset: -50, // offset for edgeType: 'node' loops
  nodeParams: function( sourceNode, targetNode ) {
    // for edges between the specified source and target
    // return element object to be passed to cy.add() for intermediary node
    return {};
  },
  edgeParams: function( sourceNode, targetNode, i ) {
    // for edges between the specified source and target
    // return element object to be passed to cy.add() for edge
    // NB: i indicates edge index in case of edgeType: 'node'
    return {};
  },
  start: function( sourceNode ) {
    // fired when edgehandles interaction starts (drag on handle)
  },
  complete: function( sourceNode, targetNodes, addedEntities ) {
    // fired when edgehandles is done and entities are added
  },
  stop: function( sourceNode ) {
    // fired when edgehandles interaction is stopped (either complete with added edges or incomplete)
  }, 
  cancel: function( sourceNode, renderedPosition ){
    // fired when edgehandles are cancelled ( incomplete - nothing has been added ) - renderedPosition is where the edgehandle was released
  }
};

cy.edgehandles( defaults );

console.log(cy);

What did I do wrong?

Thanks in advance!`

Preview state does not remove preview when moving between nodes

Steps to recreate using defaults....

  1. Hover over node
  2. Click on edge handle
  3. Drag to other node (see preview get displayed)
  4. Continue to hold mouse click and drag to another and separate node (third node) (see preview stay displayed on first node as well as second node)
  5. Release mouse click (see all edges stay connected)

Strange edge-arrow behaviour when drawing non-circle nodes

Just came across this and after a bit of testing I think i've found what seems to be the cause of the issue. As you can see below when using node shapes other than circle when you reduce the border-width to 0 then when you are dragging the edge you occasionally get the arrow flipping around which way it is facing. You can easily recreate this with the demo.html in the repo by simply adding 'shape': 'rectangle' to the node style.

With border-width set to 2px:
proper

With border-width set to 0:
bad

Blinking line while creating new edge

When you try to add an edge the line you drag from source node constantly blinks. You can even find position where line becomes invisible. When you comment lines 290-292 - that is:

if( now - lastDrawLine < lineDrawRate ){
return;
}

line stops to blink and is drawn properly. Is this some kind of optimalisation?

Create Loops

Would it be at all possible for this extension to allow for self-directed edges?

No edge dragging commences when trying

I think 2.6.0 broke the extension - completely unchanged code stopped working between 2.5.0 and 2.6.0.

Initialisation works just fine, but when trying to actually drag out an edge to connect you start to drag the node instead. Regressing to 2.5.0 restores expected behaviour.

I'll look into this on monday unless someone has a solid idea on why already, but I'm guessing the jQuery-like shim now used instead has some slight incompatibility with how events used to be handled (based on skimming the commits in 30 seconds, treat accordingly. )

bower package not found

When attempting to install edgehandles via bower, I get an error message using this command.
bower install cytoscape-edgehandles --save

bower ENOTFOUND Package cytoscape-edgehandles not found

Create edge on mouse up

Currently it marks target nodes using mouse over timeout and draws edges to all of the target nodes marked. For diagram editor, it is more useful to draw one edge to the target node on mouse up event.

Maybe we can set hoverDelay to 0 to allow such behavior?

Error when taking #cy "position" is "relative"

I take <div id="cy"></div> position is relative and I scroll down the scroll bar (it's not on top). I cannot connect 2 nodes together.

I think we have a problem with "mdownHandler" function about calculated height and top offset page.

Could you consider this issue.

Thanks

Target node is set to last node that was hovered over, but not removed

I am documenting this issue because I discovered it while working on #2. I believe I have a fix for both but I figured I should document this part too.

With edgehandles started from a source node, mouse button down, if you hover over one node, then leave that node and release somewhere on the background (even very far away from that node), the edge will be created to the last hovered node.

It seems this is because the "mouseout" event is not removing the "edgehandles-target" class. Adding this.removeClass("edgehandles-target"); to line 527 fixes the issue. I will post a patch.

This should also fix #2.

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.