diff --git a/.travis.yml b/.travis.yml index 5dee622ad..c84eb4e2a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ sudo: false language: node_js node_js: - - '6' + - '8' script: - 'if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then grunt ci; else grunt ci-pull; fi' env: diff --git a/D3v4 Upgrade Notes.md b/D3v4 Upgrade Notes.md new file mode 100644 index 000000000..5f347a107 --- /dev/null +++ b/D3v4 Upgrade Notes.md @@ -0,0 +1,35 @@ +##Non working examples + +- http://localhost:8888/web/examples/filter-stacks.html + (fading is peculiar) +- http://localhost:8888/web/zoom/restrict-panning.html + Need to increase height of range chart - currently height of + brushable area is zero. New implementation needs it be more than zero. +- http://localhost:8888/web/ + Range brushing inconsistent with previous version + If the range chart is brushed first it works correctly + If the Focus chart is zoomed first, brushing range chart fails. + + +##Issues to be fixed + +- Peculiar fading in filter-stacks.html (Medium) + + +##Before release + +- All High priority issues +- Possibly Medium priority issues +- Prepare upgrade guide (Initial version ready) + + +### Next set of pull requests + +- Cleanup of zoom behavior. Testing of restrict panning etc. +- dc.event.trigger +- exit/enter/update sequence +- Additional test cases for dc.util.add and dc.util.subtract +- One for each new chart type - original PRs from community +- Consider removing transitions for zooming and brushing +- d3 stack to D3v4 +- Changing .tension call in lineChart diff --git a/Gruntfile.js b/Gruntfile.js index f6908373a..ae6056ddf 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -289,7 +289,7 @@ module.exports = function (grunt) { '<%= conf.pkg.name %>.js.map', '<%= conf.pkg.name %>.min.js', '<%= conf.pkg.name %>.min.js.map', - 'node_modules/d3/d3.js', + 'node_modules/d3/build/d3.js', 'node_modules/crossfilter2/crossfilter.js', 'node_modules/queue-async/build/queue.js', 'node_modules/grunt-saucelabs/examples/jasmine/lib/jasmine-jsreporter/jasmine-jsreporter.js', @@ -452,6 +452,7 @@ module.exports = function (grunt) { module.exports.jsFiles = [ 'src/banner.js', // NOTE: keep this first + 'src/d3v3-compat.js', 'src/core.js', 'src/errors.js', 'src/utils.js', diff --git a/docs/dc-v3-upgrade-guide.md b/docs/dc-v3-upgrade-guide.md new file mode 100644 index 000000000..121a5e36a --- /dev/null +++ b/docs/dc-v3-upgrade-guide.md @@ -0,0 +1,22 @@ +# dc v3 Upgrade Guide + +The dc has undergone significant internal changes while moving to v3. +Effort has been made to keep the API as close as possible. + +d3 team has released version 4 which is not backward compatible with +their version 3. dc relies very heavily on d3. It is quite likely that +your code uses bits of d3. + +Outline of the upgrade process: + +- First of all update all d3 functions calls in your code. Most of these + would start with d3. Check https://github.com/d3/d3/blob/master/CHANGES.md + for new function name corresponding to old functions. +- dc.lineChart .interpolate earlier took string parameter, these will get + replaced by specialized curve functions. For example 'step-before' + changes to `d3.curveStepBefore` and 'cardinal' to `d3.curveCardinal`. + See https://github.com/d3/d3/blob/master/CHANGES.md#shapes-d3-shape + for equivalent function calls. +- For dc.geoChoroplethChart earlier `d3.geoAlbersUsa()` was the default + for .projection. If you are plotting US states please call + `.projection(d3.geoAlbersUsa())` explicitly on your chart. diff --git a/jsdoc.conf.json b/jsdoc.conf.json index b5bbc1064..feb3debfa 100644 --- a/jsdoc.conf.json +++ b/jsdoc.conf.json @@ -12,7 +12,7 @@ "outputSourcePath": true, "systemName": "dc.js", "footer": "", - "copyright": "dc.js Copyright © 2012-2016 Copyright 2012-2016 Nick Zhu & the dc.js Developers", + "copyright": "dc.js Copyright © 2012-2018 Nick Zhu & the dc.js Developers", "navType": "vertical", "theme": "cosmo", "linenums": true, diff --git a/package-lock.json b/package-lock.json index 115407d24..2994dd1e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -106,7 +106,8 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true }, "ansi-styles": { "version": "2.2.1", @@ -139,12 +140,14 @@ "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true }, "are-we-there-yet": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "dev": true, "requires": { "delegates": "1.0.0", "readable-stream": "2.2.11" @@ -825,6 +828,7 @@ "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, + "optional": true, "requires": { "align-text": "0.1.4", "lazy-cache": "1.0.4" @@ -927,6 +931,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, + "optional": true, "requires": { "center-align": "0.1.3", "right-align": "0.1.3", @@ -936,7 +941,8 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true }, "coffee-script": { "version": "1.10.0", @@ -1074,7 +1080,6 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", - "dev": true, "requires": { "graceful-readlink": "1.0.1" } @@ -1166,7 +1171,8 @@ "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true }, "constants-browserify": { "version": "1.0.0", @@ -1195,7 +1201,8 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, "create-ecdh": { "version": "4.0.0", @@ -1306,9 +1313,259 @@ "dev": true }, "d3": { - "version": "3.5.17", - "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", - "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=" + "version": "4.13.0", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3/-/d3-4.13.0.tgz", + "integrity": "sha512-l8c4+0SldjVKLaE2WG++EQlqD7mh/dmQjvi2L2lKPadAVC+TbJC4ci7Uk9bRi+To0+ansgsS0iWfPjD7DBy+FQ==", + "requires": { + "d3-array": "1.2.1", + "d3-axis": "1.0.8", + "d3-brush": "1.0.4", + "d3-chord": "1.0.4", + "d3-collection": "1.0.4", + "d3-color": "1.0.3", + "d3-dispatch": "1.0.3", + "d3-drag": "1.2.1", + "d3-dsv": "1.0.8", + "d3-ease": "1.0.3", + "d3-force": "1.1.0", + "d3-format": "1.2.2", + "d3-geo": "1.9.1", + "d3-hierarchy": "1.1.5", + "d3-interpolate": "1.1.6", + "d3-path": "1.0.5", + "d3-polygon": "1.0.3", + "d3-quadtree": "1.0.3", + "d3-queue": "3.0.7", + "d3-random": "1.1.0", + "d3-request": "1.0.6", + "d3-scale": "1.0.7", + "d3-selection": "1.3.0", + "d3-shape": "1.2.0", + "d3-time": "1.0.8", + "d3-time-format": "2.1.1", + "d3-timer": "1.0.7", + "d3-transition": "1.1.1", + "d3-voronoi": "1.1.2", + "d3-zoom": "1.7.1" + } + }, + "d3-array": { + "version": "1.2.1", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-array/-/d3-array-1.2.1.tgz", + "integrity": "sha512-CyINJQ0SOUHojDdFDH4JEM0552vCR1utGyLHegJHyYH0JyCpSeTPxi4OBqHMA2jJZq4NH782LtaJWBImqI/HBw==" + }, + "d3-axis": { + "version": "1.0.8", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-axis/-/d3-axis-1.0.8.tgz", + "integrity": "sha1-MacFoLU15ldZ3hQXOjGTMTfxjvo=" + }, + "d3-brush": { + "version": "1.0.4", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-brush/-/d3-brush-1.0.4.tgz", + "integrity": "sha1-AMLyOAGfJPbAoZSibUGhUw/+e8Q=", + "requires": { + "d3-dispatch": "1.0.3", + "d3-drag": "1.2.1", + "d3-interpolate": "1.1.6", + "d3-selection": "1.3.0", + "d3-transition": "1.1.1" + } + }, + "d3-chord": { + "version": "1.0.4", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-chord/-/d3-chord-1.0.4.tgz", + "integrity": "sha1-fexPC6iG9xP+ERxF92NBT290yiw=", + "requires": { + "d3-array": "1.2.1", + "d3-path": "1.0.5" + } + }, + "d3-collection": { + "version": "1.0.4", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-collection/-/d3-collection-1.0.4.tgz", + "integrity": "sha1-NC39EoN8kJdPM/HMCnha6lcNzcI=" + }, + "d3-color": { + "version": "1.0.3", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-color/-/d3-color-1.0.3.tgz", + "integrity": "sha1-vHZD/KjlOoNH4vva/6I2eWtYUJs=" + }, + "d3-dispatch": { + "version": "1.0.3", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-dispatch/-/d3-dispatch-1.0.3.tgz", + "integrity": "sha1-RuFJHqqbWMNY/OW+TovtYm54cfg=" + }, + "d3-drag": { + "version": "1.2.1", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-drag/-/d3-drag-1.2.1.tgz", + "integrity": "sha512-Cg8/K2rTtzxzrb0fmnYOUeZHvwa4PHzwXOLZZPwtEs2SKLLKLXeYwZKBB+DlOxUvFmarOnmt//cU4+3US2lyyQ==", + "requires": { + "d3-dispatch": "1.0.3", + "d3-selection": "1.3.0" + } + }, + "d3-dsv": { + "version": "1.0.8", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-dsv/-/d3-dsv-1.0.8.tgz", + "integrity": "sha512-IVCJpQ+YGe3qu6odkPQI0KPqfxkhbP/oM1XhhE/DFiYmcXKfCRub4KXyiuehV1d4drjWVXHUWx4gHqhdZb6n/A==", + "requires": { + "commander": "2.8.1", + "iconv-lite": "0.4.18", + "rw": "1.3.3" + } + }, + "d3-ease": { + "version": "1.0.3", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-ease/-/d3-ease-1.0.3.tgz", + "integrity": "sha1-aL+8NJM4o4DETYrMT7wzBKotjA4=" + }, + "d3-force": { + "version": "1.1.0", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-force/-/d3-force-1.1.0.tgz", + "integrity": "sha512-2HVQz3/VCQs0QeRNZTYb7GxoUCeb6bOzMp/cGcLa87awY9ZsPvXOGeZm0iaGBjXic6I1ysKwMn+g+5jSAdzwcg==", + "requires": { + "d3-collection": "1.0.4", + "d3-dispatch": "1.0.3", + "d3-quadtree": "1.0.3", + "d3-timer": "1.0.7" + } + }, + "d3-format": { + "version": "1.2.2", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-format/-/d3-format-1.2.2.tgz", + "integrity": "sha512-zH9CfF/3C8zUI47nsiKfD0+AGDEuM8LwBIP7pBVpyR4l/sKkZqITmMtxRp04rwBrlshIZ17XeFAaovN3++wzkw==" + }, + "d3-geo": { + "version": "1.9.1", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-geo/-/d3-geo-1.9.1.tgz", + "integrity": "sha512-l9wL/cEQkyZQYXw3xbmLsH3eQ5ij+icNfo4r0GrLa5rOCZR/e/3am45IQ0FvQ5uMsv+77zBRunLc9ufTWSQYFA==", + "requires": { + "d3-array": "1.2.1" + } + }, + "d3-hierarchy": { + "version": "1.1.5", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-hierarchy/-/d3-hierarchy-1.1.5.tgz", + "integrity": "sha1-ochFxC+Eoga88cAcAQmOpN2qeiY=" + }, + "d3-interpolate": { + "version": "1.1.6", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-interpolate/-/d3-interpolate-1.1.6.tgz", + "integrity": "sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==", + "requires": { + "d3-color": "1.0.3" + } + }, + "d3-path": { + "version": "1.0.5", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-path/-/d3-path-1.0.5.tgz", + "integrity": "sha1-JB6xhJvZ6egCHA0KeZ+KDo5EF2Q=" + }, + "d3-polygon": { + "version": "1.0.3", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-polygon/-/d3-polygon-1.0.3.tgz", + "integrity": "sha1-FoiOkCZGCTPysXllKtN4Ik04LGI=" + }, + "d3-quadtree": { + "version": "1.0.3", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-quadtree/-/d3-quadtree-1.0.3.tgz", + "integrity": "sha1-rHmH4+I/6AWpkPKOG1DTj8uCJDg=" + }, + "d3-queue": { + "version": "3.0.7", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-queue/-/d3-queue-3.0.7.tgz", + "integrity": "sha1-yTouVLQXwJWRKdfXP2z31Ckudhg=" + }, + "d3-random": { + "version": "1.1.0", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-random/-/d3-random-1.1.0.tgz", + "integrity": "sha1-ZkLlBsb6OmSFldKyRpeIqNElKdM=" + }, + "d3-request": { + "version": "1.0.6", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-request/-/d3-request-1.0.6.tgz", + "integrity": "sha512-FJj8ySY6GYuAJHZMaCQ83xEYE4KbkPkmxZ3Hu6zA1xxG2GD+z6P+Lyp+zjdsHf0xEbp2xcluDI50rCS855EQ6w==", + "requires": { + "d3-collection": "1.0.4", + "d3-dispatch": "1.0.3", + "d3-dsv": "1.0.8", + "xmlhttprequest": "1.8.0" + } + }, + "d3-scale": { + "version": "1.0.7", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-scale/-/d3-scale-1.0.7.tgz", + "integrity": "sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==", + "requires": { + "d3-array": "1.2.1", + "d3-collection": "1.0.4", + "d3-color": "1.0.3", + "d3-format": "1.2.2", + "d3-interpolate": "1.1.6", + "d3-time": "1.0.8", + "d3-time-format": "2.1.1" + } + }, + "d3-selection": { + "version": "1.3.0", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-selection/-/d3-selection-1.3.0.tgz", + "integrity": "sha512-qgpUOg9tl5CirdqESUAu0t9MU/t3O9klYfGfyKsXEmhyxyzLpzpeh08gaxBUTQw1uXIOkr/30Ut2YRjSSxlmHA==" + }, + "d3-shape": { + "version": "1.2.0", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-shape/-/d3-shape-1.2.0.tgz", + "integrity": "sha1-RdAVOPBkuv0F6j1tLLdI/YxB93c=", + "requires": { + "d3-path": "1.0.5" + } + }, + "d3-time": { + "version": "1.0.8", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-time/-/d3-time-1.0.8.tgz", + "integrity": "sha512-YRZkNhphZh3KcnBfitvF3c6E0JOFGikHZ4YqD+Lzv83ZHn1/u6yGenRU1m+KAk9J1GnZMnKcrtfvSktlA1DXNQ==" + }, + "d3-time-format": { + "version": "2.1.1", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-time-format/-/d3-time-format-2.1.1.tgz", + "integrity": "sha512-8kAkymq2WMfzW7e+s/IUNAtN/y3gZXGRrdGfo6R8NKPAA85UBTxZg5E61bR6nLwjPjj4d3zywSQe1CkYLPFyrw==", + "requires": { + "d3-time": "1.0.8" + } + }, + "d3-timer": { + "version": "1.0.7", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-timer/-/d3-timer-1.0.7.tgz", + "integrity": "sha512-vMZXR88XujmG/L5oB96NNKH5lCWwiLM/S2HyyAQLcjWJCloK5shxta4CwOFYLZoY3AWX73v8Lgv4cCAdWtRmOA==" + }, + "d3-transition": { + "version": "1.1.1", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-transition/-/d3-transition-1.1.1.tgz", + "integrity": "sha512-xeg8oggyQ+y5eb4J13iDgKIjUcEfIOZs2BqV/eEmXm2twx80wTzJ4tB4vaZ5BKfz7XsI/DFmQL5me6O27/5ykQ==", + "requires": { + "d3-color": "1.0.3", + "d3-dispatch": "1.0.3", + "d3-ease": "1.0.3", + "d3-interpolate": "1.1.6", + "d3-selection": "1.3.0", + "d3-timer": "1.0.7" + } + }, + "d3-voronoi": { + "version": "1.1.2", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-voronoi/-/d3-voronoi-1.1.2.tgz", + "integrity": "sha1-Fodmfo8TotFYyAwUgMWinLDYlzw=" + }, + "d3-zoom": { + "version": "1.7.1", + "resolved": "https://repos.kreatio.com/repository/npm-all/d3-zoom/-/d3-zoom-1.7.1.tgz", + "integrity": "sha512-sZHQ55DGq5BZBFGnRshUT8tm2sfhPHFnOlmPbbwTkAoPeVdRTkB4Xsf9GCY0TSHrTD8PeJPZGmP/TpGicwJDJQ==", + "requires": { + "d3-dispatch": "1.0.3", + "d3-drag": "1.2.1", + "d3-interpolate": "1.1.6", + "d3-selection": "1.3.0", + "d3-transition": "1.1.1" + } }, "dashdash": { "version": "1.14.1", @@ -1406,7 +1663,8 @@ "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true }, "depd": { "version": "1.1.0", @@ -3009,6 +3267,7 @@ "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, "requires": { "aproba": "1.2.0", "console-control-strings": "1.1.0", @@ -3154,8 +3413,7 @@ "graceful-readlink": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" }, "grunt": { "version": "1.0.1", @@ -3353,34 +3611,37 @@ } }, "grunt-contrib-uglify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-2.0.0.tgz", - "integrity": "sha1-jJlw1pCTbN5tJaoRk1Sb2SkBaTA=", + "version": "3.2.1", + "resolved": "https://repos.kreatio.com/repository/npm-all/grunt-contrib-uglify/-/grunt-contrib-uglify-3.2.1.tgz", + "integrity": "sha512-xBPwg8wuA/m+HiSh2uMADuadKEnFQt9N5OhEy35vIl945yG6095oY1H1Og3ucg0wBSOieIBn3raqStvIcwKqHg==", "dev": true, "requires": { "chalk": "1.1.3", - "lodash.assign": "4.2.0", "maxmin": "1.1.0", - "uglify-js": "2.7.5", + "uglify-js": "3.2.2", "uri-path": "1.0.0" }, "dependencies": { - "async": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "commander": { + "version": "2.12.2", + "resolved": "https://repos.kreatio.com/repository/npm-all/commander/-/commander-2.12.2.tgz", + "integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://repos.kreatio.com/repository/npm-all/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "uglify-js": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.5.tgz", - "integrity": "sha1-RhLAx7qu4rp8SH3kkErhIgefLKg=", + "version": "3.2.2", + "resolved": "https://repos.kreatio.com/repository/npm-all/uglify-js/-/uglify-js-3.2.2.tgz", + "integrity": "sha512-++1NO/zZIEdWf6cDIGceSJQPX31SqIpbVAHwFG5+240MtZqPG/NIPoinj8zlXQtAfMBqEt1Jyv2FiLP3n9gVhQ==", "dev": true, "requires": { - "async": "0.2.10", - "source-map": "0.5.6", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" + "commander": "2.12.2", + "source-map": "0.6.1" } } } @@ -3788,7 +4049,8 @@ "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true }, "hash-base": { "version": "2.0.2", @@ -3966,8 +4228,7 @@ "iconv-lite": { "version": "0.4.18", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", - "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==", - "dev": true + "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==" }, "ieee754": { "version": "1.1.8", @@ -4015,7 +4276,8 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true }, "ink-docstrap": { "version": "1.3.0", @@ -4128,6 +4390,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, "requires": { "number-is-nan": "1.0.1" } @@ -4201,7 +4464,8 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true }, "isexe": { "version": "2.0.0", @@ -4791,7 +5055,8 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "dev": true + "dev": true, + "optional": true }, "lcid": { "version": "1.0.0", @@ -5400,7 +5665,8 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true }, "oauth-sign": { "version": "0.8.2", @@ -5411,7 +5677,8 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true }, "object-get": { "version": "2.1.0", @@ -5891,7 +6158,8 @@ "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true }, "progress": { "version": "1.1.8", @@ -6150,6 +6418,7 @@ "version": "2.2.11", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.11.tgz", "integrity": "sha512-h+8+r3MKEhkiVrwdKL8aWs1oc1VvBu33ueshOvS26RsZQ3Amhx/oO3TKe4lApSV9ueY6as8EAh7mtuFjdlhg9Q==", + "dev": true, "requires": { "core-util-is": "1.0.2", "inherits": "2.0.3", @@ -6164,6 +6433,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.2.tgz", "integrity": "sha1-sp4fThEl+pehA4K4pTNze3SR4Xk=", + "dev": true, "requires": { "safe-buffer": "5.0.1" } @@ -6428,6 +6698,7 @@ "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, + "optional": true, "requires": { "align-text": "0.1.4" } @@ -6448,10 +6719,16 @@ "inherits": "2.0.3" } }, + "rw": { + "version": "1.3.3", + "resolved": "https://repos.kreatio.com/repository/npm-all/rw/-/rw-1.3.3.tgz", + "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" + }, "safe-buffer": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz", - "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=" + "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=", + "dev": true }, "sanitize-html": { "version": "1.14.1", @@ -6709,7 +6986,8 @@ "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true }, "sntp": { "version": "1.0.9", @@ -6895,6 +7173,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, "requires": { "code-point-at": "1.1.0", "is-fullwidth-code-point": "1.0.0", @@ -6917,6 +7196,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, "requires": { "ansi-regex": "2.1.1" } @@ -7241,7 +7521,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "dev": true + "dev": true, + "optional": true }, "umd": { "version": "3.0.1", @@ -7391,7 +7672,8 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true }, "utile": { "version": "0.2.1", @@ -7557,6 +7839,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "dev": true, "requires": { "string-width": "1.0.2" } @@ -7565,7 +7848,8 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "dev": true + "dev": true, + "optional": true }, "winston": { "version": "0.8.3", @@ -7649,6 +7933,11 @@ "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=", "dev": true }, + "xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://repos.kreatio.com/repository/npm-all/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", @@ -7672,6 +7961,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, + "optional": true, "requires": { "camelcase": "1.2.1", "cliui": "2.1.0", @@ -7683,7 +7973,8 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true + "dev": true, + "optional": true } } }, diff --git a/package.json b/package.json index 3c365c519..0abf9e156 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ }, "dependencies": { "crossfilter2": "~1.4", - "d3": "^3" + "d3": "^4" }, "devDependencies": { "file-saver": "^1.3.0", diff --git a/spec/bar-chart-spec.js b/spec/bar-chart-spec.js index 9fd1923e9..bb31c9c38 100644 --- a/spec/bar-chart-spec.js +++ b/spec/bar-chart-spec.js @@ -5,7 +5,7 @@ describe('dc.barChart', function () { beforeEach(function () { data = crossfilter(loadDateFixture()); - dimension = data.dimension(function (d) { return d3.time.day.utc(d.dd); }); + dimension = data.dimension(function (d) { return d3.utcDay(d.dd); }); group = dimension.group(); id = 'bar-chart'; @@ -14,7 +14,7 @@ describe('dc.barChart', function () { chart = dc.barChart('#' + id); chart.dimension(dimension).group(group) .width(1100).height(200) - .x(d3.time.scale.utc().domain([makeDate(2012, 0, 1), makeDate(2012, 11, 31)])) + .x(d3.scaleUtc().domain([makeDate(2012, 0, 1), makeDate(2012, 11, 31)])) .transitionDuration(0) .controlsUseVisibility(true); }); @@ -125,13 +125,13 @@ describe('dc.barChart', function () { var domain = [makeDate(2012, 4, 20), makeDate(2012, 7, 15)]; - chart.x(d3.time.scale.utc().domain(domain)) + chart.x(d3.scaleUtc().domain(domain)) .group(dimension.group().reduceSum(function (d) { return +d.nvalue; })) .elasticY(true) .centerBar(false) - .xUnits(d3.time.days.utc) + .xUnits(d3.utcDays) .yAxis().ticks(5); chart.render(); @@ -147,7 +147,7 @@ describe('dc.barChart', function () { }); }); function nthYAxisText (n) { - return d3.select(chart.selectAll('g.y text')[0][n]); + return d3.select(chart.selectAll('g.y text').nodes()[n]); } it('should generate bars with positions corresponding to their data', function () { expect(nthStack(0).nthBar(0).attr('x')).toBeWithinDelta(58, 1); @@ -184,7 +184,7 @@ describe('dc.barChart', function () { chart.dimension(stateDimension) .group(stateGroup) .xUnits(dc.units.ordinal) - .x(d3.scale.ordinal().domain(ordinalDomainValues)) + .x(d3.scaleOrdinal().domain(ordinalDomainValues)) .barPadding(0) .outerPadding(0.1) .render(); @@ -240,7 +240,7 @@ describe('dc.barChart', function () { describe('with an unspecified domain', function () { beforeEach(function () { - chart.x(d3.scale.ordinal()).render(); + chart.x(d3.scaleOrdinal()).render(); }); it('should use alphabetical ordering', function () { @@ -305,7 +305,7 @@ describe('dc.barChart', function () { chart.dimension(linearDimension) .group(linearGroup) .xUnits(dc.units.integers) - .x(d3.scale.linear().domain([20, 70])) + .x(d3.scaleLinear().domain([20, 70])) .render(); }); @@ -350,7 +350,7 @@ describe('dc.barChart', function () { chart .brushOn(false) - .x(d3.time.scale.utc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])) + .x(d3.scaleUtc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])) .group(idGroup, 'stack 0') .title('stack 0', function (d) { return 'stack 0: ' + d.value; }) .stack(sumGroup, 'stack 1') @@ -404,7 +404,7 @@ describe('dc.barChart', function () { it('should have titles rendered for extra stacks', function () { nthStack(1).forEachBar(function (bar, datum) { - expect(bar.selectAll('title')[0].length).toBe(1); + expect(bar.selectAll('title').nodes().length).toBe(1); expect(bar.select('title').text()).toBe('stack 1: ' + datum.data.value); }); }); @@ -423,7 +423,7 @@ describe('dc.barChart', function () { it('should not create extra title elements', function () { nthStack(1).forEachBar(function (bar, datum) { - expect(bar.selectAll('title')[0].length).toBe(1); + expect(bar.selectAll('title').nodes().length).toBe(1); }); }); }); @@ -500,12 +500,12 @@ describe('dc.barChart', function () { var mixedGroup = dimension.group().reduceSum(function (d) { return d.nvalue; }); chart.group(mixedGroup).stack(mixedGroup).stack(mixedGroup); - chart.x(d3.time.scale.utc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])); + chart.x(d3.scaleUtc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])); chart.margins({top: 30, right: 50, bottom: 30, left: 30}) .yAxisPadding(5) .elasticY(true) - .xUnits(d3.time.days.utc) + .xUnits(d3.utcDays) .yAxis().ticks(5); chart.rescale(); // BUG: barWidth cannot change after initial rendering @@ -552,7 +552,7 @@ describe('dc.barChart', function () { }); it('should generate y axis domain dynamically', function () { - var nthText = function (n) { return d3.select(chart.selectAll('g.axis.y .tick text')[0][n]); }; + var nthText = function (n) { return d3.select(chart.selectAll('g.axis.y .tick text').nodes()[n]); }; expect(nthText(0).text()).toBe('-20'); expect(nthText(1).text()).toBe('0'); @@ -565,18 +565,18 @@ describe('dc.barChart', function () { var negativeGroup = dimension.group().reduceSum(function (d) { return -Math.abs(d.nvalue); }); chart.group(negativeGroup).stack(negativeGroup).stack(negativeGroup); - chart.x(d3.time.scale.utc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])); + chart.x(d3.scaleUtc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])); chart.margins({top: 30, right: 50, bottom: 30, left: 30}) .elasticY(true) - .xUnits(d3.time.days.utc) + .xUnits(d3.utcDays) .yAxis().ticks(3); chart.render(); }); it('should generate y axis domain dynamically', function () { - var nthText = function (n) { return d3.select(chart.selectAll('g.axis.y .tick text')[0][n]); }; + var nthText = function (n) { return d3.select(chart.selectAll('g.axis.y .tick text').nodes()[n]); }; expect(nthText(0).text()).toBe('-30'); expect(nthText(1).text()).toBe('-20'); @@ -592,7 +592,7 @@ describe('dc.barChart', function () { describe('when focused', function () { beforeEach(function () { - chart.elasticY(true).gap(1).xUnits(d3.time.days.utc); + chart.elasticY(true).gap(1).xUnits(d3.utcDays); chart.focus([makeDate(2012, 5, 11), makeDate(2012, 6, 9)]); }); @@ -634,7 +634,7 @@ describe('dc.barChart', function () { } function xAxisText () { - return chart.selectAll('g.x text')[0].map(function (x) { return d3.select(x).text(); }); + return chart.selectAll('g.x text').nodes().map(function (x) { return d3.select(x).text(); }); } }); @@ -686,7 +686,7 @@ describe('dc.barChart', function () { d3.select('#' + id).append('span').attr('class', 'filter').style('visibility', 'hidden'); d3.select('#' + id).append('a').attr('class', 'reset').style('visibility', 'hidden'); chart.filter([makeDate(2012, 5, 1), makeDate(2012, 5, 30)]).redraw(); - dc.dateFormat = d3.time.format.utc('%m/%d/%Y'); + dc.dateFormat = d3.utcFormat('%m/%d/%Y'); chart.redraw(); }); @@ -716,31 +716,32 @@ describe('dc.barChart', function () { }); it('should create a fancy brush resize handle', function () { - chart.select('g.brush').selectAll('.resize path').each(function (d, i) { + var selectAll = chart.select('g.brush').selectAll('path.handle--custom'); + selectAll.each(function (d, i) { if (i === 0) { expect(d3.select(this).attr('d')) - .toMatchPath('M0.5,53 A6,6 0 0 1 6.5,59 V100 A6,6 0 0 1 0.5,106 ZM2.5,61 V98 M4.5,61 V98'); + .toMatchPath('M-0.5,53 A6,6 0 0 0 -6.5,59 V100 A6,6 0 0 0 -0.5,106 ZM-2.5,61 V98 M-4.5,61 V98'); } else { expect(d3.select(this).attr('d')) - .toMatchPath('M-0.5,53 A6,6 0 0 0 -6.5,59 V100 A6,6 0 0 0 -0.5,106 ZM-2.5,61 V98 M-4.5,61 V98'); + .toMatchPath('M0.5,53 A6,6 0 0 1 6.5,59 V100 A6,6 0 0 1 0.5,106 ZM2.5,61 V98 M4.5,61 V98'); } }); }); it('should stretch the background', function () { - expect(+chart.select('g.brush rect.background').attr('width')).toBe(1020); + expect(+chart.select('g.brush rect.overlay').attr('width')).toBe(1020); }); it('should set the background height to the chart height', function () { - expect(+chart.select('g.brush rect.background').attr('height')).toBe(160); + expect(+chart.select('g.brush rect.overlay').attr('height')).toBe(160); }); it('should set extent height to the chart height', function () { - expect(+chart.select('g.brush rect.extent').attr('height')).toBe(160); + expect(+chart.select('g.brush rect.selection').attr('height')).toBe(160); }); it('should set extent width based on filter set', function () { - expect(chart.select('g.brush rect.extent').attr('width')).toBeWithinDelta(81, 1); + expect(chart.select('g.brush rect.selection').attr('width')).toBeWithinDelta(81, 1); }); it('should push unselected bars to the background', function () { @@ -771,7 +772,7 @@ describe('dc.barChart', function () { describe('a chart with a large domain', function () { beforeEach(function () { - chart.x(d3.time.scale.utc().domain([makeDate(2000, 0, 1), makeDate(2012, 11, 31)])); + chart.x(d3.scaleUtc().domain([makeDate(2000, 0, 1), makeDate(2012, 11, 31)])); }); describe('when filters are applied', function () { @@ -798,14 +799,14 @@ describe('dc.barChart', function () { beforeEach(function () { var numericalDimension = data.dimension(function (d) { return +d.value; }); chart.dimension(numericalDimension).group(numericalDimension.group()); - chart.x(d3.scale.linear().domain([10, 80])).elasticY(true); + chart.x(d3.scaleLinear().domain([10, 80])).elasticY(true); chart.render(); }); it('should base the y-axis height on the maximum value in the data', function () { var yAxisMax = 3.0; var ticks = chart.selectAll('g.y g.tick'); - var tickValues = ticks[0].map(function (tick) { return +d3.select(tick).text(); }); + var tickValues = ticks.nodes().map(function (tick) { return +d3.select(tick).text(); }); var maxTickValue = Math.max.apply(this, tickValues); expect(maxTickValue).toBe(yAxisMax); }); @@ -819,7 +820,7 @@ describe('dc.barChart', function () { it('should rescale the y-axis after applying a filter', function () { var yAxisMax = 1.0; var ticks = chart.selectAll('g.y g.tick'); - var tickValues = ticks[0].map(function (tick) { return +d3.select(tick).text(); }); + var tickValues = ticks.nodes().map(function (tick) { return +d3.select(tick).text(); }); var maxTickValue = Math.max.apply(this, tickValues); expect(maxTickValue).toBe(yAxisMax); }); @@ -838,7 +839,7 @@ describe('dc.barChart', function () { chart = dc.barChart('#' + id); chart.xUnits(dc.units.ordinal) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .transitionDuration(0) .dimension(dimension) .group(group, 'Population'); @@ -890,7 +891,7 @@ describe('dc.barChart', function () { .outerPadding(0) .dimension(dimension) .group(group) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal); chart.render(); }); @@ -920,7 +921,7 @@ describe('dc.barChart', function () { chart = dc.barChart('#' + id); chart.width(500).transitionDuration(0) - .x(d3.scale.linear().domain([0,7])) + .x(d3.scaleLinear().domain([0,7])) .elasticY(true) .dimension(dimension) .group(group); @@ -965,7 +966,7 @@ describe('dc.barChart', function () { chart = dc.barChart('#' + id); chart.width(500) .transitionDuration(0) - .x(d3.time.scale()) + .x(d3.scaleTime()) .elasticY(true).elasticX(true) .dimension(dimension) .group(group); @@ -980,8 +981,8 @@ describe('dc.barChart', function () { it('should render the right xAxisMax/Min when 10 day padding', function () { chart.xAxisPadding(10) .render(); - var expectedStartDate = d3.time.day.offset(date, -10); - var expectedEndDate = d3.time.day.offset(date, 10); + var expectedStartDate = d3.timeDay.offset(date, -10); + var expectedEndDate = d3.timeDay.offset(date, 10); expect(chart.xAxisMin()).toEqual(expectedStartDate); expect(chart.xAxisMax()).toEqual(expectedEndDate); }); @@ -989,8 +990,8 @@ describe('dc.barChart', function () { chart.xAxisPaddingUnit('month') .xAxisPadding(2) .render(); - var expectedStartDate = d3.time.month.offset(date, -2); - var expectedEndDate = d3.time.month.offset(date, 2); + var expectedStartDate = d3.timeMonth.offset(date, -2); + var expectedEndDate = d3.timeMonth.offset(date, 2); expect(chart.xAxisMin()).toEqual(expectedStartDate); expect(chart.xAxisMax()).toEqual(expectedEndDate); }); @@ -1014,7 +1015,7 @@ describe('dc.barChart', function () { chart = dc.barChart('#' + id); chart.width(500).transitionDuration(0) - .x(d3.scale.linear()) + .x(d3.scaleLinear()) .elasticY(true).elasticX(true) .dimension(dimension) .group(group); @@ -1062,7 +1063,7 @@ describe('dc.barChart', function () { chart = dc.barChart('#' + id); chart.width(500).transitionDuration(0) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .elasticY(true).elasticX(true) .dimension(dimension) @@ -1096,7 +1097,7 @@ describe('dc.barChart', function () { beforeEach(function () { chart .brushOn(true) - .round(d3.time.month.utc.round) + .round(d3.utcMonth.round) .centerBar(true); }); @@ -1107,8 +1108,11 @@ describe('dc.barChart', function () { chart.alwaysUseRounding(false); consoleWarnSpy = spyOn(console, 'warn'); chart.render(); - chart.brush().extent([makeDate(2012, 6, 1), makeDate(2012, 7, 15)]); - chart.brush().event(chart.root()); + + // Setup a dummy event - just enough for the handler to get fooled + setupEventForBrushing(chart, [makeDate(2012, 6, 1), makeDate(2012, 7, 15)]); + // Directly call the handler + chart._brushing(); }); it('should log a warning indicating that brush rounding was disabled', function () { @@ -1126,13 +1130,16 @@ describe('dc.barChart', function () { beforeEach(function () { chart.alwaysUseRounding(true); chart.render(); - chart.brush().extent([makeDate(2012, 6, 1), makeDate(2012, 7, 15)]); - chart.brush().event(chart.root()); + // Setup a dummy event - just enough for the handler to get fooled + setupEventForBrushing(chart, [makeDate(2012, 6, 1), makeDate(2012, 7, 15)]); + // Directly call the handler + chart._brushing(); }); it('should round the brush', function () { jasmine.clock().tick(100); - expect(chart.brush().extent()).toEqual([makeDate(2012, 6, 1), makeDate(2012, 7, 1)]); + var filter = cleanDateRange(chart.filter()); + expect(filter).toEqual([makeDate(2012, 6, 1), makeDate(2012, 7, 1)]); }); }); }); @@ -1158,7 +1165,7 @@ describe('dc.barChart', function () { chart = dc.barChart('#' + id); chart.width(500).transitionDuration(0) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .elasticY(true).elasticX(true) .dimension(dimension) @@ -1191,7 +1198,7 @@ describe('dc.barChart', function () { }); function xAxisText () { - return chart.selectAll('g.x text')[0].map(function (x) { return d3.select(x).text(); }); + return chart.selectAll('g.x text').nodes().map(function (x) { return d3.select(x).text(); }); } }); @@ -1219,7 +1226,7 @@ describe('dc.barChart', function () { chart = dc.barChart('#' + id); chart.width(500).transitionDuration(0) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .elasticY(true).elasticX(true) .dimension(dimension) @@ -1255,19 +1262,19 @@ describe('dc.barChart', function () { }); function xAxisText () { - return chart.selectAll('g.x text')[0].map(function (x) { return d3.select(x).text(); }); + return chart.selectAll('g.x text').nodes().map(function (x) { return d3.select(x).text(); }); } }); function nthStack (n) { - var stack = d3.select(chart.selectAll('.stack')[0][n]); + var stack = d3.select(chart.selectAll('.stack').nodes()[n]); stack.nthBar = function (n) { - return d3.select(this.selectAll('rect.bar')[0][n]); + return d3.select(this.selectAll('rect.bar').nodes()[n]); }; stack.nthLabel = function (n) { - return d3.select(this.selectAll('text.barLabel')[0][n]); + return d3.select(this.selectAll('text.barLabel').nodes()[n]); }; stack.forEachBar = function (assertions) { diff --git a/spec/base-mixin-spec.js b/spec/base-mixin-spec.js index baa4bc5a3..3875a4795 100644 --- a/spec/base-mixin-spec.js +++ b/spec/base-mixin-spec.js @@ -5,7 +5,7 @@ describe('dc.baseMixin', function () { beforeEach(function () { var data = crossfilter(loadDateFixture()); dimension = data.dimension(function (d) { - return d3.time.day.utc(d.dd); + return d3.utcDay(d.dd); }); group = dimension.group().reduceSum(function (d) { return d.value; @@ -28,116 +28,159 @@ describe('dc.baseMixin', function () { }); describe('renderlets', function () { - var firstRenderlet, secondRenderlet, thirdRenderlet, - pretransition; - beforeEach(function () { - var expectedCallbackSignature = function (callbackChart) { + it('should not execute a renderlet until after the render transitions', function (done) { + var firstRenderlet = jasmine.createSpy().and.callFake(function (callbackChart) { expect(callbackChart).toBe(chart); - }; - firstRenderlet = jasmine.createSpy().and.callFake(expectedCallbackSignature); - secondRenderlet = jasmine.createSpy().and.callFake(expectedCallbackSignature); - thirdRenderlet = jasmine.createSpy().and.callFake(expectedCallbackSignature); - pretransition = jasmine.createSpy().and.callFake(expectedCallbackSignature); - chart.renderlet(firstRenderlet); // still testing renderlet event-namespace generation here - chart.renderlet(secondRenderlet); - chart.on('renderlet.third', thirdRenderlet); - chart.on('pretransition.pret', pretransition); - }); - - it('should not execute a renderlet until after the render transitions', function () { + done(); + }); + chart.renderlet(firstRenderlet); chart.render(); expect(firstRenderlet).not.toHaveBeenCalled(); flushAllD3Transitions(); - expect(firstRenderlet).toHaveBeenCalled(); + // Test will wait until firstRenderlet has been called }); - it('should not execute a renderlet until after the redraw transitions', function () { + it('should not execute a renderlet until after the redraw transitions', function (done) { + var firstRenderlet = jasmine.createSpy().and.callFake(function (callbackChart) { + expect(callbackChart).toBe(chart); + done(); + }); + chart.renderlet(firstRenderlet); chart.redraw(); expect(firstRenderlet).not.toHaveBeenCalled(); flushAllD3Transitions(); - expect(firstRenderlet).toHaveBeenCalled(); + // Test will wait until firstRenderlet has been called }); it('should execute pretransition event before the render transitions', function () { + var pretransition = jasmine.createSpy(); + chart.on('pretransition.pret', pretransition); chart.render(); - expect(pretransition).toHaveBeenCalled(); + expect(pretransition).toHaveBeenCalledWith(chart); flushAllD3Transitions(); }); it('should execute pretransition event before the redraw transitions', function () { + var pretransition = jasmine.createSpy(); + chart.on('pretransition.pret', pretransition); chart.redraw(); - expect(pretransition).toHaveBeenCalled(); + expect(pretransition).toHaveBeenCalledWith(chart); flushAllD3Transitions(); }); - it('should execute each renderlet after a render', function () { + it('should execute each renderlet after a render', function (done) { + var count = 0; + var renderlet = jasmine.createSpy().and.callFake(function (callbackChart) { + expect(callbackChart).toBe(chart); + count++; + if(count === 2){ + done(); + } + }); + var firstRenderlet = renderlet, + secondRenderlet = firstRenderlet; + chart.renderlet(firstRenderlet); + chart.renderlet(firstRenderlet); chart.render(); flushAllD3Transitions(); - expect(firstRenderlet).toHaveBeenCalled(); - expect(secondRenderlet).toHaveBeenCalled(); + // Test will wait till firstRenderlet and secondRenderlet both have been called }); - it('should execute each renderlet after a redraw', function () { + it('should execute each renderlet after a redraw', function (done) { + var count = 0; + var renderlet = jasmine.createSpy().and.callFake(function (callbackChart) { + expect(callbackChart).toBe(chart); + count++; + if(count === 2){ + done(); + } + }); + var firstRenderlet = renderlet, + secondRenderlet = firstRenderlet; + chart.renderlet(firstRenderlet); + chart.renderlet(firstRenderlet); chart.redraw(); flushAllD3Transitions(); - expect(firstRenderlet).toHaveBeenCalled(); - expect(secondRenderlet).toHaveBeenCalled(); + // Test will wait till firstRenderlet and secondRenderlet both have been called }); - it('should execute a named renderlet after a render', function () { + it('should execute a named renderlet after a render', function (done) { + var thirdRenderlet = jasmine.createSpy().and.callFake(function (callbackChart) { + expect(callbackChart).toBe(chart); + done(); + }); + chart.on('renderlet.third', thirdRenderlet); chart.render(); + expect(thirdRenderlet).not.toHaveBeenCalled(); flushAllD3Transitions(); - expect(thirdRenderlet).toHaveBeenCalled(); + // Test will wait until thirdRenderlet has been called }); - it('should execute a named renderlet after a redraw', function () { + it('should execute a named renderlet after a redraw', function (done) { + var thirdRenderlet = jasmine.createSpy().and.callFake(function (callbackChart) { + expect(callbackChart).toBe(chart); + done(); + }); + chart.on('renderlet.third', thirdRenderlet); chart.redraw(); flushAllD3Transitions(); - expect(thirdRenderlet).toHaveBeenCalled(); + // Test will wait until thirdRenderlet has been called }); - it('should remove a named renderlet expect no call after a redraw', function () { + it('should remove a named renderlet expect no call after a redraw', function (done) { + var secondRenderlet = jasmine.createSpy().and.callFake(function (callbackChart) { + expect(thirdRenderlet).not.toHaveBeenCalled(); + done(); + }); + var thirdRenderlet = jasmine.createSpy(); + chart.on('renderlet.third' , secondRenderlet); + chart.renderlet(secondRenderlet); chart.on('renderlet.third'); chart.redraw(); flushAllD3Transitions(); - expect(secondRenderlet).toHaveBeenCalled(); - expect(thirdRenderlet).not.toHaveBeenCalled(); + // Test will wait until secondRenderlet has been called }); - it('should remove a named renderlet and expect no call after a redraw', function () { + it('should remove a named renderlet and expect no call after a render', function (done) { + var secondRenderlet = jasmine.createSpy().and.callFake(function (callbackChart) { + expect(thirdRenderlet).not.toHaveBeenCalled(); + done(); + }); + var thirdRenderlet = jasmine.createSpy(); + chart.on('renderlet.third' , secondRenderlet); + chart.renderlet(secondRenderlet); chart.on('renderlet.third'); chart.render(); flushAllD3Transitions(); - expect(secondRenderlet).toHaveBeenCalled(); - expect(thirdRenderlet).not.toHaveBeenCalled(); + // Test will wait until secondRenderlet has been called }); }); describe('event listeners', function () { describe('on render', function () { - var preRenderSpy, postRenderSpy; - beforeEach(function () { - var expectedCallbackSignature = function (callbackChart) { - expect(callbackChart).toBe(chart); - }; - - preRenderSpy = jasmine.createSpy().and.callFake(expectedCallbackSignature); - postRenderSpy = jasmine.createSpy().and.callFake(expectedCallbackSignature); - - chart.on('preRender', preRenderSpy); - chart.on('postRender', postRenderSpy); - }); - it('should execute the preRender callback', function () { + var preRenderSpy = jasmine.createSpy(); + chart.on('preRender', preRenderSpy); chart.render(); flushAllD3Transitions(); - expect(preRenderSpy).toHaveBeenCalled(); + expect(preRenderSpy).toHaveBeenCalledWith(chart); }); - it('should execute the postRender callback', function () { + it('should execute the postRender callback', function (done) { + var preRenderSpy = jasmine.createSpy(); + var postRender = function (callbackChart) { + // By now preRender must have been called + expect(preRenderSpy).toHaveBeenCalledWith(chart); + + expect(callbackChart).toBe(chart); + done(); + }; + + chart.on('preRender', preRenderSpy); + chart.on('postRender', postRender); chart.render(); flushAllD3Transitions(); - expect(postRenderSpy).toHaveBeenCalled(); + // Test case will wait until postRender has been called }); }); @@ -199,30 +242,30 @@ describe('dc.baseMixin', function () { }); describe('on redraw', function () { - var preRedrawSpy, postRedrawSpy; - beforeEach(function () { - var expectedCallbackSignature = function (callbackChart) { - expect(callbackChart).toBe(chart); - }; - - preRedrawSpy = jasmine.createSpy().and.callFake(expectedCallbackSignature); - postRedrawSpy = jasmine.createSpy().and.callFake(expectedCallbackSignature); - - chart.on('preRedraw', preRedrawSpy); - chart.on('postRedraw', postRedrawSpy); - }); - it('should execute the preRedraw callback before transitions', function () { + var preRedrawSpy = jasmine.createSpy(); + chart.on('preRedraw', preRedrawSpy); chart.redraw(); - expect(preRedrawSpy).toHaveBeenCalled(); + expect(preRedrawSpy).toHaveBeenCalledWith(chart); flushAllD3Transitions(); }); - it('should execute the postRedraw callback after transitions', function () { + it('should execute the postRedraw callback after transitions', function (done) { + var preRedrawSpy = jasmine.createSpy(); + var postRedraw = function (callbackChart) { + // By now preRedraw must have been called + expect(preRedrawSpy).toHaveBeenCalledWith(chart); + + expect(callbackChart).toBe(chart); + done(); + }; + var postRedrawSpy = jasmine.createSpy().and.callFake(postRedraw); + chart.on('preRedraw', preRedrawSpy); + chart.on('postRedraw', postRedraw); chart.redraw(); expect(postRedrawSpy).not.toHaveBeenCalled(); flushAllD3Transitions(); - expect(postRedrawSpy).toHaveBeenCalled(); + // The test case will wait till postRedraw has been called }); }); }); @@ -358,16 +401,15 @@ describe('dc.baseMixin', function () { beforeEach(function () { dimdiv = appendChartID('dimensionTest'); chart.anchor('#dimensionTest'); - bodyWidth = d3.select('body')[0][0].getBoundingClientRect().width; + bodyWidth = d3.select('body').nodes()[0].getBoundingClientRect().width; }); describe('when set to a falsy on a sized div', function () { var h0, w0; beforeEach(function () { - dimdiv.style({ - height: '220px', - width: '230px' - }); + dimdiv + .style('height', '220px') + .style('width', '230px'); chart.width(null).height(null).render(); w0 = chart.width(); h0 = chart.height(); diff --git a/spec/biggish-data-spec.js b/spec/biggish-data-spec.js index 27d0653ed..5476778f8 100644 --- a/spec/biggish-data-spec.js +++ b/spec/biggish-data-spec.js @@ -14,8 +14,6 @@ describe('dc.barChart.biggish', function () { var chartAttemptSeries = dc.lineChart('#stack-chart'); var chartRange = dc.barChart('#range-chart'); - var dateFormat = d3.time.format.iso; - var xfilter; var data = biggishData(); @@ -24,11 +22,11 @@ describe('dc.barChart.biggish', function () { // coerce k(ind) into a number row.k = +row.k; // convert event time into d3 date format - row.dd = dateFormat.parse(row.t); + row.dd = d3.isoParse(row.t); // pre-calculate the day of the time - row.day = d3.time.day(row.dd); + row.day = d3.timeDay(row.dd); // precalculate the hour of the time - row.hour = d3.time.hour(row.dd); + row.hour = d3.timeHour(row.dd); // coerce n(umber of attempts) into a number row.n = +row.n; }); @@ -83,13 +81,13 @@ describe('dc.barChart.biggish', function () { // calculate day extent (two element array of first and last items in the range) - of the hour data var extentDay = d3.extent(data, function (row) { return row.day; }); // select the following day for the end of the extent - extentDay[1] = d3.time.day.offset(extentDay[1], 1); + extentDay[1] = d3.timeDay.offset(extentDay[1], 1); chartAttemptSeries .margins({top: 30, right: 50, bottom: 25, left: 40}) .renderArea(true) .height(200) - .x(d3.time.scale().domain(extentDay)) + .x(d3.scaleTime().domain(extentDay)) .renderHorizontalGridLines(true) .rangeChart(chartRange) .transitionDuration(1000) @@ -103,7 +101,7 @@ describe('dc.barChart.biggish', function () { .valueAccessor(function (d) { return d.value.bfa; }) .stack(groupHourSeries, 'Horizontal Movement', function (d) { return d.value.hma; }) .stack(groupHourSeries, 'User Account Hacking', function (d) { return d.value.uha; }) - .xUnits(d3.time.hours); + .xUnits(d3.timeHours); chartAttemptSeries.legend(dc.legend().horizontal(true).x(50).y(0).itemWidth(150).gap(5)); @@ -113,10 +111,10 @@ describe('dc.barChart.biggish', function () { .group(groupHourSum) .centerBar(true) .gap(1) - .xUnits(d3.time.hours) - .round(d3.time.hour.round) + .xUnits(d3.timeHours) + .round(d3.timeHour.round) .alwaysUseRounding(true) - .x(d3.time.scale().domain(extentDay)) + .x(d3.scaleTime().domain(extentDay)) // hide the range chart's y axis // note: breaks function chaining by returning the yAxis diff --git a/spec/box-plot-spec.js b/spec/box-plot-spec.js index b553dad32..5bd3cf2b4 100644 --- a/spec/box-plot-spec.js +++ b/spec/box-plot-spec.js @@ -26,7 +26,7 @@ describe('dc.boxPlot', function () { .boxPadding(0) .transitionDuration(0) .transitionDelay(0) - .y(d3.scale.linear().domain([0, 144])) + .y(d3.scaleLinear().domain([0, 144])) .ordinalColors(['#01','#02']); }); @@ -196,15 +196,15 @@ describe('dc.boxPlot', function () { }); function box (n) { - var nthBox = d3.select(chart.selectAll('g.box')[0][n]); + var nthBox = d3.select(chart.selectAll('g.box').nodes()[n]); nthBox.boxText = function (n) { - return d3.select(this.selectAll('text.box')[0][n]); + return d3.select(this.selectAll('text.box').nodes()[n]); }; nthBox.whiskerLine = function (n) { - return d3.select(this.selectAll('line.whisker')[0][n]); + return d3.select(this.selectAll('line.whisker').nodes()[n]); }; nthBox.whiskerText = function (n) { - return d3.select(this.selectAll('text.whisker')[0][n]); + return d3.select(this.selectAll('text.whisker').nodes()[n]); }; return nthBox; } diff --git a/spec/bubble-chart-spec.js b/spec/bubble-chart-spec.js index 26a83103b..5c9a9ec6b 100644 --- a/spec/bubble-chart-spec.js +++ b/spec/bubble-chart-spec.js @@ -56,9 +56,9 @@ describe('dc.bubbleChart', function () { .radiusValueAccessor(function (p) { return p.value.count; }) - .x(d3.scale.linear().domain([0, 300])) - .y(d3.scale.linear().domain([0, 10])) - .r(d3.scale.linear().domain([0, 30])) + .x(d3.scaleLinear().domain([0, 300])) + .y(d3.scaleLinear().domain([0, 10])) + .r(d3.scaleLinear().domain([0, 30])) .maxBubbleRelativeSize(0.3) .transitionDuration(0) .renderLabel(true) @@ -98,7 +98,7 @@ describe('dc.bubbleChart', function () { }); it('generates right number of bubbles', function () { - expect(chart.selectAll('circle.bubble')[0].length).toBe(2); + expect(chart.selectAll('circle.bubble').nodes().length).toBe(2); }); it('calculates right cx for each bubble', function () { @@ -142,7 +142,7 @@ describe('dc.bubbleChart', function () { }); it('generates right number of labels', function () { - expect(chart.selectAll('g.node text')[0].length).toBe(2); + expect(chart.selectAll('g.node text').nodes().length).toBe(2); }); it('creates correct label for each bubble', function () { @@ -157,7 +157,7 @@ describe('dc.bubbleChart', function () { }); it('generates right number of titles', function () { - expect(chart.selectAll('g.node title')[0].length).toBe(2); + expect(chart.selectAll('g.node title').nodes().length).toBe(2); }); it('creates correct title for each bubble', function () { @@ -189,11 +189,11 @@ describe('dc.bubbleChart', function () { }); it('generates right number of labels', function () { - expect(chart.selectAll('g.node text')[0].length).toBe(0); + expect(chart.selectAll('g.node text').nodes().length).toBe(0); }); it('generates right number of titles', function () { - expect(chart.selectAll('g.node title')[0].length).toBe(0); + expect(chart.selectAll('g.node title').nodes().length).toBe(0); }); }); @@ -375,7 +375,7 @@ describe('dc.bubbleChart', function () { }); it('generates right number of bubbles', function () { - expect(chart.selectAll('circle.bubble')[0].length).toBe(10); + expect(chart.selectAll('circle.bubble').nodes().length).toBe(10); }); it('auto calculates x range based on width', function () { @@ -415,8 +415,8 @@ describe('dc.bubbleChart', function () { .valueAccessor(function (kv) { return 0; }) - .x(d3.scale.log().domain([1, 300])) - .y(d3.scale.log().domain([1, 10])) + .x(d3.scaleLog().domain([1, 300])) + .y(d3.scaleLog().domain([1, 10])) .elasticX(false) .elasticY(false); chart.render(); @@ -431,13 +431,13 @@ describe('dc.bubbleChart', function () { describe('with a date-based scale', function () { beforeEach(function () { - dimension = data.dimension(function (d) { return d3.time.day.utc(d.dd); }); + dimension = data.dimension(function (d) { return d3.utcDay(d.dd); }); group = dimension.group(); chart .dimension(dimension) .group(group) - .x(d3.time.scale.utc().domain([makeDate(2012, 0, 1), makeDate(2012, 11, 31)])) + .x(d3.scaleUtc().domain([makeDate(2012, 0, 1), makeDate(2012, 11, 31)])) .elasticX(true) .elasticY(true) .keyAccessor(function (kv) { @@ -449,7 +449,7 @@ describe('dc.bubbleChart', function () { .radiusValueAccessor(function (kv) { return kv.value; }) - .colors(d3.scale.ordinal().range(['#a60000', '#ff0000', '#ff4040', '#ff7373', '#67e667', '#39e639', '#00cc00'])) + .colors(d3.scaleOrdinal().range(['#a60000', '#ff0000', '#ff4040', '#ff7373', '#67e667', '#39e639', '#00cc00'])) .colorAccessor(function (kv) { return kv.key; }) @@ -587,15 +587,15 @@ describe('dc.bubbleChart', function () { .transitionDuration(0) .width(400) .height(400) - .x(d3.scale.linear()).xAxisPadding(0.5) - .y(d3.scale.linear()).yAxisPadding(0.5) + .x(d3.scaleLinear()).xAxisPadding(0.5) + .y(d3.scaleLinear()).yAxisPadding(0.5) .elasticX(true) .elasticY(true) .keyAccessor(key_part(0)) .valueAccessor(key_part(1)) .radiusValueAccessor(function (kv) { return kv.value.total; }) .elasticRadius(true) - .colors(d3.scale.ordinal() + .colors(d3.scaleOrdinal() .domain(species.concat('none')) .range(['#e41a1c','#377eb8','#4daf4a', '#f8f8f8'])) .colorAccessor(function (d) { @@ -616,7 +616,7 @@ describe('dc.bubbleChart', function () { .xBorderRadius(15).yBorderRadius(15) .keyAccessor(key_part(0)) .valueAccessor(key_part(1)) - .colors(d3.scale.ordinal() + .colors(d3.scaleOrdinal() .domain(species.concat('none')) .range(['#e41a1c','#377eb8','#4daf4a', '#f8f8f8'])) .colorAccessor(function (d) { @@ -659,14 +659,14 @@ describe('dc.bubbleChart', function () { } function testBubbleRadiiCol3 (chart) { - var bubbles = chart.selectAll('circle.bubble')[0]; + var bubbles = chart.selectAll('circle.bubble').nodes(); var expected = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34.5, 16.1, 0, 0, 16.1, 59.1, 34.5, 16.1, 96, 0, 22.2, 0, 0, 0, 0]; bubbles.forEach(function (b, i) { expect(+d3.select(b).attr('r')).toBeWithinDelta(expected[i], 0.1); }); } function testBubbleTitlesCol3 (chart) { - var titles = chart.selectAll('g.node title')[0]; + var titles = chart.selectAll('g.node title').nodes(); var expected = [ {'total': 0,'setosa': 0,'versicolor': 0,'virginica': 0},{'total': 0,'setosa': 0,'versicolor': 0,'virginica': 0}, {'total': 0,'setosa': 0,'versicolor': 0,'virginica': 0},{'total': 0,'setosa': 0,'versicolor': 0,'virginica': 0}, @@ -687,7 +687,7 @@ describe('dc.bubbleChart', function () { }); } function testBubbleLabelsCol3 (chart) { - var labels = chart.selectAll('g.node text')[0]; + var labels = chart.selectAll('g.node text').nodes(); var expected = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0, 0, 1, 8, 4, 1, 14, 0, 2, 0, 0, 0, 0]; labels.forEach(function (l, i) { expect(+d3.select(l).text()).toBe(expected[i]); @@ -695,9 +695,9 @@ describe('dc.bubbleChart', function () { } describe('column filtering with straight crossfilter', function () { beforeEach(function () { - var axisLabel = d3.select(heatMap.selectAll('.cols.axis text')[0][3]); + var axisLabel = d3.select(heatMap.selectAll('.cols.axis text').nodes()[3]); axisLabel.on('click')(axisLabel.datum()); - d3.timer.flush(); + d3.timerFlush(); }); it('updates bubble radii correctly', function () { testBubbleRadiiCol3(chart); @@ -713,9 +713,9 @@ describe('dc.bubbleChart', function () { beforeEach(function () { chart.group(clone_group(sepalGroup)); chart.render(); - var axisLabel = d3.select(heatMap.selectAll('.cols.axis text')[0][3]); + var axisLabel = d3.select(heatMap.selectAll('.cols.axis text').nodes()[3]); axisLabel.on('click')(axisLabel.datum()); - d3.timer.flush(); + d3.timerFlush(); }); it('updates bubble radii correctly', function () { testBubbleRadiiCol3(chart); diff --git a/spec/bubble-overlay-spec.js b/spec/bubble-overlay-spec.js index 0621fa5f1..80d9b6285 100644 --- a/spec/bubble-overlay-spec.js +++ b/spec/bubble-overlay-spec.js @@ -12,7 +12,8 @@ describe('dc.bubbleOverlay', function () { var parent = appendChartID(id); var width = 600, height = 400; var svg = parent.append('svg') - .attr({width: width, height: height}); + .attr('width', width) + .attr('height', height); chart = dc.bubbleOverlay('#' + id) .svg(svg) @@ -22,7 +23,7 @@ describe('dc.bubbleOverlay', function () { .height(height) .transitionDuration(0) .title(function (d) {return 'Title: ' + d.key;}) - .r(d3.scale.linear().domain([0, 100])) + .r(d3.scaleLinear().domain([0, 100])) .maxBubbleRelativeSize(0.1) .ordinalColors(['blue']) .point('California', 100, 120) @@ -45,60 +46,60 @@ describe('dc.bubbleOverlay', function () { }); it('should generate the correct number of overlay groups', function () { - expect(chart.selectAll('g.node')[0].length).toEqual(6); + expect(chart.selectAll('g.node').nodes().length).toEqual(6); }); it('should generate a correct class name for the overlay groups', function () { - expect(d3.select(chart.selectAll('g.node')[0][0]).attr('class')).toEqual('node california'); - expect(d3.select(chart.selectAll('g.node')[0][3]).attr('class')).toEqual('node ontario'); + expect(d3.select(chart.selectAll('g.node').nodes()[0]).attr('class')).toEqual('node california'); + expect(d3.select(chart.selectAll('g.node').nodes()[3]).attr('class')).toEqual('node ontario'); }); it('should generate the correct number of overlay bubbles', function () { - expect(chart.selectAll('circle.bubble')[0].length).toEqual(6); + expect(chart.selectAll('circle.bubble').nodes().length).toEqual(6); }); it('should generate a correct translate for overlay groups', function () { - expect(d3.select(chart.selectAll('g.node')[0][0]).attr('transform')).toMatchTranslate(100, 120); - expect(d3.select(chart.selectAll('g.node')[0][3]).attr('transform')).toMatchTranslate(180, 90); + expect(d3.select(chart.selectAll('g.node').nodes()[0]).attr('transform')).toMatchTranslate(100, 120); + expect(d3.select(chart.selectAll('g.node').nodes()[3]).attr('transform')).toMatchTranslate(180, 90); }); it('should generate correct radii for circles', function () { - expect(d3.select(chart.selectAll('circle.bubble')[0][0]).attr('r')).toEqual('87'); - expect(d3.select(chart.selectAll('circle.bubble')[0][3]).attr('r')).toEqual('48.5'); + expect(d3.select(chart.selectAll('circle.bubble').nodes()[0]).attr('r')).toEqual('87'); + expect(d3.select(chart.selectAll('circle.bubble').nodes()[3]).attr('r')).toEqual('48.5'); }); it('should generate correct labels', function () { - expect(d3.select(chart.selectAll('g.node text')[0][0]).text()).toEqual('California'); - expect(d3.select(chart.selectAll('g.node text')[0][3]).text()).toEqual('Ontario'); + expect(d3.select(chart.selectAll('g.node text').nodes()[0]).text()).toEqual('California'); + expect(d3.select(chart.selectAll('g.node text').nodes()[3]).text()).toEqual('Ontario'); }); it('should generate the label only once', function () { chart.redraw(); - expect(chart.selectAll('g.node text')[0].length).toEqual(6); + expect(chart.selectAll('g.node text').nodes().length).toEqual(6); }); it('generate the correct titles', function () { - expect(d3.select(chart.selectAll('g.node title')[0][0]).text()).toEqual('Title: California'); - expect(d3.select(chart.selectAll('g.node title')[0][3]).text()).toEqual('Title: Ontario'); + expect(d3.select(chart.selectAll('g.node title').nodes()[0]).text()).toEqual('Title: California'); + expect(d3.select(chart.selectAll('g.node title').nodes()[3]).text()).toEqual('Title: Ontario'); }); it('should only generate titles once', function () { chart.redraw(); - expect(chart.selectAll('g.node title')[0].length).toEqual(6); + expect(chart.selectAll('g.node title').nodes().length).toEqual(6); }); it('should fill circles with the specified colors', function () { - expect(d3.select(chart.selectAll('circle.bubble')[0][0]).attr('fill')).toEqual('blue'); - expect(d3.select(chart.selectAll('circle.bubble')[0][3]).attr('fill')).toEqual('blue'); + expect(d3.select(chart.selectAll('circle.bubble').nodes()[0]).attr('fill')).toEqual('blue'); + expect(d3.select(chart.selectAll('circle.bubble').nodes()[3]).attr('fill')).toEqual('blue'); }); it('should highlight the filtered bubbles', function () { chart.filter('Colorado'); chart.filter('California'); chart.redraw(); - expect(d3.select(chart.selectAll('g.node')[0][0]).attr('class')).toEqual('node california selected'); - expect(d3.select(chart.selectAll('g.node')[0][1]).attr('class')).toEqual('node colorado selected'); - expect(d3.select(chart.selectAll('g.node')[0][3]).attr('class')).toEqual('node ontario deselected'); + expect(d3.select(chart.selectAll('g.node').nodes()[0]).attr('class')).toEqual('node california selected'); + expect(d3.select(chart.selectAll('g.node').nodes()[1]).attr('class')).toEqual('node colorado selected'); + expect(d3.select(chart.selectAll('g.node').nodes()[3]).attr('class')).toEqual('node ontario deselected'); }); }); @@ -118,7 +119,7 @@ describe('dc.bubbleOverlay', function () { regionDim = data.dimension(function (d) { return d.region; }); }); function expectRadii (expected) { - var circles = chart.selectAll('circle.bubble')[0]; + var circles = chart.selectAll('circle.bubble').nodes(); console.log(circles.map(function (c) { return +d3.select(c).attr('r'); })); circles.forEach(function (c, i) { expect(+d3.select(c).attr('r')).toBeWithinDelta(expected[i], 0.1); diff --git a/spec/color-spec.js b/spec/color-spec.js index d30382092..161514c2b 100644 --- a/spec/color-spec.js +++ b/spec/color-spec.js @@ -17,24 +17,24 @@ describe('dc.colorMixin', function () { }); it('default', function () { - expect(colorTest(chart, domain)).toEqual(['#3182bd','#6baed6','#9ecae1','#c6dbef','#e6550d']); + expect(colorTest(chart, domain)).toMatchColors(['#3182bd','#6baed6','#9ecae1','#c6dbef','#e6550d']); }); it('custom', function () { - chart.colors(d3.scale.category10()); - expect(colorTest(chart, domain)).toEqual(['#1f77b4','#ff7f0e','#2ca02c','#d62728','#9467bd']); + chart.colors(d3.scaleOrdinal(d3.schemeCategory10)); + expect(colorTest(chart, domain)).toMatchColors(['#1f77b4','#ff7f0e','#2ca02c','#d62728','#9467bd']); }); it('ordinal', function () { chart.ordinalColors(['red','green','blue']); - expect(colorTest(chart, domain)).toEqual(['red','green','blue','red','green']); + expect(colorTest(chart, domain)).toMatchColors(['red','green','blue','red','green']); }); it('linear', function () { // GIGO: mapping ordinal domain to linear scale is nonsensical // actually it gets scaled to NaN and then d3 corrects it chart.linearColors(['#ff0000','#00ff00']); - expect(colorTest(chart, domain)).toEqual(['#000000', '#000000', '#000000', '#000000', '#000000']); + expect(colorTest(chart, domain)).toMatchColors(['#000000', '#000000', '#000000', '#000000', '#000000']); }); }); describe('with numeric domain' , function () { @@ -48,22 +48,22 @@ describe('dc.colorMixin', function () { }); it('default', function () { - expect(colorTest(chart, domain, test)).toEqual(['#9ecae1','#3182bd','#c6dbef','#6baed6','#e6550d','#3182bd']); + expect(colorTest(chart, domain, test)).toMatchColors(['#9ecae1','#3182bd','#c6dbef','#6baed6','#e6550d','#3182bd']); }); it('custom', function () { - chart.colors(d3.scale.category10()); - expect(colorTest(chart, domain, test)).toEqual(['#2ca02c', '#1f77b4', '#d62728', '#ff7f0e', '#9467bd', '#1f77b4']); + chart.colors(d3.scaleOrdinal(d3.schemeCategory10)); + expect(colorTest(chart, domain, test)).toMatchColors(['#2ca02c', '#1f77b4', '#d62728', '#ff7f0e', '#9467bd', '#1f77b4']); }); it('ordinal', function () { chart.ordinalColors(['red','green','blue']); - expect(colorTest(chart, domain, test)).toEqual(['blue', 'red', 'red', 'green', 'green', 'red']); + expect(colorTest(chart, domain, test)).toMatchColors(['blue', 'red', 'red', 'green', 'green', 'red']); }); it('linear', function () { chart.linearColors(['#4575b4','#ffffbf']); - expect(colorTest(chart, domain, test)).toEqual(['#4773b3', '#4575b4', '#4dc6c1', '#ffffbf', '#ffffc0', '#4575b4']); + expect(colorTest(chart, domain, test)).toMatchColors(['#4773b3', '#4575b4', '#4dc6c1', '#ffffbf', '#ffffc0', '#4575b4']); }); }); describe('calculateColorDomain' , function () { diff --git a/spec/composite-chart-spec.js b/spec/composite-chart-spec.js index a3b7fb488..fd482514b 100644 --- a/spec/composite-chart-spec.js +++ b/spec/composite-chart-spec.js @@ -5,7 +5,7 @@ describe('dc.compositeChart', function () { beforeEach(function () { data = crossfilter(loadDateFixture()); - dateDimension = data.dimension(function (d) { return d3.time.day.utc(d.dd); }); + dateDimension = data.dimension(function (d) { return d3.utcDay(d.dd); }); dateValueSumGroup = dateDimension.group().reduceSum(function (d) { return d.value; }); dateValueNegativeSumGroup = dateDimension.group().reduceSum(function (d) { return -d.value; }); dateIdSumGroup = dateDimension.group().reduceSum(function (d) { return d.id; }); @@ -21,9 +21,9 @@ describe('dc.compositeChart', function () { .group(dateIdSumGroup) .width(500) .height(150) - .x(d3.time.scale.utc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])) + .x(d3.scaleUtc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])) .transitionDuration(0) - .xUnits(d3.time.days.utc) + .xUnits(d3.utcDays) .shareColors(true) .compose([ dc.barChart(chart) @@ -78,7 +78,7 @@ describe('dc.compositeChart', function () { }); it('should set the x units', function () { - expect(chart.xUnits()).toBe(d3.time.days.utc); + expect(chart.xUnits()).toBe(d3.utcDays); }); it('should create the x axis', function () { @@ -98,7 +98,7 @@ describe('dc.compositeChart', function () { }); it('can change round', function () { - chart.round(d3.time.day.utc.round); + chart.round(d3.utcDay.round); expect(chart.round()).not.toBeNull(); }); @@ -156,8 +156,8 @@ describe('dc.compositeChart', function () { }); it('should index each subchart g by css class', function () { - expect(d3.select(chart.selectAll('g.sub')[0][0]).attr('class')).toBe('sub _0'); - expect(d3.select(chart.selectAll('g.sub')[0][1]).attr('class')).toBe('sub _1'); + expect(d3.select(chart.selectAll('g.sub').nodes()[0]).attr('class')).toBe('sub _0'); + expect(d3.select(chart.selectAll('g.sub').nodes()[1]).attr('class')).toBe('sub _1'); }); it('should generate sub line chart paths', function () { @@ -236,32 +236,28 @@ describe('dc.compositeChart', function () { }); it('should have a resize handle', function () { - expect(chart.selectAll('g.brush .resize path').size()).not.toBe(0); - chart.selectAll('g.brush .resize path').each(function (d, i) { + expect(chart.selectAll('g.brush path.handle--custom').size()).not.toBe(0); + chart.selectAll('g.brush path.handle--custom').each(function (d, i) { if (i === 0) { - expect(d3.select(this).attr('d')) - .toMatchPath('M0.5,36.666666666666664A6,6 0 0 1 6.5,42.666666666666664V67.33333333333333A6,' + - '6 0 0 1 0.5,73.33333333333333ZM2.5,44.666666666666664V65.33333333333333M4.5,' + - '44.666666666666664V65.33333333333333'); - } else { expect(d3.select(this).attr('d')) .toMatchPath('M-0.5,36.666666666666664A6,6 0 0 0 -6.5,42.666666666666664V67.33333333333333A6,' + - '6 0 0 0 -0.5,73.33333333333333ZM-2.5,44.666666666666664V65.33333333333333M-4.5,' + - '44.666666666666664V65.33333333333333'); + '6 0 0 0 -0.5,73.33333333333333ZM-2.5,44.666666666666664V65.33333333333333M-4.5,' + + '44.666666666666664V65.33333333333333'); + } else { + expect(d3.select(this).attr('d')) + .toMatchPath('M0.5,36.666666666666664A6,6 0 0 1 6.5,42.666666666666664V67.33333333333333A6,' + + '6 0 0 1 0.5,73.33333333333333ZM2.5,44.666666666666664V65.33333333333333M4.5,' + + '44.666666666666664V65.33333333333333'); } }); }); it('should stretch the background', function () { - expect(chart.select('g.brush rect.background').attr('width')).toBe('420'); + expect(chart.select('g.brush rect.overlay').attr('width')).toBe('420'); }); it('should set the height of background to height of chart', function () { - expect(chart.select('g.brush rect.background').attr('height')).toBe('110'); - }); - - it('should set the extent height to chart height', function () { - expect(chart.select('g.brush rect.extent').attr('height')).toBe('110'); + expect(chart.select('g.brush rect.overlay').attr('height')).toBe('110'); }); describe('when filtering the chart', function () { @@ -269,8 +265,12 @@ describe('dc.compositeChart', function () { chart.filter([makeDate(2012, 5, 1), makeDate(2012, 5, 30)]).redraw(); }); + it('should set the extent height to chart height', function () { + expect(chart.select('g.brush rect.selection').attr('height')).toBe('110'); + }); + it('should set extent width to chart width based on filter set', function () { - expect(chart.select('g.brush rect.extent').attr('width')).toBe('140'); + expect(chart.select('g.brush rect.selection').attr('width')).toBe('140'); }); it('should fade filtered bars into the background', function () { @@ -311,7 +311,7 @@ describe('dc.compositeChart', function () { it('should generate legend labels with their associated group text', function () { function legendText (n) { - return d3.select(chart.selectAll('g.dc-legend g.dc-legend-item text')[0][n]).text(); + return d3.select(chart.selectAll('g.dc-legend g.dc-legend-item text').nodes()[n]).text(); } expect(legendText(0)).toBe('Date Value Group Bar'); expect(legendText(1)).toBe('Date ID Group'); @@ -332,11 +332,11 @@ describe('dc.compositeChart', function () { }); it('should hide hidable child stacks', function () { - var dateValueGroupLine2 = d3.select(chart.selectAll('g.dc-legend g.dc-legend-item')[0][3]); + var dateValueGroupLine2 = d3.select(chart.selectAll('g.dc-legend g.dc-legend-item').nodes()[3]); dateValueGroupLine2.on('click')(dateValueGroupLine2.datum()); expect(dateValueGroupLine2.text()).toBe('Date Value Group Line 2'); - expect(d3.select(chart.selectAll('g.dc-legend g.dc-legend-item')[0][3]).classed('fadeout')).toBeTruthy(); + expect(d3.select(chart.selectAll('g.dc-legend g.dc-legend-item').nodes()[3]).classed('fadeout')).toBeTruthy(); expect(chart.selectAll('path.line').size()).toEqual(3); }); }); @@ -344,7 +344,7 @@ describe('dc.compositeChart', function () { describe('no elastic', function () { beforeEach(function () { - chart.y(d3.scale.linear().domain([-200, 200])); + chart.y(d3.scaleLinear().domain([-200, 200])); chart.render(); }); @@ -384,7 +384,7 @@ describe('dc.compositeChart', function () { }); it('should trigger the sub-chart renderlet', function () { - expect(d3.select(chart.selectAll('rect')[0][0]).attr('width')).toBe('10'); + expect(d3.select(chart.selectAll('rect').nodes()[0]).attr('width')).toBe('10'); }); }); @@ -412,7 +412,7 @@ describe('dc.compositeChart', function () { .brushOn(false) .dimension(dimension) .shareTitle(false) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .compose([ dc.lineChart(chart) @@ -547,10 +547,11 @@ describe('dc.compositeChart', function () { describe('when composing charts with just a right axis', function () { beforeEach(function () { - chart.yAxis().ticks(7); chart.compose([ dc.lineChart(chart).group(dateGroup).useRightYAxis(true) - ]).renderHorizontalGridLines(true).render(); + ]).renderHorizontalGridLines(true); + chart.rightYAxis().ticks(7); + chart.render(); }); it('should only render a right y axis', function () { @@ -683,7 +684,7 @@ describe('dc.compositeChart', function () { chart .dimension(scatterDimension) .group(scatterGroup) - .x(d3.scale.linear().domain([0,70])) + .x(d3.scaleLinear().domain([0,70])) .brushOn(true) .compose([ dc.scatterPlot(chart), @@ -697,8 +698,10 @@ describe('dc.compositeChart', function () { beforeEach(function () { otherDimension = data.dimension(function (d) { return [+d.value, +d.nvalue]; }); - chart.brush().extent([22, 35]); - chart.brush().on('brush')(); + // Setup a dummy event - just enough for the handler to get fooled + setupEventForBrushing(chart, [22, 35]); + // Directly call the handler + chart._brushing(); chart.redraw(); }); @@ -708,8 +711,10 @@ describe('dc.compositeChart', function () { describe('brush decreases in size', function () { beforeEach(function () { - chart.brush().extent([22, 33]); - chart.brush().on('brush')(); + // Setup a dummy event - just enough for the handler to get fooled + setupEventForBrushing(chart, [22, 33]); + // Directly call the handler + chart._brushing(); chart.redraw(); }); @@ -721,8 +726,10 @@ describe('dc.compositeChart', function () { describe('brush disappears', function () { beforeEach(function () { - chart.brush().extent([22, 22]); - chart.brush().on('brush')(); + // Setup a dummy event - just enough for the handler to get fooled + setupEventForBrushing(chart, [22, 22]); + // Directly call the handler + chart._brushing(); chart.redraw(); }); diff --git a/spec/coordinate-grid-chart-spec.js b/spec/coordinate-grid-chart-spec.js index 41160e53b..785e31d80 100644 --- a/spec/coordinate-grid-chart-spec.js +++ b/spec/coordinate-grid-chart-spec.js @@ -5,7 +5,7 @@ describe('dc.coordinateGridChart', function () { beforeEach(function () { data = crossfilter(loadDateFixture()); - dimension = data.dimension(function (d) { return d3.time.day.utc(d.dd); }); + dimension = data.dimension(function (d) { return d3.utcDay(d.dd); }); group = dimension.group(); id = 'coordinate-grid-chart'; @@ -20,7 +20,7 @@ describe('dc.coordinateGridChart', function () { .transitionDelay(0) .brushOn(false) .margins({top: 20, bottom: 0, right: 10, left: 0}) - .x(d3.time.scale.utc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])); + .x(d3.scaleUtc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])); }); describe('rendering', function () { @@ -108,7 +108,7 @@ describe('dc.coordinateGridChart', function () { }); it('should be able to change round', function () { - chart.round(d3.time.day.utc.round); + chart.round(d3.utcDay.round); expect(chart.round()).not.toBeNull(); }); @@ -205,7 +205,7 @@ describe('dc.coordinateGridChart', function () { .transitionDelay(0) .brushOn(false) .margins({top: 20, bottom: 0, right: 10, left: 0}) - .x(d3.time.scale.utc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])); + .x(d3.scaleUtc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])); chart.render(); }); it('should generate a valid clippath id', function () { @@ -226,7 +226,7 @@ describe('dc.coordinateGridChart', function () { .transitionDelay(0) .brushOn(false) .margins({top: 20, bottom: 0, right: 10, left: 0}) - .x(d3.time.scale.utc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])); + .x(d3.scaleUtc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])); chart.render(); }); it('should generate a valid clippath id', function () { @@ -307,6 +307,10 @@ describe('dc.coordinateGridChart', function () { describe('y-axes', function () { describe('grid lines', function () { beforeEach(function () { + // The calculations have changed internally for tick count from D3v3 to D3v4 + // By default it guesses 10 ticks and computes from there. In v3 it ends up with 7 in v4 + // it is 16. For 9 as well as 11 both the versions agree. + chart.yAxis().ticks(9); chart .renderHorizontalGridLines(true) .renderVerticalGridLines(true) @@ -314,8 +318,8 @@ describe('dc.coordinateGridChart', function () { }); describe('horizontal grid lines', function () { - it('should draw lines associated with the data shown on the right y-axis', function () { - var nthGridLine = function (n) { return d3.select(chart.selectAll('.grid-line.horizontal line')[0][n]); }; + it('should draw lines associated with the data shown on the y-axis', function () { + var nthGridLine = function (n) { return d3.select(chart.selectAll('.grid-line.horizontal line').nodes()[n]); }; expect(chart.selectAll('.grid-line.horizontal line').size()).toBe(7); expect(nthGridLine(0).attr('y2')).toBe('130'); @@ -338,7 +342,7 @@ describe('dc.coordinateGridChart', function () { }); it('should draws lines associated with the data using the custom ticks', function () { - var nthGridLine = function (n) { return d3.select(chart.selectAll('.grid-line.horizontal line')[0][n]); }; + var nthGridLine = function (n) { return d3.select(chart.selectAll('.grid-line.horizontal line').nodes()[n]); }; expect(chart.selectAll('.grid-line.horizontal line').size()).toBe(3); expect(nthGridLine(0).attr('y2')).toBe('130'); @@ -351,7 +355,7 @@ describe('dc.coordinateGridChart', function () { describe('vertical grid lines', function () { it('should draw lines associated with the data shown on the x-axis', function () { - var nthGridLine = function (n) { return d3.select(chart.selectAll('.grid-line.vertical line')[0][n]); }; + var nthGridLine = function (n) { return d3.select(chart.selectAll('.grid-line.vertical line').nodes()[n]); }; expect(chart.selectAll('.grid-line.vertical line').size()).toBe(13); expect(nthGridLine(0).attr('x2')).toBe('0'); @@ -374,7 +378,7 @@ describe('dc.coordinateGridChart', function () { }); it('should draw lines associated with the data using the custom ticks', function () { - var nthGridLine = function (n) { return d3.select(chart.selectAll('.grid-line.vertical line')[0][n]); }; + var nthGridLine = function (n) { return d3.select(chart.selectAll('.grid-line.vertical line').nodes()[n]); }; expect(chart.selectAll('.grid-line.vertical line').size()).toBe(3); expect(nthGridLine(0).attr('x2')).toBeWithinDelta(6, 1); @@ -386,7 +390,7 @@ describe('dc.coordinateGridChart', function () { describe('with an ordinal x axis', function () { beforeEach(function () { - chart.x(d3.scale.ordinal()) + chart.x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .render(); }); @@ -406,9 +410,10 @@ describe('dc.coordinateGridChart', function () { expect(chart.selectAll('.axis.y').size()).toBe(1); }); - it('should orient the y-axis text to the left by default', function () { + // No longer valid in D3v4 + /*it('should orient the y-axis text to the left by default', function () { expect(chart.yAxis().orient()).toBe('left'); - }); + });*/ it('should place the y axis to the left', function () { expect(chart.select('g.y').attr('transform')).toMatchTranslate(0, 20); @@ -453,9 +458,10 @@ describe('dc.coordinateGridChart', function () { expect(chart.selectAll('.axis.y').size()).toBe(1); }); - it('should orient the y-axis text to the right', function () { + // Not applicable in D3v4 + /*it('should orient the y-axis text to the right', function () { expect(chart.yAxis().orient()).toBe('right'); - }); + });*/ it('should position the axis to the right of the chart', function () { expect(chart.select('.axis.y').attr('transform')).toMatchTranslate(490, 20); @@ -587,7 +593,7 @@ describe('dc.coordinateGridChart', function () { describe('setting x', function () { var newDomain = [1,10]; beforeEach(function () { - chart.x(d3.scale.linear().domain(newDomain)); + chart.x(d3.scaleLinear().domain(newDomain)); }); it('should reset the original x domain', function () { @@ -638,8 +644,12 @@ describe('dc.coordinateGridChart', function () { chart.filter(filter); }); - it('should update the brush extent', function () { - expect(chart.brush().extent()).toEqual(filter); + it('should update the brush selection', function () { + // expect(chart.getBrushSelection()).toEqual(filter); + var brushSelectionRect = chart.select('g.brush rect.selection'); + expect(brushSelectionRect.attr('x')).toBeCloseTo(chart.x()(filter[0]), 1); + expect(+brushSelectionRect.attr('x') + +brushSelectionRect.attr('width')) + .toBeCloseTo(chart.x()(filter[1]), 1); }); }); @@ -647,12 +657,16 @@ describe('dc.coordinateGridChart', function () { beforeEach(function () { chart.brushOn(true); chart.render(); - chart.brush().extent([makeDate(2012, 5, 20), makeDate(2012, 6, 15)]); + // Setup a dummy event - just enough for the handler to get fooled + setupEventForBrushing(chart, [makeDate(2012, 5, 20), makeDate(2012, 6, 15)]); + // Directly call the handler + chart._brushing(); chart.filter(null); }); - it('should clear the brush extent', function () { - expect(chart.brush().empty()).toBeTruthy(); + it('should clear the brush selection', function () { + var brushSelectionRect = chart.select('g.brush rect.selection'); + expect(+brushSelectionRect.attr('width')).toEqual(0); }); }); @@ -790,50 +804,19 @@ describe('dc.coordinateGridChart', function () { describe('brushing', function () { beforeEach(function () { chart.brushOn(true); - }); - - describe('with mouse zoom enabled', function () { - beforeEach(function () { - spyOn(chart, '_disableMouseZoom'); - spyOn(chart, '_enableMouseZoom'); - chart.mouseZoomable(true); - chart.render(); - chart.brush().extent([makeDate(2012, 6, 1), makeDate(2012, 6, 15)]); - chart.brush().event(chart.root()); - }); - - it('should disable mouse zooming on brush start, and re-enables it afterwards', function () { - chart.brush().extent([makeDate(2012, 6, 1), makeDate(2012, 6, 15)]); - chart.brush().event(chart.root()); - expect(chart._disableMouseZoom).toHaveBeenCalled(); - expect(chart._enableMouseZoom).toHaveBeenCalled(); - }); - }); - - describe('with mouse zoom disabled', function () { - beforeEach(function () { - spyOn(chart, '_enableMouseZoom'); - chart.mouseZoomable(false); - chart.render(); - chart.brush().extent([makeDate(2012, 6, 1), makeDate(2012, 6, 15)]); - chart.brush().event(chart.root()); - }); - - it('should not enable mouse zooming', function () { - expect(chart._enableMouseZoom).not.toHaveBeenCalled(); - }); + chart.render(); }); describe('with equal dates', function () { beforeEach(function () { - spyOn(chart, 'filter'); - chart.brush().clear(); - chart.render(); - chart.brush().event(chart.root()); + // Setup a dummy event - just enough for the handler to get fooled + setupEventForBrushing(chart, [22, 22]); + // Directly call the handler + chart._brushing(); }); it('should clear the chart filter', function () { - expect(chart.filter()).toEqual(undefined); + expect(chart.filter()).toBeFalsy(); }); }); }); @@ -851,17 +834,20 @@ describe('dc.coordinateGridChart', function () { it('should zoom the focus chart when range chart is brushed', function () { spyOn(chart, 'focus').and.callThrough(); - rangeChart.brush().extent(selectedRange); - rangeChart.brush().event(rangeChart.g()); + // Setup a dummy event - just enough for the handler to get fooled + setupEventForBrushing(rangeChart, selectedRange); + // Directly call the handler + rangeChart._brushing(); jasmine.clock().tick(100); - // expect(chart.focus).toHaveBeenCalledWith(selectedRange); var focus = cleanDateRange(chart.focus.calls.argsFor(0)[0]); expect(focus).toEqual(selectedRange); }); it('should zoom the focus chart back out when range chart is un-brushed', function () { - rangeChart.brush().extent(selectedRange); - rangeChart.brush().event(rangeChart.g()); + // Setup a dummy event - just enough for the handler to get fooled + setupEventForBrushing(rangeChart, selectedRange); + // Directly call the handler + rangeChart._brushing(); jasmine.clock().tick(100); expect(chart.x().domain()).toEqual(selectedRange); @@ -956,7 +942,7 @@ describe('dc.coordinateGridChart', function () { return dc.lineChart('#' + rangeId) .dimension(dimension) .group(dimension.group().reduceSum(function (d) { return d.id; })) - .x(d3.time.scale.utc().domain([makeDate(2012, 5, 20), makeDate(2012, 6, 15)])); + .x(d3.scaleUtc().domain([makeDate(2012, 5, 20), makeDate(2012, 6, 15)])); } function doubleClick (chart) { diff --git a/spec/data-addition-spec.js b/spec/data-addition-spec.js index 1b6e618e7..ed84d206c 100644 --- a/spec/data-addition-spec.js +++ b/spec/data-addition-spec.js @@ -48,14 +48,14 @@ describe('Dynamic data addition in crossfilter', function () { expect(chart.selectAll('svg g g.pie-slice path').data().length).toEqual(7); }); it('default function should be used to dynamically generate label', function () { - expect(d3.select(chart.selectAll('text.pie-slice')[0][0]).text()).toEqual('11'); + expect(d3.select(chart.selectAll('text.pie-slice').nodes()[0]).text()).toEqual('11'); }); it('pie chart slices should be in numerical order', function () { expect(chart.selectAll('text.pie-slice').data().map(function (slice) { return slice.data.key; })) .toEqual(['11','22','33','44','55','66','76']); }); it('default function should be used to dynamically generate title', function () { - expect(d3.select(chart.selectAll('g.pie-slice title')[0][0]).text()).toEqual('11: 1'); + expect(d3.select(chart.selectAll('g.pie-slice title').nodes()[0]).text()).toEqual('11: 1'); }); afterEach(function () { valueDimension.filterAll(); @@ -69,9 +69,9 @@ describe('Dynamic data addition in crossfilter', function () { var chart = dc.lineChart('#' + id); chart.dimension(timeDimension).group(timeGroup) .width(width).height(height) - .x(d3.time.scale.utc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])) + .x(d3.scaleUtc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])) .transitionDuration(0) - .xUnits(d3.time.days.utc) + .xUnits(d3.utcDays) .brushOn(false) .renderArea(true) .renderTitle(true); @@ -89,7 +89,7 @@ describe('Dynamic data addition in crossfilter', function () { chart.render(); }); it('number of dots should equal the size of the group', function () { - expect(chart.selectAll('circle.dot')[0].length).toEqual(timeGroup.size()); + expect(chart.selectAll('circle.dot').nodes().length).toEqual(timeGroup.size()); }); it('number of line segments should equal the size of the group', function () { var path = chart.selectAll('path.line').attr('d'); diff --git a/spec/data-count-spec.js b/spec/data-count-spec.js index bff0d789d..8603bf5bf 100644 --- a/spec/data-count-spec.js +++ b/spec/data-count-spec.js @@ -16,7 +16,7 @@ describe('dc.dataCount', function () { .dimension(data) .group(groupAll); chart.render(); - d3.timer.flush(); + d3.timerFlush(); return chart; } describe('creation', function () { diff --git a/spec/data-grid-spec.js b/spec/data-grid-spec.js index 759fa73cd..a12fb3b53 100644 --- a/spec/data-grid-spec.js +++ b/spec/data-grid-spec.js @@ -9,7 +9,7 @@ describe('dc.dataGrid', function () { dateFixture = loadDateFixture(); data = crossfilter(dateFixture); dimension = data.dimension(function (d) { - return d3.time.day.utc(d.dd); + return d3.utcDay(d.dd); }); countryDimension = data.dimension(function (d) { return d.countrycode; @@ -49,17 +49,17 @@ describe('dc.dataGrid', function () { expect(chart.order()).toBe(d3.descending); }); it('sets the group label', function () { - expect(chart.selectAll('.dc-grid-group h1.dc-grid-label')[0][0].innerHTML).toEqual('Data Grid'); + expect(chart.selectAll('.dc-grid-group h1.dc-grid-label').nodes()[0].innerHTML).toEqual('Data Grid'); }); it('creates id div', function () { - expect(chart.selectAll('.dc-grid-item div#id_9')[0].length).toEqual(1); - expect(chart.selectAll('.dc-grid-item div#id_8')[0].length).toEqual(1); - expect(chart.selectAll('.dc-grid-item div#id_3')[0].length).toEqual(1); + expect(chart.selectAll('.dc-grid-item div#id_9').nodes().length).toEqual(1); + expect(chart.selectAll('.dc-grid-item div#id_8').nodes().length).toEqual(1); + expect(chart.selectAll('.dc-grid-item div#id_3').nodes().length).toEqual(1); }); it('creates div content', function () { - expect(chart.selectAll('.dc-grid-item div')[0][0].innerHTML).toEqual('Mississippi:44'); - expect(chart.selectAll('.dc-grid-item div')[0][1].innerHTML).toEqual('Mississippi:33'); - expect(chart.selectAll('.dc-grid-item div')[0][2].innerHTML).toEqual('Delaware:33'); + expect(chart.selectAll('.dc-grid-item div').nodes()[0].innerHTML).toEqual('Mississippi:44'); + expect(chart.selectAll('.dc-grid-item div').nodes()[1].innerHTML).toEqual('Mississippi:33'); + expect(chart.selectAll('.dc-grid-item div').nodes()[2].innerHTML).toEqual('Delaware:33'); }); }); @@ -70,14 +70,14 @@ describe('dc.dataGrid', function () { }); it('slice beginning', function () { - expect(chart.selectAll('.dc-grid-item')[0].length).toEqual(2); + expect(chart.selectAll('.dc-grid-item').nodes().length).toEqual(2); }); it('slice beginning and end', function () { chart.endSlice(2); chart.redraw(); - expect(chart.selectAll('.dc-grid-item')[0].length).toEqual(1); + expect(chart.selectAll('.dc-grid-item').nodes().length).toEqual(1); }); }); @@ -87,11 +87,11 @@ describe('dc.dataGrid', function () { chart.redraw(); }); it('renders only filtered data set', function () { - expect(chart.selectAll('.dc-grid-item div')[0].length).toEqual(2); + expect(chart.selectAll('.dc-grid-item div').nodes().length).toEqual(2); }); it('renders the correctly filtered records', function () { - expect(chart.selectAll('.dc-grid-item div')[0][0].innerHTML).toEqual('Ontario:22'); - expect(chart.selectAll('.dc-grid-item div')[0][1].innerHTML).toEqual('Ontario:55'); + expect(chart.selectAll('.dc-grid-item div').nodes()[0].innerHTML).toEqual('Ontario:22'); + expect(chart.selectAll('.dc-grid-item div').nodes()[1].innerHTML).toEqual('Ontario:55'); }); }); diff --git a/spec/data-table-spec.js b/spec/data-table-spec.js index 9b7eb5232..9634c1424 100644 --- a/spec/data-table-spec.js +++ b/spec/data-table-spec.js @@ -10,7 +10,7 @@ describe('dc.dataTable', function () { dateFixture = loadDateFixture(); data = crossfilter(dateFixture); dimension = data.dimension(function (d) { - return d3.time.day.utc(d.dd); + return d3.utcDay(d.dd); }); countryDimension = data.dimension(function (d) { return d.countrycode; @@ -62,20 +62,20 @@ describe('dc.dataTable', function () { expect(chart.group()).toEqual(valueGroup); }); it('group tr should not be undefined', function () { - expect(typeof(chart.selectAll('tr.dc-table-group')[0][0])).not.toBe('undefined'); + expect(typeof(chart.selectAll('tr.dc-table-group').nodes()[0])).not.toBe('undefined'); }); it('sets column span set on group tr', function () { - expect(chart.selectAll('tr.dc-table-group td')[0][0].getAttribute('colspan')).toEqual('2'); + expect(chart.selectAll('tr.dc-table-group td').nodes()[0].getAttribute('colspan')).toEqual('2'); }); it('creates id column', function () { - expect(chart.selectAll('td._0')[0][0].innerHTML).toEqual('9'); - expect(chart.selectAll('td._0')[0][1].innerHTML).toEqual('8'); - expect(chart.selectAll('td._0')[0][2].innerHTML).toEqual('3'); + expect(chart.selectAll('td._0').nodes()[0].innerHTML).toEqual('9'); + expect(chart.selectAll('td._0').nodes()[1].innerHTML).toEqual('8'); + expect(chart.selectAll('td._0').nodes()[2].innerHTML).toEqual('3'); }); it('creates status column', function () { - expect(chart.selectAll('td._1')[0][0].innerHTML).toEqual('T'); - expect(chart.selectAll('td._1')[0][1].innerHTML).toEqual('F'); - expect(chart.selectAll('td._1')[0][2].innerHTML).toEqual('T'); + expect(chart.selectAll('td._1').nodes()[0].innerHTML).toEqual('T'); + expect(chart.selectAll('td._1').nodes()[1].innerHTML).toEqual('F'); + expect(chart.selectAll('td._1').nodes()[2].innerHTML).toEqual('T'); }); }); @@ -86,14 +86,14 @@ describe('dc.dataTable', function () { }); it('slice beginning', function () { - expect(chart.selectAll('tr.dc-table-row')[0].length).toEqual(2); + expect(chart.selectAll('tr.dc-table-row').nodes().length).toEqual(2); }); it('slice beginning and end', function () { chart.endSlice(2); chart.redraw(); - expect(chart.selectAll('tr.dc-table-row')[0].length).toEqual(1); + expect(chart.selectAll('tr.dc-table-row').nodes().length).toEqual(1); }); }); @@ -103,11 +103,11 @@ describe('dc.dataTable', function () { chart.redraw(); }); it('renders only filtered data set', function () { - expect(chart.selectAll('td._0')[0].length).toEqual(2); + expect(chart.selectAll('td._0').nodes().length).toEqual(2); }); it('renders the correctly filtered records', function () { - expect(chart.selectAll('td._0')[0][0].innerHTML).toEqual('7'); - expect(chart.selectAll('td._0')[0][1].innerHTML).toEqual('5'); + expect(chart.selectAll('td._0').nodes()[0].innerHTML).toEqual('7'); + expect(chart.selectAll('td._0').nodes()[1].innerHTML).toEqual('5'); }); }); @@ -117,7 +117,7 @@ describe('dc.dataTable', function () { chart.redraw(); }); it('uses dimension.bottom() instead of top()', function () { - expect(chart.selectAll('td._0')[0][0].innerHTML).toEqual('1'); + expect(chart.selectAll('td._0').nodes()[0].innerHTML).toEqual('1'); }); }); }); @@ -149,13 +149,13 @@ describe('dc.dataTable', function () { chart.render(); }); it('should render value and capitalized header', function () { - var cols = chart.selectAll('td.dc-table-column')[0].map(function (d) {return d.textContent;}); + var cols = chart.selectAll('td.dc-table-column').nodes().map(function (d) {return d.textContent;}); var expected = ['Mississippi', 'Mississippi', 'Delaware']; expect(cols.length).toEqual(expected.length); expected.forEach(function (d) { expect(cols).toContain(d); }); - var colheader = chart.selectAll('th.dc-table-head')[0].map(function (d) {return d.textContent;}); + var colheader = chart.selectAll('th.dc-table-head').nodes().map(function (d) {return d.textContent;}); expect(colheader.length).toEqual(1); expect(colheader[0]).toEqual('State'); @@ -167,13 +167,13 @@ describe('dc.dataTable', function () { chart.render(); }); it('should render function result and no header', function () { - var cols = chart.selectAll('td.dc-table-column')[0].map(function (d) {return d.textContent;}); + var cols = chart.selectAll('td.dc-table-column').nodes().map(function (d) {return d.textContent;}); var expected = ['9test', '8test', '3test']; expect(cols.length).toEqual(expected.length); expected.forEach(function (d) { expect(cols).toContain(d); }); - var colheader = chart.selectAll('th.dc-table-head')[0].map(function (d) {return d.textContent;}); + var colheader = chart.selectAll('th.dc-table-head').nodes().map(function (d) {return d.textContent;}); expect(colheader.length).toEqual(0); }); }); @@ -189,16 +189,16 @@ describe('dc.dataTable', function () { }); it('should produce correct table header with single column', function () { var thead = chart.selectAll('thead'); - expect(thead.length).toBe(1); + expect(thead.nodes().length).toBe(1); var tr = thead.selectAll('tr'); - expect(tr.length).toBe(1); - var colheader = tr.selectAll('th.dc-table-head')[0].map(function (d) {return d.textContent;}); + expect(tr.nodes().length).toBe(1); + var colheader = tr.selectAll('th.dc-table-head').nodes().map(function (d) {return d.textContent;}); expect(colheader.length).toEqual(1); expect(colheader[0]).toEqual('Test ID'); }); it('should render correct values in rows', function () { - var cols = chart.selectAll('td.dc-table-column')[0].map(function (d) {return d.textContent;}); + var cols = chart.selectAll('td.dc-table-column').nodes().map(function (d) {return d.textContent;}); var expected = ['test9', 'test8', 'test3']; expect(cols.length).toEqual(expected.length); expected.forEach(function (d, i) { @@ -224,10 +224,10 @@ describe('dc.dataTable', function () { }); it('should produce correct table header with single column', function () { var thead = chart.selectAll('thead'); - expect(thead.length).toBe(1); + expect(thead.nodes().length).toBe(1); var tr = thead.selectAll('tr'); - expect(tr.length).toBe(1); - var colheader = tr.selectAll('th.dc-table-head')[0].map(function (d) {return d.textContent;}); + expect(tr.nodes().length).toBe(1); + var colheader = tr.selectAll('th.dc-table-head').nodes().map(function (d) {return d.textContent;}); expect(colheader.length).toEqual(1); expect(colheader[0]).toEqual('Test ID'); }); @@ -239,7 +239,7 @@ describe('dc.dataTable', function () { chart.render(); }); it('group tr should be undefined', function () { - expect(typeof(chart.selectAll('tr.dc-table-group')[0][0])).toBe('undefined'); + expect(typeof(chart.selectAll('tr.dc-table-group').nodes()[0])).toBe('undefined'); }); }); diff --git a/spec/geo-choropleth-chart-spec.js b/spec/geo-choropleth-chart-spec.js index 4d23a04d6..7dc3f53db 100644 --- a/spec/geo-choropleth-chart-spec.js +++ b/spec/geo-choropleth-chart-spec.js @@ -52,7 +52,7 @@ describe('dc.geoChoropleth', function () { var chart = dc.geoChoroplethChart('#' + id); chart.dimension(districtDimension) .group(districtValueEnrollGroup) - .projection(d3.geo.mercator() + .projection(d3.geoMercator() .scale(26778) .translate([8227, 3207])) .width(990) @@ -79,7 +79,7 @@ describe('dc.geoChoropleth', function () { it('should return not null', function () { expect(chart).not.toBeNull(); }); - it('should have a d3.geo.path', function () { + it('should have a d3.geoPath', function () { expect(chart.geoPath()).not.toBeNull(); }); it('svg is created', function () { @@ -89,64 +89,64 @@ describe('dc.geoChoropleth', function () { expect(chart.selectAll('g.layer0').length).not.toEqual(0); }); it('correct number of states should be generated', function () { - expect(chart.selectAll('g.layer0 g.state')[0].length).toEqual(52); + expect(chart.selectAll('g.layer0 g.state').nodes().length).toEqual(52); }); it('correct css class should be set [Alaska]', function () { - expect(chart.selectAll('g.layer0 g.state')[0][1].getAttribute('class')).toEqual('state alaska'); + expect(chart.selectAll('g.layer0 g.state').nodes()[1].getAttribute('class')).toEqual('state alaska'); }); it('correct title should be set [Alaska]', function () { - expect(chart.selectAll('g.layer0 g.state title')[0][1].textContent).toEqual('Alaska : 0'); + expect(chart.selectAll('g.layer0 g.state title').nodes()[1].textContent).toEqual('Alaska : 0'); }); it('correct color filling should be set [Alaska]', function () { - expect(chart.selectAll('g.layer0 g.state path')[0][1].getAttribute('fill')).toMatch(/#ccc/i); + expect(chart.selectAll('g.layer0 g.state path').nodes()[1].getAttribute('fill')).toMatch(/#ccc/i); }); it('correct state boundary should be rendered [Alaska]', function () { - expect(chart.selectAll('g.layer0 g.state path')[0][1].getAttribute('d').length).not.toEqual(0); + expect(chart.selectAll('g.layer0 g.state path').nodes()[1].getAttribute('d').length).not.toEqual(0); }); it('correct css class should be set [California]', function () { - expect(chart.selectAll('g.layer0 g.state')[0][4].getAttribute('class')).toEqual('state california'); + expect(chart.selectAll('g.layer0 g.state').nodes()[4].getAttribute('class')).toEqual('state california'); }); it('correct css class should be set [District of Columbia]', function () { - expect(chart.selectAll('g.layer0 g.state')[0][8].getAttribute('class')).toEqual('state district_of_columbia'); + expect(chart.selectAll('g.layer0 g.state').nodes()[8].getAttribute('class')).toEqual('state district_of_columbia'); }); it('correct title should be set [California]', function () { - expect(chart.selectAll('g.layer0 g.state title')[0][4].textContent).toEqual('California : 154'); + expect(chart.selectAll('g.layer0 g.state title').nodes()[4].textContent).toEqual('California : 154'); }); it('correct color should be set [California]', function () { - expect(chart.selectAll('g.layer0 g.state path')[0][4].getAttribute('fill')).toMatch(/#0089ff/i); + expect(chart.selectAll('g.layer0 g.state path').nodes()[4].getAttribute('fill')).toMatch(/#0089ff/i); }); it('correct state boundary should be rendered [California]', function () { - expect(chart.selectAll('g.layer0 g.state path')[0][4].getAttribute('d').length).not.toEqual(0); + expect(chart.selectAll('g.layer0 g.state path').nodes()[4].getAttribute('d').length).not.toEqual(0); }); it('correct css class should be set [Colorado]', function () { - expect(chart.selectAll('g.layer0 g.state')[0][5].getAttribute('class')).toEqual('state colorado'); + expect(chart.selectAll('g.layer0 g.state').nodes()[5].getAttribute('class')).toEqual('state colorado'); }); it('correct title should be set [Colorado]', function () { - expect(chart.selectAll('g.layer0 g.state title')[0][5].textContent).toEqual('Colorado : 22'); + expect(chart.selectAll('g.layer0 g.state title').nodes()[5].textContent).toEqual('Colorado : 22'); }); it('correct color should be set [Colorado]', function () { - expect(chart.selectAll('g.layer0 g.state path')[0][5].getAttribute('fill')).toMatch(/#e2f2ff/i); + expect(chart.selectAll('g.layer0 g.state path').nodes()[5].getAttribute('fill')).toMatch(/#e2f2ff/i); }); it('correct state boundary should be rendered [Colorado]', function () { - expect(chart.selectAll('g.layer0 g.state path')[0][5].getAttribute('d').length).not.toEqual(0); + expect(chart.selectAll('g.layer0 g.state path').nodes()[5].getAttribute('d').length).not.toEqual(0); }); it('geo layer1 g is created', function () { expect(chart.selectAll('g.layer1').length).not.toEqual(0); }); it('correct number of counties should be generated', function () { - expect(chart.selectAll('g.layer1 g.county')[0].length).toEqual(5); + expect(chart.selectAll('g.layer1 g.county').nodes().length).toEqual(5); }); it('correct css class should be set [county]', function () { - expect(chart.selectAll('g.layer1 g.county')[0][1].getAttribute('class')).toEqual('county'); + expect(chart.selectAll('g.layer1 g.county').nodes()[1].getAttribute('class')).toEqual('county'); }); it('correct title should be set [county]', function () { - expect(chart.selectAll('g.layer1 g.county title')[0][1].textContent).toEqual(''); + expect(chart.selectAll('g.layer1 g.county title').nodes()[1].textContent).toEqual(''); }); it('correct color filling should be set [county]', function () { - expect(chart.selectAll('g.layer1 g.county path')[0][1].getAttribute('fill')).toEqual('white'); + expect(chart.selectAll('g.layer1 g.county path').nodes()[1].getAttribute('fill')).toEqual('white'); }); it('correct state boundary should be rendered [county]', function () { - expect(chart.selectAll('g.layer1 g.county path')[0][1].getAttribute('d').length).not.toEqual(0); + expect(chart.selectAll('g.layer1 g.county path').nodes()[1].getAttribute('d').length).not.toEqual(0); }); }); @@ -160,12 +160,12 @@ describe('dc.geoChoropleth', function () { }); it('sets deselected classes for some states', function () { - expect(chart.selectAll('g.layer0 g.state')[0][0].getAttribute('class')).toEqual('state alabama deselected'); - expect(chart.selectAll('g.layer0 g.state')[0][1].getAttribute('class')).toEqual('state alaska deselected'); + expect(chart.selectAll('g.layer0 g.state').nodes()[0].getAttribute('class')).toEqual('state alabama deselected'); + expect(chart.selectAll('g.layer0 g.state').nodes()[1].getAttribute('class')).toEqual('state alaska deselected'); }); it('sets selected classes for selected states', function () { - expect(chart.selectAll('g.layer0 g.state')[0][4].getAttribute('class')).toEqual('state california selected'); - expect(chart.selectAll('g.layer0 g.state')[0][5].getAttribute('class')).toEqual('state colorado selected'); + expect(chart.selectAll('g.layer0 g.state').nodes()[4].getAttribute('class')).toEqual('state california selected'); + expect(chart.selectAll('g.layer0 g.state').nodes()[5].getAttribute('class')).toEqual('state colorado selected'); }); }); diff --git a/spec/heatmap-spec.js b/spec/heatmap-spec.js index aa4a626b9..d409f6576 100644 --- a/spec/heatmap-spec.js +++ b/spec/heatmap-spec.js @@ -46,26 +46,26 @@ describe('dc.heatmap', function () { it('should position the heatboxes in a matrix', function () { var heatBoxes = chart.selectAll('rect.heat-box'); - expect(+heatBoxes[0][0].getAttribute('x')).toEqual(0); - expect(+heatBoxes[0][0].getAttribute('y')).toEqual(100); + expect(+heatBoxes.nodes()[0].getAttribute('x')).toEqual(0); + expect(+heatBoxes.nodes()[0].getAttribute('y')).toEqual(100); - expect(+heatBoxes[0][1].getAttribute('x')).toEqual(0); - expect(+heatBoxes[0][1].getAttribute('y')).toEqual(0); + expect(+heatBoxes.nodes()[1].getAttribute('x')).toEqual(0); + expect(+heatBoxes.nodes()[1].getAttribute('y')).toEqual(0); - expect(+heatBoxes[0][2].getAttribute('x')).toEqual(100); - expect(+heatBoxes[0][2].getAttribute('y')).toEqual(100); + expect(+heatBoxes.nodes()[2].getAttribute('x')).toEqual(100); + expect(+heatBoxes.nodes()[2].getAttribute('y')).toEqual(100); - expect(+heatBoxes[0][3].getAttribute('x')).toEqual(100); - expect(+heatBoxes[0][3].getAttribute('y')).toEqual(0); + expect(+heatBoxes.nodes()[3].getAttribute('x')).toEqual(100); + expect(+heatBoxes.nodes()[3].getAttribute('y')).toEqual(0); }); it('should color heatboxes using the provided color option', function () { var heatBoxes = chart.selectAll('rect.heat-box'); - expect(heatBoxes[0][0].getAttribute('fill')).toMatch(/#000001/i); - expect(heatBoxes[0][1].getAttribute('fill')).toMatch(/#000002/i); - expect(heatBoxes[0][2].getAttribute('fill')).toMatch(/#000003/i); - expect(heatBoxes[0][3].getAttribute('fill')).toMatch(/#000004/i); + expect(heatBoxes.nodes()[0].getAttribute('fill')).toMatch(/#000001/i); + expect(heatBoxes.nodes()[1].getAttribute('fill')).toMatch(/#000002/i); + expect(heatBoxes.nodes()[2].getAttribute('fill')).toMatch(/#000003/i); + expect(heatBoxes.nodes()[3].getAttribute('fill')).toMatch(/#000004/i); }); it('should size heatboxes based on the size of the matrix', function () { @@ -77,30 +77,30 @@ describe('dc.heatmap', function () { it('should position the y-axis labels with their associated rows', function () { var yaxisTexts = chart.selectAll('.rows.axis text'); - expect(+yaxisTexts[0][0].getAttribute('y')).toEqual(150); - expect(+yaxisTexts[0][0].getAttribute('x')).toEqual(0); - expect(+yaxisTexts[0][1].getAttribute('y')).toEqual(50); - expect(+yaxisTexts[0][1].getAttribute('x')).toEqual(0); + expect(+yaxisTexts.nodes()[0].getAttribute('y')).toEqual(150); + expect(+yaxisTexts.nodes()[0].getAttribute('x')).toEqual(0); + expect(+yaxisTexts.nodes()[1].getAttribute('y')).toEqual(50); + expect(+yaxisTexts.nodes()[1].getAttribute('x')).toEqual(0); }); it('should have labels on the y-axis corresponding to the row values', function () { var yaxisTexts = chart.selectAll('.rows.axis text'); - expect(yaxisTexts[0][0].textContent).toEqual('1'); - expect(yaxisTexts[0][1].textContent).toEqual('2'); + expect(yaxisTexts.nodes()[0].textContent).toEqual('1'); + expect(yaxisTexts.nodes()[1].textContent).toEqual('2'); }); it('should position the x-axis labels with their associated columns', function () { var xaxisTexts = chart.selectAll('.cols.axis text'); - expect(+xaxisTexts[0][0].getAttribute('y')).toEqual(200); - expect(+xaxisTexts[0][0].getAttribute('x')).toEqual(50); - expect(+xaxisTexts[0][1].getAttribute('y')).toEqual(200); - expect(+xaxisTexts[0][1].getAttribute('x')).toEqual(150); + expect(+xaxisTexts.nodes()[0].getAttribute('y')).toEqual(200); + expect(+xaxisTexts.nodes()[0].getAttribute('x')).toEqual(50); + expect(+xaxisTexts.nodes()[1].getAttribute('y')).toEqual(200); + expect(+xaxisTexts.nodes()[1].getAttribute('x')).toEqual(150); }); it('should have labels on the x-axis corresponding to the row values', function () { var xaxisTexts = chart.selectAll('.cols.axis text'); - expect(xaxisTexts[0][0].textContent).toEqual('1'); - expect(xaxisTexts[0][1].textContent).toEqual('2'); + expect(xaxisTexts.nodes()[0].textContent).toEqual('1'); + expect(xaxisTexts.nodes()[1].textContent).toEqual('2'); }); describe('with custom labels', function () { @@ -111,13 +111,13 @@ describe('dc.heatmap', function () { }); it('should display the custom labels on the x axis', function () { var xaxisTexts = chart.selectAll('.cols.axis text'); - expect(xaxisTexts[0][0].textContent).toEqual('col 1'); - expect(xaxisTexts[0][1].textContent).toEqual('col 2'); + expect(xaxisTexts.nodes()[0].textContent).toEqual('col 1'); + expect(xaxisTexts.nodes()[1].textContent).toEqual('col 2'); }); it('should display the custom labels on the y axis', function () { var yaxisTexts = chart.selectAll('.rows.axis text'); - expect(yaxisTexts[0][0].textContent).toEqual('row 1'); - expect(yaxisTexts[0][1].textContent).toEqual('row 2'); + expect(yaxisTexts.nodes()[0].textContent).toEqual('row 1'); + expect(yaxisTexts.nodes()[1].textContent).toEqual('row 2'); }); }); @@ -164,32 +164,32 @@ describe('dc.heatmap', function () { it('should only have 1 row on the y axis', function () { var yaxisTexts = chart.selectAll('.rows.axis text'); - expect(yaxisTexts[0].length).toEqual(1); - expect(yaxisTexts[0][0].textContent).toEqual('1'); + expect(yaxisTexts.nodes().length).toEqual(1); + expect(yaxisTexts.nodes()[0].textContent).toEqual('1'); }); it('should only have 1 col on the x axis', function () { var xaxisTexts = chart.selectAll('.cols.axis text'); - expect(xaxisTexts[0].length).toEqual(1); - expect(xaxisTexts[0][0].textContent).toEqual('1'); + expect(xaxisTexts.nodes().length).toEqual(1); + expect(xaxisTexts.nodes()[0].textContent).toEqual('1'); }); it('should reset the rows to using the chart data on the y axis', function () { chart.rows(null); chart.redraw(); var yaxisTexts = chart.selectAll('.rows.axis text'); - expect(yaxisTexts[0].length).toEqual(2); - expect(yaxisTexts[0][0].textContent).toEqual('1'); - expect(yaxisTexts[0][1].textContent).toEqual('2'); + expect(yaxisTexts.nodes().length).toEqual(2); + expect(yaxisTexts.nodes()[0].textContent).toEqual('1'); + expect(yaxisTexts.nodes()[1].textContent).toEqual('2'); }); it('should reset the cols to using the chart data on the y axis', function () { chart.cols(null); chart.redraw(); var xaxisTexts = chart.selectAll('.cols.axis text'); - expect(xaxisTexts[0].length).toEqual(2); - expect(xaxisTexts[0][0].textContent).toEqual('1'); - expect(xaxisTexts[0][1].textContent).toEqual('2'); + expect(xaxisTexts.nodes().length).toEqual(2); + expect(xaxisTexts.nodes()[0].textContent).toEqual('1'); + expect(xaxisTexts.nodes()[1].textContent).toEqual('2'); }); }); @@ -202,14 +202,14 @@ describe('dc.heatmap', function () { it('should have descending rows', function () { var yaxisTexts = chart.selectAll('.rows.axis text'); - expect(yaxisTexts[0][0].textContent).toEqual('2'); - expect(yaxisTexts[0][1].textContent).toEqual('1'); + expect(yaxisTexts.nodes()[0].textContent).toEqual('2'); + expect(yaxisTexts.nodes()[1].textContent).toEqual('1'); }); it('should have descending cols', function () { var yaxisTexts = chart.selectAll('.rows.axis text'); - expect(yaxisTexts[0][0].textContent).toEqual('2'); - expect(yaxisTexts[0][1].textContent).toEqual('1'); + expect(yaxisTexts.nodes()[0].textContent).toEqual('2'); + expect(yaxisTexts.nodes()[1].textContent).toEqual('1'); }); }); @@ -371,8 +371,8 @@ describe('dc.heatmap', function () { }); describe('with one cell on that axis already filtered', function () { it('should filter all cells on that axis (and the original cell should remain filtered)', function () { - var boxes = chart.selectAll('.box-group'); - var box = d3.select(boxes[0][Math.floor(Math.random() * boxes.length)]); + var boxNodes = chart.selectAll('.box-group').nodes(); + var box = d3.select(boxNodes[Math.floor(Math.random() * boxNodes.length)]); box.select('rect').on('click')(box.datum()); @@ -495,16 +495,16 @@ describe('dc.heatmap', function () { .width(400) .height(400) .transitionDuration(0) - .x(d3.scale.linear()).xAxisPadding(0.5) - .y(d3.scale.linear()).yAxisPadding(0.5) + .x(d3.scaleLinear()).xAxisPadding(0.5) + .y(d3.scaleLinear()).yAxisPadding(0.5) .elasticX(true) .elasticY(true) .label(d3.functor('')) .keyAccessor(key_part(0)) .valueAccessor(key_part(1)) - .r(d3.scale.linear().domain([0,20]).range([4,25])) + .r(d3.scaleLinear().domain([0,20]).range([4,25])) .radiusValueAccessor(function (kv) { return kv.value.total; }) - .colors(d3.scale.ordinal() + .colors(d3.scaleOrdinal() .domain(species.concat('none')) .range(['#e41a1c','#377eb8','#4daf4a', '#f8f8f8'])) .colorAccessor(function (d) { @@ -518,7 +518,7 @@ describe('dc.heatmap', function () { .xBorderRadius(15).yBorderRadius(15) .keyAccessor(key_part(0)) .valueAccessor(key_part(1)) - .colors(d3.scale.ordinal() + .colors(d3.scaleOrdinal() .domain(species.concat('none')) .range(['#e41a1c','#377eb8','#4daf4a', '#f8f8f8'])) .colorAccessor(function (d) { @@ -565,7 +565,7 @@ describe('dc.heatmap', function () { } function testRectFillsBubble12 (chart) { - var rects = chart.selectAll('rect')[0]; + var rects = chart.selectAll('rect').nodes(); expect(d3.select(rects[0]).attr('fill')).toMatch(/#f8f8f8/i); expect(d3.select(rects[3]).attr('fill')).toMatch(/#377eb8/i); expect(d3.select(rects[4]).attr('fill')).toMatch(/#377eb8/i); @@ -576,7 +576,7 @@ describe('dc.heatmap', function () { expect(d3.select(rects[12]).attr('fill')).toMatch(/#f8f8f8/i); } function testRectTitlesBubble12 (chart) { - var titles = chart.selectAll('g.box-group title')[0]; + var titles = chart.selectAll('g.box-group title').nodes(); expect(JSON.parse(d3.select(titles[0]).text()).total).toBe(0); expect(JSON.parse(d3.select(titles[2]).text()).total).toBe(0); expect(JSON.parse(d3.select(titles[3]).text()).total).toBe(2); diff --git a/spec/helpers/custom_matchers.js b/spec/helpers/custom_matchers.js index 557d45710..3fb5607c5 100644 --- a/spec/helpers/custom_matchers.js +++ b/spec/helpers/custom_matchers.js @@ -188,8 +188,20 @@ beforeEach(function () { toMatchUrl: function () { return { compare: function (actual, url) { - var regexp = new RegExp('url\\("?' + url + '"?\\)'); - expect(actual).toMatch(regexp); + /* + URL can be like: + url(http://localhost:8888/spec/?random=true#composite-chart-clip) + http://localhost:8888/spec/?random=true#composite-chart-clip + http://localhost:8888/spec/##composite-chart-clip + */ + var cleanURL = function(u) { + var matches = u.match(/url\((.*)\)/); + if (matches) { + u = matches[1]; + } + return u.replace(/\#+/, '#'); + }; + expect(cleanURL(actual)).toEqual(cleanURL(url)); return {pass: true}; } }; @@ -208,6 +220,22 @@ beforeEach(function () { return { compare: compareIntList }; + }, + toMatchColors: function () { + return { + compare: function (actual, expected) { + // Colors can be rgb(0, 0, 0), #000000 or black + var normalizeColor = function(c){ + // will convert to rgb(0, 0, 0) + return d3.color(c).toString(); + }; + actual = actual.map(normalizeColor); + expected = expected.map(normalizeColor); + + expect(actual).toEqual(expected); + return {pass: true}; + } + }; } }); }); diff --git a/spec/helpers/fixtures.js b/spec/helpers/fixtures.js index 7f895fac3..c537864d8 100644 --- a/spec/helpers/fixtures.js +++ b/spec/helpers/fixtures.js @@ -1,7 +1,7 @@ /* jscs:disable validateQuoteMarks, maximumLineLength */ /* jshint -W109, -W101, -W098 */ function dateCleaner (e) { - e.dd = d3.time.format.iso.parse(e.date); + e.dd = d3.isoParse(e.date); } function loadDateFixture () { @@ -79,7 +79,7 @@ function loadColorFixture2 () { } function loadIrisFixture () { - return d3.csv.parse( + return d3.csvParse( "sepal_length,sepal_width,petal_length,petal_width,species\n" + "5.1,3.5,1.4,0.2,setosa\n" + "4.9,3,1.4,0.2,setosa\n" + diff --git a/spec/helpers/spec-helper.js b/spec/helpers/spec-helper.js index 0e96ceef6..84b6ed348 100644 --- a/spec/helpers/spec-helper.js +++ b/spec/helpers/spec-helper.js @@ -45,9 +45,34 @@ function cleanDateRange (range) { // http://stackoverflow.com/questions/20068497/d3-transition-in-unit-testing function flushAllD3Transitions () { - var now = Date.now; - Date.now = function () { return Infinity; }; - d3.timer.flush(); - Date.now = now; + d3.timerFlush(); } + +// Setup a dummy event - just enough for the handler to get fooled +var setupEventForBrushing = function (chart, domainSelection) { + // D3v4 needs scaled coordinates for the event + var scaledSelection = domainSelection.map(function (coord) { + return chart.x()(coord); + }); + d3.event = { + sourceEvent: true, + selection: scaledSelection + }; +}; + +// Setup a dummy event - just enough for the handler to get fooled +var setupEventFor2DBrushing = function (chart, domainSelection) { + // D3v4 needs scaled coordinates for the event + var scaledSelection = domainSelection.map(function (point) { + return point.map(function (coord, i) { + var scale = i === 0 ? chart.x() : chart.y(); + return scale(coord); + }); + }); + d3.event = { + sourceEvent: true, + selection: scaledSelection + }; +}; + /* jshint +W098 */ diff --git a/spec/legend-spec.js b/spec/legend-spec.js index 200b65f1d..941fcc1d8 100644 --- a/spec/legend-spec.js +++ b/spec/legend-spec.js @@ -4,7 +4,7 @@ describe('dc.legend', function () { beforeEach(function () { var data = crossfilter(loadDateFixture()); - dateDimension = data.dimension(function (d) { return d3.time.day.utc(d.dd); }); + dateDimension = data.dimension(function (d) { return d3.utcDay(d.dd); }); dateValueSumGroup = dateDimension.group().reduceSum(function (d) { return d.value; }); dateIdSumGroup = dateDimension.group().reduceSum(function (d) { return d.id; }); @@ -17,7 +17,7 @@ describe('dc.legend', function () { .group(dateIdSumGroup, 'Id Sum') .stack(dateValueSumGroup, 'Value Sum') .stack(dateValueSumGroup, 'Fixed', function () {}) - .x(d3.time.scale.utc().domain([new Date(2012, 4, 20), new Date(2012, 7, 15)])) + .x(d3.scaleUtc().domain([new Date(2012, 4, 20), new Date(2012, 7, 15)])) .legend(dc.legend().x(400).y(10).itemHeight(13).gap(5)); }); @@ -69,7 +69,7 @@ describe('dc.legend', function () { }); it('not allow hiding stacks be default', function () { - legendItem(0).on('click').call(legendItem(0)[0][0], legendItem(0).datum()); + legendItem(0).on('click').call(legendItem(0).nodes()[0], legendItem(0).datum()); expect(chart.selectAll('path.line').size()).toBe(3); }); @@ -228,7 +228,7 @@ describe('dc.legend', function () { .dashStyle([2,1]); chart - .x(d3.scale.linear().domain([0,20])) + .x(d3.scaleLinear().domain([0,20])) .legend(dc.legend().x(400).y(10).itemHeight(13).gap(5)) .compose([subChart1, subChart2]) .render(); @@ -247,7 +247,7 @@ describe('dc.legend', function () { describe('clicking on a legend item', function () { beforeEach(function () { - legendItem(0).on('click').call(legendItem(0)[0][0], legendItem(0).datum()); + legendItem(0).on('click').call(legendItem(0).nodes()[0], legendItem(0).datum()); }); it('should fade out the legend item', function () { @@ -260,12 +260,12 @@ describe('dc.legend', function () { it('disable hover highlighting for that legend item', function () { legendItem(0).on('mouseover')(legendItem(0).datum()); - expect(d3.select(chart.selectAll('path.line')[0][1]).classed('fadeout')).toBeFalsy(); + expect(d3.select(chart.selectAll('path.line').nodes()[1]).classed('fadeout')).toBeFalsy(); }); describe('clicking on a faded out legend item', function () { beforeEach(function () { - legendItem(0).on('click').call(legendItem(0)[0][0], legendItem(0).datum()); + legendItem(0).on('click').call(legendItem(0).nodes()[0], legendItem(0).datum()); }); it('should unfade the legend item', function () { @@ -280,16 +280,16 @@ describe('dc.legend', function () { }); function legendItem (n) { - return d3.select(chart.selectAll('g.dc-legend g.dc-legend-item')[0][n]); + return d3.select(chart.selectAll('g.dc-legend g.dc-legend-item').nodes()[n]); } function legendLabel (n) { - return d3.select(chart.selectAll('g.dc-legend g.dc-legend-item text')[0][n]); + return d3.select(chart.selectAll('g.dc-legend g.dc-legend-item text').nodes()[n]); } function legendIcon (n) { - return d3.select(chart.selectAll('g.dc-legend g.dc-legend-item rect')[0][n]); + return d3.select(chart.selectAll('g.dc-legend g.dc-legend-item rect').nodes()[n]); } function legendLine (n) { - return d3.select(chart.selectAll('g.dc-legend g.dc-legend-item line')[0][n]); + return d3.select(chart.selectAll('g.dc-legend g.dc-legend-item line').nodes()[n]); } }); diff --git a/spec/line-chart-spec.js b/spec/line-chart-spec.js index c7f7875a0..5a9c73a02 100644 --- a/spec/line-chart-spec.js +++ b/spec/line-chart-spec.js @@ -5,7 +5,7 @@ describe('dc.lineChart', function () { beforeEach(function () { data = crossfilter(loadDateFixture()); - dimension = data.dimension(function (d) { return d3.time.day.utc(d.dd); }); + dimension = data.dimension(function (d) { return d3.utcDay(d.dd); }); group = dimension.group(); id = 'line-chart'; @@ -14,7 +14,7 @@ describe('dc.lineChart', function () { chart = dc.lineChart('#' + id); chart.dimension(dimension).group(group) .width(1100).height(200) - .x(d3.time.scale.utc().domain([makeDate(2012, 1, 1), makeDate(2012, 11, 31)])) + .x(d3.scaleUtc().domain([makeDate(2012, 1, 1), makeDate(2012, 11, 31)])) .transitionDuration(0); }); @@ -252,7 +252,7 @@ describe('dc.lineChart', function () { var x; beforeEach(function () { var dot = chart.select('circle.dot'); - dot.on('mousemove').call(dot[0][0]); + dot.on('mousemove').call(dot.nodes()[0]); x = dot.attr('cx'); }); @@ -268,7 +268,7 @@ describe('dc.lineChart', function () { var x; beforeEach(function () { var dot = chart.select('circle.dot'); - dot.on('mousemove').call(dot[0][0]); + dot.on('mousemove').call(dot.nodes()[0]); x = dot.attr('cx'); }); @@ -284,7 +284,7 @@ describe('dc.lineChart', function () { beforeEach(function () { chart.useRightYAxis(true).render(); var dot = chart.select('circle.dot'); - dot.on('mousemove').call(dot[0][0]); + dot.on('mousemove').call(dot.nodes()[0]); x = dot.attr('cx'); }); @@ -337,7 +337,7 @@ describe('dc.lineChart', function () { chart.dimension(stateDimension) .group(stateGroup) .xUnits(dc.units.ordinal) - .x(d3.scale.ordinal().domain(['California', 'Colorado', 'Delaware', 'Mississippi', 'Oklahoma', 'Ontario'])) + .x(d3.scaleOrdinal().domain(['California', 'Colorado', 'Delaware', 'Mississippi', 'Oklahoma', 'Ontario'])) .render(); }); @@ -358,7 +358,7 @@ describe('dc.lineChart', function () { chart.dimension(dimension) .brushOn(false) - .x(d3.time.scale.utc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])) + .x(d3.scaleUtc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])) .group(idGroup, 'stack 0') .title('stack 0', function (d) { return 'stack 0: ' + d.value; }) .stack(valueGroup, 'stack 1') @@ -429,9 +429,9 @@ describe('dc.lineChart', function () { it('should draw tooltip dots on top of paths and areas', function () { var list = chart.selectAll('circle.dot, path.line, path.area'); - var indexOfLastLine = list[0].indexOf(list.filter('path.line')[0][2]); - var indexOfLastArea = list[0].indexOf(list.filter('path.area')[0][2]); - var indexOfDot = list[0].indexOf(list.filter('circle.dot')[0][0]); + var indexOfLastLine = list.nodes().indexOf(list.filter('path.line').nodes()[2]); + var indexOfLastArea = list.nodes().indexOf(list.filter('path.area').nodes()[2]); + var indexOfDot = list.nodes().indexOf(list.filter('circle.dot').nodes()[0]); expect(indexOfDot).toBeGreaterThan(indexOfLastArea); expect(indexOfDot).toBeGreaterThan(indexOfLastLine); @@ -440,11 +440,11 @@ describe('dc.lineChart', function () { it('should draw tooltip ref lines on top of paths', function () { var list = chart.selectAll('path.yRef, path.xRef, path.line, path.area'); - var indexOfLastLine = list[0].indexOf(list.filter('path.line')[0][2]); - var indexOfLastArea = list[0].indexOf(list.filter('path.area')[0][2]); + var indexOfLastLine = list.nodes().indexOf(list.filter('path.line').nodes()[2]); + var indexOfLastArea = list.nodes().indexOf(list.filter('path.area').nodes()[2]); - var indexOfFirstYRef = list[0].indexOf(list.filter('path.yRef')[0][0]); - var indexOfFirstXRef = list[0].indexOf(list.filter('path.xRef')[0][0]); + var indexOfFirstYRef = list.nodes().indexOf(list.filter('path.yRef').nodes()[0]); + var indexOfFirstXRef = list.nodes().indexOf(list.filter('path.xRef').nodes()[0]); expect(indexOfLastLine).toBeLessThan(indexOfFirstXRef); expect(indexOfLastLine).toBeLessThan(indexOfFirstYRef); @@ -529,7 +529,7 @@ describe('dc.lineChart', function () { var mixedGroup = dimension.group().reduceSum(function (d) { return d.nvalue; }); chart.group(mixedGroup).stack(mixedGroup).stack(mixedGroup); - chart.x(d3.time.scale.utc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])); + chart.x(d3.scaleUtc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])); chart.margins({top: 30, right: 50, bottom: 30, left: 30}) .renderArea(true) @@ -558,7 +558,7 @@ describe('dc.lineChart', function () { }); it('should generate y axis domain dynamically', function () { - var nthText = function (n) { return d3.select(chart.selectAll('g.axis.y .tick text')[0][n]); }; + var nthText = function (n) { return d3.select(chart.selectAll('g.axis.y .tick text').nodes()[n]); }; expect(nthText(0).text()).toBe('-20'); expect(nthText(1).text()).toBe('0'); @@ -581,18 +581,18 @@ describe('dc.lineChart', function () { var negativeGroup = dimension.group().reduceSum(function (d) { return -Math.abs(d.nvalue); }); chart.group(negativeGroup).stack(negativeGroup).stack(negativeGroup); - chart.x(d3.time.scale.utc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])); + chart.x(d3.scaleUtc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)])); chart.margins({top: 30, right: 50, bottom: 30, left: 30}) .elasticY(true) - .xUnits(d3.time.days.utc) + .xUnits(d3.utcDays) .yAxis().ticks(3); chart.render(); }); it('should generate y axis domain dynamically', function () { - var nthText = function (n) { return d3.select(chart.selectAll('g.axis.y .tick text')[0][n]); }; + var nthText = function (n) { return d3.select(chart.selectAll('g.axis.y .tick text').nodes()[n]); }; expect(nthText(0).text()).toBe('-30'); expect(nthText(1).text()).toBe('-20'); @@ -642,11 +642,11 @@ describe('dc.lineChart', function () { }); function nthLine (n) { - return d3.select(chart.selectAll('path.line')[0][n]); + return d3.select(chart.selectAll('path.line').nodes()[n]); } function nthArea (n) { - return d3.select(chart.selectAll('path.area')[0][n]); + return d3.select(chart.selectAll('path.area').nodes()[n]); } }); @@ -673,31 +673,32 @@ describe('dc.lineChart', function () { }); it('should create a fancy brush resize handle', function () { - chart.select('g.brush').selectAll('.resize path').each(function (d, i) { + var selectAll = chart.select('g.brush').selectAll('path.handle--custom'); + selectAll.each(function (d, i) { if (i === 0) { expect(d3.select(this).attr('d')) - .toMatchPath('M0.5,53 A6,6 0 0 1 6.5,59 V100 A6,6 0 0 1 0.5,106 ZM2.5,61 V98 M4.5,61 V98'); + .toMatchPath('M-0.5,53 A6,6 0 0 0 -6.5,59 V100 A6,6 0 0 0 -0.5,106 ZM-2.5,61 V98 M-4.5,61 V98'); } else { expect(d3.select(this).attr('d')) - .toMatchPath('M-0.5,53 A6,6 0 0 0 -6.5,59 V100 A6,6 0 0 0 -0.5,106 ZM-2.5,61 V98 M-4.5,61 V98'); + .toMatchPath('M0.5,53 A6,6 0 0 1 6.5,59 V100 A6,6 0 0 1 0.5,106 ZM2.5,61 V98 M4.5,61 V98'); } }); }); it('should stretch the background', function () { - expect(chart.select('g.brush rect.background').attr('width')).toBe('1020'); + expect(chart.select('g.brush rect.overlay').attr('width')).toBe('1020'); }); it('should set the background height to the chart height', function () { - expect(chart.select('g.brush rect.background').attr('height')).toBe('160'); + expect(chart.select('g.brush rect.overlay').attr('height')).toBe('160'); }); it('should set extent height to the chart height', function () { - expect(chart.select('g.brush rect.extent').attr('height')).toBe('160'); + expect(chart.select('g.brush rect.selection').attr('height')).toBe('160'); }); it('should set extent width based on filter set', function () { - expect(chart.select('g.brush rect.extent').attr('width')).toBeWithinDelta(88, 1); + expect(chart.select('g.brush rect.selection').attr('width')).toBeWithinDelta(88, 1); }); it('should not have an area path', function () { @@ -740,7 +741,7 @@ describe('dc.lineChart', function () { .render(); }); it('updates dot colors', function () { - expect(chart.select('circle.dot')[0][0].attributes.fill.value).toMatch(/#ff0000/i); + expect(chart.select('circle.dot').nodes()[0].attributes.fill.value).toMatch(/#ff0000/i); }); }); @@ -750,8 +751,8 @@ describe('dc.lineChart', function () { function lineLabelPositions () { var LABEL_PADDING = 3; - chart.selectAll('.stack')[0].forEach(function (stack, i) { - d3.select(stack).selectAll('text.lineLabel')[0].forEach(function (lineLabel, j) { + chart.selectAll('.stack').nodes().forEach(function (stack, i) { + d3.select(stack).selectAll('text.lineLabel').nodes().forEach(function (lineLabel, j) { expect(+d3.select(lineLabel).attr('x')).toBeCloseTo(chart.x()(chart.data()[i].values[j].x)); expect(+d3.select(lineLabel).attr('y') + LABEL_PADDING).toBeCloseTo(chart.y()(chart.data()[i].values[j].y + chart.data()[i].values[j].y0)); diff --git a/spec/number-display-spec.js b/spec/number-display-spec.js index c6d1619c7..6615e71fc 100644 --- a/spec/number-display-spec.js +++ b/spec/number-display-spec.js @@ -35,7 +35,7 @@ describe('dc.numberDisplay', function () { .formatNumber(d3.format('.3s')) .valueAccessor(average); chart.render(); - d3.timer.flush(); + d3.timerFlush(); return chart; } @@ -62,7 +62,7 @@ describe('dc.numberDisplay', function () { beforeEach(function () { countryDimension.filterAll(); chart.redraw(); - d3.timer.flush(); + d3.timerFlush(); }); it('should update value', function () { expect(chart.select('span.number-display').text()).toEqual('41.8'); @@ -72,7 +72,7 @@ describe('dc.numberDisplay', function () { beforeEach(function () { chart.html({one: '%number number',none: 'no number',some: '%number numbers'}); chart.redraw(); - d3.timer.flush(); + d3.timerFlush(); }); it('should use some for some', function () { expect(chart.select('span.number-display').text()).toEqual('38.5 numbers'); @@ -83,7 +83,7 @@ describe('dc.numberDisplay', function () { chart.html({one: '%number number',none: 'no number',some: '%number numbers'}); chart.valueAccessor(function (d) {return 1;}); chart.redraw(); - d3.timer.flush(); + d3.timerFlush(); }); it('should use one for one', function () { expect(chart.select('span.number-display').text()).toEqual('1.00 number'); @@ -94,7 +94,7 @@ describe('dc.numberDisplay', function () { chart.html({one: '%number number',none: 'no number',some: '%number numbers'}); chart.valueAccessor(function (d) {return 0;}); chart.redraw(); - d3.timer.flush(); + d3.timerFlush(); }); it('should use zero for zero', function () { expect(chart.select('span.number-display').text()).toEqual('no number'); @@ -104,7 +104,7 @@ describe('dc.numberDisplay', function () { beforeEach(function () { chart.html({one: '%number number'}); chart.redraw(); - d3.timer.flush(); + d3.timerFlush(); }); it('should use one for showing some', function () { expect(chart.select('span.number-display').text()).toEqual('38.5 number'); @@ -114,7 +114,7 @@ describe('dc.numberDisplay', function () { beforeEach(function () { chart.html({some: '%number numbers'}); chart.redraw(); - d3.timer.flush(); + d3.timerFlush(); }); it('should use some for showing one', function () { expect(chart.select('span.number-display').text()).toEqual('38.5 numbers'); @@ -124,7 +124,7 @@ describe('dc.numberDisplay', function () { beforeEach(function () { chart.html({}); chart.redraw(); - d3.timer.flush(); + d3.timerFlush(); }); it('should just show the number in case of some and one', function () { expect(chart.select('span.number-display').text()).toEqual('38.5'); @@ -177,7 +177,7 @@ describe('dc.numberDisplay', function () { .group(group) .valueAccessor(function (kv) { return kv.value; }) .render(); - d3.timer.flush(); + d3.timerFlush(); }); it('should show the largest value', function () { @@ -188,7 +188,7 @@ describe('dc.numberDisplay', function () { beforeEach(function () { chart.ordering(function (kv) { return -kv.value; }) .render(); - d3.timer.flush(); + d3.timerFlush(); }); it('should show the smallest value', function () { expect(chart.select('span.number-display').text()).toEqual('77.0'); @@ -206,7 +206,7 @@ describe('dc.numberDisplay', function () { .group({value: function () { return Infinity; }}) .formatNumber(function (d) { return d; }) .render(); - d3.timer.flush(); + d3.timerFlush(); }); it('should display as Infinity', function () { expect(chart.root().text()).toEqual('Infinity'); @@ -215,7 +215,7 @@ describe('dc.numberDisplay', function () { beforeEach(function () { chart.group({value: function () { return 17; }}) .render(); - d3.timer.flush(); + d3.timerFlush(); }); it('should display finite', function () { expect(chart.root().text()).toEqual('17'); diff --git a/spec/pie-chart-spec.js b/spec/pie-chart-spec.js index fc405c3e8..18c4bfebe 100644 --- a/spec/pie-chart-spec.js +++ b/spec/pie-chart-spec.js @@ -27,7 +27,7 @@ describe('dc.pieChart', function () { }); countryGroup = countryDimension.group(); dateDimension = data.dimension(function (d) { - return d3.time.day.utc(d.dd); + return d3.utcDay(d.dd); }); statusGroup = statusDimension.group(); statusMultiGroup = statusGroup.reduce( @@ -157,10 +157,10 @@ describe('dc.pieChart', function () { }); }); it('slice path fill should be set correctly', function () { - expect(d3.select(chart.selectAll('g.pie-slice path')[0][0]).attr('fill')).toMatch(/#3182bd/i); - expect(d3.select(chart.selectAll('g.pie-slice path')[0][1]).attr('fill')).toMatch(/#6baed6/i); - expect(d3.select(chart.selectAll('g.pie-slice path')[0][2]).attr('fill')).toMatch(/#9ecae1/i); - expect(d3.select(chart.selectAll('g.pie-slice path')[0][3]).attr('fill')).toMatch(/#c6dbef/i); + expect(d3.select(chart.selectAll('g.pie-slice path').nodes()[0]).attr('fill')).toMatch(/#3182bd/i); + expect(d3.select(chart.selectAll('g.pie-slice path').nodes()[1]).attr('fill')).toMatch(/#6baed6/i); + expect(d3.select(chart.selectAll('g.pie-slice path').nodes()[2]).attr('fill')).toMatch(/#9ecae1/i); + expect(d3.select(chart.selectAll('g.pie-slice path').nodes()[3]).attr('fill')).toMatch(/#c6dbef/i); }); it('slice label should be created', function () { expect(chart.selectAll('svg text.pie-slice').data().length).toEqual(5); @@ -227,7 +227,7 @@ describe('dc.pieChart', function () { return chart; }); it('multiple invocation of render should update chart', function () { - expect(d3.selectAll('#pie-chart-age svg')[0].length).toEqual(1); + expect(d3.selectAll('#pie-chart-age svg').nodes().length).toEqual(1); }); }); describe('filter', function () { @@ -236,8 +236,8 @@ describe('dc.pieChart', function () { chart.render(); }); it('label should be hidden if filtered out', function () { - expect(chart.selectAll('svg g text.pie-slice')[0][0].textContent).toEqual('22'); - expect(chart.selectAll('svg g text.pie-slice')[0][1].textContent).toEqual(''); + expect(chart.selectAll('svg g text.pie-slice').nodes()[0].textContent).toEqual('22'); + expect(chart.selectAll('svg g text.pie-slice').nodes()[1].textContent).toEqual(''); }); afterEach(function () { regionDimension.filterAll(); @@ -253,7 +253,7 @@ describe('dc.pieChart', function () { expect(chart.select('g').classed('empty-chart')).toBeTruthy(); }); it('should have one slice', function () { - expect(chart.selectAll('svg g text.pie-slice').length).toBe(1); + expect(chart.selectAll('svg g text.pie-slice').nodes().length).toBe(1); }); afterEach(function () { statusDimension.filterAll(); @@ -456,14 +456,14 @@ describe('dc.pieChart', function () { }); it('label should not be generated if the slice is too small', function () { // slice '66' - expect(d3.select(chart.selectAll('text.pie-slice')[0][4]).text()).toEqual(''); + expect(d3.select(chart.selectAll('text.pie-slice').nodes()[4]).text()).toEqual(''); }); describe('selected', function () { beforeEach(function () { chart.filter('66').redraw(); }); it('a small slice should be labelled if it is selected', function () { - expect(d3.select(chart.selectAll('text.pie-slice')[0][4]).text()).toEqual('66'); + expect(d3.select(chart.selectAll('text.pie-slice').nodes()[4]).text()).toEqual('66'); }); afterEach(function () { chart.filter(null); @@ -486,17 +486,17 @@ describe('dc.pieChart', function () { chart.render(); }); it('should render correct number of text', function () { - expect(chart.selectAll('text.pie-slice')[0].length).toEqual(5); + expect(chart.selectAll('text.pie-slice').nodes().length).toEqual(5); }); it('custom function should be used to dynamically generate label', function () { - expect(d3.select(chart.selectAll('text.pie-slice')[0][0]).text()).toEqual('custom'); + expect(d3.select(chart.selectAll('text.pie-slice').nodes()[0]).text()).toEqual('custom'); }); it('label should not be generated if the slice is too small', function () { // slice '66' - expect(d3.select(chart.selectAll('text.pie-slice')[0][4]).text()).toEqual(''); + expect(d3.select(chart.selectAll('text.pie-slice').nodes()[4]).text()).toEqual(''); }); it('should render correct number of title', function () { - expect(chart.selectAll('g.pie-slice title')[0].length).toEqual(5); + expect(chart.selectAll('g.pie-slice title').nodes().length).toEqual(5); }); it('custom function should be used to dynamically generate title', function () { chart.selectAll('g.pie-slice title').each(function (p) { @@ -525,10 +525,10 @@ describe('dc.pieChart', function () { .render(); }); it('produce expected number of slices', function () { - expect(chart.selectAll('text.pie-slice')[0].length).toEqual(3); + expect(chart.selectAll('text.pie-slice').nodes().length).toEqual(3); }); it('others slice should use custom name', function () { - expect(d3.select(chart.selectAll('text.pie-slice')[0][2]).text()).toEqual('small'); + expect(d3.select(chart.selectAll('text.pie-slice').nodes()[2]).text()).toEqual('small'); }); it('remaining slices should be in descending value order', function () { expect(chart.selectAll('text.pie-slice').data().map(dc.pluck('value'))) @@ -539,14 +539,14 @@ describe('dc.pieChart', function () { beforeEach(function () { event = document.createEvent('MouseEvents'); event.initEvent('click', true, true); - chart.selectAll('.pie-slice path')[0][2].dispatchEvent(event); + chart.selectAll('.pie-slice path').nodes()[2].dispatchEvent(event); }); it('should filter three smallest', function () { expect(chart.filters()).toEqual(['33', '55', '66','small']); }); describe('clicking again', function () { beforeEach(function () { - chart.selectAll('.pie-slice path')[0][2].dispatchEvent(event); + chart.selectAll('.pie-slice path').nodes()[2].dispatchEvent(event); }); it('should reset filter', function () { expect(chart.filters()).toEqual([]); @@ -577,7 +577,7 @@ describe('dc.pieChart', function () { chart.cap(1).render(); }); it('correct values, others row', function () { - expect(chart.selectAll('title')[0].map(function (t) {return d3.select(t).text();})) + expect(chart.selectAll('title').nodes().map(function (t) {return d3.select(t).text();})) .toEqual(['F: 220', 'small: 198']); }); }); @@ -632,10 +632,10 @@ describe('dc.pieChart', function () { return chart; }); it('default function should be used to dynamically generate label', function () { - expect(d3.select(chart.selectAll('text.pie-slice')[0][0]).text()).toEqual('F'); + expect(d3.select(chart.selectAll('text.pie-slice').nodes()[0]).text()).toEqual('F'); }); it('default function should be used to dynamically generate title', function () { - expect(d3.select(chart.selectAll('g.pie-slice title')[0][0]).text()).toEqual('F: 5'); + expect(d3.select(chart.selectAll('g.pie-slice title').nodes()[0]).text()).toEqual('F: 5'); }); describe('with n/a filter', function () { beforeEach(function () { @@ -647,17 +647,17 @@ describe('dc.pieChart', function () { expect(chart.select('g').classed('empty-chart')).toBeTruthy(); }); it('should have one slice', function () { - expect(chart.selectAll('svg g text.pie-slice').length).toBe(1); + expect(chart.selectAll('svg g text.pie-slice').nodes().length).toBe(1); }); it('should have slice labeled empty', function () { - expect(d3.select(chart.selectAll('text.pie-slice')[0][0]).text()).toEqual('empty'); + expect(d3.select(chart.selectAll('text.pie-slice').nodes()[0]).text()).toEqual('empty'); }); describe('with emptyTitle', function () { beforeEach(function () { chart.emptyTitle('nothing').render(); }); it('should respect the emptyTitle', function () { - expect(d3.select(chart.selectAll('text.pie-slice')[0][0]).text()).toEqual('nothing'); + expect(d3.select(chart.selectAll('text.pie-slice').nodes()[0]).text()).toEqual('nothing'); }); afterEach(function () { chart.emptyTitle('empty'); @@ -699,7 +699,7 @@ describe('dc.pieChart', function () { it('should place labels outside of pie offset by given radius', function () { var label = d3.select('#pie-chart-external-labeling svg g text.pie-slice'); - var centroid = d3.svg.arc() + var centroid = d3.arc() .outerRadius(chart.radius() + 10) .innerRadius(chart.radius() + 10) .centroid(label.datum()); @@ -720,7 +720,7 @@ describe('dc.pieChart', function () { d3.selectAll('#pie-chart-external-labeling svg g text.pie-slice').each(function () { var label = d3.select(this); - var centroid = d3.svg.arc() + var centroid = d3.arc() .outerRadius(chart.radius()) .innerRadius(chart.innerRadius()) .centroid(label.datum()); diff --git a/spec/row-chart-spec.js b/spec/row-chart-spec.js index c42a83ece..d7da3613f 100644 --- a/spec/row-chart-spec.js +++ b/spec/row-chart-spec.js @@ -52,7 +52,7 @@ describe('dc.rowChart', function () { beforeEach(function () { chart.group(positiveGroupHolder.group); chart.elasticX(false); - chart.x(d3.scale.log()); + chart.x(d3.scaleLog()); chart.render(); }); @@ -65,7 +65,7 @@ describe('dc.rowChart', function () { beforeEach(function () { chart.group(positiveGroupHolder.group); chart.elasticX(false); - chart.x(d3.scale.log()); + chart.x(d3.scaleLog()); chart.fixedBarHeight(10); chart.render(); }); @@ -78,7 +78,7 @@ describe('dc.rowChart', function () { describe('with renderTitleLabel', function () { beforeEach(function () { chart.group(positiveGroupHolder.group); - chart.x(d3.scale.linear()); + chart.x(d3.scaleLinear()); chart.title(function () { return 'test title'; }); @@ -117,11 +117,11 @@ describe('dc.rowChart', function () { }); it('should fill each row rect with pre-defined colors', function () { - expect(d3.select(chart.selectAll('g.row rect')[0][0]).attr('fill')).toMatch(/#3182bd/i); - expect(d3.select(chart.selectAll('g.row rect')[0][1]).attr('fill')).toMatch(/#6baed6/i); - expect(d3.select(chart.selectAll('g.row rect')[0][2]).attr('fill')).toMatch(/#9ecae1/i); - expect(d3.select(chart.selectAll('g.row rect')[0][3]).attr('fill')).toMatch(/#c6dbef/i); - expect(d3.select(chart.selectAll('g.row rect')[0][4]).attr('fill')).toMatch(/#e6550d/i); + expect(d3.select(chart.selectAll('g.row rect').nodes()[0]).attr('fill')).toMatch(/#3182bd/i); + expect(d3.select(chart.selectAll('g.row rect').nodes()[1]).attr('fill')).toMatch(/#6baed6/i); + expect(d3.select(chart.selectAll('g.row rect').nodes()[2]).attr('fill')).toMatch(/#9ecae1/i); + expect(d3.select(chart.selectAll('g.row rect').nodes()[3]).attr('fill')).toMatch(/#c6dbef/i); + expect(d3.select(chart.selectAll('g.row rect').nodes()[4]).attr('fill')).toMatch(/#e6550d/i); }); it('should create a row label from the data for each row', function () { @@ -141,8 +141,8 @@ describe('dc.rowChart', function () { function itShouldVerticallyCenterLabelWithinRow (i) { it('should place label ' + i + ' within row ' + i, function () { - var rowpos = rows[0][i].getBoundingClientRect(), - textpos = labels[0][i].getBoundingClientRect(); + var rowpos = rows.nodes()[i].getBoundingClientRect(), + textpos = labels.nodes()[i].getBoundingClientRect(); expect((textpos.top + textpos.bottom) / 2) .toBeWithinDelta((rowpos.top + rowpos.bottom) / 2, 2); }); @@ -381,7 +381,7 @@ describe('dc.rowChart', function () { }); it('should generate x axis domain dynamically', function () { - var nthText = function (n) { return d3.select(chart.selectAll('g.axis .tick text')[0][n]); }; + var nthText = function (n) { return d3.select(chart.selectAll('g.axis .tick text').nodes()[n]); }; for (var i = 0; i < xAxisTicks.length; i++) { expect(nthText(i).text()).toBe(xAxisTicks[i]); diff --git a/spec/scatter-plot-spec.js b/spec/scatter-plot-spec.js index 1f5eb4863..8b8809fdd 100644 --- a/spec/scatter-plot-spec.js +++ b/spec/scatter-plot-spec.js @@ -15,7 +15,7 @@ describe('dc.scatterPlot', function () { chart.dimension(dimension) .group(group) .width(500).height(180) - .x(d3.scale.linear().domain([0, 70])) + .x(d3.scaleLinear().domain([0, 70])) .symbolSize(10) .nonemptyOpacity(0.9) .excludedSize(2) @@ -81,7 +81,7 @@ describe('dc.scatterPlot', function () { // native size is 3 square pixels, so to get size N, multiply by sqrt(N)/3 var m = size.call(this, d, i); m = Math.sqrt(m) / 3; - var path = d3.svg.line() + var path = d3.line() .x(function (d) { return d[0] * m; }) @@ -127,7 +127,7 @@ describe('dc.scatterPlot', function () { }); function nthSymbol (i) { - return d3.select(chart.selectAll('path.symbol')[0][i]); + return d3.select(chart.selectAll('path.symbol').nodes()[i]); } describe('filtering the chart', function () { @@ -229,8 +229,11 @@ describe('dc.scatterPlot', function () { beforeEach(function () { otherDimension = data.dimension(function (d) { return [+d.value, +d.nvalue]; }); - chart.brush().extent([[22, -3], [44, 2]]); - chart.brush().on('brush')(); + // Setup a dummy event - just enough for the handler to get fooled + setupEventFor2DBrushing(chart, [[22, -3], [44, 2]]); + // Directly call the handler + chart._brushing(); + chart.redraw(); }); @@ -239,9 +242,11 @@ describe('dc.scatterPlot', function () { expect(otherDimension.top(Infinity).length).toBe(3); }); +/* D3v4 - no easy replacement, dropping this case it('should set the height of the brush to the height implied by the extent', function () { expect(chart.select('g.brush rect.extent').attr('height')).toBe('46'); }); +*/ it('should not add handles to the brush', function () { expect(chart.select('.resize path').empty()).toBeTruthy(); @@ -307,8 +312,10 @@ describe('dc.scatterPlot', function () { }); it('should restore sizes, colors, and opacity when the brush is empty', function () { - chart.brush().extent([[22, 2], [22, -3]]); - chart.brush().on('brush')(); + // Setup a dummy event - just enough for the handler to get fooled + setupEventFor2DBrushing(chart, [[22, 2], [22, -3]]); + // Directly call the handler + chart._brushing(); jasmine.clock().tick(100); selectedPoints = symbolsOfRadius(chart.symbolSize()); @@ -339,7 +346,7 @@ describe('dc.scatterPlot', function () { return function () { var symbol = d3.select(this); var size = Math.pow(r, 2); - var path = d3.svg.symbol().size(size)(); + var path = d3.symbol().size(size)(); var result = comparePaths(symbol.attr('d'), path); return result.pass; }; @@ -357,7 +364,7 @@ describe('dc.scatterPlot', function () { function symbolsMatching (pred) { function getData (symbols) { - return symbols[0].map(function (symbol) { + return symbols.nodes().map(function (symbol) { return d3.select(symbol).datum(); }); } @@ -380,7 +387,7 @@ describe('dc.scatterPlot', function () { compositeChart = dc.compositeChart('#' + id); compositeChart .dimension(dimension) - .x(d3.time.scale.utc().domain([makeDate(2012, 0, 1), makeDate(2012, 11, 31)])) + .x(d3.scaleUtc().domain([makeDate(2012, 0, 1), makeDate(2012, 11, 31)])) .transitionDuration(0) .legend(dc.legend()) .compose([ @@ -430,7 +437,7 @@ describe('dc.scatterPlot', function () { }); function nthChart (n) { - var subChart = d3.select(compositeChart.selectAll('g.sub')[0][n]); + var subChart = d3.select(compositeChart.selectAll('g.sub').nodes()[n]); subChart.expectPlotSymbolsToHaveClass = function (className) { subChart.selectAll('path.symbol').each(function () { diff --git a/spec/select-menu-spec.js b/spec/select-menu-spec.js index 51a688b00..a4a83022d 100644 --- a/spec/select-menu-spec.js +++ b/spec/select-menu-spec.js @@ -36,7 +36,7 @@ describe('dc.selectMenu', function () { expect(chart.promptText()).toBe('Select all'); }); it('creates select tag', function () { - expect(chart.selectAll('select').length).toEqual(1); + expect(chart.selectAll('select').nodes().length).toEqual(1); }); it('select tag is not a multiple select by default', function () { expect(chart.selectAll('select').attr('multiple')).toBeNull(); @@ -53,16 +53,16 @@ describe('dc.selectMenu', function () { expect(chart.selectAll('select').attr('size')).toEqual('10'); }); it('creates prompt option with empty value', function () { - var option = chart.selectAll('option')[0][0]; + var option = chart.selectAll('option').nodes()[0]; expect(option).not.toBeNull(); expect(option.value).toEqual(''); }); it('creates prompt option with default prompt text', function () { - var option = chart.selectAll('option')[0][0]; + var option = chart.selectAll('option').nodes()[0]; expect(option.text).toEqual('Select all'); }); it('creates correct number of options', function () { - expect(chart.selectAll('option.dc-select-option')[0].length).toEqual(stateGroup.all().length); + expect(chart.selectAll('option.dc-select-option').nodes().length).toEqual(stateGroup.all().length); }); }); @@ -121,7 +121,7 @@ describe('dc.selectMenu', function () { it('selects option corresponding to active filter', function () { chart.onChange(stateGroup.all()[0].key); chart.redraw(); - expect(chart.selectAll('select')[0][0].value).toEqual('California'); + expect(chart.selectAll('select').nodes()[0].value).toEqual('California'); }); }); @@ -149,7 +149,7 @@ describe('dc.selectMenu', function () { expect(regionGroup.all()[0].value).toEqual(1); }); it('selects all options corresponding to active filters on redraw', function () { - var selectedOptions = chart.selectAll('select').selectAll('option')[0].filter(function (d) { + var selectedOptions = chart.selectAll('select').selectAll('option').nodes().filter(function (d) { // IE returns an extra option with value '', not sure what it means return d.value && d.selected; }); @@ -159,7 +159,7 @@ describe('dc.selectMenu', function () { it('does not deselect previously filtered options when new option is added', function () { chart.onChange([stateGroup.all()[0].key, stateGroup.all()[1].key, stateGroup.all()[5].key]); - var selectedOptions = chart.selectAll('select').selectAll('option')[0].filter(function (d) { + var selectedOptions = chart.selectAll('select').selectAll('option').nodes().filter(function (d) { // IE returns an extra option with value '', not sure what it means return d.value && d.selected; }); @@ -176,13 +176,13 @@ describe('dc.selectMenu', function () { it('only displays options whose value > 0 by default', function () { regionDimension.filter('South'); chart.redraw(); - expect(chart.selectAll('option.dc-select-option')[0].length).toEqual(1); + expect(chart.selectAll('option.dc-select-option').nodes().length).toEqual(1); expect(getOption(chart, 0).text).toEqual('California: 2'); }); it('can be overridden', function () { regionDimension.filter('South'); chart.filterDisplayed(function (d) { return true; }).redraw(); - expect(chart.selectAll('option.dc-select-option')[0].length).toEqual(stateGroup.all().length); + expect(chart.selectAll('option.dc-select-option').nodes().length).toEqual(stateGroup.all().length); expect(getOption(chart, stateGroup.all().length - 1).text).toEqual('Ontario: 0'); }); it('retains order with filtered options', function () { @@ -197,6 +197,6 @@ describe('dc.selectMenu', function () { }); function getOption (chart, i) { - return chart.selectAll('option.dc-select-option')[0][i]; + return chart.selectAll('option.dc-select-option').nodes()[i]; } }); diff --git a/spec/series-chart-spec.js b/spec/series-chart-spec.js index 00320fc29..3133808c4 100644 --- a/spec/series-chart-spec.js +++ b/spec/series-chart-spec.js @@ -22,7 +22,7 @@ describe('dc.seriesChart', function () { chart .width(210) .height(210) - .x(d3.scale.linear().domain([1,2])) + .x(d3.scaleLinear().domain([1,2])) .dimension(dimensionColorData) .group(groupColorData) .ordinalColors(['#000001', '#000002']) @@ -45,22 +45,22 @@ describe('dc.seriesChart', function () { it('should position generated lineCharts using the data', function () { var lines = chart.selectAll('path.line'); - expect(d3.select(lines[0][0]).attr('d')).toMatchPath('M0,128L130,85'); - expect(d3.select(lines[0][1]).attr('d')).toMatchPath('M0,43L130,0'); + expect(d3.select(lines.nodes()[0]).attr('d')).toMatchPath('M0,128L130,85'); + expect(d3.select(lines.nodes()[1]).attr('d')).toMatchPath('M0,43L130,0'); }); it('should color lines using the colors in the data', function () { var lines = chart.selectAll('path.line'); - expect(d3.select(lines[0][0]).attr('stroke')).toMatch(/#000001/i); - expect(d3.select(lines[0][1]).attr('stroke')).toMatch(/#000002/i); + expect(d3.select(lines.nodes()[0]).attr('stroke')).toMatch(/#000001/i); + expect(d3.select(lines.nodes()[1]).attr('stroke')).toMatch(/#000002/i); }); describe('with brush off', function () { it('should create line chart dots', function () { chart.brushOn(false).render(); var dots = chart.selectAll('circle.dot'); - expect(dots[0].length).toEqual(4); + expect(dots.nodes().length).toEqual(4); chart.brushOn(true); }); }); @@ -76,8 +76,8 @@ describe('dc.seriesChart', function () { it('should order lineCharts in the order specified', function () { var lines = chart.selectAll('path.line'); - expect(d3.select(lines[0][1]).attr('d')).toMatchPath('M0,128L130,85'); - expect(d3.select(lines[0][0]).attr('d')).toMatchPath('M0,43L130,0'); + expect(d3.select(lines.nodes()[1]).attr('d')).toMatchPath('M0,128L130,85'); + expect(d3.select(lines.nodes()[0]).attr('d')).toMatchPath('M0,43L130,0'); }); }); @@ -90,11 +90,11 @@ describe('dc.seriesChart', function () { var lines = chart.selectAll('path.line'); var areas = chart.selectAll('path.area'); - expect(d3.select(lines[0][0]).attr('stroke-dasharray')).toEqualIntList('3,1,1'); - expect(d3.select(lines[0][1]).attr('stroke-dasharray')).toEqualIntList('3,1,1'); + expect(d3.select(lines.nodes()[0]).attr('stroke-dasharray')).toEqualIntList('3,1,1'); + expect(d3.select(lines.nodes()[1]).attr('stroke-dasharray')).toEqualIntList('3,1,1'); - expect(d3.select(areas[0][0]).attr('fill')).toMatch(/#000001/i); - expect(d3.select(areas[0][1]).attr('fill')).toMatch(/#000002/i); + expect(d3.select(areas.nodes()[0]).attr('fill')).toMatch(/#000001/i); + expect(d3.select(areas.nodes()[1]).attr('fill')).toMatch(/#000002/i); }); }); @@ -127,7 +127,7 @@ describe('dc.seriesChart', function () { it('is redrawn with dots', function () { var dots = chart.selectAll('circle.dot'); - expect(dots[0].length).toEqual(6); + expect(dots.nodes().length).toEqual(6); }); }); }); diff --git a/spec/utils-spec.js b/spec/utils-spec.js index da1bd8db2..b32e29c96 100644 --- a/spec/utils-spec.js +++ b/spec/utils-spec.js @@ -20,7 +20,7 @@ describe('dc utils', function () { var printer; beforeEach(function () { printer = dc.printers.filter; - dc.dateFormat = d3.time.format.utc('%m/%d/%Y'); + dc.dateFormat = d3.utcFormat('%m/%d/%Y'); }); it('print simple string', function () { expect(printer('a')).toEqual('a'); diff --git a/src/bar-chart.js b/src/bar-chart.js index 9775065a9..9498a4f0d 100644 --- a/src/bar-chart.js +++ b/src/bar-chart.js @@ -16,7 +16,7 @@ * // create a sub-chart under a composite parent chart * var chart3 = dc.barChart(compositeChart); * @param {String|node|d3.selection|dc.compositeChart} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} * specifying a dom block element such as a div; or a dom element or d3 selection. If the bar * chart is a sub-chart in a {@link dc.compositeChart Composite Chart} then pass in the parent * composite chart instance instead. @@ -62,12 +62,13 @@ dc.barChart = function (parent, chartGroup) { calculateBarWidth(); - layers + layers = layers .enter() - .append('g') - .attr('class', function (d, i) { - return 'stack ' + '_' + i; - }); + .append('g') + .attr('class', function (d, i) { + return 'stack ' + '_' + i; + }) + .merge(layers); var last = layers.size() - 1; layers.each(function (d, i) { @@ -89,17 +90,19 @@ dc.barChart = function (parent, chartGroup) { var labels = layer.selectAll('text.barLabel') .data(d.values, dc.pluck('x')); - labels.enter() - .append('text') - .attr('class', 'barLabel') - .attr('text-anchor', 'middle'); + var labelsEnterUpdate = labels + .enter() + .append('text') + .attr('class', 'barLabel') + .attr('text-anchor', 'middle') + .merge(labels); if (_chart.isOrdinal()) { - labels.on('click', _chart.onClick); - labels.attr('cursor', 'pointer'); + labelsEnterUpdate.on('click', _chart.onClick); + labelsEnterUpdate.attr('cursor', 'pointer'); } - dc.transition(labels, _chart.transitionDuration(), _chart.transitionDelay()) + dc.transition(labelsEnterUpdate, _chart.transitionDuration(), _chart.transitionDelay()) .attr('x', function (d) { var x = _chart.x()(d.x); if (!_centerBar) { @@ -136,15 +139,17 @@ dc.barChart = function (parent, chartGroup) { .attr('y', _chart.yAxisHeight()) .attr('height', 0); + var barsEnterUpdate = enter.merge(bars); + if (_chart.renderTitle()) { enter.append('title').text(dc.pluck('data', _chart.title(d.name))); } if (_chart.isOrdinal()) { - bars.on('click', _chart.onClick); + barsEnterUpdate.on('click', _chart.onClick); } - dc.transition(bars, _chart.transitionDuration(), _chart.transitionDelay()) + dc.transition(barsEnterUpdate, _chart.transitionDuration(), _chart.transitionDelay()) .attr('x', function (d) { var x = _chart.x()(d.x); if (_centerBar) { @@ -183,7 +188,7 @@ dc.barChart = function (parent, chartGroup) { // please can't we always use rangeBands for bar charts? if (_chart.isOrdinal() && _gap === undefined) { - _barWidth = Math.floor(_chart.x().rangeBand()); + _barWidth = Math.floor(_chart.x().bandwidth()); } else if (_gap) { _barWidth = Math.floor((_chart.xAxisLength() - (numberOfBars - 1) * _gap) / numberOfBars); } else { @@ -196,9 +201,8 @@ dc.barChart = function (parent, chartGroup) { } } - _chart.fadeDeselectedArea = function () { + _chart.fadeDeselectedArea = function (selection) { var bars = _chart.chartBodyG().selectAll('rect.bar'); - var extent = _chart.brush().extent(); if (_chart.isOrdinal()) { if (_chart.hasFilter()) { @@ -213,9 +217,9 @@ dc.barChart = function (parent, chartGroup) { bars.classed(dc.constants.DESELECTED_CLASS, false); } } else { - if (!_chart.brushIsEmpty(extent)) { - var start = extent[0]; - var end = extent[1]; + if (!_chart.brushIsEmpty(selection)) { + var start = selection[0]; + var end = selection[1]; bars.classed(dc.constants.DESELECTED_CLASS, function (d) { return d.x < start || d.x >= end; @@ -249,7 +253,7 @@ dc.barChart = function (parent, chartGroup) { /** * Get or set the spacing between bars as a fraction of bar size. Valid values are between 0-1. * Setting this value will also remove any previously set {@link dc.barChart#gap gap}. See the - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Ordinal-Scales.md#ordinal_rangeBands d3 docs} + * {@link https://github.com/d3/d3-scale/blob/master/README.md#scaleBand d3 docs} * for a visual description of how the padding is applied. * @method barPadding * @memberof dc.barChart @@ -299,17 +303,12 @@ dc.barChart = function (parent, chartGroup) { return _chart; }; - _chart.extendBrush = function () { - var extent = _chart.brush().extent(); - if (_chart.round() && (!_centerBar || _alwaysUseRounding)) { - extent[0] = extent.map(_chart.round())[0]; - extent[1] = extent.map(_chart.round())[1]; - - _chart.chartBodyG().select('.brush') - .call(_chart.brush().extent(extent)); + _chart.extendBrush = function (selection) { + if (selection && _chart.round() && (!_centerBar || _alwaysUseRounding)) { + selection[0] = _chart.round()(selection[0]); + selection[1] = _chart.round()(selection[1]); } - - return extent; + return selection; }; /** diff --git a/src/base-mixin.js b/src/base-mixin.js index 03d57676c..a9de8b917 100644 --- a/src/base-mixin.js +++ b/src/base-mixin.js @@ -385,7 +385,7 @@ dc.baseMixin = function (_chart) { * @method select * @memberof dc.baseMixin * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#d3_select d3.select} + * @see {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3.select} * @example * // Has the same effect as d3.select('#chart-id').select(selector) * chart.select(selector) @@ -403,7 +403,7 @@ dc.baseMixin = function (_chart) { * @method selectAll * @memberof dc.baseMixin * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#d3_selectAll d3.selectAll} + * @see {@link https://github.com/d3/d3-selection/blob/master/README.md#selectAll d3.selectAll} * @example * // Has the same effect as d3.select('#chart-id').selectAll(selector) * chart.selectAll(selector) @@ -415,7 +415,7 @@ dc.baseMixin = function (_chart) { /** * Set the root SVGElement to either be an existing chart's root; or any valid [d3 single - * selector](https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements) specifying a dom + * selector](https://github.com/d3/d3-selection/blob/master/README.md#selecting-elements) specifying a dom * block element such as a div; or a dom element or d3 selection. Optionally registers the chart * within the chartGroup. This class is called internally on chart initialization, but be called * again to relocate the chart. However, it will orphan any previously created SVGElements. @@ -688,7 +688,7 @@ dc.baseMixin = function (_chart) { */ _chart.render = function () { _height = _width = undefined; // force recalculate - _listeners.preRender(_chart); + _listeners.call('preRender', _chart, _chart); if (_mandatoryAttributes) { _mandatoryAttributes.forEach(checkForMandatoryAttributes); @@ -706,19 +706,19 @@ dc.baseMixin = function (_chart) { }; _chart._activateRenderlets = function (event) { - _listeners.pretransition(_chart); + _listeners.call('pretransition', _chart, _chart); if (_chart.transitionDuration() > 0 && _svg) { _svg.transition().duration(_chart.transitionDuration()).delay(_chart.transitionDelay()) - .each('end', function () { - _listeners.renderlet(_chart); + .on('end', function () { + _listeners.call('renderlet', _chart, _chart); if (event) { - _listeners[event](_chart); + _listeners.call(event, _chart, _chart); } }); } else { - _listeners.renderlet(_chart); + _listeners.call('renderlet', _chart, _chart); if (event) { - _listeners[event](_chart); + _listeners.call(event, _chart, _chart); } } }; @@ -738,7 +738,7 @@ dc.baseMixin = function (_chart) { */ _chart.redraw = function () { sizeSvg(); - _listeners.preRedraw(_chart); + _listeners.call('preRedraw', _chart, _chart); var result = _chart._doRedraw(); @@ -821,12 +821,12 @@ dc.baseMixin = function (_chart) { _chart._invokeFilteredListener = function (f) { if (f !== undefined) { - _listeners.filtered(_chart, f); + _listeners.call('filtered', _chart, _chart, f); } }; _chart._invokeZoomedListener = function () { - _listeners.zoomed(_chart); + _listeners.call('zoomed', _chart, _chart); }; var _hasFilterHandler = function (filters, filter) { @@ -1544,7 +1544,7 @@ dc.baseMixin = function (_chart) { * @method on * @memberof dc.baseMixin * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Internals.md#dispatch_on d3.dispatch.on} + * @see {@link https://github.com/d3/d3-dispatch/blob/master/README.md#dispatch_on d3.dispatch.on} * @example * .on('renderlet', function(chart, filter){...}) * .on('pretransition', function(chart, filter){...}) diff --git a/src/box-plot.js b/src/box-plot.js index 8c3006005..66a1995ba 100644 --- a/src/box-plot.js +++ b/src/box-plot.js @@ -14,7 +14,7 @@ * // create a box plot under #chart-container2 element using chart group A * var boxPlot2 = dc.boxPlot('#chart-container2', 'chartGroupA'); * @param {String|node|d3.selection} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} specifying + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. @@ -46,7 +46,7 @@ dc.boxPlot = function (parent, chartGroup) { var _boxWidth = function (innerChartWidth, xUnits) { if (_chart.isOrdinal()) { - return _chart.x().rangeBand(); + return _chart.x().bandwidth(); } else { return innerChartWidth / (1 + _chart.boxPadding()) / xUnits; } @@ -56,7 +56,7 @@ dc.boxPlot = function (parent, chartGroup) { _chart.yAxisPadding(12); // default to ordinal - _chart.x(d3.scale.ordinal()); + _chart.x(d3.scaleBand()); _chart.xUnits(dc.units.ordinal); // valueAccessor should return an array of values that can be coerced into numbers @@ -74,12 +74,12 @@ dc.boxPlot = function (parent, chartGroup) { /** * Get or set the spacing between boxes as a fraction of box size. Valid values are within 0-1. - * See the {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Ordinal-Scales.md#ordinal_rangeBands d3 docs} + * See the {@link https://github.com/d3/d3-scale/blob/master/README.md#scaleBand d3 docs} * for a visual description of how the padding is applied. * @method boxPadding * @memberof dc.boxPlot * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Ordinal-Scales.md#ordinal_rangeBands d3.scale.ordinal.rangeBands} + * @see {@link https://github.com/d3/d3-scale/blob/master/README.md#scaleBand d3.scaleBand} * @param {Number} [padding=0.8] * @returns {Number|dc.boxPlot} */ @@ -146,11 +146,11 @@ dc.boxPlot = function (parent, chartGroup) { var boxesG = _chart.chartBodyG().selectAll('g.box').data(_chart.data(), _chart.keyAccessor()); - renderBoxes(boxesG); - updateBoxes(boxesG); + var boxesGEnterUpdate = renderBoxes(boxesG); + updateBoxes(boxesGEnterUpdate); removeBoxes(boxesG); - _chart.fadeDeselectedArea(); + _chart.fadeDeselectedArea(_chart.filter()); }; function renderBoxes (boxesG) { @@ -164,6 +164,8 @@ dc.boxPlot = function (parent, chartGroup) { _chart.filter(_chart.keyAccessor()(d)); _chart.redrawGroup(); }); + + return boxesGEnter.merge(boxesG); } function updateBoxes (boxesG) { @@ -179,7 +181,7 @@ dc.boxPlot = function (parent, chartGroup) { boxesG.exit().remove().call(_box); } - _chart.fadeDeselectedArea = function () { + _chart.fadeDeselectedArea = function (selection) { if (_chart.hasFilter()) { if (_chart.isOrdinal()) { _chart.g().selectAll('g.box').each(function (d) { @@ -190,9 +192,8 @@ dc.boxPlot = function (parent, chartGroup) { } }); } else { - var extent = _chart.brush().extent(); - var start = extent[0]; - var end = extent[1]; + var start = selection[0]; + var end = selection[1]; var keyAccessor = _chart.keyAccessor(); _chart.g().selectAll('g.box').each(function (d) { var key = keyAccessor(d); diff --git a/src/bubble-chart.js b/src/bubble-chart.js index 52063992a..7ae603997 100644 --- a/src/bubble-chart.js +++ b/src/bubble-chart.js @@ -19,7 +19,7 @@ * // create a bubble chart under #chart-container2 element using chart group A * var bubbleChart2 = dc.bubbleChart('#chart-container2', 'chartGroupA'); * @param {String|node|d3.selection} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} specifying + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. @@ -48,13 +48,13 @@ dc.bubbleChart = function (parent, chartGroup) { bubbleG.order(); } - renderNodes(bubbleG); + bubbleG = renderNodes(bubbleG); updateNodes(bubbleG); removeNodes(bubbleG); - _chart.fadeDeselectedArea(); + _chart.fadeDeselectedArea(_chart.filter()); }; function renderNodes (bubbleG) { @@ -69,6 +69,9 @@ dc.bubbleChart = function (parent, chartGroup) { .on('click', _chart.onClick) .attr('fill', _chart.getColor) .attr('r', 0); + + bubbleG = bubbleGEnter.merge(bubbleG); + dc.transition(bubbleG, _chart.transitionDuration(), _chart.transitionDelay()) .select('circle.' + _chart.BUBBLE_CLASS) .attr('r', function (d) { @@ -81,6 +84,8 @@ dc.bubbleChart = function (parent, chartGroup) { _chart._doRenderLabel(bubbleGEnter); _chart._doRenderTitles(bubbleGEnter); + + return bubbleG; } function updateNodes (bubbleG) { @@ -105,7 +110,7 @@ dc.bubbleChart = function (parent, chartGroup) { function bubbleX (d) { var x = _chart.x()(_chart.keyAccessor()(d)); - if (isNaN(x)) { + if (isNaN(x) || !isFinite(x)) { x = 0; } return x; @@ -113,7 +118,7 @@ dc.bubbleChart = function (parent, chartGroup) { function bubbleY (d) { var y = _chart.y()(_chart.valueAccessor()(d)); - if (isNaN(y)) { + if (isNaN(y) || !isFinite(y)) { y = 0; } return y; @@ -123,9 +128,9 @@ dc.bubbleChart = function (parent, chartGroup) { // override default x axis brush from parent chart }; - _chart.redrawBrush = function () { + _chart.redrawBrush = function (g, selection, doTransition) { // override default x axis brush from parent chart - _chart.fadeDeselectedArea(); + _chart.fadeDeselectedArea(selection); }; return _chart.anchor(parent, chartGroup); diff --git a/src/bubble-mixin.js b/src/bubble-mixin.js index 527049cae..f0c2133a7 100644 --- a/src/bubble-mixin.js +++ b/src/bubble-mixin.js @@ -31,7 +31,7 @@ dc.bubbleMixin = function (_chart) { return data; }); - var _r = d3.scale.linear().domain([0, 100]); + var _r = d3.scaleLinear().domain([0, 100]); var _rValueAccessor = function (d) { return d.r; @@ -39,13 +39,13 @@ dc.bubbleMixin = function (_chart) { /** * Get or set the bubble radius scale. By default the bubble chart uses - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Quantitative-Scales.md#linear d3.scale.linear().domain([0, 100])} + * {@link https://github.com/d3/d3-scale/blob/master/README.md#scaleLinear d3.scaleLinear().domain([0, 100])} * as its radius scale. * @method r * @memberof dc.bubbleMixin * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Scales.md d3.scale} - * @param {d3.scale} [bubbleRadiusScale=d3.scale.linear().domain([0, 100])] + * @see {@link https://github.com/d3/d3-scale/blob/master/README.md d3.scale} + * @param {d3.scale} [bubbleRadiusScale=d3.scaleLinear().domain([0, 100])] * @returns {d3.scale|dc.bubbleMixin} */ _chart.r = function (bubbleRadiusScale) { @@ -255,7 +255,7 @@ dc.bubbleMixin = function (_chart) { return _chart; }; - _chart.fadeDeselectedArea = function () { + _chart.fadeDeselectedArea = function (selection) { if (_chart.hasFilter()) { _chart.selectAll('g.' + _chart.BUBBLE_NODE_CLASS).each(function (d) { if (_chart.isSelectedNode(d)) { diff --git a/src/bubble-overlay.js b/src/bubble-overlay.js index ed5efc7a7..87c9a40d7 100644 --- a/src/bubble-overlay.js +++ b/src/bubble-overlay.js @@ -16,7 +16,7 @@ * // create a bubble overlay chart on top of the '#chart-container2 svg' element using chart group A * var bubbleChart2 = dc.compositeChart('#chart-container2', 'chartGroupA').svg(d3.select('#chart-container2 svg')); * @param {String|node|d3.selection} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} specifying + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. @@ -81,7 +81,7 @@ dc.bubbleOverlay = function (parent, chartGroup) { initializeBubbles(); - _chart.fadeDeselectedArea(); + _chart.fadeDeselectedArea(_chart.filter()); return _chart; }; @@ -149,7 +149,7 @@ dc.bubbleOverlay = function (parent, chartGroup) { _chart._doRedraw = function () { updateBubbles(); - _chart.fadeDeselectedArea(); + _chart.fadeDeselectedArea(_chart.filter()); return _chart; }; diff --git a/src/color-mixin.js b/src/color-mixin.js index 2774cf76f..fe6b24225 100644 --- a/src/color-mixin.js +++ b/src/color-mixin.js @@ -8,7 +8,7 @@ * @returns {dc.colorMixin} */ dc.colorMixin = function (_chart) { - var _colors = d3.scale.category20c(); + var _colors = d3.scaleOrdinal(d3.schemeCategory20c); var _defaultAccessor = true; var _colorAccessor = function (d) { return _chart.keyAccessor()(d); }; @@ -19,17 +19,17 @@ dc.colorMixin = function (_chart) { * @method colors * @memberof dc.colorMixin * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Scales.md d3.scale} + * @see {@link https://github.com/d3/d3-scale/blob/master/README.md d3.scale} * @example * // alternate categorical scale * chart.colors(d3.scale.category20b()); * // ordinal scale - * chart.colors(d3.scale.ordinal().range(['red','green','blue'])); + * chart.colors(d3.scaleOrdinal().range(['red','green','blue'])); * // convenience method, the same as above * chart.ordinalColors(['red','green','blue']); * // set a linear scale * chart.linearColors(["#4575b4", "#ffffbf", "#a50026"]); - * @param {d3.scale} [colorScale=d3.scale.category20c()] + * @param {d3.scale} [colorScale=d3.scaleOrdinal(d3.schemeCategory20c)] * @returns {d3.scale|dc.colorMixin} */ _chart.colors = function (colorScale) { @@ -37,7 +37,7 @@ dc.colorMixin = function (_chart) { return _colors; } if (colorScale instanceof Array) { - _colors = d3.scale.quantize().range(colorScale); // deprecated legacy support, note: this fails for ordinal domains + _colors = d3.scaleQuantize().range(colorScale); // deprecated legacy support, note: this fails for ordinal domains } else { _colors = d3.functor(colorScale); } @@ -46,7 +46,7 @@ dc.colorMixin = function (_chart) { /** * Convenience method to set the color scale to - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Ordinal-Scales.md#ordinal d3.scale.ordinal} with + * {@link https://github.com/d3/d3-scale/blob/master/README.md#ordinal-scales d3.scaleOrdinal} with * range `r`. * @method ordinalColors * @memberof dc.colorMixin @@ -55,7 +55,7 @@ dc.colorMixin = function (_chart) { * @returns {dc.colorMixin} */ _chart.ordinalColors = function (r) { - return _chart.colors(d3.scale.ordinal().range(r)); + return _chart.colors(d3.scaleOrdinal().range(r)); }; /** @@ -67,7 +67,7 @@ dc.colorMixin = function (_chart) { * @returns {dc.colorMixin} */ _chart.linearColors = function (r) { - return _chart.colors(d3.scale.linear() + return _chart.colors(d3.scaleLinear() .range(r) .interpolate(d3.interpolateHcl)); }; diff --git a/src/composite-chart.js b/src/composite-chart.js index de1cb352d..a3608b6c5 100644 --- a/src/composite-chart.js +++ b/src/composite-chart.js @@ -11,7 +11,7 @@ * // create a composite chart under #chart-container2 element using chart group A * var compositeChart2 = dc.compositeChart('#chart-container2', 'chartGroupA'); * @param {String|node|d3.selection} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} specifying + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. @@ -31,7 +31,7 @@ dc.compositeChart = function (parent, chartGroup) { _shareTitle = true, _alignYAxes = false; - var _rightYAxis = d3.svg.axis(), + var _rightYAxis = d3.axisRight(), _rightYAxisLabel = 0, _rightYAxisLabelPadding = DEFAULT_RIGHT_Y_AXIS_LABEL_PADDING, _rightY, @@ -69,11 +69,21 @@ dc.compositeChart = function (parent, chartGroup) { }); _chart._brushing = function () { - var extent = _chart.extendBrush(); - var brushIsEmpty = _chart.brushIsEmpty(extent); + var event = d3.event; + // Avoids infinite recursion + // To ensure that when it is called because of brush.move there is no d3.event.sourceEvent + d3.event = null; + if (!event.sourceEvent) return; + var selection = event.selection; + if (selection) { + selection = selection.map(_chart.x().invert); + } + selection = _chart.extendBrush(selection); + + var brushIsEmpty = _chart.brushIsEmpty(selection); for (var i = 0; i < _children.length; ++i) { - _children[i].replaceFilter(brushIsEmpty ? null : extent); + _children[i].replaceFilter(brushIsEmpty ? null : selection); } }; @@ -153,7 +163,7 @@ dc.compositeChart = function (parent, chartGroup) { var needDomain = _chart.rightY() === undefined || _chart.elasticY(), needRange = needDomain || _chart.resizing(); if (_chart.rightY() === undefined) { - _chart.rightY(d3.scale.linear()); + _chart.rightY(d3.scaleLinear()); } if (needDomain) { _chart.rightY().domain([ranges.ryAxisMin, ranges.ryAxisMax]); @@ -165,14 +175,15 @@ dc.compositeChart = function (parent, chartGroup) { _chart.rightY().range([_chart.yAxisHeight(), 0]); _chart.rightYAxis(_chart.rightYAxis().scale(_chart.rightY())); - _chart.rightYAxis().orient('right'); + // In D3v4 create a RightAxis + // _chart.rightYAxis().orient('right'); } function prepareLeftYAxis (ranges) { var needDomain = _chart.y() === undefined || _chart.elasticY(), needRange = needDomain || _chart.resizing(); if (_chart.y() === undefined) { - _chart.y(d3.scale.linear()); + _chart.y(d3.scaleLinear()); } if (needDomain) { _chart.y().domain([ranges.lyAxisMin, ranges.lyAxisMax]); @@ -184,7 +195,8 @@ dc.compositeChart = function (parent, chartGroup) { _chart.y().range([_chart.yAxisHeight(), 0]); _chart.yAxis(_chart.yAxis().scale(_chart.y())); - _chart.yAxis().orient('left'); + // In D3v4 create a LeftAxis + // _chart.yAxis().orient('left'); } function generateChildG (child, i) { @@ -261,11 +273,11 @@ dc.compositeChart = function (parent, chartGroup) { return _chart; }; - _chart.fadeDeselectedArea = function () { + _chart.fadeDeselectedArea = function (selection) { for (var i = 0; i < _children.length; ++i) { var child = _children[i]; child.brush(_chart.brush()); - child.fadeDeselectedArea(); + child.fadeDeselectedArea(selection); } }; @@ -384,7 +396,7 @@ dc.compositeChart = function (parent, chartGroup) { * @method rightY * @memberof dc.compositeChart * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Scales.md d3.scale} + * @see {@link https://github.com/d3/d3-scale/blob/master/README.md d3.scale} * @param {d3.scale} [yScale] * @returns {d3.scale|dc.compositeChart} */ @@ -508,15 +520,21 @@ dc.compositeChart = function (parent, chartGroup) { /** * Set or get the right y axis used by the composite chart. This function is most useful when y * axis customization is required. The y axis in dc.js is an instance of a [d3 axis - * object](https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Axes.md#axis) therefore it supports any valid + * object](https://github.com/d3/d3-axis/blob/master/README.md) therefore it supports any valid * d3 axis manipulation. * * **Caution**: The y axis is usually generated internally by dc; resetting it may cause - * unexpected results. + * unexpected results. Note also that when used as a getter, this function is not chainable: it + * returns the axis, not the chart, + * {@link https://github.com/dc-js/dc.js/wiki/FAQ#why-does-everything-break-after-a-call-to-xaxis-or-yaxis + * so attempting to call chart functions after calling `.yAxis()` will fail}. + * In addition, depending on whether you are going to use the axis on left or right + * you need to appropriately pass [d3.axisLeft](https://github.com/d3/d3-axis/blob/master/README.md#axisLeft) + * or [d3.axisRight](https://github.com/d3/d3-axis/blob/master/README.md#axisRight) * @method rightYAxis * @memberof dc.compositeChart * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Axes.md#axis d3.svg.axis} + * @see {@link https://github.com/d3/d3-axis/blob/master/README.md d3.axis} * @example * // customize y axis tick format * chart.rightYAxis().tickFormat(function (v) {return v + '%';}); diff --git a/src/coordinate-grid-mixin.js b/src/coordinate-grid-mixin.js index 2e91f0cbb..015fce065 100644 --- a/src/coordinate-grid-mixin.js +++ b/src/coordinate-grid-mixin.js @@ -20,15 +20,16 @@ dc.coordinateGridMixin = function (_chart) { _chart = dc.colorMixin(dc.marginMixin(dc.baseMixin(_chart))); - _chart.colors(d3.scale.category10()); + _chart.colors(d3.scaleOrdinal(d3.schemeCategory10)); _chart._mandatoryAttributes().push('x'); var _parent; var _g; var _chartBodyG; var _x; + var _origX; // Will hold orginial scale in case of zoom var _xOriginalDomain; - var _xAxis = d3.svg.axis().orient('bottom'); + var _xAxis = d3.axisBottom(); var _xUnits = dc.units.integers; var _xAxisPadding = 0; var _xAxisPaddingUnit = 'day'; @@ -38,13 +39,15 @@ dc.coordinateGridMixin = function (_chart) { var _lastXDomain; var _y; - var _yAxis = d3.svg.axis().orient('left'); + var _yAxis = d3.axisLeft(); var _yAxisPadding = 0; var _yElasticity = false; var _yAxisLabel; var _yAxisLabelPadding = 0; - var _brush = d3.svg.brush(); + var _brush = d3.brushX(); + var _gBrush; + var _brushHandles; var _brushOn = true; var _round; @@ -57,8 +60,8 @@ dc.coordinateGridMixin = function (_chart) { var _zoomScale = [1, Infinity]; var _zoomOutRestrict = true; - var _zoom = d3.behavior.zoom().on('zoom', zoomHandler); - var _nullZoom = d3.behavior.zoom().on('zoom', null); + var _zoom = d3.zoom().on('zoom', onZoom); + var _nullZoom = d3.zoom().on('zoom', null); var _hasBeenMouseZoomable = false; var _rangeChart; @@ -225,17 +228,17 @@ dc.coordinateGridMixin = function (_chart) { * **mandatory** * * Get or set the x scale. The x scale can be any d3 - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Quantitative-Scales.md quantitive scale} or - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Ordinal-Scales.md ordinal scale}. + * {@link https://github.com/d3/d3-scale/blob/master/README.md d3.scale} or + * {@link https://github.com/d3/d3-scale/blob/master/README.md#ordinal-scales ordinal scale} * @method x * @memberof dc.coordinateGridMixin * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Scales.md d3.scale} + * @see {@link https://github.com/d3/d3-scale/blob/master/README.md d3.scale} * @example * // set x to a linear scale - * chart.x(d3.scale.linear().domain([-2500, 2500])) + * chart.x(d3.scaleLinear().domain([-2500, 2500])) * // set x to a time scale to generate histogram - * chart.x(d3.time.scale().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)])) + * chart.x(d3.scaleTime().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)])) * @param {d3.scale} [xScale] * @returns {d3.scale|dc.coordinateGridMixin} */ @@ -258,8 +261,8 @@ dc.coordinateGridMixin = function (_chart) { * the number of data projections on x axis such as the number of bars for a bar chart or the * number of dots for a line chart. This function is expected to return a Javascript array of all * data points on x axis, or the number of points on the axis. [d3 time range functions - * d3.time.days, d3.time.months, and - * d3.time.years](https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Intervals.md#aliases) are all valid xUnits + * d3.timeDays, d3.timeMonths, and + * d3.timeYears](https://github.com/d3/d3-time/blob/master/README.md#intervals) are all valid xUnits * function. dc.js also provides a few units function, see the {@link dc.units Units Namespace} for * a list of built-in units functions. * @method xUnits @@ -268,9 +271,9 @@ dc.coordinateGridMixin = function (_chart) { * @todo Add docs for utilities * @example * // set x units to count days - * chart.xUnits(d3.time.days); + * chart.xUnits(d3.timeDays); * // set x units to count months - * chart.xUnits(d3.time.months); + * chart.xUnits(d3.timeMonths); * * // A custom xUnits function can be used as long as it follows the following interface: * // units in integer @@ -297,8 +300,8 @@ dc.coordinateGridMixin = function (_chart) { /** * Set or get the x axis used by a particular coordinate grid chart instance. This function is most * useful when x axis customization is required. The x axis in dc.js is an instance of a - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Axes.md#axis d3 axis object}; - * therefore it supports any valid d3 axis manipulation. + * {@link https://github.com/d3/d3-axis/blob/master/README.md#axisBottom d3 bottom axis object}; + * therefore it supports any valid d3 axisBottom manipulation. * * **Caution**: The x axis is usually generated internally by dc; resetting it may cause * unexpected results. Note also that when used as a getter, this function is not chainable: @@ -308,14 +311,14 @@ dc.coordinateGridMixin = function (_chart) { * @method xAxis * @memberof dc.coordinateGridMixin * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Axes.md#axis d3.svg.axis} + * @see {@link https://github.com/d3/d3-axis/blob/master/README.md#axisBottom d3.axisBottom} * @example * // customize x axis tick format * chart.xAxis().tickFormat(function(v) {return v + '%';}); * // customize x axis tick values * chart.xAxis().tickValues([0, 100, 200, 300]); - * @param {d3.svg.axis} [xAxis=d3.svg.axis().orient('bottom')] - * @returns {d3.svg.axis|dc.coordinateGridMixin} + * @param {d3.axisBottom} [xAxis=d3.axisBottom] + * @returns {d3.axisBottom|dc.coordinateGridMixin} */ _chart.xAxis = function (xAxis) { if (!arguments.length) { @@ -371,7 +374,7 @@ dc.coordinateGridMixin = function (_chart) { * * Padding unit is a string that will be used when the padding is calculated. Available parameters are * the available d3 time intervals; see - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Intervals.md#interval d3.time.interval}. + * {@link https://github.com/d3/d3-time/blob/master/README.md#intervals d3.timeInterval}. * @method xAxisPaddingUnit * @memberof dc.coordinateGridMixin * @instance @@ -396,7 +399,13 @@ dc.coordinateGridMixin = function (_chart) { */ _chart.xUnitCount = function () { if (_unitCount === undefined) { - var units = _chart.xUnits()(_chart.x().domain()[0], _chart.x().domain()[1], _chart.x().domain()); + var units; + if(_chart.xUnits() === dc.units.ordinal) { + // In this case it number of items in domain + units = _chart.x().domain(); + } else { + units = _chart.xUnits()(_chart.x().domain()[0], _chart.x().domain()[1]); + } if (units instanceof Array) { _unitCount = units.length; @@ -459,6 +468,15 @@ dc.coordinateGridMixin = function (_chart) { _x.domain([_chart.xAxisMin(), _chart.xAxisMax()]); } } else { // _chart.isOrdinal() + // D3v4 - Ordinal charts would need scaleBand + // bandwidth is a method in scaleBand + // (https://github.com/d3/d3-scale/blob/master/README.md#scaleBand) + if (!_x.bandwidth) { + // If _x is not a scaleBand create a new scale and + // copy the original domain to the new scale + _x = d3.scaleBand().domain(_x.domain()); + } + if (_chart.elasticX() || _x.domain().length === 0) { _x.domain(_chart._ordinalXDomain()); } @@ -473,8 +491,9 @@ dc.coordinateGridMixin = function (_chart) { // please can't we always use rangeBands for bar charts? if (_chart.isOrdinal()) { - _x.rangeBands([0, _chart.xAxisLength()], _rangeBandPadding, - _chart._useOuterPadding() ? _outerRangeBandPadding : 0); + _x.range([0, _chart.xAxisLength()]) + .paddingInner(_rangeBandPadding) + .paddingOuter(_chart._useOuterPadding() ? _outerRangeBandPadding : 0); } else { _x.range([0, _chart.xAxisLength()]); } @@ -545,7 +564,8 @@ dc.coordinateGridMixin = function (_chart) { .attr('opacity', 1); // update - dc.transition(lines, _chart.transitionDuration(), _chart.transitionDelay()) + var linesGEnterUpdate = linesGEnter.merge(lines); + dc.transition(linesGEnterUpdate, _chart.transitionDuration(), _chart.transitionDelay()) .attr('x1', function (d) { return _x(d); }) @@ -594,7 +614,7 @@ dc.coordinateGridMixin = function (_chart) { _chart._prepareYAxis = function (g) { if (_y === undefined || _chart.elasticY()) { if (_y === undefined) { - _y = d3.scale.linear(); + _y = d3.scaleLinear(); } var min = _chart.yAxisMin() || 0, max = _chart.yAxisMax() || 0; @@ -602,12 +622,19 @@ dc.coordinateGridMixin = function (_chart) { } _y.range([_chart.yAxisHeight(), 0]); - _yAxis = _yAxis.scale(_y); - if (_useRightYAxis) { - _yAxis.orient('right'); + // Ideally we should update the API so that if someone uses Right Y Axis + // they would need to pass _yAxis as well + if (!_yAxis) { + if (_useRightYAxis) { + _yAxis = d3.axisRight(); + } else { + _yAxis = d3.axisLeft(); + } } + _yAxis = _yAxis.scale(_y); + _chart._renderHorizontalGridLinesForAxis(g, _y, _yAxis); }; @@ -655,7 +682,8 @@ dc.coordinateGridMixin = function (_chart) { var gridLineG = g.select('g.' + HORIZONTAL_CLASS); if (_renderHorizontalGridLine) { - var ticks = axis.tickValues() ? axis.tickValues() : scale.ticks(axis.ticks()[0]); + // Last part copied from https://github.com/d3/d3-axis/blob/master/src/axis.js#L48 + var ticks = axis.tickValues() ? axis.tickValues() : scale.ticks.apply(scale, axis.tickArguments()); if (gridLineG.empty()) { gridLineG = g.insert('g', ':first-child') @@ -682,7 +710,8 @@ dc.coordinateGridMixin = function (_chart) { .attr('opacity', 1); // update - dc.transition(lines, _chart.transitionDuration(), _chart.transitionDelay()) + var linesGEnterUpdate = linesGEnter.merge(lines); + dc.transition(linesGEnterUpdate, _chart.transitionDuration(), _chart.transitionDelay()) .attr('x1', 1) .attr('y1', function (d) { return scale(d); @@ -730,7 +759,7 @@ dc.coordinateGridMixin = function (_chart) { * @method y * @memberof dc.coordinateGridMixin * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Scales.md d3.scale} + * @see {@link https://github.com/d3/d3-scale/blob/master/README.md d3.scale} * @param {d3.scale} [yScale] * @returns {d3.scale|dc.coordinateGridMixin} */ @@ -746,7 +775,7 @@ dc.coordinateGridMixin = function (_chart) { /** * Set or get the y axis used by the coordinate grid chart instance. This function is most useful * when y axis customization is required. The y axis in dc.js is simply an instance of a [d3 axis - * object](https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Axes.md#axis); therefore it supports any + * object](https://github.com/d3/d3-axis/blob/master/README.md); therefore it supports any * valid d3 axis manipulation. * * **Caution**: The y axis is usually generated internally by dc; resetting it may cause @@ -754,10 +783,13 @@ dc.coordinateGridMixin = function (_chart) { * returns the axis, not the chart, * {@link https://github.com/dc-js/dc.js/wiki/FAQ#why-does-everything-break-after-a-call-to-xaxis-or-yaxis * so attempting to call chart functions after calling `.yAxis()` will fail}. + * In addition, depending on whether you are going to use the axis on left or right + * you need to appropriately pass [d3.axisLeft](https://github.com/d3/d3-axis/blob/master/README.md#axisLeft) + * or [d3.axisRight](https://github.com/d3/d3-axis/blob/master/README.md#axisRight) * @method yAxis * @memberof dc.coordinateGridMixin * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Axes.md#axis d3.svg.axis} + * @see {@link https://github.com/d3/d3-axis/blob/master/README.md d3.axis} * @example * // customize y axis tick format * chart.yAxis().tickFormat(function(v) {return v + '%';}); @@ -912,7 +944,7 @@ dc.coordinateGridMixin = function (_chart) { * @example * // set x unit round to by month, this will make sure range selection brush will * // select whole months - * chart.round(d3.time.month.round); + * chart.round(d3.timeMonth.round); * @param {Function} [round] * @returns {Function|dc.coordinateGridMixin} */ @@ -947,15 +979,26 @@ dc.coordinateGridMixin = function (_chart) { _chart._filter(_); - if (_) { - _chart.brush().extent(_); - } else { - _chart.brush().clear(); - } + _chart.redrawBrush(_); return _chart; }); + /** + * Get or set the brush. Brush must be an instance of d3 brushes + * https://github.com/d3/d3-brush/blob/master/README.md + * You will use this only if you are writing a new chart type that supports brushing. + * + * **Caution**: dc creates and manages brushes internally. Go through and understand the source code + * if you want to pass a new brush object. Even if you are only using the getter, + * the brush object may not behave the way you expect. + * + * @method brush + * @memberof dc.coordinateGridMixin + * @instance + * @param {d3.brush} [brush] + * @returns {d3.brush|dc.coordinateGridMixin} + */ _chart.brush = function (_) { if (!arguments.length) { return _brush; @@ -964,68 +1007,78 @@ dc.coordinateGridMixin = function (_chart) { return _chart; }; - function brushHeight () { - return _chart._xAxisY() - _chart.margins().top; + function brushHeight() { + return _chart.effectiveHeight(); + } + + function brushWidth() { + return _chart.effectiveWidth(); } _chart.renderBrush = function (g) { if (_brushOn) { - _brush.on('brush', _chart._brushing); - _brush.on('brushstart', _chart._disableMouseZoom); - _brush.on('brushend', configureMouseZoom); + _brush.on('start brush end', _chart._brushing); - var gBrush = g.append('g') + // Set boundaries of the brush, must set it before applying to _gBrush + _brush.extent([[0, 0], [brushWidth(), brushHeight()]]); + + // To retrieve selection we need _gBrush + _gBrush = g.append('g') .attr('class', 'brush') .attr('transform', 'translate(' + _chart.margins().left + ',' + _chart.margins().top + ')') - .call(_brush.x(_chart.x())); - _chart.setBrushY(gBrush, false); - _chart.setHandlePaths(gBrush); + .call(_brush); - if (_chart.hasFilter()) { - _chart.redrawBrush(g, false); - } + _chart.setHandlePaths(_gBrush); + + _chart.redrawBrush(_chart.filter()); } }; _chart.setHandlePaths = function (gBrush) { - gBrush.selectAll('.resize').append('path').attr('d', _chart.resizeHandlePath); - }; + _brushHandles = gBrush.selectAll('.handle--custom').data([{type: "w"}, {type: "e"}]); - _chart.setBrushY = function (gBrush) { - gBrush.selectAll('rect') - .attr('height', brushHeight()); - gBrush.selectAll('.resize path') - .attr('d', _chart.resizeHandlePath); + _brushHandles = _brushHandles + .enter() + .append('path') + .attr("class", "handle--custom") + .attr('d', _chart.resizeHandlePath) + .merge(_brushHandles); }; - _chart.extendBrush = function () { - var extent = _brush.extent(); - if (_chart.round()) { - extent[0] = extent.map(_chart.round())[0]; - extent[1] = extent.map(_chart.round())[1]; - - _g.select('.brush') - .call(_brush.extent(extent)); + _chart.extendBrush = function (selection) { + if (selection && _chart.round()) { + selection[0] = _chart.round()(selection[0]); + selection[1] = _chart.round()(selection[1]); } - return extent; + return selection; }; - _chart.brushIsEmpty = function (extent) { - return _brush.empty() || !extent || extent[1] <= extent[0]; + _chart.brushIsEmpty = function (selection) { + return !selection || selection[1] <= selection[0]; }; _chart._brushing = function () { - var extent = _chart.extendBrush(); + var event = d3.event; + // Avoids infinite recursion + // To ensure that when it is called because of brush.move there is no d3.event.sourceEvent + d3.event = null; + if (!event.sourceEvent) return; + var selection = event.selection; + if (selection) { + selection = selection.map(_chart.x().invert); + } - _chart.redrawBrush(_g, false); + selection = _chart.extendBrush(selection); - if (_chart.brushIsEmpty(extent)) { + _chart.redrawBrush(selection); + + if (_chart.brushIsEmpty(selection)) { dc.events.trigger(function () { _chart.filter(null); _chart.redrawGroup(); }, dc.constants.EVENT_DELAY); } else { - var rangedFilter = dc.filters.RangedFilter(extent[0], extent[1]); + var rangedFilter = dc.filters.RangedFilter(selection[0], selection[1]); dc.events.trigger(function () { _chart.replaceFilter(rangedFilter); @@ -1034,28 +1087,34 @@ dc.coordinateGridMixin = function (_chart) { } }; - _chart.redrawBrush = function (g, doTransition) { - if (_brushOn) { - if (_chart.filter() && _chart.brush().empty()) { - _chart.brush().extent(_chart.filter()); - } + _chart.redrawBrush = function (selection) { + if (_brushOn && _gBrush) { + if (!selection) { + _brush.move(_gBrush, null); - var gBrush = dc.optionalTransition(doTransition, _chart.transitionDuration(), _chart.transitionDelay())(g.select('g.brush')); - _chart.setBrushY(gBrush); - gBrush.call(_chart.brush() - .x(_chart.x()) - .extent(_chart.brush().extent())); + _brushHandles + .attr("display", "none"); + } else { + var scaledSelection = [_x(selection[0]), _x(selection[1])]; + _brush.move(_gBrush, scaledSelection); + + _brushHandles + .attr("display", null) + .attr("transform", function (d, i) { + return "translate(" + _x(selection[i]) + ", 0)"; + }); + } } - - _chart.fadeDeselectedArea(); + _chart.fadeDeselectedArea(selection); }; - _chart.fadeDeselectedArea = function () { + _chart.fadeDeselectedArea = function (selection) { // do nothing, sub-chart should override this function }; // borrowed from Crossfilter example _chart.resizeHandlePath = function (d) { + d = d.type; var e = +(d === 'e'), x = e ? 1 : -1, y = brushHeight() / 3; return 'M' + (0.5 * x) + ',' + y + 'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6) + @@ -1152,13 +1211,16 @@ dc.coordinateGridMixin = function (_chart) { if (render) { _chart.renderBrush(_chart.g(), false); } else { - _chart.redrawBrush(_chart.g(), _resizing); + _chart.redrawBrush(_chart.filter()); } - _chart.fadeDeselectedArea(); + _chart.fadeDeselectedArea(_chart.filter()); _resizing = false; } function configureMouseZoom () { + // Save a copy of original x scale + _origX = _x.copy(); + if (_mouseZoomable) { _chart._enableMouseZoom(); } else if (_hasBeenMouseZoomable) { @@ -1168,10 +1230,12 @@ dc.coordinateGridMixin = function (_chart) { _chart._enableMouseZoom = function () { _hasBeenMouseZoomable = true; - _zoom.x(_chart.x()) + + _zoom .scaleExtent(_zoomScale) - .size([_chart.width(), _chart.height()]) + .extent([[0, 0], [_chart.width(), _chart.height()]]) .duration(_chart.transitionDuration()); + _chart.root().call(_zoom); }; @@ -1215,6 +1279,14 @@ dc.coordinateGridMixin = function (_chart) { _refocused = !rangesEqual(domain, _xOriginalDomain); } + function onZoom () { + if (!d3.event.sourceEvent && d3.event.sourceEvent.type !== "zoom") return; + + _chart.x(d3.event.transform.rescaleX(_origX)); + + zoomHandler(); + } + function intersectExtents (ext1, ext2) { if (ext1[0] > ext2[1] || ext1[1] < ext2[0]) { console.warn('could not intersect extents'); @@ -1258,7 +1330,6 @@ dc.coordinateGridMixin = function (_chart) { _chart.x().domain(_xOriginalDomain); } - _zoom.x(_chart.x()); zoomHandler(); }; @@ -1285,7 +1356,7 @@ dc.coordinateGridMixin = function (_chart) { return _chart; }; - function rangesEqual (range1, range2) { + function rangesEqual(range1, range2) { if (!range1 && !range2) { return true; } else if (!range1 || !range2) { @@ -1320,6 +1391,11 @@ dc.coordinateGridMixin = function (_chart) { return _chart; }; + // Get the SVG rendered brush + _chart.gBrush = function () { + return _gBrush; + }; + function hasRangeSelected (range) { return range instanceof Array && range.length > 1; } diff --git a/src/core.js b/src/core.js index 6a911e032..64dcb9ee6 100644 --- a/src/core.js +++ b/src/core.js @@ -319,7 +319,7 @@ dc.afterTransition = function (transition, callback) { var n = 0; transition .each(function () { ++n; }) - .each('end', function () { + .on('end', function () { if (!--n) { callback.call(transition); } @@ -355,17 +355,17 @@ dc.units.integers = function (start, end) { /** * This argument can be passed to the {@link dc.coordinateGridMixin#xUnits .xUnits} function of the to * specify ordinal units for the x axis. Usually this parameter is used in combination with passing - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Ordinal-Scales.md d3.scale.ordinal} to + * {@link https://github.com/d3/d3-scale/blob/master/README.md#ordinal-scales d3.scaleOrdinal} to * {@link dc.coordinateGridMixin#x .x}. * It just returns the domain passed to it, which for ordinal charts is an array of all values. * @method ordinal * @memberof dc.units - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Ordinal-Scales.md d3.scale.ordinal} + * @see {@link https://github.com/d3/d3-scale/blob/master/README.md#ordinal-scales d3.scaleOrdinal} * @see {@link dc.coordinateGridMixin#xUnits coordinateGridMixin.xUnits} * @see {@link dc.coordinateGridMixin#x coordinateGridMixin.x} * @example * chart.xUnits(dc.units.ordinal) - * .x(d3.scale.ordinal()) + * .x(d3.scaleOrdinal()) * @param {*} start * @param {*} end * @param {Array} domain diff --git a/src/d3.box.js b/src/d3.box.js index 5aaa9df7f..147bb0da1 100644 --- a/src/d3.box.js +++ b/src/d3.box.js @@ -35,12 +35,12 @@ d3.range(0, whiskerIndices[0]).concat(d3.range(whiskerIndices[1] + 1, n)) : d3.range(n); // Compute the new x-scale. - var x1 = d3.scale.linear() + var x1 = d3.scaleLinear() .domain(domain && domain.call(this, d, i) || [min, max]) .range([height, 0]); // Retrieve the old x-scale, if this is an update. - var x0 = this.__chart__ || d3.scale.linear() + var x0 = this.__chart__ || d3.scaleLinear() .domain([0, Infinity]) .range(x1.range()); @@ -261,7 +261,7 @@ .style('opacity', 1e-6) .remove(); }); - d3.timer.flush(); + d3.timerFlush(); } box.width = function (x) { diff --git a/src/d3v3-compat.js b/src/d3v3-compat.js new file mode 100644 index 000000000..da75659d2 --- /dev/null +++ b/src/d3v3-compat.js @@ -0,0 +1,97 @@ +// Missing in D3v4, code picked up from D3v3 +d3.functor = function (v) { + return typeof v === "function" ? v : function () { + return v; + }; +}; + +// Significant changes in d3.layout.stack - copying from D3v3 for now +d3.stackD3v3 = function () { + function d3_layout_stackOrderDefault(data) { + return d3.range(data.length); + } + + function d3_layout_stackOffsetZero(data) { + var j = -1, m = data[0].length, y0 = []; + while (++j < m) y0[j] = 0; + return y0; + } + + function d3_layout_stackOut(d, y0, y) { + d.y0 = y0; + d.y = y; + } + + function d3_layout_stackX(d) { + return d.x; + } + + function d3_layout_stackY(d) { + return d.y; + } + + function d3_identity(d) { + return d; + } + + return function () { + var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, + out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY; + + function stack(data, index) { + if (!(n = data.length)) return data; + var series = data.map(function (d, i) { + return values.call(stack, d, i); + }); + var points = series.map(function (d) { + return d.map(function (v, i) { + return [x.call(stack, v, i), y.call(stack, v, i)]; + }); + }); + var orders = order.call(stack, points, index); + series = d3.permute(series, orders); + points = d3.permute(points, orders); + var offsets = offset.call(stack, points, index); + var m = series[0].length, n, i, j, o; + for (j = 0; j < m; ++j) { + out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); + for (i = 1; i < n; ++i) { + out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); + } + } + return data; + } + + stack.values = function (x) { + if (!arguments.length) return values; + values = x; + return stack; + }; + stack.order = function (x) { + if (!arguments.length) return order; + order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault; + return stack; + }; + stack.offset = function (x) { + if (!arguments.length) return offset; + offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero; + return stack; + }; + stack.x = function (z) { + if (!arguments.length) return x; + x = z; + return stack; + }; + stack.y = function (z) { + if (!arguments.length) return y; + y = z; + return stack; + }; + stack.out = function (z) { + if (!arguments.length) return out; + out = z; + return stack; + }; + return stack; + } +}(); diff --git a/src/data-count.js b/src/data-count.js index 82adf8518..619bdaa5f 100644 --- a/src/data-count.js +++ b/src/data-count.js @@ -23,7 +23,7 @@ * .dimension(ndx) * .group(all); * @param {String|node|d3.selection} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} specifying + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. @@ -69,7 +69,7 @@ dc.dataCount = function (parent, chartGroup) { * @method formatNumber * @memberof dc.dataCount * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Formatting.md d3.format} + * @see {@link https://github.com/d3/d3-format/blob/master/README.md#format d3.format} * @example * counter.formatNumber(d3.format('.2g')) * @param {Function} [formatter=d3.format('.2g')] diff --git a/src/data-grid.js b/src/data-grid.js index 9bdac5f95..2dd31c94d 100644 --- a/src/data-grid.js +++ b/src/data-grid.js @@ -3,7 +3,7 @@ * a simple way to define how the items are displayed. * * Note: Unlike other charts, the data grid chart (and data table) use the {@link dc.dataGrid#group group} attribute as a keying function - * for {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Arrays.md#nest nesting} the data together in groups. + * for {@link https://github.com/d3/d3-collection/blob/master/README.md#nest nesting} the data together in groups. * Do not pass in a crossfilter group as this will not work. * * Examples: @@ -12,7 +12,7 @@ * @memberof dc * @mixes dc.baseMixin * @param {String|node|d3.selection} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} specifying + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. @@ -87,15 +87,17 @@ dc.dataGrid = function (parent, chartGroup) { return d.values; }); - items.enter() - .append('div') - .attr('class', ITEM_CSS_CLASS) - .html(function (d) { - return _html(d); - }); - items.exit().remove(); + items = items + .enter() + .append('div') + .attr('class', ITEM_CSS_CLASS) + .html(function (d) { + return _html(d); + }) + .merge(items); + return items; } @@ -105,7 +107,7 @@ dc.dataGrid = function (parent, chartGroup) { /** * Get or set the group function for the data grid. The group function takes a data row and - * returns the key to specify to {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Arrays.md#d3_nest d3.nest} + * returns the key to specify to {@link https://github.com/d3/d3-collection/blob/master/README.md#nest d3.nest} * to split rows into groups. * * Do not pass in a crossfilter group as this will not work. @@ -234,8 +236,8 @@ dc.dataGrid = function (parent, chartGroup) { * @method order * @memberof dc.dataGrid * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Arrays.md#d3_ascending d3.ascending} - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Arrays.md#d3_descending d3.descending} + * @see {@link https://github.com/d3/d3-array/blob/master/README.md#ascending d3.ascending} + * @see {@link https://github.com/d3/d3-array/blob/master/README.md#descending d3.descending} * @example * chart.order(d3.descending); * @param {Function} [order=d3.ascending] diff --git a/src/data-table.js b/src/data-table.js index 108761705..22e1f61e8 100644 --- a/src/data-table.js +++ b/src/data-table.js @@ -3,7 +3,7 @@ * filtered) in a good old tabular fashion. * * Note: Unlike other charts, the data table (and data grid chart) use the {@link dc.dataTable#group group} attribute as a - * keying function for {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Arrays.md#nest nesting} the data + * keying function for {@link https://github.com/d3/d3-collection/blob/master/README.md#nest nesting} the data * together in groups. Do not pass in a crossfilter group as this will not work. * * Another interesting feature of the data table is that you can pass a crossfilter group to the `dimension`, as @@ -19,7 +19,7 @@ * @memberof dc * @mixes dc.baseMixin * @param {String|node|d3.selection} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} specifying + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. @@ -110,25 +110,27 @@ dc.dataTable = function (parent, chartGroup) { if (!bAllFunctions) { // ensure one thead var thead = _chart.selectAll('thead').data([0]); - thead.enter().append('thead'); thead.exit().remove(); + thead = thead.enter() + .append('thead') + .merge(thead); // with one tr var headrow = thead.selectAll('tr').data([0]); - headrow.enter().append('tr'); headrow.exit().remove(); + headrow = headrow.enter() + .append('tr') + .merge(headrow); // with a th for each column var headcols = headrow.selectAll('th') .data(_columns); - headcols.enter().append('th'); headcols.exit().remove(); - - headcols - .attr('class', HEAD_CSS_CLASS) + headcols.enter().append('th') + .merge(headcols) + .attr('class', HEAD_CSS_CLASS) .html(function (d) { return (_chart._doColumnHeaderFormat(d)); - }); } @@ -204,7 +206,7 @@ dc.dataTable = function (parent, chartGroup) { /** * Get or set the group function for the data table. The group function takes a data row and - * returns the key to specify to {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Arrays.md#d3_nest d3.nest} + * returns the key to specify to {@link https://github.com/d3/d3-collection/blob/master/README.md#nest d3.nest} * to split rows into groups. * * Do not pass in a crossfilter group as this will not work. @@ -388,8 +390,8 @@ dc.dataTable = function (parent, chartGroup) { * @method order * @memberof dc.dataTable * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Arrays.md#d3_ascending d3.ascending} - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Arrays.md#d3_descending d3.descending} + * @see {@link https://github.com/d3/d3-array/blob/master/README.md#ascending d3.ascending} + * @see {@link https://github.com/d3/d3-array/blob/master/README.md#descending d3.descending} * @example * chart.order(d3.descending); * @param {Function} [order=d3.ascending] diff --git a/src/geo-choropleth-chart.js b/src/geo-choropleth-chart.js index e0b1971f2..683a8b07e 100644 --- a/src/geo-choropleth-chart.js +++ b/src/geo-choropleth-chart.js @@ -15,7 +15,7 @@ * // create a choropleth chart under '#us-chart2' element using chart group A * var chart2 = dc.compositeChart('#us-chart2', 'chartGroupA'); * @param {String|node|d3.selection} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} specifying + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. @@ -28,7 +28,7 @@ dc.geoChoroplethChart = function (parent, chartGroup) { return d || 0; }); - var _geoPath = d3.geo.path(); + var _geoPath = d3.geoPath(); var _projectionFlag; var _geoJsons = []; @@ -40,10 +40,12 @@ dc.geoChoroplethChart = function (parent, chartGroup) { .attr('class', 'layer' + layerIndex); var regionG = states.selectAll('g.' + geoJson(layerIndex).name) - .data(geoJson(layerIndex).data) - .enter() - .append('g') - .attr('class', geoJson(layerIndex).name); + .data(geoJson(layerIndex).data); + + regionG = regionG.enter() + .append('g') + .attr('class', geoJson(layerIndex).name) + .merge(regionG); regionG .append('path') @@ -210,13 +212,13 @@ dc.geoChoroplethChart = function (parent, chartGroup) { /** * Set custom geo projection function. See the available - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Geo-Projections.md d3 geo projection functions}. + * {@link https://github.com/d3/d3-geo/blob/master/README.md#projections d3 geo projection functions}. * @method projection * @memberof dc.geoChoroplethChart * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Geo-Projections.md d3.geo.projection} - * @see {@link https://github.com/d3/d3-geo-projection Extended d3.geo.projection} - * @param {d3.projection} [projection=d3.geo.albersUsa()] + * @see {@link https://github.com/d3/d3-geo/blob/master/README.md#projections d3.projection} + * @see {@link https://github.com/d3/d3-geo-projection d3-geo-projection} + * @param {d3.projection} [projection=d3.geoAlbersUsa()] * @returns {dc.geoChoroplethChart} */ _chart.projection = function (projection) { @@ -239,14 +241,14 @@ dc.geoChoroplethChart = function (parent, chartGroup) { }; /** - * Returns the {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Geo-Paths.md#path d3.geo.path} object used to + * Returns the {@link https://github.com/d3/d3-geo/blob/master/README.md#paths d3.geoPath} object used to * render the projection and features. Can be useful for figuring out the bounding box of the * feature set and thus a way to calculate scale and translation for the projection. * @method geoPath * @memberof dc.geoChoroplethChart * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Geo-Paths.md#path d3.geo.path} - * @returns {d3.geo.path} + * @see {@link https://github.com/d3/d3-geo/blob/master/README.md#paths d3.geoPath} + * @returns {d3.geoPath} */ _chart.geoPath = function () { return _geoPath; diff --git a/src/heatmap.js b/src/heatmap.js index 6a802cca2..7f20a4708 100644 --- a/src/heatmap.js +++ b/src/heatmap.js @@ -11,7 +11,7 @@ * // create a heat map under #chart-container2 element using chart group A * var heatMap2 = dc.heatMap('#chart-container2', 'chartGroupA'); * @param {String|node|d3.selection} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} specifying + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. @@ -27,8 +27,8 @@ dc.heatMap = function (parent, chartGroup) { var _rows; var _colOrdering = d3.ascending; var _rowOrdering = d3.ascending; - var _colScale = d3.scale.ordinal(); - var _rowScale = d3.scale.ordinal(); + var _colScale = d3.scaleBand(); + var _rowScale = d3.scaleBand(); var _xBorderRadius = DEFAULT_BORDER_RADIUS; var _yBorderRadius = DEFAULT_BORDER_RADIUS; @@ -207,12 +207,15 @@ dc.heatMap = function (parent, chartGroup) { boxWidth = Math.floor(_chart.effectiveWidth() / colCount), boxHeight = Math.floor(_chart.effectiveHeight() / rowCount); - cols.rangeRoundBands([0, _chart.effectiveWidth()]); - rows.rangeRoundBands([_chart.effectiveHeight(), 0]); + cols.rangeRound([0, _chart.effectiveWidth()]); + rows.rangeRound([_chart.effectiveHeight(), 0]); var boxes = _chartBody.selectAll('g.box-group').data(_chart.data(), function (d, i) { return _chart.keyAccessor()(d, i) + '\0' + _chart.valueAccessor()(d, i); }); + + boxes.exit().remove(); + var gEnter = boxes.enter().append('g') .attr('class', 'box-group'); @@ -226,6 +229,8 @@ dc.heatMap = function (parent, chartGroup) { boxes.select('title').text(_chart.title()); } + boxes = gEnter.merge(boxes); + dc.transition(boxes.select('rect'), _chart.transitionDuration(), _chart.transitionDelay()) .attr('x', function (d, i) { return cols(_chart.keyAccessor()(d, i)); }) .attr('y', function (d, i) { return rows(_chart.valueAccessor()(d, i)); }) @@ -235,41 +240,57 @@ dc.heatMap = function (parent, chartGroup) { .attr('width', boxWidth) .attr('height', boxHeight); - boxes.exit().remove(); var gCols = _chartBody.select('g.cols'); if (gCols.empty()) { gCols = _chartBody.append('g').attr('class', 'cols axis'); } var gColsText = gCols.selectAll('text').data(cols.domain()); - gColsText.enter().append('text') - .attr('x', function (d) { return cols(d) + boxWidth / 2; }) - .style('text-anchor', 'middle') - .attr('y', _chart.effectiveHeight()) - .attr('dy', 12) - .on('click', _chart.xAxisOnClick()) - .text(_chart.colsLabel()); + + gColsText.exit().remove(); + + gColsText = gColsText + .enter() + .append('text') + .attr('x', function (d) { + return cols(d) + boxWidth / 2; + }) + .style('text-anchor', 'middle') + .attr('y', _chart.effectiveHeight()) + .attr('dy', 12) + .on('click', _chart.xAxisOnClick()) + .text(_chart.colsLabel()) + .merge(gColsText); + dc.transition(gColsText, _chart.transitionDuration(), _chart.transitionDelay()) .text(_chart.colsLabel()) .attr('x', function (d) { return cols(d) + boxWidth / 2; }) .attr('y', _chart.effectiveHeight()); - gColsText.exit().remove(); + + var gRows = _chartBody.select('g.rows'); if (gRows.empty()) { gRows = _chartBody.append('g').attr('class', 'rows axis'); } + var gRowsText = gRows.selectAll('text').data(rows.domain()); - gRowsText.enter().append('text') - .attr('dy', 6) - .style('text-anchor', 'end') - .attr('x', 0) - .attr('dx', -2) - .on('click', _chart.yAxisOnClick()) - .text(_chart.rowsLabel()); + + gRowsText.exit().remove(); + + gRowsText = gRowsText + .enter() + .append('text') + .attr('dy', 6) + .style('text-anchor', 'end') + .attr('x', 0) + .attr('dx', -2) + .on('click', _chart.yAxisOnClick()) + .text(_chart.rowsLabel()) + .merge(gRowsText); + dc.transition(gRowsText, _chart.transitionDuration(), _chart.transitionDelay()) .text(_chart.rowsLabel()) .attr('y', function (d) { return rows(d) + boxHeight / 2; }); - gRowsText.exit().remove(); if (_chart.hasFilter()) { _chart.selectAll('g.box-group').each(function (d) { diff --git a/src/line-chart.js b/src/line-chart.js index b8f0b9410..020294ba8 100644 --- a/src/line-chart.js +++ b/src/line-chart.js @@ -16,7 +16,7 @@ * // create a sub-chart under a composite parent chart * var chart3 = dc.lineChart(compositeChart); * @param {String|node|d3.selection|dc.compositeChart} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} * specifying a dom block element such as a div; or a dom element or d3 selection. If the line * chart is a sub-chart in a {@link dc.compositeChart Composite Chart} then pass in the parent * composite chart instance instead. @@ -39,8 +39,8 @@ dc.lineChart = function (parent, chartGroup) { var _dataPointRadius = null; var _dataPointFillOpacity = DEFAULT_DOT_OPACITY; var _dataPointStrokeOpacity = DEFAULT_DOT_OPACITY; - var _interpolate = 'linear'; - var _tension = 0.7; + var _interpolate = d3.curveLinear; + var _tension = 0; var _defined; var _dashStyle; var _xyTipsOn = true; @@ -66,6 +66,8 @@ dc.lineChart = function (parent, chartGroup) { return 'stack ' + '_' + i; }); + layers = layersEnter.merge(layers); + drawLine(layersEnter, layers); drawArea(layersEnter, layers); @@ -79,17 +81,20 @@ dc.lineChart = function (parent, chartGroup) { /** * Gets or sets the interpolator to use for lines drawn, by string name, allowing e.g. step - * functions, splines, and cubic interpolation. This is passed to - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#line_interpolate d3.svg.line.interpolate} and - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#area_interpolate d3.svg.area.interpolate}, + * functions, splines, and cubic interpolation. Typically you would use one of the interpolator functions + * provided by {@link https://github.com/d3/d3-shape/blob/master/README.md#curves d3 curves}. + * Please note that d3 version 4 has renamed interpolate to curve. + * This is passed to + * {@link https://github.com/d3/d3-shape/blob/master/README.md#line_curve line.curve} and + * {@link https://github.com/d3/d3-shape/blob/master/README.md#area_curve area.curve}, * where you can find a complete list of valid arguments. * @method interpolate * @memberof dc.lineChart * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#line_interpolate d3.svg.line.interpolate} - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#area_interpolate d3.svg.area.interpolate} - * @param {String} [interpolate='linear'] - * @returns {String|dc.lineChart} + * @see {@link https://github.com/d3/d3-shape/blob/master/README.md#line_curve line.curve} + * @see {@link https://github.com/d3/d3-shape/blob/master/README.md#area_curve area.curve} + * @param {d3.curve} [interpolate=d3.curveLinear()] + * @returns {d3.curve|dc.lineChart} */ _chart.interpolate = function (interpolate) { if (!arguments.length) { @@ -101,16 +106,25 @@ dc.lineChart = function (parent, chartGroup) { /** * Gets or sets the tension to use for lines drawn, in the range 0 to 1. - * This parameter further customizes the interpolation behavior. It is passed to - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#line_tension d3.svg.line.tension} and - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#area_tension d3.svg.area.tension}. + * Some interpolate (curve) functions {@link https://github.com/d3/d3-shape/blob/master/README.md#curves d3 curves} + * support additional customization using tension. Example: + * {@link https://github.com/d3/d3-shape/blob/master/README.md#curveCardinal_tension curveCardinal.tension}. + * It is passed to the interpolate (d3 curve) function if it supports concept of tension. + * See individual {@link https://github.com/d3/d3-shape/blob/master/README.md#curves d3 curve functions} + * documentation for their support of tension. * @method tension * @memberof dc.lineChart * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#line_interpolate d3.svg.line.interpolate} - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#area_interpolate d3.svg.area.interpolate} - * @param {Number} [tension=0.7] + * @see {@link https://github.com/d3/d3-shape/blob/master/README.md#line_curve line.curve} + * @see {@link https://github.com/d3/d3-shape/blob/master/README.md#area_curve area.curve} + * @param {Number} [tension=0] * @returns {Number|dc.lineChart} + * + * + * @see {@link https://github.com/d3/d3-shape/blob/master/README.md#line_curve line.curve} + * @see {@link https://github.com/d3/d3-shape/blob/master/README.md#area_curve area.curve} + * @param {d3.curve} [interpolate=d3.curveLinear()] + * @returns {d3.curve|dc.lineChart} */ _chart.tension = function (tension) { if (!arguments.length) { @@ -124,7 +138,7 @@ dc.lineChart = function (parent, chartGroup) { * Gets or sets a function that will determine discontinuities in the line which should be * skipped: the path will be broken into separate subpaths if some points are undefined. * This function is passed to - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#line_defined d3.svg.line.defined} + * {@link https://github.com/d3/d3-shape/blob/master/README.md#line_defined line.defined} * * Note: crossfilter will sometimes coerce nulls to 0, so you may need to carefully write * custom reduce functions to get this to work, depending on your data. See @@ -133,7 +147,7 @@ dc.lineChart = function (parent, chartGroup) { * @method defined * @memberof dc.lineChart * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#line_defined d3.svg.line.defined} + * @see {@link https://github.com/d3/d3-shape/blob/master/README.md#line_defined line.defined} * @param {Function} [defined] * @returns {Function|dc.lineChart} */ @@ -187,16 +201,21 @@ dc.lineChart = function (parent, chartGroup) { return _chart.getColor.call(d, d.values, i); } + // Behavior of interpolator has changed in D3v4 + var _interpolateWithTension = function () { + return typeof _interpolate.tension === "function" ? + _interpolate.tension(_tension) : _interpolate; + }; + function drawLine (layersEnter, layers) { - var line = d3.svg.line() + var line = d3.line() .x(function (d) { return _chart.x()(d.x); }) .y(function (d) { return _chart.y()(d.y + d.y0); }) - .interpolate(_interpolate) - .tension(_tension); + .curve(_interpolateWithTension()); if (_defined) { line.defined(_defined); } @@ -218,18 +237,17 @@ dc.lineChart = function (parent, chartGroup) { function drawArea (layersEnter, layers) { if (_renderArea) { - var area = d3.svg.area() + var area = d3.area() .x(function (d) { return _chart.x()(d.x); }) - .y(function (d) { + .y1(function (d) { return _chart.y()(d.y + d.y0); }) .y0(function (d) { return _chart.y()(d.y0); }) - .interpolate(_interpolate) - .tension(_tension); + .curve(_interpolateWithTension()); if (_defined) { area.defined(_defined); } @@ -279,27 +297,29 @@ dc.lineChart = function (parent, chartGroup) { var dots = g.selectAll('circle.' + DOT_CIRCLE_CLASS) .data(points, dc.pluck('x')); - dots.enter() - .append('circle') - .attr('class', DOT_CIRCLE_CLASS) - .attr('r', getDotRadius()) - .style('fill-opacity', _dataPointFillOpacity) - .style('stroke-opacity', _dataPointStrokeOpacity) - .attr('fill', _chart.getColor) - .on('mousemove', function () { - var dot = d3.select(this); - showDot(dot); - showRefLines(dot, g); - }) - .on('mouseout', function () { - var dot = d3.select(this); - hideDot(dot); - hideRefLines(g); - }); - - dots.call(renderTitle, d); - - dc.transition(dots, _chart.transitionDuration()) + var dotsEnterModify = dots + .enter() + .append('circle') + .attr('class', DOT_CIRCLE_CLASS) + .attr('r', getDotRadius()) + .style('fill-opacity', _dataPointFillOpacity) + .style('stroke-opacity', _dataPointStrokeOpacity) + .attr('fill', _chart.getColor) + .on('mousemove', function () { + var dot = d3.select(this); + showDot(dot); + showRefLines(dot, g); + }) + .on('mouseout', function () { + var dot = d3.select(this); + hideDot(dot); + hideRefLines(g); + }) + .merge(dots); + + dotsEnterModify.call(renderTitle, d); + + dc.transition(dotsEnterModify, _chart.transitionDuration()) .attr('cx', function (d) { return dc.utils.safeNumber(_chart.x()(d.x)); }) @@ -323,12 +343,14 @@ dc.lineChart = function (parent, chartGroup) { var labels = layer.selectAll('text.lineLabel') .data(d.values, dc.pluck('x')); - labels.enter() - .append('text') - .attr('class', 'lineLabel') - .attr('text-anchor', 'middle'); + var labelsEnterModify = labels + .enter() + .append('text') + .attr('class', 'lineLabel') + .attr('text-anchor', 'middle') + .merge(labels); - dc.transition(labels, _chart.transitionDuration()) + dc.transition(labelsEnterModify, _chart.transitionDuration()) .attr('x', function (d) { return dc.utils.safeNumber(_chart.x()(d.x)); }) diff --git a/src/number-display.js b/src/number-display.js index a19e891cb..10d52890a 100644 --- a/src/number-display.js +++ b/src/number-display.js @@ -9,7 +9,7 @@ * // create a number display under #chart-container1 element using the default global chart group * var display1 = dc.numberDisplay('#chart-container1'); * @param {String|node|d3.selection} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} specifying + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. @@ -102,19 +102,23 @@ dc.numberDisplay = function (parent, chartGroup) { if (span.empty()) { span = span.data([0]) .enter() - .append('span') - .attr('class', SPAN_CLASS); + .append('span') + .attr('class', SPAN_CLASS) + .merge(span); } span.transition() .duration(_chart.transitionDuration()) .delay(_chart.transitionDelay()) - .ease('quad-out-in') + .ease(d3.easeQuadIn) .tween('text', function () { // [XA] don't try and interpolate from Infinity, else this breaks. var interpStart = isFinite(_lastValue) ? _lastValue : 0; var interp = d3.interpolateNumber(interpStart || 0, newValue); _lastValue = newValue; + + // need to save it in D3v4 + var node = this; return function (t) { var html = null, num = _chart.formatNumber()(interp(t)); if (newValue === 0 && (_html.none !== '')) { @@ -124,7 +128,7 @@ dc.numberDisplay = function (parent, chartGroup) { } else if (_html.some !== '') { html = _html.some; } - this.innerHTML = html ? html.replace('%number', num) : num; + node.innerHTML = html ? html.replace('%number', num) : num; }; }); }; @@ -138,7 +142,7 @@ dc.numberDisplay = function (parent, chartGroup) { * @method formatNumber * @memberof dc.numberDisplay * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Formatting.md d3.format} + * @see {@link https://github.com/d3/d3-format/blob/master/README.md#format d3.format} * @param {Function} [formatter=d3.format('.2s')] * @returns {Function|dc.numberDisplay} */ diff --git a/src/pie-chart.js b/src/pie-chart.js index 24473951c..2023340db 100644 --- a/src/pie-chart.js +++ b/src/pie-chart.js @@ -17,7 +17,7 @@ * // create a pie chart under #chart-container2 element using chart group A * var chart2 = dc.pieChart('#chart-container2', 'chartGroupA'); * @param {String|node|d3.selection} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} specifying + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. @@ -113,11 +113,14 @@ dc.pieChart = function (parent, chartGroup) { .selectAll('text.' + _labelCssClass) .data(pieData); - createElements(slices, labels, arc, pieData); + removeElements(slices, labels); - updateElements(pieData, arc); + // Uglify does not like array assignments + var t = createElements(slices, labels, arc, pieData); + slices = t[0]; + labels = t[1]; - removeElements(slices, labels); + updateElements(pieData, arc); highlightFilter(); @@ -127,13 +130,19 @@ dc.pieChart = function (parent, chartGroup) { } function createElements (slices, labels, arc, pieData) { - var slicesEnter = createSliceNodes(slices); + + // Uglify does not like array assignments + var t = createSliceNodes(slices); + var slicesEnter = t[0]; + slices = t[1]; createSlicePath(slicesEnter, arc); createTitles(slicesEnter); - createLabels(labels, pieData, arc); + labels = createLabels(labels, pieData, arc); + + return [slices, labels]; } function createSliceNodes (slices) { @@ -143,7 +152,9 @@ dc.pieChart = function (parent, chartGroup) { .attr('class', function (d, i) { return _sliceCssClass + ' _' + i; }); - return slicesEnter; + + slices = slicesEnter.merge(slices); + return [slicesEnter, slices]; } function createSlicePath (slicesEnter, arc) { @@ -216,29 +227,35 @@ dc.pieChart = function (parent, chartGroup) { if (_externalLabelRadius && _drawPaths) { updateLabelPaths(pieData, arc); } + + labels = labelsEnter.merge(labels); } + + return labels; } function updateLabelPaths (pieData, arc) { var polyline = _g.selectAll('polyline.' + _sliceCssClass) - .data(pieData); - - polyline - .enter() - .append('polyline') - .attr('class', function (d, i) { - return 'pie-path _' + i + ' ' + _sliceCssClass; - }) - .on('click', onClick) - .on('mouseover', function (d, i) { - highlightSlice(i, true); - }) - .on('mouseout', function (d, i) { - highlightSlice(i, false); - }); + .data(pieData); polyline.exit().remove(); - var arc2 = d3.svg.arc() + + polyline = polyline + .enter() + .append('polyline') + .attr('class', function (d, i) { + return 'pie-path _' + i + ' ' + _sliceCssClass; + }) + .on('click', onClick) + .on('mouseover', function (d, i) { + highlightSlice(i, true); + }) + .on('mouseout', function (d, i) { + highlightSlice(i, false); + }) + .merge(polyline); + + var arc2 = d3.arc() .outerRadius(_radius - _externalRadiusPadding + _externalLabelRadius) .innerRadius(_radius - _externalRadiusPadding); var transition = dc.transition(polyline, _chart.transitionDuration(), _chart.transitionDelay()); @@ -413,7 +430,7 @@ dc.pieChart = function (parent, chartGroup) { }; function buildArcs () { - return d3.svg.arc() + return d3.arc() .outerRadius(_radius - _externalRadiusPadding) .innerRadius(_innerRadius); } @@ -445,7 +462,7 @@ dc.pieChart = function (parent, chartGroup) { }; function pieLayout () { - return d3.layout.pie().sort(null).value(_chart.cappedValueAccessor); + return d3.pie().sort(null).value(_chart.cappedValueAccessor); } function sliceTooSmall (d) { @@ -553,7 +570,7 @@ dc.pieChart = function (parent, chartGroup) { function labelPosition (d, arc) { var centroid; if (_externalLabelRadius) { - centroid = d3.svg.arc() + centroid = d3.arc() .outerRadius(_radius - _externalRadiusPadding + _externalLabelRadius) .innerRadius(_radius - _externalRadiusPadding + _externalLabelRadius) .centroid(d); diff --git a/src/row-chart.js b/src/row-chart.js index a89cc19fd..078f61087 100644 --- a/src/row-chart.js +++ b/src/row-chart.js @@ -15,7 +15,7 @@ * // create a row chart under #chart-container2 element using chart group A * var chart2 = dc.rowChart('#chart-container2', 'chartGroupA'); * @param {String|node|d3.selection} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} specifying + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. @@ -44,7 +44,7 @@ dc.rowChart = function (parent, chartGroup) { var _elasticX; - var _xAxis = d3.svg.axis().orient('bottom'); + var _xAxis = d3.axisBottom(); var _rowData; @@ -59,7 +59,7 @@ dc.rowChart = function (parent, chartGroup) { if (extent[1] < 0) { extent[1] = 0; } - _x = d3.scale.linear().domain(extent) + _x = d3.scaleLinear().domain(extent) .range([0, _chart.effectiveWidth()]); } _xAxis.scale(_x); @@ -99,11 +99,11 @@ dc.rowChart = function (parent, chartGroup) { /** * Gets or sets the x scale. The x scale can be any d3 - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Quantitative-Scales.md quantitive scale}. + * {@link https://github.com/d3/d3-scale/blob/master/README.md d3.scale}. * @method x * @memberof dc.rowChart * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Quantitative-Scales.md quantitive scale} + * @see {@link https://github.com/d3/d3-scale/blob/master/README.md d3.scale} * @param {d3.scale} [scale] * @returns {d3.scale|dc.rowChart} */ @@ -140,8 +140,9 @@ dc.rowChart = function (parent, chartGroup) { var rows = _g.selectAll('g.' + _rowCssClass) .data(_rowData); - createElements(rows); removeElements(rows); + rows = createElements(rows) + .merge(rows); updateElements(rows); } @@ -155,6 +156,8 @@ dc.rowChart = function (parent, chartGroup) { rowEnter.append('rect').attr('width', 0); createLabels(rowEnter); + + return rowEnter; } function removeElements (rows) { @@ -291,12 +294,12 @@ dc.rowChart = function (parent, chartGroup) { /** * Get the x axis for the row chart instance. Note: not settable for row charts. - * See the {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Axes.md#axis d3 axis object} + * See the {@link https://github.com/d3/d3-axis/blob/master/README.md#axisBottom d3.axisBottom} * documention for more information. * @method xAxis * @memberof dc.rowChart * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Axes.md#axis d3.svg.axis} + * @see {@link https://github.com/d3/d3-axis/blob/master/README.md#axisBottom d3.axisBottom} * @example * // customize x axis tick format * chart.xAxis().tickFormat(function (v) {return v + '%';}); diff --git a/src/scatter-plot.js b/src/scatter-plot.js index d4fc4d5f5..1a8e783b2 100644 --- a/src/scatter-plot.js +++ b/src/scatter-plot.js @@ -15,7 +15,7 @@ * // create a sub-chart under a composite parent chart * var chart3 = dc.scatterPlot(compositeChart); * @param {String|node|d3.selection} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} specifying + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. @@ -23,7 +23,7 @@ */ dc.scatterPlot = function (parent, chartGroup) { var _chart = dc.coordinateGridMixin({}); - var _symbol = d3.svg.symbol(); + var _symbol = d3.symbol(); var _existenceAccessor = function (d) { return d.value; }; @@ -55,6 +55,9 @@ dc.scatterPlot = function (parent, chartGroup) { var _emptyColor = null; var _filtered = []; + // Use a 2 dimensional brush + _chart.brush(d3.brush()); + function elementSize (d, i) { if (!_existenceAccessor(d)) { return Math.pow(_emptySize, 2); @@ -78,13 +81,14 @@ dc.scatterPlot = function (parent, chartGroup) { var symbols = _chart.chartBodyG().selectAll('path.symbol') .data(_chart.data()); - symbols + symbols = symbols .enter() - .append('path') - .attr('class', 'symbol') - .attr('opacity', 0) - .attr('fill', _chart.getColor) - .attr('transform', _locator); + .append('path') + .attr('class', 'symbol') + .attr('opacity', 0) + .attr('fill', _chart.getColor) + .attr('transform', _locator) + .merge(symbols); symbols.call(renderTitles, _chart.data()); @@ -153,19 +157,19 @@ dc.scatterPlot = function (parent, chartGroup) { }; /** - * Get or set the symbol type used for each point. By default the symbol is a circle. + * Get or set the symbol type used for each point. By default the symbol is a circle (d3.symbolCircle). * Type can be a constant or an accessor. * @method symbol * @memberof dc.scatterPlot * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#symbol_type d3.svg.symbol.type} + * @see {@link https://github.com/d3/d3-shape/blob/master/README.md#symbol_type symbol.type} * @example * // Circle type - * chart.symbol('circle'); + * chart.symbol(d3.symbolCircle); * // Square type - * chart.symbol('square'); - * @param {String|Function} [type='circle'] - * @returns {String|Function|dc.scatterPlot} + * chart.symbol(d3.symbolSquare); + * @param {Function} [type=d3.symbolCircle] + * @returns {Function|dc.scatterPlot} */ _chart.symbol = function (type) { if (!arguments.length) { @@ -177,16 +181,16 @@ dc.scatterPlot = function (parent, chartGroup) { /** * Get or set the symbol generator. By default `dc.scatterPlot` will use - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#symbol d3.svg.symbol()} + * {@link https://github.com/d3/d3-shape/blob/master/README.md#symbol d3.symbol()} * to generate symbols. `dc.scatterPlot` will set the - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#symbol_size size accessor} + * {@link https://github.com/d3/d3-shape/blob/master/README.md#symbol_size symbol size accessor} * on the symbol generator. * @method customSymbol * @memberof dc.scatterPlot * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#symbol d3.svg.symbol} + * @see {@link https://github.com/d3/d3-shape/blob/master/README.md#symbol d3.symbol} * @see {@link https://stackoverflow.com/questions/25332120/create-additional-d3-js-symbols Create additional D3.js symbols} - * @param {String|Function} [customSymbol=d3.svg.symbol()] + * @param {String|Function} [customSymbol=d3.symbol()] * @returns {String|Function|dc.scatterPlot} */ _chart.customSymbol = function (customSymbol) { @@ -203,7 +207,7 @@ dc.scatterPlot = function (parent, chartGroup) { * @method symbolSize * @memberof dc.scatterPlot * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#symbol_size d3.svg.symbol.size} + * @see {@link https://github.com/d3/d3-shape/blob/master/README.md#symbol_size d3.symbol.size} * @param {Number} [symbolSize=3] * @returns {Number|dc.scatterPlot} */ @@ -220,7 +224,7 @@ dc.scatterPlot = function (parent, chartGroup) { * @method highlightedSize * @memberof dc.scatterPlot * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#symbol_size d3.svg.symbol.size} + * @see {@link https://github.com/d3/d3-shape/blob/master/README.md#symbol_size d3.symbol.size} * @param {Number} [highlightedSize=5] * @returns {Number|dc.scatterPlot} */ @@ -238,7 +242,7 @@ dc.scatterPlot = function (parent, chartGroup) { * @method excludedSize * @memberof dc.scatterPlot * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#symbol_size d3.svg.symbol.size} + * @see {@link https://github.com/d3/d3-shape/blob/master/README.md#symbol_size d3.symbol.size} * @param {Number} [excludedSize=null] * @returns {Number|dc.scatterPlot} */ @@ -288,7 +292,7 @@ dc.scatterPlot = function (parent, chartGroup) { * @method emptySize * @memberof dc.scatterPlot * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/SVG-Shapes.md#symbol_size d3.svg.symbol.size} + * @see {@link https://github.com/d3/d3-shape/blob/master/README.md#symbol_size d3.symbol.size} * @param {Number} [emptySize=0] * @returns {Number|dc.scatterPlot} */ @@ -388,35 +392,49 @@ dc.scatterPlot = function (parent, chartGroup) { // no handle paths for poly-brushes }; - _chart.extendBrush = function () { - var extent = _chart.brush().extent(); + _chart.extendBrush = function (selection) { if (_chart.round()) { - extent[0] = extent[0].map(_chart.round()); - extent[1] = extent[1].map(_chart.round()); - - _chart.g().select('.brush') - .call(_chart.brush().extent(extent)); + selection[0] = selection[0].map(_chart.round()); + selection[1] = selection[1].map(_chart.round()); } - return extent; + return selection; }; - _chart.brushIsEmpty = function (extent) { - return _chart.brush().empty() || !extent || extent[0][0] >= extent[1][0] || extent[0][1] >= extent[1][1]; + _chart.brushIsEmpty = function (selection) { + return !selection || selection[0][0] === selection[1][0] || selection[0][1] === selection[1][1]; }; _chart._brushing = function () { - var extent = _chart.extendBrush(); + var event = d3.event; + // Avoids infinite recursion + // To ensure that when it is called because of brush.move there is no d3.event.sourceEvent + d3.event = null; + if (!event.sourceEvent) return; + var selection = event.selection; + + // Testing with pixels is more reliable + var brushIsEmpty = _chart.brushIsEmpty(selection); + + if (selection) { + selection = selection.map(function (point) { + return point.map(function (coord, i) { + var scale = i === 0 ? _chart.x() : _chart.y(); + return scale.invert(coord); + }); + }) + } + selection = _chart.extendBrush(selection); - _chart.redrawBrush(_chart.g()); + _chart.redrawBrush(selection); - if (_chart.brushIsEmpty(extent)) { + if (brushIsEmpty) { dc.events.trigger(function () { _chart.filter(null); _chart.redrawGroup(); }); } else { - var ranged2DFilter = dc.filters.RangedTwoDimensionalFilter(extent); + var ranged2DFilter = dc.filters.RangedTwoDimensionalFilter(selection); dc.events.trigger(function () { _chart.filter(null); _chart.filter(ranged2DFilter); @@ -426,6 +444,27 @@ dc.scatterPlot = function (parent, chartGroup) { } }; + _chart.redrawBrush = function (selection) { + // override default x axis brush from parent chart + var _brush = _chart.brush(); + var _gBrush = _chart.gBrush(); + + if (_brush && _gBrush) { + if (selection) { + selection = selection.map(function (point) { + return point.map(function (coord, i) { + var scale = i === 0 ? _chart.x() : _chart.y(); + return scale(coord); + }); + }) + } + + _brush.move(_gBrush, selection); + } + + _chart.fadeDeselectedArea(selection); + }; + _chart.setBrushY = function (gBrush) { gBrush.call(_chart.brush().y(_chart.y())); }; diff --git a/src/select-menu.js b/src/select-menu.js index 7efd752a3..e0727177f 100644 --- a/src/select-menu.js +++ b/src/select-menu.js @@ -85,17 +85,21 @@ dc.selectMenu = function (parent, chartGroup) { var options = _select.selectAll('option.' + OPTION_CSS_CLASS) .data(_chart.data(), function (d) { return _chart.keyAccessor()(d); }); + options.exit().remove(); + options.enter() .append('option') .classed(OPTION_CSS_CLASS, true) - .attr('value', function (d) { return _chart.keyAccessor()(d); }); + .attr('value', function (d) { return _chart.keyAccessor()(d); }) + .merge(options) + .text(_chart.title()); - options.text(_chart.title()); - options.exit().remove(); _select.selectAll('option.' + OPTION_CSS_CLASS).sort(_order); _select.on('change', onChange); - return options; + + // indicate that no one should use return value + return null; } function onChange (d, i) { diff --git a/src/series-chart.js b/src/series-chart.js index f072f506a..f4817103a 100644 --- a/src/series-chart.js +++ b/src/series-chart.js @@ -14,7 +14,7 @@ * // create a series chart under #chart-container2 element using chart group A * var seriesChart2 = dc.seriesChart("#chart-container2", "chartGroupA"); * @param {String|node|d3.selection} parent - Any valid - * {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#selecting-elements d3 single selector} specifying + * {@link https://github.com/d3/d3-selection/blob/master/README.md#select d3 single selector} specifying * a dom block element such as a div; or a dom element or d3 selection. * @param {String} [chartGroup] - The name of the chart group this chart instance should be placed in. * Interaction with a chart will only trigger events and redraws within the chart's group. @@ -138,8 +138,8 @@ dc.seriesChart = function (parent, chartGroup) { * @method seriesSort * @memberof dc.seriesChart * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Arrays.md#d3_ascending d3.ascending} - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Arrays.md#d3_descending d3.descending} + * @see {@link https://github.com/d3/d3-array/blob/master/README.md#ascending d3.ascending} + * @see {@link https://github.com/d3/d3-array/blob/master/README.md#descending d3.descending} * @example * chart.seriesSort(d3.descending); * @param {Function} [sortFunction=d3.ascending] @@ -161,8 +161,8 @@ dc.seriesChart = function (parent, chartGroup) { * @method valueSort * @memberof dc.seriesChart * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Arrays.md#d3_ascending d3.ascending} - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Arrays.md#d3_descending d3.descending} + * @see {@link https://github.com/d3/d3-array/blob/master/README.md#ascending d3.ascending} + * @see {@link https://github.com/d3/d3-array/blob/master/README.md#descending d3.descending} * @example * // Default value sort * _chart.valueSort(function keySort (a, b) { diff --git a/src/stack-mixin.js b/src/stack-mixin.js index 17d4cf0ab..70efea70d 100644 --- a/src/stack-mixin.js +++ b/src/stack-mixin.js @@ -1,5 +1,5 @@ /** - * Stack Mixin is an mixin that provides cross-chart support of stackability using d3.layout.stack. + * Stack Mixin is an mixin that provides cross-chart support of stackability using d3.stackD3v3. * @name stackMixin * @memberof dc * @mixin @@ -25,7 +25,7 @@ dc.stackMixin = function (_chart) { return layer.values; } - var _stackLayout = d3.layout.stack() + var _stackLayout = d3.stackD3v3() .values(prepareValues); var _stack = []; @@ -249,8 +249,8 @@ dc.stackMixin = function (_chart) { * @method stackLayout * @memberof dc.stackMixin * @instance - * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Stack-Layout.md d3.layout.stack} - * @param {Function} [stack=d3.layout.stack] + * @see {@link https://github.com/d3/d3-3.x-api-reference/blob/master/Stack-Layout.md d3.stackD3v3} + * @param {Function} [stack=d3.stackD3v3] * @returns {Function|dc.stackMixin} */ _chart.stackLayout = function (stack) { @@ -258,7 +258,7 @@ dc.stackMixin = function (_chart) { return _stackLayout; } _stackLayout = stack; - if (_stackLayout.values() === d3.layout.stack().values()) { + if (_stackLayout.values() === d3.stackD3v3().values()) { _stackLayout.values(prepareValues); } return _chart; diff --git a/src/utils.js b/src/utils.js index 56928b9f4..c33eaa0ce 100644 --- a/src/utils.js +++ b/src/utils.js @@ -3,9 +3,9 @@ * @name dateFormat * @memberof dc * @type {Function} - * @default d3.time.format('%m/%d/%Y') + * @default d3.timeFormat('%m/%d/%Y') */ -dc.dateFormat = d3.time.format('%m/%d/%Y'); +dc.dateFormat = d3.timeFormat('%m/%d/%Y'); /** * @namespace printers @@ -120,19 +120,29 @@ dc.utils.printSingleValue = function (filter) { }; dc.utils.printSingleValue.fformat = d3.format('.2f'); +// convert 'day' to 'timeDay' and similar +dc.utils.toTimeFunc = function (t) { + return 'time' + t.charAt(0).toUpperCase() + t.slice(1); +}; + /** * Arbitrary add one value to another. * @method add * @memberof dc.utils - * @todo - * These assume than any string r is a percentage (whether or not it includes %). + * + * If the value l is of type Date, adds r units to it. t becomes the unit. + * For example dc.utils.add(dt, 3, 'week') will add 3 (r = 3) weeks (t= 'week') to dt. + * + * If l is of type numeric, t is ignored. In this case if r is of type string, + * it is assumed to be percentage (whether or not it includes %). For example + * dc.utils.add(30, 10) will give 40 and dc.utils.add(30, '10') will give 33. + * * They also generate strange results if l is a string. - * @param {String|Date|Number} l the value to modify - * @param {Number} r the amount by which to modify the value - * @param {String} [t] if `l` is a `Date`, the - * [interval](https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Intervals.md#interval) in - * the `d3.time` namespace - * @returns {String|Date|Number} + * @param {Date|Number} l the value to modify + * @param {String|Number} r the amount by which to modify the value + * @param {String} [t] if `l` is a `Date`, then possible values are + * 'millis', 'second', 'minute', 'hour', 'day', 'week', 'month', and 'year' + * @returns {Date|Number} */ dc.utils.add = function (l, r, t) { if (typeof r === 'string') { @@ -147,7 +157,7 @@ dc.utils.add = function (l, r, t) { return new Date(l.getTime() + r); } t = t || 'day'; - return d3.time[t].offset(l, r); + return d3[dc.utils.toTimeFunc(t)].offset(l, r); } else if (typeof r === 'string') { var percentage = (+r / 100); return l > 0 ? l * (1 + percentage) : l * (1 - percentage); @@ -160,15 +170,19 @@ dc.utils.add = function (l, r, t) { * Arbitrary subtract one value from another. * @method subtract * @memberof dc.utils - * @todo - * These assume than any string r is a percentage (whether or not it includes %). + * If the value l is of type Date, subtracts r units from it. t becomes the unit. + * For example dc.utils.subtract(dt, 3, 'week') will subtract 3 (r = 3) weeks (t= 'week') from dt. + * + * If l is of type numeric, t is ignored. In this case if r is of type string, + * it is assumed to be percentage (whether or not it includes %). For example + * dc.utils.subtract(30, 10) will give 20 and dc.utils.subtract(30, '10') will give 27. + * * They also generate strange results if l is a string. - * @param {String|Date|Number} l the value to modify - * @param {Number} r the amount by which to modify the value - * @param {String} [t] if `l` is a `Date`, the - * [interval](https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Intervals.md#interval) in - * the `d3.time` namespace - * @returns {String|Date|Number} + * @param {Date|Number} l the value to modify + * @param {String|Number} r the amount by which to modify the value + * @param {String} [t] if `l` is a `Date`, then possible values are + * 'millis', 'second', 'minute', 'hour', 'day', 'week', 'month', and 'year' + * @returns {Date|Number} */ dc.utils.subtract = function (l, r, t) { if (typeof r === 'string') { @@ -183,7 +197,7 @@ dc.utils.subtract = function (l, r, t) { return new Date(l.getTime() - r); } t = t || 'day'; - return d3.time[t].offset(l, -r); + return d3[dc.utils.toTimeFunc(t)].offset(l, -r); } else if (typeof r === 'string') { var percentage = (+r / 100); return l < 0 ? l * (1 + percentage) : l * (1 - percentage); diff --git a/style/dc.scss b/style/dc.scss index 8844ac771..ca3506413 100644 --- a/style/dc.scss +++ b/style/dc.scss @@ -96,17 +96,15 @@ div.dc-chart { } .brush { rect { - &.background { - z-index: -999; - } - &.extent { + &.selection { fill: $color_steel_blue; fill-opacity: .125; } } - .resize path { + .handle--custom { fill: $color_gallery; stroke: $color_storm_dust; + cursor: ew-resize; } } path { diff --git a/web/crime/index.html b/web/crime/index.html index 6af9a7f3c..77a3127b6 100644 --- a/web/crime/index.html +++ b/web/crime/index.html @@ -462,7 +462,7 @@

Major Canadian City Crime Stats 1998-2011

.radiusValueAccessor(function(p) { return p.value.avgTotalCrimeRate; }) - .r(d3.scale.linear().domain([0, 200000])) + .r(d3.scaleLinear().domain([0, 200000])) .colors(["#ff7373","#ff4040","#ff0000","#bf3030","#a60000"]) .colorDomain([13, 30]) .colorAccessor(function(p) { @@ -500,7 +500,7 @@

Major Canadian City Crime Stats 1998-2011

return d.value.nonViolentCrimeAvg; }) .stack(crimeIncidentByYear, "Violent Crime", function(d){return d.value.violentCrimeAvg;}) - .x(d3.scale.linear().domain([1997, 2012])) + .x(d3.scaleLinear().domain([1997, 2012])) .renderHorizontalGridLines(true) .centerBar(true) .elasticY(true) @@ -522,7 +522,7 @@

Major Canadian City Crime Stats 1998-2011

.valueAccessor(function(d) { return d.value.homicide; }) - .x(d3.scale.linear().domain([1997, 2012])) + .x(d3.scaleLinear().domain([1997, 2012])) .renderHorizontalGridLines(true) .elasticY(true) .brushOn(true) diff --git a/web/docs/stock.html b/web/docs/stock.html index b539042a5..7667bed3d 100644 --- a/web/docs/stock.html +++ b/web/docs/stock.html @@ -231,12 +231,14 @@

