commit
3357daab80
@ -0,0 +1,10 @@ |
||||
*~ |
||||
**/.DS_Store |
||||
paper/template.aux |
||||
paper/template.fdb_latexmk |
||||
paper/template.fls |
||||
paper/template.log |
||||
paper/template.out |
||||
paper/template.pdf |
||||
template.bbl |
||||
template.blg |
File diff suppressed because one or more lines are too long
@ -0,0 +1,249 @@ |
||||
.dc-chart path.dc-symbol, .dc-legend g.dc-legend-item.fadeout { |
||||
fill-opacity: 0.5; |
||||
stroke-opacity: 0.5; } |
||||
|
||||
div.dc-chart { |
||||
float: left; } |
||||
|
||||
.dc-chart rect.bar { |
||||
stroke: none; |
||||
cursor: pointer; } |
||||
.dc-chart rect.bar:hover { |
||||
fill-opacity: .5; } |
||||
|
||||
.dc-chart rect.deselected { |
||||
stroke: none; |
||||
fill: #ccc; } |
||||
|
||||
.dc-chart .pie-slice { |
||||
fill: #fff; |
||||
font-size: 12px; |
||||
cursor: pointer; } |
||||
.dc-chart .pie-slice.external { |
||||
fill: #000; } |
||||
.dc-chart .pie-slice :hover, .dc-chart .pie-slice.highlight { |
||||
fill-opacity: .8; } |
||||
|
||||
.dc-chart .pie-path { |
||||
fill: none; |
||||
stroke-width: 2px; |
||||
stroke: #000; |
||||
opacity: 0.4; } |
||||
|
||||
.dc-chart .selected path, .dc-chart .selected circle { |
||||
stroke-width: 3; |
||||
stroke: #ccc; |
||||
fill-opacity: 1; } |
||||
|
||||
.dc-chart .deselected path, .dc-chart .deselected circle { |
||||
stroke: none; |
||||
fill-opacity: .5; |
||||
fill: #ccc; } |
||||
|
||||
.dc-chart .axis path, .dc-chart .axis line { |
||||
fill: none; |
||||
stroke: #000; |
||||
shape-rendering: crispEdges; } |
||||
|
||||
.dc-chart .axis text { |
||||
font: 10px sans-serif; } |
||||
|
||||
.dc-chart .grid-line, .dc-chart .axis .grid-line, .dc-chart .grid-line line, .dc-chart .axis .grid-line line { |
||||
fill: none; |
||||
stroke: #ccc; |
||||
shape-rendering: crispEdges; } |
||||
|
||||
.dc-chart .brush rect.selection { |
||||
fill: #4682b4; |
||||
fill-opacity: .125; } |
||||
|
||||
.dc-chart .brush .custom-brush-handle { |
||||
fill: #eee; |
||||
stroke: #666; |
||||
cursor: ew-resize; } |
||||
|
||||
.dc-chart path.line { |
||||
fill: none; |
||||
stroke-width: 1.5px; } |
||||
|
||||
.dc-chart path.area { |
||||
fill-opacity: .3; |
||||
stroke: none; } |
||||
|
||||
.dc-chart path.highlight { |
||||
stroke-width: 3; |
||||
fill-opacity: 1; |
||||
stroke-opacity: 1; } |
||||
|
||||
.dc-chart g.state { |
||||
cursor: pointer; } |
||||
.dc-chart g.state :hover { |
||||
fill-opacity: .8; } |
||||
.dc-chart g.state path { |
||||
stroke: #fff; } |
||||
|
||||
.dc-chart g.deselected path { |
||||
fill: #808080; } |
||||
|
||||
.dc-chart g.deselected text { |
||||
display: none; } |
||||
|
||||
.dc-chart g.row rect { |
||||
fill-opacity: 0.8; |
||||
cursor: pointer; } |
||||
.dc-chart g.row rect:hover { |
||||
fill-opacity: 0.6; } |
||||
|
||||
.dc-chart g.row text { |
||||
fill: #fff; |
||||
font-size: 12px; |
||||
cursor: pointer; } |
||||
|
||||
.dc-chart g.dc-tooltip path { |
||||
fill: none; |
||||
stroke: #808080; |
||||
stroke-opacity: .8; } |
||||
|
||||
.dc-chart g.county path { |
||||
stroke: #fff; |
||||
fill: none; } |
||||
|
||||
.dc-chart g.debug rect { |
||||
fill: #00f; |
||||
fill-opacity: .2; } |
||||
|
||||
.dc-chart g.axis text { |
||||
-webkit-touch-callout: none; |
||||
-webkit-user-select: none; |
||||
-khtml-user-select: none; |
||||
-moz-user-select: none; |
||||
-ms-user-select: none; |
||||
user-select: none; |
||||
pointer-events: none; } |
||||
|
||||
.dc-chart .node { |
||||
font-size: 0.7em; |
||||
cursor: pointer; } |
||||
.dc-chart .node :hover { |
||||
fill-opacity: .8; } |
||||
|
||||
.dc-chart .bubble { |
||||
stroke: none; |
||||
fill-opacity: 0.6; } |
||||
|
||||
.dc-chart .highlight { |
||||
fill-opacity: 1; |
||||
stroke-opacity: 1; } |
||||
|
||||
.dc-chart .fadeout { |
||||
fill-opacity: 0.2; |
||||
stroke-opacity: 0.2; } |
||||
|
||||
.dc-chart .box text { |
||||
font: 10px sans-serif; |
||||
-webkit-touch-callout: none; |
||||
-webkit-user-select: none; |
||||
-khtml-user-select: none; |
||||
-moz-user-select: none; |
||||
-ms-user-select: none; |
||||
user-select: none; |
||||
pointer-events: none; } |
||||
|
||||
.dc-chart .box line { |
||||
fill: #fff; } |
||||
|
||||
.dc-chart .box rect, .dc-chart .box line, .dc-chart .box circle { |
||||
stroke: #000; |
||||
stroke-width: 1.5px; } |
||||
|
||||
.dc-chart .box .center { |
||||
stroke-dasharray: 3, 3; } |
||||
|
||||
.dc-chart .box .data { |
||||
stroke: none; |
||||
stroke-width: 0px; } |
||||
|
||||
.dc-chart .box .outlier { |
||||
fill: none; |
||||
stroke: #ccc; } |
||||
|
||||
.dc-chart .box .outlierBold { |
||||
fill: red; |
||||
stroke: none; } |
||||
|
||||
.dc-chart .box.deselected { |
||||
opacity: 0.5; } |
||||
.dc-chart .box.deselected .box { |
||||
fill: #ccc; } |
||||
|
||||
.dc-chart .symbol { |
||||
stroke: none; } |
||||
|
||||
.dc-chart .heatmap .box-group.deselected rect { |
||||
stroke: none; |
||||
fill-opacity: 0.5; |
||||
fill: #ccc; } |
||||
|
||||
.dc-chart .heatmap g.axis text { |
||||
pointer-events: all; |
||||
cursor: pointer; } |
||||
|
||||
.dc-chart .empty-chart .pie-slice { |
||||
cursor: default; } |
||||
.dc-chart .empty-chart .pie-slice path { |
||||
fill: #fee; |
||||
cursor: default; } |
||||
|
||||
.dc-data-count { |
||||
float: right; |
||||
margin-top: 15px; |
||||
margin-right: 15px; } |
||||
.dc-data-count .filter-count, .dc-data-count .total-count { |
||||
color: #3182bd; |
||||
font-weight: bold; } |
||||
|
||||
.dc-legend { |
||||
font-size: 11px; } |
||||
.dc-legend .dc-legend-item { |
||||
cursor: pointer; } |
||||
|
||||
.dc-hard .number-display { |
||||
float: none; } |
||||
|
||||
div.dc-html-legend { |
||||
overflow-y: auto; |
||||
overflow-x: hidden; |
||||
height: inherit; |
||||
float: right; |
||||
padding-right: 2px; } |
||||
div.dc-html-legend .dc-legend-item-horizontal { |
||||
display: inline-block; |
||||
margin-left: 5px; |
||||
margin-right: 5px; |
||||
cursor: pointer; } |
||||
div.dc-html-legend .dc-legend-item-horizontal.selected { |
||||
background-color: #3182bd; |
||||
color: white; } |
||||
div.dc-html-legend .dc-legend-item-vertical { |
||||
display: block; |
||||
margin-top: 5px; |
||||
padding-top: 1px; |
||||
padding-bottom: 1px; |
||||
cursor: pointer; } |
||||
div.dc-html-legend .dc-legend-item-vertical.selected { |
||||
background-color: #3182bd; |
||||
color: white; } |
||||
div.dc-html-legend .dc-legend-item-color { |
||||
display: table-cell; |
||||
width: 12px; |
||||
height: 12px; } |
||||
div.dc-html-legend .dc-legend-item-label { |
||||
line-height: 12px; |
||||
display: table-cell; |
||||
vertical-align: middle; |
||||
padding-left: 3px; |
||||
padding-right: 3px; |
||||
font-size: 0.75em; } |
||||
|
||||
.dc-html-legend-container { |
||||
height: inherit; } |
@ -0,0 +1,301 @@ |
||||
/* Main html/body configurations */ |
||||
html, body { |
||||
max-width: 100%; |
||||
margin-top: 15px; |
||||
font: serif; |
||||
} |
||||
|
||||
#param-correlation { |
||||
flex: 1; |
||||
display: flex; |
||||
flex-direction: column; |
||||
} |
||||
|
||||
#param-correlation > .param { |
||||
display: flex; |
||||
margin: 5px 0px; |
||||
} |
||||
|
||||
#param-correlation > .param > label { |
||||
width: 200px; |
||||
text-align: left; |
||||
padding: 4px 0 0 0px; |
||||
user-select: none; |
||||
-webkit-user-select: none; |
||||
-moz-user-select: none; |
||||
cursor: default; |
||||
} |
||||
|
||||
#param-correlation > .param > input[type='range'] { |
||||
width: 60%; |
||||
margin-right: 10px; |
||||
text-align: left; |
||||
} |
||||
|
||||
#param-correlation > .param > select { |
||||
flex: 0 0 45%; |
||||
width: 100%; |
||||
text-align: left; |
||||
} |
||||
|
||||
#param-correlation > .param > output { |
||||
flex: 1; |
||||
text-align: left; |
||||
padding:5px 0; |
||||
vertical-align: middle; |
||||
user-select: none; |
||||
-webkit-user-select: none; |
||||
-moz-user-select: none; |
||||
cursor: default; |
||||
} |
||||
|
||||
|
||||
/* Control panels on the left side are styled */ |
||||
|
||||
#control-panel { |
||||
flex: 1; |
||||
display: flex; |
||||
flex-direction: column; |
||||
} |
||||
|
||||
#control-panel > .param { |
||||
display: flex; |
||||
margin: 5px 0px; |
||||
} |
||||
|
||||
#control-panel > .param > label { |
||||
width: 200px; |
||||
text-align: left; |
||||
padding: 4px 0 0 8px; |
||||
user-select: none; |
||||
-webkit-user-select: none; |
||||
-moz-user-select: none; |
||||
cursor: default; |
||||
} |
||||
|
||||
#control-panel > .param > input[type='range'] { |
||||
width: 60%; |
||||
margin-right: 10px; |
||||
text-align: left; |
||||
} |
||||
|
||||
#control-panel > .param > select { |
||||
flex: 0 0 45%; |
||||
width: 100%; |
||||
text-align: left; |
||||
} |
||||
|
||||
#control-panel > .param > output { |
||||
flex: 1; |
||||
text-align: left; |
||||
padding:5px 0; |
||||
vertical-align: middle; |
||||
user-select: none; |
||||
-webkit-user-select: none; |
||||
-moz-user-select: none; |
||||
cursor: default; |
||||
} |
||||
|
||||
/* Styling of the main canvas */ |
||||
#modtSNEcanvas { |
||||
width: 50vw; |
||||
height: 50vw; |
||||
border: 1px solid black; |
||||
position: absolute; |
||||
display: block; |
||||
} |
||||
|
||||
/* Styling of the overview canvas */ |
||||
#tSNEcanvas { |
||||
border: 1px solid black; |
||||
width: 11vw; |
||||
height: 11vw; |
||||
position: absolute; |
||||
} |
||||
|
||||
/* A little styling for knn's bar chart */ |
||||
#knnBarChart { |
||||
width: 50vw; |
||||
height: 4.2vw; |
||||
margin-top: 3.6vw; |
||||
border: 1px solid black; |
||||
position: absolute; |
||||
display: block; |
||||
} |
||||
|
||||
/* Styling of the main SVG behind canvas */ |
||||
#modtSNEcanvas_svg { |
||||
width: 50vw; |
||||
height: 50vw; |
||||
opacity: 1.0; |
||||
margin-left: 15px; |
||||
position:absolute; |
||||
z-index: 2; |
||||
} |
||||
|
||||
/* Legend of the Overview t-SNE canvas */ |
||||
div#legend3 { |
||||
height: 11vw; |
||||
width: 11vw; |
||||
text-align: left; |
||||
overflow: auto; |
||||
} |
||||
|
||||
/* Legend of the Overview t-SNE canvas */ |
||||
#legend1 { |
||||
height: 11vw; |
||||
width: 5vw; |
||||
text-align: left; |
||||
} |
||||
|
||||
/* Styling of the ShepardHeatmap */ |
||||
#sheparheat { |
||||
width: 11vw; |
||||
height: 11vw; |
||||
position: absolute; |
||||
} |
||||
|
||||
/* Number of Points font-size */ |
||||
text.legendtitle { |
||||
font-size: 12px; |
||||
} |
||||
|
||||
/* Number of Points font-size */ |
||||
text.label { |
||||
font-size: 10px; |
||||
} |
||||
|
||||
/* Styling of the ShepardHeatmap */ |
||||
svg#legend4 { |
||||
height: 11vw; |
||||
width: 11vw; |
||||
text-align: left; |
||||
overflow: auto; |
||||
} |
||||
|
||||
/* This is the styling for the thumbnails list*/ |
||||
#ThumbNailsList{ |
||||
border: 1px solid black; |
||||
width: 15.4vw; |
||||
height: 8vw; |
||||
padding: 10px 10px 10px 10px; |
||||
} |
||||
|
||||
/* ShepardHeatmap Styling for the different rectangles used there */ |
||||
rect { |
||||
stroke: #E6E6E6; |
||||
stroke-width: 1.5px; |
||||
} |
||||
|
||||
.axis text { |
||||
font-size: 9pt; |
||||
font-family: Consolas, courier; |
||||
fill: #000; |
||||
} |
||||
|
||||
.axis path, |
||||
.axis line { |
||||
fill: none; |
||||
stroke: none; |
||||
} |
||||
|
||||
.d3-tip { |
||||
line-height: 1; |
||||
font: 14px sans-serif; |
||||
padding: 12px; |
||||
background: rgba(0, 0, 0, 0.8); |
||||
color: rgb(185, 185, 185); |
||||
border-radius: 2px; |
||||
} |
||||
|
||||
/* Creates a small triangle extender for the tooltip */ |
||||
.d3-tip:after { |
||||
box-sizing: border-box; |
||||
display: inline; |
||||
font-size: 10px; |
||||
width: 100%; |
||||
line-height: 1; |
||||
color: rgba(0, 0, 0, 0.8); |
||||
content: "\25BC"; |
||||
position: absolute; |
||||
text-align: center; |
||||
} |
||||
|
||||
/* Style northward tooltips differently */ |
||||
.d3-tip.n:after { |
||||
margin: -1px 0 0 0; |
||||
top: 100%; |
||||
left: 0; |
||||
} |
||||
|
||||
/* Dropdown Button */ |
||||
.dropbtn { |
||||
background-color: rgb(185, 185, 185); |
||||
color: black; |
||||
padding: 14px; |
||||
border: none; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
/* Dropdown button on hover & focus */ |
||||
.dropbtn:hover, .dropbtn:focus { |
||||
background-color: lightblue; |
||||
} |
||||
|
||||
/* The container <div> - needed to position the dropdown content */ |
||||
.dropdown { |
||||
position: relative; |
||||
display: inline-block; |
||||
} |
||||
|
||||
/* Dropdown Content (Hidden by Default) */ |
||||
.dropdown-content { |
||||
display: none; |
||||
position: absolute; |
||||
background-color: rgb(146, 168, 177); |
||||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); |
||||
z-index: 1; |
||||
} |
||||
|
||||
/* Links inside the dropdown */ |
||||
.dropdown-content a { |
||||
color: black; |
||||
padding: 12px 16px; |
||||
text-decoration: none; |
||||
display: block; |
||||
} |
||||
|
||||
/* Show the dropdown menu (use JS to add this class to the .dropdown-content container when the user clicks on the dropdown button) */ |
||||
.show {display:block;} |
||||
|
||||
/* This is for the Correlation bar chart */ |
||||
.y.axis line { |
||||
fill: none; |
||||
} |
||||
|
||||
.x.axis line { |
||||
fill: none; |
||||
stroke: #e0e0e0; |
||||
shape-rendering: crispEdges; |
||||
} |
||||
|
||||
.axis path { |
||||
display: none; |
||||
} |
||||
|
||||
.brush .extent { |
||||
fill-opacity: .125; |
||||
shape-rendering: crispEdges; |
||||
} |
||||
|
||||
.resize { |
||||
display: inline !important; /* show when empty */ |
||||
fill: #7A7A7A; |
||||
fill-opacity: 1; |
||||
stroke: #7A7A7A; |
||||
stroke-width: 2px; |
||||
} |
||||
|
||||
.bar { |
||||
/*shape-rendering: crispEdges;*/ |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,100 @@ |
||||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {}; |
||||
/******/ |
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) { |
||||
/******/ |
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) { |
||||
/******/ return installedModules[moduleId].exports; |
||||
/******/ } |
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = { |
||||
/******/ i: moduleId, |
||||
/******/ l: false, |
||||
/******/ exports: {} |
||||
/******/ }; |
||||
/******/ |
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); |
||||
/******/ |
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true; |
||||
/******/ |
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports; |
||||
/******/ } |
||||
/******/ |
||||
/******/ |
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules; |
||||
/******/ |
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules; |
||||
/******/ |
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) { |
||||
/******/ if(!__webpack_require__.o(exports, name)) { |
||||
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); |
||||
/******/ } |
||||
/******/ }; |
||||
/******/ |
||||
/******/ // define __esModule on exports
|
||||
/******/ __webpack_require__.r = function(exports) { |
||||
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { |
||||
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); |
||||
/******/ } |
||||
/******/ Object.defineProperty(exports, '__esModule', { value: true }); |
||||
/******/ }; |
||||
/******/ |
||||
/******/ // create a fake namespace object
|
||||
/******/ // mode & 1: value is a module id, require it
|
||||
/******/ // mode & 2: merge all properties of value into the ns
|
||||
/******/ // mode & 4: return value when already ns object
|
||||
/******/ // mode & 8|1: behave like require
|
||||
/******/ __webpack_require__.t = function(value, mode) { |
||||
/******/ if(mode & 1) value = __webpack_require__(value); |
||||
/******/ if(mode & 8) return value; |
||||
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; |
||||
/******/ var ns = Object.create(null); |
||||
/******/ __webpack_require__.r(ns); |
||||
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); |
||||
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); |
||||
/******/ return ns; |
||||
/******/ }; |
||||
/******/ |
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) { |
||||
/******/ var getter = module && module.__esModule ? |
||||
/******/ function getDefault() { return module['default']; } : |
||||
/******/ function getModuleExports() { return module; }; |
||||
/******/ __webpack_require__.d(getter, 'a', getter); |
||||
/******/ return getter; |
||||
/******/ }; |
||||
/******/ |
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; |
||||
/******/ |
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = ""; |
||||
/******/ |
||||
/******/ |
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = "./js/index.jsx"); |
||||
/******/ }) |
||||
/************************************************************************/ |
||||
/******/ ({ |
||||
|
||||
/***/ "./js/index.jsx": |
||||
/*!**********************!*\ |
||||
!*** ./js/index.jsx ***! |
||||
\**********************/ |
||||
/*! no static exports found */ |
||||
/***/ (function(module, exports) { |
||||
|
||||
eval("throw new Error(\"Module parse failed: Unexpected character '“' (2:18)\\nYou may need an appropriate loader to handle this file type.\\n| // App.jsx\\n> import React from “react”;\\n| export default class App extends React.Component {\\n| render () {\");//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9qcy9pbmRleC5qc3guanMiLCJzb3VyY2VzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./js/index.jsx\n"); |
||||
|
||||
/***/ }) |
||||
|
||||
/******/ }); |
@ -0,0 +1,245 @@ |
||||
<html> |
||||
<head> |
||||
<!-- Ignore Favicon -> Solved the warning... --> |
||||
<link rel="icon" href="data:;base64,iVBORw0KGgo="> |
||||
|
||||
<!-- Importing D3 module --> |
||||
<script src='./modules/d3v3/d3.min.js'></script> |
||||
<script src='./modules/d3/d3.min.js'></script> |
||||
|
||||
|
||||
<script src="./modules/d3-tip/tip.js"></script> |
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.13.0/d3-legend.js"></script> |
||||
<script src="./modules/savage.toggle-switch.js" type="text/javascript"></script> |
||||
|
||||
<script src="./modules/papa/papaparse.min.js"></script> |
||||
<script src="./modules/jquery/jquery.min.js"></script> |
||||
|
||||
<!-- Basic scripts --> |
||||
<script src="./js/tsne.js"></script> |
||||
<script src="./js/k-nearest.js"></script> |
||||
<script src="./js/checkbox.js"></script> |
||||
<script src="./js/data_form_handler.js"></script> |
||||
<script src="./lasso.js"></script> |
||||
|
||||
<!-- CSS --> |
||||
<link rel="stylesheet" href="./css/style.css"/> |
||||
<link rel="stylesheet" href="./css/bootstrap.min.css"/> |
||||
<link rel="stylesheet" href="./css/dc.css"/> |
||||
|
||||
<!-- Bootstrap --> |
||||
<script src="./modules/bootstrap.min.js"></script> |
||||
|
||||
|
||||
</head> |
||||
|
||||
<body> |
||||
|
||||
<div class="container-fluid"> |
||||
<div class="row"> |
||||
<div class="col-md-3"> |
||||
<div class="panel panel-default"> |
||||
<div class="panel-heading"> |
||||
<h3 class="panel-title">t-SNE Overview</h3> |
||||
</div> |
||||
<div class="row"> |
||||
<div class="panel-body"> |
||||
<div class="col-md-6"> |
||||
<canvas id = "tSNEcanvas"></canvas> |
||||
</div> |
||||
<div class="col-md-2"> |
||||
<div class="legend" id = "legend3"></div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div id="control-panel"> |
||||
<div class="param"> |
||||
<label for="param-lim">Points radius scaling factor</label> |
||||
<input id="param-lim" type="range" min="4" max="20" value="10", step="4"> |
||||
<output for="param-lim" id="param-lim-value">10</output> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="col-md-6"> |
||||
<svg id="modtSNEcanvas_svg"></svg> |
||||
<canvas id = "modtSNEcanvas" ></canvas> |
||||
</div> |
||||
<div class="col-md-1"> |
||||
<svg id="legend1"></svg> |
||||
</div> |
||||
<div class="col-md-2"> |
||||
<div id="ThumbNailsList"> |
||||
<label for="male">Neighborhood Preservation</label> |
||||
<select id="param-neighborhoodMapping" name ="param-neighborhoodMapping"> |
||||
<option selected="selected" value="color">Color</option> |
||||
<option value="size">Size</option> |
||||
</select> |
||||
<label for="male">Final Cost (Kullback-Leibler)</label> |
||||
<select id="param-divergenceMapping" name ="param-divergenceMapping"> |
||||
<option value="color">Color</option> |
||||
<option selected="selected" value="size">Size</option> |
||||
</select> |
||||
<div id="param-correlation"> |
||||
<div class="param"> |
||||
<label for="param-corr">Correlation threshold</label> |
||||
<input id="param-corr" type="range" min="0" max="750" value="150", step="50"> |
||||
<output for="param-corr" id="param-corr-value">150</output> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="row"> |
||||
<div class="col-md-3"> |
||||
<div class="panel panel-default"> |
||||
<div class="panel-heading"> |
||||
<h3 class="panel-title">Shepard Heatmap</h3> |
||||
</div> |
||||
<div class="panel-body"> |
||||
<div class="row"> |
||||
<div class="col-md-6"> |
||||
<svg id="sheparheat"></svg> |
||||
</div> |
||||
<div class="col-md-2"> |
||||
<svg id="legend4"></svg> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="col-md-3 col-md-offset-6"> |
||||
<svg id="correlation"></svg> |
||||
</div> |
||||
</div> |
||||
<div class="row"> |
||||
<div class="col-md-3"> |
||||
<div class="panel panel-default"> |
||||
<div class="panel-heading"> |
||||
<h3 class="panel-title">t-SNE Parameters</h3> |
||||
</div> |
||||
<div class="panel-body"> |
||||
<div id="control-panel" data-sr="enter left over 8s"> |
||||
<div class="param"> |
||||
<label id="data" for="param-dataset">Data sets</label> |
||||
<select id="param-dataset" name="param-dataset" onChange="changeDataset(this.value);"> |
||||
<option value="winequality-red.csv">Red Wine - Quality</option> |
||||
<option value="iris.csv" selected>Iris</option> |
||||
<option value="mnist.csv" >Mnist</option> |
||||
<option value="Frogs_MFCCs_s.csv" >Frogs</option> |
||||
<option value="empty">Add New File</option> |
||||
</select> |
||||
</div> |
||||
<div class="param"> |
||||
<label for="param-perplexity">Perplexity</label> |
||||
<input id="param-perplexity" type="range" min="2" max="100" value="30", step="1"> |
||||
<output for="param-perplexity" id="param-perplexity-value">30</output> |
||||
</div> |
||||
<div class="param"> |
||||
<label for="param-learningrate">Learning rate</label> |
||||
<input id="param-learningrate" type="range" min="1" max="300" value="10", step="1"> |
||||
<output for="param-learningrate" id="param-learningrate-value">10</output> |
||||
</div> |
||||
<div class="param"> |
||||
<label for="param-maxiter">Max iterations</label> |
||||
<input id="param-maxiter" type="range" min="10" max="1000" value="10", step="10"> |
||||
<output for="param-maxiter" id="param-maxiter-value">10</output> |
||||
</div> |
||||
<div class="param"> |
||||
<label for="param-distance">Distance metric</label> |
||||
<select id="param-distance" name="param-distance"> |
||||
<option value="euclideanDist" selected>Euclidean distance</option> |
||||
<option value="jaccardDist">Jaccard dissimilarity</option> |
||||
</select> |
||||
<output for="param-distance" id="param-distance-value"></output> |
||||
</div> |
||||
<div class="param"> |
||||
<label for="param-transform">Data transform</label> |
||||
<select id="param-transform" name="param-transform"> |
||||
<option value="noTrans" selected>No transform</option> |
||||
<option value="logTrans">Log10</option> |
||||
<option value="asinhTrans">asinh</option> |
||||
<option value="binTrans">Binarize</option> |
||||
</select> |
||||
<output for="param-transform" id="param-transform-value"></output> |
||||
</div> |
||||
<p><div id="run-button"><button class="btn btn-primary btn-block" onclick="getData();">Run New tSNE</button></div></p> |
||||
<div id="cost"></div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="row"> |
||||
<div class="col-md-3"> |
||||
<div class="panel panel-default"> |
||||
<div class="panel-heading"> |
||||
<h3 class="panel-title">History Thumbnails</h3> |
||||
</div> |
||||
<div class="panel-body"> |
||||
<div id="toggleLassoAndLine"></div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class = col-md-6> |
||||
<svg id="knnBarChart"></svg> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<script> |
||||
$('#param-neighborHood').bind('input', function () { $('#param-neighborhoodMapping-value').text($('#param-neighborhoodMapping').val()); }); |
||||
$('#param-divergence').bind('input', function () { $('#param-divergenceMapping-value').text($('#param-divergenceMapping').val()); }); |
||||
$('#param-lim').bind('input', function () { $('#param-lim-value').text($('#param-lim').val()); }); |
||||
$('#param-corr').bind('input', function () { $('#param-corr-value').text($('#param-corr').val()); }); |
||||
$('#param-perplexity').bind('input', function () { $('#param-perplexity-value').text($('#param-perplexity').val()); }); |
||||
$('#param-earlyexag').bind('input', function () { $('#param-earlyexag-value').text($('#param-earlyexag').val()); }); |
||||
$('#param-learningrate').bind('input', function () { $('#param-learningrate-value').text($('#param-learningrate').val()); }); |
||||
$('#param-maxiter').bind('input', function () { $('#param-maxiter-value').text($('#param-maxiter').val()); }); |
||||
SaVaGe.ToggleSwitch({container: "#toggleLassoAndLine", onChange: function(toggler){ setToggle(toggler.getValue()); }} ); |
||||
</script> |
||||
<script> |
||||
/* On resize refresh the shepardHeatmap */ |
||||
window.onresize = function(event) { |
||||
if ( document.getElementById('cost').hasChildNodes() ) { |
||||
// Clear legend for the shepardHeatmap |
||||
var svgLegend = d3.select("#legend4"); |
||||
svgLegend.selectAll("*").remove(); |
||||
|
||||
// Clear the SheapHeardmap before refreshing |
||||
var svg = d3.select("#sheparheat"); |
||||
svg.selectAll("*").remove(); |
||||
|
||||
// Call the ShepardHeatmap again to be redrawn |
||||
ShepardHeatMap(); |
||||
} |
||||
|
||||
} |
||||
|
||||
/* When the user clicks on the button, |
||||
toggle between hiding and showing the dropdown content */ |
||||
function myFunction() { |
||||
document.getElementById("myDropdown").classList.toggle("show"); |
||||
} |
||||
|
||||
// Close the dropdown menu if the user clicks outside of it |
||||
window.onclick = function(event) { |
||||
if (!event.target.matches('.dropbtn')) { |
||||
var dropdowns = document.getElementsByClassName("dropdown-content"); |
||||
var i; |
||||
for (i = 0; i < dropdowns.length; i++) { |
||||
var openDropdown = dropdowns[i]; |
||||
if (openDropdown.classList.contains('show')) { |
||||
openDropdown.classList.remove('show'); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<!-- |
||||
Load the visualization script |
||||
--> |
||||
<script src="./js/tsne_vis.js"></script> |
||||
|
||||
</body> |
||||
</html> |
@ -0,0 +1,113 @@ |
||||
function d3CheckBox () { |
||||
|
||||
var size = 20, |
||||
x = 0, |
||||
y = 0, |
||||
rx = 0, |
||||
ry = 0, |
||||
markStrokeWidth = 3, |
||||
boxStrokeWidth = 3, |
||||
checked = false, |
||||
clickEvent; |
||||
|
||||
function checkBox (selection) { |
||||
|
||||
var g = selection.append("g"), |
||||
box = g.append("rect") |
||||
.attr("width", size) |
||||
.attr("height", size) |
||||
.attr("x", x) |
||||
.attr("y", y) |
||||
.attr("rx", rx) |
||||
.attr("ry", ry) |
||||
.style({ |
||||
"fill-opacity": 0, |
||||
"stroke-width": boxStrokeWidth, |
||||
"stroke": "black" |
||||
}); |
||||
|
||||
//Data to represent the check mark
|
||||
var coordinates = [ |
||||
{x: x + (size / 8), y: y + (size / 3)}, |
||||
{x: x + (size / 2.2), y: (y + size) - (size / 4)}, |
||||
{x: (x + size) - (size / 8), y: (y + (size / 10))} |
||||
]; |
||||
|
||||
var line = d3.svg.line() |
||||
.x(function(d){ return d.x; }) |
||||
.y(function(d){ return d.y; }) |
||||
.interpolate("basic"); |
||||
|
||||
var mark = g.append("path") |
||||
.attr("d", line(coordinates)) |
||||
.style({ |
||||
"stroke-width" : markStrokeWidth, |
||||
"stroke" : "black", |
||||
"fill" : "none", |
||||
"opacity": (checked)? 1 : 0 |
||||
}); |
||||
|
||||
g.on("click", function () { |
||||
checked = !checked; |
||||
mark.style("opacity", (checked)? 1 : 0); |
||||
|
||||
if(clickEvent) |
||||
clickEvent(); |
||||
|
||||
d3.event.stopPropagation(); |
||||
}); |
||||
|
||||
} |
||||
|
||||
checkBox.size = function (val) { |
||||
size = val; |
||||
return checkBox; |
||||
} |
||||
|
||||
checkBox.x = function (val) { |
||||
x = val; |
||||
return checkBox; |
||||
} |
||||
|
||||
checkBox.y = function (val) { |
||||
y = val; |
||||
return checkBox; |
||||
} |
||||
|
||||
checkBox.rx = function (val) { |
||||
rx = val; |
||||
return checkBox; |
||||
} |
||||
|
||||
checkBox.ry = function (val) { |
||||
ry = val; |
||||
return checkBox; |
||||
} |
||||
|
||||
checkBox.markStrokeWidth = function (val) { |
||||
markStrokeWidth = val; |
||||
return checkBox; |
||||
} |
||||
|
||||
checkBox.boxStrokeWidth = function (val) { |
||||
boxStrokeWidth = val; |
||||
return checkBox; |
||||
} |
||||
|
||||
checkBox.checked = function (val) { |
||||
|
||||
if(val === undefined) { |
||||
return checked; |
||||
} else { |
||||
checked = val; |
||||
return checkBox; |
||||
} |
||||
} |
||||
|
||||
checkBox.clickEvent = function (val) { |
||||
clickEvent = val; |
||||
return checkBox; |
||||
} |
||||
|
||||
return checkBox; |
||||
} |
@ -0,0 +1,16 @@ |
||||
|
||||
function changeDataset(value) { |
||||
var format = value.split("."); //get the actual format
|
||||
|
||||
if (format[value.split(".").length-1] == "csv") { |
||||
}else{ |
||||
d3.select("#data").select("input").remove(); |
||||
d3.select("#data") |
||||
.append("input") |
||||
.attr("type", "file") |
||||
.on("change", function() { |
||||
var file = d3.event.target.files[0]; |
||||
getfile(file); |
||||
}) |
||||
} |
||||
} |
@ -0,0 +1,270 @@ |
||||
function kNearestNeighbors(k, points, points2d) { |
||||
|
||||
var averagekNN = 0; |
||||
var Distances = []; |
||||
var Distances2d = []; |
||||
//var sortedDistances = [];
|
||||
var point = points; |
||||
var point2d = points2d; |
||||
/* |
||||
* Loop through our nodes and look for unknown types. |
||||
*/ |
||||
for (var i=0; i<point.length; i++){ |
||||
/* |
||||
if (this.nodes.hasOwnProperty(i)) { |
||||
|
||||
if ( ! this.nodes[i].type) {*/ |
||||
/* |
||||
* If the node is an unknown type, clone the nodes list and then measure distances. |
||||
*/ |
||||
|
||||
/* Clone nodes *//* |
||||
this.nodes[i].neighbors = []; |
||||
|
||||
for (var j in this.nodes) { |
||||
if ( ! this.nodes[j].type) |
||||
continue; |
||||
this.nodes[i].neighbors.push( new KNN.Item(this.nodes[j]) ); |
||||
}*/ |
||||
|
||||
/* Measure distances */ |
||||
Distances[i] = measureDistances(point[i],points); |
||||
Distances2d[i] = measureDistances(point2d[i],points2d); |
||||
Distances[i].sort(); |
||||
Distances2d[i].sort(); |
||||
/* Sort by distance */ |
||||
//sortByDistance();
|
||||
/* Guess type */ |
||||
//this.type = this.nodes[i].guessType(this.k);
|
||||
} |
||||
//console.log(Distances);
|
||||
sum = LimitKNeighbor(Distances, k); |
||||
sum2d = LimitKNeighbor(Distances2d, k); |
||||
averagekNN = Math.round((sum2d / sum) * 100) / 100; |
||||
return averagekNN; |
||||
|
||||
} |
||||
|
||||
function measureDistances(point,points) { |
||||
var neighborDistances = []; |
||||
var checkForSame = []; |
||||
for (var j=0; j<points.length; j++){ |
||||
|
||||
neighborDistances[j] = Math.sqrt( (point.x-points[j].x)*(point.x-points[j].x) + (point.y-points[j].y)*(point.y-points[j].y) ); |
||||
} |
||||
|
||||
//neighborDistances = sortByDistance(neighborDistances);
|
||||
return neighborDistances; |
||||
} |
||||
|
||||
function LimitKNeighbor(Distances, k) { |
||||
var DistancesSliced = []; |
||||
var sum = 0; |
||||
for (var i = 0; i < Distances.length; i++) { |
||||
//for (var j = 0; j < Distances.length; j++) {
|
||||
DistancesSliced[i] = Distances[i].slice(0,k); |
||||
for (var j = 0 ; j < k ; j++){ |
||||
sum = DistancesSliced[i][j] + sum; |
||||
} |
||||
//sum = DistancesSliced[i] + sum;
|
||||
//}
|
||||
} |
||||
//console.log(sum);
|
||||
return sum; |
||||
//console.log(DistancesBetweenAllThePoints[0][0]);
|
||||
//console.log(DistancesBetweenAllThePoints);
|
||||
/* |
||||
var guess = {type: false, count: 0}; |
||||
|
||||
for (var type in types) { |
||||
if (types[type] > guess.count) { |
||||
guess.type = type; |
||||
guess.count = types[type]; |
||||
} |
||||
} |
||||
|
||||
this.guess = guess; |
||||
|
||||
return types; |
||||
}; |
||||
|
||||
calculateRanges = function() { |
||||
this.areas = {min: 1000000, max: 0}; |
||||
this.rooms = {min: 1000000, max: 0}; |
||||
|
||||
for (var i in this.nodes) { |
||||
if (this.nodes.hasOwnProperty(i)) { |
||||
|
||||
if (this.nodes[i].rooms < this.rooms.min) { |
||||
this.rooms.min = this.nodes[i].rooms; |
||||
} |
||||
|
||||
if (this.nodes[i].rooms > this.rooms.max) { |
||||
this.rooms.max = this.nodes[i].rooms; |
||||
} |
||||
|
||||
if (this.nodes[i].area < this.areas.min) { |
||||
this.areas.min = this.nodes[i].area; |
||||
} |
||||
|
||||
if (this.nodes[i].area > this.areas.max) { |
||||
this.areas.max = this.nodes[i].area; |
||||
} |
||||
} |
||||
} |
||||
|
||||
};*/ |
||||
} |
||||
|
||||
/* |
||||
function findNearest(point) { |
||||
|
||||
// TODO: make this more efficient by not recalculating quadtree at
|
||||
// each call of findNearest()
|
||||
|
||||
// Extract points from the data array
|
||||
//points = data.map(function(d) { return [x(d), y(d)]; });
|
||||
|
||||
// Add quadtree info to the points
|
||||
//nodes = quadtreeify(points);
|
||||
|
||||
// Flag k-nearest points by adding `selected` property set to `true`
|
||||
kNearest(new Array(nodes), [], point); |
||||
|
||||
// Return nearest points along with indices from origianl `data` array
|
||||
return points |
||||
.map(function(d, i) { |
||||
var datum = [d[0], d[1]]; |
||||
datum.i = i; |
||||
return d.selected ? datum : null;
|
||||
}) |
||||
.filter(function(d) { return d !== null; }); |
||||
} |
||||
|
||||
findNearest.extent = function(_) { |
||||
if (!arguments.length) return extent; |
||||
extent = _; |
||||
//quadtree.extent(extent);
|
||||
return findNearest; |
||||
}; |
||||
|
||||
findNearest.data = function(_) { |
||||
if (!arguments.length) return data; |
||||
data = _; |
||||
return findNearest; |
||||
}; |
||||
|
||||
findNearest.k = function(_) { |
||||
if (!arguments.length) return k; |
||||
k = _; |
||||
return findNearest; |
||||
}; |
||||
|
||||
findNearest.x = function(_) { |
||||
if (!arguments.length) return x; |
||||
x = _; |
||||
return findNearest; |
||||
}; |
||||
|
||||
findNearest.y = function(_) { |
||||
if (!arguments.length) return y; |
||||
y = _; |
||||
return findNearest; |
||||
}; |
||||
|
||||
return findNearest; |
||||
|
||||
// Add quadtree information to each point (i.e., rectangles, depth, ...)
|
||||
function quadtreeify(points) { |
||||
var nodes = quadtree(points); |
||||
nodes.depth = 0; |
||||
nodes.visit(function(node, x1, y1, x2, y2) { |
||||
node.x1 = x1; |
||||
node.y1 = y1; |
||||
node.x2 = x2; |
||||
node.y2 = y2; |
||||
for (var i = 0; i < 4; i++) { |
||||
if (node.nodes[i]) node.nodes[i].depth = node.depth + 1; |
||||
} |
||||
}); |
||||
return nodes; |
||||
} |
||||
|
||||
// calculate the euclidean distance of two points with coordinates a(ax, ay) and b(bx, by)
|
||||
function euclideanDistance(ax, ay, bx, by) { |
||||
return Math.sqrt(Math.pow(ax - bx, 2) + Math.pow(ay - by, 2)); |
||||
} |
||||
|
||||
// calculate minimum distance between search point rectangles
|
||||
function minDistance(x, y, x1, y1, x2, y2) { |
||||
var dx1 = x - x1, |
||||
dx2 = x - x2, |
||||
dy1 = y - y1, |
||||
dy2 = y - y2; |
||||
|
||||
// x is between x1 and x2
|
||||
if (dx1 * dx2 < 0) { |
||||
// (x, y) is inside the rectangle
|
||||
if (dy1 * dy2 < 0) { |
||||
return 0; // return 0 as a point in the rectangle
|
||||
} |
||||
return Math.min(Math.abs(dy1), Math.abs(dy2)); |
||||
} |
||||
|
||||
// y is between y1 and y2 (and not inside rectangle)
|
||||
if (dy1 * dy2 < 0) { |
||||
return Math.min(Math.abs(dx1), Math.abs(dx2)); |
||||
} |
||||
return Math.min(
|
||||
Math.min(euclideanDistance(x,y,x1,y1), euclideanDistance(x,y,x2,y2)),
|
||||
Math.min(euclideanDistance(x,y,x1,y2), euclideanDistance(x,y,x2,y1)) |
||||
); |
||||
} |
||||
|
||||
// Find the nodes within the specified rectangle (used recursively)
|
||||
function kNearest(bestQueue, resultQueue, point) { |
||||
var x = point[0], |
||||
y = point[1]; |
||||
|
||||
// sort children according to their minDistance/euclideanDistance to search point
|
||||
bestQueue.sort(function(a, b) { |
||||
// add minDistance to nodes if not there already
|
||||
[a, b].forEach(function(d) { |
||||
if (d.minDistance === undefined) { |
||||
d.scanned = true; |
||||
if (d.leaf) { |
||||
d.point.scanned = true; |
||||
d.minDistance = euclideanDistance(x, y, d.x, d.y); |
||||
} |
||||
else { |
||||
d.minDistance = minDistance(x, y, d.x1, d.y1, d.x2, d.y2); |
||||
} |
||||
} |
||||
}); |
||||
return b.minDistance - a.minDistance; |
||||
}); |
||||
|
||||
// add nearest leafs (if any)
|
||||
for (var i = bestQueue.length - 1; i >= 0; i--) { |
||||
var elem = bestQueue[i]; |
||||
if (elem.leaf) { |
||||
elem.point.selected = true; |
||||
bestQueue.pop(); |
||||
resultQueue.push(elem); |
||||
} else { break; } |
||||
if (resultQueue.length >= k) break; |
||||
} |
||||
|
||||
// check if enough points found
|
||||
if (resultQueue.length >= k || bestQueue.length == 0) { return; } |
||||
else { |
||||
// ...otherwise add child nodes to bestQueue and recurse
|
||||
var visitedNode = bestQueue.pop(); |
||||
visitedNode.visited = true; |
||||
visitedNode.nodes.forEach(function(d) { |
||||
bestQueue.push(d); |
||||
}); |
||||
kNearest(bestQueue, resultQueue, point); |
||||
} |
||||
} |
||||
*/ |
@ -0,0 +1,340 @@ |
||||
// create main global object
|
||||
var tsnejs = tsnejs || { REVISION: 'ALPHA' }; |
||||
|
||||
(function(global) { |
||||
"use strict"; |
||||
|
||||
// utility function
|
||||
var assert = function(condition, message) { |
||||
if (!condition) { throw message || "Assertion failed"; } |
||||
} |
||||
|
||||
// syntax sugar
|
||||
var getopt = function(opt, field, defaultval) { |
||||
if(opt.hasOwnProperty(field)) { |
||||
return opt[field]; |
||||
} else { |
||||
return defaultval; |
||||
} |
||||
} |
||||
|
||||
// return 0 mean unit standard deviation random number
|
||||
var return_v = false; |
||||
var v_val = 0.0; |
||||
var gaussRandom = function() { |
||||
if(return_v) { |
||||
return_v = false; |
||||
return v_val; |
||||
} |
||||
var u = 2*Math.random()-1; |
||||
var v = 2*Math.random()-1; |
||||
var r = u*u + v*v; |
||||
if(r == 0 || r > 1) return gaussRandom(); |
||||
var c = Math.sqrt(-2*Math.log(r)/r); |
||||
v_val = v*c; // cache this for next function call for efficiency
|
||||
return_v = true; |
||||
return u*c; |
||||
} |
||||
|
||||
// return random normal number
|
||||
var randn = function(mu, std){ return mu+gaussRandom()*std; } |
||||
|
||||
// utilitity that creates contiguous vector of zeros of size n
|
||||
var zeros = function(n) { |
||||
if(typeof(n)==='undefined' || isNaN(n)) { return []; } |
||||
if(typeof ArrayBuffer === 'undefined') { |
||||
// lacking browser support
|
||||
var arr = new Array(n); |
||||
for(var i=0;i<n;i++) { arr[i]= 0; } |
||||
return arr; |
||||
} else { |
||||
return new Float64Array(n); // typed arrays are faster
|
||||
} |
||||
} |
||||
|
||||
// utilitity that creates contiguous vector of ones of size n
|
||||
var ones = function(n) { |
||||
if(typeof(n)==='undefined' || isNaN(n)) { return []; } |
||||
// lacking browser support
|
||||
var arr = new Array(n); |
||||
for(var i=0;i<n;i++) { arr[i]= 1; } |
||||
return arr; |
||||
} |
||||
|
||||
// utility that returns 2d array filled with random numbers
|
||||
// or with value s, if provided
|
||||
var randn2d = function(n,d,s) { |
||||
var uses = typeof s !== 'undefined'; |
||||
var x = []; |
||||
for(var i=0;i<n;i++) { |
||||
var xhere = []; |
||||
for(var j=0;j<d;j++) { |
||||
if(uses) { |
||||
xhere.push(s); |
||||
} else { |
||||
xhere.push(randn(0.0, 1e-4)); |
||||
} |
||||
} |
||||
x.push(xhere); |
||||
} |
||||
return x; |
||||
} |
||||
|
||||
// compute (p_{i|j} + p_{j|i})/(2n)
|
||||
var d2p = function(D, perplexity, tol) { |
||||
var Nf = Math.sqrt(D.length); // this better be an integer
|
||||
var N = Math.floor(Nf); |
||||
assert(N === Nf, "D should have square number of elements."); |
||||
var Htarget = Math.log(perplexity); // target entropy of distribution
|
||||
var P = zeros(N * N); // temporary probability matrix
|
||||
var prow = zeros(N); // a temporary storage compartment
|
||||
var beta = ones(N); // a temporary storage compartment
|
||||
for(var i=0;i<N;i++) { |
||||
var betamin = -Infinity; |
||||
var betamax = Infinity; |
||||
var done = false; |
||||
var maxtries = 50; |
||||
|
||||
// perform binary search to find a suitable precision beta
|
||||
// so that the entropy of the distribution is appropriate
|
||||
var num = 0; |
||||
while(!done) { |
||||
//debugger;
|
||||
|
||||
// compute entropy and kernel row with beta precision
|
||||
var psum = 0.0; |
||||
for(var j=0;j<N;j++) { |
||||
var pj = Math.exp(- Math.pow(D[i*N+j], 2) * beta[i]); |
||||
if(i===j) { pj = 0; } // we dont care about diagonals
|
||||
prow[j] = pj; |
||||
psum += pj; |
||||
} |
||||
// normalize p and compute entropy
|
||||
var Hhere = 0.0; |
||||
for(var j=0;j<N;j++) { |
||||
var pj = prow[j] / psum; |
||||
prow[j] = pj; |
||||
if(pj > 1e-7) Hhere -= pj * Math.log(pj); |
||||
} |
||||
|
||||
// adjust beta based on result
|
||||
if(Hhere > Htarget) { |
||||
// entropy was too high (distribution too diffuse)
|
||||
// so we need to increase the precision for more peaky distribution
|
||||
betamin = beta[i]; // move up the bounds
|
||||
if(betamax === Infinity) { beta[i] = beta[i] * 2; } |
||||
else { beta[i] = (beta[i] + betamax) / 2; } |
||||
|
||||
} else { |
||||
// converse case. make distrubtion less peaky
|
||||
betamax = beta[i]; |
||||
if(betamin === -Infinity) { beta = beta / 2; } |
||||
else { beta[i] = (beta[i] + betamin) / 2; } |
||||
} |
||||
|
||||
// stopping conditions: too many tries or got a good precision
|
||||
num++; |
||||
if(Math.abs(Hhere - Htarget) < tol) { done = true; } |
||||
if(num >= maxtries) { done = true; } |
||||
} |
||||
//console.log('data point ' + i + ' gets precision ' + beta[i] + ' after ' + num + ' binary search steps.');
|
||||
// copy over the final prow to P at row i
|
||||
for(var j=0;j<N;j++) { P[i*N+j] = prow[j]; } |
||||
|
||||
} // end loop over examples i
|
||||
|
||||
// symmetrize P and normalize it to sum to 1 over all ij
|
||||
var Pout = zeros(N * N); |
||||
var N2 = N*2; |
||||
for(var i=0;i<N;i++) { |
||||
for(var j=0;j<N;j++) { |
||||
Pout[i*N+j] = Math.max((P[i*N+j] + P[j*N+i])/N2, 1e-100); |
||||
} |
||||
} |
||||
|
||||
return [Pout, beta]; |
||||
} |
||||
|
||||
// helper function
|
||||
function sign(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; } |
||||
|
||||
var tSNE = function(opt) { |
||||
|
||||
var opt = opt || {}; |
||||
this.perplexity = getopt(opt, "perplexity", 30); // effective number of nearest neighbors
|
||||
this.dim = getopt(opt, "dim", 2); // by default 2-D tSNE
|
||||
this.epsilon = getopt(opt, "epsilon", 10); // learning rate
|
||||
this.iter = 0; |
||||
|
||||
} |
||||
|
||||
tSNE.prototype = { |
||||
|
||||
// this function takes a given distance matrix and creates
|
||||
// matrix P from them.
|
||||
// D is assumed to be provided as a list of lists, and should be symmetric
|
||||
initDataDist: function(D) { |
||||
var N = D.length; |
||||
assert(N > 0, " X is empty? You must have some data!"); |
||||
// convert D to a (fast) typed array version
|
||||
var dists = zeros(N * N); // allocate contiguous array
|
||||
for(var i=0;i<N;i++) { |
||||
for(var j=i+1;j<N;j++) { |
||||
var d = D[i][j]; |
||||
dists[i*N+j] = d; |
||||
dists[j*N+i] = d; |
||||
} |
||||
} |
||||
var results = d2p(dists, this.perplexity, 1e-4); |
||||
this.P = results[0]; |
||||
this.beta = results[1]; |
||||
this.N = N; |
||||
this.initSolution(); // refresh this
|
||||
}, |
||||
|
||||
// (re)initializes the solution to random
|
||||
initSolution: function() { |
||||
// generate random solution to t-SNE
|
||||
this.Y = randn2d(this.N, this.dim); // the solution
|
||||
this.gains = randn2d(this.N, this.dim, 1.0); // step gains to accelerate progress in unchanging directions
|
||||
this.ystep = randn2d(this.N, this.dim, 0.0); // momentum accumulator
|
||||
this.iter = 0; |
||||
}, |
||||
|
||||
// return pointer to current solution
|
||||
getSolution: function() { |
||||
return this.Y; |
||||
}, |
||||
|
||||
// perform a single step of optimization to improve the embedding
|
||||
step: function() { |
||||
this.iter += 1; |
||||
var N = this.N; |
||||
|
||||
var cg = this.costGrad(this.Y); // evaluate gradient
|
||||
var cost = cg.cost; |
||||
var cost_each = cg.cost_each; |
||||
var grad = cg.grad; |
||||
|
||||
// perform gradient step
|
||||
var ymean = zeros(this.dim); |
||||
for(var i=0;i<N;i++) { |
||||
for(var d=0;d<this.dim;d++) { |
||||
var gid = grad[i][d]; |
||||
var sid = this.ystep[i][d]; |
||||
var gainid = this.gains[i][d]; |
||||
// compute gain update
|
||||
var newgain = sign(gid) === sign(sid) ? gainid * 0.8 : gainid + 0.2; |
||||
if(newgain < 0.01) newgain = 0.01; // clamp
|
||||
this.gains[i][d] = newgain; // store for next turn
|
||||
|
||||
// compute momentum step direction
|
||||
var momval = this.iter < 250 ? 0.5 : 0.8; |
||||
var newsid = momval * sid - this.epsilon * newgain * grad[i][d]; |
||||
this.ystep[i][d] = newsid; // remember the step we took
|
||||
|
||||
// step!
|
||||
this.Y[i][d] += newsid; |
||||
|
||||
ymean[d] += this.Y[i][d]; // accumulate mean so that we can center later
|
||||
} |
||||
} |
||||
// reproject Y to be zero mean
|
||||
for(var i=0;i<N;i++) { |
||||
for(var d=0;d<this.dim;d++) { |
||||
this.Y[i][d] -= ymean[d]/N; |
||||
} |
||||
} |
||||
|
||||
//if(this.iter%100===0) console.log('iter ' + this.iter + ', cost: ' + cost);
|
||||
return [cost, cost_each]; // return current cost
|
||||
}, |
||||
|
||||
// for debugging: gradient check
|
||||
debugGrad: function() { |
||||
var N = this.N; |
||||
|
||||
var cg = this.costGrad(this.Y); // evaluate gradient
|
||||
var cost = cg.cost; |
||||
var grad = cg.grad; |
||||
|
||||
var e = 1e-5; |
||||
for(var i=0;i<N;i++) { |
||||
for(var d=0;d<this.dim;d++) { |
||||
var yold = this.Y[i][d]; |
||||
|
||||
this.Y[i][d] = yold + e; |
||||
var cg0 = this.costGrad(this.Y); |
||||
|
||||
this.Y[i][d] = yold - e; |
||||
var cg1 = this.costGrad(this.Y); |
||||
|
||||
var analytic = grad[i][d]; |
||||
var numerical = (cg0.cost - cg1.cost) / ( 2 * e ); |
||||
console.log(i + ',' + d + ': gradcheck analytic: ' + analytic + ' vs. numerical: ' + numerical); |
||||
|
||||
this.Y[i][d] = yold; |
||||
} |
||||
} |
||||
}, |
||||
|
||||
// return cost and gradient, given an arrangement
|
||||
costGrad: function(Y) { |
||||
var N = this.N; |
||||
var dim = this.dim; // dim of output space
|
||||
var P = this.P; |
||||
var pmul = this.iter < 100 ? 4 : 1; // trick that helps with local optima
|
||||
|
||||
// compute current Q distribution, unnormalized first
|
||||
var Qu = zeros(N * N); |
||||
var qsum = 0.0; |
||||
for(var i=0;i<N;i++) { |
||||
for(var j=i+1;j<N;j++) { |
||||
var dsum = 0.0; |
||||
for(var d=0;d<dim;d++) { |
||||
var dhere = Y[i][d] - Y[j][d]; |
||||
dsum += dhere * dhere; |
||||
} |
||||
var qu = 1.0 / (1.0 + dsum); // Student t-distribution
|
||||
Qu[i*N+j] = qu; |
||||
Qu[j*N+i] = qu; |
||||
qsum += 2 * qu; |
||||
} |
||||
} |
||||
// normalize Q distribution to sum to 1
|
||||
var NN = N*N; |
||||
var Q = zeros(NN); |
||||
for(var q=0;q<NN;q++) { Q[q] = Math.max(Qu[q] / qsum, 1e-100); } |
||||
|
||||
var cost = 0.0; |
||||
var cost_each = zeros(N); |
||||
var grad = []; |
||||
for(var i=0;i<N;i++) { |
||||
var gsum = new Array(dim); // init grad for point i
|
||||
for(var d=0;d<dim;d++) { gsum[d] = 0.0; } |
||||
for(var j=0;j<N;j++) { |
||||
cost += - P[i*N+j] * Math.log(Q[i*N+j]); // accumulate cost (the non-constant portion at least...)
|
||||
cost_each[j] = - P[i*N+j] * Math.log(Q[i*N+j]); // cost for each point
|
||||
var premult = 4 * (pmul * P[i*N+j] - Q[i*N+j]) * Qu[i*N+j]; |
||||
for(var d=0;d<dim;d++) { |
||||
gsum[d] += premult * (Y[i][d] - Y[j][d]); |
||||
} |
||||
} |
||||
grad.push(gsum); |
||||
} |
||||
return {cost: cost, grad: grad, cost_each: cost_each}; |
||||
} |
||||
} |
||||
|
||||
global.tSNE = tSNE; // export tSNE class
|
||||
})(tsnejs); |
||||
|
||||
// export the library to window, or to module in nodejs
|
||||
(function(lib) { |
||||
"use strict"; |
||||
if (typeof module === "undefined" || typeof module.exports === "undefined") { |
||||
window.tsnejs = lib; // in ordinary browser attach library to window
|
||||
} else { |
||||
module.exports = lib; // in nodejs
|
||||
} |
||||
})(tsnejs); |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,125 @@ |
||||
//import * as d3 from 'd3';
|
||||
|
||||
function polygonToPath(polygon) { |
||||
return ("M" + (polygon.map(function (d) { return d.join(','); }).join('L'))); |
||||
} |
||||
|
||||
function distance(pt1, pt2) { |
||||
return Math.sqrt(Math.pow( (pt2[0] - pt1[0]), 2 ) + Math.pow( (pt2[1] - pt1[1]), 2 )); |
||||
} |
||||
|
||||
function lasso() { |
||||
var dispatch = d3.dispatch('start', 'end'); |
||||
|
||||
// distance last point has to be to first point before it auto closes when mouse is released
|
||||
var closeDistance = 75; |
||||
|
||||
function lasso(root) { |
||||
// append a <g> with a rect
|
||||
var g = root.append('g').attr('class', 'lasso-group'); |
||||
var bbox = root.node().getBoundingClientRect(); |
||||
var area = g |
||||
.append('rect') |
||||
.attr('width', bbox.width) |
||||
.attr('height', bbox.height) |
||||
.attr('fill', 'tomato') |
||||
.attr('opacity', 0); |
||||
|
||||
var drag = d3 |
||||
.drag() |
||||
.on('start', handleDragStart) |
||||
.on('drag', handleDrag) |
||||
.on('end', handleDragEnd); |
||||
|
||||
area.call(drag); |
||||
|
||||
var lassoPolygon; |
||||
var lassoPath; |
||||
var closePath; |
||||
|
||||
function handleDragStart() { |
||||
lassoPolygon = [d3.mouse(this)]; |
||||
if (lassoPath) { |
||||
lassoPath.remove(); |
||||
} |
||||
|
||||
lassoPath = g |
||||
.append('path') |
||||
.attr('fill', '#0bb') |
||||
.attr('fill-opacity', 0.1) |
||||
.attr('stroke', '#0bb') |
||||
.attr('stroke-dasharray', '3, 3'); |
||||
|
||||
closePath = g |
||||
.append('line') |
||||
.attr('x2', lassoPolygon[0][0]) |
||||
.attr('y2', lassoPolygon[0][1]) |
||||
.attr('stroke', '#0bb') |
||||
.attr('stroke-dasharray', '3, 3') |
||||
.attr('opacity', 0); |
||||
|
||||
dispatch.call('start', lasso, lassoPolygon); |
||||
} |
||||
|
||||
function handleDrag() { |
||||
var point = d3.mouse(this); |
||||
lassoPolygon.push(point); |
||||
lassoPath.attr('d', polygonToPath(lassoPolygon)); |
||||
|
||||
// indicate if we are within closing distance
|
||||
if ( |
||||
distance(lassoPolygon[0], lassoPolygon[lassoPolygon.length - 1]) < |
||||
closeDistance |
||||
) { |
||||
closePath |
||||
.attr('x1', point[0]) |
||||
.attr('y1', point[1]) |
||||
.attr('opacity', 1); |
||||
} else { |
||||
closePath.attr('opacity', 0); |
||||
} |
||||
} |
||||
|
||||
function handleDragEnd() { |
||||
// remove the close path
|
||||
closePath.remove(); |
||||
closePath = null; |
||||
|
||||
// succesfully closed
|
||||
if ( |
||||
distance(lassoPolygon[0], lassoPolygon[lassoPolygon.length - 1]) < |
||||
closeDistance |
||||
) { |
||||
lassoPath.attr('d', polygonToPath(lassoPolygon) + 'Z'); |
||||
dispatch.call('end', lasso, lassoPolygon); |
||||
|
||||
// otherwise cancel
|
||||
} else { |
||||
lassoPath.remove(); |
||||
lassoPath = null; |
||||
lassoPolygon = null; |
||||
} |
||||
} |
||||
|
||||
lasso.reset = function () { |
||||
if (lassoPath) { |
||||
lassoPath.remove(); |
||||
lassoPath = null; |
||||
} |
||||
|
||||
lassoPolygon = null; |
||||
if (closePath) { |
||||
closePath.remove(); |
||||
closePath = null; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
lasso.on = function (type, callback) { |
||||
dispatch.on(type, callback); |
||||
return lasso; |
||||
}; |
||||
|
||||
return lasso; |
||||
} |
||||
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,5 @@ |
||||
node_modules |
||||
.DS_Store |
||||
docs/ga.js |
||||
docs/favicon.ico |
||||
bower_components |
@ -0,0 +1,57 @@ |
||||
var stringify = require('stringify'); |
||||
|
||||
|
||||
module.exports = function(grunt){ |
||||
|
||||
// configure plugins
|
||||
grunt.initConfig({ |
||||
|
||||
browserify: { |
||||
dist: { |
||||
files: { |
||||
'd3-legend.js': ['src/web.js'], |
||||
} |
||||
}, |
||||
docs: { |
||||
files: { |
||||
'docs/docs.js': ['docs/legends.js', 'docs/markdown.js'] |
||||
}, |
||||
options: { |
||||
transform: [ |
||||
function(file) { |
||||
return stringify({extensions: ['.md']}).call(stringify, file); |
||||
} |
||||
] |
||||
} |
||||
} |
||||
}, |
||||
|
||||
// Uglify js for build
|
||||
uglify: { |
||||
build: { |
||||
files: { |
||||
'd3-legend.min.js': 'd3-legend.js' |
||||
} |
||||
}, |
||||
docs: { |
||||
files: { |
||||
'docs/d3-legend.min.js': 'd3-legend.js' |
||||
} |
||||
}, |
||||
docsjs: { |
||||
files: { |
||||
'docs/docs.min.js': 'docs/docs.js' |
||||
} |
||||
} |
||||
} |
||||
|
||||
}); |
||||
|
||||
// Loading tasks
|
||||
grunt.loadNpmTasks('grunt-browserify'); |
||||
grunt.loadNpmTasks('grunt-contrib-uglify'); |
||||
|
||||
// Registering tasks
|
||||
grunt.registerTask('default', ['browserify', 'uglify']); |
||||
|
||||
}; |
@ -0,0 +1,5 @@ |
||||
Copyright (c) 2015, Susie Lu |
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
@ -0,0 +1,57 @@ |
||||
# d3-legend |
||||
|
||||
Full documentation: [http://d3-legend.susielu.com](http://d3-legend.susielu.com) |
||||
|
||||
## Usage |
||||
|
||||
### Using just the minified file |
||||
|
||||
|
||||
You must inclue the [d3 library](http://d3js.org/) before including the legend file. Then you can simply add the compiled js file to your website: |
||||
|
||||
- d3-legend.min.js |
||||
- d3-legend.js (Human readable version) |
||||
|
||||
### Using CDN |
||||
|
||||
You can also add latest version of [d3-legend hosted on cdnjs](https://cdnjs.com/libraries/d3-legend/1.13.0). |
||||
|
||||
### Using npm |
||||
|
||||
Already using d3? Great! You can add the d3 legend as a node module by running: |
||||
|
||||
`npm i d3-svg-legend -S` |
||||
|
||||
If not, install both this way: |
||||
|
||||
`npm i d3@^3.0.0 d3-svg-legend -S` |
||||
|
||||
Please note, d3 is now a peer dependency, you will have to have the npm d3 module separately. This component works with any 3.x version of d3. |
||||
|
||||
If you `require('d3-svg-legend')` we attach to d3 as `d3.legend`. If you'd like to use d3-legend without extending d3, `require('d3-svg-legend/no-extend')`. For example: |
||||
``` |
||||
var d3 = require('d3') |
||||
var legend = require('d3-svg-legend/no-extend') |
||||
|
||||
var svg = d3.select("#svg-color-quant"); |
||||
|
||||
var quantize = d3.scale.quantize() |
||||
.domain([ 0, 0.15 ]) |
||||
.range(d3.range(9).map(function(i) { return "q" + i + "-9"; })); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendQuant") |
||||
.attr("transform", "translate(20,20)"); |
||||
|
||||
var colorLegend = legend.color() |
||||
.labelFormat(d3.format(".2f")) |
||||
.useClass(true) |
||||
.scale(quantize); |
||||
|
||||
svg.select(".legendQuant") |
||||
.call(colorLegend); |
||||
|
||||
``` |
||||
|
||||
## Feedback |
||||
I would love to hear from you about any additional features that would be useful, please say hi on twitter [@DataToViz](https://www.twitter.com/DataToViz). |
@ -0,0 +1,26 @@ |
||||
{ |
||||
"name": "d3-legend", |
||||
"main": "d3-legend.min.js", |
||||
"version": "1.0.0", |
||||
"homepage": "https://github.com/susielu/d3-legend", |
||||
"keywords": [ |
||||
"d3", |
||||
"legend", |
||||
"data", |
||||
"visualization" |
||||
], |
||||
"authors": [ |
||||
"Susie Lu" |
||||
], |
||||
"license": "MIT", |
||||
"ignore": [ |
||||
"**/.*", |
||||
"node_modules", |
||||
"bower_components", |
||||
"test", |
||||
"tests" |
||||
], |
||||
"dependencies": { |
||||
"d3": "~3.5.6" |
||||
} |
||||
} |
File diff suppressed because one or more lines are too long
@ -0,0 +1,742 @@ |
||||
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ |
||||
var helper = require('./legend'); |
||||
|
||||
module.exports = function(){ |
||||
|
||||
var scale = d3.scale.linear(), |
||||
shape = "rect", |
||||
shapeWidth = 15, |
||||
shapeHeight = 15, |
||||
shapeRadius = 10, |
||||
shapePadding = 2, |
||||
cells = [5], |
||||
labels = [], |
||||
classPrefix = "", |
||||
useClass = false, |
||||
title = "", |
||||
labelFormat = d3.format(".01f"), |
||||
labelOffset = 10, |
||||
labelAlign = "middle", |
||||
labelDelimiter = "to", |
||||
orient = "vertical", |
||||
ascending = false, |
||||
path, |
||||
legendDispatcher = d3.dispatch("cellover", "cellout", "cellclick"); |
||||
|
||||
function legend(svg){ |
||||
|
||||
var type = helper.d3_calcType(scale, ascending, cells, labels, labelFormat, labelDelimiter), |
||||
legendG = svg.selectAll('g').data([scale]); |
||||
|
||||
legendG.enter().append('g').attr('class', classPrefix + 'legendCells'); |
||||
|
||||
|
||||
var cell = legendG.selectAll("." + classPrefix + "cell").data(type.data), |
||||
cellEnter = cell.enter().append("g", ".cell").attr("class", classPrefix + "cell").style("opacity", 1e-6), |
||||
shapeEnter = cellEnter.append(shape).attr("class", classPrefix + "swatch"), |
||||
shapes = cell.select("g." + classPrefix + "cell " + shape); |
||||
|
||||
//add event handlers
|
||||
helper.d3_addEvents(cellEnter, legendDispatcher); |
||||
|
||||
cell.exit().transition().style("opacity", 0).remove(); |
||||
|
||||
helper.d3_drawShapes(shape, shapes, shapeHeight, shapeWidth, shapeRadius, path); |
||||
|
||||
helper.d3_addText(legendG, cellEnter, type.labels, classPrefix) |
||||
|
||||
// sets placement
|
||||
var text = cell.select("text"), |
||||
shapeSize = shapes[0].map( function(d){ return d.getBBox(); }); |
||||
|
||||
//sets scale
|
||||
//everything is fill except for line which is stroke,
|
||||
if (!useClass){ |
||||
if (shape == "line"){ |
||||
shapes.style("stroke", type.feature); |
||||
} else { |
||||
shapes.style("fill", type.feature); |
||||
} |
||||
} else { |
||||
shapes.attr("class", function(d){ return classPrefix + "swatch " + type.feature(d); }); |
||||
} |
||||
|
||||
var cellTrans, |
||||
textTrans, |
||||
textAlign = (labelAlign == "start") ? 0 : (labelAlign == "middle") ? 0.5 : 1; |
||||
|
||||
//positions cells and text
|
||||
if (orient === "vertical"){ |
||||
cellTrans = function(d,i) { return "translate(0, " + (i * (shapeSize[i].height + shapePadding)) + ")"; }; |
||||
textTrans = function(d,i) { return "translate(" + (shapeSize[i].width + shapeSize[i].x + |
||||
labelOffset) + "," + (shapeSize[i].y + shapeSize[i].height/2 + 5) + ")"; }; |
||||
|
||||
} else if (orient === "horizontal"){ |
||||
cellTrans = function(d,i) { return "translate(" + (i * (shapeSize[i].width + shapePadding)) + ",0)"; } |
||||
textTrans = function(d,i) { return "translate(" + (shapeSize[i].width*textAlign + shapeSize[i].x) + |
||||
"," + (shapeSize[i].height + shapeSize[i].y + labelOffset + 8) + ")"; }; |
||||
} |
||||
|
||||
helper.d3_placement(orient, cell, cellTrans, text, textTrans, labelAlign); |
||||
helper.d3_title(svg, legendG, title, classPrefix); |
||||
|
||||
cell.transition().style("opacity", 1); |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
legend.scale = function(_) { |
||||
if (!arguments.length) return scale; |
||||
scale = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.cells = function(_) { |
||||
if (!arguments.length) return cells; |
||||
if (_.length > 1 || _ >= 2 ){ |
||||
cells = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shape = function(_, d) { |
||||
if (!arguments.length) return shape; |
||||
if (_ == "rect" || _ == "circle" || _ == "line" || (_ == "path" && (typeof d === 'string')) ){ |
||||
shape = _; |
||||
path = d; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shapeWidth = function(_) { |
||||
if (!arguments.length) return shapeWidth; |
||||
shapeWidth = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shapeHeight = function(_) { |
||||
if (!arguments.length) return shapeHeight; |
||||
shapeHeight = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shapeRadius = function(_) { |
||||
if (!arguments.length) return shapeRadius; |
||||
shapeRadius = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shapePadding = function(_) { |
||||
if (!arguments.length) return shapePadding; |
||||
shapePadding = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labels = function(_) { |
||||
if (!arguments.length) return labels; |
||||
labels = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelAlign = function(_) { |
||||
if (!arguments.length) return labelAlign; |
||||
if (_ == "start" || _ == "end" || _ == "middle") { |
||||
labelAlign = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelFormat = function(_) { |
||||
if (!arguments.length) return labelFormat; |
||||
labelFormat = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelOffset = function(_) { |
||||
if (!arguments.length) return labelOffset; |
||||
labelOffset = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelDelimiter = function(_) { |
||||
if (!arguments.length) return labelDelimiter; |
||||
labelDelimiter = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.useClass = function(_) { |
||||
if (!arguments.length) return useClass; |
||||
if (_ === true || _ === false){ |
||||
useClass = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.orient = function(_){ |
||||
if (!arguments.length) return orient; |
||||
_ = _.toLowerCase(); |
||||
if (_ == "horizontal" || _ == "vertical") { |
||||
orient = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.ascending = function(_) { |
||||
if (!arguments.length) return ascending; |
||||
ascending = !!_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.classPrefix = function(_) { |
||||
if (!arguments.length) return classPrefix; |
||||
classPrefix = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.title = function(_) { |
||||
if (!arguments.length) return title; |
||||
title = _; |
||||
return legend; |
||||
}; |
||||
|
||||
d3.rebind(legend, legendDispatcher, "on"); |
||||
|
||||
return legend; |
||||
|
||||
}; |
||||
|
||||
},{"./legend":2}],2:[function(require,module,exports){ |
||||
module.exports = { |
||||
|
||||
d3_identity: function (d) { |
||||
return d; |
||||
}, |
||||
|
||||
d3_mergeLabels: function (gen, labels) { |
||||
|
||||
if(labels.length === 0) return gen; |
||||
|
||||
gen = (gen) ? gen : []; |
||||
|
||||
var i = labels.length; |
||||
for (; i < gen.length; i++) { |
||||
labels.push(gen[i]); |
||||
} |
||||
return labels; |
||||
}, |
||||
|
||||
d3_linearLegend: function (scale, cells, labelFormat) { |
||||
var data = []; |
||||
|
||||
if (cells.length > 1){ |
||||
data = cells; |
||||
|
||||
} else { |
||||
var domain = scale.domain(), |
||||
increment = (domain[domain.length - 1] - domain[0])/(cells - 1), |
||||
i = 0; |
||||
|
||||
for (; i < cells; i++){ |
||||
data.push(domain[0] + i*increment); |
||||
} |
||||
} |
||||
|
||||
var labels = data.map(labelFormat); |
||||
|
||||
return {data: data, |
||||
labels: labels, |
||||
feature: function(d){ return scale(d); }}; |
||||
}, |
||||
|
||||
d3_quantLegend: function (scale, labelFormat, labelDelimiter) { |
||||
var labels = scale.range().map(function(d){ |
||||
var invert = scale.invertExtent(d), |
||||
a = labelFormat(invert[0]), |
||||
b = labelFormat(invert[1]); |
||||
|
||||
// if (( (a) && (a.isNan()) && b){
|
||||
// console.log("in initial statement")
|
||||
return labelFormat(invert[0]) + " " + labelDelimiter + " " + labelFormat(invert[1]); |
||||
// } else if (a || b) {
|
||||
// console.log('in else statement')
|
||||
// return (a) ? a : b;
|
||||
// }
|
||||
|
||||
}); |
||||
|
||||
return {data: scale.range(), |
||||
labels: labels, |
||||
feature: this.d3_identity |
||||
}; |
||||
}, |
||||
|
||||
d3_ordinalLegend: function (scale) { |
||||
return {data: scale.domain(), |
||||
labels: scale.domain(), |
||||
feature: function(d){ return scale(d); }}; |
||||
}, |
||||
|
||||
d3_drawShapes: function (shape, shapes, shapeHeight, shapeWidth, shapeRadius, path) { |
||||
if (shape === "rect"){ |
||||
shapes.attr("height", shapeHeight).attr("width", shapeWidth); |
||||
|
||||
} else if (shape === "circle") { |
||||
shapes.attr("r", shapeRadius)//.attr("cx", shapeRadius).attr("cy", shapeRadius);
|
||||
|
||||
} else if (shape === "line") { |
||||
shapes.attr("x1", 0).attr("x2", shapeWidth).attr("y1", 0).attr("y2", 0); |
||||
|
||||
} else if (shape === "path") { |
||||
shapes.attr("d", path); |
||||
} |
||||
}, |
||||
|
||||
d3_addText: function (svg, enter, labels, classPrefix){ |
||||
enter.append("text").attr("class", classPrefix + "label"); |
||||
svg.selectAll("g." + classPrefix + "cell text." + classPrefix + "label") |
||||
.data(labels).text(this.d3_identity); |
||||
}, |
||||
|
||||
d3_calcType: function (scale, ascending, cells, labels, labelFormat, labelDelimiter){ |
||||
var type = scale.ticks ? |
||||
this.d3_linearLegend(scale, cells, labelFormat) : scale.invertExtent ? |
||||
this.d3_quantLegend(scale, labelFormat, labelDelimiter) : this.d3_ordinalLegend(scale); |
||||
|
||||
type.labels = this.d3_mergeLabels(type.labels, labels); |
||||
|
||||
if (ascending) { |
||||
type.labels = this.d3_reverse(type.labels); |
||||
type.data = this.d3_reverse(type.data); |
||||
} |
||||
|
||||
return type; |
||||
}, |
||||
|
||||
d3_reverse: function(arr) { |
||||
var mirror = []; |
||||
for (var i = 0, l = arr.length; i < l; i++) { |
||||
mirror[i] = arr[l-i-1]; |
||||
} |
||||
return mirror; |
||||
}, |
||||
|
||||
d3_placement: function (orient, cell, cellTrans, text, textTrans, labelAlign) { |
||||
cell.attr("transform", cellTrans); |
||||
text.attr("transform", textTrans); |
||||
if (orient === "horizontal"){ |
||||
text.style("text-anchor", labelAlign); |
||||
} |
||||
}, |
||||
|
||||
d3_addEvents: function(cells, dispatcher){ |
||||
var _ = this; |
||||
|
||||
cells.on("mouseover.legend", function (d) { _.d3_cellOver(dispatcher, d, this); }) |
||||
.on("mouseout.legend", function (d) { _.d3_cellOut(dispatcher, d, this); }) |
||||
.on("click.legend", function (d) { _.d3_cellClick(dispatcher, d, this); }); |
||||
}, |
||||
|
||||
d3_cellOver: function(cellDispatcher, d, obj){ |
||||
cellDispatcher.cellover.call(obj, d); |
||||
}, |
||||
|
||||
d3_cellOut: function(cellDispatcher, d, obj){ |
||||
cellDispatcher.cellout.call(obj, d); |
||||
}, |
||||
|
||||
d3_cellClick: function(cellDispatcher, d, obj){ |
||||
cellDispatcher.cellclick.call(obj, d); |
||||
}, |
||||
|
||||
d3_title: function(svg, cellsSvg, title, classPrefix){ |
||||
if (title !== ""){ |
||||
|
||||
var titleText = svg.selectAll('text.' + classPrefix + 'legendTitle'); |
||||
|
||||
titleText.data([title]) |
||||
.enter() |
||||
.append('text') |
||||
.attr('class', classPrefix + 'legendTitle'); |
||||
|
||||
svg.selectAll('text.' + classPrefix + 'legendTitle') |
||||
.text(title) |
||||
|
||||
var yOffset = svg.select('.' + classPrefix + 'legendTitle') |
||||
.map(function(d) { return d[0].getBBox().height})[0], |
||||
xOffset = -cellsSvg.map(function(d) { return d[0].getBBox().x})[0]; |
||||
|
||||
cellsSvg.attr('transform', 'translate(' + xOffset + ',' + (yOffset + 10) + ')'); |
||||
|
||||
} |
||||
} |
||||
} |
||||
|
||||
},{}],3:[function(require,module,exports){ |
||||
var helper = require('./legend'); |
||||
|
||||
module.exports = function(){ |
||||
|
||||
var scale = d3.scale.linear(), |
||||
shape = "rect", |
||||
shapeWidth = 15, |
||||
shapePadding = 2, |
||||
cells = [5], |
||||
labels = [], |
||||
useStroke = false, |
||||
classPrefix = "", |
||||
title = "", |
||||
labelFormat = d3.format(".01f"), |
||||
labelOffset = 10, |
||||
labelAlign = "middle", |
||||
labelDelimiter = "to", |
||||
orient = "vertical", |
||||
ascending = false, |
||||
path, |
||||
legendDispatcher = d3.dispatch("cellover", "cellout", "cellclick"); |
||||
|
||||
function legend(svg){ |
||||
|
||||
var type = helper.d3_calcType(scale, ascending, cells, labels, labelFormat, labelDelimiter), |
||||
legendG = svg.selectAll('g').data([scale]); |
||||
|
||||
legendG.enter().append('g').attr('class', classPrefix + 'legendCells'); |
||||
|
||||
|
||||
var cell = legendG.selectAll("." + classPrefix + "cell").data(type.data), |
||||
cellEnter = cell.enter().append("g", ".cell").attr("class", classPrefix + "cell").style("opacity", 1e-6), |
||||
shapeEnter = cellEnter.append(shape).attr("class", classPrefix + "swatch"), |
||||
shapes = cell.select("g." + classPrefix + "cell " + shape); |
||||
|
||||
//add event handlers
|
||||
helper.d3_addEvents(cellEnter, legendDispatcher); |
||||
|
||||
cell.exit().transition().style("opacity", 0).remove(); |
||||
|
||||
//creates shape
|
||||
if (shape === "line"){ |
||||
helper.d3_drawShapes(shape, shapes, 0, shapeWidth); |
||||
shapes.attr("stroke-width", type.feature); |
||||
} else { |
||||
helper.d3_drawShapes(shape, shapes, type.feature, type.feature, type.feature, path); |
||||
} |
||||
|
||||
helper.d3_addText(legendG, cellEnter, type.labels, classPrefix) |
||||
|
||||
//sets placement
|
||||
var text = cell.select("text"), |
||||
shapeSize = shapes[0].map( |
||||
function(d, i){ |
||||
var bbox = d.getBBox() |
||||
var stroke = scale(type.data[i]); |
||||
|
||||
if (shape === "line" && orient === "horizontal") { |
||||
bbox.height = bbox.height + stroke; |
||||
} else if (shape === "line" && orient === "vertical"){ |
||||
bbox.width = bbox.width; |
||||
} |
||||
|
||||
return bbox; |
||||
}); |
||||
|
||||
var maxH = d3.max(shapeSize, function(d){ return d.height + d.y; }), |
||||
maxW = d3.max(shapeSize, function(d){ return d.width + d.x; }); |
||||
|
||||
var cellTrans, |
||||
textTrans, |
||||
textAlign = (labelAlign == "start") ? 0 : (labelAlign == "middle") ? 0.5 : 1; |
||||
|
||||
//positions cells and text
|
||||
if (orient === "vertical"){ |
||||
|
||||
cellTrans = function(d,i) { |
||||
var height = d3.sum(shapeSize.slice(0, i + 1 ), function(d){ return d.height; }); |
||||
return "translate(0, " + (height + i*shapePadding) + ")"; }; |
||||
|
||||
textTrans = function(d,i) { return "translate(" + (maxW + labelOffset) + "," + |
||||
(shapeSize[i].y + shapeSize[i].height/2 + 5) + ")"; }; |
||||
|
||||
} else if (orient === "horizontal"){ |
||||
cellTrans = function(d,i) { |
||||
var width = d3.sum(shapeSize.slice(0, i + 1 ), function(d){ return d.width; }); |
||||
return "translate(" + (width + i*shapePadding) + ",0)"; }; |
||||
|
||||
textTrans = function(d,i) { return "translate(" + (shapeSize[i].width*textAlign + shapeSize[i].x) + "," + |
||||
(maxH + labelOffset ) + ")"; }; |
||||
} |
||||
|
||||
helper.d3_placement(orient, cell, cellTrans, text, textTrans, labelAlign); |
||||
helper.d3_title(svg, legendG, title, classPrefix); |
||||
|
||||
cell.transition().style("opacity", 1); |
||||
|
||||
} |
||||
|
||||
legend.scale = function(_) { |
||||
if (!arguments.length) return scale; |
||||
scale = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.cells = function(_) { |
||||
if (!arguments.length) return cells; |
||||
if (_.length > 1 || _ >= 2 ){ |
||||
cells = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
|
||||
legend.shape = function(_, d) { |
||||
if (!arguments.length) return shape; |
||||
if (_ == "rect" || _ == "circle" || _ == "line" ){ |
||||
shape = _; |
||||
path = d; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shapeWidth = function(_) { |
||||
if (!arguments.length) return shapeWidth; |
||||
shapeWidth = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shapePadding = function(_) { |
||||
if (!arguments.length) return shapePadding; |
||||
shapePadding = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labels = function(_) { |
||||
if (!arguments.length) return labels; |
||||
labels = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelAlign = function(_) { |
||||
if (!arguments.length) return labelAlign; |
||||
if (_ == "start" || _ == "end" || _ == "middle") { |
||||
labelAlign = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelFormat = function(_) { |
||||
if (!arguments.length) return labelFormat; |
||||
labelFormat = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelOffset = function(_) { |
||||
if (!arguments.length) return labelOffset; |
||||
labelOffset = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelDelimiter = function(_) { |
||||
if (!arguments.length) return labelDelimiter; |
||||
labelDelimiter = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.orient = function(_){ |
||||
if (!arguments.length) return orient; |
||||
_ = _.toLowerCase(); |
||||
if (_ == "horizontal" || _ == "vertical") { |
||||
orient = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.ascending = function(_) { |
||||
if (!arguments.length) return ascending; |
||||
ascending = !!_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.classPrefix = function(_) { |
||||
if (!arguments.length) return classPrefix; |
||||
classPrefix = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.title = function(_) { |
||||
if (!arguments.length) return title; |
||||
title = _; |
||||
return legend; |
||||
}; |
||||
|
||||
d3.rebind(legend, legendDispatcher, "on"); |
||||
|
||||
return legend; |
||||
|
||||
}; |
||||
|
||||
},{"./legend":2}],4:[function(require,module,exports){ |
||||
var helper = require('./legend'); |
||||
|
||||
module.exports = function(){ |
||||
|
||||
var scale = d3.scale.linear(), |
||||
shape = "path", |
||||
shapeWidth = 15, |
||||
shapeHeight = 15, |
||||
shapeRadius = 10, |
||||
shapePadding = 5, |
||||
cells = [5], |
||||
labels = [], |
||||
classPrefix = "", |
||||
useClass = false, |
||||
title = "", |
||||
labelFormat = d3.format(".01f"), |
||||
labelAlign = "middle", |
||||
labelOffset = 10, |
||||
labelDelimiter = "to", |
||||
orient = "vertical", |
||||
ascending = false, |
||||
legendDispatcher = d3.dispatch("cellover", "cellout", "cellclick"); |
||||
|
||||
function legend(svg){ |
||||
|
||||
var type = helper.d3_calcType(scale, ascending, cells, labels, labelFormat, labelDelimiter), |
||||
legendG = svg.selectAll('g').data([scale]); |
||||
|
||||
legendG.enter().append('g').attr('class', classPrefix + 'legendCells'); |
||||
|
||||
var cell = legendG.selectAll("." + classPrefix + "cell").data(type.data), |
||||
cellEnter = cell.enter().append("g", ".cell").attr("class", classPrefix + "cell").style("opacity", 1e-6), |
||||
shapeEnter = cellEnter.append(shape).attr("class", classPrefix + "swatch"), |
||||
shapes = cell.select("g." + classPrefix + "cell " + shape); |
||||
|
||||
//add event handlers
|
||||
helper.d3_addEvents(cellEnter, legendDispatcher); |
||||
|
||||
//remove old shapes
|
||||
cell.exit().transition().style("opacity", 0).remove(); |
||||
|
||||
helper.d3_drawShapes(shape, shapes, shapeHeight, shapeWidth, shapeRadius, type.feature); |
||||
helper.d3_addText(legendG, cellEnter, type.labels, classPrefix) |
||||
|
||||
// sets placement
|
||||
var text = cell.select("text"), |
||||
shapeSize = shapes[0].map( function(d){ return d.getBBox(); }); |
||||
|
||||
var maxH = d3.max(shapeSize, function(d){ return d.height; }), |
||||
maxW = d3.max(shapeSize, function(d){ return d.width; }); |
||||
|
||||
var cellTrans, |
||||
textTrans, |
||||
textAlign = (labelAlign == "start") ? 0 : (labelAlign == "middle") ? 0.5 : 1; |
||||
|
||||
//positions cells and text
|
||||
if (orient === "vertical"){ |
||||
cellTrans = function(d,i) { return "translate(0, " + (i * (maxH + shapePadding)) + ")"; }; |
||||
textTrans = function(d,i) { return "translate(" + (maxW + labelOffset) + "," + |
||||
(shapeSize[i].y + shapeSize[i].height/2 + 5) + ")"; }; |
||||
|
||||
} else if (orient === "horizontal"){ |
||||
cellTrans = function(d,i) { return "translate(" + (i * (maxW + shapePadding)) + ",0)"; }; |
||||
textTrans = function(d,i) { return "translate(" + (shapeSize[i].width*textAlign + shapeSize[i].x) + "," + |
||||
(maxH + labelOffset ) + ")"; }; |
||||
} |
||||
|
||||
helper.d3_placement(orient, cell, cellTrans, text, textTrans, labelAlign); |
||||
helper.d3_title(svg, legendG, title, classPrefix); |
||||
cell.transition().style("opacity", 1); |
||||
|
||||
} |
||||
|
||||
|
||||
legend.scale = function(_) { |
||||
if (!arguments.length) return scale; |
||||
scale = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.cells = function(_) { |
||||
if (!arguments.length) return cells; |
||||
if (_.length > 1 || _ >= 2 ){ |
||||
cells = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shapePadding = function(_) { |
||||
if (!arguments.length) return shapePadding; |
||||
shapePadding = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labels = function(_) { |
||||
if (!arguments.length) return labels; |
||||
labels = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelAlign = function(_) { |
||||
if (!arguments.length) return labelAlign; |
||||
if (_ == "start" || _ == "end" || _ == "middle") { |
||||
labelAlign = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelFormat = function(_) { |
||||
if (!arguments.length) return labelFormat; |
||||
labelFormat = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelOffset = function(_) { |
||||
if (!arguments.length) return labelOffset; |
||||
labelOffset = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelDelimiter = function(_) { |
||||
if (!arguments.length) return labelDelimiter; |
||||
labelDelimiter = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.orient = function(_){ |
||||
if (!arguments.length) return orient; |
||||
_ = _.toLowerCase(); |
||||
if (_ == "horizontal" || _ == "vertical") { |
||||
orient = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.ascending = function(_) { |
||||
if (!arguments.length) return ascending; |
||||
ascending = !!_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.classPrefix = function(_) { |
||||
if (!arguments.length) return classPrefix; |
||||
classPrefix = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.title = function(_) { |
||||
if (!arguments.length) return title; |
||||
title = _; |
||||
return legend; |
||||
}; |
||||
|
||||
d3.rebind(legend, legendDispatcher, "on"); |
||||
|
||||
return legend; |
||||
|
||||
}; |
||||
|
||||
},{"./legend":2}],5:[function(require,module,exports){ |
||||
d3.legend = { |
||||
color: require('./color'), |
||||
size: require('./size'), |
||||
symbol: require('./symbol') |
||||
}; |
||||
},{"./color":1,"./size":3,"./symbol":4}]},{},[5]); |
@ -0,0 +1,55 @@ |
||||
// d3.legend.js
|
||||
// (C) 2012 ziggy.jonsson.nyc@gmail.com
|
||||
// MIT licence
|
||||
|
||||
(function() { |
||||
d3.legend = function(g) { |
||||
g.each(function() { |
||||
var g= d3.select(this), |
||||
items = {}, |
||||
svg = d3.select(g.property("nearestViewportElement")), |
||||
legendPadding = g.attr("data-style-padding") || 5, |
||||
lb = g.selectAll(".legend-box").data([true]), |
||||
li = g.selectAll(".legend-items").data([true]) |
||||
|
||||
lb.enter().append("rect").classed("legend-box",true) |
||||
li.enter().append("g").classed("legend-items",true) |
||||
|
||||
svg.selectAll("[data-legend]").each(function() { |
||||
var self = d3.select(this) |
||||
items[self.attr("data-legend")] = { |
||||
pos : self.attr("data-legend-pos") || this.getBBox().y, |
||||
color : self.attr("data-legend-color") != undefined ? self.attr("data-legend-color") : self.style("fill") != 'none' ? self.style("fill") : self.style("stroke")
|
||||
} |
||||
}) |
||||
|
||||
items = d3.entries(items).sort(function(a,b) { return a.value.pos-b.value.pos}) |
||||
|
||||
|
||||
li.selectAll("text") |
||||
.data(items,function(d) { return d.key}) |
||||
.call(function(d) { d.enter().append("text")}) |
||||
.call(function(d) { d.exit().remove()}) |
||||
.attr("y",function(d,i) { return i+"em"}) |
||||
.attr("x","1em") |
||||
.text(function(d) { ;return d.key}) |
||||
|
||||
li.selectAll("circle") |
||||
.data(items,function(d) { return d.key}) |
||||
.call(function(d) { d.enter().append("circle")}) |
||||
.call(function(d) { d.exit().remove()}) |
||||
.attr("cy",function(d,i) { return i-0.25+"em"}) |
||||
.attr("cx",0) |
||||
.attr("r","0.4em") |
||||
.style("fill",function(d) { console.log(d.value.color);return d.value.color})
|
||||
|
||||
// Reposition and resize the box
|
||||
var lbbox = li[0][0].getBBox()
|
||||
lb.attr("x",(lbbox.x-legendPadding)) |
||||
.attr("y",(lbbox.y-legendPadding)) |
||||
.attr("height",(lbbox.height+2*legendPadding)) |
||||
.attr("width",(lbbox.width+2*legendPadding)) |
||||
}) |
||||
return g |
||||
} |
||||
})() |
@ -0,0 +1,75 @@ |
||||
d3.legend.**color()** |
||||
|
||||
Constructs a new color legend. The legend component expects a d3 scale as the basic input, but also has a number of optional parameters for changing the default display such as vertical or horizontal orientation, shape of the symbol next to the label, symbol sizing, and label formatting. |
||||
|
||||
color.**scale(d3.scale)** |
||||
|
||||
Creates a new d3 legend based on the scale. The code determines the type of scale and generates the appropriate symbol and label pairs. |
||||
|
||||
color.**cells(number or [numbers])** |
||||
|
||||
This parameter is only valid for continuous scales (like linear and log). When there is no indication from the domain or range for the number of steps in the legend you may want to display, it defaults to five steps in equal increments. You can pass the cells function a single number which will create equal increments for that number of steps, or an array of the [specific steps](#color-linear-custom) you want the legend to display. |
||||
|
||||
color.**orient(string)** |
||||
|
||||
Accepts "vertical" or "horizontal" for legend orientation. Default set to "vertical." |
||||
|
||||
color.**ascending(boolean)** |
||||
|
||||
If you pass this a true, it will reverse the order of the scale. |
||||
|
||||
color.**shape(string[, path-string])** |
||||
|
||||
Accepts "rect", "circle", "line", or "path". If you choose "path," you must also pass a second parameter as a path string. Defaults to "rect." An example: [Color - Ordinal Scale Legend, custom shape](#color-ordinal). |
||||
|
||||
color.**shapeWidth(number)** |
||||
|
||||
Only applies to shape of "rect" or "line." Default set to 15px. |
||||
|
||||
color.**shapeHeight(number)** |
||||
|
||||
Only applies to shape of "rect." Default set to 15px. |
||||
|
||||
color.**shapeRadius(number)** |
||||
|
||||
Only applies to shape of "circle." Default set to 10px. |
||||
|
||||
color.**shapePadding(number)** |
||||
|
||||
Applies to all shapes. Determines vertical or horizontal spacing between shapes depending on the respective orient setting. Default set to 2px. |
||||
|
||||
color.**useClass(boolean)** |
||||
|
||||
The default behavior is for the legend to set the fill of the legend's symbols (except for the "line" shape which uses stroke). If you set useClass to `true` then it will apply the scale's output as classes to the shapes instead of the fill or stroke. An example: [Color - Quantile Scale Legend](#color-quant). |
||||
|
||||
color.**classPrefix(string)** |
||||
|
||||
Adds this string to the beginning of all of the components of the legend that have a class. This allows for namespacing of the classes. |
||||
|
||||
color.**title(string)** |
||||
|
||||
Sets the legend's title to the string. Automatically moves the legend cells down based on the size of the title. An example: [Symbol - Ordinal Scale](#symbol-ordinal). |
||||
|
||||
color.**labels([string])** |
||||
|
||||
Sets the legend labels to the array of strings passed to the legend. If the array is not the same length as the array the legend calculates, it merges the values and gives the calculated labels for the remaining items. An example: [Size - Linear Scale Legend, Lines](#size-line). |
||||
|
||||
color.**labelAlign(string)** |
||||
|
||||
Only used if the legend's orient is set to "horizontal." Accepts "start", "middle", or "end" as inputs to determine if the labels are aligned on the left, middle or right under the symbol in a horizontal legend. An example: [Size - Linear Scale Legend, Lines](#size-line). |
||||
|
||||
color.**labelFormat(d3.format)** |
||||
|
||||
Takes a [d3.format](https://github.com/mbostock/d3/wiki/Formatting) and applies that styling to the legend labels. Default is set to `d3.format(".01f")`. |
||||
|
||||
color.**labelOffset(number)** |
||||
|
||||
A value that determines how far the label is from the symbol in each legend item. Default set to 10px. |
||||
|
||||
color.**labelDelimiter(string)** |
||||
|
||||
Change the default "to" text when working with a quant scale. |
||||
|
||||
color.**on(string, function)** |
||||
|
||||
There are three custom event types you can bind to the legend: "cellover", "cellout", and "cellclick" An exampe: [Symbol - Ordinal Scale](#symbol-ordinal) |
@ -0,0 +1,20 @@ |
||||
- [Color Legend](#color) |
||||
- [Documentation](#color-doc) |
||||
- [Examples](#color-examples) |
||||
- [Quantile Scale Legend](#color-quant) |
||||
- [Linear Scale Legend - Horizontal](#color-linear) |
||||
- [Linear Scale Legend - 10 cells](#color-linear-10) |
||||
- [Linear Scale Legend - Custom cells](#color-linear-custom) |
||||
- [Ordinal Scale Legend - Custom shape](#color-ordinal) |
||||
- [Size Legend](#size) |
||||
- [Documentation](#size-doc) |
||||
- [Examples](#size-examples) |
||||
- [Linear Scale Legend - Circles](#size-linear) |
||||
- [Linear Scale Legend - Lines](#size-line) |
||||
|
||||
- [Symbol Legend](#symbol) |
||||
- [Documentation](#symbol-doc) |
||||
- [Examples](#symbol-examples) |
||||
- [Ordinal Scale Legend - Custom Symbols](#symbol-ordinal) |
||||
|
||||
- [Summary of Functions](#summary) - table of which functions are shared across legend types |
After Width: | Height: | Size: 161 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -0,0 +1,92 @@ |
||||
<!DOCTYPE html> |
||||
<meta charset="utf-8"> |
||||
<style> |
||||
|
||||
body { |
||||
margin: 0; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
svg { |
||||
font: 10px sans-serif; |
||||
} |
||||
|
||||
.caption { |
||||
font-weight: bold; |
||||
} |
||||
|
||||
.key path { |
||||
display: none; |
||||
} |
||||
|
||||
.key line { |
||||
stroke: #000; |
||||
shape-rendering: crispEdges; |
||||
} |
||||
|
||||
</style> |
||||
<body> |
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> |
||||
<script src="../d3-legend.min.js"></script> |
||||
<script> |
||||
|
||||
var width = 960, |
||||
height = 500, |
||||
formatPercent = d3.format(".0%"), |
||||
formatNumber = d3.format(".0f"); |
||||
|
||||
var threshold = d3.scale.threshold() |
||||
.domain([.11, .22, .33, .50]) |
||||
.range(["#6e7c5a", "#a0b28f", "#d8b8b3", "#b45554", "#760000"]); |
||||
|
||||
// A position encoding for the key only. |
||||
var x = d3.scale.linear() |
||||
.domain([0, 1]) |
||||
.range([0, 240]); |
||||
|
||||
var xAxis = d3.svg.axis() |
||||
.scale(x) |
||||
.orient("bottom") |
||||
.tickSize(13) |
||||
.tickValues(threshold.domain()) |
||||
.tickFormat(function(d) { return d === .5 ? formatPercent(d) : formatNumber(100 * d); }); |
||||
|
||||
var svg = d3.select("body").append("svg") |
||||
.attr("width", width) |
||||
.attr("height", height); |
||||
|
||||
var g = svg.append("g") |
||||
.attr("class", "key") |
||||
.attr("transform", "translate(" + (width - 240) / 2 + "," + height / 2 + ")"); |
||||
|
||||
var legend = d3.legend.color() |
||||
.scale(threshold) |
||||
.orient("horizontal") |
||||
.shapeWidth(60); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legend") |
||||
.attr("transform", "translate(20,20)"); |
||||
|
||||
svg.select(".legend") |
||||
.call(legend); |
||||
|
||||
g.selectAll("rect") |
||||
.data(threshold.range().map(function(color) { |
||||
var d = threshold.invertExtent(color); |
||||
if (d[0] == null) d[0] = x.domain()[0]; |
||||
if (d[1] == null) d[1] = x.domain()[1]; |
||||
return d; |
||||
})) |
||||
.enter().append("rect") |
||||
.attr("height", 8) |
||||
.attr("x", function(d) { return x(d[0]); }) |
||||
.attr("width", function(d) { return x(d[1]) - x(d[0]); }) |
||||
.style("fill", function(d) { return threshold(d[0]); }); |
||||
|
||||
g.call(xAxis).append("text") |
||||
.attr("class", "caption") |
||||
.attr("y", -6) |
||||
.text("Percentage of stops that involved force"); |
||||
|
||||
</script> |
@ -0,0 +1,635 @@ |
||||
<!DOCTYPE html> |
||||
<meta charset="utf-8"> |
||||
<head> |
||||
|
||||
|
||||
<meta name="author" content="Susie Lu"> |
||||
<meta name="description" content="Tired of making legends for your data visualizations? This is a component for d3 that allows you to reuse the scales you’ve made for your visualization to quickly add a legend."> |
||||
<link rel="canonical" href="http://d3-legend.susielu.com"> |
||||
|
||||
|
||||
<link href='http://fonts.googleapis.com/css?family=Cardo:400,700' rel='stylesheet' type='text/css'> |
||||
<link href='http://fonts.googleapis.com/css?family=Montserrat:400,700' rel='stylesheet' type='text/css'> |
||||
<link rel="stylesheet" href="minimal-ui.min.css"> |
||||
<link rel="stylesheet" href="prism.css"> |
||||
|
||||
<style> |
||||
svg { |
||||
padding: 10px 15px; |
||||
margin-bottom: 5px; |
||||
display: block; |
||||
background: white; |
||||
border: 1px solid $grey; |
||||
} |
||||
|
||||
pre[class*="language-"]{ |
||||
margin-top: 0px; |
||||
margin-bottom: 30px; |
||||
border: 1px solid #E4E4E4; |
||||
} |
||||
|
||||
:not(pre) > code[class*="language-"], pre[class*="language-"] { |
||||
background: #FFFFFF; |
||||
} |
||||
|
||||
.token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { |
||||
color: #323232; |
||||
} |
||||
|
||||
.token.function { |
||||
color: #989898; |
||||
} |
||||
|
||||
.token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { |
||||
color: #00993C; |
||||
} |
||||
|
||||
h4 { |
||||
display: inline-block; |
||||
} |
||||
|
||||
strong { |
||||
color: #272727; |
||||
} |
||||
|
||||
text { |
||||
font: 12px sans-serif; |
||||
} |
||||
|
||||
hr { |
||||
border-top: 1px solid #999; |
||||
} |
||||
|
||||
table tbody tr:not(:last-child) td{ |
||||
border-bottom: 2px solid #E7E7E7; |
||||
} |
||||
|
||||
table tbody td:not(:last-child), table thead th:not(:last-child) { |
||||
border-right: 2px solid #e7e7e7 |
||||
} |
||||
|
||||
table td:not(:first-child){ |
||||
width: 60px; |
||||
} |
||||
|
||||
table td.included{ |
||||
background-color: rgb(102, 178, 155); |
||||
} |
||||
|
||||
@media only screen and (max-width: 480px){ |
||||
table { |
||||
font-size: 11px; |
||||
} |
||||
} |
||||
|
||||
#contents ul li { |
||||
font-size: 16px; |
||||
} |
||||
|
||||
.legendSize rect, .legendSize circle{ |
||||
fill: rgb(46, 73, 123); |
||||
} |
||||
|
||||
|
||||
.legendSizeHorz circle{ |
||||
stroke: rgb(71, 187, 94); |
||||
fill: none; |
||||
} |
||||
|
||||
.legendSizeLine line { |
||||
stroke: rgb(46, 73, 123); |
||||
} |
||||
|
||||
.legendSymbol path { |
||||
fill: rgb(64, 108, 189); |
||||
} |
||||
|
||||
|
||||
.q0-9 { fill:rgb(247,251,255); } |
||||
.q1-9 { fill:rgb(222,235,247); } |
||||
.q2-9 { fill:rgb(198,219,239); } |
||||
.q3-9 { fill:rgb(158,202,225); } |
||||
.q4-9 { fill:rgb(107,174,214); } |
||||
.q5-9 { fill:rgb(66,146,198); } |
||||
.q6-9 { fill:rgb(33,113,181); } |
||||
.q7-9 { fill:rgb(8,81,156); } |
||||
.q8-9 { fill:rgb(8,48,107); } |
||||
</style> |
||||
|
||||
</head> |
||||
<body> |
||||
<header> |
||||
<div class="container"> |
||||
<div class="txt-center"> |
||||
<h1 class="column12">d3 SVG Legend</h1> |
||||
<div class="column6 prefix3"> |
||||
<p>Tired of making legends for your data visualizations? Me too, enjoy.</p> |
||||
<p>A library to make legends in svg-land easy as pie.</p> |
||||
<img src="d3-legend.jpg"> |
||||
<p>By <a href="http://www.susielu.com">Susie Lu</a></p> |
||||
</div> |
||||
<nav class="column6 prefix3 nav nav-small"> |
||||
<a href="#usage">Usage</a> |
||||
<a href="#contents">Contents</a> |
||||
<a href="#color">Color</a> |
||||
<a href="#size">Size</a> |
||||
<a href="#symbol">Symbol</a> |
||||
<a href="#summary">Summary of Functions</a> |
||||
</nav> |
||||
</div> |
||||
</div> |
||||
|
||||
</header> |
||||
|
||||
|
||||
<section id="usage"> |
||||
<div class="container"> |
||||
<div class="column6 prefix3"> |
||||
<h2>Usage</h2> |
||||
|
||||
<h3>Client-side</h3> |
||||
|
||||
<h4>CDN</h4> |
||||
<p>You can add latest version of d3-legend hosted on cdnjs.<p> |
||||
<a href="https://cdnjs.com/libraries/d3-legend">https://cdnjs.com/libraries/d3-legend</a> |
||||
|
||||
<h4>Include the file directly</h4> |
||||
<p>You must include the <a href="http://d3js.org/">d3 library</a> before including the legend file. Then you can simply add the compiled js file to your website:</p> |
||||
<ul> |
||||
<li><a href="https://raw.githubusercontent.com/susielu/d3-legend/master/d3-legend.min.js">All legends</a></li> |
||||
<li><a href="https://github.com/susielu/d3-legend/blob/master/d3-legend.js">All legends - human readable</a></li> |
||||
|
||||
</ul> |
||||
|
||||
<h3>npm</h3> |
||||
<p>Already using d3? Great! You can add the d3 legend as a node module by running:<p> |
||||
<code>npm i d3-svg-legend -S</code> |
||||
|
||||
<p>If not, install both this way:</p> |
||||
<code>npm i d3@^3.0.0 d3-svg-legend -S</code> |
||||
|
||||
|
||||
<h3>Github + feedback</h3> |
||||
<p>The full source code is available on <a href="https://github.com/susielu/d3-legend">github</a>. I would love to hear from you about any additional features that would be useful, please say hi on twitter <a href="https://www.twitter.com/DataToViz">@DataToViz</a>.</p> |
||||
</div> |
||||
</div> |
||||
</section> |
||||
<section class="bg-light" id="contents"> |
||||
<div class="container"> |
||||
<div class="column6 prefix3"> |
||||
<h2>Contents</h2> |
||||
<div id="contents-md"></div> |
||||
</div> |
||||
</div> |
||||
</section> |
||||
|
||||
<section class="" id="color"> |
||||
<div class="container"> |
||||
<div class="column6 prefix3"> |
||||
<h2>Color</h2> |
||||
|
||||
<h3 id="color-doc">Documentation</h3> |
||||
<div id="color-md"> </div> |
||||
</div> |
||||
</div> |
||||
</section> |
||||
<section class="bg-light" id="color-examples"> |
||||
<div class="container"> |
||||
<div class="column6 prefix3"> |
||||
<h3 >Examples</h3> |
||||
|
||||
<h4 id="color-quant">Quantile Scale Legend</h4> |
||||
<svg height=200 width=160 id="svg-color-quant"></svg> |
||||
<pre class="column6 left-margin right-margin"> |
||||
<code class="language-javascript"> |
||||
|
||||
var quantize = d3.scale.quantize() |
||||
.domain([ 0, 0.15 ]) |
||||
.range(d3.range(9).map(function(i) { return "q" + i + "-9"; })); |
||||
|
||||
var svg = d3.select("svg"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendQuant") |
||||
.attr("transform", "translate(20,20)"); |
||||
|
||||
var legend = d3.legend.color() |
||||
.labelFormat(d3.format(".2f")) |
||||
.useClass(true) |
||||
.scale(quantize); |
||||
|
||||
svg.select(".legendQuant") |
||||
.call(legend); |
||||
</code> |
||||
</pre> |
||||
|
||||
<h4 id="color-quant">Log Scale Legend</h4> |
||||
<svg height=160 width=100 id="svg-color-log"></svg> |
||||
<pre class="column6 left-margin right-margin"> |
||||
<code class="language-javascript"> |
||||
|
||||
var log = d3.scale.log() |
||||
.domain([ 0.1, 100, 1000 ]) |
||||
.range(["rgb(46, 73, 123)", "rgb(71, 187, 94)"]); |
||||
|
||||
var svg = d3.select("svg"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendLog") |
||||
.attr("transform", "translate(20,20)"); |
||||
|
||||
var logLegend = d3.legend.color() |
||||
.cells([0.1, 5, 10, 50, 100, 500, 1000]) |
||||
.scale(log); |
||||
|
||||
svg.select(".legendLog") |
||||
.call(logLegend); |
||||
|
||||
</code> |
||||
</pre> |
||||
|
||||
<h4 id="color-linear">Linear Scale Legend - Horizontal</h4> |
||||
<svg height=60 width=200 id="svg-color-linear"></svg> |
||||
<pre class="column6 left-margin right-margin"> |
||||
<code class="language-javascript"> |
||||
|
||||
var linear = d3.scale.linear() |
||||
.domain([0,10]) |
||||
.range(["rgb(46, 73, 123)", "rgb(71, 187, 94)"]); |
||||
|
||||
var svg = d3.select("svg"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendLinear") |
||||
.attr("transform", "translate(20,20)"); |
||||
|
||||
var legendLinear = d3.legend.color() |
||||
.shapeWidth(30) |
||||
.orient('horizontal') |
||||
.scale(linear); |
||||
|
||||
svg.select(".legendLinear") |
||||
.call(legendLinear); |
||||
</code> |
||||
</pre> |
||||
|
||||
<h4 id="color-linear-10">Linear Scale Legend - 10 cells</h4> |
||||
<svg height=60 width=360 id="svg-color-linear-10"></svg> |
||||
<pre class="column6 left-margin right-margin"> |
||||
<code class="language-javascript"> |
||||
|
||||
var linear = d3.scale.linear() |
||||
.domain([0,10]) |
||||
.range(["rgb(46, 73, 123)", "rgb(71, 187, 94)"]); |
||||
|
||||
var svg = d3.select("svg"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendLinear") |
||||
.attr("transform", "translate(20,20)"); |
||||
|
||||
var legendLinear = d3.legend.color() |
||||
.shapeWidth(30) |
||||
.cells(10) |
||||
.orient('horizontal') |
||||
.scale(linear); |
||||
|
||||
svg.select(".legendLinear") |
||||
.call(legendLinear); |
||||
</code> |
||||
</pre> |
||||
|
||||
<h4 id="color-linear-custom">Linear Scale Legend - Custom cells</h4> |
||||
<svg height=60 width=200 id="svg-color-linear-custom"></svg> |
||||
<pre class="column6 left-margin right-margin"> |
||||
<code class="language-javascript"> |
||||
|
||||
var linear = d3.scale.linear() |
||||
.domain([0,10]) |
||||
.range(["rgb(46, 73, 123)", "rgb(71, 187, 94)"]); |
||||
|
||||
var svg = d3.select("svg"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendLinear") |
||||
.attr("transform", "translate(20,20)"); |
||||
|
||||
var legendLinear = d3.legend.color() |
||||
.shapeWidth(30) |
||||
.cells([1, 2, 3, 6, 8]) |
||||
.orient('horizontal') |
||||
.scale(linear); |
||||
|
||||
svg.select(".legendLinear") |
||||
.call(legendLinear); |
||||
</code> |
||||
</pre> |
||||
|
||||
<h4 id="color-ordinal">Ordinal Scale Legend - Custom shape</h4> |
||||
<svg height=150 width=70 id="svg-color-ordinal"></svg> |
||||
<pre class="column6 left-margin right-margin"> |
||||
<code class="language-javascript"> |
||||
|
||||
var ordinal = d3.scale.ordinal() |
||||
.domain(["a", "b", "c", "d", "e"]) |
||||
.range([ "rgb(153, 107, 195)", "rgb(56, 106, 197)", "rgb(93, 199, 76)", "rgb(223, 199, 31)", "rgb(234, 118, 47)"]); |
||||
|
||||
var svg = d3.select("svg"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendOrdinal") |
||||
.attr("transform", "translate(20,20)"); |
||||
|
||||
var legendOrdinal = d3.legend.color() |
||||
//d3 symbol creates a path-string, for example |
||||
//"M0,-8.059274488676564L9.306048591020996, |
||||
//8.059274488676564 -9.306048591020996,8.059274488676564Z" |
||||
.shape("path", d3.svg.symbol().type("triangle-up").size(150)()) |
||||
.shapePadding(10) |
||||
.scale(ordinal); |
||||
|
||||
svg.select(".legendOrdinal") |
||||
.call(legendOrdinal); |
||||
</code> |
||||
</pre> |
||||
|
||||
</div> |
||||
</div> |
||||
</section> |
||||
|
||||
<section class="" id="size"> |
||||
<div class="container"> |
||||
<div class="column6 prefix3"> |
||||
<h2>Size</h2> |
||||
|
||||
<h3 id="size-doc">Documentation</h3> |
||||
<div id="size-md"></div> |
||||
|
||||
</div> |
||||
</div> |
||||
</section> |
||||
<section class="bg-light" id="size-examples"> |
||||
<div class="container"> |
||||
<div class="column6 prefix3"> |
||||
|
||||
<h3>Examples</h3> |
||||
<h4 id="size-linear">Linear Scale Legend - Circles</h4> |
||||
<svg height=100 width=350 id="svg-size-linear"></svg> |
||||
<pre class="column6 left-margin right-margin"> |
||||
<code class="language-javascript"> |
||||
|
||||
var linearSize = d3.scale.linear().domain([0,10]).range([10, 30]); |
||||
|
||||
var svg = d3.select("svg"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendSize") |
||||
.attr("transform", "translate(20, 40)"); |
||||
|
||||
var legendSize = d3.legend.size() |
||||
.scale(linearSize) |
||||
.shape('circle') |
||||
.shapePadding(15) |
||||
.labelOffset(20) |
||||
.orient('horizontal'); |
||||
|
||||
svg.select(".legendSize") |
||||
.call(legendSize); |
||||
</code> |
||||
</pre> |
||||
|
||||
<h4 id="size-line">Linear Scale Legend - Lines</h4> |
||||
<svg height=60 width=380 id="svg-size-line"></svg> |
||||
<pre class="column6 left-margin right-margin"> |
||||
<code class="language-javascript"> |
||||
|
||||
var lineSize = d3.scale.linear().domain([0,10]).range([2, 10]); |
||||
|
||||
var svg = d3.select("svg"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendSizeLine") |
||||
.attr("transform", "translate(0, 20)"); |
||||
|
||||
var legendSizeLine = d3.legend.size() |
||||
.scale(lineSize) |
||||
.shape("line") |
||||
.orient("horizontal") |
||||
//otherwise labels would have displayed: |
||||
// 0, 2.5, 5, 10 |
||||
.labels(["tiny", "small", "medium", "large", "grand"]) |
||||
.shapeWidth(40) |
||||
.labelAlign("start") |
||||
.shapePadding(10); |
||||
|
||||
svg.select(".legendSizeLine") |
||||
.call(legendSizeLine); |
||||
</code> |
||||
</pre> |
||||
</div> |
||||
</div> |
||||
</section> |
||||
|
||||
<section class="" id="symbol"> |
||||
<div class="container"> |
||||
<div class="column6 prefix3"> |
||||
<h2>Symbol</h2> |
||||
|
||||
<h3 id="symbol-doc">Documentation</h3> |
||||
<div id="symbol-md"></div> |
||||
|
||||
</div> |
||||
</div> |
||||
</section> |
||||
<section class="bg-light" id="symbol-examples"> |
||||
<div class="container"> |
||||
<div class="column6 prefix3"> |
||||
<h3>Examples</h3> |
||||
<h4 id="symbol-ordinal">Ordinal Scale Legend - Custom symbols</h4> |
||||
<svg height=90 width=170 id="svg-symbol-ordinal"></svg> |
||||
<pre class="column6 left-margin right-margin"> |
||||
<code class="language-javascript"> |
||||
|
||||
var triangleU = d3.svg.symbol().type('triangle-up')(), |
||||
circle = d3.svg.symbol().type('circle')(), |
||||
cross = d3.svg.symbol().type('cross')(), |
||||
diamond = d3.svg.symbol().type('diamond')(), |
||||
triangleD = d3.svg.symbol().type('triangle-down')(); |
||||
|
||||
//example output of d3.svg.symbol().type('circle')(); |
||||
//"M0,4.51351666838205A4.51351666838205,4.51351666838205 0 1,1 0, |
||||
//-4.51351666838205A4.51351666838205,4.51351666838205 0 1,1 0,4.51351666838205Z" |
||||
|
||||
var symbolScale = d3.scale.ordinal() |
||||
.domain(['a','b','c', 'd', 'e']) |
||||
.range([ triangleU, circle, cross, diamond, triangleD] ); |
||||
|
||||
var svg = d3.select("svg"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendSymbol") |
||||
.attr("transform", "translate(20, 20)"); |
||||
|
||||
var legendPath = d3.legend.symbol() |
||||
.scale(symbolScale) |
||||
.orient("horizontal") |
||||
.title("Symbol Legend Title") |
||||
.on("cellclick", function(d){alert("clicked " + d);}); |
||||
|
||||
svg.select(".legendSymbol") |
||||
.call(legendPath); |
||||
</code> |
||||
</pre> |
||||
</div> |
||||
</div> |
||||
</section> |
||||
|
||||
<section id="summary"> |
||||
<div class="container"> |
||||
<div class="column6 prefix3"> |
||||
<h2>Summary of Functions</h2> |
||||
<table> |
||||
<tr> |
||||
<th>Function</th> |
||||
<th>Color</th> |
||||
<th>Size</th> |
||||
<th>Symbol</th> |
||||
</tr> |
||||
|
||||
<tr> |
||||
<td>scale</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
</tr> |
||||
<tr> |
||||
<td>cells</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
</tr> |
||||
<tr> |
||||
<td>orient</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
</tr> |
||||
<tr> |
||||
<td>ascending</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
</tr> |
||||
<tr> |
||||
<td>shape</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td></td> |
||||
</tr> |
||||
<tr> |
||||
<td>shapeWidth</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td></td> |
||||
</tr> |
||||
<tr> |
||||
<td>shapeHeight</td> |
||||
<td class="included"></td> |
||||
<td></td> |
||||
<td></td> |
||||
</tr> |
||||
<tr> |
||||
<td>shapeRadius</td> |
||||
<td class="included"></td> |
||||
<td></td> |
||||
<td></td> |
||||
</tr> |
||||
<tr> |
||||
<td>shapePadding</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
</tr> |
||||
<tr> |
||||
<td>useClass</td> |
||||
<td class="included"></td> |
||||
<td></td> |
||||
<td></td> |
||||
</tr> |
||||
<tr> |
||||
<td>classPrefix</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
</tr> |
||||
<tr> |
||||
<td>title</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
</tr> |
||||
<tr> |
||||
<td>labels</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
</tr> |
||||
<tr> |
||||
<td>labelAlign</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
</tr> |
||||
<tr> |
||||
<td>labelFormat</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
</tr> |
||||
<tr> |
||||
<td>labelOffset</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
</tr> |
||||
<tr> |
||||
<td>labelDelimiter</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
</tr> |
||||
<tr> |
||||
<td>on</td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
<td class="included"></td> |
||||
</tr> |
||||
</table> |
||||
</div> |
||||
</div> |
||||
</section> |
||||
|
||||
<section class="bg-light"> |
||||
<div class="container"> |
||||
<div class="column6 prefix3"> |
||||
|
||||
<br /> |
||||
<p>NOTES</p> |
||||
|
||||
<p>Huge thanks to <a href="http://elijahmeeks.com/">Elijah Meeks</a> for discussing ideas and encouraging me to complete this project.</p> |
||||
<p>The styling and layout of this page is made with another project of mine, <a href="http://minimal-ui.susielu.com">minimal-ui.</a></p> |
||||
<p>The fonts on this page are provided by Google Fonts, and created by <a href="https://www.google.com/fonts/specimen/Montserrat">Julieta Ulanovsky</a> and <a href="https://www.google.com/fonts/specimen/Cardo">David Perry</a>.</p> |
||||
<p>Using <a href="http://prismjs.com/">Prism</a> for syntax highlighting.</p> |
||||
<p>And of course, thanks <a href="http://d3js.org/">d3.js</a> for creating such a lovely project and <a href="http://bost.ocks.org/mike/">Mike Bostock</a> for providing <a href="http://bost.ocks.org/mike/chart/">examples</a> on how to make your own components.</p> |
||||
|
||||
</div> |
||||
</div> |
||||
</section> |
||||
<script src="prism.js"></script> |
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" charset="utf-8"></script> |
||||
<script src="d3-legend.min.js"></script> |
||||
|
||||
<script src="docs.min.js"></script> |
||||
<script src="ga.js"></script> |
||||
</body> |
@ -0,0 +1,175 @@ |
||||
|
||||
|
||||
//Color: Quantile #svg-color-quant
|
||||
|
||||
var svg = d3.select("#svg-color-quant"); |
||||
|
||||
var quantize = d3.scale.quantize() |
||||
.domain([ 0, 0.15 ]) |
||||
.range(d3.range(9).map(function(i) { return "q" + i + "-9"; })); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendQuant") |
||||
.attr("transform", "translate(20,20)"); |
||||
|
||||
var legend = d3.legend.color() |
||||
.labelFormat(d3.format(".2f")) |
||||
.useClass(true) |
||||
.scale(quantize); |
||||
|
||||
svg.select(".legendQuant") |
||||
.call(legend); |
||||
|
||||
//Color: Log #svg-color-log
|
||||
var svg = d3.select("#svg-color-log"); |
||||
|
||||
var log = d3.scale.log() |
||||
.domain([ 0.1, 100, 1000 ]) |
||||
.range(["rgb(46, 73, 123)", "rgb(71, 187, 94)"]); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendLog") |
||||
.attr("transform", "translate(20,20)"); |
||||
|
||||
var logLegend = d3.legend.color() |
||||
.cells([0.1, 5, 10, 50, 100, 500, 1000]) |
||||
.scale(log); |
||||
|
||||
svg.select(".legendLog") |
||||
.call(logLegend); |
||||
|
||||
//Color Linear #svg-color-linear
|
||||
var linear = d3.scale.linear().domain([0,10]).range(["rgb(46, 73, 123)", "rgb(71, 187, 94)"]); |
||||
|
||||
svg = d3.select("#svg-color-linear"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendLinear") |
||||
.attr("transform", "translate(20,20)"); |
||||
|
||||
var legendLinear = d3.legend.color() |
||||
.shapeWidth(30) |
||||
.orient('horizontal') |
||||
.scale(linear); |
||||
|
||||
//Color Linear #svg-color-linear-10
|
||||
svg.select(".legendLinear") |
||||
.call(legendLinear); |
||||
|
||||
svg = d3.select("#svg-color-linear-10"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendLinear") |
||||
.attr("transform", "translate(20,20)"); |
||||
|
||||
legendLinear.cells(10); |
||||
|
||||
svg.select(".legendLinear") |
||||
.call(legendLinear); |
||||
|
||||
//Linear #svg-color-linear-custom
|
||||
svg.select(".legendLinear") |
||||
.call(legendLinear); |
||||
|
||||
svg = d3.select("#svg-color-linear-custom"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendLinear") |
||||
.attr("transform", "translate(20,20)"); |
||||
|
||||
legendLinear.cells([1, 2, 3, 6, 8]); |
||||
|
||||
svg.select(".legendLinear") |
||||
.call(legendLinear); |
||||
|
||||
|
||||
//Ordinal #svg-color-ordinal
|
||||
var ordinal = d3.scale.ordinal() |
||||
.domain(["a", "b", "c", "d", "e"]) |
||||
.range([ "rgb(153, 107, 195)", "rgb(56, 106, 197)", "rgb(93, 199, 76)", "rgb(223, 199, 31)", "rgb(234, 118, 47)"]); |
||||
|
||||
svg = d3.select("#svg-color-ordinal"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendOrdinal") |
||||
.attr("transform", "translate(20,20)"); |
||||
|
||||
var legendOrdinal = d3.legend.color() |
||||
.shape("path", d3.svg.symbol().type("triangle-up").size(150)()) |
||||
.shapePadding(10) |
||||
.scale(ordinal); |
||||
|
||||
svg.select(".legendOrdinal") |
||||
.call(legendOrdinal); |
||||
|
||||
|
||||
//Size: Linear Circle #svg-size-linear
|
||||
var linearSize = d3.scale.linear().domain([0,10]).range([10, 30]); |
||||
|
||||
svg = d3.select("#svg-size-linear"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendSize") |
||||
.attr("transform", "translate(20, 40)"); |
||||
|
||||
|
||||
var legendSize = d3.legend.size() |
||||
.scale(linearSize) |
||||
.shape('circle') |
||||
.shapePadding(15) |
||||
.labelOffset(20) |
||||
.orient('horizontal'); |
||||
|
||||
svg.select(".legendSize") |
||||
.call(legendSize); |
||||
|
||||
//Size: Linear Line #svg-size-line
|
||||
var lineSize = d3.scale.linear().domain([0,10]).range([2, 10]); |
||||
|
||||
svg = d3.select("#svg-size-line"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendSizeLine") |
||||
.attr("transform", "translate(0, 20)"); |
||||
|
||||
var legendSizeLine = d3.legend.size() |
||||
.scale(lineSize) |
||||
.shape("line") |
||||
.orient("horizontal") |
||||
.labels(["tiny", "small", "medium", "large", "grand"]) |
||||
.shapeWidth(50) |
||||
.labelAlign("start") |
||||
.shapePadding(10); |
||||
|
||||
svg.select(".legendSizeLine") |
||||
.call(legendSizeLine); |
||||
|
||||
//Symbol: Ordinal #svg-symbol-ordinal
|
||||
svg = d3.select("#svg-symbol-ordinal"); |
||||
|
||||
svg.append("g") |
||||
.attr("class", "legendSymbol") |
||||
.attr("transform", "translate(20, 20)"); |
||||
|
||||
var triangleU = d3.svg.symbol().type('triangle-up')(), |
||||
circle = d3.svg.symbol().type('circle')(), |
||||
cross = d3.svg.symbol().type('cross')(), |
||||
diamond = d3.svg.symbol().type('diamond')(), |
||||
triangleD = d3.svg.symbol().type('triangle-down')(); |
||||
|
||||
//example output of d3.svg.symbol().type('circle')();
|
||||
//"M0,4.51351666838205A4.51351666838205,4.51351666838205 0 1,1 0,
|
||||
//-4.51351666838205A4.51351666838205,4.51351666838205 0 1,1 0,4.51351666838205Z"
|
||||
|
||||
var symbolScale = d3.scale.ordinal() |
||||
.domain(['a','b','c', 'd', 'e']) |
||||
.range([ triangleU, circle, cross, diamond, triangleD] ); |
||||
|
||||
var legendPath = d3.legend.symbol() |
||||
.scale(symbolScale) |
||||
.orient("horizontal") |
||||
.title('Symbol Legend Title') |
||||
.on("cellclick", function(d){alert("clicked " + d);}); |
||||
|
||||
svg.select(".legendSymbol") |
||||
.call(legendPath); |
@ -0,0 +1,11 @@ |
||||
var md = require('marked'); |
||||
|
||||
var contents = require('./contents.md') |
||||
var color = require('./color.md'); |
||||
var size = require('./size.md'); |
||||
var symbol = require('./symbol.md'); |
||||
|
||||
document.getElementById('contents-md').innerHTML = md(contents); |
||||
document.getElementById('color-md').innerHTML = md(color); |
||||
document.getElementById('size-md').innerHTML = md(size); |
||||
document.getElementById('symbol-md').innerHTML = md(symbol); |
File diff suppressed because one or more lines are too long
@ -0,0 +1,137 @@ |
||||
/* http://prismjs.com/download.html?themes=prism&languages=clike+javascript */ |
||||
/** |
||||
* prism.js default theme for JavaScript, CSS and HTML |
||||
* Based on dabblet (http://dabblet.com) |
||||
* @author Lea Verou |
||||
*/ |
||||
|
||||
code[class*="language-"], |
||||
pre[class*="language-"] { |
||||
color: black; |
||||
text-shadow: 0 1px white; |
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace; |
||||
direction: ltr; |
||||
text-align: left; |
||||
white-space: pre; |
||||
word-spacing: normal; |
||||
word-break: normal; |
||||
line-height: 1.5; |
||||
|
||||
-moz-tab-size: 4; |
||||
-o-tab-size: 4; |
||||
tab-size: 4; |
||||
|
||||
-webkit-hyphens: none; |
||||
-moz-hyphens: none; |
||||
-ms-hyphens: none; |
||||
hyphens: none; |
||||
} |
||||
|
||||
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, |
||||
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { |
||||
text-shadow: none; |
||||
background: #b3d4fc; |
||||
} |
||||
|
||||
pre[class*="language-"]::selection, pre[class*="language-"] ::selection, |
||||
code[class*="language-"]::selection, code[class*="language-"] ::selection { |
||||
text-shadow: none; |
||||
background: #b3d4fc; |
||||
} |
||||
|
||||
@media print { |
||||
code[class*="language-"], |
||||
pre[class*="language-"] { |
||||
text-shadow: none; |
||||
} |
||||
} |
||||
|
||||
/* Code blocks */ |
||||
pre[class*="language-"] { |
||||
padding: 1em; |
||||
margin: .5em 0; |
||||
overflow: auto; |
||||
} |
||||
|
||||
:not(pre) > code[class*="language-"], |
||||
pre[class*="language-"] { |
||||
background: #f5f2f0; |
||||
} |
||||
|
||||
/* Inline code */ |
||||
:not(pre) > code[class*="language-"] { |
||||
padding: .1em; |
||||
border-radius: .3em; |
||||
} |
||||
|
||||
.token.comment, |
||||
.token.prolog, |
||||
.token.doctype, |
||||
.token.cdata { |
||||
color: slategray; |
||||
} |
||||
|
||||
.token.punctuation { |
||||
color: #999; |
||||
} |
||||
|
||||
.namespace { |
||||
opacity: .7; |
||||
} |
||||
|
||||
.token.property, |
||||
.token.tag, |
||||
.token.boolean, |
||||
.token.number, |
||||
.token.constant, |
||||
.token.symbol, |
||||
.token.deleted { |
||||
color: #905; |
||||
} |
||||
|
||||
.token.selector, |
||||
.token.attr-name, |
||||
.token.string, |
||||
.token.char, |
||||
.token.builtin, |
||||
.token.inserted { |
||||
color: #690; |
||||
} |
||||
|
||||
.token.operator, |
||||
.token.entity, |
||||
.token.url, |
||||
.language-css .token.string, |
||||
.style .token.string { |
||||
color: #a67f59; |
||||
background: hsla(0, 0%, 100%, .5); |
||||
} |
||||
|
||||
.token.atrule, |
||||
.token.attr-value, |
||||
.token.keyword { |
||||
color: #07a; |
||||
} |
||||
|
||||
.token.function { |
||||
color: #DD4A68; |
||||
} |
||||
|
||||
.token.regex, |
||||
.token.important, |
||||
.token.variable { |
||||
color: #e90; |
||||
} |
||||
|
||||
.token.important, |
||||
.token.bold { |
||||
font-weight: bold; |
||||
} |
||||
.token.italic { |
||||
font-style: italic; |
||||
} |
||||
|
||||
.token.entity { |
||||
cursor: help; |
||||
} |
||||
|
@ -0,0 +1,4 @@ |
||||
/* http://prismjs.com/download.html?themes=prism&languages=clike+javascript */ |
||||
self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{};var Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content),e.alias):"Array"===t.util.type(e)?e.map(t.util.encode):e.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},clone:function(e){var n=t.util.type(e);switch(n){case"Object":var a={};for(var r in e)e.hasOwnProperty(r)&&(a[r]=t.util.clone(e[r]));return a;case"Array":return e.map(function(e){return t.util.clone(e)})}return e}},languages:{extend:function(e,n){var a=t.util.clone(t.languages[e]);for(var r in n)a[r]=n[r];return a},insertBefore:function(e,n,a,r){r=r||t.languages;var i=r[e];if(2==arguments.length){a=arguments[1];for(var l in a)a.hasOwnProperty(l)&&(i[l]=a[l]);return i}var s={};for(var o in i)if(i.hasOwnProperty(o)){if(o==n)for(var l in a)a.hasOwnProperty(l)&&(s[l]=a[l]);s[o]=i[o]}return t.languages.DFS(t.languages,function(t,n){n===r[e]&&t!=e&&(this[t]=s)}),r[e]=s},DFS:function(e,n,a){for(var r in e)e.hasOwnProperty(r)&&(n.call(e,r,e[r],a||r),"Object"===t.util.type(e[r])?t.languages.DFS(e[r],n):"Array"===t.util.type(e[r])&&t.languages.DFS(e[r],n,r))}},highlightAll:function(e,n){for(var a,r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'),i=0;a=r[i++];)t.highlightElement(a,e===!0,n)},highlightElement:function(a,r,i){for(var l,s,o=a;o&&!e.test(o.className);)o=o.parentNode;if(o&&(l=(o.className.match(e)||[,""])[1],s=t.languages[l]),a.className=a.className.replace(e,"").replace(/\s+/g," ")+" language-"+l,o=a.parentNode,/pre/i.test(o.nodeName)&&(o.className=o.className.replace(e,"").replace(/\s+/g," ")+" language-"+l),s){var u=a.textContent;if(u){u=u.replace(/^(?:\r?\n|\r)/,"");var g={element:a,language:l,grammar:s,code:u};if(t.hooks.run("before-highlight",g),r&&self.Worker){var c=new Worker(t.filename);c.onmessage=function(e){g.highlightedCode=n.stringify(JSON.parse(e.data),l),t.hooks.run("before-insert",g),g.element.innerHTML=g.highlightedCode,i&&i.call(g.element),t.hooks.run("after-highlight",g)},c.postMessage(JSON.stringify({language:g.language,code:g.code}))}else g.highlightedCode=t.highlight(g.code,g.grammar,g.language),t.hooks.run("before-insert",g),g.element.innerHTML=g.highlightedCode,i&&i.call(a),t.hooks.run("after-highlight",g)}}},highlight:function(e,a,r){var i=t.tokenize(e,a);return n.stringify(t.util.encode(i),r)},tokenize:function(e,n){var a=t.Token,r=[e],i=n.rest;if(i){for(var l in i)n[l]=i[l];delete n.rest}e:for(var l in n)if(n.hasOwnProperty(l)&&n[l]){var s=n[l];s="Array"===t.util.type(s)?s:[s];for(var o=0;o<s.length;++o){var u=s[o],g=u.inside,c=!!u.lookbehind,f=0,h=u.alias;u=u.pattern||u;for(var p=0;p<r.length;p++){var d=r[p];if(r.length>e.length)break e;if(!(d instanceof a)){u.lastIndex=0;var m=u.exec(d);if(m){c&&(f=m[1].length);var y=m.index-1+f,m=m[0].slice(f),v=m.length,k=y+v,b=d.slice(0,y+1),w=d.slice(k+1),N=[p,1];b&&N.push(b);var O=new a(l,g?t.tokenize(m,g):m,h);N.push(O),w&&N.push(w),Array.prototype.splice.apply(r,N)}}}}}return r},hooks:{all:{},add:function(e,n){var a=t.hooks.all;a[e]=a[e]||[],a[e].push(n)},run:function(e,n){var a=t.hooks.all[e];if(a&&a.length)for(var r,i=0;r=a[i++];)r(n)}}},n=t.Token=function(e,t,n){this.type=e,this.content=t,this.alias=n};if(n.stringify=function(e,a,r){if("string"==typeof e)return e;if("Array"===t.util.type(e))return e.map(function(t){return n.stringify(t,a,e)}).join("");var i={type:e.type,content:n.stringify(e.content,a,r),tag:"span",classes:["token",e.type],attributes:{},language:a,parent:r};if("comment"==i.type&&(i.attributes.spellcheck="true"),e.alias){var l="Array"===t.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(i.classes,l)}t.hooks.run("wrap",i);var s="";for(var o in i.attributes)s+=o+'="'+(i.attributes[o]||"")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'" '+s+">"+i.content+"</"+i.tag+">"},!self.document)return self.addEventListener?(self.addEventListener("message",function(e){var n=JSON.parse(e.data),a=n.language,r=n.code;self.postMessage(JSON.stringify(t.util.encode(t.tokenize(r,t.languages[a])))),self.close()},!1),self.Prism):self.Prism;var a=document.getElementsByTagName("script");return a=a[a.length-1],a&&(t.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)),self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism);; |
||||
Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0}],string:/("|')(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,"class-name":{pattern:/((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":{pattern:/[a-z0-9_]+\(/i,inside:{punctuation:/\(/}},number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,operator:/[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|~|\^|%/,ignore:/&(lt|gt|amp);/i,punctuation:/[{}[\];(),.:]/};; |
||||
Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,"function":/(?!\d)[a-z0-9_$]+(?=\()/i}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}}),Prism.languages.insertBefore("javascript","class-name",{"template-string":{pattern:/`(?:\\`|\\?[^`])*`/,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/<script[\w\W]*?>[\w\W]*?<\/script>/i,inside:{tag:{pattern:/<script[\w\W]*?>|<\/script>/i,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript},alias:"language-javascript"}});; |
@ -0,0 +1,63 @@ |
||||
d3.legend.**size()** |
||||
|
||||
Constructs a new size legend. The legend component expects a d3 scale as the basic input, but also has a number of optional parameters for changing the default display such as vertical or horizontal orientation, shape of the symbol next to the label, symbol sizing, and label formatting. |
||||
|
||||
size.**scale(d3.scale)** |
||||
|
||||
Creates a new d3 legend based on the scale. The code determines the type of scale and generates the different symbol and label pairs. Expects a scale that has a numerical range. |
||||
|
||||
size.**cells(number or [numbers])** |
||||
|
||||
This parameter is only valid for continuous scales (like linear and log). When there is no indication from the domain or range for the number of steps in the legend you may want to display, it defaults to five steps in equal increments. You can pass the cells function a single number which will create equal increments for that number of steps, or an array of the [specific steps](#color-linear-custom) you want the legend to display. |
||||
|
||||
size.**orient(string)** |
||||
|
||||
Accepts "vertical" or "horizontal" for legend orientation. Default set to "vertical." |
||||
|
||||
size.**ascending(boolean)** |
||||
|
||||
If you pass this a true, it will reverse the order of the scale. |
||||
|
||||
size.**shape(string)** |
||||
|
||||
Accepts "rect", "circle", or "line". Defaults to "rect." The assumption is that the scale's output will be used for the width and height if you select "rect," the radius if you select "circle," and the stroke-width if you select "line." If you want to have a custom shape of different sizes in your legend, use the symbol legend and make each path string for the sizes you want as the range array. |
||||
|
||||
size.**shapeWidth(number)** |
||||
|
||||
Only applies to shape "line." Default set to 15px. |
||||
|
||||
size.**shapePadding(number)** |
||||
|
||||
Applies to all shapes. Determines vertical or horizontal spacing between shapes depending on the respective orient setting. Default set to 2px. |
||||
|
||||
size.**classPrefix(string)** |
||||
|
||||
Adds this string to the beginning of all of the components of the legend that have a class. This allows for namespacing of the classes. |
||||
|
||||
size.**title(string)** |
||||
|
||||
Sets the legend's title to the string. Automatically moves the legend cells down based on the size of the title. An example: [Symbol - Ordinal Scale](#symbol-ordinal). |
||||
|
||||
size.**labels([string])** |
||||
|
||||
Sets the legend labels to the array of strings passed to the legend. If the array is not the same length as the array the legend calculates, it merges the values and gives the calculated labels for the remaining items. An example: [Size - Linear Scale Legend, Lines](#size-line) |
||||
|
||||
size.**labelAlign(string)** |
||||
|
||||
Only used if the legend's orient is set to "horizontal." Accepts "start", "middle", or "end" as inputs to determine if the labels are aligned on the left, middle or right under the symbol in a horizontal legend. An example: [Size - Linear Scale Legend, Lines](#size-line). |
||||
|
||||
size.**labelFormat(d3.format)** |
||||
|
||||
Takes a [d3.format](https://github.com/mbostock/d3/wiki/Formatting) and applies that styling to the legend labels. Default is set to `d3.format(".01f")`. |
||||
|
||||
size.**labelOffset(number)** |
||||
|
||||
A value that determines how far the label is from the symbol in each legend item. Default set to 10px. |
||||
|
||||
size.**labelDelimiter(string)** |
||||
|
||||
Change the default "to" text when working with a quant scale. |
||||
|
||||
size.**on(string, function)** |
||||
|
||||
There are three custom event types you can bind to the legend: "cellover", "cellout", and "cellclick" An exampe: [Symbol - Ordinal Scale](#symbol-ordinal) |
@ -0,0 +1,55 @@ |
||||
d3.legend.**symbol()** |
||||
|
||||
Constructs a new symbol legend. The legend component expects a d3 scale as the basic input, but also has a number of optional parameters for changing the default display such as vertical or horizontal orientation, shape of the symbol next to the label, symbol sizing, and label formatting. |
||||
|
||||
symbol.**scale()** |
||||
|
||||
Creates a new d3 legend based on the scale. The code determines the type of scale and generates the different symbol and label pairs. The scale's range will be used as the d-attribute in an svg path for each symbol in the legend. |
||||
|
||||
symbol.**cells()** |
||||
|
||||
This parameter is only valid for continuous scales (like linear and log). When there is no indication from the domain or range for the number of steps in the legend you may want to display, it defaults to five steps in equal increments. You can pass the cells function a single number which will create equal increments for that number of steps, or an array of the [specific steps](#color-linear-custom) you want the legend to display. |
||||
|
||||
symbol.**orient(string)** |
||||
|
||||
Accepts "vertical" or "horizontal" for legend orientation. Default set to "vertical." |
||||
|
||||
symbol.**ascending(boolean)** |
||||
|
||||
If you pass this a true, it will reverse the order of the scale. |
||||
|
||||
symbol.**shapePadding()** |
||||
|
||||
Applies to all shapes. Determines vertical or horizontal spacing between shapes depending on the respective orient setting. Default set to 2px. |
||||
|
||||
symbol.**classPrefix(string)** |
||||
|
||||
Adds this string to the beginning of all of the components of the legend that have a class. This allows for namespacing of the classes. |
||||
|
||||
symbol.**title(string)** |
||||
|
||||
Sets the legend's title to the string. Automatically moves the legend cells down based on the size of the title. An example: [Symbol - Ordinal Scale](#symbol-ordinal). |
||||
|
||||
symbol.**labels([string])** |
||||
|
||||
Sets the legend labels to the array of strings passed to the legend. If the array is not the same length as the array the legend calculates, it merges the values and gives the calculated labels for the remaining items. An example: [Size - Linear Scale Legend, Lines](#size-line). |
||||
|
||||
symbol.**labelAlign(string)** |
||||
|
||||
Only used if the legend's orient is set to "horizontal." Accepts "start", "middle", or "end" as inputs to determine if the labels are aligned on the left, middle or right under the symbol in a horizontal legend. An example: [Size - Linear Scale Legend, Lines](#size-line). |
||||
|
||||
symbol.**labelFormat(d3.format)** |
||||
|
||||
Takes a [d3.format](https://github.com/mbostock/d3/wiki/Formatting) and applies that styling to the legend labels. Default is set to `d3.format(".01f")`. |
||||
|
||||
symbol.**labelOffset(number)** |
||||
|
||||
A value that determines how far the label is from the symbol in each legend item. Default set to 10px. |
||||
|
||||
symbol.**labelDelimiter(string)** |
||||
|
||||
Change the default "to" text when working with a quant scale. |
||||
|
||||
symbol.**on(string, function)** |
||||
|
||||
There are three custom event types you can bind to the legend: "cellover", "cellout", and "cellclick" An exampe: [Symbol - Ordinal Scale](#symbol-ordinal) |
@ -0,0 +1,5 @@ |
||||
var d3 = require('d3'); |
||||
|
||||
d3.legend = require('./no-extend'); |
||||
|
||||
module.exports = d3; |
@ -0,0 +1,5 @@ |
||||
module.exports = { |
||||
color: require('./src/color'), |
||||
size: require('./src/size'), |
||||
symbol: require('./src/symbol') |
||||
}; |
@ -0,0 +1,49 @@ |
||||
{ |
||||
"name": "d3-svg-legend", |
||||
"version": "1.13.0", |
||||
"description": "A legend component for d3. Given a d3.scale it can create either a color legend, size legend, or symbol legend.", |
||||
"main": "index.js", |
||||
"files": [ |
||||
"src", |
||||
"index.js", |
||||
"d3-legend.*", |
||||
"no-extend.js" |
||||
], |
||||
"keywords": [ |
||||
"d3", |
||||
"legend" |
||||
], |
||||
"directories": { |
||||
"example": "examples", |
||||
"test": "test" |
||||
}, |
||||
"peerDependencies": { |
||||
"d3": "^3.0.0" |
||||
}, |
||||
"devDependencies": { |
||||
"chai": "3.4.1", |
||||
"grunt": "0.4.5", |
||||
"grunt-browserify": "3.8.0", |
||||
"grunt-contrib-uglify": "0.9.1", |
||||
"marked": "0.3.5", |
||||
"mocha": "2.2.5", |
||||
"stringify": "3.1.0" |
||||
}, |
||||
"scripts": { |
||||
"prepublish": "npm t", |
||||
"test": "mocha test/test.js" |
||||
}, |
||||
"repository": { |
||||
"type": "git", |
||||
"url": "https://github.com/susielu/d3-legend.git" |
||||
}, |
||||
"author": { |
||||
"name": "Susie Lu", |
||||
"url": "http://www.susielu.com" |
||||
}, |
||||
"license": "ISC", |
||||
"bugs": { |
||||
"url": "https://github.com/susielu/d3-legend/issues" |
||||
}, |
||||
"homepage": "http://d3-legend.susielu.com" |
||||
} |
@ -0,0 +1,206 @@ |
||||
var helper = require('./legend'); |
||||
|
||||
module.exports = function(){ |
||||
|
||||
var scale = d3.scale.linear(), |
||||
shape = "rect", |
||||
shapeWidth = 15, |
||||
shapeHeight = 15, |
||||
shapeRadius = 10, |
||||
shapePadding = 2, |
||||
cells = [5], |
||||
labels = [], |
||||
classPrefix = "", |
||||
useClass = false, |
||||
title = "", |
||||
labelFormat = d3.format(".01f"), |
||||
labelOffset = 10, |
||||
labelAlign = "middle", |
||||
labelDelimiter = "to", |
||||
orient = "vertical", |
||||
ascending = false, |
||||
path, |
||||
legendDispatcher = d3.dispatch("cellover", "cellout", "cellclick"); |
||||
|
||||
function legend(svg){ |
||||
|
||||
var type = helper.d3_calcType(scale, ascending, cells, labels, labelFormat, labelDelimiter), |
||||
legendG = svg.selectAll('g').data([scale]); |
||||
|
||||
legendG.enter().append('g').attr('class', classPrefix + 'legendCells'); |
||||
|
||||
|
||||
var cell = legendG.selectAll("." + classPrefix + "cell").data(type.data), |
||||
cellEnter = cell.enter().append("g", ".cell").attr("class", classPrefix + "cell").style("opacity", 1e-6), |
||||
shapeEnter = cellEnter.append(shape).attr("class", classPrefix + "swatch"), |
||||
shapes = cell.select("g." + classPrefix + "cell " + shape); |
||||
|
||||
//add event handlers
|
||||
helper.d3_addEvents(cellEnter, legendDispatcher); |
||||
|
||||
cell.exit().transition().style("opacity", 0).remove(); |
||||
|
||||
helper.d3_drawShapes(shape, shapes, shapeHeight, shapeWidth, shapeRadius, path); |
||||
|
||||
helper.d3_addText(legendG, cellEnter, type.labels, classPrefix) |
||||
|
||||
// sets placement
|
||||
var text = cell.select("text"), |
||||
shapeSize = shapes[0].map( function(d){ return d.getBBox(); }); |
||||
|
||||
//sets scale
|
||||
//everything is fill except for line which is stroke,
|
||||
if (!useClass){ |
||||
if (shape == "line"){ |
||||
shapes.style("stroke", type.feature); |
||||
} else { |
||||
shapes.style("fill", type.feature); |
||||
} |
||||
} else { |
||||
shapes.attr("class", function(d){ return classPrefix + "swatch " + type.feature(d); }); |
||||
} |
||||
|
||||
var cellTrans, |
||||
textTrans, |
||||
textAlign = (labelAlign == "start") ? 0 : (labelAlign == "middle") ? 0.5 : 1; |
||||
|
||||
//positions cells and text
|
||||
if (orient === "vertical"){ |
||||
cellTrans = function(d,i) { return "translate(0, " + (i * (shapeSize[i].height + shapePadding)) + ")"; }; |
||||
textTrans = function(d,i) { return "translate(" + (shapeSize[i].width + shapeSize[i].x + |
||||
labelOffset) + "," + (shapeSize[i].y + shapeSize[i].height/2 + 5) + ")"; }; |
||||
|
||||
} else if (orient === "horizontal"){ |
||||
cellTrans = function(d,i) { return "translate(" + (i * (shapeSize[i].width + shapePadding)) + ",0)"; } |
||||
textTrans = function(d,i) { return "translate(" + (shapeSize[i].width*textAlign + shapeSize[i].x) + |
||||
"," + (shapeSize[i].height + shapeSize[i].y + labelOffset + 8) + ")"; }; |
||||
} |
||||
|
||||
helper.d3_placement(orient, cell, cellTrans, text, textTrans, labelAlign); |
||||
helper.d3_title(svg, legendG, title, classPrefix); |
||||
|
||||
cell.transition().style("opacity", 1); |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
legend.scale = function(_) { |
||||
if (!arguments.length) return scale; |
||||
scale = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.cells = function(_) { |
||||
if (!arguments.length) return cells; |
||||
if (_.length > 1 || _ >= 2 ){ |
||||
cells = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shape = function(_, d) { |
||||
if (!arguments.length) return shape; |
||||
if (_ == "rect" || _ == "circle" || _ == "line" || (_ == "path" && (typeof d === 'string')) ){ |
||||
shape = _; |
||||
path = d; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shapeWidth = function(_) { |
||||
if (!arguments.length) return shapeWidth; |
||||
shapeWidth = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shapeHeight = function(_) { |
||||
if (!arguments.length) return shapeHeight; |
||||
shapeHeight = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shapeRadius = function(_) { |
||||
if (!arguments.length) return shapeRadius; |
||||
shapeRadius = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shapePadding = function(_) { |
||||
if (!arguments.length) return shapePadding; |
||||
shapePadding = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labels = function(_) { |
||||
if (!arguments.length) return labels; |
||||
labels = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelAlign = function(_) { |
||||
if (!arguments.length) return labelAlign; |
||||
if (_ == "start" || _ == "end" || _ == "middle") { |
||||
labelAlign = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelFormat = function(_) { |
||||
if (!arguments.length) return labelFormat; |
||||
labelFormat = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelOffset = function(_) { |
||||
if (!arguments.length) return labelOffset; |
||||
labelOffset = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelDelimiter = function(_) { |
||||
if (!arguments.length) return labelDelimiter; |
||||
labelDelimiter = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.useClass = function(_) { |
||||
if (!arguments.length) return useClass; |
||||
if (_ === true || _ === false){ |
||||
useClass = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.orient = function(_){ |
||||
if (!arguments.length) return orient; |
||||
_ = _.toLowerCase(); |
||||
if (_ == "horizontal" || _ == "vertical") { |
||||
orient = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.ascending = function(_) { |
||||
if (!arguments.length) return ascending; |
||||
ascending = !!_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.classPrefix = function(_) { |
||||
if (!arguments.length) return classPrefix; |
||||
classPrefix = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.title = function(_) { |
||||
if (!arguments.length) return title; |
||||
title = _; |
||||
return legend; |
||||
}; |
||||
|
||||
d3.rebind(legend, legendDispatcher, "on"); |
||||
|
||||
return legend; |
||||
|
||||
}; |
@ -0,0 +1,164 @@ |
||||
module.exports = { |
||||
|
||||
d3_identity: function (d) { |
||||
return d; |
||||
}, |
||||
|
||||
d3_mergeLabels: function (gen, labels) { |
||||
|
||||
if(labels.length === 0) return gen; |
||||
|
||||
gen = (gen) ? gen : []; |
||||
|
||||
var i = labels.length; |
||||
for (; i < gen.length; i++) { |
||||
labels.push(gen[i]); |
||||
} |
||||
return labels; |
||||
}, |
||||
|
||||
d3_linearLegend: function (scale, cells, labelFormat) { |
||||
var data = []; |
||||
|
||||
if (cells.length > 1){ |
||||
data = cells; |
||||
|
||||
} else { |
||||
var domain = scale.domain(), |
||||
increment = (domain[domain.length - 1] - domain[0])/(cells - 1), |
||||
i = 0; |
||||
|
||||
for (; i < cells; i++){ |
||||
data.push(domain[0] + i*increment); |
||||
} |
||||
} |
||||
|
||||
var labels = data.map(labelFormat); |
||||
|
||||
return {data: data, |
||||
labels: labels, |
||||
feature: function(d){ return scale(d); }}; |
||||
}, |
||||
|
||||
d3_quantLegend: function (scale, labelFormat, labelDelimiter) { |
||||
var labels = scale.range().map(function(d){ |
||||
var invert = scale.invertExtent(d), |
||||
a = labelFormat(invert[0]), |
||||
b = labelFormat(invert[1]); |
||||
|
||||
// if (( (a) && (a.isNan()) && b){
|
||||
// console.log("in initial statement")
|
||||
return labelFormat(invert[0]) + " " + labelDelimiter + " " + labelFormat(invert[1]); |
||||
// } else if (a || b) {
|
||||
// console.log('in else statement')
|
||||
// return (a) ? a : b;
|
||||
// }
|
||||
|
||||
}); |
||||
|
||||
return {data: scale.range(), |
||||
labels: labels, |
||||
feature: this.d3_identity |
||||
}; |
||||
}, |
||||
|
||||
d3_ordinalLegend: function (scale) { |
||||
return {data: scale.domain(), |
||||
labels: scale.domain(), |
||||
feature: function(d){ return scale(d); }}; |
||||
}, |
||||
|
||||
d3_drawShapes: function (shape, shapes, shapeHeight, shapeWidth, shapeRadius, path) { |
||||
if (shape === "rect"){ |
||||
shapes.attr("height", shapeHeight).attr("width", shapeWidth); |
||||
|
||||
} else if (shape === "circle") { |
||||
shapes.attr("r", shapeRadius)//.attr("cx", shapeRadius).attr("cy", shapeRadius);
|
||||
|
||||
} else if (shape === "line") { |
||||
shapes.attr("x1", 0).attr("x2", shapeWidth).attr("y1", 0).attr("y2", 0); |
||||
|
||||
} else if (shape === "path") { |
||||
shapes.attr("d", path); |
||||
} |
||||
}, |
||||
|
||||
d3_addText: function (svg, enter, labels, classPrefix){ |
||||
enter.append("text").attr("class", classPrefix + "label"); |
||||
svg.selectAll("g." + classPrefix + "cell text." + classPrefix + "label") |
||||
.data(labels).text(this.d3_identity); |
||||
}, |
||||
|
||||
d3_calcType: function (scale, ascending, cells, labels, labelFormat, labelDelimiter){ |
||||
var type = scale.ticks ? |
||||
this.d3_linearLegend(scale, cells, labelFormat) : scale.invertExtent ? |
||||
this.d3_quantLegend(scale, labelFormat, labelDelimiter) : this.d3_ordinalLegend(scale); |
||||
|
||||
type.labels = this.d3_mergeLabels(type.labels, labels); |
||||
|
||||
if (ascending) { |
||||
type.labels = this.d3_reverse(type.labels); |
||||
type.data = this.d3_reverse(type.data); |
||||
} |
||||
|
||||
return type; |
||||
}, |
||||
|
||||
d3_reverse: function(arr) { |
||||
var mirror = []; |
||||
for (var i = 0, l = arr.length; i < l; i++) { |
||||
mirror[i] = arr[l-i-1]; |
||||
} |
||||
return mirror; |
||||
}, |
||||
|
||||
d3_placement: function (orient, cell, cellTrans, text, textTrans, labelAlign) { |
||||
cell.attr("transform", cellTrans); |
||||
text.attr("transform", textTrans); |
||||
if (orient === "horizontal"){ |
||||
text.style("text-anchor", labelAlign); |
||||
} |
||||
}, |
||||
|
||||
d3_addEvents: function(cells, dispatcher){ |
||||
var _ = this; |
||||
|
||||
cells.on("mouseover.legend", function (d) { _.d3_cellOver(dispatcher, d, this); }) |
||||
.on("mouseout.legend", function (d) { _.d3_cellOut(dispatcher, d, this); }) |
||||
.on("click.legend", function (d) { _.d3_cellClick(dispatcher, d, this); }); |
||||
}, |
||||
|
||||
d3_cellOver: function(cellDispatcher, d, obj){ |
||||
cellDispatcher.cellover.call(obj, d); |
||||
}, |
||||
|
||||
d3_cellOut: function(cellDispatcher, d, obj){ |
||||
cellDispatcher.cellout.call(obj, d); |
||||
}, |
||||
|
||||
d3_cellClick: function(cellDispatcher, d, obj){ |
||||
cellDispatcher.cellclick.call(obj, d); |
||||
}, |
||||
|
||||
d3_title: function(svg, cellsSvg, title, classPrefix){ |
||||
if (title !== ""){ |
||||
|
||||
var titleText = svg.selectAll('text.' + classPrefix + 'legendTitle'); |
||||
|
||||
titleText.data([title]) |
||||
.enter() |
||||
.append('text') |
||||
.attr('class', classPrefix + 'legendTitle'); |
||||
|
||||
svg.selectAll('text.' + classPrefix + 'legendTitle') |
||||
.text(title) |
||||
|
||||
var yOffset = svg.select('.' + classPrefix + 'legendTitle') |
||||
.map(function(d) { return d[0].getBBox().height})[0], |
||||
xOffset = -cellsSvg.map(function(d) { return d[0].getBBox().x})[0]; |
||||
|
||||
cellsSvg.attr('transform', 'translate(' + xOffset + ',' + (yOffset + 10) + ')'); |
||||
|
||||
} |
||||
} |
||||
} |
@ -0,0 +1,199 @@ |
||||
var helper = require('./legend'); |
||||
|
||||
module.exports = function(){ |
||||
|
||||
var scale = d3.scale.linear(), |
||||
shape = "rect", |
||||
shapeWidth = 15, |
||||
shapePadding = 2, |
||||
cells = [5], |
||||
labels = [], |
||||
useStroke = false, |
||||
classPrefix = "", |
||||
title = "", |
||||
labelFormat = d3.format(".01f"), |
||||
labelOffset = 10, |
||||
labelAlign = "middle", |
||||
labelDelimiter = "to", |
||||
orient = "vertical", |
||||
ascending = false, |
||||
path, |
||||
legendDispatcher = d3.dispatch("cellover", "cellout", "cellclick"); |
||||
|
||||
function legend(svg){ |
||||
|
||||
var type = helper.d3_calcType(scale, ascending, cells, labels, labelFormat, labelDelimiter), |
||||
legendG = svg.selectAll('g').data([scale]); |
||||
|
||||
legendG.enter().append('g').attr('class', classPrefix + 'legendCells'); |
||||
|
||||
|
||||
var cell = legendG.selectAll("." + classPrefix + "cell").data(type.data), |
||||
cellEnter = cell.enter().append("g", ".cell").attr("class", classPrefix + "cell").style("opacity", 1e-6), |
||||
shapeEnter = cellEnter.append(shape).attr("class", classPrefix + "swatch"), |
||||
shapes = cell.select("g." + classPrefix + "cell " + shape); |
||||
|
||||
//add event handlers
|
||||
helper.d3_addEvents(cellEnter, legendDispatcher); |
||||
|
||||
cell.exit().transition().style("opacity", 0).remove(); |
||||
|
||||
//creates shape
|
||||
if (shape === "line"){ |
||||
helper.d3_drawShapes(shape, shapes, 0, shapeWidth); |
||||
shapes.attr("stroke-width", type.feature); |
||||
} else { |
||||
helper.d3_drawShapes(shape, shapes, type.feature, type.feature, type.feature, path); |
||||
} |
||||
|
||||
helper.d3_addText(legendG, cellEnter, type.labels, classPrefix) |
||||
|
||||
//sets placement
|
||||
var text = cell.select("text"), |
||||
shapeSize = shapes[0].map( |
||||
function(d, i){ |
||||
var bbox = d.getBBox() |
||||
var stroke = scale(type.data[i]); |
||||
|
||||
if (shape === "line" && orient === "horizontal") { |
||||
bbox.height = bbox.height + stroke; |
||||
} else if (shape === "line" && orient === "vertical"){ |
||||
bbox.width = bbox.width; |
||||
} |
||||
|
||||
return bbox; |
||||
}); |
||||
|
||||
var maxH = d3.max(shapeSize, function(d){ return d.height + d.y; }), |
||||
maxW = d3.max(shapeSize, function(d){ return d.width + d.x; }); |
||||
|
||||
var cellTrans, |
||||
textTrans, |
||||
textAlign = (labelAlign == "start") ? 0 : (labelAlign == "middle") ? 0.5 : 1; |
||||
|
||||
//positions cells and text
|
||||
if (orient === "vertical"){ |
||||
|
||||
cellTrans = function(d,i) { |
||||
var height = d3.sum(shapeSize.slice(0, i + 1 ), function(d){ return d.height; }); |
||||
return "translate(0, " + (height + i*shapePadding) + ")"; }; |
||||
|
||||
textTrans = function(d,i) { return "translate(" + (maxW + labelOffset) + "," + |
||||
(shapeSize[i].y + shapeSize[i].height/2 + 5) + ")"; }; |
||||
|
||||
} else if (orient === "horizontal"){ |
||||
cellTrans = function(d,i) { |
||||
var width = d3.sum(shapeSize.slice(0, i + 1 ), function(d){ return d.width; }); |
||||
return "translate(" + (width + i*shapePadding) + ",0)"; }; |
||||
|
||||
textTrans = function(d,i) { return "translate(" + (shapeSize[i].width*textAlign + shapeSize[i].x) + "," + |
||||
(maxH + labelOffset ) + ")"; }; |
||||
} |
||||
|
||||
helper.d3_placement(orient, cell, cellTrans, text, textTrans, labelAlign); |
||||
helper.d3_title(svg, legendG, title, classPrefix); |
||||
|
||||
cell.transition().style("opacity", 1); |
||||
|
||||
} |
||||
|
||||
legend.scale = function(_) { |
||||
if (!arguments.length) return scale; |
||||
scale = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.cells = function(_) { |
||||
if (!arguments.length) return cells; |
||||
if (_.length > 1 || _ >= 2 ){ |
||||
cells = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
|
||||
legend.shape = function(_, d) { |
||||
if (!arguments.length) return shape; |
||||
if (_ == "rect" || _ == "circle" || _ == "line" ){ |
||||
shape = _; |
||||
path = d; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shapeWidth = function(_) { |
||||
if (!arguments.length) return shapeWidth; |
||||
shapeWidth = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shapePadding = function(_) { |
||||
if (!arguments.length) return shapePadding; |
||||
shapePadding = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labels = function(_) { |
||||
if (!arguments.length) return labels; |
||||
labels = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelAlign = function(_) { |
||||
if (!arguments.length) return labelAlign; |
||||
if (_ == "start" || _ == "end" || _ == "middle") { |
||||
labelAlign = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelFormat = function(_) { |
||||
if (!arguments.length) return labelFormat; |
||||
labelFormat = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelOffset = function(_) { |
||||
if (!arguments.length) return labelOffset; |
||||
labelOffset = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelDelimiter = function(_) { |
||||
if (!arguments.length) return labelDelimiter; |
||||
labelDelimiter = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.orient = function(_){ |
||||
if (!arguments.length) return orient; |
||||
_ = _.toLowerCase(); |
||||
if (_ == "horizontal" || _ == "vertical") { |
||||
orient = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.ascending = function(_) { |
||||
if (!arguments.length) return ascending; |
||||
ascending = !!_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.classPrefix = function(_) { |
||||
if (!arguments.length) return classPrefix; |
||||
classPrefix = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.title = function(_) { |
||||
if (!arguments.length) return title; |
||||
title = _; |
||||
return legend; |
||||
}; |
||||
|
||||
d3.rebind(legend, legendDispatcher, "on"); |
||||
|
||||
return legend; |
||||
|
||||
}; |
@ -0,0 +1,158 @@ |
||||
var helper = require('./legend'); |
||||
|
||||
module.exports = function(){ |
||||
|
||||
var scale = d3.scale.linear(), |
||||
shape = "path", |
||||
shapeWidth = 15, |
||||
shapeHeight = 15, |
||||
shapeRadius = 10, |
||||
shapePadding = 5, |
||||
cells = [5], |
||||
labels = [], |
||||
classPrefix = "", |
||||
useClass = false, |
||||
title = "", |
||||
labelFormat = d3.format(".01f"), |
||||
labelAlign = "middle", |
||||
labelOffset = 10, |
||||
labelDelimiter = "to", |
||||
orient = "vertical", |
||||
ascending = false, |
||||
legendDispatcher = d3.dispatch("cellover", "cellout", "cellclick"); |
||||
|
||||
function legend(svg){ |
||||
|
||||
var type = helper.d3_calcType(scale, ascending, cells, labels, labelFormat, labelDelimiter), |
||||
legendG = svg.selectAll('g').data([scale]); |
||||
|
||||
legendG.enter().append('g').attr('class', classPrefix + 'legendCells'); |
||||
|
||||
var cell = legendG.selectAll("." + classPrefix + "cell").data(type.data), |
||||
cellEnter = cell.enter().append("g", ".cell").attr("class", classPrefix + "cell").style("opacity", 1e-6), |
||||
shapeEnter = cellEnter.append(shape).attr("class", classPrefix + "swatch"), |
||||
shapes = cell.select("g." + classPrefix + "cell " + shape); |
||||
|
||||
//add event handlers
|
||||
helper.d3_addEvents(cellEnter, legendDispatcher); |
||||
|
||||
//remove old shapes
|
||||
cell.exit().transition().style("opacity", 0).remove(); |
||||
|
||||
helper.d3_drawShapes(shape, shapes, shapeHeight, shapeWidth, shapeRadius, type.feature); |
||||
helper.d3_addText(legendG, cellEnter, type.labels, classPrefix) |
||||
|
||||
// sets placement
|
||||
var text = cell.select("text"), |
||||
shapeSize = shapes[0].map( function(d){ return d.getBBox(); }); |
||||
|
||||
var maxH = d3.max(shapeSize, function(d){ return d.height; }), |
||||
maxW = d3.max(shapeSize, function(d){ return d.width; }); |
||||
|
||||
var cellTrans, |
||||
textTrans, |
||||
textAlign = (labelAlign == "start") ? 0 : (labelAlign == "middle") ? 0.5 : 1; |
||||
|
||||
//positions cells and text
|
||||
if (orient === "vertical"){ |
||||
cellTrans = function(d,i) { return "translate(0, " + (i * (maxH + shapePadding)) + ")"; }; |
||||
textTrans = function(d,i) { return "translate(" + (maxW + labelOffset) + "," + |
||||
(shapeSize[i].y + shapeSize[i].height/2 + 5) + ")"; }; |
||||
|
||||
} else if (orient === "horizontal"){ |
||||
cellTrans = function(d,i) { return "translate(" + (i * (maxW + shapePadding)) + ",0)"; }; |
||||
textTrans = function(d,i) { return "translate(" + (shapeSize[i].width*textAlign + shapeSize[i].x) + "," + |
||||
(maxH + labelOffset ) + ")"; }; |
||||
} |
||||
|
||||
helper.d3_placement(orient, cell, cellTrans, text, textTrans, labelAlign); |
||||
helper.d3_title(svg, legendG, title, classPrefix); |
||||
cell.transition().style("opacity", 1); |
||||
|
||||
} |
||||
|
||||
|
||||
legend.scale = function(_) { |
||||
if (!arguments.length) return scale; |
||||
scale = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.cells = function(_) { |
||||
if (!arguments.length) return cells; |
||||
if (_.length > 1 || _ >= 2 ){ |
||||
cells = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.shapePadding = function(_) { |
||||
if (!arguments.length) return shapePadding; |
||||
shapePadding = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labels = function(_) { |
||||
if (!arguments.length) return labels; |
||||
labels = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelAlign = function(_) { |
||||
if (!arguments.length) return labelAlign; |
||||
if (_ == "start" || _ == "end" || _ == "middle") { |
||||
labelAlign = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelFormat = function(_) { |
||||
if (!arguments.length) return labelFormat; |
||||
labelFormat = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelOffset = function(_) { |
||||
if (!arguments.length) return labelOffset; |
||||
labelOffset = +_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.labelDelimiter = function(_) { |
||||
if (!arguments.length) return labelDelimiter; |
||||
labelDelimiter = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.orient = function(_){ |
||||
if (!arguments.length) return orient; |
||||
_ = _.toLowerCase(); |
||||
if (_ == "horizontal" || _ == "vertical") { |
||||
orient = _; |
||||
} |
||||
return legend; |
||||
}; |
||||
|
||||
legend.ascending = function(_) { |
||||
if (!arguments.length) return ascending; |
||||
ascending = !!_; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.classPrefix = function(_) { |
||||
if (!arguments.length) return classPrefix; |
||||
classPrefix = _; |
||||
return legend; |
||||
}; |
||||
|
||||
legend.title = function(_) { |
||||
if (!arguments.length) return title; |
||||
title = _; |
||||
return legend; |
||||
}; |
||||
|
||||
d3.rebind(legend, legendDispatcher, "on"); |
||||
|
||||
return legend; |
||||
|
||||
}; |
@ -0,0 +1,5 @@ |
||||
d3.legend = { |
||||
color: require('./color'), |
||||
size: require('./size'), |
||||
symbol: require('./symbol') |
||||
}; |
@ -0,0 +1,20 @@ |
||||
const chai = require('chai') |
||||
const expect = chai.expect |
||||
|
||||
describe('d3-legend', function () { |
||||
var d3Legend |
||||
|
||||
beforeEach(function () { |
||||
d3Legend = require('../no-extend') |
||||
}) |
||||
|
||||
it('should export an object', function () { |
||||
expect(d3Legend).to.be.an('object') |
||||
}) |
||||
|
||||
it('should have color, size & symbol functions', function () { |
||||
['color','size','symbol'].forEach(function (fieldName) { |
||||
expect(d3Legend[fieldName]).to.be.a('function') |
||||
}) |
||||
}) |
||||
}) |
@ -0,0 +1,2 @@ |
||||
components |
||||
bower_components |
@ -0,0 +1,8 @@ |
||||
The MIT License (MIT) |
||||
Copyright (c) 2013 Justin Palmer |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,5 @@ |
||||
d3.tip.min.js: clean |
||||
uglifyjs src/d3.tip.js -c -m -o d3.tip.min.js
|
||||
|
||||
clean: |
||||
@rm -f d3.tip.min.js
|
@ -0,0 +1,38 @@ |
||||
# d3.tip: Tooltips for d3.js visualizations |
||||
|
||||
[![](https://github-images.s3.amazonaws.com/skitch/Screen_Shot_2013-04-08_at_11.40.10_AM-20130408-114054.png)](http://bl.ocks.org/Caged/6476579) |
||||
|
||||
* [See a live demo](http://bl.ocks.org/Caged/6476579) |
||||
* [Example code](/examples) |
||||
|
||||
### API Docs |
||||
See the [API Documentation](docs/index.md) |
||||
|
||||
### Download Latest Version |
||||
* [Development Version](https://raw.github.com/Caged/d3-tip/master/index.js) : **6kb** / **~2kb gzipped** |
||||
|
||||
### Install with Bower |
||||
``` |
||||
bower install d3-tip |
||||
``` |
||||
|
||||
### Quick Usage |
||||
``` javascript |
||||
|
||||
/* Initialize tooltip */ |
||||
tip = d3.tip().attr('class', 'd3-tip').html(function(d) { return d; }); |
||||
|
||||
/* Invoke the tip in the context of your visualization */ |
||||
vis.call(tip) |
||||
|
||||
vis.selectAll('rect') |
||||
.data(data) |
||||
.enter().append('rect') |
||||
.attr('width', function() { return x.rangeBand() }) |
||||
.attr('height', function(d) { return h - y(d) }) |
||||
.attr('y', function(d) { return y(d) }) |
||||
.attr('x', function(d, i) { return x(i) }) |
||||
/* Show and hide tip on mouse events */ |
||||
.on('mouseover', tip.show) |
||||
.on('mouseout', tip.hide) |
||||
``` |
@ -0,0 +1,17 @@ |
||||
{ |
||||
"name": "d3-tip", |
||||
"version": "0.6.3", |
||||
"main": "index.js", |
||||
"ignore": [ |
||||
"**/.*", |
||||
"node_modules", |
||||
"components", |
||||
"bower_components", |
||||
"examples", |
||||
"Makefile", |
||||
"docs" |
||||
], |
||||
"dependencies": { |
||||
"d3": "3" |
||||
} |
||||
} |
@ -0,0 +1,19 @@ |
||||
# d3.tip API documetation |
||||
|
||||
#### [Initializing tooltips](initializing-tooltips.md) |
||||
* [d3.tip](initializing-tooltips.md#d3tip) |
||||
|
||||
#### [Showing and hiding tooltips](showing-and-hiding-tooltips.md) |
||||
* [tip.show](showing-and-hiding-tooltips.md#tipshow) |
||||
* [tip.hide](showing-and-hiding-tooltips.md#tiphide) |
||||
|
||||
#### [Styling and modifying tooltips](styling-and-modifying-tooltips.md) |
||||
* [tip.attr](styling-and-modifying-tooltips.md#tipattr) |
||||
* [tip.style](styling-and-modifying-tooltips.md#tipstyle) |
||||
|
||||
#### [Positioning tooltips](positioning-tooltips.md) |
||||
* [tip.direction](positioning-tooltips.md#tipdirection) |
||||
* [tip.offset](positioning-tooltips.md#tipoffset) |
||||
|
||||
#### [Updating tooltip content](updating-tooltip-content.md) |
||||
* [tip.html](updating-tooltip-content.md#tiphtml) |
@ -0,0 +1,27 @@ |
||||
[API Documentation](index.md) ➤ Initializing tooltips |
||||
|
||||
# Initializing tooltips |
||||
|
||||
### d3.tip |
||||
Create and return a [configurable function](http://bost.ocks.org/mike/chart) for |
||||
a tooltip. |
||||
|
||||
You ***must*** call the tip on the context of the target visualization. |
||||
|
||||
``` javascript |
||||
var tip = d3.tip() |
||||
.attr('class', 'd3-tip') |
||||
.html(function(d) { return d; }) |
||||
|
||||
var vis = d3.select(document.body) |
||||
.append('svg') |
||||
// REQUIRED: Call the tooltip on the context of the visualization |
||||
.call(tip) |
||||
|
||||
vis.append('rect') |
||||
.attr('width', 100) |
||||
.attr('height', 100) |
||||
// Show and hide the tooltip |
||||
.on('mouseover', tip.show) |
||||
.on('mouseout', tip.hide) |
||||
``` |
@ -0,0 +1,33 @@ |
||||
[API Documentation](index.md) ➤ Positioning tooltips |
||||
|
||||
# Positioning tooltips |
||||
|
||||
### tip.direction(direction) |
||||
Sets the position of a tooltip relative to a target element. `direction` can be |
||||
`n`, `s`, `e`, `w`, `nw`, `ne`, `sw` or `se`. The direction will also automatically be included as a classname |
||||
on the tooltip element which allows for different style hooks based on the direction. |
||||
|
||||
``` javascript |
||||
tip.direction('n') // Position the tooltip to the top of a target element |
||||
tip.direction('s') // Position the tooltip to the bottom of a target element |
||||
tip.direction('e') // Position the tooltip to the right of a target element |
||||
tip.direction('w') // Position the tooltip to the left of a target element |
||||
``` |
||||
##### Changing the direction programatically |
||||
``` javascript |
||||
tip.direction(function(d) { |
||||
if(d == 'california') return 'w' |
||||
if(d == 'new york') return 'e' |
||||
}) |
||||
``` |
||||
|
||||
### tip.offset([values]) |
||||
Offset a tooltip relative to its calculated position. Offset is computed from |
||||
`[top, left]`. |
||||
|
||||
If you want to draw extenders on tooltips, use this method to offset the tooltip |
||||
enough in the desired direction so the extender doesn't overlap the target element. |
||||
|
||||
``` javascript |
||||
tip.offset([10, -10]) |
||||
``` |
@ -0,0 +1,40 @@ |
||||
[API Documentation](index.md) ➤ Showing and hiding tooltips |
||||
|
||||
# Showing and hiding tooltips |
||||
|
||||
### tip.show |
||||
Show a tooltip on the screen. |
||||
|
||||
``` javascript |
||||
rect.on('mouseover', tip.show) |
||||
``` |
||||
|
||||
``` javascript |
||||
rect.on('mouseover', function(d) { |
||||
tip.show(d) |
||||
}) |
||||
``` |
||||
|
||||
#### Explicit targets |
||||
Sometimes you need to manually specify a target to act on. For instance, maybe |
||||
you want the tooltip to appear over a different element than the one that triggered |
||||
a `mouseover` event. You can specify an explicit target by passing an `SVGElement` |
||||
as the last argument. |
||||
|
||||
``` javascript |
||||
tip.show(data, target) |
||||
``` |
||||
|
||||
|
||||
### tip.hide |
||||
Hide a tooltip |
||||
|
||||
``` javascript |
||||
rect.on('mouseout', tip.hide) |
||||
``` |
||||
|
||||
``` javascript |
||||
rect.on('mouseout', function(d) { |
||||
tip.hide(d) |
||||
}) |
||||
``` |
@ -0,0 +1,72 @@ |
||||
[API Documentation](index.md) ➤ Styling and modifying tooltips |
||||
|
||||
# Styling and modifying tooltips |
||||
Tooltips make no assumption about how they will be styled. Any style is left up |
||||
to the user. |
||||
|
||||
### tip.style |
||||
A proxy to d3's [selection.style](https://github.com/mbostock/d3/wiki/Selections#wiki-style). |
||||
|
||||
### tip.attr |
||||
A proxy to d3's [selection.attr](https://github.com/mbostock/d3/wiki/Selections#wiki-attr). |
||||
|
||||
### Example Styles |
||||
``` css |
||||
.d3-tip { |
||||
line-height: 1; |
||||
font-weight: bold; |
||||
padding: 12px; |
||||
background: rgba(0, 0, 0, 0.8); |
||||
color: #fff; |
||||
border-radius: 2px; |
||||
} |
||||
|
||||
/* Creates a small triangle extender for the tooltip */ |
||||
.d3-tip:after { |
||||
box-sizing: border-box; |
||||
display: inline; |
||||
font-size: 10px; |
||||
width: 100%; |
||||
line-height: 1; |
||||
color: rgba(0, 0, 0, 0.8); |
||||
position: absolute; |
||||
} |
||||
|
||||
/* Nrthward tooltips */ |
||||
.d3-tip.n:after { |
||||
content: "\25BC"; |
||||
margin: -1px 0 0 0; |
||||
top: 100%; |
||||
left: 0; |
||||
text-align: center; |
||||
} |
||||
|
||||
/* Eastward tooltips */ |
||||
.d3-tip.e:after { |
||||
content: "\25C0"; |
||||
margin: -4px 0 0 0; |
||||
top: 50%; |
||||
left: -8px; |
||||
} |
||||
|
||||
/* Southward tooltips */ |
||||
.d3-tip.s:after { |
||||
content: "\25B2"; |
||||
margin: 0 0 1px 0; |
||||
top: -8px; |
||||
left: 0; |
||||
text-align: center; |
||||
} |
||||
|
||||
/* Westward tooltips */ |
||||
.d3-tip.w:after { |
||||
content: "\25B6"; |
||||
margin: -4px 0 0 -1px; |
||||
top: 50%; |
||||
left: 100%; |
||||
} |
||||
``` |
||||
|
||||
See these stylings in action in either |
||||
[a live example](http://bl.ocks.org/deanmalmgren/6638585) or the |
||||
[examples directory](../examples/arrow-styles.html). |
@ -0,0 +1,10 @@ |
||||
[API Documentation](index.md) ➤ Updating tooltip content |
||||
|
||||
# Updating tooltip content |
||||
|
||||
### tip.html([content]) |
||||
Set or get a tip's HTML content. |
||||
|
||||
``` javascript |
||||
var tip = d3.tip().html(function(d) { return "<span>" + d + "</span>" }) |
||||
``` |
@ -0,0 +1,150 @@ |
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<title>d3.tip.js - Tooltips for D3</title> |
||||
<meta charset="utf-8" /> |
||||
<title>Example styles</title> |
||||
<script type="text/javascript" src="../bower_components/d3/d3.js"></script> |
||||
<script type="text/javascript" src="../index.js"></script> |
||||
<style type="text/css"> |
||||
body { |
||||
padding: 40px; |
||||
font-family: "Helvetica Neue", Helvetica, sans-serif; |
||||
font-size: 12px; |
||||
width: 600px; |
||||
} |
||||
|
||||
svg.n, svg.s { |
||||
margin-left: 200px; |
||||
margin-right: 200px; |
||||
} |
||||
svg.e { |
||||
margin-left: 200px; |
||||
} |
||||
|
||||
.d3-tip { |
||||
line-height: 1; |
||||
font-weight: bold; |
||||
padding: 12px; |
||||
background: rgba(0, 0, 0, 0.8); |
||||
color: #fff; |
||||
border-radius: 2px; |
||||
} |
||||
|
||||
/* Creates a small triangle extender for the tooltip */ |
||||
.d3-tip:after { |
||||
box-sizing: border-box; |
||||
display: inline; |
||||
font-size: 10px; |
||||
width: 100%; |
||||
line-height: 1; |
||||
color: rgba(0, 0, 0, 0.8); |
||||
position: absolute; |
||||
} |
||||
|
||||
/* Nrthward tooltips */ |
||||
.d3-tip.n:after { |
||||
content: "\25BC"; |
||||
margin: -1px 0 0 0; |
||||
top: 100%; |
||||
left: 0; |
||||
text-align: center; |
||||
} |
||||
|
||||
/* Eastward tooltips */ |
||||
.d3-tip.e:after { |
||||
content: "\25C0"; |
||||
margin: -4px 0 0 0; |
||||
top: 50%; |
||||
left: -8px; |
||||
} |
||||
|
||||
/* Southward tooltips */ |
||||
.d3-tip.s:after { |
||||
content: "\25B2"; |
||||
margin: 0 0 1px 0; |
||||
top: -8px; |
||||
left: 0; |
||||
text-align: center; |
||||
} |
||||
|
||||
/* Westward tooltips */ |
||||
.d3-tip.w:after { |
||||
content: "\25B6"; |
||||
margin: -4px 0 0 -1px; |
||||
top: 50%; |
||||
left: 100%; |
||||
} |
||||
|
||||
circle { |
||||
fill: #ccc; |
||||
fill-opacity: 0.6; |
||||
stroke: #bbb; |
||||
stroke-width: 1px; |
||||
} |
||||
|
||||
circle:hover { |
||||
fill: #bbb; |
||||
stroke: #999; |
||||
} |
||||
|
||||
text { |
||||
text-anchor: middle; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
<script type="text/javascript"> |
||||
var data = [], |
||||
random = d3.random.normal(5), |
||||
random2 = d3.random.irwinHall(1) |
||||
for(var i = 0; i < 25; i++) data.push(random(i)) |
||||
|
||||
var w = 200, |
||||
h = 200, |
||||
b = 20, |
||||
r = 10, |
||||
x = d3.scale.linear().domain([0, data.length - 1]).range([r, w - r]), |
||||
y = d3.scale.linear().domain([0, d3.max(data)]).range([h, 0]) |
||||
|
||||
var directions = ['n', 'w', 'e', 's']; |
||||
directions.forEach(function (direction) { |
||||
var tip = d3.tip() |
||||
.attr('class', 'd3-tip') |
||||
.html(function(d) { return d.toFixed(2) }) |
||||
.direction(direction) |
||||
.offset(function () { |
||||
if(direction=='n') { return [-10,0] } |
||||
else if(direction=='s') { return [10,0] } |
||||
else if(direction=='e') { return [0,10] } |
||||
else if(direction=='w') { return [0,-10] } |
||||
}) |
||||
|
||||
var vis = d3.select(document.body) |
||||
.append('svg') |
||||
.attr('class', direction) |
||||
.attr('width', w) |
||||
.attr('height', h) |
||||
.append('g') |
||||
.attr('transform', 'translate('+b+','+b+')') |
||||
.call(tip) |
||||
|
||||
vis.append('text') |
||||
.attr('class', 'direction') |
||||
.attr('x', w/2) |
||||
.attr('y', -b) |
||||
.attr('dy', '1em') |
||||
.text('direction: ' + direction) |
||||
|
||||
vis.selectAll('circle') |
||||
.data(data) |
||||
.enter().append('circle') |
||||
.attr('r', function(d, i) { return random2(i) * 10 }) |
||||
.attr('cx', function(d, i) { return x(i) }) |
||||
.attr('cy', y) |
||||
.on('mouseover', tip.show) |
||||
.on('mouseout', tip.hide) |
||||
}) |
||||
</script> |
||||
</body> |
||||
</html> |
@ -0,0 +1,130 @@ |
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<title>d3.tip.js - Tooltips for D3</title> |
||||
<meta charset="utf-8" /> |
||||
<title>Bar Chart</title> |
||||
<script type="text/javascript" src="../bower_components/d3/d3.js"></script> |
||||
<script type="text/javascript" src="../index.js"></script> |
||||
<script type="text/javascript"> |
||||
data = [{"total":225,"days":[12,51,60,26,38,31,7]},{"total":279,"days":[42,33,34,72,61,12,25]},{"total":212,"days":[12,59,24,70,36,5,6]},{"total":335,"days":[17,43,38,58,67,72,40]},{"total":329,"days":[40,53,62,48,38,36,52]},{"total":234,"days":[15,25,41,66,35,37,15]},{"total":175,"days":[2,40,23,40,23,34,13]},{"total":308,"days":[20,22,63,55,51,66,31]},{"total":401,"days":[20,64,42,62,88,79,46]},{"total":214,"days":[24,27,25,48,38,28,24]},{"total":332,"days":[26,43,20,109,74,29,31]},{"total":333,"days":[65,66,62,60,14,43,23]},{"total":437,"days":[33,74,82,70,85,64,29]},{"total":687,"days":[29,82,87,167,156,126,40]},{"total":243,"days":[11,52,44,50,46,30,10]},{"total":360,"days":[16,41,86,62,83,60,12]},{"total":349,"days":[22,55,48,36,88,57,43]},{"total":368,"days":[29,100,68,54,55,46,16]},{"total":377,"days":[3,71,66,57,93,82,5]},{"total":265,"days":[12,61,61,19,44,46,22]},{"total":396,"days":[20,58,70,52,84,93,19]},{"total":467,"days":[25,47,128,93,70,35,69]},{"total":524,"days":[55,79,94,95,122,70,9]},{"total":535,"days":[21,96,95,115,78,89,41]},{"total":333,"days":[20,50,49,52,58,51,53]},{"total":258,"days":[7,23,50,59,46,50,23]},{"total":242,"days":[12,4,54,53,46,33,40]},{"total":335,"days":[1,34,40,75,97,51,37]},{"total":325,"days":[32,57,65,46,60,58,7]},{"total":224,"days":[23,42,43,28,31,27,30]},{"total":317,"days":[20,46,43,46,83,36,43]},{"total":119,"days":[1,10,9,45,30,17,7]},{"total":368,"days":[13,74,77,85,72,40,7]},{"total":271,"days":[10,50,46,61,68,31,5]},{"total":290,"days":[26,48,39,37,68,43,29]},{"total":393,"days":[27,50,133,47,73,37,26]},{"total":316,"days":[2,63,66,47,63,33,42]},{"total":146,"days":[0,32,38,23,45,7,1]},{"total":255,"days":[23,34,72,46,48,24,8]},{"total":196,"days":[9,32,82,18,16,29,10]},{"total":410,"days":[41,52,67,42,49,103,56]},{"total":280,"days":[13,35,40,60,68,53,11]},{"total":432,"days":[45,65,59,55,71,68,69]},{"total":371,"days":[19,104,95,51,66,20,16]},{"total":285,"days":[2,38,50,72,74,47,2]},{"total":350,"days":[47,16,96,93,32,52,14]},{"total":234,"days":[34,68,66,32,5,10,19]},{"total":279,"days":[27,43,64,48,60,25,12]},{"total":391,"days":[40,54,59,68,80,51,39]},{"total":168,"days":[0,44,42,36,30,16,0]},{"total":0,"days":[0,0,0,0,0,0,0]},{"total":14,"days":[6,0,0,0,0,2,6]},{"total":0,"days":[0,0,0,0,0,0,0]}] |
||||
</script> |
||||
<style type="text/css"> |
||||
body { |
||||
padding: 40px; |
||||
font-family: "Helvetica Neue", Helvetica, sans-serif; |
||||
font-size: 12px; |
||||
height: 1000px; |
||||
} |
||||
|
||||
.d3-tip { |
||||
line-height: 1; |
||||
font-weight: bold; |
||||
padding: 12px; |
||||
background: rgba(0, 0, 0, 0.8); |
||||
color: #fff; |
||||
border-radius: 2px; |
||||
} |
||||
|
||||
.d3-tip:after { |
||||
box-sizing: border-box; |
||||
display: inline; |
||||
font-size: 10px; |
||||
width: 100%; |
||||
line-height: 1; |
||||
color: rgba(0, 0, 0, 0.8); |
||||
content: "\25BC"; |
||||
position: absolute; |
||||
text-align: center; |
||||
} |
||||
|
||||
.d3-tip.n:after { |
||||
margin: -1px 0 0 0; |
||||
top: 100%; |
||||
left: 0; |
||||
} |
||||
|
||||
.d3-tip span { |
||||
color: #ff00c7; |
||||
} |
||||
|
||||
.domain { |
||||
display: none; |
||||
} |
||||
|
||||
.axis line { |
||||
stroke-width: 1px; |
||||
stroke: #eee; |
||||
shape-rendering: crispedges; |
||||
} |
||||
|
||||
.axis text { |
||||
fill: #888; |
||||
} |
||||
|
||||
rect { |
||||
fill: #339cff; |
||||
fill-opacity: 0.7; |
||||
} |
||||
|
||||
rect:hover { |
||||
fill-opacity: 1; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
<div id="graph"> |
||||
|
||||
</div> |
||||
<script type="text/javascript"> |
||||
var tip = d3.tip() |
||||
.attr('class', 'd3-tip') |
||||
.html(function(d) { return '<span>' + d.total + '</span>' + ' entries' }) |
||||
.offset([-12, 0]) |
||||
|
||||
var w = 800, |
||||
h = 300, |
||||
padt = 20, padr = 20, padb = 60, padl = 30, |
||||
x = d3.scale.ordinal().rangeRoundBands([0, w - padl - padr], 0.1), |
||||
y = d3.scale.linear().range([h, 0]), |
||||
yAxis = d3.svg.axis().scale(y).orient('left').tickSize(-w + padl + padr), |
||||
xAxis = d3.svg.axis().scale(x).orient('bottom') |
||||
|
||||
vis = d3.select('#graph') |
||||
.append('svg') |
||||
.attr('width', w) |
||||
.attr('height', h + padt + padb) |
||||
.append('g') |
||||
.attr('transform', 'translate(' + padl + ',' + padt + ')') |
||||
|
||||
var max = d3.max(data, function(d) { return d.total }) |
||||
x.domain(d3.range(data.length)) |
||||
y.domain([0, max]) |
||||
|
||||
vis.call(tip) |
||||
vis.append("g") |
||||
.attr("class", "y axis") |
||||
.call(yAxis) |
||||
|
||||
vis.append("g") |
||||
.attr("class", "x axis") |
||||
.attr('transform', 'translate(0,' + h + ')') |
||||
.call(xAxis) |
||||
.selectAll('.x.axis g') |
||||
.style('display', function (d, i) { return i % 3 != 0 ? 'none' : 'block' }) |
||||
|
||||
var bars = vis.selectAll('g.bar') |
||||
.data(data) |
||||
.enter().append('g') |
||||
.attr('class', 'bar') |
||||
.attr('transform', function (d, i) { return "translate(" + x(i) + ", 0)" }) |
||||
|
||||
bars.append('rect') |
||||
.attr('width', function() { return x.rangeBand() }) |
||||
.attr('height', function(d) { return h - y(d.total) }) |
||||
.attr('y', function(d) { return y(d.total) }) |
||||
.on('mouseover', tip.show) |
||||
.on('mouseout', tip.hide) |
||||
</script> |
||||
</body> |
||||
</html> |
@ -0,0 +1,135 @@ |
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<title>d3.tip.js - Tooltips for D3</title> |
||||
<meta charset="utf-8" /> |
||||
<title>Bar Chart</title> |
||||
<script type="text/javascript" src="../bower_components/d3/d3.js"></script> |
||||
<script type="text/javascript" src="../index.js"></script> |
||||
<script type="text/javascript"> |
||||
data = [{"total":225,"days":[12,51,60,26,38,31,7]},{"total":279,"days":[42,33,34,72,61,12,25]},{"total":212,"days":[12,59,24,70,36,5,6]},{"total":335,"days":[17,43,38,58,67,72,40]},{"total":329,"days":[40,53,62,48,38,36,52]},{"total":234,"days":[15,25,41,66,35,37,15]},{"total":175,"days":[2,40,23,40,23,34,13]},{"total":308,"days":[20,22,63,55,51,66,31]},{"total":401,"days":[20,64,42,62,88,79,46]},{"total":214,"days":[24,27,25,48,38,28,24]},{"total":332,"days":[26,43,20,109,74,29,31]},{"total":333,"days":[65,66,62,60,14,43,23]},{"total":437,"days":[33,74,82,70,85,64,29]},{"total":687,"days":[29,82,87,167,156,126,40]},{"total":243,"days":[11,52,44,50,46,30,10]},{"total":360,"days":[16,41,86,62,83,60,12]},{"total":349,"days":[22,55,48,36,88,57,43]},{"total":368,"days":[29,100,68,54,55,46,16]},{"total":377,"days":[3,71,66,57,93,82,5]},{"total":265,"days":[12,61,61,19,44,46,22]},{"total":396,"days":[20,58,70,52,84,93,19]},{"total":467,"days":[25,47,128,93,70,35,69]},{"total":524,"days":[55,79,94,95,122,70,9]},{"total":535,"days":[21,96,95,115,78,89,41]},{"total":333,"days":[20,50,49,52,58,51,53]},{"total":258,"days":[7,23,50,59,46,50,23]},{"total":242,"days":[12,4,54,53,46,33,40]},{"total":335,"days":[1,34,40,75,97,51,37]},{"total":325,"days":[32,57,65,46,60,58,7]},{"total":224,"days":[23,42,43,28,31,27,30]},{"total":317,"days":[20,46,43,46,83,36,43]},{"total":119,"days":[1,10,9,45,30,17,7]},{"total":368,"days":[13,74,77,85,72,40,7]},{"total":271,"days":[10,50,46,61,68,31,5]},{"total":290,"days":[26,48,39,37,68,43,29]},{"total":393,"days":[27,50,133,47,73,37,26]},{"total":316,"days":[2,63,66,47,63,33,42]},{"total":146,"days":[0,32,38,23,45,7,1]},{"total":255,"days":[23,34,72,46,48,24,8]},{"total":196,"days":[9,32,82,18,16,29,10]},{"total":410,"days":[41,52,67,42,49,103,56]},{"total":280,"days":[13,35,40,60,68,53,11]},{"total":432,"days":[45,65,59,55,71,68,69]},{"total":371,"days":[19,104,95,51,66,20,16]},{"total":285,"days":[2,38,50,72,74,47,2]},{"total":350,"days":[47,16,96,93,32,52,14]},{"total":234,"days":[34,68,66,32,5,10,19]},{"total":279,"days":[27,43,64,48,60,25,12]},{"total":391,"days":[40,54,59,68,80,51,39]},{"total":168,"days":[0,44,42,36,30,16,0]},{"total":0,"days":[0,0,0,0,0,0,0]},{"total":14,"days":[6,0,0,0,0,2,6]},{"total":0,"days":[0,0,0,0,0,0,0]}] |
||||
</script> |
||||
<style type="text/css"> |
||||
body { |
||||
padding: 40px; |
||||
font-family: "Helvetica Neue", Helvetica, sans-serif; |
||||
font-size: 12px; |
||||
height: 1000px; |
||||
} |
||||
|
||||
.d3-tip { |
||||
line-height: 1; |
||||
font-weight: bold; |
||||
padding: 12px; |
||||
background: rgba(0, 0, 0, 0.8); |
||||
color: #fff; |
||||
border-radius: 2px; |
||||
} |
||||
|
||||
.d3-tip:after { |
||||
box-sizing: border-box; |
||||
display: inline; |
||||
font-size: 10px; |
||||
width: 100%; |
||||
line-height: 1; |
||||
color: rgba(0, 0, 0, 0.8); |
||||
content: "\25BC"; |
||||
position: absolute; |
||||
text-align: center; |
||||
} |
||||
|
||||
.d3-tip.n:after { |
||||
margin: -1px 0 0 0; |
||||
top: 100%; |
||||
left: 0; |
||||
} |
||||
|
||||
.d3-tip span { |
||||
color: #ff00c7; |
||||
} |
||||
|
||||
.domain { |
||||
display: none; |
||||
} |
||||
|
||||
.axis line { |
||||
stroke-width: 1px; |
||||
stroke: #eee; |
||||
shape-rendering: crispedges; |
||||
} |
||||
|
||||
.axis text { |
||||
fill: #888; |
||||
} |
||||
|
||||
rect { |
||||
fill: #339cff; |
||||
fill-opacity: 0.7; |
||||
} |
||||
|
||||
rect:hover { |
||||
fill-opacity: 1; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
<div id="graph"> |
||||
|
||||
</div> |
||||
<script type="text/javascript"> |
||||
var tip = d3.tip() |
||||
.attr({'class': 'd3-tip', title: 'Some tooltip'}) |
||||
.style({border: '1px solid #fff', 'box-shadow': '1px 1px 4px rgba(0,0,0,0.5)', 'border-radius': 'none'}) |
||||
.html(function(d) { return '<span>' + d.total + '</span>' + ' entries' }) |
||||
.offset([-12, 0]) |
||||
|
||||
console.log(tip.attr('class')) |
||||
var w = 800, |
||||
h = 300, |
||||
padt = 20, padr = 20, padb = 60, padl = 30, |
||||
x = d3.scale.ordinal().rangeRoundBands([0, w - padl - padr], 0.1), |
||||
y = d3.scale.linear().range([h, 0]), |
||||
yAxis = d3.svg.axis().scale(y).orient('left').tickSize(-w + padl + padr), |
||||
xAxis = d3.svg.axis().scale(x).orient('bottom') |
||||
|
||||
vis = d3.select('#graph') |
||||
.append('svg') |
||||
.attr('width', w) |
||||
.attr('height', h + padt + padb) |
||||
.append('g') |
||||
.attr('transform', 'translate(' + padl + ',' + padt + ')') |
||||
|
||||
var max = d3.max(data, function(d) { return d.total }) |
||||
x.domain(d3.range(data.length)) |
||||
y.domain([0, max]) |
||||
|
||||
vis.call(tip) |
||||
vis.append("g") |
||||
.attr("class", "y axis") |
||||
.call(yAxis) |
||||
|
||||
vis.append("g") |
||||
.attr("class", "x axis") |
||||
.attr('transform', 'translate(0,' + h + ')') |
||||
.call(xAxis) |
||||
.selectAll('.x.axis g') |
||||
.style('display', function (d, i) { return i % 3 != 0 ? 'none' : 'block' }) |
||||
|
||||
var bars = vis.selectAll('g.bar') |
||||
.data(data) |
||||
.enter().append('g') |
||||
.attr('class', 'bar') |
||||
.attr('transform', function (d, i) { return "translate(" + x(i) + ", 0)" }) |
||||
|
||||
bars.append('rect') |
||||
.attr('width', function() { return x.rangeBand() }) |
||||
.attr('height', function(d) { return h - y(d.total) }) |
||||
.attr('y', function(d) { return y(d.total) }) |
||||
.on('mouseover', function(d) { |
||||
tip.show(d) |
||||
console.log(tip.style('box-shadow')) |
||||
}) |
||||
.on('mouseout', tip.hide) |
||||
</script> |
||||
</body> |
||||
</html> |
@ -0,0 +1,119 @@ |
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<title>d3.tip.js - Tooltips for D3</title> |
||||
<meta charset="utf-8" /> |
||||
<title>Circles</title> |
||||
<script type="text/javascript" src="../bower_components/d3/d3.js"></script> |
||||
<script type="text/javascript" src="../index.js"></script> |
||||
<style type="text/css"> |
||||
body { |
||||
padding: 40px; |
||||
font-family: "Helvetica Neue", Helvetica, sans-serif; |
||||
font-size: 12px; |
||||
} |
||||
|
||||
.d3-tip { |
||||
line-height: 1; |
||||
font-weight: bold; |
||||
padding: 12px; |
||||
background: rgba(0, 0, 0, 0.8); |
||||
color: #fff; |
||||
border-radius: 2px; |
||||
} |
||||
|
||||
.d3-tip text { |
||||
fill: #fff; |
||||
font-size: 12px; |
||||
stroke: none; |
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; |
||||
} |
||||
|
||||
circle { |
||||
fill: #ccc; |
||||
fill-opacity: 0.6; |
||||
stroke: #bbb; |
||||
stroke-width: 1px; |
||||
} |
||||
|
||||
circle:hover { |
||||
fill: #bbb; |
||||
stroke: #999; |
||||
} |
||||
|
||||
circle.clickable:hover { |
||||
cursor: pointer; |
||||
} |
||||
|
||||
.rule { |
||||
stroke-width: 1px; |
||||
stroke: #c00; |
||||
shape-rendering: crispedges; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
<script type="text/javascript"> |
||||
var data = [], |
||||
random = d3.random.normal(5), |
||||
random2 = d3.random.irwinHall(1) |
||||
for(var i = 0; i < 100; i++) data.push(random(i)) |
||||
|
||||
var tip = d3.tip() |
||||
.attr('class', 'd3-tip') |
||||
.html(function(d) { return d.toFixed(2) }) |
||||
.direction('nw') |
||||
.offset([0, 3]) |
||||
|
||||
var tip2 = d3.tip() |
||||
.attr('class', 'd3-tip') |
||||
.html(function(d) { return d.toFixed(2) }) |
||||
.direction('n') |
||||
.offset([-3, 0]) |
||||
|
||||
var w = 1000, |
||||
h = 500, |
||||
r = 10, |
||||
linex, liney, |
||||
x = d3.scale.linear().domain([0, data.length - 1]).range([r, w - r]), |
||||
y = d3.scale.linear().domain([0, d3.max(data)]).range([h, 0]) |
||||
|
||||
var vis = d3.select(document.body) |
||||
.append('svg') |
||||
.attr('width', w) |
||||
.attr('height', h) |
||||
.append('g') |
||||
.attr('transform', 'translate(20, 20)') |
||||
.call(tip) |
||||
|
||||
vis.selectAll('circle') |
||||
.data(data) |
||||
.enter().append('circle') |
||||
.attr('r', function(d, i) { return random2(i) * 10 }) |
||||
.attr('cx', function(d, i) { return x(i) }) |
||||
.attr('cy', y) |
||||
.on('mouseover', tip.show) |
||||
.on('mouseout', tip.hide) |
||||
|
||||
var vis2 = d3.select(document.body) |
||||
.append('svg') |
||||
.attr('width', w) |
||||
.attr('height', h) |
||||
.append('g') |
||||
.attr('transform', 'translate(20, 20)') |
||||
.call(tip2) |
||||
|
||||
vis2.selectAll('circle') |
||||
.data(data) |
||||
.enter().append('circle') |
||||
.attr('class', 'clickable') |
||||
.attr('r', function(d, i) { return random2(i) * 10 }) |
||||
.attr('cx', function(d, i) { return x(i) }) |
||||
.attr('cy', y) |
||||
.on('click', function(d) { |
||||
tip2.hide(d).show(d) |
||||
}) |
||||
|
||||
</script> |
||||
</body> |
||||
</html> |
@ -0,0 +1,182 @@ |
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<title>d3.tip.js - Tooltips for D3</title> |
||||
<meta charset="utf-8" /> |
||||
<title>CSS Transitions</title> |
||||
<script type="text/javascript" src="../bower_components/d3/d3.js"></script> |
||||
<script type="text/javascript" src="../index.js"></script> |
||||
<script type="text/javascript"> |
||||
data = [{"total":225,"days":[12,51,60,26,38,31,7]},{"total":279,"days":[42,33,34,72,61,12,25]},{"total":212,"days":[12,59,24,70,36,5,6]},{"total":335,"days":[17,43,38,58,67,72,40]},{"total":329,"days":[40,53,62,48,38,36,52]},{"total":234,"days":[15,25,41,66,35,37,15]},{"total":175,"days":[2,40,23,40,23,34,13]},{"total":308,"days":[20,22,63,55,51,66,31]},{"total":401,"days":[20,64,42,62,88,79,46]},{"total":214,"days":[24,27,25,48,38,28,24]},{"total":332,"days":[26,43,20,109,74,29,31]},{"total":333,"days":[65,66,62,60,14,43,23]},{"total":437,"days":[33,74,82,70,85,64,29]},{"total":687,"days":[29,82,87,167,156,126,40]},{"total":243,"days":[11,52,44,50,46,30,10]},{"total":360,"days":[16,41,86,62,83,60,12]},{"total":349,"days":[22,55,48,36,88,57,43]},{"total":368,"days":[29,100,68,54,55,46,16]},{"total":377,"days":[3,71,66,57,93,82,5]},{"total":265,"days":[12,61,61,19,44,46,22]},{"total":396,"days":[20,58,70,52,84,93,19]},{"total":467,"days":[25,47,128,93,70,35,69]},{"total":524,"days":[55,79,94,95,122,70,9]},{"total":535,"days":[21,96,95,115,78,89,41]},{"total":333,"days":[20,50,49,52,58,51,53]},{"total":258,"days":[7,23,50,59,46,50,23]},{"total":242,"days":[12,4,54,53,46,33,40]},{"total":335,"days":[1,34,40,75,97,51,37]},{"total":325,"days":[32,57,65,46,60,58,7]},{"total":224,"days":[23,42,43,28,31,27,30]},{"total":317,"days":[20,46,43,46,83,36,43]},{"total":119,"days":[1,10,9,45,30,17,7]},{"total":368,"days":[13,74,77,85,72,40,7]},{"total":271,"days":[10,50,46,61,68,31,5]},{"total":290,"days":[26,48,39,37,68,43,29]},{"total":393,"days":[27,50,133,47,73,37,26]},{"total":316,"days":[2,63,66,47,63,33,42]},{"total":146,"days":[0,32,38,23,45,7,1]},{"total":255,"days":[23,34,72,46,48,24,8]},{"total":196,"days":[9,32,82,18,16,29,10]},{"total":410,"days":[41,52,67,42,49,103,56]},{"total":280,"days":[13,35,40,60,68,53,11]},{"total":432,"days":[45,65,59,55,71,68,69]},{"total":371,"days":[19,104,95,51,66,20,16]},{"total":285,"days":[2,38,50,72,74,47,2]},{"total":350,"days":[47,16,96,93,32,52,14]},{"total":234,"days":[34,68,66,32,5,10,19]},{"total":279,"days":[27,43,64,48,60,25,12]},{"total":391,"days":[40,54,59,68,80,51,39]},{"total":168,"days":[0,44,42,36,30,16,0]},{"total":0,"days":[0,0,0,0,0,0,0]},{"total":14,"days":[6,0,0,0,0,2,6]},{"total":0,"days":[0,0,0,0,0,0,0]}] |
||||
</script> |
||||
<style type="text/css"> |
||||
@-webkit-keyframes bounceIn { |
||||
0% { |
||||
opacity: 0; |
||||
-webkit-transform: scale(.3); |
||||
} |
||||
|
||||
50% { |
||||
opacity: 1; |
||||
-webkit-transform: scale(1.05); |
||||
} |
||||
|
||||
70% { |
||||
-webkit-transform: scale(.9); |
||||
} |
||||
|
||||
100% { |
||||
-webkit-transform: scale(1); |
||||
} |
||||
} |
||||
|
||||
@keyframes bounceIn { |
||||
0% { |
||||
opacity: 0; |
||||
transform: scale(.3); |
||||
} |
||||
|
||||
50% { |
||||
opacity: 1; |
||||
transform: scale(1.05); |
||||
} |
||||
|
||||
70% { |
||||
transform: scale(.9); |
||||
} |
||||
|
||||
100% { |
||||
transform: scale(1); |
||||
} |
||||
} |
||||
|
||||
body { |
||||
padding: 40px; |
||||
font-family: "Helvetica Neue", Helvetica, sans-serif; |
||||
font-size: 12px; |
||||
height: 1000px; |
||||
-webkit-backface-visibility: hidden; |
||||
} |
||||
|
||||
.d3-tip { |
||||
line-height: 1; |
||||
font-weight: bold; |
||||
padding: 12px; |
||||
background: rgba(0, 0, 0, 0.8); |
||||
color: #fff; |
||||
border-radius: 2px; |
||||
} |
||||
|
||||
.d3-tip.animate { |
||||
animation: bounceIn 0.2s ease-out; |
||||
-webkit-animation: bounceIn 0.2s ease-out; |
||||
} |
||||
|
||||
.d3-tip:after { |
||||
box-sizing: border-box; |
||||
display: inline; |
||||
font-size: 10px; |
||||
width: 100%; |
||||
line-height: 1; |
||||
color: rgba(0, 0, 0, 0.8); |
||||
content: "\25BC"; |
||||
position: absolute; |
||||
text-align: center; |
||||
} |
||||
|
||||
.d3-tip.n:after { |
||||
margin: -1px 0 0 0; |
||||
top: 100%; |
||||
left: 0; |
||||
} |
||||
|
||||
.d3-tip span { |
||||
color: #ff00c7; |
||||
} |
||||
|
||||
.domain { |
||||
display: none; |
||||
} |
||||
|
||||
.axis line { |
||||
stroke-width: 1px; |
||||
stroke: #eee; |
||||
shape-rendering: crispedges; |
||||
} |
||||
|
||||
.axis text { |
||||
fill: #888; |
||||
} |
||||
|
||||
rect { |
||||
fill: #339cff; |
||||
fill-opacity: 0.7; |
||||
} |
||||
|
||||
rect:hover { |
||||
fill-opacity: 1; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
<div id="graph"> |
||||
|
||||
</div> |
||||
<script type="text/javascript"> |
||||
var tip = d3.tip() |
||||
.attr('class', 'd3-tip') |
||||
.html(function(d) { return '<span>' + d.total + '</span>' + ' entries' }) |
||||
.offset([-12, 0]) |
||||
|
||||
var w = 800, |
||||
h = 300, |
||||
padt = 20, padr = 20, padb = 60, padl = 30, |
||||
x = d3.scale.ordinal().rangeRoundBands([0, w - padl - padr], 0.1), |
||||
y = d3.scale.linear().range([h, 0]), |
||||
yAxis = d3.svg.axis().scale(y).orient('left').tickSize(-w + padl + padr), |
||||
xAxis = d3.svg.axis().scale(x).orient('bottom') |
||||
|
||||
vis = d3.select('#graph') |
||||
.append('svg') |
||||
.attr('width', w) |
||||
.attr('height', h + padt + padb) |
||||
.append('g') |
||||
.attr('transform', 'translate(' + padl + ',' + padt + ')') |
||||
|
||||
var max = d3.max(data, function(d) { return d.total }) |
||||
x.domain(d3.range(data.length)) |
||||
y.domain([0, max]) |
||||
|
||||
vis.call(tip) |
||||
vis.append("g") |
||||
.attr("class", "y axis") |
||||
.call(yAxis) |
||||
|
||||
vis.append("g") |
||||
.attr("class", "x axis") |
||||
.attr('transform', 'translate(0,' + h + ')') |
||||
.call(xAxis) |
||||
.selectAll('.x.axis g') |
||||
.style('display', function (d, i) { return i % 3 != 0 ? 'none' : 'block' }) |
||||
|
||||
var bars = vis.selectAll('g.bar') |
||||
.data(data) |
||||
.enter().append('g') |
||||
.attr('class', 'bar') |
||||
.attr('transform', function (d, i) { return "translate(" + x(i) + ", 0)" }) |
||||
|
||||
bars.append('rect') |
||||
.attr('width', function() { return x.rangeBand() }) |
||||
.attr('height', function(d) { return h - y(d.total) }) |
||||
.attr('y', function(d) { return y(d.total) }) |
||||
.on('mouseover', function(d) { |
||||
tip.attr('class', 'd3-tip animate').show(d) |
||||
}) |
||||
.on('mouseout', function(d) { |
||||
tip.attr('class', 'd3-tip').show(d) |
||||
tip.hide() |
||||
}) |
||||
|
||||
</script> |
||||
</body> |
||||
</html> |
@ -0,0 +1,145 @@ |
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<title>d3.tip.js - Tooltips for D3</title> |
||||
<meta charset="utf-8" /> |
||||
<title>Explicit Target</title> |
||||
<script type="text/javascript" src="../bower_components/d3/d3.js"></script> |
||||
<script type="text/javascript" src="../index.js"></script> |
||||
<script type="text/javascript"> |
||||
data = [{"total":225,"days":[12,51,60,26,38,31,7]},{"total":279,"days":[42,33,34,72,61,12,25]},{"total":212,"days":[12,59,24,70,36,5,6]},{"total":335,"days":[17,43,38,58,67,72,40]},{"total":329,"days":[40,53,62,48,38,36,52]},{"total":234,"days":[15,25,41,66,35,37,15]},{"total":175,"days":[2,40,23,40,23,34,13]},{"total":308,"days":[20,22,63,55,51,66,31]},{"total":401,"days":[20,64,42,62,88,79,46]},{"total":214,"days":[24,27,25,48,38,28,24]},{"total":332,"days":[26,43,20,109,74,29,31]},{"total":333,"days":[65,66,62,60,14,43,23]},{"total":437,"days":[33,74,82,70,85,64,29]},{"total":687,"days":[29,82,87,167,156,126,40]},{"total":243,"days":[11,52,44,50,46,30,10]},{"total":360,"days":[16,41,86,62,83,60,12]},{"total":349,"days":[22,55,48,36,88,57,43]},{"total":368,"days":[29,100,68,54,55,46,16]},{"total":377,"days":[3,71,66,57,93,82,5]},{"total":265,"days":[12,61,61,19,44,46,22]},{"total":396,"days":[20,58,70,52,84,93,19]},{"total":467,"days":[25,47,128,93,70,35,69]},{"total":524,"days":[55,79,94,95,122,70,9]},{"total":535,"days":[21,96,95,115,78,89,41]},{"total":333,"days":[20,50,49,52,58,51,53]},{"total":258,"days":[7,23,50,59,46,50,23]},{"total":242,"days":[12,4,54,53,46,33,40]},{"total":335,"days":[1,34,40,75,97,51,37]},{"total":325,"days":[32,57,65,46,60,58,7]},{"total":224,"days":[23,42,43,28,31,27,30]},{"total":317,"days":[20,46,43,46,83,36,43]},{"total":119,"days":[1,10,9,45,30,17,7]},{"total":368,"days":[13,74,77,85,72,40,7]},{"total":271,"days":[10,50,46,61,68,31,5]},{"total":290,"days":[26,48,39,37,68,43,29]},{"total":393,"days":[27,50,133,47,73,37,26]},{"total":316,"days":[2,63,66,47,63,33,42]},{"total":146,"days":[0,32,38,23,45,7,1]},{"total":255,"days":[23,34,72,46,48,24,8]},{"total":196,"days":[9,32,82,18,16,29,10]},{"total":410,"days":[41,52,67,42,49,103,56]},{"total":280,"days":[13,35,40,60,68,53,11]},{"total":432,"days":[45,65,59,55,71,68,69]},{"total":371,"days":[19,104,95,51,66,20,16]},{"total":285,"days":[2,38,50,72,74,47,2]},{"total":350,"days":[47,16,96,93,32,52,14]},{"total":234,"days":[34,68,66,32,5,10,19]},{"total":279,"days":[27,43,64,48,60,25,12]},{"total":391,"days":[40,54,59,68,80,51,39]},{"total":168,"days":[0,44,42,36,30,16,0]},{"total":0,"days":[0,0,0,0,0,0,0]},{"total":14,"days":[6,0,0,0,0,2,6]},{"total":0,"days":[0,0,0,0,0,0,0]}] |
||||
</script> |
||||
<style type="text/css"> |
||||
body { |
||||
padding: 40px; |
||||
font-family: "Helvetica Neue", Helvetica, sans-serif; |
||||
font-size: 12px; |
||||
height: 1000px; |
||||
} |
||||
|
||||
.d3-tip { |
||||
line-height: 1; |
||||
font-weight: bold; |
||||
padding: 12px; |
||||
background: rgba(0, 0, 0, 0.8); |
||||
color: #fff; |
||||
border-radius: 2px; |
||||
} |
||||
|
||||
.d3-tip:after { |
||||
box-sizing: border-box; |
||||
display: inline; |
||||
font-size: 10px; |
||||
width: 100%; |
||||
line-height: 1; |
||||
color: rgba(0, 0, 0, 0.8); |
||||
content: "\25BC"; |
||||
position: absolute; |
||||
text-align: center; |
||||
} |
||||
|
||||
.d3-tip.n:after { |
||||
margin: -5px 0 0 0; |
||||
top: 100%; |
||||
left: 0; |
||||
} |
||||
|
||||
.d3-tip span { |
||||
color: #ff00c7; |
||||
} |
||||
|
||||
.domain { |
||||
display: none; |
||||
} |
||||
|
||||
.axis line { |
||||
stroke-width: 1px; |
||||
stroke: #eee; |
||||
shape-rendering: crispedges; |
||||
} |
||||
|
||||
.axis text { |
||||
fill: #888; |
||||
} |
||||
|
||||
rect { |
||||
fill: #339cff; |
||||
fill-opacity: 0.7; |
||||
} |
||||
|
||||
rect:hover { |
||||
fill-opacity: 1; |
||||
} |
||||
|
||||
.legend { |
||||
fill: none; |
||||
stroke: #ccc; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
<div id="graph"> |
||||
|
||||
</div> |
||||
<script type="text/javascript"> |
||||
var tip = d3.tip() |
||||
.attr('class', 'd3-tip') |
||||
.html(function(d) { return '<span>' + d.total + '</span>' + ' entries' }) |
||||
.offset([-12, 0]) |
||||
|
||||
var w = 800, |
||||
h = 300, |
||||
padt = 40, padr = 20, padb = 60, padl = 30, |
||||
x = d3.scale.ordinal().rangeRoundBands([0, w - padl - padr], 0.1), |
||||
y = d3.scale.linear().range([h, 0]), |
||||
yAxis = d3.svg.axis().scale(y).orient('left').tickSize(-w + padl + padr), |
||||
xAxis = d3.svg.axis().scale(x).orient('bottom') |
||||
|
||||
vis = d3.select('#graph') |
||||
.append('svg') |
||||
.attr('width', w) |
||||
.attr('height', h + padt + padb) |
||||
.append('g') |
||||
.attr('transform', 'translate(' + padl + ',' + padt + ')') |
||||
|
||||
var max = d3.max(data, function(d) { return d.total }) |
||||
x.domain(d3.range(data.length)) |
||||
y.domain([0, max]) |
||||
|
||||
vis.call(tip) |
||||
vis.append("g") |
||||
.attr("class", "y axis") |
||||
.call(yAxis) |
||||
|
||||
legend = vis.append('rect') |
||||
.attr('width', 50) |
||||
.attr('height', 25) |
||||
.attr('x', 0) |
||||
.attr('y', 0) |
||||
.attr('class', 'legend') |
||||
|
||||
vis.append("g") |
||||
.attr("class", "x axis") |
||||
.attr('transform', 'translate(0,' + h + ')') |
||||
.call(xAxis) |
||||
.selectAll('.x.axis g') |
||||
.style('display', function (d, i) { return i % 3 != 0 ? 'none' : 'block' }) |
||||
|
||||
var bars = vis.selectAll('g.bar') |
||||
.data(data) |
||||
.enter().append('g') |
||||
.attr('class', 'bar') |
||||
.attr('transform', function (d, i) { return "translate(" + x(i) + ", 0)" }) |
||||
|
||||
bars.append('rect') |
||||
.attr('width', function() { return x.rangeBand() }) |
||||
.attr('height', function(d) { return h - y(d.total) }) |
||||
.attr('y', function(d) { return y(d.total) }) |
||||
.on('mouseout', tip.hide) |
||||
.on('mouseover', function(d) { |
||||
tip.show(d, legend.node()) |
||||
}) |
||||
|
||||
</script> |
||||
</body> |
||||
</html> |
@ -0,0 +1,114 @@ |
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<title>d3.tip.js - Tooltips for D3</title> |
||||
<meta charset="utf-8" /> |
||||
<title>Bar Chart</title> |
||||
<script type="text/javascript" src="../bower_components/d3/d3.js"></script> |
||||
<script type="text/javascript" src="../index.js"></script> |
||||
<style type="text/css"> |
||||
body { |
||||
padding: 40px; |
||||
font-family: "Helvetica Neue", Helvetica, sans-serif; |
||||
font-size: 12px; |
||||
} |
||||
|
||||
.d3-tip { |
||||
line-height: 1; |
||||
font-weight: bold; |
||||
padding: 12px; |
||||
background: rgba(0, 0, 0, 0.8); |
||||
color: #fff; |
||||
border-radius: 2px; |
||||
} |
||||
|
||||
.d3-tip text { |
||||
fill: #fff; |
||||
font-size: 12px; |
||||
stroke: none; |
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; |
||||
} |
||||
|
||||
circle { |
||||
fill: #ccc; |
||||
fill-opacity: 0.6; |
||||
stroke: #bbb; |
||||
stroke-width: 1px; |
||||
} |
||||
|
||||
circle:hover { |
||||
fill: #bbb; |
||||
stroke: #999; |
||||
} |
||||
|
||||
circle.clickable:hover { |
||||
cursor: pointer; |
||||
} |
||||
|
||||
.rule { |
||||
stroke-width: 1px; |
||||
stroke: #c00; |
||||
shape-rendering: crispedges; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
<script type="text/javascript"> |
||||
var NODES = 5000 |
||||
var RUNS = 3 |
||||
|
||||
var data = [], |
||||
random = d3.random.normal(5), |
||||
random2 = d3.random.irwinHall(1) |
||||
for(var i = 0; i < NODES; i++) data.push(random(i)) |
||||
|
||||
var tip = d3.tip() |
||||
.attr('class', 'd3-tip') |
||||
.html(function(d) { return d.toFixed(2) }) |
||||
.direction('nw') |
||||
.offset([0, 3]) |
||||
|
||||
var w = 1000, |
||||
h = 500, |
||||
r = 10, |
||||
linex, liney, |
||||
x = d3.scale.linear().domain([0, data.length - 1]).range([r, w - r]), |
||||
y = d3.scale.linear().domain([0, d3.max(data)]).range([h, 0]) |
||||
|
||||
var vis = d3.select(document.body) |
||||
.append('svg') |
||||
.attr('width', w) |
||||
.attr('height', h) |
||||
.append('g') |
||||
.attr('transform', 'translate(20, 20)') |
||||
.call(tip) |
||||
|
||||
// Create some artificial nesting |
||||
gs = vis.append('g').append('g') |
||||
|
||||
circles = gs.selectAll('circle') |
||||
.data(data) |
||||
.enter().append('circle') |
||||
|
||||
circles.attr('r', function(d, i) { return random2(i) * 10 }) |
||||
.attr('cx', function(d, i) { return x(i) }) |
||||
.attr('cy', y) |
||||
.on('mouseover', tip.show) |
||||
.on('mouseout', tip.hide) |
||||
|
||||
var elements = circles[0], |
||||
length = elements.length |
||||
e = new MouseEvent('mouseover') |
||||
for(var i = 0; i <= RUNS; i++) { |
||||
var j = 0 |
||||
console.time(i) |
||||
for(j; j < length; j++) |
||||
elements[i].dispatchEvent(e) |
||||
console.timeEnd(i) |
||||
} |
||||
|
||||
|
||||
|
||||
</script> |
||||
</body> |
||||
</html> |
@ -0,0 +1,320 @@ |
||||
// d3.tip
|
||||
// Copyright (c) 2013 Justin Palmer
|
||||
// ES6 / D3 v4 Adaption Copyright (c) 2016 Constantin Gavrilete
|
||||
// Removal of ES6 for D3 v4 Adaption Copyright (c) 2016 David Gotz
|
||||
//
|
||||
// Tooltips for d3.js SVG visualizations
|
||||
|
||||
d3.functor = function functor(v) { |
||||
return typeof v === "function" ? v : function() { |
||||
return v; |
||||
}; |
||||
}; |
||||
|
||||
d3.tip = function() { |
||||
|
||||
var direction = d3_tip_direction, |
||||
offset = d3_tip_offset, |
||||
html = d3_tip_html, |
||||
node = initNode(), |
||||
svg = null, |
||||
point = null, |
||||
target = null |
||||
|
||||
function tip(vis) { |
||||
svg = getSVGNode(vis) |
||||
point = svg.createSVGPoint() |
||||
document.body.appendChild(node) |
||||
} |
||||
|
||||
// Public - show the tooltip on the screen
|
||||
//
|
||||
// Returns a tip
|
||||
tip.show = function() { |
||||
var args = Array.prototype.slice.call(arguments) |
||||
if(args[args.length - 1] instanceof SVGElement) target = args.pop() |
||||
|
||||
var content = html.apply(this, args), |
||||
poffset = offset.apply(this, args), |
||||
dir = direction.apply(this, args), |
||||
nodel = getNodeEl(), |
||||
i = directions.length, |
||||
coords, |
||||
scrollTop = document.documentElement.scrollTop || document.body.scrollTop, |
||||
scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft |
||||
|
||||
nodel.html(content) |
||||
.style('position', 'absolute') |
||||
.style('opacity', 1) |
||||
.style('pointer-events', 'all') |
||||
|
||||
while(i--) nodel.classed(directions[i], false) |
||||
coords = direction_callbacks[dir].apply(this) |
||||
nodel.classed(dir, true) |
||||
.style('top', (coords.top + poffset[0]) + scrollTop + 'px') |
||||
.style('left', (coords.left + poffset[1]) + scrollLeft + 'px') |
||||
|
||||
return tip |
||||
} |
||||
|
||||
// Public - hide the tooltip
|
||||
//
|
||||
// Returns a tip
|
||||
tip.hide = function() { |
||||
var nodel = getNodeEl() |
||||
nodel |
||||
.style('opacity', 0) |
||||
.style('pointer-events', 'none') |
||||
return tip |
||||
} |
||||
|
||||
// Public: Proxy attr calls to the d3 tip container. Sets or gets attribute value.
|
||||
//
|
||||
// n - name of the attribute
|
||||
// v - value of the attribute
|
||||
//
|
||||
// Returns tip or attribute value
|
||||
tip.attr = function(n, v) { |
||||
if (arguments.length < 2 && typeof n === 'string') { |
||||
return getNodeEl().attr(n) |
||||
} else { |
||||
var args = Array.prototype.slice.call(arguments) |
||||
d3.selection.prototype.attr.apply(getNodeEl(), args) |
||||
} |
||||
|
||||
return tip |
||||
} |
||||
|
||||
// Public: Proxy style calls to the d3 tip container. Sets or gets a style value.
|
||||
//
|
||||
// n - name of the property
|
||||
// v - value of the property
|
||||
//
|
||||
// Returns tip or style property value
|
||||
tip.style = function(n, v) { |
||||
// debugger;
|
||||
if (arguments.length < 2 && typeof n === 'string') { |
||||
return getNodeEl().style(n) |
||||
} else { |
||||
var args = Array.prototype.slice.call(arguments); |
||||
if (args.length === 1) { |
||||
var styles = args[0]; |
||||
Object.keys(styles).forEach(function(key) { |
||||
return d3.selection.prototype.style.apply(getNodeEl(), [key, styles[key]]); |
||||
}); |
||||
} |
||||
} |
||||
|
||||
return tip |
||||
} |
||||
|
||||
// Public: Set or get the direction of the tooltip
|
||||
//
|
||||
// v - One of n(north), s(south), e(east), or w(west), nw(northwest),
|
||||
// sw(southwest), ne(northeast) or se(southeast)
|
||||
//
|
||||
// Returns tip or direction
|
||||
tip.direction = function(v) { |
||||
if (!arguments.length) return direction |
||||
direction = v == null ? v : d3.functor(v) |
||||
|
||||
return tip |
||||
} |
||||
|
||||
// Public: Sets or gets the offset of the tip
|
||||
//
|
||||
// v - Array of [x, y] offset
|
||||
//
|
||||
// Returns offset or
|
||||
tip.offset = function(v) { |
||||
if (!arguments.length) return offset |
||||
offset = v == null ? v : d3.functor(v) |
||||
|
||||
return tip |
||||
} |
||||
|
||||
// Public: sets or gets the html value of the tooltip
|
||||
//
|
||||
// v - String value of the tip
|
||||
//
|
||||
// Returns html value or tip
|
||||
tip.html = function(v) { |
||||
if (!arguments.length) return html |
||||
html = v == null ? v : d3.functor(v) |
||||
|
||||
return tip |
||||
} |
||||
|
||||
// Public: destroys the tooltip and removes it from the DOM
|
||||
//
|
||||
// Returns a tip
|
||||
tip.destroy = function() { |
||||
if(node) { |
||||
getNodeEl().remove(); |
||||
node = null; |
||||
} |
||||
return tip; |
||||
} |
||||
|
||||
function d3_tip_direction() { return 'n' } |
||||
function d3_tip_offset() { return [0, 0] } |
||||
function d3_tip_html() { return ' ' } |
||||
|
||||
var direction_callbacks = { |
||||
n: direction_n, |
||||
s: direction_s, |
||||
e: direction_e, |
||||
w: direction_w, |
||||
nw: direction_nw, |
||||
ne: direction_ne, |
||||
sw: direction_sw, |
||||
se: direction_se |
||||
}; |
||||
|
||||
var directions = Object.keys(direction_callbacks); |
||||
|
||||
function direction_n() { |
||||
var bbox = getScreenBBox() |
||||
return { |
||||
top: bbox.n.y - node.offsetHeight, |
||||
left: bbox.n.x - node.offsetWidth / 2 |
||||
} |
||||
} |
||||
|
||||
function direction_s() { |
||||
var bbox = getScreenBBox() |
||||
return { |
||||
top: bbox.s.y, |
||||
left: bbox.s.x - node.offsetWidth / 2 |
||||
} |
||||
} |
||||
|
||||
function direction_e() { |
||||
var bbox = getScreenBBox() |
||||
return { |
||||
top: bbox.e.y - node.offsetHeight / 2, |
||||
left: bbox.e.x |
||||
} |
||||
} |
||||
|
||||
function direction_w() { |
||||
var bbox = getScreenBBox() |
||||
return { |
||||
top: bbox.w.y - node.offsetHeight / 2, |
||||
left: bbox.w.x - node.offsetWidth |
||||
} |
||||
} |
||||
|
||||
function direction_nw() { |
||||
var bbox = getScreenBBox() |
||||
return { |
||||
top: bbox.nw.y - node.offsetHeight, |
||||
left: bbox.nw.x - node.offsetWidth |
||||
} |
||||
} |
||||
|
||||
function direction_ne() { |
||||
var bbox = getScreenBBox() |
||||
return { |
||||
top: bbox.ne.y - node.offsetHeight, |
||||
left: bbox.ne.x |
||||
} |
||||
} |
||||
|
||||
function direction_sw() { |
||||
var bbox = getScreenBBox() |
||||
return { |
||||
top: bbox.sw.y, |
||||
left: bbox.sw.x - node.offsetWidth |
||||
} |
||||
} |
||||
|
||||
function direction_se() { |
||||
var bbox = getScreenBBox() |
||||
return { |
||||
top: bbox.se.y, |
||||
left: bbox.e.x |
||||
} |
||||
} |
||||
|
||||
function initNode() { |
||||
var node = d3.select(document.createElement('div')) |
||||
node |
||||
.style('position', 'absolute') |
||||
.style('top', 0) |
||||
.style('opacity', 0) |
||||
.style('pointer-events', 'none') |
||||
.style('box-sizing', 'border-box') |
||||
|
||||
return node.node() |
||||
} |
||||
|
||||
function getSVGNode(el) { |
||||
el = el.node() |
||||
if(el.tagName.toLowerCase() === 'svg') |
||||
return el |
||||
|
||||
return el.ownerSVGElement |
||||
} |
||||
|
||||
function getNodeEl() { |
||||
if(node === null) { |
||||
node = initNode(); |
||||
// re-add node to DOM
|
||||
document.body.appendChild(node); |
||||
}; |
||||
return d3.select(node); |
||||
} |
||||
|
||||
// Private - gets the screen coordinates of a shape
|
||||
//
|
||||
// Given a shape on the screen, will return an SVGPoint for the directions
|
||||
// n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest),
|
||||
// sw(southwest).
|
||||
//
|
||||
// +-+-+
|
||||
// | |
|
||||
// + +
|
||||
// | |
|
||||
// +-+-+
|
||||
//
|
||||
// Returns an Object {n, s, e, w, nw, sw, ne, se}
|
||||
function getScreenBBox() { |
||||
var targetel = target || d3.event.target; |
||||
|
||||
while ('undefined' === typeof targetel.getScreenCTM && 'undefined' === targetel.parentNode) { |
||||
targetel = targetel.parentNode; |
||||
} |
||||
|
||||
var bbox = {}, |
||||
matrix = targetel.getScreenCTM(), |
||||
tbbox = targetel.getBBox(), |
||||
width = tbbox.width, |
||||
height = tbbox.height, |
||||
x = tbbox.x, |
||||
y = tbbox.y |
||||
|
||||
point.x = x |
||||
point.y = y |
||||
bbox.nw = point.matrixTransform(matrix) |
||||
point.x += width |
||||
bbox.ne = point.matrixTransform(matrix) |
||||
point.y += height |
||||
bbox.se = point.matrixTransform(matrix) |
||||
point.x -= width |
||||
bbox.sw = point.matrixTransform(matrix) |
||||
point.y -= height / 2 |
||||
bbox.w = point.matrixTransform(matrix) |
||||
point.x += width |
||||
bbox.e = point.matrixTransform(matrix) |
||||
point.x -= width / 2 |
||||
point.y -= height / 2 |
||||
bbox.n = point.matrixTransform(matrix) |
||||
point.y += height |
||||
bbox.s = point.matrixTransform(matrix) |
||||
|
||||
return bbox |
||||
} |
||||
|
||||
return tip |
||||
}; |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,27 @@ |
||||
Copyright 2010-2017 Mike Bostock |
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, |
||||
are permitted provided that the following conditions are met: |
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this |
||||
list of conditions and the following disclaimer. |
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, |
||||
this list of conditions and the following disclaimer in the documentation |
||||
and/or other materials provided with the distribution. |
||||
|
||||
* Neither the name of the author nor the names of contributors may be used to |
||||
endorse or promote products derived from this software without specific prior |
||||
written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,57 @@ |
||||
# D3: Data-Driven Documents |
||||
|
||||
<a href="https://d3js.org"><img src="https://d3js.org/logo.svg" align="left" hspace="10" vspace="6"></a> |
||||
|
||||
**D3** (or **D3.js**) is a JavaScript library for visualizing data using web standards. D3 helps you bring data to life using SVG, Canvas and HTML. D3 combines powerful visualization and interaction techniques with a data-driven approach to DOM manipulation, giving you the full capabilities of modern browsers and the freedom to design the right visual interface for your data. |
||||
|
||||
## Resources |
||||
|
||||
* [API Reference](https://github.com/d3/d3/blob/master/API.md) |
||||
* [Release Notes](https://github.com/d3/d3/releases) |
||||
* [Gallery](https://github.com/d3/d3/wiki/Gallery) |
||||
* [Examples](https://bl.ocks.org/mbostock) |
||||
* [Wiki](https://github.com/d3/d3/wiki) |
||||
|
||||
## Installing |
||||
|
||||
If you use npm, `npm install d3`. Otherwise, download the [latest release](https://github.com/d3/d3/releases/latest). The released bundle supports anonymous AMD, CommonJS, and vanilla environments. You can load directly from [d3js.org](https://d3js.org), [CDNJS](https://cdnjs.com/libraries/d3), or [unpkg](https://unpkg.com/d3/). For example: |
||||
|
||||
```html |
||||
<script src="https://d3js.org/d3.v5.js"></script> |
||||
``` |
||||
|
||||
For the minified version: |
||||
|
||||
```html |
||||
<script src="https://d3js.org/d3.v5.min.js"></script> |
||||
``` |
||||
|
||||
You can also use the standalone D3 microlibraries. For example, [d3-selection](https://github.com/d3/d3-selection): |
||||
|
||||
```html |
||||
<script src="https://d3js.org/d3-selection.v1.js"></script> |
||||
``` |
||||
|
||||
D3 is written using [ES2015 modules](http://www.2ality.com/2014/09/es6-modules-final.html). Create a [custom bundle using Rollup](https://bl.ocks.org/mbostock/bb09af4c39c79cffcde4), Webpack, or your preferred bundler. To import D3 into an ES2015 application, either import specific symbols from specific D3 modules: |
||||
|
||||
```js |
||||
import {scaleLinear} from "d3-scale"; |
||||
``` |
||||
|
||||
Or import everything into a namespace (here, `d3`): |
||||
|
||||
```js |
||||
import * as d3 from "d3"; |
||||
``` |
||||
|
||||
In Node: |
||||
|
||||
```js |
||||
var d3 = require("d3"); |
||||
``` |
||||
|
||||
You can also require individual modules and combine them into a `d3` object using [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign): |
||||
|
||||
```js |
||||
var d3 = Object.assign({}, require("d3-format"), require("d3-geo"), require("d3-geo-projection")); |
||||
``` |
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue