├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmrc ├── .nuxtrc ├── .nvmrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── nuxt-plotly-logo.svg ├── package-lock.json ├── package.json ├── playground ├── app.vue ├── components │ └── PieChart.client.vue ├── nuxt.config.ts ├── package.json ├── server │ └── tsconfig.json └── tsconfig.json ├── src ├── module.ts └── runtime │ ├── components │ └── nuxt-plotly.ts │ └── plugin.ts ├── test ├── basic.test.ts └── fixtures │ └── basic │ ├── app.vue │ ├── nuxt.config.ts │ └── package.json └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_size = 2 5 | indent_style = space 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["@nuxt/eslint-config"] 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules 3 | 4 | # Logs 5 | *.log* 6 | 7 | # Temp directories 8 | .temp 9 | .tmp 10 | .cache 11 | 12 | # Yarn 13 | **/.yarn/cache 14 | **/.yarn/*state* 15 | 16 | # Generated dirs 17 | dist 18 | 19 | # Nuxt 20 | .nuxt 21 | .output 22 | .vercel_build_output 23 | .build-* 24 | .env 25 | .netlify 26 | 27 | # Env 28 | .env 29 | 30 | # Testing 31 | reports 32 | coverage 33 | *.lcov 34 | .nyc_output 35 | 36 | # VSCode 37 | .vscode/* 38 | !.vscode/settings.json 39 | !.vscode/tasks.json 40 | !.vscode/launch.json 41 | !.vscode/extensions.json 42 | !.vscode/*.code-snippets 43 | 44 | # Intellij idea 45 | *.iml 46 | .idea 47 | 48 | # OSX 49 | .DS_Store 50 | .AppleDouble 51 | .LSOverride 52 | .AppleDB 53 | .AppleDesktop 54 | Network Trash Folder 55 | Temporary Items 56 | .apdisk 57 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | strict-peer-dependencies=false 3 | -------------------------------------------------------------------------------- /.nuxtrc: -------------------------------------------------------------------------------- 1 | imports.autoImport=false 2 | typescript.includeWorkspace=true 3 | # enable TypeScript bundler module resolution - https://www.typescriptlang.org/docs/handbook/modules/reference.html#bundler 4 | experimental.typescriptBundlerResolution=true 5 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v18.16.1 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v1.0.14 2 | 3 | [compare changes](https://undefined/undefined/compare/v1.0.13...v1.0.14) 4 | 5 | ### 📖 Documentation 6 | 7 | - Use new `nuxi module add` command in installation (1be925d) 8 | 9 | ### 🏡 Chore 10 | 11 | - Test bundler module resolution (33ce203) 12 | 13 | ### ❤️ Contributors 14 | 15 | - Daniel Roe ([@danielroe](http://github.com/danielroe)) 16 | 17 | ## v1.0.13 18 | 19 | [compare changes](https://undefined/undefined/compare/v1.0.12...v1.0.13) 20 | 21 | ## v1.0.12 22 | 23 | [compare changes](https://undefined/undefined/compare/v1.0.11...v1.0.12) 24 | 25 | ## v1.0.11 26 | 27 | [compare changes](https://undefined/undefined/compare/v1.0.10...v1.0.11) 28 | 29 | ## Updated 30 | 31 | - Add nuxt plugin `$plotly` 32 | 33 | ## Require 34 | 35 | - work with `client-only` 36 | 37 | ## Features 38 | 39 | - 🎇   All plotly.js methods and events 40 | - 🗾   Auto redraw on screensize changes and props update 41 | - 🚀   Data reactivity 42 | - 🏝️   TypeScript support 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2023-present Supanut Dokmaithong (Boomgeek) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | nuxt-plotly logo 4 | 5 |

6 |
7 |

8 | npm version 9 | npm download 10 | MIT license 11 | nuxt-plotly module on nuxt official 12 |