Load your data

-
    var dateFormat = d3.time.format('%m/%d/%Y');
+            
    var dateFormatSpecifier = '%m/%d/%Y';
+    var dateFormat = d3.timeFormat(dateFormatSpecifier);
+    var dateFormatParser = d3.timeParse(dateFormatSpecifier);
     var numberFormat = d3.format('.2f');
 
     data.forEach(function (d) {
-        d.dd = dateFormat.parse(d.date);
-        d.month = d3.time.month(d.dd); // pre-calculate month for better performance
+        d.dd = dateFormatParser(d.date);
+        d.month = d3.timeMonth(d.dd); // pre-calculate month for better performance
         d.close = +d.close; // coerce to number
         d.open = +d.open;
     });
@@ -284,7 +286,7 @@

Create Crossfilter Dimensions

    var yearlyDimension = ndx.dimension(function (d) {
-        return d3.time.year(d.dd).getFullYear();
+        return d3.timeYear(d.dd).getFullYear();
     });
@@ -757,9 +759,9 @@
Accessors
return p.value.fluctuationPercentage; }) .maxBubbleRelativeSize(0.3) - .x(d3.scale.linear().domain([-2500, 2500])) - .y(d3.scale.linear().domain([-100, 100])) - .r(d3.scale.linear().domain([0, 4000]))
+ .x(d3.scaleLinear().domain([-2500, 2500])) + .y(d3.scaleLinear().domain([-100, 100])) + .r(d3.scaleLinear().domain([0, 4000])) @@ -1343,7 +1345,7 @@

