From c4e6588c22ab42aaa2bbf48cf522374d92c3d32f Mon Sep 17 00:00:00 2001 From: Zalmoxisus Date: Wed, 19 Dec 2018 00:24:39 +0200 Subject: [PATCH] Merge d3tooltip from romseguy/d3tooltip --- packages/d3tooltip/.babelrc | 3 + packages/d3tooltip/.eslintignore | 4 + packages/d3tooltip/.eslintrc | 16 ++++ packages/d3tooltip/.npmignore | 5 ++ packages/d3tooltip/LICENSE.md | 21 +++++ packages/d3tooltip/README.md | 54 ++++++++++++ packages/d3tooltip/package.json | 49 +++++++++++ packages/d3tooltip/src/index.js | 84 +++++++++++++++++++ packages/d3tooltip/src/utils/functor.js | 5 ++ packages/d3tooltip/src/utils/index.js | 7 ++ packages/d3tooltip/src/utils/prependClass.js | 20 +++++ packages/d3tooltip/webpack.config.base.js | 16 ++++ .../d3tooltip/webpack.config.development.js | 14 ++++ .../d3tooltip/webpack.config.production.js | 20 +++++ 14 files changed, 318 insertions(+) create mode 100644 packages/d3tooltip/.babelrc create mode 100644 packages/d3tooltip/.eslintignore create mode 100644 packages/d3tooltip/.eslintrc create mode 100644 packages/d3tooltip/.npmignore create mode 100644 packages/d3tooltip/LICENSE.md create mode 100644 packages/d3tooltip/README.md create mode 100644 packages/d3tooltip/package.json create mode 100644 packages/d3tooltip/src/index.js create mode 100644 packages/d3tooltip/src/utils/functor.js create mode 100644 packages/d3tooltip/src/utils/index.js create mode 100644 packages/d3tooltip/src/utils/prependClass.js create mode 100644 packages/d3tooltip/webpack.config.base.js create mode 100644 packages/d3tooltip/webpack.config.development.js create mode 100644 packages/d3tooltip/webpack.config.production.js diff --git a/packages/d3tooltip/.babelrc b/packages/d3tooltip/.babelrc new file mode 100644 index 00000000..9d06ebbb --- /dev/null +++ b/packages/d3tooltip/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015-loose", "stage-0"] +} diff --git a/packages/d3tooltip/.eslintignore b/packages/d3tooltip/.eslintignore new file mode 100644 index 00000000..0d38857e --- /dev/null +++ b/packages/d3tooltip/.eslintignore @@ -0,0 +1,4 @@ +lib +**/node_modules +**/webpack.config.js +examples/**/server.js \ No newline at end of file diff --git a/packages/d3tooltip/.eslintrc b/packages/d3tooltip/.eslintrc new file mode 100644 index 00000000..8132e1fa --- /dev/null +++ b/packages/d3tooltip/.eslintrc @@ -0,0 +1,16 @@ +{ + "extends": "eslint-config-airbnb", + "env": { + "browser": true, + "mocha": true, + "node": true + }, + "rules": { + "react/jsx-uses-react": 2, + "react/jsx-uses-vars": 2, + "react/react-in-jsx-scope": 2 + }, + "plugins": [ + "react" + ] +} diff --git a/packages/d3tooltip/.npmignore b/packages/d3tooltip/.npmignore new file mode 100644 index 00000000..1f9f292d --- /dev/null +++ b/packages/d3tooltip/.npmignore @@ -0,0 +1,5 @@ +.DS_Store +*.log +test +examples +coverage diff --git a/packages/d3tooltip/LICENSE.md b/packages/d3tooltip/LICENSE.md new file mode 100644 index 00000000..ee3e925d --- /dev/null +++ b/packages/d3tooltip/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 romseguy + +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. diff --git a/packages/d3tooltip/README.md b/packages/d3tooltip/README.md new file mode 100644 index 00000000..491d16f9 --- /dev/null +++ b/packages/d3tooltip/README.md @@ -0,0 +1,54 @@ +d3tooltip +========================= + +This tooltip aims for a minimal yet highly configurable API. It has a long way to go, but the essentials are there. + +## Installation + +`npm install d3-state-visualizer` + +## Quick usage + +```javascript +import d3 from 'd3'; +import d3tooltip from 'd3tooltip'; + +const DOMNode = document.getElementById('chart'); +const root = d3.select(DOMNode); +const vis = root.append('svg'); + +let options = { + offset: {left: 30, top: 10} +}; + +vis.selectAll('circle').data(someData).enter() + .append('circle') + .attr('r', 10) + .call( + d3tooltip(d3, 'tooltipClassName', options) + .text((d, i) => toStringOrHtml(d)) + .attr({ 'class': 'anotherClassName' }) + .style({ 'min-width': '50px', 'border-radius: 5px' }) + ) + .on({ + mouseover(d, i) { + d3.select(this).style({ + fill: 'skyblue' + }); + }, + mouseout(d, i) { + d3.select(this).style({ + fill: 'black' + }); + } + }); +``` + +## API + +Option | Type | Default | Description +--------------------------|--------------|---------------------|-------------------------------------------------------------- +`root` | DOM.Element | `body` | The tooltip will be added as a child of that element. You can also use a D3 [selection](https://github.com/mbostock/d3/wiki/Selections#d3_select) +`left` | Number | `undefined` | Sets the tooltip `x` absolute position instead of the mouse `x` position, relative to the `root` element +`top` | Number | `undefined` | Sets the tooltip `y` absolute position instead of the mouse `y` position, relative to the `root` element +`offset` | Object | `{left: 0, top: 0}` | Sets the distance, starting from the cursor position, until the tooltip is rendered. **Warning**: only applicable if you don't provide a `left` or `top` option diff --git a/packages/d3tooltip/package.json b/packages/d3tooltip/package.json new file mode 100644 index 00000000..c1d4698a --- /dev/null +++ b/packages/d3tooltip/package.json @@ -0,0 +1,49 @@ +{ + "name": "d3tooltip", + "version": "1.2.2", + "description": "A highly configurable tooltip for d3", + "main": "lib/index.js", + "scripts": { + "clean": "rimraf lib dist", + "lint": "eslint src", + "build": "npm run build:lib && npm run build:umd && npm run build:umd:min", + "build:lib": "babel src --out-dir lib", + "build:umd": "webpack src/index.js dist/d3tooltip.js --config webpack.config.development.js", + "build:umd:min": "webpack src/index.js dist/d3tooltip.min.js --config webpack.config.production.js", + "version": "npm run build", + "postversion": "git push && git push --tags && npm run clean", + "prepublish": "npm run clean && npm run build" + }, + "repository": { + "type": "git", + "url": "https://github.com/romseguy/d3tooltip.git" + }, + "keywords": [ + "d3", + "tooltip" + ], + "author": "romseguy", + "license": "MIT", + "bugs": { + "url": "https://github.com/romseguy/d3tooltip/issues" + }, + "homepage": "https://github.com/romseguy/d3tooltip", + "devDependencies": { + "babel-cli": "^6.3.15", + "babel-core": "^6.1.20", + "babel-eslint": "^5.0.0-beta4", + "babel-loader": "^6.2.0", + "babel-preset-es2015-loose": "^6.1.3", + "babel-preset-react": "^6.3.13", + "babel-preset-stage-0": "^6.3.13", + "eslint": "^0.23", + "eslint-config-airbnb": "0.0.6", + "eslint-plugin-react": "^3.6.3", + "rimraf": "^2.3.4", + "webpack": "^1.9.6", + "webpack-dev-server": "^1.8.2" + }, + "dependencies": { + "ramda": "^0.17.1" + } +} diff --git a/packages/d3tooltip/src/index.js b/packages/d3tooltip/src/index.js new file mode 100644 index 00000000..75c42732 --- /dev/null +++ b/packages/d3tooltip/src/index.js @@ -0,0 +1,84 @@ +import { is } from 'ramda'; +import utils from './utils'; +const { prependClass, functor } = utils.default || utils; + +const defaultOptions = { + left: undefined, // mouseX + top: undefined, // mouseY + offset: {left: 0, top: 0}, + root: undefined +}; + +export default function tooltip(d3, className = 'tooltip', options = {}) { + const { + left, + top, + offset, + root + } = {...defaultOptions, ...options}; + + let attrs = {'class': className}; + let text = () => ''; + let styles = {}; + + let el; + const anchor = root || d3.select('body'); + const rootNode = anchor.node(); + + function tip(selection) { + selection.on({ + 'mouseover.tip': node => { + let [mouseX, mouseY] = d3.mouse(rootNode); + let [x, y] = [left || mouseX + offset.left, top || mouseY - offset.top]; + + anchor.selectAll(`div.${className}`).remove(); + + el = anchor.append('div') + .attr(prependClass(className)(attrs)) + .style({ + position: 'absolute', + 'z-index': 1001, + left: x + 'px', + top: y + 'px', + ...styles + }) + .html(() => text(node)); + }, + + 'mousemove.tip': node => { + let [mouseX, mouseY] = d3.mouse(rootNode); + let [x, y] = [left || mouseX + offset.left, top || mouseY - offset.top]; + + el + .style({ + left: x + 'px', + top: y + 'px' + }) + .html(() => text(node)); + }, + + 'mouseout.tip': () => el.remove() + }); + } + + tip.attr = function setAttr(d) { + if (is(Object, d)) { + attrs = {...attrs, ...d}; + } + return this; + }; + + tip.style = function setStyle(d) { + if (is(Object, d)) { + styles = {...styles, ...d}; + } + return this; + }; + + tip.text = function setText(d) { + text = functor(d); + return this; + }; + + return tip; +} diff --git a/packages/d3tooltip/src/utils/functor.js b/packages/d3tooltip/src/utils/functor.js new file mode 100644 index 00000000..007885d3 --- /dev/null +++ b/packages/d3tooltip/src/utils/functor.js @@ -0,0 +1,5 @@ +import { is } from 'ramda'; + +export default function functor(v) { + return is(Function, v) ? v : () => v; +} diff --git a/packages/d3tooltip/src/utils/index.js b/packages/d3tooltip/src/utils/index.js new file mode 100644 index 00000000..7893c5ca --- /dev/null +++ b/packages/d3tooltip/src/utils/index.js @@ -0,0 +1,7 @@ +import prependClass from './prependClass'; +import functor from './functor'; + +export default { + prependClass, + functor +}; diff --git a/packages/d3tooltip/src/utils/prependClass.js b/packages/d3tooltip/src/utils/prependClass.js new file mode 100644 index 00000000..2194f865 --- /dev/null +++ b/packages/d3tooltip/src/utils/prependClass.js @@ -0,0 +1,20 @@ +import { mapObjIndexed, join } from 'ramda'; +import functor from './functor'; + +export default function prependClass(className) { + return mapObjIndexed((value, key) => { + if (key === 'class') { + const fn = functor(value); + + return (d, i) => { + const classNames = fn(d, i); + if (classNames !== className) { + return join(' ', [className, classNames]); + } + return classNames; + }; + } + + return value; + }); +} diff --git a/packages/d3tooltip/webpack.config.base.js b/packages/d3tooltip/webpack.config.base.js new file mode 100644 index 00000000..9576681c --- /dev/null +++ b/packages/d3tooltip/webpack.config.base.js @@ -0,0 +1,16 @@ +'use strict'; + +module.exports = { + module: { + loaders: [ + { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ } + ] + }, + output: { + library: 'd3tooltip', + libraryTarget: 'umd' + }, + resolve: { + extensions: ['', '.js'] + } +}; diff --git a/packages/d3tooltip/webpack.config.development.js b/packages/d3tooltip/webpack.config.development.js new file mode 100644 index 00000000..e509d7cd --- /dev/null +++ b/packages/d3tooltip/webpack.config.development.js @@ -0,0 +1,14 @@ +'use strict'; + +var webpack = require('webpack'); +var baseConfig = require('./webpack.config.base'); + +var config = Object.create(baseConfig); +config.plugins = [ + new webpack.optimize.OccurenceOrderPlugin(), + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify('development') + }) +]; + +module.exports = config; diff --git a/packages/d3tooltip/webpack.config.production.js b/packages/d3tooltip/webpack.config.production.js new file mode 100644 index 00000000..f4589cc0 --- /dev/null +++ b/packages/d3tooltip/webpack.config.production.js @@ -0,0 +1,20 @@ +'use strict'; + +var webpack = require('webpack'); +var baseConfig = require('./webpack.config.base'); + +var config = Object.create(baseConfig); +config.plugins = [ + new webpack.optimize.OccurenceOrderPlugin(), + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify('production') + }), + new webpack.optimize.UglifyJsPlugin({ + compressor: { + screw_ie8: true, + warnings: false + } + }) +]; + +module.exports = config;