13 |
14 | 15 | # Nuxt Plotly Module 16 | 17 | 📊 `nuxt-plotly` module is thin Nuxt3 wrapper for [plotly.js](https://plotly.com/javascript/) 18 | 19 | - [🏀 Online playground](https://stackblitz.com/edit/nuxt-starter-1bs1ke?file=app.vue) 20 | - [📖  Plotly Documentation](https://plotly.com/javascript/plotly-fundamentals/) 21 | 22 | ## Features 23 | 24 | 25 | 26 | - 🎇   All plotly.js methods and events 27 | - 🗾   Auto redraw on screensize changes and props update 28 | - 🚀   Data reactivity 29 | - 🏝️   TypeScript support 30 | 31 | ## Quick Setup 32 | 33 | 1. Add `nuxt-plotly` dependency to your project 34 | 35 | ```bash 36 | npx nuxi@latest module add nuxt-plotly 37 | ``` 38 | 39 | 2. Add `nuxt-plotly` to the `modules` section of `nuxt.config.ts` 40 | 41 | ```js 42 | // nuxt.config.js 43 | export default defineNuxtConfig({ 44 | /** 45 | * Add nuxt-plotly module 46 | */ 47 | modules: ["nuxt-plotly"], 48 | 49 | /** 50 | * Add nuxt-plotly module with options 51 | * Set the inject option to true to use plotly function via $plotly 52 | */ 53 | // modules: [["nuxt-plotly", { inject: true }]], 54 | }); 55 | ``` 56 | 57 | 3. Add `plotly.js-dist-min` to the `vite.optimizeDeps.include` section of `nuxt.config.ts` 58 | 59 | ```js 60 | // nuxt.config.js 61 | export default defineNuxtConfig({ 62 | vite: { 63 | optimizeDeps: { 64 | include: ["plotly.js-dist-min"], 65 | }, 66 | }, 67 | }); 68 | ``` 69 | 70 | That's it! You can now use Nuxt Plotly Module in your Nuxt app ✨ 71 | 72 | ## Require client-side 73 | 74 | There are two ways to use the `nuxt-plotly` module on the client-side in Nuxt3: 75 | 76 | 1. Wrap the component with the `` tag. 77 | 78 | ```html 79 | 80 | 86 | 87 | ``` 88 | 89 | 2. Create a file with the `.client.vue` extension, for example, [PieChart.client.vue](https://github.com/superdev-tech/nuxt-plotly/blob/main/playground/components/PieChart.client.vue) and then you can use the component without the `` tag. 90 | 91 | ## Plotly Event listeners 92 | 93 | You can access [Plotly events](https://plotly.com/javascript/plotlyjs-events) using the `@on-ready` directive to receive the `PlotlyHTMLElement` object from the `` component. 94 | 95 | - HTML template example 96 | 97 | ```html 98 | 108 | ``` 109 | 110 | - After receiving the PlotlyHTMLElement, you can access Plotly events 111 | 112 | ```typescript 113 | function myChartOnReady(plotlyHTMLElement: NuxtPlotlyHTMLElement) { 114 | console.log({ plotlyHTMLElement }); 115 | 116 | plotlyHTMLElement.on?.("plotly_afterplot", function () { 117 | console.log("done plotting"); 118 | }); 119 | 120 | plotlyHTMLElement.on?.("plotly_click", function () { 121 | alert("You clicked this Plotly chart!"); 122 | }); 123 | } 124 | ``` 125 | 126 | ## Plotly Functions 127 | 128 | To use the [Plotly Function](https://plotly.com/javascript/plotlyjs-function-reference/) in your nuxt project, follow these steps: 129 | 130 | - Step 1: Set the `inject` option to `true` in the `nuxt-plotly` module configuration of your `nuxt.config.ts` file. 131 | 132 | ```js 133 | // nuxt.config.js 134 | export default defineNuxtConfig({ 135 | modules: [["nuxt-plotly", { inject: true }]], 136 | }); 137 | ``` 138 | 139 | - Step 2: After setting the inject option to true, you can now access the plotly function via `$plotly` in your nuxt project. 140 | 141 | ```ts 142 | // app.vue 143 | 144 | const { $plotly } = useNuxtApp(); 145 | 146 | /** 147 | * Show all plotly functions 148 | */ 149 | console.log($plotly); 150 | 151 | /** 152 | * Use downloadImage function 153 | */ 154 | $plotly.downloadImage(plotlyHTMLElement as HTMLElement, { 155 | format: "png", 156 | width: 800, 157 | height: 600, 158 | filename: "newplot", 159 | }); 160 | ``` 161 | 162 | ## Type Aliases 163 | 164 | These type aliases simplify the usage of Plotly types in your Nuxt project: 165 | 166 | ```typescript 167 | /** 168 | * Represents an array of Plotly data objects. 169 | */ 170 | export type NuxtPlotlyData = Array; 171 | 172 | /** 173 | * Represents a partial configuration object for Plotly charts. 174 | */ 175 | export type NuxtPlotlyConfig = Partial; 176 | 177 | /** 178 | * Represents a partial layout object for Plotly charts. 179 | */ 180 | export type NuxtPlotlyLayout = Partial; 181 | 182 | /** 183 | * Represents a partial HTML element that holds a rendered Plotly chart. 184 | */ 185 | export type NuxtPlotlyHTMLElement = Partial; 186 | ``` 187 | 188 | With these type aliases, you can easily work with Plotly data, configurations, layouts, and HTML elements in your Nuxt application, enhancing your experience when creating interactive charts and visualizations. 189 | 190 | ## Development: If you want to contribute 191 | 192 | ```bash 193 | # Install dependencies 194 | npm install 195 | 196 | # Generate type stubs 197 | npm run dev:prepare 198 | 199 | # Develop with the playground 200 | npm run dev 201 | 202 | # Build the playground 203 | npm run dev:build 204 | 205 | # Run ESLint 206 | npm run lint 207 | 208 | # Run Vitest 209 | npm run test 210 | npm run test:watch 211 | 212 | # Release new version 213 | npm run release 214 | ``` 215 | 216 | ## License 217 | 218 | Copyright © 2023 [Supanut Dokmaithong](https://github.com/Boomgeek). 219 | 220 | This project is [MIT licensed](https://github.com/superdev-tech/nuxt-plotly/blob/main/LICENSE). 221 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuxt-plotly", 3 | "version": "1.0.14", 4 | "description": "nuxt-plotly module is thin Nuxt3 wrapper for plotly.js", 5 | "repository": "superdev-tech/nuxt-plotly", 6 | "author": "Supanut Dokmaithong", 7 | "keywords": [ 8 | "nuxt", 9 | "nuxt3", 10 | "plotly", 11 | "plotly.js", 12 | "module" 13 | ], 14 | "license": "MIT", 15 | "type": "module", 16 | "exports": { 17 | ".": { 18 | "types": "./dist/types.d.ts", 19 | "import": "./dist/module.mjs", 20 | "require": "./dist/module.cjs" 21 | } 22 | }, 23 | "main": "./dist/module.cjs", 24 | "types": "./dist/types.d.ts", 25 | "files": [ 26 | "dist" 27 | ], 28 | "scripts": { 29 | "prepack": "nuxt-module-build", 30 | "dev": "nuxi dev playground", 31 | "dev:build": "nuxi build playground", 32 | "dev:prepare": "nuxt-module-build --stub && nuxi prepare playground", 33 | "release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags", 34 | "lint": "eslint .", 35 | "test": "vitest run", 36 | "test:watch": "vitest watch" 37 | }, 38 | "dependencies": { 39 | "@nuxt/kit": "^3.6.5", 40 | "plotly.js-dist-min": "^2.24.3", 41 | "uuid": "^9.0.0" 42 | }, 43 | "devDependencies": { 44 | "@nuxt/devtools": "latest", 45 | "@nuxt/eslint-config": "^0.1.1", 46 | "@nuxt/module-builder": "^0.4.0", 47 | "@nuxt/schema": "^3.6.5", 48 | "@nuxt/test-utils": "^3.6.5", 49 | "@types/node": "^18.16.19", 50 | "@types/plotly.js-dist-min": "^2.3.1", 51 | "@types/uuid": "^9.0.2", 52 | "changelogen": "^0.5.4", 53 | "eslint": "^8.45.0", 54 | "nuxt": "^3.6.5", 55 | "vitest": "^0.33.0" 56 | } 57 | } -------------------------------------------------------------------------------- /playground/app.vue: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 63 | -------------------------------------------------------------------------------- /playground/components/PieChart.client.vue: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 116 | -------------------------------------------------------------------------------- /playground/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | modules: [["../src/module", { inject: true }]], 3 | devtools: { enabled: true }, 4 | vite: { 5 | optimizeDeps: { 6 | include: ["plotly.js-dist-min"], 7 | }, 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "my-module-playground", 4 | "type": "module", 5 | "scripts": { 6 | "dev": "nuxi dev", 7 | "build": "nuxi build", 8 | "generate": "nuxi generate" 9 | }, 10 | "devDependencies": { 11 | "nuxt": "latest" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /playground/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /playground/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /src/module.ts: -------------------------------------------------------------------------------- 1 | import { 2 | defineNuxtModule, 3 | createResolver, 4 | addComponent, 5 | addPlugin, 6 | } from "@nuxt/kit"; 7 | import { name, version } from "../package.json"; 8 | export type { 9 | NuxtPlotlyData, 10 | NuxtPlotlyConfig, 11 | NuxtPlotlyLayout, 12 | NuxtPlotlyHTMLElement, 13 | } from "./runtime/components/nuxt-plotly"; 14 | 15 | export interface ModuleOptions { 16 | inject: boolean; 17 | } 18 | 19 | export default defineNuxtModule({ 20 | defaults: () => ({ 21 | inject: false, 22 | }), 23 | meta: { 24 | name, 25 | version, 26 | configKey: "nuxtPlotly", 27 | compatibility: { 28 | nuxt: "^3.6.0", 29 | }, 30 | }, 31 | setup(options) { 32 | const resolver = createResolver(import.meta.url); 33 | 34 | // Add component 35 | addComponent({ 36 | name: "NuxtPlotly", 37 | filePath: resolver.resolve("./runtime/components/nuxt-plotly"), 38 | mode: "client", 39 | }); 40 | 41 | // Add runtime plugin 42 | if (options.inject) { 43 | addPlugin({ src: resolver.resolve("./runtime/plugin"), mode: "client" }); 44 | } 45 | }, 46 | }); 47 | -------------------------------------------------------------------------------- /src/runtime/components/nuxt-plotly.ts: -------------------------------------------------------------------------------- 1 | // nuxt-img.ts 2 | import { 3 | h, 4 | defineComponent, 5 | reactive, 6 | onBeforeUnmount, 7 | onMounted, 8 | watch, 9 | PropType, 10 | } from "vue"; 11 | import { v4 as uuidv4 } from "uuid"; 12 | import Plotly from "plotly.js-dist-min"; 13 | 14 | export type NuxtPlotlyData = Array; 15 | export type NuxtPlotlyConfig = Partial; 16 | export type NuxtPlotlyLayout = Partial; 17 | export type NuxtPlotlyHTMLElement = Partial; 18 | 19 | export default defineComponent({ 20 | props: { 21 | data: { type: Array as PropType, required: true }, 22 | config: { 23 | type: Object as PropType, 24 | required: false, 25 | default: undefined, 26 | }, 27 | layout: { 28 | type: Object as PropType, 29 | required: false, 30 | default: undefined, 31 | }, 32 | }, 33 | emits: ["on-ready"], 34 | setup(props, ctx) { 35 | const datas = reactive({ 36 | plotlyId: `plotly-${uuidv4()}`, 37 | resizeObserver: {} as ResizeObserver, 38 | timeOutFunctionId: {} as NodeJS.Timeout, 39 | plotlyHTMLElement: {} as NuxtPlotlyHTMLElement, 40 | }); 41 | 42 | const setGraph = async () => { 43 | datas.plotlyHTMLElement = await Plotly.newPlot( 44 | datas.plotlyId, 45 | props.data, 46 | props.layout, 47 | props.config 48 | ); 49 | 50 | ctx.emit("on-ready", datas.plotlyHTMLElement); 51 | }; 52 | 53 | const setResizeObserver = () => { 54 | datas.resizeObserver = new ResizeObserver(() => { 55 | // debounce the reset 56 | clearTimeout(datas.timeOutFunctionId); 57 | datas.timeOutFunctionId = setTimeout(() => { 58 | setGraph(); 59 | }, 100); 60 | }); 61 | const plotlyElm = document.getElementById(datas.plotlyId); 62 | if (plotlyElm) { 63 | datas.resizeObserver.observe(plotlyElm); 64 | } 65 | }; 66 | 67 | // the plotly component is running only on the client-side 68 | onMounted(() => { 69 | setGraph(); 70 | setResizeObserver(); 71 | }); 72 | 73 | // reset graph when props change 74 | watch( 75 | () => [props.data, props.layout, props.config], 76 | () => { 77 | setGraph(); 78 | }, 79 | { deep: true } 80 | ); 81 | 82 | onBeforeUnmount(() => { 83 | datas.resizeObserver.disconnect(); 84 | }); 85 | 86 | return () => h("div", { id: datas.plotlyId }); 87 | }, 88 | }); 89 | -------------------------------------------------------------------------------- /src/runtime/plugin.ts: -------------------------------------------------------------------------------- 1 | import type { Plugin } from "nuxt/app"; 2 | import { defineNuxtPlugin } from "#imports"; 3 | 4 | import Plotly from "plotly.js-dist-min"; 5 | 6 | export default defineNuxtPlugin(() => { 7 | return { 8 | provide: { 9 | plotly: Plotly, 10 | }, 11 | }; 12 | }) as Plugin<{ plotly: typeof Plotly }>; 13 | -------------------------------------------------------------------------------- /test/basic.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | import { fileURLToPath } from 'node:url' 3 | import { setup, $fetch } from '@nuxt/test-utils' 4 | 5 | describe('ssr', async () => { 6 | await setup({ 7 | rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)), 8 | }) 9 | 10 | it('renders the index page', async () => { 11 | // Get response to a server-rendered page with `$fetch`. 12 | const html = await $fetch('/') 13 | expect(html).toContain('
basic
') 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /test/fixtures/basic/app.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 7 | -------------------------------------------------------------------------------- /test/fixtures/basic/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | import MyModule from '../../../src/module' 2 | 3 | export default defineNuxtConfig({ 4 | modules: [ 5 | MyModule 6 | ] 7 | }) 8 | -------------------------------------------------------------------------------- /test/fixtures/basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "basic", 4 | "type": "module" 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./playground/.nuxt/tsconfig.json", 3 | "compilerOptions": { 4 | "target": "esnext", 5 | "module": "esnext" 6 | } 7 | } 8 | --------------------------------------------------------------------------------