Bar Chart

        .round(dc.round.floor)
         .alwaysUseRounding(true)
-        .x(d3.scale.linear().domain([-25, 25]))
+        .x(d3.scaleLinear().domain([-25, 25]))
         .renderHorizontalGridLines(true)
@@ -1433,9 +1435,9 @@

Stacked Area Chart

        .rangeChart(volumeChart)
-        .x(d3.time.scale().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)]))
-        .round(d3.time.month.round)
-        .xUnits(d3.time.months)
+        .x(d3.scaleTime().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)]))
+        .round(d3.timeMonth.round)
+        .xUnits(d3.timeMonths)
         .elasticY(true)
         .renderHorizontalGridLines(true)
@@ -1561,10 +1563,10 @@

Range Chart

.group(volumeByMonthGroup) .centerBar(true) .gap(1) - .x(d3.time.scale().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)])) - .round(d3.time.month.round) + .x(d3.scaleTime().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)])) + .round(d3.timeMonth.round) .alwaysUseRounding(true) - .xUnits(d3.time.months); + .xUnits(d3.timeMonths); @@ -2266,7 +2268,7 @@

Bubble Overlay Chart

-
            .r(d3.scale.linear().domain([0, 3]))
+
            .r(d3.scaleLinear().domain([0, 3]))
