├── .babelrc.json
├── .eslintrc.json
├── .github
├── dependabot.yml
└── workflows
│ ├── codeql-analysis.yml
│ └── nodejs.yml
├── .gitignore
├── .npmignore
├── .prettierignore
├── .prettierrc
├── .storybook
└── main.js
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── example
└── index.html
├── package-lock.json
├── package.json
├── rollup.config.js
├── src
├── d3-compat.js
├── index.js
└── slider.js
├── stories
├── basic-functionality.stories.js
├── demos
│ ├── color-picker.stories.js
│ ├── music-player-controls.css
│ ├── music-player-controls.stories.js
│ └── new-york-times.stories.js
├── extended-functionality.stories.js
└── styling.stories.mdx
└── test
├── .eslintrc.json
├── slider-horizontal.html
├── slider-test.js
└── slider-vertical.html
/.babelrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "sourceType": "unambiguous",
3 | "presets": [
4 | [
5 | "@babel/preset-env",
6 | {
7 | "targets": {
8 | "chrome": 100
9 | }
10 | }
11 | ]
12 | ],
13 | "plugins": []
14 | }
15 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint:recommended",
3 | "parserOptions": {
4 | "sourceType": "module",
5 | "ecmaVersion": 11
6 | },
7 | "env": {
8 | "es6": true
9 | },
10 | "rules": {
11 | "no-cond-assign": 0
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "npm"
9 | directory: "/"
10 | schedule:
11 | interval: "monthly"
12 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL"
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | # The branches below must be a subset of the branches above
8 | branches: [master]
9 | schedule:
10 | - cron: '0 18 * * 5'
11 |
12 | jobs:
13 | analyze:
14 | name: Analyze
15 | runs-on: ubuntu-latest
16 |
17 | strategy:
18 | fail-fast: false
19 | matrix:
20 | # Override automatic language detection by changing the below list
21 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
22 | language: ['javascript']
23 | # Learn more...
24 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
25 |
26 | steps:
27 | - name: Checkout repository
28 | uses: actions/checkout@v2
29 | with:
30 | # We must fetch at least the immediate parents so that if this is
31 | # a pull request then we can checkout the head.
32 | fetch-depth: 2
33 |
34 | # If this run was triggered by a pull request event, then checkout
35 | # the head of the pull request instead of the merge commit.
36 | - run: git checkout HEAD^2
37 | if: ${{ github.event_name == 'pull_request' }}
38 |
39 | # Initializes the CodeQL tools for scanning.
40 | - name: Initialize CodeQL
41 | uses: github/codeql-action/init@v1
42 | with:
43 | languages: ${{ matrix.language }}
44 | # If you wish to specify custom queries, you can do so here or in a config file.
45 | # By default, queries listed here will override any specified in a config file.
46 | # Prefix the list here with "+" to use these queries and those in the config file.
47 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
48 |
49 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
50 | # If this step fails, then you should remove it and run the build manually (see below)
51 | - name: Autobuild
52 | uses: github/codeql-action/autobuild@v1
53 |
54 | # ℹ️ Command-line programs to run using the OS shell.
55 | # 📚 https://git.io/JvXDl
56 |
57 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
58 | # and modify them (or add more) to build your code if your project
59 | # uses a compiled language
60 |
61 | #- run: |
62 | # make bootstrap
63 | # make release
64 |
65 | - name: Perform CodeQL Analysis
66 | uses: github/codeql-action/analyze@v1
67 |
--------------------------------------------------------------------------------
/.github/workflows/nodejs.yml:
--------------------------------------------------------------------------------
1 | name: Node CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 |
9 | strategy:
10 | matrix:
11 | node-version: [18.x]
12 |
13 | steps:
14 | - uses: actions/checkout@v1
15 | - name: Use Node.js ${{ matrix.node-version }}
16 | uses: actions/setup-node@v1
17 | with:
18 | node-version: ${{ matrix.node-version }}
19 | - name: npm install, build, and test
20 | run: |
21 | npm ci
22 | npm run build --if-present
23 | npm test
24 | env:
25 | CI: true
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | dist/
3 | node_modules
4 | npm-debug.log
5 | storybook-static
6 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | dist/*.zip
2 | test/
3 | .storybook/
4 | stories/
5 | storybook-static/
6 | example/
7 | .travis.yml
8 | .prettierrc
9 | .eslintrc
10 | rollup.config.js
11 | .prettierignore
12 | .eslintrc.yaml
13 | .github/workflows/nodejs.yml
14 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | test/slider-horizontal.html
2 | test/slider-vertical.html
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "es5"
4 | }
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | stories: ['../stories/**/*.stories.@(js|mdx)'],
3 | addons: ['@storybook/addon-essentials', '@storybook/addon-mdx-gfm'],
4 | framework: {
5 | name: '@storybook/html-webpack5',
6 | options: {},
7 | },
8 | docs: {
9 | autodocs: true,
10 | },
11 | };
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - stable
5 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | The production source code does not make use of most modern syntax and runtime features. The exception is importing and exporting modules. This reflects the approach used by official d3 packages at the time this project was started.
2 |
3 | With newer versions of d3 modules now starting to use newer features, e.g. [d3-array](https://github.com/d3/d3-array) we may introduce new language features but it would be a breaking change and require a new major version.
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2017-2021 John Walley
2 |
3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4 |
5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6 |
7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8 |
9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10 |
11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # d3-simple-slider
2 |
3 | [](https://npmjs.com/package/d3-simple-slider)
4 | [](https://github.com/johnwalley/d3-simple-slider/actions/workflows/nodejs.yml)
5 |
6 | Render a simple interactive slider using SVG.
7 |
8 | 
9 |
10 | Examples:
11 |
12 | - [Storybook](https://d3-simple-slider.mulberryhousesoftware.com)
13 | - [Bl.ocks.org](https://bl.ocks.org/johnwalley/e1d256b81e51da68f7feb632a53c3518)
14 |
15 | Inspired by The New York Times [Is It Better to Rent or Buy?](https://www.nytimes.com/interactive/2014/upshot/buy-rent-calculator.html)
16 |
17 | ## Why use d3-simple-slider?
18 |
19 | If you need to include a slider within an svg element this is for you. For example, use a slider in place of an axis in a chart.
20 |
21 | If you don't need to work inside an svg element then I would consider using one of the many excellent html-based components which may be better suited to your needs. Of course you might just love using d3!
22 |
23 | ## Installing
24 |
25 | There are three ways to use this library.
26 |
27 | ### Include the file directly
28 |
29 | You must include the [d3 library](http://d3js.org/) before including the slider file. Then you can add the [compiled js file](https://github.com/johnwalley/d3-simple-slider/releases/latest/download/d3-simple-slider.zip) to your website.
30 |
31 | The d3-simple-slider functionality is added to the `d3` global object.
32 |
33 | ```html
34 |
35 |
36 |
37 |
38 |
39 |
40 |
60 | ```
61 |
62 | ### Using a CDN
63 |
64 | You can add the latest version of [d3-simple-slider hosted on unpkg](https://unpkg.com/d3-simple-slider).
65 |
66 | The d3-simple-slider functionality is added to the `d3` global object.
67 |
68 | ```html
69 |
70 |
71 |
72 |
73 |
74 |
75 |
95 | ```
96 |
97 | ### Using npm or yarn
98 |
99 | You can add d3-simple-slider as a node module by running
100 |
101 | ```node
102 | npm install d3-simple-slider
103 | ```
104 |
105 | or
106 |
107 | ```node
108 | yarn add d3-simple-slider
109 | ```
110 |
111 | You can then import any of the exported functions: `sliderHorizontal`, `sliderVertical`, `sliderTop`, `sliderRight`, `sliderBottom`, `sliderLeft`.
112 |
113 | ```js
114 | import * as d3 from 'd3';
115 | import { sliderBottom } from 'd3-simple-slider';
116 |
117 | const div = document.createElement('div');
118 | const slider = sliderBottom().min(0).max(10).step(1).width(300);
119 |
120 | const g = d3
121 | .select(div)
122 | .append('svg')
123 | .attr('width', 500)
124 | .attr('height', 100)
125 | .append('g')
126 | .attr('transform', 'translate(30,30)');
127 |
128 | g.call(slider);
129 | ```
130 |
131 | ## Styling
132 |
133 | To change the font size:
134 |
135 | ```css
136 | .axis text,
137 | .slider text {
138 | font-size: 18px;
139 | }
140 | ```
141 |
142 | To change the tick text color:
143 |
144 | ```css
145 | .axis text {
146 | fill: red;
147 | }
148 | ```
149 |
150 | To change the parameter value text color:
151 |
152 | ```css
153 | .slider text {
154 | fill: green;
155 | }
156 | ```
157 |
158 | ## API Reference
159 |
160 | Regardless of orientation, sliders are always rendered at the origin. To change the position of the slider specify a [transform attribute](http://www.w3.org/TR/SVG/coords.html#TransformAttribute) on the containing element. For example:
161 |
162 | ```js
163 | d3.select('body')
164 | .append('svg')
165 | .attr('width', 1440)
166 | .attr('height', 30)
167 | .append('g')
168 | .attr('transform', 'translate(0,30)')
169 | .call(slider);
170 | ```
171 |
172 | The orientation of a slider is fixed; to change the orientation, remove the old slider and create a new slider.
173 |
174 | All sliders may take a [scale](https://github.com/d3/d3-scale) as an argument. If _scale_ is specified, the slider will use the scale to render the slider. This must be either [scaleLinear](https://github.com/d3/d3-scale#scaleLinear) or [scaleTime](https://github.com/d3/d3-scale#scaleTime). The domain will be used to calculate minimum and maximum values. The range will be used to calculate the width or height of the slider. This means you do not need to set these if passing a scale.
175 |
176 | # d3.sliderHorizontal([scale]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L859 'Source')
177 |
178 | Constructs a new horizontal slider generator. _Note that this is equivalent to [`sliderBottom`](#sliderBottom)._
179 |
180 | # d3.sliderVertical([scale]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L863 'Source')
181 |
182 | Constructs a new vertical slider generator. _Note that this is equivalent to [`sliderLeft`](#sliderLeft)._
183 |
184 | # d3.sliderTop([scale]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L867 'Source')
185 |
186 | Constructs a new horizontal slider generator. Ticks on top.
187 |
188 | # d3.sliderRight([scale]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L839 'Source')
189 |
190 | Constructs a new vertical slider generator. Ticks to the right;
191 |
192 | # d3.sliderBottom([scale]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L871 'Source')
193 |
194 | Constructs a new horizontal slider generator. Ticks on the bottom.
195 |
196 | # d3.sliderLeft([scale]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L879 'Source')
197 |
198 | Constructs a new vertical slider generator. Ticks to the left;
199 |
200 | #slider(context) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L30 'Source')
201 |
202 | Render the slider to the given _context_, which may be either a [selection](https://github.com/d3/d3-selection) of SVG containers (either SVG or G elements) or a corresponding [transition](https://github.com/d3/d3-transition).
203 |
204 | #slider.ticks([count]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L729 'Source')
205 |
206 | To generate twenty ticks:
207 |
208 | ```js
209 | slider.ticks(20);
210 | ```
211 |
212 | #slider.tickValues([values]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L815 'Source')
213 |
214 | If a values array is specified, the specified values are used for ticks rather than using the sliders' automatic tick generator. If values is null, clears any previously-set explicit tick values and reverts back to the sliders' tick generator. If values is not specified, returns the current tick values, which defaults to null. For example, to generate ticks at specific values:
215 |
216 | ```js
217 | slider.tickValues([1, 2, 3, 5, 8, 13, 21]);
218 | ```
219 |
220 | #slider.tickPadding([padding]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L821 'Source')
221 |
222 | If _padding_ is specified, sets the padding to the specified value in pixels and returns the axis. If _padding_ is not specified, returns the current padding which defaults to 3 pixels.
223 |
224 | #slider.tickFormat([format]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L717 'Source')
225 |
226 | If _format_ is specified, sets the tick format function and returns the slider. If _format_ is not specified, returns the current format function, which defaults to null. A null format indicates that the slider's default formatter should be used.
227 |
228 | See [d3-format](https://github.com/d3/d3-format) and [d3-time-format](https://github.com/d3/d3-time-format) for help creating formatters. For example, to display integers with comma-grouping for thousands:
229 |
230 | ```js
231 | slider.tickFormat(d3.format(',.0f'));
232 | ```
233 |
234 | #slider.displayFormat([format]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L723 'Source')
235 |
236 | If _format_ is specified, sets the function used to format the highlighted value and returns the slider. If _format_ is not specified, returns the current format function, which defaults to null. A null format indicates that the tickFormat should be used. If tickFormat is null then the slider's default formatter should be used.
237 |
238 | See [d3-format](https://github.com/d3/d3-format) and [d3-time-format](https://github.com/d3/d3-time-format) for help creating formatters. For example, to display integers with comma-grouping for thousands:
239 |
240 | ```js
241 | slider.displayFormat(d3.format(',.0f'));
242 | ```
243 |
244 | #slider.value([value]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L735 'Source')
245 |
246 | If _value_ is specified, sets the value of the slider to the specified value and returns the slider. If _value_ is not specified, returns the current value.
247 |
248 | If _value_ is an array of length two then the values represent a range.
249 |
250 | #slider.silentValue([value]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L762 'Source')
251 |
252 | If _value_ is specified, sets the value of the slider to the specified value and returns the slider _without_ invoking any listeners. If _value_ is not specified, returns the current value.
253 |
254 | If _value_ is an array of length two then the values represent a range.
255 |
256 | #slider.displayValue([value]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L839 'Source')
257 |
258 | If _value_ is specified, sets the whether the highlighted value of the slider should be shown and returns the slider. If _value_ is not specified, returns the current value, which defaults to true.
259 |
260 | #slider.handle([value]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L833 'Source')
261 |
262 | If _value_ is specified, sets the [SVG path definition](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d) used to render the slider handle and returns the slider. If _value_ is not specified, returns the current value, which defaults to 'M-5.5,-5.5v10l6,5.5l6,-5.5v-10z'.
263 |
264 | #slider.width([size]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L695 'Source')
265 |
266 | If _size_ is specified, sets the width of the slider to the specified value and returns the slider. If _size_ is not specified, returns the current width, which defaults to 100. This property only affects horizontal sliders and is ignored otherwise.
267 |
268 | #slider.height([size]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L706 'Source')
269 |
270 | If _size_ is specified, sets the height of the slider to the specified value and returns the slider. If _size_ is not specified, returns the current height, which defaults to 100. This property only affects vertical sliders and is ignored otherwise.
271 |
272 | #slider.min([value]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L662 'Source')
273 |
274 | If _value_ is specified, sets the minimum value of the slider to the specified value and returns the slider. If _value_ is not specified, returns the current minimum value, which defaults to 0.
275 |
276 | #slider.max([value]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L673 'Source')
277 |
278 | If _value_ is specified, sets the maximum value of the slider to the specified value and returns the slider. If _value_ is not specified, returns the current maximum value, which defaults to 10.
279 |
280 | #slider.domain([value]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L684 'Source')
281 |
282 | If _value_ is specified, an array which sets the minimum and maximum values of the slider and returns the slider. If _value_ is not specified, returns the current maximum value, which defaults to [0, 10].
283 |
284 | #slider.fill([color]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L845 'Source')
285 |
286 | If _color_ is specified, sets the color of the slider track-fill and returns the slider. If _color_ is not specified, returns the current value, which defaults to null.
287 |
288 | #slider.step([value]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L809 'Source')
289 |
290 | If _value_ is specified, sets the increment which the slider will move in and returns the slider. If _value_ is not specified, returns the current value, which defaults to null.
291 |
292 | #slider.marks([value]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L827 'Source')
293 |
294 | If _value_ is specified, sets the values to which the slider will snap to and returns the slider. If _value_ is not specified, returns the current value, which defaults to null.
295 |
296 | #slider.default([value]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L789 'Source')
297 |
298 | If _value_ is specified, sets the initial value of the slider and returns the slider. If _value_ is not specified, returns the current value, which defaults to null.
299 |
300 | #slider.on(typenames, [listener]) [<>](https://github.com/johnwalley/d3-simple-slider/blob/main/src/slider.js#L851 'Source')
301 |
302 | If _listener_ is specified, sets the event _listener_ for the specified _typenames_ and returns the slider. If an event listener was already registered for the same type and name, the existing listener is removed before the new listener is added. If _listener_ is null, removes the current event listeners for the specified _typenames_, if any. If _listener_ is not specified, returns the first currently-assigned listener matching the specified _typenames_, if any. When a specified event is dispatched, each _listener_ will be invoked with the same context and arguments as [_selection_.on](https://github.com/d3/d3-selection#selection_on) listeners: the current datum `d` and index `i`, with the `this` context as the current DOM element.
303 |
304 | The _typenames_ is a string containing one or more _typename_ separated by whitespace. Each _typename_ is a _type_, optionally followed by a period (`.`) and a _name_, such as `drag.foo` and `drag.bar`; the name allows multiple listeners to be registered for the same _type_. The _type_ must be one of the following:
305 |
306 | - `onchange` - after the slider value has changed.
307 | - `start` - after a new pointer becomes active (on mousedown or touchstart).
308 | - `drag` - after an active pointer moves (on mousemove or touchmove).
309 | - `end` - after an active pointer becomes inactive (on mouseup, touchend or touchcancel).
310 |
311 | You might consider throttling `onchange` and `drag` events. For example using [`lodash.throttle`](https://lodash.com/docs/4.17.4#throttle).
312 |
313 | See [_dispatch_.on](https://github.com/d3/d3-dispatch#dispatch_on) for more.
314 |
315 | ## 🤝 How to Contribute
316 |
317 | Please read the [contribution guidelines for this project](CONTRIBUTING.md)
318 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
6 | d3-simple-slider
7 |
8 |
9 |
10 |
11 |
17 |
18 |