diff --git a/web/ep/index.html b/web/ep/index.html index 899fe3677..91a134925 100644 --- a/web/ep/index.html +++ b/web/ep/index.html @@ -26,12 +26,12 @@ function adjust (data) { //calculate age - var dateFormat = d3.time.format("%Y-%m-%d"); + var dateParse = d3.timeParse("%Y-%m-%d"); var now = Date.now(); var birthdate=null; data.forEach(function (e) { - birthdate = dateFormat.parse(e.birthdate); + birthdate = dateParse(e.birthdate); e.age= ~~((now - birthdate) / (31557600000));// 24 * 3600 * 365.25 * 1000 }); } @@ -54,12 +54,12 @@ }); var ageGroup = age.group().reduceSum(function(d) { return 1; }); - //.x(d3.scale.ordinal()) + //.x(d3.scaleOrdinal()) chart_age .width(444) .height(200) .margins({top: 0, right: 0, bottom: 95, left: 30}) - .x(d3.scale.linear().domain([20,100])) + .x(d3.scaleLinear().domain([20,100])) .brushOn(true) .renderArea(true) .elasticY(true) @@ -112,7 +112,7 @@ .width(200) .height(200) .dimension(group) - .colors(d3.scale.category10()) + .colors(d3.scaleOrdinal(d3.schemeCategory10)) .group(groupGroup) .on('renderlet', function (chart) { }); @@ -123,7 +123,7 @@ .outerPadding(0) .gap(1) .margins({top: 0, right: 0, bottom: 95, left: 30}) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .brushOn(false) .elasticY(true) diff --git a/web/ep/list.js b/web/ep/list.js index 1c172741e..299cf435f 100644 --- a/web/ep/list.js +++ b/web/ep/list.js @@ -35,7 +35,7 @@ function list (selector,path,data) { .width(200) .height(200) .dimension(group) - .colors(d3.scale.category10()) + .colors(d3.scaleOrdinal(d3.schemeCategory10)) .group(groupGroup) .on('renderlet', function (chart) { }); @@ -46,7 +46,7 @@ function list (selector,path,data) { .outerPadding(0) .gap(1) .margins({top: 0, right: 0, bottom: 95, left: 30}) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .brushOn(false) .elasticY(true) diff --git a/web/examples/adjustable-threshold.html b/web/examples/adjustable-threshold.html index 1036f275b..94b1fdb5b 100644 --- a/web/examples/adjustable-threshold.html +++ b/web/examples/adjustable-threshold.html @@ -55,7 +55,7 @@ .dimension(bookDimension) .group(bookscoresGroup) .elasticY(true) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .colors(["orange"]) .yAxis().ticks(5); diff --git a/web/examples/align-axes.html b/web/examples/align-axes.html index 1662d683e..de20659f8 100644 --- a/web/examples/align-axes.html +++ b/web/examples/align-axes.html @@ -84,7 +84,7 @@ var posiness = ['heading', 'above', 'upward', 'even', 'downward', 'below']; var N = 20; - var gen = d3.random.normal(); + var gen = d3.randomNormal(); function distribute(vals, min, max) { var ext = d3.extent(vals); return vals.map(function(x) { @@ -110,8 +110,8 @@ return ldist.map(function(v, i) { return {key: i, lvalue: v, rvalue: rdist[i]}; }); } - var line = d3.svg.line() - .interpolate('linear'); + var line = d3.line() + .curve(d3.curveLinear); function draw_horizontals(chart, hz) { chart.g().select('g.chart-body') @@ -157,7 +157,7 @@ .width(200) .height(200) .margins({left: 25, top: 20, right: 30, bottom: 20}) - .x(d3.scale.linear()) + .x(d3.scaleLinear()) .brushOn(false) .alignYAxes(true) .elasticX(true) @@ -166,7 +166,7 @@ dc.lineChart(chart) .dimension(dim) .group(lgroup) - .x(d3.scale.linear()) + .x(d3.scaleLinear()) .elasticX(true) .elasticY(true) .yAxisPadding(1) @@ -180,7 +180,7 @@ dc.lineChart(chart) .dimension(dim) .group(rgroup) - .x(d3.scale.linear()) + .x(d3.scaleLinear()) .ordinalColors(["darkorange"]) .elasticX(true) .elasticY(true) diff --git a/web/examples/area.html b/web/examples/area.html index d00d63269..de4b02216 100644 --- a/web/examples/area.html +++ b/web/examples/area.html @@ -45,7 +45,7 @@ chart .width(768) .height(480) - .x(d3.scale.linear().domain([1,20])) + .x(d3.scaleLinear().domain([1,20])) .margins({left: 50, top: 10, right: 10, bottom: 20}) .renderArea(true) .brushOn(false) diff --git a/web/examples/bar-extra-line.html b/web/examples/bar-extra-line.html index 4e27b8019..3f6f965a1 100644 --- a/web/examples/bar-extra-line.html +++ b/web/examples/bar-extra-line.html @@ -37,7 +37,7 @@ chart .width(768) .height(480) - .x(d3.scale.linear().domain([6,20])) + .x(d3.scaleLinear().domain([6,20])) .brushOn(false) .yAxisLabel("This is the Y Axis!") .dimension(runDimension) @@ -49,28 +49,31 @@ }); var left_y = 10, right_y = 70; // use real statistics here! var extra_data = [{x: chart.x().range()[0], y: chart.y()(left_y)}, {x: chart.x().range()[1], y: chart.y()(right_y)}]; - var line = d3.svg.line() + var line = d3.line() .x(function(d) { return d.x; }) .y(function(d) { return d.y; }) - .interpolate('linear'); + .curve(d3.curveLinear); var chartBody = chart.select('g.chart-body'); var path = chartBody.selectAll('path.extra').data([extra_data]); - path.enter().append('path').attr({ - class: 'extra', - stroke: 'red', - id: 'extra-line' - }); + path = path + .enter() + .append('path') + .attr('class', 'extra') + .attr('stroke', 'red') + .attr('id', 'extra-line') + .merge(path); path.attr('d', line); + // and perhaps you'd like to label it? var text = chartBody.selectAll('text.extra-label').data([0]); - text.enter().append('text') + text.enter() + .append('text') .attr('text-anchor', 'middle') - .append('textPath').attr({ - class: 'extra-label', - 'xlink:href': '#extra-line', - startOffset: '50%' - }) - .text('this is a label for the line'); + .append('textPath') + .attr('class', 'extra-label') + .attr('xlink:href', '#extra-line') + .attr('startOffset', '50%') + .text('this is a label for the line'); }); chart.render(); }); diff --git a/web/examples/bar-single-select.html b/web/examples/bar-single-select.html index d26d3b688..14224cfcd 100644 --- a/web/examples/bar-single-select.html +++ b/web/examples/bar-single-select.html @@ -14,7 +14,7 @@
- +
@@ -37,7 +37,7 @@ chart .width(768) .height(480) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .brushOn(true) .yAxisLabel("This is the Y Axis!") diff --git a/web/examples/bar.html b/web/examples/bar.html index 382bc89fa..36af85fc4 100644 --- a/web/examples/bar.html +++ b/web/examples/bar.html @@ -31,7 +31,7 @@ chart .width(768) .height(480) - .x(d3.scale.linear().domain([6,20])) + .x(d3.scaleLinear().domain([6,20])) .brushOn(false) .yAxisLabel("This is the Y Axis!") .dimension(runDimension) diff --git a/web/examples/box-plot-time.html b/web/examples/box-plot-time.html index 5daa03349..29f97b6df 100644 --- a/web/examples/box-plot-time.html +++ b/web/examples/box-plot-time.html @@ -33,7 +33,7 @@ var ndx = crossfilter(data), openDimension = ndx.dimension(function(d) {return parseInt(d.open/10)*10;}), openGroup = openDimension.group(), - monthDimension = ndx.dimension(function(d) {return d3.time.month(d.date); }), + monthDimension = ndx.dimension(function(d) {return d3.timeMonth(d.date); }), closeGroup = monthDimension.group().reduce( function(p,v) { p.push(v.close); @@ -54,9 +54,9 @@ .margins({top: 10, right: 50, bottom: 30, left: 50}) .dimension(monthDimension) .group(closeGroup) - .x(d3.time.scale()) - .round(d3.time.month.round) - .xUnits(d3.time.months) + .x(d3.scaleTime()) + .round(d3.timeMonth.round) + .xUnits(d3.timeMonths) .elasticY(true); // this demonstrates solving elasticX manually, avoiding the @@ -64,7 +64,7 @@ function calc_domain(chart) { var min = d3.min(chart.group().all(), function(kv) { return kv.key; }), max = d3.max(chart.group().all(), function(kv) { return kv.key; }); - max = d3.time.month.offset(max, 1); + max = d3.timeMonth.offset(max, 1); chart.x().domain([min, max]); } chart.on('preRender', calc_domain); diff --git a/web/examples/complex-reduce.html b/web/examples/complex-reduce.html index 359c4cb00..5c5bc852e 100644 --- a/web/examples/complex-reduce.html +++ b/web/examples/complex-reduce.html @@ -36,13 +36,13 @@

Run

Experiment

@@ -137,7 +137,7 @@

Experiment

runChart .width(400) .height(300) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .valueAccessor(medianSpeed) .elasticY(true) @@ -149,7 +149,7 @@

Experiment

exptChart .width(400) .height(300) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .valueAccessor(medianSpeed) .elasticY(true) diff --git a/web/examples/composite.html b/web/examples/composite.html index 5ddb24aa6..b6a70fec3 100644 --- a/web/examples/composite.html +++ b/web/examples/composite.html @@ -41,7 +41,7 @@ composite .width(768) .height(480) - .x(d3.scale.linear().domain([0,20])) + .x(d3.scaleLinear().domain([0,20])) .yAxisLabel("The Y Axis") .legend(dc.legend().x(80).y(20).itemHeight(13).gap(5)) .renderHorizontalGridLines(true) diff --git a/web/examples/download-table.html b/web/examples/download-table.html index aa8878f4a..7b9e0aa04 100644 --- a/web/examples/download-table.html +++ b/web/examples/download-table.html @@ -91,7 +91,7 @@ spendHistChart .dimension(spendDim) .group(spendHist) - .x(d3.scale.linear().domain([0,10])) + .x(d3.scaleLinear().domain([0,10])) .elasticY(true) .controlsUseVisibility(true); @@ -143,7 +143,7 @@ return row; }); } - var blob = new Blob([d3.csv.format(data)], {type: "text/csv;charset=utf-8"}); + var blob = new Blob([d3.csvFormat(data)], {type: "text/csv;charset=utf-8"}); saveAs(blob, 'data.csv'); }); diff --git a/web/examples/filter-stacks.html b/web/examples/filter-stacks.html index 225b133a8..33d8913b3 100644 --- a/web/examples/filter-stacks.html +++ b/web/examples/filter-stacks.html @@ -81,7 +81,7 @@ return d.Speed; }), stackedGroup = stack_second(runExptGroup); - var quantizeSpeed = d3.scale.quantize().domain(d3.extent(experiments, function(d) { + var quantizeSpeed = d3.scaleQuantize().domain(d3.extent(experiments, function(d) { return d.Speed; })).range(['lowest', 'low', 'medium', 'high', 'highest']); var quantizeSpeedDim = ndx.dimension(function(d) { @@ -98,7 +98,7 @@ .width(600) .height(400) .controlsUseVisibility(true) - .x(d3.scale.linear().domain([1,21])) + .x(d3.scaleLinear().domain([1,21])) .margins({left: 80, top: 20, right: 10, bottom: 20}) .brushOn(false) .clipPadding(10) diff --git a/web/examples/filtering-removing.html b/web/examples/filtering-removing.html index 934451a8c..b1c6816b5 100644 --- a/web/examples/filtering-removing.html +++ b/web/examples/filtering-removing.html @@ -75,7 +75,7 @@ .width(300).height(200) .dimension(spendDim) .group(nonEmptyHist) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .elasticX(true) .elasticY(true); diff --git a/web/examples/filtering.html b/web/examples/filtering.html index 0aaf305f0..da7ee6e7c 100644 --- a/web/examples/filtering.html +++ b/web/examples/filtering.html @@ -69,7 +69,7 @@ spendHistChart .dimension(spendDim) .group(spendHist) - .x(d3.scale.linear().domain([0,10])) + .x(d3.scaleLinear().domain([0,10])) .elasticY(true) .controlsUseVisibility(true); @@ -86,18 +86,19 @@ var is_empty = d3.sum(chart.group().all().map(chart.valueAccessor())) === 0; var data = is_empty ? [1] : []; var empty = chart.svg().selectAll('.empty-message').data(data); - empty.enter().append('text') - .text('NO DATA!') - .attr({ - 'text-anchor': 'middle', - 'alignment-baseline': 'middle', - class: 'empty-message', - x: chart.margins().left + chart.effectiveWidth()/2, - y: chart.margins().top + chart.effectiveHeight()/2 - }) - .style('opacity', 0); - empty.transition().duration(1000).style('opacity', 1); empty.exit().remove(); + empty = empty + .enter() + .append('text') + .text('NO DATA!') + .attr('text-anchor', 'middle') + .attr('alignment-baseline', 'middle') + .attr('class', 'empty-message') + .attr('x', chart.margins().left + chart.effectiveWidth()/2) + .attr('y', chart.margins().top + chart.effectiveHeight()/2) + .style('opacity', 0) + .merge(empty); + empty.transition().duration(1000).style('opacity', 1); } spendHistChart.on('pretransition', show_empty_message); diff --git a/web/examples/heatmap-filtering.html b/web/examples/heatmap-filtering.html index 33008e3f4..679dad1cc 100644 --- a/web/examples/heatmap-filtering.html +++ b/web/examples/heatmap-filtering.html @@ -27,12 +27,14 @@

Nasdaq 100 Percentage Gain by Month of Year

d3.csv("../ndx.csv", function(error, data) { - var dateFormat = d3.time.format("%m/%d/%Y"); + var dateFormatSpecifier = "%m/%d/%Y"; + var dateFormat = d3.timeFormat(dateFormatSpecifier); + var dateFormatParser = d3.timeParse(dateFormatSpecifier); data.forEach(function (d) { - d.dd = dateFormat.parse(d.date); - d.month = d3.time.month(d.dd).getMonth(); // pre-calculate month for better performance - d.year = d3.time.year(d.dd).getFullYear(); + d.dd = dateFormatParser(d.date); + d.month = d3.timeMonth(d.dd).getMonth(); // pre-calculate month for better performance + d.year = d3.timeYear(d.dd).getFullYear(); d.close = +d.close; // coerce to number d.open = +d.open; }); @@ -68,7 +70,7 @@

Nasdaq 100 Percentage Gain by Month of Year

} ); - var heatColorMapping = d3.scale.linear() + var heatColorMapping = d3.scaleLinear() .domain([-23, 0, 23]) .range(["red", "#e5e5e5", "green"]); @@ -113,8 +115,8 @@

Nasdaq 100 Percentage Gain by Month of Year

.group(percentageGainByMonthArrayGroup) .width(12 * 80 + 80) .height(480) - .y(d3.scale.linear().domain([-10.0,100.0])) - .x(d3.scale.linear().domain([-0.5,11.5])) + .y(d3.scaleLinear().domain([-10.0,100.0])) + .x(d3.scaleLinear().domain([-0.5,11.5])) .elasticY(true) .centerBar(true); barChart.render(); diff --git a/web/examples/line.html b/web/examples/line.html index 39960e3be..ee7eaff2c 100644 --- a/web/examples/line.html +++ b/web/examples/line.html @@ -31,8 +31,8 @@ chart .width(768) .height(480) - .x(d3.scale.linear().domain([0,20])) - .interpolate('step-before') + .x(d3.scaleLinear().domain([0,20])) + .interpolate(d3.curveStepBefore) .renderArea(true) .brushOn(false) .renderDataPoints(true) diff --git a/web/examples/multi-focus.html b/web/examples/multi-focus.html index 437b763ed..58343a931 100644 --- a/web/examples/multi-focus.html +++ b/web/examples/multi-focus.html @@ -40,7 +40,7 @@ chart .width(400) .height(300) - .x(d3.scale.linear().domain([6,20])) + .x(d3.scaleLinear().domain([6,20])) .brushOn(false) .yAxisLabel("This is the Y Axis!") .dimension(runDimension) diff --git a/web/examples/multi-scatter.html b/web/examples/multi-scatter.html index a870a5505..8e9ca58ac 100644 --- a/web/examples/multi-scatter.html +++ b/web/examples/multi-scatter.html @@ -35,7 +35,7 @@ chart .width(768) .height(480) - .x(d3.scale.linear().domain([6,20])) + .x(d3.scaleLinear().domain([6,20])) .yAxisLabel("This is the Y Axis!") .clipPadding(10) .dimension(scatterDimension) diff --git a/web/examples/ordinal-bar.html b/web/examples/ordinal-bar.html index 0fbed6da6..335fce0d8 100644 --- a/web/examples/ordinal-bar.html +++ b/web/examples/ordinal-bar.html @@ -30,7 +30,7 @@ chart .width(768) .height(380) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .brushOn(false) .xAxisLabel('Fruit') diff --git a/web/examples/ordinal-line.html b/web/examples/ordinal-line.html index 87f0edaf9..b24876b2f 100644 --- a/web/examples/ordinal-line.html +++ b/web/examples/ordinal-line.html @@ -30,7 +30,7 @@ chart .width(768) .height(380) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .brushOn(false) .xAxisLabel('Fruit') diff --git a/web/examples/range-series.html b/web/examples/range-series.html index a314c0c48..e0a707069 100644 --- a/web/examples/range-series.html +++ b/web/examples/range-series.html @@ -35,8 +35,8 @@ focusChart .width(768) .height(480) - .chart(function(c) { return dc.lineChart(c).interpolate('cardinal').evadeDomainFilter(true); }) - .x(d3.scale.linear().domain([0,20])) + .chart(function(c) { return dc.lineChart(c).interpolate(d3.curveCardinal).evadeDomainFilter(true); }) + .x(d3.scaleLinear().domain([0,20])) .brushOn(false) .yAxisLabel("Measured Speed km/s") .xAxisLabel("Run") @@ -74,7 +74,7 @@ .width(768) .height(100) .chart(function(c,_,_,i) { - var chart = dc.lineChart(c).interpolate('cardinal'); + var chart = dc.lineChart(c).interpolate(d3.curveCardinal); if(i===0) chart.on('filtered', function (chart) { if (!chart.filter()) { @@ -90,7 +90,7 @@ }); return chart; }) - .x(d3.scale.linear().domain([0,20])) + .x(d3.scaleLinear().domain([0,20])) .brushOn(true) .xAxisLabel("Run") .clipPadding(10) diff --git a/web/examples/right-axis.html b/web/examples/right-axis.html index a20d5f652..154b739e8 100644 --- a/web/examples/right-axis.html +++ b/web/examples/right-axis.html @@ -22,12 +22,14 @@ var moveChart = dc.compositeChart("#monthly-move-chart"); d3.csv("monthly-move.csv", function (error, data) { - var dateFormat = d3.time.format("%m/%d/%Y"); + var dateFormatSpecifier = "%m/%d/%Y"; + var dateFormat = d3.timeFormat(dateFormatSpecifier); + var dateFormatParser = d3.timeParse(dateFormatSpecifier); var numberFormat = d3.format(".2f"); data.forEach(function (e) { - e.dd = dateFormat.parse(e.date); - e.month = d3.time.month(e.dd); // pre-calculate month for better performance + e.dd = dateFormatParser(e.date); + e.month = d3.timeMonth(e.dd); // pre-calculate month for better performance }); var ndx = crossfilter(data); @@ -63,9 +65,9 @@ .dimension(moveMonths) .mouseZoomable(true) .shareTitle(false) - .x(d3.time.scale().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)])) - .round(d3.time.month.round) - .xUnits(d3.time.months) + .x(d3.scaleTime().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)])) + .round(d3.timeMonth.round) + .xUnits(d3.timeMonths) .elasticY(true) .renderHorizontalGridLines(true) .legend(dc.legend().x(70).y(10).itemHeight(13).gap(5)) diff --git a/web/examples/row.html b/web/examples/row.html index 9e342e3e6..de2a814d0 100644 --- a/web/examples/row.html +++ b/web/examples/row.html @@ -31,7 +31,7 @@ chart .width(768) .height(480) - .x(d3.scale.linear().domain([6,20])) + .x(d3.scaleLinear().domain([6,20])) .elasticX(true) .dimension(runDimension) .group(speedSumGroup) diff --git a/web/examples/scatter-brushing.html b/web/examples/scatter-brushing.html index 35ea6d427..b87b26a9f 100644 --- a/web/examples/scatter-brushing.html +++ b/web/examples/scatter-brushing.html @@ -32,7 +32,7 @@ "8,6,14\n"+ "1,4,9\n"+ "8,8,12\n"; -var data = d3.csv.parse(data); +var data = d3.csvParse(data); data.forEach(function (x) { x.x = +x.x; @@ -52,7 +52,7 @@ chart1.width(300) .height(300) - .x(d3.scale.linear().domain([0, 20])) + .x(d3.scaleLinear().domain([0, 20])) .yAxisLabel("y") .xAxisLabel("x") .clipPadding(10) @@ -62,7 +62,7 @@ chart2.width(300) .height(300) - .x(d3.scale.linear().domain([0, 20])) + .x(d3.scaleLinear().domain([0, 20])) .yAxisLabel("z") .xAxisLabel("y") .clipPadding(10) diff --git a/web/examples/scatter-series.html b/web/examples/scatter-series.html index e06e35a1b..c2ec61b94 100644 --- a/web/examples/scatter-series.html +++ b/web/examples/scatter-series.html @@ -26,7 +26,7 @@ runDimension = ndx.dimension(function(d) {return [+d.Expt, +d.Run]; }); runGroup = runDimension.group().reduceSum(function(d) { return +d.Speed; }); - var symbolScale = d3.scale.ordinal().range(d3.svg.symbolTypes); + var symbolScale = d3.scaleOrdinal().range(d3.symbols); var symbolAccessor = function(d) { return symbolScale(d.key[0]); }; var subChart = function(c) { return dc.scatterPlot(c) @@ -39,7 +39,7 @@ .width(768) .height(480) .chart(subChart) - .x(d3.scale.linear().domain([0,20])) + .x(d3.scaleLinear().domain([0,20])) .brushOn(false) .yAxisLabel("Measured Speed km/s") .xAxisLabel("Run") diff --git a/web/examples/scatter.html b/web/examples/scatter.html index d72232400..44b99abf5 100644 --- a/web/examples/scatter.html +++ b/web/examples/scatter.html @@ -31,7 +31,7 @@ chart .width(768) .height(480) - .x(d3.scale.linear().domain([6,20])) + .x(d3.scaleLinear().domain([6,20])) .brushOn(false) .symbolSize(8) .clipPadding(10) diff --git a/web/examples/series.html b/web/examples/series.html index bd9dd097d..4b1001d10 100644 --- a/web/examples/series.html +++ b/web/examples/series.html @@ -32,8 +32,8 @@ chart .width(768) .height(480) - .chart(function(c) { return dc.lineChart(c).interpolate('cardinal'); }) - .x(d3.scale.linear().domain([0,20])) + .chart(function(c) { return dc.lineChart(c).interpolate(d3.curveCardinal); }) + .x(d3.scaleLinear().domain([0,20])) .brushOn(false) .yAxisLabel("Measured Speed km/s") .xAxisLabel("Run") diff --git a/web/examples/sparkline.html b/web/examples/sparkline.html index 18bac4377..456d70e19 100644 --- a/web/examples/sparkline.html +++ b/web/examples/sparkline.html @@ -41,7 +41,7 @@

Sparklines

.width(100) .height(20) .margins({left: 0, top: 0, right: 0, bottom: 0}) - .x(d3.scale.linear().domain([6,20])) + .x(d3.scaleLinear().domain([6,20])) .brushOn(true) .dimension(runDimension) .group(speedSumGroup); @@ -49,7 +49,7 @@

Sparklines

.width(100) .height(20) .margins({left: 0, top: 0, right: 0, bottom: 0}) - .x(d3.scale.linear().domain([6,20])) + .x(d3.scaleLinear().domain([6,20])) .brushOn(true) .dimension(runDimension2) .group(speedSumGroup2); diff --git a/web/examples/splom.html b/web/examples/splom.html index 44057cb63..bf0994b07 100644 --- a/web/examples/splom.html +++ b/web/examples/splom.html @@ -157,8 +157,8 @@ .valueAccessor(key_part(1)) .colorAccessor(key_part(2)) .colorDomain(['setosa', 'versicolor', 'virginica']) - .x(d3.scale.linear()).xAxisPadding("0.001%") - .y(d3.scale.linear()).yAxisPadding("0.001%") + .x(d3.scaleLinear()).xAxisPadding("0.001%") + .y(d3.scaleLinear()).yAxisPadding("0.001%") .brushOn(true) .elasticX(true) .elasticY(true) diff --git a/web/examples/stacked-bar.html b/web/examples/stacked-bar.html index 7c6633e3c..6767fd7f3 100644 --- a/web/examples/stacked-bar.html +++ b/web/examples/stacked-bar.html @@ -50,7 +50,7 @@ chart .width(768) .height(480) - .x(d3.scale.linear().domain([1,21])) + .x(d3.scaleLinear().domain([1,21])) .margins({left: 80, top: 20, right: 10, bottom: 20}) .brushOn(false) .clipPadding(10) diff --git a/web/examples/switching-time-intervals.html b/web/examples/switching-time-intervals.html index 485b39c5c..7aa2d4844 100644 --- a/web/examples/switching-time-intervals.html +++ b/web/examples/switching-time-intervals.html @@ -69,10 +69,10 @@ var ndx = crossfilter(posts), dateDim, postsGroup; var intervals = { - Days: d3.time.day, - Weeks: d3.time.week, - Months: d3.time.month, - Years: d3.time.year + Days: d3.timeDay, + Weeks: d3.timeWeek, + Months: d3.timeMonth, + Years: d3.timeYear }; var defint = find_query('interval') || 'Weeks'; d3.select('#interval').selectAll('option') @@ -85,7 +85,7 @@ dateDim.dispose(); group.dispose(); } - var interval = intervals[d3.select('#interval')[0][0].value]; + var interval = intervals[d3.select('#interval').nodes()[0].value]; dateDim = ndx.dimension(function(d) {return interval(d[date_col]);}); chart.xUnits(interval.range); group = dateDim @@ -127,8 +127,8 @@ chart .width(768) .height(480) - .x(d3.time.scale()) - .xUnits(d3.time.weeks) + .x(d3.scaleTime()) + .xUnits(d3.timeWeeks) .margins({left: 50, top: 0, right: 0, bottom: 20}) .elasticY(true) .clipPadding(10); @@ -139,7 +139,7 @@ function calc_domain(chart) { var min = d3.min(chart.group().all(), function(kv) { return kv.key; }), max = d3.max(chart.group().all(), function(kv) { return kv.key; }); - max = d3.time.month.offset(max, 1); + max = d3.timeMonth.offset(max, 1); chart.x().domain([min, max]); } chart.on('preRender', calc_domain); diff --git a/web/examples/time-intervals.html b/web/examples/time-intervals.html index 099606e7e..5f7332cdd 100644 --- a/web/examples/time-intervals.html +++ b/web/examples/time-intervals.html @@ -16,12 +16,12 @@ any items whose intervals overlap with it.

@@ -34,7 +34,7 @@ function intervalTreeGroup(tree, firstDate, lastDate) { return { all: function() { - var begin = d3.time.month(firstDate), end = d3.time.month(lastDate); + var begin = d3.timeMonth(firstDate), end = d3.timeMonth(lastDate); var i = new Date(begin); var ret = [], count; do { @@ -52,15 +52,18 @@ } }; } - var timeFormat = d3.time.format('%x'); + + var dateFormatSpecifier = '%x'; + var timeFormat = d3.timeFormat(dateFormatSpecifier); + var dateFormatParser = d3.timeParse(dateFormatSpecifier); var monthChart = dc.barChart("#month"); var costChart = dc.barChart("#cost"); // data from http://stackoverflow.com/questions/22603788/crossfilter-how-to-extract-time-information-from-start-date-and-end-date-column d3.csv("intervals.csv", function(error, projects) { projects.forEach(function(x) { - x['Start Date'] = timeFormat.parse(x['Start Date']); - x['End Date'] = timeFormat.parse(x['End Date']); + x['Start Date'] = dateFormatParser(x['Start Date']); + x['End Date'] = dateFormatParser(x['End Date']); // the library uses object identity so we have to cache the interval arrays x.interval = [x['Start Date'].getTime(), x['End Date'].getTime()]; x.Cost = +x.Cost; @@ -91,9 +94,9 @@ monthChart .width(400) .height(300) - .x(d3.time.scale()) - .y(d3.scale.linear().domain([0,25])) - .xUnits(d3.time.months) + .x(d3.scaleTime()) + .y(d3.scaleLinear().domain([0,25])) + .xUnits(d3.timeMonths) .gap(5) .elasticX(true) .brushOn(true) @@ -120,8 +123,8 @@ costChart .width(400) .height(300) - .x(d3.scale.linear().domain([0,24])) - .y(d3.scale.linear().domain([0,25])) + .x(d3.scaleLinear().domain([0,24])) + .y(d3.scaleLinear().domain([0,25])) .brushOn(true) .yAxisLabel("Number of Projects") .xAxisLabel("Cost") diff --git a/web/resizing/dc-resizing.js b/web/resizing/dc-resizing.js index 39318db12..46be4e733 100644 --- a/web/resizing/dc-resizing.js +++ b/web/resizing/dc-resizing.js @@ -28,7 +28,9 @@ function apply_resizing(chart, adjustX, adjustY, onresize) { .width(window.innerWidth-adjustX) .height(window.innerHeight-adjustY); window.onresize = function() { - onresize(chart); + if(onresize) { + onresize(chart); + } chart .width(window.innerWidth-20) .height(window.innerHeight-20) diff --git a/web/resizing/resizing-bar.html b/web/resizing/resizing-bar.html index 80f7208bd..d4f243a98 100644 --- a/web/resizing/resizing-bar.html +++ b/web/resizing/resizing-bar.html @@ -28,7 +28,7 @@ speedSumGroup = runDimension.group().reduceSum(function(d) {return d.Speed * d.Run / 1000;}); chart - .x(d3.scale.linear().domain([6,20])) + .x(d3.scaleLinear().domain([6,20])) .brushOn(true) .xAxisLabel("This is the X Axis!!") .yAxisLabel("This is the Y Axis!") diff --git a/web/resizing/resizing-heatmap.html b/web/resizing/resizing-heatmap.html index 2d6137311..b2fa9be65 100644 --- a/web/resizing/resizing-heatmap.html +++ b/web/resizing/resizing-heatmap.html @@ -23,12 +23,12 @@

Michelson–Morley experiment

d3.csv("../ndx.csv", function(error, data) { - var dateFormat = d3.time.format("%m/%d/%Y"); + var dateParse = d3.timeParse("%m/%d/%Y"); data.forEach(function (d) { - d.dd = dateFormat.parse(d.date); - d.month = d3.time.month(d.dd).getMonth(); // pre-calculate month for better performance - d.year = d3.time.year(d.dd).getFullYear(); + d.dd = dateParse(d.date); + d.month = d3.timeMonth(d.dd).getMonth(); // pre-calculate month for better performance + d.year = d3.timeYear(d.dd).getFullYear(); d.close = +d.close; // coerce to number d.open = +d.open; }); @@ -66,10 +66,10 @@

Michelson–Morley experiment

var heatColorMapping = function(d) { if (d < 0) { - return d3.scale.linear().domain([-23,0]).range(["red", "#e5e5e5"])(d); + return d3.scaleLinear().domain([-23,0]).range(["red", "#e5e5e5"])(d); } else { - return d3.scale.linear().domain([0,23]).range(["#e5e5e5", "green"])(d); + return d3.scaleLinear().domain([0,23]).range(["#e5e5e5", "green"])(d); } }; heatColorMapping.domain = function() { @@ -120,8 +120,8 @@

Michelson–Morley experiment

.group(percentageGainByMonthArrayGroup) .width(window.innerWidth-20) .height(window.innerHeight/2-fudge) - .y(d3.scale.linear().domain([-10.0,100.0])) - .x(d3.scale.linear().domain([-0.5,11.5])) + .y(d3.scaleLinear().domain([-10.0,100.0])) + .x(d3.scaleLinear().domain([-0.5,11.5])) .elasticY(true) .centerBar(true); barChart.render(); diff --git a/web/resizing/resizing-right-axis.html b/web/resizing/resizing-right-axis.html index 2ccc3bcc8..48965469e 100644 --- a/web/resizing/resizing-right-axis.html +++ b/web/resizing/resizing-right-axis.html @@ -22,12 +22,12 @@ var moveChart = dc.compositeChart("#monthly-move-chart"); d3.csv("../examples/monthly-move.csv", function (error, data) { - var dateFormat = d3.time.format("%m/%d/%Y"); + var dateParse = d3.timeParse("%m/%d/%Y"); var numberFormat = d3.format(".2f"); data.forEach(function (e) { - e.dd = dateFormat.parse(e.date); - e.month = d3.time.month(e.dd); // pre-calculate month for better performance + e.dd = dateParse(e.date); + e.month = d3.timeMonth(e.dd); // pre-calculate month for better performance }); var ndx = crossfilter(data); @@ -64,9 +64,9 @@ .margins({top: 30, right: 50, bottom: 25, left: 60}) .dimension(moveMonths) .mouseZoomable(true) - .x(d3.time.scale().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)])) - .round(d3.time.month.round) - .xUnits(d3.time.months) + .x(d3.scaleTime().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)])) + .round(d3.timeMonth.round) + .xUnits(d3.timeMonths) .elasticY(true) .renderHorizontalGridLines(true) .legend(dc.legend().x(90).y(10).itemHeight(13).gap(5)) @@ -85,7 +85,7 @@ .title(function (d) { var value = d.data.value.avg ? d.data.value.avg : d.data.value; if (isNaN(value)) value = 0; - return dateFormat(d.data.key) + "\n" + numberFormat(value); + return dateParse(d.data.key) + "\n" + numberFormat(value); }) .ordinalColors(["orange"]) .useRightYAxis(true) diff --git a/web/resizing/resizing-row.html b/web/resizing/resizing-row.html index 8787cec9b..1b1df370c 100644 --- a/web/resizing/resizing-row.html +++ b/web/resizing/resizing-row.html @@ -30,7 +30,7 @@ chart .width(window.innerWidth-20) .height(window.innerHeight-20) - .x(d3.scale.linear().domain([6,20])) + .x(d3.scaleLinear().domain([6,20])) .elasticX(true) .dimension(runDimension) .group(speedSumGroup) diff --git a/web/resizing/resizing-series.html b/web/resizing/resizing-series.html index 816ba8715..13531b6ee 100644 --- a/web/resizing/resizing-series.html +++ b/web/resizing/resizing-series.html @@ -32,8 +32,8 @@ chart .width(window.innerWidth-adjustX) .height(window.innerHeight-adjustY) - .chart(function(c) { return dc.lineChart(c).interpolate('cardinal'); }) - .x(d3.scale.linear().domain([0,20])) + .chart(function(c) { return dc.lineChart(c).interpolate(d3.curveCardinal); }) + .x(d3.scaleLinear().domain([0,20])) .brushOn(false) .yAxisLabel("Measured Speed km/s") .xAxisLabel("Run") diff --git a/web/stock.js b/web/stock.js index 1eaf655f5..322e24a34 100644 --- a/web/stock.js +++ b/web/stock.js @@ -61,12 +61,14 @@ var nasdaqTable = dc.dataTable('.dc-data-table'); //``` d3.csv('ndx.csv', function (data) { // Since its a csv file we need to format the data a bit. - var dateFormat = d3.time.format('%m/%d/%Y'); + var dateFormatSpecifier = '%m/%d/%Y'; + var dateFormat = d3.timeFormat(dateFormatSpecifier); + var dateFormatParser = d3.timeParse(dateFormatSpecifier); var numberFormat = d3.format('.2f'); data.forEach(function (d) { - d.dd = dateFormat.parse(d.date); - d.month = d3.time.month(d.dd); // pre-calculate month for better performance + d.dd = dateFormatParser(d.date); + d.month = d3.timeMonth(d.dd); // pre-calculate month for better performance d.close = +d.close; // coerce to number d.open = +d.open; }); @@ -79,7 +81,7 @@ d3.csv('ndx.csv', function (data) { // Dimension by year var yearlyDimension = ndx.dimension(function (d) { - return d3.time.year(d.dd).getFullYear(); + return d3.timeYear(d.dd).getFullYear(); }); // Maintain running tallies by year as filters are applied or removed var yearlyPerformanceGroup = yearlyDimension.group().reduce( @@ -243,9 +245,9 @@ d3.csv('ndx.csv', function (data) { return p.value.fluctuationPercentage; }) .maxBubbleRelativeSize(0.3) - .x(d3.scale.linear().domain([-2500, 2500])) - .y(d3.scale.linear().domain([-100, 100])) - .r(d3.scale.linear().domain([0, 4000])) + .x(d3.scaleLinear().domain([-2500, 2500])) + .y(d3.scaleLinear().domain([-100, 100])) + .r(d3.scaleLinear().domain([0, 4000])) //##### Elastic Scaling //`.elasticY` and `.elasticX` determine whether the chart should rescale each axis to fit the data. @@ -388,7 +390,7 @@ d3.csv('ndx.csv', function (data) { // (_optional_) set filter brush rounding .round(dc.round.floor) .alwaysUseRounding(true) - .x(d3.scale.linear().domain([-25, 25])) + .x(d3.scaleLinear().domain([-25, 25])) .renderHorizontalGridLines(true) // Customize the filter displayed in the control span .filterPrinter(function (filters) { @@ -417,9 +419,9 @@ d3.csv('ndx.csv', function (data) { .mouseZoomable(true) // Specify a "range chart" to link its brush extent with the zoom of the current "focus chart". .rangeChart(volumeChart) - .x(d3.time.scale().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)])) - .round(d3.time.month.round) - .xUnits(d3.time.months) + .x(d3.scaleTime().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)])) + .round(d3.timeMonth.round) + .xUnits(d3.timeMonths) .elasticY(true) .renderHorizontalGridLines(true) //##### Legend @@ -459,10 +461,10 @@ d3.csv('ndx.csv', function (data) { .group(volumeByMonthGroup) .centerBar(true) .gap(1) - .x(d3.time.scale().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)])) - .round(d3.time.month.round) + .x(d3.scaleTime().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)])) + .round(d3.timeMonth.round) .alwaysUseRounding(true) - .xUnits(d3.time.months); + .xUnits(d3.timeMonths); //#### Data Count @@ -635,7 +637,7 @@ d3.csv('ndx.csv', function (data) { // Closure used to retrieve radius value from multi-value group .radiusValueAccessor(function(p) {return p.value.fluctuationPercentage;}) // set radius scale - .r(d3.scale.linear().domain([0, 3])) + .r(d3.scaleLinear().domain([0, 3])) // (_optional_) whether chart should render labels, `default = true` .renderLabel(true) // (_optional_) closure to generate label per bubble, `default = group.key` diff --git a/web/transitions/area-progression.html b/web/transitions/area-progression.html index 72ca110a9..8e2508f28 100644 --- a/web/transitions/area-progression.html +++ b/web/transitions/area-progression.html @@ -42,7 +42,7 @@ .transitionDuration(transitionTest.duration) .width(768) .height(480) - .x(d3.scale.linear()) + .x(d3.scaleLinear()) .elasticX(true) .elasticY(true) .margins({left: 50, top: 10, right: 10, bottom: 20}) diff --git a/web/transitions/area-transitions.html b/web/transitions/area-transitions.html index db811f950..ef521786c 100644 --- a/web/transitions/area-transitions.html +++ b/web/transitions/area-transitions.html @@ -54,7 +54,7 @@ .transitionDuration(transitionTest.duration) .width(768) .height(480) - .x(d3.scale.linear().domain([1,20])) + .x(d3.scaleLinear().domain([1,20])) .margins({left: 50, top: 10, right: 10, bottom: 20}) .renderArea(doArea) .brushOn(false) diff --git a/web/transitions/bar-progression.html b/web/transitions/bar-progression.html index b7ad72901..c63f88eb9 100644 --- a/web/transitions/bar-progression.html +++ b/web/transitions/bar-progression.html @@ -40,7 +40,7 @@ .transitionDuration(transitionTest.duration) .width(768) .height(480) - .x(d3.scale.linear()) + .x(d3.scaleLinear()) .elasticX(true) .elasticY(true) .margins({left: 50, top: 10, right: 10, bottom: 20}) diff --git a/web/transitions/bar-transitions.html b/web/transitions/bar-transitions.html index 8839a22c2..65aebbe84 100644 --- a/web/transitions/bar-transitions.html +++ b/web/transitions/bar-transitions.html @@ -37,7 +37,7 @@ .transitionDuration(transitionTest.duration) .width(768) .height(480) - .x(d3.scale.linear().domain([0,20])) + .x(d3.scaleLinear().domain([0,20])) .brushOn(false) .yAxisLabel("This is the Y Axis!") .dimension(runDimension) diff --git a/web/transitions/ordinal-bar-transitions.html b/web/transitions/ordinal-bar-transitions.html index b2ac602f1..556a10e3c 100644 --- a/web/transitions/ordinal-bar-transitions.html +++ b/web/transitions/ordinal-bar-transitions.html @@ -31,7 +31,7 @@ return chart .width(768) .height(380) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .elasticX(true) .elasticY(true) diff --git a/web/transitions/ordinal-line-transitions.html b/web/transitions/ordinal-line-transitions.html index 871803041..9edb68cbb 100644 --- a/web/transitions/ordinal-line-transitions.html +++ b/web/transitions/ordinal-line-transitions.html @@ -31,7 +31,7 @@ return chart .width(768) .height(380) - .x(d3.scale.ordinal()) + .x(d3.scaleOrdinal()) .xUnits(dc.units.ordinal) .elasticX(true) .elasticY(true) diff --git a/web/transitions/stacked-bar-transitions.html b/web/transitions/stacked-bar-transitions.html index 5952c2619..687b6601d 100644 --- a/web/transitions/stacked-bar-transitions.html +++ b/web/transitions/stacked-bar-transitions.html @@ -52,7 +52,7 @@ .transitionDuration(transitionTest.duration) .width(768) .height(480) - .x(d3.scale.linear().domain([1,21])) + .x(d3.scaleLinear().domain([1,21])) .margins({left: 50, top: 10, right: 10, bottom: 20}) .brushOn(false) .clipPadding(10) diff --git a/web/transitions/transition-test.js b/web/transitions/transition-test.js index dfd492089..b2dc322ac 100644 --- a/web/transitions/transition-test.js +++ b/web/transitions/transition-test.js @@ -44,7 +44,7 @@ var transitionTest = (function() { _magnitude = 1, // maximum change in y per observation _reverse = false; // whether to regress instead of progress var _data = []; - var rand = d3.random.normal(); + var rand = d3.randomNormal(); function startval() { // .fill() (when can we drop ie?) var a = new Array(N); for(var i = 0; iUS Venture Capital Landscape 2011 .height(500) .dimension(states) .group(stateRaisedSum) - .colors(d3.scale.quantize().range(["#E2F2FF", "#C4E4FF", "#9ED2FF", "#81C5FF", "#6BBAFF", "#51AEFF", "#36A2FF", "#1E96FF", "#0089FF", "#0061B5"])) + .colors(d3.scaleQuantize().range(["#E2F2FF", "#C4E4FF", "#9ED2FF", "#81C5FF", "#6BBAFF", "#51AEFF", "#36A2FF", "#1E96FF", "#0089FF", "#0061B5"])) .colorDomain([0, 200]) .colorCalculator(function (d) { return d ? usChart.colors()(d) : '#ccc'; }) .overlayGeoJson(statesJson.features, "state", function (d) { return d.properties.name; }) + .projection(d3.geoAlbersUsa()) .valueAccessor(function(kv) { console.log(kv); return kv.value; @@ -150,7 +151,7 @@

US Venture Capital Landscape 2011

.margins({top: 10, right: 50, bottom: 30, left: 60}) .dimension(industries) .group(statsByIndustries) - .colors(d3.scale.category10()) + .colors(d3.scaleOrdinal(d3.schemeCategory10)) .keyAccessor(function (p) { return p.value.amountRaised; }) @@ -160,8 +161,8 @@

US Venture Capital Landscape 2011

.radiusValueAccessor(function (p) { return p.value.amountRaised; }) - .x(d3.scale.linear().domain([0, 5000])) - .r(d3.scale.linear().domain([0, 4000])) + .x(d3.scaleLinear().domain([0, 5000])) + .r(d3.scaleLinear().domain([0, 4000])) .minRadiusWithLabel(15) .elasticY(true) .yAxisPadding(100) @@ -190,7 +191,7 @@

US Venture Capital Landscape 2011

.margins({top: 10, right: 50, bottom: 30, left: 60}) .dimension(rounds) .group(statsByRounds) - .colors(d3.scale.category10()) + .colors(d3.scaleOrdinal(d3.schemeCategory10)) .keyAccessor(function (p) { return p.value.amountRaised; }) @@ -200,8 +201,8 @@

US Venture Capital Landscape 2011

.radiusValueAccessor(function (p) { return p.value.amountRaised; }) - .x(d3.scale.linear().domain([0, 5000])) - .r(d3.scale.linear().domain([0, 9000])) + .x(d3.scaleLinear().domain([0, 5000])) + .r(d3.scaleLinear().domain([0, 9000])) .minRadiusWithLabel(15) .elasticY(true) .yAxisPadding(150) diff --git a/web/zoom/restrict-panning.html b/web/zoom/restrict-panning.html index 03194d0ce..ac7442fd0 100644 --- a/web/zoom/restrict-panning.html +++ b/web/zoom/restrict-panning.html @@ -135,8 +135,8 @@ .height(40) .dimension(dimension) .group(group) - .x(d3.time.scale().domain(domain)) - .xUnits(d3.time.month) + .x(d3.scaleTime().domain(domain)) + .xUnits(d3.timeMonth) .centerBar(true) .render(); @@ -145,8 +145,8 @@ .dimension(dimension) .group(group) .rangeChart(rangeChart) - .x(d3.time.scale().domain(domain)) - .xUnits(d3.time.day) + .x(d3.scaleTime().domain(domain)) + .xUnits(d3.timeDay) .brushOn(false) .mouseZoomable(true) .zoomScale([1, 100])